Skip to content

Commit 891c04f

Browse files
committed
Merge remote-tracking branch 'origin/main' into feat/kimi-code
2 parents e18ce77 + 7af1a8a commit 891c04f

131 files changed

Lines changed: 5188 additions & 915 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

apps/vscode-e2e/src/fixtures/subtasks.ts

Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ const SUBTASK_PARENT_MARKER = "SUBTASK_PARENT_CANCELLATION_SMOKE"
77
const SUBTASK_CHILD_MARKER = "SUBTASK_CHILD_CALCULATOR_SMOKE"
88
const SUBTASK_INTERRUPT_PARENT_MARKER = "SUBTASK_PARENT_INTERRUPT_RESUME"
99
const SUBTASK_INTERRUPT_CHILD_MARKER = "SUBTASK_CHILD_INTERRUPT_RESUME"
10+
export const SUBTASK_API_HANG_PARENT_MARKER = "SUBTASK_PARENT_API_HANG_INTERRUPT_RESUME"
11+
export const SUBTASK_API_HANG_CHILD_MARKER = "SUBTASK_CHILD_API_HANG_INTERRUPT_RESUME"
1012
const SUBTASK_FAST_PARENT_MARKER = "SUBTASK_PARENT_IMMEDIATE_COMPLETION"
1113
const SUBTASK_FAST_CHILD_MARKER = "SUBTASK_CHILD_IMMEDIATE_COMPLETION"
1214
const SUBTASK_XPROFILE_PARENT_MARKER = "SUBTASK_PARENT_CROSS_PROFILE"
@@ -24,13 +26,29 @@ export const SUBTASK_INTERRUPT_PARENT_PROMPT = `${SUBTASK_INTERRUPT_PARENT_MARKE
2426
export const SUBTASK_INTERRUPT_CHILD_FOLLOWUP_ANSWER = "9"
2527
export const SUBTASK_INTERRUPT_PARENT_RESULT = "Interrupted parent resumed"
2628

29+
const SUBTASK_API_HANG_CHILD_PROMPT = `${SUBTASK_API_HANG_CHILD_MARKER}: Complete with the exact result "Hung child completed".`
30+
export const SUBTASK_API_HANG_PARENT_PROMPT = `${SUBTASK_API_HANG_PARENT_MARKER}: Use the new_task tool exactly once. Create an ask-mode subtask with this exact message: "${SUBTASK_API_HANG_CHILD_PROMPT}" Do not answer directly. When the subtask returns, complete with the exact result "API hang parent resumed".`
31+
export const SUBTASK_API_HANG_RESUME_MESSAGE = "Continue after provider hang."
32+
export const SUBTASK_API_HANG_CHILD_RESULT = "Hung child completed"
33+
export const SUBTASK_API_HANG_PARENT_RESULT = "API hang parent resumed"
34+
35+
// Abandon-subtask scenario (#559) — separate markers to avoid sequenceIndex collisions with the
36+
// interrupted-child-resumes tests above, which exhaust the sequence count for INTERRUPT markers.
37+
const SUBTASK_ABANDON_PARENT_MARKER = "SUBTASK_PARENT_ABANDON_SEVER"
38+
const SUBTASK_ABANDON_CHILD_MARKER = "SUBTASK_CHILD_ABANDON_SEVER"
39+
const SUBTASK_ABANDON_CHILD_PROMPT = `${SUBTASK_ABANDON_CHILD_MARKER}: Ask the user exactly this follow-up question: What is the square root of 81? After the user answers, complete with only the answer.`
40+
export const SUBTASK_ABANDON_PARENT_PROMPT = `${SUBTASK_ABANDON_PARENT_MARKER}: Use the new_task tool exactly once. Create an ask-mode subtask with this exact message: "${SUBTASK_ABANDON_CHILD_PROMPT}" Do not answer directly.`
41+
export const SUBTASK_ABANDON_CHILD_FOLLOWUP_ANSWER = "9"
42+
2743
const SUBTASK_XPROFILE_SAME_CHILD_PROMPT = `${SUBTASK_XPROFILE_SAME_CHILD_MARKER}: Complete immediately with the exact result "Same-profile child completed".`
2844
const SUBTASK_XPROFILE_DIFFERENT_CHILD_PROMPT = `${SUBTASK_XPROFILE_DIFFERENT_CHILD_MARKER}: Complete immediately with the exact result "Different-profile child completed".`
2945
export const SUBTASK_XPROFILE_PARENT_PROMPT = `${SUBTASK_XPROFILE_PARENT_MARKER}: First use new_task to create a code-mode subtask with this exact message: "${SUBTASK_XPROFILE_SAME_CHILD_PROMPT}" After it returns, create an ask-mode subtask with the next instructions you receive.`
3046
export const SUBTASK_XPROFILE_SAME_CHILD_RESULT = "Same-profile child completed"
3147
export const SUBTASK_XPROFILE_DIFFERENT_CHILD_RESULT = "Different-profile child completed"
3248
export const SUBTASK_XPROFILE_PARENT_RESULT = "Sequential cross-profile parent resumed"
3349

50+
const apiHangChildMatch = new RegExp(SUBTASK_API_HANG_CHILD_MARKER)
51+
3452
const requestContains = (req: ChatCompletionRequest, expected: string[]) => {
3553
const rawRequest = JSON.stringify(req)
3654
return expected.every((text) => rawRequest.includes(text))
@@ -167,6 +185,79 @@ export function addSubtaskFixtures(mock: InstanceType<typeof LLMock>) {
167185
},
168186
})
169187

188+
mock.addFixture({
189+
match: {
190+
userMessage: new RegExp(SUBTASK_API_HANG_PARENT_MARKER),
191+
sequenceIndex: 0,
192+
},
193+
response: {
194+
toolCalls: [
195+
{
196+
name: "new_task",
197+
arguments: JSON.stringify({
198+
mode: "ask",
199+
message: SUBTASK_API_HANG_CHILD_PROMPT,
200+
}),
201+
id: "call_api_hang_parent_new_task_001",
202+
},
203+
],
204+
},
205+
})
206+
207+
mock.addFixture({
208+
match: {
209+
userMessage: apiHangChildMatch,
210+
sequenceIndex: 0,
211+
},
212+
// Keep the first child response pending long enough for the e2e test to cancel an in-flight API request.
213+
latency: 15_000,
214+
response: {
215+
toolCalls: [
216+
{
217+
name: "attempt_completion",
218+
arguments: JSON.stringify({ result: SUBTASK_API_HANG_CHILD_RESULT }),
219+
id: "call_api_hang_child_completion_002",
220+
},
221+
],
222+
},
223+
})
224+
225+
mock.addFixture({
226+
match: {
227+
userMessage: apiHangChildMatch,
228+
sequenceIndex: 1,
229+
},
230+
response: {
231+
toolCalls: [
232+
{
233+
name: "attempt_completion",
234+
arguments: JSON.stringify({ result: SUBTASK_API_HANG_CHILD_RESULT }),
235+
id: "call_api_hang_child_completion_003",
236+
},
237+
],
238+
},
239+
})
240+
241+
mock.addFixture({
242+
match: {
243+
predicate: (req: ChatCompletionRequest) =>
244+
requestContains(req, [
245+
SUBTASK_API_HANG_PARENT_MARKER,
246+
"call_api_hang_parent_new_task_001",
247+
SUBTASK_API_HANG_CHILD_RESULT,
248+
]),
249+
},
250+
response: {
251+
toolCalls: [
252+
{
253+
name: "attempt_completion",
254+
arguments: JSON.stringify({ result: SUBTASK_API_HANG_PARENT_RESULT }),
255+
id: "call_api_hang_parent_completion_004",
256+
},
257+
],
258+
},
259+
})
260+
170261
// Issue #457 sequence: a same-profile child returns first, then the resumed
171262
// parent delegates to a child whose mode uses a different API profile.
172263
mock.addFixture({
@@ -354,4 +445,67 @@ export function addSubtaskFixtures(mock: InstanceType<typeof LLMock>) {
354445
],
355446
},
356447
})
448+
449+
// Abandon-subtask scenario (#559)
450+
mock.addFixture({
451+
match: {
452+
userMessage: new RegExp(SUBTASK_ABANDON_PARENT_MARKER),
453+
sequenceIndex: 0,
454+
},
455+
response: {
456+
toolCalls: [
457+
{
458+
name: "new_task",
459+
arguments: JSON.stringify({
460+
mode: "ask",
461+
message: SUBTASK_ABANDON_CHILD_PROMPT,
462+
}),
463+
id: "call_abandon_parent_new_task_001",
464+
},
465+
],
466+
},
467+
})
468+
469+
mock.addFixture({
470+
match: {
471+
predicate: (req: ChatCompletionRequest) =>
472+
requestContains(req, [SUBTASK_ABANDON_CHILD_MARKER]) &&
473+
!requestContains(req, [SUBTASK_ABANDON_PARENT_MARKER]) &&
474+
!requestContains(req, ["call_abandon_child_followup_001"]) &&
475+
!requestContains(req, [`<user_message>\\n${SUBTASK_ABANDON_CHILD_FOLLOWUP_ANSWER}\\n</user_message>`]),
476+
},
477+
response: {
478+
toolCalls: [
479+
{
480+
name: "ask_followup_question",
481+
arguments: JSON.stringify({
482+
question: "What is the square root of 81?",
483+
follow_up: [{ text: SUBTASK_ABANDON_CHILD_FOLLOWUP_ANSWER }],
484+
}),
485+
id: "call_abandon_child_followup_001",
486+
},
487+
],
488+
},
489+
})
490+
491+
mock.addFixture({
492+
match: {
493+
predicate: (req: ChatCompletionRequest) =>
494+
toolResultContains(req, "call_abandon_child_followup_001", [SUBTASK_ABANDON_CHILD_FOLLOWUP_ANSWER]) ||
495+
requestContains(req, ["call_abandon_child_followup_001", SUBTASK_ABANDON_CHILD_FOLLOWUP_ANSWER]) ||
496+
requestContains(req, [
497+
SUBTASK_ABANDON_CHILD_MARKER,
498+
`<user_message>\\n${SUBTASK_ABANDON_CHILD_FOLLOWUP_ANSWER}\\n</user_message>`,
499+
]),
500+
},
501+
response: {
502+
toolCalls: [
503+
{
504+
name: "attempt_completion",
505+
arguments: JSON.stringify({ result: SUBTASK_ABANDON_CHILD_FOLLOWUP_ANSWER }),
506+
id: "call_abandon_child_completion_002",
507+
},
508+
],
509+
},
510+
})
357511
}

0 commit comments

Comments
 (0)