Skip to content

Commit 840eda2

Browse files
test(handle-subtask): assert SubtaskPart.variant reaches tool input
Add a new live test "subtask variant is threaded into tool-part state.input" that creates a subtask with variant="high", drives the loop until the tool-part is observable, and asserts state.input.variant === "high". Also extends the addSubtask helper with an optional `variant` parameter and adds a variantProviderCfg helper with high/low variants on test-model. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent c853245 commit 840eda2

1 file changed

Lines changed: 70 additions & 1 deletion

File tree

packages/opencode/test/session/prompt-effect.test.ts

Lines changed: 70 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,30 @@ function providerCfg(url: string) {
265265
}
266266
}
267267

268+
// kilocode_change start — provider config with variants for subtask variant threading test
269+
function variantProviderCfg(url: string) {
270+
return {
271+
...providerCfg(url),
272+
provider: {
273+
...providerCfg(url).provider,
274+
test: {
275+
...providerCfg(url).provider.test,
276+
models: {
277+
"test-model": {
278+
...cfg.provider.test.models["test-model"],
279+
reasoning: true,
280+
variants: {
281+
low: { reasoningEffort: "low" },
282+
high: { reasoningEffort: "high" },
283+
},
284+
},
285+
},
286+
},
287+
},
288+
}
289+
}
290+
// kilocode_change end
291+
268292
const user = Effect.fn("test.user")(function* (sessionID: SessionID, text: string) {
269293
const session = yield* Session.Service
270294
const msg = yield* session.updateMessage({
@@ -314,7 +338,7 @@ const seed = Effect.fn("test.seed")(function* (sessionID: SessionID, opts?: { fi
314338
return { user: msg, assistant }
315339
})
316340

317-
const addSubtask = (sessionID: SessionID, messageID: MessageID, model = ref) =>
341+
const addSubtask = (sessionID: SessionID, messageID: MessageID, model = ref, variant?: string) => // kilocode_change — added optional variant param
318342
Effect.gen(function* () {
319343
const session = yield* Session.Service
320344
yield* session.updatePart({
@@ -326,6 +350,7 @@ const addSubtask = (sessionID: SessionID, messageID: MessageID, model = ref) =>
326350
description: "inspect bug",
327351
agent: "general",
328352
model,
353+
variant, // kilocode_change — forward variant to subtask part
329354
})
330355
})
331356

@@ -693,6 +718,50 @@ it.live(
693718
10_000,
694719
)
695720

721+
// kilocode_change start — assert SubtaskPart.variant reaches tool-call input
722+
// Note: this observes the persisted tool-part `state.input` only. `handleSubtask` writes
723+
// `task.variant` to both `state.input` and the separate `taskArgs` object passed to
724+
// TaskTool.execute — see handleSubtask in prompt.ts. A one-sided revert of only the
725+
// taskArgs write would pass this test but silently break forwarding. Both writes read
726+
// the same `task.variant` expression on adjacent lines, so the practical risk is low.
727+
it.live(
728+
"subtask variant is threaded into tool-part state.input",
729+
() =>
730+
provideTmpdirServer(
731+
Effect.fnUntraced(function* ({ llm }) {
732+
const prompt = yield* SessionPrompt.Service
733+
const sessions = yield* Session.Service
734+
const chat = yield* sessions.create({ title: "Pinned" })
735+
yield* llm.hang
736+
const msg = yield* user(chat.id, "hello")
737+
yield* addSubtask(chat.id, msg.id, ref, "high")
738+
739+
const fiber = yield* prompt.loop({ sessionID: chat.id }).pipe(Effect.forkChild)
740+
741+
const tool = yield* Effect.promise(async () => {
742+
const end = Date.now() + 5_000
743+
while (Date.now() < end) {
744+
const msgs = await Effect.runPromise(MessageV2.filterCompactedEffect(chat.id))
745+
const taskMsg = msgs.find((item) => item.info.role === "assistant" && item.info.agent === "general")
746+
const tool = taskMsg?.parts.find((part): part is MessageV2.ToolPart => part.type === "tool")
747+
if (tool?.state.status === "running" && tool.state.metadata?.sessionId) return tool
748+
await new Promise((done) => setTimeout(done, 20))
749+
}
750+
throw new Error("timed out waiting for subtask tool part with sessionId metadata")
751+
})
752+
753+
if (tool.state.status !== "running") return
754+
expect(tool.state.input?.variant).toBe("high")
755+
756+
yield* prompt.cancel(chat.id)
757+
yield* Fiber.await(fiber)
758+
}),
759+
{ git: true, config: variantProviderCfg },
760+
),
761+
5_000,
762+
)
763+
// kilocode_change end
764+
696765
it.live(
697766
"loop sets status to busy then idle",
698767
() =>

0 commit comments

Comments
 (0)