Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 0 additions & 7 deletions PRIVACY.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,13 +40,6 @@ go—and, importantly, where they don't.
We retain telemetry only as long as needed for product analytics and debugging.
Telemetry does **not** collect your code or AI prompts, and you can opt out at
any time through the settings.
- **Zoo Code Observability (Authenticated Subscribers Only):** If you sign in to
Zoo Code and have an active subscription, Zoo Code will send LLM usage
telemetry to the Zoo Code backend (zoocode.dev). This includes task ID, AI
provider name, model name, token counts (input/output/cache), and estimated
cost. This data is linked to your authenticated Zoo Code account. You can stop
this collection at any time by signing out via the Zoo Code badge in the chat
area.
- **Marketplace Requests**: When you browse or search the Marketplace for Model
Configuration Profiles (MCPs) or Custom Modes, Zoo Code makes a secure API
call to Zoo Code's backend servers to retrieve listing information. These
Expand Down
32 changes: 32 additions & 0 deletions apps/vscode-e2e/fixtures/terminal-profile.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
{
"fixtures": [
{
"match": {
"userMessage": "TERMINAL_PROFILE_E2E_OVERRIDE"
},
"response": {
"toolCalls": [
{
"name": "execute_command",
"arguments": "{\"command\":\"printf 'zoo-profile-override-ok\\\\n' > terminal-profile-e2e/terminal-profile-override.txt\"}",
"id": "call_terminal_profile_override_001"
}
]
}
},
{
"match": {
"userMessage": "TERMINAL_PROFILE_E2E_DEFAULT"
},
"response": {
"toolCalls": [
{
"name": "execute_command",
"arguments": "{\"command\":\"printf 'zoo-profile-default-ok\\\\n' > terminal-profile-e2e/terminal-profile-default.txt\"}",
"id": "call_terminal_profile_default_001"
}
]
}
}
]
}
95 changes: 95 additions & 0 deletions apps/vscode-e2e/src/fixtures/subtasks.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,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",
},
],
},
})
}
58 changes: 58 additions & 0 deletions apps/vscode-e2e/src/fixtures/terminal-profile.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { LLMock } from "@copilotkit/aimock"

import { toolResultContains } from "./tool-result"

type TerminalProfileToolCall = {
name: "execute_command" | "attempt_completion"
params: Record<string, unknown>
id: string
}

type TerminalProfileFixture = {
toolCallId: string
expected: string[]
toolCalls: TerminalProfileToolCall[]
}

export function addTerminalProfileResultFixtures(mock: InstanceType<typeof LLMock>) {
const fixtures: TerminalProfileFixture[] = [
{
toolCallId: "call_terminal_profile_override_001",
expected: ["Exit code: 0"],
toolCalls: [
{
name: "attempt_completion",
params: { result: "Ran the command using the Zoo E2E Bash profile override." },
id: "call_terminal_profile_override_002",
},
],
},
{
toolCallId: "call_terminal_profile_default_001",
expected: ["Exit code: 0"],
toolCalls: [
{
name: "attempt_completion",
params: { result: "Ran the command using the default terminal profile." },
id: "call_terminal_profile_default_002",
},
],
},
]

for (const fixture of fixtures) {
mock.addFixture({
match: {
toolCallId: fixture.toolCallId,
predicate: (req) => toolResultContains(req, fixture.toolCallId, fixture.expected),
},
response: {
toolCalls: fixture.toolCalls.map((toolCall) => ({
name: toolCall.name,
arguments: JSON.stringify(toolCall.params),
id: toolCall.id,
})),
},
})
}
}
4 changes: 4 additions & 0 deletions apps/vscode-e2e/src/runTest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,11 @@ import { LLMock } from "@copilotkit/aimock"

import { addApplyDiffResultFixtures } from "./fixtures/apply-diff"
import { addExecuteCommandResultFixtures } from "./fixtures/execute-command"
import { addTerminalProfileResultFixtures } from "./fixtures/terminal-profile"
import { addListFilesResultFixtures } from "./fixtures/list-files"
import { addReadFileResultFixtures } from "./fixtures/read-file"
import { addSearchFilesResultFixtures } from "./fixtures/search-files"
import { addSubtaskFixtures } from "./fixtures/subtasks"
import { addUseMcpToolResultFixtures } from "./fixtures/use-mcp-tool"
import { addWriteToFileResultFixtures } from "./fixtures/write-to-file"

Expand Down Expand Up @@ -96,9 +98,11 @@ async function main() {
if (!isRecord) {
addApplyDiffResultFixtures(mock)
addExecuteCommandResultFixtures(mock)
addTerminalProfileResultFixtures(mock)
addListFilesResultFixtures(mock)
addReadFileResultFixtures(mock)
addSearchFilesResultFixtures(mock)
addSubtaskFixtures(mock)
addUseMcpToolResultFixtures(mock)
addWriteToFileResultFixtures(mock)

Expand Down
Loading
Loading