macro-agent 0.0.11 → 0.0.12
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/.macro-agent/teams/self-driving/prompts/grinder.md +27 -0
- package/.macro-agent/teams/self-driving/prompts/judge.md +27 -0
- package/.macro-agent/teams/self-driving/prompts/planner.md +33 -0
- package/.macro-agent/teams/self-driving/roles/grinder.yaml +17 -0
- package/.macro-agent/teams/self-driving/roles/judge.yaml +24 -0
- package/.macro-agent/teams/self-driving/roles/planner.yaml +18 -0
- package/.macro-agent/teams/self-driving/team.yaml +103 -0
- package/.macro-agent/teams/structured/prompts/developer.md +26 -0
- package/.macro-agent/teams/structured/prompts/lead.md +25 -0
- package/.macro-agent/teams/structured/prompts/reviewer.md +24 -0
- package/.macro-agent/teams/structured/roles/developer.yaml +12 -0
- package/.macro-agent/teams/structured/roles/lead.yaml +11 -0
- package/.macro-agent/teams/structured/roles/reviewer.yaml +19 -0
- package/.macro-agent/teams/structured/team.yaml +89 -0
- package/.sudocode/issues.jsonl +6 -0
- package/.sudocode/specs.jsonl +7 -0
- package/CLAUDE.md +110 -30
- package/README.md +60 -3
- package/dist/acp/macro-agent.d.ts +4 -0
- package/dist/acp/macro-agent.d.ts.map +1 -1
- package/dist/acp/macro-agent.js +50 -4
- package/dist/acp/macro-agent.js.map +1 -1
- package/dist/acp/session-mapper.d.ts +20 -1
- package/dist/acp/session-mapper.d.ts.map +1 -1
- package/dist/acp/session-mapper.js +90 -1
- package/dist/acp/session-mapper.js.map +1 -1
- package/dist/acp/types.d.ts +24 -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 +25 -1
- package/dist/agent/agent-manager.d.ts.map +1 -1
- package/dist/agent/agent-manager.js +93 -7
- package/dist/agent/agent-manager.js.map +1 -1
- package/dist/agent/types.d.ts +22 -0
- package/dist/agent/types.d.ts.map +1 -1
- package/dist/agent/types.js.map +1 -1
- package/dist/agent-detection/command-builder.d.ts +30 -0
- package/dist/agent-detection/command-builder.d.ts.map +1 -0
- package/dist/agent-detection/command-builder.js +71 -0
- package/dist/agent-detection/command-builder.js.map +1 -0
- package/dist/agent-detection/detector.d.ts +84 -0
- package/dist/agent-detection/detector.d.ts.map +1 -0
- package/dist/agent-detection/detector.js +240 -0
- package/dist/agent-detection/detector.js.map +1 -0
- package/dist/agent-detection/index.d.ts +12 -0
- package/dist/agent-detection/index.d.ts.map +1 -0
- package/dist/agent-detection/index.js +14 -0
- package/dist/agent-detection/index.js.map +1 -0
- package/dist/agent-detection/registry.d.ts +53 -0
- package/dist/agent-detection/registry.d.ts.map +1 -0
- package/dist/agent-detection/registry.js +177 -0
- package/dist/agent-detection/registry.js.map +1 -0
- package/dist/agent-detection/types.d.ts +121 -0
- package/dist/agent-detection/types.d.ts.map +1 -0
- package/dist/agent-detection/types.js +20 -0
- package/dist/agent-detection/types.js.map +1 -0
- package/dist/api/server.d.ts.map +1 -1
- package/dist/api/server.js +95 -0
- package/dist/api/server.js.map +1 -1
- package/dist/cli/index.js +29 -0
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/mcp.js +38 -0
- package/dist/cli/mcp.js.map +1 -1
- package/dist/config/index.d.ts +2 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +2 -0
- package/dist/config/index.js.map +1 -0
- package/dist/config/project-config.d.ts +46 -0
- package/dist/config/project-config.d.ts.map +1 -0
- package/dist/config/project-config.js +68 -0
- package/dist/config/project-config.js.map +1 -0
- package/dist/lifecycle/cascade.d.ts +1 -1
- package/dist/lifecycle/cascade.d.ts.map +1 -1
- package/dist/lifecycle/handlers/index.d.ts +4 -0
- package/dist/lifecycle/handlers/index.d.ts.map +1 -1
- package/dist/lifecycle/handlers/index.js +2 -0
- package/dist/lifecycle/handlers/index.js.map +1 -1
- package/dist/lifecycle/handlers/worker.d.ts +4 -0
- package/dist/lifecycle/handlers/worker.d.ts.map +1 -1
- package/dist/lifecycle/handlers/worker.js +35 -3
- package/dist/lifecycle/handlers/worker.js.map +1 -1
- package/dist/map/adapter/acp-over-map.d.ts.map +1 -1
- package/dist/map/adapter/acp-over-map.js +32 -2
- package/dist/map/adapter/acp-over-map.js.map +1 -1
- package/dist/map/adapter/event-translator.d.ts.map +1 -1
- package/dist/map/adapter/event-translator.js +1 -0
- package/dist/map/adapter/event-translator.js.map +1 -1
- package/dist/map/adapter/extensions/agent-detection.d.ts +49 -0
- package/dist/map/adapter/extensions/agent-detection.d.ts.map +1 -0
- package/dist/map/adapter/extensions/agent-detection.js +91 -0
- package/dist/map/adapter/extensions/agent-detection.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 +39 -0
- package/dist/map/adapter/extensions/index.js.map +1 -1
- package/dist/map/adapter/extensions/resume.d.ts +47 -0
- package/dist/map/adapter/extensions/resume.d.ts.map +1 -0
- package/dist/map/adapter/extensions/resume.js +59 -0
- package/dist/map/adapter/extensions/resume.js.map +1 -0
- package/dist/map/adapter/extensions/workspace-files.d.ts +42 -0
- package/dist/map/adapter/extensions/workspace-files.d.ts.map +1 -0
- package/dist/map/adapter/extensions/workspace-files.js +338 -0
- package/dist/map/adapter/extensions/workspace-files.js.map +1 -0
- package/dist/mcp/mcp-server.d.ts +6 -0
- package/dist/mcp/mcp-server.d.ts.map +1 -1
- package/dist/mcp/mcp-server.js +45 -0
- package/dist/mcp/mcp-server.js.map +1 -1
- package/dist/mcp/tools/claim_task.d.ts +35 -0
- package/dist/mcp/tools/claim_task.d.ts.map +1 -0
- package/dist/mcp/tools/claim_task.js +58 -0
- package/dist/mcp/tools/claim_task.js.map +1 -0
- package/dist/mcp/tools/done.d.ts +11 -2
- package/dist/mcp/tools/done.d.ts.map +1 -1
- package/dist/mcp/tools/done.js +15 -10
- package/dist/mcp/tools/done.js.map +1 -1
- package/dist/mcp/tools/list_claimable_tasks.d.ts +38 -0
- package/dist/mcp/tools/list_claimable_tasks.d.ts.map +1 -0
- package/dist/mcp/tools/list_claimable_tasks.js +63 -0
- package/dist/mcp/tools/list_claimable_tasks.js.map +1 -0
- package/dist/mcp/tools/unclaim_task.d.ts +31 -0
- package/dist/mcp/tools/unclaim_task.d.ts.map +1 -0
- package/dist/mcp/tools/unclaim_task.js +47 -0
- package/dist/mcp/tools/unclaim_task.js.map +1 -0
- package/dist/metrics/index.d.ts +2 -0
- package/dist/metrics/index.d.ts.map +1 -0
- package/dist/metrics/index.js +2 -0
- package/dist/metrics/index.js.map +1 -0
- package/dist/metrics/metrics.d.ts +79 -0
- package/dist/metrics/metrics.d.ts.map +1 -0
- package/dist/metrics/metrics.js +166 -0
- package/dist/metrics/metrics.js.map +1 -0
- package/dist/roles/capabilities.d.ts +1 -0
- package/dist/roles/capabilities.d.ts.map +1 -1
- package/dist/roles/capabilities.js +3 -0
- package/dist/roles/capabilities.js.map +1 -1
- package/dist/roles/types.d.ts +1 -1
- package/dist/roles/types.d.ts.map +1 -1
- package/dist/router/message-router.d.ts +41 -0
- package/dist/router/message-router.d.ts.map +1 -1
- package/dist/router/message-router.js +136 -5
- package/dist/router/message-router.js.map +1 -1
- package/dist/store/event-store.d.ts +8 -1
- package/dist/store/event-store.d.ts.map +1 -1
- package/dist/store/event-store.js +120 -4
- package/dist/store/event-store.js.map +1 -1
- package/dist/store/types/agents.d.ts +1 -1
- 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/store/types/events.js.map +1 -1
- package/dist/store/types/index.d.ts +1 -0
- package/dist/store/types/index.d.ts.map +1 -1
- package/dist/store/types/index.js +1 -0
- package/dist/store/types/index.js.map +1 -1
- package/dist/store/types/sessions.d.ts +44 -0
- package/dist/store/types/sessions.d.ts.map +1 -0
- package/dist/store/types/sessions.js +9 -0
- package/dist/store/types/sessions.js.map +1 -0
- package/dist/store/types/tasks.d.ts +2 -0
- package/dist/store/types/tasks.d.ts.map +1 -1
- package/dist/task/backend/memory.d.ts +4 -1
- package/dist/task/backend/memory.d.ts.map +1 -1
- package/dist/task/backend/memory.js +81 -0
- package/dist/task/backend/memory.js.map +1 -1
- package/dist/task/backend/types.d.ts +30 -0
- package/dist/task/backend/types.d.ts.map +1 -1
- package/dist/task/backend/types.js.map +1 -1
- package/dist/teams/index.d.ts +4 -0
- package/dist/teams/index.d.ts.map +1 -0
- package/dist/teams/index.js +4 -0
- package/dist/teams/index.js.map +1 -0
- package/dist/teams/team-loader.d.ts +20 -0
- package/dist/teams/team-loader.d.ts.map +1 -0
- package/dist/teams/team-loader.js +293 -0
- package/dist/teams/team-loader.js.map +1 -0
- package/dist/teams/team-runtime.d.ts +139 -0
- package/dist/teams/team-runtime.d.ts.map +1 -0
- package/dist/teams/team-runtime.js +613 -0
- package/dist/teams/team-runtime.js.map +1 -0
- package/dist/teams/types.d.ts +266 -0
- package/dist/teams/types.d.ts.map +1 -0
- package/dist/teams/types.js +20 -0
- package/dist/teams/types.js.map +1 -0
- package/dist/workspace/dataplane-adapter.d.ts +1 -1
- package/dist/workspace/dataplane-adapter.d.ts.map +1 -1
- package/dist/workspace/dataplane-adapter.js +1 -1
- package/dist/workspace/dataplane-adapter.js.map +1 -1
- package/dist/workspace/index.d.ts +1 -1
- package/dist/workspace/index.d.ts.map +1 -1
- package/dist/workspace/strategies/index.d.ts +6 -0
- package/dist/workspace/strategies/index.d.ts.map +1 -0
- package/dist/workspace/strategies/index.js +5 -0
- package/dist/workspace/strategies/index.js.map +1 -0
- package/dist/workspace/strategies/optimistic.d.ts +26 -0
- package/dist/workspace/strategies/optimistic.d.ts.map +1 -0
- package/dist/workspace/strategies/optimistic.js +121 -0
- package/dist/workspace/strategies/optimistic.js.map +1 -0
- package/dist/workspace/strategies/queue.d.ts +26 -0
- package/dist/workspace/strategies/queue.d.ts.map +1 -0
- package/dist/workspace/strategies/queue.js +67 -0
- package/dist/workspace/strategies/queue.js.map +1 -0
- package/dist/workspace/strategies/registry.d.ts +37 -0
- package/dist/workspace/strategies/registry.d.ts.map +1 -0
- package/dist/workspace/strategies/registry.js +63 -0
- package/dist/workspace/strategies/registry.js.map +1 -0
- package/dist/workspace/strategies/trunk.d.ts +20 -0
- package/dist/workspace/strategies/trunk.d.ts.map +1 -0
- package/dist/workspace/strategies/trunk.js +108 -0
- package/dist/workspace/strategies/trunk.js.map +1 -0
- package/dist/workspace/strategies/types.d.ts +104 -0
- package/dist/workspace/strategies/types.d.ts.map +1 -0
- package/dist/workspace/strategies/types.js +11 -0
- package/dist/workspace/strategies/types.js.map +1 -0
- package/dist/workspace/types.d.ts +1 -1
- package/dist/workspace/types.d.ts.map +1 -1
- package/dist/workspace/workspace-manager.d.ts +1 -1
- package/dist/workspace/workspace-manager.d.ts.map +1 -1
- package/docs/implementation-details.md +1127 -0
- package/docs/implementation-summary.md +448 -0
- package/docs/plan-self-driving-support.md +433 -0
- package/docs/spec-self-driving-support.md +462 -0
- package/docs/team-templates.md +860 -0
- package/docs/teams.md +233 -0
- package/package.json +4 -2
- package/src/acp/__tests__/integration.test.ts +161 -1
- package/src/acp/__tests__/macro-agent.test.ts +95 -0
- package/src/acp/__tests__/session-persistence.test.ts +276 -0
- package/src/acp/macro-agent.ts +79 -7
- package/src/acp/session-mapper.ts +108 -1
- package/src/acp/types.ts +33 -1
- package/src/agent/agent-manager.ts +158 -6
- package/src/agent/types.ts +27 -0
- package/src/agent-detection/__tests__/command-builder.test.ts +336 -0
- package/src/agent-detection/__tests__/detector.test.ts +768 -0
- package/src/agent-detection/__tests__/registry.test.ts +254 -0
- package/src/agent-detection/command-builder.ts +90 -0
- package/src/agent-detection/detector.ts +307 -0
- package/src/agent-detection/index.ts +36 -0
- package/src/agent-detection/registry.ts +200 -0
- package/src/agent-detection/types.ts +184 -0
- package/src/api/server.ts +110 -0
- package/src/cli/index.ts +44 -0
- package/src/cli/mcp.ts +47 -0
- package/src/config/index.ts +9 -0
- package/src/config/project-config.ts +107 -0
- package/src/lifecycle/cascade.ts +1 -1
- package/src/lifecycle/handlers/index.ts +8 -0
- package/src/lifecycle/handlers/worker.ts +48 -3
- package/src/map/adapter/__tests__/extensions.test.ts +359 -0
- package/src/map/adapter/__tests__/workspace-files.test.ts +673 -0
- package/src/map/adapter/acp-over-map.ts +45 -2
- package/src/map/adapter/event-translator.ts +1 -0
- package/src/map/adapter/extensions/agent-detection.ts +201 -0
- package/src/map/adapter/extensions/index.ts +63 -0
- package/src/map/adapter/extensions/resume.ts +114 -0
- package/src/map/adapter/extensions/workspace-files.ts +449 -0
- package/src/mcp/mcp-server.ts +67 -0
- package/src/mcp/tools/claim_task.ts +86 -0
- package/src/mcp/tools/done.ts +24 -10
- package/src/mcp/tools/list_claimable_tasks.ts +93 -0
- package/src/mcp/tools/unclaim_task.ts +71 -0
- package/src/metrics/index.ts +9 -0
- package/src/metrics/metrics.ts +280 -0
- package/src/roles/capabilities.ts +3 -0
- package/src/roles/types.ts +2 -1
- package/src/router/__tests__/message-router.test.ts +561 -0
- package/src/router/message-router.ts +223 -6
- package/src/store/event-store.ts +151 -3
- package/src/store/types/agents.ts +1 -1
- package/src/store/types/events.ts +2 -1
- package/src/store/types/index.ts +1 -0
- package/src/store/types/sessions.ts +53 -0
- package/src/store/types/tasks.ts +3 -0
- package/src/task/backend/memory.ts +116 -0
- package/src/task/backend/types.ts +43 -0
- package/src/teams/__tests__/cross-subsystem.integration.test.ts +983 -0
- package/src/teams/__tests__/e2e/team-runtime.e2e.test.ts +553 -0
- package/src/teams/__tests__/team-system.test.ts +1280 -0
- package/src/teams/index.ts +13 -0
- package/src/teams/team-loader.ts +434 -0
- package/src/teams/team-runtime.ts +727 -0
- package/src/teams/types.ts +377 -0
- package/src/workspace/dataplane-adapter.ts +1 -1
- package/src/workspace/index.ts +1 -1
- package/src/workspace/strategies/index.ts +18 -0
- package/src/workspace/strategies/optimistic.ts +136 -0
- package/src/workspace/strategies/queue.ts +81 -0
- package/src/workspace/strategies/registry.ts +89 -0
- package/src/workspace/strategies/trunk.ts +123 -0
- package/src/workspace/strategies/types.ts +145 -0
- package/src/workspace/types.ts +1 -1
- package/src/workspace/workspace-manager.ts +1 -1
- package/.claude/settings.local.json +0 -59
- package/dist/map/utils/address-translation.d.ts +0 -99
- package/dist/map/utils/address-translation.d.ts.map +0 -1
- package/dist/map/utils/address-translation.js +0 -285
- package/dist/map/utils/address-translation.js.map +0 -1
- package/dist/map/utils/index.d.ts +0 -7
- package/dist/map/utils/index.d.ts.map +0 -1
- package/dist/map/utils/index.js +0 -7
- package/dist/map/utils/index.js.map +0 -1
- package/references/acp-factory-ref/CHANGELOG.md +0 -33
- package/references/acp-factory-ref/LICENSE +0 -21
- package/references/acp-factory-ref/README.md +0 -341
- package/references/acp-factory-ref/package-lock.json +0 -3102
- package/references/acp-factory-ref/package.json +0 -96
- package/references/acp-factory-ref/python/CHANGELOG.md +0 -33
- package/references/acp-factory-ref/python/LICENSE +0 -21
- package/references/acp-factory-ref/python/Makefile +0 -57
- package/references/acp-factory-ref/python/README.md +0 -253
- package/references/acp-factory-ref/python/pyproject.toml +0 -73
- package/references/acp-factory-ref/python/tests/__init__.py +0 -0
- package/references/acp-factory-ref/python/tests/e2e/__init__.py +0 -1
- package/references/acp-factory-ref/python/tests/e2e/test_codex_e2e.py +0 -349
- package/references/acp-factory-ref/python/tests/e2e/test_gemini_e2e.py +0 -165
- package/references/acp-factory-ref/python/tests/e2e/test_opencode_e2e.py +0 -296
- package/references/acp-factory-ref/python/tests/test_client_handler.py +0 -543
- package/references/acp-factory-ref/python/tests/test_pushable.py +0 -199
- package/references/claude-code-acp/.github/workflows/ci.yml +0 -45
- package/references/claude-code-acp/.github/workflows/publish.yml +0 -34
- package/references/claude-code-acp/.prettierrc.json +0 -4
- package/references/claude-code-acp/CHANGELOG.md +0 -249
- package/references/claude-code-acp/LICENSE +0 -222
- package/references/claude-code-acp/README.md +0 -53
- package/references/claude-code-acp/docs/RELEASES.md +0 -24
- package/references/claude-code-acp/eslint.config.js +0 -48
- package/references/claude-code-acp/package-lock.json +0 -4570
- package/references/claude-code-acp/package.json +0 -88
- package/references/claude-code-acp/scripts/release.sh +0 -119
- package/references/claude-code-acp/src/acp-agent.ts +0 -2065
- package/references/claude-code-acp/src/index.ts +0 -26
- package/references/claude-code-acp/src/lib.ts +0 -38
- package/references/claude-code-acp/src/mcp-server.ts +0 -911
- package/references/claude-code-acp/src/settings.ts +0 -522
- package/references/claude-code-acp/src/tests/.claude/commands/quick-math.md +0 -5
- package/references/claude-code-acp/src/tests/.claude/commands/say-hello.md +0 -6
- package/references/claude-code-acp/src/tests/acp-agent-fork.test.ts +0 -479
- package/references/claude-code-acp/src/tests/acp-agent.test.ts +0 -1502
- package/references/claude-code-acp/src/tests/extract-lines.test.ts +0 -103
- package/references/claude-code-acp/src/tests/fork-session.test.ts +0 -335
- package/references/claude-code-acp/src/tests/replace-and-calculate-location.test.ts +0 -334
- package/references/claude-code-acp/src/tests/settings.test.ts +0 -617
- package/references/claude-code-acp/src/tests/skills-options.test.ts +0 -187
- package/references/claude-code-acp/src/tests/tools.test.ts +0 -318
- package/references/claude-code-acp/src/tests/typescript-declarations.test.ts +0 -558
- package/references/claude-code-acp/src/tools.ts +0 -819
- package/references/claude-code-acp/src/utils.ts +0 -171
- package/references/claude-code-acp/tsconfig.json +0 -18
- package/references/claude-code-acp/vitest.config.ts +0 -19
- package/references/multi-agent-protocol/.sudocode/issues.jsonl +0 -111
- package/references/multi-agent-protocol/.sudocode/specs.jsonl +0 -13
- package/references/multi-agent-protocol/LICENSE +0 -21
- package/references/multi-agent-protocol/README.md +0 -113
- package/references/multi-agent-protocol/docs/00-design-specification.md +0 -496
- package/references/multi-agent-protocol/docs/01-open-questions.md +0 -1050
- package/references/multi-agent-protocol/docs/02-wire-protocol.md +0 -296
- package/references/multi-agent-protocol/docs/03-streaming-semantics.md +0 -252
- package/references/multi-agent-protocol/docs/04-error-handling.md +0 -231
- package/references/multi-agent-protocol/docs/05-connection-model.md +0 -244
- package/references/multi-agent-protocol/docs/06-visibility-permissions.md +0 -243
- package/references/multi-agent-protocol/docs/07-federation.md +0 -259
- package/references/multi-agent-protocol/docs/08-macro-agent-migration.md +0 -253
- package/references/multi-agent-protocol/docs/09-authentication.md +0 -680
- package/references/multi-agent-protocol/docs/10-mail-protocol.md +0 -553
- package/references/multi-agent-protocol/docs/agent-iam-integration.md +0 -877
- package/references/multi-agent-protocol/docs/agentic-mesh-integration-draft.md +0 -459
- package/references/multi-agent-protocol/docs/git-transport-draft.md +0 -251
- package/references/multi-agent-protocol/docs-site/Gemfile +0 -22
- package/references/multi-agent-protocol/docs-site/README.md +0 -82
- package/references/multi-agent-protocol/docs-site/_config.yml +0 -91
- package/references/multi-agent-protocol/docs-site/_includes/head_custom.html +0 -20
- package/references/multi-agent-protocol/docs-site/_sass/color_schemes/map.scss +0 -42
- package/references/multi-agent-protocol/docs-site/_sass/custom/custom.scss +0 -34
- package/references/multi-agent-protocol/docs-site/examples/full-integration.md +0 -510
- package/references/multi-agent-protocol/docs-site/examples/index.md +0 -138
- package/references/multi-agent-protocol/docs-site/examples/simple-chat.md +0 -282
- package/references/multi-agent-protocol/docs-site/examples/task-queue.md +0 -399
- package/references/multi-agent-protocol/docs-site/getting-started/index.md +0 -98
- package/references/multi-agent-protocol/docs-site/getting-started/installation.md +0 -219
- package/references/multi-agent-protocol/docs-site/getting-started/overview.md +0 -172
- package/references/multi-agent-protocol/docs-site/getting-started/quickstart.md +0 -237
- package/references/multi-agent-protocol/docs-site/index.md +0 -136
- package/references/multi-agent-protocol/docs-site/protocol/authentication.md +0 -391
- package/references/multi-agent-protocol/docs-site/protocol/connection-model.md +0 -376
- package/references/multi-agent-protocol/docs-site/protocol/design.md +0 -284
- package/references/multi-agent-protocol/docs-site/protocol/error-handling.md +0 -312
- package/references/multi-agent-protocol/docs-site/protocol/federation.md +0 -449
- package/references/multi-agent-protocol/docs-site/protocol/index.md +0 -129
- package/references/multi-agent-protocol/docs-site/protocol/permissions.md +0 -398
- package/references/multi-agent-protocol/docs-site/protocol/streaming.md +0 -353
- package/references/multi-agent-protocol/docs-site/protocol/wire-protocol.md +0 -369
- package/references/multi-agent-protocol/docs-site/sdk/api/agent.md +0 -357
- package/references/multi-agent-protocol/docs-site/sdk/api/client.md +0 -380
- package/references/multi-agent-protocol/docs-site/sdk/api/index.md +0 -62
- package/references/multi-agent-protocol/docs-site/sdk/api/server.md +0 -453
- package/references/multi-agent-protocol/docs-site/sdk/api/types.md +0 -468
- package/references/multi-agent-protocol/docs-site/sdk/guides/agent.md +0 -375
- package/references/multi-agent-protocol/docs-site/sdk/guides/authentication.md +0 -405
- package/references/multi-agent-protocol/docs-site/sdk/guides/client.md +0 -352
- package/references/multi-agent-protocol/docs-site/sdk/guides/index.md +0 -89
- package/references/multi-agent-protocol/docs-site/sdk/guides/server.md +0 -360
- package/references/multi-agent-protocol/docs-site/sdk/guides/testing.md +0 -446
- package/references/multi-agent-protocol/docs-site/sdk/guides/transports.md +0 -363
- package/references/multi-agent-protocol/docs-site/sdk/index.md +0 -206
- package/references/multi-agent-protocol/package-lock.json +0 -3886
- package/references/multi-agent-protocol/package.json +0 -56
- package/references/multi-agent-protocol/schema/meta.json +0 -467
- package/references/multi-agent-protocol/schema/schema.json +0 -2558
|
@@ -1,543 +0,0 @@
|
|
|
1
|
-
"""Tests for ACPClientHandler."""
|
|
2
|
-
|
|
3
|
-
import asyncio
|
|
4
|
-
import tempfile
|
|
5
|
-
from pathlib import Path
|
|
6
|
-
from unittest.mock import AsyncMock
|
|
7
|
-
|
|
8
|
-
import pytest
|
|
9
|
-
|
|
10
|
-
from acp_factory.client_handler import ACPClientHandler
|
|
11
|
-
from acp_factory.types import ClientHandlers
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
def create_permission_request(
|
|
15
|
-
options: list[dict[str, str]],
|
|
16
|
-
session_id: str = "test-session",
|
|
17
|
-
) -> tuple[str, dict, list[dict]]:
|
|
18
|
-
"""Helper to create permission request parameters."""
|
|
19
|
-
tool_call = {
|
|
20
|
-
"toolCallId": "tool-1",
|
|
21
|
-
"title": "Test Tool",
|
|
22
|
-
"status": "pending",
|
|
23
|
-
}
|
|
24
|
-
formatted_options = [
|
|
25
|
-
{"kind": opt["kind"], "optionId": opt["optionId"], "name": opt["name"]}
|
|
26
|
-
for opt in options
|
|
27
|
-
]
|
|
28
|
-
return session_id, tool_call, formatted_options
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
class TestACPClientHandlerRequestPermission:
|
|
32
|
-
"""Tests for permission request handling."""
|
|
33
|
-
|
|
34
|
-
@pytest.mark.asyncio
|
|
35
|
-
async def test_should_auto_approve_by_selecting_allow_once_option(self) -> None:
|
|
36
|
-
"""Auto-approve mode selects allow_once option."""
|
|
37
|
-
handler = ACPClientHandler(permission_mode="auto-approve")
|
|
38
|
-
|
|
39
|
-
session_id, tool_call, options = create_permission_request([
|
|
40
|
-
{"kind": "allow_once", "optionId": "allow", "name": "Allow"},
|
|
41
|
-
{"kind": "reject_once", "optionId": "reject", "name": "Reject"},
|
|
42
|
-
])
|
|
43
|
-
|
|
44
|
-
result = await handler.request_permission(session_id, tool_call, options)
|
|
45
|
-
|
|
46
|
-
assert result["outcome"] == {"outcome": "selected", "optionId": "allow"}
|
|
47
|
-
|
|
48
|
-
@pytest.mark.asyncio
|
|
49
|
-
async def test_should_auto_approve_by_selecting_allow_always_option(self) -> None:
|
|
50
|
-
"""Auto-approve mode selects allow_always option."""
|
|
51
|
-
handler = ACPClientHandler(permission_mode="auto-approve")
|
|
52
|
-
|
|
53
|
-
session_id, tool_call, options = create_permission_request([
|
|
54
|
-
{"kind": "reject_once", "optionId": "reject", "name": "Reject"},
|
|
55
|
-
{"kind": "allow_always", "optionId": "allow-all", "name": "Allow Always"},
|
|
56
|
-
])
|
|
57
|
-
|
|
58
|
-
result = await handler.request_permission(session_id, tool_call, options)
|
|
59
|
-
|
|
60
|
-
assert result["outcome"] == {"outcome": "selected", "optionId": "allow-all"}
|
|
61
|
-
|
|
62
|
-
@pytest.mark.asyncio
|
|
63
|
-
async def test_should_auto_deny_by_selecting_reject_once_option(self) -> None:
|
|
64
|
-
"""Auto-deny mode selects reject_once option."""
|
|
65
|
-
handler = ACPClientHandler(permission_mode="auto-deny")
|
|
66
|
-
|
|
67
|
-
session_id, tool_call, options = create_permission_request([
|
|
68
|
-
{"kind": "allow_once", "optionId": "allow", "name": "Allow"},
|
|
69
|
-
{"kind": "reject_once", "optionId": "reject", "name": "Reject"},
|
|
70
|
-
])
|
|
71
|
-
|
|
72
|
-
result = await handler.request_permission(session_id, tool_call, options)
|
|
73
|
-
|
|
74
|
-
assert result["outcome"] == {"outcome": "selected", "optionId": "reject"}
|
|
75
|
-
|
|
76
|
-
@pytest.mark.asyncio
|
|
77
|
-
async def test_should_auto_deny_by_selecting_reject_always_option(self) -> None:
|
|
78
|
-
"""Auto-deny mode selects reject_always option."""
|
|
79
|
-
handler = ACPClientHandler(permission_mode="auto-deny")
|
|
80
|
-
|
|
81
|
-
session_id, tool_call, options = create_permission_request([
|
|
82
|
-
{"kind": "allow_once", "optionId": "allow", "name": "Allow"},
|
|
83
|
-
{"kind": "reject_always", "optionId": "reject-all", "name": "Reject Always"},
|
|
84
|
-
])
|
|
85
|
-
|
|
86
|
-
result = await handler.request_permission(session_id, tool_call, options)
|
|
87
|
-
|
|
88
|
-
assert result["outcome"] == {"outcome": "selected", "optionId": "reject-all"}
|
|
89
|
-
|
|
90
|
-
@pytest.mark.asyncio
|
|
91
|
-
async def test_should_use_callback_handler_in_callback_mode(self) -> None:
|
|
92
|
-
"""Callback mode delegates to handler."""
|
|
93
|
-
mock_handler = AsyncMock(return_value={
|
|
94
|
-
"outcome": {"outcome": "selected", "optionId": "custom"},
|
|
95
|
-
})
|
|
96
|
-
|
|
97
|
-
handlers = ClientHandlers(on_permission_request=mock_handler)
|
|
98
|
-
handler = ACPClientHandler(handlers=handlers, permission_mode="callback")
|
|
99
|
-
|
|
100
|
-
session_id, tool_call, options = create_permission_request([
|
|
101
|
-
{"kind": "allow_once", "optionId": "allow", "name": "Allow"},
|
|
102
|
-
])
|
|
103
|
-
|
|
104
|
-
result = await handler.request_permission(session_id, tool_call, options)
|
|
105
|
-
|
|
106
|
-
mock_handler.assert_called_once()
|
|
107
|
-
assert result["outcome"] == {"outcome": "selected", "optionId": "custom"}
|
|
108
|
-
|
|
109
|
-
@pytest.mark.asyncio
|
|
110
|
-
async def test_should_fallback_to_first_option_when_no_matching_option(self) -> None:
|
|
111
|
-
"""Falls back to first option when no matching option found."""
|
|
112
|
-
handler = ACPClientHandler(permission_mode="auto-approve")
|
|
113
|
-
|
|
114
|
-
# Only reject options available
|
|
115
|
-
session_id, tool_call, options = create_permission_request([
|
|
116
|
-
{"kind": "reject_once", "optionId": "reject", "name": "Reject"},
|
|
117
|
-
{"kind": "reject_always", "optionId": "reject-all", "name": "Reject Always"},
|
|
118
|
-
])
|
|
119
|
-
|
|
120
|
-
result = await handler.request_permission(session_id, tool_call, options)
|
|
121
|
-
|
|
122
|
-
# Should fallback to first option
|
|
123
|
-
assert result["outcome"] == {"outcome": "selected", "optionId": "reject"}
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
class TestACPClientHandlerInteractivePermission:
|
|
127
|
-
"""Tests for interactive permission mode."""
|
|
128
|
-
|
|
129
|
-
@pytest.mark.asyncio
|
|
130
|
-
async def test_should_emit_permission_request_to_session_stream(self) -> None:
|
|
131
|
-
"""Interactive mode emits permission request to stream."""
|
|
132
|
-
handler = ACPClientHandler(permission_mode="interactive")
|
|
133
|
-
stream = handler.get_session_stream("session-1")
|
|
134
|
-
|
|
135
|
-
session_id, tool_call, options = create_permission_request(
|
|
136
|
-
[
|
|
137
|
-
{"kind": "allow_once", "optionId": "allow", "name": "Allow"},
|
|
138
|
-
{"kind": "reject_once", "optionId": "reject", "name": "Reject"},
|
|
139
|
-
],
|
|
140
|
-
session_id="session-1",
|
|
141
|
-
)
|
|
142
|
-
|
|
143
|
-
# Start permission request (will block until responded)
|
|
144
|
-
permission_task = asyncio.create_task(
|
|
145
|
-
handler.request_permission(session_id, tool_call, options)
|
|
146
|
-
)
|
|
147
|
-
|
|
148
|
-
# Get the emitted update from the stream
|
|
149
|
-
update = await stream.__anext__()
|
|
150
|
-
|
|
151
|
-
assert update.session_update == "permission_request"
|
|
152
|
-
assert update.request_id.startswith("perm-")
|
|
153
|
-
assert update.session_id == "session-1"
|
|
154
|
-
assert update.tool_call["toolCallId"] == "tool-1"
|
|
155
|
-
assert len(update.options) == 2
|
|
156
|
-
|
|
157
|
-
# Respond to unblock the promise
|
|
158
|
-
handler.respond_to_permission(update.request_id, "allow")
|
|
159
|
-
result = await permission_task
|
|
160
|
-
|
|
161
|
-
assert result["outcome"] == {"outcome": "selected", "optionId": "allow"}
|
|
162
|
-
|
|
163
|
-
@pytest.mark.asyncio
|
|
164
|
-
async def test_should_handle_respond_to_permission_correctly(self) -> None:
|
|
165
|
-
"""respond_to_permission resolves pending request."""
|
|
166
|
-
handler = ACPClientHandler(permission_mode="interactive")
|
|
167
|
-
handler.get_session_stream("session-1") # Initialize stream
|
|
168
|
-
|
|
169
|
-
session_id, tool_call, options = create_permission_request(
|
|
170
|
-
[
|
|
171
|
-
{"kind": "allow_once", "optionId": "allow", "name": "Allow"},
|
|
172
|
-
{"kind": "reject_once", "optionId": "reject", "name": "Reject"},
|
|
173
|
-
],
|
|
174
|
-
session_id="session-1",
|
|
175
|
-
)
|
|
176
|
-
|
|
177
|
-
permission_task = asyncio.create_task(
|
|
178
|
-
handler.request_permission(session_id, tool_call, options)
|
|
179
|
-
)
|
|
180
|
-
|
|
181
|
-
# Wait a tick for the update to be pushed
|
|
182
|
-
await asyncio.sleep(0.01)
|
|
183
|
-
|
|
184
|
-
# Get pending permission IDs
|
|
185
|
-
pending_ids = handler.get_pending_permission_ids("session-1")
|
|
186
|
-
assert len(pending_ids) == 1
|
|
187
|
-
|
|
188
|
-
# Respond with reject
|
|
189
|
-
handler.respond_to_permission(pending_ids[0], "reject")
|
|
190
|
-
result = await permission_task
|
|
191
|
-
|
|
192
|
-
assert result["outcome"] == {"outcome": "selected", "optionId": "reject"}
|
|
193
|
-
|
|
194
|
-
@pytest.mark.asyncio
|
|
195
|
-
async def test_should_handle_cancel_permission_correctly(self) -> None:
|
|
196
|
-
"""cancel_permission cancels the pending request."""
|
|
197
|
-
handler = ACPClientHandler(permission_mode="interactive")
|
|
198
|
-
handler.get_session_stream("session-1")
|
|
199
|
-
|
|
200
|
-
session_id, tool_call, options = create_permission_request(
|
|
201
|
-
[{"kind": "allow_once", "optionId": "allow", "name": "Allow"}],
|
|
202
|
-
session_id="session-1",
|
|
203
|
-
)
|
|
204
|
-
|
|
205
|
-
permission_task = asyncio.create_task(
|
|
206
|
-
handler.request_permission(session_id, tool_call, options)
|
|
207
|
-
)
|
|
208
|
-
|
|
209
|
-
await asyncio.sleep(0.01)
|
|
210
|
-
|
|
211
|
-
pending_ids = handler.get_pending_permission_ids("session-1")
|
|
212
|
-
handler.cancel_permission(pending_ids[0])
|
|
213
|
-
|
|
214
|
-
result = await permission_task
|
|
215
|
-
assert result["outcome"] == {"outcome": "cancelled"}
|
|
216
|
-
|
|
217
|
-
def test_should_throw_error_when_responding_to_nonexistent_permission(self) -> None:
|
|
218
|
-
"""Throws error when responding to non-existent permission."""
|
|
219
|
-
handler = ACPClientHandler(permission_mode="interactive")
|
|
220
|
-
|
|
221
|
-
with pytest.raises(ValueError, match="No pending permission request with ID"):
|
|
222
|
-
handler.respond_to_permission("non-existent", "allow")
|
|
223
|
-
|
|
224
|
-
def test_should_throw_error_when_cancelling_nonexistent_permission(self) -> None:
|
|
225
|
-
"""Throws error when cancelling non-existent permission."""
|
|
226
|
-
handler = ACPClientHandler(permission_mode="interactive")
|
|
227
|
-
|
|
228
|
-
with pytest.raises(ValueError, match="No pending permission request with ID"):
|
|
229
|
-
handler.cancel_permission("non-existent")
|
|
230
|
-
|
|
231
|
-
@pytest.mark.asyncio
|
|
232
|
-
async def test_should_track_has_pending_permissions_correctly(self) -> None:
|
|
233
|
-
"""has_pending_permissions reflects state correctly."""
|
|
234
|
-
handler = ACPClientHandler(permission_mode="interactive")
|
|
235
|
-
handler.get_session_stream("session-1")
|
|
236
|
-
|
|
237
|
-
assert handler.has_pending_permissions() is False
|
|
238
|
-
|
|
239
|
-
session_id, tool_call, options = create_permission_request(
|
|
240
|
-
[{"kind": "allow_once", "optionId": "allow", "name": "Allow"}],
|
|
241
|
-
session_id="session-1",
|
|
242
|
-
)
|
|
243
|
-
|
|
244
|
-
permission_task = asyncio.create_task(
|
|
245
|
-
handler.request_permission(session_id, tool_call, options)
|
|
246
|
-
)
|
|
247
|
-
|
|
248
|
-
await asyncio.sleep(0.01)
|
|
249
|
-
assert handler.has_pending_permissions() is True
|
|
250
|
-
|
|
251
|
-
pending_ids = handler.get_pending_permission_ids("session-1")
|
|
252
|
-
handler.respond_to_permission(pending_ids[0], "allow")
|
|
253
|
-
await permission_task
|
|
254
|
-
|
|
255
|
-
assert handler.has_pending_permissions() is False
|
|
256
|
-
|
|
257
|
-
@pytest.mark.asyncio
|
|
258
|
-
async def test_should_handle_multiple_pending_permissions_for_different_sessions(
|
|
259
|
-
self,
|
|
260
|
-
) -> None:
|
|
261
|
-
"""Multiple pending permissions for different sessions work correctly."""
|
|
262
|
-
handler = ACPClientHandler(permission_mode="interactive")
|
|
263
|
-
handler.get_session_stream("session-1")
|
|
264
|
-
handler.get_session_stream("session-2")
|
|
265
|
-
|
|
266
|
-
_, tool_call1, options1 = create_permission_request(
|
|
267
|
-
[{"kind": "allow_once", "optionId": "allow", "name": "Allow"}],
|
|
268
|
-
session_id="session-1",
|
|
269
|
-
)
|
|
270
|
-
_, tool_call2, options2 = create_permission_request(
|
|
271
|
-
[{"kind": "allow_once", "optionId": "allow", "name": "Allow"}],
|
|
272
|
-
session_id="session-2",
|
|
273
|
-
)
|
|
274
|
-
|
|
275
|
-
task1 = asyncio.create_task(
|
|
276
|
-
handler.request_permission("session-1", tool_call1, options1)
|
|
277
|
-
)
|
|
278
|
-
task2 = asyncio.create_task(
|
|
279
|
-
handler.request_permission("session-2", tool_call2, options2)
|
|
280
|
-
)
|
|
281
|
-
|
|
282
|
-
await asyncio.sleep(0.01)
|
|
283
|
-
|
|
284
|
-
assert len(handler.get_pending_permission_ids("session-1")) == 1
|
|
285
|
-
assert len(handler.get_pending_permission_ids("session-2")) == 1
|
|
286
|
-
|
|
287
|
-
# Respond to session-1
|
|
288
|
-
ids1 = handler.get_pending_permission_ids("session-1")
|
|
289
|
-
handler.respond_to_permission(ids1[0], "allow")
|
|
290
|
-
await task1
|
|
291
|
-
|
|
292
|
-
assert len(handler.get_pending_permission_ids("session-1")) == 0
|
|
293
|
-
assert len(handler.get_pending_permission_ids("session-2")) == 1
|
|
294
|
-
|
|
295
|
-
# Respond to session-2
|
|
296
|
-
ids2 = handler.get_pending_permission_ids("session-2")
|
|
297
|
-
handler.respond_to_permission(ids2[0], "allow")
|
|
298
|
-
await task2
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
class TestACPClientHandlerSessionUpdate:
|
|
302
|
-
"""Tests for session update handling."""
|
|
303
|
-
|
|
304
|
-
@pytest.mark.asyncio
|
|
305
|
-
async def test_should_push_updates_to_session_stream(self) -> None:
|
|
306
|
-
"""Session updates are pushed to stream."""
|
|
307
|
-
handler = ACPClientHandler()
|
|
308
|
-
|
|
309
|
-
update = {
|
|
310
|
-
"sessionUpdate": "agent_message_chunk",
|
|
311
|
-
"content": {"type": "text", "text": "Hello"},
|
|
312
|
-
}
|
|
313
|
-
|
|
314
|
-
# Get stream before pushing
|
|
315
|
-
stream = handler.get_session_stream("session-1")
|
|
316
|
-
|
|
317
|
-
# Push update
|
|
318
|
-
await handler.session_update("session-1", update)
|
|
319
|
-
|
|
320
|
-
# End stream
|
|
321
|
-
handler.end_session_stream("session-1")
|
|
322
|
-
|
|
323
|
-
# Collect results
|
|
324
|
-
results = []
|
|
325
|
-
async for item in stream:
|
|
326
|
-
results.append(item)
|
|
327
|
-
|
|
328
|
-
assert len(results) == 1
|
|
329
|
-
assert results[0] == update
|
|
330
|
-
|
|
331
|
-
@pytest.mark.asyncio
|
|
332
|
-
async def test_should_handle_multiple_sessions_independently(self) -> None:
|
|
333
|
-
"""Multiple sessions have independent streams."""
|
|
334
|
-
handler = ACPClientHandler()
|
|
335
|
-
|
|
336
|
-
stream1 = handler.get_session_stream("session-1")
|
|
337
|
-
stream2 = handler.get_session_stream("session-2")
|
|
338
|
-
|
|
339
|
-
await handler.session_update(
|
|
340
|
-
"session-1",
|
|
341
|
-
{"sessionUpdate": "agent_message_chunk", "content": {"type": "text", "text": "S1"}},
|
|
342
|
-
)
|
|
343
|
-
await handler.session_update(
|
|
344
|
-
"session-2",
|
|
345
|
-
{"sessionUpdate": "agent_message_chunk", "content": {"type": "text", "text": "S2"}},
|
|
346
|
-
)
|
|
347
|
-
|
|
348
|
-
handler.end_session_stream("session-1")
|
|
349
|
-
handler.end_session_stream("session-2")
|
|
350
|
-
|
|
351
|
-
results1 = []
|
|
352
|
-
async for item in stream1:
|
|
353
|
-
results1.append(item)
|
|
354
|
-
|
|
355
|
-
results2 = []
|
|
356
|
-
async for item in stream2:
|
|
357
|
-
results2.append(item)
|
|
358
|
-
|
|
359
|
-
assert len(results1) == 1
|
|
360
|
-
assert len(results2) == 1
|
|
361
|
-
assert results1[0]["content"]["text"] == "S1"
|
|
362
|
-
assert results2[0]["content"]["text"] == "S2"
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
class TestACPClientHandlerFileOperations:
|
|
366
|
-
"""Tests for file operations."""
|
|
367
|
-
|
|
368
|
-
@pytest.mark.asyncio
|
|
369
|
-
async def test_should_use_custom_handler_for_read(self) -> None:
|
|
370
|
-
"""Custom handler is used for file read."""
|
|
371
|
-
mock_read = AsyncMock(return_value="custom content")
|
|
372
|
-
handlers = ClientHandlers(on_file_read=mock_read)
|
|
373
|
-
handler = ACPClientHandler(handlers=handlers)
|
|
374
|
-
|
|
375
|
-
result = await handler.read_text_file("/test/file.txt", "s1")
|
|
376
|
-
|
|
377
|
-
mock_read.assert_called_once_with("/test/file.txt")
|
|
378
|
-
assert result["content"] == "custom content"
|
|
379
|
-
|
|
380
|
-
@pytest.mark.asyncio
|
|
381
|
-
async def test_should_read_from_filesystem_by_default(self) -> None:
|
|
382
|
-
"""Default file read uses filesystem."""
|
|
383
|
-
handler = ACPClientHandler()
|
|
384
|
-
|
|
385
|
-
with tempfile.NamedTemporaryFile(mode="w", suffix=".txt", delete=False) as f:
|
|
386
|
-
f.write("test content")
|
|
387
|
-
temp_path = f.name
|
|
388
|
-
|
|
389
|
-
try:
|
|
390
|
-
result = await handler.read_text_file(temp_path, "s1")
|
|
391
|
-
assert result["content"] == "test content"
|
|
392
|
-
finally:
|
|
393
|
-
Path(temp_path).unlink()
|
|
394
|
-
|
|
395
|
-
@pytest.mark.asyncio
|
|
396
|
-
async def test_should_throw_error_when_file_read_fails(self) -> None:
|
|
397
|
-
"""Throws error when file read fails."""
|
|
398
|
-
handler = ACPClientHandler()
|
|
399
|
-
|
|
400
|
-
with pytest.raises(RuntimeError, match="Failed to read file"):
|
|
401
|
-
await handler.read_text_file("/nonexistent/path/file.txt", "s1")
|
|
402
|
-
|
|
403
|
-
@pytest.mark.asyncio
|
|
404
|
-
async def test_should_use_custom_handler_for_write(self) -> None:
|
|
405
|
-
"""Custom handler is used for file write."""
|
|
406
|
-
mock_write = AsyncMock()
|
|
407
|
-
handlers = ClientHandlers(on_file_write=mock_write)
|
|
408
|
-
handler = ACPClientHandler(handlers=handlers)
|
|
409
|
-
|
|
410
|
-
result = await handler.write_text_file("/test/file.txt", "test content", "s1")
|
|
411
|
-
|
|
412
|
-
mock_write.assert_called_once_with("/test/file.txt", "test content")
|
|
413
|
-
assert result == {}
|
|
414
|
-
|
|
415
|
-
@pytest.mark.asyncio
|
|
416
|
-
async def test_should_write_to_filesystem_by_default(self) -> None:
|
|
417
|
-
"""Default file write uses filesystem."""
|
|
418
|
-
handler = ACPClientHandler()
|
|
419
|
-
|
|
420
|
-
with tempfile.NamedTemporaryFile(mode="w", suffix=".txt", delete=False) as f:
|
|
421
|
-
temp_path = f.name
|
|
422
|
-
|
|
423
|
-
try:
|
|
424
|
-
await handler.write_text_file(temp_path, "written content", "s1")
|
|
425
|
-
assert Path(temp_path).read_text() == "written content"
|
|
426
|
-
finally:
|
|
427
|
-
Path(temp_path).unlink()
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
class TestACPClientHandlerTerminalOperations:
|
|
431
|
-
"""Tests for terminal operations."""
|
|
432
|
-
|
|
433
|
-
@pytest.mark.asyncio
|
|
434
|
-
async def test_should_throw_error_when_create_terminal_handler_not_provided(
|
|
435
|
-
self,
|
|
436
|
-
) -> None:
|
|
437
|
-
"""Throws error when create_terminal handler not provided."""
|
|
438
|
-
handler = ACPClientHandler()
|
|
439
|
-
|
|
440
|
-
with pytest.raises(RuntimeError, match="no on_terminal_create handler provided"):
|
|
441
|
-
await handler.create_terminal("ls", "s1", cwd="/tmp")
|
|
442
|
-
|
|
443
|
-
@pytest.mark.asyncio
|
|
444
|
-
async def test_should_throw_error_when_terminal_output_handler_not_provided(
|
|
445
|
-
self,
|
|
446
|
-
) -> None:
|
|
447
|
-
"""Throws error when terminal_output handler not provided."""
|
|
448
|
-
handler = ACPClientHandler()
|
|
449
|
-
|
|
450
|
-
with pytest.raises(RuntimeError, match="no on_terminal_output handler provided"):
|
|
451
|
-
await handler.terminal_output("s1", "term-1")
|
|
452
|
-
|
|
453
|
-
@pytest.mark.asyncio
|
|
454
|
-
async def test_should_throw_error_when_kill_terminal_handler_not_provided(
|
|
455
|
-
self,
|
|
456
|
-
) -> None:
|
|
457
|
-
"""Throws error when kill_terminal handler not provided."""
|
|
458
|
-
handler = ACPClientHandler()
|
|
459
|
-
|
|
460
|
-
with pytest.raises(RuntimeError, match="no on_terminal_kill handler provided"):
|
|
461
|
-
await handler.kill_terminal("s1", "term-1")
|
|
462
|
-
|
|
463
|
-
@pytest.mark.asyncio
|
|
464
|
-
async def test_should_throw_error_when_release_terminal_handler_not_provided(
|
|
465
|
-
self,
|
|
466
|
-
) -> None:
|
|
467
|
-
"""Throws error when release_terminal handler not provided."""
|
|
468
|
-
handler = ACPClientHandler()
|
|
469
|
-
|
|
470
|
-
with pytest.raises(RuntimeError, match="no on_terminal_release handler provided"):
|
|
471
|
-
await handler.release_terminal("s1", "term-1")
|
|
472
|
-
|
|
473
|
-
@pytest.mark.asyncio
|
|
474
|
-
async def test_should_throw_error_when_wait_for_terminal_exit_handler_not_provided(
|
|
475
|
-
self,
|
|
476
|
-
) -> None:
|
|
477
|
-
"""Throws error when wait_for_terminal_exit handler not provided."""
|
|
478
|
-
handler = ACPClientHandler()
|
|
479
|
-
|
|
480
|
-
with pytest.raises(
|
|
481
|
-
RuntimeError, match="no on_terminal_wait_for_exit handler provided"
|
|
482
|
-
):
|
|
483
|
-
await handler.wait_for_terminal_exit("s1", "term-1")
|
|
484
|
-
|
|
485
|
-
@pytest.mark.asyncio
|
|
486
|
-
async def test_should_delegate_to_create_terminal_handler(self) -> None:
|
|
487
|
-
"""Delegates to create_terminal handler."""
|
|
488
|
-
mock_create = AsyncMock(return_value={"terminalId": "term-123"})
|
|
489
|
-
handlers = ClientHandlers(on_terminal_create=mock_create)
|
|
490
|
-
handler = ACPClientHandler(handlers=handlers)
|
|
491
|
-
|
|
492
|
-
result = await handler.create_terminal("ls", "s1", cwd="/tmp")
|
|
493
|
-
|
|
494
|
-
mock_create.assert_called_once()
|
|
495
|
-
assert result == {"terminalId": "term-123"}
|
|
496
|
-
|
|
497
|
-
@pytest.mark.asyncio
|
|
498
|
-
async def test_should_delegate_to_terminal_output_handler(self) -> None:
|
|
499
|
-
"""Delegates to terminal_output handler."""
|
|
500
|
-
mock_output = AsyncMock(return_value="output text")
|
|
501
|
-
handlers = ClientHandlers(on_terminal_output=mock_output)
|
|
502
|
-
handler = ACPClientHandler(handlers=handlers)
|
|
503
|
-
|
|
504
|
-
result = await handler.terminal_output("s1", "term-1")
|
|
505
|
-
|
|
506
|
-
mock_output.assert_called_once_with("term-1")
|
|
507
|
-
assert result == {"output": "output text", "truncated": False}
|
|
508
|
-
|
|
509
|
-
@pytest.mark.asyncio
|
|
510
|
-
async def test_should_delegate_to_wait_for_terminal_exit_handler(self) -> None:
|
|
511
|
-
"""Delegates to wait_for_terminal_exit handler."""
|
|
512
|
-
mock_wait = AsyncMock(return_value=0)
|
|
513
|
-
handlers = ClientHandlers(on_terminal_wait_for_exit=mock_wait)
|
|
514
|
-
handler = ACPClientHandler(handlers=handlers)
|
|
515
|
-
|
|
516
|
-
result = await handler.wait_for_terminal_exit("s1", "term-1")
|
|
517
|
-
|
|
518
|
-
mock_wait.assert_called_once_with("term-1")
|
|
519
|
-
assert result == {"exitCode": 0}
|
|
520
|
-
|
|
521
|
-
@pytest.mark.asyncio
|
|
522
|
-
async def test_should_delegate_to_kill_terminal_handler(self) -> None:
|
|
523
|
-
"""Delegates to kill_terminal handler."""
|
|
524
|
-
mock_kill = AsyncMock()
|
|
525
|
-
handlers = ClientHandlers(on_terminal_kill=mock_kill)
|
|
526
|
-
handler = ACPClientHandler(handlers=handlers)
|
|
527
|
-
|
|
528
|
-
result = await handler.kill_terminal("s1", "term-1")
|
|
529
|
-
|
|
530
|
-
mock_kill.assert_called_once_with("term-1")
|
|
531
|
-
assert result == {}
|
|
532
|
-
|
|
533
|
-
@pytest.mark.asyncio
|
|
534
|
-
async def test_should_delegate_to_release_terminal_handler(self) -> None:
|
|
535
|
-
"""Delegates to release_terminal handler."""
|
|
536
|
-
mock_release = AsyncMock()
|
|
537
|
-
handlers = ClientHandlers(on_terminal_release=mock_release)
|
|
538
|
-
handler = ACPClientHandler(handlers=handlers)
|
|
539
|
-
|
|
540
|
-
result = await handler.release_terminal("s1", "term-1")
|
|
541
|
-
|
|
542
|
-
mock_release.assert_called_once_with("term-1")
|
|
543
|
-
assert result == {}
|