@clinebot/core 0.0.27 → 0.0.29
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -0
- package/dist/ClineCore.d.ts +28 -2
- package/dist/ClineCore.d.ts.map +1 -1
- package/dist/account/cline-account-service.d.ts +1 -1
- package/dist/account/cline-account-service.d.ts.map +1 -1
- package/dist/account/index.d.ts +1 -1
- package/dist/account/index.d.ts.map +1 -1
- package/dist/account/types.d.ts +5 -0
- package/dist/account/types.d.ts.map +1 -1
- package/dist/auth/bounded-ttl-cache.d.ts +14 -0
- package/dist/auth/bounded-ttl-cache.d.ts.map +1 -0
- package/dist/auth/cline.d.ts +27 -2
- package/dist/auth/cline.d.ts.map +1 -1
- package/dist/auth/oca.d.ts.map +1 -1
- package/dist/chat/chat-schema.d.ts +8 -8
- package/dist/extensions/config/agent-config-loader.d.ts.map +1 -0
- package/dist/{agents → extensions/config}/agent-config-parser.d.ts +2 -2
- package/dist/extensions/config/agent-config-parser.d.ts.map +1 -0
- package/dist/{agents → extensions/config}/hooks-config-loader.d.ts +1 -1
- package/dist/extensions/config/hooks-config-loader.d.ts.map +1 -0
- package/dist/{agents → extensions/config}/index.d.ts +2 -4
- package/dist/extensions/config/index.d.ts.map +1 -0
- package/dist/{runtime/commands.d.ts → extensions/config/runtime-commands.d.ts} +2 -3
- package/dist/extensions/config/runtime-commands.d.ts.map +1 -0
- package/dist/extensions/config/unified-config-file-watcher.d.ts.map +1 -0
- package/dist/extensions/config/user-instruction-config-loader.d.ts.map +1 -0
- package/dist/extensions/context/agentic-compaction.d.ts +13 -0
- package/dist/extensions/context/agentic-compaction.d.ts.map +1 -0
- package/dist/extensions/context/basic-compaction.d.ts +9 -0
- package/dist/extensions/context/basic-compaction.d.ts.map +1 -0
- package/dist/extensions/context/compaction-shared.d.ts +60 -0
- package/dist/extensions/context/compaction-shared.d.ts.map +1 -0
- package/dist/extensions/context/compaction.d.ts +20 -0
- package/dist/extensions/context/compaction.d.ts.map +1 -0
- package/dist/extensions/index.d.ts +5 -0
- package/dist/extensions/index.d.ts.map +1 -0
- package/dist/extensions/mcp/client.d.ts +3 -0
- package/dist/extensions/mcp/client.d.ts.map +1 -0
- package/dist/extensions/mcp/config-loader.d.ts.map +1 -0
- package/dist/extensions/mcp/index.d.ts +9 -0
- package/dist/extensions/mcp/index.d.ts.map +1 -0
- package/dist/{mcp → extensions/mcp}/manager.d.ts +1 -2
- package/dist/extensions/mcp/manager.d.ts.map +1 -0
- package/dist/extensions/mcp/name-transform.d.ts +3 -0
- package/dist/extensions/mcp/name-transform.d.ts.map +1 -0
- package/dist/extensions/mcp/policies.d.ts +15 -0
- package/dist/extensions/mcp/policies.d.ts.map +1 -0
- package/dist/extensions/mcp/tools.d.ts +4 -0
- package/dist/extensions/mcp/tools.d.ts.map +1 -0
- package/dist/{mcp → extensions/mcp}/types.d.ts +29 -1
- package/dist/extensions/mcp/types.d.ts.map +1 -0
- package/dist/{agents → extensions/plugin}/plugin-config-loader.d.ts +1 -1
- package/dist/extensions/plugin/plugin-config-loader.d.ts.map +1 -0
- package/dist/{agents → extensions/plugin}/plugin-loader.d.ts +1 -1
- package/dist/extensions/plugin/plugin-loader.d.ts.map +1 -0
- package/dist/extensions/plugin/plugin-module-import.d.ts +5 -0
- package/dist/extensions/plugin/plugin-module-import.d.ts.map +1 -0
- package/dist/{agents → extensions/plugin}/plugin-sandbox.d.ts +1 -1
- package/dist/extensions/plugin/plugin-sandbox.d.ts.map +1 -0
- package/dist/extensions/plugin-sandbox-bootstrap.js +485 -0
- package/dist/hooks/index.d.ts +4 -0
- package/dist/hooks/index.d.ts.map +1 -0
- package/dist/hooks/persistent.d.ts +64 -0
- package/dist/hooks/persistent.d.ts.map +1 -0
- package/dist/hooks/subprocess-runner.d.ts +22 -0
- package/dist/hooks/subprocess-runner.d.ts.map +1 -0
- package/dist/hooks/subprocess.d.ts +189 -0
- package/dist/hooks/subprocess.d.ts.map +1 -0
- package/dist/index.d.ts +22 -25
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +560 -447
- package/dist/prompt/default-system.d.ts +2 -0
- package/dist/prompt/default-system.d.ts.map +1 -0
- package/dist/providers/local-provider-service.d.ts +1 -1
- package/dist/providers/local-provider-service.d.ts.map +1 -1
- package/dist/runtime/checkpoint-hooks.d.ts +21 -0
- package/dist/runtime/checkpoint-hooks.d.ts.map +1 -0
- package/dist/runtime/hook-file-hooks.d.ts +1 -1
- package/dist/runtime/hook-file-hooks.d.ts.map +1 -1
- package/dist/runtime/rules.d.ts +1 -1
- package/dist/runtime/rules.d.ts.map +1 -1
- package/dist/runtime/runtime-builder.d.ts +1 -1
- package/dist/runtime/runtime-builder.d.ts.map +1 -1
- package/dist/runtime/session-runtime.d.ts +25 -5
- package/dist/runtime/session-runtime.d.ts.map +1 -1
- package/dist/runtime/subprocess-sandbox.d.ts.map +1 -0
- package/dist/runtime/team-runtime-registry.d.ts +1 -1
- package/dist/runtime/team-runtime-registry.d.ts.map +1 -1
- package/dist/runtime/tool-approval.d.ts +1 -1
- package/dist/session/default-session-manager.d.ts +4 -3
- package/dist/session/default-session-manager.d.ts.map +1 -1
- package/dist/session/file-session-service.d.ts +1 -1
- package/dist/session/file-session-service.d.ts.map +1 -1
- package/dist/session/{unified-session-persistence-service.d.ts → persistence-service.d.ts} +11 -42
- package/dist/session/persistence-service.d.ts.map +1 -0
- package/dist/session/rpc-session-service.d.ts +1 -1
- package/dist/session/rpc-session-service.d.ts.map +1 -1
- package/dist/session/session-agent-events.d.ts +1 -1
- package/dist/session/session-artifacts.d.ts.map +1 -1
- package/dist/session/session-config-builder.d.ts.map +1 -1
- package/dist/session/session-graph.d.ts +1 -1
- package/dist/session/session-graph.d.ts.map +1 -1
- package/dist/session/session-host.d.ts.map +1 -1
- package/dist/session/session-manager.d.ts +6 -5
- package/dist/session/session-manager.d.ts.map +1 -1
- package/dist/session/session-manifest.d.ts +1 -1
- package/dist/session/session-service.d.ts +3 -2
- package/dist/session/session-service.d.ts.map +1 -1
- package/dist/session/session-team-coordination.d.ts +2 -1
- package/dist/session/session-team-coordination.d.ts.map +1 -1
- package/dist/session/utils/helpers.d.ts +51 -3
- package/dist/session/utils/helpers.d.ts.map +1 -1
- package/dist/session/utils/types.d.ts +41 -7
- package/dist/session/utils/types.d.ts.map +1 -1
- package/dist/session/workspace-manager.d.ts +1 -2
- package/dist/session/workspace-manager.d.ts.map +1 -1
- package/dist/session/workspace-manifest.d.ts +1 -22
- package/dist/session/workspace-manifest.d.ts.map +1 -1
- package/dist/storage/file-team-store.d.ts +2 -1
- package/dist/storage/file-team-store.d.ts.map +1 -1
- package/dist/storage/sqlite-team-store.d.ts +4 -1
- package/dist/storage/sqlite-team-store.d.ts.map +1 -1
- package/dist/storage/team-store.d.ts.map +1 -1
- package/dist/team/delegated-agent.d.ts +44 -0
- package/dist/team/delegated-agent.d.ts.map +1 -0
- package/dist/team/index.d.ts +1 -0
- package/dist/team/index.d.ts.map +1 -1
- package/dist/team/multi-agent.d.ts +229 -0
- package/dist/team/multi-agent.d.ts.map +1 -0
- package/dist/team/projections.d.ts +2 -2
- package/dist/team/projections.d.ts.map +1 -1
- package/dist/team/runtime.d.ts +5 -0
- package/dist/team/runtime.d.ts.map +1 -0
- package/dist/team/spawn-agent-tool.d.ts +85 -0
- package/dist/team/spawn-agent-tool.d.ts.map +1 -0
- package/dist/team/subagent-prompts.d.ts +4 -0
- package/dist/team/subagent-prompts.d.ts.map +1 -0
- package/dist/team/team-tools.d.ts +35 -0
- package/dist/team/team-tools.d.ts.map +1 -0
- package/dist/telemetry/OpenTelemetryProvider.d.ts +11 -1
- package/dist/telemetry/OpenTelemetryProvider.d.ts.map +1 -1
- package/dist/telemetry/{LoggerTelemetryAdapter.d.ts → TelemetryLoggerSink.d.ts} +10 -4
- package/dist/telemetry/TelemetryLoggerSink.d.ts.map +1 -0
- package/dist/telemetry/TelemetryService.d.ts.map +1 -1
- package/dist/telemetry/index.js +15 -28
- package/dist/tools/definitions.d.ts +4 -3
- package/dist/tools/definitions.d.ts.map +1 -1
- package/dist/tools/index.d.ts +5 -5
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/model-tool-routing.d.ts.map +1 -1
- package/dist/tools/presets.d.ts +26 -0
- package/dist/tools/presets.d.ts.map +1 -1
- package/dist/tools/schemas.d.ts +8 -0
- package/dist/tools/schemas.d.ts.map +1 -1
- package/dist/tools/types.d.ts +23 -2
- package/dist/tools/types.d.ts.map +1 -1
- package/dist/types/config.d.ts +47 -3
- package/dist/types/config.d.ts.map +1 -1
- package/dist/types/events.d.ts +1 -1
- package/dist/types/provider-settings.d.ts +1 -1
- package/dist/types/provider-settings.d.ts.map +1 -1
- package/dist/types/storage.d.ts +2 -1
- package/dist/types/storage.d.ts.map +1 -1
- package/dist/types.d.ts +7 -16
- package/dist/types.d.ts.map +1 -1
- package/package.json +16 -13
- package/src/ClineCore.test.ts +150 -0
- package/src/ClineCore.ts +114 -8
- package/src/account/cline-account-service.test.ts +84 -0
- package/src/account/cline-account-service.ts +2 -2
- package/src/account/index.ts +1 -0
- package/src/account/types.ts +6 -0
- package/src/auth/bounded-ttl-cache.test.ts +38 -0
- package/src/auth/bounded-ttl-cache.ts +53 -0
- package/src/auth/cline.test.ts +173 -36
- package/src/auth/cline.ts +395 -93
- package/src/auth/oca.test.ts +125 -0
- package/src/auth/oca.ts +17 -4
- package/src/{agents → extensions/config}/agent-config-loader.test.ts +1 -1
- package/src/{agents → extensions/config}/agent-config-parser.ts +2 -2
- package/src/{agents → extensions/config}/hooks-config-loader.ts +1 -1
- package/src/{agents → extensions/config}/index.ts +7 -11
- package/src/{runtime/commands.test.ts → extensions/config/runtime-commands.test.ts} +20 -3
- package/src/{runtime/commands.ts → extensions/config/runtime-commands.ts} +1 -8
- package/src/{agents → extensions/config}/unified-config-file-watcher.ts +15 -2
- package/src/{agents → extensions/config}/user-instruction-config-loader.test.ts +90 -2
- package/src/{agents → extensions/config}/user-instruction-config-loader.ts +126 -12
- package/src/extensions/context/agentic-compaction.ts +119 -0
- package/src/extensions/context/basic-compaction.ts +275 -0
- package/src/extensions/context/compaction-shared.ts +458 -0
- package/src/extensions/context/compaction.test.ts +477 -0
- package/src/extensions/context/compaction.ts +203 -0
- package/src/extensions/index.ts +12 -0
- package/src/extensions/mcp/client.ts +420 -0
- package/src/{mcp → extensions/mcp}/index.ts +16 -0
- package/src/{mcp → extensions/mcp}/manager.test.ts +1 -2
- package/src/{mcp → extensions/mcp}/manager.ts +3 -5
- package/src/extensions/mcp/name-transform.ts +33 -0
- package/src/extensions/mcp/policies.ts +47 -0
- package/src/extensions/mcp/tools.ts +47 -0
- package/src/{mcp → extensions/mcp}/types.ts +35 -7
- package/src/{agents → extensions/plugin}/plugin-config-loader.test.ts +18 -13
- package/src/{agents → extensions/plugin}/plugin-config-loader.ts +1 -1
- package/src/{agents → extensions/plugin}/plugin-loader.test.ts +41 -4
- package/src/extensions/plugin/plugin-loader.ts +106 -0
- package/src/extensions/plugin/plugin-module-import.ts +278 -0
- package/src/{agents → extensions/plugin}/plugin-sandbox-bootstrap.ts +30 -92
- package/src/{agents → extensions/plugin}/plugin-sandbox.test.ts +60 -3
- package/src/{agents → extensions/plugin}/plugin-sandbox.ts +146 -56
- package/src/hooks/index.ts +25 -0
- package/src/hooks/persistent.ts +661 -0
- package/src/hooks/subprocess-runner.ts +196 -0
- package/src/hooks/subprocess.ts +669 -0
- package/src/index.ts +200 -118
- package/src/prompt/default-system.ts +21 -0
- package/src/providers/local-provider-registry.ts +1 -1
- package/src/providers/local-provider-service.test.ts +23 -2
- package/src/providers/local-provider-service.ts +2 -2
- package/src/runtime/checkpoint-hooks.test.ts +167 -0
- package/src/runtime/checkpoint-hooks.ts +186 -0
- package/src/runtime/hook-file-hooks.test.ts +40 -1
- package/src/runtime/hook-file-hooks.ts +35 -16
- package/src/runtime/index.ts +4 -19
- package/src/runtime/rules.ts +4 -1
- package/src/runtime/runtime-builder.team-persistence.test.ts +3 -6
- package/src/runtime/runtime-builder.test.ts +266 -160
- package/src/runtime/runtime-builder.ts +120 -47
- package/src/runtime/runtime-parity.test.ts +22 -22
- package/src/runtime/session-runtime.ts +36 -6
- package/src/runtime/{sandbox/subprocess-sandbox.ts → subprocess-sandbox.ts} +24 -3
- package/src/runtime/team-runtime-registry.ts +1 -4
- package/src/runtime/tool-approval.ts +1 -1
- package/src/session/default-session-manager.e2e.test.ts +2 -2
- package/src/session/default-session-manager.test.ts +553 -9
- package/src/session/default-session-manager.ts +140 -46
- package/src/session/file-session-service.ts +3 -3
- package/src/session/index.ts +6 -6
- package/src/session/persistence-service.test.ts +212 -0
- package/src/session/{unified-session-persistence-service.ts → persistence-service.ts} +106 -172
- package/src/session/rpc-session-service.ts +3 -3
- package/src/session/runtime-oauth-token-manager.ts +1 -1
- package/src/session/session-agent-events.ts +1 -1
- package/src/session/session-artifacts.ts +32 -4
- package/src/session/session-config-builder.ts +22 -9
- package/src/session/session-graph.ts +1 -1
- package/src/session/session-host.ts +19 -11
- package/src/session/session-manager.ts +11 -6
- package/src/session/session-service.team-persistence.test.ts +1 -1
- package/src/session/session-service.ts +6 -9
- package/src/session/session-team-coordination.ts +7 -3
- package/src/session/session-telemetry.ts +1 -1
- package/src/session/utils/helpers.test.ts +160 -0
- package/src/session/utils/helpers.ts +289 -42
- package/src/session/utils/types.ts +47 -7
- package/src/session/workspace-manager.ts +5 -3
- package/src/session/workspace-manifest.ts +3 -49
- package/src/storage/file-team-store.ts +2 -5
- package/src/storage/provider-settings-legacy-migration.ts +2 -2
- package/src/storage/provider-settings-manager.test.ts +1 -1
- package/src/storage/sqlite-team-store.ts +212 -125
- package/src/storage/team-store.ts +1 -5
- package/src/team/delegated-agent.ts +131 -0
- package/src/team/index.ts +1 -0
- package/src/team/multi-agent.lifecycle.test.ts +201 -0
- package/src/team/multi-agent.ts +1666 -0
- package/src/team/projections.ts +2 -4
- package/src/team/runtime.ts +54 -0
- package/src/team/spawn-agent-tool.test.ts +387 -0
- package/src/team/spawn-agent-tool.ts +207 -0
- package/src/team/subagent-prompts.ts +41 -0
- package/src/team/team-tools.test.ts +802 -0
- package/src/team/team-tools.ts +792 -0
- package/src/telemetry/OpenTelemetryProvider.test.ts +25 -3
- package/src/telemetry/OpenTelemetryProvider.ts +108 -18
- package/src/telemetry/TelemetryLoggerSink.test.ts +42 -0
- package/src/telemetry/{LoggerTelemetryAdapter.ts → TelemetryLoggerSink.ts} +21 -14
- package/src/telemetry/TelemetryService.test.ts +7 -7
- package/src/telemetry/TelemetryService.ts +2 -4
- package/src/tools/definitions.test.ts +76 -0
- package/src/tools/definitions.ts +41 -2
- package/src/tools/executors/apply-patch.ts +1 -1
- package/src/tools/executors/editor.ts +1 -1
- package/src/tools/executors/file-read.ts +1 -1
- package/src/tools/executors/search.ts +1 -1
- package/src/tools/executors/web-fetch.ts +1 -1
- package/src/tools/index.ts +6 -1
- package/src/tools/model-tool-routing.ts +2 -0
- package/src/tools/presets.test.ts +8 -0
- package/src/tools/presets.ts +40 -2
- package/src/tools/schemas.ts +19 -0
- package/src/tools/types.ts +31 -2
- package/src/types/config.ts +61 -7
- package/src/types/events.ts +1 -1
- package/src/types/index.ts +0 -1
- package/src/types/provider-settings.ts +1 -1
- package/src/types/storage.ts +2 -5
- package/src/types.ts +32 -44
- package/dist/agents/agent-config-loader.d.ts.map +0 -1
- package/dist/agents/agent-config-parser.d.ts.map +0 -1
- package/dist/agents/hooks-config-loader.d.ts.map +0 -1
- package/dist/agents/index.d.ts.map +0 -1
- package/dist/agents/plugin-config-loader.d.ts.map +0 -1
- package/dist/agents/plugin-loader.d.ts.map +0 -1
- package/dist/agents/plugin-sandbox-bootstrap.js +0 -446
- package/dist/agents/plugin-sandbox.d.ts.map +0 -1
- package/dist/agents/unified-config-file-watcher.d.ts.map +0 -1
- package/dist/agents/user-instruction-config-loader.d.ts.map +0 -1
- package/dist/mcp/config-loader.d.ts.map +0 -1
- package/dist/mcp/index.d.ts +0 -5
- package/dist/mcp/index.d.ts.map +0 -1
- package/dist/mcp/manager.d.ts.map +0 -1
- package/dist/mcp/types.d.ts.map +0 -1
- package/dist/runtime/commands.d.ts.map +0 -1
- package/dist/runtime/sandbox/subprocess-sandbox.d.ts.map +0 -1
- package/dist/runtime/skills.d.ts +0 -14
- package/dist/runtime/skills.d.ts.map +0 -1
- package/dist/runtime/workflows.d.ts +0 -14
- package/dist/runtime/workflows.d.ts.map +0 -1
- package/dist/session/unified-session-persistence-service.d.ts.map +0 -1
- package/dist/telemetry/LoggerTelemetryAdapter.d.ts.map +0 -1
- package/dist/types/workspace.d.ts +0 -8
- package/dist/types/workspace.d.ts.map +0 -1
- package/src/agents/plugin-loader.ts +0 -175
- package/src/runtime/skills.ts +0 -44
- package/src/runtime/workflows.test.ts +0 -119
- package/src/runtime/workflows.ts +0 -45
- package/src/session/unified-session-persistence-service.test.ts +0 -85
- package/src/telemetry/LoggerTelemetryAdapter.test.ts +0 -42
- package/src/types/workspace.ts +0 -7
- /package/dist/{agents → extensions/config}/agent-config-loader.d.ts +0 -0
- /package/dist/{agents → extensions/config}/unified-config-file-watcher.d.ts +0 -0
- /package/dist/{agents → extensions/config}/user-instruction-config-loader.d.ts +0 -0
- /package/dist/{mcp → extensions/mcp}/config-loader.d.ts +0 -0
- /package/dist/runtime/{sandbox/subprocess-sandbox.d.ts → subprocess-sandbox.d.ts} +0 -0
- /package/src/{agents → extensions/config}/agent-config-loader.ts +0 -0
- /package/src/{agents → extensions/config}/hooks-config-loader.test.ts +0 -0
- /package/src/{agents → extensions/config}/unified-config-file-watcher.test.ts +0 -0
- /package/src/{mcp → extensions/mcp}/config-loader.test.ts +0 -0
- /package/src/{mcp → extensions/mcp}/config-loader.ts +0 -0
|
@@ -0,0 +1,802 @@
|
|
|
1
|
+
import { join } from "node:path";
|
|
2
|
+
import { resolveTeamDataDir } from "@clinebot/shared/storage";
|
|
3
|
+
import { afterEach, describe, expect, it, vi } from "vitest";
|
|
4
|
+
import { createDelegatedAgentConfigProvider } from "./delegated-agent";
|
|
5
|
+
import { AgentTeamsRuntime } from "./multi-agent";
|
|
6
|
+
import { createAgentTeamsTools } from "./team-tools";
|
|
7
|
+
|
|
8
|
+
type EnvSnapshot = {
|
|
9
|
+
CLINE_DATA_DIR: string | undefined;
|
|
10
|
+
CLINE_TEAM_DATA_DIR: string | undefined;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
function captureEnv(): EnvSnapshot {
|
|
14
|
+
return {
|
|
15
|
+
CLINE_DATA_DIR: process.env.CLINE_DATA_DIR,
|
|
16
|
+
CLINE_TEAM_DATA_DIR: process.env.CLINE_TEAM_DATA_DIR,
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function restoreEnv(snapshot: EnvSnapshot): void {
|
|
21
|
+
process.env.CLINE_DATA_DIR = snapshot.CLINE_DATA_DIR;
|
|
22
|
+
process.env.CLINE_TEAM_DATA_DIR = snapshot.CLINE_TEAM_DATA_DIR;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function makeTeammateConfigProvider(
|
|
26
|
+
overrides?: Partial<Parameters<typeof createDelegatedAgentConfigProvider>[0]>,
|
|
27
|
+
) {
|
|
28
|
+
return createDelegatedAgentConfigProvider({
|
|
29
|
+
providerId: "anthropic",
|
|
30
|
+
modelId: "claude-sonnet-4-5-20250929",
|
|
31
|
+
...overrides,
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
describe("resolveTeamDataDir", () => {
|
|
36
|
+
let snapshot: EnvSnapshot = captureEnv();
|
|
37
|
+
|
|
38
|
+
afterEach(() => {
|
|
39
|
+
restoreEnv(snapshot);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it("uses CLINE_TEAM_DATA_DIR when set", () => {
|
|
43
|
+
snapshot = captureEnv();
|
|
44
|
+
process.env.CLINE_TEAM_DATA_DIR = "/tmp/team-dir";
|
|
45
|
+
process.env.CLINE_DATA_DIR = "/tmp/cline-data";
|
|
46
|
+
expect(resolveTeamDataDir()).toBe("/tmp/team-dir");
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
it("falls back to CLINE_DATA_DIR/teams", () => {
|
|
50
|
+
snapshot = captureEnv();
|
|
51
|
+
delete process.env.CLINE_TEAM_DATA_DIR;
|
|
52
|
+
process.env.CLINE_DATA_DIR = "/tmp/cline-data";
|
|
53
|
+
expect(resolveTeamDataDir()).toBe(join("/tmp/cline-data", "teams"));
|
|
54
|
+
});
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
describe("createAgentTeamsTools schema surface", () => {
|
|
58
|
+
it("exposes a compact task action tool plus strict schemas elsewhere", () => {
|
|
59
|
+
const runtime = new AgentTeamsRuntime({ teamName: "test-team" });
|
|
60
|
+
const tools = createAgentTeamsTools({
|
|
61
|
+
runtime,
|
|
62
|
+
requesterId: "lead",
|
|
63
|
+
teammateConfigProvider: makeTeammateConfigProvider(),
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
const spawn = tools.find((tool) => tool.name === "team_spawn_teammate");
|
|
67
|
+
const teamTask = tools.find((tool) => tool.name === "team_task");
|
|
68
|
+
const send = tools.find((tool) => tool.name === "team_send_message");
|
|
69
|
+
const createOutcome = tools.find(
|
|
70
|
+
(tool) => tool.name === "team_create_outcome",
|
|
71
|
+
);
|
|
72
|
+
const teamAwaitRun = tools.find((tool) => tool.name === "team_await_run");
|
|
73
|
+
const teamLogUpdate = tools.find((tool) => tool.name === "team_log_update");
|
|
74
|
+
|
|
75
|
+
expect(spawn?.inputSchema.type).toBe("object");
|
|
76
|
+
const teamTaskSchema = teamTask?.inputSchema as
|
|
77
|
+
| {
|
|
78
|
+
type?: string;
|
|
79
|
+
properties?: Record<string, unknown>;
|
|
80
|
+
required?: unknown[];
|
|
81
|
+
}
|
|
82
|
+
| undefined;
|
|
83
|
+
expect(teamTaskSchema?.type).toBe("object");
|
|
84
|
+
expect(teamTaskSchema?.properties).toHaveProperty("action");
|
|
85
|
+
expect(teamTaskSchema?.required).toEqual(["action"]);
|
|
86
|
+
expect(send?.inputSchema.type).toBe("object");
|
|
87
|
+
expect(createOutcome?.inputSchema.type).toBe("object");
|
|
88
|
+
expect(teamAwaitRun?.inputSchema.type).toBe("object");
|
|
89
|
+
const schema = teamLogUpdate?.inputSchema as
|
|
90
|
+
| { properties: Record<string, unknown>; required: unknown[] }
|
|
91
|
+
| undefined;
|
|
92
|
+
expect(schema?.properties.kind).toEqual({
|
|
93
|
+
type: "string",
|
|
94
|
+
enum: ["progress", "handoff", "blocked", "decision", "done", "error"],
|
|
95
|
+
});
|
|
96
|
+
expect(schema?.required).toEqual(["kind", "summary"]);
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
it("rejects extra fields for strict spawn schema", async () => {
|
|
100
|
+
const runtime = new AgentTeamsRuntime({ teamName: "test-team" });
|
|
101
|
+
const tools = createAgentTeamsTools({
|
|
102
|
+
runtime,
|
|
103
|
+
requesterId: "lead",
|
|
104
|
+
teammateConfigProvider: makeTeammateConfigProvider(),
|
|
105
|
+
});
|
|
106
|
+
const spawn = tools.find((tool) => tool.name === "team_spawn_teammate");
|
|
107
|
+
expect(spawn).toBeDefined();
|
|
108
|
+
|
|
109
|
+
await expect(
|
|
110
|
+
spawn?.execute(
|
|
111
|
+
{
|
|
112
|
+
agentId: "python-poet",
|
|
113
|
+
rolePrompt: "Write concise Python-focused haiku",
|
|
114
|
+
action: "spawn",
|
|
115
|
+
},
|
|
116
|
+
{
|
|
117
|
+
agentId: "lead",
|
|
118
|
+
conversationId: "conv-1",
|
|
119
|
+
iteration: 1,
|
|
120
|
+
},
|
|
121
|
+
),
|
|
122
|
+
).rejects.toThrow("Unrecognized key");
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
it("can expose only the spawn tool until the first teammate is created", async () => {
|
|
126
|
+
const runtime = new AgentTeamsRuntime({ teamName: "test-team" });
|
|
127
|
+
const onLeadToolsUnlocked = vi.fn();
|
|
128
|
+
const tools = createAgentTeamsTools({
|
|
129
|
+
runtime,
|
|
130
|
+
requesterId: "lead",
|
|
131
|
+
teammateConfigProvider: makeTeammateConfigProvider(),
|
|
132
|
+
includeSpawnTool: true,
|
|
133
|
+
includeManagementTools: false,
|
|
134
|
+
onLeadToolsUnlocked,
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
expect(tools.map((tool) => tool.name)).toEqual(["team_spawn_teammate"]);
|
|
138
|
+
|
|
139
|
+
const spawn = tools[0];
|
|
140
|
+
await expect(
|
|
141
|
+
spawn?.execute(
|
|
142
|
+
{
|
|
143
|
+
agentId: "writer",
|
|
144
|
+
rolePrompt: "Write concise summaries",
|
|
145
|
+
},
|
|
146
|
+
{
|
|
147
|
+
agentId: "lead",
|
|
148
|
+
conversationId: "conv-1",
|
|
149
|
+
iteration: 1,
|
|
150
|
+
},
|
|
151
|
+
),
|
|
152
|
+
).resolves.toEqual({
|
|
153
|
+
agentId: "writer",
|
|
154
|
+
status: "spawned",
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
expect(onLeadToolsUnlocked).toHaveBeenCalledTimes(1);
|
|
158
|
+
const unlockedTools = onLeadToolsUnlocked.mock.calls[0]?.[0] as
|
|
159
|
+
| Array<{ name: string }>
|
|
160
|
+
| undefined;
|
|
161
|
+
expect(unlockedTools?.some((tool) => tool.name === "team_task")).toBe(true);
|
|
162
|
+
expect(
|
|
163
|
+
unlockedTools?.some((tool) => tool.name === "team_spawn_teammate"),
|
|
164
|
+
).toBe(false);
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
it("rejects non-object payloads for task tools", async () => {
|
|
168
|
+
const runtime = new AgentTeamsRuntime({ teamName: "test-team" });
|
|
169
|
+
const tools = createAgentTeamsTools({
|
|
170
|
+
runtime,
|
|
171
|
+
requesterId: "lead",
|
|
172
|
+
teammateConfigProvider: makeTeammateConfigProvider(),
|
|
173
|
+
});
|
|
174
|
+
const teamTask = tools.find((tool) => tool.name === "team_task");
|
|
175
|
+
expect(teamTask).toBeDefined();
|
|
176
|
+
|
|
177
|
+
await expect(
|
|
178
|
+
teamTask?.execute(["create", "task"], {
|
|
179
|
+
agentId: "lead",
|
|
180
|
+
conversationId: "conv-1",
|
|
181
|
+
iteration: 1,
|
|
182
|
+
}),
|
|
183
|
+
).rejects.toThrow("expected object");
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
it("normalizes null placeholders for required fields into missing-field errors", async () => {
|
|
187
|
+
const runtime = new AgentTeamsRuntime({ teamName: "test-team" });
|
|
188
|
+
const tools = createAgentTeamsTools({
|
|
189
|
+
runtime,
|
|
190
|
+
requesterId: "lead",
|
|
191
|
+
teammateConfigProvider: makeTeammateConfigProvider(),
|
|
192
|
+
});
|
|
193
|
+
const teamTask = tools.find((tool) => tool.name === "team_task");
|
|
194
|
+
expect(teamTask).toBeDefined();
|
|
195
|
+
|
|
196
|
+
await expect(
|
|
197
|
+
teamTask?.execute(
|
|
198
|
+
{
|
|
199
|
+
action: "complete",
|
|
200
|
+
taskId: "task_0001",
|
|
201
|
+
summary: null,
|
|
202
|
+
},
|
|
203
|
+
{
|
|
204
|
+
agentId: "lead",
|
|
205
|
+
conversationId: "conv-1",
|
|
206
|
+
iteration: 1,
|
|
207
|
+
},
|
|
208
|
+
),
|
|
209
|
+
).rejects.toThrow('Field "summary" is required when action=complete');
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
it("accepts null placeholders for optional fields", async () => {
|
|
213
|
+
const runtime = new AgentTeamsRuntime({ teamName: "test-team" });
|
|
214
|
+
const tools = createAgentTeamsTools({
|
|
215
|
+
runtime,
|
|
216
|
+
requesterId: "lead",
|
|
217
|
+
teammateConfigProvider: makeTeammateConfigProvider(),
|
|
218
|
+
});
|
|
219
|
+
const teamTask = tools.find((tool) => tool.name === "team_task");
|
|
220
|
+
expect(teamTask).toBeDefined();
|
|
221
|
+
if (!teamTask) {
|
|
222
|
+
throw new Error("Expected team_task tool to be defined");
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
await expect(
|
|
226
|
+
teamTask.execute(
|
|
227
|
+
{
|
|
228
|
+
action: "create",
|
|
229
|
+
title: "Investigate llms boundaries",
|
|
230
|
+
description: "Deep dive models and providers",
|
|
231
|
+
dependsOn: null,
|
|
232
|
+
},
|
|
233
|
+
{
|
|
234
|
+
agentId: "lead",
|
|
235
|
+
conversationId: "conv-1",
|
|
236
|
+
iteration: 1,
|
|
237
|
+
},
|
|
238
|
+
),
|
|
239
|
+
).resolves.toMatchObject({
|
|
240
|
+
action: "create",
|
|
241
|
+
status: "pending",
|
|
242
|
+
taskId: expect.stringMatching(/^task_/),
|
|
243
|
+
});
|
|
244
|
+
});
|
|
245
|
+
|
|
246
|
+
it("rejects fields that do not belong to the selected action", async () => {
|
|
247
|
+
const runtime = new AgentTeamsRuntime({ teamName: "test-team" });
|
|
248
|
+
const tools = createAgentTeamsTools({
|
|
249
|
+
runtime,
|
|
250
|
+
requesterId: "lead",
|
|
251
|
+
teammateConfigProvider: makeTeammateConfigProvider(),
|
|
252
|
+
});
|
|
253
|
+
const teamTask = tools.find((tool) => tool.name === "team_task");
|
|
254
|
+
expect(teamTask).toBeDefined();
|
|
255
|
+
|
|
256
|
+
await expect(
|
|
257
|
+
teamTask?.execute(
|
|
258
|
+
{
|
|
259
|
+
action: "claim",
|
|
260
|
+
taskId: "task_0001",
|
|
261
|
+
title: "should not be here",
|
|
262
|
+
},
|
|
263
|
+
{
|
|
264
|
+
agentId: "lead",
|
|
265
|
+
conversationId: "conv-1",
|
|
266
|
+
iteration: 1,
|
|
267
|
+
},
|
|
268
|
+
),
|
|
269
|
+
).rejects.toThrow('Field "title" is not allowed when action=claim');
|
|
270
|
+
});
|
|
271
|
+
|
|
272
|
+
it("defaults requiredSections for team_create_outcome", async () => {
|
|
273
|
+
const runtime = new AgentTeamsRuntime({ teamName: "test-team" });
|
|
274
|
+
const tools = createAgentTeamsTools({
|
|
275
|
+
runtime,
|
|
276
|
+
requesterId: "lead",
|
|
277
|
+
teammateConfigProvider: makeTeammateConfigProvider(),
|
|
278
|
+
});
|
|
279
|
+
const createOutcome = tools.find(
|
|
280
|
+
(tool) => tool.name === "team_create_outcome",
|
|
281
|
+
);
|
|
282
|
+
expect(createOutcome).toBeDefined();
|
|
283
|
+
|
|
284
|
+
await expect(
|
|
285
|
+
createOutcome?.execute(
|
|
286
|
+
{
|
|
287
|
+
title: "LLMS boundary redesign",
|
|
288
|
+
},
|
|
289
|
+
{
|
|
290
|
+
agentId: "lead",
|
|
291
|
+
conversationId: "conv-1",
|
|
292
|
+
iteration: 1,
|
|
293
|
+
},
|
|
294
|
+
),
|
|
295
|
+
).resolves.toMatchObject({
|
|
296
|
+
outcomeId: expect.stringMatching(/^out_/),
|
|
297
|
+
status: "draft",
|
|
298
|
+
});
|
|
299
|
+
|
|
300
|
+
const outcomes = runtime.listOutcomes();
|
|
301
|
+
expect(outcomes).toHaveLength(1);
|
|
302
|
+
expect(outcomes[0]?.requiredSections).toEqual([
|
|
303
|
+
"current_state",
|
|
304
|
+
"boundary_analysis",
|
|
305
|
+
"interface_proposal",
|
|
306
|
+
]);
|
|
307
|
+
});
|
|
308
|
+
|
|
309
|
+
it("can list outcomes via dedicated list tool", async () => {
|
|
310
|
+
const runtime = new AgentTeamsRuntime({ teamName: "test-team" });
|
|
311
|
+
const tools = createAgentTeamsTools({
|
|
312
|
+
runtime,
|
|
313
|
+
requesterId: "lead",
|
|
314
|
+
teammateConfigProvider: makeTeammateConfigProvider(),
|
|
315
|
+
});
|
|
316
|
+
const createOutcome = tools.find(
|
|
317
|
+
(tool) => tool.name === "team_create_outcome",
|
|
318
|
+
);
|
|
319
|
+
const listOutcomes = tools.find(
|
|
320
|
+
(tool) => tool.name === "team_list_outcomes",
|
|
321
|
+
);
|
|
322
|
+
expect(createOutcome).toBeDefined();
|
|
323
|
+
expect(listOutcomes).toBeDefined();
|
|
324
|
+
|
|
325
|
+
await createOutcome?.execute(
|
|
326
|
+
{ title: "LLMS redesign" },
|
|
327
|
+
{
|
|
328
|
+
agentId: "lead",
|
|
329
|
+
conversationId: "conv-1",
|
|
330
|
+
iteration: 1,
|
|
331
|
+
},
|
|
332
|
+
);
|
|
333
|
+
|
|
334
|
+
await expect(
|
|
335
|
+
listOutcomes?.execute(
|
|
336
|
+
{},
|
|
337
|
+
{
|
|
338
|
+
agentId: "lead",
|
|
339
|
+
conversationId: "conv-1",
|
|
340
|
+
iteration: 1,
|
|
341
|
+
},
|
|
342
|
+
),
|
|
343
|
+
).resolves.toEqual(
|
|
344
|
+
expect.arrayContaining([
|
|
345
|
+
expect.objectContaining({
|
|
346
|
+
title: expect.any(String),
|
|
347
|
+
}),
|
|
348
|
+
]),
|
|
349
|
+
);
|
|
350
|
+
});
|
|
351
|
+
|
|
352
|
+
it("accepts null sourceRunId for team_attach_outcome_fragment", async () => {
|
|
353
|
+
const runtime = new AgentTeamsRuntime({ teamName: "test-team" });
|
|
354
|
+
const tools = createAgentTeamsTools({
|
|
355
|
+
runtime,
|
|
356
|
+
requesterId: "lead",
|
|
357
|
+
teammateConfigProvider: makeTeammateConfigProvider(),
|
|
358
|
+
});
|
|
359
|
+
const createOutcome = tools.find(
|
|
360
|
+
(tool) => tool.name === "team_create_outcome",
|
|
361
|
+
);
|
|
362
|
+
const attachFragment = tools.find(
|
|
363
|
+
(tool) => tool.name === "team_attach_outcome_fragment",
|
|
364
|
+
);
|
|
365
|
+
expect(createOutcome).toBeDefined();
|
|
366
|
+
expect(attachFragment).toBeDefined();
|
|
367
|
+
if (!createOutcome || !attachFragment) {
|
|
368
|
+
throw new Error("Expected outcome tools to be defined");
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
const createdResult = await createOutcome.execute(
|
|
372
|
+
{ title: "Providers report" },
|
|
373
|
+
{
|
|
374
|
+
agentId: "lead",
|
|
375
|
+
conversationId: "conv-1",
|
|
376
|
+
iteration: 1,
|
|
377
|
+
},
|
|
378
|
+
);
|
|
379
|
+
expect(createdResult).toMatchObject({
|
|
380
|
+
outcomeId: expect.stringMatching(/^out_/),
|
|
381
|
+
status: "draft",
|
|
382
|
+
});
|
|
383
|
+
const isCreatedOutcome = (
|
|
384
|
+
value: unknown,
|
|
385
|
+
): value is { outcomeId: string; status: string } => {
|
|
386
|
+
if (typeof value !== "object" || value === null) {
|
|
387
|
+
return false;
|
|
388
|
+
}
|
|
389
|
+
const record = value as Record<string, unknown>;
|
|
390
|
+
return (
|
|
391
|
+
typeof record.outcomeId === "string" &&
|
|
392
|
+
typeof record.status === "string"
|
|
393
|
+
);
|
|
394
|
+
};
|
|
395
|
+
if (!isCreatedOutcome(createdResult)) {
|
|
396
|
+
throw new Error(
|
|
397
|
+
"Expected createOutcome result to include outcomeId and status",
|
|
398
|
+
);
|
|
399
|
+
}
|
|
400
|
+
const created = createdResult;
|
|
401
|
+
|
|
402
|
+
await expect(
|
|
403
|
+
attachFragment.execute(
|
|
404
|
+
{
|
|
405
|
+
outcomeId: created.outcomeId,
|
|
406
|
+
section: "current_state",
|
|
407
|
+
sourceRunId: null,
|
|
408
|
+
content: "Current findings.",
|
|
409
|
+
},
|
|
410
|
+
{
|
|
411
|
+
agentId: "lead",
|
|
412
|
+
conversationId: "conv-1",
|
|
413
|
+
iteration: 1,
|
|
414
|
+
},
|
|
415
|
+
),
|
|
416
|
+
).resolves.toMatchObject({
|
|
417
|
+
fragmentId: expect.stringMatching(/^frag_/),
|
|
418
|
+
status: "draft",
|
|
419
|
+
});
|
|
420
|
+
|
|
421
|
+
const [fragment] = runtime.listOutcomeFragments(created.outcomeId);
|
|
422
|
+
expect(fragment?.sourceRunId).toBeUndefined();
|
|
423
|
+
});
|
|
424
|
+
});
|
|
425
|
+
|
|
426
|
+
describe("createAgentTeamsTools runtime behavior", () => {
|
|
427
|
+
it("forwards teammateRuntime headers when spawning teammates", async () => {
|
|
428
|
+
const spawnTeammate = vi.fn();
|
|
429
|
+
const runtime = {
|
|
430
|
+
getMemberRole: vi.fn(() => "lead"),
|
|
431
|
+
isTeammateActive: vi.fn(() => false),
|
|
432
|
+
spawnTeammate,
|
|
433
|
+
} as unknown as AgentTeamsRuntime;
|
|
434
|
+
|
|
435
|
+
const tools = createAgentTeamsTools({
|
|
436
|
+
runtime,
|
|
437
|
+
requesterId: "lead",
|
|
438
|
+
teammateConfigProvider: makeTeammateConfigProvider({
|
|
439
|
+
providerId: "cline",
|
|
440
|
+
modelId: "anthropic/claude-sonnet-4.6",
|
|
441
|
+
headers: { Authorization: "Bearer token" },
|
|
442
|
+
}),
|
|
443
|
+
createBaseTools: () => [],
|
|
444
|
+
});
|
|
445
|
+
const spawnTool = tools.find((tool) => tool.name === "team_spawn_teammate");
|
|
446
|
+
expect(spawnTool).toBeDefined();
|
|
447
|
+
|
|
448
|
+
await spawnTool?.execute(
|
|
449
|
+
{
|
|
450
|
+
agentId: "investigator",
|
|
451
|
+
rolePrompt: "Investigate code boundaries",
|
|
452
|
+
},
|
|
453
|
+
{
|
|
454
|
+
agentId: "lead",
|
|
455
|
+
conversationId: "conv-1",
|
|
456
|
+
iteration: 1,
|
|
457
|
+
},
|
|
458
|
+
);
|
|
459
|
+
|
|
460
|
+
expect(spawnTeammate).toHaveBeenCalledWith(
|
|
461
|
+
expect.objectContaining({
|
|
462
|
+
config: expect.objectContaining({
|
|
463
|
+
headers: { Authorization: "Bearer token" },
|
|
464
|
+
}),
|
|
465
|
+
}),
|
|
466
|
+
);
|
|
467
|
+
});
|
|
468
|
+
|
|
469
|
+
it("injects workspace metadata into cline teammate system prompt", async () => {
|
|
470
|
+
const spawnTeammate = vi.fn();
|
|
471
|
+
const runtime = {
|
|
472
|
+
getMemberRole: vi.fn(() => "lead"),
|
|
473
|
+
isTeammateActive: vi.fn(() => false),
|
|
474
|
+
spawnTeammate,
|
|
475
|
+
} as unknown as AgentTeamsRuntime;
|
|
476
|
+
|
|
477
|
+
const tools = createAgentTeamsTools({
|
|
478
|
+
runtime,
|
|
479
|
+
requesterId: "lead",
|
|
480
|
+
teammateConfigProvider: makeTeammateConfigProvider({
|
|
481
|
+
providerId: "cline",
|
|
482
|
+
modelId: "anthropic/claude-sonnet-4.6",
|
|
483
|
+
cwd: "/repo/app",
|
|
484
|
+
}),
|
|
485
|
+
});
|
|
486
|
+
const spawnTool = tools.find((tool) => tool.name === "team_spawn_teammate");
|
|
487
|
+
expect(spawnTool).toBeDefined();
|
|
488
|
+
|
|
489
|
+
await spawnTool?.execute(
|
|
490
|
+
{
|
|
491
|
+
agentId: "researcher",
|
|
492
|
+
rolePrompt: "Investigate runtime boundary regressions.",
|
|
493
|
+
},
|
|
494
|
+
{
|
|
495
|
+
agentId: "lead",
|
|
496
|
+
conversationId: "conv-1",
|
|
497
|
+
iteration: 1,
|
|
498
|
+
},
|
|
499
|
+
);
|
|
500
|
+
|
|
501
|
+
expect(spawnTeammate).toHaveBeenCalledWith(
|
|
502
|
+
expect.objectContaining({
|
|
503
|
+
config: expect.objectContaining({
|
|
504
|
+
systemPrompt: expect.stringContaining("# Workspace Configuration"),
|
|
505
|
+
}),
|
|
506
|
+
}),
|
|
507
|
+
);
|
|
508
|
+
expect(spawnTeammate).toHaveBeenCalledWith(
|
|
509
|
+
expect.objectContaining({
|
|
510
|
+
config: expect.objectContaining({
|
|
511
|
+
systemPrompt: expect.stringContaining('"/repo/app"'),
|
|
512
|
+
}),
|
|
513
|
+
}),
|
|
514
|
+
);
|
|
515
|
+
expect(spawnTeammate).toHaveBeenCalledWith(
|
|
516
|
+
expect.objectContaining({
|
|
517
|
+
config: expect.objectContaining({
|
|
518
|
+
systemPrompt: expect.stringContaining('"hint": "app"'),
|
|
519
|
+
}),
|
|
520
|
+
}),
|
|
521
|
+
);
|
|
522
|
+
expect(spawnTeammate).toHaveBeenCalledWith(
|
|
523
|
+
expect.objectContaining({
|
|
524
|
+
config: expect.objectContaining({
|
|
525
|
+
systemPrompt: expect.stringContaining(
|
|
526
|
+
"# Team Teammate Role\nInvestigate runtime boundary regressions.",
|
|
527
|
+
),
|
|
528
|
+
}),
|
|
529
|
+
}),
|
|
530
|
+
);
|
|
531
|
+
});
|
|
532
|
+
|
|
533
|
+
it("throws from team_await_run when async delegated run fails", async () => {
|
|
534
|
+
const runtime = {
|
|
535
|
+
awaitRun: vi.fn(async () => ({
|
|
536
|
+
id: "run_0001",
|
|
537
|
+
status: "failed",
|
|
538
|
+
error: "Authentication failed",
|
|
539
|
+
})),
|
|
540
|
+
} as unknown as AgentTeamsRuntime;
|
|
541
|
+
|
|
542
|
+
const tools = createAgentTeamsTools({
|
|
543
|
+
runtime,
|
|
544
|
+
requesterId: "lead",
|
|
545
|
+
teammateConfigProvider: makeTeammateConfigProvider(),
|
|
546
|
+
});
|
|
547
|
+
const awaitRun = tools.find((tool) => tool.name === "team_await_run");
|
|
548
|
+
expect(awaitRun).toBeDefined();
|
|
549
|
+
|
|
550
|
+
await expect(
|
|
551
|
+
awaitRun?.execute(
|
|
552
|
+
{ runId: "run_0001" },
|
|
553
|
+
{
|
|
554
|
+
agentId: "lead",
|
|
555
|
+
conversationId: "conv-1",
|
|
556
|
+
iteration: 1,
|
|
557
|
+
},
|
|
558
|
+
),
|
|
559
|
+
).rejects.toThrow('Run "run_0001" failed: Authentication failed');
|
|
560
|
+
});
|
|
561
|
+
|
|
562
|
+
it("throws from team_await_all_runs when any delegated run is not successful", async () => {
|
|
563
|
+
const runtime = {
|
|
564
|
+
awaitAllRuns: vi.fn(async () => [
|
|
565
|
+
{ id: "run_ok", status: "completed" },
|
|
566
|
+
{ id: "run_bad", status: "failed", error: "Auth expired" },
|
|
567
|
+
]),
|
|
568
|
+
} as unknown as AgentTeamsRuntime;
|
|
569
|
+
|
|
570
|
+
const tools = createAgentTeamsTools({
|
|
571
|
+
runtime,
|
|
572
|
+
requesterId: "lead",
|
|
573
|
+
teammateConfigProvider: makeTeammateConfigProvider(),
|
|
574
|
+
});
|
|
575
|
+
const awaitAllRuns = tools.find(
|
|
576
|
+
(tool) => tool.name === "team_await_all_runs",
|
|
577
|
+
);
|
|
578
|
+
expect(awaitAllRuns).toBeDefined();
|
|
579
|
+
|
|
580
|
+
await expect(
|
|
581
|
+
awaitAllRuns?.execute(
|
|
582
|
+
{},
|
|
583
|
+
{
|
|
584
|
+
agentId: "lead",
|
|
585
|
+
conversationId: "conv-1",
|
|
586
|
+
iteration: 1,
|
|
587
|
+
},
|
|
588
|
+
),
|
|
589
|
+
).rejects.toThrow(
|
|
590
|
+
"One or more runs did not complete successfully: run_bad:failed(Auth expired)",
|
|
591
|
+
);
|
|
592
|
+
});
|
|
593
|
+
|
|
594
|
+
it("returns compact summaries from team_await_run without full teammate transcripts", async () => {
|
|
595
|
+
const runtime = {
|
|
596
|
+
awaitRun: vi.fn(async () => ({
|
|
597
|
+
id: "run_0001",
|
|
598
|
+
agentId: "models-investigator",
|
|
599
|
+
status: "completed",
|
|
600
|
+
message:
|
|
601
|
+
"Investigate the models directory and summarize the boundaries",
|
|
602
|
+
priority: 0,
|
|
603
|
+
retryCount: 0,
|
|
604
|
+
maxRetries: 0,
|
|
605
|
+
startedAt: new Date("2026-03-24T09:00:00.000Z"),
|
|
606
|
+
endedAt: new Date("2026-03-24T09:01:00.000Z"),
|
|
607
|
+
lastProgressAt: new Date("2026-03-24T09:00:59.000Z"),
|
|
608
|
+
lastProgressMessage: "completed",
|
|
609
|
+
currentActivity: "completed",
|
|
610
|
+
result: {
|
|
611
|
+
text: "Models are the public catalog and provider files are provider-specific defaults.",
|
|
612
|
+
usage: {
|
|
613
|
+
inputTokens: 1200,
|
|
614
|
+
outputTokens: 300,
|
|
615
|
+
cacheReadTokens: 900,
|
|
616
|
+
cacheWriteTokens: 120,
|
|
617
|
+
totalCost: 0.12,
|
|
618
|
+
},
|
|
619
|
+
messages: [{ role: "user", content: "huge transcript omitted" }],
|
|
620
|
+
toolCalls: [{ name: "read_file", input: {}, output: "omitted" }],
|
|
621
|
+
iterations: 3,
|
|
622
|
+
finishReason: "completed",
|
|
623
|
+
model: { id: "claude-sonnet-4-5-20250929", provider: "anthropic" },
|
|
624
|
+
startedAt: new Date("2026-03-24T09:00:00.000Z"),
|
|
625
|
+
endedAt: new Date("2026-03-24T09:01:00.000Z"),
|
|
626
|
+
durationMs: 60_000,
|
|
627
|
+
},
|
|
628
|
+
})),
|
|
629
|
+
} as unknown as AgentTeamsRuntime;
|
|
630
|
+
|
|
631
|
+
const tools = createAgentTeamsTools({
|
|
632
|
+
runtime,
|
|
633
|
+
requesterId: "lead",
|
|
634
|
+
teammateConfigProvider: makeTeammateConfigProvider(),
|
|
635
|
+
});
|
|
636
|
+
const awaitRun = tools.find((tool) => tool.name === "team_await_run");
|
|
637
|
+
|
|
638
|
+
await expect(
|
|
639
|
+
awaitRun?.execute(
|
|
640
|
+
{ runId: "run_0001" },
|
|
641
|
+
{
|
|
642
|
+
agentId: "lead",
|
|
643
|
+
conversationId: "conv-1",
|
|
644
|
+
iteration: 1,
|
|
645
|
+
},
|
|
646
|
+
),
|
|
647
|
+
).resolves.toEqual({
|
|
648
|
+
id: "run_0001",
|
|
649
|
+
agentId: "models-investigator",
|
|
650
|
+
status: "completed",
|
|
651
|
+
messagePreview:
|
|
652
|
+
"Investigate the models directory and summarize the boundaries",
|
|
653
|
+
priority: 0,
|
|
654
|
+
retryCount: 0,
|
|
655
|
+
maxRetries: 0,
|
|
656
|
+
startedAt: new Date("2026-03-24T09:00:00.000Z"),
|
|
657
|
+
endedAt: new Date("2026-03-24T09:01:00.000Z"),
|
|
658
|
+
lastProgressAt: new Date("2026-03-24T09:00:59.000Z"),
|
|
659
|
+
lastProgressMessage: "completed",
|
|
660
|
+
currentActivity: "completed",
|
|
661
|
+
resultSummary: {
|
|
662
|
+
textPreview:
|
|
663
|
+
"Models are the public catalog and provider files are provider-specific defaults.",
|
|
664
|
+
iterations: 3,
|
|
665
|
+
finishReason: "completed",
|
|
666
|
+
durationMs: 60_000,
|
|
667
|
+
usage: {
|
|
668
|
+
inputTokens: 1200,
|
|
669
|
+
outputTokens: 300,
|
|
670
|
+
cacheReadTokens: 900,
|
|
671
|
+
cacheWriteTokens: 120,
|
|
672
|
+
totalCost: 0.12,
|
|
673
|
+
},
|
|
674
|
+
},
|
|
675
|
+
});
|
|
676
|
+
});
|
|
677
|
+
|
|
678
|
+
it("returns compact summaries from team_list_runs", async () => {
|
|
679
|
+
const runtime = {
|
|
680
|
+
listRuns: vi.fn(() => [
|
|
681
|
+
{
|
|
682
|
+
id: "run_0001",
|
|
683
|
+
agentId: "providers-investigator",
|
|
684
|
+
status: "running",
|
|
685
|
+
message: "Investigate providers directory in detail",
|
|
686
|
+
priority: 0,
|
|
687
|
+
retryCount: 0,
|
|
688
|
+
maxRetries: 0,
|
|
689
|
+
startedAt: new Date("2026-03-24T09:00:00.000Z"),
|
|
690
|
+
lastProgressAt: new Date("2026-03-24T09:00:30.000Z"),
|
|
691
|
+
lastProgressMessage: "reading files",
|
|
692
|
+
currentActivity: "reading_files",
|
|
693
|
+
},
|
|
694
|
+
]),
|
|
695
|
+
} as unknown as AgentTeamsRuntime;
|
|
696
|
+
|
|
697
|
+
const tools = createAgentTeamsTools({
|
|
698
|
+
runtime,
|
|
699
|
+
requesterId: "lead",
|
|
700
|
+
teammateConfigProvider: makeTeammateConfigProvider(),
|
|
701
|
+
});
|
|
702
|
+
const listRuns = tools.find((tool) => tool.name === "team_list_runs");
|
|
703
|
+
|
|
704
|
+
await expect(
|
|
705
|
+
listRuns?.execute(
|
|
706
|
+
{},
|
|
707
|
+
{
|
|
708
|
+
agentId: "lead",
|
|
709
|
+
conversationId: "conv-1",
|
|
710
|
+
iteration: 1,
|
|
711
|
+
},
|
|
712
|
+
),
|
|
713
|
+
).resolves.toEqual([
|
|
714
|
+
{
|
|
715
|
+
id: "run_0001",
|
|
716
|
+
agentId: "providers-investigator",
|
|
717
|
+
status: "running",
|
|
718
|
+
messagePreview: "Investigate providers directory in detail",
|
|
719
|
+
priority: 0,
|
|
720
|
+
retryCount: 0,
|
|
721
|
+
maxRetries: 0,
|
|
722
|
+
startedAt: new Date("2026-03-24T09:00:00.000Z"),
|
|
723
|
+
lastProgressAt: new Date("2026-03-24T09:00:30.000Z"),
|
|
724
|
+
lastProgressMessage: "reading files",
|
|
725
|
+
currentActivity: "reading_files",
|
|
726
|
+
resultSummary: undefined,
|
|
727
|
+
},
|
|
728
|
+
]);
|
|
729
|
+
});
|
|
730
|
+
|
|
731
|
+
it("sets long timeout for team await tools", () => {
|
|
732
|
+
const runtime = new AgentTeamsRuntime({ teamName: "test-team" });
|
|
733
|
+
const tools = createAgentTeamsTools({
|
|
734
|
+
runtime,
|
|
735
|
+
requesterId: "lead",
|
|
736
|
+
teammateConfigProvider: makeTeammateConfigProvider(),
|
|
737
|
+
});
|
|
738
|
+
const awaitRun = tools.find((tool) => tool.name === "team_await_run");
|
|
739
|
+
const awaitAllRuns = tools.find(
|
|
740
|
+
(tool) => tool.name === "team_await_all_runs",
|
|
741
|
+
);
|
|
742
|
+
expect(awaitRun?.timeoutMs).toBe(60 * 60 * 1000);
|
|
743
|
+
expect(awaitAllRuns?.timeoutMs).toBe(60 * 60 * 1000);
|
|
744
|
+
});
|
|
745
|
+
|
|
746
|
+
it("lists ready-to-claim tasks through team_task list action", async () => {
|
|
747
|
+
const runtime = new AgentTeamsRuntime({ teamName: "test-team" });
|
|
748
|
+
const tools = createAgentTeamsTools({
|
|
749
|
+
runtime,
|
|
750
|
+
requesterId: "lead",
|
|
751
|
+
teammateConfigProvider: makeTeammateConfigProvider(),
|
|
752
|
+
});
|
|
753
|
+
const teamTask = tools.find((tool) => tool.name === "team_task");
|
|
754
|
+
expect(teamTask).toBeDefined();
|
|
755
|
+
|
|
756
|
+
const first = (await teamTask?.execute(
|
|
757
|
+
{
|
|
758
|
+
action: "create",
|
|
759
|
+
title: "Ready task",
|
|
760
|
+
description: "Claim immediately",
|
|
761
|
+
},
|
|
762
|
+
{
|
|
763
|
+
agentId: "lead",
|
|
764
|
+
conversationId: "conv-1",
|
|
765
|
+
iteration: 1,
|
|
766
|
+
},
|
|
767
|
+
)) as { taskId: string };
|
|
768
|
+
await teamTask?.execute(
|
|
769
|
+
{
|
|
770
|
+
action: "create",
|
|
771
|
+
title: "Blocked task",
|
|
772
|
+
description: "Wait on dependency",
|
|
773
|
+
dependsOn: [first.taskId],
|
|
774
|
+
},
|
|
775
|
+
{
|
|
776
|
+
agentId: "lead",
|
|
777
|
+
conversationId: "conv-1",
|
|
778
|
+
iteration: 1,
|
|
779
|
+
},
|
|
780
|
+
);
|
|
781
|
+
|
|
782
|
+
await expect(
|
|
783
|
+
teamTask?.execute(
|
|
784
|
+
{ action: "list", readyOnly: true },
|
|
785
|
+
{
|
|
786
|
+
agentId: "lead",
|
|
787
|
+
conversationId: "conv-1",
|
|
788
|
+
iteration: 1,
|
|
789
|
+
},
|
|
790
|
+
),
|
|
791
|
+
).resolves.toEqual({
|
|
792
|
+
action: "list",
|
|
793
|
+
tasks: [
|
|
794
|
+
expect.objectContaining({
|
|
795
|
+
id: first.taskId,
|
|
796
|
+
isReady: true,
|
|
797
|
+
blockedBy: [],
|
|
798
|
+
}),
|
|
799
|
+
],
|
|
800
|
+
});
|
|
801
|
+
});
|
|
802
|
+
});
|