Skip to content

Commit e948609

Browse files
committed
Infer provider from model for requested turns
- Resolve turn provider from explicit provider or model hint before canonicalizing selection - Tighten projector test assertions for thread shape - Use non-mutating key sorting in model selection equality
1 parent bc01562 commit e948609

File tree

3 files changed

+40
-22
lines changed

3 files changed

+40
-22
lines changed

apps/server/src/orchestration/Layers/ProviderCommandReactor.ts

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,16 @@ const make = Effect.gen(function* () {
270270
return readModel.threads.find((entry) => entry.id === threadId);
271271
});
272272

273+
const resolveRequestedTurnProvider = (input: {
274+
readonly threadSelection: ModelSelection;
275+
readonly provider?: ProviderKind;
276+
readonly model?: string;
277+
}): ProviderKind =>
278+
input.provider ??
279+
(input.model !== undefined
280+
? inferProviderForModel(input.model, input.threadSelection.provider)
281+
: input.threadSelection.provider);
282+
273283
const ensureSessionForThread = Effect.fnUntraced(function* (
274284
threadId: ThreadId,
275285
createdAt: string,
@@ -294,11 +304,16 @@ const make = Effect.gen(function* () {
294304
? thread.session.providerName
295305
: undefined;
296306
const threadSelection = resolveThreadModelSelection(thread);
307+
const requestedProvider = resolveRequestedTurnProvider({
308+
threadSelection,
309+
...(options?.provider !== undefined ? { provider: options.provider } : {}),
310+
...(options?.model !== undefined ? { model: options.model } : {}),
311+
});
297312
const requestedSelection =
298313
options?.modelSelection ??
299314
(options?.provider || options?.model || options?.modelOptions
300315
? toCanonicalModelSelection(
301-
options?.provider ?? threadSelection.provider,
316+
requestedProvider,
302317
options?.model ?? threadSelection.model,
303318
options?.modelOptions ?? getModelSelectionOptions(threadSelection),
304319
)

apps/server/src/orchestration/projector.test.ts

Lines changed: 22 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -72,27 +72,30 @@ describe("orchestration projector", () => {
7272
);
7373

7474
expect(next.snapshotSequence).toBe(1);
75-
expect(next.threads).toEqual([
76-
{
77-
id: "thread-1",
78-
projectId: "project-1",
79-
title: "demo",
75+
expect(next.threads).toHaveLength(1);
76+
expect(next.threads[0]).toMatchObject({
77+
id: "thread-1",
78+
projectId: "project-1",
79+
title: "demo",
80+
model: "gpt-5-codex",
81+
modelSelection: {
82+
provider: "codex",
8083
model: "gpt-5-codex",
81-
runtimeMode: "full-access",
82-
interactionMode: "chat",
83-
branch: null,
84-
worktreePath: null,
85-
latestTurn: null,
86-
createdAt: now,
87-
updatedAt: now,
88-
deletedAt: null,
89-
messages: [],
90-
proposedPlans: [],
91-
activities: [],
92-
checkpoints: [],
93-
session: null,
9484
},
95-
]);
85+
runtimeMode: "full-access",
86+
interactionMode: "chat",
87+
branch: null,
88+
worktreePath: null,
89+
latestTurn: null,
90+
createdAt: now,
91+
updatedAt: now,
92+
deletedAt: null,
93+
});
94+
expect(next.threads[0]?.session ?? null).toBeNull();
95+
expect(next.threads[0]?.messages).toEqual([]);
96+
expect(next.threads[0]?.proposedPlans).toEqual([]);
97+
expect(next.threads[0]?.activities).toEqual([]);
98+
expect(next.threads[0]?.checkpoints).toEqual([]);
9699
});
97100

98101
it("fails when event payload cannot be decoded by runtime schema", async () => {

packages/shared/src/modelSelection.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,8 +75,8 @@ export function modelSelectionsAreEqual(
7575
const bOpts = b.options ?? null;
7676
if (aOpts === null && bOpts === null) return true;
7777
if (aOpts === null || bOpts === null) return false;
78-
const aKeys = Object.keys(aOpts).sort();
79-
const bKeys = Object.keys(bOpts).sort();
78+
const aKeys = Object.keys(aOpts).toSorted();
79+
const bKeys = Object.keys(bOpts).toSorted();
8080
if (aKeys.join(",") !== bKeys.join(",")) return false;
8181
return aKeys.every(
8282
(k) => (aOpts as Record<string, unknown>)[k] === (bOpts as Record<string, unknown>)[k],

0 commit comments

Comments
 (0)