groundswell 0.0.2 → 1.0.0
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/LICENSE +21 -0
- package/README.md +26 -9
- package/dist/cache/cache-key.d.ts +86 -0
- package/dist/cache/cache-key.d.ts.map +1 -0
- package/dist/cache/cache-key.js +204 -0
- package/dist/cache/cache-key.js.map +1 -0
- package/dist/cache/cache.d.ts +104 -0
- package/dist/cache/cache.d.ts.map +1 -0
- package/dist/cache/cache.js +179 -0
- package/dist/cache/cache.js.map +1 -0
- package/{src/cache/index.ts → dist/cache/index.d.ts} +1 -1
- package/dist/cache/index.d.ts.map +1 -0
- package/dist/cache/index.js +6 -0
- package/dist/cache/index.js.map +1 -0
- package/dist/core/agent.d.ts +203 -0
- package/dist/core/agent.d.ts.map +1 -0
- package/dist/core/agent.js +833 -0
- package/dist/core/agent.js.map +1 -0
- package/{src/core/context.ts → dist/core/context.d.ts} +16 -67
- package/dist/core/context.d.ts.map +1 -0
- package/dist/core/context.js +80 -0
- package/dist/core/context.js.map +1 -0
- package/dist/core/event-tree.d.ts +72 -0
- package/dist/core/event-tree.d.ts.map +1 -0
- package/dist/core/event-tree.js +211 -0
- package/dist/core/event-tree.js.map +1 -0
- package/{src/core/factory.ts → dist/core/factory.d.ts} +6 -27
- package/dist/core/factory.d.ts.map +1 -0
- package/dist/core/factory.js +110 -0
- package/dist/core/factory.js.map +1 -0
- package/{src/core/index.ts → dist/core/index.d.ts} +2 -10
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +9 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/logger.d.ts +50 -0
- package/dist/core/logger.d.ts.map +1 -0
- package/dist/core/logger.js +91 -0
- package/dist/core/logger.js.map +1 -0
- package/dist/core/mcp-handler.d.ts +127 -0
- package/dist/core/mcp-handler.d.ts.map +1 -0
- package/dist/core/mcp-handler.js +323 -0
- package/dist/core/mcp-handler.js.map +1 -0
- package/dist/core/prompt.d.ts +80 -0
- package/dist/core/prompt.d.ts.map +1 -0
- package/dist/core/prompt.js +120 -0
- package/dist/core/prompt.js.map +1 -0
- package/dist/core/workflow-context.d.ts +61 -0
- package/dist/core/workflow-context.d.ts.map +1 -0
- package/dist/core/workflow-context.js +358 -0
- package/dist/core/workflow-context.js.map +1 -0
- package/dist/core/workflow.d.ts +543 -0
- package/dist/core/workflow.d.ts.map +1 -0
- package/dist/core/workflow.js +986 -0
- package/dist/core/workflow.js.map +1 -0
- package/dist/debugger/event-replayer.d.ts +422 -0
- package/dist/debugger/event-replayer.d.ts.map +1 -0
- package/dist/debugger/event-replayer.js +639 -0
- package/dist/debugger/event-replayer.js.map +1 -0
- package/dist/debugger/index.d.ts +2 -0
- package/dist/debugger/index.d.ts.map +1 -0
- package/{src/debugger/index.ts → dist/debugger/index.js} +1 -0
- package/dist/debugger/index.js.map +1 -0
- package/dist/debugger/tree-debugger.d.ts +240 -0
- package/dist/debugger/tree-debugger.d.ts.map +1 -0
- package/dist/debugger/tree-debugger.js +620 -0
- package/dist/debugger/tree-debugger.js.map +1 -0
- package/dist/decorators/index.d.ts +4 -0
- package/dist/decorators/index.d.ts.map +1 -0
- package/{src/decorators/index.ts → dist/decorators/index.js} +1 -0
- package/dist/decorators/index.js.map +1 -0
- package/dist/decorators/observed-state.d.ts +32 -0
- package/dist/decorators/observed-state.d.ts.map +1 -0
- package/dist/decorators/observed-state.js +79 -0
- package/dist/decorators/observed-state.js.map +1 -0
- package/dist/decorators/step.d.ts +15 -0
- package/dist/decorators/step.d.ts.map +1 -0
- package/dist/decorators/step.js +192 -0
- package/dist/decorators/step.js.map +1 -0
- package/dist/decorators/task.d.ts +50 -0
- package/dist/decorators/task.d.ts.map +1 -0
- package/dist/decorators/task.js +118 -0
- package/dist/decorators/task.js.map +1 -0
- package/dist/examples/index.d.ts +3 -0
- package/dist/examples/index.d.ts.map +1 -0
- package/{src/examples/index.ts → dist/examples/index.js} +1 -0
- package/dist/examples/index.js.map +1 -0
- package/dist/examples/tdd-orchestrator.d.ts +15 -0
- package/dist/examples/tdd-orchestrator.d.ts.map +1 -0
- package/dist/examples/tdd-orchestrator.js +121 -0
- package/dist/examples/tdd-orchestrator.js.map +1 -0
- package/dist/examples/test-cycle-workflow.d.ts +14 -0
- package/dist/examples/test-cycle-workflow.d.ts.map +1 -0
- package/dist/examples/test-cycle-workflow.js +116 -0
- package/dist/examples/test-cycle-workflow.js.map +1 -0
- package/dist/harnesses/claude-code-harness.d.ts +391 -0
- package/dist/harnesses/claude-code-harness.d.ts.map +1 -0
- package/dist/harnesses/claude-code-harness.js +1076 -0
- package/dist/harnesses/claude-code-harness.js.map +1 -0
- package/dist/harnesses/harness-registry.d.ts +440 -0
- package/dist/harnesses/harness-registry.d.ts.map +1 -0
- package/dist/harnesses/harness-registry.js +543 -0
- package/dist/harnesses/harness-registry.js.map +1 -0
- package/dist/harnesses/index.d.ts +12 -0
- package/dist/harnesses/index.d.ts.map +1 -0
- package/dist/harnesses/index.js +11 -0
- package/dist/harnesses/index.js.map +1 -0
- package/dist/harnesses/pi-harness.d.ts +219 -0
- package/dist/harnesses/pi-harness.d.ts.map +1 -0
- package/dist/harnesses/pi-harness.js +676 -0
- package/dist/harnesses/pi-harness.js.map +1 -0
- package/dist/harnesses/pi-schema-converter.d.ts +24 -0
- package/dist/harnesses/pi-schema-converter.d.ts.map +1 -0
- package/dist/harnesses/pi-schema-converter.js +81 -0
- package/dist/harnesses/pi-schema-converter.js.map +1 -0
- package/dist/harnesses/register-defaults.d.ts +24 -0
- package/dist/harnesses/register-defaults.d.ts.map +1 -0
- package/dist/harnesses/register-defaults.js +40 -0
- package/dist/harnesses/register-defaults.js.map +1 -0
- package/dist/harnesses/session-store.d.ts +201 -0
- package/dist/harnesses/session-store.d.ts.map +1 -0
- package/dist/harnesses/session-store.js +254 -0
- package/dist/harnesses/session-store.js.map +1 -0
- package/dist/index.d.ts +37 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +57 -0
- package/dist/index.js.map +1 -0
- package/dist/reflection/index.d.ts +5 -0
- package/dist/reflection/index.d.ts.map +1 -0
- package/{src/reflection/index.ts → dist/reflection/index.js} +1 -1
- package/dist/reflection/index.js.map +1 -0
- package/dist/reflection/reflection.d.ts +84 -0
- package/dist/reflection/reflection.d.ts.map +1 -0
- package/dist/reflection/reflection.js +344 -0
- package/dist/reflection/reflection.js.map +1 -0
- package/dist/tools/index.d.ts +6 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +11 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/introspection.d.ts +165 -0
- package/dist/tools/introspection.d.ts.map +1 -0
- package/dist/tools/introspection.js +324 -0
- package/dist/tools/introspection.js.map +1 -0
- package/dist/types/agent.d.ts +1317 -0
- package/dist/types/agent.d.ts.map +1 -0
- package/dist/types/agent.js +423 -0
- package/dist/types/agent.js.map +1 -0
- package/dist/types/decorators.d.ts +40 -0
- package/dist/types/decorators.d.ts.map +1 -0
- package/dist/types/decorators.js +2 -0
- package/dist/types/decorators.js.map +1 -0
- package/dist/types/error-strategy.d.ts +13 -0
- package/dist/types/error-strategy.d.ts.map +1 -0
- package/dist/types/error-strategy.js +2 -0
- package/dist/types/error-strategy.js.map +1 -0
- package/dist/types/error.d.ts +20 -0
- package/dist/types/error.d.ts.map +1 -0
- package/dist/types/error.js +2 -0
- package/dist/types/error.js.map +1 -0
- package/dist/types/events.d.ts +113 -0
- package/dist/types/events.d.ts.map +1 -0
- package/dist/types/events.js +2 -0
- package/dist/types/events.js.map +1 -0
- package/dist/types/harnesses.d.ts +474 -0
- package/dist/types/harnesses.d.ts.map +1 -0
- package/dist/types/harnesses.js +2 -0
- package/dist/types/harnesses.js.map +1 -0
- package/dist/types/index.d.ts +23 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +8 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/logging.d.ts +24 -0
- package/dist/types/logging.d.ts.map +1 -0
- package/dist/types/logging.js +2 -0
- package/dist/types/logging.js.map +1 -0
- package/dist/types/observer.d.ts +18 -0
- package/dist/types/observer.d.ts.map +1 -0
- package/dist/types/observer.js +2 -0
- package/dist/types/observer.js.map +1 -0
- package/dist/types/prompt.d.ts +31 -0
- package/dist/types/prompt.d.ts.map +1 -0
- package/dist/types/prompt.js +6 -0
- package/dist/types/prompt.js.map +1 -0
- package/dist/types/providers.d.ts +691 -0
- package/dist/types/providers.d.ts.map +1 -0
- package/dist/types/providers.js +14 -0
- package/dist/types/providers.js.map +1 -0
- package/dist/types/reflection.d.ts +96 -0
- package/dist/types/reflection.d.ts.map +1 -0
- package/dist/types/reflection.js +24 -0
- package/dist/types/reflection.js.map +1 -0
- package/dist/types/restart.d.ts +132 -0
- package/dist/types/restart.d.ts.map +1 -0
- package/dist/types/restart.js +2 -0
- package/dist/types/restart.js.map +1 -0
- package/dist/types/sdk-primitives.d.ts +118 -0
- package/dist/types/sdk-primitives.d.ts.map +1 -0
- package/dist/types/sdk-primitives.js +6 -0
- package/dist/types/sdk-primitives.js.map +1 -0
- package/{src/types/snapshot.ts → dist/types/snapshot.d.ts} +5 -5
- package/dist/types/snapshot.d.ts.map +1 -0
- package/dist/types/snapshot.js +2 -0
- package/dist/types/snapshot.js.map +1 -0
- package/dist/types/streaming.d.ts +194 -0
- package/dist/types/streaming.d.ts.map +1 -0
- package/dist/types/streaming.js +67 -0
- package/dist/types/streaming.js.map +1 -0
- package/dist/types/workflow-context.d.ts +275 -0
- package/dist/types/workflow-context.d.ts.map +1 -0
- package/dist/types/workflow-context.js +8 -0
- package/dist/types/workflow-context.js.map +1 -0
- package/dist/types/workflow.d.ts +30 -0
- package/dist/types/workflow.d.ts.map +1 -0
- package/dist/types/workflow.js +2 -0
- package/dist/types/workflow.js.map +1 -0
- package/dist/utils/agent-validation.d.ts +88 -0
- package/dist/utils/agent-validation.d.ts.map +1 -0
- package/dist/utils/agent-validation.js +87 -0
- package/dist/utils/agent-validation.js.map +1 -0
- package/dist/utils/delay.d.ts +7 -0
- package/dist/utils/delay.d.ts.map +1 -0
- package/dist/utils/delay.js +9 -0
- package/dist/utils/delay.js.map +1 -0
- package/dist/utils/harness-config.d.ts +180 -0
- package/dist/utils/harness-config.d.ts.map +1 -0
- package/dist/utils/harness-config.js +311 -0
- package/dist/utils/harness-config.js.map +1 -0
- package/dist/utils/id.d.ts +6 -0
- package/dist/utils/id.d.ts.map +1 -0
- package/dist/utils/id.js +12 -0
- package/dist/utils/id.js.map +1 -0
- package/dist/utils/index.d.ts +13 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +11 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/model-spec.d.ts +110 -0
- package/dist/utils/model-spec.d.ts.map +1 -0
- package/dist/utils/model-spec.js +149 -0
- package/dist/utils/model-spec.js.map +1 -0
- package/dist/utils/observable.d.ts +54 -0
- package/dist/utils/observable.d.ts.map +1 -0
- package/dist/utils/observable.js +82 -0
- package/dist/utils/observable.js.map +1 -0
- package/dist/utils/provider-config.d.ts +10 -0
- package/dist/utils/provider-config.d.ts.map +1 -0
- package/dist/utils/provider-config.js +10 -0
- package/dist/utils/provider-config.js.map +1 -0
- package/dist/utils/restart-analysis.d.ts +202 -0
- package/dist/utils/restart-analysis.d.ts.map +1 -0
- package/dist/utils/restart-analysis.js +426 -0
- package/dist/utils/restart-analysis.js.map +1 -0
- package/dist/utils/session-serialization.d.ts +118 -0
- package/dist/utils/session-serialization.d.ts.map +1 -0
- package/dist/utils/session-serialization.js +217 -0
- package/dist/utils/session-serialization.js.map +1 -0
- package/dist/utils/workflow-error-utils.d.ts +22 -0
- package/dist/utils/workflow-error-utils.d.ts.map +1 -0
- package/dist/utils/workflow-error-utils.js +45 -0
- package/dist/utils/workflow-error-utils.js.map +1 -0
- package/package.json +34 -5
- package/.claude/commands/subtask-planning/prp-base-create.md +0 -120
- package/.claude/commands/subtask-planning/prp-base-execute.md +0 -65
- package/.claude/commands/task-breakdown.md +0 -94
- package/.claude/settings.local.json +0 -9
- package/.claude/system_prompts/task-breakdown.md +0 -101
- package/CHANGELOG.md +0 -188
- package/PRD.md +0 -543
- package/PRPs/001-hierarchical-workflow-engine.md +0 -2438
- package/PRPs/PRDs/002-agent-prompt.md +0 -390
- package/PRPs/PRDs/003-agent-prompt.md +0 -943
- package/PRPs/PRDs/004-agent-prompt.md +0 -1136
- package/PRPs/PRDs/tasks-001.json +0 -492
- package/PRPs/README.md +0 -83
- package/PRPs/templates/prp_base.md +0 -222
- package/docs/agent.md +0 -422
- package/docs/prompt.md +0 -419
- package/docs/workflow.md +0 -600
- package/examples/README.md +0 -258
- package/examples/examples/01-basic-workflow.ts +0 -100
- package/examples/examples/02-decorator-options.ts +0 -217
- package/examples/examples/03-parent-child.ts +0 -241
- package/examples/examples/04-observers-debugger.ts +0 -340
- package/examples/examples/05-error-handling.ts +0 -387
- package/examples/examples/06-concurrent-tasks.ts +0 -352
- package/examples/examples/07-agent-loops.ts +0 -432
- package/examples/examples/08-sdk-features.ts +0 -667
- package/examples/examples/09-reflection.ts +0 -573
- package/examples/examples/10-introspection.ts +0 -550
- package/examples/examples/11-reparenting-workflows.ts +0 -269
- package/examples/index.ts +0 -147
- package/examples/utils/helpers.ts +0 -57
- package/package-lock.json +0 -2398
- package/plan/001_d3bb02af4886/TEST_RESULTS.md +0 -259
- package/plan/001_d3bb02af4886/backlog.json +0 -867
- package/plan/001_d3bb02af4886/bug_fix_tasks.json +0 -484
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M1T1S1/PRP.md +0 -488
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M1T1S2/PRP.md +0 -581
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M1T1S3/PRP.md +0 -687
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M2T1S1/PRP.md +0 -492
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M2T1S3/PRP.md +0 -932
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M2T1S3/research/concurrent_error_testing_patterns.md +0 -1109
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M2T1S3/research/vitest_concurrent_testing.md +0 -802
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M2T1S3/research/workflow_engine_test_references.md +0 -603
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M2T2S1/PRP.md +0 -564
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M2T2S3/PRP.md +0 -518
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M2T2S4/PRP.md +0 -1252
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M2T3S1/PRP.md +0 -364
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M2T3S1/research/CODEBASE_INVENTORY.md +0 -114
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M2T3S1/research/DECORATOR_DOCUMENTATION_PATTERNS.md +0 -205
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M2T3S1/research/PRD_LOCATION_ANALYSIS.md +0 -199
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M2T3S1/research/ULTRATHINK_PRP_PLAN.md +0 -134
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M3T1S1/PRP.md +0 -495
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M3T1S1/research/console_error_inventory.md +0 -435
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M3T1S2/PRP.md +0 -506
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M3T1S3/PRP.md +0 -612
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M3T2S2/PRP.md +0 -558
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M3T2S2/research/external_research.md +0 -788
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M3T3S2/PRP.md +0 -460
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M3T3S3/PRP.md +0 -454
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M3T4S1/PRP.md +0 -520
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M3T4S1/RECOMMENDATION.md +0 -417
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M3T4S1/research/external_workflow_engines_research.md +0 -760
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M3T4S1/research/security_implications_analysis.md +0 -245
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M3T4S2/PRP.md +0 -792
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M4T1S1/PRP.md +0 -535
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M4T1S1/TEST_EXECUTION_REPORT.md +0 -190
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M4T1S2/PRP.md +0 -654
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M4T1S2/TEST_FIX_REPORT.md +0 -227
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M4T1S2/research/KEY_FINDINGS.md +0 -345
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M4T1S2/research/QUICK_REFERENCE.md +0 -193
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M4T1S2/research/test_maintenance_research.md +0 -1323
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M4T3S1/BREAKING_CHANGES_AUDIT.md +0 -1011
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M4T3S1/PRP.md +0 -927
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M4T3S2/PRP.md +0 -505
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/architecture/logger_child_signature_analysis.md +0 -401
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M1T1S3/child_implementation_research.md +0 -142
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M1T1S3/test_patterns_research.md +0 -112
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M1T1S3/vitest_patterns_research.md +0 -159
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M1T1S4/PRP.md +0 -549
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M1T1S4/VERIFICATION_REPORT.md +0 -368
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M1T1S4/edge_case_analysis.md +0 -172
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M1T1S4/usage_inventory.md +0 -175
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T1S2/PRP.md +0 -696
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T1S4/PRP.md +0 -860
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T2S2/PRP.md +0 -1066
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T2S2/research/01-testing-aggregated-errors.md +0 -1103
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T2S2/research/01_typescript_error_aggregation_patterns.md +0 -789
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T2S2/research/02-error-merge-strategy-testing-guide.md +0 -1098
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T2S2/research/02_aggregate_error_patterns.md +0 -1037
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T2S2/research/03-promise-allsettled-testing-patterns.md +0 -916
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T2S2/research/03_error_merging_strategies.md +0 -1045
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T2S2/research/04_github_stackoverflow_examples.md +0 -890
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T2S2/research/05_comprehensive_summary.md +0 -822
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T2S2/research/INDEX.md +0 -668
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T2S2/research/QUICK_REFERENCE.md +0 -706
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T2S2/research/README.md +0 -265
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T2S2/research/RESEARCH_REPORT.md +0 -655
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T2S4/research/vitest_testing_patterns.md +0 -1103
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T3S2/PRP.md +0 -426
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T1S2/PRP.md +0 -506
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T1S2/research/QUICK_REFERENCE.md +0 -114
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T1S2/research/RESEARCH_SUMMARY.md +0 -316
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T1S2/research/vitest_observer_error_logging_best_practices.md +0 -754
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T1S3/PRP.md +0 -612
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T2S1/PRP.md +0 -719
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T2S1/README.md +0 -215
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T2S1/analysis.md +0 -765
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T2S3/PRP.md +0 -718
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T3S1/DECISION.md +0 -149
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T3S1/PRP.md +0 -470
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T3S1/research/ULTRATHINK_PLAN.md +0 -332
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T3S1/research/codebase_workflow_name_analysis.md +0 -167
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T3S1/research/external_best_practices.md +0 -265
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T3S1/research/validation_patterns.md +0 -273
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T4S1/workflow_engine_ancestry_api_research.md +0 -760
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T4S3-PRP.md +0 -434
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M4T2S1/PRP.md +0 -717
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M4T2S2/PRP.md +0 -472
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M4T2S2/VALIDATION_REPORT.md +0 -125
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M4T2S2/research/ULTRATHINK_PRP_PLAN.md +0 -301
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/error-logging-best-practices.md +0 -1170
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/research_typescript_partial_and_overloads.md +0 -940
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/vitest-quick-reference.md +0 -151
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/vitest-research.md +0 -650
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/prd_snapshot.md +0 -259
- package/plan/001_d3bb02af4886/bugfix/P1M1T1S1/PRP.md +0 -457
- package/plan/001_d3bb02af4886/bugfix/RESEARCH_SUMMARY.md +0 -346
- package/plan/001_d3bb02af4886/bugfix/architecture/codebase_structure.md +0 -311
- package/plan/001_d3bb02af4886/bugfix/architecture/concurrent_execution_best_practices.md +0 -1565
- package/plan/001_d3bb02af4886/bugfix/architecture/error_handling_patterns.md +0 -288
- package/plan/001_d3bb02af4886/bugfix/architecture/promise_all_analysis.md +0 -741
- package/plan/001_d3bb02af4886/docs/PRP/P1M1T1S4-functional-workflow-error-state-capture-test.md +0 -652
- package/plan/001_d3bb02af4886/docs/PRP/P1P2-PRP.md +0 -527
- package/plan/001_d3bb02af4886/docs/PRP/P3P4-PRP.md +0 -1388
- package/plan/001_d3bb02af4886/docs/PRP/P4P5-PRP.md +0 -1136
- package/plan/001_d3bb02af4886/docs/PRP/PRP.md +0 -527
- package/plan/001_d3bb02af4886/docs/PRP/bugfix/P1M1T2S1-PRP.md +0 -415
- package/plan/001_d3bb02af4886/docs/PRP/bugfix/P1M1T2S2-PRP.md +0 -378
- package/plan/001_d3bb02af4886/docs/PRP/bugfix/P1M1T2S4-PRP.md +0 -713
- package/plan/001_d3bb02af4886/docs/PRP/bugfix/P1M2T1S4-PRP.md +0 -370
- package/plan/001_d3bb02af4886/docs/PRP_P1M3T1S3.md +0 -499
- package/plan/001_d3bb02af4886/docs/TEST_RESULTS.md +0 -230
- package/plan/001_d3bb02af4886/docs/architecture/external_deps.md +0 -358
- package/plan/001_d3bb02af4886/docs/architecture/system_context.md +0 -242
- package/plan/001_d3bb02af4886/docs/bugfix/ANALYSIS_PRD_VS_IMPLEMENTATION.md +0 -1134
- package/plan/001_d3bb02af4886/docs/bugfix/GAP_ANALYSIS_SUMMARY.md +0 -179
- package/plan/001_d3bb02af4886/docs/bugfix/P1M4T2S1/PRP.md +0 -629
- package/plan/001_d3bb02af4886/docs/bugfix/P1M4T2S1/validation-report.md +0 -214
- package/plan/001_d3bb02af4886/docs/bugfix/PRP_P1M4T2S3.md +0 -629
- package/plan/001_d3bb02af4886/docs/bugfix/bugfix_PRP.md +0 -529
- package/plan/001_d3bb02af4886/docs/bugfix/bugfix_QUICK_REFERENCE.md +0 -142
- package/plan/001_d3bb02af4886/docs/bugfix/bugfix_README.md +0 -304
- package/plan/001_d3bb02af4886/docs/bugfix/bugfix_TEST_RESULTS.md +0 -558
- package/plan/001_d3bb02af4886/docs/bugfix/bugfix_VALIDATION_SUMMARY.md +0 -256
- package/plan/001_d3bb02af4886/docs/bugfix/system_context.md +0 -346
- package/plan/001_d3bb02af4886/docs/bugfix-architecture/bug_analysis.md +0 -415
- package/plan/001_d3bb02af4886/docs/bugfix-architecture/implementation_patterns.md +0 -489
- package/plan/001_d3bb02af4886/docs/bugfix-architecture/system_context.md +0 -218
- package/plan/001_d3bb02af4886/docs/bugfix_INITIATION_SUMMARY.md +0 -380
- package/plan/001_d3bb02af4886/docs/research/CYCLE_DETECTION_PATTERNS.md +0 -1923
- package/plan/001_d3bb02af4886/docs/research/CYCLE_DETECTION_QUICK_REF.md +0 -319
- package/plan/001_d3bb02af4886/docs/research/P1M1T2S1/codebase-context.md +0 -115
- package/plan/001_d3bb02af4886/docs/research/P1M1T2S1/cycle-detection-algorithms.md +0 -134
- package/plan/001_d3bb02af4886/docs/research/P1M1T2S1/test-patterns.md +0 -153
- package/plan/001_d3bb02af4886/docs/research/P1M1T2S1/workflow-class.md +0 -132
- package/plan/001_d3bb02af4886/docs/research/P1M2T1S4/DECORATOR_DOCUMENTATION_BEST_PRACTICES.md +0 -716
- package/plan/001_d3bb02af4886/docs/research/P1M2T1S4/DECORATOR_DOCUMENTATION_QUICK_REF.md +0 -186
- package/plan/001_d3bb02af4886/docs/research/P1M2T1S4/GROUNDSWELL_DECORATOR_EXAMPLES.md +0 -604
- package/plan/001_d3bb02af4886/docs/research/P1M2T1S4/INDEX.md +0 -213
- package/plan/001_d3bb02af4886/docs/research/P1M2T1S4/codebase_structure.md +0 -30
- package/plan/001_d3bb02af4886/docs/research/P1M2T1S4/existing_test_pattern.md +0 -56
- package/plan/001_d3bb02af4886/docs/research/P1M2T1S4/getRootObservers_implementation.md +0 -53
- package/plan/001_d3bb02af4886/docs/research/P1M2T1S4/test_conventions.md +0 -49
- package/plan/001_d3bb02af4886/docs/research/P1M3T1S4/PRP.md +0 -958
- package/plan/001_d3bb02af4886/docs/research/P1M3T1S4/QUICK_REFERENCE.md +0 -339
- package/plan/001_d3bb02af4886/docs/research/P1M3T1S4/README.md +0 -305
- package/plan/001_d3bb02af4886/docs/research/P1M3T1S4/SUMMARY.md +0 -433
- package/plan/001_d3bb02af4886/docs/research/P1M3T1S4/bidirectional-tree-consistency-testing.md +0 -1574
- package/plan/001_d3bb02af4886/docs/research/P1M3T1S4/test-pattern-examples.md +0 -1014
- package/plan/001_d3bb02af4886/docs/research/P1P2/LRU_CACHE_BEST_PRACTICES.md +0 -1929
- package/plan/001_d3bb02af4886/docs/research/P1P2/LRU_CACHE_CODE_PATTERNS.md +0 -857
- package/plan/001_d3bb02af4886/docs/research/P1P2/LRU_CACHE_INTEGRATION_GUIDE.md +0 -738
- package/plan/001_d3bb02af4886/docs/research/P1P2/LRU_CACHE_RESEARCH_INDEX.md +0 -424
- package/plan/001_d3bb02af4886/docs/research/P1P2/REFLECTION_INDEX.md +0 -291
- package/plan/001_d3bb02af4886/docs/research/P1P2/REFLECTION_RESEARCH_REPORT.md +0 -1342
- package/plan/001_d3bb02af4886/docs/research/P1P2/RESEARCH_SUMMARY.md +0 -342
- package/plan/001_d3bb02af4886/docs/research/P1P2/anthropic-sdk.md +0 -174
- package/plan/001_d3bb02af4886/docs/research/P1P2/async-local-storage.md +0 -200
- package/plan/001_d3bb02af4886/docs/research/P1P2/reflection-code-patterns.md +0 -1205
- package/plan/001_d3bb02af4886/docs/research/P1P2/reflection-decision-matrix.md +0 -421
- package/plan/001_d3bb02af4886/docs/research/P1P2/reflection-implementation-guide.md +0 -1341
- package/plan/001_d3bb02af4886/docs/research/P1P2/reflection-integration-guide.md +0 -834
- package/plan/001_d3bb02af4886/docs/research/P1P2/reflection-patterns.md +0 -1468
- package/plan/001_d3bb02af4886/docs/research/P1P2/reflection-quick-reference.md +0 -558
- package/plan/001_d3bb02af4886/docs/research/P1P2/zod-schema.md +0 -152
- package/plan/001_d3bb02af4886/docs/research/P3P4/caching-lru.md +0 -116
- package/plan/001_d3bb02af4886/docs/research/P3P4/introspection-tools.md +0 -177
- package/plan/001_d3bb02af4886/docs/research/P3P4/reflection-patterns.md +0 -117
- package/plan/001_d3bb02af4886/docs/research/P4P5/RESEARCH_SUMMARY.md +0 -151
- package/plan/001_d3bb02af4886/docs/research/PROMISE_ALLSETTLED_QUICK_REF.md +0 -376
- package/plan/001_d3bb02af4886/docs/research/PROMISE_ALLSETTLED_RESEARCH.md +0 -1507
- package/plan/001_d3bb02af4886/docs/research/bugfix_typescript_patterns.md +0 -949
- package/plan/001_d3bb02af4886/docs/research/error-testing-research.md +0 -619
- package/plan/001_d3bb02af4886/docs/research/error_handling_patterns.md +0 -723
- package/plan/001_d3bb02af4886/docs/research/general/INTROSPECTION_RESEARCH_SUMMARY.md +0 -378
- package/plan/001_d3bb02af4886/docs/research/general/README-INTROSPECTION.md +0 -352
- package/plan/001_d3bb02af4886/docs/research/general/agent-introspection-patterns.md +0 -1085
- package/plan/001_d3bb02af4886/docs/research/general/introspection-security-guide.md +0 -984
- package/plan/001_d3bb02af4886/docs/research/general/introspection-tool-examples.md +0 -875
- package/plan/001_d3bb02af4886/docs/research/incremental-tree-map-updates/PRP_TEMPLATE.md +0 -460
- package/plan/001_d3bb02af4886/docs/research/incremental-tree-map-updates/QUICK_REFERENCE.md +0 -324
- package/plan/001_d3bb02af4886/docs/research/incremental-tree-map-updates/README.md +0 -175
- package/plan/001_d3bb02af4886/docs/research/incremental-tree-map-updates/RESEARCH_REPORT.md +0 -499
- package/plan/001_d3bb02af4886/docs/research/incremental-tree-map-updates/SUMMARY.md +0 -163
- package/plan/001_d3bb02af4886/prd_snapshot.md +0 -543
- package/plan/bugfix/BUG_FIX_SUMMARY.md +0 -961
- package/scripts/generate-llms-full.ts +0 -206
- package/src/__tests__/adversarial/attachChild-performance.test.ts +0 -216
- package/src/__tests__/adversarial/circular-reference.test.ts +0 -101
- package/src/__tests__/adversarial/complex-circular-reference.test.ts +0 -139
- package/src/__tests__/adversarial/concurrent-task-failures.test.ts +0 -571
- package/src/__tests__/adversarial/deep-analysis.test.ts +0 -729
- package/src/__tests__/adversarial/deep-hierarchy-stress.test.ts +0 -213
- package/src/__tests__/adversarial/e2e-prd-validation.test.ts +0 -448
- package/src/__tests__/adversarial/edge-case.test.ts +0 -703
- package/src/__tests__/adversarial/error-merge-strategy.test.ts +0 -760
- package/src/__tests__/adversarial/incremental-performance.test.ts +0 -140
- package/src/__tests__/adversarial/node-map-update-benchmarks.test.ts +0 -457
- package/src/__tests__/adversarial/observer-propagation.test.ts +0 -487
- package/src/__tests__/adversarial/parent-validation.test.ts +0 -143
- package/src/__tests__/adversarial/prd-12-2-compliance.test.ts +0 -611
- package/src/__tests__/adversarial/prd-compliance.test.ts +0 -731
- package/src/__tests__/compatibility/backward-compatibility.test.ts +0 -1572
- package/src/__tests__/helpers/index.ts +0 -18
- package/src/__tests__/helpers/tree-verification.ts +0 -257
- package/src/__tests__/integration/agent-workflow.test.ts +0 -256
- package/src/__tests__/integration/bidirectional-consistency.test.ts +0 -847
- package/src/__tests__/integration/observer-logging.test.ts +0 -643
- package/src/__tests__/integration/tree-mirroring.test.ts +0 -151
- package/src/__tests__/integration/workflow-reparenting.test.ts +0 -303
- package/src/__tests__/unit/agent.test.ts +0 -169
- package/src/__tests__/unit/cache-key.test.ts +0 -182
- package/src/__tests__/unit/cache.test.ts +0 -172
- package/src/__tests__/unit/context.test.ts +0 -217
- package/src/__tests__/unit/decorators.test.ts +0 -100
- package/src/__tests__/unit/introspection-tools.test.ts +0 -277
- package/src/__tests__/unit/logger.test.ts +0 -293
- package/src/__tests__/unit/observable.test.ts +0 -321
- package/src/__tests__/unit/prompt.test.ts +0 -135
- package/src/__tests__/unit/reflection.test.ts +0 -210
- package/src/__tests__/unit/tree-debugger-incremental.test.ts +0 -170
- package/src/__tests__/unit/tree-debugger.test.ts +0 -85
- package/src/__tests__/unit/utils/workflow-error-utils.test.ts +0 -209
- package/src/__tests__/unit/workflow-detachChild.test.ts +0 -100
- package/src/__tests__/unit/workflow-emitEvent-childDetached.test.ts +0 -153
- package/src/__tests__/unit/workflow-isDescendantOf.test.ts +0 -180
- package/src/__tests__/unit/workflow.test.ts +0 -357
- package/src/cache/cache-key.ts +0 -244
- package/src/cache/cache.ts +0 -236
- package/src/core/agent.ts +0 -593
- package/src/core/event-tree.ts +0 -260
- package/src/core/logger.ts +0 -112
- package/src/core/mcp-handler.ts +0 -184
- package/src/core/prompt.ts +0 -150
- package/src/core/workflow-context.ts +0 -351
- package/src/core/workflow.ts +0 -540
- package/src/debugger/tree-debugger.ts +0 -255
- package/src/decorators/observed-state.ts +0 -95
- package/src/decorators/step.ts +0 -139
- package/src/decorators/task.ts +0 -159
- package/src/examples/tdd-orchestrator.ts +0 -65
- package/src/examples/test-cycle-workflow.ts +0 -64
- package/src/index.ts +0 -142
- package/src/reflection/reflection.ts +0 -407
- package/src/tools/index.ts +0 -36
- package/src/tools/introspection.ts +0 -464
- package/src/types/agent.ts +0 -90
- package/src/types/decorators.ts +0 -32
- package/src/types/error-strategy.ts +0 -13
- package/src/types/error.ts +0 -20
- package/src/types/events.ts +0 -75
- package/src/types/index.ts +0 -55
- package/src/types/logging.ts +0 -24
- package/src/types/observer.ts +0 -18
- package/src/types/prompt.ts +0 -40
- package/src/types/reflection.ts +0 -117
- package/src/types/sdk-primitives.ts +0 -128
- package/src/types/workflow-context.ts +0 -163
- package/src/types/workflow.ts +0 -37
- package/src/utils/id.ts +0 -11
- package/src/utils/index.ts +0 -4
- package/src/utils/observable.ts +0 -106
- package/src/utils/workflow-error-utils.ts +0 -56
- package/tsconfig.json +0 -22
- package/vitest.config.ts +0 -16
|
@@ -0,0 +1,1076 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Claude Code harness implementation (PRD §7.1)
|
|
3
|
+
*
|
|
4
|
+
* Wraps the @anthropic-ai/claude-agent-sdk to provide Anthropic Claude
|
|
5
|
+
* model access through the unified Harness interface.
|
|
6
|
+
*
|
|
7
|
+
* ## Capabilities
|
|
8
|
+
*
|
|
9
|
+
* - **MCP**: Model Context Protocol integration via createSdkMcpServer
|
|
10
|
+
* - **Skills**: System prompt-based skill loading
|
|
11
|
+
* - **LSP**: Language Server Protocol via MCP plugins
|
|
12
|
+
* - **Streaming**: Streaming response support
|
|
13
|
+
* - **Sessions**: Session-based state via abstraction layer
|
|
14
|
+
* - **Extended Thinking**: maxThinkingTokens for extended reasoning
|
|
15
|
+
*
|
|
16
|
+
* ## SDK Integration
|
|
17
|
+
*
|
|
18
|
+
* Uses lazy loading for the Anthropic SDK. The SDK is imported dynamically
|
|
19
|
+
* in the initialize() method to support optional dependencies.
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* ```ts
|
|
23
|
+
* import { ClaudeCodeHarness } from 'groundswell';
|
|
24
|
+
*
|
|
25
|
+
* const harness = new ClaudeCodeHarness();
|
|
26
|
+
* await harness.initialize({ apiKey: 'sk-...' });
|
|
27
|
+
*
|
|
28
|
+
* const result = await harness.execute(
|
|
29
|
+
* { prompt: 'Hello, Claude!', options: {} },
|
|
30
|
+
* toolExecutor
|
|
31
|
+
* );
|
|
32
|
+
* ```
|
|
33
|
+
*
|
|
34
|
+
* @see {@link https://docs.anthropic.com/en/api/messages | Anthropic Messages API}
|
|
35
|
+
* @see {@link https://www.npmjs.com/package/@anthropic-ai/claude-agent-sdk | Agent SDK Package}
|
|
36
|
+
*/
|
|
37
|
+
import { createSuccessResponse, createErrorResponse, AGENT_ERROR_CODES } from "../types/agent.js";
|
|
38
|
+
import { MemorySessionStore, FileSessionStore, } from "./session-store.js";
|
|
39
|
+
import { MCPHandler } from "../core/mcp-handler.js";
|
|
40
|
+
import { parseModelSpec } from "../utils/model-spec.js";
|
|
41
|
+
import { readFile } from "fs/promises";
|
|
42
|
+
import { join } from "path";
|
|
43
|
+
/**
|
|
44
|
+
* Thrown when a harness receives a configuration it cannot honour — e.g. a model
|
|
45
|
+
* provider it cannot run (ClaudeCodeHarness + non-anthropic, PRD §7.8). Carries a
|
|
46
|
+
* machine-readable `code` (default `AGENT_ERROR_CODES.CONFIG_ERROR`) so callers and
|
|
47
|
+
* Agent retry logic can branch structurally rather than parsing message text.
|
|
48
|
+
*
|
|
49
|
+
* @see AGENT_ERROR_CODES
|
|
50
|
+
*/
|
|
51
|
+
export class ConfigError extends Error {
|
|
52
|
+
code;
|
|
53
|
+
details;
|
|
54
|
+
constructor(message, options = {}) {
|
|
55
|
+
super(message);
|
|
56
|
+
this.name = 'ConfigError';
|
|
57
|
+
this.code = options.code ?? AGENT_ERROR_CODES.CONFIG_ERROR;
|
|
58
|
+
this.details = options.details;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
export class ClaudeCodeHarness {
|
|
62
|
+
/**
|
|
63
|
+
* Unique harness identifier (PRD §7.2)
|
|
64
|
+
*
|
|
65
|
+
* @readonly
|
|
66
|
+
*/
|
|
67
|
+
id = "claude-code";
|
|
68
|
+
/**
|
|
69
|
+
* Provider capability flags
|
|
70
|
+
*
|
|
71
|
+
* Anthropic SDK v0.1.77 capabilities:
|
|
72
|
+
* - MCP via createSdkMcpServer
|
|
73
|
+
* - Skills via system prompt
|
|
74
|
+
* - LSP via MCP plugins
|
|
75
|
+
* - Streaming responses
|
|
76
|
+
* - No native sessions (stateless)
|
|
77
|
+
* - Extended thinking via maxThinkingTokens
|
|
78
|
+
*
|
|
79
|
+
* @readonly
|
|
80
|
+
*/
|
|
81
|
+
capabilities = {
|
|
82
|
+
/** MCP server connections via createSdkMcpServer */
|
|
83
|
+
mcp: true,
|
|
84
|
+
/** Skill loading via system prompt */
|
|
85
|
+
skills: true,
|
|
86
|
+
/** LSP integration via MCP plugins */
|
|
87
|
+
lsp: true,
|
|
88
|
+
/** Streaming response support */
|
|
89
|
+
streaming: true,
|
|
90
|
+
/** Session-based state (via abstraction layer) */
|
|
91
|
+
sessions: true,
|
|
92
|
+
/** Extended thinking via maxThinkingTokens */
|
|
93
|
+
extendedThinking: true,
|
|
94
|
+
};
|
|
95
|
+
/**
|
|
96
|
+
* Check if a specific capability is supported
|
|
97
|
+
*
|
|
98
|
+
* @param capability - The capability to check
|
|
99
|
+
* @returns true if the capability is supported
|
|
100
|
+
*/
|
|
101
|
+
supports(capability) {
|
|
102
|
+
return this.capabilities[capability];
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Check if all specified features are supported
|
|
106
|
+
*
|
|
107
|
+
* @param features - Array of capability keys to check
|
|
108
|
+
* @returns true if all features are supported
|
|
109
|
+
*/
|
|
110
|
+
requiresFeatures(features) {
|
|
111
|
+
return features.every(f => this.capabilities[f]);
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Anthropic SDK module (lazy loaded)
|
|
115
|
+
*
|
|
116
|
+
* Dynamically imported in initialize() to support optional dependencies.
|
|
117
|
+
* Typed using typeof import() pattern for accurate module types.
|
|
118
|
+
*
|
|
119
|
+
* @internal
|
|
120
|
+
*/
|
|
121
|
+
sdk = null;
|
|
122
|
+
/**
|
|
123
|
+
* MCP handler for server registration and tool management
|
|
124
|
+
*
|
|
125
|
+
* Manages MCP server connections and converts tools to SDK format.
|
|
126
|
+
* Created on first use and reused for subsequent registrations.
|
|
127
|
+
*
|
|
128
|
+
* @internal
|
|
129
|
+
*/
|
|
130
|
+
mcpHandler = new MCPHandler();
|
|
131
|
+
/**
|
|
132
|
+
* SDK MCP server configuration for use in execute()
|
|
133
|
+
*
|
|
134
|
+
* Stores the converted SDK server config from registerMCPs().
|
|
135
|
+
* Used in sdkOptions.mcpServers during execute() calls.
|
|
136
|
+
*
|
|
137
|
+
* @internal
|
|
138
|
+
*/
|
|
139
|
+
mcpServerConfig = null;
|
|
140
|
+
/**
|
|
141
|
+
* Combined skills prompt for injection into system prompts
|
|
142
|
+
*
|
|
143
|
+
* Stores the formatted skills content from loadSkills() for injection
|
|
144
|
+
* into system prompts during execute() calls. Skills are combined with
|
|
145
|
+
* markdown headers and separators.
|
|
146
|
+
*
|
|
147
|
+
* @internal
|
|
148
|
+
*/
|
|
149
|
+
skillsPrompt = "";
|
|
150
|
+
/**
|
|
151
|
+
* Session storage backend
|
|
152
|
+
*
|
|
153
|
+
* Manages session state using pluggable storage backends. Defaults to
|
|
154
|
+
* in-memory storage but can be configured with file-based, Redis, or
|
|
155
|
+
* custom implementations via ProviderOptions or setSessionStore().
|
|
156
|
+
*
|
|
157
|
+
* @internal
|
|
158
|
+
*/
|
|
159
|
+
sessionStore = new MemorySessionStore();
|
|
160
|
+
/**
|
|
161
|
+
* Session TTL in milliseconds from ProviderOptions
|
|
162
|
+
*
|
|
163
|
+
* @internal
|
|
164
|
+
*/
|
|
165
|
+
sessionTtl;
|
|
166
|
+
/**
|
|
167
|
+
* Initialize the Anthropic provider
|
|
168
|
+
*
|
|
169
|
+
* Loads the Anthropic SDK and initializes the client.
|
|
170
|
+
*
|
|
171
|
+
* @param options - Optional provider configuration (apiKey, endpoint, sessionPersistence, etc.)
|
|
172
|
+
* @remarks Session storage defaults to MemorySessionStore if not specified.
|
|
173
|
+
* Implemented in P2.M1.T1.S2
|
|
174
|
+
*/
|
|
175
|
+
async initialize(options) {
|
|
176
|
+
// Idempotent check: if SDK is already loaded, return immediately
|
|
177
|
+
if (this.sdk) {
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
// Dynamic import of the Anthropic SDK for lazy loading
|
|
181
|
+
// This allows optional dependencies and faster startup
|
|
182
|
+
try {
|
|
183
|
+
this.sdk = await import("@anthropic-ai/claude-agent-sdk");
|
|
184
|
+
}
|
|
185
|
+
catch (error) {
|
|
186
|
+
// Rethrow with descriptive message for ProviderRegistry to track
|
|
187
|
+
throw new Error(`Failed to load @anthropic-ai/claude-agent-sdk: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
188
|
+
}
|
|
189
|
+
// Validate import succeeded
|
|
190
|
+
if (!this.sdk) {
|
|
191
|
+
throw new Error("Failed to load @anthropic-ai/claude-agent-sdk: Import returned null");
|
|
192
|
+
}
|
|
193
|
+
// Handle session store configuration
|
|
194
|
+
// Priority: sessionStore (direct injection) > sessionPersistence (declarative)
|
|
195
|
+
if (options?.sessionStore) {
|
|
196
|
+
// Direct injection (backward compatibility)
|
|
197
|
+
this.sessionStore = options.sessionStore;
|
|
198
|
+
// Store sessionTtl for cleanup operations
|
|
199
|
+
this.sessionTtl = options.sessionTtl ?? 86400000; // 24 hours default
|
|
200
|
+
}
|
|
201
|
+
else if (options?.sessionPersistence) {
|
|
202
|
+
// Create SessionStore from sessionPersistence option
|
|
203
|
+
switch (options.sessionPersistence) {
|
|
204
|
+
case "memory":
|
|
205
|
+
this.sessionStore = new MemorySessionStore();
|
|
206
|
+
break;
|
|
207
|
+
case "file": {
|
|
208
|
+
const path = options.sessionPath ?? "./sessions";
|
|
209
|
+
const ttl = options.sessionTtl ?? 86400000; // 24 hours default
|
|
210
|
+
this.sessionTtl = ttl;
|
|
211
|
+
this.sessionStore = new FileSessionStore(path, ttl);
|
|
212
|
+
break;
|
|
213
|
+
}
|
|
214
|
+
case "redis":
|
|
215
|
+
throw new Error('Redis session storage not yet implemented. Use sessionPersistence: "memory" or "file", or provide a custom sessionStore instance.');
|
|
216
|
+
default: {
|
|
217
|
+
// Exhaustive check - TypeScript will error if missing case
|
|
218
|
+
const _exhaustiveCheck = options.sessionPersistence;
|
|
219
|
+
throw new Error(`Unknown session persistence type: ${_exhaustiveCheck}`);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
else {
|
|
224
|
+
// If neither sessionStore nor sessionPersistence provided, keep existing default (MemorySessionStore)
|
|
225
|
+
this.sessionTtl = options?.sessionTtl ?? 86400000; // 24 hours default
|
|
226
|
+
}
|
|
227
|
+
// Restore sessions from persistent store (non-memory stores)
|
|
228
|
+
// For persistent stores (File, Redis, custom), verify the store is accessible
|
|
229
|
+
if (!(this.sessionStore instanceof MemorySessionStore)) {
|
|
230
|
+
const sessionIds = await this.sessionStore.list();
|
|
231
|
+
// Sessions are already in store - no need to load into memory
|
|
232
|
+
// Just verify store is accessible by listing sessions
|
|
233
|
+
// Cleanup expired sessions on initialization for persistent stores
|
|
234
|
+
if (this.sessionTtl !== undefined && 'deleteExpired' in this.sessionStore) {
|
|
235
|
+
const deletedIds = await this.sessionStore.deleteExpired(this.sessionTtl);
|
|
236
|
+
if (deletedIds.length > 0) {
|
|
237
|
+
// Log cleanup (optional, for debugging)
|
|
238
|
+
console.debug(`Cleaned up ${deletedIds.length} expired sessions`);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
// Note: Options are stored for later use in execute() method
|
|
243
|
+
// The actual SDK client creation happens when execute() is called
|
|
244
|
+
// This is because SDK may need different clients per-request (e.g., custom endpoint)
|
|
245
|
+
//
|
|
246
|
+
// Relevant options for Anthropic (stored implicitly via options parameter):
|
|
247
|
+
// - options.apiKey: Will be used in execute() for SDK client
|
|
248
|
+
// - options.endpoint: Will be used in execute() for custom endpoint
|
|
249
|
+
// - options.timeout: Will be used in execute() for request timeout
|
|
250
|
+
// - options.headers: Will be used in execute() for custom headers
|
|
251
|
+
// - options.sessionStore: Configured above for persistent storage
|
|
252
|
+
// - options.sessionPersistence: Creates appropriate SessionStore instance
|
|
253
|
+
// - options.sessionPath: Custom path for FileSessionStore
|
|
254
|
+
// - options.sessionTtl: Reserved for future TTL enforcement (P2.M2.T2.S2)
|
|
255
|
+
//
|
|
256
|
+
// Note: No internal initialization flag needed - ProviderRegistry manages state externally
|
|
257
|
+
}
|
|
258
|
+
/**
|
|
259
|
+
* Terminate the provider and cleanup resources
|
|
260
|
+
*
|
|
261
|
+
* Clears the SDK module reference to allow garbage collection.
|
|
262
|
+
* The Anthropic SDK is stateless and manages its own resources internally.
|
|
263
|
+
*
|
|
264
|
+
* @remarks
|
|
265
|
+
* Implemented in P2.M1.T1.S3
|
|
266
|
+
*/
|
|
267
|
+
async terminate() {
|
|
268
|
+
// Idempotent check: if SDK is already null, return immediately
|
|
269
|
+
// FOLLOW: initialize() pattern at lines 107-110 (if (this.sdk) { return; })
|
|
270
|
+
if (this.sdk === null) {
|
|
271
|
+
return;
|
|
272
|
+
}
|
|
273
|
+
// Clear SDK reference to allow garbage collection
|
|
274
|
+
// CRITICAL: No other cleanup needed - SDK is stateless (see research/anthropic_sdk_cleanup.md)
|
|
275
|
+
// CRITICAL: SDK manages its own resources - Query objects auto-cleanup on completion
|
|
276
|
+
// CRITICAL: ProviderRegistry manages initialization state externally
|
|
277
|
+
this.sdk = null;
|
|
278
|
+
// Clear MCP server configuration (from P2.M1.T1.S7)
|
|
279
|
+
this.mcpServerConfig = null;
|
|
280
|
+
// Clear skills prompt (from P2.M1.T1.S8)
|
|
281
|
+
this.skillsPrompt = "";
|
|
282
|
+
// Clear session storage only for MemorySessionStore
|
|
283
|
+
// Persistent stores (File, Redis, custom) keep sessions after termination
|
|
284
|
+
if (this.sessionStore instanceof MemorySessionStore) {
|
|
285
|
+
await this.sessionStore.clear();
|
|
286
|
+
}
|
|
287
|
+
// For persistent stores, sessions remain in storage
|
|
288
|
+
// GOTCHA: No return value needed - Promise<void> is implicit
|
|
289
|
+
// GOTCHA: No throws possible from null check and assignment
|
|
290
|
+
}
|
|
291
|
+
/**
|
|
292
|
+
* Execute a prompt request
|
|
293
|
+
*
|
|
294
|
+
* Constructs the SDK query from ProviderRequest and executes it via the Anthropic SDK.
|
|
295
|
+
*
|
|
296
|
+
* When options.streaming is true, returns an AsyncGenerator that yields StreamEvent objects.
|
|
297
|
+
* When options.streaming is false or undefined, returns a complete AgentResponse.
|
|
298
|
+
*
|
|
299
|
+
* @param request - Provider request with prompt and options
|
|
300
|
+
* @param toolExecutor - Callback for executing tools (used in P2.M1.T1.S6)
|
|
301
|
+
* @param hooks - Optional lifecycle hooks (adapter in P2.M1.T2.S1)
|
|
302
|
+
* @returns Typed agent response or AsyncGenerator for streaming
|
|
303
|
+
* @throws {ConfigError} (code CONFIG_ERROR) if request.options.model resolves to a
|
|
304
|
+
* non-anthropic provider (PRD §7.8) — enforced via normalizeModel.
|
|
305
|
+
* @remarks
|
|
306
|
+
* P2.M1.T1.S5: Query construction - builds AgentSDKOptions and calls SDK query()
|
|
307
|
+
* P2.M1.T1.S6: Message iteration - iterates AsyncGenerator and builds AgentResponse
|
|
308
|
+
* Streaming: Returns AsyncGenerator<StreamEvent> when options.streaming = true
|
|
309
|
+
*/
|
|
310
|
+
execute(request, toolExecutor, hooks) {
|
|
311
|
+
// STREAMING MODE: Check if streaming is enabled
|
|
312
|
+
// When options.streaming is true, return an AsyncGenerator that yields StreamEvent objects
|
|
313
|
+
if (request.options.streaming) {
|
|
314
|
+
// PATTERN: SDK initialization check (follow initialize() pattern at lines 107-110)
|
|
315
|
+
// CRITICAL: Validate SDK is loaded before attempting to use it
|
|
316
|
+
if (!this.sdk) {
|
|
317
|
+
throw new Error("SDK not initialized. Call initialize() first.");
|
|
318
|
+
}
|
|
319
|
+
return this.executeStreaming(request, toolExecutor, hooks);
|
|
320
|
+
}
|
|
321
|
+
// NON-STREAMING MODE: Wrap in async IIFE to return Promise<AgentResponse<T>>
|
|
322
|
+
// Note: This function is not 'async' because it needs to return either Promise or AsyncGenerator
|
|
323
|
+
// The non-streaming path is wrapped in an async IIFE to return a Promise
|
|
324
|
+
return (async () => {
|
|
325
|
+
// PATTERN: SDK initialization check (follow initialize() pattern at lines 107-110)
|
|
326
|
+
// CRITICAL: Validate SDK is loaded before attempting to use it
|
|
327
|
+
if (!this.sdk) {
|
|
328
|
+
throw new Error("SDK not initialized. Call initialize() first.");
|
|
329
|
+
}
|
|
330
|
+
// P2.M2.T1.S2: Session detection and retrieval
|
|
331
|
+
// Extract sessionId from request options and retrieve session state
|
|
332
|
+
const sessionId = request.options.sessionId;
|
|
333
|
+
let session;
|
|
334
|
+
let isContinuation = false;
|
|
335
|
+
if (sessionId) {
|
|
336
|
+
session = await this.getSession(sessionId);
|
|
337
|
+
// Check if this is a continuation (existing history)
|
|
338
|
+
// Only continue if session exists and has history
|
|
339
|
+
if (session && session.history.length > 0) {
|
|
340
|
+
isContinuation = true;
|
|
341
|
+
}
|
|
342
|
+
// P2.M2.T1.S2: Create session if it doesn't exist (lazy session creation)
|
|
343
|
+
// Session will be populated with user messages during message iteration
|
|
344
|
+
if (!session) {
|
|
345
|
+
await this.createSession(sessionId);
|
|
346
|
+
session = await this.getSession(sessionId);
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
// PATTERN: Model resolution using normalizeModel()
|
|
350
|
+
// FROM: src/harnesses/anthropic-provider.ts:246-259
|
|
351
|
+
// Default model from src/core/agent.ts:320
|
|
352
|
+
const modelSpec = this.normalizeModel(request.options.model ?? "claude-sonnet-4-20250514");
|
|
353
|
+
// PATTERN: Convert Provider hooks to SDK hooks
|
|
354
|
+
// Adapts ProviderHookEvents to SDK-compatible format for use in query()
|
|
355
|
+
const sdkHooks = this.buildAgentSDKHooks(hooks);
|
|
356
|
+
// PATTERN: AgentSDKOptions construction (EXACT pattern from src/core/agent.ts:397-426)
|
|
357
|
+
// CRITICAL: Map ProviderRequest fields to SDK Options format
|
|
358
|
+
const sdkOptions = {
|
|
359
|
+
// Model mapping
|
|
360
|
+
model: modelSpec.model,
|
|
361
|
+
// System prompt mapping (from src/core/agent.ts:317-318)
|
|
362
|
+
// CRITICAL: Inject loaded skills via buildSystemPromptWithSkills() helper
|
|
363
|
+
systemPrompt: this.buildSystemPromptWithSkills(request.options.systemPrompt),
|
|
364
|
+
// P2.M2.T1.S2: Continue flag for session continuation
|
|
365
|
+
// CRITICAL: When continuing, SDK expects continue: true AND streamInput() with history
|
|
366
|
+
...(isContinuation && { continue: true }),
|
|
367
|
+
// Tools mapping to allowedTools (string[])
|
|
368
|
+
// CRITICAL: Map tool objects to tool names (from src/core/agent.ts:405-407)
|
|
369
|
+
...(request.options.tools &&
|
|
370
|
+
request.options.tools.length > 0 && {
|
|
371
|
+
allowedTools: request.options.tools.map((t) => t.name),
|
|
372
|
+
}),
|
|
373
|
+
// MCP servers integration (from P2.M1.T1.S7)
|
|
374
|
+
// Include registered MCP servers if available
|
|
375
|
+
...(this.mcpServerConfig && {
|
|
376
|
+
mcpServers: {
|
|
377
|
+
"groundswell-mcp": this.mcpServerConfig,
|
|
378
|
+
},
|
|
379
|
+
}),
|
|
380
|
+
// Hooks integration (from P2.M1.T2.S1)
|
|
381
|
+
// Include converted hooks if any were mapped
|
|
382
|
+
...(Object.keys(sdkHooks).length > 0 && {
|
|
383
|
+
hooks: sdkHooks,
|
|
384
|
+
}),
|
|
385
|
+
};
|
|
386
|
+
// PATTERN: Start time tracking for duration calculation
|
|
387
|
+
// FROM: src/core/agent.ts line 406
|
|
388
|
+
const startTime = Date.now();
|
|
389
|
+
// PATTERN: SDK query() call (EXACT pattern from src/core/agent.ts:431)
|
|
390
|
+
// CRITICAL: query() returns AsyncGenerator<SDKMessage> (not Promise!)
|
|
391
|
+
// Do NOT await the query() call - it returns the generator synchronously
|
|
392
|
+
// P2.M2.T1.S2: For continuation, use empty prompt (history comes via streamInput)
|
|
393
|
+
const queryResult = this.sdk.query({
|
|
394
|
+
prompt: isContinuation ? "" : request.prompt,
|
|
395
|
+
options: sdkOptions,
|
|
396
|
+
});
|
|
397
|
+
// P2.M2.T1.S2: Stream session history for continuation
|
|
398
|
+
// CRITICAL: continue: true alone is insufficient - must also call streamInput() with history
|
|
399
|
+
if (isContinuation && session) {
|
|
400
|
+
await queryResult.streamInput((async function* historyStream() {
|
|
401
|
+
for (const msg of session.history) {
|
|
402
|
+
yield msg;
|
|
403
|
+
}
|
|
404
|
+
})());
|
|
405
|
+
// Stream new user message for continuation
|
|
406
|
+
// CRITICAL: New message also goes via streamInput(), not prompt parameter
|
|
407
|
+
await queryResult.streamInput((async function* newMessageStream() {
|
|
408
|
+
yield {
|
|
409
|
+
type: "user",
|
|
410
|
+
message: { content: request.prompt },
|
|
411
|
+
parent_tool_use_id: null,
|
|
412
|
+
session_id: session.history[0]?.session_id ?? "",
|
|
413
|
+
};
|
|
414
|
+
})());
|
|
415
|
+
}
|
|
416
|
+
// PATTERN: Message iteration and AgentResponse construction
|
|
417
|
+
// FROM: src/core/agent.ts lines 437-492
|
|
418
|
+
let resultMessage = null;
|
|
419
|
+
let toolCallCount = 0;
|
|
420
|
+
// Iterate over the AsyncGenerator of SDK messages
|
|
421
|
+
for await (const message of queryResult) {
|
|
422
|
+
// Count tool uses from assistant messages
|
|
423
|
+
if (message.type === "assistant") {
|
|
424
|
+
const content = message.message?.content;
|
|
425
|
+
if (Array.isArray(content)) {
|
|
426
|
+
for (const block of content) {
|
|
427
|
+
if (block.type === "tool_use") {
|
|
428
|
+
toolCallCount++;
|
|
429
|
+
// Note: Hooks adapter will be implemented in P2.M1.T2.S1
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
// P2.M2.T1.S2: Capture user messages and append to session history
|
|
435
|
+
// CRITICAL: User messages must be accumulated for next turn's streamInput()
|
|
436
|
+
if (message.type === "user" && session && sessionId) {
|
|
437
|
+
session.history.push(message);
|
|
438
|
+
// CRITICAL: Save back to store for persistent stores
|
|
439
|
+
// FileSessionStore returns copies - must save after mutation
|
|
440
|
+
if (!(this.sessionStore instanceof MemorySessionStore)) {
|
|
441
|
+
await this.sessionStore.save(sessionId, session);
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
// Capture the final result message
|
|
445
|
+
if (message.type === "result") {
|
|
446
|
+
resultMessage =
|
|
447
|
+
message;
|
|
448
|
+
// P2.M2.T1.S2: Update session lastResult with latest execution result
|
|
449
|
+
if (session && sessionId) {
|
|
450
|
+
session.lastResult = resultMessage;
|
|
451
|
+
// CRITICAL: Save back to store for persistent stores
|
|
452
|
+
if (!(this.sessionStore instanceof MemorySessionStore)) {
|
|
453
|
+
await this.sessionStore.save(sessionId, session);
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
// Calculate duration from start time
|
|
459
|
+
const duration = Date.now() - startTime;
|
|
460
|
+
// Handle missing result message
|
|
461
|
+
if (!resultMessage) {
|
|
462
|
+
return createErrorResponse("INVALID_RESPONSE_FORMAT", "No result message received from Agent SDK", { duration }, false);
|
|
463
|
+
}
|
|
464
|
+
// Handle error subtypes (error_during_execution, error_max_turns)
|
|
465
|
+
if (resultMessage.subtype !== "success") {
|
|
466
|
+
const errorResult = resultMessage;
|
|
467
|
+
return createErrorResponse("EXECUTION_FAILED", `Agent SDK execution failed: ${errorResult.subtype}`, {
|
|
468
|
+
errors: errorResult.errors ?? [],
|
|
469
|
+
subtype: errorResult.subtype,
|
|
470
|
+
}, errorResult.subtype === "error_max_turns");
|
|
471
|
+
}
|
|
472
|
+
// Extract usage from result
|
|
473
|
+
const usage = {
|
|
474
|
+
input_tokens: resultMessage.usage?.input_tokens ?? 0,
|
|
475
|
+
output_tokens: resultMessage.usage?.output_tokens ?? 0,
|
|
476
|
+
};
|
|
477
|
+
// Extract data from result (prefer structured_output, fallback to result)
|
|
478
|
+
const data = (resultMessage.structured_output ??
|
|
479
|
+
resultMessage.result);
|
|
480
|
+
// Return success response with metadata
|
|
481
|
+
return createSuccessResponse(data, {
|
|
482
|
+
agentId: this.id,
|
|
483
|
+
timestamp: Date.now(),
|
|
484
|
+
duration,
|
|
485
|
+
usage,
|
|
486
|
+
toolCalls: toolCallCount,
|
|
487
|
+
});
|
|
488
|
+
})();
|
|
489
|
+
}
|
|
490
|
+
/**
|
|
491
|
+
* Execute a prompt request with streaming
|
|
492
|
+
*
|
|
493
|
+
* Returns an AsyncGenerator that yields StreamEvent objects during execution.
|
|
494
|
+
* Implements streaming mode for real-time response generation.
|
|
495
|
+
*
|
|
496
|
+
* @param request - Provider request with prompt and options
|
|
497
|
+
* @param toolExecutor - Callback for executing tools
|
|
498
|
+
* @param hooks - Optional lifecycle hooks
|
|
499
|
+
* @returns AsyncGenerator yielding StreamEvent objects, returning final AgentResponse
|
|
500
|
+
* @private
|
|
501
|
+
* @remarks
|
|
502
|
+
* Streaming mode implementation following PRP P4.M2.T1.S4 specification.
|
|
503
|
+
*/
|
|
504
|
+
async *executeStreaming(request, toolExecutor, hooks) {
|
|
505
|
+
// SDK initialization check (required by TypeScript strict mode)
|
|
506
|
+
// The caller (execute) already checks this, but we need to assert here
|
|
507
|
+
// for TypeScript's control flow analysis across method boundaries
|
|
508
|
+
if (!this.sdk) {
|
|
509
|
+
throw new Error("SDK not initialized. Call initialize() first.");
|
|
510
|
+
}
|
|
511
|
+
// P2.M2.T1.S2: Session detection and retrieval
|
|
512
|
+
const sessionId = request.options.sessionId;
|
|
513
|
+
let session;
|
|
514
|
+
let isContinuation = false;
|
|
515
|
+
if (sessionId) {
|
|
516
|
+
session = await this.getSession(sessionId);
|
|
517
|
+
if (session && session.history.length > 0) {
|
|
518
|
+
isContinuation = true;
|
|
519
|
+
}
|
|
520
|
+
if (!session) {
|
|
521
|
+
await this.createSession(sessionId);
|
|
522
|
+
session = await this.getSession(sessionId);
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
// Model resolution
|
|
526
|
+
const modelSpec = this.normalizeModel(request.options.model ?? "claude-sonnet-4-20250514");
|
|
527
|
+
// Build SDK hooks
|
|
528
|
+
const sdkHooks = this.buildAgentSDKHooks(hooks);
|
|
529
|
+
// Build SDK options
|
|
530
|
+
const sdkOptions = {
|
|
531
|
+
model: modelSpec.model,
|
|
532
|
+
systemPrompt: this.buildSystemPromptWithSkills(request.options.systemPrompt),
|
|
533
|
+
...(isContinuation && { continue: true }),
|
|
534
|
+
...(request.options.tools &&
|
|
535
|
+
request.options.tools.length > 0 && {
|
|
536
|
+
allowedTools: request.options.tools.map((t) => t.name),
|
|
537
|
+
}),
|
|
538
|
+
...(this.mcpServerConfig && {
|
|
539
|
+
mcpServers: {
|
|
540
|
+
"groundswell-mcp": this.mcpServerConfig,
|
|
541
|
+
},
|
|
542
|
+
}),
|
|
543
|
+
...(Object.keys(sdkHooks).length > 0 && {
|
|
544
|
+
hooks: sdkHooks,
|
|
545
|
+
}),
|
|
546
|
+
};
|
|
547
|
+
const startTime = Date.now();
|
|
548
|
+
// Yield metadata event first
|
|
549
|
+
yield {
|
|
550
|
+
type: "metadata",
|
|
551
|
+
metadata: {
|
|
552
|
+
requestId: `${this.id}-${Date.now()}`,
|
|
553
|
+
model: modelSpec.model,
|
|
554
|
+
provider: modelSpec.provider,
|
|
555
|
+
},
|
|
556
|
+
};
|
|
557
|
+
// Create SDK query
|
|
558
|
+
const queryResult = this.sdk.query({
|
|
559
|
+
prompt: isContinuation ? "" : request.prompt,
|
|
560
|
+
options: sdkOptions,
|
|
561
|
+
});
|
|
562
|
+
// Stream session history for continuation
|
|
563
|
+
if (isContinuation && session) {
|
|
564
|
+
await queryResult.streamInput((async function* historyStream() {
|
|
565
|
+
for (const msg of session.history) {
|
|
566
|
+
yield msg;
|
|
567
|
+
}
|
|
568
|
+
})());
|
|
569
|
+
await queryResult.streamInput((async function* newMessageStream() {
|
|
570
|
+
yield {
|
|
571
|
+
type: "user",
|
|
572
|
+
message: { content: request.prompt },
|
|
573
|
+
parent_tool_use_id: null,
|
|
574
|
+
session_id: session.history[0]?.session_id ?? "",
|
|
575
|
+
};
|
|
576
|
+
})());
|
|
577
|
+
}
|
|
578
|
+
let resultMessage = null;
|
|
579
|
+
let toolCallCount = 0;
|
|
580
|
+
let fullText = "";
|
|
581
|
+
let textIndex = 0;
|
|
582
|
+
// Iterate over the AsyncGenerator of SDK messages
|
|
583
|
+
for await (const message of queryResult) {
|
|
584
|
+
// Process assistant messages for text content
|
|
585
|
+
if (message.type === "assistant") {
|
|
586
|
+
const content = message.message?.content;
|
|
587
|
+
if (Array.isArray(content)) {
|
|
588
|
+
for (const block of content) {
|
|
589
|
+
if (block.type === "text") {
|
|
590
|
+
// Yield text delta event
|
|
591
|
+
const text = block.text;
|
|
592
|
+
if (text && text !== fullText) {
|
|
593
|
+
const delta = text.slice(fullText.length);
|
|
594
|
+
fullText = text;
|
|
595
|
+
yield {
|
|
596
|
+
type: "text_delta",
|
|
597
|
+
delta,
|
|
598
|
+
index: textIndex++,
|
|
599
|
+
};
|
|
600
|
+
}
|
|
601
|
+
}
|
|
602
|
+
else if (block.type === "tool_use") {
|
|
603
|
+
toolCallCount++;
|
|
604
|
+
// Yield tool call start event
|
|
605
|
+
yield {
|
|
606
|
+
type: "tool_call_start",
|
|
607
|
+
id: block.id,
|
|
608
|
+
name: block.name,
|
|
609
|
+
index: 0,
|
|
610
|
+
};
|
|
611
|
+
// Tool execution happens via SDK, toolExecutor is called through hooks
|
|
612
|
+
// Yield tool call done event
|
|
613
|
+
yield {
|
|
614
|
+
type: "tool_call_done",
|
|
615
|
+
id: block.id,
|
|
616
|
+
result: null, // Results come back in subsequent messages
|
|
617
|
+
};
|
|
618
|
+
}
|
|
619
|
+
}
|
|
620
|
+
}
|
|
621
|
+
}
|
|
622
|
+
// Capture user messages for session history
|
|
623
|
+
if (message.type === "user" && session && sessionId) {
|
|
624
|
+
session.history.push(message);
|
|
625
|
+
// CRITICAL: Save back to store for persistent stores
|
|
626
|
+
if (!(this.sessionStore instanceof MemorySessionStore)) {
|
|
627
|
+
await this.sessionStore.save(sessionId, session);
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
// Capture the final result message
|
|
631
|
+
if (message.type === "result") {
|
|
632
|
+
resultMessage =
|
|
633
|
+
message;
|
|
634
|
+
if (session && sessionId) {
|
|
635
|
+
session.lastResult = resultMessage;
|
|
636
|
+
// CRITICAL: Save back to store for persistent stores
|
|
637
|
+
if (!(this.sessionStore instanceof MemorySessionStore)) {
|
|
638
|
+
await this.sessionStore.save(sessionId, session);
|
|
639
|
+
}
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
const duration = Date.now() - startTime;
|
|
644
|
+
// Handle missing result message
|
|
645
|
+
if (!resultMessage) {
|
|
646
|
+
yield {
|
|
647
|
+
type: "error",
|
|
648
|
+
error: new Error("No result message received from Agent SDK"),
|
|
649
|
+
code: "INVALID_RESPONSE_FORMAT",
|
|
650
|
+
retryable: false,
|
|
651
|
+
};
|
|
652
|
+
throw new Error("No result message received from Agent SDK");
|
|
653
|
+
}
|
|
654
|
+
// Handle error subtypes
|
|
655
|
+
if (resultMessage.subtype !== "success") {
|
|
656
|
+
const errorResult = resultMessage;
|
|
657
|
+
yield {
|
|
658
|
+
type: "error",
|
|
659
|
+
error: new Error(`Agent SDK execution failed: ${errorResult.subtype}`),
|
|
660
|
+
code: "EXECUTION_FAILED",
|
|
661
|
+
retryable: errorResult.subtype === "error_max_turns",
|
|
662
|
+
};
|
|
663
|
+
throw new Error(`Agent SDK execution failed: ${errorResult.subtype}`);
|
|
664
|
+
}
|
|
665
|
+
// Yield usage event
|
|
666
|
+
if (resultMessage.usage) {
|
|
667
|
+
yield {
|
|
668
|
+
type: "usage",
|
|
669
|
+
inputTokens: resultMessage.usage.input_tokens ?? 0,
|
|
670
|
+
outputTokens: resultMessage.usage.output_tokens ?? 0,
|
|
671
|
+
cacheTokens: resultMessage.usage.cache_read_tokens ??
|
|
672
|
+
resultMessage.usage.cache_write_tokens,
|
|
673
|
+
};
|
|
674
|
+
}
|
|
675
|
+
// Yield done event
|
|
676
|
+
yield {
|
|
677
|
+
type: "done",
|
|
678
|
+
finishReason: "stop",
|
|
679
|
+
};
|
|
680
|
+
// Extract data and return final AgentResponse
|
|
681
|
+
const data = (resultMessage.structured_output ?? resultMessage.result);
|
|
682
|
+
return createSuccessResponse(data, {
|
|
683
|
+
agentId: this.id,
|
|
684
|
+
timestamp: Date.now(),
|
|
685
|
+
duration,
|
|
686
|
+
usage: {
|
|
687
|
+
input_tokens: resultMessage.usage?.input_tokens ?? 0,
|
|
688
|
+
output_tokens: resultMessage.usage?.output_tokens ?? 0,
|
|
689
|
+
},
|
|
690
|
+
toolCalls: toolCallCount,
|
|
691
|
+
});
|
|
692
|
+
}
|
|
693
|
+
/**
|
|
694
|
+
* Register MCP servers and return available tools
|
|
695
|
+
*
|
|
696
|
+
* Registers MCP servers with the internal MCPHandler and returns
|
|
697
|
+
* discovered tools in MCP format. Also converts tools to SDK format
|
|
698
|
+
* and stores the configuration for use in execute().
|
|
699
|
+
*
|
|
700
|
+
* @param servers - Array of MCP server configurations (required)
|
|
701
|
+
* @returns Array of discovered tools in MCP format (serverName__toolName)
|
|
702
|
+
* @remarks Modifies internal MCP handler state, converts tools to SDK format.
|
|
703
|
+
* Implemented in P2.M1.T1.S7
|
|
704
|
+
*
|
|
705
|
+
* @example
|
|
706
|
+
* ```ts
|
|
707
|
+
* const provider = new AnthropicProvider();
|
|
708
|
+
* await provider.initialize();
|
|
709
|
+
*
|
|
710
|
+
* const tools = await provider.registerMCPs([
|
|
711
|
+
* {
|
|
712
|
+
* name: 'filesystem',
|
|
713
|
+
* transport: 'inprocess',
|
|
714
|
+
* tools: [
|
|
715
|
+
* {
|
|
716
|
+
* name: 'read_file',
|
|
717
|
+
* description: 'Read a file',
|
|
718
|
+
* input_schema: {
|
|
719
|
+
* type: 'object',
|
|
720
|
+
* properties: { path: { type: 'string' } },
|
|
721
|
+
* required: ['path']
|
|
722
|
+
* }
|
|
723
|
+
* }
|
|
724
|
+
* ]
|
|
725
|
+
* }
|
|
726
|
+
* ]);
|
|
727
|
+
*
|
|
728
|
+
* console.log(tools); // [{ name: 'filesystem__read_file', ... }]
|
|
729
|
+
* ```
|
|
730
|
+
*/
|
|
731
|
+
async registerMCPs(servers) {
|
|
732
|
+
// PATTERN: SDK initialization check (follow execute() pattern at lines 197-199)
|
|
733
|
+
// CRITICAL: Validate SDK is loaded before attempting to use it
|
|
734
|
+
if (!this.sdk) {
|
|
735
|
+
throw new Error("SDK not initialized. Call initialize() first.");
|
|
736
|
+
}
|
|
737
|
+
// Register each server with the MCPHandler
|
|
738
|
+
// MCPHandler will:
|
|
739
|
+
// - Validate server name uniqueness (throws if duplicate)
|
|
740
|
+
// - Register tools with fullName pattern: serverName__toolName
|
|
741
|
+
// - Create tool executors based on transport type
|
|
742
|
+
for (const server of servers) {
|
|
743
|
+
this.mcpHandler.registerServer(server);
|
|
744
|
+
}
|
|
745
|
+
// Convert to SDK format and store for execute() method
|
|
746
|
+
// toAgentSDKServer() returns McpServerConfig | null
|
|
747
|
+
const sdkConfig = this.mcpHandler.toAgentSDKServer();
|
|
748
|
+
if (sdkConfig) {
|
|
749
|
+
this.mcpServerConfig = sdkConfig;
|
|
750
|
+
}
|
|
751
|
+
// Return discovered tools in MCP format (NOT SDK format)
|
|
752
|
+
// Tools have: { name, description, input_schema }
|
|
753
|
+
// Tool names are prefixed: serverName__toolName
|
|
754
|
+
return this.mcpHandler.getTools();
|
|
755
|
+
}
|
|
756
|
+
/**
|
|
757
|
+
* Load skills into the provider
|
|
758
|
+
*
|
|
759
|
+
* Skills are read from SKILL.md files in each skill directory and combined
|
|
760
|
+
* into a formatted system prompt fragment for injection during execute().
|
|
761
|
+
*
|
|
762
|
+
* @param skills - Array of skill definitions with name and path (empty array clears existing skills)
|
|
763
|
+
* @throws {Error} When SDK is not initialized
|
|
764
|
+
* @throws {Error} When SKILL.md file cannot be read
|
|
765
|
+
* @remarks Each skill directory must contain a SKILL.md file. Skills are combined
|
|
766
|
+
* with markdown headers (### Skill Name) and separators (---).
|
|
767
|
+
*
|
|
768
|
+
* @example
|
|
769
|
+
* ```ts
|
|
770
|
+
* const provider = new AnthropicProvider();
|
|
771
|
+
* await provider.initialize();
|
|
772
|
+
* await provider.loadSkills([
|
|
773
|
+
* { name: 'math-expert', path: '/skills/math' },
|
|
774
|
+
* { name: 'code-reviewer', path: '/skills/code' }
|
|
775
|
+
* ]);
|
|
776
|
+
* ```
|
|
777
|
+
*/
|
|
778
|
+
async loadSkills(skills) {
|
|
779
|
+
// PATTERN: SDK initialization check (follow execute() pattern at lines 219-223)
|
|
780
|
+
// CRITICAL: Validate SDK is loaded before proceeding
|
|
781
|
+
if (!this.sdk) {
|
|
782
|
+
throw new Error("SDK not initialized. Call initialize() first.");
|
|
783
|
+
}
|
|
784
|
+
// Handle empty skills array - nothing to load
|
|
785
|
+
if (skills.length === 0) {
|
|
786
|
+
this.skillsPrompt = "";
|
|
787
|
+
return;
|
|
788
|
+
}
|
|
789
|
+
// Load each skill's SKILL.md content
|
|
790
|
+
const skillContents = [];
|
|
791
|
+
for (const skill of skills) {
|
|
792
|
+
try {
|
|
793
|
+
// GOTCHA: Skill.path is directory, must join with 'SKILL.md'
|
|
794
|
+
const skillMdPath = join(skill.path, "SKILL.md");
|
|
795
|
+
const content = await readFile(skillMdPath, "utf-8");
|
|
796
|
+
// Format skill with markdown header
|
|
797
|
+
skillContents.push(`### ${skill.name}\n\n${content.trim()}`);
|
|
798
|
+
}
|
|
799
|
+
catch (error) {
|
|
800
|
+
// PATTERN: Wrap errors with context (follow registerMCPs pattern)
|
|
801
|
+
throw new Error(`Failed to load skill '${skill.name}' from ${skill.path}: ` +
|
|
802
|
+
`${error instanceof Error ? error.message : "Unknown error"}`);
|
|
803
|
+
}
|
|
804
|
+
}
|
|
805
|
+
// Combine all skills with markdown separator
|
|
806
|
+
// PATTERN: Use "\n\n---\n\n" for visual clarity (horizontal rule)
|
|
807
|
+
this.skillsPrompt = skillContents.join("\n\n---\n\n");
|
|
808
|
+
}
|
|
809
|
+
/**
|
|
810
|
+
* Build system prompt with skills injected
|
|
811
|
+
*
|
|
812
|
+
* Combines the base system prompt with loaded skills for injection into
|
|
813
|
+
* the Anthropic SDK's systemPrompt parameter.
|
|
814
|
+
*
|
|
815
|
+
* @param baseSystemPrompt - Optional base system prompt to enhance with skills
|
|
816
|
+
* @returns Enhanced system prompt with skills section, or base prompt unchanged if no skills loaded
|
|
817
|
+
* @internal
|
|
818
|
+
* @remarks
|
|
819
|
+
* Three handling cases:
|
|
820
|
+
* 1. No skills loaded - returns basePrompt unchanged
|
|
821
|
+
* 2. No base prompt - returns skills-only prompt with default header
|
|
822
|
+
* 3. Both exist - combines with "## Available Skills" section
|
|
823
|
+
*/
|
|
824
|
+
buildSystemPromptWithSkills(baseSystemPrompt) {
|
|
825
|
+
// Case 1: No skills loaded - return base prompt unchanged
|
|
826
|
+
if (!this.skillsPrompt) {
|
|
827
|
+
return baseSystemPrompt ?? "";
|
|
828
|
+
}
|
|
829
|
+
// Case 2: No base prompt - return skills with default header
|
|
830
|
+
if (!baseSystemPrompt) {
|
|
831
|
+
return `You are a helpful assistant.
|
|
832
|
+
|
|
833
|
+
## Available Skills
|
|
834
|
+
|
|
835
|
+
${this.skillsPrompt}
|
|
836
|
+
|
|
837
|
+
## Instructions
|
|
838
|
+
Leverage the available skills above when responding to requests.
|
|
839
|
+
`;
|
|
840
|
+
}
|
|
841
|
+
// Case 3: Both exist - combine with skills section
|
|
842
|
+
return `${baseSystemPrompt}
|
|
843
|
+
|
|
844
|
+
## Available Skills
|
|
845
|
+
|
|
846
|
+
${this.skillsPrompt}
|
|
847
|
+
|
|
848
|
+
## Skill Usage
|
|
849
|
+
When responding, leverage the available skills above.
|
|
850
|
+
Each skill provides specific capabilities and guidelines.
|
|
851
|
+
`;
|
|
852
|
+
}
|
|
853
|
+
/**
|
|
854
|
+
* Build Agent SDK hooks from Provider hook events
|
|
855
|
+
*
|
|
856
|
+
* Adapts ProviderHookEvents to Anthropic Agent SDK-compatible hook format.
|
|
857
|
+
* Transforms signatures between Provider and SDK hook formats and handles
|
|
858
|
+
* async/sync hook execution.
|
|
859
|
+
*
|
|
860
|
+
* @param hooks - Optional provider hook events to adapt
|
|
861
|
+
* @returns SDK-compatible hooks object with HookCallbackMatcher arrays
|
|
862
|
+
* @internal
|
|
863
|
+
* @remarks
|
|
864
|
+
* Hook mapping:
|
|
865
|
+
* - onToolStart → PreToolUse
|
|
866
|
+
* - onToolEnd → PostToolUse
|
|
867
|
+
* - onSessionStart → SessionStart
|
|
868
|
+
* - onSessionEnd → SessionEnd
|
|
869
|
+
*
|
|
870
|
+
* Each adapter returns { continue: true } for SDK compatibility.
|
|
871
|
+
* Duration values are set to 0 as SDK doesn't provide them in hook input.
|
|
872
|
+
*/
|
|
873
|
+
buildAgentSDKHooks(hooks) {
|
|
874
|
+
// Early return: no hooks to convert
|
|
875
|
+
if (!hooks) {
|
|
876
|
+
return {};
|
|
877
|
+
}
|
|
878
|
+
const sdkHooks = {};
|
|
879
|
+
// Map onToolStart → PreToolUse
|
|
880
|
+
if (hooks.onToolStart) {
|
|
881
|
+
sdkHooks["PreToolUse"] = [
|
|
882
|
+
{
|
|
883
|
+
hooks: [
|
|
884
|
+
async (input, _toolUseID, _options) => {
|
|
885
|
+
const preInput = input;
|
|
886
|
+
const toolRequest = {
|
|
887
|
+
name: preInput.tool_name,
|
|
888
|
+
input: preInput.tool_input,
|
|
889
|
+
};
|
|
890
|
+
await hooks.onToolStart(toolRequest);
|
|
891
|
+
return { continue: true };
|
|
892
|
+
},
|
|
893
|
+
],
|
|
894
|
+
},
|
|
895
|
+
];
|
|
896
|
+
}
|
|
897
|
+
// Map onToolEnd → PostToolUse
|
|
898
|
+
if (hooks.onToolEnd) {
|
|
899
|
+
sdkHooks["PostToolUse"] = [
|
|
900
|
+
{
|
|
901
|
+
hooks: [
|
|
902
|
+
async (input, _toolUseID, _options) => {
|
|
903
|
+
const postInput = input;
|
|
904
|
+
const toolRequest = {
|
|
905
|
+
name: postInput.tool_name,
|
|
906
|
+
input: postInput.tool_input,
|
|
907
|
+
};
|
|
908
|
+
const toolResult = {
|
|
909
|
+
content: postInput.tool_response,
|
|
910
|
+
isError: false, // SDK limitation - always false
|
|
911
|
+
};
|
|
912
|
+
const duration = 0; // SDK limitation - duration not available
|
|
913
|
+
await hooks.onToolEnd(toolRequest, toolResult, duration);
|
|
914
|
+
return { continue: true };
|
|
915
|
+
},
|
|
916
|
+
],
|
|
917
|
+
},
|
|
918
|
+
];
|
|
919
|
+
}
|
|
920
|
+
// Map onSessionStart → SessionStart
|
|
921
|
+
if (hooks.onSessionStart) {
|
|
922
|
+
sdkHooks["SessionStart"] = [
|
|
923
|
+
{
|
|
924
|
+
hooks: [
|
|
925
|
+
async (_input, _toolUseID, _options) => {
|
|
926
|
+
await hooks.onSessionStart();
|
|
927
|
+
return { continue: true };
|
|
928
|
+
},
|
|
929
|
+
],
|
|
930
|
+
},
|
|
931
|
+
];
|
|
932
|
+
}
|
|
933
|
+
// Map onSessionEnd → SessionEnd
|
|
934
|
+
if (hooks.onSessionEnd) {
|
|
935
|
+
sdkHooks["SessionEnd"] = [
|
|
936
|
+
{
|
|
937
|
+
hooks: [
|
|
938
|
+
async (_input, _toolUseID, _options) => {
|
|
939
|
+
const totalDuration = 0; // SDK limitation - duration not available
|
|
940
|
+
await hooks.onSessionEnd(totalDuration);
|
|
941
|
+
return { continue: true };
|
|
942
|
+
},
|
|
943
|
+
],
|
|
944
|
+
},
|
|
945
|
+
];
|
|
946
|
+
}
|
|
947
|
+
return sdkHooks;
|
|
948
|
+
}
|
|
949
|
+
/**
|
|
950
|
+
* Normalize a model string to a ModelSpec
|
|
951
|
+
*
|
|
952
|
+
* Parses model strings in two formats:
|
|
953
|
+
* - Plain: "claude-sonnet-4" → { provider: 'anthropic', model: 'claude-sonnet-4', raw: 'claude-sonnet-4' }
|
|
954
|
+
* - Qualified: "anthropic/claude-opus-4" → { provider: 'anthropic', model: 'claude-opus-4', raw: 'anthropic/claude-opus-4' }
|
|
955
|
+
*
|
|
956
|
+
* Delegates to {@link parseModelSpec} for parsing and validation.
|
|
957
|
+
* Validates that the provider is 'anthropic'.
|
|
958
|
+
*
|
|
959
|
+
* @param model - Model string to normalize (required)
|
|
960
|
+
* @returns Parsed ModelSpec with provider='anthropic'
|
|
961
|
+
* @throws {Error} When model specification is invalid (delegated to parseModelSpec)
|
|
962
|
+
* @throws {ConfigError} When provider is not 'anthropic' (code === AGENT_ERROR_CODES.CONFIG_ERROR)
|
|
963
|
+
*
|
|
964
|
+
* @example
|
|
965
|
+
* ```ts
|
|
966
|
+
* const provider = new AnthropicProvider();
|
|
967
|
+
*
|
|
968
|
+
* // Plain format
|
|
969
|
+
* provider.normalizeModel('claude-sonnet-4');
|
|
970
|
+
* // Returns: { provider: 'anthropic', model: 'claude-sonnet-4', raw: 'claude-sonnet-4' }
|
|
971
|
+
*
|
|
972
|
+
* // Qualified format
|
|
973
|
+
* provider.normalizeModel('anthropic/claude-opus-4');
|
|
974
|
+
* // Returns: { provider: 'anthropic', model: 'claude-opus-4', raw: 'anthropic/claude-opus-4' }
|
|
975
|
+
*
|
|
976
|
+
* // Error: wrong provider
|
|
977
|
+
* provider.normalizeModel('openai/gpt-4');
|
|
978
|
+
* // Throws: "Cannot normalize openai/gpt-4 with ClaudeCodeHarness..."
|
|
979
|
+
* ```
|
|
980
|
+
*/
|
|
981
|
+
normalizeModel(model) {
|
|
982
|
+
// Delegate to existing utility function
|
|
983
|
+
const spec = parseModelSpec(model, "anthropic");
|
|
984
|
+
// PRD §7.8 — claude-code can ONLY run anthropic/* models.
|
|
985
|
+
// Compare against the literal LLM-host 'anthropic', NOT this.id (which is the harness id
|
|
986
|
+
// 'claude-code' — a different axis). A naive `!== this.id` would throw on every call.
|
|
987
|
+
if (spec.provider !== "anthropic") {
|
|
988
|
+
throw new ConfigError(`Cannot normalize ${spec.provider}/${spec.model} with ClaudeCodeHarness. ` +
|
|
989
|
+
`The claude-code harness only supports anthropic/* models (PRD §7.8). ` +
|
|
990
|
+
`Use HarnessRegistry to select a harness that supports the '${spec.provider}' provider.`, {
|
|
991
|
+
code: AGENT_ERROR_CODES.CONFIG_ERROR,
|
|
992
|
+
details: { provider: spec.provider, model: spec.model, harnessId: this.id },
|
|
993
|
+
});
|
|
994
|
+
}
|
|
995
|
+
return spec;
|
|
996
|
+
}
|
|
997
|
+
/**
|
|
998
|
+
* Create a new session with the specified ID
|
|
999
|
+
*
|
|
1000
|
+
* Initializes empty session state for the given session ID.
|
|
1001
|
+
* If session already exists, this is a no-op (idempotent).
|
|
1002
|
+
*
|
|
1003
|
+
* @param sessionId - Unique identifier for the session (required)
|
|
1004
|
+
* @throws {Error} If SDK is not initialized
|
|
1005
|
+
* @remarks Idempotent: if session exists, this is a no-op.
|
|
1006
|
+
* Session will be used when execute() receives matching sessionId in options.
|
|
1007
|
+
*/
|
|
1008
|
+
async createSession(sessionId) {
|
|
1009
|
+
// PATTERN: SDK initialization check (follow execute() pattern at lines 219-223)
|
|
1010
|
+
if (!this.sdk) {
|
|
1011
|
+
throw new Error("SDK not initialized. Call initialize() first.");
|
|
1012
|
+
}
|
|
1013
|
+
// PATTERN: Idempotent operation (follow initialize() pattern)
|
|
1014
|
+
// Only create if doesn't exist
|
|
1015
|
+
const exists = await this.sessionStore.has(sessionId);
|
|
1016
|
+
if (!exists) {
|
|
1017
|
+
const now = Date.now();
|
|
1018
|
+
const emptyState = {
|
|
1019
|
+
history: [],
|
|
1020
|
+
lastResult: null,
|
|
1021
|
+
createdAt: now,
|
|
1022
|
+
lastAccessedAt: now,
|
|
1023
|
+
};
|
|
1024
|
+
await this.sessionStore.save(sessionId, emptyState);
|
|
1025
|
+
}
|
|
1026
|
+
// If exists, do nothing (idempotent)
|
|
1027
|
+
}
|
|
1028
|
+
/**
|
|
1029
|
+
* Get session state for the specified ID
|
|
1030
|
+
*
|
|
1031
|
+
* Retrieves the current session state including conversation history
|
|
1032
|
+
* and last result. Returns undefined if session doesn't exist.
|
|
1033
|
+
*
|
|
1034
|
+
* @param sessionId - Session identifier to retrieve (required)
|
|
1035
|
+
* @returns Session state or undefined if not found
|
|
1036
|
+
* @remarks Updates lastAccessedAt timestamp and saves back to persistent stores.
|
|
1037
|
+
*/
|
|
1038
|
+
async getSession(sessionId) {
|
|
1039
|
+
const state = await this.sessionStore.load(sessionId);
|
|
1040
|
+
if (state) {
|
|
1041
|
+
// Update lastAccessedAt timestamp
|
|
1042
|
+
state.lastAccessedAt = Date.now();
|
|
1043
|
+
// Save back to store for persistent stores
|
|
1044
|
+
if (!(this.sessionStore instanceof MemorySessionStore)) {
|
|
1045
|
+
await this.sessionStore.save(sessionId, state);
|
|
1046
|
+
}
|
|
1047
|
+
}
|
|
1048
|
+
// Convert null to undefined for consistency
|
|
1049
|
+
return state ?? undefined;
|
|
1050
|
+
}
|
|
1051
|
+
/**
|
|
1052
|
+
* Delete a session
|
|
1053
|
+
*
|
|
1054
|
+
* Removes the session from storage. If the session doesn't exist,
|
|
1055
|
+
* returns false.
|
|
1056
|
+
*
|
|
1057
|
+
* @param sessionId - Session identifier to delete (required)
|
|
1058
|
+
* @returns true if deleted, false if not found
|
|
1059
|
+
* @throws {Error} If SDK is not initialized
|
|
1060
|
+
* @remarks Destructive operation: deleted sessions cannot be recovered
|
|
1061
|
+
* unless the store has backup/retention policies.
|
|
1062
|
+
*/
|
|
1063
|
+
async deleteSession(sessionId) {
|
|
1064
|
+
// PATTERN: SDK initialization check
|
|
1065
|
+
if (!this.sdk) {
|
|
1066
|
+
throw new Error("SDK not initialized. Call initialize() first.");
|
|
1067
|
+
}
|
|
1068
|
+
return await this.sessionStore.delete(sessionId);
|
|
1069
|
+
}
|
|
1070
|
+
}
|
|
1071
|
+
/**
|
|
1072
|
+
* @deprecated Since v1.2. Use {@link ClaudeCodeHarness}. Renamed as part of the
|
|
1073
|
+
* Harness/Provider split (PRD §7). Identity preserved for backward compatibility.
|
|
1074
|
+
*/
|
|
1075
|
+
export const AnthropicProvider = ClaudeCodeHarness;
|
|
1076
|
+
//# sourceMappingURL=claude-code-harness.js.map
|