macro-agent 0.1.0 → 0.1.1
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/.claude/settings.local.json +3 -1
- package/.sudocode/specs.jsonl +4 -0
- package/CLAUDE.md +16 -14
- package/README.md +11 -29
- package/dist/acp/macro-agent.d.ts +15 -0
- package/dist/acp/macro-agent.d.ts.map +1 -1
- package/dist/acp/macro-agent.js +131 -35
- package/dist/acp/macro-agent.js.map +1 -1
- package/dist/acp/types.d.ts +32 -1
- package/dist/acp/types.d.ts.map +1 -1
- package/dist/acp/types.js.map +1 -1
- package/dist/agent/agent-manager.d.ts +65 -1
- package/dist/agent/agent-manager.d.ts.map +1 -1
- package/dist/agent/agent-manager.js +464 -183
- package/dist/agent/agent-manager.js.map +1 -1
- package/dist/agent/types.d.ts +1 -1
- package/dist/agent/types.d.ts.map +1 -1
- package/dist/api/server.d.ts +3 -0
- package/dist/api/server.d.ts.map +1 -1
- package/dist/api/server.js +37 -6
- package/dist/api/server.js.map +1 -1
- package/dist/auth/index.d.ts +2 -0
- package/dist/auth/index.d.ts.map +1 -0
- package/dist/auth/index.js +2 -0
- package/dist/auth/index.js.map +1 -0
- package/dist/auth/token.d.ts +41 -0
- package/dist/auth/token.d.ts.map +1 -0
- package/dist/auth/token.js +73 -0
- package/dist/auth/token.js.map +1 -0
- package/dist/cli/acp.d.ts +2 -23
- package/dist/cli/acp.d.ts.map +1 -1
- package/dist/cli/acp.js +127 -61
- package/dist/cli/acp.js.map +1 -1
- package/dist/cli/index.js +147 -15
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/mcp.d.ts +6 -0
- package/dist/cli/mcp.d.ts.map +1 -1
- package/dist/cli/mcp.js +268 -181
- package/dist/cli/mcp.js.map +1 -1
- package/dist/cli/parse-args.d.ts +20 -0
- package/dist/cli/parse-args.d.ts.map +1 -0
- package/dist/cli/parse-args.js +43 -0
- package/dist/cli/parse-args.js.map +1 -0
- package/dist/cli/stable-instance-id.d.ts +8 -0
- package/dist/cli/stable-instance-id.d.ts.map +1 -0
- package/dist/cli/stable-instance-id.js +14 -0
- package/dist/cli/stable-instance-id.js.map +1 -0
- package/dist/config/project-config.d.ts +74 -7
- package/dist/config/project-config.d.ts.map +1 -1
- package/dist/config/project-config.js +123 -20
- package/dist/config/project-config.js.map +1 -1
- package/dist/map/adapter/acp-over-map.d.ts +17 -0
- package/dist/map/adapter/acp-over-map.d.ts.map +1 -1
- package/dist/map/adapter/acp-over-map.js +384 -23
- package/dist/map/adapter/acp-over-map.js.map +1 -1
- package/dist/map/adapter/connection-manager.d.ts.map +1 -1
- package/dist/map/adapter/connection-manager.js +3 -0
- package/dist/map/adapter/connection-manager.js.map +1 -1
- package/dist/map/adapter/event-log.d.ts +87 -0
- package/dist/map/adapter/event-log.d.ts.map +1 -0
- package/dist/map/adapter/event-log.js +122 -0
- package/dist/map/adapter/event-log.js.map +1 -0
- package/dist/map/adapter/event-translator.js +6 -6
- package/dist/map/adapter/event-translator.js.map +1 -1
- package/dist/map/adapter/extensions/agent-lifecycle.d.ts +82 -0
- package/dist/map/adapter/extensions/agent-lifecycle.d.ts.map +1 -0
- package/dist/map/adapter/extensions/agent-lifecycle.js +164 -0
- package/dist/map/adapter/extensions/agent-lifecycle.js.map +1 -0
- package/dist/map/adapter/extensions/index.d.ts +10 -1
- package/dist/map/adapter/extensions/index.d.ts.map +1 -1
- package/dist/map/adapter/extensions/index.js +34 -0
- package/dist/map/adapter/extensions/index.js.map +1 -1
- package/dist/map/adapter/extensions/mcp-bridge.d.ts +57 -0
- package/dist/map/adapter/extensions/mcp-bridge.d.ts.map +1 -0
- package/dist/map/adapter/extensions/mcp-bridge.js +745 -0
- package/dist/map/adapter/extensions/mcp-bridge.js.map +1 -0
- package/dist/map/adapter/extensions/rename.d.ts +29 -0
- package/dist/map/adapter/extensions/rename.d.ts.map +1 -0
- package/dist/map/adapter/extensions/rename.js +49 -0
- package/dist/map/adapter/extensions/rename.js.map +1 -0
- package/dist/map/adapter/extensions/task.d.ts.map +1 -1
- package/dist/map/adapter/extensions/task.js +10 -0
- package/dist/map/adapter/extensions/task.js.map +1 -1
- package/dist/map/adapter/extensions/update-metadata.d.ts +29 -0
- package/dist/map/adapter/extensions/update-metadata.d.ts.map +1 -0
- package/dist/map/adapter/extensions/update-metadata.js +67 -0
- package/dist/map/adapter/extensions/update-metadata.js.map +1 -0
- package/dist/map/adapter/index.d.ts +2 -1
- package/dist/map/adapter/index.d.ts.map +1 -1
- package/dist/map/adapter/index.js +8 -2
- package/dist/map/adapter/index.js.map +1 -1
- package/dist/map/adapter/interface.d.ts +2 -0
- package/dist/map/adapter/interface.d.ts.map +1 -1
- package/dist/map/adapter/map-adapter.d.ts +3 -0
- package/dist/map/adapter/map-adapter.d.ts.map +1 -1
- package/dist/map/adapter/map-adapter.js +258 -35
- package/dist/map/adapter/map-adapter.js.map +1 -1
- package/dist/map/adapter/subscription-manager.d.ts.map +1 -1
- package/dist/map/adapter/subscription-manager.js +5 -1
- package/dist/map/adapter/subscription-manager.js.map +1 -1
- package/dist/map/adapter/types.d.ts +2 -0
- package/dist/map/adapter/types.d.ts.map +1 -1
- package/dist/mcp/map-client.d.ts +39 -0
- package/dist/mcp/map-client.d.ts.map +1 -0
- package/dist/mcp/map-client.js +129 -0
- package/dist/mcp/map-client.js.map +1 -0
- package/dist/mcp/mcp-server.d.ts +14 -0
- package/dist/mcp/mcp-server.d.ts.map +1 -1
- package/dist/mcp/mcp-server.js +113 -85
- package/dist/mcp/mcp-server.js.map +1 -1
- package/dist/mcp/types.d.ts +9 -1
- package/dist/mcp/types.d.ts.map +1 -1
- package/dist/mcp/types.js.map +1 -1
- package/dist/metrics/metrics.js +1 -1
- package/dist/metrics/metrics.js.map +1 -1
- package/dist/roles/capabilities.d.ts +3 -1
- package/dist/roles/capabilities.d.ts.map +1 -1
- package/dist/roles/capabilities.js +17 -7
- package/dist/roles/capabilities.js.map +1 -1
- package/dist/roles/config-loader.d.ts +6 -6
- package/dist/roles/config-loader.d.ts.map +1 -1
- package/dist/roles/config-loader.js +6 -6
- package/dist/roles/config-loader.js.map +1 -1
- package/dist/roles/registry.d.ts +2 -2
- package/dist/roles/registry.js +2 -2
- package/dist/server/combined-server.d.ts +20 -0
- package/dist/server/combined-server.d.ts.map +1 -1
- package/dist/server/combined-server.js +107 -8
- package/dist/server/combined-server.js.map +1 -1
- package/dist/store/event-store.d.ts +2 -1
- package/dist/store/event-store.d.ts.map +1 -1
- package/dist/store/event-store.js +69 -20
- package/dist/store/event-store.js.map +1 -1
- package/dist/store/types/agents.d.ts +18 -0
- package/dist/store/types/agents.d.ts.map +1 -1
- package/dist/store/types/events.d.ts +1 -1
- package/dist/store/types/events.d.ts.map +1 -1
- package/dist/task/backend/index.d.ts +47 -29
- package/dist/task/backend/index.d.ts.map +1 -1
- package/dist/task/backend/index.js +109 -71
- package/dist/task/backend/index.js.map +1 -1
- package/dist/task/backend/memory.d.ts +1 -0
- package/dist/task/backend/memory.d.ts.map +1 -1
- package/dist/task/backend/memory.js +3 -0
- package/dist/task/backend/memory.js.map +1 -1
- package/dist/task/backend/opentasks/backend.d.ts +140 -0
- package/dist/task/backend/opentasks/backend.d.ts.map +1 -0
- package/dist/task/backend/opentasks/backend.js +1023 -0
- package/dist/task/backend/opentasks/backend.js.map +1 -0
- package/dist/task/backend/opentasks/client.d.ts +337 -0
- package/dist/task/backend/opentasks/client.d.ts.map +1 -0
- package/dist/task/backend/opentasks/client.js +225 -0
- package/dist/task/backend/opentasks/client.js.map +1 -0
- package/dist/task/backend/opentasks/daemon-manager.d.ts +89 -0
- package/dist/task/backend/opentasks/daemon-manager.d.ts.map +1 -0
- package/dist/task/backend/opentasks/daemon-manager.js +195 -0
- package/dist/task/backend/opentasks/daemon-manager.js.map +1 -0
- package/dist/task/backend/opentasks/index.d.ts +21 -0
- package/dist/task/backend/opentasks/index.d.ts.map +1 -0
- package/dist/task/backend/opentasks/index.js +21 -0
- package/dist/task/backend/opentasks/index.js.map +1 -0
- package/dist/task/backend/opentasks/mapping.d.ts +48 -0
- package/dist/task/backend/opentasks/mapping.d.ts.map +1 -0
- package/dist/task/backend/opentasks/mapping.js +77 -0
- package/dist/task/backend/opentasks/mapping.js.map +1 -0
- package/dist/task/backend/types.d.ts +33 -53
- package/dist/task/backend/types.d.ts.map +1 -1
- package/dist/task/backend/types.js +7 -11
- package/dist/task/backend/types.js.map +1 -1
- package/dist/task/backend/unified-tool-provider.d.ts +57 -0
- package/dist/task/backend/unified-tool-provider.d.ts.map +1 -0
- package/dist/task/backend/unified-tool-provider.js +623 -0
- package/dist/task/backend/unified-tool-provider.js.map +1 -0
- package/dist/teams/team-loader.d.ts +2 -2
- package/dist/teams/team-loader.js +3 -3
- package/dist/teams/team-loader.js.map +1 -1
- package/dist/teams/team-runtime.d.ts.map +1 -1
- package/dist/teams/team-runtime.js +2 -0
- package/dist/teams/team-runtime.js.map +1 -1
- package/docs/architecture.md +7 -6
- package/docs/configuration.md +26 -62
- package/docs/implementation-details.md +5 -5
- package/docs/implementation-summary.md +17 -17
- package/docs/plan-self-driving-support.md +4 -4
- package/docs/spec-self-driving-support.md +10 -10
- package/docs/team-templates.md +2 -2
- package/docs/teams.md +3 -3
- package/docs/troubleshooting.md +10 -11
- package/package.json +6 -4
- package/src/__tests__/e2e/agent-spawn-visibility.e2e.test.ts +761 -0
- package/src/__tests__/e2e/full-agent-conflict-resolution.e2e.test.ts +2 -2
- package/src/__tests__/e2e/mcp-thin-client-bridge.e2e.test.ts +304 -0
- package/src/__tests__/e2e/mcp-tools-available.e2e.test.ts +324 -0
- package/src/__tests__/e2e/multi-agent.e2e.test.ts +5 -5
- package/src/__tests__/e2e/spawn-session-streaming.e2e.test.ts +563 -0
- package/src/acp/__tests__/integration.test.ts +56 -31
- package/src/acp/__tests__/macro-agent.test.ts +16 -7
- package/src/acp/macro-agent.ts +170 -36
- package/src/acp/types.ts +46 -1
- package/src/agent/__tests__/agent-manager.test.ts +228 -2
- package/src/agent/agent-manager.ts +714 -261
- package/src/agent/types.ts +3 -1
- package/src/api/server.ts +41 -7
- package/src/auth/__tests__/token.test.ts +100 -0
- package/src/auth/index.ts +1 -0
- package/src/auth/token.ts +82 -0
- package/src/cli/__tests__/acp.test.ts +1 -1
- package/src/cli/__tests__/stable-instance-id.test.ts +1 -1
- package/src/cli/acp.ts +130 -72
- package/src/cli/index.ts +120 -14
- package/src/cli/mcp.ts +311 -207
- package/src/cli/parse-args.ts +54 -0
- package/src/cli/stable-instance-id.ts +14 -0
- package/src/config/project-config.ts +190 -27
- package/src/lifecycle/__tests__/cascade-termination.test.ts +1 -1
- package/src/map/adapter/__tests__/acp-over-map-cancel.test.ts +22 -4
- package/src/map/adapter/__tests__/acp-over-map-getmodels.test.ts +355 -0
- package/src/map/adapter/__tests__/acp-over-map-history.test.ts +263 -0
- package/src/map/adapter/__tests__/acp-over-map-persistence.e2e.test.ts +1 -1
- package/src/map/adapter/__tests__/event-broadcast.test.ts +420 -0
- package/src/map/adapter/__tests__/event-log.test.ts +527 -0
- package/src/map/adapter/__tests__/event-translator.test.ts +3 -3
- package/src/map/adapter/__tests__/extensions.test.ts +408 -0
- package/src/map/adapter/__tests__/map-adapter.test.ts +99 -0
- package/src/map/adapter/__tests__/mcp-bridge.test.ts +1187 -0
- package/src/map/adapter/__tests__/multi-client-broadcast.test.ts +711 -0
- package/src/map/adapter/__tests__/websocket-integration.test.ts +218 -0
- package/src/map/adapter/acp-over-map.ts +678 -66
- package/src/map/adapter/connection-manager.ts +3 -0
- package/src/map/adapter/event-log.ts +208 -0
- package/src/map/adapter/event-translator.ts +6 -6
- package/src/map/adapter/extensions/agent-lifecycle.ts +267 -0
- package/src/map/adapter/extensions/index.ts +60 -0
- package/src/map/adapter/extensions/mcp-bridge.ts +995 -0
- package/src/map/adapter/extensions/task.ts +11 -0
- package/src/map/adapter/extensions/update-metadata.ts +126 -0
- package/src/map/adapter/index.ts +28 -0
- package/src/map/adapter/interface.ts +2 -0
- package/src/map/adapter/map-adapter.ts +312 -47
- package/src/map/adapter/subscription-manager.ts +5 -1
- package/src/map/adapter/types.ts +2 -0
- package/src/mcp/__tests__/map-client.test.ts +386 -0
- package/src/mcp/__tests__/mcp-server-thin-client.test.ts +368 -0
- package/src/mcp/__tests__/mcp-server.test.ts +100 -1
- package/src/mcp/map-client.ts +177 -0
- package/src/mcp/mcp-server.ts +191 -100
- package/src/mcp/types.ts +6 -1
- package/src/metrics/metrics.ts +1 -1
- package/src/monitor/__tests__/stale-agent-flow.integration.test.ts +1 -1
- package/src/roles/__tests__/config-loader.test.ts +7 -7
- package/src/roles/capabilities.ts +17 -7
- package/src/roles/config-loader.ts +6 -6
- package/src/roles/registry.ts +2 -2
- package/src/server/__tests__/combined-server.test.ts +94 -21
- package/src/server/combined-server.ts +189 -33
- package/src/steering/__tests__/steering-integration.test.ts +1 -1
- package/src/store/__tests__/event-store.test.ts +196 -1
- package/src/store/__tests__/instance.test.ts +3 -3
- package/src/store/event-store.ts +80 -21
- package/src/store/types/agents.ts +15 -0
- package/src/store/types/events.ts +1 -1
- package/src/task/backend/__tests__/create-task-backend.test.ts +225 -0
- package/src/task/backend/__tests__/e2e/unified-tool-provider-opentasks.e2e.test.ts +524 -0
- package/src/task/backend/__tests__/unified-tool-provider.test.ts +579 -0
- package/src/task/backend/index.ts +156 -106
- package/src/task/backend/memory.ts +4 -0
- package/src/task/backend/opentasks/__tests__/backend.test.ts +968 -0
- package/src/task/backend/opentasks/__tests__/daemon-manager.test.ts +406 -0
- package/src/task/backend/opentasks/__tests__/mapping.test.ts +84 -0
- package/src/task/backend/opentasks/__tests__/opentasks-backend.e2e.test.ts +1338 -0
- package/src/task/backend/opentasks/backend.ts +1323 -0
- package/src/task/backend/opentasks/client.ts +652 -0
- package/src/task/backend/opentasks/daemon-manager.ts +253 -0
- package/src/task/backend/opentasks/index.ts +69 -0
- package/src/task/backend/opentasks/mapping.ts +94 -0
- package/src/task/backend/types.ts +42 -66
- package/src/task/backend/unified-tool-provider.ts +779 -0
- package/src/teams/__tests__/cross-subsystem.integration.test.ts +1 -1
- package/src/teams/team-loader.ts +3 -3
- package/src/teams/team-runtime.ts +2 -0
- package/test_fixtures/README.md +2 -3
- package/test_fixtures/fixtures/index.ts +0 -3
- package/test_fixtures/fixtures/projects/project-with-specs.ts +7 -149
- package/test_fixtures/fixtures/repos/index.ts +1 -3
- package/test_fixtures/fixtures/repos/temp-repo-factory.ts +0 -116
- package/test_fixtures/fixtures/repos/types.ts +0 -11
- package/test_fixtures/harness/__tests__/fixtures.test.ts +10 -102
- package/test_fixtures/harness/__tests__/temp-repo-and-simulator.test.ts +0 -33
- package/test_fixtures/harness/simulator/agent-simulator.ts +4 -4
- package/vitest.config.ts +1 -1
- package/vitest.e2e.config.ts +1 -1
- package/vitest.setup.ts +1 -30
- package/.macro-agent/teams/self-driving/prompts/grinder.md +0 -27
- package/.macro-agent/teams/self-driving/prompts/judge.md +0 -27
- package/.macro-agent/teams/self-driving/prompts/planner.md +0 -33
- package/.macro-agent/teams/self-driving/roles/grinder.yaml +0 -17
- package/.macro-agent/teams/self-driving/roles/judge.yaml +0 -24
- package/.macro-agent/teams/self-driving/roles/planner.yaml +0 -18
- package/.macro-agent/teams/self-driving/team.yaml +0 -103
- package/.macro-agent/teams/structured/prompts/developer.md +0 -26
- package/.macro-agent/teams/structured/prompts/lead.md +0 -25
- package/.macro-agent/teams/structured/prompts/reviewer.md +0 -24
- package/.macro-agent/teams/structured/roles/developer.yaml +0 -12
- package/.macro-agent/teams/structured/roles/lead.yaml +0 -11
- package/.macro-agent/teams/structured/roles/reviewer.yaml +0 -19
- package/.macro-agent/teams/structured/team.yaml +0 -89
- package/docs/sudocode-integration.md +0 -383
- package/src/task/backend/__tests__/backend-parity.test.ts +0 -451
- package/src/task/backend/__tests__/tool-provider-edge-cases.test.ts +0 -430
- package/src/task/backend/__tests__/tool-provider.test.ts +0 -983
- package/src/task/backend/sudocode/__tests__/backend-edge-cases.test.ts +0 -575
- package/src/task/backend/sudocode/__tests__/backend.test.ts +0 -1194
- package/src/task/backend/sudocode/__tests__/client-integration.test.ts +0 -418
- package/src/task/backend/sudocode/__tests__/client.test.ts +0 -345
- package/src/task/backend/sudocode/__tests__/e2e/backend.e2e.test.ts +0 -753
- package/src/task/backend/sudocode/__tests__/e2e/server-client.e2e.test.ts +0 -680
- package/src/task/backend/sudocode/__tests__/e2e-workflow.test.ts +0 -666
- package/src/task/backend/sudocode/__tests__/integration/standalone-client.integration.test.ts +0 -396
- package/src/task/backend/sudocode/__tests__/integration/sudocode-cli.integration.test.ts +0 -328
- package/src/task/backend/sudocode/__tests__/integration/test-utils.ts +0 -175
- package/src/task/backend/sudocode/__tests__/mapping-edge-cases.test.ts +0 -265
- package/src/task/backend/sudocode/__tests__/server-client.test.ts +0 -675
- package/src/task/backend/sudocode/__tests__/sync-policy-edge-cases.test.ts +0 -521
- package/src/task/backend/sudocode/__tests__/sync-policy.test.ts +0 -519
- package/src/task/backend/sudocode/__tests__/tools.test.ts +0 -471
- package/src/task/backend/sudocode/backend.ts +0 -1237
- package/src/task/backend/sudocode/client.ts +0 -515
- package/src/task/backend/sudocode/index.ts +0 -120
- package/src/task/backend/sudocode/mapping.ts +0 -93
- package/src/task/backend/sudocode/server-client.ts +0 -522
- package/src/task/backend/sudocode/standalone-client.ts +0 -623
- package/src/task/backend/sudocode/sync-policy.ts +0 -387
- package/src/task/backend/sudocode/tools.ts +0 -896
- package/src/task/backend/tool-provider.ts +0 -506
- package/test_fixtures/fixtures/sudocode/index.ts +0 -29
- package/test_fixtures/fixtures/sudocode/issues.ts +0 -185
- package/test_fixtures/fixtures/sudocode/specs.ts +0 -159
|
@@ -1,983 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Tests for InMemoryTaskToolProvider
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import { describe, it, expect, beforeEach, afterEach } from "vitest";
|
|
6
|
-
import { createEventStore, type EventStore } from "../../../store/event-store.js";
|
|
7
|
-
import { createInMemoryTaskBackend, type InMemoryTaskBackend } from "../memory.js";
|
|
8
|
-
import {
|
|
9
|
-
InMemoryTaskToolProvider,
|
|
10
|
-
createTaskToolProvider,
|
|
11
|
-
type TaskToolContext,
|
|
12
|
-
} from "../tool-provider.js";
|
|
13
|
-
|
|
14
|
-
describe("InMemoryTaskToolProvider", () => {
|
|
15
|
-
let eventStore: EventStore;
|
|
16
|
-
let backend: InMemoryTaskBackend;
|
|
17
|
-
let provider: InMemoryTaskToolProvider;
|
|
18
|
-
const testAgentId = "agent_test";
|
|
19
|
-
|
|
20
|
-
const getContext = (): TaskToolContext => ({
|
|
21
|
-
agent_id: testAgentId,
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
beforeEach(async () => {
|
|
25
|
-
eventStore = await createEventStore({ inMemory: true });
|
|
26
|
-
backend = createInMemoryTaskBackend(eventStore);
|
|
27
|
-
provider = createTaskToolProvider(backend, getContext);
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
afterEach(async () => {
|
|
31
|
-
await eventStore.close();
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
35
|
-
// Basic Tests
|
|
36
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
37
|
-
|
|
38
|
-
describe("getTools", () => {
|
|
39
|
-
it("should return all task tools", () => {
|
|
40
|
-
const tools = provider.getTools();
|
|
41
|
-
expect(tools.length).toBeGreaterThan(0);
|
|
42
|
-
|
|
43
|
-
const toolNames = tools.map((t) => t.name);
|
|
44
|
-
expect(toolNames).toContain("create_task");
|
|
45
|
-
expect(toolNames).toContain("get_task");
|
|
46
|
-
expect(toolNames).toContain("list_tasks");
|
|
47
|
-
expect(toolNames).toContain("list_ready_tasks");
|
|
48
|
-
expect(toolNames).toContain("get_task_blockers");
|
|
49
|
-
expect(toolNames).toContain("update_task_status");
|
|
50
|
-
expect(toolNames).toContain("add_blocker");
|
|
51
|
-
expect(toolNames).toContain("remove_blocker");
|
|
52
|
-
expect(toolNames).toContain("assign_task");
|
|
53
|
-
expect(toolNames).toContain("complete_task");
|
|
54
|
-
});
|
|
55
|
-
|
|
56
|
-
it("should have valid schema for each tool", () => {
|
|
57
|
-
const tools = provider.getTools();
|
|
58
|
-
|
|
59
|
-
for (const tool of tools) {
|
|
60
|
-
expect(tool.name).toBeDefined();
|
|
61
|
-
expect(tool.description).toBeDefined();
|
|
62
|
-
expect(tool.schema).toBeDefined();
|
|
63
|
-
expect(tool.handler).toBeDefined();
|
|
64
|
-
expect(typeof tool.handler).toBe("function");
|
|
65
|
-
}
|
|
66
|
-
});
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
describe("getExcludedTools", () => {
|
|
70
|
-
it("should return excluded tool names", () => {
|
|
71
|
-
const excluded = provider.getExcludedTools();
|
|
72
|
-
expect(excluded).toContain("create_task");
|
|
73
|
-
expect(excluded).toContain("get_task");
|
|
74
|
-
});
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
78
|
-
// Tool Handler Tests
|
|
79
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
80
|
-
|
|
81
|
-
describe("create_task handler", () => {
|
|
82
|
-
it("should create a task", async () => {
|
|
83
|
-
const tools = provider.getTools();
|
|
84
|
-
const createTask = tools.find((t) => t.name === "create_task")!;
|
|
85
|
-
|
|
86
|
-
const result = (await createTask.handler({
|
|
87
|
-
description: "Test task",
|
|
88
|
-
})) as { task_id: string; status: string };
|
|
89
|
-
|
|
90
|
-
expect(result.task_id).toBeDefined();
|
|
91
|
-
expect(result.status).toBe("pending");
|
|
92
|
-
});
|
|
93
|
-
|
|
94
|
-
it("should create a subtask with parent", async () => {
|
|
95
|
-
const tools = provider.getTools();
|
|
96
|
-
const createTask = tools.find((t) => t.name === "create_task")!;
|
|
97
|
-
|
|
98
|
-
const parent = (await createTask.handler({
|
|
99
|
-
description: "Parent task",
|
|
100
|
-
})) as { task_id: string };
|
|
101
|
-
|
|
102
|
-
const child = (await createTask.handler({
|
|
103
|
-
description: "Child task",
|
|
104
|
-
parent_task: parent.task_id,
|
|
105
|
-
})) as { task_id: string };
|
|
106
|
-
|
|
107
|
-
expect(child.task_id).toBeDefined();
|
|
108
|
-
|
|
109
|
-
// Verify parent-child relationship
|
|
110
|
-
const getTask = tools.find((t) => t.name === "get_task")!;
|
|
111
|
-
const childDetails = (await getTask.handler({
|
|
112
|
-
task_id: child.task_id,
|
|
113
|
-
})) as { parent_task: string };
|
|
114
|
-
|
|
115
|
-
expect(childDetails.parent_task).toBe(parent.task_id);
|
|
116
|
-
});
|
|
117
|
-
});
|
|
118
|
-
|
|
119
|
-
describe("get_task handler", () => {
|
|
120
|
-
it("should get task details", async () => {
|
|
121
|
-
const tools = provider.getTools();
|
|
122
|
-
const createTask = tools.find((t) => t.name === "create_task")!;
|
|
123
|
-
const getTask = tools.find((t) => t.name === "get_task")!;
|
|
124
|
-
|
|
125
|
-
const created = (await createTask.handler({
|
|
126
|
-
description: "Test task",
|
|
127
|
-
})) as { task_id: string };
|
|
128
|
-
|
|
129
|
-
const result = (await getTask.handler({
|
|
130
|
-
task_id: created.task_id,
|
|
131
|
-
})) as { id: string; description: string; status: string };
|
|
132
|
-
|
|
133
|
-
expect(result.id).toBe(created.task_id);
|
|
134
|
-
expect(result.description).toBe("Test task");
|
|
135
|
-
expect(result.status).toBe("pending");
|
|
136
|
-
});
|
|
137
|
-
|
|
138
|
-
it("should throw for non-existent task", async () => {
|
|
139
|
-
const tools = provider.getTools();
|
|
140
|
-
const getTask = tools.find((t) => t.name === "get_task")!;
|
|
141
|
-
|
|
142
|
-
await expect(
|
|
143
|
-
getTask.handler({ task_id: "nonexistent" })
|
|
144
|
-
).rejects.toThrow("Task not found");
|
|
145
|
-
});
|
|
146
|
-
});
|
|
147
|
-
|
|
148
|
-
describe("list_tasks handler", () => {
|
|
149
|
-
it("should list all tasks", async () => {
|
|
150
|
-
const tools = provider.getTools();
|
|
151
|
-
const createTask = tools.find((t) => t.name === "create_task")!;
|
|
152
|
-
const listTasks = tools.find((t) => t.name === "list_tasks")!;
|
|
153
|
-
|
|
154
|
-
await createTask.handler({ description: "Task 1" });
|
|
155
|
-
await createTask.handler({ description: "Task 2" });
|
|
156
|
-
|
|
157
|
-
const result = (await listTasks.handler({})) as {
|
|
158
|
-
tasks: Array<{ id: string }>;
|
|
159
|
-
total: number;
|
|
160
|
-
};
|
|
161
|
-
|
|
162
|
-
expect(result.tasks).toHaveLength(2);
|
|
163
|
-
expect(result.total).toBe(2);
|
|
164
|
-
});
|
|
165
|
-
|
|
166
|
-
it("should filter by status", async () => {
|
|
167
|
-
const tools = provider.getTools();
|
|
168
|
-
const createTask = tools.find((t) => t.name === "create_task")!;
|
|
169
|
-
const assignTask = tools.find((t) => t.name === "assign_task")!;
|
|
170
|
-
const listTasks = tools.find((t) => t.name === "list_tasks")!;
|
|
171
|
-
|
|
172
|
-
const task1 = (await createTask.handler({
|
|
173
|
-
description: "Task 1",
|
|
174
|
-
})) as { task_id: string };
|
|
175
|
-
await createTask.handler({ description: "Task 2" });
|
|
176
|
-
|
|
177
|
-
await assignTask.handler({ task_id: task1.task_id });
|
|
178
|
-
|
|
179
|
-
const result = (await listTasks.handler({ status: "assigned" })) as {
|
|
180
|
-
tasks: Array<{ id: string }>;
|
|
181
|
-
total: number;
|
|
182
|
-
};
|
|
183
|
-
|
|
184
|
-
expect(result.tasks).toHaveLength(1);
|
|
185
|
-
expect(result.tasks[0].id).toBe(task1.task_id);
|
|
186
|
-
});
|
|
187
|
-
});
|
|
188
|
-
|
|
189
|
-
describe("list_ready_tasks handler", () => {
|
|
190
|
-
it("should list only unblocked tasks", async () => {
|
|
191
|
-
const tools = provider.getTools();
|
|
192
|
-
const createTask = tools.find((t) => t.name === "create_task")!;
|
|
193
|
-
const addBlocker = tools.find((t) => t.name === "add_blocker")!;
|
|
194
|
-
const listReady = tools.find((t) => t.name === "list_ready_tasks")!;
|
|
195
|
-
|
|
196
|
-
const task1 = (await createTask.handler({
|
|
197
|
-
description: "Blocker task",
|
|
198
|
-
})) as { task_id: string };
|
|
199
|
-
const task2 = (await createTask.handler({
|
|
200
|
-
description: "Blocked task",
|
|
201
|
-
})) as { task_id: string };
|
|
202
|
-
|
|
203
|
-
await addBlocker.handler({
|
|
204
|
-
task_id: task2.task_id,
|
|
205
|
-
blocker_id: task1.task_id,
|
|
206
|
-
});
|
|
207
|
-
|
|
208
|
-
const result = (await listReady.handler({})) as {
|
|
209
|
-
tasks: Array<{ id: string }>;
|
|
210
|
-
total: number;
|
|
211
|
-
};
|
|
212
|
-
|
|
213
|
-
// Only task1 should be ready
|
|
214
|
-
expect(result.tasks).toHaveLength(1);
|
|
215
|
-
expect(result.tasks[0].id).toBe(task1.task_id);
|
|
216
|
-
});
|
|
217
|
-
});
|
|
218
|
-
|
|
219
|
-
describe("get_task_blockers handler", () => {
|
|
220
|
-
it("should return blockers for a task", async () => {
|
|
221
|
-
const tools = provider.getTools();
|
|
222
|
-
const createTask = tools.find((t) => t.name === "create_task")!;
|
|
223
|
-
const addBlocker = tools.find((t) => t.name === "add_blocker")!;
|
|
224
|
-
const getBlockers = tools.find((t) => t.name === "get_task_blockers")!;
|
|
225
|
-
|
|
226
|
-
const blocker = (await createTask.handler({
|
|
227
|
-
description: "Blocker",
|
|
228
|
-
})) as { task_id: string };
|
|
229
|
-
const blocked = (await createTask.handler({
|
|
230
|
-
description: "Blocked",
|
|
231
|
-
})) as { task_id: string };
|
|
232
|
-
|
|
233
|
-
await addBlocker.handler({
|
|
234
|
-
task_id: blocked.task_id,
|
|
235
|
-
blocker_id: blocker.task_id,
|
|
236
|
-
});
|
|
237
|
-
|
|
238
|
-
const result = (await getBlockers.handler({
|
|
239
|
-
task_id: blocked.task_id,
|
|
240
|
-
})) as {
|
|
241
|
-
task_id: string;
|
|
242
|
-
blockers: Array<{ id: string }>;
|
|
243
|
-
isBlocked: boolean;
|
|
244
|
-
};
|
|
245
|
-
|
|
246
|
-
expect(result.blockers).toHaveLength(1);
|
|
247
|
-
expect(result.blockers[0].id).toBe(blocker.task_id);
|
|
248
|
-
expect(result.isBlocked).toBe(true);
|
|
249
|
-
});
|
|
250
|
-
});
|
|
251
|
-
|
|
252
|
-
describe("add_blocker handler", () => {
|
|
253
|
-
it("should add a blocker to a task", async () => {
|
|
254
|
-
const tools = provider.getTools();
|
|
255
|
-
const createTask = tools.find((t) => t.name === "create_task")!;
|
|
256
|
-
const addBlocker = tools.find((t) => t.name === "add_blocker")!;
|
|
257
|
-
const getTask = tools.find((t) => t.name === "get_task")!;
|
|
258
|
-
|
|
259
|
-
const blocker = (await createTask.handler({
|
|
260
|
-
description: "Blocker",
|
|
261
|
-
})) as { task_id: string };
|
|
262
|
-
const blocked = (await createTask.handler({
|
|
263
|
-
description: "Blocked",
|
|
264
|
-
})) as { task_id: string };
|
|
265
|
-
|
|
266
|
-
const result = (await addBlocker.handler({
|
|
267
|
-
task_id: blocked.task_id,
|
|
268
|
-
blocker_id: blocker.task_id,
|
|
269
|
-
})) as { added: boolean };
|
|
270
|
-
|
|
271
|
-
expect(result.added).toBe(true);
|
|
272
|
-
|
|
273
|
-
const taskDetails = (await getTask.handler({
|
|
274
|
-
task_id: blocked.task_id,
|
|
275
|
-
})) as { isBlocked: boolean; blockers: string[] };
|
|
276
|
-
|
|
277
|
-
expect(taskDetails.isBlocked).toBe(true);
|
|
278
|
-
expect(taskDetails.blockers).toContain(blocker.task_id);
|
|
279
|
-
});
|
|
280
|
-
});
|
|
281
|
-
|
|
282
|
-
describe("remove_blocker handler", () => {
|
|
283
|
-
it("should remove a blocker from a task", async () => {
|
|
284
|
-
const tools = provider.getTools();
|
|
285
|
-
const createTask = tools.find((t) => t.name === "create_task")!;
|
|
286
|
-
const addBlocker = tools.find((t) => t.name === "add_blocker")!;
|
|
287
|
-
const removeBlocker = tools.find((t) => t.name === "remove_blocker")!;
|
|
288
|
-
const getTask = tools.find((t) => t.name === "get_task")!;
|
|
289
|
-
|
|
290
|
-
const blocker = (await createTask.handler({
|
|
291
|
-
description: "Blocker",
|
|
292
|
-
})) as { task_id: string };
|
|
293
|
-
const blocked = (await createTask.handler({
|
|
294
|
-
description: "Blocked",
|
|
295
|
-
})) as { task_id: string };
|
|
296
|
-
|
|
297
|
-
await addBlocker.handler({
|
|
298
|
-
task_id: blocked.task_id,
|
|
299
|
-
blocker_id: blocker.task_id,
|
|
300
|
-
});
|
|
301
|
-
|
|
302
|
-
const result = (await removeBlocker.handler({
|
|
303
|
-
task_id: blocked.task_id,
|
|
304
|
-
blocker_id: blocker.task_id,
|
|
305
|
-
})) as { removed: boolean };
|
|
306
|
-
|
|
307
|
-
expect(result.removed).toBe(true);
|
|
308
|
-
|
|
309
|
-
const taskDetails = (await getTask.handler({
|
|
310
|
-
task_id: blocked.task_id,
|
|
311
|
-
})) as { isBlocked: boolean; blockers: string[] };
|
|
312
|
-
|
|
313
|
-
expect(taskDetails.isBlocked).toBe(false);
|
|
314
|
-
expect(taskDetails.blockers).not.toContain(blocker.task_id);
|
|
315
|
-
});
|
|
316
|
-
});
|
|
317
|
-
|
|
318
|
-
describe("assign_task handler", () => {
|
|
319
|
-
it("should assign task to calling agent by default", async () => {
|
|
320
|
-
const tools = provider.getTools();
|
|
321
|
-
const createTask = tools.find((t) => t.name === "create_task")!;
|
|
322
|
-
const assignTask = tools.find((t) => t.name === "assign_task")!;
|
|
323
|
-
const getTask = tools.find((t) => t.name === "get_task")!;
|
|
324
|
-
|
|
325
|
-
const task = (await createTask.handler({
|
|
326
|
-
description: "Test task",
|
|
327
|
-
})) as { task_id: string };
|
|
328
|
-
|
|
329
|
-
const result = (await assignTask.handler({
|
|
330
|
-
task_id: task.task_id,
|
|
331
|
-
})) as { assigned_agent: string };
|
|
332
|
-
|
|
333
|
-
expect(result.assigned_agent).toBe(testAgentId);
|
|
334
|
-
|
|
335
|
-
const taskDetails = (await getTask.handler({
|
|
336
|
-
task_id: task.task_id,
|
|
337
|
-
})) as { assigned_agent: string; status: string };
|
|
338
|
-
|
|
339
|
-
expect(taskDetails.assigned_agent).toBe(testAgentId);
|
|
340
|
-
expect(taskDetails.status).toBe("assigned");
|
|
341
|
-
});
|
|
342
|
-
|
|
343
|
-
it("should assign task to specified agent", async () => {
|
|
344
|
-
const tools = provider.getTools();
|
|
345
|
-
const createTask = tools.find((t) => t.name === "create_task")!;
|
|
346
|
-
const assignTask = tools.find((t) => t.name === "assign_task")!;
|
|
347
|
-
|
|
348
|
-
const task = (await createTask.handler({
|
|
349
|
-
description: "Test task",
|
|
350
|
-
})) as { task_id: string };
|
|
351
|
-
|
|
352
|
-
const result = (await assignTask.handler({
|
|
353
|
-
task_id: task.task_id,
|
|
354
|
-
agent_id: "agent_other",
|
|
355
|
-
})) as { assigned_agent: string };
|
|
356
|
-
|
|
357
|
-
expect(result.assigned_agent).toBe("agent_other");
|
|
358
|
-
});
|
|
359
|
-
});
|
|
360
|
-
|
|
361
|
-
describe("complete_task handler", () => {
|
|
362
|
-
it("should complete a task", async () => {
|
|
363
|
-
const tools = provider.getTools();
|
|
364
|
-
const createTask = tools.find((t) => t.name === "create_task")!;
|
|
365
|
-
const completeTask = tools.find((t) => t.name === "complete_task")!;
|
|
366
|
-
const getTask = tools.find((t) => t.name === "get_task")!;
|
|
367
|
-
|
|
368
|
-
const task = (await createTask.handler({
|
|
369
|
-
description: "Test task",
|
|
370
|
-
})) as { task_id: string };
|
|
371
|
-
|
|
372
|
-
// Start task first
|
|
373
|
-
await backend.start(task.task_id);
|
|
374
|
-
|
|
375
|
-
const result = (await completeTask.handler({
|
|
376
|
-
task_id: task.task_id,
|
|
377
|
-
summary: "Task completed successfully",
|
|
378
|
-
})) as { completed: boolean };
|
|
379
|
-
|
|
380
|
-
expect(result.completed).toBe(true);
|
|
381
|
-
|
|
382
|
-
const taskDetails = (await getTask.handler({
|
|
383
|
-
task_id: task.task_id,
|
|
384
|
-
})) as { status: string };
|
|
385
|
-
|
|
386
|
-
expect(taskDetails.status).toBe("completed");
|
|
387
|
-
});
|
|
388
|
-
});
|
|
389
|
-
|
|
390
|
-
describe("update_task_status handler", () => {
|
|
391
|
-
it("should update task status", async () => {
|
|
392
|
-
const tools = provider.getTools();
|
|
393
|
-
const createTask = tools.find((t) => t.name === "create_task")!;
|
|
394
|
-
const updateStatus = tools.find((t) => t.name === "update_task_status")!;
|
|
395
|
-
const getTask = tools.find((t) => t.name === "get_task")!;
|
|
396
|
-
|
|
397
|
-
const task = (await createTask.handler({
|
|
398
|
-
description: "Test task",
|
|
399
|
-
})) as { task_id: string };
|
|
400
|
-
|
|
401
|
-
const result = (await updateStatus.handler({
|
|
402
|
-
task_id: task.task_id,
|
|
403
|
-
status: "in_progress",
|
|
404
|
-
})) as { status: string };
|
|
405
|
-
|
|
406
|
-
expect(result.status).toBe("in_progress");
|
|
407
|
-
|
|
408
|
-
const taskDetails = (await getTask.handler({
|
|
409
|
-
task_id: task.task_id,
|
|
410
|
-
})) as { status: string };
|
|
411
|
-
|
|
412
|
-
expect(taskDetails.status).toBe("in_progress");
|
|
413
|
-
});
|
|
414
|
-
});
|
|
415
|
-
|
|
416
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
417
|
-
// Error Handling Tests
|
|
418
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
419
|
-
|
|
420
|
-
describe("error handling", () => {
|
|
421
|
-
it("get_task should throw for non-existent task", async () => {
|
|
422
|
-
const tools = provider.getTools();
|
|
423
|
-
const getTask = tools.find((t) => t.name === "get_task")!;
|
|
424
|
-
|
|
425
|
-
await expect(
|
|
426
|
-
getTask.handler({ task_id: "task_invalid" })
|
|
427
|
-
).rejects.toThrow("Task not found");
|
|
428
|
-
});
|
|
429
|
-
|
|
430
|
-
it("assign_task should throw for non-existent task", async () => {
|
|
431
|
-
const tools = provider.getTools();
|
|
432
|
-
const assignTask = tools.find((t) => t.name === "assign_task")!;
|
|
433
|
-
|
|
434
|
-
await expect(
|
|
435
|
-
assignTask.handler({ task_id: "task_invalid" })
|
|
436
|
-
).rejects.toThrow();
|
|
437
|
-
});
|
|
438
|
-
|
|
439
|
-
it("complete_task should throw for non-existent task", async () => {
|
|
440
|
-
const tools = provider.getTools();
|
|
441
|
-
const completeTask = tools.find((t) => t.name === "complete_task")!;
|
|
442
|
-
|
|
443
|
-
await expect(
|
|
444
|
-
completeTask.handler({ task_id: "task_invalid" })
|
|
445
|
-
).rejects.toThrow();
|
|
446
|
-
});
|
|
447
|
-
|
|
448
|
-
it("add_blocker should throw for non-existent task", async () => {
|
|
449
|
-
const tools = provider.getTools();
|
|
450
|
-
const addBlocker = tools.find((t) => t.name === "add_blocker")!;
|
|
451
|
-
|
|
452
|
-
await expect(
|
|
453
|
-
addBlocker.handler({
|
|
454
|
-
task_id: "task_invalid",
|
|
455
|
-
blocker_id: "task_also_invalid",
|
|
456
|
-
})
|
|
457
|
-
).rejects.toThrow();
|
|
458
|
-
});
|
|
459
|
-
|
|
460
|
-
it("remove_blocker should throw for non-existent task", async () => {
|
|
461
|
-
const tools = provider.getTools();
|
|
462
|
-
const removeBlocker = tools.find((t) => t.name === "remove_blocker")!;
|
|
463
|
-
|
|
464
|
-
await expect(
|
|
465
|
-
removeBlocker.handler({
|
|
466
|
-
task_id: "task_invalid",
|
|
467
|
-
blocker_id: "task_also_invalid",
|
|
468
|
-
})
|
|
469
|
-
).rejects.toThrow();
|
|
470
|
-
});
|
|
471
|
-
|
|
472
|
-
it("get_task_blockers should throw for non-existent task", async () => {
|
|
473
|
-
const tools = provider.getTools();
|
|
474
|
-
const getBlockers = tools.find((t) => t.name === "get_task_blockers")!;
|
|
475
|
-
|
|
476
|
-
await expect(
|
|
477
|
-
getBlockers.handler({ task_id: "task_invalid" })
|
|
478
|
-
).rejects.toThrow();
|
|
479
|
-
});
|
|
480
|
-
|
|
481
|
-
it("update_task_status should throw for non-existent task", async () => {
|
|
482
|
-
const tools = provider.getTools();
|
|
483
|
-
const updateStatus = tools.find((t) => t.name === "update_task_status")!;
|
|
484
|
-
|
|
485
|
-
await expect(
|
|
486
|
-
updateStatus.handler({ task_id: "task_invalid", status: "in_progress" })
|
|
487
|
-
).rejects.toThrow();
|
|
488
|
-
});
|
|
489
|
-
});
|
|
490
|
-
|
|
491
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
492
|
-
// Edge Case Tests
|
|
493
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
494
|
-
|
|
495
|
-
describe("edge cases", () => {
|
|
496
|
-
it("list_tasks should return empty array when no tasks exist", async () => {
|
|
497
|
-
const tools = provider.getTools();
|
|
498
|
-
const listTasks = tools.find((t) => t.name === "list_tasks")!;
|
|
499
|
-
|
|
500
|
-
const result = (await listTasks.handler({})) as {
|
|
501
|
-
tasks: Array<{ id: string }>;
|
|
502
|
-
total: number;
|
|
503
|
-
};
|
|
504
|
-
|
|
505
|
-
expect(result.tasks).toEqual([]);
|
|
506
|
-
expect(result.total).toBe(0);
|
|
507
|
-
});
|
|
508
|
-
|
|
509
|
-
it("list_ready_tasks should return empty array when no tasks exist", async () => {
|
|
510
|
-
const tools = provider.getTools();
|
|
511
|
-
const listReady = tools.find((t) => t.name === "list_ready_tasks")!;
|
|
512
|
-
|
|
513
|
-
const result = (await listReady.handler({})) as {
|
|
514
|
-
tasks: Array<{ id: string }>;
|
|
515
|
-
total: number;
|
|
516
|
-
};
|
|
517
|
-
|
|
518
|
-
expect(result.tasks).toEqual([]);
|
|
519
|
-
expect(result.total).toBe(0);
|
|
520
|
-
});
|
|
521
|
-
|
|
522
|
-
it("get_task_blockers should return empty array for unblocked task", async () => {
|
|
523
|
-
const tools = provider.getTools();
|
|
524
|
-
const createTask = tools.find((t) => t.name === "create_task")!;
|
|
525
|
-
const getBlockers = tools.find((t) => t.name === "get_task_blockers")!;
|
|
526
|
-
|
|
527
|
-
const task = (await createTask.handler({
|
|
528
|
-
description: "Unblocked task",
|
|
529
|
-
})) as { task_id: string };
|
|
530
|
-
|
|
531
|
-
const result = (await getBlockers.handler({
|
|
532
|
-
task_id: task.task_id,
|
|
533
|
-
})) as {
|
|
534
|
-
blockers: Array<{ id: string }>;
|
|
535
|
-
isBlocked: boolean;
|
|
536
|
-
};
|
|
537
|
-
|
|
538
|
-
expect(result.blockers).toEqual([]);
|
|
539
|
-
expect(result.isBlocked).toBe(false);
|
|
540
|
-
});
|
|
541
|
-
|
|
542
|
-
it("create_task should include created_at timestamp", async () => {
|
|
543
|
-
const tools = provider.getTools();
|
|
544
|
-
const createTask = tools.find((t) => t.name === "create_task")!;
|
|
545
|
-
|
|
546
|
-
const result = (await createTask.handler({
|
|
547
|
-
description: "Task with timestamp",
|
|
548
|
-
})) as { task_id: string; created_at: number };
|
|
549
|
-
|
|
550
|
-
expect(result.created_at).toBeDefined();
|
|
551
|
-
expect(typeof result.created_at).toBe("number");
|
|
552
|
-
});
|
|
553
|
-
|
|
554
|
-
it("get_task should return all expected fields", async () => {
|
|
555
|
-
const tools = provider.getTools();
|
|
556
|
-
const createTask = tools.find((t) => t.name === "create_task")!;
|
|
557
|
-
const getTask = tools.find((t) => t.name === "get_task")!;
|
|
558
|
-
|
|
559
|
-
const created = (await createTask.handler({
|
|
560
|
-
description: "Full details task",
|
|
561
|
-
})) as { task_id: string };
|
|
562
|
-
|
|
563
|
-
const result = (await getTask.handler({
|
|
564
|
-
task_id: created.task_id,
|
|
565
|
-
})) as Record<string, unknown>;
|
|
566
|
-
|
|
567
|
-
expect(result).toHaveProperty("id");
|
|
568
|
-
expect(result).toHaveProperty("description");
|
|
569
|
-
expect(result).toHaveProperty("status");
|
|
570
|
-
expect(result).toHaveProperty("isBlocked");
|
|
571
|
-
expect(result).toHaveProperty("blockers");
|
|
572
|
-
expect(result).toHaveProperty("created_at");
|
|
573
|
-
});
|
|
574
|
-
|
|
575
|
-
it("list_tasks should include isBlocked field", async () => {
|
|
576
|
-
const tools = provider.getTools();
|
|
577
|
-
const createTask = tools.find((t) => t.name === "create_task")!;
|
|
578
|
-
const listTasks = tools.find((t) => t.name === "list_tasks")!;
|
|
579
|
-
|
|
580
|
-
await createTask.handler({ description: "Task" });
|
|
581
|
-
|
|
582
|
-
const result = (await listTasks.handler({ include_blocked: true })) as {
|
|
583
|
-
tasks: Array<{ id: string; isBlocked: boolean }>;
|
|
584
|
-
};
|
|
585
|
-
|
|
586
|
-
expect(result.tasks[0]).toHaveProperty("isBlocked");
|
|
587
|
-
});
|
|
588
|
-
});
|
|
589
|
-
|
|
590
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
591
|
-
// Complex Filter Tests
|
|
592
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
593
|
-
|
|
594
|
-
describe("complex filtering", () => {
|
|
595
|
-
it("list_tasks should filter by parent_task", async () => {
|
|
596
|
-
const tools = provider.getTools();
|
|
597
|
-
const createTask = tools.find((t) => t.name === "create_task")!;
|
|
598
|
-
const listTasks = tools.find((t) => t.name === "list_tasks")!;
|
|
599
|
-
|
|
600
|
-
const parent = (await createTask.handler({
|
|
601
|
-
description: "Parent",
|
|
602
|
-
})) as { task_id: string };
|
|
603
|
-
|
|
604
|
-
await createTask.handler({
|
|
605
|
-
description: "Child 1",
|
|
606
|
-
parent_task: parent.task_id,
|
|
607
|
-
});
|
|
608
|
-
await createTask.handler({
|
|
609
|
-
description: "Child 2",
|
|
610
|
-
parent_task: parent.task_id,
|
|
611
|
-
});
|
|
612
|
-
await createTask.handler({ description: "Orphan" });
|
|
613
|
-
|
|
614
|
-
const result = (await listTasks.handler({
|
|
615
|
-
parent_task: parent.task_id,
|
|
616
|
-
include_blocked: true,
|
|
617
|
-
})) as {
|
|
618
|
-
tasks: Array<{ id: string }>;
|
|
619
|
-
total: number;
|
|
620
|
-
};
|
|
621
|
-
|
|
622
|
-
expect(result.total).toBe(2);
|
|
623
|
-
});
|
|
624
|
-
|
|
625
|
-
it("list_tasks should filter root_only tasks", async () => {
|
|
626
|
-
const tools = provider.getTools();
|
|
627
|
-
const createTask = tools.find((t) => t.name === "create_task")!;
|
|
628
|
-
const listTasks = tools.find((t) => t.name === "list_tasks")!;
|
|
629
|
-
|
|
630
|
-
const parent = (await createTask.handler({
|
|
631
|
-
description: "Parent",
|
|
632
|
-
})) as { task_id: string };
|
|
633
|
-
|
|
634
|
-
await createTask.handler({
|
|
635
|
-
description: "Child",
|
|
636
|
-
parent_task: parent.task_id,
|
|
637
|
-
});
|
|
638
|
-
|
|
639
|
-
const result = (await listTasks.handler({
|
|
640
|
-
root_only: true,
|
|
641
|
-
include_blocked: true,
|
|
642
|
-
})) as {
|
|
643
|
-
tasks: Array<{ id: string }>;
|
|
644
|
-
total: number;
|
|
645
|
-
};
|
|
646
|
-
|
|
647
|
-
expect(result.total).toBe(1);
|
|
648
|
-
expect(result.tasks[0].id).toBe(parent.task_id);
|
|
649
|
-
});
|
|
650
|
-
|
|
651
|
-
it("list_tasks should filter by assigned_agent", async () => {
|
|
652
|
-
const tools = provider.getTools();
|
|
653
|
-
const createTask = tools.find((t) => t.name === "create_task")!;
|
|
654
|
-
const assignTask = tools.find((t) => t.name === "assign_task")!;
|
|
655
|
-
const listTasks = tools.find((t) => t.name === "list_tasks")!;
|
|
656
|
-
|
|
657
|
-
const task1 = (await createTask.handler({
|
|
658
|
-
description: "Task 1",
|
|
659
|
-
})) as { task_id: string };
|
|
660
|
-
const task2 = (await createTask.handler({
|
|
661
|
-
description: "Task 2",
|
|
662
|
-
})) as { task_id: string };
|
|
663
|
-
await createTask.handler({ description: "Task 3" });
|
|
664
|
-
|
|
665
|
-
await assignTask.handler({ task_id: task1.task_id, agent_id: "agent_a" });
|
|
666
|
-
await assignTask.handler({ task_id: task2.task_id, agent_id: "agent_b" });
|
|
667
|
-
|
|
668
|
-
const result = (await listTasks.handler({
|
|
669
|
-
assigned_agent: "agent_a",
|
|
670
|
-
include_blocked: true,
|
|
671
|
-
})) as {
|
|
672
|
-
tasks: Array<{ id: string }>;
|
|
673
|
-
total: number;
|
|
674
|
-
};
|
|
675
|
-
|
|
676
|
-
expect(result.total).toBe(1);
|
|
677
|
-
expect(result.tasks[0].id).toBe(task1.task_id);
|
|
678
|
-
});
|
|
679
|
-
|
|
680
|
-
it("list_ready_tasks should filter by assigned_agent", async () => {
|
|
681
|
-
const tools = provider.getTools();
|
|
682
|
-
const createTask = tools.find((t) => t.name === "create_task")!;
|
|
683
|
-
const assignTask = tools.find((t) => t.name === "assign_task")!;
|
|
684
|
-
const listReady = tools.find((t) => t.name === "list_ready_tasks")!;
|
|
685
|
-
|
|
686
|
-
const task1 = (await createTask.handler({
|
|
687
|
-
description: "Task 1",
|
|
688
|
-
})) as { task_id: string };
|
|
689
|
-
await createTask.handler({ description: "Task 2" });
|
|
690
|
-
|
|
691
|
-
await assignTask.handler({ task_id: task1.task_id, agent_id: "agent_a" });
|
|
692
|
-
|
|
693
|
-
const result = (await listReady.handler({
|
|
694
|
-
assigned_agent: "agent_a",
|
|
695
|
-
})) as {
|
|
696
|
-
tasks: Array<{ id: string }>;
|
|
697
|
-
total: number;
|
|
698
|
-
};
|
|
699
|
-
|
|
700
|
-
expect(result.total).toBe(1);
|
|
701
|
-
expect(result.tasks[0].id).toBe(task1.task_id);
|
|
702
|
-
});
|
|
703
|
-
});
|
|
704
|
-
|
|
705
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
706
|
-
// Context Switching Tests
|
|
707
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
708
|
-
|
|
709
|
-
describe("context switching", () => {
|
|
710
|
-
it("should use different agent contexts", async () => {
|
|
711
|
-
let currentAgent = "agent_a";
|
|
712
|
-
const dynamicContext = () => ({ agent_id: currentAgent });
|
|
713
|
-
const dynamicProvider = createTaskToolProvider(backend, dynamicContext);
|
|
714
|
-
const tools = dynamicProvider.getTools();
|
|
715
|
-
const createTask = tools.find((t) => t.name === "create_task")!;
|
|
716
|
-
const getTask = tools.find((t) => t.name === "get_task")!;
|
|
717
|
-
|
|
718
|
-
// Create task as agent_a
|
|
719
|
-
const task1 = (await createTask.handler({
|
|
720
|
-
description: "Task by A",
|
|
721
|
-
})) as { task_id: string };
|
|
722
|
-
|
|
723
|
-
// Switch to agent_b
|
|
724
|
-
currentAgent = "agent_b";
|
|
725
|
-
|
|
726
|
-
// Create task as agent_b
|
|
727
|
-
const task2 = (await createTask.handler({
|
|
728
|
-
description: "Task by B",
|
|
729
|
-
})) as { task_id: string };
|
|
730
|
-
|
|
731
|
-
// Verify created_by is different
|
|
732
|
-
const details1 = await backend.get(task1.task_id);
|
|
733
|
-
const details2 = await backend.get(task2.task_id);
|
|
734
|
-
|
|
735
|
-
expect(details1!.created_by).toBe("agent_a");
|
|
736
|
-
expect(details2!.created_by).toBe("agent_b");
|
|
737
|
-
});
|
|
738
|
-
|
|
739
|
-
it("assign_task should default to current context agent", async () => {
|
|
740
|
-
let currentAgent = "agent_context";
|
|
741
|
-
const dynamicContext = () => ({ agent_id: currentAgent });
|
|
742
|
-
const dynamicProvider = createTaskToolProvider(backend, dynamicContext);
|
|
743
|
-
const tools = dynamicProvider.getTools();
|
|
744
|
-
const createTask = tools.find((t) => t.name === "create_task")!;
|
|
745
|
-
const assignTask = tools.find((t) => t.name === "assign_task")!;
|
|
746
|
-
|
|
747
|
-
const task = (await createTask.handler({
|
|
748
|
-
description: "Task",
|
|
749
|
-
})) as { task_id: string };
|
|
750
|
-
|
|
751
|
-
const result = (await assignTask.handler({
|
|
752
|
-
task_id: task.task_id,
|
|
753
|
-
})) as { assigned_agent: string };
|
|
754
|
-
|
|
755
|
-
expect(result.assigned_agent).toBe("agent_context");
|
|
756
|
-
});
|
|
757
|
-
});
|
|
758
|
-
|
|
759
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
760
|
-
// Full Workflow Integration Tests
|
|
761
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
762
|
-
|
|
763
|
-
describe("full workflow integration", () => {
|
|
764
|
-
it("should handle complete task lifecycle via tools", async () => {
|
|
765
|
-
const tools = provider.getTools();
|
|
766
|
-
const createTask = tools.find((t) => t.name === "create_task")!;
|
|
767
|
-
const assignTask = tools.find((t) => t.name === "assign_task")!;
|
|
768
|
-
const updateStatus = tools.find((t) => t.name === "update_task_status")!;
|
|
769
|
-
const completeTask = tools.find((t) => t.name === "complete_task")!;
|
|
770
|
-
const getTask = tools.find((t) => t.name === "get_task")!;
|
|
771
|
-
|
|
772
|
-
// Create
|
|
773
|
-
const task = (await createTask.handler({
|
|
774
|
-
description: "Lifecycle test task",
|
|
775
|
-
})) as { task_id: string };
|
|
776
|
-
|
|
777
|
-
// Assign
|
|
778
|
-
await assignTask.handler({ task_id: task.task_id });
|
|
779
|
-
|
|
780
|
-
// Start
|
|
781
|
-
await updateStatus.handler({
|
|
782
|
-
task_id: task.task_id,
|
|
783
|
-
status: "in_progress",
|
|
784
|
-
});
|
|
785
|
-
|
|
786
|
-
// Complete
|
|
787
|
-
await completeTask.handler({
|
|
788
|
-
task_id: task.task_id,
|
|
789
|
-
summary: "Done!",
|
|
790
|
-
});
|
|
791
|
-
|
|
792
|
-
// Verify
|
|
793
|
-
const details = (await getTask.handler({
|
|
794
|
-
task_id: task.task_id,
|
|
795
|
-
})) as { status: string; completed_at: number };
|
|
796
|
-
|
|
797
|
-
expect(details.status).toBe("completed");
|
|
798
|
-
expect(details.completed_at).toBeDefined();
|
|
799
|
-
});
|
|
800
|
-
|
|
801
|
-
it("should handle dependency-based workflow via tools", async () => {
|
|
802
|
-
const tools = provider.getTools();
|
|
803
|
-
const createTask = tools.find((t) => t.name === "create_task")!;
|
|
804
|
-
const addBlocker = tools.find((t) => t.name === "add_blocker")!;
|
|
805
|
-
const listReady = tools.find((t) => t.name === "list_ready_tasks")!;
|
|
806
|
-
const updateStatus = tools.find((t) => t.name === "update_task_status")!;
|
|
807
|
-
const completeTask = tools.find((t) => t.name === "complete_task")!;
|
|
808
|
-
|
|
809
|
-
// Create tasks with dependencies
|
|
810
|
-
const taskA = (await createTask.handler({
|
|
811
|
-
description: "Task A (first)",
|
|
812
|
-
})) as { task_id: string };
|
|
813
|
-
const taskB = (await createTask.handler({
|
|
814
|
-
description: "Task B (depends on A)",
|
|
815
|
-
})) as { task_id: string };
|
|
816
|
-
const taskC = (await createTask.handler({
|
|
817
|
-
description: "Task C (depends on B)",
|
|
818
|
-
})) as { task_id: string };
|
|
819
|
-
|
|
820
|
-
await addBlocker.handler({
|
|
821
|
-
task_id: taskB.task_id,
|
|
822
|
-
blocker_id: taskA.task_id,
|
|
823
|
-
});
|
|
824
|
-
await addBlocker.handler({
|
|
825
|
-
task_id: taskC.task_id,
|
|
826
|
-
blocker_id: taskB.task_id,
|
|
827
|
-
});
|
|
828
|
-
|
|
829
|
-
// Only A should be ready
|
|
830
|
-
let ready = (await listReady.handler({})) as {
|
|
831
|
-
tasks: Array<{ id: string }>;
|
|
832
|
-
};
|
|
833
|
-
expect(ready.tasks).toHaveLength(1);
|
|
834
|
-
expect(ready.tasks[0].id).toBe(taskA.task_id);
|
|
835
|
-
|
|
836
|
-
// Complete A
|
|
837
|
-
await updateStatus.handler({
|
|
838
|
-
task_id: taskA.task_id,
|
|
839
|
-
status: "in_progress",
|
|
840
|
-
});
|
|
841
|
-
await completeTask.handler({ task_id: taskA.task_id });
|
|
842
|
-
|
|
843
|
-
// Now B should be ready
|
|
844
|
-
ready = (await listReady.handler({})) as {
|
|
845
|
-
tasks: Array<{ id: string }>;
|
|
846
|
-
};
|
|
847
|
-
expect(ready.tasks).toHaveLength(1);
|
|
848
|
-
expect(ready.tasks[0].id).toBe(taskB.task_id);
|
|
849
|
-
|
|
850
|
-
// Complete B
|
|
851
|
-
await updateStatus.handler({
|
|
852
|
-
task_id: taskB.task_id,
|
|
853
|
-
status: "in_progress",
|
|
854
|
-
});
|
|
855
|
-
await completeTask.handler({ task_id: taskB.task_id });
|
|
856
|
-
|
|
857
|
-
// Now C should be ready
|
|
858
|
-
ready = (await listReady.handler({})) as {
|
|
859
|
-
tasks: Array<{ id: string }>;
|
|
860
|
-
};
|
|
861
|
-
expect(ready.tasks).toHaveLength(1);
|
|
862
|
-
expect(ready.tasks[0].id).toBe(taskC.task_id);
|
|
863
|
-
});
|
|
864
|
-
|
|
865
|
-
it("should handle parent-child task relationships via tools", async () => {
|
|
866
|
-
const tools = provider.getTools();
|
|
867
|
-
const createTask = tools.find((t) => t.name === "create_task")!;
|
|
868
|
-
const listTasks = tools.find((t) => t.name === "list_tasks")!;
|
|
869
|
-
const getTask = tools.find((t) => t.name === "get_task")!;
|
|
870
|
-
|
|
871
|
-
// Create parent
|
|
872
|
-
const parent = (await createTask.handler({
|
|
873
|
-
description: "Parent task",
|
|
874
|
-
})) as { task_id: string };
|
|
875
|
-
|
|
876
|
-
// Create children
|
|
877
|
-
const child1 = (await createTask.handler({
|
|
878
|
-
description: "Child 1",
|
|
879
|
-
parent_task: parent.task_id,
|
|
880
|
-
})) as { task_id: string };
|
|
881
|
-
const child2 = (await createTask.handler({
|
|
882
|
-
description: "Child 2",
|
|
883
|
-
parent_task: parent.task_id,
|
|
884
|
-
})) as { task_id: string };
|
|
885
|
-
|
|
886
|
-
// Verify parent-child relationships
|
|
887
|
-
const parentDetails = (await getTask.handler({
|
|
888
|
-
task_id: parent.task_id,
|
|
889
|
-
})) as { id: string };
|
|
890
|
-
const child1Details = (await getTask.handler({
|
|
891
|
-
task_id: child1.task_id,
|
|
892
|
-
})) as { parent_task: string };
|
|
893
|
-
const child2Details = (await getTask.handler({
|
|
894
|
-
task_id: child2.task_id,
|
|
895
|
-
})) as { parent_task: string };
|
|
896
|
-
|
|
897
|
-
expect(child1Details.parent_task).toBe(parent.task_id);
|
|
898
|
-
expect(child2Details.parent_task).toBe(parent.task_id);
|
|
899
|
-
|
|
900
|
-
// Filter by parent
|
|
901
|
-
const children = (await listTasks.handler({
|
|
902
|
-
parent_task: parent.task_id,
|
|
903
|
-
include_blocked: true,
|
|
904
|
-
})) as {
|
|
905
|
-
tasks: Array<{ id: string }>;
|
|
906
|
-
total: number;
|
|
907
|
-
};
|
|
908
|
-
|
|
909
|
-
expect(children.total).toBe(2);
|
|
910
|
-
});
|
|
911
|
-
|
|
912
|
-
it("should handle blocker completion unblocking workflow", async () => {
|
|
913
|
-
const tools = provider.getTools();
|
|
914
|
-
const createTask = tools.find((t) => t.name === "create_task")!;
|
|
915
|
-
const addBlocker = tools.find((t) => t.name === "add_blocker")!;
|
|
916
|
-
const getBlockers = tools.find((t) => t.name === "get_task_blockers")!;
|
|
917
|
-
const updateStatus = tools.find((t) => t.name === "update_task_status")!;
|
|
918
|
-
const completeTask = tools.find((t) => t.name === "complete_task")!;
|
|
919
|
-
|
|
920
|
-
const blocker = (await createTask.handler({
|
|
921
|
-
description: "Blocker",
|
|
922
|
-
})) as { task_id: string };
|
|
923
|
-
const blocked = (await createTask.handler({
|
|
924
|
-
description: "Blocked",
|
|
925
|
-
})) as { task_id: string };
|
|
926
|
-
|
|
927
|
-
await addBlocker.handler({
|
|
928
|
-
task_id: blocked.task_id,
|
|
929
|
-
blocker_id: blocker.task_id,
|
|
930
|
-
});
|
|
931
|
-
|
|
932
|
-
// Initially blocked
|
|
933
|
-
let blockerStatus = (await getBlockers.handler({
|
|
934
|
-
task_id: blocked.task_id,
|
|
935
|
-
})) as { isBlocked: boolean; blockers: Array<{ isCompleted: boolean }> };
|
|
936
|
-
|
|
937
|
-
expect(blockerStatus.isBlocked).toBe(true);
|
|
938
|
-
expect(blockerStatus.blockers[0].isCompleted).toBe(false);
|
|
939
|
-
|
|
940
|
-
// Complete blocker
|
|
941
|
-
await updateStatus.handler({
|
|
942
|
-
task_id: blocker.task_id,
|
|
943
|
-
status: "in_progress",
|
|
944
|
-
});
|
|
945
|
-
await completeTask.handler({ task_id: blocker.task_id });
|
|
946
|
-
|
|
947
|
-
// Now unblocked
|
|
948
|
-
blockerStatus = (await getBlockers.handler({
|
|
949
|
-
task_id: blocked.task_id,
|
|
950
|
-
})) as { isBlocked: boolean; blockers: Array<{ isCompleted: boolean }> };
|
|
951
|
-
|
|
952
|
-
expect(blockerStatus.isBlocked).toBe(false);
|
|
953
|
-
expect(blockerStatus.blockers[0].isCompleted).toBe(true);
|
|
954
|
-
});
|
|
955
|
-
});
|
|
956
|
-
|
|
957
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
958
|
-
// Schema Validation Tests
|
|
959
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
960
|
-
|
|
961
|
-
describe("schema structure", () => {
|
|
962
|
-
it("each tool should have proper JSON schema structure", () => {
|
|
963
|
-
const tools = provider.getTools();
|
|
964
|
-
|
|
965
|
-
for (const tool of tools) {
|
|
966
|
-
expect(tool.schema).toHaveProperty("type");
|
|
967
|
-
expect(tool.schema.type).toBe("object");
|
|
968
|
-
expect(tool.schema).toHaveProperty("properties");
|
|
969
|
-
}
|
|
970
|
-
});
|
|
971
|
-
|
|
972
|
-
it("required fields should be specified in schema", () => {
|
|
973
|
-
const tools = provider.getTools();
|
|
974
|
-
|
|
975
|
-
const toolsWithRequired = ["create_task", "get_task", "get_task_blockers"];
|
|
976
|
-
|
|
977
|
-
for (const toolName of toolsWithRequired) {
|
|
978
|
-
const tool = tools.find((t) => t.name === toolName)!;
|
|
979
|
-
expect(tool.schema).toHaveProperty("required");
|
|
980
|
-
}
|
|
981
|
-
});
|
|
982
|
-
});
|
|
983
|
-
});
|