authorgravatar for 142016413+chuks-qua@users.noreply.github.com(CJ) Chukwudi Nwobodo <142016413+chuks-qua@users.noreply.github.com> 2026-03-08 22:55:49+00:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2026-03-08 15:55:49-07:00
loga7ec0179fb42b12ab7e1fd4c2cabd508c8f8de67
tree5d97745b5e18e9b6b39ff6ea2de9fa640dcf5897
parentc97c6b7836ce888b24a157de8eb4aea761028979
signature Signed by PGP key B5690EEEBB952194

Fix codex binary path setting having no effect (#493)

* refactor(contracts): export ProviderStartOptions schema * feat(contracts): add providerOptions to ThreadTurnStartCommand * feat(web): send codex binary/home path settings to server * feat(server): thread providerOptions through to session startup * fix(contracts): define ProviderStartOptions inline to avoid circular dep The import from provider.ts caused a ReferenceError at runtime because of module initialization order in the bundled output. * fix(server): preserve providerOptions across runtime mode changes and session recovery Runtime mode toggles and server restarts silently dropped the custom codex binary/home path, falling back to the default binary. Cache providerOptions per thread in ProviderCommandReactor and persist it in the session binding's runtimePayload so recovery can restore it. Closes #486

7 files changed, 79 insertions(+), 9 deletions(-)

apps/server/scripts/cli.ts+2
...@@ -132,6 +132,7 @@ const buildCmd = Command.make(...@@ -132,6 +132,7 @@ const buildCmd = Command.make(
132 cwd: serverDir,132 cwd: serverDir,
133 stdout: config.verbose ? "inherit" : "ignore",133 stdout: config.verbose ? "inherit" : "ignore",
134 stderr: "inherit",134 stderr: "inherit",
135 shell: process.platform === "win32",
135 })`bun tsdown`,136 })`bun tsdown`,
136 );137 );
137138
...@@ -225,6 +226,7 @@ const publishCmd = Command.make(...@@ -225,6 +226,7 @@ const publishCmd = Command.make(
225 cwd: serverDir,226 cwd: serverDir,
226 stdout: config.verbose ? "inherit" : "ignore",227 stdout: config.verbose ? "inherit" : "ignore",
227 stderr: "inherit",228 stderr: "inherit",
229 shell: process.platform === "win32",
228 }),230 }),
229 );231 );
230 }),232 }),
apps/server/src/orchestration/Layers/ProviderCommandReactor.ts+15-1
...@@ -6,6 +6,7 @@ import {...@@ -6,6 +6,7 @@ import {
6 type ProviderModelOptions,6 type ProviderModelOptions,
7 type ProviderKind,7 type ProviderKind,
8 type ProviderServiceTier,8 type ProviderServiceTier,
9 type ProviderStartOptions,
9 type OrchestrationSession,10 type OrchestrationSession,
10 ThreadId,11 ThreadId,
11 type ProviderSession,12 type ProviderSession,
...@@ -144,6 +145,8 @@ const make = Effect.gen(function* () {...@@ -144,6 +145,8 @@ const make = Effect.gen(function* () {
144 ),145 ),
145 );146 );
146147
148 const threadProviderOptions = new Map<string, ProviderStartOptions>();
149
147 const appendProviderFailureActivity = (input: {150 const appendProviderFailureActivity = (input: {
148 readonly threadId: ThreadId;151 readonly threadId: ThreadId;
149 readonly kind:152 readonly kind:
...@@ -203,6 +206,7 @@ const make = Effect.gen(function* () {...@@ -203,6 +206,7 @@ const make = Effect.gen(function* () {
203 readonly model?: string;206 readonly model?: string;
204 readonly modelOptions?: ProviderModelOptions;207 readonly modelOptions?: ProviderModelOptions;
205 readonly serviceTier?: ProviderServiceTier | null;208 readonly serviceTier?: ProviderServiceTier | null;
209 readonly providerOptions?: ProviderStartOptions;
206 },210 },
207 ) {211 ) {
208 const readModel = yield* orchestrationEngine.getReadModel();212 const readModel = yield* orchestrationEngine.getReadModel();
...@@ -239,6 +243,7 @@ const make = Effect.gen(function* () {...@@ -239,6 +243,7 @@ const make = Effect.gen(function* () {
239 ...(desiredModel ? { model: desiredModel } : {}),243 ...(desiredModel ? { model: desiredModel } : {}),
240 ...(options?.serviceTier !== undefined ? { serviceTier: options.serviceTier } : {}),244 ...(options?.serviceTier !== undefined ? { serviceTier: options.serviceTier } : {}),
241 ...(options?.modelOptions !== undefined ? { modelOptions: options.modelOptions } : {}),245 ...(options?.modelOptions !== undefined ? { modelOptions: options.modelOptions } : {}),
246 ...(options?.providerOptions !== undefined ? { providerOptions: options.providerOptions } : {}),
242 ...(input?.resumeCursor !== undefined ? { resumeCursor: input.resumeCursor } : {}),247 ...(input?.resumeCursor !== undefined ? { resumeCursor: input.resumeCursor } : {}),
243 runtimeMode: desiredRuntimeMode,248 runtimeMode: desiredRuntimeMode,
244 });249 });
...@@ -325,6 +330,7 @@ const make = Effect.gen(function* () {...@@ -325,6 +330,7 @@ const make = Effect.gen(function* () {
325 readonly model?: string;330 readonly model?: string;
326 readonly serviceTier?: ProviderServiceTier | null;331 readonly serviceTier?: ProviderServiceTier | null;
327 readonly modelOptions?: ProviderModelOptions;332 readonly modelOptions?: ProviderModelOptions;
333 readonly providerOptions?: ProviderStartOptions;
328 readonly interactionMode?: "default" | "plan";334 readonly interactionMode?: "default" | "plan";
329 readonly createdAt: string;335 readonly createdAt: string;
330 }) {336 }) {
...@@ -332,11 +338,15 @@ const make = Effect.gen(function* () {...@@ -332,11 +338,15 @@ const make = Effect.gen(function* () {
332 if (!thread) {338 if (!thread) {
333 return;339 return;
334 }340 }
341 if (input.providerOptions !== undefined) {
342 threadProviderOptions.set(input.threadId, input.providerOptions);
343 }
335 yield* ensureSessionForThread(input.threadId, input.createdAt, {344 yield* ensureSessionForThread(input.threadId, input.createdAt, {
336 ...(input.provider !== undefined ? { provider: input.provider } : {}),345 ...(input.provider !== undefined ? { provider: input.provider } : {}),
337 ...(input.model !== undefined ? { model: input.model } : {}),346 ...(input.model !== undefined ? { model: input.model } : {}),
338 ...(input.serviceTier !== undefined ? { serviceTier: input.serviceTier } : {}),347 ...(input.serviceTier !== undefined ? { serviceTier: input.serviceTier } : {}),
339 ...(input.modelOptions !== undefined ? { modelOptions: input.modelOptions } : {}),348 ...(input.modelOptions !== undefined ? { modelOptions: input.modelOptions } : {}),
349 ...(input.providerOptions !== undefined ? { providerOptions: input.providerOptions } : {}),
340 });350 });
341 const normalizedInput = toNonEmptyProviderInput(input.messageText);351 const normalizedInput = toNonEmptyProviderInput(input.messageText);
342 const normalizedAttachments = input.attachments ?? [];352 const normalizedAttachments = input.attachments ?? [];
...@@ -472,6 +482,7 @@ const make = Effect.gen(function* () {...@@ -472,6 +482,7 @@ const make = Effect.gen(function* () {
472 ...(event.payload.model !== undefined ? { model: event.payload.model } : {}),482 ...(event.payload.model !== undefined ? { model: event.payload.model } : {}),
473 ...(event.payload.serviceTier !== undefined ? { serviceTier: event.payload.serviceTier } : {}),483 ...(event.payload.serviceTier !== undefined ? { serviceTier: event.payload.serviceTier } : {}),
474 ...(event.payload.modelOptions !== undefined ? { modelOptions: event.payload.modelOptions } : {}),484 ...(event.payload.modelOptions !== undefined ? { modelOptions: event.payload.modelOptions } : {}),
485 ...(event.payload.providerOptions !== undefined ? { providerOptions: event.payload.providerOptions } : {}),
475 interactionMode: event.payload.interactionMode,486 interactionMode: event.payload.interactionMode,
476 createdAt: event.payload.createdAt,487 createdAt: event.payload.createdAt,
477 });488 });
...@@ -627,7 +638,10 @@ const make = Effect.gen(function* () {...@@ -627,7 +638,10 @@ const make = Effect.gen(function* () {
627 if (!thread?.session || thread.session.status === "stopped") {638 if (!thread?.session || thread.session.status === "stopped") {
628 return;639 return;
629 }640 }
630 yield* ensureSessionForThread(event.payload.threadId, event.occurredAt);641 const cachedProviderOptions = threadProviderOptions.get(event.payload.threadId);
642 yield* ensureSessionForThread(event.payload.threadId, event.occurredAt, {
643 ...(cachedProviderOptions !== undefined ? { providerOptions: cachedProviderOptions } : {}),
644 });
631 return;645 return;
632 }646 }
633 case "thread.turn-start-requested":647 case "thread.turn-start-requested":
apps/server/src/orchestration/decider.ts+1
...@@ -303,6 +303,7 @@ export const decideOrchestrationCommand = Effect.fn("decideOrchestrationCommand"...@@ -303,6 +303,7 @@ export const decideOrchestrationCommand = Effect.fn("decideOrchestrationCommand"
303 ...(command.model !== undefined ? { model: command.model } : {}),303 ...(command.model !== undefined ? { model: command.model } : {}),
304 ...(command.serviceTier !== undefined ? { serviceTier: command.serviceTier } : {}),304 ...(command.serviceTier !== undefined ? { serviceTier: command.serviceTier } : {}),
305 ...(command.modelOptions !== undefined ? { modelOptions: command.modelOptions } : {}),305 ...(command.modelOptions !== undefined ? { modelOptions: command.modelOptions } : {}),
306 ...(command.providerOptions !== undefined ? { providerOptions: command.providerOptions } : {}),
306 assistantDeliveryMode: command.assistantDeliveryMode ?? DEFAULT_ASSISTANT_DELIVERY_MODE,307 assistantDeliveryMode: command.assistantDeliveryMode ?? DEFAULT_ASSISTANT_DELIVERY_MODE,
307 runtimeMode:308 runtimeMode:
308 readModel.threads.find((entry) => entry.id === command.threadId)?.runtimeMode ??309 readModel.threads.find((entry) => entry.id === command.threadId)?.runtimeMode ??
apps/server/src/provider/Layers/ProviderService.ts+23-3
...@@ -86,15 +86,30 @@ function toRuntimeStatus(session: ProviderSession): "starting" | "running" | "st...@@ -86,15 +86,30 @@ function toRuntimeStatus(session: ProviderSession): "starting" | "running" | "st
86 }86 }
87}87}
8888
89function toRuntimePayloadFromSession(session: ProviderSession): Record<string, unknown> {89function toRuntimePayloadFromSession(
90 session: ProviderSession,
91 extra?: { readonly providerOptions?: unknown },
92): Record<string, unknown> {
90 return {93 return {
91 cwd: session.cwd ?? null,94 cwd: session.cwd ?? null,
92 model: session.model ?? null,95 model: session.model ?? null,
93 activeTurnId: session.activeTurnId ?? null,96 activeTurnId: session.activeTurnId ?? null,
94 lastError: session.lastError ?? null,97 lastError: session.lastError ?? null,
98 ...(extra?.providerOptions !== undefined ? { providerOptions: extra.providerOptions } : {}),
95 };99 };
96}100}
97101
102function readPersistedProviderOptions(
103 runtimePayload: ProviderRuntimeBinding["runtimePayload"],
104): Record<string, unknown> | undefined {
105 if (!runtimePayload || typeof runtimePayload !== "object" || Array.isArray(runtimePayload)) {
106 return undefined;
107 }
108 const raw = "providerOptions" in runtimePayload ? runtimePayload.providerOptions : undefined;
109 if (!raw || typeof raw !== "object" || Array.isArray(raw)) return undefined;
110 return raw as Record<string, unknown>;
111}
112
98function readPersistedCwd(113function readPersistedCwd(
99 runtimePayload: ProviderRuntimeBinding["runtimePayload"],114 runtimePayload: ProviderRuntimeBinding["runtimePayload"],
100): string | undefined {115): string | undefined {
...@@ -137,6 +152,7 @@ const makeProviderService = (options?: ProviderServiceLiveOptions) =>...@@ -137,6 +152,7 @@ const makeProviderService = (options?: ProviderServiceLiveOptions) =>
137 const upsertSessionBinding = (152 const upsertSessionBinding = (
138 session: ProviderSession,153 session: ProviderSession,
139 threadId: ThreadId,154 threadId: ThreadId,
155 extra?: { readonly providerOptions?: unknown },
140 ) =>156 ) =>
141 directory.upsert({157 directory.upsert({
142 threadId,158 threadId,
...@@ -144,7 +160,7 @@ const makeProviderService = (options?: ProviderServiceLiveOptions) =>...@@ -144,7 +160,7 @@ const makeProviderService = (options?: ProviderServiceLiveOptions) =>
144 runtimeMode: session.runtimeMode,160 runtimeMode: session.runtimeMode,
145 status: toRuntimeStatus(session),161 status: toRuntimeStatus(session),
146 ...(session.resumeCursor !== undefined ? { resumeCursor: session.resumeCursor } : {}),162 ...(session.resumeCursor !== undefined ? { resumeCursor: session.resumeCursor } : {}),
147 runtimePayload: toRuntimePayloadFromSession(session),163 runtimePayload: toRuntimePayloadFromSession(session, extra),
148 });164 });
149165
150 const providers = yield* registry.listProviders();166 const providers = yield* registry.listProviders();
...@@ -197,11 +213,13 @@ const makeProviderService = (options?: ProviderServiceLiveOptions) =>...@@ -197,11 +213,13 @@ const makeProviderService = (options?: ProviderServiceLiveOptions) =>
197 }213 }
198214
199 const persistedCwd = readPersistedCwd(input.binding.runtimePayload);215 const persistedCwd = readPersistedCwd(input.binding.runtimePayload);
216 const persistedProviderOptions = readPersistedProviderOptions(input.binding.runtimePayload);
200217
201 const resumed = yield* adapter.startSession({218 const resumed = yield* adapter.startSession({
202 threadId: input.binding.threadId,219 threadId: input.binding.threadId,
203 provider: input.binding.provider,220 provider: input.binding.provider,
204 ...(persistedCwd ? { cwd: persistedCwd } : {}),221 ...(persistedCwd ? { cwd: persistedCwd } : {}),
222 ...(persistedProviderOptions ? { providerOptions: persistedProviderOptions } : {}),
205 ...(hasResumeCursor ? { resumeCursor: input.binding.resumeCursor } : {}),223 ...(hasResumeCursor ? { resumeCursor: input.binding.resumeCursor } : {}),
206 runtimeMode: input.binding.runtimeMode ?? "full-access",224 runtimeMode: input.binding.runtimeMode ?? "full-access",
207 });225 });
...@@ -273,7 +291,9 @@ const makeProviderService = (options?: ProviderServiceLiveOptions) =>...@@ -273,7 +291,9 @@ const makeProviderService = (options?: ProviderServiceLiveOptions) =>
273 );291 );
274 }292 }
275293
276 yield* upsertSessionBinding(session, threadId);294 yield* upsertSessionBinding(session, threadId, {
295 ...(input.providerOptions !== undefined ? { providerOptions: input.providerOptions } : {}),
296 });
277 yield* analytics.record("provider.session.started", {297 yield* analytics.record("provider.session.started", {
278 provider: session.provider,298 provider: session.provider,
279 runtimeMode: input.runtimeMode,299 runtimeMode: input.runtimeMode,
apps/web/src/components/ChatView.tsx+26-4
...@@ -830,6 +830,17 @@ export default function ChatView({ threadId }: ChatViewProps) {...@@ -830,6 +830,17 @@ export default function ChatView({ threadId }: ChatViewProps) {
830 };830 };
831 return Object.keys(codexOptions).length > 0 ? { codex: codexOptions } : undefined;831 return Object.keys(codexOptions).length > 0 ? { codex: codexOptions } : undefined;
832 }, [selectedCodexFastModeEnabled, selectedEffort, selectedProvider, supportsReasoningEffort]);832 }, [selectedCodexFastModeEnabled, selectedEffort, selectedProvider, supportsReasoningEffort]);
833 const providerOptionsForDispatch = useMemo(() => {
834 if (!settings.codexBinaryPath && !settings.codexHomePath) {
835 return undefined;
836 }
837 return {
838 codex: {
839 ...(settings.codexBinaryPath ? { binaryPath: settings.codexBinaryPath } : {}),
840 ...(settings.codexHomePath ? { homePath: settings.codexHomePath } : {}),
841 },
842 };
843 }, [settings.codexBinaryPath, settings.codexHomePath]);
833 const selectedModelForPicker = selectedModel;844 const selectedModelForPicker = selectedModel;
834 const modelOptionsByProvider = useMemo(845 const modelOptionsByProvider = useMemo(
835 () => getCustomModelOptionsByProvider(settings),846 () => getCustomModelOptionsByProvider(settings),
...@@ -2626,6 +2637,9 @@ export default function ChatView({ threadId }: ChatViewProps) {...@@ -2626,6 +2637,9 @@ export default function ChatView({ threadId }: ChatViewProps) {
2626 ...(selectedModelOptionsForDispatch2637 ...(selectedModelOptionsForDispatch
2627 ? { modelOptions: selectedModelOptionsForDispatch }2638 ? { modelOptions: selectedModelOptionsForDispatch }
2628 : {}),2639 : {}),
2640 ...(providerOptionsForDispatch
2641 ? { providerOptions: providerOptionsForDispatch }
2642 : {}),
2629 provider: selectedProvider,2643 provider: selectedProvider,
2630 assistantDeliveryMode: settings.enableAssistantStreaming ? "streaming" : "buffered",2644 assistantDeliveryMode: settings.enableAssistantStreaming ? "streaming" : "buffered",
2631 runtimeMode,2645 runtimeMode,
...@@ -2903,6 +2917,9 @@ export default function ChatView({ threadId }: ChatViewProps) {...@@ -2903,6 +2917,9 @@ export default function ChatView({ threadId }: ChatViewProps) {
2903 ...(selectedModelOptionsForDispatch2917 ...(selectedModelOptionsForDispatch
2904 ? { modelOptions: selectedModelOptionsForDispatch }2918 ? { modelOptions: selectedModelOptionsForDispatch }
2905 : {}),2919 : {}),
2920 ...(providerOptionsForDispatch
2921 ? { providerOptions: providerOptionsForDispatch }
2922 : {}),
2906 assistantDeliveryMode: settings.enableAssistantStreaming ? "streaming" : "buffered",2923 assistantDeliveryMode: settings.enableAssistantStreaming ? "streaming" : "buffered",
2907 runtimeMode,2924 runtimeMode,
2908 interactionMode: nextInteractionMode,2925 interactionMode: nextInteractionMode,
...@@ -2933,6 +2950,7 @@ export default function ChatView({ threadId }: ChatViewProps) {...@@ -2933,6 +2950,7 @@ export default function ChatView({ threadId }: ChatViewProps) {
2933 runtimeMode,2950 runtimeMode,
2934 selectedModel,2951 selectedModel,
2935 selectedModelOptionsForDispatch,2952 selectedModelOptionsForDispatch,
2953 providerOptionsForDispatch,
2936 selectedProvider,2954 selectedProvider,
2937 setComposerDraftInteractionMode,2955 setComposerDraftInteractionMode,
2938 setThreadError,2956 setThreadError,
...@@ -2987,8 +3005,8 @@ export default function ChatView({ threadId }: ChatViewProps) {...@@ -2987,8 +3005,8 @@ export default function ChatView({ threadId }: ChatViewProps) {
2987 worktreePath: activeThread.worktreePath,3005 worktreePath: activeThread.worktreePath,
2988 createdAt,3006 createdAt,
2989 })3007 })
2990 .then(() =>3008 .then(() => {
2991 api.orchestration.dispatchCommand({3009 return api.orchestration.dispatchCommand({
2992 type: "thread.turn.start",3010 type: "thread.turn.start",
2993 commandId: newCommandId(),3011 commandId: newCommandId(),
2994 threadId: nextThreadId,3012 threadId: nextThreadId,
...@@ -3003,12 +3021,15 @@ export default function ChatView({ threadId }: ChatViewProps) {...@@ -3003,12 +3021,15 @@ export default function ChatView({ threadId }: ChatViewProps) {
3003 ...(selectedModelOptionsForDispatch3021 ...(selectedModelOptionsForDispatch
3004 ? { modelOptions: selectedModelOptionsForDispatch }3022 ? { modelOptions: selectedModelOptionsForDispatch }
3005 : {}),3023 : {}),
3024 ...(providerOptionsForDispatch
3025 ? { providerOptions: providerOptionsForDispatch }
3026 : {}),
3006 assistantDeliveryMode: settings.enableAssistantStreaming ? "streaming" : "buffered",3027 assistantDeliveryMode: settings.enableAssistantStreaming ? "streaming" : "buffered",
3007 runtimeMode,3028 runtimeMode,
3008 interactionMode: "default",3029 interactionMode: "default",
3009 createdAt,3030 createdAt,
3010 }),3031 });
3011 )3032 })
3012 .then(() => api.orchestration.getSnapshot())3033 .then(() => api.orchestration.getSnapshot())
3013 .then((snapshot) => {3034 .then((snapshot) => {
3014 syncServerReadModel(snapshot);3035 syncServerReadModel(snapshot);
...@@ -3052,6 +3073,7 @@ export default function ChatView({ threadId }: ChatViewProps) {...@@ -3052,6 +3073,7 @@ export default function ChatView({ threadId }: ChatViewProps) {
3052 runtimeMode,3073 runtimeMode,
3053 selectedModel,3074 selectedModel,
3054 selectedModelOptionsForDispatch,3075 selectedModelOptionsForDispatch,
3076 providerOptionsForDispatch,
3055 selectedProvider,3077 selectedProvider,
3056 settings.enableAssistantStreaming,3078 settings.enableAssistantStreaming,
3057 syncServerReadModel,3079 syncServerReadModel,
packages/contracts/src/orchestration.ts+10
...@@ -45,6 +45,13 @@ export type ProviderSandboxMode = typeof ProviderSandboxMode.Type;...@@ -45,6 +45,13 @@ export type ProviderSandboxMode = typeof ProviderSandboxMode.Type;
45export const ProviderServiceTier = Schema.Literals(["fast", "flex"]);45export const ProviderServiceTier = Schema.Literals(["fast", "flex"]);
46export type ProviderServiceTier = typeof ProviderServiceTier.Type;46export type ProviderServiceTier = typeof ProviderServiceTier.Type;
47export const DEFAULT_PROVIDER_KIND: ProviderKind = "codex";47export const DEFAULT_PROVIDER_KIND: ProviderKind = "codex";
48const CodexProviderStartOptions = Schema.Struct({
49 binaryPath: Schema.optional(TrimmedNonEmptyString),
50 homePath: Schema.optional(TrimmedNonEmptyString),
51});
52const ProviderStartOptions = Schema.Struct({
53 codex: Schema.optional(CodexProviderStartOptions),
54});
48export const RuntimeMode = Schema.Literals(["approval-required", "full-access"]);55export const RuntimeMode = Schema.Literals(["approval-required", "full-access"]);
49export type RuntimeMode = typeof RuntimeMode.Type;56export type RuntimeMode = typeof RuntimeMode.Type;
50export const DEFAULT_RUNTIME_MODE: RuntimeMode = "full-access";57export const DEFAULT_RUNTIME_MODE: RuntimeMode = "full-access";
...@@ -366,6 +373,7 @@ export const ThreadTurnStartCommand = Schema.Struct({...@@ -366,6 +373,7 @@ export const ThreadTurnStartCommand = Schema.Struct({
366 model: Schema.optional(TrimmedNonEmptyString),373 model: Schema.optional(TrimmedNonEmptyString),
367 serviceTier: Schema.optional(Schema.NullOr(ProviderServiceTier)),374 serviceTier: Schema.optional(Schema.NullOr(ProviderServiceTier)),
368 modelOptions: Schema.optional(ProviderModelOptions),375 modelOptions: Schema.optional(ProviderModelOptions),
376 providerOptions: Schema.optional(ProviderStartOptions),
369 assistantDeliveryMode: Schema.optional(AssistantDeliveryMode),377 assistantDeliveryMode: Schema.optional(AssistantDeliveryMode),
370 runtimeMode: RuntimeMode.pipe(Schema.withDecodingDefault(() => DEFAULT_RUNTIME_MODE)),378 runtimeMode: RuntimeMode.pipe(Schema.withDecodingDefault(() => DEFAULT_RUNTIME_MODE)),
371 interactionMode: ProviderInteractionMode.pipe(379 interactionMode: ProviderInteractionMode.pipe(
...@@ -388,6 +396,7 @@ const ClientThreadTurnStartCommand = Schema.Struct({...@@ -388,6 +396,7 @@ const ClientThreadTurnStartCommand = Schema.Struct({
388 model: Schema.optional(TrimmedNonEmptyString),396 model: Schema.optional(TrimmedNonEmptyString),
389 serviceTier: Schema.optional(Schema.NullOr(ProviderServiceTier)),397 serviceTier: Schema.optional(Schema.NullOr(ProviderServiceTier)),
390 modelOptions: Schema.optional(ProviderModelOptions),398 modelOptions: Schema.optional(ProviderModelOptions),
399 providerOptions: Schema.optional(ProviderStartOptions),
391 assistantDeliveryMode: Schema.optional(AssistantDeliveryMode),400 assistantDeliveryMode: Schema.optional(AssistantDeliveryMode),
392 runtimeMode: RuntimeMode,401 runtimeMode: RuntimeMode,
393 interactionMode: ProviderInteractionMode,402 interactionMode: ProviderInteractionMode,
...@@ -668,6 +677,7 @@ export const ThreadTurnStartRequestedPayload = Schema.Struct({...@@ -668,6 +677,7 @@ export const ThreadTurnStartRequestedPayload = Schema.Struct({
668 model: Schema.optional(TrimmedNonEmptyString),677 model: Schema.optional(TrimmedNonEmptyString),
669 serviceTier: Schema.optional(Schema.NullOr(ProviderServiceTier)),678 serviceTier: Schema.optional(Schema.NullOr(ProviderServiceTier)),
670 modelOptions: Schema.optional(ProviderModelOptions),679 modelOptions: Schema.optional(ProviderModelOptions),
680 providerOptions: Schema.optional(ProviderStartOptions),
671 assistantDeliveryMode: Schema.optional(AssistantDeliveryMode),681 assistantDeliveryMode: Schema.optional(AssistantDeliveryMode),
672 runtimeMode: RuntimeMode.pipe(Schema.withDecodingDefault(() => DEFAULT_RUNTIME_MODE)),682 runtimeMode: RuntimeMode.pipe(Schema.withDecodingDefault(() => DEFAULT_RUNTIME_MODE)),
673 interactionMode: ProviderInteractionMode.pipe(683 interactionMode: ProviderInteractionMode.pipe(
packages/contracts/src/provider.ts+2-1
...@@ -53,9 +53,10 @@ const CodexProviderStartOptions = Schema.Struct({...@@ -53,9 +53,10 @@ const CodexProviderStartOptions = Schema.Struct({
53 homePath: Schema.optional(TrimmedNonEmptyStringSchema),53 homePath: Schema.optional(TrimmedNonEmptyStringSchema),
54});54});
5555
56const ProviderStartOptions = Schema.Struct({56export const ProviderStartOptions = Schema.Struct({
57 codex: Schema.optional(CodexProviderStartOptions),57 codex: Schema.optional(CodexProviderStartOptions),
58});58});
59export type ProviderStartOptions = typeof ProviderStartOptions.Type;
5960
60export const ProviderSessionStartInput = Schema.Struct({61export const ProviderSessionStartInput = Schema.Struct({
61 threadId: ThreadId,62 threadId: ThreadId,