-
Notifications
You must be signed in to change notification settings - Fork 212
Expand file tree
/
Copy pathsubtasks.ts
More file actions
95 lines (86 loc) · 2.86 KB
/
Copy pathsubtasks.ts
File metadata and controls
95 lines (86 loc) · 2.86 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
import { LLMock } from "@copilotkit/aimock"
import type { ChatCompletionRequest } from "@copilotkit/aimock"
import { toolResultContains } from "./tool-result"
const SUBTASK_PARENT_MARKER = "SUBTASK_PARENT_CANCELLATION_SMOKE"
const SUBTASK_CHILD_MARKER = "SUBTASK_CHILD_CALCULATOR_SMOKE"
const SUBTASK_CHILD_PROMPT = `${SUBTASK_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.`
export const SUBTASK_PARENT_PROMPT = `${SUBTASK_PARENT_MARKER}: Use the new_task tool exactly once. Create an ask-mode subtask with this exact message: "${SUBTASK_CHILD_PROMPT}" Do not answer directly.`
export const SUBTASK_CHILD_FOLLOWUP_ANSWER = "9"
const requestContains = (req: ChatCompletionRequest, expected: string[]) => {
const rawRequest = JSON.stringify(req)
return expected.every((text) => rawRequest.includes(text))
}
const completionAfterAnswer = (followupId: string, completionId: string) => ({
match: {
predicate: (req: ChatCompletionRequest) =>
// Preferred: structured tool-result message carries the followup answer.
toolResultContains(req, followupId, [SUBTASK_CHILD_FOLLOWUP_ANSWER]) ||
// Fallback 1: answer present alongside the tool-call ID but not in a role:tool message.
requestContains(req, [followupId, SUBTASK_CHILD_FOLLOWUP_ANSWER]) ||
// Fallback 2: answer arrives as a bare user message after task resume (no tool-call ID context).
requestContains(req, [
SUBTASK_CHILD_MARKER,
`<user_message>\\n${SUBTASK_CHILD_FOLLOWUP_ANSWER}\\n</user_message>`,
]),
},
response: {
toolCalls: [
{
name: "attempt_completion",
arguments: JSON.stringify({ result: "9" }),
id: completionId,
},
],
},
})
export function addSubtaskFixtures(mock: InstanceType<typeof LLMock>) {
mock.addFixture({
match: {
userMessage: new RegExp(SUBTASK_PARENT_MARKER),
},
response: {
toolCalls: [
{
name: "new_task",
arguments: JSON.stringify({
mode: "ask",
message: SUBTASK_CHILD_PROMPT,
}),
id: "call_subtasks_parent_new_task_001",
},
],
},
})
mock.addFixture({
match: {
userMessage: new RegExp(SUBTASK_CHILD_MARKER),
},
response: {
toolCalls: [
{
name: "ask_followup_question",
arguments: JSON.stringify({
question: "What is the square root of 81?",
follow_up: [{ text: SUBTASK_CHILD_FOLLOWUP_ANSWER }],
}),
id: "call_subtasks_child_followup_001",
},
],
},
})
mock.addFixture(completionAfterAnswer("call_subtasks_child_followup_001", "call_subtasks_child_completion_002"))
mock.addFixture({
match: {
toolCallId: "call_subtasks_parent_new_task_001",
},
response: {
toolCalls: [
{
name: "attempt_completion",
arguments: JSON.stringify({ result: "Parent task resumed" }),
id: "call_subtasks_parent_completion_003",
},
],
},
})
}