gauss-ai 4.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/CHANGELOG.md +489 -0
- package/LICENSE +21 -0
- package/README.md +269 -0
- package/dist/a2a/index.cjs +7 -0
- package/dist/a2a/index.cjs.map +1 -0
- package/dist/a2a/index.d.cts +30 -0
- package/dist/a2a/index.d.ts +30 -0
- package/dist/a2a/index.js +7 -0
- package/dist/a2a/index.js.map +1 -0
- package/dist/agent-UIQDSYCE.js +16 -0
- package/dist/agent-UIQDSYCE.js.map +1 -0
- package/dist/agent-builder-8W3mBR-N.d.ts +1075 -0
- package/dist/agent-builder-GEMYdb1p.d.cts +1075 -0
- package/dist/agent-graph-AMQYAWNF.js +1422 -0
- package/dist/agent-graph-AMQYAWNF.js.map +1 -0
- package/dist/ai-sdk-mcp.adapter-SEN6KHNU.js +124 -0
- package/dist/ai-sdk-mcp.adapter-SEN6KHNU.js.map +1 -0
- package/dist/browser/index.js +10 -0
- package/dist/browser/index.js.map +1 -0
- package/dist/bun-runtime.adapter-MQDAJLQM.js +8 -0
- package/dist/bun-runtime.adapter-MQDAJLQM.js.map +1 -0
- package/dist/bun-runtime.adapter-XKOUXVAK.cjs +8 -0
- package/dist/bun-runtime.adapter-XKOUXVAK.cjs.map +1 -0
- package/dist/chat-A3XMRPJL.js +129 -0
- package/dist/chat-A3XMRPJL.js.map +1 -0
- package/dist/chunk-2ZRU47NC.js +91 -0
- package/dist/chunk-2ZRU47NC.js.map +1 -0
- package/dist/chunk-3LD3JTH4.cjs +18 -0
- package/dist/chunk-3LD3JTH4.cjs.map +1 -0
- package/dist/chunk-5FE5TG2W.cjs +16 -0
- package/dist/chunk-5FE5TG2W.cjs.map +1 -0
- package/dist/chunk-6XF673YC.cjs +436 -0
- package/dist/chunk-6XF673YC.cjs.map +1 -0
- package/dist/chunk-7CKWZJNS.js +230 -0
- package/dist/chunk-7CKWZJNS.js.map +1 -0
- package/dist/chunk-BI2G665F.js +4588 -0
- package/dist/chunk-BI2G665F.js.map +1 -0
- package/dist/chunk-C5NLWJS2.js +139 -0
- package/dist/chunk-C5NLWJS2.js.map +1 -0
- package/dist/chunk-CJZ66SU3.cjs +4321 -0
- package/dist/chunk-CJZ66SU3.cjs.map +1 -0
- package/dist/chunk-DAMT2CXW.cjs +91 -0
- package/dist/chunk-DAMT2CXW.cjs.map +1 -0
- package/dist/chunk-E7WG3MO5.js +18 -0
- package/dist/chunk-E7WG3MO5.js.map +1 -0
- package/dist/chunk-EFDM6R4J.js +99 -0
- package/dist/chunk-EFDM6R4J.js.map +1 -0
- package/dist/chunk-F7WIPPEO.js +256 -0
- package/dist/chunk-F7WIPPEO.js.map +1 -0
- package/dist/chunk-FAYDE67N.js +6927 -0
- package/dist/chunk-FAYDE67N.js.map +1 -0
- package/dist/chunk-GAE2KKCM.js +21 -0
- package/dist/chunk-GAE2KKCM.js.map +1 -0
- package/dist/chunk-INLNGRXM.cjs +130 -0
- package/dist/chunk-INLNGRXM.cjs.map +1 -0
- package/dist/chunk-JKXKXB5O.js +130 -0
- package/dist/chunk-JKXKXB5O.js.map +1 -0
- package/dist/chunk-K6SAETGP.js +375 -0
- package/dist/chunk-K6SAETGP.js.map +1 -0
- package/dist/chunk-KEASLAYR.js +157 -0
- package/dist/chunk-KEASLAYR.js.map +1 -0
- package/dist/chunk-KKJVNM6O.js +436 -0
- package/dist/chunk-KKJVNM6O.js.map +1 -0
- package/dist/chunk-KYIMVRIM.js +16 -0
- package/dist/chunk-KYIMVRIM.js.map +1 -0
- package/dist/chunk-MB7NXIZD.js +4321 -0
- package/dist/chunk-MB7NXIZD.js.map +1 -0
- package/dist/chunk-MHHDXPGE.js +209 -0
- package/dist/chunk-MHHDXPGE.js.map +1 -0
- package/dist/chunk-NE6JJA5W.js +401 -0
- package/dist/chunk-NE6JJA5W.js.map +1 -0
- package/dist/chunk-PF46XZBF.cjs +6927 -0
- package/dist/chunk-PF46XZBF.cjs.map +1 -0
- package/dist/chunk-PSJIAGDE.cjs +375 -0
- package/dist/chunk-PSJIAGDE.cjs.map +1 -0
- package/dist/chunk-PWOQDXNQ.js +16 -0
- package/dist/chunk-PWOQDXNQ.js.map +1 -0
- package/dist/chunk-QYOMQBBZ.cjs +230 -0
- package/dist/chunk-QYOMQBBZ.cjs.map +1 -0
- package/dist/chunk-UDFXLC4J.cjs +16 -0
- package/dist/chunk-UDFXLC4J.cjs.map +1 -0
- package/dist/chunk-UO4NGXRT.cjs +259 -0
- package/dist/chunk-UO4NGXRT.cjs.map +1 -0
- package/dist/chunk-UPFDFLEW.js +40 -0
- package/dist/chunk-UPFDFLEW.js.map +1 -0
- package/dist/chunk-V55JSQS7.cjs +16 -0
- package/dist/chunk-V55JSQS7.cjs.map +1 -0
- package/dist/chunk-VJADHXZL.cjs +16 -0
- package/dist/chunk-VJADHXZL.cjs.map +1 -0
- package/dist/chunk-VRWD7LCI.js +59 -0
- package/dist/chunk-VRWD7LCI.js.map +1 -0
- package/dist/chunk-WKKQ443C.js +487 -0
- package/dist/chunk-WKKQ443C.js.map +1 -0
- package/dist/chunk-X2GHUHAF.js +436 -0
- package/dist/chunk-X2GHUHAF.js.map +1 -0
- package/dist/chunk-XLGW3XNI.cjs +256 -0
- package/dist/chunk-XLGW3XNI.cjs.map +1 -0
- package/dist/chunk-ZFJKX4DP.js +16 -0
- package/dist/chunk-ZFJKX4DP.js.map +1 -0
- package/dist/chunk-ZM2OEWM2.js +259 -0
- package/dist/chunk-ZM2OEWM2.js.map +1 -0
- package/dist/chunk-ZNAIP2XV.js +16 -0
- package/dist/chunk-ZNAIP2XV.js.map +1 -0
- package/dist/chunk-ZYFAZYSL.js +42 -0
- package/dist/chunk-ZYFAZYSL.js.map +1 -0
- package/dist/cli/index.js +421 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/config-4MHT6TQW.js +153 -0
- package/dist/config-4MHT6TQW.js.map +1 -0
- package/dist/config-REERQFK4.cjs +153 -0
- package/dist/config-REERQFK4.cjs.map +1 -0
- package/dist/cost-tracker-JLOU7IZJ.js +7 -0
- package/dist/cost-tracker-JLOU7IZJ.js.map +1 -0
- package/dist/demo-C52GMSYH.js +188 -0
- package/dist/demo-C52GMSYH.js.map +1 -0
- package/dist/deno/index.js +306 -0
- package/dist/deno/index.js.map +1 -0
- package/dist/deno-runtime.adapter-F744HY7K.js +8 -0
- package/dist/deno-runtime.adapter-F744HY7K.js.map +1 -0
- package/dist/deno-runtime.adapter-RFEVNSCV.cjs +8 -0
- package/dist/deno-runtime.adapter-RFEVNSCV.cjs.map +1 -0
- package/dist/dev-D7DDVDA4.js +218 -0
- package/dist/dev-D7DDVDA4.js.map +1 -0
- package/dist/edge/index.js +10 -0
- package/dist/edge/index.js.map +1 -0
- package/dist/edge-runtime.adapter-UQCW2F7X.js +8 -0
- package/dist/edge-runtime.adapter-UQCW2F7X.js.map +1 -0
- package/dist/edge-runtime.adapter-YED6F3AY.cjs +8 -0
- package/dist/edge-runtime.adapter-YED6F3AY.cjs.map +1 -0
- package/dist/graph-MGFAQZ5W.js +50 -0
- package/dist/graph-MGFAQZ5W.js.map +1 -0
- package/dist/graph-visualization-HBSVQXJK.js +9 -0
- package/dist/graph-visualization-HBSVQXJK.js.map +1 -0
- package/dist/index-BRgqNnh3.d.cts +982 -0
- package/dist/index-CZxpYUxZ.d.ts +982 -0
- package/dist/index.cjs +14789 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +10275 -0
- package/dist/index.d.ts +10275 -0
- package/dist/index.js +14789 -0
- package/dist/index.js.map +1 -0
- package/dist/init-CFWXTQ35.js +133 -0
- package/dist/init-CFWXTQ35.js.map +1 -0
- package/dist/llm-VWO4MC7J.cjs +17 -0
- package/dist/llm-VWO4MC7J.cjs.map +1 -0
- package/dist/llm-XLXVSPBI.js +17 -0
- package/dist/llm-XLXVSPBI.js.map +1 -0
- package/dist/logging-WRAK5ZXT.js +33 -0
- package/dist/logging-WRAK5ZXT.js.map +1 -0
- package/dist/metrics-FAHZVVD4.js +47 -0
- package/dist/metrics-FAHZVVD4.js.map +1 -0
- package/dist/node/index.cjs +280 -0
- package/dist/node/index.cjs.map +1 -0
- package/dist/node/index.d.cts +51 -0
- package/dist/node/index.d.ts +51 -0
- package/dist/node/index.js +280 -0
- package/dist/node/index.js.map +1 -0
- package/dist/node-runtime.adapter-5L7PJ6W2.js +8 -0
- package/dist/node-runtime.adapter-5L7PJ6W2.js.map +1 -0
- package/dist/node-runtime.adapter-CCRZVGHB.cjs +8 -0
- package/dist/node-runtime.adapter-CCRZVGHB.cjs.map +1 -0
- package/dist/persist-usage-WTBTCWEF.js +7 -0
- package/dist/persist-usage-WTBTCWEF.js.map +1 -0
- package/dist/plugin-RCPBWUUA.js +207 -0
- package/dist/plugin-RCPBWUUA.js.map +1 -0
- package/dist/plugins/index.cjs +75 -0
- package/dist/plugins/index.cjs.map +1 -0
- package/dist/plugins/index.d.cts +8 -0
- package/dist/plugins/index.d.ts +8 -0
- package/dist/plugins/index.js +75 -0
- package/dist/plugins/index.js.map +1 -0
- package/dist/plugins-L4ING3CX.js +4625 -0
- package/dist/plugins-L4ING3CX.js.map +1 -0
- package/dist/providers/index.cjs +189 -0
- package/dist/providers/index.cjs.map +1 -0
- package/dist/providers/index.d.cts +168 -0
- package/dist/providers/index.d.ts +168 -0
- package/dist/providers/index.js +189 -0
- package/dist/providers/index.js.map +1 -0
- package/dist/providers-3RNQ5CKZ.js +59 -0
- package/dist/providers-3RNQ5CKZ.js.map +1 -0
- package/dist/providers-66GPXUGQ.cjs +59 -0
- package/dist/providers-66GPXUGQ.cjs.map +1 -0
- package/dist/repl-K6QN4I2S.js +678 -0
- package/dist/repl-K6QN4I2S.js.map +1 -0
- package/dist/rest/index.cjs +17 -0
- package/dist/rest/index.cjs.map +1 -0
- package/dist/rest/index.d.cts +102 -0
- package/dist/rest/index.d.ts +102 -0
- package/dist/rest/index.js +17 -0
- package/dist/rest/index.js.map +1 -0
- package/dist/runtime-deno.js +15 -0
- package/dist/runtime-deno.js.map +1 -0
- package/dist/runtime-edge.js +15 -0
- package/dist/runtime-edge.js.map +1 -0
- package/dist/runtime-node.js +15 -0
- package/dist/runtime-node.js.map +1 -0
- package/dist/scraping/index.cjs +11 -0
- package/dist/scraping/index.cjs.map +1 -0
- package/dist/scraping/index.d.cts +17 -0
- package/dist/scraping/index.d.ts +17 -0
- package/dist/scraping/index.js +11 -0
- package/dist/scraping/index.js.map +1 -0
- package/dist/semantic-scraping.port-CZWUea88.d.cts +54 -0
- package/dist/semantic-scraping.port-CZWUea88.d.ts +54 -0
- package/dist/server/index.js +166 -0
- package/dist/server/index.js.map +1 -0
- package/dist/testing/index.cjs +25 -0
- package/dist/testing/index.cjs.map +1 -0
- package/dist/testing/index.d.cts +63 -0
- package/dist/testing/index.d.ts +63 -0
- package/dist/testing/index.js +25 -0
- package/dist/testing/index.js.map +1 -0
- package/dist/token-counter.port-CRgxZZGe.d.ts +334 -0
- package/dist/token-counter.port-D7BHMCRR.d.cts +334 -0
- package/dist/tools-BZM33OBZ.js +10 -0
- package/dist/tools-BZM33OBZ.js.map +1 -0
- package/dist/tracing-XA3TEWP4.js +48 -0
- package/dist/tracing-XA3TEWP4.js.map +1 -0
- package/dist/types-CVsP7gFI.d.cts +235 -0
- package/dist/types-CVsP7gFI.d.ts +235 -0
- package/dist/virtual-fs.adapter-BBLS-3AY.d.ts +26 -0
- package/dist/virtual-fs.adapter-nb0CTYOj.d.cts +26 -0
- package/dist/workflow/index.cjs +9 -0
- package/dist/workflow/index.cjs.map +1 -0
- package/dist/workflow/index.d.cts +62 -0
- package/dist/workflow/index.d.ts +62 -0
- package/dist/workflow/index.js +9 -0
- package/dist/workflow/index.js.map +1 -0
- package/dist/workflow.port-BaCttxrw.d.cts +153 -0
- package/dist/workflow.port-BaCttxrw.d.ts +153 -0
- package/package.json +230 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["/Users/giulioleone/Sviluppo/gauss/gauss-flow/dist/index.cjs","../src/rag/pipeline.ts","../src/graph/team-builder.ts","../src/domain/workflow-dsl.ts","../src/domain/multimodal.ts","../src/domain/video-processor.ts","../src/gauss.ts","../src/core/agent/run.ts","../src/core/agent/stream.ts","../src/core/agent/subagent.ts","../src/core/agent/agent.ts","../src/core/agent/graph.ts","../src/decorators/memory.ts","../src/decorators/telemetry.ts","../src/decorators/resilience.ts","../src/decorators/cost-limit.ts","../src/decorators/planning.ts","../src/decorators/approval.ts","../src/decorators/learning.ts","../src/decorators/checkpoint.ts","../src/errors/index.ts","../src/agent/progress.ts","../src/agent/stop-conditions.ts","../src/adapters/voice/openai/openai-voice.adapter.ts","../src/adapters/voice/elevenlabs/elevenlabs-voice.adapter.ts","../src/adapters/voice/voice-pipeline.ts","../src/ports/di.port.ts","../src/plugins/memory.plugin.ts","../src/adapters/memory/memory-utils.ts","../src/adapters/memory/in-memory-agent-memory.adapter.ts","../src/plugins/plugin-registry.plugin.ts","../src/adapters/plugin-registry/default-plugin-registry.adapter.ts","../src/middleware/logging.ts","../src/middleware/caching.ts","../src/middleware/hitl.ts","../src/middleware/processor.ts","../src/middleware/skills.ts","../src/middleware/observational-memory.ts","../src/middleware/result-eviction.ts","../src/middleware/summarization.ts","../src/middleware/trip-wire.ts","../src/middleware/prompt-caching.ts","../src/middleware/tool-call-patching.ts","../src/adapters/consensus/llm-judge.adapter.ts","../src/adapters/consensus/majority-vote.adapter.ts","../src/adapters/consensus/debate.adapter.ts","../src/graph/agent-supervisor.ts","../src/graph/supervisor-builder.ts","../src/graph/dynamic-agent-graph.ts","../src/rag/graph-rag.pipeline.ts","../src/adapters/embedding/inmemory.adapter.ts","../src/adapters/vector-store/inmemory.adapter.ts","../src/adapters/document/markdown.adapter.ts","../src/adapters/working-memory/inmemory.adapter.ts","../src/adapters/knowledge-graph/inmemory.adapter.ts","../src/adapters/entity-extractor/pattern.adapter.ts","../src/context/context-manager.ts","../src/context/rolling-summarizer.ts","../src/templates/prompt-template.ts","../src/streaming/delta-encoder.ts","../src/streaming/event-stream.ts","../src/streaming/sse-handler.ts","../src/streaming/ws-handler.ts","../src/streaming/graph-stream.ts","../src/adapters/partial-json/default-partial-json.adapter.ts","../src/streaming/stream-json.ts","../src/server/node-http.server.ts","../src/protocols/acp/acp-server.ts","../src/adapters/memory/tiered-agent-memory.adapter.ts","../src/domain/checkpoint.schema.ts","../src/domain/todo.schema.ts","../src/adapters/memory/supabase.adapter.ts","../src/adapters/learning/in-memory-learning.adapter.ts","../src/adapters/mcp/gauss-mcp.adapter.ts","../src/adapters/mcp/ai-sdk-mcp.adapter.ts","../src/adapters/policy/mcp-policy-engine.ts","../src/adapters/model/ai-sdk.adapter.ts","../src/adapters/model/router.adapter.ts","../src/adapters/auth/auth.adapter.ts","../src/adapters/agent-network/agent-network.adapter.ts","../src/adapters/telemetry/console-telemetry.adapter.ts","../src/adapters/telemetry/otel-telemetry.adapter.ts","../src/adapters/logging/console-logging.adapter.ts","../src/adapters/tracing/in-memory-tracing.adapter.ts","../src/adapters/metrics/in-memory-metrics.adapter.ts","../src/adapters/metrics/prometheus.adapter.ts","../src/adapters/cost-tracker/default-cost-tracker.adapter.ts","../src/adapters/tool-composition/default-tool-composition.adapter.ts","../src/runtime/detect.ts","../src/domain/compiler.schema.ts","../src/adapters/compiler/llm-nl-parser.ts","../src/adapters/compiler/llm-compiler-engine.ts","../src/adapters/compiler/compile-from-nl.ts","../src/adapters/compiler/llm-skill-matcher.ts","../src/adapters/compiler/inmemory-skill-registry.ts","../src/adapters/compiler/json-serializer.ts","../src/adapters/compiler/markdown-serializer.ts","../src/adapters/compiler/file-workflow-storage.ts","../src/adapters/compiler/dual-workflow-storage.ts","../src/adapters/compiler/inmemory-workflow-storage.ts","../src/adapters/compiler/storage-factory.ts","../src/adapters/suspension/inmemory.adapter.ts","../src/adapters/skills/file-skill.adapter.ts","../src/adapters/sandbox/local-shell.adapter.ts","../src/adapters/sandbox/e2b.adapter.ts","../src/adapters/sandbox/factory.ts","../src/adapters/hot-reload/file-watcher.adapter.ts","../src/agent/agent-config-loader.ts","../src/ports/storage-domain.port.ts","../src/adapters/storage/inmemory.adapter.ts","../src/adapters/storage/postgres/postgres-storage.adapter.ts","../src/adapters/storage/redis/redis-storage.adapter.ts","../src/adapters/vector-store/pgvector/pgvector-store.adapter.ts","../src/adapters/object-storage/s3/s3-object-storage.adapter.ts","../src/adapters/queue/bullmq/bullmq-queue.adapter.ts","../src/adapters/learning/file-learning.adapter.ts","../src/adapters/voice/inmemory.adapter.ts","../src/adapters/datasets/inmemory.adapter.ts","../src/adapters/deployer/inmemory.adapter.ts","../src/adapters/plugin-marketplace/local-cache.ts","../src/adapters/plugin-marketplace/github-registry.adapter.ts","../src/adapters/plugin-marketplace/npm-registry.adapter.ts","../src/adapters/plugin-marketplace/composite-marketplace.adapter.ts","../src/adapters/plugin-marketplace/plugin-loader.ts","../src/evals/semantic-search-harness.ts","../src/evals/semantic-search-benchmark.ts","../src/evals/semantic-search-stress-suite.ts","../src/evals/scorer.ts","../src/evals/trajectory.ts","../src/server/playground-api.ts","../src/server/playground-collector.ts","../src/cli/playground.ts","../src/domain/learning.schema.ts","../src/domain/conversation.schema.ts","../src/domain/events.schema.ts","../src/domain/eval.schema.ts","../src/tools/llm-recorder.ts","../src/tools/visual-agent-builder.ts","../src/tools/agent-builder-api.ts","../src/docs/doc-generator.ts","../src/adapters/agent-debugger/debug-session.ts","../src/adapters/agent-debugger/debugger.adapter.ts","../src/adapters/agent-debugger/debug-middleware.ts","../src/adapters/agent-orchestrator/patterns/supervisor.ts","../src/adapters/agent-orchestrator/patterns/swarm.ts","../src/adapters/agent-orchestrator/patterns/pipeline.ts","../src/adapters/agent-orchestrator/patterns/map-reduce.ts","../src/adapters/agent-orchestrator/patterns/debate.ts","../src/adapters/agent-orchestrator/orchestrator.adapter.ts","../src/adapters/structured-output/parsers/json-parser.ts","../src/adapters/structured-output/parsers/yaml-parser.ts","../src/adapters/structured-output/parsers/csv-parser.ts","../src/adapters/structured-output/parsers/markdown-parser.ts","../src/adapters/structured-output/repair-engine.ts","../src/adapters/structured-output/stream-parser.ts","../src/adapters/structured-output/structured-output.adapter.ts","../src/adapters/agent-memory/similarity.ts","../src/adapters/agent-memory/memory-consolidator.ts","../src/adapters/agent-memory/memory.adapter.ts","../src/adapters/guardrails/guardrails.adapter.ts","../src/adapters/guardrails/builtin/pii-detector.ts","../src/adapters/guardrails/builtin/injection-detector.ts","../src/adapters/guardrails/builtin/content-moderator.ts","../src/adapters/guardrails/builtin/token-budget.ts","../src/adapters/guardrails/builtin/schema-validator.ts","../src/adapters/observability-pipeline/span.ts","../src/adapters/observability-pipeline/trace.ts","../src/adapters/observability-pipeline/metrics-collector.ts","../src/adapters/observability-pipeline/pipeline.adapter.ts","../src/adapters/observability-pipeline/exporters/console-exporter.ts","../src/adapters/observability-pipeline/exporters/json-exporter.ts","../src/adapters/rate-limiter/rate-limiter.adapter.ts","../src/adapters/cost-tracker/cost-tracker.adapter.ts"],"names":["buildRunContext","Agent","graph","GaussError","Lifetime","SUMMARY_MAX_LENGTH","safeClone","path","resolve","sessionId","session","params","remaining","z","checkpoint","memory","agent","row","parts","idx","aggregate","average","MessageSchema","sessionCounter","DEFAULT_MAX_ROUNDS","cosineSimilarity"],"mappings":"AAAA;AACE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACF,wDAA6B;AAC7B;AACE;AACF,wDAA6B;AAC7B;AACE;AACF,wDAA6B;AAC7B;AACE;AACF,wDAA6B;AAC7B;AACE;AACF,wDAA6B;AAC7B;AACE;AACF,wDAA6B;AAC7B;AACE;AACA;AACF,wDAA6B;AAC7B;AACE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACF,wDAA6B;AAC7B;AACE;AACF,wDAA6B;AAC7B;AACE;AACA;AACA;AACA;AACA;AACA;AACF,wDAA6B;AAC7B;AACE;AACA;AACA;AACF,wDAA6B;AAC7B;AACE;AACA;AACF,wDAA6B;AAC7B;AACE;AACF,wDAA6B;AAC7B;AACE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACF,wDAA6B;AAC7B;AACA;AClJO,IAAM,YAAA,EAAN,MAAkB;AAAA,EACN;AAAA,EAEjB,WAAA,CAAY,MAAA,EAA2B;AACrC,IAAA,IAAA,CAAK,OAAA,EAAS,MAAA;AAAA,EAChB;AAAA;AAAA,EAGA,MAAM,MA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A;AACT,EAAA;AACA,EAAA;AACD;AAGY;AACL,EAAA;AACGA,EAAAA;AACD,EAAA;AACR,EAAA;AACQA,EAAAA;AACR,EAAA;AACD;AAIY;AACL,EAAA;AACGA,EAAAA;AACCA,EAAAA;AACF,EAAA;AACR,EAAA;AACA,EAAA;AACD;ApIwwUW;AACA;AqIxyUH;AAEIS;AACH,EAAA;AACCT,EAAAA;AACT,EAAA;AACD;AAIY;AACFA,EAAAA;AACT,EAAA;AAGA,EAAA;AACD;AAIY;AACX,EAAA;AACUA,EAAAA;AACV,EAAA;AAIA,EAAA;AACD;ArI8xUW;AACA;AsI3zUH;AAEI;AACX,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACD;AAIY;AACL,EAAA;AACN,EAAA;AACA,EAAA;AACQ,EAAA;AACT;AtIyzUW;AACA;AuIx3UH;AAEI;AACX,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACUA,IAAAA;AACR,IAAA;AACOA,IAAAA;AACN,EAAA;AACH,EAAA;AACD;AAGY;AACL,EAAA;AACN,EAAA;AACQA,EAAAA;AACAA,EAAAA;AACC,EAAA;AACT,EAAA;AACD;AvIu3UW;AACA;AwI54UA;AACA;AAsCC;AACwB,mBAAA;AAC3B,mBAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;A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A;AAEU,EAAA;AACH,IAAA;AACP,EAAA;AAEA,EAAA;AACS,IAAA;AACT,EAAA;AAEM,EAAA;AACC,IAAA;AACP,EAAA;AAEQ,EAAA;AACD,IAAA;AACC,IAAA;AACG,IAAA;AACF,IAAA;AACT,EAAA;AACF;A5Ks7bY;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA","file":"/Users/giulioleone/Sviluppo/gauss/gauss-flow/dist/index.cjs","sourcesContent":[null,"// =============================================================================\n// RAG Pipeline — Extract → Transform → Chunk → Embed → Store → Query\n// =============================================================================\n\nimport type { DocumentPort, Document, ChunkOptions } from \"../ports/document.port.js\";\nimport type { EmbeddingPort } from \"../ports/embedding.port.js\";\nimport type { VectorStorePort, VectorSearchResult, VectorFilter } from \"../ports/vector-store.port.js\";\n\n// =============================================================================\n// Configuration\n// =============================================================================\n\nexport interface RAGPipelineConfig {\n documentPort: DocumentPort;\n embeddingPort: EmbeddingPort;\n vectorStorePort: VectorStorePort;\n chunkOptions?: ChunkOptions;\n /** Minimum relevance score (0-1) for query results */\n minRelevance?: number;\n /** Maximum results to return */\n maxResults?: number;\n /** Diversity threshold — skip results too similar to already selected */\n diversityThreshold?: number;\n}\n\nexport interface IngestResult {\n documentsProcessed: number;\n chunksCreated: number;\n embeddingsGenerated: number;\n totalTokens: number;\n}\n\nexport interface QueryResult {\n results: VectorSearchResult[];\n /** Formatted context string for prompt injection */\n context: string;\n totalTokensUsed: number;\n}\n\n// =============================================================================\n// Pipeline\n// =============================================================================\n\nexport class RAGPipeline {\n private readonly config: RAGPipelineConfig;\n\n constructor(config: RAGPipelineConfig) {\n this.config = config;\n }\n\n /** Ingest: extract → transform → chunk → embed → store */\n async ingest(source: string, mimeType?: string): Promise<IngestResult> {\n const { documentPort, embeddingPort, vectorStorePort, chunkOptions } = this.config;\n\n // Extract\n const rawDocs = await documentPort.extract(source, mimeType);\n\n // Transform\n const transformed = await documentPort.transform(rawDocs);\n\n // Chunk\n const chunks = await documentPort.chunk(transformed, chunkOptions);\n\n // Embed in batches\n const batchSize = 32;\n let totalTokens = 0;\n const vectorDocs = [];\n\n for (let i = 0; i < chunks.length; i += batchSize) {\n const batch = chunks.slice(i, i + batchSize);\n const embeddings = await embeddingPort.embedBatch(\n batch.map((c) => c.content),\n );\n\n for (let j = 0; j < batch.length; j++) {\n totalTokens += embeddings[j].tokenCount;\n vectorDocs.push({\n id: batch[j].id,\n embedding: embeddings[j].embedding,\n content: batch[j].content,\n metadata: {\n ...batch[j].metadata,\n source: batch[j].source,\n chunkIndex: batch[j].chunkIndex,\n totalChunks: batch[j].totalChunks,\n },\n });\n }\n }\n\n // Store\n await vectorStorePort.upsert(vectorDocs);\n\n return {\n documentsProcessed: rawDocs.length,\n chunksCreated: chunks.length,\n embeddingsGenerated: vectorDocs.length,\n totalTokens,\n };\n }\n\n /** Query: embed query → vector search → filter → format context */\n async query(\n queryText: string,\n options?: { filter?: VectorFilter; topK?: number },\n ): Promise<QueryResult> {\n const { embeddingPort, vectorStorePort } = this.config;\n const topK = options?.topK ?? this.config.maxResults ?? 5;\n const minScore = this.config.minRelevance ?? 0;\n\n // Embed query\n const queryEmb = await embeddingPort.embed(queryText);\n\n // Search\n let results = await vectorStorePort.query({\n embedding: queryEmb.embedding,\n topK: topK * 2, // Over-fetch for diversity filtering\n minScore,\n filter: options?.filter,\n });\n\n // Diversity filter\n if (this.config.diversityThreshold !== undefined) {\n results = this.applyDiversity(results, this.config.diversityThreshold);\n }\n\n results = results.slice(0, topK);\n\n // Format context\n const context = results\n .map((r, i) => `[Source ${i + 1}] (score: ${r.score.toFixed(3)})\\n${r.content}`)\n .join(\"\\n\\n---\\n\\n\");\n\n return {\n results,\n context,\n totalTokensUsed: queryEmb.tokenCount,\n };\n }\n\n private applyDiversity(\n results: VectorSearchResult[],\n threshold: number,\n ): VectorSearchResult[] {\n const selected: VectorSearchResult[] = [];\n for (const r of results) {\n const tooSimilar = selected.some(\n (s) => Math.abs(s.score - r.score) < threshold && s.content === r.content,\n );\n if (!tooSimilar) {\n selected.push(r);\n }\n }\n return selected;\n }\n}\n","// =============================================================================\n// TeamBuilder — Fluent API for composing teams of specialist agents\n// Supports coordinator/specialist roles and 4 coordination strategies.\n// =============================================================================\n\nimport type { AgentNode } from \"./agent-node.js\";\nimport { EventBus } from \"../agent/event-bus.js\";\nimport type { AgentEventType } from \"../types.js\";\n\n// =============================================================================\n// Lightweight team context (avoids FilesystemPort dependency)\n// =============================================================================\n\nclass TeamContext {\n private data = new Map<string, unknown>();\n\n get(key: string): unknown { return this.data.get(key); }\n set(key: string, value: unknown): void { this.data.set(key, value); }\n has(key: string): boolean { return this.data.has(key); }\n entries(): IterableIterator<[string, unknown]> { return this.data.entries(); }\n}\n\n// =============================================================================\n// Types\n// =============================================================================\n\nexport type CoordinationStrategy =\n | \"round-robin\"\n | \"broadcast\"\n | \"delegate\"\n | \"consensus\";\n\nexport interface TeamMember {\n id: string;\n role: \"coordinator\" | \"specialist\";\n agent: AgentNode;\n /** Optional specialties for delegate strategy routing */\n specialties?: string[];\n}\n\nexport interface TeamConfig {\n id: string;\n members: TeamMember[];\n strategy: CoordinationStrategy;\n maxRounds?: number;\n consensusThreshold?: number;\n eventBus?: EventBus;\n}\n\nexport interface TeamResult {\n teamId: string;\n strategy: CoordinationStrategy;\n rounds: TeamRound[];\n finalAnswer: string;\n metadata: Record<string, unknown>;\n}\n\nexport interface TeamRound {\n round: number;\n memberId: string;\n role: \"coordinator\" | \"specialist\";\n input: string;\n output: string;\n durationMs: number;\n}\n\n// =============================================================================\n// Team class — runtime execution of a team\n// =============================================================================\n\nexport class Team {\n readonly id: string;\n readonly members: ReadonlyArray<TeamMember>;\n readonly strategy: CoordinationStrategy;\n readonly context: TeamContext;\n readonly eventBus: EventBus;\n private readonly maxRounds: number;\n private readonly consensusThreshold: number;\n\n constructor(config: TeamConfig) {\n this.id = config.id;\n this.members = config.members;\n this.strategy = config.strategy;\n this.maxRounds = config.maxRounds ?? 10;\n this.consensusThreshold = config.consensusThreshold ?? 0.5;\n this.eventBus = config.eventBus ?? new EventBus(`team-${config.id}`);\n this.context = new TeamContext();\n }\n\n /** Execute the team on a task */\n async run(task: string): Promise<TeamResult> {\n const rounds: TeamRound[] = [];\n let finalAnswer = \"\";\n\n switch (this.strategy) {\n case \"round-robin\":\n finalAnswer = await this.runRoundRobin(task, rounds);\n break;\n case \"broadcast\":\n finalAnswer = await this.runBroadcast(task, rounds);\n break;\n case \"delegate\":\n finalAnswer = await this.runDelegate(task, rounds);\n break;\n case \"consensus\":\n finalAnswer = await this.runConsensus(task, rounds);\n break;\n }\n\n return {\n teamId: this.id,\n strategy: this.strategy,\n rounds,\n finalAnswer,\n metadata: { totalRounds: rounds.length },\n };\n }\n\n private getCoordinator(): TeamMember {\n const coord = this.members.find((m) => m.role === \"coordinator\");\n if (!coord) throw new Error(`Team \"${this.id}\" has no coordinator`);\n return coord;\n }\n\n private getSpecialists(): TeamMember[] {\n return this.members.filter((m) => m.role === \"specialist\");\n }\n\n /** Round-robin: each specialist answers in turn, coordinator synthesizes */\n private async runRoundRobin(\n task: string,\n rounds: TeamRound[]\n ): Promise<string> {\n const specialists = this.getSpecialists();\n const coordinator = this.getCoordinator();\n const responses: string[] = [];\n\n for (const spec of specialists) {\n const round = await this.executeAgent(spec, task, rounds.length);\n rounds.push(round);\n responses.push(round.output);\n }\n\n // Coordinator synthesizes\n const synthesisPrompt = `Synthesize these specialist responses into a final answer:\\n\\nTask: ${task}\\n\\n${responses.map((r, i) => `Specialist ${i + 1}: ${r}`).join(\"\\n\\n\")}`;\n const final = await this.executeAgent(\n coordinator,\n synthesisPrompt,\n rounds.length\n );\n rounds.push(final);\n return final.output;\n }\n\n /** Broadcast: all specialists answer in parallel, coordinator synthesizes */\n private async runBroadcast(\n task: string,\n rounds: TeamRound[]\n ): Promise<string> {\n const specialists = this.getSpecialists();\n const coordinator = this.getCoordinator();\n\n const results = await Promise.all(\n specialists.map((spec) => this.executeAgent(spec, task, rounds.length))\n );\n rounds.push(...results);\n\n const synthesisPrompt = `Synthesize these specialist responses into a final answer:\\n\\nTask: ${task}\\n\\n${results.map((r) => `${r.memberId}: ${r.output}`).join(\"\\n\\n\")}`;\n const final = await this.executeAgent(\n coordinator,\n synthesisPrompt,\n rounds.length\n );\n rounds.push(final);\n return final.output;\n }\n\n /** Delegate: coordinator picks a specialist based on specialties */\n private async runDelegate(\n task: string,\n rounds: TeamRound[]\n ): Promise<string> {\n const specialists = this.getSpecialists();\n const coordinator = this.getCoordinator();\n\n // Coordinator decides who to delegate to\n const specList = specialists\n .map(\n (s) =>\n `- ${s.id}: specialties=[${(s.specialties ?? []).join(\", \")}]`\n )\n .join(\"\\n\");\n const delegatePrompt = `Given this task, which specialist should handle it? Reply with ONLY the specialist ID.\\n\\nTask: ${task}\\n\\nAvailable specialists:\\n${specList}`;\n const decision = await this.executeAgent(\n coordinator,\n delegatePrompt,\n rounds.length\n );\n rounds.push(decision);\n\n // Find the chosen specialist (fallback to first)\n const chosenId = decision.output.trim();\n const chosen =\n specialists.find((s) => s.id === chosenId) ?? specialists[0];\n\n if (!chosen) return decision.output;\n\n const result = await this.executeAgent(chosen, task, rounds.length);\n rounds.push(result);\n return result.output;\n }\n\n /** Consensus: all specialists vote, majority wins */\n private async runConsensus(\n task: string,\n rounds: TeamRound[]\n ): Promise<string> {\n const specialists = this.getSpecialists();\n const coordinator = this.getCoordinator();\n\n const results = await Promise.all(\n specialists.map((spec) => this.executeAgent(spec, task, rounds.length))\n );\n rounds.push(...results);\n\n // Coordinator evaluates consensus\n const consensusPrompt = `Evaluate these responses and determine the consensus answer. If >=${Math.round(this.consensusThreshold * 100)}% agree, return the consensus. Otherwise, synthesize the best answer.\\n\\nTask: ${task}\\n\\n${results.map((r) => `${r.memberId}: ${r.output}`).join(\"\\n\\n\")}`;\n const final = await this.executeAgent(\n coordinator,\n consensusPrompt,\n rounds.length\n );\n rounds.push(final);\n return final.output;\n }\n\n private async executeAgent(\n member: TeamMember,\n input: string,\n roundNum: number\n ): Promise<TeamRound> {\n const start = Date.now();\n const agentFn = (member.agent as any).execute ?? (member.agent as any).run;\n const result = await agentFn(input, this.context);\n return {\n round: roundNum,\n memberId: member.id,\n role: member.role,\n input,\n output: typeof result === \"string\" ? result : JSON.stringify(result),\n durationMs: Date.now() - start,\n };\n }\n}\n\n// =============================================================================\n// TeamBuilder — fluent API\n// =============================================================================\n\nexport class TeamBuilder {\n private _id = \"team\";\n private _members: TeamMember[] = [];\n private _strategy: CoordinationStrategy = \"broadcast\";\n private _maxRounds = 10;\n private _consensusThreshold = 0.5;\n private _eventBus?: EventBus;\n\n /** Set team ID */\n id(id: string): this {\n this._id = id;\n return this;\n }\n\n /** Add the coordinator agent */\n coordinator(agent: AgentNode, id?: string): this {\n this._members.push({\n id: id ?? \"coordinator\",\n role: \"coordinator\",\n agent,\n });\n return this;\n }\n\n /** Add a specialist agent */\n specialist(\n agent: AgentNode,\n options?: { id?: string; specialties?: string[] }\n ): this {\n this._members.push({\n id: options?.id ?? `specialist-${this._members.length}`,\n role: \"specialist\",\n agent,\n specialties: options?.specialties,\n });\n return this;\n }\n\n /** Set coordination strategy */\n strategy(strategy: CoordinationStrategy): this {\n this._strategy = strategy;\n return this;\n }\n\n /** Set max rounds */\n maxRounds(n: number): this {\n this._maxRounds = n;\n return this;\n }\n\n /** Set consensus threshold (0-1) */\n consensusThreshold(t: number): this {\n this._consensusThreshold = t;\n return this;\n }\n\n /** Set event bus */\n eventBus(bus: EventBus): this {\n this._eventBus = bus;\n return this;\n }\n\n /** Build the team */\n build(): Team {\n if (!this._members.some((m) => m.role === \"coordinator\")) {\n throw new Error(\"Team must have at least one coordinator\");\n }\n if (!this._members.some((m) => m.role === \"specialist\")) {\n throw new Error(\"Team must have at least one specialist\");\n }\n return new Team({\n id: this._id,\n members: this._members,\n strategy: this._strategy,\n maxRounds: this._maxRounds,\n consensusThreshold: this._consensusThreshold,\n eventBus: this._eventBus,\n });\n }\n}\n\n/** Factory function */\nexport function team(): TeamBuilder {\n return new TeamBuilder();\n}\n","// =============================================================================\n// WorkflowDSL — Fluent chainable API for building workflows\n// Usage: workflow('my-flow').then(step).branch(cond, ifTrue, ifFalse).parallel(steps).build()\n// =============================================================================\n\nimport type {\n WorkflowDefinition,\n WorkflowStep,\n WorkflowContext,\n RetryConfig,\n} from \"../domain/workflow.schema.js\";\nimport { z } from \"zod\";\n\n// =============================================================================\n// Types\n// =============================================================================\n\nexport interface StepDefinition {\n id: string;\n name?: string;\n execute: (ctx: WorkflowContext) => Promise<WorkflowContext>;\n rollback?: (ctx: WorkflowContext) => Promise<void>;\n retry?: Partial<RetryConfig>;\n inputSchema?: z.ZodType;\n outputSchema?: z.ZodType;\n}\n\nexport interface BranchDefinition {\n condition: (ctx: WorkflowContext) => boolean;\n ifTrue: StepDefinition | StepDefinition[];\n ifFalse?: StepDefinition | StepDefinition[];\n}\n\ninterface DSLNode {\n type: \"step\" | \"branch\" | \"parallel\";\n step?: StepDefinition;\n branch?: BranchDefinition;\n parallel?: StepDefinition[];\n}\n\n// =============================================================================\n// WorkflowDSL class\n// =============================================================================\n\nexport class WorkflowDSL {\n private _id: string;\n private _name?: string;\n private nodes: DSLNode[] = [];\n\n constructor(id: string) {\n this._id = id;\n }\n\n /** Set workflow name */\n name(name: string): this {\n this._name = name;\n return this;\n }\n\n /** Add a sequential step */\n then(step: StepDefinition): this {\n this.nodes.push({ type: \"step\", step });\n return this;\n }\n\n /** Add a conditional branch */\n branch(\n condition: (ctx: WorkflowContext) => boolean,\n ifTrue: StepDefinition | StepDefinition[],\n ifFalse?: StepDefinition | StepDefinition[]\n ): this {\n this.nodes.push({\n type: \"branch\",\n branch: { condition, ifTrue, ifFalse },\n });\n return this;\n }\n\n /** Add parallel steps (all execute concurrently) */\n parallel(...steps: StepDefinition[]): this {\n this.nodes.push({ type: \"parallel\", parallel: steps });\n return this;\n }\n\n /** Compile DSL to WorkflowDefinition for the engine */\n build(): WorkflowDefinition {\n const steps: WorkflowStep[] = [];\n let idx = 0;\n\n for (const node of this.nodes) {\n switch (node.type) {\n case \"step\":\n if (node.step) {\n steps.push(this.toWorkflowStep(node.step));\n }\n break;\n\n case \"branch\":\n if (node.branch) {\n steps.push(this.buildBranchStep(node.branch, idx));\n }\n break;\n\n case \"parallel\":\n if (node.parallel) {\n steps.push(this.buildParallelStep(node.parallel, idx));\n }\n break;\n }\n idx++;\n }\n\n return {\n id: this._id,\n name: this._name ?? this._id,\n steps,\n };\n }\n\n private toWorkflowStep(def: StepDefinition): WorkflowStep {\n const step: WorkflowStep = {\n id: def.id,\n name: def.name ?? def.id,\n execute: this.wrapWithValidation(def),\n rollback: def.rollback,\n retry: def.retry,\n };\n return step;\n }\n\n private wrapWithValidation(\n def: StepDefinition\n ): (ctx: WorkflowContext) => Promise<WorkflowContext> {\n return async (ctx: WorkflowContext) => {\n if (def.inputSchema) {\n def.inputSchema.parse(ctx);\n }\n const result = await def.execute(ctx);\n if (def.outputSchema) {\n def.outputSchema.parse(result);\n }\n return result;\n };\n }\n\n private buildBranchStep(\n branch: BranchDefinition,\n idx: number\n ): WorkflowStep {\n const ifTrueSteps = Array.isArray(branch.ifTrue)\n ? branch.ifTrue\n : [branch.ifTrue];\n const ifFalseSteps = branch.ifFalse\n ? Array.isArray(branch.ifFalse)\n ? branch.ifFalse\n : [branch.ifFalse]\n : [];\n\n return {\n id: `branch-${idx}`,\n name: `Branch ${idx}`,\n condition: branch.condition,\n execute: async (ctx: WorkflowContext) => {\n const path = branch.condition(ctx) ? ifTrueSteps : ifFalseSteps;\n let result = ctx;\n for (const s of path) {\n result = await this.wrapWithValidation(s)(result);\n }\n return result;\n },\n };\n }\n\n private buildParallelStep(\n steps: StepDefinition[],\n idx: number\n ): WorkflowStep {\n return {\n id: `parallel-${idx}`,\n name: `Parallel ${idx}`,\n type: \"parallel\",\n execute: async (ctx: WorkflowContext) => {\n const results = await Promise.all(\n steps.map((s) => this.wrapWithValidation(s)({ ...ctx }))\n );\n // Merge all results\n return results.reduce(\n (acc, r) => ({ ...acc, ...r }),\n ctx\n );\n },\n };\n }\n}\n\n/** Factory function */\nexport function workflow(id: string): WorkflowDSL {\n return new WorkflowDSL(id);\n}\n","// =============================================================================\n// Multimodal — Image processing and multimodal message types\n// =============================================================================\n\nimport type { LanguageModel } from \"../core/llm/index.js\";\nimport { generateText } from \"../core/llm/index.js\";\n\n// =============================================================================\n// Types\n// =============================================================================\n\nexport type ImageSource =\n | { type: \"url\"; url: string }\n | { type: \"base64\"; data: string; mimeType: string }\n | { type: \"file\"; path: string };\n\nexport interface ImageInput {\n source: ImageSource;\n detail?: \"auto\" | \"low\" | \"high\";\n}\n\nexport interface MultimodalContent {\n type: \"text\" | \"image\";\n text?: string;\n image?: ImageInput;\n}\n\nexport interface MultimodalMessage {\n role: \"user\" | \"assistant\" | \"system\";\n content: MultimodalContent[];\n}\n\nexport interface MultimodalResult {\n text: string;\n usage?: { inputTokens?: number; outputTokens?: number };\n durationMs: number;\n}\n\n// =============================================================================\n// MultimodalAgent — Handles text + image inputs\n// =============================================================================\n\nexport class MultimodalAgent {\n private model: LanguageModel;\n private instructions?: string;\n\n constructor(config: { model: LanguageModel; instructions?: string }) {\n this.model = config.model;\n this.instructions = config.instructions;\n }\n\n /** Process a multimodal message (text + images) */\n async process(messages: MultimodalMessage[]): Promise<MultimodalResult> {\n const start = Date.now();\n\n // Convert to AI SDK format\n const prompt = this.buildPrompt(messages);\n\n const result = await generateText({\n model: this.model as any,\n prompt,\n system: this.instructions,\n });\n\n return {\n text: result.text,\n usage: result.usage\n ? {\n inputTokens: result.usage.inputTokens,\n outputTokens: result.usage.outputTokens,\n }\n : undefined,\n durationMs: Date.now() - start,\n };\n }\n\n /** Shortcut: describe a single image */\n async describeImage(\n image: ImageInput,\n prompt?: string\n ): Promise<MultimodalResult> {\n return this.process([\n {\n role: \"user\",\n content: [\n { type: \"image\", image },\n {\n type: \"text\",\n text: prompt ?? \"Describe this image in detail.\",\n },\n ],\n },\n ]);\n }\n\n /** Shortcut: extract text from image (OCR) */\n async extractText(image: ImageInput): Promise<MultimodalResult> {\n return this.process([\n {\n role: \"user\",\n content: [\n { type: \"image\", image },\n {\n type: \"text\",\n text: \"Extract all visible text from this image. Return only the extracted text, preserving the original formatting as much as possible.\",\n },\n ],\n },\n ]);\n }\n\n /** Shortcut: compare two images */\n async compareImages(\n image1: ImageInput,\n image2: ImageInput,\n prompt?: string\n ): Promise<MultimodalResult> {\n return this.process([\n {\n role: \"user\",\n content: [\n { type: \"image\", image: image1 },\n { type: \"image\", image: image2 },\n {\n type: \"text\",\n text:\n prompt ??\n \"Compare these two images and describe the differences.\",\n },\n ],\n },\n ]);\n }\n\n private buildPrompt(messages: MultimodalMessage[]): string {\n return messages\n .map((msg) =>\n msg.content\n .filter((c) => c.type === \"text\")\n .map((c) => c.text)\n .join(\"\\n\")\n )\n .join(\"\\n\\n\");\n }\n}\n\n// =============================================================================\n// Factory function\n// =============================================================================\n\nexport function multimodal(config: {\n model: LanguageModel;\n instructions?: string;\n}): MultimodalAgent {\n return new MultimodalAgent(config);\n}\n","// =============================================================================\n// Video Processing — Frame extraction, analysis, audio extraction\n// =============================================================================\n\nimport type { LanguageModel } from \"../core/llm/index.js\";\nimport {\n MultimodalAgent,\n type ImageInput,\n type MultimodalResult,\n} from \"./multimodal.js\";\n\n// =============================================================================\n// Types\n// =============================================================================\n\nexport type VideoSource =\n | { type: \"url\"; url: string }\n | { type: \"file\"; path: string }\n | { type: \"base64\"; data: string; mimeType: string };\n\nexport interface VideoInput {\n source: VideoSource;\n /** Duration in seconds (if known) */\n duration?: number;\n}\n\nexport interface VideoFrame {\n index: number;\n timestampMs: number;\n image: ImageInput;\n}\n\nexport interface FrameExtractionOptions {\n /** Interval between frames in milliseconds (default: 1000) */\n intervalMs?: number;\n /** Maximum number of frames to extract (default: 30) */\n maxFrames?: number;\n /** Start time in milliseconds */\n startMs?: number;\n /** End time in milliseconds */\n endMs?: number;\n}\n\nexport interface VideoAnalysisResult {\n description: string;\n frames: Array<{\n index: number;\n timestampMs: number;\n description: string;\n }>;\n duration?: number;\n durationMs: number;\n}\n\nexport interface AudioExtractionResult {\n audio: Uint8Array;\n format: string;\n durationMs: number;\n}\n\n// =============================================================================\n// FrameExtractor — Extracts frames from video at intervals\n// =============================================================================\n\nexport interface FrameExtractorPort {\n extractFrames(\n video: VideoInput,\n options?: FrameExtractionOptions\n ): Promise<VideoFrame[]>;\n extractAudio?(video: VideoInput): Promise<AudioExtractionResult>;\n}\n\n/**\n * Default frame extractor — generates placeholder frames.\n * In production, replace with ffmpeg-based or browser Canvas adapter.\n */\nexport class DefaultFrameExtractor implements FrameExtractorPort {\n async extractFrames(\n video: VideoInput,\n options: FrameExtractionOptions = {}\n ): Promise<VideoFrame[]> {\n const intervalMs = options.intervalMs ?? 1000;\n const maxFrames = options.maxFrames ?? 30;\n const startMs = options.startMs ?? 0;\n const durationMs = (video.duration ?? 30) * 1000;\n const endMs = options.endMs ?? durationMs;\n\n const frames: VideoFrame[] = [];\n let ts = startMs;\n let index = 0;\n\n while (ts < endMs && index < maxFrames) {\n frames.push({\n index,\n timestampMs: ts,\n image: this.frameToImage(video, ts),\n });\n ts += intervalMs;\n index++;\n }\n\n return frames;\n }\n\n private frameToImage(video: VideoInput, timestampMs: number): ImageInput {\n // In production, this extracts actual frame data\n const sourceId =\n video.source.type === \"url\"\n ? video.source.url\n : video.source.type === \"file\"\n ? video.source.path\n : \"base64-video\";\n\n return {\n source: {\n type: \"url\",\n url: `frame://${sourceId}?t=${timestampMs}`,\n },\n };\n }\n}\n\n// =============================================================================\n// VideoProcessor — Orchestrates frame extraction + multimodal analysis\n// =============================================================================\n\nexport class VideoProcessor {\n private multimodal: MultimodalAgent;\n private frameExtractor: FrameExtractorPort;\n\n constructor(config: {\n model: LanguageModel;\n instructions?: string;\n frameExtractor?: FrameExtractorPort;\n }) {\n this.multimodal = new MultimodalAgent({\n model: config.model,\n instructions: config.instructions ?? \"You are a video analysis expert.\",\n });\n this.frameExtractor =\n config.frameExtractor ?? new DefaultFrameExtractor();\n }\n\n /** Extract frames from video at specified intervals */\n async extractFrames(\n video: VideoInput,\n options?: FrameExtractionOptions\n ): Promise<VideoFrame[]> {\n return this.frameExtractor.extractFrames(video, options);\n }\n\n /** Describe video by analyzing individual frames and synthesizing */\n async describeVideo(\n video: VideoInput,\n options?: FrameExtractionOptions & { prompt?: string }\n ): Promise<VideoAnalysisResult> {\n const start = Date.now();\n const frames = await this.extractFrames(video, options);\n\n // Analyze each frame\n const frameDescriptions = await Promise.all(\n frames.map(async (frame) => {\n const result = await this.multimodal.describeImage(\n frame.image,\n `Describe what is happening at timestamp ${frame.timestampMs}ms in this video frame.`\n );\n return {\n index: frame.index,\n timestampMs: frame.timestampMs,\n description: result.text,\n };\n })\n );\n\n // Synthesize overall description\n const framesSummary = frameDescriptions\n .map((f) => `[${f.timestampMs}ms] ${f.description}`)\n .join(\"\\n\");\n\n const synthesis = await this.multimodal.process([\n {\n role: \"user\",\n content: [\n {\n type: \"text\",\n text: `Based on these video frame descriptions, provide a coherent summary of what happens in the video:\\n\\n${framesSummary}\\n\\n${options?.prompt ?? \"Describe the video.\"}`,\n },\n ],\n },\n ]);\n\n return {\n description: synthesis.text,\n frames: frameDescriptions,\n duration: video.duration,\n durationMs: Date.now() - start,\n };\n }\n\n /** Extract audio from video (requires FrameExtractorPort with audio support) */\n async extractAudio(video: VideoInput): Promise<AudioExtractionResult> {\n if (!this.frameExtractor.extractAudio) {\n throw new Error(\n \"Audio extraction not supported by current FrameExtractor. \" +\n \"Provide a FrameExtractorPort that implements extractAudio().\"\n );\n }\n return this.frameExtractor.extractAudio(video);\n }\n}\n\n// =============================================================================\n// Factory function\n// =============================================================================\n\nexport function videoProcessor(config: {\n model: LanguageModel;\n instructions?: string;\n frameExtractor?: FrameExtractorPort;\n}): VideoProcessor {\n return new VideoProcessor(config);\n}\n","// =============================================================================\n// gauss — Clean Public API Surface\n// =============================================================================\n//\n// Zero-config quickstart:\n// import gauss from 'gauss'\n// const answer = await gauss('Explain quantum computing')\n//\n// Power user:\n// import { agent, graph, rag, team, workflow } from 'gauss'\n//\n// =============================================================================\n\nimport type { LanguageModel } from \"./core/llm/index.js\";\nimport type { AgentConfig } from \"./types.js\";\nimport type { GraphConfig } from \"./domain/graph.schema.js\";\nimport { AgentBuilder } from \"./agent/agent-builder.js\";\nimport { AgentGraph } from \"./graph/agent-graph.js\";\nimport { RAGPipeline } from \"./rag/pipeline.js\";\nimport type { RAGPipelineConfig } from \"./rag/pipeline.js\";\n\n// =============================================================================\n// Smart model detection from environment\n// =============================================================================\n\ninterface QuickOptions {\n model?: string | LanguageModel;\n instructions?: string;\n temperature?: number;\n}\n\nconst ENV_PROVIDER_MAP: Array<{ env: string; pkg: string; factory: string; defaultModel: string }> = [\n { env: \"OPENAI_API_KEY\", pkg: \"@ai-sdk/openai\", factory: \"createOpenAI\", defaultModel: \"gpt-5.2\" },\n { env: \"ANTHROPIC_API_KEY\", pkg: \"@ai-sdk/anthropic\", factory: \"createAnthropic\", defaultModel: \"claude-sonnet-4-20250514\" },\n { env: \"GOOGLE_GENERATIVE_AI_API_KEY\", pkg: \"@ai-sdk/google\", factory: \"createGoogleGenerativeAI\", defaultModel: \"gemini-2.5-flash-preview-05-20\" },\n { env: \"GROQ_API_KEY\", pkg: \"@ai-sdk/groq\", factory: \"createGroq\", defaultModel: \"llama-3.3-70b-versatile\" },\n { env: \"MISTRAL_API_KEY\", pkg: \"@ai-sdk/mistral\", factory: \"createMistral\", defaultModel: \"mistral-large-latest\" },\n];\n\nasync function detectModel(): Promise<LanguageModel> {\n for (const { env, pkg, factory, defaultModel } of ENV_PROVIDER_MAP) {\n if (process.env[env]) {\n try {\n const mod = await import(pkg);\n const create = mod[factory] ?? mod.default;\n if (typeof create === \"function\") {\n return create()(defaultModel) as LanguageModel;\n }\n } catch {\n // Package not installed, try next\n }\n }\n }\n throw new GaussError(\n \"No AI provider detected\",\n \"Set one of these environment variables: \" +\n ENV_PROVIDER_MAP.map((p) => p.env).join(\", \") +\n \"\\n\\nOr provide a model explicitly:\\n\" +\n \" import { openai } from 'gauss/providers'\\n\" +\n \" const answer = await gauss('Hello', { model: openai('gpt-5.2') })\"\n );\n}\n\n// =============================================================================\n// GaussError — Actionable error messages\n// =============================================================================\n\nexport class GaussError extends Error {\n readonly suggestion: string;\n\n constructor(message: string, suggestion: string) {\n super(`${message}\\n\\n💡 ${suggestion}`);\n this.name = \"GaussError\";\n this.suggestion = suggestion;\n }\n}\n\n// =============================================================================\n// gauss() — Zero-config one-liner\n// =============================================================================\n\n/**\n * The simplest way to use Gauss. Auto-detects model from environment.\n *\n * @example\n * ```ts\n * // One-liner (auto-detects OPENAI_API_KEY, ANTHROPIC_API_KEY, etc.)\n * const answer = await gauss('Explain quantum computing')\n *\n * // With options\n * const answer = await gauss('Translate to Italian', {\n * model: 'gpt-5.2',\n * instructions: 'You are a translator.',\n * temperature: 0.3,\n * })\n * ```\n */\nasync function gauss(prompt: string, options?: QuickOptions): Promise<string> {\n let model: LanguageModel;\n\n if (options?.model) {\n if (typeof options.model === \"string\") {\n // String shorthand: \"gpt-5.2\" → use detected provider\n model = await detectModel();\n } else {\n model = options.model;\n }\n } else {\n model = await detectModel();\n }\n\n const { generateText } = await import(\"./core/llm/index.js\");\n const result = await (generateText as any)({\n model,\n prompt,\n system: options?.instructions,\n temperature: options?.temperature,\n });\n\n return result.text;\n}\n\n// Attach named exports as properties for `import gauss from 'gauss'` usage\ngauss.agent = agent;\ngauss.graph = graph;\ngauss.rag = rag;\n\nexport default gauss;\n\n// =============================================================================\n// agent() — Create an agent via builder pattern\n// =============================================================================\n\n/**\n * Create a new agent builder with the given configuration.\n *\n * @example\n * ```ts\n * const myAgent = agent({\n * model: openai('gpt-5.2'),\n * instructions: 'You are a helpful assistant.',\n * })\n * .withPlanning()\n * .withMemory(memory)\n * .build()\n *\n * const result = await myAgent.run('Hello!')\n * ```\n */\nexport function agent(config: AgentConfig): AgentBuilder {\n return new AgentBuilder(config);\n}\n\n// =============================================================================\n// graph() — Create a multi-agent graph\n// =============================================================================\n\n/**\n * Create a new agent graph builder.\n *\n * @example\n * ```ts\n * const pipeline = graph()\n * .node('extract', { model, instructions: 'Extract entities.' })\n * .node('classify', { model, instructions: 'Classify entities.' })\n * .edge('extract', 'classify')\n * .build()\n *\n * const result = await pipeline.run('Analyze this document...')\n * ```\n */\nexport function graph(config?: Partial<GraphConfig>) {\n return AgentGraph.create(config);\n}\n\n// =============================================================================\n// rag() — Create a RAG pipeline\n// =============================================================================\n\n/**\n * Create a new RAG (Retrieval-Augmented Generation) pipeline.\n *\n * @example\n * ```ts\n * const pipeline = rag({\n * documentPort: new MarkdownDocumentAdapter(),\n * embeddingPort: new InMemoryEmbeddingAdapter(),\n * vectorStorePort: new InMemoryVectorStore(),\n * })\n *\n * await pipeline.ingest('path/to/docs')\n * const result = await pipeline.query('How does authentication work?')\n * ```\n */\nexport function rag(config: RAGPipelineConfig): RAGPipeline {\n return new RAGPipeline(config);\n}\n\n// =============================================================================\n// team() — Create a team of coordinated agents\n// =============================================================================\n\nexport { team } from \"./graph/team-builder.js\";\nexport type { CoordinationStrategy, TeamResult } from \"./graph/team-builder.js\";\n\n// =============================================================================\n// workflow() — Create a workflow via fluent DSL\n// =============================================================================\n\nexport { workflow } from \"./domain/workflow-dsl.js\";\nexport type { StepDefinition, BranchDefinition } from \"./domain/workflow-dsl.js\";\n\n// =============================================================================\n// multimodal() — Create a multimodal (text + image) agent\n// =============================================================================\n\nexport { multimodal } from \"./domain/multimodal.js\";\nexport type { ImageInput, MultimodalMessage, MultimodalResult } from \"./domain/multimodal.js\";\n\n// =============================================================================\n// videoProcessor() — Create a video analysis pipeline\n// =============================================================================\n\nexport { videoProcessor } from \"./domain/video-processor.js\";\nexport type { VideoInput, VideoFrame, VideoAnalysisResult } from \"./domain/video-processor.js\";\n","// =============================================================================\n// Gauss Agent Core — run() Implementation\n// Executes generateText with full decorator lifecycle.\n// =============================================================================\n\nimport type {\n AgentConfig,\n AgentResult,\n Decorator,\n RunContext,\n RunOptions,\n StepContext,\n ToolCallContext,\n} from \"./types.js\";\nimport type { CoreMessage, StepResult, ToolResult } from \"../llm/types.js\";\nimport { generateText } from \"../llm/generate-text.js\";\n\n/**\n * Execute an agent run with decorator lifecycle hooks.\n *\n * Lifecycle order:\n * beforeRun (FIFO) → generateText (with step/tool hooks) → afterRun (LIFO)\n */\nexport async function runAgent(\n config: AgentConfig,\n decorators: ReadonlyArray<Decorator>,\n prompt: string,\n options?: RunOptions,\n): Promise<AgentResult> {\n const startTime = performance.now();\n\n // Build initial context\n let ctx = buildRunContext(config, prompt, options);\n\n // Execute beforeRun (FIFO order)\n for (const d of decorators) {\n if (d.beforeRun) {\n const result = await d.beforeRun(ctx);\n if (result) ctx = result;\n }\n }\n\n try {\n // Build messages\n const messages: CoreMessage[] = [];\n if (ctx.options.messages) {\n messages.push(...ctx.options.messages);\n }\n\n // Resolve output spec (per-run overrides config)\n const outputSpec = ctx.options.output ?? config.output;\n\n // Call generateText\n const generateResult = await generateText({\n model: config.model,\n system: config.instructions,\n prompt: ctx.prompt,\n tools: config.tools,\n maxSteps: ctx.options.maxSteps ?? config.maxSteps ?? 10,\n output: outputSpec\n ? { type: \"object\" as const, schema: outputSpec.schema }\n : undefined,\n abortSignal: ctx.abortSignal,\n });\n\n // Build AgentResult\n let agentResult: AgentResult = {\n text: generateResult.text,\n output: generateResult.text as never,\n steps: generateResult.steps,\n toolCalls: generateResult.toolCalls,\n toolResults: generateResult.toolResults,\n usage: generateResult.usage,\n finishReason: generateResult.finishReason,\n duration: performance.now() - startTime,\n messages: ctx.messages,\n };\n\n // Execute afterRun (LIFO order)\n for (let i = decorators.length - 1; i >= 0; i--) {\n const d = decorators[i];\n if (d.afterRun) {\n agentResult = await d.afterRun(ctx, agentResult);\n }\n }\n\n return agentResult;\n } catch (error) {\n // Execute onError hooks\n for (const d of decorators) {\n if (d.onError) {\n await d.onError(error as Error, ctx);\n }\n }\n throw error;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nfunction buildRunContext(\n config: AgentConfig,\n prompt: string,\n options?: RunOptions,\n): RunContext {\n return {\n config,\n prompt,\n options: options ?? {},\n messages: [],\n metadata: options?.metadata ?? {},\n abortSignal: options?.abortSignal,\n };\n}\n","// =============================================================================\n// Gauss Agent Core — stream() Implementation\n// Streaming agent execution with decorator lifecycle.\n// =============================================================================\n\nimport type {\n AgentConfig,\n AgentResult,\n AgentStream,\n Decorator,\n RunContext,\n RunOptions,\n StreamChunk,\n} from \"./types.js\";\nimport type { CoreMessage, TokenUsage } from \"../llm/types.js\";\nimport { streamText } from \"../llm/stream-text.js\";\n\n/**\n * Execute a streaming agent run with decorator lifecycle.\n * Returns an AgentStream that is both async-iterable and has promise accessors.\n */\nexport function streamAgent(\n config: AgentConfig,\n decorators: ReadonlyArray<Decorator>,\n prompt: string,\n options?: RunOptions,\n initPromise?: Promise<void>,\n): AgentStream {\n const startTime = performance.now();\n const abortController = new AbortController();\n\n // Deferred result\n let resolveResult: (r: AgentResult) => void;\n let rejectResult: (e: Error) => void;\n const resultPromise = new Promise<AgentResult>((res, rej) => {\n resolveResult = res;\n rejectResult = rej;\n });\n\n let resolveText: (t: string) => void;\n const textPromise = new Promise<string>((res) => {\n resolveText = res;\n });\n\n let resolveUsage: (u: TokenUsage) => void;\n const usagePromise = new Promise<TokenUsage>((res) => {\n resolveUsage = res;\n });\n\n // The async generator that yields chunks\n async function* generateChunks(): AsyncGenerator<StreamChunk> {\n // Wait for initialization\n if (initPromise) await initPromise;\n\n // Build context\n let ctx = buildRunContext(config, prompt, options, abortController.signal);\n\n // Execute beforeRun (FIFO)\n for (const d of decorators) {\n if (d.beforeRun) {\n const result = await d.beforeRun(ctx);\n if (result) ctx = result;\n }\n }\n\n try {\n const outputSpec = ctx.options.output ?? config.output;\n\n const streamResult = await streamText({\n model: config.model,\n system: config.instructions,\n prompt: ctx.prompt,\n tools: config.tools,\n maxSteps: ctx.options.maxSteps ?? config.maxSteps ?? 10,\n output: outputSpec ? { type: \"object\" as const, schema: outputSpec.schema } : undefined,\n abortSignal: abortController.signal,\n });\n\n let fullText = \"\";\n\n // Yield text chunks from the stream\n const reader = streamResult.textStream.getReader();\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n fullText += value;\n yield { text: value };\n }\n } finally {\n reader.releaseLock();\n }\n\n // Resolve promises with final values\n const [text, usage, toolCalls, toolResults, finishReason, steps] = await Promise.all([\n streamResult.text,\n streamResult.usage,\n streamResult.toolCalls,\n streamResult.toolResults,\n streamResult.finishReason,\n streamResult.steps,\n ]);\n\n resolveText(text);\n resolveUsage(usage);\n\n let agentResult: AgentResult = {\n text,\n output: text as never,\n steps,\n toolCalls,\n toolResults,\n usage,\n finishReason,\n duration: performance.now() - startTime,\n messages: ctx.messages,\n };\n\n // Execute afterRun (LIFO)\n for (let i = decorators.length - 1; i >= 0; i--) {\n const d = decorators[i];\n if (d.afterRun) {\n agentResult = await d.afterRun(ctx, agentResult);\n }\n }\n\n resolveResult(agentResult);\n } catch (error) {\n for (const d of decorators) {\n if (d.onError) {\n await d.onError(error as Error, ctx);\n }\n }\n rejectResult!(error as Error);\n throw error;\n }\n }\n\n // Build the AgentStream object\n const chunks = generateChunks();\n\n const stream: AgentStream = {\n [Symbol.asyncIterator]() {\n return chunks;\n },\n\n get text() {\n return textPromise;\n },\n\n get result() {\n return resultPromise;\n },\n\n get usage() {\n return usagePromise;\n },\n\n abort() {\n abortController.abort();\n },\n };\n\n return stream;\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nfunction buildRunContext(\n config: AgentConfig,\n prompt: string,\n options?: RunOptions,\n abortSignal?: AbortSignal,\n): RunContext {\n return {\n config,\n prompt,\n options: options ?? {},\n messages: [] as CoreMessage[],\n metadata: options?.metadata ?? {},\n abortSignal,\n };\n}\n","// =============================================================================\n// Gauss Agent Core — Subagent-as-Tool Conversion\n// Converts agents config into automatic tools.\n// =============================================================================\n\nimport { z } from \"zod\";\nimport { tool } from \"../llm/tool.js\";\nimport type { ToolSet } from \"../llm/types.js\";\nimport type { AgentInstance } from \"./types.js\";\n\n/**\n * Convert a record of AgentInstances into a ToolSet.\n * Each agent becomes a tool that delegates to agent.run().\n *\n * @example\n * ```ts\n * const tools = agentsToTools({\n * researcher: researcherAgent,\n * writer: writerAgent,\n * });\n * // tools.researcher — calls researcherAgent.run(prompt)\n * // tools.writer — calls writerAgent.run(prompt)\n * ```\n */\nexport function agentsToTools(\n agents: Record<string, AgentInstance>,\n): ToolSet {\n const tools: ToolSet = {};\n\n for (const [name, agent] of Object.entries(agents)) {\n const description =\n agent.config.description ??\n `Delegate task to the \"${agent.config.name ?? name}\" agent`;\n\n tools[name] = tool({\n description,\n inputSchema: z.object({\n prompt: z.string().describe(\"The task or question to delegate to this agent\"),\n }),\n execute: async ({ prompt }) => {\n const result = await agent.run(prompt);\n return result.text;\n },\n });\n }\n\n return tools;\n}\n","// =============================================================================\n// Gauss Agent Core — Factory Function\n// Agent() is the foundational primitive of gauss-flow.\n// Every .with() returns a NEW immutable instance.\n// =============================================================================\n\nimport type {\n AgentConfig,\n AgentInstance,\n AgentResult,\n AgentStream,\n Decorator,\n RunOptions,\n} from \"./types.js\";\nimport { runAgent } from \"./run.js\";\nimport { streamAgent } from \"./stream.js\";\nimport { agentsToTools } from \"./subagent.js\";\n\n// ---------------------------------------------------------------------------\n// Defaults\n// ---------------------------------------------------------------------------\n\nconst DEFAULT_MAX_STEPS = 10;\n\n// ---------------------------------------------------------------------------\n// Agent factory\n// ---------------------------------------------------------------------------\n\n/**\n * Create a new Agent instance.\n *\n * @example\n * ```ts\n * const agent = Agent({ model, instructions: \"You help with weather.\", tools: { weather } });\n * const { text } = await agent.run(\"What's the weather in Rome?\");\n * ```\n */\nexport function Agent(config: AgentConfig): AgentInstance {\n if (!config.model) {\n throw new Error(\"Agent requires a model\");\n }\n\n const resolvedConfig: AgentConfig = {\n ...config,\n maxSteps: config.maxSteps ?? DEFAULT_MAX_STEPS,\n tools: mergeToolsWithAgents(config.tools, config.agents),\n };\n\n return createInstance(resolvedConfig, []);\n}\n\n// ---------------------------------------------------------------------------\n// Internal instance builder\n// ---------------------------------------------------------------------------\n\nfunction createInstance(\n config: AgentConfig,\n decorators: ReadonlyArray<Decorator>,\n): AgentInstance {\n const frozenConfig = Object.freeze({ ...config });\n const frozenDecorators = Object.freeze([...decorators]);\n\n let initialized = false;\n\n async function ensureInitialized(): Promise<void> {\n if (initialized) return;\n initialized = true;\n for (const d of frozenDecorators) {\n if (d.initialize) await d.initialize();\n }\n }\n\n const instance: AgentInstance = {\n async run(prompt: string, options?: RunOptions): Promise<AgentResult> {\n await ensureInitialized();\n return runAgent(frozenConfig, frozenDecorators, prompt, options);\n },\n\n stream(prompt: string, options?: RunOptions): AgentStream {\n const initPromise = ensureInitialized();\n return streamAgent(frozenConfig, frozenDecorators, prompt, options, initPromise);\n },\n\n with(decorator: Decorator): AgentInstance {\n return createInstance(frozenConfig, [...frozenDecorators, decorator]);\n },\n\n clone(overrides?: Partial<AgentConfig>): AgentInstance {\n const merged: AgentConfig = {\n ...frozenConfig,\n ...overrides,\n tools: mergeToolsWithAgents(\n overrides?.tools ?? frozenConfig.tools,\n overrides?.agents ?? frozenConfig.agents,\n ),\n };\n return createInstance(merged, [...frozenDecorators]);\n },\n\n get config() {\n return frozenConfig;\n },\n\n get decorators() {\n return frozenDecorators;\n },\n };\n\n return Object.freeze(instance);\n}\n\n// ---------------------------------------------------------------------------\n// Merge explicit tools with agent-derived tools\n// ---------------------------------------------------------------------------\n\nfunction mergeToolsWithAgents(\n tools: AgentConfig[\"tools\"],\n agents: AgentConfig[\"agents\"],\n): AgentConfig[\"tools\"] {\n if (!agents || Object.keys(agents).length === 0) {\n return tools;\n }\n\n const agentTools = agentsToTools(agents);\n return { ...agentTools, ...tools }; // explicit tools take precedence\n}\n","// =============================================================================\n// Gauss Agent Core — graph() Factory\n// Simple DAG execution of Agent instances.\n// =============================================================================\n\nimport type { AgentInstance, AgentResult } from \"./types.js\";\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport interface GraphConfig {\n nodes: Record<string, AgentInstance>;\n edges: Array<{ from: string; to: string }>;\n conditions?: Record<string, (result: AgentResult) => boolean>;\n}\n\nexport interface GraphResult {\n /** Final output from the terminal node(s) */\n output: string;\n /** Results from all nodes */\n nodeResults: Map<string, AgentResult>;\n /** Total duration in ms */\n duration: number;\n}\n\nexport interface GraphPipeline {\n run(input: string): Promise<GraphResult>;\n}\n\n// ---------------------------------------------------------------------------\n// graph() factory\n// ---------------------------------------------------------------------------\n\n/**\n * Create a DAG pipeline of Agent instances.\n *\n * @example\n * ```ts\n * const pipeline = graph({\n * nodes: { research: researchAgent, write: writeAgent, review: reviewAgent },\n * edges: [\n * { from: \"research\", to: \"write\" },\n * { from: \"write\", to: \"review\" },\n * ],\n * });\n * const result = await pipeline.run(\"Write an article about AI\");\n * ```\n */\nexport function graph(config: GraphConfig): GraphPipeline {\n validateGraph(config);\n\n return {\n async run(input: string): Promise<GraphResult> {\n const startTime = performance.now();\n const nodeResults = new Map<string, AgentResult>();\n\n // Build dependency map: nodeId → [nodes it depends on]\n const deps = new Map<string, string[]>();\n for (const nodeId of Object.keys(config.nodes)) {\n deps.set(nodeId, []);\n }\n for (const edge of config.edges) {\n deps.get(edge.to)!.push(edge.from);\n }\n\n // Topological execution\n const executed = new Set<string>();\n const nodeIds = Object.keys(config.nodes);\n\n while (executed.size < nodeIds.length) {\n // Find ready nodes (all deps satisfied)\n const ready = nodeIds.filter(\n (id) =>\n !executed.has(id) &&\n deps.get(id)!.every((dep) => executed.has(dep)),\n );\n\n if (ready.length === 0) {\n throw new Error(\"Graph execution stalled — check for cycles\");\n }\n\n // Execute ready nodes in parallel\n await Promise.all(\n ready.map(async (nodeId) => {\n const agent = config.nodes[nodeId];\n const depResults = deps.get(nodeId)!;\n\n // Build prompt with upstream results\n let prompt = input;\n if (depResults.length > 0) {\n const contextParts = depResults.map((depId) => {\n const depResult = nodeResults.get(depId);\n return `[${depId}]: ${depResult?.text ?? \"\"}`;\n });\n prompt = `${input}\\n\\n--- Previous results ---\\n${contextParts.join(\"\\n\")}`;\n }\n\n // Check edge conditions\n const edgeKey = depResults.length === 1\n ? `${depResults[0]}->${nodeId}`\n : undefined;\n if (edgeKey && config.conditions?.[edgeKey]) {\n const depResult = nodeResults.get(depResults[0]);\n if (depResult && !config.conditions[edgeKey](depResult)) {\n // Condition not met — skip this node\n executed.add(nodeId);\n return;\n }\n }\n\n const result = await agent.run(prompt);\n nodeResults.set(nodeId, result);\n executed.add(nodeId);\n }),\n );\n }\n\n // Find terminal nodes (no outgoing edges)\n const hasOutgoing = new Set(config.edges.map((e) => e.from));\n const terminals = nodeIds.filter((id) => !hasOutgoing.has(id));\n const terminalOutputs = terminals\n .map((id) => nodeResults.get(id)?.text ?? \"\")\n .filter(Boolean);\n\n return {\n output: terminalOutputs.join(\"\\n\\n\"),\n nodeResults,\n duration: performance.now() - startTime,\n };\n },\n };\n}\n\n// ---------------------------------------------------------------------------\n// Validation\n// ---------------------------------------------------------------------------\n\nfunction validateGraph(config: GraphConfig): void {\n const nodeIds = new Set(Object.keys(config.nodes));\n\n for (const edge of config.edges) {\n if (!nodeIds.has(edge.from)) {\n throw new Error(`Edge source \"${edge.from}\" is not a registered node`);\n }\n if (!nodeIds.has(edge.to)) {\n throw new Error(`Edge target \"${edge.to}\" is not a registered node`);\n }\n }\n\n // Cycle detection (simple DFS)\n const visited = new Set<string>();\n const inStack = new Set<string>();\n\n const adjList = new Map<string, string[]>();\n for (const id of nodeIds) adjList.set(id, []);\n for (const edge of config.edges) {\n adjList.get(edge.from)!.push(edge.to);\n }\n\n function dfs(node: string): boolean {\n visited.add(node);\n inStack.add(node);\n for (const neighbor of adjList.get(node) ?? []) {\n if (inStack.has(neighbor)) return true; // cycle\n if (!visited.has(neighbor) && dfs(neighbor)) return true;\n }\n inStack.delete(node);\n return false;\n }\n\n for (const id of nodeIds) {\n if (!visited.has(id) && dfs(id)) {\n throw new Error(\"Graph contains a cycle\");\n }\n }\n}\n","// =============================================================================\n// Memory Decorator — Injects conversation history and user memories\n// =============================================================================\n\nimport type { Decorator, RunContext, AgentResult } from \"../core/agent/types.js\";\n\nexport interface MemoryPort {\n saveConversation(sessionId: string, messages: unknown[]): Promise<void>;\n loadConversation(sessionId: string): Promise<unknown[]>;\n saveMetadata(sessionId: string, key: string, value: unknown): Promise<void>;\n loadMetadata<T>(sessionId: string, key: string): Promise<T | null>;\n}\n\nexport interface MemoryDecoratorConfig {\n backend: MemoryPort;\n sessionId?: string;\n maxMessages?: number;\n}\n\nexport function memory(config: MemoryDecoratorConfig): Decorator {\n const { backend, maxMessages = 100 } = config;\n\n return {\n name: \"memory\",\n\n async beforeRun(ctx: RunContext) {\n const sessionId = config.sessionId ?? (ctx.metadata[\"sessionId\"] as string) ?? \"default\";\n ctx.metadata[\"sessionId\"] = sessionId;\n\n const history = await backend.loadConversation(sessionId);\n if (history && history.length > 0) {\n const recent = history.slice(-maxMessages);\n ctx.messages.push(...(recent as typeof ctx.messages));\n }\n\n return ctx;\n },\n\n async afterRun(ctx: RunContext, result: AgentResult) {\n const sessionId = ctx.metadata[\"sessionId\"] as string ?? \"default\";\n\n await backend.saveConversation(sessionId, [\n { role: \"user\", content: ctx.prompt },\n { role: \"assistant\", content: result.text },\n ]);\n\n return result;\n },\n };\n}\n","// =============================================================================\n// Telemetry Decorator — Spans and metrics for agent execution\n// =============================================================================\n\nimport type { Decorator, RunContext, AgentResult } from \"../core/agent/types.js\";\n\nexport interface TelemetrySpan {\n setAttribute(key: string, value: string | number | boolean): void;\n setStatus(status: \"ok\" | \"error\", message?: string): void;\n end(): void;\n}\n\nexport interface TelemetryPort {\n startSpan(name: string, attributes?: Record<string, string | number | boolean>): TelemetrySpan;\n recordMetric(name: string, value: number, attributes?: Record<string, string>): void;\n flush(): Promise<void>;\n}\n\nexport interface TelemetryDecoratorConfig {\n provider: TelemetryPort;\n spanPrefix?: string;\n}\n\nexport function telemetry(config: TelemetryDecoratorConfig): Decorator {\n const { provider, spanPrefix = \"agent\" } = config;\n\n return {\n name: \"telemetry\",\n\n async beforeRun(ctx: RunContext) {\n const span = provider.startSpan(`${spanPrefix}.run`, {\n \"agent.name\": ctx.config.name ?? \"unnamed\",\n \"agent.prompt.length\": ctx.prompt.length,\n });\n ctx.metadata[\"_telemetrySpan\"] = span;\n ctx.metadata[\"_telemetryStartTime\"] = performance.now();\n return ctx;\n },\n\n async afterRun(ctx: RunContext, result: AgentResult) {\n const span = ctx.metadata[\"_telemetrySpan\"] as TelemetrySpan | undefined;\n const startTime = ctx.metadata[\"_telemetryStartTime\"] as number | undefined;\n\n if (span) {\n span.setAttribute(\"agent.steps\", result.steps.length);\n span.setAttribute(\"agent.tokens.input\", result.usage.inputTokens);\n span.setAttribute(\"agent.tokens.output\", result.usage.outputTokens);\n span.setAttribute(\"agent.finish_reason\", result.finishReason);\n span.setStatus(\"ok\");\n span.end();\n }\n\n if (startTime) {\n provider.recordMetric(`${spanPrefix}.duration_ms`, performance.now() - startTime);\n }\n\n provider.recordMetric(`${spanPrefix}.tokens.input`, result.usage.inputTokens);\n provider.recordMetric(`${spanPrefix}.tokens.output`, result.usage.outputTokens);\n provider.recordMetric(`${spanPrefix}.steps`, result.steps.length);\n\n return result;\n },\n\n async onError(error: Error, ctx: RunContext) {\n const span = ctx.metadata[\"_telemetrySpan\"] as TelemetrySpan | undefined;\n if (span) {\n span.setStatus(\"error\", error.message);\n span.end();\n }\n },\n\n async destroy() {\n await provider.flush();\n },\n };\n}\n","// =============================================================================\n// Resilience Decorator — Circuit Breaker + Rate Limiting + Tool Cache\n// =============================================================================\n\nimport type { Decorator, RunContext, AgentResult } from \"../core/agent/types.js\";\n\nexport interface ResilienceConfig {\n circuitBreaker?: boolean | CircuitBreakerOptions;\n retries?: number;\n retryDelay?: number;\n cache?: boolean | CacheOptions;\n}\n\nexport interface CircuitBreakerOptions {\n failureThreshold?: number;\n resetTimeout?: number;\n}\n\nexport interface CacheOptions {\n ttl?: number;\n maxSize?: number;\n}\n\ntype CircuitState = \"closed\" | \"open\" | \"half-open\";\n\nexport function resilience(config: ResilienceConfig): Decorator {\n const retries = config.retries ?? 0;\n const retryDelay = config.retryDelay ?? 1000;\n\n // Circuit breaker state\n let cbState: CircuitState = \"closed\";\n let failureCount = 0;\n const cbOpts = typeof config.circuitBreaker === \"object\" ? config.circuitBreaker : {};\n const failureThreshold = cbOpts.failureThreshold ?? 5;\n const resetTimeout = cbOpts.resetTimeout ?? 30000;\n let lastFailureTime = 0;\n\n // Simple result cache\n const cacheEnabled = !!config.cache;\n const cacheOpts = typeof config.cache === \"object\" ? config.cache : {};\n const cacheTtl = cacheOpts.ttl ?? 60000;\n const cacheMaxSize = cacheOpts.maxSize ?? 100;\n const cache = new Map<string, { result: AgentResult; timestamp: number }>();\n\n return {\n name: \"resilience\",\n\n async beforeRun(ctx: RunContext) {\n // Circuit breaker check\n if (config.circuitBreaker) {\n if (cbState === \"open\") {\n if (Date.now() - lastFailureTime > resetTimeout) {\n cbState = \"half-open\";\n } else {\n throw new Error(\"Circuit breaker is OPEN — agent temporarily unavailable\");\n }\n }\n }\n\n // Cache lookup\n if (cacheEnabled) {\n const key = ctx.prompt;\n const cached = cache.get(key);\n if (cached && Date.now() - cached.timestamp < cacheTtl) {\n ctx.metadata[\"_cachedResult\"] = cached.result;\n }\n }\n\n return ctx;\n },\n\n async afterRun(ctx: RunContext, result: AgentResult) {\n // Circuit breaker: reset on success\n if (config.circuitBreaker) {\n failureCount = 0;\n cbState = \"closed\";\n }\n\n // Cache store\n if (cacheEnabled) {\n if (cache.size >= cacheMaxSize) {\n const oldest = cache.keys().next().value;\n if (oldest !== undefined) cache.delete(oldest);\n }\n cache.set(ctx.prompt, { result, timestamp: Date.now() });\n }\n\n return result;\n },\n\n async onError(error: Error, _ctx: RunContext) {\n if (config.circuitBreaker) {\n failureCount++;\n lastFailureTime = Date.now();\n if (failureCount >= failureThreshold) {\n cbState = \"open\";\n }\n }\n },\n };\n}\n","// =============================================================================\n// Cost Limit Decorator — Budget enforcement for agent runs\n// =============================================================================\n\nimport type { Decorator, RunContext, AgentResult } from \"../core/agent/types.js\";\n\nexport interface CostLimitConfig {\n maxUsd: number;\n onBudgetExceeded?: \"abort\" | \"warn\";\n /** Cost per 1M input tokens in USD (default: $3.00 — GPT-4o class) */\n inputCostPer1M?: number;\n /** Cost per 1M output tokens in USD (default: $15.00 — GPT-4o class) */\n outputCostPer1M?: number;\n}\n\nexport function costLimit(config: CostLimitConfig): Decorator {\n const { maxUsd, onBudgetExceeded = \"abort\" } = config;\n const inputCostPer1M = config.inputCostPer1M ?? 3.0;\n const outputCostPer1M = config.outputCostPer1M ?? 15.0;\n\n let cumulativeCost = 0;\n\n return {\n name: \"cost-limit\",\n\n async afterRun(ctx: RunContext, result: AgentResult) {\n const inputCost = (result.usage.inputTokens / 1_000_000) * inputCostPer1M;\n const outputCost = (result.usage.outputTokens / 1_000_000) * outputCostPer1M;\n const runCost = inputCost + outputCost;\n cumulativeCost += runCost;\n\n result.cost = {\n totalUsd: runCost,\n inputTokensCost: inputCost,\n outputTokensCost: outputCost,\n };\n\n if (cumulativeCost > maxUsd) {\n if (onBudgetExceeded === \"abort\") {\n throw new Error(\n `Budget exceeded: $${cumulativeCost.toFixed(4)} > $${maxUsd.toFixed(2)} limit`,\n );\n }\n // \"warn\" mode — attach warning but return result\n ctx.metadata[\"_costWarning\"] = `Budget warning: $${cumulativeCost.toFixed(4)} of $${maxUsd.toFixed(2)}`;\n }\n\n return result;\n },\n };\n}\n","// =============================================================================\n// Planning Decorator — Injects planning tools into agent\n// =============================================================================\n\nimport type { Decorator, RunContext } from \"../core/agent/types.js\";\n\nexport interface PlanningConfig {\n /** Enable plan visualization (default: true) */\n visualization?: boolean;\n /** Enable todo tracking (default: true) */\n todos?: boolean;\n}\n\nexport function planning(_config?: PlanningConfig): Decorator {\n return {\n name: \"planning\",\n\n async beforeRun(ctx: RunContext) {\n // Inject planning context into system prompt\n const planningInstructions = [\n \"You have access to planning tools for structured task decomposition.\",\n \"Use create_plan for complex multi-step tasks.\",\n \"Use write_todos to track progress on subtasks.\",\n \"Use get_plan_status to review current plan progress.\",\n ].join(\"\\n\");\n\n if (!ctx.metadata[\"_planningInjected\"]) {\n ctx.messages.push({\n role: \"system\",\n content: planningInstructions,\n });\n ctx.metadata[\"_planningInjected\"] = true;\n }\n\n return ctx;\n },\n };\n}\n","// =============================================================================\n// Approval Decorator — Human-in-the-loop tool call gating\n// =============================================================================\n\nimport type { Decorator, RunContext, ToolCallContext } from \"../core/agent/types.js\";\n\nexport interface ApprovalConfig {\n mode: \"approve-all\" | \"require-approval\" | \"auto-approve\";\n /** Tools that always need approval (when mode is \"auto-approve\") */\n requireApprovalFor?: string[];\n /** Tools that never need approval (when mode is \"require-approval\") */\n autoApproveFor?: string[];\n /** Custom approval handler */\n handler?: (request: ApprovalRequest) => Promise<ApprovalResponse>;\n}\n\nexport interface ApprovalRequest {\n toolName: string;\n toolArgs: unknown;\n toolCallId: string;\n prompt: string;\n}\n\nexport interface ApprovalResponse {\n approved: boolean;\n reason?: string;\n}\n\nexport function approval(config: ApprovalConfig): Decorator {\n const { mode, requireApprovalFor = [], autoApproveFor = [], handler } = config;\n\n function needsApproval(toolName: string): boolean {\n switch (mode) {\n case \"approve-all\":\n return false;\n case \"require-approval\":\n return !autoApproveFor.includes(toolName);\n case \"auto-approve\":\n return requireApprovalFor.includes(toolName);\n default:\n return false;\n }\n }\n\n return {\n name: \"approval\",\n\n async beforeToolCall(ctx: ToolCallContext) {\n if (!needsApproval(ctx.toolName)) return ctx;\n\n if (!handler) {\n throw new Error(\n `Tool \"${ctx.toolName}\" requires approval but no handler is configured`,\n );\n }\n\n const response = await handler({\n toolName: ctx.toolName,\n toolArgs: ctx.toolArgs,\n toolCallId: ctx.toolCallId,\n prompt: ctx.prompt,\n });\n\n if (!response.approved) {\n throw new Error(\n `Tool \"${ctx.toolName}\" was rejected: ${response.reason ?? \"No reason given\"}`,\n );\n }\n\n return ctx;\n },\n };\n}\n","// =============================================================================\n// Learning Decorator — User profile and memory injection\n// =============================================================================\n\nimport type { Decorator, RunContext } from \"../core/agent/types.js\";\n\nexport interface LearningPort {\n getProfile(userId: string): Promise<UserProfile | null>;\n getMemories(userId: string, options?: { limit?: number }): Promise<UserMemory[]>;\n addMemory(userId: string, memory: { content: string; category?: string }): Promise<void>;\n}\n\nexport interface UserProfile {\n name?: string;\n preferences?: Record<string, unknown>;\n language?: string;\n style?: string;\n}\n\nexport interface UserMemory {\n id: string;\n content: string;\n category?: string;\n confidence: number;\n}\n\nexport interface LearningConfig {\n backend: LearningPort;\n userId: string;\n maxMemories?: number;\n}\n\nexport function learning(config: LearningConfig): Decorator {\n const { backend, userId, maxMemories = 10 } = config;\n\n return {\n name: \"learning\",\n\n async beforeRun(ctx: RunContext) {\n const [profile, memories] = await Promise.all([\n backend.getProfile(userId),\n backend.getMemories(userId, { limit: maxMemories }),\n ]);\n\n const contextParts: string[] = [];\n\n if (profile) {\n const profileInfo = [\n profile.name ? `User: ${profile.name}` : null,\n profile.language ? `Language: ${profile.language}` : null,\n profile.style ? `Communication style: ${profile.style}` : null,\n ]\n .filter(Boolean)\n .join(\". \");\n if (profileInfo) contextParts.push(`[User Profile] ${profileInfo}`);\n }\n\n if (memories.length > 0) {\n const memoryText = memories\n .sort((a, b) => b.confidence - a.confidence)\n .map((m) => `- ${m.content}`)\n .join(\"\\n\");\n contextParts.push(`[User Memories]\\n${memoryText}`);\n }\n\n if (contextParts.length > 0) {\n ctx.messages.push({\n role: \"system\",\n content: contextParts.join(\"\\n\\n\"),\n });\n }\n\n return ctx;\n },\n };\n}\n","// =============================================================================\n// Checkpoint Decorator — Save/restore agent state\n// =============================================================================\n\nimport type { Decorator, RunContext, AgentResult } from \"../core/agent/types.js\";\nimport type { StepResult } from \"../core/llm/types.js\";\n\nexport interface CheckpointStorage {\n save(sessionId: string, checkpoint: CheckpointData): Promise<void>;\n load(sessionId: string): Promise<CheckpointData | null>;\n list(sessionId: string): Promise<CheckpointData[]>;\n deleteOld(sessionId: string, keepCount: number): Promise<void>;\n}\n\nexport interface CheckpointData {\n id: string;\n sessionId: string;\n stepIndex: number;\n messages: unknown[];\n metadata: Record<string, unknown>;\n timestamp: number;\n}\n\nexport interface CheckpointConfig {\n storage: CheckpointStorage;\n interval?: number;\n maxCheckpoints?: number;\n sessionId?: string;\n}\n\nexport function checkpoint(config: CheckpointConfig): Decorator {\n const { storage, interval = 5, maxCheckpoints = 10 } = config;\n let stepCount = 0;\n\n return {\n name: \"checkpoint\",\n\n async beforeRun(ctx: RunContext) {\n const sessionId = config.sessionId ?? (ctx.metadata[\"sessionId\"] as string) ?? \"default\";\n ctx.metadata[\"_checkpointSessionId\"] = sessionId;\n\n // Try to restore from latest checkpoint\n const latest = await storage.load(sessionId);\n if (latest) {\n ctx.messages.push(...(latest.messages as typeof ctx.messages));\n Object.assign(ctx.metadata, latest.metadata);\n }\n\n return ctx;\n },\n\n async afterStep(ctx, step: StepResult) {\n stepCount++;\n\n if (stepCount % interval === 0) {\n const sessionId = ctx.metadata[\"_checkpointSessionId\"] as string;\n await storage.save(sessionId, {\n id: `cp_${Date.now()}`,\n sessionId,\n stepIndex: stepCount,\n messages: ctx.messages,\n metadata: { ...ctx.metadata },\n timestamp: Date.now(),\n });\n await storage.deleteOld(sessionId, maxCheckpoints);\n }\n\n return step;\n },\n };\n}\n","// =============================================================================\n// Domain Error Classes\n// =============================================================================\n\nexport class GaussError extends Error {\n constructor(\n message: string,\n public readonly code: string,\n public readonly cause?: unknown,\n ) {\n super(message);\n this.name = \"GaussError\";\n }\n}\n\nexport class ToolExecutionError extends GaussError {\n constructor(message: string, cause?: unknown) {\n super(message, \"TOOL_EXECUTION_ERROR\", cause);\n this.name = \"ToolExecutionError\";\n }\n}\n\nexport class PluginError extends GaussError {\n constructor(message: string, cause?: unknown) {\n super(message, \"PLUGIN_ERROR\", cause);\n this.name = \"PluginError\";\n }\n}\n\nexport class McpConnectionError extends GaussError {\n constructor(message: string, cause?: unknown) {\n super(message, \"MCP_CONNECTION_ERROR\", cause);\n this.name = \"McpConnectionError\";\n }\n}\n\nexport class RuntimeError extends GaussError {\n constructor(message: string, cause?: unknown) {\n super(message, \"RUNTIME_ERROR\", cause);\n this.name = \"RuntimeError\";\n }\n}\n\nexport class StreamingError extends GaussError {\n constructor(message: string, cause?: unknown) {\n super(message, \"STREAMING_ERROR\", cause);\n this.name = \"StreamingError\";\n }\n}\n\nexport class ConfigurationError extends GaussError {\n constructor(message: string, cause?: unknown) {\n super(message, \"CONFIGURATION_ERROR\", cause);\n this.name = \"ConfigurationError\";\n }\n}\n","// =============================================================================\n// Streaming Progress Events — Typed event schema + emitter\n// =============================================================================\n\nexport type ProgressPhase =\n | \"plan_start\" | \"plan_complete\"\n | \"step_start\" | \"step_complete\"\n | \"tool_call\" | \"tool_result\"\n | \"agent_thinking\" | \"agent_response\"\n | \"complete\" | \"error\";\n\nexport interface ProgressEvent {\n type: ProgressPhase;\n step?: number;\n totalSteps?: number;\n progress?: number; // 0-100\n message: string;\n metadata?: Record<string, unknown>;\n timestamp: number;\n}\n\nexport type ProgressListener = (event: ProgressEvent) => void;\n\nexport class ProgressEmitter {\n private listeners: ProgressListener[] = [];\n\n on(listener: ProgressListener): () => void {\n this.listeners.push(listener);\n return () => {\n this.listeners = this.listeners.filter(l => l !== listener);\n };\n }\n\n emit(event: Omit<ProgressEvent, \"timestamp\">): void {\n const full: ProgressEvent = { ...event, timestamp: Date.now() };\n for (const listener of this.listeners) {\n try { listener(full); } catch { /* isolated */ }\n }\n }\n\n /** Create an SSE async generator for HTTP streaming */\n async *sse(): AsyncGenerator<string> {\n const queue: ProgressEvent[] = [];\n let notify: (() => void) | null = null;\n\n const unsub = this.on((evt) => {\n queue.push(evt);\n notify?.();\n });\n\n try {\n while (true) {\n // Drain all queued events\n while (queue.length > 0) {\n const evt = queue.shift()!;\n yield JSON.stringify(evt);\n if (evt.type === \"complete\" || evt.type === \"error\") return;\n }\n // Wait for next event; if one arrives between check and await, notify resolves immediately\n await new Promise<void>(r => { notify = r; });\n notify = null;\n }\n } finally {\n unsub();\n }\n }\n}\n","import type { FilesystemPort } from \"../ports/filesystem.port.js\";\nimport type { Todo } from \"../domain/todo.schema.js\";\nimport { TODOS_PATH } from \"../tools/planning/shared.js\";\n\n/**\n * Returns an async function that checks whether all todos are done.\n * Returns false if no todos exist (don't stop with an empty plan).\n */\nexport function createAllTodosDoneCondition(\n fs: FilesystemPort,\n): () => Promise<boolean> {\n return async () => {\n const exists = await fs.exists(TODOS_PATH, \"persistent\");\n if (!exists) return false;\n\n const raw = await fs.read(TODOS_PATH, \"persistent\");\n const todos: Todo[] = JSON.parse(raw);\n if (todos.length === 0) return false;\n\n return todos.every((t) => t.status === \"done\");\n };\n}\n","// =============================================================================\n// OpenAIVoiceAdapter — STT (Whisper) + TTS via OpenAI APIs\n// =============================================================================\n\nimport type {\n VoicePort,\n VoiceConfig,\n VoiceEventListener,\n VoiceEvent,\n} from \"../../../ports/voice.port.js\";\n\nexport interface OpenAIVoiceOptions {\n apiKey: string;\n sttModel?: string;\n ttsModel?: string;\n ttsVoice?: string;\n baseUrl?: string;\n}\n\nexport class OpenAIVoiceAdapter implements VoicePort {\n private readonly apiKey: string;\n private readonly sttModel: string;\n private readonly ttsModel: string;\n private readonly ttsVoice: string;\n private readonly baseUrl: string;\n private listeners: VoiceEventListener[] = [];\n private connected = false;\n\n constructor(options: OpenAIVoiceOptions) {\n this.apiKey = options.apiKey;\n this.sttModel = options.sttModel ?? \"whisper-1\";\n this.ttsModel = options.ttsModel ?? \"tts-1\";\n this.ttsVoice = options.ttsVoice ?? \"alloy\";\n this.baseUrl = options.baseUrl ?? \"https://api.openai.com/v1\";\n }\n\n async speak(text: string, config?: VoiceConfig): Promise<Uint8Array> {\n const response = await fetch(`${this.baseUrl}/audio/speech`, {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${this.apiKey}`,\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({\n model: config?.model ?? this.ttsModel,\n input: text,\n voice: this.ttsVoice,\n response_format: \"mp3\",\n }),\n });\n\n if (!response.ok) {\n const err = await response.text();\n throw new Error(`OpenAI TTS failed: ${response.status} ${err}`);\n }\n\n this.emit({ type: \"speaking\", text });\n const buffer = await response.arrayBuffer();\n const audio = new Uint8Array(buffer);\n this.emit({ type: \"audio\", data: audio });\n return audio;\n }\n\n async listen(audio: Uint8Array, config?: VoiceConfig): Promise<string> {\n this.emit({ type: \"listening\" });\n\n const blob = new Blob([audio as unknown as Blob], { type: \"audio/mp3\" });\n const formData = new FormData();\n formData.append(\"file\", blob, \"audio.mp3\");\n formData.append(\"model\", config?.model ?? this.sttModel);\n if (config?.language) formData.append(\"language\", config.language);\n\n const response = await fetch(`${this.baseUrl}/audio/transcriptions`, {\n method: \"POST\",\n headers: { Authorization: `Bearer ${this.apiKey}` },\n body: formData,\n });\n\n if (!response.ok) {\n const err = await response.text();\n throw new Error(`OpenAI STT failed: ${response.status} ${err}`);\n }\n\n const data = (await response.json()) as { text: string };\n this.emit({ type: \"transcript\", text: data.text, isFinal: true });\n return data.text;\n }\n\n async connect(_config?: VoiceConfig): Promise<void> {\n this.connected = true;\n this.emit({ type: \"connected\" });\n }\n\n async disconnect(): Promise<void> {\n this.connected = false;\n this.emit({ type: \"disconnected\" });\n }\n\n on(listener: VoiceEventListener): () => void {\n this.listeners.push(listener);\n return () => {\n this.listeners = this.listeners.filter((l) => l !== listener);\n };\n }\n\n private emit(event: VoiceEvent): void {\n for (const l of this.listeners) l(event);\n }\n}\n","// =============================================================================\n// ElevenLabsVoiceAdapter — Premium TTS via ElevenLabs API\n// =============================================================================\n\nimport type {\n VoicePort,\n VoiceConfig,\n VoiceEventListener,\n VoiceEvent,\n} from \"../../../ports/voice.port.js\";\n\nexport interface ElevenLabsVoiceOptions {\n apiKey: string;\n voiceId?: string;\n model?: string;\n baseUrl?: string;\n}\n\nexport class ElevenLabsVoiceAdapter implements VoicePort {\n private readonly apiKey: string;\n private readonly voiceId: string;\n private readonly model: string;\n private readonly baseUrl: string;\n private listeners: VoiceEventListener[] = [];\n\n constructor(options: ElevenLabsVoiceOptions) {\n this.apiKey = options.apiKey;\n this.voiceId = options.voiceId ?? \"21m00Tcm4TlvDq8ikWAM\"; // Rachel\n this.model = options.model ?? \"eleven_multilingual_v2\";\n this.baseUrl = options.baseUrl ?? \"https://api.elevenlabs.io/v1\";\n }\n\n async speak(text: string, _config?: VoiceConfig): Promise<Uint8Array> {\n const response = await fetch(\n `${this.baseUrl}/text-to-speech/${this.voiceId}`,\n {\n method: \"POST\",\n headers: {\n \"xi-api-key\": this.apiKey,\n \"Content-Type\": \"application/json\",\n Accept: \"audio/mpeg\",\n },\n body: JSON.stringify({\n text,\n model_id: this.model,\n voice_settings: {\n stability: 0.5,\n similarity_boost: 0.75,\n },\n }),\n }\n );\n\n if (!response.ok) {\n const err = await response.text();\n throw new Error(`ElevenLabs TTS failed: ${response.status} ${err}`);\n }\n\n this.emit({ type: \"speaking\", text });\n const buffer = await response.arrayBuffer();\n const audio = new Uint8Array(buffer);\n this.emit({ type: \"audio\", data: audio });\n return audio;\n }\n\n async listen(\n _audio: Uint8Array,\n _config?: VoiceConfig\n ): Promise<string> {\n throw new Error(\n \"ElevenLabs does not support STT. Use OpenAIVoiceAdapter for STT.\"\n );\n }\n\n async connect(_config?: VoiceConfig): Promise<void> {\n this.emit({ type: \"connected\" });\n }\n\n async disconnect(): Promise<void> {\n this.emit({ type: \"disconnected\" });\n }\n\n on(listener: VoiceEventListener): () => void {\n this.listeners.push(listener);\n return () => {\n this.listeners = this.listeners.filter((l) => l !== listener);\n };\n }\n\n private emit(event: VoiceEvent): void {\n for (const l of this.listeners) l(event);\n }\n}\n","// =============================================================================\n// VoicePipeline — STT → Agent → TTS orchestration for voice agents\n// =============================================================================\n\nimport type { VoicePort, VoiceConfig } from \"../../ports/voice.port.js\";\n\nexport interface VoicePipelineConfig {\n /** STT adapter (e.g. OpenAIVoiceAdapter) */\n stt: VoicePort;\n /** TTS adapter (e.g. ElevenLabsVoiceAdapter or OpenAIVoiceAdapter) */\n tts: VoicePort;\n /** Agent or function that processes text → text */\n agent: (input: string) => Promise<string>;\n /** Optional STT config */\n sttConfig?: VoiceConfig;\n /** Optional TTS config */\n ttsConfig?: VoiceConfig;\n}\n\nexport interface VoicePipelineResult {\n /** Transcribed text from STT */\n transcript: string;\n /** Agent's text response */\n agentResponse: string;\n /** TTS audio output */\n audio: Uint8Array;\n /** Timing info */\n timing: {\n sttMs: number;\n agentMs: number;\n ttsMs: number;\n totalMs: number;\n };\n}\n\nexport class VoicePipeline {\n private readonly config: VoicePipelineConfig;\n\n constructor(config: VoicePipelineConfig) {\n this.config = config;\n }\n\n /** Process audio input through STT → Agent → TTS pipeline */\n async process(audioInput: Uint8Array): Promise<VoicePipelineResult> {\n const totalStart = Date.now();\n\n // STT\n const sttStart = Date.now();\n const transcript = await this.config.stt.listen(\n audioInput,\n this.config.sttConfig\n );\n const sttMs = Date.now() - sttStart;\n\n // Agent\n const agentStart = Date.now();\n const agentResponse = await this.config.agent(transcript);\n const agentMs = Date.now() - agentStart;\n\n // TTS\n const ttsStart = Date.now();\n const audio = await this.config.tts.speak(\n agentResponse,\n this.config.ttsConfig\n );\n const ttsMs = Date.now() - ttsStart;\n\n return {\n transcript,\n agentResponse,\n audio,\n timing: {\n sttMs,\n agentMs,\n ttsMs,\n totalMs: Date.now() - totalStart,\n },\n };\n }\n\n /** Process text input (skip STT), still generates TTS audio */\n async processText(\n text: string\n ): Promise<Omit<VoicePipelineResult, \"transcript\"> & { transcript: string }> {\n const totalStart = Date.now();\n\n const agentStart = Date.now();\n const agentResponse = await this.config.agent(text);\n const agentMs = Date.now() - agentStart;\n\n const ttsStart = Date.now();\n const audio = await this.config.tts.speak(\n agentResponse,\n this.config.ttsConfig\n );\n const ttsMs = Date.now() - ttsStart;\n\n return {\n transcript: text,\n agentResponse,\n audio,\n timing: {\n sttMs: 0,\n agentMs,\n ttsMs,\n totalMs: Date.now() - totalStart,\n },\n };\n }\n}\n","// =============================================================================\n// DI Port — Dependency Injection contract (Inversion of Control)\n// =============================================================================\n\n/**\n * Service lifetime — controls instance reuse.\n */\nexport enum Lifetime {\n /** One instance shared across all resolutions */\n SINGLETON = \"singleton\",\n /** New instance per scope (e.g., per request) */\n SCOPED = \"scoped\",\n /** New instance every resolution */\n TRANSIENT = \"transient\",\n}\n\n/**\n * Token used to identify a service in the container.\n * Can be a string key, a symbol, or a class constructor.\n */\nexport type Token<T = unknown> = string | symbol | (new (...args: never[]) => T);\n\n/**\n * Factory function that creates a service instance.\n * Receives the container to resolve its own dependencies.\n */\nexport type Factory<T> = (container: ContainerPort) => T | Promise<T>;\n\n/**\n * Registration descriptor for a service.\n */\nexport interface Registration<T = unknown> {\n token: Token<T>;\n factory: Factory<T>;\n lifetime: Lifetime;\n tags?: string[];\n}\n\n/**\n * ContainerPort — DI container contract.\n *\n * Supports: singleton/scoped/transient lifetimes, child scopes,\n * tagged resolution, async factories, and disposal.\n */\nexport interface ContainerPort {\n /** Register a service with a factory and lifetime. */\n register<T>(\n token: Token<T>,\n factory: Factory<T>,\n lifetime?: Lifetime,\n ): void;\n\n /** Register a constant value as a singleton. */\n registerValue<T>(token: Token<T>, value: T): void;\n\n /** Register a class (auto-resolves constructor deps via metadata). */\n registerClass<T>(\n token: Token<T>,\n ctor: new (...args: never[]) => T,\n lifetime?: Lifetime,\n ): void;\n\n /** Resolve a service by token. Throws if not registered. */\n resolve<T>(token: Token<T>): T;\n\n /** Resolve a service asynchronously (for async factories). */\n resolveAsync<T>(token: Token<T>): Promise<T>;\n\n /** Check if a token is registered. */\n has(token: Token): boolean;\n\n /** Create a child scope (inherits parent registrations). */\n createScope(): ContainerPort;\n\n /** Dispose all singletons and scoped instances. */\n dispose(): Promise<void>;\n\n /** Resolve all services registered with a given tag. */\n resolveTagged<T>(tag: string): T[];\n}\n","// =============================================================================\n// MemoryPlugin — Agent memory & context tools for Gauss\n// =============================================================================\n\nimport { tool, type Tool } from \"../core/llm/index.js\";\nimport { z } from \"zod\";\n\nimport type { Plugin, PluginHooks, PluginContext, AfterRunParams } from \"../ports/plugin.port.js\";\nimport type { AgentMemoryPort, MemoryEntry } from \"../ports/agent-memory.port.js\";\nimport { InMemoryAgentMemoryAdapter } from \"../adapters/memory/in-memory-agent-memory.adapter.js\";\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Shared schema constants\n// ─────────────────────────────────────────────────────────────────────────────\n\n/** Max characters kept when summarizing memory entries */\nconst SUMMARY_MAX_LENGTH = 500;\nconst REFLECTION_DEFAULT_LIMIT = 20;\n\nconst memoryTypeSchema = z.enum([\"conversation\", \"fact\", \"preference\", \"task\", \"summary\"]);\nconst memoryTierSchema = z.enum([\"short\", \"working\", \"semantic\", \"observation\"]);\nconst importanceSchema = z.number().min(0).max(1).optional();\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Types\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface MemoryPluginOptions {\n /** Memory adapter to use (defaults to InMemoryAgentMemoryAdapter) */\n adapter?: AgentMemoryPort;\n /** Automatically store conversation summaries after each run */\n autoStore?: boolean;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Plugin\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport class MemoryPlugin implements Plugin {\n readonly name = \"memory\";\n readonly version = \"1.0.0\";\n readonly hooks: PluginHooks;\n readonly tools: Record<string, Tool<any, any>>;\n\n private readonly adapter: AgentMemoryPort;\n\n constructor(options: MemoryPluginOptions = {}) {\n this.adapter = options.adapter ?? new InMemoryAgentMemoryAdapter();\n const autoStore = options.autoStore ?? false;\n this.hooks = autoStore ? { afterRun: this.onAfterRun.bind(this) } : {};\n this.tools = this.buildTools();\n }\n\n private buildTools(): Record<string, Tool<any, any>> {\n return {\n \"memory:store\": tool({\n description: \"Store a memory entry for future recall\",\n inputSchema: z.object({\n content: z.string().describe(\"The content to remember\"),\n type: memoryTypeSchema.describe(\"Type of memory\"),\n tier: memoryTierSchema.optional().describe(\"Optional memory tier\"),\n importance: importanceSchema.describe(\"Importance score 0-1\"),\n }),\n execute: async (args: unknown) => {\n const { content, type, tier, importance } = z.object({\n content: z.string(),\n type: memoryTypeSchema,\n tier: memoryTierSchema.optional(),\n importance: importanceSchema,\n }).parse(args);\n const entry: MemoryEntry = {\n id: crypto.randomUUID(),\n content,\n type,\n tier,\n timestamp: new Date().toISOString(),\n importance,\n };\n await this.adapter.store(entry);\n return `Stored memory entry ${entry.id} (type: ${type}${tier ? `, tier: ${tier}` : \"\"})`;\n },\n }),\n\n \"memory:recall\": tool({\n description: \"Recall memories matching a query\",\n inputSchema: z.object({\n query: z.string().optional().describe(\"Keyword search query\"),\n type: memoryTypeSchema.optional().describe(\"Filter by type\"),\n tier: memoryTierSchema.optional().describe(\"Filter by tier\"),\n includeTiers: z.array(memoryTierSchema).optional().describe(\"Filter by multiple tiers\"),\n limit: z.number().optional().describe(\"Max entries to return (default 10)\"),\n minImportance: importanceSchema.describe(\"Minimum importance threshold\"),\n }),\n execute: async (args: unknown) => {\n const { query, type, tier, includeTiers, limit, minImportance } = z.object({\n query: z.string().optional(),\n type: memoryTypeSchema.optional(),\n tier: memoryTierSchema.optional(),\n includeTiers: z.array(memoryTierSchema).optional(),\n limit: z.number().optional(),\n minImportance: importanceSchema,\n }).parse(args);\n const entries = await this.adapter.recall(query ?? \"\", {\n query,\n type,\n tier,\n includeTiers,\n limit,\n minImportance,\n });\n if (entries.length === 0) return \"No memories found.\";\n return entries\n .map((e) => `[${e.tier ?? \"unknown\"}:${e.type}] ${e.content}`)\n .join(\"\\n\");\n },\n }),\n\n \"memory:observe\": tool({\n description: \"Store an observation entry in the observation tier\",\n inputSchema: z.object({\n content: z.string().describe(\"Observation content\"),\n importance: importanceSchema.describe(\"Importance score 0-1\"),\n }),\n execute: async (args: unknown) => {\n const { content, importance } = z\n .object({\n content: z.string(),\n importance: importanceSchema,\n })\n .parse(args);\n\n const entry: MemoryEntry = {\n id: crypto.randomUUID(),\n content,\n type: \"summary\",\n tier: \"observation\",\n timestamp: new Date().toISOString(),\n importance,\n metadata: { source: \"observation\" },\n };\n\n await this.adapter.store(entry);\n return `Stored observation ${entry.id}`;\n },\n }),\n\n \"memory:reflect\": tool({\n description:\n \"Summarize observation-tier memories into a reflection memory\",\n inputSchema: z.object({\n limit: z\n .number()\n .int()\n .min(1)\n .max(100)\n .default(REFLECTION_DEFAULT_LIMIT)\n .describe(\"Max observation entries to summarize\"),\n minImportance: importanceSchema.describe(\n \"Minimum importance threshold for observations\",\n ),\n targetTier: memoryTierSchema\n .default(\"semantic\")\n .describe(\"Tier where reflection output will be stored\"),\n }),\n execute: async (args: unknown) => {\n const { limit, minImportance, targetTier } = z\n .object({\n limit: z\n .number()\n .int()\n .min(1)\n .max(100)\n .default(REFLECTION_DEFAULT_LIMIT),\n minImportance: importanceSchema,\n targetTier: memoryTierSchema.default(\"semantic\"),\n })\n .parse(args);\n\n const observations = await this.adapter.recall(\"\", {\n tier: \"observation\",\n limit,\n minImportance,\n });\n\n if (observations.length === 0) {\n return \"No observation memories found.\";\n }\n\n const reflection = await this.adapter.summarize(observations);\n const reflectionEntry: MemoryEntry = {\n id: crypto.randomUUID(),\n content: reflection,\n type: \"summary\",\n tier: targetTier,\n timestamp: new Date().toISOString(),\n importance: 0.7,\n metadata: {\n source: \"reflection\",\n observationCount: observations.length,\n },\n };\n\n await this.adapter.store(reflectionEntry);\n\n return `Reflection stored in tier '${targetTier}' from ${observations.length} observation(s).\\n\\n${reflection}`;\n },\n }),\n\n \"memory:stats\": tool({\n description: \"Get memory statistics\",\n inputSchema: z.object({}),\n execute: async () => {\n const stats = await this.adapter.getStats();\n return JSON.stringify(stats, null, 2);\n },\n }),\n\n \"memory:clear\": tool({\n description: \"Clear all stored memories\",\n inputSchema: z.object({}),\n execute: async () => {\n await this.adapter.clear();\n return \"All memories cleared.\";\n },\n }),\n };\n }\n\n private async onAfterRun(_ctx: PluginContext, params: AfterRunParams): Promise<void> {\n const text = params.result.text;\n if (!text) return;\n\n const summary = text.length > SUMMARY_MAX_LENGTH ? text.slice(0, SUMMARY_MAX_LENGTH) + \"...\" : text;\n const entry: MemoryEntry = {\n id: crypto.randomUUID(),\n content: summary,\n type: \"summary\",\n tier: \"short\",\n timestamp: new Date().toISOString(),\n importance: 0.5,\n sessionId: params.result.sessionId,\n };\n await this.adapter.store(entry);\n }\n\n /** Direct access to the underlying adapter */\n getAdapter(): AgentMemoryPort {\n return this.adapter;\n }\n}\n\nexport function createMemoryPlugin(options?: MemoryPluginOptions): MemoryPlugin {\n return new MemoryPlugin(options);\n}\n","// =============================================================================\n// Shared memory statistics calculation\n// =============================================================================\n\nimport type { MemoryEntry, MemoryStats } from \"../../ports/agent-memory.port.js\";\n\n/**\n * Calculate memory statistics from an iterable of entries.\n */\nexport function calculateMemoryStats(entries: Iterable<MemoryEntry>): MemoryStats {\n const byType: Record<string, number> = {};\n const byTier: Record<string, number> = {};\n let oldest: string | undefined;\n let newest: string | undefined;\n let totalEntries = 0;\n\n for (const entry of entries) {\n totalEntries++;\n byType[entry.type] = (byType[entry.type] ?? 0) + 1;\n if (entry.tier) {\n byTier[entry.tier] = (byTier[entry.tier] ?? 0) + 1;\n }\n if (!oldest || entry.timestamp < oldest) oldest = entry.timestamp;\n if (!newest || entry.timestamp > newest) newest = entry.timestamp;\n }\n\n return {\n totalEntries,\n byType,\n byTier,\n oldestEntry: oldest,\n newestEntry: newest,\n };\n}\n","// =============================================================================\n// InMemoryAgentMemoryAdapter — In-memory implementation of AgentMemoryPort\n// =============================================================================\n\nimport type {\n AgentMemoryPort,\n MemoryEntry,\n RecallOptions,\n MemoryStats,\n} from \"../../ports/agent-memory.port.js\";\nimport { calculateMemoryStats } from \"./memory-utils.js\";\n\n/** Max characters kept when summarizing memory entries */\nconst SUMMARY_MAX_LENGTH = 500;\n\nexport interface InMemoryAgentMemoryOptions {\n maxEntries?: number; // default 10000\n}\n\nexport class InMemoryAgentMemoryAdapter implements AgentMemoryPort {\n private readonly entries = new Map<string, MemoryEntry>();\n private readonly insertionOrder = new Map<string, true>();\n private readonly maxEntries: number;\n\n constructor(options: InMemoryAgentMemoryOptions = {}) {\n this.maxEntries = options.maxEntries ?? 10_000;\n }\n\n async store(entry: MemoryEntry): Promise<void> {\n // Delete + re-insert for LRU ordering (Map preserves insertion order)\n this.insertionOrder.delete(entry.id);\n this.insertionOrder.set(entry.id, true);\n\n this.entries.set(entry.id, { ...entry });\n\n // LRU eviction\n while (this.insertionOrder.size > this.maxEntries) {\n const oldest = this.insertionOrder.keys().next().value;\n if (oldest !== undefined) {\n this.insertionOrder.delete(oldest);\n this.entries.delete(oldest);\n }\n }\n }\n\n async recall(_query: string, options: RecallOptions = {}): Promise<MemoryEntry[]> {\n const {\n limit = 10,\n type,\n tier,\n includeTiers,\n sessionId,\n minImportance,\n query,\n } = options;\n const lower = query?.toLowerCase();\n const results: MemoryEntry[] = [];\n const tierSet = includeTiers ? new Set(includeTiers) : undefined;\n\n for (const e of this.entries.values()) {\n if (type && e.type !== type) continue;\n if (tier && e.tier !== tier) continue;\n if (tierSet && (!e.tier || !tierSet.has(e.tier))) continue;\n if (sessionId && e.sessionId !== sessionId) continue;\n if (minImportance !== undefined && (e.importance ?? 0) < minImportance) continue;\n if (lower && !e.content.toLowerCase().includes(lower)) continue;\n results.push(e);\n }\n\n // Sort by timestamp descending (newest first)\n results.sort((a, b) => b.timestamp.localeCompare(a.timestamp));\n\n return results.slice(0, limit);\n }\n\n async summarize(entries: MemoryEntry[]): Promise<string> {\n const combined = entries.map((e) => e.content).join(\"\\n\");\n return combined.length > SUMMARY_MAX_LENGTH ? combined.slice(0, SUMMARY_MAX_LENGTH) + \"...\" : combined;\n }\n\n async clear(): Promise<void> {\n this.entries.clear();\n this.insertionOrder.clear();\n }\n\n async getStats(): Promise<MemoryStats> {\n return calculateMemoryStats(this.entries.values());\n }\n}\n","// =============================================================================\n// PluginRegistryPlugin — Exposes plugin registry as agent tools\n// =============================================================================\n\nimport { tool, type Tool } from \"../core/llm/index.js\";\nimport { z } from \"zod\";\n\nimport type { Plugin } from \"../ports/plugin.port.js\";\nimport type { PluginRegistryPort } from \"../ports/plugin-registry.port.js\";\nimport { DefaultPluginRegistryAdapter } from \"../adapters/plugin-registry/default-plugin-registry.adapter.js\";\n\nexport interface PluginRegistryPluginOptions {\n registry?: PluginRegistryPort;\n}\n\nexport class PluginRegistryPlugin implements Plugin {\n readonly name = \"plugin-registry\";\n readonly version = \"1.0.0\";\n readonly tools: Record<string, Tool<any, any>>;\n\n private readonly registry: PluginRegistryPort;\n\n constructor(options: PluginRegistryPluginOptions = {}) {\n this.registry = options.registry ?? new DefaultPluginRegistryAdapter();\n\n this.tools = {\n \"registry:list\": tool({\n description: \"List all registered plugins in the marketplace.\",\n inputSchema: z.object({}),\n execute: async () => {\n const manifests = this.registry.list();\n return {\n count: manifests.length,\n plugins: manifests.map((m) => ({\n name: m.name,\n version: m.version,\n description: m.description,\n author: m.author,\n tags: m.tags,\n })),\n };\n },\n }),\n\n \"registry:search\": tool({\n description: \"Search plugins by keyword across name, description, and tags.\",\n inputSchema: z.object({\n query: z.string().describe(\"Search keyword\"),\n }),\n execute: async (args: unknown) => {\n const { query } = z.object({ query: z.string() }).parse(args);\n const results = this.registry.search(query);\n return {\n query,\n count: results.length,\n plugins: results.map((m) => ({\n name: m.name,\n version: m.version,\n description: m.description,\n author: m.author,\n tags: m.tags,\n })),\n };\n },\n }),\n\n \"registry:info\": tool({\n description: \"Get detailed information about a registered plugin.\",\n inputSchema: z.object({\n name: z.string().describe(\"Plugin name\"),\n }),\n execute: async (args: unknown) => {\n const { name } = z.object({ name: z.string() }).parse(args);\n const manifest = this.registry.get(name);\n if (!manifest) {\n return { error: `Plugin \"${name}\" not found.` };\n }\n return {\n name: manifest.name,\n version: manifest.version,\n description: manifest.description,\n author: manifest.author,\n tags: manifest.tags,\n sourceType: manifest.source.type,\n dependencies: manifest.dependencies,\n };\n },\n }),\n\n \"registry:install\": tool({\n description:\n \"Install and load a plugin from a local module path. \" +\n \"The module is dynamically imported, instantiated, and registered.\",\n inputSchema: z.object({\n name: z.string().describe(\"Plugin name to register as\"),\n modulePath: z\n .string()\n .describe(\"Local module path to import the plugin from\"),\n exportName: z\n .string()\n .optional()\n .describe(\n \"Named export to use (defaults to 'default')\",\n ),\n }),\n execute: async (args: unknown) => {\n const { name, modulePath, exportName } = z\n .object({\n name: z.string(),\n modulePath: z.string(),\n exportName: z.string().optional(),\n })\n .parse(args);\n\n // Dynamic import and instantiate\n const mod = await import(modulePath);\n const expName = exportName ?? \"default\";\n const exported = mod[expName];\n if (!exported) {\n return {\n error: `Module \"${modulePath}\" does not export \"${expName}\".`,\n };\n }\n\n const plugin: Plugin =\n typeof exported === \"function\" && exported.prototype\n ? (new exported() as Plugin)\n : (exported as Plugin);\n\n // Register manifest\n this.registry.register({\n name,\n version: plugin.version ?? \"0.0.0\",\n description: `Dynamically installed from ${modulePath}`,\n source: { type: \"module\", modulePath, exportName },\n });\n\n return {\n installed: true,\n name,\n version: plugin.version ?? \"0.0.0\",\n tools: plugin.tools ? Object.keys(plugin.tools) : [],\n };\n },\n }),\n };\n }\n\n /** Expose the underlying registry for programmatic access */\n getRegistry(): PluginRegistryPort {\n return this.registry;\n }\n}\n\n/** Factory function for consistency with other plugins */\nexport function createPluginRegistryPlugin(\n options?: PluginRegistryPluginOptions,\n): PluginRegistryPlugin {\n return new PluginRegistryPlugin(options);\n}\n","// =============================================================================\n// DefaultPluginRegistryAdapter — In-memory plugin registry implementation\n// =============================================================================\n\nimport type { Plugin } from \"../../ports/plugin.port.js\";\nimport type {\n PluginManifest,\n PluginRegistryPort,\n} from \"../../ports/plugin-registry.port.js\";\n\nexport class DefaultPluginRegistryAdapter implements PluginRegistryPort {\n private readonly manifests = new Map<string, PluginManifest>();\n\n register(manifest: PluginManifest): void {\n this.validateManifest(manifest);\n\n if (this.manifests.has(manifest.name)) {\n throw new Error(\n `Plugin \"${manifest.name}\" is already registered. Unregister it first to replace.`,\n );\n }\n\n this.manifests.set(manifest.name, manifest);\n }\n\n unregister(name: string): void {\n if (!this.manifests.has(name)) {\n throw new Error(`Plugin \"${name}\" is not registered.`);\n }\n this.manifests.delete(name);\n }\n\n get(name: string): PluginManifest | undefined {\n return this.manifests.get(name);\n }\n\n list(): PluginManifest[] {\n return [...this.manifests.values()];\n }\n\n search(query: string): PluginManifest[] {\n const lower = query.toLowerCase();\n return this.list().filter((m) => {\n if (m.name.toLowerCase().includes(lower)) return true;\n if (m.description.toLowerCase().includes(lower)) return true;\n if (m.tags?.some((t) => t.toLowerCase().includes(lower))) return true;\n return false;\n });\n }\n\n async resolve(name: string): Promise<Plugin> {\n const manifest = this.manifests.get(name);\n if (!manifest) {\n throw new Error(`Plugin \"${name}\" is not registered.`);\n }\n\n this.checkDependencies(manifest);\n\n const { source } = manifest;\n\n switch (source.type) {\n case \"builtin\":\n return source.factory();\n\n case \"module\": {\n const mod = await import(source.modulePath);\n const exportName = source.exportName ?? \"default\";\n const exported = mod[exportName];\n if (!exported) {\n throw new Error(\n `Module \"${source.modulePath}\" does not export \"${exportName}\".`,\n );\n }\n // Support both class exports (new) and factory/instance exports\n return typeof exported === \"function\" && exported.prototype\n ? (new exported() as Plugin)\n : (exported as Plugin);\n }\n\n case \"url\":\n throw new Error(\n `Loading plugins from URLs is not supported for security reasons. ` +\n `Download the plugin locally and use { type: \"module\", modulePath: \"...\" } instead.`,\n );\n }\n }\n\n // ─── Private helpers ────────────────────────────────────────────────────────\n\n private validateManifest(manifest: PluginManifest): void {\n if (!manifest.name || typeof manifest.name !== \"string\") {\n throw new Error(\"Plugin manifest must have a non-empty 'name' string.\");\n }\n if (!manifest.version || typeof manifest.version !== \"string\") {\n throw new Error(\"Plugin manifest must have a non-empty 'version' string.\");\n }\n if (!manifest.description || typeof manifest.description !== \"string\") {\n throw new Error(\n \"Plugin manifest must have a non-empty 'description' string.\",\n );\n }\n if (!manifest.source || typeof manifest.source.type !== \"string\") {\n throw new Error(\"Plugin manifest must have a valid 'source' object.\");\n }\n }\n\n private checkDependencies(manifest: PluginManifest): void {\n if (!manifest.dependencies?.length) return;\n\n const missing = manifest.dependencies.filter(\n (dep) => !this.manifests.has(dep),\n );\n if (missing.length > 0) {\n throw new Error(\n `Plugin \"${manifest.name}\" has unresolved dependencies: ${missing.join(\", \")}. ` +\n `Register them before resolving.`,\n );\n }\n }\n}\n","// =============================================================================\n// LoggingMiddleware — Structured agent & tool event logging\n// =============================================================================\n\nimport type {\n MiddlewarePort,\n MiddlewareContext,\n BeforeAgentParams,\n AfterAgentParams,\n BeforeToolCallParams,\n AfterToolCallParams,\n OnMiddlewareErrorParams,\n} from \"../ports/middleware.port.js\";\nimport { MiddlewarePriority } from \"../ports/middleware.port.js\";\n\nexport interface LoggingMiddlewareOptions {\n /** Custom logger function (defaults to console.log) */\n logger?: (entry: LogEntry) => void;\n /** Include tool args in logs (default: false for security) */\n logToolArgs?: boolean;\n /** Include tool results in logs (default: false) */\n logToolResults?: boolean;\n}\n\nexport interface LogEntry {\n timestamp: number;\n level: \"info\" | \"warn\" | \"error\" | \"debug\";\n event: string;\n sessionId: string;\n agentName?: string;\n data?: Record<string, unknown>;\n}\n\nexport function createLoggingMiddleware(\n options: LoggingMiddlewareOptions = {},\n): MiddlewarePort {\n const log = options.logger ?? ((entry: LogEntry) => {\n const prefix = `[${new Date(entry.timestamp).toISOString()}] [${entry.level}]`;\n // eslint-disable-next-line no-console\n console.log(`${prefix} ${entry.event}`, entry.data ?? \"\");\n });\n\n function emit(\n ctx: MiddlewareContext,\n level: LogEntry[\"level\"],\n event: string,\n data?: Record<string, unknown>,\n ): void {\n log({\n timestamp: Date.now(),\n level,\n event,\n sessionId: ctx.sessionId,\n agentName: ctx.agentName,\n data,\n });\n }\n\n return {\n name: \"gauss:logging\",\n priority: MiddlewarePriority.LATE,\n\n beforeAgent(ctx: MiddlewareContext, params: BeforeAgentParams) {\n emit(ctx, \"info\", \"agent:start\", {\n promptLength: params.prompt.length,\n toolCount: Object.keys(params.tools).length,\n });\n },\n\n afterAgent(ctx: MiddlewareContext, params: AfterAgentParams) {\n emit(ctx, \"info\", \"agent:complete\", {\n resultLength: params.result.text.length,\n stepCount: params.result.steps.length,\n });\n },\n\n beforeTool(ctx: MiddlewareContext, params: BeforeToolCallParams) {\n const data: Record<string, unknown> = {\n toolName: params.toolName,\n stepIndex: params.stepIndex,\n };\n if (options.logToolArgs) data.args = params.args;\n emit(ctx, \"debug\", \"tool:start\", data);\n },\n\n afterTool(ctx: MiddlewareContext, params: AfterToolCallParams) {\n const data: Record<string, unknown> = {\n toolName: params.toolName,\n stepIndex: params.stepIndex,\n durationMs: params.durationMs,\n };\n if (options.logToolResults) data.result = params.result;\n emit(ctx, \"debug\", \"tool:complete\", data);\n },\n\n onError(ctx: MiddlewareContext, params: OnMiddlewareErrorParams) {\n emit(ctx, \"error\", \"middleware:error\", {\n phase: params.phase,\n middlewareName: params.middlewareName,\n error: params.error instanceof Error\n ? { message: params.error.message, stack: params.error.stack }\n : String(params.error),\n });\n },\n };\n}\n","// =============================================================================\n// CachingMiddleware — Response caching with TTL & invalidation\n// =============================================================================\n\nimport type {\n MiddlewarePort,\n MiddlewareContext,\n BeforeToolCallParams,\n BeforeToolCallResult,\n AfterToolCallParams,\n AfterToolCallResult,\n} from \"../ports/middleware.port.js\";\nimport { MiddlewarePriority } from \"../ports/middleware.port.js\";\n\nexport interface CachingMiddlewareOptions {\n /** Default TTL in milliseconds (default: 5 minutes) */\n ttlMs?: number;\n /** Max entries in cache (default: 1000) */\n maxEntries?: number;\n /** Tool names to cache (if empty, caches all tools) */\n includeTools?: string[];\n /** Tool names to exclude from caching */\n excludeTools?: string[];\n /** Custom cache key generator */\n keyGenerator?: (toolName: string, args: unknown) => string;\n}\n\ninterface CacheEntry {\n result: unknown;\n createdAt: number;\n ttlMs: number;\n}\n\nexport function createCachingMiddleware(\n options: CachingMiddlewareOptions = {},\n): MiddlewarePort & { invalidate(toolName?: string): void; stats(): CacheStats } {\n const ttlMs = options.ttlMs ?? 300_000;\n const maxEntries = options.maxEntries ?? 1000;\n const cache = new Map<string, CacheEntry>();\n let hits = 0;\n let misses = 0;\n\n function makeKey(toolName: string, args: unknown): string {\n if (options.keyGenerator) return options.keyGenerator(toolName, args);\n return `${toolName}:${JSON.stringify(args)}`;\n }\n\n function shouldCache(toolName: string): boolean {\n if (options.excludeTools?.includes(toolName)) return false;\n if (options.includeTools && options.includeTools.length > 0) {\n return options.includeTools.includes(toolName);\n }\n return true;\n }\n\n function evictExpired(): void {\n const now = Date.now();\n for (const [key, entry] of cache) {\n if (now - entry.createdAt > entry.ttlMs) {\n cache.delete(key);\n }\n }\n }\n\n function evictLRU(): void {\n if (cache.size <= maxEntries) return;\n // Delete oldest entries\n const toDelete = cache.size - maxEntries;\n const keys = cache.keys();\n for (let i = 0; i < toDelete; i++) {\n const next = keys.next();\n if (next.done) break;\n cache.delete(next.value);\n }\n }\n\n const middleware: MiddlewarePort & { invalidate(toolName?: string): void; stats(): CacheStats } = {\n name: \"gauss:caching\",\n priority: MiddlewarePriority.EARLY,\n\n beforeTool(\n _ctx: MiddlewareContext,\n params: BeforeToolCallParams,\n ): BeforeToolCallResult | void {\n if (!shouldCache(params.toolName)) return;\n\n evictExpired();\n const key = makeKey(params.toolName, params.args);\n const entry = cache.get(key);\n\n if (entry && Date.now() - entry.createdAt <= entry.ttlMs) {\n hits++;\n return { skip: true, mockResult: entry.result };\n }\n\n misses++;\n },\n\n afterTool(\n _ctx: MiddlewareContext,\n params: AfterToolCallParams,\n ): AfterToolCallResult | void {\n if (!shouldCache(params.toolName)) return;\n\n const key = makeKey(params.toolName, params.args);\n cache.set(key, {\n result: params.result,\n createdAt: Date.now(),\n ttlMs,\n });\n evictLRU();\n },\n\n invalidate(toolName?: string): void {\n if (!toolName) {\n cache.clear();\n return;\n }\n for (const key of cache.keys()) {\n if (key.startsWith(`${toolName}:`)) {\n cache.delete(key);\n }\n }\n },\n\n stats(): CacheStats {\n return {\n size: cache.size,\n hits,\n misses,\n hitRate: hits + misses > 0 ? hits / (hits + misses) : 0,\n };\n },\n };\n\n return middleware;\n}\n\nexport interface CacheStats {\n size: number;\n hits: number;\n misses: number;\n hitRate: number;\n}\n","// =============================================================================\n// HITLMiddleware — Human-in-the-loop per-tool interrupt, approve/reject/edit\n// =============================================================================\n\nimport type {\n MiddlewarePort,\n MiddlewareContext,\n BeforeToolCallParams,\n BeforeToolCallResult,\n} from \"../ports/middleware.port.js\";\nimport { MiddlewarePriority } from \"../ports/middleware.port.js\";\n\n// =============================================================================\n// HITL Decision types\n// =============================================================================\n\nexport type HITLDecision =\n | { action: \"approve\" }\n | { action: \"reject\"; reason?: string }\n | { action: \"edit\"; args: unknown };\n\nexport type HITLApprovalHandler = (\n toolName: string,\n args: unknown,\n ctx: MiddlewareContext,\n) => Promise<HITLDecision>;\n\nexport interface HITLMiddlewareOptions {\n /** Handler invoked when a tool requires approval */\n approvalHandler: HITLApprovalHandler;\n /** Tool names that require HITL approval (if empty, requires approval for all) */\n requireApproval?: string[];\n /** Tool names that never require approval */\n alwaysAllow?: string[];\n /** Timeout in ms for approval (auto-rejects on timeout) */\n timeoutMs?: number;\n /** Default decision when timeout occurs (default: reject) */\n onTimeout?: \"approve\" | \"reject\";\n}\n\nexport function createHITLMiddleware(\n options: HITLMiddlewareOptions,\n): MiddlewarePort {\n const timeoutMs = options.timeoutMs ?? 300_000; // 5 min default\n const onTimeout = options.onTimeout ?? \"reject\";\n\n function needsApproval(toolName: string): boolean {\n if (options.alwaysAllow?.includes(toolName)) return false;\n if (options.requireApproval && options.requireApproval.length > 0) {\n return options.requireApproval.includes(toolName);\n }\n return true;\n }\n\n return {\n name: \"gauss:hitl\",\n priority: MiddlewarePriority.FIRST,\n\n async beforeTool(\n ctx: MiddlewareContext,\n params: BeforeToolCallParams,\n ): Promise<BeforeToolCallResult | void> {\n if (!needsApproval(params.toolName)) return;\n\n let decision: HITLDecision;\n try {\n decision = await Promise.race([\n options.approvalHandler(params.toolName, params.args, ctx),\n new Promise<HITLDecision>((resolve) =>\n setTimeout(\n () =>\n resolve(\n onTimeout === \"approve\"\n ? { action: \"approve\" }\n : { action: \"reject\", reason: \"Approval timed out\" },\n ),\n timeoutMs,\n ),\n ),\n ]);\n } catch {\n decision = { action: \"reject\", reason: \"Approval handler error\" };\n }\n\n switch (decision.action) {\n case \"approve\":\n return;\n case \"reject\":\n return {\n skip: true,\n mockResult: {\n error: `Tool call rejected${decision.reason ? `: ${decision.reason}` : \"\"}`,\n },\n };\n case \"edit\":\n return { args: decision.args };\n }\n },\n };\n}\n","// =============================================================================\n// ProcessorPipeline — Input/Output transform chains with retry\n// =============================================================================\n\nimport type {\n MiddlewarePort,\n MiddlewareContext,\n BeforeAgentParams,\n BeforeAgentResult,\n AfterAgentParams,\n AfterAgentResult,\n} from \"../ports/middleware.port.js\";\nimport { MiddlewarePriority } from \"../ports/middleware.port.js\";\n\n// =============================================================================\n// Processor interfaces\n// =============================================================================\n\nexport interface ProcessorResult<T> {\n value: T;\n metadata?: Record<string, unknown>;\n}\n\nexport interface InputProcessor {\n readonly name: string;\n process(prompt: string, ctx: MiddlewareContext): Promise<ProcessorResult<string>>;\n}\n\nexport interface OutputProcessor {\n readonly name: string;\n process(text: string, ctx: MiddlewareContext): Promise<ProcessorResult<string>>;\n}\n\n// =============================================================================\n// Pipeline options\n// =============================================================================\n\nexport interface ProcessorPipelineOptions {\n /** Input processors — executed in order before agent */\n inputProcessors?: InputProcessor[];\n /** Output processors — executed in order after agent */\n outputProcessors?: OutputProcessor[];\n /** Max retries per processor on failure (default: 0) */\n maxRetries?: number;\n /** Delay between retries in ms (default: 100) */\n retryDelayMs?: number;\n}\n\n// =============================================================================\n// Pipeline implementation as middleware\n// =============================================================================\n\nexport function createProcessorPipeline(\n options: ProcessorPipelineOptions,\n): MiddlewarePort {\n const maxRetries = options.maxRetries ?? 0;\n const retryDelayMs = options.retryDelayMs ?? 100;\n const inputs = options.inputProcessors ?? [];\n const outputs = options.outputProcessors ?? [];\n\n async function runWithRetry<T>(\n fn: () => Promise<T>,\n processorName: string,\n ): Promise<T> {\n let lastError: unknown;\n for (let attempt = 0; attempt <= maxRetries; attempt++) {\n try {\n return await fn();\n } catch (error) {\n lastError = error;\n if (attempt < maxRetries) {\n await new Promise((r) => setTimeout(r, retryDelayMs * (attempt + 1)));\n }\n }\n }\n throw new Error(\n `Processor \"${processorName}\" failed after ${maxRetries + 1} attempts: ${\n lastError instanceof Error ? lastError.message : String(lastError)\n }`,\n );\n }\n\n return {\n name: \"gauss:processor-pipeline\",\n priority: MiddlewarePriority.EARLY,\n\n async beforeAgent(\n ctx: MiddlewareContext,\n params: BeforeAgentParams,\n ): Promise<BeforeAgentResult | void> {\n if (inputs.length === 0) return;\n\n let prompt = params.prompt;\n for (const processor of inputs) {\n const result = await runWithRetry(\n () => processor.process(prompt, ctx),\n processor.name,\n );\n prompt = result.value;\n if (result.metadata) {\n Object.assign(ctx.metadata, result.metadata);\n }\n }\n\n if (prompt !== params.prompt) {\n return { prompt };\n }\n },\n\n async afterAgent(\n ctx: MiddlewareContext,\n params: AfterAgentParams,\n ): Promise<AfterAgentResult | void> {\n if (outputs.length === 0) return;\n\n let text = params.result.text;\n for (const processor of outputs) {\n const result = await runWithRetry(\n () => processor.process(text, ctx),\n processor.name,\n );\n text = result.value;\n if (result.metadata) {\n Object.assign(ctx.metadata, result.metadata);\n }\n }\n\n if (text !== params.result.text) {\n return { text };\n }\n },\n };\n}\n","// =============================================================================\n// SkillsMiddleware — Loads skills into agent system prompt\n// =============================================================================\n\nimport type {\n MiddlewarePort,\n MiddlewareContext,\n BeforeAgentParams,\n BeforeAgentResult,\n} from \"../ports/middleware.port.js\";\nimport { MiddlewarePriority } from \"../ports/middleware.port.js\";\nimport type { SkillsPort, Skill, SkillInheritanceConfig } from \"../ports/skills.port.js\";\n\nexport interface SkillsMiddlewareOptions {\n /** Skills port to load skills from */\n skillsPort: SkillsPort;\n /** Directories to scan for skills */\n searchPaths?: string[];\n /** Inheritance config for subagents */\n inheritanceConfig?: SkillInheritanceConfig;\n}\n\nexport function createSkillsMiddleware(\n options: SkillsMiddlewareOptions,\n): MiddlewarePort {\n let loadedSkills: Skill[] = [];\n\n return {\n name: \"gauss:skills\",\n priority: MiddlewarePriority.EARLY,\n\n async setup(_ctx: MiddlewareContext) {\n // Load skills from all search paths\n for (const path of options.searchPaths ?? []) {\n const skills = await options.skillsPort.loadSkills(path);\n loadedSkills.push(...skills);\n }\n // Deduplicate by name (last wins)\n const seen = new Map<string, Skill>();\n for (const skill of loadedSkills) {\n seen.set(skill.name, skill);\n }\n loadedSkills = Array.from(seen.values());\n },\n\n async beforeAgent(\n _ctx: MiddlewareContext,\n params: BeforeAgentParams,\n ): Promise<BeforeAgentResult | void> {\n if (loadedSkills.length === 0) return;\n\n const skillsBlock = loadedSkills\n .map((s) => `## Skill: ${s.name}\\n${s.description}\\n\\n${s.content}`)\n .join(\"\\n\\n---\\n\\n\");\n\n const augmented = `${params.instructions}\\n\\n# Active Skills\\n\\n${skillsBlock}`;\n return { instructions: augmented };\n },\n };\n}\n","// =============================================================================\n// ObservationalMemoryMiddleware — Summarization at token thresholds\n// =============================================================================\n\nimport type {\n MiddlewarePort,\n MiddlewareContext,\n AfterAgentParams,\n AfterAgentResult,\n} from \"../ports/middleware.port.js\";\nimport { MiddlewarePriority } from \"../ports/middleware.port.js\";\n\nexport interface ObservationalMemoryOptions {\n /** Token threshold fraction (0-1) to trigger summarization (default: 0.7) */\n thresholdFraction?: number;\n /** Max context tokens */\n maxTokens?: number;\n /** Summarization function */\n summarize: (text: string) => Promise<string>;\n /** Persistence callback */\n onSummarize?: (summary: string, metadata: ObservationMetadata) => Promise<void>;\n}\n\nexport interface ObservationMetadata {\n currentTask?: string;\n suggestedResponse?: string;\n lastObservedAt: number;\n messageCount: number;\n tokenEstimate: number;\n}\n\nexport function createObservationalMemoryMiddleware(\n options: ObservationalMemoryOptions,\n): MiddlewarePort {\n const threshold = options.thresholdFraction ?? 0.7;\n const maxTokens = options.maxTokens ?? 128_000;\n let messageCount = 0;\n let totalEstimatedTokens = 0;\n\n return {\n name: \"gauss:observational-memory\",\n priority: MiddlewarePriority.LATE,\n\n async afterAgent(\n _ctx: MiddlewareContext,\n params: AfterAgentParams,\n ): Promise<AfterAgentResult | void> {\n messageCount++;\n // Rough token estimate: ~4 chars per token\n const responseTokens = Math.ceil(params.result.text.length / 4);\n totalEstimatedTokens += responseTokens;\n\n if (totalEstimatedTokens > maxTokens * threshold) {\n const summary = await options.summarize(params.result.text);\n\n const metadata: ObservationMetadata = {\n lastObservedAt: Date.now(),\n messageCount,\n tokenEstimate: totalEstimatedTokens,\n };\n\n await options.onSummarize?.(summary, metadata);\n\n // Reset counters after summarization\n totalEstimatedTokens = Math.ceil(summary.length / 4);\n messageCount = 0;\n\n return { text: summary };\n }\n },\n };\n}\n","// =============================================================================\n// ResultEvictionMiddleware — Offload oversized tool results to storage\n// =============================================================================\n\nimport type {\n MiddlewarePort,\n MiddlewareContext,\n AfterToolCallParams,\n AfterToolCallResult,\n} from \"../ports/middleware.port.js\";\nimport { MiddlewarePriority } from \"../ports/middleware.port.js\";\n\nexport interface ResultEvictionOptions {\n /** Token threshold for eviction (default: 50_000) */\n tokenThreshold?: number;\n /** Tools excluded from eviction */\n excludeTools?: string[];\n /** Store evicted content */\n store: (id: string, content: string) => Promise<void>;\n}\n\nexport function createResultEvictionMiddleware(\n options: ResultEvictionOptions,\n): MiddlewarePort {\n const threshold = options.tokenThreshold ?? 50_000;\n const excluded = new Set(options.excludeTools ?? [\"ls\", \"glob\", \"grep\"]);\n let evictionCounter = 0;\n\n return {\n name: \"gauss:result-eviction\",\n priority: MiddlewarePriority.LATE,\n\n async afterTool(\n _ctx: MiddlewareContext,\n params: AfterToolCallParams,\n ): Promise<AfterToolCallResult | void> {\n if (excluded.has(params.toolName)) return;\n\n let resultStr: string;\n try {\n resultStr = typeof params.result === \"string\"\n ? params.result\n : JSON.stringify(params.result);\n } catch {\n // Non-serializable result — skip eviction\n return;\n }\n\n const estimatedTokens = Math.ceil(resultStr.length / 4);\n\n if (estimatedTokens > threshold) {\n const id = `evicted-${++evictionCounter}-${Date.now()}`;\n await options.store(id, resultStr);\n\n return {\n result: `[Result evicted to storage: ${id}] (${estimatedTokens} tokens, tool: ${params.toolName}). Use retrieval to access if needed.`,\n };\n }\n },\n };\n}\n","// =============================================================================\n// Summarization Middleware — Context management with configurable triggers\n// =============================================================================\n\nimport type { MiddlewarePort, MiddlewareContext, BeforeAgentParams, BeforeAgentResult, AfterAgentParams, AfterAgentResult } from \"../ports/middleware.port.js\";\nimport { MiddlewarePriority } from \"../ports/middleware.port.js\";\n\nexport interface SummarizationConfig {\n /** Token fraction threshold to trigger (default 0.85) */\n fractionThreshold?: number;\n /** Absolute token count threshold */\n tokenThreshold?: number;\n /** Message count threshold */\n messageThreshold?: number;\n /** Summarizer function: take messages, return summary */\n summarize: (messages: string[]) => Promise<string>;\n /** Estimate token count for a string */\n estimateTokens?: (text: string) => number;\n /** Max context tokens (default 128000) */\n maxContextTokens?: number;\n}\n\nfunction defaultEstimateTokens(text: string): number {\n return Math.ceil(text.length / 4);\n}\n\nexport class SummarizationMiddleware implements MiddlewarePort {\n readonly name = \"summarization\";\n readonly priority = MiddlewarePriority.EARLY;\n\n private config: Required<Omit<SummarizationConfig, \"tokenThreshold\" | \"messageThreshold\">> & Pick<SummarizationConfig, \"tokenThreshold\" | \"messageThreshold\">;\n\n constructor(config: SummarizationConfig) {\n this.config = {\n fractionThreshold: config.fractionThreshold ?? 0.85,\n tokenThreshold: config.tokenThreshold,\n messageThreshold: config.messageThreshold,\n summarize: config.summarize,\n estimateTokens: config.estimateTokens ?? defaultEstimateTokens,\n maxContextTokens: config.maxContextTokens ?? 128_000,\n };\n }\n\n async beforeAgent(ctx: MiddlewareContext, _params: BeforeAgentParams): Promise<BeforeAgentResult | void> {\n const messages = ctx.metadata?.messages as string[] | undefined;\n if (!messages || messages.length === 0) return;\n\n const shouldSummarize = this.shouldTrigger(messages);\n if (!shouldSummarize) return;\n\n const keepCount = Math.max(2, Math.floor(messages.length * 0.2));\n const toSummarize = messages.slice(0, messages.length - keepCount);\n if (toSummarize.length === 0) return;\n const kept = messages.slice(messages.length - keepCount);\n\n const summary = await this.config.summarize(toSummarize);\n const newMessages = [`[Summary of ${toSummarize.length} previous messages]: ${summary}`, ...kept];\n ctx.metadata.messages = newMessages;\n }\n\n async afterAgent(_ctx: MiddlewareContext, _params: AfterAgentParams): Promise<AfterAgentResult | void> {\n // No-op\n }\n\n private shouldTrigger(messages: string[]): boolean {\n // Message count threshold\n if (this.config.messageThreshold && messages.length >= this.config.messageThreshold) return true;\n\n // Token thresholds\n const totalTokens = messages.reduce((sum, m) => sum + this.config.estimateTokens(m), 0);\n\n if (this.config.tokenThreshold && totalTokens >= this.config.tokenThreshold) return true;\n\n const fraction = totalTokens / this.config.maxContextTokens;\n if (fraction >= this.config.fractionThreshold) return true;\n\n return false;\n }\n}\n","// =============================================================================\n// TripWire Middleware — Execution safety controls\n// =============================================================================\n\nimport type {\n MiddlewarePort,\n MiddlewareContext,\n BeforeAgentParams,\n BeforeAgentResult,\n AfterAgentParams,\n AfterAgentResult,\n BeforeToolCallParams,\n BeforeToolCallResult,\n AfterToolCallParams,\n AfterToolCallResult,\n} from \"../ports/middleware.port.js\";\nimport { MiddlewarePriority } from \"../ports/middleware.port.js\";\n\nexport interface TripWireOptions {\n /** Max total tokens (prompt + completion) across all steps. */\n maxTokens?: number;\n /** Max wall-clock time in milliseconds. */\n maxTimeMs?: number;\n /** Max USD cost across all LLM calls. */\n maxCostUsd?: number;\n /** Max number of tool calls. */\n maxToolCalls?: number;\n /** Max number of agent steps (iterations). */\n maxSteps?: number;\n /** Callback when a wire is tripped. */\n onTrip?: (wire: TripWireViolation) => void;\n}\n\nexport interface TripWireViolation {\n wire: \"tokens\" | \"time\" | \"cost\" | \"toolCalls\" | \"steps\";\n limit: number;\n actual: number;\n}\n\ninterface TripWireState {\n totalTokens: number;\n startTime: number;\n totalCostUsd: number;\n toolCallCount: number;\n stepCount: number;\n}\n\nexport function createTripWireMiddleware(\n options: TripWireOptions = {},\n): MiddlewarePort & { stats(): TripWireState; reset(): void } {\n let state: TripWireState = {\n totalTokens: 0,\n startTime: Date.now(),\n totalCostUsd: 0,\n toolCallCount: 0,\n stepCount: 0,\n };\n\n function checkWires(): TripWireViolation | null {\n if (options.maxTokens && state.totalTokens > options.maxTokens) {\n return { wire: \"tokens\", limit: options.maxTokens, actual: state.totalTokens };\n }\n if (options.maxTimeMs && Date.now() - state.startTime > options.maxTimeMs) {\n return { wire: \"time\", limit: options.maxTimeMs, actual: Date.now() - state.startTime };\n }\n if (options.maxCostUsd && state.totalCostUsd > options.maxCostUsd) {\n return { wire: \"cost\", limit: options.maxCostUsd, actual: state.totalCostUsd };\n }\n if (options.maxToolCalls && state.toolCallCount > options.maxToolCalls) {\n return { wire: \"toolCalls\", limit: options.maxToolCalls, actual: state.toolCallCount };\n }\n if (options.maxSteps && state.stepCount > options.maxSteps) {\n return { wire: \"steps\", limit: options.maxSteps, actual: state.stepCount };\n }\n return null;\n }\n\n const middleware: MiddlewarePort & { stats(): TripWireState; reset(): void } = {\n name: \"gauss:trip-wire\",\n priority: MiddlewarePriority.FIRST,\n\n beforeAgent(\n _ctx: MiddlewareContext,\n _params: BeforeAgentParams,\n ): BeforeAgentResult | void {\n state.stepCount++;\n state.startTime = state.startTime || Date.now();\n const violation = checkWires();\n if (violation) {\n options.onTrip?.(violation);\n return {\n abort: true,\n earlyResult: `[TripWire] Execution halted: ${violation.wire} limit exceeded (${violation.actual}/${violation.limit})`,\n };\n }\n },\n\n beforeTool(\n _ctx: MiddlewareContext,\n _params: BeforeToolCallParams,\n ): BeforeToolCallResult | void {\n state.toolCallCount++;\n const violation = checkWires();\n if (violation) {\n options.onTrip?.(violation);\n return {\n skip: true,\n mockResult: `[TripWire] Tool call skipped: ${violation.wire} limit exceeded (${violation.actual}/${violation.limit})`,\n };\n }\n },\n\n afterTool(\n _ctx: MiddlewareContext,\n params: AfterToolCallParams,\n ): AfterToolCallResult | void {\n // Track tokens from tool result metadata if available\n const meta = params.result as { tokens?: number; costUsd?: number } | null;\n if (meta?.tokens) state.totalTokens += meta.tokens;\n if (meta?.costUsd) state.totalCostUsd += meta.costUsd;\n },\n\n afterAgent(\n _ctx: MiddlewareContext,\n params: AfterAgentParams,\n ): AfterAgentResult | void {\n // Track tokens from result metadata if available\n const meta = params.result as { tokens?: number; costUsd?: number } | null;\n if (meta?.tokens) state.totalTokens += meta.tokens;\n if (meta?.costUsd) state.totalCostUsd += meta.costUsd;\n },\n\n stats() {\n return { ...state };\n },\n\n reset() {\n state = {\n totalTokens: 0,\n startTime: Date.now(),\n totalCostUsd: 0,\n toolCallCount: 0,\n stepCount: 0,\n };\n },\n };\n\n return middleware;\n}\n","// =============================================================================\n// PromptCaching Middleware — Provider-specific prompt caching (Anthropic, etc.)\n// =============================================================================\n\nimport type {\n MiddlewarePort,\n MiddlewareContext,\n BeforeAgentParams,\n BeforeAgentResult,\n AfterAgentParams,\n AfterAgentResult,\n} from \"../ports/middleware.port.js\";\nimport { MiddlewarePriority } from \"../ports/middleware.port.js\";\n\nexport interface PromptCachingOptions {\n /** Provider to optimize for (default: \"anthropic\") */\n provider?: \"anthropic\" | \"openai\" | \"auto\";\n /** Cache the system/instruction prompt (default: true) */\n cacheInstructions?: boolean;\n /** Cache tool definitions (default: true) */\n cacheToolDefinitions?: boolean;\n /** Min token threshold for caching (Anthropic requires 1024+) */\n minTokenThreshold?: number;\n}\n\ninterface CacheStats {\n cacheHits: number;\n cacheMisses: number;\n tokensCreated: number;\n tokensRead: number;\n}\n\n/**\n * Creates middleware that applies prompt caching headers/markers.\n *\n * For Anthropic: adds `cache_control: { type: \"ephemeral\" }` to system\n * messages and tool definitions that exceed the min token threshold.\n *\n * This reduces costs by ~90% on cached content and latency by ~80%.\n */\nexport function createPromptCachingMiddleware(\n options: PromptCachingOptions = {},\n): MiddlewarePort & { stats(): CacheStats } {\n const provider = options.provider ?? \"anthropic\";\n const cacheInstructions = options.cacheInstructions ?? true;\n const cacheToolDefinitions = options.cacheToolDefinitions ?? true;\n const minTokenThreshold = options.minTokenThreshold ?? 1024;\n\n const stats: CacheStats = {\n cacheHits: 0,\n cacheMisses: 0,\n tokensCreated: 0,\n tokensRead: 0,\n };\n\n function estimateTokens(text: string): number {\n // Rough estimate: ~4 chars per token\n return Math.ceil(text.length / 4);\n }\n\n function applyAnthropicCaching(params: BeforeAgentParams): BeforeAgentResult | void {\n const modifications: BeforeAgentResult = {};\n let modified = false;\n\n // Cache instructions if long enough\n if (cacheInstructions && params.instructions) {\n const tokens = estimateTokens(params.instructions);\n if (tokens >= minTokenThreshold) {\n // Mark instructions with cache control metadata\n // The actual cache_control header is applied at the provider level\n modifications.instructions = params.instructions;\n // Store cache marker in metadata via the prompt\n if (!params.prompt.includes(\"[cache:instructions]\")) {\n modifications.prompt = params.prompt;\n }\n stats.tokensCreated += tokens;\n modified = true;\n }\n }\n\n // Cache tool definitions if long enough\n if (cacheToolDefinitions && params.tools) {\n const toolJson = JSON.stringify(params.tools);\n const tokens = estimateTokens(toolJson);\n if (tokens >= minTokenThreshold) {\n stats.tokensCreated += tokens;\n modified = true;\n }\n }\n\n return modified ? modifications : undefined;\n }\n\n const middleware: MiddlewarePort & { stats(): CacheStats } = {\n name: \"gauss:prompt-caching\",\n priority: MiddlewarePriority.EARLY,\n\n beforeAgent(\n ctx: MiddlewareContext,\n params: BeforeAgentParams,\n ): BeforeAgentResult | void {\n // Set cache metadata for downstream provider usage\n ctx.metadata[\"gauss:prompt-cache\"] = {\n enabled: true,\n provider,\n cacheInstructions,\n cacheToolDefinitions,\n minTokenThreshold,\n };\n\n if (provider === \"anthropic\" || provider === \"auto\") {\n return applyAnthropicCaching(params);\n }\n },\n\n afterAgent(\n ctx: MiddlewareContext,\n params: AfterAgentParams,\n ): AfterAgentResult | void {\n // Track cache metrics from result if available\n const result = params.result as {\n cacheCreationInputTokens?: number;\n cacheReadInputTokens?: number;\n } | null;\n\n if (result?.cacheCreationInputTokens) {\n stats.cacheMisses++;\n stats.tokensCreated += result.cacheCreationInputTokens;\n }\n if (result?.cacheReadInputTokens) {\n stats.cacheHits++;\n stats.tokensRead += result.cacheReadInputTokens;\n }\n },\n\n stats() {\n return { ...stats };\n },\n };\n\n return middleware;\n}\n","// =============================================================================\n// ToolCallPatching Middleware — Cross-provider tool call normalization\n// =============================================================================\n\nimport type {\n MiddlewarePort,\n MiddlewareContext,\n BeforeToolCallParams,\n BeforeToolCallResult,\n AfterToolCallParams,\n AfterToolCallResult,\n} from \"../ports/middleware.port.js\";\nimport { MiddlewarePriority } from \"../ports/middleware.port.js\";\n\nexport interface ToolCallPatchingOptions {\n /** Normalize stringified JSON args to objects (default: true) */\n parseStringArgs?: boolean;\n /** Strip null/undefined fields from args (default: false) */\n stripNullArgs?: boolean;\n /** Apply type coercion for common mismatches (default: true) */\n coerceTypes?: boolean;\n /** Rename tool calls using a mapping (e.g., provider-specific aliases) */\n aliasMap?: Record<string, string>;\n /** Normalize result format to standard shape (default: true) */\n normalizeResults?: boolean;\n}\n\ninterface PatchStats {\n argsParsed: number;\n nullsStripped: number;\n typesCoerced: number;\n aliasesApplied: number;\n resultsNormalized: number;\n}\n\n/**\n * Normalizes tool call arguments and results across providers.\n *\n * Handles common issues:\n * - OpenAI sends args as stringified JSON, Anthropic sends objects\n * - Google wraps results differently than OpenAI\n * - Null fields that should be omitted\n * - Type mismatches (string \"42\" vs number 42)\n */\nexport function createToolCallPatchingMiddleware(\n options: ToolCallPatchingOptions = {},\n): MiddlewarePort & { stats(): PatchStats } {\n const parseStringArgs = options.parseStringArgs ?? true;\n const stripNullArgs = options.stripNullArgs ?? false;\n const coerceTypes = options.coerceTypes ?? true;\n const aliasMap = options.aliasMap ?? {};\n const normalizeResults = options.normalizeResults ?? true;\n\n const stats: PatchStats = {\n argsParsed: 0,\n nullsStripped: 0,\n typesCoerced: 0,\n aliasesApplied: 0,\n resultsNormalized: 0,\n };\n\n function patchArgs(args: unknown): unknown {\n let result = args;\n\n // Parse stringified JSON\n if (parseStringArgs && typeof result === \"string\") {\n try {\n result = JSON.parse(result);\n stats.argsParsed++;\n } catch {\n // Not JSON, leave as-is\n }\n }\n\n if (typeof result !== \"object\" || result === null) return result;\n\n let obj = result as Record<string, unknown>;\n\n // Strip null/undefined fields\n if (stripNullArgs) {\n const cleaned: Record<string, unknown> = {};\n let stripped = false;\n for (const [k, v] of Object.entries(obj)) {\n if (v !== null && v !== undefined) {\n cleaned[k] = v;\n } else {\n stripped = true;\n }\n }\n if (stripped) {\n obj = cleaned;\n stats.nullsStripped++;\n }\n }\n\n // Coerce common type mismatches\n if (coerceTypes) {\n const coerced: Record<string, unknown> = {};\n let didCoerce = false;\n for (const [k, v] of Object.entries(obj)) {\n if (typeof v === \"string\") {\n // String → number\n if (/^-?\\d+(\\.\\d+)?$/.test(v)) {\n coerced[k] = Number(v);\n didCoerce = true;\n continue;\n }\n // String → boolean\n if (v === \"true\" || v === \"false\") {\n coerced[k] = v === \"true\";\n didCoerce = true;\n continue;\n }\n }\n coerced[k] = v;\n }\n if (didCoerce) {\n obj = coerced;\n stats.typesCoerced++;\n }\n }\n\n return obj;\n }\n\n function normalizeResult(result: unknown): unknown {\n if (!normalizeResults) return result;\n\n // Unwrap common provider wrappers\n if (typeof result === \"object\" && result !== null) {\n const r = result as Record<string, unknown>;\n // Google Gemini wraps in { functionResponse: { response: { ... } } }\n if (\"functionResponse\" in r && typeof r.functionResponse === \"object\") {\n const fr = r.functionResponse as Record<string, unknown>;\n if (\"response\" in fr) {\n stats.resultsNormalized++;\n return fr.response;\n }\n }\n // Some providers wrap in { output: ... }\n if (\"output\" in r && Object.keys(r).length === 1) {\n stats.resultsNormalized++;\n return r.output;\n }\n }\n\n return result;\n }\n\n const middleware: MiddlewarePort & { stats(): PatchStats } = {\n name: \"gauss:tool-call-patching\",\n priority: MiddlewarePriority.EARLY,\n\n beforeTool(\n _ctx: MiddlewareContext,\n params: BeforeToolCallParams,\n ): BeforeToolCallResult | void {\n const patchedArgs = patchArgs(params.args);\n const toolName = aliasMap[params.toolName] ?? params.toolName;\n\n if (toolName !== params.toolName) stats.aliasesApplied++;\n\n const argsChanged = patchedArgs !== params.args;\n const nameChanged = toolName !== params.toolName;\n\n if (argsChanged || nameChanged) {\n const patch: BeforeToolCallResult = { args: patchedArgs };\n if (nameChanged) (patch as Record<string, unknown>).toolName = toolName;\n return patch;\n }\n },\n\n afterTool(\n _ctx: MiddlewareContext,\n params: AfterToolCallParams,\n ): AfterToolCallResult | void {\n const normalized = normalizeResult(params.result);\n if (normalized !== params.result) {\n return { result: normalized };\n }\n },\n\n stats() {\n return { ...stats };\n },\n };\n\n return middleware;\n}\n","// =============================================================================\n// LlmJudgeConsensus — LLM-based consensus using a judge model\n// =============================================================================\n\nimport { generateText } from \"../../core/llm/index.js\";\nimport type { LanguageModel } from \"../../core/llm/index.js\";\nimport type {\n ConsensusPort,\n ConsensusResult,\n} from \"../../ports/consensus.port.js\";\n\nexport interface LlmJudgeOptions {\n model: LanguageModel;\n criteria?: string;\n}\n\nconst DEFAULT_CRITERIA =\n \"quality, completeness, correctness, and clarity\";\n\nexport class LlmJudgeConsensus implements ConsensusPort {\n constructor(private readonly options: LlmJudgeOptions) {}\n\n async evaluate(\n results: Array<{ id: string; output: string }>,\n ): Promise<ConsensusResult> {\n if (results.length === 0) {\n throw new Error(\"No results to evaluate\");\n }\n if (results.length === 1) {\n return {\n winnerId: results[0].id,\n winnerOutput: results[0].output,\n scores: { [results[0].id]: 10 },\n };\n }\n\n const criteria = this.options.criteria ?? DEFAULT_CRITERIA;\n\n const prompt = [\n \"You are a judge evaluating multiple results. Evaluate each result based on: \" + criteria + \".\",\n \"\",\n \"Results:\",\n ...results.map(\n (r, i) => `--- Result ${i + 1} (id: ${r.id}) ---\\n${r.output}\\n`,\n ),\n \"\",\n \"Respond ONLY with a JSON object (no markdown fences) with this structure:\",\n JSON.stringify({\n scores: { \"<id>\": \"<number 1-10>\" },\n winnerId: \"<id of best result>\",\n merged: \"<if top scores are within 1 point, merge the best parts into a single output; otherwise null>\",\n reasoning: \"<brief explanation>\",\n }),\n ].join(\"\\n\");\n\n try {\n const { text } = await generateText({\n model: this.options.model,\n prompt,\n });\n\n const cleaned = text\n .replace(/```(?:json)?\\s*/g, \"\")\n .replace(/```\\s*/g, \"\")\n .trim();\n\n const parsed = JSON.parse(cleaned) as {\n scores?: Record<string, number>;\n winnerId?: string;\n merged?: string | null;\n reasoning?: string;\n };\n\n const scores: Record<string, number> = {};\n if (parsed.scores) {\n for (const [k, v] of Object.entries(parsed.scores)) {\n scores[k] = Number(v);\n }\n }\n\n const winnerId =\n parsed.winnerId && results.some((r) => r.id === parsed.winnerId)\n ? parsed.winnerId\n : results[0].id;\n\n const winner = results.find((r) => r.id === winnerId)!;\n\n return {\n winnerId,\n winnerOutput: winner.output,\n scores,\n merged: parsed.merged ?? undefined,\n reasoning: parsed.reasoning ?? undefined,\n };\n } catch {\n // Fallback to first result on any error\n return {\n winnerId: results[0].id,\n winnerOutput: results[0].output,\n reasoning: \"LLM judge evaluation failed; falling back to first result\",\n };\n }\n }\n}\n","// =============================================================================\n// MajorityVoteConsensus — Simple majority voting by output similarity\n// =============================================================================\n\nimport type {\n ConsensusPort,\n ConsensusResult,\n} from \"../../ports/consensus.port.js\";\n\nexport class MajorityVoteConsensus implements ConsensusPort {\n async evaluate(\n results: Array<{ id: string; output: string }>,\n ): Promise<ConsensusResult> {\n if (results.length === 0) {\n throw new Error(\"No results to evaluate\");\n }\n\n const groups = new Map<string, Array<{ id: string; output: string }>>();\n\n for (const r of results) {\n const key = r.output.trim();\n const group = groups.get(key) ?? [];\n group.push(r);\n groups.set(key, group);\n }\n\n let bestGroup: Array<{ id: string; output: string }> = [];\n for (const group of groups.values()) {\n if (group.length > bestGroup.length) {\n bestGroup = group;\n }\n }\n\n const winner = bestGroup[0];\n const scores: Record<string, number> = {};\n for (const r of results) {\n scores[r.id] = r.output.trim() === winner.output.trim() ? 1 : 0;\n }\n\n return {\n winnerId: winner.id,\n winnerOutput: winner.output,\n scores,\n reasoning: `Selected by majority vote (${bestGroup.length}/${results.length} matching outputs)`,\n };\n }\n}\n","// =============================================================================\n// DebateConsensus — Multi-round debate until convergence\n// =============================================================================\n\nimport { generateText } from \"../../core/llm/index.js\";\nimport type { LanguageModel } from \"../../core/llm/index.js\";\nimport type {\n ConsensusPort,\n ConsensusResult,\n} from \"../../ports/consensus.port.js\";\n\nexport interface DebateOptions {\n model: LanguageModel;\n maxRounds?: number;\n}\n\nconst DEFAULT_MAX_ROUNDS = 3;\n\nexport class DebateConsensus implements ConsensusPort {\n constructor(private readonly options: DebateOptions) {}\n\n async evaluate(\n results: Array<{ id: string; output: string }>,\n ): Promise<ConsensusResult> {\n if (results.length === 0) {\n throw new Error(\"No results to evaluate\");\n }\n if (results.length === 1) {\n return {\n winnerId: results[0].id,\n winnerOutput: results[0].output,\n };\n }\n\n const maxRounds = this.options.maxRounds ?? DEFAULT_MAX_ROUNDS;\n let previousSynthesis = \"\";\n\n try {\n for (let round = 0; round < maxRounds; round++) {\n const prompt = [\n `Debate round ${round + 1}/${maxRounds}.`,\n \"Review the following results, critique them, and produce an improved synthesis that combines the best aspects of all results.\",\n \"\",\n \"Results:\",\n ...results.map(\n (r, i) => `--- Result ${i + 1} (id: ${r.id}) ---\\n${r.output}\\n`,\n ),\n ...(previousSynthesis\n ? [\n \"Previous synthesis:\",\n previousSynthesis,\n \"\",\n \"Improve upon the previous synthesis if possible. If it is already optimal, repeat it exactly.\",\n ]\n : []),\n \"\",\n \"Respond with ONLY the improved synthesis text, nothing else.\",\n ].join(\"\\n\");\n\n const { text } = await generateText({\n model: this.options.model,\n prompt,\n });\n\n const synthesis = text.trim();\n\n if (synthesis === previousSynthesis) {\n break; // converged\n }\n\n previousSynthesis = synthesis;\n }\n } catch {\n // On error, fall back to first result if no synthesis yet\n if (!previousSynthesis) {\n return {\n winnerId: results[0].id,\n winnerOutput: results[0].output,\n reasoning: \"Debate failed; falling back to first result\",\n };\n }\n }\n\n return {\n winnerId: \"debate-synthesis\",\n winnerOutput: previousSynthesis,\n merged: previousSynthesis,\n reasoning: `Produced via multi-round debate (up to ${maxRounds} rounds)`,\n };\n }\n}\n","// =============================================================================\n// AgentSupervisor — Erlang-style OTP supervisor for Gauss\n// =============================================================================\n\nimport type { AgentEventType } from \"../types.js\";\nimport { EventBus } from \"../agent/event-bus.js\";\nimport { AgentNode } from \"./agent-node.js\";\n\n// =============================================================================\n// Public Types\n// =============================================================================\n\nexport type SupervisorStrategy = \"one-for-one\" | \"one-for-all\" | \"rest-for-one\";\nexport type ChildPolicy = \"permanent\" | \"temporary\" | \"transient\";\n\nexport interface RestartIntensity {\n /** Maximum number of restarts allowed within the windowMs period. */\n maxRestarts: number;\n /** Sliding window duration in milliseconds. */\n windowMs: number;\n}\n\nexport interface ChildSpec {\n id: string;\n policy: ChildPolicy;\n factory: () => Promise<AgentNode>;\n heartbeatIntervalMs?: number;\n heartbeatTimeoutMs?: number;\n /** Called when intensity is exceeded and no parent supervisor is available. */\n degradedFallback?: () => Promise<string>;\n}\n\nexport interface SupervisorConfig {\n id: string;\n strategy: SupervisorStrategy;\n intensity: RestartIntensity;\n children: ChildSpec[];\n eventBus?: EventBus;\n parentSupervisor?: AgentSupervisor;\n shutdownTimeoutMs?: number;\n}\n\nexport type ChildStatus = \"running\" | \"stopped\" | \"crashed\" | \"restarting\";\n\n// =============================================================================\n// Internal state per child\n// =============================================================================\n\ninterface ChildState {\n spec: ChildSpec;\n node: AgentNode | null;\n status: ChildStatus;\n /** Timestamps of restarts within the sliding window. */\n restartTimestamps: number[];\n heartbeatTimer: ReturnType<typeof setInterval> | null;\n}\n\n// =============================================================================\n// AgentSupervisor\n// =============================================================================\n\nexport class AgentSupervisor {\n private readonly id: string;\n private readonly strategy: SupervisorStrategy;\n private readonly intensity: RestartIntensity;\n private readonly childSpecs: ChildSpec[];\n private readonly eventBus: EventBus | undefined;\n private readonly parentSupervisor: AgentSupervisor | undefined;\n private readonly shutdownTimeoutMs: number;\n\n private readonly children = new Map<string, ChildState>();\n\n constructor(config: SupervisorConfig) {\n this.id = config.id;\n this.strategy = config.strategy;\n this.intensity = config.intensity;\n this.childSpecs = config.children;\n this.eventBus = config.eventBus;\n this.parentSupervisor = config.parentSupervisor;\n this.shutdownTimeoutMs = config.shutdownTimeoutMs ?? 5000;\n }\n\n /** Start all children in declaration order. */\n async start(): Promise<void> {\n this.emit(\"supervisor:start\", { supervisorId: this.id });\n for (const spec of this.childSpecs) {\n await this.startChild(spec);\n }\n }\n\n /**\n * Entry point for crash recovery.\n * Checks policy, restart intensity, applies strategy.\n */\n async handleChildCrash(childId: string, error: Error): Promise<void> {\n const state = this.children.get(childId);\n if (!state) return;\n\n // Guard against concurrent/duplicate crash handling\n if (state.status === \"crashed\" || state.status === \"restarting\") return;\n\n state.status = \"crashed\";\n this.clearHeartbeat(state);\n this.emit(\"supervisor:child-crashed\", { supervisorId: this.id, childId, error: error.message });\n\n const { policy } = state.spec;\n\n // temporary: never restart\n if (policy === \"temporary\") {\n state.status = \"stopped\";\n this.emit(\"supervisor:child-stopped\", { supervisorId: this.id, childId, reason: \"temporary\" });\n return;\n }\n\n // Check restart intensity (sliding window)\n const now = Date.now();\n state.restartTimestamps = state.restartTimestamps.filter(\n (ts) => now - ts < this.intensity.windowMs,\n );\n\n if (state.restartTimestamps.length >= this.intensity.maxRestarts) {\n this.emit(\"supervisor:intensity-exceeded\", { supervisorId: this.id, childId });\n\n if (this.parentSupervisor) {\n await this.parentSupervisor.handleChildCrash(\n this.id,\n new Error(`Child supervisor \"${this.id}\" exceeded restart intensity for child \"${childId}\"`),\n );\n } else if (state.spec.degradedFallback) {\n try {\n await state.spec.degradedFallback();\n } catch {\n // ignore fallback errors\n }\n state.status = \"stopped\";\n } else {\n state.status = \"stopped\";\n }\n return;\n }\n\n state.restartTimestamps.push(now);\n\n switch (this.strategy) {\n case \"one-for-one\":\n await this.restartChild(childId);\n break;\n case \"one-for-all\":\n await this.restartAll();\n break;\n case \"rest-for-one\":\n await this.restartRestForOne(childId);\n break;\n }\n }\n\n /** Graceful shutdown: stop children in reverse declaration order. */\n async shutdown(): Promise<void> {\n this.emit(\"supervisor:stop\", { supervisorId: this.id });\n const reversed = [...this.childSpecs].reverse();\n for (const spec of reversed) {\n const state = this.children.get(spec.id);\n if (!state) continue;\n this.clearHeartbeat(state);\n state.status = \"stopped\";\n state.node = null;\n }\n }\n\n /** Return the status of a single child, or undefined if unknown. */\n getChildState(id: string): ChildStatus | undefined {\n return this.children.get(id)?.status;\n }\n\n /** Return a status map for all children. */\n getChildrenStatus(): Record<string, ChildStatus> {\n const result: Record<string, ChildStatus> = {};\n for (const [id, state] of this.children) {\n result[id] = state.status;\n }\n return result;\n }\n\n /** Return the live AgentNode for a running child, or null. */\n getLiveNode(id: string): AgentNode | null {\n const state = this.children.get(id);\n return state?.status === \"running\" ? (state.node ?? null) : null;\n }\n\n // ===========================================================================\n // Internal helpers\n // ===========================================================================\n\n private async startChild(spec: ChildSpec): Promise<void> {\n let state = this.children.get(spec.id);\n if (!state) {\n state = {\n spec,\n node: null,\n status: \"stopped\",\n restartTimestamps: [],\n heartbeatTimer: null,\n };\n this.children.set(spec.id, state);\n }\n\n state.status = \"restarting\";\n try {\n const node = await spec.factory();\n state.node = node;\n state.status = \"running\";\n this.emit(\"supervisor:child-started\", { supervisorId: this.id, childId: spec.id });\n } catch (err) {\n state.status = \"crashed\";\n this.emit(\"supervisor:child-crashed\", {\n supervisorId: this.id,\n childId: spec.id,\n error: err instanceof Error ? err.message : String(err),\n });\n throw err;\n }\n\n if (spec.heartbeatIntervalMs) {\n this.scheduleHeartbeat(spec.id, spec.heartbeatIntervalMs, spec.heartbeatTimeoutMs ?? 5000);\n }\n }\n\n private async restartChild(childId: string): Promise<void> {\n const state = this.children.get(childId);\n if (!state) return;\n\n state.status = \"restarting\";\n try {\n const node = await state.spec.factory();\n state.node = node;\n state.status = \"running\";\n this.emit(\"supervisor:child-restarted\", { supervisorId: this.id, childId });\n } catch (err) {\n state.status = \"crashed\";\n this.emit(\"supervisor:child-crashed\", {\n supervisorId: this.id,\n childId,\n error: err instanceof Error ? err.message : String(err),\n });\n throw err;\n }\n\n if (state.spec.heartbeatIntervalMs) {\n this.scheduleHeartbeat(\n childId,\n state.spec.heartbeatIntervalMs,\n state.spec.heartbeatTimeoutMs ?? 5000,\n );\n }\n }\n\n private async restartAll(): Promise<void> {\n // Stop all heartbeats and mark as stopped\n for (const state of this.children.values()) {\n this.clearHeartbeat(state);\n state.status = \"stopped\";\n state.node = null;\n }\n // Restart in declaration order, continue on individual failures\n for (const spec of this.childSpecs) {\n try {\n await this.restartChild(spec.id);\n } catch {\n // Factory failure already handled inside restartChild (status set to crashed)\n }\n }\n }\n\n private async restartRestForOne(crashedId: string): Promise<void> {\n const crashedIndex = this.childSpecs.findIndex((s) => s.id === crashedId);\n if (crashedIndex === -1) return;\n\n // Stop the crashed child and all subsequent children\n const toRestart = this.childSpecs.slice(crashedIndex);\n for (const spec of toRestart) {\n const state = this.children.get(spec.id);\n if (state) {\n this.clearHeartbeat(state);\n state.status = \"stopped\";\n state.node = null;\n }\n }\n\n // Restart in order, continue on individual failures\n for (const spec of toRestart) {\n try {\n await this.restartChild(spec.id);\n } catch {\n // Factory failure already handled inside restartChild (status set to crashed)\n }\n }\n }\n\n private scheduleHeartbeat(childId: string, intervalMs: number, timeoutMs: number): void {\n const state = this.children.get(childId);\n if (!state) return;\n\n this.clearHeartbeat(state);\n\n state.heartbeatTimer = setInterval(async () => {\n const current = this.children.get(childId);\n if (!current || current.status !== \"running\") return;\n\n const node = current.node;\n if (!node || typeof (node as unknown as Record<string, unknown>)[\"ping\"] !== \"function\") return;\n\n try {\n const ping = (node as unknown as Record<string, unknown>)[\"ping\"] as () => Promise<void>;\n await Promise.race([\n ping(),\n new Promise<never>((_, reject) =>\n setTimeout(\n () => reject(new Error(`Heartbeat timeout for child \"${childId}\"`)),\n timeoutMs,\n ),\n ),\n ]);\n } catch (err) {\n this.handleChildCrash(\n childId,\n err instanceof Error ? err : new Error(String(err)),\n ).catch(() => { /* crash handler errors are emitted as events */ });\n }\n }, intervalMs);\n }\n\n private clearHeartbeat(state: ChildState): void {\n if (state.heartbeatTimer !== null) {\n clearInterval(state.heartbeatTimer);\n state.heartbeatTimer = null;\n }\n }\n\n private emit(type: string, data?: unknown): void {\n this.eventBus?.emit(type as AgentEventType, data);\n }\n}\n","// =============================================================================\n// SupervisorBuilder — Fluent builder for AgentSupervisor\n// =============================================================================\n\nimport { AbstractBuilder } from \"../utils/abstract-builder.js\";\nimport { EventBus } from \"../agent/event-bus.js\";\nimport {\n AgentSupervisor,\n ChildSpec,\n RestartIntensity,\n SupervisorStrategy,\n SupervisorConfig,\n} from \"./agent-supervisor.js\";\n\nexport class SupervisorBuilder extends AbstractBuilder<AgentSupervisor> {\n private readonly supervisorId: string;\n private supervisorStrategy: SupervisorStrategy = \"one-for-one\";\n private supervisorIntensity: RestartIntensity = { maxRestarts: 3, windowMs: 5000 };\n private readonly childSpecs: ChildSpec[] = [];\n private bus: EventBus | undefined;\n private parent: AgentSupervisor | undefined;\n private shutdownTimeoutMs: number | undefined;\n\n constructor(id: string) {\n super();\n this.supervisorId = id;\n }\n\n strategy(s: SupervisorStrategy): this {\n this.supervisorStrategy = s;\n return this;\n }\n\n intensity(maxRestarts: number, windowMs: number): this {\n this.supervisorIntensity = { maxRestarts, windowMs };\n return this;\n }\n\n child(spec: ChildSpec): this {\n this.childSpecs.push(spec);\n return this;\n }\n\n withEventBus(bus: EventBus): this {\n this.bus = bus;\n return this;\n }\n\n withParent(parent: AgentSupervisor): this {\n this.parent = parent;\n return this;\n }\n\n withShutdownTimeout(ms: number): this {\n this.shutdownTimeoutMs = ms;\n return this;\n }\n\n protected validate(): void {\n if (!this.supervisorId) {\n throw new Error(\"SupervisorBuilder: supervisor id is required\");\n }\n }\n\n protected construct(): AgentSupervisor {\n const config: SupervisorConfig = {\n id: this.supervisorId,\n strategy: this.supervisorStrategy,\n intensity: this.supervisorIntensity,\n children: this.childSpecs,\n eventBus: this.bus,\n parentSupervisor: this.parent,\n shutdownTimeoutMs: this.shutdownTimeoutMs,\n };\n return new AgentSupervisor(config);\n }\n}\n","// =============================================================================\n// DynamicAgentGraph — AgentGraph with runtime mutation support\n// =============================================================================\n\nimport { AgentNode, type AgentNodeConfig } from \"./agent-node.js\";\nimport type { EventBus } from \"../agent/event-bus.js\";\n\nexport type MutationType =\n | \"add-node\"\n | \"remove-node\"\n | \"replace-node\"\n | \"add-edge\"\n | \"remove-edge\";\n\nexport interface MutationEntry {\n id: string;\n type: MutationType;\n timestamp: number;\n actorId: string;\n payload: unknown;\n status: \"applied\" | \"rejected\";\n rejectionReason?: string;\n}\n\nexport interface MutationResult {\n success: boolean;\n mutationId: string;\n violations?: { invariant: string; description: string }[];\n}\n\nfunction newMutationId(): string {\n return Math.random().toString(36).slice(2) + Date.now().toString(36);\n}\n\nexport class DynamicAgentGraph {\n // edges[to] = [from, ...] — same convention as AgentGraph\n private readonly nodes = new Map<string, AgentNode>();\n private readonly edges = new Map<string, string[]>();\n private readonly log: MutationEntry[] = [];\n\n constructor(private readonly eventBus?: EventBus) {}\n\n // ---------------------------------------------------------------------------\n // Mutations\n // ---------------------------------------------------------------------------\n\n addNode(config: AgentNodeConfig, actorId: string): MutationResult {\n if (this.nodes.has(config.id)) {\n return this.recordReject(\"add-node\", actorId, config, [\n { invariant: \"node-unique\", description: `Node \"${config.id}\" already exists` },\n ]);\n }\n this.nodes.set(config.id, new AgentNode(config));\n return this.recordApply(\"add-node\", actorId, config);\n }\n\n removeNode(nodeId: string, actorId: string): MutationResult {\n if (!this.nodes.has(nodeId)) {\n return this.recordReject(\"remove-node\", actorId, { nodeId }, [\n { invariant: \"node-exists\", description: `Node \"${nodeId}\" does not exist` },\n ]);\n }\n // Reject if any other node depends on this one\n const dependents: string[] = [];\n for (const [target, sources] of this.edges) {\n if (sources.includes(nodeId)) dependents.push(target);\n }\n if (dependents.length > 0) {\n return this.recordReject(\"remove-node\", actorId, { nodeId }, [\n {\n invariant: \"no-dependents\",\n description: `Node \"${nodeId}\" is depended upon by: ${dependents.join(\", \")}`,\n },\n ]);\n }\n this.nodes.delete(nodeId);\n // Remove any edges where nodeId is the target\n this.edges.delete(nodeId);\n return this.recordApply(\"remove-node\", actorId, { nodeId });\n }\n\n replaceNode(nodeId: string, newConfig: AgentNodeConfig, actorId: string): MutationResult {\n if (!this.nodes.has(nodeId)) {\n return this.recordReject(\"replace-node\", actorId, { nodeId, newConfig }, [\n { invariant: \"node-exists\", description: `Node \"${nodeId}\" does not exist` },\n ]);\n }\n // Hot-swap: keep the same id so existing edges remain valid\n this.nodes.set(nodeId, new AgentNode({ ...newConfig, id: nodeId }));\n return this.recordApply(\"replace-node\", actorId, { nodeId, newConfig });\n }\n\n addEdge(from: string, to: string, actorId: string): MutationResult {\n const violations: { invariant: string; description: string }[] = [];\n if (!this.nodes.has(from)) {\n violations.push({ invariant: \"node-exists\", description: `Node \"${from}\" does not exist` });\n }\n if (!this.nodes.has(to)) {\n violations.push({ invariant: \"node-exists\", description: `Node \"${to}\" does not exist` });\n }\n if (violations.length > 0) {\n return this.recordReject(\"add-edge\", actorId, { from, to }, violations);\n }\n if (this.wouldCreateCycle(from, to)) {\n return this.recordReject(\"add-edge\", actorId, { from, to }, [\n {\n invariant: \"no-cycle\",\n description: `Adding edge \"${from}\"→\"${to}\" would create a cycle`,\n },\n ]);\n }\n const deps = this.edges.get(to) ?? [];\n if (deps.includes(from)) {\n return this.recordReject(\"add-edge\", actorId, { from, to }, [\n { invariant: \"no-duplicate\", description: `Edge \"${from}\"→\"${to}\" already exists` },\n ]);\n }\n deps.push(from);\n this.edges.set(to, deps);\n return this.recordApply(\"add-edge\", actorId, { from, to });\n }\n\n removeEdge(from: string, to: string, actorId: string): MutationResult {\n const sources = this.edges.get(to);\n if (!sources?.includes(from)) {\n return this.recordReject(\"remove-edge\", actorId, { from, to }, [\n { invariant: \"edge-exists\", description: `Edge \"${from}\"→\"${to}\" does not exist` },\n ]);\n }\n const updated = sources.filter((s) => s !== from);\n if (updated.length === 0) {\n this.edges.delete(to);\n } else {\n this.edges.set(to, updated);\n }\n return this.recordApply(\"remove-edge\", actorId, { from, to });\n }\n\n // ---------------------------------------------------------------------------\n // Read\n // ---------------------------------------------------------------------------\n\n getNodes(): ReadonlyMap<string, AgentNode> {\n return this.nodes;\n }\n\n getEdges(): ReadonlyMap<string, readonly string[]> {\n return this.edges;\n }\n\n getMutationLog(): readonly MutationEntry[] {\n return this.log;\n }\n\n // ---------------------------------------------------------------------------\n // Internal helpers\n // ---------------------------------------------------------------------------\n\n /** DFS from `to` in the forward-edge direction to detect if `from` is reachable. */\n private wouldCreateCycle(from: string, to: string): boolean {\n // Build forward adjacency: source → [target, ...]\n const fwdAdj = new Map<string, string[]>();\n for (const [target, sources] of this.edges) {\n for (const source of sources) {\n const list = fwdAdj.get(source) ?? [];\n list.push(target);\n fwdAdj.set(source, list);\n }\n }\n // DFS from `to`, looking for `from`\n const visited = new Set<string>();\n const stack: string[] = [to];\n while (stack.length > 0) {\n const current = stack.pop()!;\n if (current === from) return true;\n if (visited.has(current)) continue;\n visited.add(current);\n for (const next of fwdAdj.get(current) ?? []) stack.push(next);\n }\n return false;\n }\n\n private recordApply(type: MutationType, actorId: string, payload: unknown): MutationResult {\n const id = newMutationId();\n const entry: MutationEntry = { id, type, timestamp: Date.now(), actorId, payload, status: \"applied\" };\n this.log.push(entry);\n this.eventBus?.emit(\"graph:mutation\", { mutationId: id, type, actorId, status: \"applied\" });\n return { success: true, mutationId: id };\n }\n\n private recordReject(\n type: MutationType,\n actorId: string,\n payload: unknown,\n violations: { invariant: string; description: string }[],\n ): MutationResult {\n const id = newMutationId();\n const rejectionReason = violations.map((v) => v.description).join(\"; \");\n const entry: MutationEntry = {\n id,\n type,\n timestamp: Date.now(),\n actorId,\n payload,\n status: \"rejected\",\n rejectionReason,\n };\n this.log.push(entry);\n this.eventBus?.emit(\"graph:mutation\", { mutationId: id, type, actorId, status: \"rejected\", rejectionReason });\n return { success: false, mutationId: id, violations };\n }\n}\n","// =============================================================================\n// GraphRAG Pipeline — Entity extraction → Knowledge graph → Hybrid retrieval\n// =============================================================================\n\nimport type { DocumentPort } from \"../ports/document.port.js\";\nimport type { EmbeddingPort } from \"../ports/embedding.port.js\";\nimport type { VectorStorePort, VectorSearchResult, VectorFilter } from \"../ports/vector-store.port.js\";\nimport type { KnowledgeGraphPort, GraphNode, GraphEdge } from \"../ports/knowledge-graph.port.js\";\nimport type { EntityExtractorPort } from \"../ports/entity-extractor.port.js\";\nimport type { ChunkOptions } from \"../ports/document.port.js\";\n\n// =============================================================================\n// Configuration\n// =============================================================================\n\nexport interface GraphRAGConfig {\n documentPort: DocumentPort;\n embeddingPort: EmbeddingPort;\n vectorStorePort: VectorStorePort;\n graphPort: KnowledgeGraphPort;\n entityExtractor: EntityExtractorPort;\n chunkOptions?: ChunkOptions;\n /** Weight for vector similarity in hybrid scoring (0-1, default 0.6) */\n vectorWeight?: number;\n /** Weight for graph proximity in hybrid scoring (0-1, default 0.4) */\n graphWeight?: number;\n /** Max graph traversal depth for context expansion (default 2) */\n maxGraphDepth?: number;\n /** Minimum relevance score for results (default 0) */\n minRelevance?: number;\n /** Maximum results (default 10) */\n maxResults?: number;\n}\n\nexport interface GraphIngestResult {\n documentsProcessed: number;\n chunksCreated: number;\n embeddingsGenerated: number;\n entitiesExtracted: number;\n relationsExtracted: number;\n graphNodesAdded: number;\n graphEdgesAdded: number;\n totalTokens: number;\n}\n\nexport interface GraphQueryResult {\n results: Array<VectorSearchResult & { graphScore: number; hybridScore: number }>;\n /** Graph context: related entities and relations */\n graphContext: { nodes: GraphNode[]; edges: GraphEdge[] };\n /** Formatted context for prompt injection */\n context: string;\n totalTokensUsed: number;\n}\n\n// =============================================================================\n// Pipeline\n// =============================================================================\n\nexport class GraphRAGPipeline {\n private readonly config: Required<\n Pick<GraphRAGConfig, \"vectorWeight\" | \"graphWeight\" | \"maxGraphDepth\" | \"minRelevance\" | \"maxResults\">\n > & GraphRAGConfig;\n\n constructor(config: GraphRAGConfig) {\n this.config = {\n ...config,\n vectorWeight: config.vectorWeight ?? 0.6,\n graphWeight: config.graphWeight ?? 0.4,\n maxGraphDepth: config.maxGraphDepth ?? 2,\n minRelevance: config.minRelevance ?? 0,\n maxResults: config.maxResults ?? 10,\n };\n const wSum = this.config.vectorWeight + this.config.graphWeight;\n if (this.config.vectorWeight < 0 || this.config.graphWeight < 0) {\n throw new Error(\"vectorWeight and graphWeight must be non-negative\");\n }\n if (Math.abs(wSum - 1.0) > 0.001) {\n throw new Error(`vectorWeight + graphWeight must sum to 1.0 (got ${wSum})`);\n }\n }\n\n /** Ingest: extract → chunk → embed → store + entity extraction → graph build */\n async ingest(source: string, mimeType?: string): Promise<GraphIngestResult> {\n const { documentPort, embeddingPort, vectorStorePort, graphPort, entityExtractor, chunkOptions } = this.config;\n\n // Extract & transform & chunk\n const rawDocs = await documentPort.extract(source, mimeType);\n const transformed = await documentPort.transform(rawDocs);\n const chunks = await documentPort.chunk(transformed, chunkOptions);\n\n // Embed and store in vector store\n const batchSize = 32;\n let totalTokens = 0;\n const vectorDocs = [];\n\n for (let i = 0; i < chunks.length; i += batchSize) {\n const batch = chunks.slice(i, i + batchSize);\n const embeddings = await embeddingPort.embedBatch(batch.map((c) => c.content));\n for (let j = 0; j < batch.length; j++) {\n totalTokens += embeddings[j].tokenCount;\n vectorDocs.push({\n id: batch[j].id,\n embedding: embeddings[j].embedding,\n content: batch[j].content,\n metadata: { ...batch[j].metadata, source: batch[j].source, chunkIndex: batch[j].chunkIndex },\n });\n }\n }\n await vectorStorePort.upsert(vectorDocs);\n\n // Entity extraction + graph building\n let totalEntities = 0;\n let totalRelations = 0;\n const allNodes: GraphNode[] = [];\n const allEdges: GraphEdge[] = [];\n const seenNodeIds = new Set<string>();\n\n for (const chunk of chunks) {\n const { entities, relations } = await entityExtractor.extract(chunk.content);\n totalEntities += entities.length;\n totalRelations += relations.length;\n\n // Create graph nodes from entities\n for (const entity of entities) {\n const nodeId = `${entity.type}::${entity.name}`;\n if (!seenNodeIds.has(nodeId)) {\n seenNodeIds.add(nodeId);\n allNodes.push({\n id: nodeId,\n type: entity.type,\n properties: { ...entity.properties, name: entity.name },\n });\n }\n }\n\n // Create graph edges from relations\n for (const rel of relations) {\n // Find matching entity types for source/target (case-insensitive)\n const srcEntity = entities.find((e) => e.name.toLowerCase().trim() === rel.source.toLowerCase().trim());\n const tgtEntity = entities.find((e) => e.name.toLowerCase().trim() === rel.target.toLowerCase().trim());\n const sourceId = srcEntity ? `${srcEntity.type}::${srcEntity.name}` : `UNKNOWN::${rel.source}`;\n const targetId = tgtEntity ? `${tgtEntity.type}::${tgtEntity.name}` : `UNKNOWN::${rel.target}`;\n\n // Ensure nodes exist for relation endpoints\n if (!seenNodeIds.has(sourceId)) {\n seenNodeIds.add(sourceId);\n allNodes.push({ id: sourceId, type: srcEntity?.type ?? \"UNKNOWN\", properties: { name: rel.source } });\n }\n if (!seenNodeIds.has(targetId)) {\n seenNodeIds.add(targetId);\n allNodes.push({ id: targetId, type: tgtEntity?.type ?? \"UNKNOWN\", properties: { name: rel.target } });\n }\n\n allEdges.push({\n source: sourceId,\n target: targetId,\n type: rel.type,\n weight: rel.confidence,\n properties: { sourceChunkId: chunk.id },\n });\n }\n\n // Link chunk to its entities via \"MENTIONED_IN\" edges\n const chunkNodeId = `CHUNK::${chunk.id}`;\n if (!seenNodeIds.has(chunkNodeId)) {\n seenNodeIds.add(chunkNodeId);\n allNodes.push({ id: chunkNodeId, type: \"CHUNK\", properties: { content: chunk.content.slice(0, 200) } });\n }\n for (const entity of entities) {\n const entityNodeId = `${entity.type}::${entity.name}`;\n allEdges.push({\n source: entityNodeId,\n target: chunkNodeId,\n type: \"MENTIONED_IN\",\n weight: 1.0,\n properties: {},\n });\n }\n }\n\n if (allNodes.length > 0) await graphPort.addNodes(allNodes);\n if (allEdges.length > 0) await graphPort.addEdges(allEdges);\n\n return {\n documentsProcessed: rawDocs.length,\n chunksCreated: chunks.length,\n embeddingsGenerated: vectorDocs.length,\n entitiesExtracted: totalEntities,\n relationsExtracted: totalRelations,\n graphNodesAdded: allNodes.length,\n graphEdgesAdded: allEdges.length,\n totalTokens,\n };\n }\n\n /** Query: vector search + entity extraction from query + graph expansion + hybrid scoring */\n async query(queryText: string, options?: { filter?: VectorFilter; topK?: number }): Promise<GraphQueryResult> {\n const { embeddingPort, vectorStorePort, graphPort, entityExtractor, vectorWeight, graphWeight, maxGraphDepth, maxResults, minRelevance } = this.config;\n const topK = options?.topK ?? maxResults;\n\n // 1. Vector search\n const queryEmb = await embeddingPort.embed(queryText);\n const vectorResults = await vectorStorePort.query({\n embedding: queryEmb.embedding,\n topK: topK * 3, // Over-fetch for hybrid scoring\n minScore: minRelevance,\n filter: options?.filter,\n });\n\n // 2. Extract entities from query for graph traversal\n const queryExtraction = await entityExtractor.extract(queryText);\n const queryEntityIds = queryExtraction.entities.map((e) => `${e.type}::${e.name}`);\n\n // 3. Graph expansion: find neighbors of query entities\n const graphNodes: GraphNode[] = [];\n const graphEdges: GraphEdge[] = [];\n const relatedChunkIds = new Set<string>();\n\n for (const entityId of queryEntityIds) {\n const node = await graphPort.getNode(entityId);\n if (!node) continue;\n graphNodes.push(node);\n\n const subgraph = await graphPort.query({\n startNodeId: entityId,\n maxDepth: maxGraphDepth,\n });\n for (const n of subgraph.nodes) {\n if (!graphNodes.some((gn) => gn.id === n.id)) graphNodes.push(n);\n if (n.type === \"CHUNK\") relatedChunkIds.add(n.id.replace(\"CHUNK::\", \"\"));\n }\n for (const e of subgraph.edges) graphEdges.push(e);\n }\n\n // 4. Hybrid scoring: combine vector similarity + graph proximity\n const hybridResults = vectorResults.map((vr) => {\n const chunkId = vr.id;\n const isGraphRelated = relatedChunkIds.has(chunkId);\n const graphScore = isGraphRelated ? 1.0 : 0.0;\n const hybridScore = vectorWeight * vr.score + graphWeight * graphScore;\n return { ...vr, graphScore, hybridScore };\n });\n\n // Sort by hybrid score descending and limit\n hybridResults.sort((a, b) => b.hybridScore - a.hybridScore);\n const finalResults = hybridResults.slice(0, topK);\n\n // 5. Format context\n const graphSummary = graphNodes.length > 0\n ? `\\n\\n[Knowledge Graph Context]\\nEntities: ${graphNodes.filter((n) => n.type !== \"CHUNK\").map((n) => `${n.properties.name} (${n.type})`).join(\", \")}\\nRelations: ${graphEdges.filter((e) => e.type !== \"MENTIONED_IN\").map((e) => `${e.source} -[${e.type}]-> ${e.target}`).join(\", \")}`\n : \"\";\n\n const vectorContext = finalResults\n .map((r, i) => `[Source ${i + 1}] (hybrid: ${r.hybridScore.toFixed(3)}, vec: ${r.score.toFixed(3)}, graph: ${r.graphScore.toFixed(1)})\\n${r.content}`)\n .join(\"\\n\\n---\\n\\n\");\n\n const context = graphSummary + (graphSummary ? \"\\n\\n\" : \"\") + vectorContext;\n\n return {\n results: finalResults,\n graphContext: { nodes: graphNodes, edges: graphEdges },\n context,\n totalTokensUsed: queryEmb.tokenCount,\n };\n }\n}\n","// =============================================================================\n// InMemoryEmbeddingAdapter — Mock embedding for testing (random vectors)\n// =============================================================================\n\nimport type { EmbeddingPort, EmbeddingResult } from \"../../ports/embedding.port.js\";\n\nexport class InMemoryEmbeddingAdapter implements EmbeddingPort {\n readonly dimensions: number;\n readonly modelId: string;\n private readonly embedFn: (text: string) => number[];\n\n constructor(options?: {\n dimensions?: number;\n modelId?: string;\n embedFn?: (text: string) => number[];\n }) {\n this.dimensions = options?.dimensions ?? 384;\n this.modelId = options?.modelId ?? \"inmemory-mock\";\n this.embedFn = options?.embedFn ?? (() => this.randomVector());\n }\n\n async embed(text: string): Promise<EmbeddingResult> {\n const embedding = this.embedFn(text);\n return { embedding, tokenCount: Math.ceil(text.length / 4) };\n }\n\n async embedBatch(texts: string[]): Promise<EmbeddingResult[]> {\n return Promise.all(texts.map((t) => this.embed(t)));\n }\n\n private randomVector(): number[] {\n const vec = new Array(this.dimensions);\n let norm = 0;\n for (let i = 0; i < this.dimensions; i++) {\n vec[i] = Math.random() * 2 - 1;\n norm += vec[i] * vec[i];\n }\n norm = Math.sqrt(norm);\n for (let i = 0; i < this.dimensions; i++) {\n vec[i] /= norm;\n }\n return vec;\n }\n}\n","// =============================================================================\n// InMemoryVectorStore — Brute-force cosine similarity vector search\n// =============================================================================\n\nimport type {\n VectorStorePort,\n VectorDocument,\n VectorSearchParams,\n VectorSearchResult,\n VectorIndexStats,\n VectorFilter,\n} from \"../../ports/vector-store.port.js\";\n\nexport class InMemoryVectorStore implements VectorStorePort {\n private readonly store = new Map<string, VectorDocument>();\n\n async upsert(documents: VectorDocument[]): Promise<void> {\n for (const doc of documents) {\n this.store.set(doc.id, safeClone(doc));\n }\n }\n\n async query(params: VectorSearchParams): Promise<VectorSearchResult[]> {\n const results: VectorSearchResult[] = [];\n\n for (const doc of this.store.values()) {\n if (params.filter && !matchesFilter(doc.metadata, params.filter)) {\n continue;\n }\n\n const score = cosineSimilarity(params.embedding, doc.embedding);\n if (params.minScore !== undefined && score < params.minScore) continue;\n\n results.push({\n id: doc.id,\n content: doc.content,\n metadata: { ...doc.metadata },\n score,\n embedding: params.includeEmbeddings ? [...doc.embedding] : undefined,\n });\n }\n\n results.sort((a, b) => b.score - a.score);\n return results.slice(0, params.topK);\n }\n\n async delete(ids: string[]): Promise<void> {\n for (const id of ids) {\n this.store.delete(id);\n }\n }\n\n async indexStats(): Promise<VectorIndexStats> {\n let dims = 0;\n for (const doc of this.store.values()) {\n dims = doc.embedding.length;\n break;\n }\n return {\n totalDocuments: this.store.size,\n dimensions: dims,\n indexType: \"brute-force\",\n };\n }\n}\n\n// =============================================================================\n// Cosine similarity\n// =============================================================================\n\nfunction cosineSimilarity(a: number[], b: number[]): number {\n if (a.length !== b.length) return 0;\n let dot = 0, normA = 0, normB = 0;\n for (let i = 0; i < a.length; i++) {\n dot += a[i] * b[i];\n normA += a[i] * a[i];\n normB += b[i] * b[i];\n }\n const denom = Math.sqrt(normA) * Math.sqrt(normB);\n return denom === 0 ? 0 : dot / denom;\n}\n\n// =============================================================================\n// Metadata filter evaluation (MongoDB-style subset)\n// =============================================================================\n\nfunction matchesFilter(\n metadata: Record<string, unknown>,\n filter: VectorFilter,\n): boolean {\n if (\"$and\" in filter) {\n return (filter.$and as VectorFilter[]).every((f) => matchesFilter(metadata, f));\n }\n if (\"$or\" in filter) {\n return (filter.$or as VectorFilter[]).some((f) => matchesFilter(metadata, f));\n }\n if (\"$not\" in filter) {\n return !matchesFilter(metadata, filter.$not as VectorFilter);\n }\n\n // Field-level comparison\n for (const [key, condition] of Object.entries(filter)) {\n const val = metadata[key];\n\n if (condition === null || condition === undefined || typeof condition !== \"object\") {\n // Direct equality\n if (val !== condition) return false;\n continue;\n }\n\n const cond = condition as Record<string, unknown>;\n\n if (\"$eq\" in cond && val !== cond.$eq) return false;\n if (\"$ne\" in cond && val === cond.$ne) return false;\n if (\"$gt\" in cond && !(typeof val === \"number\" && val > (cond.$gt as number))) return false;\n if (\"$gte\" in cond && !(typeof val === \"number\" && val >= (cond.$gte as number))) return false;\n if (\"$lt\" in cond && !(typeof val === \"number\" && val < (cond.$lt as number))) return false;\n if (\"$lte\" in cond && !(typeof val === \"number\" && val <= (cond.$lte as number))) return false;\n if (\"$in\" in cond && !(cond.$in as unknown[]).includes(val)) return false;\n if (\"$nin\" in cond && (cond.$nin as unknown[]).includes(val)) return false;\n }\n\n return true;\n}\n\nfunction safeClone<T>(value: T): T {\n try {\n // JSON roundtrip guarantees serializability downstream\n return JSON.parse(JSON.stringify(value));\n } catch {\n // Fallback for types JSON can't handle (Date, Map, etc.)\n try {\n return structuredClone(value);\n } catch {\n return value;\n }\n }\n}\n","// =============================================================================\n// MarkdownDocumentAdapter — Extract, transform, chunk markdown content\n// =============================================================================\n\nimport type { DocumentPort, Document, ChunkOptions } from \"../../ports/document.port.js\";\n\nconst DEFAULT_CHUNK_SIZE = 1000;\nconst DEFAULT_OVERLAP = 200;\n\nexport class MarkdownDocumentAdapter implements DocumentPort {\n async extract(source: string, _mimeType?: string): Promise<Document[]> {\n // Source is raw text content\n return [\n {\n id: generateId(source),\n content: source,\n source: \"inline\",\n metadata: {},\n },\n ];\n }\n\n async transform(documents: Document[]): Promise<Document[]> {\n return documents.map((doc) => ({\n ...doc,\n // Normalize whitespace, trim\n content: doc.content.replace(/\\r\\n/g, \"\\n\").replace(/\\n{3,}/g, \"\\n\\n\").trim(),\n }));\n }\n\n async chunk(documents: Document[], options?: ChunkOptions): Promise<Document[]> {\n const chunkSize = options?.chunkSize ?? DEFAULT_CHUNK_SIZE;\n const overlap = options?.chunkOverlap ?? DEFAULT_OVERLAP;\n const separator = options?.separator ?? \"\\n\\n\";\n\n const result: Document[] = [];\n\n for (const doc of documents) {\n const segments = doc.content.split(separator);\n let currentChunk = \"\";\n let chunkIndex = 0;\n const chunks: string[] = [];\n\n for (const segment of segments) {\n if (currentChunk.length + segment.length + separator.length > chunkSize && currentChunk.length > 0) {\n chunks.push(currentChunk.trim());\n // Overlap: keep tail of current chunk\n if (overlap > 0) {\n currentChunk = currentChunk.slice(-overlap) + separator + segment;\n } else {\n currentChunk = segment;\n }\n } else {\n currentChunk = currentChunk\n ? currentChunk + separator + segment\n : segment;\n }\n }\n\n if (currentChunk.trim()) {\n chunks.push(currentChunk.trim());\n }\n\n for (const chunk of chunks) {\n result.push({\n id: `${doc.id}-chunk-${chunkIndex}`,\n content: chunk,\n source: doc.source,\n chunkIndex,\n totalChunks: chunks.length,\n metadata: { ...doc.metadata, parentId: doc.id },\n });\n chunkIndex++;\n }\n }\n\n return result;\n }\n}\n\nfunction generateId(content: string): string {\n let hash = 0;\n for (let i = 0; i < content.length; i++) {\n hash = ((hash << 5) - hash + content.charCodeAt(i)) | 0;\n }\n return `doc-${Math.abs(hash).toString(36)}`;\n}\n","// =============================================================================\n// InMemoryWorkingMemory — TTL-based ephemeral key-value store\n// =============================================================================\n\nimport type { WorkingMemoryPort, WorkingMemoryEntry } from \"../../ports/working-memory.port.js\";\n\ninterface StoredEntry {\n value: unknown;\n createdAt: number;\n expiresAt: number;\n}\n\nexport class InMemoryWorkingMemory implements WorkingMemoryPort {\n private readonly store = new Map<string, StoredEntry>();\n\n async get<T = unknown>(key: string): Promise<T | null> {\n const entry = this.store.get(key);\n if (!entry) return null;\n if (entry.expiresAt > 0 && Date.now() > entry.expiresAt) {\n this.store.delete(key);\n return null;\n }\n return entry.value as T;\n }\n\n async set(key: string, value: unknown, ttlMs?: number): Promise<void> {\n const now = Date.now();\n this.store.set(key, {\n value: safeClone(value),\n createdAt: now,\n expiresAt: ttlMs && ttlMs > 0 ? now + ttlMs : 0,\n });\n }\n\n async delete(key: string): Promise<boolean> {\n return this.store.delete(key);\n }\n\n async list(): Promise<WorkingMemoryEntry[]> {\n const now = Date.now();\n const entries: WorkingMemoryEntry[] = [];\n for (const [key, entry] of this.store) {\n if (entry.expiresAt > 0 && now > entry.expiresAt) {\n this.store.delete(key);\n continue;\n }\n entries.push({\n key,\n value: safeClone(entry.value),\n createdAt: entry.createdAt,\n expiresAt: entry.expiresAt,\n });\n }\n return entries;\n }\n\n async clear(): Promise<void> {\n this.store.clear();\n }\n}\n\nfunction safeClone<T>(value: T): T {\n try {\n return JSON.parse(JSON.stringify(value));\n } catch {\n try {\n return structuredClone(value);\n } catch {\n return value;\n }\n }\n}\n","// =============================================================================\n// InMemoryKnowledgeGraph — Adjacency list graph with BFS/DFS/Dijkstra\n// =============================================================================\n\nimport type {\n KnowledgeGraphPort,\n GraphNode,\n GraphEdge,\n GraphQueryOptions,\n SubgraphResult,\n} from \"../../ports/knowledge-graph.port.js\";\n\nexport class InMemoryKnowledgeGraphAdapter implements KnowledgeGraphPort {\n private nodes = new Map<string, GraphNode>();\n // adjacency: nodeId → Set of { target, edgeKey }\n private outEdges = new Map<string, Map<string, GraphEdge>>();\n private inEdges = new Map<string, Map<string, GraphEdge>>();\n\n private edgeKey(source: string, target: string): string {\n return `${source}::${target}`;\n }\n\n async addNodes(nodes: GraphNode[]): Promise<void> {\n for (const n of nodes) {\n this.nodes.set(n.id, { ...n });\n if (!this.outEdges.has(n.id)) this.outEdges.set(n.id, new Map());\n if (!this.inEdges.has(n.id)) this.inEdges.set(n.id, new Map());\n }\n }\n\n async addEdges(edges: GraphEdge[]): Promise<void> {\n for (const e of edges) {\n if (!this.nodes.has(e.source) || !this.nodes.has(e.target)) continue;\n if (e.weight < 0) throw new Error(`Edge weight must be non-negative, got ${e.weight} for ${e.source}->${e.target}`);\n const key = this.edgeKey(e.source, e.target);\n const edge = { ...e };\n this.outEdges.get(e.source)!.set(key, edge);\n this.inEdges.get(e.target)!.set(key, edge);\n }\n }\n\n async getNode(id: string): Promise<GraphNode | undefined> {\n return this.nodes.get(id);\n }\n\n async getNeighbors(nodeId: string, depth = 1): Promise<GraphNode[]> {\n const visited = new Set<string>();\n const queue: Array<{ id: string; d: number }> = [{ id: nodeId, d: 0 }];\n visited.add(nodeId);\n\n while (queue.length > 0) {\n const { id, d } = queue.shift()!;\n if (d >= depth) continue;\n const outMap = this.outEdges.get(id);\n if (outMap) {\n for (const edge of outMap.values()) {\n if (!visited.has(edge.target)) {\n visited.add(edge.target);\n queue.push({ id: edge.target, d: d + 1 });\n }\n }\n }\n const inMap = this.inEdges.get(id);\n if (inMap) {\n for (const edge of inMap.values()) {\n if (!visited.has(edge.source)) {\n visited.add(edge.source);\n queue.push({ id: edge.source, d: d + 1 });\n }\n }\n }\n }\n\n visited.delete(nodeId);\n return [...visited].map((id) => this.nodes.get(id)!).filter(Boolean);\n }\n\n async query(options: GraphQueryOptions): Promise<SubgraphResult> {\n const { startNodeId, maxDepth = 3, edgeTypes, nodeTypes, limit } = options;\n const visited = new Set<string>();\n const resultNodes: GraphNode[] = [];\n const resultEdges: GraphEdge[] = [];\n const queue: Array<{ id: string; d: number }> = [{ id: startNodeId, d: 0 }];\n visited.add(startNodeId);\n const start = this.nodes.get(startNodeId);\n if (start) resultNodes.push(start);\n\n while (queue.length > 0) {\n const { id, d } = queue.shift()!;\n if (d >= maxDepth) continue;\n if (limit && resultNodes.length >= limit) break;\n\n const outMap = this.outEdges.get(id);\n if (outMap) {\n for (const edge of outMap.values()) {\n if (edgeTypes && !edgeTypes.includes(edge.type)) continue;\n const targetNode = this.nodes.get(edge.target);\n if (!targetNode) continue;\n if (nodeTypes && !nodeTypes.includes(targetNode.type)) continue;\n resultEdges.push(edge);\n if (!visited.has(edge.target)) {\n visited.add(edge.target);\n resultNodes.push(targetNode);\n queue.push({ id: edge.target, d: d + 1 });\n }\n }\n }\n }\n\n return { nodes: resultNodes, edges: resultEdges };\n }\n\n async shortestPath(fromId: string, toId: string): Promise<GraphNode[]> {\n if (!this.nodes.has(fromId) || !this.nodes.has(toId)) return [];\n if (fromId === toId) return [this.nodes.get(fromId)!];\n\n // Dijkstra\n const dist = new Map<string, number>();\n const prev = new Map<string, string>();\n const pq: Array<{ id: string; cost: number }> = [];\n\n dist.set(fromId, 0);\n pq.push({ id: fromId, cost: 0 });\n\n while (pq.length > 0) {\n pq.sort((a, b) => a.cost - b.cost);\n const { id, cost } = pq.shift()!;\n if (cost > (dist.get(id) ?? Infinity)) continue;\n if (id === toId) break;\n\n const outMap = this.outEdges.get(id);\n if (outMap) {\n for (const edge of outMap.values()) {\n const alt = cost + edge.weight;\n if (alt < (dist.get(edge.target) ?? Infinity)) {\n dist.set(edge.target, alt);\n prev.set(edge.target, id);\n pq.push({ id: edge.target, cost: alt });\n }\n }\n }\n // Bidirectional for undirected traversal\n const inMap = this.inEdges.get(id);\n if (inMap) {\n for (const edge of inMap.values()) {\n const alt = cost + edge.weight;\n if (alt < (dist.get(edge.source) ?? Infinity)) {\n dist.set(edge.source, alt);\n prev.set(edge.source, id);\n pq.push({ id: edge.source, cost: alt });\n }\n }\n }\n }\n\n if (!prev.has(toId) && fromId !== toId) return [];\n\n const path: GraphNode[] = [];\n let cur: string | undefined = toId;\n while (cur !== undefined) {\n const node = this.nodes.get(cur);\n if (node) path.unshift(node);\n cur = prev.get(cur);\n }\n return path;\n }\n\n async subgraph(nodeIds: string[]): Promise<SubgraphResult> {\n const idSet = new Set(nodeIds);\n const nodes = nodeIds.map((id) => this.nodes.get(id)).filter(Boolean) as GraphNode[];\n const edges: GraphEdge[] = [];\n for (const id of nodeIds) {\n const outMap = this.outEdges.get(id);\n if (outMap) {\n for (const edge of outMap.values()) {\n if (idSet.has(edge.target)) edges.push(edge);\n }\n }\n }\n return { nodes, edges };\n }\n\n async removeNodes(ids: string[]): Promise<void> {\n for (const id of ids) {\n this.nodes.delete(id);\n // Remove all edges involving this node\n const outMap = this.outEdges.get(id);\n if (outMap) {\n for (const edge of outMap.values()) {\n this.inEdges.get(edge.target)?.delete(this.edgeKey(edge.source, edge.target));\n }\n }\n const inMap = this.inEdges.get(id);\n if (inMap) {\n for (const edge of inMap.values()) {\n this.outEdges.get(edge.source)?.delete(this.edgeKey(edge.source, edge.target));\n }\n }\n this.outEdges.delete(id);\n this.inEdges.delete(id);\n }\n }\n\n async removeEdges(pairs: Array<{ source: string; target: string }>): Promise<void> {\n for (const { source, target } of pairs) {\n const key = this.edgeKey(source, target);\n this.outEdges.get(source)?.delete(key);\n this.inEdges.get(target)?.delete(key);\n }\n }\n\n async clear(): Promise<void> {\n this.nodes.clear();\n this.outEdges.clear();\n this.inEdges.clear();\n }\n\n async stats(): Promise<{ nodeCount: number; edgeCount: number }> {\n let edgeCount = 0;\n for (const m of this.outEdges.values()) edgeCount += m.size;\n return { nodeCount: this.nodes.size, edgeCount };\n }\n}\n","// =============================================================================\n// PatternEntityExtractor — Regex/pattern-based entity extraction (NER-lite)\n// =============================================================================\n\nimport type { EntityExtractorPort, ExtractionResult, Entity, Relation } from \"../../ports/entity-extractor.port.js\";\n\nexport interface PatternRule {\n type: string;\n pattern: RegExp;\n /** Extract properties from match groups */\n extract?: (match: RegExpExecArray) => Record<string, unknown>;\n}\n\nexport interface RelationPattern {\n /** Pattern that spans two entity references */\n pattern: RegExp;\n type: string;\n /** Map group indices to source (1-based) and target (1-based) entity names */\n sourceGroup: number;\n targetGroup: number;\n confidence?: number;\n}\n\nexport interface PatternEntityExtractorConfig {\n entityPatterns: PatternRule[];\n relationPatterns?: RelationPattern[];\n}\n\n/** Default patterns for common entities */\nexport const DEFAULT_ENTITY_PATTERNS: PatternRule[] = [\n { type: \"PERSON\", pattern: /\\b([A-Z][a-z]+ [A-Z][a-z]+)\\b/g },\n { type: \"EMAIL\", pattern: /\\b([a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,})\\b/g },\n { type: \"URL\", pattern: /\\bhttps?:\\/\\/[^\\s<>\\\"]+/g },\n { type: \"DATE\", pattern: /\\b(\\d{4}-\\d{2}-\\d{2})\\b/g },\n { type: \"NUMBER\", pattern: /\\b(\\d+(?:\\.\\d+)?)\\b/g },\n];\n\nexport class PatternEntityExtractorAdapter implements EntityExtractorPort {\n private config: PatternEntityExtractorConfig;\n\n constructor(config?: Partial<PatternEntityExtractorConfig>) {\n this.config = {\n entityPatterns: config?.entityPatterns ?? DEFAULT_ENTITY_PATTERNS,\n relationPatterns: config?.relationPatterns ?? [],\n };\n }\n\n async extract(text: string): Promise<ExtractionResult> {\n const entities: Entity[] = [];\n const seen = new Set<string>();\n\n for (const rule of this.config.entityPatterns) {\n // Reset lastIndex for global patterns\n const pattern = new RegExp(rule.pattern.source, rule.pattern.flags);\n let match: RegExpExecArray | null;\n while ((match = pattern.exec(text)) !== null) {\n const name = match[1] ?? match[0];\n const key = `${rule.type}::${name}`;\n if (seen.has(key)) continue;\n seen.add(key);\n entities.push({\n name,\n type: rule.type,\n properties: rule.extract ? rule.extract(match) : {},\n start: match.index,\n end: match.index + match[0].length,\n });\n }\n }\n\n const relations: Relation[] = [];\n for (const rp of this.config.relationPatterns ?? []) {\n const pattern = new RegExp(rp.pattern.source, rp.pattern.flags);\n let match: RegExpExecArray | null;\n while ((match = pattern.exec(text)) !== null) {\n const source = match[rp.sourceGroup];\n const target = match[rp.targetGroup];\n if (source && target) {\n relations.push({\n source,\n target,\n type: rp.type,\n confidence: rp.confidence ?? 0.8,\n });\n }\n }\n }\n\n return { entities, relations };\n }\n}\n","// =============================================================================\n// ContextManager — Tool result offloading and message truncation\n// =============================================================================\n\nimport type { Message } from \"../types.js\";\nimport type { ContextManagerDeps } from \"./types.js\";\n\nconst TOOL_RESULTS_PATH = \"tool-results\";\n\nexport class ContextManager {\n private readonly deps: ContextManagerDeps;\n\n constructor(deps: ContextManagerDeps) {\n this.deps = deps;\n }\n\n shouldOffload(toolResult: string): boolean {\n const tokens = this.deps.tokenCounter.count(toolResult);\n return tokens > this.deps.config.offloadTokenThreshold;\n }\n\n async offloadToFilesystem(\n toolCallId: string,\n result: string,\n ): Promise<string> {\n const path = `${TOOL_RESULTS_PATH}/${toolCallId}.txt`;\n await this.deps.filesystem.write(path, result, \"transient\");\n return `[Result saved to transient/${path}]`;\n }\n\n shouldTruncate(messages: Message[], model: string): boolean {\n const tokenCount = this.deps.tokenCounter.countMessages(messages);\n const windowSize = this.deps.tokenCounter.getContextWindowSize(model);\n return tokenCount > windowSize * this.deps.config.truncationThreshold;\n }\n\n truncateMessages(messages: Message[], model: string): Message[] {\n if (!messages.length) return [];\n\n const windowSize = this.deps.tokenCounter.getContextWindowSize(model);\n const budget = Math.floor(\n windowSize * this.deps.config.truncationThreshold,\n );\n\n const systemMessages = messages.filter((m) => m.role === \"system\");\n const nonSystem = messages.filter((m) => m.role !== \"system\");\n\n const systemTokens = this.deps.tokenCounter.countMessages(systemMessages);\n const remaining = budget - systemTokens;\n\n if (remaining <= 0) return systemMessages;\n\n // Keep messages from the end (most recent first)\n const kept: Message[] = [];\n let used = 0;\n\n for (let i = nonSystem.length - 1; i >= 0; i--) {\n const msg = nonSystem[i]!;\n const tokens =\n this.deps.tokenCounter.count(msg.content) + 4;\n if (used + tokens > remaining) break;\n kept.unshift(msg);\n used += tokens;\n }\n\n return [...systemMessages, ...kept];\n }\n}\n","// =============================================================================\n// RollingSummarizer — LLM-based conversation summarization\n// =============================================================================\n\nimport type { Message, CompressedContext } from \"../types.js\";\nimport type { RollingSummarizerDeps } from \"./types.js\";\n\nconst SUMMARIZATION_PROMPT =\n \"Summarize the following conversation concisely, preserving key decisions, facts, and context:\";\n\nexport class RollingSummarizer {\n private readonly deps: RollingSummarizerDeps;\n\n constructor(deps: RollingSummarizerDeps) {\n this.deps = deps;\n }\n\n shouldSummarize(messages: Message[], model: string): boolean {\n const tokenCount = this.deps.tokenCounter.countMessages(messages);\n const windowSize = this.deps.tokenCounter.getContextWindowSize(model);\n return tokenCount > windowSize * this.deps.config.summarizationThreshold;\n }\n\n async summarize(\n messages: Message[],\n ): Promise<{\n summary: CompressedContext;\n remainingMessages: Message[];\n }> {\n const preserveCount = this.deps.config.preserveRecentMessages;\n\n const systemMessages = messages.filter((m) => m.role === \"system\");\n const nonSystem = messages.filter((m) => m.role !== \"system\");\n\n if (nonSystem.length <= preserveCount) {\n return {\n summary: {\n summary: \"\",\n originalMessageCount: 0,\n compressedAt: Date.now(),\n },\n remainingMessages: messages,\n };\n }\n\n const toSummarize = nonSystem.slice(0, -preserveCount);\n const recent = nonSystem.slice(-preserveCount);\n\n const conversationText = toSummarize\n .map((m) => `${m.role}: ${m.content}`)\n .join(\"\\n\\n\");\n\n const result = await this.deps.model.generate({\n messages: [\n {\n role: \"user\",\n content: `${SUMMARIZATION_PROMPT}\\n\\n${conversationText}`,\n },\n ],\n });\n\n const summary: CompressedContext = {\n summary: result.text,\n originalMessageCount: toSummarize.length,\n compressedAt: Date.now(),\n };\n\n const summaryMessage: Message = {\n role: \"system\",\n content: `[Previous conversation summary]\\n${result.text}`,\n };\n\n return {\n summary,\n remainingMessages: [\n ...systemMessages,\n summaryMessage,\n ...recent,\n ],\n };\n }\n}\n","const PARTIAL_RE = /\\{\\{>(\\w+)\\}\\}/g;\nconst VARIABLE_RE = /\\{\\{(\\w+)\\}\\}/g;\nconst BLOCK_VAR_RE = /\\{\\{#(?:each|if|unless)\\s+(\\w+)\\}\\}/g;\n\nconst FILTER_RE = /\\{\\{(\\w+(?:\\.\\w+)*)\\s*\\|([^}]+)\\}\\}/g;\n\nconst BLOCKED_PROPS = new Set(['__proto__', 'constructor', 'prototype']);\nconst KEYWORDS = new Set(['if', 'else', 'unless', 'each', 'this']);\n\nfunction isWordChar(ch: string | undefined): boolean {\n return ch !== undefined && /\\w/.test(ch);\n}\n\ntype ScanTarget = 'close' | 'else';\n\n/**\n * Generic depth-tracking scanner used by both findMatchingClose and findElseAtDepth0.\n * Walks `template` from `startIndex`, tracking depth via open/close tags that use\n * exact tag-name matching (no prefix matches).\n * - target='close': returns the index where the matching close tag brings depth to 0.\n * - target='else': starts at depth 0 and returns the index of `{{else}}` at depth 0.\n */\nfunction scanAtDepth0(\n template: string,\n openTags: string[],\n closeTags: string[],\n startIndex: number,\n target: ScanTarget,\n): number {\n let depth = target === 'close' ? 1 : 0;\n let i = startIndex;\n while (i < template.length) {\n // Check for {{else}} at depth 0 when searching for else\n if (target === 'else' && template.startsWith('{{else}}', i) && depth === 0) {\n return i;\n }\n let matched = false;\n for (const tag of openTags) {\n if (template.startsWith(tag, i) && !isWordChar(template[i + tag.length])) {\n depth++;\n i += tag.length;\n matched = true;\n break;\n }\n }\n if (!matched) {\n for (const tag of closeTags) {\n if (template.startsWith(tag, i)) {\n depth--;\n if (target === 'close' && depth === 0) return i;\n i += tag.length;\n matched = true;\n break;\n }\n }\n }\n if (!matched) i++;\n }\n return -1;\n}\n\nfunction findMatchingClose(template: string, openTag: string, closeTag: string, startIndex: number): number {\n return scanAtDepth0(template, [openTag], [closeTag], startIndex, 'close');\n}\n\nfunction findElseAtDepth0(body: string): number {\n return scanAtDepth0(body, ['{{#if', '{{#unless'], ['{{/if}}', '{{/unless}}'], 0, 'else');\n}\n\nfunction replaceAtDepth0(body: string, regex: RegExp, replacement: string | ((match: string, ...args: string[]) => string)): string {\n // Protect nested {{#each}}...{{/each}} blocks from replacement\n const id = Math.random().toString(36).slice(2, 10);\n const nested: string[] = [];\n let protected_ = body;\n const eachOpenRe = /\\{\\{#each\\s+\\w+\\}\\}/;\n let m: RegExpMatchArray | null;\n while ((m = eachOpenRe.exec(protected_)) !== null) {\n const start = m.index!;\n const bodyStart = start + m[0].length;\n const closeIndex = findMatchingClose(protected_, '{{#each', '{{/each}}', bodyStart);\n if (closeIndex === -1) break;\n const end = closeIndex + '{{/each}}'.length;\n const block = protected_.slice(start, end);\n const placeholder = `\\x00${id}_NESTED_${nested.length}\\x00`;\n nested.push(block);\n protected_ = protected_.slice(0, start) + placeholder + protected_.slice(end);\n }\n // Apply replacement only at depth 0\n if (typeof replacement === 'string') {\n protected_ = protected_.replace(regex, replacement);\n } else {\n protected_ = protected_.replace(regex, replacement as (...args: string[]) => string);\n }\n // Restore nested blocks\n for (let i = nested.length - 1; i >= 0; i--) {\n protected_ = protected_.replace(`\\x00${id}_NESTED_${i}\\x00`, nested[i]);\n }\n return protected_;\n}\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport type TemplateValue = string | number | boolean | null | undefined | any[] | Record<string, any>;\n\nexport interface PromptTemplateConfig {\n template: string;\n variables?: Record<string, TemplateValue>;\n partials?: Record<string, PromptTemplate>;\n}\n\ntype FilterFn = (value: string, ...args: string[]) => string;\n\nfunction splitFilterChain(chain: string): string[] {\n const parts: string[] = [];\n let current = '';\n let depth = 0;\n for (let i = 0; i < chain.length; i++) {\n const ch = chain[i];\n if (ch === '(') { depth++; current += ch; }\n else if (ch === ')') { depth--; current += ch; }\n else if (ch === '|' && depth === 0) {\n parts.push(current.trim());\n current = '';\n } else {\n current += ch;\n }\n }\n if (current.trim()) parts.push(current.trim());\n return parts;\n}\n\nconst BUILTIN_FILTERS: Record<string, FilterFn> = {\n uppercase: (v) => v.toUpperCase(),\n lowercase: (v) => v.toLowerCase(),\n trim: (v) => v.trim(),\n json: (v) => {\n try { return JSON.stringify(JSON.parse(v)); } catch { return JSON.stringify(v); }\n },\n default: (v, fallback) => (v === '' || v === 'undefined' || v === 'null') ? fallback : v,\n};\n\nfunction applyFilterChain(value: string, filterChain: string): string {\n let result = value;\n const filters = splitFilterChain(filterChain);\n for (const filterExpr of filters) {\n const parenMatch = filterExpr.match(/^(\\w+)\\(([^)]*)\\)$/);\n const filterName = parenMatch ? parenMatch[1] : filterExpr;\n const args = parenMatch ? [parenMatch[2].replace(/^['\"]|['\"]$/g, '')] : [];\n const filterFn = BUILTIN_FILTERS[filterName];\n if (filterFn) {\n result = filterFn(result, ...args);\n }\n }\n return result;\n}\n\nexport class PromptTemplate {\n constructor(private readonly config: PromptTemplateConfig) {}\n\n compile(overrides?: Record<string, TemplateValue>): string {\n const variables: Record<string, TemplateValue> = { ...this.config.variables, ...overrides };\n let compiled = this.config.template;\n\n // 1. Handle partials first {{>partialName}}\n compiled = compiled.replace(PARTIAL_RE, (_match, partialName) => {\n const partial = this.config.partials?.[partialName];\n if (!partial) {\n throw new Error(`Partial \"${partialName}\" not found`);\n }\n return partial.compile(variables);\n });\n\n // 2. Handle loops {{#each items}}...{{/each}}\n compiled = this.processLoops(compiled, variables);\n\n // 3. Handle conditionals {{#if}}...{{/if}} and {{#unless}}...{{/unless}}\n compiled = this.processConditionals(compiled, variables);\n\n // 4. Handle filters {{var | filter}}\n compiled = this.processFilters(compiled, variables);\n\n // 5. Handle variables {{var}}\n compiled = compiled.replace(VARIABLE_RE, (_match, varName) => {\n if (KEYWORDS.has(varName)) return '';\n if (!(varName in variables)) {\n throw new Error(`Required variable \"${varName}\" is missing`);\n }\n return String(variables[varName]);\n });\n\n return compiled;\n }\n\n private processLoops(template: string, variables: Record<string, TemplateValue>): string {\n const openRe = /\\{\\{#each\\s+(\\w+)\\}\\}/;\n let result = template;\n let match: RegExpMatchArray | null;\n while ((match = openRe.exec(result)) !== null) {\n const varName = match[1];\n const bodyStart = match.index! + match[0].length;\n const closeIndex = findMatchingClose(result, '{{#each', '{{/each}}', bodyStart);\n if (closeIndex === -1) break;\n const body = result.slice(bodyStart, closeIndex);\n const items = variables[varName];\n let replacement = '';\n if (Array.isArray(items)) {\n replacement = items.map((item, index) => {\n let r = body;\n r = replaceAtDepth0(r, /\\{\\{@index\\}\\}/g, String(index));\n r = replaceAtDepth0(r, /\\{\\{this\\.(\\w+)\\s*\\|([^}]+)\\}\\}/g, (_m: string, prop: string, filterChain: string) => {\n let value = '';\n if (item != null && typeof item === 'object' && Object.hasOwn(item as object, prop)) {\n value = String(item[prop]);\n }\n return applyFilterChain(value, filterChain);\n });\n r = replaceAtDepth0(r, /\\{\\{this\\s*\\|([^}]+)\\}\\}/g, (_m: string, filterChain: string) => {\n return applyFilterChain(String(item), filterChain);\n });\n r = replaceAtDepth0(r, /\\{\\{this\\.(\\w+)\\}\\}/g, (_m: string, prop: string) => {\n if (item != null && typeof item === 'object' && Object.hasOwn(item as object, prop)) {\n return String(item[prop]);\n }\n return '';\n });\n r = replaceAtDepth0(r, /\\{\\{this\\}\\}/g, String(item));\n r = this.processConditionals(r, variables);\n return r;\n }).join('');\n }\n result = result.slice(0, match.index!) + replacement + result.slice(closeIndex + '{{/each}}'.length);\n }\n return result;\n }\n\n private processConditionals(template: string, variables: Record<string, TemplateValue>): string {\n let compiled = template;\n\n // Handle {{#unless condition}}...{{/unless}}\n const unlessRe = /\\{\\{#unless\\s+(\\w+)\\}\\}/;\n let match: RegExpMatchArray | null;\n while ((match = unlessRe.exec(compiled)) !== null) {\n const varName = match[1];\n const bodyStart = match.index! + match[0].length;\n const closeIndex = findMatchingClose(compiled, '{{#unless', '{{/unless}}', bodyStart);\n if (closeIndex === -1) break;\n const body = compiled.slice(bodyStart, closeIndex);\n const value = variables[varName];\n const elseIndex = findElseAtDepth0(body);\n let replacement: string;\n if (elseIndex !== -1) {\n const falseBranch = body.slice(0, elseIndex);\n const trueBranch = body.slice(elseIndex + '{{else}}'.length);\n replacement = !value ? falseBranch : trueBranch;\n } else {\n replacement = !value ? body : '';\n }\n compiled = compiled.slice(0, match.index!) + replacement + compiled.slice(closeIndex + '{{/unless}}'.length);\n }\n\n // Handle {{#if condition}}...{{else}}...{{/if}} and {{#if condition}}...{{/if}}\n const ifRe = /\\{\\{#if\\s+(\\w+)\\}\\}/;\n while ((match = ifRe.exec(compiled)) !== null) {\n const varName = match[1];\n const bodyStart = match.index! + match[0].length;\n const closeIndex = findMatchingClose(compiled, '{{#if', '{{/if}}', bodyStart);\n if (closeIndex === -1) break;\n const body = compiled.slice(bodyStart, closeIndex);\n const value = variables[varName];\n const elseIndex = findElseAtDepth0(body);\n let replacement: string;\n if (elseIndex !== -1) {\n const trueBranch = body.slice(0, elseIndex);\n const falseBranch = body.slice(elseIndex + '{{else}}'.length);\n replacement = value ? trueBranch : falseBranch;\n } else {\n replacement = value ? body : '';\n }\n compiled = compiled.slice(0, match.index!) + replacement + compiled.slice(closeIndex + '{{/if}}'.length);\n }\n\n return compiled;\n }\n\n private processFilters(template: string, variables: Record<string, TemplateValue>): string {\n return template.replace(FILTER_RE, (_match, varPath, filterChain) => {\n // Resolve variable value (supports dot notation for nested access)\n const rootVar = varPath.includes('.') ? varPath.split('.')[0] : varPath;\n\n // Throw for missing root variable (consistent with compile step 5)\n if (!(rootVar in variables)) {\n throw new Error(`Required variable \"${rootVar}\" is missing`);\n }\n\n let value: TemplateValue;\n if (varPath.includes('.')) {\n const parts = varPath.split('.');\n if (BLOCKED_PROPS.has(parts[0])) { return ''; }\n value = variables[parts[0]];\n for (let i = 1; i < parts.length && value != null; i++) {\n if (BLOCKED_PROPS.has(parts[i])) { return ''; }\n value = (value as Record<string, TemplateValue>)[parts[i]];\n }\n } else {\n value = variables[varPath];\n }\n\n const result = value != null ? String(value) : '';\n return applyFilterChain(result, filterChain as string);\n });\n }\n\n extend(overrides: Partial<PromptTemplateConfig>): PromptTemplate {\n return new PromptTemplate({\n template: overrides.template ?? this.config.template,\n variables: { ...this.config.variables, ...overrides.variables } as Record<string, TemplateValue>,\n partials: { ...this.config.partials, ...overrides.partials }\n });\n }\n\n get requiredVariables(): string[] {\n const variables = new Set<string>();\n \n // Extract variables from simple {{var}} tags\n const variableMatches = this.config.template.match(VARIABLE_RE) || [];\n variableMatches.forEach(match => {\n const varName = match.slice(2, -2);\n if (!varName.startsWith('>') && !KEYWORDS.has(varName)) {\n variables.add(varName);\n }\n });\n\n // Extract variables from block tags {{#each items}}, {{#if show}}, {{#unless hidden}}\n const blockMatches = this.config.template.matchAll(BLOCK_VAR_RE);\n for (const bm of blockMatches) {\n if (!KEYWORDS.has(bm[1])) {\n variables.add(bm[1]);\n }\n }\n\n // Extract root variables from filter expressions {{var | filter}} or {{var.prop | filter}}\n const filterMatches = this.config.template.matchAll(FILTER_RE);\n for (const fm of filterMatches) {\n const rootVar = fm[1].split('.')[0];\n if (!KEYWORDS.has(rootVar)) {\n variables.add(rootVar);\n }\n }\n\n // Extract variables from partials\n if (this.config.partials) {\n Object.values(this.config.partials).forEach(partial => {\n partial.requiredVariables.forEach(varName => variables.add(varName));\n });\n }\n\n return Array.from(variables).sort();\n }\n\n static from(template: string): PromptTemplate {\n return new PromptTemplate({ template });\n }\n}","// =============================================================================\n// Delta Encoder — Reduces redundancy in high-frequency event streams\n// =============================================================================\n\nimport type { AgentEvent } from \"../types.js\";\n\n/** Default cap on tracked entries to bound memory usage */\nconst DEFAULT_MAX_ENTRIES = 1000;\n\nexport interface DeltaEncoder {\n /** Encode an event, returning null if identical to previous of same type. */\n encode(event: AgentEvent): string | null;\n /** Reset all tracked state. */\n reset(): void;\n}\n\nexport interface DeltaEncoderOptions {\n /** Maximum number of entries to track (default: 1000). */\n maxEntries?: number;\n}\n\nfunction fieldsEqual(a: unknown, b: unknown): boolean {\n if (a === b) return true;\n if (a === null || b === null || a === undefined || b === undefined) return false;\n if (typeof a !== typeof b) return false;\n if (typeof a !== \"object\") return false;\n return JSON.stringify(a) === JSON.stringify(b);\n}\n\nexport function createDeltaEncoder(options?: DeltaEncoderOptions): DeltaEncoder {\n const maxEntries = options?.maxEntries ?? DEFAULT_MAX_ENTRIES;\n const lastSeen = new Map<string, { serialized: string; event: AgentEvent }>();\n\n return {\n encode(event: AgentEvent): string | null {\n const serialized = JSON.stringify(event);\n const prev = lastSeen.get(event.type);\n\n if (prev !== undefined && prev.serialized === serialized) return null;\n\n // Evict oldest entry when at capacity and inserting new key\n if (prev === undefined && lastSeen.size >= maxEntries) {\n const oldest = lastSeen.keys().next().value as string;\n lastSeen.delete(oldest);\n }\n lastSeen.set(event.type, { serialized, event: JSON.parse(serialized) as AgentEvent });\n\n if (prev === undefined) return serialized;\n\n // Delta: only changed fields (structural comparison, no re-serialization)\n const prevEvent = prev.event as unknown as Record<string, unknown>;\n const delta: Record<string, unknown> = { type: event.type };\n for (const key of Object.keys(event) as (keyof AgentEvent)[]) {\n if (!fieldsEqual(event[key], prevEvent[key])) {\n delta[key] = event[key];\n }\n }\n return JSON.stringify(delta);\n },\n\n reset(): void {\n lastSeen.clear();\n },\n };\n}\n","// =============================================================================\n// Event Stream — Wraps EventBus into a Web ReadableStream for SSE consumption\n// =============================================================================\n\nimport type { EventBus } from \"../agent/event-bus.js\";\nimport type { AgentEvent } from \"../types.js\";\nimport { createDeltaEncoder } from \"./delta-encoder.js\";\n\nexport interface EventStreamOptions {\n /** Filter to specific event types. Default: all (\"*\"). */\n eventTypes?: string[];\n /** \"full\" sends every event as-is; \"delta\" uses delta encoding. */\n mode?: \"full\" | \"delta\";\n /** How to handle backpressure: 'drop' (default) discards events, 'buffer' keeps last N. */\n backpressureStrategy?: \"drop\" | \"buffer\";\n /** Max events to buffer when using 'buffer' strategy (default: 100). */\n bufferSize?: number;\n}\n\n/**\n * Creates a ReadableStream of SSE-formatted strings from an EventBus.\n */\nexport function createEventStream(\n eventBus: EventBus,\n options?: EventStreamOptions,\n): ReadableStream<string> {\n const mode = options?.mode ?? \"full\";\n const eventTypes = options?.eventTypes;\n const encoder = mode === \"delta\" ? createDeltaEncoder() : null;\n const backpressureStrategy = options?.backpressureStrategy ?? \"drop\";\n const bufferSize = options?.bufferSize ?? 100;\n let id = 0;\n let droppedEvents = 0;\n let isEmitting = false;\n const buffer: string[] = [];\n\n const unsubscribes: (() => void)[] = [];\n\n return new ReadableStream<string>({\n start(controller) {\n const handler = (event: AgentEvent) => {\n // Re-entrancy guard: skip events triggered by our own emit\n if (isEmitting) return;\n\n let data: string;\n if (encoder) {\n const encoded = encoder.encode(event);\n if (encoded === null) return;\n data = encoded;\n } else {\n data = JSON.stringify(event);\n }\n\n id++;\n const chunk = `id: ${id}\\nevent: ${event.type}\\ndata: ${data}\\n\\n`;\n\n // Backpressure handling\n if ((controller.desiredSize ?? 1) <= 0) {\n if (backpressureStrategy === \"buffer\") {\n buffer.push(chunk);\n while (buffer.length > bufferSize) buffer.shift();\n } else {\n droppedEvents++;\n if (droppedEvents % 10 === 0) {\n isEmitting = true;\n try {\n eventBus.emit(\"stream:warning\" as any, {\n reason: \"backpressure\",\n droppedEvents,\n });\n } finally {\n isEmitting = false;\n }\n }\n }\n return;\n }\n\n // Flush buffer first, respecting backpressure\n while (buffer.length > 0 && (controller.desiredSize ?? 1) > 0) {\n controller.enqueue(buffer.shift()!);\n }\n if ((controller.desiredSize ?? 1) > 0) {\n controller.enqueue(chunk);\n } else {\n buffer.push(chunk);\n }\n };\n\n if (eventTypes && eventTypes.length > 0) {\n for (const type of eventTypes) {\n unsubscribes.push(eventBus.on(type as any, handler));\n }\n } else {\n unsubscribes.push(eventBus.on(\"*\", handler));\n }\n },\n\n cancel() {\n for (const unsub of unsubscribes) unsub();\n },\n });\n}\n","// =============================================================================\n// SSE Handler — Server-Sent Events HTTP handler using Web APIs\n// =============================================================================\n\nimport type { EventBus } from \"../agent/event-bus.js\";\nimport { createEventStream } from \"./event-stream.js\";\n\nexport interface SseHandlerOptions {\n eventBus: EventBus;\n /** CORS origin. Default: \"*\" */\n corsOrigin?: string;\n}\n\n/**\n * Returns a Request → Response handler that streams agent events as SSE.\n *\n * Query parameters:\n * ?mode=full|delta — encoding mode (default: full)\n * ?filter=type1,type2 — comma-separated event type filter\n */\nexport function createSseHandler(\n options: SseHandlerOptions,\n): (request: Request) => Response {\n const { eventBus, corsOrigin = \"*\" } = options;\n\n return (request: Request): Response => {\n const url = new URL(request.url);\n const mode = (url.searchParams.get(\"mode\") as \"full\" | \"delta\") ?? \"full\";\n const filterParam = url.searchParams.get(\"filter\");\n const eventTypes = filterParam\n ? filterParam.split(\",\").map((t) => t.trim()).filter(Boolean)\n : undefined;\n\n const eventStream = createEventStream(eventBus, { mode, eventTypes });\n\n // Prepend an `:ok` comment as initial keep-alive\n const keepAlive = new ReadableStream<string>({\n start(controller) {\n controller.enqueue(\":ok\\n\\n\");\n controller.close();\n },\n });\n\n const merged = concatStreams(keepAlive, eventStream);\n\n const textEncoder = new TextEncoder();\n const body = merged.pipeThrough(\n new TransformStream<string, Uint8Array>({\n transform(chunk, controller) {\n controller.enqueue(textEncoder.encode(chunk));\n },\n }),\n );\n\n return new Response(body, {\n status: 200,\n headers: {\n \"Content-Type\": \"text/event-stream\",\n \"Cache-Control\": \"no-cache\",\n Connection: \"keep-alive\",\n \"Access-Control-Allow-Origin\": corsOrigin,\n },\n });\n };\n}\n\n/** Concatenate two ReadableStreams sequentially. */\nfunction concatStreams<T>(\n first: ReadableStream<T>,\n second: ReadableStream<T>,\n): ReadableStream<T> {\n const readerA = first.getReader();\n const readerB = second.getReader();\n let readingFirst = true;\n\n return new ReadableStream<T>({\n async pull(controller) {\n if (readingFirst) {\n const { value, done } = await readerA.read();\n if (!done) {\n controller.enqueue(value);\n return;\n }\n readingFirst = false;\n }\n const { value, done } = await readerB.read();\n if (done) {\n controller.close();\n } else {\n controller.enqueue(value);\n }\n },\n cancel() {\n readerA.cancel();\n readerB.cancel();\n },\n });\n}\n","// =============================================================================\n// WebSocket Handler — Bidirectional event streaming and command handling\n// =============================================================================\n\nimport type { EventBus } from \"../agent/event-bus.js\";\n\nexport interface WsCommand {\n type: \"pause\" | \"resume\" | \"cancel\" | \"approve\" | \"deny\";\n data?: unknown;\n}\n\nexport interface WsHandlerOptions {\n eventBus: EventBus;\n /** Callback invoked when a valid command is received from the client. */\n onCommand?: (command: WsCommand) => void | Promise<void>;\n}\n\n/** Runtime-agnostic WebSocket interface. */\nexport interface WebSocketLike {\n send(data: string): void;\n close(): void;\n onmessage: ((event: { data: string }) => void) | null;\n onclose: (() => void) | null;\n}\n\nconst VALID_COMMANDS = new Set<string>([\"pause\", \"resume\", \"cancel\", \"approve\", \"deny\"]);\n\n/**\n * Binds an EventBus to a WebSocket for bidirectional communication.\n * Events are forwarded as JSON; incoming messages are parsed as commands.\n */\nexport function handleWebSocket(\n ws: WebSocketLike,\n options: WsHandlerOptions,\n): void {\n const { eventBus, onCommand } = options;\n\n const unsubscribe = eventBus.on(\"*\", (event) => {\n try {\n ws.send(JSON.stringify(event));\n } catch {\n // Socket may be closing — ignore send errors\n }\n });\n\n ws.onmessage = (event) => {\n let parsed: unknown;\n try {\n parsed = JSON.parse(event.data);\n } catch {\n return; // ignore malformed messages\n }\n\n if (!isValidCommand(parsed)) return;\n\n onCommand?.(parsed)?.catch?.(() => {\n // Swallow async errors from command handler\n });\n };\n\n ws.onclose = () => {\n unsubscribe();\n ws.onmessage = null;\n ws.onclose = null;\n };\n}\n\nfunction isValidCommand(value: unknown): value is WsCommand {\n if (typeof value !== \"object\" || value === null) return false;\n const obj = value as Record<string, unknown>;\n return typeof obj.type === \"string\" && VALID_COMMANDS.has(obj.type);\n}\n","// =============================================================================\n// Graph Event Stream — Filtered event stream for graph-specific events\n// =============================================================================\n\nimport type { EventBus } from \"../agent/event-bus.js\";\nimport { createEventStream, type EventStreamOptions } from \"./event-stream.js\";\n\n/** Convenience: creates an event stream filtered to graph-specific events. */\nexport function createGraphEventStream(\n eventBus: EventBus,\n options?: Omit<EventStreamOptions, \"eventTypes\">,\n): ReadableStream<string> {\n return createEventStream(eventBus, {\n ...options,\n eventTypes: [\n \"graph:start\", \"graph:complete\",\n \"node:start\", \"node:complete\",\n \"fork:start\", \"fork:complete\",\n \"consensus:start\", \"consensus:result\",\n ],\n });\n}\n","// =============================================================================\n// Default Partial JSON Adapter — Incremental JSON parsing without dependencies\n// =============================================================================\n\nimport type {\n PartialJsonPort,\n JsonAccumulator,\n} from \"../../ports/partial-json.port.js\";\n\n/**\n * Attempt to complete an incomplete JSON string by closing unclosed\n * brackets, braces, and strings, and removing trailing commas.\n */\nfunction completePartialJson(partial: string): string {\n let s = partial.trimEnd();\n if (s.length === 0) return s;\n\n // Track whether we are inside a string and the nesting stack\n let inString = false;\n let escaped = false;\n const stack: string[] = [];\n\n for (let i = 0; i < s.length; i++) {\n const ch = s[i];\n\n if (escaped) {\n escaped = false;\n continue;\n }\n\n if (ch === \"\\\\\") {\n if (inString) escaped = true;\n continue;\n }\n\n if (ch === '\"') {\n inString = !inString;\n continue;\n }\n\n if (inString) continue;\n\n if (ch === \"{\") stack.push(\"}\");\n else if (ch === \"[\") stack.push(\"]\");\n else if (ch === \"}\" || ch === \"]\") stack.pop();\n }\n\n // Close unclosed string — strip a dangling backslash so the added\n // closing quote isn't interpreted as an escaped quote (R1 fix).\n if (inString) {\n if (escaped) {\n s = s.slice(0, -1);\n }\n s += '\"';\n }\n\n // Remove trailing commas (invalid JSON) before closing brackets\n s = s.replace(/,\\s*$/, \"\");\n\n // Close unclosed brackets / braces\n while (stack.length > 0) {\n s += stack.pop();\n }\n\n return s;\n}\n\n/**\n * Parse an incomplete JSON string, returning whatever is parseable so far.\n */\nfunction parsePartialJson(partial: string): { value: unknown; complete: boolean } {\n const trimmed = partial.trim();\n if (trimmed.length === 0) {\n return { value: undefined, complete: false };\n }\n\n // Try parsing the original string first (complete JSON)\n try {\n const value = JSON.parse(trimmed);\n return { value, complete: true };\n } catch {\n // Not complete — try to repair\n }\n\n // Attempt to complete the partial JSON and parse\n const completed = completePartialJson(trimmed);\n try {\n const value = JSON.parse(completed);\n return { value, complete: false };\n } catch {\n return { value: undefined, complete: false };\n }\n}\n\n/**\n * Create a JsonAccumulator that buffers incoming chunks and\n * incrementally parses the accumulated JSON.\n */\nfunction createJsonAccumulator<T>(): JsonAccumulator<T> {\n let buffer = \"\";\n let lastParsed: Partial<T> | null = null;\n let complete = false;\n\n return {\n push(chunk: string): void {\n buffer += chunk;\n const result = parsePartialJson(buffer);\n if (result.value !== undefined) {\n lastParsed = result.value as Partial<T>;\n complete = result.complete;\n }\n },\n\n current(): Partial<T> | null {\n return lastParsed;\n },\n\n isComplete(): boolean {\n return complete;\n },\n\n reset(): void {\n buffer = \"\";\n lastParsed = null;\n complete = false;\n },\n };\n}\n\n// =============================================================================\n// Adapter factory\n// =============================================================================\n\nexport function createDefaultPartialJsonAdapter(): PartialJsonPort {\n return {\n parse: parsePartialJson,\n createAccumulator: createJsonAccumulator,\n };\n}\n\nexport const DefaultPartialJsonAdapter = {\n create: createDefaultPartialJsonAdapter,\n};\n","// =============================================================================\n// Stream JSON — Utility that yields Partial<T> objects from a token stream\n// =============================================================================\n\nimport { createDefaultPartialJsonAdapter } from \"../adapters/partial-json/default-partial-json.adapter.js\";\n\n/**\n * Takes an AsyncIterable of string tokens (e.g. from LLM streaming) and\n * yields `Partial<T>` objects as they become available via incremental parsing.\n *\n * Only yields when the parsed value actually changes.\n */\nexport async function* streamJson<T>(\n tokens: AsyncIterable<string>,\n): AsyncGenerator<Partial<T>> {\n const adapter = createDefaultPartialJsonAdapter();\n const accumulator = adapter.createAccumulator<T>();\n let lastJson: string | null = null;\n\n for await (const token of tokens) {\n accumulator.push(token);\n const current = accumulator.current();\n\n if (current !== null) {\n const currentJson = JSON.stringify(current);\n if (currentJson !== lastJson) {\n lastJson = currentJson;\n yield current;\n }\n }\n }\n}\n","// =============================================================================\n// NodeHttpServer — Zero-dependency HTTP server using Node http module\n// =============================================================================\n\nimport { createServer, type Server, type IncomingMessage, type ServerResponse } from \"node:http\";\nimport type { HttpServerPort, HttpMethod, HttpRequest, HttpResponse, HttpHandler, HttpMiddleware, Route } from \"../ports/http-server.port.js\";\n\ninterface ParsedRoute {\n method: HttpMethod;\n segments: string[];\n paramNames: string[];\n handler: HttpHandler;\n middleware: HttpMiddleware[];\n}\n\nfunction parseUrl(url: string): { path: string; query: Record<string, string> } {\n const qIdx = url.indexOf(\"?\");\n const path = qIdx >= 0 ? url.slice(0, qIdx) : url;\n const query: Record<string, string> = {};\n if (qIdx >= 0) {\n const qs = url.slice(qIdx + 1);\n for (const pair of qs.split(\"&\")) {\n const eq = pair.indexOf(\"=\");\n if (eq >= 0) {\n query[decodeURIComponent(pair.slice(0, eq))] = decodeURIComponent(pair.slice(eq + 1));\n }\n }\n }\n return { path: path.replace(/\\/+$/, \"\") || \"/\", query };\n}\n\nfunction matchRoute(routeSegments: string[], paramNames: string[], pathSegments: string[]): Record<string, string> | null {\n if (routeSegments.length !== pathSegments.length) return null;\n const params: Record<string, string> = {};\n let paramIdx = 0;\n for (let i = 0; i < routeSegments.length; i++) {\n if (routeSegments[i].startsWith(\":\")) {\n params[paramNames[paramIdx++]] = pathSegments[i];\n } else if (routeSegments[i] !== pathSegments[i]) {\n return null;\n }\n }\n return params;\n}\n\nfunction createResponse(raw: ServerResponse): HttpResponse {\n let statusCode = 200;\n let sent = false;\n const res: HttpResponse = {\n status(code: number) { statusCode = code; return res; },\n header(name: string, value: string) { raw.setHeader(name, value); return res; },\n json(data: unknown) {\n if (sent) return;\n sent = true;\n raw.writeHead(statusCode, { \"Content-Type\": \"application/json\" });\n raw.end(JSON.stringify(data));\n },\n text(data: string) {\n if (sent) return;\n sent = true;\n raw.writeHead(statusCode, { \"Content-Type\": \"text/plain\" });\n raw.end(data);\n },\n async stream(generator: AsyncGenerator<string>) {\n if (sent) return;\n sent = true;\n raw.writeHead(statusCode, {\n \"Content-Type\": \"text/event-stream\",\n \"Cache-Control\": \"no-cache\",\n \"Connection\": \"keep-alive\",\n });\n try {\n for await (const chunk of generator) {\n raw.write(`data: ${chunk}\\n\\n`);\n }\n } catch (err) {\n raw.write(`event: error\\ndata: ${err instanceof Error ? err.message : \"stream error\"}\\n\\n`);\n }\n raw.end();\n },\n };\n return res;\n}\n\nconst MAX_BODY_BYTES = 10 * 1024 * 1024; // 10 MB\n\nasync function readBody(req: IncomingMessage, maxBytes = MAX_BODY_BYTES): Promise<unknown> {\n return new Promise((resolve, reject) => {\n const chunks: Buffer[] = [];\n let size = 0;\n req.on(\"error\", (err) => reject(err));\n req.on(\"data\", (c: Buffer) => {\n size += c.length;\n if (size > maxBytes) { req.destroy(); reject(new Error(\"Request body too large\")); return; }\n chunks.push(c);\n });\n req.on(\"end\", () => {\n const raw = Buffer.concat(chunks).toString();\n if (!raw) { resolve(undefined); return; }\n try { resolve(JSON.parse(raw)); }\n catch { resolve(raw); }\n });\n });\n}\n\nexport class NodeHttpServer implements HttpServerPort {\n private server: Server | null = null;\n private parsedRoutes: ParsedRoute[] = [];\n private globalMiddleware: HttpMiddleware[] = [];\n private registeredRoutes: Route[] = [];\n private corsOrigin: string;\n private maxBodyBytes: number;\n\n constructor(opts?: { cors?: string; maxBodyBytes?: number }) {\n this.corsOrigin = opts?.cors ?? \"*\";\n this.maxBodyBytes = opts?.maxBodyBytes ?? MAX_BODY_BYTES;\n }\n\n route(method: HttpMethod, path: string, handler: HttpHandler, middleware?: HttpMiddleware[]): void {\n const segments = path.split(\"/\").filter(Boolean);\n const paramNames = segments.filter(s => s.startsWith(\":\")).map(s => s.slice(1));\n this.parsedRoutes.push({ method, segments, paramNames, handler, middleware: middleware ?? [] });\n this.registeredRoutes.push({ method, path, handler, middleware });\n }\n\n use(mw: HttpMiddleware): void {\n this.globalMiddleware.push(mw);\n }\n\n routes(): Route[] {\n return [...this.registeredRoutes];\n }\n\n async listen(port: number, hostname?: string): Promise<void> {\n return new Promise((resolve) => {\n this.server = createServer(async (rawReq, rawRes) => {\n // CORS\n rawRes.setHeader(\"Access-Control-Allow-Origin\", this.corsOrigin);\n rawRes.setHeader(\"Access-Control-Allow-Methods\", \"GET,POST,PUT,DELETE,PATCH,OPTIONS\");\n rawRes.setHeader(\"Access-Control-Allow-Headers\", \"Content-Type,Authorization\");\n if (rawReq.method === \"OPTIONS\") {\n rawRes.writeHead(204);\n rawRes.end();\n return;\n }\n\n try {\n const { path, query } = parseUrl(rawReq.url ?? \"/\");\n const pathSegments = path.split(\"/\").filter(Boolean);\n const method = (rawReq.method ?? \"GET\").toUpperCase() as HttpMethod;\n\n // Find matching route\n let matched: ParsedRoute | undefined;\n let params: Record<string, string> = {};\n for (const r of this.parsedRoutes) {\n if (r.method !== method) continue;\n const m = matchRoute(r.segments, r.paramNames, pathSegments);\n if (m) { matched = r; params = m; break; }\n }\n\n if (!matched) {\n rawRes.writeHead(404, { \"Content-Type\": \"application/json\" });\n rawRes.end(JSON.stringify({ error: \"Not Found\" }));\n return;\n }\n\n const body = await readBody(rawReq, this.maxBodyBytes);\n const req: HttpRequest = {\n method, path, query, body, params,\n headers: rawReq.headers as Record<string, string | string[] | undefined>,\n };\n const res = createResponse(rawRes);\n\n // Execute middleware chain: global → route-level → handler\n const allMw = [...this.globalMiddleware, ...matched.middleware];\n let idx = 0;\n const next = async (): Promise<void> => {\n if (idx < allMw.length) {\n const mw = allMw[idx++];\n await mw(req, res, next);\n } else {\n await matched!.handler(req, res);\n }\n };\n await next();\n } catch (err) {\n if (!rawRes.headersSent) {\n rawRes.writeHead(500, { \"Content-Type\": \"application/json\" });\n rawRes.end(JSON.stringify({ error: err instanceof Error ? err.message : \"Internal Server Error\" }));\n }\n }\n });\n this.server.listen(port, hostname ?? \"0.0.0.0\", () => resolve());\n });\n }\n\n async close(): Promise<void> {\n return new Promise((resolve, reject) => {\n if (!this.server) { resolve(); return; }\n this.server.close((err) => err ? reject(err) : resolve());\n this.server = null;\n });\n }\n}\n","// =============================================================================\n// ACP Server — JSON-RPC 2.0 implementation\n// =============================================================================\n\nimport type { AcpServerPort, AcpMessage, AcpSession, AcpHandler } from \"../../ports/acp.port.js\";\n\nlet sessionCounter = 0;\n\nfunction parseMessage(raw: string): AcpMessage | null {\n try {\n const parsed = JSON.parse(raw);\n if (parsed.jsonrpc !== \"2.0\") return null;\n return parsed as AcpMessage;\n } catch {\n return null;\n }\n}\n\nfunction errorResponse(id: string | number | undefined, code: number, message: string, data?: unknown): AcpMessage {\n return { jsonrpc: \"2.0\", id, error: { code, message, data } };\n}\n\nfunction successResponse(id: string | number | undefined, result: unknown): AcpMessage {\n return { jsonrpc: \"2.0\", id, result };\n}\n\nexport class AcpServer implements AcpServerPort {\n private handler: AcpHandler | null = null;\n private sessions = new Map<string, AcpSession>();\n private defaultAgentName: string;\n private running = false;\n private stdinHandler: ((data: Buffer) => void) | null = null;\n\n constructor(opts: { agentName: string }) {\n this.defaultAgentName = opts.agentName;\n }\n\n registerHandler(handler: AcpHandler): void {\n this.handler = handler;\n }\n\n async start(): Promise<void> {\n if (this.running) return;\n this.running = true;\n\n let buffer = \"\";\n let writeQueue = Promise.resolve();\n this.stdinHandler = (data: Buffer) => {\n buffer += data.toString();\n const lines = buffer.split(\"\\n\");\n buffer = lines.pop() ?? \"\";\n for (const line of lines) {\n const trimmed = line.trim();\n if (!trimmed) continue;\n // Serialize responses to maintain request order\n writeQueue = writeQueue.then(async () => {\n const response = await this.processMessage(trimmed);\n process.stdout.write(JSON.stringify(response) + \"\\n\");\n });\n }\n };\n process.stdin.on(\"data\", this.stdinHandler);\n }\n\n async stop(): Promise<void> {\n this.running = false;\n if (this.stdinHandler) {\n process.stdin.removeListener(\"data\", this.stdinHandler);\n this.stdinHandler = null;\n }\n this.sessions.clear();\n }\n\n async processMessage(raw: string): Promise<AcpMessage> {\n const msg = parseMessage(raw);\n if (!msg) return errorResponse(undefined, -32700, \"Parse error\");\n if (!msg.method) return errorResponse(msg.id, -32600, \"Invalid Request: missing method\");\n\n // Built-in methods\n if (msg.method === \"acp/initialize\") {\n const sessionId = `session-${++sessionCounter}`;\n const session: AcpSession = {\n id: sessionId,\n agentName: this.defaultAgentName,\n createdAt: Date.now(),\n metadata: (msg.params as Record<string, unknown>) ?? {},\n };\n this.sessions.set(sessionId, session);\n return successResponse(msg.id, { sessionId, agentName: this.defaultAgentName, capabilities: [\"chat\", \"tools\"] });\n }\n\n if (msg.method === \"acp/shutdown\") {\n const params = msg.params as Record<string, unknown> | undefined;\n const sessionId = params?.sessionId as string | undefined;\n if (sessionId) this.sessions.delete(sessionId);\n return successResponse(msg.id, { ok: true });\n }\n\n // Route to handler\n if (!this.handler) return errorResponse(msg.id, -32601, \"Method not found: no handler registered\");\n\n // Find session from params\n const params = msg.params as Record<string, unknown> | undefined;\n const sessionId = params?.sessionId as string | undefined;\n const session = sessionId ? this.sessions.get(sessionId) : undefined;\n if (!session) {\n return errorResponse(msg.id, -32602, \"Session not found: call acp/initialize first\");\n }\n\n try {\n const result = await this.handler.handle(msg.method, msg.params, session);\n return successResponse(msg.id, result);\n } catch (err) {\n return errorResponse(msg.id, -32603, err instanceof Error ? err.message : \"Internal error\");\n }\n }\n}\n","// =============================================================================\n// TieredAgentMemoryAdapter — Multi-tier composition for AgentMemoryPort\n// =============================================================================\n\nimport type {\n AgentMemoryPort,\n MemoryEntry,\n MemoryStats,\n MemoryTier,\n RecallOptions,\n} from \"../../ports/agent-memory.port.js\";\nimport { InMemoryAgentMemoryAdapter } from \"./in-memory-agent-memory.adapter.js\";\n\n/** Max characters kept when summarizing memory entries */\nconst SUMMARY_MAX_LENGTH = 500;\n\nconst DEFAULT_TIER_WEIGHTS: Record<MemoryTier, number> = {\n short: 0.4,\n working: 0.3,\n semantic: 0.2,\n observation: 0.1,\n};\n\nconst DEFAULT_TYPE_TO_TIER: Record<MemoryEntry[\"type\"], MemoryTier> = {\n conversation: \"short\",\n task: \"working\",\n fact: \"semantic\",\n preference: \"semantic\",\n summary: \"observation\",\n};\n\nexport interface TieredAgentMemoryAdapterOptions {\n shortTerm?: AgentMemoryPort;\n working?: AgentMemoryPort;\n semantic?: AgentMemoryPort;\n observation?: AgentMemoryPort;\n recallWeights?: Partial<Record<MemoryTier, number>>;\n typeToTierMap?: Partial<Record<MemoryEntry[\"type\"], MemoryTier>>;\n}\n\ntype TierAdapterMap = Record<MemoryTier, AgentMemoryPort>;\n\nexport class TieredAgentMemoryAdapter implements AgentMemoryPort {\n private readonly tiers: TierAdapterMap;\n private readonly recallWeights: Record<MemoryTier, number>;\n private readonly typeToTierMap: Record<MemoryEntry[\"type\"], MemoryTier>;\n\n constructor(options: TieredAgentMemoryAdapterOptions = {}) {\n this.tiers = {\n short: options.shortTerm ?? new InMemoryAgentMemoryAdapter(),\n working: options.working ?? new InMemoryAgentMemoryAdapter(),\n semantic: options.semantic ?? new InMemoryAgentMemoryAdapter(),\n observation: options.observation ?? new InMemoryAgentMemoryAdapter(),\n };\n this.recallWeights = {\n ...DEFAULT_TIER_WEIGHTS,\n ...(options.recallWeights ?? {}),\n };\n this.typeToTierMap = {\n ...DEFAULT_TYPE_TO_TIER,\n ...(options.typeToTierMap ?? {}),\n };\n }\n\n async store(entry: MemoryEntry): Promise<void> {\n const tier = this.resolveTier(entry);\n await this.tiers[tier].store({\n ...entry,\n tier,\n });\n }\n\n async recall(query: string, options: RecallOptions = {}): Promise<MemoryEntry[]> {\n const limit = options.limit ?? 10;\n const selectedTiers = this.resolveRequestedTiers(options);\n\n if (selectedTiers.length === 0 || limit <= 0) {\n return [];\n }\n\n if (selectedTiers.length === 1) {\n return this.recallFromTier(selectedTiers[0]!, query, options);\n }\n\n const tierLimits = this.allocateTierLimits(selectedTiers, limit);\n\n const chunks = await Promise.all(\n selectedTiers.map((tier) =>\n this.recallFromTier(tier, query, {\n ...options,\n limit: tierLimits[tier],\n }),\n ),\n );\n\n const merged = new Map<string, MemoryEntry>();\n for (const entries of chunks) {\n for (const entry of entries) {\n const prev = merged.get(entry.id);\n if (!prev || entry.timestamp > prev.timestamp) {\n merged.set(entry.id, entry);\n }\n }\n }\n\n return Array.from(merged.values())\n .sort((a, b) => b.timestamp.localeCompare(a.timestamp))\n .slice(0, limit);\n }\n\n async summarize(entries: MemoryEntry[]): Promise<string> {\n const combined = entries.map((e) => e.content).join(\"\\n\");\n return combined.length > SUMMARY_MAX_LENGTH\n ? `${combined.slice(0, SUMMARY_MAX_LENGTH)}...`\n : combined;\n }\n\n async clear(): Promise<void> {\n await Promise.all(\n (Object.keys(this.tiers) as MemoryTier[]).map((tier) =>\n this.tiers[tier].clear(),\n ),\n );\n }\n\n async getStats(): Promise<MemoryStats> {\n const entries = await Promise.all(\n (Object.keys(this.tiers) as MemoryTier[]).map(async (tier) => {\n const recalled = await this.tiers[tier].recall(\"\", {\n limit: Number.MAX_SAFE_INTEGER,\n });\n return recalled.map((entry) => ({\n ...entry,\n tier: entry.tier ?? tier,\n }));\n }),\n );\n\n const all = entries.flat();\n const byType: Record<string, number> = {};\n const byTier: Record<MemoryTier, number> = {\n short: 0,\n working: 0,\n semantic: 0,\n observation: 0,\n };\n\n let oldestEntry: string | undefined;\n let newestEntry: string | undefined;\n\n for (const entry of all) {\n byType[entry.type] = (byType[entry.type] ?? 0) + 1;\n const tier = entry.tier ?? this.resolveTier(entry);\n byTier[tier] = (byTier[tier] ?? 0) + 1;\n\n if (!oldestEntry || entry.timestamp < oldestEntry) {\n oldestEntry = entry.timestamp;\n }\n if (!newestEntry || entry.timestamp > newestEntry) {\n newestEntry = entry.timestamp;\n }\n }\n\n return {\n totalEntries: all.length,\n byType,\n byTier,\n oldestEntry,\n newestEntry,\n };\n }\n\n private resolveTier(entry: MemoryEntry): MemoryTier {\n return entry.tier ?? this.typeToTierMap[entry.type] ?? \"short\";\n }\n\n private resolveRequestedTiers(options: RecallOptions): MemoryTier[] {\n if (options.tier) return [options.tier];\n if (options.includeTiers && options.includeTiers.length > 0) {\n return Array.from(new Set(options.includeTiers));\n }\n return [\"short\", \"working\", \"semantic\", \"observation\"];\n }\n\n private async recallFromTier(\n tier: MemoryTier,\n query: string,\n options: RecallOptions,\n ): Promise<MemoryEntry[]> {\n const entries = await this.tiers[tier].recall(query, {\n ...options,\n tier: undefined,\n includeTiers: undefined,\n });\n\n return entries.map((entry) => ({\n ...entry,\n tier: entry.tier ?? tier,\n }));\n }\n\n private allocateTierLimits(\n tiers: MemoryTier[],\n limit: number,\n ): Record<MemoryTier, number> {\n const allocated: Record<MemoryTier, number> = {\n short: 0,\n working: 0,\n semantic: 0,\n observation: 0,\n };\n\n const weighted = tiers.map((tier) => ({\n tier,\n raw: Math.max(0, this.recallWeights[tier] ?? 0),\n }));\n const sum = weighted.reduce((acc, current) => acc + current.raw, 0);\n\n if (sum <= 0) {\n const fair = Math.floor(limit / tiers.length);\n let remaining = limit - fair * tiers.length;\n for (const tier of tiers) {\n allocated[tier] = fair;\n }\n for (let i = 0; i < tiers.length && remaining > 0; i++) {\n allocated[tiers[i]!] += 1;\n remaining--;\n }\n return allocated;\n }\n\n let assigned = 0;\n const remainders: Array<{ tier: MemoryTier; remainder: number }> = [];\n\n for (const item of weighted) {\n const exact = (item.raw / sum) * limit;\n const floor = Math.floor(exact);\n allocated[item.tier] = floor;\n assigned += floor;\n remainders.push({ tier: item.tier, remainder: exact - floor });\n }\n\n let remaining = limit - assigned;\n remainders.sort((a, b) => b.remainder - a.remainder);\n for (const item of remainders) {\n if (remaining <= 0) break;\n allocated[item.tier] += 1;\n remaining--;\n }\n\n return allocated;\n }\n}\n","// =============================================================================\n// Checkpoint Schema — State serialization for resume\n// =============================================================================\n\nimport { z } from \"zod\";\nimport { TodoSchema } from \"./todo.schema.js\";\n\nconst MessageSchema = z.object({\n role: z.enum([\"user\", \"assistant\", \"system\"]),\n content: z.string(),\n timestamp: z.number().optional(),\n});\n\nexport const CheckpointSchema = z.object({\n id: z.string(),\n sessionId: z.string(),\n stepIndex: z.number(),\n conversation: z.array(MessageSchema),\n todos: z.array(TodoSchema).default([]),\n filesSnapshot: z\n .record(z.string(), z.string())\n .default({})\n .describe(\"Map of path → content for files in VFS persistent zone\"),\n toolResults: z.record(z.string(), z.unknown()).default({}),\n generatedTokens: z.number().default(0),\n lastToolCallId: z.string().nullable().default(null),\n metadata: z.record(z.string(), z.unknown()).default({}),\n createdAt: z.number().default(() => Date.now()),\n});\n\nexport type Checkpoint = z.infer<typeof CheckpointSchema>;\n","// =============================================================================\n// Todo Schema — Planning & task decomposition\n// =============================================================================\n\nimport { z } from \"zod\";\n\nexport const TodoStatusSchema = z.enum([\n \"pending\",\n \"in_progress\",\n \"done\",\n \"blocked\",\n]);\n\nexport type TodoStatus = z.infer<typeof TodoStatusSchema>;\n\nexport const TodoSchema = z.object({\n id: z.string().describe(\"Unique identifier for the todo (kebab-case)\"),\n title: z.string().describe(\"Short title of the task\"),\n description: z\n .string()\n .optional()\n .describe(\"Detailed description of what needs to be done\"),\n status: TodoStatusSchema.default(\"pending\"),\n dependencies: z\n .array(z.string())\n .default([])\n .describe(\"IDs of todos this depends on\"),\n priority: z\n .enum([\"low\", \"medium\", \"high\", \"critical\"])\n .default(\"medium\")\n .describe(\"Task priority\"),\n createdAt: z.number().default(() => Date.now()),\n updatedAt: z.number().default(() => Date.now()),\n completedAt: z.number().optional(),\n});\n\nexport type Todo = z.infer<typeof TodoSchema>;\n\nexport const TodoListSchema = z.array(TodoSchema);\n\nexport type TodoList = z.infer<typeof TodoListSchema>;\n\nexport const WriteTodosInputSchema = z.object({\n todos: TodoListSchema.describe(\"List of todos to create or update\"),\n});\n\nexport type WriteTodosInput = z.infer<typeof WriteTodosInputSchema>;\n\nexport const UpdateTodoInputSchema = z.object({\n id: z.string().describe(\"ID of the todo to update\"),\n status: TodoStatusSchema.optional(),\n title: z.string().optional(),\n description: z.string().optional(),\n});\n\nexport type UpdateTodoInput = z.infer<typeof UpdateTodoInputSchema>;\n","// SupabaseMemoryAdapter — Supabase-backed implementation of MemoryPort\n\nimport type { SupabaseClient } from \"@supabase/supabase-js\";\nimport type { MemoryPort } from \"../../ports/memory.port.js\";\nimport type { Todo } from \"../../domain/todo.schema.js\";\nimport { CheckpointSchema, type Checkpoint } from \"../../domain/checkpoint.schema.js\";\nimport type { Message } from \"../../types.js\";\n\nconst T_TODOS = \"deep_agent_todos\";\nconst T_CKPT = \"deep_agent_checkpoints\";\nconst T_CONV = \"deep_agent_conversations\";\nconst T_META = \"deep_agent_metadata\";\n\nexport interface SupabaseMemoryAdapterOptions {\n strict?: boolean;\n}\n\nfunction warn(method: string, err: unknown): void {\n const msg = err instanceof Error ? err.message : String(err);\n console.warn(`[SupabaseMemoryAdapter.${method}] ${msg}`);\n}\n\nexport class SupabaseMemoryAdapter implements MemoryPort {\n private readonly strict: boolean;\n\n constructor(\n private readonly supabase: SupabaseClient,\n options?: SupabaseMemoryAdapterOptions,\n ) {\n this.strict = options?.strict ?? false;\n }\n\n private handleError(method: string, err: unknown): void {\n warn(method, err);\n if (this.strict) {\n throw err instanceof Error ? err : new Error(String(err));\n }\n }\n\n async saveTodos(sessionId: string, todos: Todo[]): Promise<void> {\n const { error } = await this.supabase.from(T_TODOS).upsert(\n { session_id: sessionId, todos, updated_at: new Date().toISOString() },\n { onConflict: \"session_id\" },\n );\n if (error) this.handleError(\"saveTodos\", error);\n }\n\n async loadTodos(sessionId: string): Promise<Todo[]> {\n const { data, error } = await this.supabase\n .from(T_TODOS).select(\"todos\").eq(\"session_id\", sessionId).single();\n if (error) { this.handleError(\"loadTodos\", error); return []; }\n return (data?.todos as Todo[]) ?? [];\n }\n\n async saveCheckpoint(sessionId: string, checkpoint: Checkpoint): Promise<void> {\n const { error } = await this.supabase.from(T_CKPT).insert({\n id: checkpoint.id,\n session_id: sessionId,\n step_index: checkpoint.stepIndex,\n state: checkpoint,\n created_at: new Date(checkpoint.createdAt).toISOString(),\n });\n if (error) this.handleError(\"saveCheckpoint\", error);\n }\n\n async loadLatestCheckpoint(sessionId: string): Promise<Checkpoint | null> {\n const { data, error } = await this.supabase\n .from(T_CKPT).select(\"state\").eq(\"session_id\", sessionId)\n .order(\"step_index\", { ascending: false }).limit(1).maybeSingle();\n if (error) { this.handleError(\"loadLatestCheckpoint\", error); return null; }\n if (!data?.state) return null;\n const parsed = CheckpointSchema.safeParse(data.state);\n if (!parsed.success) {\n this.handleError(\"loadLatestCheckpoint\", parsed.error);\n return null;\n }\n return parsed.data;\n }\n\n async listCheckpoints(sessionId: string): Promise<Checkpoint[]> {\n const { data, error } = await this.supabase\n .from(T_CKPT).select(\"state\").eq(\"session_id\", sessionId)\n .order(\"step_index\", { ascending: true });\n if (error) { this.handleError(\"listCheckpoints\", error); return []; }\n return (data ?? []).map((r) => r.state as Checkpoint);\n }\n\n async deleteOldCheckpoints(sessionId: string, keepCount: number): Promise<void> {\n const { data, error } = await this.supabase\n .from(T_CKPT).select(\"id\").eq(\"session_id\", sessionId)\n .order(\"step_index\", { ascending: false });\n if (error || !data) { this.handleError(\"deleteOldCheckpoints\", error); return; }\n const idsToDelete = data.slice(keepCount).map((r) => r.id as string);\n if (idsToDelete.length === 0) return;\n const { error: delErr } = await this.supabase\n .from(T_CKPT).delete().in(\"id\", idsToDelete);\n if (delErr) this.handleError(\"deleteOldCheckpoints.delete\", delErr);\n }\n\n async saveConversation(sessionId: string, messages: Message[]): Promise<void> {\n const { error } = await this.supabase.from(T_CONV).upsert(\n { session_id: sessionId, messages, updated_at: new Date().toISOString() },\n { onConflict: \"session_id\" },\n );\n if (error) this.handleError(\"saveConversation\", error);\n }\n\n async loadConversation(sessionId: string): Promise<Message[]> {\n const { data, error } = await this.supabase\n .from(T_CONV).select(\"messages\").eq(\"session_id\", sessionId).single();\n if (error) { this.handleError(\"loadConversation\", error); return []; }\n return (data?.messages as Message[]) ?? [];\n }\n\n async saveMetadata(sessionId: string, key: string, value: unknown): Promise<void> {\n const { error } = await this.supabase.from(T_META).upsert(\n { session_id: sessionId, key, value, updated_at: new Date().toISOString() },\n { onConflict: \"session_id,key\" },\n );\n if (error) this.handleError(\"saveMetadata\", error);\n }\n\n async loadMetadata<T = unknown>(sessionId: string, key: string): Promise<T | null> {\n const { data, error } = await this.supabase\n .from(T_META).select(\"value\")\n .eq(\"session_id\", sessionId).eq(\"key\", key).maybeSingle();\n if (error) { this.handleError(\"loadMetadata\", error); return null; }\n return (data?.value as T) ?? null;\n }\n\n async deleteMetadata(sessionId: string, key: string): Promise<void> {\n const { error } = await this.supabase\n .from(T_META).delete().eq(\"session_id\", sessionId).eq(\"key\", key);\n if (error) this.handleError(\"deleteMetadata\", error);\n }\n}\n","// =============================================================================\n// InMemoryLearningAdapter — In-memory implementation of LearningPort\n// =============================================================================\n\nimport type { LearningPort } from \"../../ports/learning.port.js\";\nimport type { UserProfile, UserMemory, UserMemoryInput, SharedKnowledge, SharedKnowledgeInput } from \"../../domain/learning.schema.js\";\n\n/**\n * Stores all learning state in Maps keyed by userId.\n * Good for testing and standalone use.\n */\nexport class InMemoryLearningAdapter implements LearningPort {\n private readonly profilesMap = new Map<string, UserProfile>();\n private readonly memoriesMap = new Map<string, UserMemory[]>();\n private readonly knowledgeMap = new Map<string, SharedKnowledge>();\n\n // -- User Profile -----------------------------------------------------------\n\n async getProfile(userId: string): Promise<UserProfile | null> {\n return this.profilesMap.get(userId) ?? null;\n }\n\n async updateProfile(\n userId: string,\n updates: Partial<Omit<UserProfile, \"userId\" | \"createdAt\">>,\n ): Promise<UserProfile> {\n const existing = this.profilesMap.get(userId);\n const now = Date.now();\n\n const profile: UserProfile = existing\n ? { ...existing, ...updates, updatedAt: now }\n : {\n userId,\n preferences: {},\n ...updates,\n updatedAt: now,\n createdAt: now,\n };\n\n this.profilesMap.set(userId, profile);\n return profile;\n }\n\n async deleteProfile(userId: string): Promise<void> {\n this.profilesMap.delete(userId);\n }\n\n // -- User Memories ----------------------------------------------------------\n\n async addMemory(\n userId: string,\n memory: Omit<UserMemoryInput, \"id\" | \"createdAt\">,\n ): Promise<UserMemory> {\n const entry: UserMemory = {\n ...memory,\n tags: memory.tags ?? [],\n confidence: memory.confidence ?? 1,\n source: memory.source ?? \"inferred\",\n id: crypto.randomUUID(),\n createdAt: Date.now(),\n };\n\n const list = this.memoriesMap.get(userId) ?? [];\n list.push(entry);\n this.memoriesMap.set(userId, list);\n return entry;\n }\n\n async getMemories(\n userId: string,\n options?: { tags?: string[]; limit?: number; since?: number },\n ): Promise<UserMemory[]> {\n let memories = this.memoriesMap.get(userId) ?? [];\n\n if (options?.tags && options.tags.length > 0) {\n memories = memories.filter((m) =>\n options.tags!.some((tag) => m.tags.includes(tag)),\n );\n }\n\n if (options?.since) {\n memories = memories.filter((m) => m.createdAt >= options.since!);\n }\n\n // Most recent first\n memories = [...memories].sort((a, b) => b.createdAt - a.createdAt);\n\n if (options?.limit) {\n memories = memories.slice(0, options.limit);\n }\n\n return memories;\n }\n\n async deleteMemory(userId: string, memoryId: string): Promise<void> {\n const list = this.memoriesMap.get(userId);\n if (!list) return;\n this.memoriesMap.set(\n userId,\n list.filter((m) => m.id !== memoryId),\n );\n }\n\n async clearMemories(userId: string): Promise<void> {\n this.memoriesMap.delete(userId);\n }\n\n // -- Shared Knowledge -------------------------------------------------------\n\n async addKnowledge(\n knowledge: Omit<SharedKnowledgeInput, \"id\" | \"createdAt\" | \"usageCount\">,\n ): Promise<SharedKnowledge> {\n const entry: SharedKnowledge = {\n ...knowledge,\n tags: knowledge.tags ?? [],\n id: crypto.randomUUID(),\n usageCount: 0,\n createdAt: Date.now(),\n };\n\n this.knowledgeMap.set(entry.id, entry);\n return entry;\n }\n\n async queryKnowledge(\n query: string,\n options?: { category?: string; limit?: number },\n ): Promise<SharedKnowledge[]> {\n const lowerQuery = query.toLowerCase();\n let results = Array.from(this.knowledgeMap.values()).filter((k) =>\n k.content.toLowerCase().includes(lowerQuery),\n );\n\n if (options?.category) {\n results = results.filter((k) => k.category === options.category);\n }\n\n // Most used first\n results.sort((a, b) => b.usageCount - a.usageCount);\n\n if (options?.limit) {\n results = results.slice(0, options.limit);\n }\n\n return results;\n }\n\n async incrementKnowledgeUsage(knowledgeId: string): Promise<void> {\n const entry = this.knowledgeMap.get(knowledgeId);\n if (entry) {\n entry.usageCount++;\n }\n }\n\n async deleteKnowledge(knowledgeId: string): Promise<void> {\n this.knowledgeMap.delete(knowledgeId);\n }\n\n // -- Utility ----------------------------------------------------------------\n\n /** Clear all data for a user */\n clear(userId: string): void {\n this.profilesMap.delete(userId);\n this.memoriesMap.delete(userId);\n }\n\n /** Clear all users and shared knowledge */\n clearAll(): void {\n this.profilesMap.clear();\n this.memoriesMap.clear();\n this.knowledgeMap.clear();\n }\n}\n","// GaussMcpAdapter — Adapter bridging @giulio-leone/gaussflow-mcp registry to McpPort\n\nimport type { McpRegistry } from \"@giulio-leone/gaussflow-mcp\";\nimport type {\n McpServerState,\n McpToolWireFormat,\n} from \"@giulio-leone/gaussflow-mcp\";\n\nimport type {\n McpPort,\n McpToolDefinition,\n McpToolResult,\n McpServerInfo,\n McpServerConfig,\n} from \"../../ports/mcp.port.js\";\n\nexport class GaussMcpAdapter implements McpPort {\n private readonly registry: McpRegistry;\n private readonly executor?: (\n serverId: string,\n toolName: string,\n args: unknown,\n ) => Promise<McpToolResult>;\n\n constructor(options: {\n registry: McpRegistry;\n executor?: (\n serverId: string,\n toolName: string,\n args: unknown,\n ) => Promise<McpToolResult>;\n }) {\n this.registry = options.registry;\n this.executor = options.executor;\n }\n\n async discoverTools(): Promise<Record<string, McpToolDefinition>> {\n const result: Record<string, McpToolDefinition> = {};\n const states = this.registry.listServerStates();\n\n for (const [, state] of states) {\n if (!state.tools) continue;\n for (const tool of state.tools) {\n const namespacedName = `${state.config.id}:${tool.name}`;\n result[namespacedName] = mapWireToDef(tool, state, namespacedName);\n }\n }\n\n return result;\n }\n\n async executeTool(name: string, args: unknown): Promise<McpToolResult> {\n const colonIndex = name.indexOf(\":\");\n const serverId = colonIndex > -1 ? name.slice(0, colonIndex) : undefined;\n const toolName = colonIndex > -1 ? name.slice(colonIndex + 1) : name;\n\n if (this.executor) {\n return this.executor(serverId ?? \"\", toolName, args);\n }\n\n throw new Error(\n `Tool execution requires an executor function. ` +\n `Pass { executor } in constructor options.`,\n );\n }\n\n async listServers(): Promise<McpServerInfo[]> {\n const states = this.registry.listServerStates();\n const infos: McpServerInfo[] = [];\n\n for (const [, state] of states) {\n infos.push(mapStateToInfo(state));\n }\n\n return infos;\n }\n\n async connect(config: McpServerConfig): Promise<void> {\n const mcpConfig = mapConfigToRegistry(config);\n if (!this.registry.hasServer(config.id)) {\n this.registry.add(mcpConfig);\n }\n this.registry.setStatus(config.id, \"connected\");\n }\n\n async disconnect(serverId: string): Promise<void> {\n if (!this.registry.hasServer(serverId)) return;\n this.registry.setStatus(serverId, \"disconnected\");\n }\n\n async closeAll(): Promise<void> {\n const servers = this.registry.listServers();\n for (const server of servers) {\n this.registry.setStatus(server.id, \"disconnected\");\n }\n }\n}\n\n// ---------------------------------------------------------------------------\n// Mapping helpers\n// ---------------------------------------------------------------------------\n\nfunction mapWireToDef(\n tool: McpToolWireFormat,\n state: McpServerState,\n namespacedName: string,\n): McpToolDefinition {\n return {\n name: namespacedName,\n description: tool.description ?? \"\",\n inputSchema: tool.inputSchema as Record<string, unknown>,\n domain: state.config.domain,\n };\n}\n\nfunction mapStateToInfo(state: McpServerState): McpServerInfo {\n const transport = state.config.transport === \"local\"\n ? \"stdio\"\n : state.config.transport;\n\n return {\n id: state.config.id,\n name: state.config.name ?? state.config.id,\n status: state.status === \"connecting\" ? \"disconnected\" : state.status,\n toolCount: state.tools?.length ?? 0,\n transport: transport as \"stdio\" | \"http\" | \"sse\",\n };\n}\n\nfunction mapConfigToRegistry(\n config: McpServerConfig,\n): import(\"@giulio-leone/gaussflow-mcp\").McpServerConfig {\n if (config.transport === \"stdio\") {\n return {\n id: config.id,\n name: config.name,\n transport: \"stdio\",\n command: config.command ?? \"\",\n args: config.args,\n env: config.env,\n };\n }\n\n if (config.transport === \"http\" || config.transport === \"sse\") {\n return {\n id: config.id,\n name: config.name,\n transport: \"http\",\n url: config.url ?? \"\",\n headers: config.headers,\n };\n }\n\n return {\n id: config.id,\n name: config.name,\n transport: \"http\",\n url: config.url ?? \"\",\n };\n}\n","// AiSdkMcpAdapter — Adapter using @ai-sdk/mcp createMCPClient\n\nimport type {\n McpPort,\n McpToolDefinition,\n McpToolResult,\n McpServerInfo,\n McpServerConfig,\n} from \"../../ports/mcp.port.js\";\n\ninterface MCPClient {\n tools(): Promise<Record<string, unknown>>;\n close(): Promise<void>;\n}\n\nexport class AiSdkMcpAdapter implements McpPort {\n private readonly clients = new Map<string, MCPClient>();\n private readonly configs = new Map<string, McpServerConfig>();\n\n constructor(options: { servers?: McpServerConfig[] } = {}) {\n for (const server of options.servers ?? []) {\n this.configs.set(server.id, server);\n }\n }\n\n async discoverTools(): Promise<Record<string, McpToolDefinition>> {\n const result: Record<string, McpToolDefinition> = {};\n for (const [serverId, client] of this.clients) {\n const tools = await client.tools();\n for (const [name, rawTool] of Object.entries(tools)) {\n const tool = rawTool as {\n description?: string;\n parameters?: Record<string, unknown>;\n };\n const namespacedName = `${serverId}:${name}`;\n result[namespacedName] = {\n name: namespacedName,\n description: tool.description ?? \"\",\n inputSchema: (tool.parameters ?? {}) as Record<string, unknown>,\n };\n }\n }\n return result;\n }\n\n async executeTool(name: string, args: unknown): Promise<McpToolResult> {\n const colonIndex = name.indexOf(\":\");\n const serverId = colonIndex > -1 ? name.slice(0, colonIndex) : undefined;\n const toolName = colonIndex > -1 ? name.slice(colonIndex + 1) : name;\n\n if (serverId) {\n const client = this.clients.get(serverId);\n if (client) {\n const tools = await client.tools();\n const toolDef = tools[toolName] as\n | { execute?: (a: unknown) => Promise<unknown> }\n | undefined;\n if (toolDef?.execute) {\n const raw = await toolDef.execute(args);\n return {\n content: [{ type: \"text\", text: String(raw) }],\n isError: false,\n };\n }\n }\n throw new Error(\n `Tool \"${toolName}\" not found on server \"${serverId}\"`,\n );\n }\n\n for (const [, client] of this.clients) {\n const tools = await client.tools();\n const toolDef = tools[toolName] as\n | { execute?: (a: unknown) => Promise<unknown> }\n | undefined;\n if (!toolDef?.execute) continue;\n const raw = await toolDef.execute(args);\n return { content: [{ type: \"text\", text: String(raw) }], isError: false };\n }\n throw new Error(`Tool \"${name}\" not found on any connected MCP server`);\n }\n\n async listServers(): Promise<McpServerInfo[]> {\n const infos: McpServerInfo[] = [];\n for (const [id, config] of this.configs) {\n infos.push({\n id,\n name: config.name,\n status: this.clients.has(id) ? \"connected\" : \"disconnected\",\n toolCount: 0,\n transport: config.transport === \"sse\" ? \"sse\" : config.transport,\n });\n }\n return infos;\n }\n\n async connect(config: McpServerConfig): Promise<void> {\n this.configs.set(config.id, config);\n if (this.clients.has(config.id)) return;\n const createClient = await loadCreateMCPClient();\n const client = await createClient(buildTransport(config));\n this.clients.set(config.id, client as MCPClient);\n }\n\n async disconnect(serverId: string): Promise<void> {\n const client = this.clients.get(serverId);\n if (!client) return;\n await client.close();\n this.clients.delete(serverId);\n }\n\n async closeAll(): Promise<void> {\n const ids = Array.from(this.clients.keys());\n for (const id of ids) {\n await this.disconnect(id);\n }\n }\n}\n\nasync function loadCreateMCPClient(): Promise<\n (config: Record<string, unknown>) => Promise<unknown>\n> {\n try {\n // @ts-expect-error — optional peer dependency, resolved at runtime\n const mod = (await import(\"@ai-sdk/mcp\")) as {\n createMCPClient?: (c: Record<string, unknown>) => Promise<unknown>;\n };\n if (!mod.createMCPClient) {\n throw new Error(\"createMCPClient not found in @ai-sdk/mcp\");\n }\n return mod.createMCPClient;\n } catch {\n throw new Error(\n \"Failed to load @ai-sdk/mcp. Install it with: pnpm add @ai-sdk/mcp\",\n );\n }\n}\n\nfunction buildTransport(config: McpServerConfig): Record<string, unknown> {\n if (config.transport === \"stdio\") {\n return {\n transport: {\n type: \"stdio\",\n command: config.command,\n args: config.args,\n env: config.env,\n },\n };\n }\n return {\n transport: {\n type: config.transport === \"sse\" ? \"sse\" : \"http\",\n url: config.url,\n headers: config.headers,\n },\n };\n}\n","import type {\n PolicyAuditRecord,\n PolicyContext,\n PolicyDecision,\n PolicyEffect,\n PolicyEnginePort,\n PolicyRequest,\n PolicyRule,\n} from \"../../ports/policy.port.js\";\n\nconst DEFAULT_AUDIT_LIMIT = 1000;\n\nexport interface McpPolicyEngineOptions {\n defaultEffect?: PolicyEffect;\n maxAuditRecords?: number;\n rules?: PolicyRule[];\n}\n\nexport class McpPolicyEngine implements PolicyEnginePort {\n private rules: PolicyRule[];\n private readonly defaultEffect: PolicyEffect;\n private readonly maxAuditRecords: number;\n private auditLog: PolicyAuditRecord[] = [];\n\n constructor(options: McpPolicyEngineOptions = {}) {\n this.rules = [...(options.rules ?? [])];\n this.defaultEffect = options.defaultEffect ?? \"allow\";\n this.maxAuditRecords = options.maxAuditRecords ?? DEFAULT_AUDIT_LIMIT;\n }\n\n async evaluate(\n request: PolicyRequest,\n context: PolicyContext,\n ): Promise<PolicyDecision> {\n const matched = this.findMatchingRules(request, context);\n\n const denyMatch = matched.find((rule) => rule.effect === \"deny\");\n const allowMatch = matched.find((rule) => rule.effect === \"allow\");\n const selected = denyMatch ?? allowMatch;\n\n const effect: PolicyEffect = selected?.effect ?? this.defaultEffect;\n const decision: PolicyDecision = {\n allowed: effect === \"allow\",\n effect,\n reason:\n selected?.reason ??\n (selected\n ? `Policy ${effect} by rule ${selected.id}`\n : `Policy ${effect} by default`),\n matchedRuleId: selected?.id,\n auditId: crypto.randomUUID(),\n };\n\n const record: PolicyAuditRecord = {\n id: decision.auditId,\n timestamp: new Date().toISOString(),\n request,\n context,\n decision,\n };\n\n this.auditLog.push(record);\n if (this.auditLog.length > this.maxAuditRecords) {\n this.auditLog = this.auditLog.slice(-this.maxAuditRecords);\n }\n\n return decision;\n }\n\n async addRule(rule: PolicyRule): Promise<void> {\n this.rules.push(rule);\n }\n\n async removeRule(id: string): Promise<boolean> {\n const before = this.rules.length;\n this.rules = this.rules.filter((rule) => rule.id !== id);\n return this.rules.length < before;\n }\n\n async setRules(rules: PolicyRule[]): Promise<void> {\n this.rules = [...rules];\n }\n\n async listRules(): Promise<PolicyRule[]> {\n return [...this.rules].sort(\n (a, b) => (b.priority ?? 0) - (a.priority ?? 0),\n );\n }\n\n async getAuditLog(limit?: number): Promise<PolicyAuditRecord[]> {\n const ordered = [...this.auditLog].reverse();\n if (!limit || limit <= 0) {\n return ordered;\n }\n return ordered.slice(0, limit);\n }\n\n async clearAuditLog(): Promise<void> {\n this.auditLog = [];\n }\n\n private findMatchingRules(\n request: PolicyRequest,\n context: PolicyContext,\n ): PolicyRule[] {\n return [...this.rules]\n .filter((rule) => this.matchesRule(rule, request, context))\n .sort((a, b) => (b.priority ?? 0) - (a.priority ?? 0));\n }\n\n private matchesRule(\n rule: PolicyRule,\n request: PolicyRequest,\n context: PolicyContext,\n ): boolean {\n if (!this.matchesPattern(rule.resourcePattern, request.resource)) {\n return false;\n }\n\n if (\n rule.serverPattern &&\n !this.matchesPattern(rule.serverPattern, request.serverName ?? \"\")\n ) {\n return false;\n }\n\n if (\n rule.toolPattern &&\n !this.matchesPattern(rule.toolPattern, request.toolName ?? \"\")\n ) {\n return false;\n }\n\n if (rule.context?.sessionId && rule.context.sessionId !== context.sessionId) {\n return false;\n }\n if (rule.context?.userId && rule.context.userId !== context.userId) {\n return false;\n }\n if (rule.context?.tenantId && rule.context.tenantId !== context.tenantId) {\n return false;\n }\n\n return true;\n }\n\n private matchesPattern(pattern: string, value: string): boolean {\n const escaped = pattern.replace(/[.+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n const regex = new RegExp(`^${escaped.replace(/\\*/g, \".*\")}$`);\n return regex.test(value);\n }\n}\n","// =============================================================================\n// AiSdkModelAdapter — Wraps Vercel AI SDK LanguageModel into ModelPort\n// =============================================================================\n\nimport type { LanguageModel } from \"../../core/llm/index.js\";\nimport { generateText, streamText } from \"../../core/llm/index.js\";\n\nimport type {\n ModelPort,\n ModelGenerateOptions,\n ModelGenerateResult,\n ModelStreamResult,\n} from \"../../ports/model.port.js\";\n\nexport interface AiSdkModelAdapterOptions {\n model: LanguageModel;\n modelId?: string;\n contextWindowSize?: number;\n}\n\nexport class AiSdkModelAdapter implements ModelPort {\n private readonly model: LanguageModel;\n private readonly _modelId: string;\n private readonly contextWindow: number;\n\n constructor(options: AiSdkModelAdapterOptions) {\n this.model = options.model;\n this._modelId = options.modelId ?? (typeof options.model === \"string\" ? options.model : \"unknown\");\n this.contextWindow = options.contextWindowSize ?? 128_000;\n }\n\n getModel(): LanguageModel {\n return this.model;\n }\n\n getContextWindowSize(): number {\n return this.contextWindow;\n }\n\n getModelId(): string {\n return this._modelId;\n }\n\n async generate(options: ModelGenerateOptions): Promise<ModelGenerateResult> {\n const result = await generateText({\n model: this.model,\n system: options.systemPrompt,\n messages: options.messages.map((m) => ({\n role: m.role as \"user\" | \"assistant\" | \"system\",\n content: m.content,\n })),\n temperature: options.temperature,\n maxTokens: options.maxTokens,\n });\n\n return {\n text: result.text,\n usage: {\n inputTokens: result.usage.inputTokens ?? 0,\n outputTokens: result.usage.outputTokens ?? 0,\n totalTokens: (result.usage.inputTokens ?? 0) + (result.usage.outputTokens ?? 0),\n },\n finishReason: result.finishReason,\n };\n }\n\n async generateStream(options: ModelGenerateOptions): Promise<ModelStreamResult> {\n const result = streamText({\n model: this.model,\n system: options.systemPrompt,\n messages: options.messages.map((m) => ({\n role: m.role as \"user\" | \"assistant\" | \"system\",\n content: m.content,\n })),\n temperature: options.temperature,\n maxTokens: options.maxTokens,\n });\n\n const usagePromise: Promise<{ inputTokens: number; outputTokens: number; totalTokens: number }> =\n Promise.resolve(result.usage).then((u) => ({\n inputTokens: u.inputTokens ?? 0,\n outputTokens: u.outputTokens ?? 0,\n totalTokens: (u.inputTokens ?? 0) + (u.outputTokens ?? 0),\n }));\n\n return {\n textStream: result.textStream,\n usage: usagePromise,\n };\n }\n}\n","// =============================================================================\n// ModelRouter — Multi-provider model routing with pluggable policies\n// =============================================================================\n\nimport type { LanguageModel } from \"../../core/llm/index.js\";\n\nimport type {\n ModelPort,\n ModelGenerateOptions,\n ModelGenerateResult,\n ModelStreamResult,\n} from \"../../ports/model.port.js\";\n\n// =============================================================================\n// Provider descriptor\n// =============================================================================\n\nexport interface ModelProviderInfo {\n /** Unique provider identifier (e.g., \"openai:gpt-5.2\") */\n id: string;\n /** Provider name (e.g., \"openai\") */\n provider: string;\n /** Model name (e.g., \"gpt-5.2\") */\n model: string;\n /** Cost per 1K input tokens */\n costPerInputKToken?: number;\n /** Cost per 1K output tokens */\n costPerOutputKToken?: number;\n /** Average latency in ms (tracked at runtime) */\n avgLatencyMs?: number;\n /** Context window size */\n contextWindow: number;\n /** Capabilities this model supports */\n capabilities: ModelCapability[];\n /** Whether this provider is currently healthy */\n healthy: boolean;\n}\n\nexport type ModelCapability =\n | \"text\"\n | \"vision\"\n | \"function-calling\"\n | \"json-mode\"\n | \"streaming\"\n | \"embedding\"\n | \"code\"\n | \"reasoning\";\n\n// =============================================================================\n// Routing policy\n// =============================================================================\n\nexport interface RoutingContext {\n /** Requested capabilities */\n requiredCapabilities?: ModelCapability[];\n /** Max acceptable latency in ms */\n maxLatencyMs?: number;\n /** Max acceptable cost per request */\n maxCostPerRequest?: number;\n /** Preferred provider (hint, not enforced) */\n preferredProvider?: string;\n /** Task complexity hint */\n complexity?: \"low\" | \"medium\" | \"high\";\n}\n\nexport interface RoutingPolicy {\n /** Policy name */\n readonly name: string;\n /** Select the best provider given context */\n select(\n providers: readonly ModelProviderInfo[],\n context: RoutingContext,\n ): ModelProviderInfo | null;\n}\n\n// =============================================================================\n// Built-in policies\n// =============================================================================\n\nexport const CostOptimalPolicy: RoutingPolicy = {\n name: \"cost-optimal\",\n select(providers, context) {\n const eligible = filterByCapabilities(providers, context);\n if (eligible.length === 0) return null;\n return eligible.reduce((best, p) => {\n const bestCost = (best.costPerInputKToken ?? Infinity) + (best.costPerOutputKToken ?? Infinity);\n const pCost = (p.costPerInputKToken ?? Infinity) + (p.costPerOutputKToken ?? Infinity);\n return pCost < bestCost ? p : best;\n });\n },\n};\n\nexport const LatencyOptimalPolicy: RoutingPolicy = {\n name: \"latency-optimal\",\n select(providers, context) {\n const eligible = filterByCapabilities(providers, context);\n if (eligible.length === 0) return null;\n return eligible.reduce((best, p) =>\n (p.avgLatencyMs ?? Infinity) < (best.avgLatencyMs ?? Infinity) ? p : best,\n );\n },\n};\n\nexport const CapabilityPolicy: RoutingPolicy = {\n name: \"capability\",\n select(providers, context) {\n const eligible = filterByCapabilities(providers, context);\n if (eligible.length === 0) return null;\n // Prefer provider with most capabilities\n return eligible.reduce((best, p) =>\n p.capabilities.length > best.capabilities.length ? p : best,\n );\n },\n};\n\nexport const FallbackPolicy: RoutingPolicy = {\n name: \"fallback\",\n select(providers, context) {\n const eligible = filterByCapabilities(providers, context);\n return eligible[0] ?? null;\n },\n};\n\nfunction filterByCapabilities(\n providers: readonly ModelProviderInfo[],\n context: RoutingContext,\n): ModelProviderInfo[] {\n return providers.filter((p) => {\n if (!p.healthy) return false;\n if (context.requiredCapabilities) {\n for (const cap of context.requiredCapabilities) {\n if (!p.capabilities.includes(cap)) return false;\n }\n }\n if (context.maxLatencyMs && p.avgLatencyMs && p.avgLatencyMs > context.maxLatencyMs) {\n return false;\n }\n return true;\n });\n}\n\n// =============================================================================\n// Registry entry — links info to a ModelPort adapter\n// =============================================================================\n\ninterface RegisteredProvider {\n info: ModelProviderInfo;\n adapter: ModelPort;\n}\n\n// =============================================================================\n// ModelRouter\n// =============================================================================\n\nexport class ModelRouter implements ModelPort {\n private readonly providers = new Map<string, RegisteredProvider>();\n private policy: RoutingPolicy;\n private defaultContext: RoutingContext;\n private activeProvider: RegisteredProvider | null = null;\n\n constructor(policy: RoutingPolicy = FallbackPolicy, defaultContext: RoutingContext = {}) {\n this.policy = policy;\n this.defaultContext = defaultContext;\n }\n\n // ---------------------------------------------------------------------------\n // Provider management\n // ---------------------------------------------------------------------------\n\n register(info: ModelProviderInfo, adapter: ModelPort): void {\n this.providers.set(info.id, { info, adapter });\n }\n\n unregister(id: string): boolean {\n return this.providers.delete(id);\n }\n\n setPolicy(policy: RoutingPolicy): void {\n this.policy = policy;\n }\n\n setDefaultContext(context: RoutingContext): void {\n this.defaultContext = context;\n }\n\n getProviders(): readonly ModelProviderInfo[] {\n return Array.from(this.providers.values()).map((p) => ({ ...p.info }));\n }\n\n // ---------------------------------------------------------------------------\n // Route selection\n // ---------------------------------------------------------------------------\n\n resolve(context?: RoutingContext, excludeIds?: ReadonlySet<string>): ModelPort {\n const ctx = { ...this.defaultContext, ...context };\n let infos = Array.from(this.providers.values()).map((p) => p.info);\n if (excludeIds) {\n infos = infos.filter((p) => !excludeIds.has(p.id));\n }\n const selected = this.policy.select(infos, ctx);\n\n if (!selected) {\n throw new Error(\n `ModelRouter: no provider matches policy \"${this.policy.name}\" with context ${JSON.stringify(ctx)}`,\n );\n }\n\n const provider = this.providers.get(selected.id)!;\n this.activeProvider = provider;\n return provider.adapter;\n }\n\n /** Resolve and return both adapter and provider ID (race-condition safe) */\n private resolveWithId(context?: RoutingContext, excludeIds?: ReadonlySet<string>): { adapter: ModelPort; providerId: string } {\n const ctx = { ...this.defaultContext, ...context };\n let infos = Array.from(this.providers.values()).map((p) => p.info);\n if (excludeIds) {\n infos = infos.filter((p) => !excludeIds.has(p.id));\n }\n const selected = this.policy.select(infos, ctx);\n\n if (!selected) {\n throw new Error(\n `ModelRouter: no provider matches policy \"${this.policy.name}\" with context ${JSON.stringify(ctx)}`,\n );\n }\n\n const provider = this.providers.get(selected.id)!;\n this.activeProvider = provider; // Keep for getActive() compatibility\n return { adapter: provider.adapter, providerId: selected.id };\n }\n\n // ---------------------------------------------------------------------------\n // Latency tracking — call after each request\n // ---------------------------------------------------------------------------\n\n recordLatency(providerId: string, latencyMs: number): void {\n const provider = this.providers.get(providerId);\n if (!provider) return;\n // Exponential moving average\n const current = provider.info.avgLatencyMs ?? latencyMs;\n provider.info.avgLatencyMs = current * 0.7 + latencyMs * 0.3;\n }\n\n markUnhealthy(providerId: string): void {\n const provider = this.providers.get(providerId);\n if (provider) provider.info.healthy = false;\n }\n\n markHealthy(providerId: string): void {\n const provider = this.providers.get(providerId);\n if (provider) provider.info.healthy = true;\n }\n\n // ---------------------------------------------------------------------------\n // ModelPort delegation — routes to resolved provider\n // ---------------------------------------------------------------------------\n\n getModel(): LanguageModel {\n return this.getActive().getModel();\n }\n\n getContextWindowSize(): number {\n return this.getActive().getContextWindowSize();\n }\n\n getModelId(): string {\n return this.getActive().getModelId();\n }\n\n async generate(options: ModelGenerateOptions): Promise<ModelGenerateResult> {\n const failedIds = new Set<string>();\n const { adapter, providerId } = this.resolveWithId(undefined, failedIds);\n const start = Date.now();\n\n try {\n const result = await adapter.generate(options);\n this.recordLatency(providerId, Date.now() - start);\n return result;\n } catch (error) {\n this.markUnhealthy(providerId);\n failedIds.add(providerId);\n // Try fallback excluding already-failed providers\n try {\n const fallback = this.resolveWithId(undefined, failedIds);\n const fallbackStart = Date.now();\n const result = await fallback.adapter.generate(options);\n this.recordLatency(fallback.providerId, Date.now() - fallbackStart);\n return result;\n } catch {\n throw error; // Original error if no fallback\n }\n }\n }\n\n async generateStream(options: ModelGenerateOptions): Promise<ModelStreamResult> {\n const { adapter } = this.resolveWithId({ requiredCapabilities: [\"streaming\"] });\n\n if (!adapter.generateStream) {\n throw new Error(\"ModelRouter: selected provider does not support streaming\");\n }\n\n return adapter.generateStream(options);\n }\n\n // ---------------------------------------------------------------------------\n // Internal\n // ---------------------------------------------------------------------------\n\n private getActive(): ModelPort {\n if (this.activeProvider) return this.activeProvider.adapter;\n return this.resolve();\n }\n}\n","// =============================================================================\n// Auth Adapters — API Key, JWT (HMAC), RBAC\n// =============================================================================\n\nimport type { AuthPort, AuthorizationPort, AuthResult, AuthUser } from \"../../ports/auth.port.js\";\n\n// --- API Key Adapter ---\n\nexport class ApiKeyAuthAdapter implements AuthPort {\n private keys: Map<string, AuthUser>;\n\n constructor(keys: Record<string, AuthUser>) {\n this.keys = new Map(Object.entries(keys));\n }\n\n async authenticate(token: string): Promise<AuthResult> {\n const user = this.keys.get(token);\n if (user) return { authenticated: true, user };\n return { authenticated: false, error: \"Invalid API key\" };\n }\n}\n\n// --- JWT Adapter (HMAC-SHA256, zero-dependency) ---\n\nfunction base64UrlDecode(str: string): string {\n const padded = str + \"=\".repeat((4 - (str.length % 4)) % 4);\n return Buffer.from(padded, \"base64url\").toString(\"utf-8\");\n}\n\nasync function hmacSha256(secret: string, data: string): Promise<string> {\n const { createHmac } = await import(\"node:crypto\");\n return createHmac(\"sha256\", secret).update(data).digest(\"base64url\");\n}\n\nexport interface JwtAuthOptions {\n secret: string;\n issuer?: string;\n audience?: string;\n clockToleranceSec?: number;\n}\n\nexport class JwtAuthAdapter implements AuthPort {\n constructor(private opts: JwtAuthOptions) {}\n\n async authenticate(token: string): Promise<AuthResult> {\n const parts = token.split(\".\");\n if (parts.length !== 3) return { authenticated: false, error: \"Malformed JWT\" };\n const [headerB64, payloadB64, signatureB64] = parts;\n\n // Verify signature (timing-safe comparison)\n const expected = await hmacSha256(this.opts.secret, `${headerB64}.${payloadB64}`);\n const { timingSafeEqual } = await import(\"node:crypto\");\n const a = Buffer.from(expected);\n const b = Buffer.from(signatureB64);\n if (a.length !== b.length || !timingSafeEqual(a, b)) {\n return { authenticated: false, error: \"Invalid signature\" };\n }\n\n // Parse payload\n let payload: Record<string, unknown>;\n try { payload = JSON.parse(base64UrlDecode(payloadB64)); }\n catch { return { authenticated: false, error: \"Invalid payload\" }; }\n\n // Validate claims\n const now = Math.floor(Date.now() / 1000);\n const tolerance = this.opts.clockToleranceSec ?? 0;\n\n if (typeof payload.exp === \"number\" && now > payload.exp + tolerance) {\n return { authenticated: false, error: \"Token expired\" };\n }\n if (typeof payload.nbf === \"number\" && now < payload.nbf - tolerance) {\n return { authenticated: false, error: \"Token not yet valid\" };\n }\n if (this.opts.issuer && payload.iss !== this.opts.issuer) {\n return { authenticated: false, error: \"Invalid issuer\" };\n }\n if (this.opts.audience && payload.aud !== this.opts.audience) {\n return { authenticated: false, error: \"Invalid audience\" };\n }\n\n const user: AuthUser = {\n id: (payload.sub as string) ?? \"unknown\",\n roles: Array.isArray(payload.roles) ? payload.roles as string[] : [],\n metadata: payload,\n };\n\n return { authenticated: true, user };\n }\n}\n\n// --- Composite Auth (try multiple providers in order) ---\n\nexport class CompositeAuthAdapter implements AuthPort {\n constructor(private providers: AuthPort[]) {}\n\n async authenticate(token: string): Promise<AuthResult> {\n for (const provider of this.providers) {\n const result = await provider.authenticate(token);\n if (result.authenticated) return result;\n }\n return { authenticated: false, error: \"All authentication providers rejected\" };\n }\n}\n\n// --- RBAC Authorization ---\n\nexport class RbacAuthorizationAdapter implements AuthorizationPort {\n private permissions: Map<string, Set<string>>;\n\n constructor(rolePermissions: Record<string, string[]>) {\n this.permissions = new Map();\n for (const [role, perms] of Object.entries(rolePermissions)) {\n this.permissions.set(role, new Set(perms));\n }\n }\n\n async authorize(user: AuthUser, permission: string): Promise<boolean> {\n for (const role of user.roles) {\n const perms = this.permissions.get(role);\n if (perms?.has(permission) || perms?.has(\"*\")) return true;\n }\n return false;\n }\n}\n","// =============================================================================\n// Agent Network Adapters — Mesh, Star, Hierarchical topologies\n// =============================================================================\n\nimport type {\n AgentNetworkPort, NetworkTopology, NetworkAgent,\n DelegationRequest, DelegationResult,\n} from \"../../ports/agent-network.port.js\";\n\nexport type DelegationHandler = (request: DelegationRequest) => Promise<unknown>;\n\nexport interface AgentNetworkOptions {\n topology: NetworkTopology;\n /** Invoked to actually run a delegation to a specific agent */\n handler: DelegationHandler;\n /** For hierarchical topology: maps agent name → parent name */\n hierarchy?: Record<string, string>;\n /** Default timeout in ms */\n timeout?: number;\n}\n\nexport class AgentNetworkAdapter implements AgentNetworkPort {\n private registry = new Map<string, NetworkAgent>();\n private opts: Required<Pick<AgentNetworkOptions, \"topology\" | \"handler\" | \"timeout\">> & { hierarchy: Record<string, string> };\n\n constructor(opts: AgentNetworkOptions) {\n this.opts = {\n topology: opts.topology,\n handler: opts.handler,\n hierarchy: opts.hierarchy ?? {},\n timeout: opts.timeout ?? 30_000,\n };\n }\n\n register(agent: NetworkAgent): void {\n this.registry.set(agent.name, agent);\n }\n\n unregister(name: string): void {\n this.registry.delete(name);\n }\n\n discover(capabilities: string[]): NetworkAgent[] {\n const results: NetworkAgent[] = [];\n for (const agent of this.registry.values()) {\n if (capabilities.every(c => agent.capabilities.includes(c))) {\n results.push(agent);\n }\n }\n return results;\n }\n\n async delegate(request: DelegationRequest): Promise<DelegationResult> {\n const target = this.registry.get(request.to);\n if (!target) return { success: false, error: `Agent \"${request.to}\" not found`, duration: 0 };\n\n // Hierarchical: validate parent→child relationship\n if (this.opts.topology === \"hierarchical\") {\n const parent = this.opts.hierarchy[request.to];\n if (parent && parent !== request.from) {\n return { success: false, error: `Agent \"${request.from}\" is not parent of \"${request.to}\"`, duration: 0 };\n }\n }\n\n const timeout = request.timeout ?? this.opts.timeout;\n const start = Date.now();\n let timeoutId: ReturnType<typeof setTimeout> | undefined;\n try {\n const result = await Promise.race([\n this.opts.handler(request),\n new Promise((_, reject) => {\n timeoutId = setTimeout(() => reject(new Error(\"Delegation timeout\")), timeout);\n }),\n ]);\n return { success: true, result, duration: Date.now() - start };\n } catch (err) {\n return { success: false, error: err instanceof Error ? err.message : String(err), duration: Date.now() - start };\n } finally {\n if (timeoutId !== undefined) clearTimeout(timeoutId);\n }\n }\n\n async broadcast(task: string, capabilities: string[], context?: Record<string, unknown>): Promise<DelegationResult[]> {\n const targets = this.discover(capabilities);\n const results = await Promise.allSettled(\n targets.map(agent =>\n this.delegate({ from: \"__broadcast__\", to: agent.name, task, context }),\n ),\n );\n return results.map(r =>\n r.status === \"fulfilled\" ? r.value : { success: false, error: r.reason?.message ?? \"Unknown error\", duration: 0 },\n );\n }\n\n topology(): NetworkTopology {\n return this.opts.topology;\n }\n\n agents(): NetworkAgent[] {\n return [...this.registry.values()];\n }\n}\n","// =============================================================================\n// ConsoleTelemetryAdapter — Logs spans and metrics to console (zero deps)\n// =============================================================================\n\nimport type { TelemetryPort, TelemetrySpan } from \"../../ports/telemetry.port.js\";\n\nclass ConsoleTelemetrySpan implements TelemetrySpan {\n private readonly name: string;\n private readonly attributes: Record<string, string | number | boolean> = {};\n private readonly startTime = Date.now();\n\n constructor(name: string, initialAttributes?: Record<string, string | number | boolean>) {\n this.name = name;\n if (initialAttributes) {\n Object.assign(this.attributes, initialAttributes);\n }\n console.log(`[telemetry] span:start ${this.name}`, this.attributes);\n }\n\n setAttribute(key: string, value: string | number | boolean): void {\n this.attributes[key] = value;\n }\n\n setStatus(code: \"OK\" | \"ERROR\", message?: string): void {\n this.attributes[\"status.code\"] = code;\n if (message) this.attributes[\"status.message\"] = message;\n }\n\n end(): void {\n const durationMs = Date.now() - this.startTime;\n console.log(`[telemetry] span:end ${this.name} (${durationMs}ms)`, this.attributes);\n }\n}\n\nexport class ConsoleTelemetryAdapter implements TelemetryPort {\n startSpan(name: string, attributes?: Record<string, string | number | boolean>): TelemetrySpan {\n return new ConsoleTelemetrySpan(name, attributes);\n }\n\n recordMetric(name: string, value: number, attributes?: Record<string, string>): void {\n console.log(`[telemetry] metric ${name}=${value}`, attributes ?? {});\n }\n\n async flush(): Promise<void> {\n // Console output is synchronous — nothing to flush\n }\n}\n","// =============================================================================\n// OtelTelemetryAdapter — Wraps @opentelemetry/api tracer and meter (peer dep)\n// =============================================================================\n\nimport type { TelemetryPort, TelemetrySpan } from \"../../ports/telemetry.port.js\";\n\n/**\n * Adapter that delegates to an OpenTelemetry Tracer and optional Meter.\n * Accepts pre-configured instances via DI — does NOT configure OTel itself.\n *\n * Usage:\n * ```ts\n * import { trace, metrics } from \"@opentelemetry/api\";\n * const adapter = new OtelTelemetryAdapter(\n * trace.getTracer(\"my-agent\"),\n * metrics.getMeter(\"my-agent\"),\n * );\n * ```\n */\nexport class OtelTelemetryAdapter implements TelemetryPort {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n private readonly histograms = new Map<string, any>();\n\n // Using `any` to avoid hard dependency on @opentelemetry/api types\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n constructor(private readonly tracer: any, private readonly meter?: any) {}\n\n startSpan(name: string, attributes?: Record<string, string | number | boolean>): TelemetrySpan {\n const otelSpan = this.tracer.startSpan(name, attributes ? { attributes } : undefined);\n return new OtelSpanWrapper(otelSpan);\n }\n\n recordMetric(name: string, value: number, attributes?: Record<string, string>): void {\n if (!this.meter) return;\n let histogram = this.histograms.get(name);\n if (!histogram) {\n histogram = this.meter.createHistogram(name);\n this.histograms.set(name, histogram);\n }\n histogram.record(value, attributes);\n }\n\n async flush(): Promise<void> {\n // Flushing is handled by the OTel SDK's configured exporter — not our responsibility\n }\n}\n\nclass OtelSpanWrapper implements TelemetrySpan {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n constructor(private readonly span: any) {}\n\n setAttribute(key: string, value: string | number | boolean): void {\n this.span.setAttribute(key, value);\n }\n\n setStatus(code: \"OK\" | \"ERROR\", message?: string): void {\n // OTel SpanStatusCode: 0=UNSET, 1=OK, 2=ERROR\n const otelCode = code === \"OK\" ? 1 : 2;\n this.span.setStatus({ code: otelCode, message });\n }\n\n end(): void {\n this.span.end();\n }\n}\n","// =============================================================================\n// ConsoleLoggingAdapter — Console-based implementation of LoggingPort\n// =============================================================================\n\nimport type { LoggingPort, LogLevel, LogEntry } from \"../../ports/logging.port.js\";\n\nexport class ConsoleLoggingAdapter implements LoggingPort {\n private readonly entries: LogEntry[] = [];\n\n log(level: LogLevel, message: string, context?: Record<string, unknown>): void {\n const entry: LogEntry = { level, message, timestamp: Date.now(), context };\n this.entries.push(entry);\n console[level](message, ...(context ? [context] : []));\n }\n\n debug(message: string, context?: Record<string, unknown>): void {\n this.log(\"debug\", message, context);\n }\n\n info(message: string, context?: Record<string, unknown>): void {\n this.log(\"info\", message, context);\n }\n\n warn(message: string, context?: Record<string, unknown>): void {\n this.log(\"warn\", message, context);\n }\n\n error(message: string, context?: Record<string, unknown>): void {\n this.log(\"error\", message, context);\n }\n\n /** Get all recorded log entries */\n getEntries(): readonly LogEntry[] {\n return this.entries;\n }\n\n /** Clear all recorded entries */\n clear(): void {\n this.entries.length = 0;\n }\n}\n","// =============================================================================\n// InMemoryTracingAdapter — In-memory implementation of TracingPort for testing\n// =============================================================================\n\nimport type { TracingPort, Span } from \"../../ports/tracing.port.js\";\n\nclass InMemorySpan implements Span {\n readonly traceId: string;\n readonly spanId: string;\n readonly name: string;\n readonly attributes = new Map<string, string | number | boolean>();\n status: \"ok\" | \"error\" | \"unset\" = \"unset\";\n statusMessage?: string;\n ended = false;\n\n constructor(name: string, traceId: string, spanId: string) {\n this.name = name;\n this.traceId = traceId;\n this.spanId = spanId;\n }\n\n setAttribute(key: string, value: string | number | boolean): void {\n this.attributes.set(key, value);\n }\n\n setStatus(status: \"ok\" | \"error\", message?: string): void {\n this.status = status;\n this.statusMessage = message;\n }\n\n end(): void {\n this.ended = true;\n }\n}\n\nexport class InMemoryTracingAdapter implements TracingPort {\n private readonly spans: InMemorySpan[] = [];\n private counter = 0;\n\n startSpan(name: string, parentSpan?: Span): InMemorySpan {\n const traceId = parentSpan?.traceId ?? `trace-${++this.counter}`;\n const spanId = `span-${++this.counter}`;\n const span = new InMemorySpan(name, traceId, spanId);\n this.spans.push(span);\n return span;\n }\n\n /** Get all recorded spans */\n getSpans(): readonly InMemorySpan[] {\n return this.spans;\n }\n\n /** Clear all recorded spans */\n clear(): void {\n this.spans.length = 0;\n }\n}\n","// =============================================================================\n// InMemoryMetricsAdapter — In-memory implementation of MetricsPort for testing\n// =============================================================================\n\nimport type { MetricsPort } from \"../../ports/metrics.port.js\";\n\nfunction labelKey(name: string, labels?: Record<string, string>): string {\n if (!labels || Object.keys(labels).length === 0) return name;\n const sorted = Object.entries(labels).sort(([a], [b]) => a.localeCompare(b));\n return `${name}{${sorted.map(([k, v]) => `${k}=\"${v}\"`).join(\",\")}}`;\n}\n\nexport class InMemoryMetricsAdapter implements MetricsPort {\n private readonly counters = new Map<string, number>();\n private readonly histograms = new Map<string, number[]>();\n private readonly gauges = new Map<string, number>();\n\n incrementCounter(name: string, value = 1, labels?: Record<string, string>): void {\n const key = labelKey(name, labels);\n this.counters.set(key, (this.counters.get(key) ?? 0) + value);\n }\n\n recordHistogram(name: string, value: number, labels?: Record<string, string>): void {\n const key = labelKey(name, labels);\n const arr = this.histograms.get(key) ?? [];\n arr.push(value);\n this.histograms.set(key, arr);\n }\n\n recordGauge(name: string, value: number, labels?: Record<string, string>): void {\n const key = labelKey(name, labels);\n this.gauges.set(key, value);\n }\n\n /** Get current counter value */\n getCounter(name: string, labels?: Record<string, string>): number {\n return this.counters.get(labelKey(name, labels)) ?? 0;\n }\n\n /** Get histogram values */\n getHistogram(name: string, labels?: Record<string, string>): readonly number[] {\n return this.histograms.get(labelKey(name, labels)) ?? [];\n }\n\n /** Get current gauge value */\n getGauge(name: string, labels?: Record<string, string>): number | undefined {\n return this.gauges.get(labelKey(name, labels));\n }\n\n /** Clear all metrics */\n clear(): void {\n this.counters.clear();\n this.histograms.clear();\n this.gauges.clear();\n }\n}\n","// =============================================================================\n// PrometheusMetricsAdapter — Prometheus-format metrics exporter\n// =============================================================================\n\nimport type { MetricsPort } from \"../../ports/metrics.port.js\";\n\ninterface MetricEntry {\n type: \"counter\" | \"gauge\" | \"histogram\";\n value: number;\n labels: Record<string, string>;\n updatedAt: number;\n}\n\ninterface HistogramBucket {\n le: number;\n count: number;\n}\n\nconst DEFAULT_BUCKETS = [0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1, 2.5, 5, 10];\n\nexport class PrometheusMetricsAdapter implements MetricsPort {\n private readonly counters = new Map<string, MetricEntry[]>();\n private readonly gauges = new Map<string, MetricEntry[]>();\n private readonly histograms = new Map<string, { sum: number; count: number; buckets: HistogramBucket[]; labels: Record<string, string> }[]>();\n private readonly buckets: number[];\n\n constructor(options?: { buckets?: number[] }) {\n this.buckets = options?.buckets ?? DEFAULT_BUCKETS;\n }\n\n incrementCounter(name: string, value = 1, labels: Record<string, string> = {}): void {\n const entries = this.counters.get(name) ?? [];\n const existing = entries.find((e) => labelsMatch(e.labels, labels));\n if (existing) {\n existing.value += value;\n existing.updatedAt = Date.now();\n } else {\n entries.push({ type: \"counter\", value, labels, updatedAt: Date.now() });\n this.counters.set(name, entries);\n }\n }\n\n recordGauge(name: string, value: number, labels: Record<string, string> = {}): void {\n const entries = this.gauges.get(name) ?? [];\n const existing = entries.find((e) => labelsMatch(e.labels, labels));\n if (existing) {\n existing.value = value;\n existing.updatedAt = Date.now();\n } else {\n entries.push({ type: \"gauge\", value, labels, updatedAt: Date.now() });\n this.gauges.set(name, entries);\n }\n }\n\n recordHistogram(name: string, value: number, labels: Record<string, string> = {}): void {\n const entries = this.histograms.get(name) ?? [];\n let existing = entries.find((e) => labelsMatch(e.labels, labels));\n if (!existing) {\n existing = {\n sum: 0,\n count: 0,\n buckets: this.buckets.map((le) => ({ le, count: 0 })),\n labels,\n };\n entries.push(existing);\n this.histograms.set(name, entries);\n }\n existing.sum += value;\n existing.count++;\n for (const bucket of existing.buckets) {\n if (value <= bucket.le) bucket.count++;\n }\n }\n\n /** Serialize all metrics to Prometheus exposition format */\n serialize(): string {\n const lines: string[] = [];\n\n for (const [name, entries] of this.counters) {\n lines.push(`# TYPE ${name} counter`);\n for (const e of entries) {\n lines.push(`${name}${formatLabels(e.labels)} ${e.value}`);\n }\n }\n\n for (const [name, entries] of this.gauges) {\n lines.push(`# TYPE ${name} gauge`);\n for (const e of entries) {\n lines.push(`${name}${formatLabels(e.labels)} ${e.value}`);\n }\n }\n\n for (const [name, entries] of this.histograms) {\n lines.push(`# TYPE ${name} histogram`);\n for (const e of entries) {\n for (const b of e.buckets) {\n lines.push(`${name}_bucket${formatLabels({ ...e.labels, le: String(b.le) })} ${b.count}`);\n }\n lines.push(`${name}_bucket${formatLabels({ ...e.labels, le: \"+Inf\" })} ${e.count}`);\n lines.push(`${name}_sum${formatLabels(e.labels)} ${e.sum}`);\n lines.push(`${name}_count${formatLabels(e.labels)} ${e.count}`);\n }\n }\n\n return lines.join(\"\\n\");\n }\n\n /** Reset all metrics */\n reset(): void {\n this.counters.clear();\n this.gauges.clear();\n this.histograms.clear();\n }\n}\n\nfunction labelsMatch(a: Record<string, string>, b: Record<string, string>): boolean {\n const aKeys = Object.keys(a);\n const bKeys = Object.keys(b);\n if (aKeys.length !== bKeys.length) return false;\n return aKeys.every((k) => a[k] === b[k]);\n}\n\nfunction formatLabels(labels: Record<string, string>): string {\n const entries = Object.entries(labels);\n if (entries.length === 0) return \"\";\n return `{${entries.map(([k, v]) => `${k}=\"${v}\"`).join(\",\")}}`;\n}\n","// =============================================================================\n// DefaultCostTrackerAdapter — In-memory cost tracking with model pricing\n// =============================================================================\n\nimport type { CostTrackerPort, CostTokenUsage, CostEstimate } from \"../../ports/cost-tracker.port.js\";\n\n// Pricing per 1M tokens: [input, output]\nconst MODEL_PRICING: Record<string, [number, number]> = {\n // OpenAI\n \"gpt-5.2\": [2.50, 10.00],\n \"gpt-5.2-mini\": [0.15, 0.60],\n \"gpt-4-turbo\": [10.00, 30.00],\n // Anthropic\n \"claude-sonnet-4-20250514\": [3.00, 15.00],\n \"claude-3-haiku\": [0.25, 1.25],\n \"claude-opus-4-20250514\": [15.00, 75.00],\n // Google\n \"gemini-2.5-flash-preview-05-20\": [0.10, 0.40],\n \"gemini-1.5-pro\": [1.25, 5.00],\n // Groq\n \"llama-3.1-70b\": [0.59, 0.79],\n // Mistral\n \"mistral-large\": [2.00, 6.00],\n};\n\nexport interface CostTrackerOptions {\n budget?: number;\n onBudgetExceeded?: () => void;\n /** When true, suppresses console.warn for unknown models (useful for replaying records). */\n silent?: boolean;\n}\n\nexport class DefaultCostTrackerAdapter implements CostTrackerPort {\n private readonly usages: CostTokenUsage[] = [];\n private readonly budget: number | null;\n private readonly onBudgetExceeded?: () => void;\n private readonly silent: boolean;\n private budgetExceededFired = false;\n private totalCost = 0;\n\n /** Models seen that have no pricing data. */\n readonly unpricedModels = new Set<string>();\n\n constructor(options: CostTrackerOptions = {}) {\n this.budget = options.budget ?? null;\n this.onBudgetExceeded = options.onBudgetExceeded;\n this.silent = options.silent ?? false;\n }\n\n recordUsage(usage: CostTokenUsage): void {\n // Validate: clamp non-finite / negative token counts to 0\n const inputTokens = Number.isFinite(usage.inputTokens) && usage.inputTokens > 0 ? usage.inputTokens : 0;\n const outputTokens = Number.isFinite(usage.outputTokens) && usage.outputTokens > 0 ? usage.outputTokens : 0;\n const sanitized: CostTokenUsage = { ...usage, inputTokens, outputTokens };\n\n this.usages.push(sanitized);\n\n // Warn and track unpriced models\n if (!MODEL_PRICING[sanitized.model]) {\n if (!this.unpricedModels.has(sanitized.model)) {\n if (!this.silent) {\n console.warn(`[CostTracker] Unknown model \"${sanitized.model}\" — cost will be recorded as $0`);\n }\n this.unpricedModels.add(sanitized.model);\n }\n }\n\n // Maintain running total for O(1) budget check\n this.totalCost += this.calculateCost(sanitized.model, inputTokens, outputTokens);\n\n if (this.onBudgetExceeded && !this.budgetExceededFired && this.isOverBudget()) {\n this.budgetExceededFired = true;\n this.onBudgetExceeded();\n }\n }\n\n getEstimate(): CostEstimate {\n const byModel = new Map<string, { inputTokens: number; outputTokens: number }>();\n\n for (const u of this.usages) {\n const existing = byModel.get(u.model) ?? { inputTokens: 0, outputTokens: 0 };\n existing.inputTokens += u.inputTokens;\n existing.outputTokens += u.outputTokens;\n byModel.set(u.model, existing);\n }\n\n let totalInputTokens = 0;\n let totalOutputTokens = 0;\n const breakdown: CostEstimate[\"breakdown\"] = [];\n\n for (const [model, tokens] of byModel) {\n const cost = this.calculateCost(model, tokens.inputTokens, tokens.outputTokens);\n totalInputTokens += tokens.inputTokens;\n totalOutputTokens += tokens.outputTokens;\n breakdown.push({ model, inputTokens: tokens.inputTokens, outputTokens: tokens.outputTokens, cost });\n }\n\n const totalCost = breakdown.reduce((sum, b) => sum + b.cost, 0);\n return { totalInputTokens, totalOutputTokens, totalCost, currency: \"USD\", breakdown };\n }\n\n getSessionBudget(): number | null {\n return this.budget;\n }\n\n isOverBudget(): boolean {\n if (this.budget === null) return false;\n return this.totalCost > this.budget;\n }\n\n reset(): void {\n this.usages.length = 0;\n this.totalCost = 0;\n this.unpricedModels.clear();\n this.budgetExceededFired = false;\n }\n\n exportUsage(): string {\n return JSON.stringify(this.usages);\n }\n\n private calculateCost(model: string, inputTokens: number, outputTokens: number): number {\n const pricing = MODEL_PRICING[model];\n if (!pricing) return 0;\n const [inputPer1M, outputPer1M] = pricing;\n return (inputTokens / 1_000_000) * inputPer1M + (outputTokens / 1_000_000) * outputPer1M;\n }\n}\n","// =============================================================================\n// DefaultToolCompositionAdapter — pipe, fallback, and middleware for AI SDK tools\n// =============================================================================\n\nimport { tool } from \"../../core/llm/index.js\";\nimport type { Tool } from \"../../core/llm/index.js\";\nimport { z } from \"zod\";\n\nimport type {\n ToolCompositionPort,\n ToolMiddleware,\n ToolPipeline,\n} from \"../../ports/tool-composition.port.js\";\n\n// ---------------------------------------------------------------------------\n// Pipeline implementation\n// ---------------------------------------------------------------------------\n\ninterface PipeEntry {\n names: string[];\n}\n\ninterface FallbackEntry {\n primary: string;\n fallback: string;\n}\n\nclass DefaultToolPipeline implements ToolPipeline {\n private readonly tools: Record<string, Tool<any, any>>;\n private readonly pipes: PipeEntry[] = [];\n private readonly fallbacks: FallbackEntry[] = [];\n private readonly middlewares: ToolMiddleware[] = [];\n\n constructor(\n tools: Record<string, Tool<any, any>>,\n pipes: PipeEntry[] = [],\n fallbacks: FallbackEntry[] = [],\n middlewares: ToolMiddleware[] = [],\n ) {\n this.tools = { ...tools };\n this.pipes = [...pipes];\n this.fallbacks = [...fallbacks];\n this.middlewares = [...middlewares];\n }\n\n pipe(names: string[]): ToolPipeline {\n return new DefaultToolPipeline(\n this.tools,\n [...this.pipes, { names }],\n this.fallbacks,\n this.middlewares,\n );\n }\n\n withFallback(primary: string, fallback: string): ToolPipeline {\n return new DefaultToolPipeline(\n this.tools,\n this.pipes,\n [...this.fallbacks, { primary, fallback }],\n this.middlewares,\n );\n }\n\n withMiddleware(middleware: ToolMiddleware): ToolPipeline {\n return new DefaultToolPipeline(\n this.tools,\n this.pipes,\n this.fallbacks,\n [...this.middlewares, middleware],\n );\n }\n\n build(): Record<string, Tool<any, any>> {\n const result: Record<string, Tool<any, any>> = { ...this.tools };\n\n // Apply fallbacks — wrap primary tool to fall back on error\n for (const { primary, fallback } of this.fallbacks) {\n const primaryTool = result[primary];\n const fallbackTool = result[fallback];\n if (!primaryTool) throw new Error(`Fallback composition failed: primary tool \"${primary}\" not found`);\n if (!fallbackTool) throw new Error(`Fallback composition failed: fallback tool \"${fallback}\" not found`);\n\n result[primary] = this.wrapWithFallback(primary, primaryTool, fallbackTool);\n }\n\n // Apply pipes — create composite tools\n for (const { names } of this.pipes) {\n if (names.length < 2) continue;\n\n const pipelineName = names.join(\"_pipe_\");\n const firstTool = result[names[0]];\n if (!firstTool) throw new Error(`Pipe composition failed: first tool \"${names[0]}\" not found`);\n\n result[pipelineName] = this.buildPipeTool(pipelineName, names, result);\n }\n\n // Apply middlewares — wrap every tool\n if (this.middlewares.length > 0) {\n for (const name of Object.keys(result)) {\n result[name] = this.wrapWithMiddlewares(name, result[name]);\n }\n }\n\n return result;\n }\n\n // ---- internal helpers ---------------------------------------------------\n\n private wrapWithFallback(name: string, primary: Tool, fallbackTool: Tool): Tool {\n const originalExecute = primary.execute;\n const fallbackExecute = fallbackTool.execute;\n\n return tool({\n description: primary.description ?? \"\",\n inputSchema: (primary as any).inputSchema ?? z.object({}).passthrough(),\n execute: async (args: any) => {\n try {\n return await originalExecute!(args, { toolCallId: \"\", messages: [], abortSignal: undefined as any });\n } catch {\n return await fallbackExecute!(args, { toolCallId: \"\", messages: [], abortSignal: undefined as any });\n }\n },\n }) as unknown as Tool;\n }\n\n private buildPipeTool(\n pipelineName: string,\n names: string[],\n allTools: Record<string, Tool<any, any>>,\n ): Tool {\n const firstTool = allTools[names[0]];\n const descriptions = names\n .map((n) => allTools[n]?.description ?? n)\n .join(\" → \");\n\n // Snapshot execute functions at build time so middleware wrapping\n // does not affect inner tool calls — middleware fires only on the pipe.\n const steps = names.map((toolName) => {\n const t = allTools[toolName];\n if (!t?.execute) {\n throw new Error(`Tool \"${toolName}\" not found or has no execute function`);\n }\n return t.execute!;\n });\n\n return tool({\n description: `Pipeline: ${descriptions}`,\n inputSchema: (firstTool as any).inputSchema ?? z.object({}).passthrough(),\n execute: async (args: any) => {\n let current: unknown = args;\n for (const execFn of steps) {\n current = await execFn(current as any, {\n toolCallId: \"\",\n messages: [],\n abortSignal: undefined as any,\n });\n }\n return current;\n },\n }) as unknown as Tool;\n }\n\n private wrapWithMiddlewares(name: string, t: Tool): Tool {\n const originalExecute = t.execute;\n const middlewares = this.middlewares;\n\n return tool({\n description: t.description ?? \"\",\n inputSchema: (t as any).inputSchema ?? z.object({}).passthrough(),\n execute: async (args: any) => {\n let currentArgs: unknown = args;\n\n // Run before hooks\n for (const mw of middlewares) {\n if (mw.before) {\n currentArgs = await mw.before(name, currentArgs);\n }\n }\n\n let result: unknown;\n try {\n result = await originalExecute!(currentArgs as any, {\n toolCallId: \"\",\n messages: [],\n abortSignal: undefined as any,\n });\n } catch (err) {\n // Run onError hooks (last middleware first for error handling)\n for (let i = middlewares.length - 1; i >= 0; i--) {\n const mw = middlewares[i];\n if (mw.onError) {\n const fallback = await mw.onError(name, err as Error);\n if (fallback != null) return fallback;\n }\n }\n throw err;\n }\n\n // Run after hooks\n for (const mw of middlewares) {\n if (mw.after) {\n result = await mw.after(name, result);\n }\n }\n\n return result;\n },\n }) as unknown as Tool;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Adapter (port implementation)\n// ---------------------------------------------------------------------------\n\nexport class DefaultToolCompositionAdapter implements ToolCompositionPort {\n createPipeline(tools: Record<string, Tool<any, any>>): ToolPipeline {\n return new DefaultToolPipeline(tools);\n }\n}\n","// =============================================================================\n// Runtime Detection — Lazy capability detection for multi-runtime support\n// =============================================================================\n\nexport type RuntimeId = \"node\" | \"deno\" | \"bun\" | \"cloudflare-workers\" | \"browser\" | \"unknown\";\n\nexport interface RuntimeCapabilities {\n runtime: RuntimeId;\n hasNativeFs: boolean;\n hasIndexedDB: boolean;\n hasOPFS: boolean;\n hasDenoKv: boolean;\n hasFetch: boolean;\n hasWebCrypto: boolean;\n}\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nconst g = globalThis as any;\n\nlet cachedRuntime: RuntimeId | undefined;\nlet cachedCapabilities: RuntimeCapabilities | undefined;\n\n/** Detect the current runtime environment (result is cached after first call) */\nexport function detectRuntime(): RuntimeId {\n if (cachedRuntime !== undefined) return cachedRuntime;\n\n if (typeof g.Deno !== \"undefined\") cachedRuntime = \"deno\";\n else if (typeof g.Bun !== \"undefined\") cachedRuntime = \"bun\";\n else if (typeof g.caches !== \"undefined\" && typeof g.process === \"undefined\" && typeof g.window === \"undefined\") cachedRuntime = \"cloudflare-workers\";\n else if (typeof g.process !== \"undefined\" && typeof g.process.versions?.node === \"string\") cachedRuntime = \"node\";\n else if (typeof g.window !== \"undefined\" && typeof g.document !== \"undefined\") cachedRuntime = \"browser\";\n else cachedRuntime = \"unknown\";\n\n return cachedRuntime;\n}\n\n/** Detect available capabilities (result is cached after first call) */\nexport function detectCapabilities(): RuntimeCapabilities {\n if (cachedCapabilities !== undefined) return cachedCapabilities;\n\n const runtime = detectRuntime();\n cachedCapabilities = {\n runtime,\n hasNativeFs: runtime === \"node\" || runtime === \"bun\" || runtime === \"deno\",\n hasIndexedDB: typeof g.indexedDB !== \"undefined\",\n hasOPFS: typeof g.navigator?.storage?.getDirectory === \"function\",\n hasDenoKv: runtime === \"deno\" && typeof g.Deno?.openKv === \"function\",\n hasFetch: typeof globalThis.fetch === \"function\",\n hasWebCrypto: typeof globalThis.crypto?.randomUUID === \"function\",\n };\n\n return cachedCapabilities;\n}\n","// =============================================================================\n// Compiler Schema — Intermediate Representation for workflow compilation\n// =============================================================================\n// The StructuredDeclaration is the IR between natural language input and\n// compiled WorkflowDefinition + Skills + AgentConfigs + A2A routes.\n// =============================================================================\n\nimport { z } from \"zod\";\n\n// -----------------------------------------------------------------------------\n// Trigger: when the workflow should execute\n// -----------------------------------------------------------------------------\n\nexport const CronTriggerSchema = z.object({\n type: z.literal(\"cron\"),\n expression: z.string().describe(\"Cron expression or human-readable frequency (e.g. 'every 2h', '0 */2 * * *')\"),\n timezone: z.string().optional().describe(\"IANA timezone (e.g. 'Europe/Rome')\"),\n});\n\nexport const EventTriggerSchema = z.object({\n type: z.literal(\"event\"),\n event: z.string().describe(\"Event name that triggers this workflow (e.g. 'source:new-content')\"),\n filter: z.record(z.string(), z.unknown()).optional().describe(\"Optional filter conditions on event payload\"),\n});\n\nexport const ManualTriggerSchema = z.object({\n type: z.literal(\"manual\"),\n});\n\nexport const WebhookTriggerSchema = z.object({\n type: z.literal(\"webhook\"),\n path: z.string().optional().describe(\"Webhook endpoint path\"),\n});\n\nexport const TriggerSchema = z.discriminatedUnion(\"type\", [\n CronTriggerSchema,\n EventTriggerSchema,\n ManualTriggerSchema,\n WebhookTriggerSchema,\n]);\n\n// -----------------------------------------------------------------------------\n// Channel: target platforms for publishing\n// -----------------------------------------------------------------------------\n\nexport const ChannelSchema = z.object({\n platform: z.string().describe(\"Platform identifier (e.g. 'linkedin', 'x', 'instagram', 'facebook', 'whatsapp')\"),\n tone: z.string().optional().describe(\"Content tone for this channel (e.g. 'professional', 'casual', 'formal')\"),\n maxLength: z.number().optional().describe(\"Max content length for this channel\"),\n format: z.string().optional().describe(\"Output format (e.g. 'article', 'thread', 'caption', 'story')\"),\n});\n\n// -----------------------------------------------------------------------------\n// Policy: automation level per channel\n// -----------------------------------------------------------------------------\n\nexport const ChannelPolicySchema = z.object({\n platform: z.string(),\n mode: z.enum([\"auto\", \"review\", \"notify\"]).describe(\"auto=YOLO publish, review=human approval, notify=alert only\"),\n});\n\nexport const PolicySchema = z.object({\n default: z.enum([\"auto\", \"review\", \"notify\"]).default(\"review\"),\n channels: z.array(ChannelPolicySchema).optional().describe(\"Per-channel policy overrides\"),\n yolo: z.boolean().default(false).describe(\"Global YOLO mode: skip all reviews\"),\n});\n\n// -----------------------------------------------------------------------------\n// Step declarations: what the workflow does\n// -----------------------------------------------------------------------------\n\nexport const MonitorStepSchema = z.object({\n type: z.literal(\"monitor\"),\n id: z.string().optional(),\n source: z.string().describe(\"URL or source identifier to monitor\"),\n description: z.string().describe(\"What to look for (NL description for AI extraction)\"),\n strategy: z.enum([\"rss\", \"adaptive\", \"fixed\"]).default(\"adaptive\"),\n frequency: z.string().optional().describe(\"Polling frequency (e.g. 'every 2h', 'every 15m')\"),\n});\n\nexport const FilterStepSchema = z.object({\n type: z.literal(\"filter\"),\n id: z.string().optional(),\n criteria: z.string().describe(\"NL filter criteria (e.g. 'only AI-related articles')\"),\n minRelevance: z.number().min(0).max(1).optional().describe(\"Minimum relevance score (0-1)\"),\n});\n\nexport const TransformStepSchema = z.object({\n type: z.literal(\"transform\"),\n id: z.string().optional(),\n action: z.string().describe(\"NL transformation (e.g. 'rewrite in professional tone', 'summarize in 3 sentences')\"),\n targetChannel: z.string().optional().describe(\"Target channel for this transformation\"),\n});\n\nexport const PublishStepSchema = z.object({\n type: z.literal(\"publish\"),\n id: z.string().optional(),\n channels: z.array(z.string()).min(1).describe(\"Target channels for publishing\"),\n});\n\nexport const CustomStepSchema = z.object({\n type: z.literal(\"custom\"),\n id: z.string().optional(),\n description: z.string().describe(\"NL description of what this step does\"),\n agentPrompt: z.string().optional().describe(\"Optional specific prompt for the agent executing this step\"),\n});\n\nexport const StepDeclarationSchema = z.discriminatedUnion(\"type\", [\n MonitorStepSchema,\n FilterStepSchema,\n TransformStepSchema,\n PublishStepSchema,\n CustomStepSchema,\n]);\n\n// -----------------------------------------------------------------------------\n// StructuredDeclaration: the full IR\n// -----------------------------------------------------------------------------\n\nexport const StructuredDeclarationSchema = z.object({\n id: z.string().optional().describe(\"Optional workflow ID (auto-generated if not provided)\"),\n name: z.string().describe(\"Human-readable workflow name\"),\n description: z.string().optional().describe(\"Optional longer description\"),\n triggers: z.array(TriggerSchema).min(1).describe(\"When this workflow should execute\"),\n steps: z.array(StepDeclarationSchema).min(1).describe(\"Ordered steps of the workflow\"),\n channels: z.array(ChannelSchema).optional().describe(\"Target channels configuration\"),\n policy: PolicySchema.optional().describe(\"Automation policy (auto/review/notify per channel)\"),\n tags: z.array(z.string()).optional().describe(\"Optional tags for categorization\"),\n maxDurationMs: z.number().optional().describe(\"Maximum workflow execution time\"),\n});\n\n// -----------------------------------------------------------------------------\n// Inferred types\n// -----------------------------------------------------------------------------\n\nexport type CronTrigger = z.infer<typeof CronTriggerSchema>;\nexport type EventTrigger = z.infer<typeof EventTriggerSchema>;\nexport type ManualTrigger = z.infer<typeof ManualTriggerSchema>;\nexport type WebhookTrigger = z.infer<typeof WebhookTriggerSchema>;\nexport type Trigger = z.infer<typeof TriggerSchema>;\n\nexport type Channel = z.infer<typeof ChannelSchema>;\nexport type ChannelPolicy = z.infer<typeof ChannelPolicySchema>;\nexport type Policy = z.infer<typeof PolicySchema>;\n\nexport type MonitorStep = z.infer<typeof MonitorStepSchema>;\nexport type FilterStep = z.infer<typeof FilterStepSchema>;\nexport type TransformStep = z.infer<typeof TransformStepSchema>;\nexport type PublishStep = z.infer<typeof PublishStepSchema>;\nexport type CustomStep = z.infer<typeof CustomStepSchema>;\nexport type StepDeclaration = z.infer<typeof StepDeclarationSchema>;\n\nexport type StructuredDeclaration = z.infer<typeof StructuredDeclarationSchema>;\n\n// -----------------------------------------------------------------------------\n// Compiler output Zod schemas (for LLM-assisted structured generation)\n// -----------------------------------------------------------------------------\n\nexport const SkillDeclarationSchema = z.object({\n id: z.string().describe(\"Unique skill ID (e.g. 'monitor-techcrunch', 'publish-linkedin')\"),\n platform: z.string().describe(\"Target platform (e.g. 'linkedin', 'x', 'web', 'internal')\"),\n description: z.string().describe(\"What this skill does in one sentence\"),\n preconditions: z.string().describe(\"What must be true before this skill can run\"),\n flow: z.array(z.string()).describe(\"Ordered list of actions this skill performs\"),\n notes: z.array(z.string()).describe(\"Implementation notes and edge cases\"),\n maxContentLength: z.number().optional().describe(\"Max output content length (platform-specific)\"),\n isExisting: z.boolean().describe(\"True if this skill already exists in the registry\"),\n});\n\nexport const AgentDeclarationSchema = z.object({\n id: z.string().describe(\"Unique agent ID (e.g. 'monitor-agent', 'content-agent')\"),\n role: z.string().describe(\"Agent role description (e.g. 'Monitors web sources for new content')\"),\n skills: z.array(z.string()).describe(\"Skill IDs this agent can use\"),\n trigger: TriggerSchema.optional().describe(\"Optional trigger that activates this agent\"),\n});\n\nexport const A2ARouteSchema = z.object({\n from: z.string().describe(\"Source agent ID\"),\n to: z.string().describe(\"Destination agent ID\"),\n event: z.string().describe(\"Event name that triggers this route (e.g. 'content:detected', 'content:ready')\"),\n condition: z.string().optional().describe(\"Optional NL condition for routing (e.g. 'only if relevance > 0.7')\"),\n});\n\nexport const CompilerOutputSchema = z.object({\n skills: z.array(SkillDeclarationSchema).describe(\"All skills needed by this workflow\"),\n agents: z.array(AgentDeclarationSchema).describe(\"Agents grouped by role (monitor, filter, content, publisher)\"),\n routes: z.array(A2ARouteSchema).describe(\"A2A communication routes between agents\"),\n});\n\n// Inferred types from Zod schemas\nexport type SkillDeclaration = z.infer<typeof SkillDeclarationSchema>;\nexport type AgentDeclaration = z.infer<typeof AgentDeclarationSchema>;\nexport type A2ARoute = z.infer<typeof A2ARouteSchema>;\n\n/** LLM-generated portion of the compiler output */\nexport type LLMCompilerOutput = z.infer<typeof CompilerOutputSchema>;\n\n/** Full compiler output including workflow metadata */\nexport interface CompilerOutput extends LLMCompilerOutput {\n workflow: {\n id: string;\n name: string;\n declaration: StructuredDeclaration;\n };\n}\n\n// -----------------------------------------------------------------------------\n// Validation helpers\n// -----------------------------------------------------------------------------\n\nexport function validateDeclaration(input: unknown): { valid: true; data: StructuredDeclaration } | { valid: false; errors: string[] } {\n const result = StructuredDeclarationSchema.safeParse(input);\n if (result.success) {\n return { valid: true, data: result.data };\n }\n return {\n valid: false,\n errors: result.error.issues.map((i) => `${i.path.join(\".\")}: ${i.message}`),\n };\n}\n","// =============================================================================\n// LLM NL Parser — Parses natural language into StructuredDeclaration via LLM\n// Uses Gauss Agent + AI SDK Output.object for structured generation.\n// =============================================================================\n\nimport { Output } from \"../../core/llm/index.js\";\nimport type { LanguageModel } from \"../../core/llm/index.js\";\nimport { StructuredDeclarationSchema, type StructuredDeclaration } from \"../../domain/compiler.schema.js\";\nimport type { NLParserPort } from \"../../ports/compiler.port.js\";\nimport { Agent } from \"../../agent/agent.js\";\n\nconst SYSTEM_PROMPT = `You are a workflow declaration parser. Your job is to convert natural language workflow descriptions into structured declarations.\n\nGiven a natural language description of a workflow, extract:\n\n1. **name**: A short, descriptive name for the workflow\n2. **triggers**: When should it run? (cron schedule, event-based, manual, webhook)\n - For time-based: use cron type with human-readable expression (e.g. \"every 2h\", \"daily at 9am\")\n - For event-based: use event type with event name\n - For on-demand: use manual type\n3. **steps**: The ordered actions (monitor, filter, transform, publish, custom)\n - monitor: visiting a URL to check for new content (include source URL and what to look for)\n - filter: filtering content by criteria (topic, relevance, keywords)\n - transform: adapting content (rewrite tone, summarize, translate, format for platform)\n - publish: publishing to specific channels\n - custom: anything else\n4. **channels**: Target platforms with their specific settings (tone, max length, format)\n5. **policy**: Automation level — which channels are auto-publish, which need review\n\nRules:\n- Extract ALL implicit information (e.g. \"post to X\" implies a publish step with channel \"x\")\n- If a channel has a specific tone mentioned, set it in the channels array\n- Default policy is \"review\" unless explicitly stated otherwise (e.g. \"auto-publish\", \"automatically\")\n- Generate meaningful step IDs based on what they do\n- If frequency is mentioned, create a cron trigger\n- Infer platform-specific constraints (X = 280 chars, Instagram = requires image)`;\n\nexport class LLMNLParser implements NLParserPort {\n constructor(private readonly model: LanguageModel) {}\n\n async parse(naturalLanguage: string): Promise<StructuredDeclaration> {\n const agent = Agent.create({\n model: this.model,\n instructions: SYSTEM_PROMPT,\n maxSteps: 1,\n })\n .withOutput(Output.object({ schema: StructuredDeclarationSchema }))\n .build();\n\n const result = await agent.run(naturalLanguage);\n\n if (!result.output) {\n throw new Error(\"NL Parser: LLM did not produce structured output\");\n }\n\n return result.output as StructuredDeclaration;\n }\n}\n","// =============================================================================\n// LLM Compiler Engine — Compiles StructuredDeclaration into executable artifacts\n// Uses Gauss Agent + AI SDK Output.object for LLM-assisted compilation\n// with Zod schema enforcement for deterministic structure.\n// =============================================================================\n\nimport { Output } from \"../../core/llm/index.js\";\nimport type { LanguageModel } from \"../../core/llm/index.js\";\nimport {\n CompilerOutputSchema,\n type StructuredDeclaration,\n type CompilerOutput,\n type LLMCompilerOutput,\n} from \"../../domain/compiler.schema.js\";\nimport type { WorkflowCompilerPort, SkillRegistryPort } from \"../../ports/compiler.port.js\";\nimport { Agent } from \"../../agent/agent.js\";\n\n// -----------------------------------------------------------------------------\n// Compiler system prompt\n// -----------------------------------------------------------------------------\n\nfunction buildCompilerPrompt(existingSkills: string[]): string {\n const skillsList = existingSkills.length > 0\n ? `\\n\\nExisting skills in the registry (reuse these when possible, set isExisting=true):\\n${existingSkills.map((s) => `- ${s}`).join(\"\\n\")}`\n : \"\";\n\n return `You are a workflow compiler. Given a StructuredDeclaration (workflow IR), generate the skills, agents, and A2A routes needed to execute it.\n\n## Agent Grouping Strategy: Role-Based\nGroup steps into agents by their logical role:\n- **monitor-agent**: All monitor steps → detects new content from sources\n- **filter-agent**: All filter steps → evaluates relevance and applies criteria\n- **content-agent**: All transform steps → rewrites/adapts content for channels\n- **publisher-agent**: All publish steps → delivers content to platforms\n- **custom-agent**: Custom steps that don't fit other roles\n\nIf a workflow has multiple steps of the same type, they share one agent with multiple skills.\n\n## Skill Generation Rules\n- Each step maps to one or more skills\n- Skill IDs follow the pattern: \\`{action}-{target}\\` (e.g. \\`monitor-techcrunch\\`, \\`publish-linkedin\\`, \\`transform-x\\`)\n- Include platform-specific constraints in notes (X=280 chars, LinkedIn=article format)\n- Set \\`isExisting: true\\` only for skills that match existing ones in the registry\n- \\`flow\\` should list concrete ordered actions (e.g. [\"fetch page\", \"extract articles\", \"compute fingerprint\", \"compare with last snapshot\"])\n- \\`preconditions\\` should state what's needed (e.g. \"URL must be accessible\", \"content must pass relevance filter\")\n\n## A2A Route Rules\n- Routes follow the pipeline order: monitor → filter → content → publisher\n- Event names follow the pattern: \\`{stage}:{action}\\` (e.g. \\`content:detected\\`, \\`content:filtered\\`, \\`content:ready\\`, \\`content:published\\`)\n- Add conditions when policy dictates (e.g. review mode adds a \"content:approved\" route)\n- If policy.default is \"review\", add an extra route for human approval between content-agent and publisher-agent${skillsList}`;\n}\n\n// -----------------------------------------------------------------------------\n// LLM Compiler Engine\n// -----------------------------------------------------------------------------\n\nexport class LLMCompilerEngine implements WorkflowCompilerPort {\n constructor(\n private readonly model: LanguageModel,\n private readonly skillRegistry?: SkillRegistryPort,\n ) {}\n\n async compile(declaration: StructuredDeclaration): Promise<CompilerOutput> {\n const existingSkills = await this.resolveExistingSkills(declaration);\n\n const compilationPrompt = this.buildPrompt(declaration);\n\n const agent = Agent.create({\n model: this.model,\n instructions: buildCompilerPrompt(existingSkills),\n maxSteps: 1,\n })\n .withOutput(Output.object({ schema: CompilerOutputSchema }))\n .build();\n\n const result = await agent.run(compilationPrompt);\n\n if (!result.output) {\n throw new Error(\"Compiler Engine: LLM did not produce structured output\");\n }\n\n const llmOutput = result.output as LLMCompilerOutput;\n\n const workflowId = declaration.id ?? this.generateId(declaration.name);\n\n return {\n workflow: {\n id: workflowId,\n name: declaration.name,\n declaration,\n },\n skills: llmOutput.skills,\n agents: llmOutput.agents,\n routes: llmOutput.routes,\n };\n }\n\n private buildPrompt(declaration: StructuredDeclaration): string {\n return `Compile this workflow declaration into skills, agents, and A2A routes:\n\n\\`\\`\\`json\n${JSON.stringify(declaration, null, 2)}\n\\`\\`\\`\n\nAnalyze the steps, identify required skills per platform, group into role-based agents, and define the A2A communication routes following the pipeline pattern.`;\n }\n\n private async resolveExistingSkills(declaration: StructuredDeclaration): Promise<string[]> {\n if (!this.skillRegistry) return [];\n\n const platforms = new Set<string>();\n for (const step of declaration.steps) {\n if (step.type === \"publish\" && \"channels\" in step) {\n step.channels.forEach((ch) => platforms.add(ch));\n }\n if (step.type === \"transform\" && step.targetChannel) {\n platforms.add(step.targetChannel);\n }\n if (step.type === \"monitor\") {\n platforms.add(\"web\");\n }\n }\n\n const skills: string[] = [];\n for (const platform of platforms) {\n const found = await this.skillRegistry.findByPlatformAndIntent(platform, \"\");\n skills.push(...found.map((s) => `${s.id}: ${s.description}`));\n }\n\n return skills;\n }\n\n private generateId(name: string): string {\n const slug = name\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, \"-\")\n .replace(/^-|-$/g, \"\")\n .slice(0, 48);\n\n const suffix = Date.now().toString(36);\n const base = slug || \"workflow\";\n return `${base}-${suffix}`;\n }\n}\n","// =============================================================================\n// CompileFromNL Service — Full pipeline: NL → parse → compile → output\n// Orchestrates NLParserPort and WorkflowCompilerPort.\n// =============================================================================\n\nimport type { NLParserPort, WorkflowCompilerPort, CompileFromNLPort } from \"../../ports/compiler.port.js\";\nimport { validateDeclaration, type CompilerOutput } from \"../../domain/compiler.schema.js\";\n\nexport class CompileFromNLService implements CompileFromNLPort {\n constructor(\n private readonly parser: NLParserPort,\n private readonly compiler: WorkflowCompilerPort,\n ) {}\n\n async compileFromNL(naturalLanguage: string): Promise<CompilerOutput> {\n const declaration = await this.parser.parse(naturalLanguage);\n\n const validation = validateDeclaration(declaration);\n if (!validation.valid) {\n throw new Error(\n `NL Parser produced invalid declaration: ${validation.errors.join(\"; \")}`,\n );\n }\n\n return this.compiler.compile(validation.data);\n }\n}\n","// =============================================================================\n// LLM Skill Matcher — Uses Agent + Output.object for semantic skill matching\n// =============================================================================\n\nimport { Output } from \"../../core/llm/index.js\";\nimport type { LanguageModel } from \"../../core/llm/index.js\";\nimport { z } from \"zod\";\nimport type { SkillDeclaration } from \"../../domain/compiler.schema.js\";\nimport type { SkillMatcherPort, SkillMatch } from \"../../ports/skill-matcher.port.js\";\nimport { Agent } from \"../../agent/agent.js\";\n\n// Zod schema for LLM match result\nconst MatchResultSchema = z.object({\n matches: z.array(\n z.object({\n existingSkillId: z.string().describe(\"ID of the matching existing skill\"),\n confidence: z\n .number()\n .min(0)\n .max(1)\n .describe(\"Match confidence (0=completely different, 1=identical)\"),\n reason: z.string().describe(\"Brief explanation of why this is a match\"),\n }),\n ),\n});\n\nconst MATCHER_PROMPT = `You are a skill matching engine. Given a candidate skill and a list of existing skills, determine which existing skills are functionally equivalent or very similar to the candidate.\n\nRules:\n- Match based on FUNCTIONAL equivalence, not naming\n- Consider: platform, description, flow steps, preconditions\n- A skill that publishes to LinkedIn via API is the same regardless of its name\n- Return confidence 0.9+ for near-identical skills (same platform, same actions)\n- Return confidence 0.7-0.9 for similar skills (same platform, different approach)\n- Return confidence 0.5-0.7 for partially overlapping skills\n- Only return matches above the minimum confidence threshold\n- If no matches found, return empty array`;\n\nexport class LLMSkillMatcher implements SkillMatcherPort {\n constructor(private readonly model: LanguageModel) {}\n\n async findMatches(\n candidate: SkillDeclaration,\n existingSkills: SkillDeclaration[],\n threshold = 0.7,\n ): Promise<SkillMatch[]> {\n if (existingSkills.length === 0) return [];\n\n const prompt = `Candidate skill:\n${JSON.stringify(candidate, null, 2)}\n\nExisting skills:\n${JSON.stringify(existingSkills, null, 2)}\n\nMinimum confidence threshold: ${threshold}\n\nFind all existing skills that match the candidate.`;\n\n const agent = Agent.create({\n model: this.model,\n instructions: MATCHER_PROMPT,\n maxSteps: 1,\n })\n .withOutput(Output.object({ schema: MatchResultSchema }))\n .build();\n\n const result = await agent.run(prompt);\n\n if (!result.output) return [];\n\n const output = result.output as z.infer<typeof MatchResultSchema>;\n\n return output.matches\n .filter((m) => m.confidence >= threshold)\n .map((m) => {\n const existingSkill = existingSkills.find((s) => s.id === m.existingSkillId);\n if (!existingSkill) return null;\n return {\n skill: existingSkill,\n confidence: m.confidence,\n reason: m.reason,\n };\n })\n .filter((m): m is SkillMatch => m !== null);\n }\n}\n","// =============================================================================\n// InMemorySkillRegistry — Skill registry with matcher-based reuse detection\n// =============================================================================\n\nimport type { SkillDeclaration } from \"../../domain/compiler.schema.js\";\nimport type { SkillRegistryPort } from \"../../ports/compiler.port.js\";\nimport type { SkillMatcherPort, SkillMatch } from \"../../ports/skill-matcher.port.js\";\n\nexport class InMemorySkillRegistry implements SkillRegistryPort {\n private readonly skills = new Map<string, SkillDeclaration>();\n private readonly matcher?: SkillMatcherPort;\n\n constructor(matcher?: SkillMatcherPort) {\n this.matcher = matcher;\n }\n\n async register(skill: SkillDeclaration): Promise<void> {\n this.skills.set(skill.id, skill);\n }\n\n async registerMany(skills: SkillDeclaration[]): Promise<void> {\n for (const skill of skills) {\n this.skills.set(skill.id, skill);\n }\n }\n\n async getAll(): Promise<SkillDeclaration[]> {\n return Array.from(this.skills.values());\n }\n\n async findByPlatformAndIntent(\n platform: string,\n intent: string,\n ): Promise<SkillDeclaration[]> {\n const allSkills = Array.from(this.skills.values());\n return allSkills.filter((s) => {\n if (s.platform !== platform) return false;\n if (!intent) return true;\n const lowerIntent = intent.toLowerCase();\n return (\n s.description.toLowerCase().includes(lowerIntent) ||\n s.id.toLowerCase().includes(lowerIntent)\n );\n });\n }\n\n async exists(skillId: string): Promise<boolean> {\n return this.skills.has(skillId);\n }\n\n /** Find existing skills that match a candidate (requires matcher) */\n async findMatches(\n candidate: SkillDeclaration,\n threshold?: number,\n ): Promise<SkillMatch[]> {\n if (!this.matcher) return [];\n const existingSkills = Array.from(this.skills.values());\n return this.matcher.findMatches(candidate, existingSkills, threshold);\n }\n}\n","// =============================================================================\n// JSON Serializer — Machine-readable CompilerOutput serialization\n// =============================================================================\n\nimport type { CompilerOutput } from \"../../domain/compiler.schema.js\";\nimport type { SerializerPort, SerializerFormat } from \"../../ports/serializer.port.js\";\n\nexport class JSONSerializer implements SerializerPort {\n readonly format: SerializerFormat = \"json\";\n\n serialize(output: CompilerOutput): string {\n return JSON.stringify(output, null, 2);\n }\n}\n","// =============================================================================\n// Markdown Serializer — Human-readable CompilerOutput as SKILLS.md / AGENTS.md\n// =============================================================================\n\nimport type { CompilerOutput, SkillDeclaration, AgentDeclaration, A2ARoute } from \"../../domain/compiler.schema.js\";\nimport type { SerializerPort, SerializerFormat } from \"../../ports/serializer.port.js\";\n\nexport class MarkdownSerializer implements SerializerPort {\n readonly format: SerializerFormat = \"markdown\";\n\n serialize(output: CompilerOutput): string {\n const sections: string[] = [\n this.renderHeader(output),\n this.renderSkills(output.skills),\n this.renderAgents(output.agents),\n this.renderRoutes(output.routes),\n ];\n\n return sections.join(\"\\n\\n\");\n }\n\n private renderHeader(output: CompilerOutput): string {\n const lines = [`# ${output.workflow.name}`, \"\"];\n const decl = output.workflow.declaration;\n if (decl.description) lines.push(decl.description, \"\");\n\n const triggers = decl.triggers\n .map((t) => {\n if (t.type === \"cron\") return `Cron: \\`${t.expression}\\``;\n if (t.type === \"event\") return `Event: \\`${t.event}\\``;\n if (t.type === \"webhook\") return `Webhook: \\`${t.path ?? \"/webhook\"}\\``;\n return \"Manual\";\n })\n .join(\", \");\n\n lines.push(`**Triggers:** ${triggers}`);\n\n if (decl.policy) {\n lines.push(`**Default Policy:** ${decl.policy.default}`);\n }\n\n return lines.join(\"\\n\");\n }\n\n private renderSkills(skills: SkillDeclaration[]): string {\n if (skills.length === 0) return \"\";\n\n const lines = [\"## Skills\", \"\"];\n\n for (const skill of skills) {\n lines.push(`### ${skill.id}`);\n lines.push(\"\");\n lines.push(`- **Platform:** ${skill.platform}`);\n lines.push(`- **Description:** ${skill.description}`);\n lines.push(`- **Preconditions:** ${skill.preconditions}`);\n lines.push(`- **Existing:** ${skill.isExisting ? \"Yes (reused)\" : \"No (new)\"}`);\n if (skill.maxContentLength) {\n lines.push(`- **Max Length:** ${skill.maxContentLength}`);\n }\n lines.push(\"\");\n lines.push(\"**Flow:**\");\n for (const step of skill.flow) {\n lines.push(`1. ${step}`);\n }\n if (skill.notes.length > 0) {\n lines.push(\"\");\n lines.push(\"**Notes:**\");\n for (const note of skill.notes) {\n lines.push(`- ${note}`);\n }\n }\n lines.push(\"\");\n }\n\n return lines.join(\"\\n\");\n }\n\n private renderAgents(agents: AgentDeclaration[]): string {\n if (agents.length === 0) return \"\";\n\n const lines = [\"## Agents\", \"\"];\n\n for (const agent of agents) {\n lines.push(`### ${agent.id}`);\n lines.push(\"\");\n lines.push(`- **Role:** ${agent.role}`);\n lines.push(`- **Skills:** ${agent.skills.join(\", \")}`);\n if (agent.trigger) {\n const triggerStr =\n agent.trigger.type === \"cron\"\n ? `Cron \\`${agent.trigger.expression}\\``\n : agent.trigger.type;\n lines.push(`- **Trigger:** ${triggerStr}`);\n }\n lines.push(\"\");\n }\n\n return lines.join(\"\\n\");\n }\n\n private renderRoutes(routes: A2ARoute[]): string {\n if (routes.length === 0) return \"\";\n\n const lines = [\n \"## A2A Routes\",\n \"\",\n \"| From | To | Event | Condition |\",\n \"|------|-----|-------|-----------|\",\n ];\n\n for (const route of routes) {\n lines.push(\n `| ${route.from} | ${route.to} | \\`${route.event}\\` | ${route.condition ?? \"-\"} |`,\n );\n }\n\n return lines.join(\"\\n\");\n }\n}\n","// =============================================================================\n// FileWorkflowStorage — Persists workflows as YAML/JSON files on disk\n// =============================================================================\n\nimport type { WorkflowStoragePort, StoredWorkflow } from \"../../ports/compiler.port.js\";\n\nexport interface FileStorageOptions {\n basePath: string;\n format?: \"json\" | \"yaml\";\n}\n\nexport class FileWorkflowStorage implements WorkflowStoragePort {\n private readonly basePath: string;\n private readonly format: \"json\" | \"yaml\";\n private fs: typeof import(\"node:fs/promises\") | undefined;\n private path: typeof import(\"node:path\") | undefined;\n\n constructor(options: FileStorageOptions) {\n this.basePath = options.basePath;\n this.format = options.format ?? \"json\";\n }\n\n private async ensureModules(): Promise<void> {\n if (!this.fs) {\n this.fs = await import(\"node:fs/promises\");\n this.path = await import(\"node:path\");\n await this.fs.mkdir(this.basePath, { recursive: true });\n }\n }\n\n private filePath(id: string): string {\n const candidate = this.path!.join(this.basePath, `${id}.${this.format}`);\n const resolved = this.path!.resolve(candidate);\n const base = this.path!.resolve(this.basePath);\n if (!resolved.startsWith(base + this.path!.sep) && resolved !== base) {\n throw new Error(\"Invalid workflow ID: path traversal detected\");\n }\n return candidate;\n }\n\n async save(workflow: StoredWorkflow): Promise<void> {\n await this.ensureModules();\n const content = JSON.stringify(workflow, null, 2);\n await this.fs!.writeFile(this.filePath(workflow.id), content, \"utf-8\");\n }\n\n async load(id: string): Promise<StoredWorkflow | null> {\n await this.ensureModules();\n try {\n const content = await this.fs!.readFile(this.filePath(id), \"utf-8\");\n return JSON.parse(content) as StoredWorkflow;\n } catch {\n return null;\n }\n }\n\n async list(): Promise<StoredWorkflow[]> {\n await this.ensureModules();\n try {\n const files = await this.fs!.readdir(this.basePath);\n const ext = `.${this.format}`;\n const workflows: StoredWorkflow[] = [];\n for (const file of files) {\n if (file.endsWith(ext)) {\n try {\n const content = await this.fs!.readFile(\n this.path!.join(this.basePath, file),\n \"utf-8\",\n );\n workflows.push(JSON.parse(content) as StoredWorkflow);\n } catch {\n // Skip corrupted files, don't break entire listing\n }\n }\n }\n return workflows;\n } catch {\n return [];\n }\n }\n\n async delete(id: string): Promise<boolean> {\n await this.ensureModules();\n try {\n await this.fs!.unlink(this.filePath(id));\n return true;\n } catch {\n return false;\n }\n }\n\n async exists(id: string): Promise<boolean> {\n await this.ensureModules();\n try {\n await this.fs!.access(this.filePath(id));\n return true;\n } catch {\n return false;\n }\n }\n}\n","// =============================================================================\n// DualWorkflowStorage — Orchestrates DB + File storage (DB is source of truth)\n// =============================================================================\n\nimport type { WorkflowStoragePort, StoredWorkflow } from \"../../ports/compiler.port.js\";\n\nexport class DualWorkflowStorage implements WorkflowStoragePort {\n constructor(\n private readonly primary: WorkflowStoragePort,\n private readonly secondary: WorkflowStoragePort,\n ) {}\n\n async save(workflow: StoredWorkflow): Promise<void> {\n await this.primary.save(workflow);\n await this.secondary.save(workflow).catch(() => {\n // Secondary write failure is non-fatal\n });\n }\n\n async load(id: string): Promise<StoredWorkflow | null> {\n return this.primary.load(id);\n }\n\n async list(): Promise<StoredWorkflow[]> {\n return this.primary.list();\n }\n\n async delete(id: string): Promise<boolean> {\n const result = await this.primary.delete(id);\n await this.secondary.delete(id).catch(() => { /* best-effort secondary cleanup */ });\n return result;\n }\n\n async exists(id: string): Promise<boolean> {\n return this.primary.exists(id);\n }\n}\n","// =============================================================================\n// InMemoryWorkflowStorage — For testing and dev environments\n// =============================================================================\n\nimport type { WorkflowStoragePort, StoredWorkflow } from \"../../ports/compiler.port.js\";\n\nexport class InMemoryWorkflowStorage implements WorkflowStoragePort {\n private readonly store = new Map<string, StoredWorkflow>();\n\n async save(workflow: StoredWorkflow): Promise<void> {\n this.store.set(workflow.id, structuredClone(workflow));\n }\n\n async load(id: string): Promise<StoredWorkflow | null> {\n const w = this.store.get(id);\n return w ? structuredClone(w) : null;\n }\n\n async list(): Promise<StoredWorkflow[]> {\n return [...this.store.values()].map((w) => structuredClone(w));\n }\n\n async delete(id: string): Promise<boolean> {\n return this.store.delete(id);\n }\n\n async exists(id: string): Promise<boolean> {\n return this.store.has(id);\n }\n\n clear(): void {\n this.store.clear();\n }\n}\n","// =============================================================================\n// Storage Factory — Env-based strategy selection for WorkflowStoragePort\n// =============================================================================\n\nimport type { WorkflowStoragePort, StorageStrategy } from \"../../ports/compiler.port.js\";\nimport { FileWorkflowStorage, type FileStorageOptions } from \"./file-workflow-storage.js\";\nimport { InMemoryWorkflowStorage } from \"./inmemory-workflow-storage.js\";\nimport { DualWorkflowStorage } from \"./dual-workflow-storage.js\";\n\nexport interface StorageFactoryOptions {\n /** Override strategy (ignores env var) */\n strategy?: StorageStrategy;\n /** File storage options */\n fileOptions?: FileStorageOptions;\n /** External DB storage adapter (injected by consumer) */\n dbStorage?: WorkflowStoragePort;\n /** Env var name for strategy selection (default: WORKFLOW_STORAGE) */\n envVar?: string;\n}\n\n/**\n * Creates a WorkflowStoragePort based on environment configuration.\n * \n * Resolution order: options.strategy → process.env[envVar] → \"file\" (default)\n * \n * Strategies:\n * - \"file\": File-based JSON storage\n * - \"db\": Database storage (requires options.dbStorage)\n * - \"dual\": Primary DB + secondary file (requires options.dbStorage)\n * - \"memory\": In-memory (for testing)\n */\nexport function createWorkflowStorage(options: StorageFactoryOptions = {}): WorkflowStoragePort {\n const envVar = options.envVar ?? \"WORKFLOW_STORAGE\";\n const raw = options.strategy ?? process.env[envVar] ?? \"file\";\n const strategy = raw as StorageStrategy | \"memory\";\n\n switch (strategy) {\n case \"file\":\n return new FileWorkflowStorage(\n options.fileOptions ?? { basePath: \".workflows\" },\n );\n\n case \"memory\":\n return new InMemoryWorkflowStorage();\n\n case \"db\":\n if (!options.dbStorage) {\n throw new Error(\n `Storage strategy \"db\" requires options.dbStorage. ` +\n `Provide a WorkflowStoragePort implementation (e.g. SupabaseWorkflowStorage).`,\n );\n }\n return options.dbStorage;\n\n case \"dual\": {\n if (!options.dbStorage) {\n throw new Error(\n `Storage strategy \"dual\" requires options.dbStorage. ` +\n `Provide a WorkflowStoragePort implementation for the primary store.`,\n );\n }\n const fileStorage = new FileWorkflowStorage(\n options.fileOptions ?? { basePath: \".workflows\" },\n );\n return new DualWorkflowStorage(options.dbStorage, fileStorage);\n }\n\n default:\n throw new Error(\n `Unknown storage strategy \"${strategy}\". Valid values: file, db, dual, memory`,\n );\n }\n}\n","// =============================================================================\n// InMemorySuspensionAdapter — Memory-backed suspension store with TTL\n// =============================================================================\n\nimport type {\n SuspensionPort,\n SuspendedState,\n ResumeDecision,\n SuspensionReason,\n} from \"../../ports/suspension.port.js\";\n\nexport class InMemorySuspensionAdapter implements SuspensionPort {\n private readonly store = new Map<string, SuspendedState>();\n\n async suspend(state: SuspendedState): Promise<void> {\n this.store.set(state.id, structuredClone(state));\n }\n\n async resume(suspensionId: string, decision: ResumeDecision): Promise<SuspendedState> {\n const stored = this.store.get(suspensionId);\n if (!stored) {\n throw new Error(`Suspension \"${suspensionId}\" not found`);\n }\n\n // Work on a deep copy to preserve store immutability\n const state: SuspendedState = structuredClone(stored);\n\n // Apply decisions to pending tool calls\n if (decision.toolDecisions) {\n state.pendingToolCalls = state.pendingToolCalls.map((tc) => {\n const d = decision.toolDecisions?.[tc.toolCallId];\n if (!d) return tc;\n if (d.action === \"edit\" && d.args !== undefined) {\n return { ...tc, args: d.args };\n }\n return tc;\n });\n }\n\n // Merge metadata\n if (decision.metadata) {\n Object.assign(state.metadata, decision.metadata);\n }\n\n // Inject input as a message\n if (decision.input) {\n state.messages.push({ role: \"user\", content: decision.input });\n }\n\n this.store.delete(suspensionId);\n return state;\n }\n\n async get(suspensionId: string): Promise<SuspendedState | null> {\n const state = this.store.get(suspensionId);\n if (!state) return null;\n if (state.expiresAt > 0 && Date.now() > state.expiresAt) {\n this.store.delete(suspensionId);\n return null;\n }\n return structuredClone(state);\n }\n\n async list(options?: {\n sessionId?: string;\n reason?: SuspensionReason;\n limit?: number;\n offset?: number;\n }): Promise<SuspendedState[]> {\n const now = Date.now();\n let results = Array.from(this.store.values()).filter((s) => {\n if (s.expiresAt > 0 && now > s.expiresAt) return false;\n if (options?.sessionId && s.sessionId !== options.sessionId) return false;\n if (options?.reason && s.reason !== options.reason) return false;\n return true;\n });\n\n const offset = options?.offset ?? 0;\n const limit = options?.limit ?? results.length;\n results = results.slice(offset, offset + limit);\n\n return results.map((s) => structuredClone(s));\n }\n\n async cancel(suspensionId: string): Promise<boolean> {\n return this.store.delete(suspensionId);\n }\n\n async cleanup(): Promise<number> {\n const now = Date.now();\n let count = 0;\n for (const [id, state] of this.store) {\n if (state.expiresAt > 0 && now > state.expiresAt) {\n this.store.delete(id);\n count++;\n }\n }\n return count;\n }\n}\n","// =============================================================================\n// FileSkillAdapter — Loads skills from SKILL.md files with YAML frontmatter\n// =============================================================================\n\nimport type {\n SkillsPort,\n Skill,\n SkillValidationResult,\n SkillInheritanceConfig,\n} from \"../../ports/skills.port.js\";\n\nconst SKILL_NAME_REGEX = /^[a-z0-9]+(-[a-z0-9]+)*$/;\nconst MAX_NAME_LENGTH = 64;\n\nexport interface FileSkillAdapterOptions {\n /** Base directories to scan for skills (in order of precedence) */\n searchPaths?: string[];\n /** Filesystem read function */\n readFile: (path: string) => Promise<string>;\n /** List directory entries */\n readDir: (path: string) => Promise<string[]>;\n /** Check if path exists */\n exists: (path: string) => Promise<boolean>;\n /** Resolve path safely */\n resolve: (...parts: string[]) => string;\n /** Check if path is a directory */\n isDirectory: (path: string) => Promise<boolean>;\n}\n\nexport class FileSkillAdapter implements SkillsPort {\n private readonly skills = new Map<string, Skill>();\n private readonly opts: FileSkillAdapterOptions;\n\n constructor(options: FileSkillAdapterOptions) {\n this.opts = options;\n }\n\n async loadSkills(source: string): Promise<Skill[]> {\n const dirExists = await this.opts.exists(source);\n if (!dirExists) return [];\n\n const isDir = await this.opts.isDirectory(source);\n if (!isDir) {\n // Single file\n const skill = await this.loadSkillFile(source);\n if (skill) {\n this.skills.set(skill.name, skill);\n return [skill];\n }\n return [];\n }\n\n const entries = await this.opts.readDir(source);\n const loaded: Skill[] = [];\n\n for (const entry of entries) {\n if (!entry.endsWith(\".md\") && !entry.endsWith(\".skill.md\")) continue;\n // Path traversal prevention\n if (entry.includes(\"..\") || entry.startsWith(\"/\")) continue;\n\n const fullPath = this.opts.resolve(source, entry);\n const skill = await this.loadSkillFile(fullPath);\n if (skill) {\n // Last-one-wins: project > user\n this.skills.set(skill.name, skill);\n loaded.push(skill);\n }\n }\n\n return loaded;\n }\n\n async getSkill(name: string): Promise<Skill | null> {\n return this.skills.get(name) ?? null;\n }\n\n async listSkills(): Promise<Skill[]> {\n return Array.from(this.skills.values());\n }\n\n async validateSkill(skill: Skill): Promise<SkillValidationResult> {\n const errors: string[] = [];\n const warnings: string[] = [];\n\n if (!skill.name) {\n errors.push(\"Skill name is required\");\n } else {\n if (!SKILL_NAME_REGEX.test(skill.name)) {\n errors.push(`Skill name must match pattern: ${SKILL_NAME_REGEX.source}`);\n }\n if (skill.name.length > MAX_NAME_LENGTH) {\n errors.push(`Skill name must be at most ${MAX_NAME_LENGTH} characters`);\n }\n }\n\n if (!skill.description) {\n errors.push(\"Skill description is required\");\n }\n\n if (!skill.content || skill.content.trim().length === 0) {\n errors.push(\"Skill content is required\");\n }\n\n if (skill.allowedTools && skill.disallowedTools) {\n const overlap = skill.allowedTools.filter((t) => skill.disallowedTools!.includes(t));\n if (overlap.length > 0) {\n warnings.push(`Tools in both allowed and disallowed: ${overlap.join(\", \")}`);\n }\n }\n\n return { valid: errors.length === 0, errors, warnings };\n }\n\n resolveInheritedSkills(\n parentSkills: Skill[],\n config: SkillInheritanceConfig,\n ): Skill[] {\n switch (config.policy) {\n case \"inherit_all\":\n return [...parentSkills];\n case \"inherit_none\":\n return [];\n case \"explicit_list\":\n return parentSkills.filter((s) => config.skills?.includes(s.name));\n }\n }\n\n // ---------------------------------------------------------------------------\n // Internal — parse SKILL.md with YAML frontmatter\n // ---------------------------------------------------------------------------\n\n private async loadSkillFile(path: string): Promise<Skill | null> {\n try {\n const content = await this.opts.readFile(path);\n return this.parseSkillMd(content, path);\n } catch {\n return null;\n }\n }\n\n private parseSkillMd(raw: string, source: string): Skill | null {\n const { frontmatter, content } = parseFrontmatter(raw);\n if (!frontmatter.name || !content) return null;\n\n return {\n name: String(frontmatter.name),\n description: String(frontmatter.description ?? \"\"),\n content: content.trim(),\n source,\n license: frontmatter.license ? String(frontmatter.license) : undefined,\n allowedTools: parseStringArray(frontmatter[\"allowed-tools\"]),\n disallowedTools: parseStringArray(frontmatter[\"disallowed-tools\"]),\n compatibility: frontmatter.compatibility\n ? {\n minVersion: (frontmatter.compatibility as Record<string, unknown>).minVersion as string | undefined,\n maxVersion: (frontmatter.compatibility as Record<string, unknown>).maxVersion as string | undefined,\n runtimes: parseStringArray((frontmatter.compatibility as Record<string, unknown>).runtimes),\n }\n : undefined,\n metadata: (frontmatter.metadata as Record<string, unknown>) ?? {},\n };\n }\n}\n\n// =============================================================================\n// Minimal YAML frontmatter parser (no dependencies)\n// =============================================================================\n\nfunction parseFrontmatter(raw: string): {\n frontmatter: Record<string, unknown>;\n content: string;\n} {\n const match = raw.match(/^---\\s*\\n([\\s\\S]*?)\\n---\\s*\\n([\\s\\S]*)$/);\n if (!match) {\n return { frontmatter: {}, content: raw };\n }\n\n const yamlBlock = match[1];\n const content = match[2];\n const frontmatter: Record<string, unknown> = {};\n\n // Simple key: value parser (handles strings, arrays, nested objects)\n let currentObject: Record<string, unknown> | null = null;\n\n for (const line of yamlBlock.split(\"\\n\")) {\n const trimmed = line.trim();\n if (!trimmed || trimmed.startsWith(\"#\")) continue;\n\n const indent = line.length - line.trimStart().length;\n const colonIdx = trimmed.indexOf(\":\");\n if (colonIdx === -1) continue;\n\n const key = trimmed.slice(0, colonIdx).trim();\n const value = trimmed.slice(colonIdx + 1).trim();\n\n if (indent > 0 && currentObject !== null) {\n // Nested property\n if (value.startsWith(\"[\") && value.endsWith(\"]\")) {\n currentObject[key] = value\n .slice(1, -1)\n .split(\",\")\n .map((s) => s.trim().replace(/^[\"']|[\"']$/g, \"\"))\n .filter(Boolean);\n } else {\n currentObject[key] = value.replace(/^[\"']|[\"']$/g, \"\");\n }\n } else if (value === \"\") {\n // Start of a nested object\n currentObject = {};\n frontmatter[key] = currentObject;\n } else if (value.startsWith(\"[\") && value.endsWith(\"]\")) {\n // Inline array: [a, b, c]\n currentObject = null;\n frontmatter[key] = value\n .slice(1, -1)\n .split(\",\")\n .map((s) => s.trim().replace(/^[\"']|[\"']$/g, \"\"))\n .filter(Boolean);\n } else {\n currentObject = null;\n frontmatter[key] = value.replace(/^[\"']|[\"']$/g, \"\");\n }\n }\n\n return { frontmatter, content };\n}\n\nfunction parseStringArray(value: unknown): string[] | undefined {\n if (!value) return undefined;\n if (Array.isArray(value)) return value.map(String);\n if (typeof value === \"string\") return value.split(\",\").map((s) => s.trim());\n return undefined;\n}\n","// =============================================================================\n// LocalShellSandboxAdapter — Subprocess-based sandbox with timeout/truncation\n// =============================================================================\n\nimport { spawn } from \"node:child_process\";\nimport type { SandboxPort, SandboxConfig, ExecuteResult } from \"../../ports/sandbox.port.js\";\n\nconst DEFAULT_TIMEOUT = 30_000;\nconst DEFAULT_MAX_OUTPUT = 1024 * 1024; // 1MB\n\nexport interface LocalShellOptions {\n /** Default working directory */\n cwd?: string;\n /** Shell binary (default: /bin/sh) */\n shell?: string;\n /** Blocked commands (regex patterns) */\n blockedPatterns?: RegExp[];\n /** Inherit parent process env (default: false for security) */\n inheritParentEnv?: boolean;\n}\n\nexport class LocalShellSandboxAdapter implements SandboxPort {\n private readonly opts: LocalShellOptions;\n private readonly uploadedFiles = new Map<string, string | Uint8Array>();\n\n constructor(options?: LocalShellOptions) {\n this.opts = options ?? {};\n }\n\n async execute(command: string, config?: SandboxConfig): Promise<ExecuteResult> {\n // Security: check blocked patterns\n if (this.opts.blockedPatterns) {\n for (const pattern of this.opts.blockedPatterns) {\n if (pattern.test(command)) {\n return {\n output: `Command blocked by security policy: ${pattern.source}`,\n exitCode: 126,\n truncated: false,\n durationMs: 0,\n };\n }\n }\n }\n\n const timeout = config?.timeoutMs ?? DEFAULT_TIMEOUT;\n const maxOutput = config?.maxOutputBytes ?? DEFAULT_MAX_OUTPUT;\n const cwd = config?.workingDir ?? this.opts.cwd ?? process.cwd();\n const shell = this.opts.shell ?? \"/bin/sh\";\n\n const env = {\n ...(this.opts.inheritParentEnv ? process.env : { PATH: process.env.PATH }),\n ...config?.env,\n };\n\n const start = Date.now();\n\n return new Promise<ExecuteResult>((resolve) => {\n const child = spawn(shell, [\"-c\", command], { cwd, env });\n\n let output = \"\";\n let truncated = false;\n let settled = false;\n\n const onData = (chunk: Buffer) => {\n if (truncated || settled) return;\n const text = chunk.toString();\n if (output.length + text.length > maxOutput) {\n output += text.slice(0, maxOutput - output.length);\n truncated = true;\n settled = true;\n clearTimeout(timer);\n child.kill(\"SIGKILL\");\n resolve({\n output: output + \"\\n[TRUNCATED]\",\n exitCode: 0,\n truncated: true,\n durationMs: Date.now() - start,\n });\n } else {\n output += text;\n }\n };\n\n child.stdout.on(\"data\", onData);\n child.stderr.on(\"data\", onData);\n\n const timer = setTimeout(() => {\n if (!settled) {\n settled = true;\n child.kill(\"SIGKILL\");\n resolve({\n output: output + \"\\n[TIMEOUT]\",\n exitCode: 124,\n truncated,\n durationMs: Date.now() - start,\n });\n }\n }, timeout);\n\n child.on(\"close\", (code) => {\n if (!settled) {\n settled = true;\n clearTimeout(timer);\n resolve({\n output,\n exitCode: code ?? 1,\n truncated,\n durationMs: Date.now() - start,\n });\n }\n });\n\n child.on(\"error\", (err) => {\n if (!settled) {\n settled = true;\n clearTimeout(timer);\n resolve({\n output: err.message,\n exitCode: 127,\n truncated: false,\n durationMs: Date.now() - start,\n });\n }\n });\n });\n }\n\n async uploadFiles(files: Array<{ path: string; content: string | Uint8Array }>): Promise<void> {\n for (const f of files) {\n this.uploadedFiles.set(f.path, f.content);\n }\n }\n\n async downloadFiles(paths: string[]): Promise<Array<{ path: string; content: string }>> {\n return paths.map((p) => {\n const content = this.uploadedFiles.get(p);\n return { path: p, content: content ? String(content) : \"\" };\n });\n }\n\n async cleanup(): Promise<void> {\n this.uploadedFiles.clear();\n }\n\n async isAvailable(): Promise<boolean> {\n try {\n const result = await this.execute(\"echo ok\", { timeoutMs: 5000 });\n return result.exitCode === 0 && result.output.trim() === \"ok\";\n } catch {\n return false;\n }\n }\n}\n","// =============================================================================\n// E2BSandboxAdapter — Cloud sandbox using E2B Code Interpreter SDK\n// =============================================================================\n// Requires: @e2b/code-interpreter as peer dependency\n// Install: npm install @e2b/code-interpreter\n// Set E2B_API_KEY environment variable\n// =============================================================================\n\nimport type { SandboxPort, SandboxConfig, ExecuteResult } from \"../../ports/sandbox.port.js\";\n\nexport interface E2BSandboxConfig {\n /** E2B API key (defaults to E2B_API_KEY env var) */\n apiKey?: string;\n /** E2B sandbox template (default: \"base\") */\n template?: string;\n /** Sandbox timeout in ms (default: 300_000 = 5 min) */\n sandboxTimeoutMs?: number;\n}\n\n/**\n * E2B Cloud Sandbox adapter.\n * Dynamically imports @e2b/code-interpreter to avoid hard dependency.\n */\nexport class E2BSandboxAdapter implements SandboxPort {\n private config: E2BSandboxConfig;\n private sandbox: unknown | null = null;\n private sandboxModule: unknown | null = null;\n\n constructor(config?: E2BSandboxConfig) {\n this.config = {\n apiKey: config?.apiKey,\n template: config?.template ?? \"base\",\n sandboxTimeoutMs: config?.sandboxTimeoutMs ?? 300_000,\n };\n }\n\n private async getSandboxModule(): Promise<{ Sandbox: any }> {\n if (this.sandboxModule) return this.sandboxModule as { Sandbox: any };\n try {\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const moduleName = \"@e2b/code-interpreter\";\n this.sandboxModule = await import(/* @vite-ignore */ moduleName);\n return this.sandboxModule as { Sandbox: any };\n } catch {\n throw new Error(\n \"E2B SDK not installed. Run: npm install @e2b/code-interpreter\\n\" +\n \"Also set E2B_API_KEY environment variable.\",\n );\n }\n }\n\n private async ensureSandbox(): Promise<any> {\n if (this.sandbox) return this.sandbox;\n const mod = await this.getSandboxModule();\n const SandboxClass = mod.Sandbox ?? (mod as any).default?.Sandbox ?? (mod as any).CodeInterpreter;\n if (!SandboxClass) {\n throw new Error(\"Could not find Sandbox class in @e2b/code-interpreter module\");\n }\n this.sandbox = await SandboxClass.create({\n apiKey: this.config.apiKey ?? process.env.E2B_API_KEY,\n template: this.config.template,\n timeout: this.config.sandboxTimeoutMs,\n });\n return this.sandbox;\n }\n\n async execute(command: string, config?: SandboxConfig): Promise<ExecuteResult> {\n const timeoutMs = config?.timeoutMs ?? 30_000;\n const maxOutputBytes = config?.maxOutputBytes ?? 1_048_576;\n const startTime = Date.now();\n\n let sandbox: any;\n try {\n sandbox = await this.ensureSandbox();\n } catch (err: unknown) {\n const message = err instanceof Error ? err.message : String(err);\n return { output: `E2B execution error: ${message}`, exitCode: 1, truncated: false, durationMs: Date.now() - startTime };\n }\n\n try {\n if (config?.env) {\n for (const [key, value] of Object.entries(config.env)) {\n await sandbox.process?.setEnv?.(key, value);\n }\n }\n\n const cwd = config?.workingDir ?? \"/home/user\";\n const proc = await sandbox.process.start({ cmd: command, cwd, timeout: timeoutMs });\n await proc.wait();\n const durationMs = Date.now() - startTime;\n\n let output = (proc.output?.stdout ?? \"\") + (proc.output?.stderr ?? \"\");\n let truncated = false;\n if (output.length > maxOutputBytes) {\n output = output.slice(0, maxOutputBytes);\n truncated = true;\n }\n\n return { output, exitCode: proc.output?.exitCode ?? proc.exitCode ?? 1, truncated, durationMs };\n } catch (err: unknown) {\n const message = err instanceof Error ? err.message : String(err);\n return { output: `E2B execution error: ${message}`, exitCode: 1, truncated: false, durationMs: Date.now() - startTime };\n }\n }\n\n async uploadFiles(files: Array<{ path: string; content: string | Uint8Array }>): Promise<void> {\n const sandbox = await this.ensureSandbox() as any;\n for (const file of files) {\n const content = typeof file.content === \"string\"\n ? new TextEncoder().encode(file.content)\n : file.content;\n await sandbox.files.write(file.path, content);\n }\n }\n\n async downloadFiles(paths: string[]): Promise<Array<{ path: string; content: string }>> {\n const sandbox = await this.ensureSandbox() as any;\n const results: Array<{ path: string; content: string }> = [];\n for (const path of paths) {\n const content = await sandbox.files.read(path);\n results.push({\n path,\n content: typeof content === \"string\" ? content : new TextDecoder().decode(content),\n });\n }\n return results;\n }\n\n async cleanup(): Promise<void> {\n if (this.sandbox) {\n try {\n await (this.sandbox as any).close?.();\n await (this.sandbox as any).kill?.();\n } catch {\n // Best-effort cleanup\n }\n this.sandbox = null;\n }\n }\n\n async isAvailable(): Promise<boolean> {\n try {\n await this.getSandboxModule();\n const apiKey = this.config.apiKey ?? process.env.E2B_API_KEY;\n return !!apiKey;\n } catch {\n return false;\n }\n }\n}\n","// =============================================================================\n// Sandbox Factory — Auto-select sandbox implementation\n// =============================================================================\n\nimport type { SandboxPort } from \"../../ports/sandbox.port.js\";\nimport { LocalShellSandboxAdapter } from \"./local-shell.adapter.js\";\nimport { E2BSandboxAdapter } from \"./e2b.adapter.js\";\nimport type { E2BSandboxConfig } from \"./e2b.adapter.js\";\n\nexport interface SandboxFactoryConfig {\n /** Force a specific sandbox type */\n type?: \"local\" | \"e2b\" | \"auto\";\n /** E2B-specific configuration */\n e2b?: E2BSandboxConfig;\n}\n\n/**\n * Create a sandbox adapter based on configuration and environment.\n *\n * Selection logic (when type=\"auto\" or omitted):\n * 1. If E2B_API_KEY is set or e2b config has apiKey → E2BSandboxAdapter\n * 2. Otherwise → LocalShellSandboxAdapter\n */\nexport function createSandbox(config?: SandboxFactoryConfig): SandboxPort {\n const type = config?.type ?? \"auto\";\n\n if (type === \"e2b\") {\n return new E2BSandboxAdapter(config?.e2b);\n }\n\n if (type === \"local\") {\n return new LocalShellSandboxAdapter();\n }\n\n // Auto-detect\n const hasE2bKey = !!(config?.e2b?.apiKey ?? process.env.E2B_API_KEY);\n if (hasE2bKey) {\n return new E2BSandboxAdapter(config?.e2b);\n }\n\n return new LocalShellSandboxAdapter();\n}\n","// =============================================================================\n// FileWatcherAdapter — Watches JSON config files for hot-reload\n// =============================================================================\n\nimport { readFileSync, watch, type FSWatcher } from \"node:fs\";\nimport type { HotReloadPort, HotReloadAgentConfig as AgentConfig } from \"../../ports/hot-reload.port.js\";\n\n/** Default debounce interval for file-change events in ms */\nconst DEFAULT_DEBOUNCE_MS = 300;\n\nfunction validateAgentConfig(data: unknown): data is AgentConfig {\n if (typeof data !== \"object\" || data === null) return false;\n const obj = data as Record<string, unknown>;\n if (typeof obj.name !== \"string\" || obj.name.length === 0) return false;\n if (typeof obj.model !== \"string\" || obj.model.length === 0) return false;\n if (obj.systemPrompt !== undefined && typeof obj.systemPrompt !== \"string\") return false;\n if (obj.maxSteps !== undefined && typeof obj.maxSteps !== \"number\") return false;\n return true;\n}\n\nexport class FileWatcherAdapter implements HotReloadPort {\n private watcher: FSWatcher | null = null;\n private debounceTimer: ReturnType<typeof setTimeout> | null = null;\n private readonly debounceMs: number;\n\n constructor(debounceMs = DEFAULT_DEBOUNCE_MS) {\n this.debounceMs = debounceMs;\n }\n\n watch(configPath: string, onChange: (config: AgentConfig) => void): void {\n this.stop();\n\n try {\n this.watcher = watch(configPath, () => {\n if (this.debounceTimer) clearTimeout(this.debounceTimer);\n this.debounceTimer = setTimeout(() => {\n try {\n const raw = readFileSync(configPath, \"utf-8\");\n const parsed: unknown = JSON.parse(raw);\n if (!validateAgentConfig(parsed)) {\n console.warn(`[hot-reload] Invalid config shape in ${configPath}`);\n return;\n }\n onChange(parsed);\n } catch (err) {\n console.warn(`[hot-reload] Failed to read/parse ${configPath}:`, err);\n }\n }, this.debounceMs);\n });\n } catch (err) {\n console.warn(`[hot-reload] Failed to watch ${configPath}:`, err);\n }\n }\n\n stop(): void {\n if (this.debounceTimer) {\n clearTimeout(this.debounceTimer);\n this.debounceTimer = null;\n }\n if (this.watcher) {\n this.watcher.close();\n this.watcher = null;\n }\n }\n}\n","// =============================================================================\n// AgentConfigLoader — Load and hot-reload Agent from config files\n// =============================================================================\n\nimport { readFileSync } from \"node:fs\";\nimport type { LanguageModel } from \"../core/llm/index.js\";\nimport type { HotReloadAgentConfig as AgentConfig, HotReloadPort } from \"../ports/hot-reload.port.js\";\nimport { FileWatcherAdapter } from \"../adapters/hot-reload/file-watcher.adapter.js\";\nimport { Agent } from \"./agent.js\";\n\nexport interface ModelResolver {\n (modelName: string): LanguageModel;\n}\n\nexport class AgentConfigLoader {\n /**\n * Creates a Agent from an AgentConfig.\n * Requires a modelResolver to convert the model string to a LanguageModel instance.\n */\n static fromConfig(config: AgentConfig, modelResolver: ModelResolver): Agent {\n const builder = Agent.create({\n name: config.name,\n model: modelResolver(config.model),\n instructions: config.systemPrompt || \"You are a helpful assistant.\",\n maxSteps: config.maxSteps,\n });\n\n return builder.build();\n }\n\n /** Reads and parses a JSON config file. */\n static loadFile(path: string): AgentConfig {\n const raw = readFileSync(path, \"utf-8\");\n const parsed: unknown = JSON.parse(raw);\n AgentConfigLoader.assertValidConfig(parsed);\n return parsed;\n }\n\n /**\n * Watches a config file and calls onReload with a new Agent when config changes.\n * Returns the HotReloadPort so the caller can stop watching.\n */\n static watchAndReload(\n path: string,\n modelResolver: ModelResolver,\n onReload: (agent: Agent) => void,\n ): HotReloadPort {\n const watcher = new FileWatcherAdapter();\n watcher.watch(path, (config) => {\n const agent = AgentConfigLoader.fromConfig(config, modelResolver);\n onReload(agent);\n });\n return watcher;\n }\n\n private static assertValidConfig(data: unknown): asserts data is AgentConfig {\n if (typeof data !== \"object\" || data === null) {\n throw new Error(\"Config must be a JSON object\");\n }\n const obj = data as Record<string, unknown>;\n if (typeof obj.name !== \"string\" || obj.name.length === 0) {\n throw new Error(\"Config 'name' is required and must be a non-empty string\");\n }\n if (typeof obj.model !== \"string\" || obj.model.length === 0) {\n throw new Error(\"Config 'model' is required and must be a non-empty string\");\n }\n }\n}\n","// =============================================================================\n// StorageDomainPort — Multi-domain storage with composite pattern\n// =============================================================================\n\nexport type StorageDomain =\n | \"memory\"\n | \"workflows\"\n | \"scores\"\n | \"agents\"\n | \"skills\"\n | \"blobs\"\n | \"learning\"\n | \"metrics\";\n\nexport interface StorageRecord {\n id: string;\n domain: StorageDomain;\n data: Record<string, unknown>;\n createdAt: number;\n updatedAt: number;\n}\n\nexport interface StorageQuery {\n domain: StorageDomain;\n filter?: Record<string, unknown>;\n limit?: number;\n offset?: number;\n orderBy?: string;\n orderDir?: \"asc\" | \"desc\";\n}\n\nexport interface PaginatedResult<T> {\n items: T[];\n total: number;\n limit: number;\n offset: number;\n hasMore: boolean;\n}\n\n// =============================================================================\n// Port interface\n// =============================================================================\n\nexport interface StorageDomainPort {\n /** Create or update a record */\n put(domain: StorageDomain, id: string, data: Record<string, unknown>): Promise<StorageRecord>;\n\n /** Get a record by ID */\n get(domain: StorageDomain, id: string): Promise<StorageRecord | null>;\n\n /** Delete a record */\n delete(domain: StorageDomain, id: string): Promise<boolean>;\n\n /** Query records with pagination */\n query(params: StorageQuery): Promise<PaginatedResult<StorageRecord>>;\n\n /** Count records in a domain */\n count(domain: StorageDomain): Promise<number>;\n\n /** Clear all records in a domain */\n clear(domain: StorageDomain): Promise<number>;\n}\n\n// =============================================================================\n// Composite Storage — Default backend + per-domain overrides\n// =============================================================================\n\nexport class CompositeStorageAdapter implements StorageDomainPort {\n private readonly defaultBackend: StorageDomainPort;\n private readonly overrides: Partial<Record<StorageDomain, StorageDomainPort>>;\n\n constructor(\n defaultBackend: StorageDomainPort,\n overrides?: Partial<Record<StorageDomain, StorageDomainPort>>,\n ) {\n this.defaultBackend = defaultBackend;\n this.overrides = overrides ?? {};\n }\n\n private resolve(domain: StorageDomain): StorageDomainPort {\n return this.overrides[domain] ?? this.defaultBackend;\n }\n\n async put(domain: StorageDomain, id: string, data: Record<string, unknown>): Promise<StorageRecord> {\n return this.resolve(domain).put(domain, id, data);\n }\n\n async get(domain: StorageDomain, id: string): Promise<StorageRecord | null> {\n return this.resolve(domain).get(domain, id);\n }\n\n async delete(domain: StorageDomain, id: string): Promise<boolean> {\n return this.resolve(domain).delete(domain, id);\n }\n\n async query(params: StorageQuery): Promise<PaginatedResult<StorageRecord>> {\n return this.resolve(params.domain).query(params);\n }\n\n async count(domain: StorageDomain): Promise<number> {\n return this.resolve(domain).count(domain);\n }\n\n async clear(domain: StorageDomain): Promise<number> {\n return this.resolve(domain).clear(domain);\n }\n}\n","// =============================================================================\n// InMemoryStorageAdapter — In-memory multi-domain storage\n// =============================================================================\n\nimport type {\n StorageDomainPort,\n StorageDomain,\n StorageRecord,\n StorageQuery,\n PaginatedResult,\n} from \"../../ports/storage-domain.port.js\";\n\nexport class InMemoryStorageAdapter implements StorageDomainPort {\n private readonly domains = new Map<StorageDomain, Map<string, StorageRecord>>();\n\n private getDomain(domain: StorageDomain): Map<string, StorageRecord> {\n let store = this.domains.get(domain);\n if (!store) {\n store = new Map();\n this.domains.set(domain, store);\n }\n return store;\n }\n\n async put(\n domain: StorageDomain,\n id: string,\n data: Record<string, unknown>,\n ): Promise<StorageRecord> {\n const store = this.getDomain(domain);\n const now = Date.now();\n const existing = store.get(id);\n const record: StorageRecord = {\n id,\n domain,\n data: { ...data },\n createdAt: existing?.createdAt ?? now,\n updatedAt: now,\n };\n store.set(id, record);\n return { ...record };\n }\n\n async get(domain: StorageDomain, id: string): Promise<StorageRecord | null> {\n const store = this.getDomain(domain);\n const record = store.get(id);\n return record ? { ...record, data: { ...record.data } } : null;\n }\n\n async delete(domain: StorageDomain, id: string): Promise<boolean> {\n return this.getDomain(domain).delete(id);\n }\n\n async query(params: StorageQuery): Promise<PaginatedResult<StorageRecord>> {\n const store = this.getDomain(params.domain);\n let items = Array.from(store.values());\n\n // Filter\n if (params.filter) {\n items = items.filter((r) => {\n for (const [key, val] of Object.entries(params.filter!)) {\n if (r.data[key] !== val) return false;\n }\n return true;\n });\n }\n\n // Sort\n if (params.orderBy) {\n const dir = params.orderDir === \"desc\" ? -1 : 1;\n const field = params.orderBy;\n items.sort((a, b) => {\n const va = (field === \"createdAt\" || field === \"updatedAt\")\n ? a[field]\n : a.data[field];\n const vb = (field === \"createdAt\" || field === \"updatedAt\")\n ? b[field]\n : b.data[field];\n if (va === vb) return 0;\n if (va === undefined || va === null) return 1;\n if (vb === undefined || vb === null) return -1;\n return va < vb ? -dir : dir;\n });\n }\n\n const total = items.length;\n const offset = params.offset ?? 0;\n const limit = params.limit ?? 50;\n const paged = items.slice(offset, offset + limit);\n\n return {\n items: paged.map((r) => ({ ...r, data: { ...r.data } })),\n total,\n limit,\n offset,\n hasMore: offset + limit < total,\n };\n }\n\n async count(domain: StorageDomain): Promise<number> {\n return this.getDomain(domain).size;\n }\n\n async clear(domain: StorageDomain): Promise<number> {\n const store = this.getDomain(domain);\n const count = store.size;\n store.clear();\n return count;\n }\n}\n","// =============================================================================\n// PostgreSQL Storage Adapter — Implements StorageDomainPort\n// =============================================================================\n//\n// Requires: pg (peer dependency)\n// Table: gauss_storage (id, domain, data JSONB, created_at, updated_at)\n//\n// Usage:\n// import { PostgresStorageAdapter } from 'gauss'\n// const storage = new PostgresStorageAdapter({ connectionString: '...' })\n// await storage.initialize() // creates table if not exists\n//\n// =============================================================================\n\nimport type {\n StorageDomainPort,\n StorageDomain,\n StorageRecord,\n StorageQuery,\n PaginatedResult,\n} from \"../../../ports/storage-domain.port.js\";\n\nexport interface PostgresStorageOptions {\n /** PostgreSQL connection string */\n connectionString: string;\n /** Table name (default: 'gauss_storage') */\n tableName?: string;\n /** Schema name (default: 'public') */\n schema?: string;\n /** Pool size (default: 10) */\n poolSize?: number;\n}\n\nexport class PostgresStorageAdapter implements StorageDomainPort {\n private pool: unknown;\n private readonly table: string;\n private readonly schema: string;\n private readonly options: PostgresStorageOptions;\n\n constructor(options: PostgresStorageOptions) {\n this.options = options;\n this.schema = options.schema ?? \"public\";\n this.table = `${this.schema}.${options.tableName ?? \"gauss_storage\"}`;\n }\n\n /** Initialize the adapter — creates table if not exists */\n async initialize(): Promise<void> {\n const pg = await import(\"pg\");\n const Pool = pg.default?.Pool ?? pg.Pool;\n this.pool = new Pool({\n connectionString: this.options.connectionString,\n max: this.options.poolSize ?? 10,\n });\n\n await (this.pool as any).query(`\n CREATE TABLE IF NOT EXISTS ${this.table} (\n id TEXT NOT NULL,\n domain TEXT NOT NULL,\n data JSONB NOT NULL DEFAULT '{}',\n created_at BIGINT NOT NULL,\n updated_at BIGINT NOT NULL,\n PRIMARY KEY (domain, id)\n )\n `);\n\n await (this.pool as any).query(`\n CREATE INDEX IF NOT EXISTS idx_${this.options.tableName ?? \"gauss_storage\"}_domain\n ON ${this.table} (domain)\n `);\n }\n\n async put(\n domain: StorageDomain,\n id: string,\n data: Record<string, unknown>,\n ): Promise<StorageRecord> {\n const now = Date.now();\n const result = await (this.pool as any).query(\n `INSERT INTO ${this.table} (id, domain, data, created_at, updated_at)\n VALUES ($1, $2, $3, $4, $5)\n ON CONFLICT (domain, id) DO UPDATE SET\n data = $3, updated_at = $5\n RETURNING *`,\n [id, domain, JSON.stringify(data), now, now],\n );\n const row = result.rows[0];\n return {\n id: row.id,\n domain: row.domain as StorageDomain,\n data: typeof row.data === \"string\" ? JSON.parse(row.data) : row.data,\n createdAt: Number(row.created_at),\n updatedAt: Number(row.updated_at),\n };\n }\n\n async get(domain: StorageDomain, id: string): Promise<StorageRecord | null> {\n const result = await (this.pool as any).query(\n `SELECT * FROM ${this.table} WHERE domain = $1 AND id = $2`,\n [domain, id],\n );\n if (result.rows.length === 0) return null;\n const row = result.rows[0];\n return {\n id: row.id,\n domain: row.domain as StorageDomain,\n data: typeof row.data === \"string\" ? JSON.parse(row.data) : row.data,\n createdAt: Number(row.created_at),\n updatedAt: Number(row.updated_at),\n };\n }\n\n async delete(domain: StorageDomain, id: string): Promise<boolean> {\n const result = await (this.pool as any).query(\n `DELETE FROM ${this.table} WHERE domain = $1 AND id = $2`,\n [domain, id],\n );\n return result.rowCount > 0;\n }\n\n async query(params: StorageQuery): Promise<PaginatedResult<StorageRecord>> {\n const conditions = [\"domain = $1\"];\n const values: unknown[] = [params.domain];\n let paramIndex = 2;\n\n if (params.filter) {\n for (const [key, val] of Object.entries(params.filter)) {\n conditions.push(`data->>$${paramIndex} = $${paramIndex + 1}`);\n values.push(key, String(val));\n paramIndex += 2;\n }\n }\n\n const where = conditions.join(\" AND \");\n\n // Count\n const countResult = await (this.pool as any).query(\n `SELECT COUNT(*) FROM ${this.table} WHERE ${where}`,\n values,\n );\n const total = Number(countResult.rows[0].count);\n\n // Fetch\n const orderBy = params.orderBy ?? \"created_at\";\n const orderDir = params.orderDir ?? \"asc\";\n const orderColumn = orderBy === \"createdAt\" ? \"created_at\"\n : orderBy === \"updatedAt\" ? \"updated_at\"\n : `data->>'${orderBy.replace(/'/g, \"''\")}'`;\n\n const limit = params.limit ?? 50;\n const offset = params.offset ?? 0;\n\n const result = await (this.pool as any).query(\n `SELECT * FROM ${this.table} WHERE ${where}\n ORDER BY ${orderColumn} ${orderDir}\n LIMIT $${paramIndex} OFFSET $${paramIndex + 1}`,\n [...values, limit, offset],\n );\n\n return {\n items: result.rows.map((row: any) => ({\n id: row.id,\n domain: row.domain as StorageDomain,\n data: typeof row.data === \"string\" ? JSON.parse(row.data) : row.data,\n createdAt: Number(row.created_at),\n updatedAt: Number(row.updated_at),\n })),\n total,\n limit,\n offset,\n hasMore: offset + limit < total,\n };\n }\n\n async count(domain: StorageDomain): Promise<number> {\n const result = await (this.pool as any).query(\n `SELECT COUNT(*) FROM ${this.table} WHERE domain = $1`,\n [domain],\n );\n return Number(result.rows[0].count);\n }\n\n async clear(domain: StorageDomain): Promise<number> {\n const result = await (this.pool as any).query(\n `DELETE FROM ${this.table} WHERE domain = $1`,\n [domain],\n );\n return result.rowCount;\n }\n\n /** Close the pool */\n async close(): Promise<void> {\n if (this.pool) await (this.pool as any).end();\n }\n}\n","// =============================================================================\n// Redis Storage Adapter — Implements StorageDomainPort with caching support\n// =============================================================================\n//\n// Requires: ioredis (peer dependency)\n//\n// Usage:\n// import { RedisStorageAdapter } from 'gauss'\n// const storage = new RedisStorageAdapter({ url: 'redis://localhost:6379' })\n//\n// =============================================================================\n\nimport type {\n StorageDomainPort,\n StorageDomain,\n StorageRecord,\n StorageQuery,\n PaginatedResult,\n} from \"../../../ports/storage-domain.port.js\";\n\nexport interface RedisStorageOptions {\n /** Redis connection URL (e.g., redis://localhost:6379) */\n url?: string;\n /** Key prefix (default: 'gauss') */\n prefix?: string;\n /** TTL for records in seconds (0 = no expiry, default: 0) */\n ttl?: number;\n}\n\nexport class RedisStorageAdapter implements StorageDomainPort {\n private client: any;\n private readonly prefix: string;\n private readonly ttl: number;\n private readonly options: RedisStorageOptions;\n\n constructor(options: RedisStorageOptions = {}) {\n this.options = options;\n this.prefix = options.prefix ?? \"gauss\";\n this.ttl = options.ttl ?? 0;\n }\n\n /** Initialize the Redis connection */\n async initialize(): Promise<void> {\n const Redis = (await import(\"ioredis\")).default;\n this.client = new Redis(this.options.url ?? \"redis://localhost:6379\");\n }\n\n private key(domain: StorageDomain, id: string): string {\n return `${this.prefix}:${domain}:${id}`;\n }\n\n private domainKey(domain: StorageDomain): string {\n return `${this.prefix}:idx:${domain}`;\n }\n\n async put(\n domain: StorageDomain,\n id: string,\n data: Record<string, unknown>,\n ): Promise<StorageRecord> {\n const now = Date.now();\n const existing = await this.get(domain, id);\n const record: StorageRecord = {\n id,\n domain,\n data,\n createdAt: existing?.createdAt ?? now,\n updatedAt: now,\n };\n\n const k = this.key(domain, id);\n const pipeline = this.client.pipeline();\n pipeline.set(k, JSON.stringify(record));\n if (this.ttl > 0) pipeline.expire(k, this.ttl);\n pipeline.sadd(this.domainKey(domain), id);\n await pipeline.exec();\n\n return { ...record };\n }\n\n async get(domain: StorageDomain, id: string): Promise<StorageRecord | null> {\n const raw = await this.client.get(this.key(domain, id));\n if (!raw) return null;\n return JSON.parse(raw) as StorageRecord;\n }\n\n async delete(domain: StorageDomain, id: string): Promise<boolean> {\n const pipeline = this.client.pipeline();\n pipeline.del(this.key(domain, id));\n pipeline.srem(this.domainKey(domain), id);\n const results = await pipeline.exec();\n return results[0][1] > 0;\n }\n\n async query(params: StorageQuery): Promise<PaginatedResult<StorageRecord>> {\n const ids = await this.client.smembers(this.domainKey(params.domain));\n if (ids.length === 0) {\n return { items: [], total: 0, limit: params.limit ?? 50, offset: params.offset ?? 0, hasMore: false };\n }\n\n // Fetch all records in bulk\n const keys = ids.map((id: string) => this.key(params.domain, id));\n const raws = await this.client.mget(...keys);\n let items: StorageRecord[] = raws\n .filter((r: string | null) => r !== null)\n .map((r: string) => JSON.parse(r));\n\n // Filter\n if (params.filter) {\n items = items.filter((r) => {\n for (const [key, val] of Object.entries(params.filter!)) {\n if (r.data[key] !== val) return false;\n }\n return true;\n });\n }\n\n // Sort\n if (params.orderBy) {\n const dir = params.orderDir === \"desc\" ? -1 : 1;\n const field = params.orderBy;\n items.sort((a, b) => {\n const va = field === \"createdAt\" || field === \"updatedAt\" ? a[field] : a.data[field];\n const vb = field === \"createdAt\" || field === \"updatedAt\" ? b[field] : b.data[field];\n if (va === vb) return 0;\n if (va === undefined || va === null) return 1;\n if (vb === undefined || vb === null) return -1;\n return (va as any) < (vb as any) ? -dir : dir;\n });\n }\n\n const total = items.length;\n const offset = params.offset ?? 0;\n const limit = params.limit ?? 50;\n const paged = items.slice(offset, offset + limit);\n\n return { items: paged, total, limit, offset, hasMore: offset + limit < total };\n }\n\n async count(domain: StorageDomain): Promise<number> {\n return this.client.scard(this.domainKey(domain));\n }\n\n async clear(domain: StorageDomain): Promise<number> {\n const ids: string[] = await this.client.smembers(this.domainKey(domain));\n if (ids.length === 0) return 0;\n\n const keys = ids.map((id) => this.key(domain, id));\n const pipeline = this.client.pipeline();\n for (const k of keys) pipeline.del(k);\n pipeline.del(this.domainKey(domain));\n await pipeline.exec();\n return ids.length;\n }\n\n /** Close the Redis connection */\n async close(): Promise<void> {\n if (this.client) await this.client.quit();\n }\n}\n","// =============================================================================\n// pgvector Vector Store Adapter — Implements VectorStorePort\n// =============================================================================\n//\n// Requires: pg (peer dependency), pgvector extension enabled in PostgreSQL\n//\n// Usage:\n// import { PgVectorStoreAdapter } from 'gauss'\n// const store = new PgVectorStoreAdapter({\n// connectionString: '...',\n// dimensions: 1536,\n// })\n// await store.initialize()\n//\n// =============================================================================\n\nimport type {\n VectorStorePort,\n VectorDocument,\n VectorSearchResult,\n VectorSearchParams,\n VectorIndexStats,\n VectorFilter,\n} from \"../../../ports/vector-store.port.js\";\n\nexport interface PgVectorStoreOptions {\n /** PostgreSQL connection string */\n connectionString: string;\n /** Table name (default: 'gauss_vectors') */\n tableName?: string;\n /** Schema name (default: 'public') */\n schema?: string;\n /** Embedding dimensions (default: 1536 for OpenAI ada-002) */\n dimensions?: number;\n /** Pool size (default: 10) */\n poolSize?: number;\n /** Use HNSW index for approximate search (default: true) */\n useHnsw?: boolean;\n}\n\nexport class PgVectorStoreAdapter implements VectorStorePort {\n private pool: any;\n private readonly table: string;\n private readonly schema: string;\n private readonly dimensions: number;\n private readonly options: PgVectorStoreOptions;\n\n constructor(options: PgVectorStoreOptions) {\n this.options = options;\n this.schema = options.schema ?? \"public\";\n this.dimensions = options.dimensions ?? 1536;\n this.table = `${this.schema}.${options.tableName ?? \"gauss_vectors\"}`;\n }\n\n /** Initialize the adapter — creates table and index */\n async initialize(): Promise<void> {\n const pg = await import(\"pg\");\n const Pool = pg.default?.Pool ?? pg.Pool;\n this.pool = new Pool({\n connectionString: this.options.connectionString,\n max: this.options.poolSize ?? 10,\n });\n\n // Enable pgvector extension\n await this.pool.query(\"CREATE EXTENSION IF NOT EXISTS vector\");\n\n await this.pool.query(`\n CREATE TABLE IF NOT EXISTS ${this.table} (\n id TEXT PRIMARY KEY,\n embedding vector(${this.dimensions}),\n content TEXT NOT NULL DEFAULT '',\n metadata JSONB NOT NULL DEFAULT '{}'\n )\n `);\n\n if (this.options.useHnsw !== false) {\n const indexName = `idx_${(this.options.tableName ?? \"gauss_vectors\")}_hnsw`;\n await this.pool.query(`\n CREATE INDEX IF NOT EXISTS ${indexName}\n ON ${this.table}\n USING hnsw (embedding vector_cosine_ops)\n `);\n }\n }\n\n async upsert(documents: VectorDocument[]): Promise<void> {\n if (documents.length === 0) return;\n\n const values: unknown[] = [];\n const placeholders: string[] = [];\n let idx = 1;\n\n for (const doc of documents) {\n placeholders.push(`($${idx}, $${idx + 1}::vector, $${idx + 2}, $${idx + 3}::jsonb)`);\n values.push(doc.id, `[${doc.embedding.join(\",\")}]`, doc.content, JSON.stringify(doc.metadata));\n idx += 4;\n }\n\n await this.pool.query(\n `INSERT INTO ${this.table} (id, embedding, content, metadata)\n VALUES ${placeholders.join(\", \")}\n ON CONFLICT (id) DO UPDATE SET\n embedding = EXCLUDED.embedding,\n content = EXCLUDED.content,\n metadata = EXCLUDED.metadata`,\n values,\n );\n }\n\n async query(params: VectorSearchParams): Promise<VectorSearchResult[]> {\n const conditions: string[] = [];\n const values: unknown[] = [`[${params.embedding.join(\",\")}]`];\n let paramIdx = 2;\n\n if (params.filter) {\n const filterSql = this.buildFilterSql(params.filter, values, paramIdx);\n if (filterSql.sql) {\n conditions.push(filterSql.sql);\n paramIdx = filterSql.nextIdx;\n }\n }\n\n const where = conditions.length > 0 ? `WHERE ${conditions.join(\" AND \")}` : \"\";\n const selectEmbedding = params.includeEmbeddings ? \", embedding\" : \"\";\n\n const result = await this.pool.query(\n `SELECT id, content, metadata, 1 - (embedding <=> $1::vector) AS score ${selectEmbedding}\n FROM ${this.table}\n ${where}\n ORDER BY embedding <=> $1::vector\n LIMIT $${paramIdx}`,\n [...values, params.topK],\n );\n\n let results: VectorSearchResult[] = result.rows.map((row: any) => ({\n id: row.id,\n content: row.content,\n metadata: typeof row.metadata === \"string\" ? JSON.parse(row.metadata) : row.metadata,\n score: Number(row.score),\n ...(params.includeEmbeddings && row.embedding ? { embedding: row.embedding } : {}),\n }));\n\n if (params.minScore !== undefined) {\n results = results.filter((r) => r.score >= params.minScore!);\n }\n\n return results;\n }\n\n async delete(ids: string[]): Promise<void> {\n if (ids.length === 0) return;\n const placeholders = ids.map((_, i) => `$${i + 1}`).join(\", \");\n await this.pool.query(`DELETE FROM ${this.table} WHERE id IN (${placeholders})`, ids);\n }\n\n async indexStats(): Promise<VectorIndexStats> {\n const result = await this.pool.query(`SELECT COUNT(*) FROM ${this.table}`);\n return {\n totalDocuments: Number(result.rows[0].count),\n dimensions: this.dimensions,\n indexType: this.options.useHnsw !== false ? \"hnsw\" : \"flat\",\n };\n }\n\n /** Close the pool */\n async close(): Promise<void> {\n if (this.pool) await this.pool.end();\n }\n\n // ─── Filter SQL Builder ─────────────────────────────────────────────────\n\n private buildFilterSql(\n filter: VectorFilter,\n values: unknown[],\n startIdx: number,\n ): { sql: string; nextIdx: number } {\n if (\"$and\" in filter) {\n const parts: string[] = [];\n let idx = startIdx;\n for (const sub of (filter as { $and: VectorFilter[] }).$and) {\n const r = this.buildFilterSql(sub, values, idx);\n if (r.sql) parts.push(r.sql);\n idx = r.nextIdx;\n }\n return { sql: parts.length > 0 ? `(${parts.join(\" AND \")})` : \"\", nextIdx: idx };\n }\n\n if (\"$or\" in filter) {\n const parts: string[] = [];\n let idx = startIdx;\n for (const sub of (filter as { $or: VectorFilter[] }).$or) {\n const r = this.buildFilterSql(sub, values, idx);\n if (r.sql) parts.push(r.sql);\n idx = r.nextIdx;\n }\n return { sql: parts.length > 0 ? `(${parts.join(\" OR \")})` : \"\", nextIdx: idx };\n }\n\n if (\"$not\" in filter) {\n const r = this.buildFilterSql((filter as { $not: VectorFilter }).$not, values, startIdx);\n return { sql: r.sql ? `NOT (${r.sql})` : \"\", nextIdx: r.nextIdx };\n }\n\n // Field-level operators\n const parts: string[] = [];\n let idx = startIdx;\n\n for (const [field, condition] of Object.entries(filter)) {\n if (condition !== null && typeof condition === \"object\" && !Array.isArray(condition)) {\n for (const [op, val] of Object.entries(condition as Record<string, unknown>)) {\n const jsonPath = `metadata->>'${field.replace(/'/g, \"''\")}'`;\n switch (op) {\n case \"$eq\":\n parts.push(`${jsonPath} = $${idx}`);\n values.push(String(val));\n idx++;\n break;\n case \"$ne\":\n parts.push(`${jsonPath} != $${idx}`);\n values.push(String(val));\n idx++;\n break;\n case \"$gt\":\n parts.push(`(${jsonPath})::numeric > $${idx}`);\n values.push(val);\n idx++;\n break;\n case \"$gte\":\n parts.push(`(${jsonPath})::numeric >= $${idx}`);\n values.push(val);\n idx++;\n break;\n case \"$lt\":\n parts.push(`(${jsonPath})::numeric < $${idx}`);\n values.push(val);\n idx++;\n break;\n case \"$lte\":\n parts.push(`(${jsonPath})::numeric <= $${idx}`);\n values.push(val);\n idx++;\n break;\n case \"$in\": {\n const arr = val as unknown[];\n const ph = arr.map((_, i) => `$${idx + i}`).join(\", \");\n parts.push(`${jsonPath} IN (${ph})`);\n for (const v of arr) { values.push(String(v)); idx++; }\n break;\n }\n case \"$nin\": {\n const arr = val as unknown[];\n const ph = arr.map((_, i) => `$${idx + i}`).join(\", \");\n parts.push(`${jsonPath} NOT IN (${ph})`);\n for (const v of arr) { values.push(String(v)); idx++; }\n break;\n }\n }\n }\n } else {\n // Direct equality\n const jsonPath = `metadata->>'${field.replace(/'/g, \"''\")}'`;\n parts.push(`${jsonPath} = $${idx}`);\n values.push(String(condition));\n idx++;\n }\n }\n\n return { sql: parts.join(\" AND \"), nextIdx: idx };\n }\n}\n","// =============================================================================\n// S3 Object Storage Adapter — Implements ObjectStoragePort\n// =============================================================================\n//\n// Requires: @aws-sdk/client-s3 (peer dependency)\n// Optionally: @aws-sdk/s3-request-presigner for signed URLs\n//\n// Usage:\n// import { S3ObjectStorageAdapter } from 'gauss'\n// const storage = new S3ObjectStorageAdapter({\n// bucket: 'my-bucket',\n// region: 'us-east-1',\n// })\n//\n// =============================================================================\n\nimport type {\n ObjectStoragePort,\n ObjectStorageMetadata,\n StoredObject,\n ListObjectsResult,\n} from \"../../../ports/object-storage.port.js\";\n\nexport interface S3ObjectStorageOptions {\n /** S3 bucket name */\n bucket: string;\n /** AWS region (default: from env AWS_REGION) */\n region?: string;\n /** Key prefix for all objects (default: '') */\n prefix?: string;\n /** Endpoint URL (for S3-compatible services like MinIO, R2, etc.) */\n endpoint?: string;\n /** Force path-style addressing (default: false, set true for MinIO) */\n forcePathStyle?: boolean;\n}\n\nexport class S3ObjectStorageAdapter implements ObjectStoragePort {\n private client: any;\n private readonly bucket: string;\n private readonly prefix: string;\n private readonly options: S3ObjectStorageOptions;\n\n constructor(options: S3ObjectStorageOptions) {\n this.options = options;\n this.bucket = options.bucket;\n this.prefix = options.prefix ?? \"\";\n }\n\n /** Lazily initialize the S3 client */\n private async getClient(): Promise<any> {\n if (this.client) return this.client;\n const { S3Client } = await import(\"@aws-sdk/client-s3\");\n this.client = new S3Client({\n region: this.options.region,\n ...(this.options.endpoint ? { endpoint: this.options.endpoint } : {}),\n ...(this.options.forcePathStyle ? { forcePathStyle: true } : {}),\n });\n return this.client;\n }\n\n private fullKey(key: string): string {\n return this.prefix ? `${this.prefix}/${key}` : key;\n }\n\n async put(\n key: string,\n body: Buffer | Uint8Array | string,\n metadata?: ObjectStorageMetadata,\n ): Promise<void> {\n const client = await this.getClient();\n const { PutObjectCommand } = await import(\"@aws-sdk/client-s3\");\n await client.send(\n new PutObjectCommand({\n Bucket: this.bucket,\n Key: this.fullKey(key),\n Body: typeof body === \"string\" ? Buffer.from(body, \"utf-8\") : body,\n ContentType: metadata?.contentType ?? \"application/octet-stream\",\n }),\n );\n }\n\n async get(key: string): Promise<StoredObject | null> {\n try {\n const client = await this.getClient();\n const { GetObjectCommand } = await import(\"@aws-sdk/client-s3\");\n const response = await client.send(\n new GetObjectCommand({\n Bucket: this.bucket,\n Key: this.fullKey(key),\n }),\n );\n const bodyBytes = await response.Body?.transformToByteArray();\n return {\n key,\n body: bodyBytes ? Buffer.from(bodyBytes) : Buffer.alloc(0),\n metadata: {\n contentType: response.ContentType,\n contentLength: response.ContentLength,\n lastModified: response.LastModified,\n etag: response.ETag,\n },\n };\n } catch (err: any) {\n if (err.name === \"NoSuchKey\" || err.$metadata?.httpStatusCode === 404) {\n return null;\n }\n throw err;\n }\n }\n\n async delete(key: string): Promise<boolean> {\n try {\n const client = await this.getClient();\n const { DeleteObjectCommand } = await import(\"@aws-sdk/client-s3\");\n await client.send(\n new DeleteObjectCommand({\n Bucket: this.bucket,\n Key: this.fullKey(key),\n }),\n );\n return true;\n } catch {\n return false;\n }\n }\n\n async exists(key: string): Promise<boolean> {\n try {\n const client = await this.getClient();\n const { HeadObjectCommand } = await import(\"@aws-sdk/client-s3\");\n await client.send(\n new HeadObjectCommand({\n Bucket: this.bucket,\n Key: this.fullKey(key),\n }),\n );\n return true;\n } catch {\n return false;\n }\n }\n\n async list(\n prefix?: string,\n maxKeys?: number,\n continuationToken?: string,\n ): Promise<ListObjectsResult> {\n const client = await this.getClient();\n const { ListObjectsV2Command } = await import(\"@aws-sdk/client-s3\");\n const fullPrefix = prefix\n ? this.fullKey(prefix)\n : this.prefix || undefined;\n\n const response = await client.send(\n new ListObjectsV2Command({\n Bucket: this.bucket,\n Prefix: fullPrefix,\n MaxKeys: maxKeys ?? 1000,\n ContinuationToken: continuationToken,\n }),\n );\n\n return {\n objects: (response.Contents ?? []).map((obj: any) => ({\n key: this.prefix ? obj.Key.slice(this.prefix.length + 1) : obj.Key,\n size: obj.Size ?? 0,\n lastModified: obj.LastModified ?? new Date(),\n })),\n continuationToken: response.NextContinuationToken,\n isTruncated: response.IsTruncated ?? false,\n };\n }\n\n async getSignedUrl(key: string, expiresInSeconds = 3600): Promise<string> {\n const client = await this.getClient();\n const { GetObjectCommand } = await import(\"@aws-sdk/client-s3\");\n const { getSignedUrl } = await import(\"@aws-sdk/s3-request-presigner\");\n return getSignedUrl(\n client,\n new GetObjectCommand({ Bucket: this.bucket, Key: this.fullKey(key) }),\n { expiresIn: expiresInSeconds },\n );\n }\n}\n","// =============================================================================\n// BullMQ Queue Adapter — Implements QueuePort\n// =============================================================================\n//\n// Requires: bullmq, ioredis (peer dependencies)\n//\n// Usage:\n// import { BullMQQueueAdapter } from 'gauss'\n// const queue = new BullMQQueueAdapter({ queueName: 'agent-tasks', redisUrl: '...' })\n// await queue.add('process', { agentId: '123' })\n// await queue.process(async (job) => { /* ... */ })\n//\n// =============================================================================\n\nimport type {\n QueuePort,\n QueueJob,\n QueueJobOptions,\n QueueJobResult,\n QueueProcessor,\n} from \"../../../ports/queue.port.js\";\n\nexport interface BullMQQueueOptions {\n /** Queue name */\n queueName: string;\n /** Redis connection URL (default: redis://localhost:6379) */\n redisUrl?: string;\n /** Default job options */\n defaultJobOptions?: QueueJobOptions;\n}\n\nexport class BullMQQueueAdapter implements QueuePort {\n private queue: any;\n private worker: any;\n private readonly options: BullMQQueueOptions;\n\n constructor(options: BullMQQueueOptions) {\n this.options = options;\n }\n\n /** Lazily initialize the BullMQ Queue */\n private async getQueue(): Promise<any> {\n if (this.queue) return this.queue;\n const { Queue } = await import(\"bullmq\");\n const connection = this.parseRedisUrl(this.options.redisUrl ?? \"redis://localhost:6379\");\n this.queue = new Queue(this.options.queueName, {\n connection,\n defaultJobOptions: this.toBullMQOpts(this.options.defaultJobOptions),\n });\n return this.queue;\n }\n\n async add<T = Record<string, unknown>>(\n name: string,\n data: T,\n opts?: QueueJobOptions,\n ): Promise<QueueJob<T>> {\n const queue = await this.getQueue();\n const job = await queue.add(name, data, this.toBullMQOpts(opts));\n return {\n id: job.id!,\n name: job.name,\n data: job.data as T,\n opts,\n };\n }\n\n async process<T = Record<string, unknown>>(\n handler: QueueProcessor<T>,\n concurrency = 1,\n ): Promise<void> {\n const { Worker } = await import(\"bullmq\");\n const connection = this.parseRedisUrl(this.options.redisUrl ?? \"redis://localhost:6379\");\n this.worker = new Worker(\n this.options.queueName,\n async (job: any) => {\n return handler({\n id: job.id!,\n name: job.name,\n data: job.data as T,\n });\n },\n { connection, concurrency },\n );\n }\n\n async getJob(id: string): Promise<QueueJobResult | null> {\n const queue = await this.getQueue();\n const job = await queue.getJob(id);\n if (!job) return null;\n\n const state = await job.getState();\n return {\n id: job.id!,\n name: job.name,\n data: job.data,\n status: state as QueueJobResult[\"status\"],\n progress: typeof job.progress === \"number\" ? job.progress : 0,\n returnvalue: job.returnvalue,\n failedReason: job.failedReason,\n attemptsMade: job.attemptsMade,\n timestamp: job.timestamp,\n finishedOn: job.finishedOn,\n };\n }\n\n async pause(): Promise<void> {\n const queue = await this.getQueue();\n await queue.pause();\n }\n\n async resume(): Promise<void> {\n const queue = await this.getQueue();\n await queue.resume();\n }\n\n async close(): Promise<void> {\n if (this.worker) await this.worker.close();\n if (this.queue) await this.queue.close();\n }\n\n // ─── Helpers ──────────────────────────────────────────────────────────\n\n private toBullMQOpts(opts?: QueueJobOptions): Record<string, unknown> | undefined {\n if (!opts) return undefined;\n return {\n delay: opts.delay,\n attempts: opts.attempts,\n backoff: opts.backoff,\n priority: opts.priority,\n removeOnComplete: opts.removeOnComplete,\n removeOnFail: opts.removeOnFail,\n };\n }\n\n private parseRedisUrl(url: string): { host: string; port: number; password?: string } {\n const parsed = new URL(url);\n return {\n host: parsed.hostname,\n port: Number(parsed.port) || 6379,\n ...(parsed.password ? { password: parsed.password } : {}),\n };\n }\n}\n","// =============================================================================\n// FileLearningAdapter — File-backed persistent learning\n// =============================================================================\n\nimport type { LearningPort } from \"../../ports/learning.port.js\";\nimport type { UserProfile, UserMemory, UserMemoryInput, SharedKnowledge, SharedKnowledgeInput } from \"../../domain/learning.schema.js\";\n\nexport interface FileLearningOptions {\n readFile: (path: string) => Promise<string>;\n writeFile: (path: string, content: string) => Promise<void>;\n exists: (path: string) => Promise<boolean>;\n /** Base directory for learning data */\n baseDir: string;\n resolve: (...parts: string[]) => string;\n}\n\ninterface LearningStore {\n profiles: Record<string, UserProfile>;\n memories: Record<string, UserMemory[]>;\n knowledge: SharedKnowledge[];\n}\n\nexport class FileLearningAdapter implements LearningPort {\n private readonly opts: FileLearningOptions;\n private store: LearningStore = { profiles: {}, memories: {}, knowledge: [] };\n private loaded = false;\n private writeQueue: Promise<void> = Promise.resolve();\n\n constructor(options: FileLearningOptions) {\n this.opts = options;\n }\n\n private get filePath(): string {\n return this.opts.resolve(this.opts.baseDir, \"learning-store.json\");\n }\n\n private async load(): Promise<void> {\n if (this.loaded) return;\n try {\n if (await this.opts.exists(this.filePath)) {\n const raw = await this.opts.readFile(this.filePath);\n this.store = JSON.parse(raw);\n }\n } catch {\n // Start fresh on corrupted file\n }\n this.loaded = true;\n }\n\n private async save(): Promise<void> {\n // Serialize writes to prevent race conditions\n const prev = this.writeQueue;\n this.writeQueue = prev.then(() =>\n this.opts.writeFile(this.filePath, JSON.stringify(this.store, null, 2)),\n );\n await this.writeQueue;\n }\n\n // -- Profile --\n async getProfile(userId: string): Promise<UserProfile | null> {\n await this.load();\n return this.store.profiles[userId] ?? null;\n }\n\n async updateProfile(\n userId: string,\n updates: Partial<Omit<UserProfile, \"userId\" | \"createdAt\">>,\n ): Promise<UserProfile> {\n await this.load();\n const existing = this.store.profiles[userId];\n const profile: UserProfile = {\n ...(existing ?? { userId, createdAt: Date.now() }),\n ...updates,\n userId,\n } as UserProfile;\n this.store.profiles[userId] = profile;\n await this.save();\n return profile;\n }\n\n async deleteProfile(userId: string): Promise<void> {\n await this.load();\n delete this.store.profiles[userId];\n await this.save();\n }\n\n // -- Memories --\n async addMemory(\n userId: string,\n memory: Omit<UserMemoryInput, \"id\" | \"createdAt\">,\n ): Promise<UserMemory> {\n await this.load();\n const id = `mem-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;\n const entry: UserMemory = {\n ...memory,\n id,\n createdAt: Date.now(),\n } as UserMemory;\n\n if (!this.store.memories[userId]) {\n this.store.memories[userId] = [];\n }\n this.store.memories[userId].push(entry);\n await this.save();\n return entry;\n }\n\n async getMemories(\n userId: string,\n options?: { tags?: string[]; limit?: number; since?: number },\n ): Promise<UserMemory[]> {\n await this.load();\n let memories = this.store.memories[userId] ?? [];\n\n if (options?.since) {\n memories = memories.filter((m) => m.createdAt >= options.since!);\n }\n if (options?.tags && options.tags.length > 0) {\n memories = memories.filter((m) =>\n options.tags!.some((t) => m.tags?.includes(t)),\n );\n }\n if (options?.limit) {\n memories = memories.slice(-options.limit);\n }\n\n return memories;\n }\n\n async deleteMemory(userId: string, memoryId: string): Promise<void> {\n await this.load();\n const mems = this.store.memories[userId];\n if (mems) {\n this.store.memories[userId] = mems.filter((m) => m.id !== memoryId);\n await this.save();\n }\n }\n\n async clearMemories(userId: string): Promise<void> {\n await this.load();\n delete this.store.memories[userId];\n await this.save();\n }\n\n // -- Knowledge --\n async addKnowledge(\n knowledge: Omit<SharedKnowledgeInput, \"id\" | \"createdAt\" | \"usageCount\">,\n ): Promise<SharedKnowledge> {\n await this.load();\n const id = `know-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;\n const entry: SharedKnowledge = {\n ...knowledge,\n id,\n createdAt: Date.now(),\n usageCount: 0,\n } as SharedKnowledge;\n this.store.knowledge.push(entry);\n await this.save();\n return entry;\n }\n\n async queryKnowledge(\n query: string,\n options?: { category?: string; limit?: number },\n ): Promise<SharedKnowledge[]> {\n await this.load();\n let results = this.store.knowledge;\n const q = query.toLowerCase();\n\n results = results.filter((k) => {\n const text = JSON.stringify(k).toLowerCase();\n return text.includes(q);\n });\n\n if (options?.category) {\n results = results.filter((k) => k.category === options.category);\n }\n\n if (options?.limit) {\n results = results.slice(0, options.limit);\n }\n\n return results;\n }\n\n async incrementKnowledgeUsage(knowledgeId: string): Promise<void> {\n await this.load();\n const entry = this.store.knowledge.find((k) => k.id === knowledgeId);\n if (entry) {\n entry.usageCount++;\n await this.save();\n }\n }\n\n async deleteKnowledge(knowledgeId: string): Promise<void> {\n await this.load();\n this.store.knowledge = this.store.knowledge.filter((k) => k.id !== knowledgeId);\n await this.save();\n }\n}\n","// =============================================================================\n// InMemoryVoiceAdapter — Mock voice adapter for testing\n// =============================================================================\n\nimport type { VoicePort, VoiceConfig, VoiceEvent, VoiceEventListener } from \"../../ports/voice.port.js\";\n\nexport class InMemoryVoiceAdapter implements VoicePort {\n private listeners: VoiceEventListener[] = [];\n private connected = false;\n /** Custom speak handler for testing (returns mock audio) */\n speakHandler: (text: string) => Uint8Array;\n /** Custom listen handler for testing (returns mock transcript) */\n listenHandler: (audio: Uint8Array) => string;\n\n constructor(opts?: {\n speakHandler?: (text: string) => Uint8Array;\n listenHandler?: (audio: Uint8Array) => string;\n }) {\n this.speakHandler = opts?.speakHandler ?? ((text) => new TextEncoder().encode(text));\n this.listenHandler = opts?.listenHandler ?? (() => \"mock transcript\");\n }\n\n async speak(text: string, _config?: VoiceConfig): Promise<Uint8Array> {\n const audio = this.speakHandler(text);\n this.emit({ type: \"speaking\", text });\n this.emit({ type: \"audio\", data: audio });\n return audio;\n }\n\n async listen(audio: Uint8Array, _config?: VoiceConfig): Promise<string> {\n this.emit({ type: \"listening\" });\n const text = this.listenHandler(audio);\n this.emit({ type: \"transcript\", text, isFinal: true });\n return text;\n }\n\n async connect(_config?: VoiceConfig): Promise<void> {\n this.connected = true;\n this.emit({ type: \"connected\" });\n }\n\n async disconnect(): Promise<void> {\n this.connected = false;\n this.emit({ type: \"disconnected\" });\n }\n\n on(listener: VoiceEventListener): () => void {\n this.listeners.push(listener);\n return () => { this.listeners = this.listeners.filter(l => l !== listener); };\n }\n\n isConnected(): boolean {\n return this.connected;\n }\n\n private emit(event: VoiceEvent): void {\n for (const listener of this.listeners) {\n try { listener(event); } catch { /* isolated */ }\n }\n }\n}\n","// =============================================================================\n// InMemoryDatasetsAdapter — In-memory dataset management\n// =============================================================================\n\nimport type { DatasetsPort, DatasetEntry, DatasetInfo, DatasetQuery } from \"../../ports/datasets.port.js\";\nimport { randomUUID } from \"node:crypto\";\n\ninterface Dataset {\n info: DatasetInfo;\n entries: Map<string, DatasetEntry>;\n metadata?: Record<string, unknown>;\n}\n\nlet idCounter = 0;\n\nexport class InMemoryDatasetsAdapter implements DatasetsPort {\n private datasets = new Map<string, Dataset>();\n\n async create(name: string, metadata?: Record<string, unknown>): Promise<DatasetInfo> {\n if (this.datasets.has(name)) throw new Error(`Dataset \"${name}\" already exists`);\n const now = Date.now();\n const info: DatasetInfo = { name, version: 1, entryCount: 0, createdAt: now, updatedAt: now };\n this.datasets.set(name, { info, entries: new Map(), metadata });\n return { ...info };\n }\n\n async insert(name: string, entries: Omit<DatasetEntry, \"id\" | \"createdAt\">[]): Promise<string[]> {\n const ds = this.datasets.get(name);\n if (!ds) throw new Error(`Dataset \"${name}\" not found`);\n const ids: string[] = [];\n for (const entry of entries) {\n const id = randomUUID();\n const full: DatasetEntry = { id, data: entry.data, metadata: entry.metadata, createdAt: Date.now() };\n ds.entries.set(id, full);\n ids.push(id);\n }\n ds.info.entryCount = ds.entries.size;\n ds.info.updatedAt = Date.now();\n return ids;\n }\n\n async query(name: string, query?: DatasetQuery): Promise<DatasetEntry[]> {\n const ds = this.datasets.get(name);\n if (!ds) throw new Error(`Dataset \"${name}\" not found`);\n let results = [...ds.entries.values()];\n\n // Filter\n if (query?.filter) {\n results = results.filter(e =>\n Object.entries(query.filter!).every(([k, v]) => e.data[k] === v),\n );\n }\n\n // Sort\n if (query?.sort) {\n const { field, order } = query.sort;\n results.sort((a, b) => {\n const av = a.data[field] as string | number, bv = b.data[field] as string | number;\n const cmp = av < bv ? -1 : av > bv ? 1 : 0;\n return order === \"desc\" ? -cmp : cmp;\n });\n }\n\n // Pagination\n const offset = query?.offset ?? 0;\n const limit = query?.limit ?? results.length;\n return results.slice(offset, offset + limit);\n }\n\n async remove(name: string): Promise<void> {\n if (!this.datasets.delete(name)) throw new Error(`Dataset \"${name}\" not found`);\n }\n\n async list(): Promise<DatasetInfo[]> {\n return [...this.datasets.values()].map(ds => ({ ...ds.info }));\n }\n\n async info(name: string): Promise<DatasetInfo | undefined> {\n const ds = this.datasets.get(name);\n return ds ? { ...ds.info } : undefined;\n }\n\n async version(name: string): Promise<number> {\n const ds = this.datasets.get(name);\n if (!ds) throw new Error(`Dataset \"${name}\" not found`);\n ds.info.version++;\n ds.info.updatedAt = Date.now();\n return ds.info.version;\n }\n}\n","// =============================================================================\n// InMemoryDeployerAdapter — Mock deployer for testing & local dev\n// =============================================================================\n\nimport type { DeployerPort, DeploymentConfig, DeploymentInfo } from \"../../ports/deployer.port.js\";\nimport { randomUUID } from \"node:crypto\";\n\nlet deployCounter = 0;\n\nexport class InMemoryDeployerAdapter implements DeployerPort {\n private deployments = new Map<string, DeploymentInfo>();\n\n async build(config: DeploymentConfig): Promise<{ artifactPath: string; size: number }> {\n return { artifactPath: `/tmp/builds/${config.name}.tar.gz`, size: 1024 };\n }\n\n async deploy(config: DeploymentConfig): Promise<DeploymentInfo> {\n const id = randomUUID();\n const existing = [...this.deployments.values()].filter(d => d.name === config.name);\n const version = existing.length + 1;\n const now = Date.now();\n const info: DeploymentInfo = {\n id,\n name: config.name,\n status: \"ready\",\n url: `https://${config.name}.local.dev`,\n version,\n createdAt: now,\n updatedAt: now,\n metadata: config.metadata,\n };\n this.deployments.set(id, info);\n return { ...info };\n }\n\n async status(deploymentId: string): Promise<DeploymentInfo | undefined> {\n const d = this.deployments.get(deploymentId);\n return d ? { ...d } : undefined;\n }\n\n async rollback(deploymentId: string, targetVersion?: number): Promise<DeploymentInfo> {\n const d = this.deployments.get(deploymentId);\n if (!d) throw new Error(`Deployment \"${deploymentId}\" not found`);\n\n // Mark current as rolled back\n d.status = \"rolled_back\";\n d.updatedAt = Date.now();\n\n // If target version specified, create a new deployment from it\n if (targetVersion !== undefined) {\n const target = [...this.deployments.values()].find(\n dep => dep.name === d.name && dep.version === targetVersion,\n );\n if (!target) throw new Error(`Version ${targetVersion} not found for \"${d.name}\"`);\n\n const id = randomUUID();\n const restored: DeploymentInfo = {\n id,\n name: d.name,\n status: \"ready\",\n url: target.url,\n version: Math.max(...[...this.deployments.values()].filter(x => x.name === d.name).map(x => x.version)) + 1,\n createdAt: Date.now(),\n updatedAt: Date.now(),\n metadata: target.metadata,\n };\n this.deployments.set(id, restored);\n return { ...restored };\n }\n\n return { ...d };\n }\n\n async list(name?: string): Promise<DeploymentInfo[]> {\n const all = [...this.deployments.values()];\n return name ? all.filter(d => d.name === name) : all;\n }\n\n async remove(deploymentId: string): Promise<void> {\n if (!this.deployments.delete(deploymentId)) throw new Error(`Deployment \"${deploymentId}\" not found`);\n }\n}\n","// =============================================================================\n// Local Plugin Cache — Helpers for managing installed plugins on disk\n// =============================================================================\n\nimport { homedir } from \"node:os\";\nimport { join, resolve, sep } from \"node:path\";\nimport { mkdirSync, writeFileSync, readFileSync, readdirSync, rmSync, existsSync } from \"node:fs\";\n\nimport type { MarketplacePluginManifest } from \"../../ports/plugin-manifest.port.js\";\n\nconst PLUGINS_ROOT = join(homedir(), \".gauss\", \"plugins\");\n\n/** Validates plugin name to prevent path traversal */\nfunction assertSafeName(name: string): void {\n if (!name || /[/\\\\]/.test(name) || name.includes(\"..\") || name === \".\" || name === \"..\") {\n throw new Error(`Invalid plugin name: \"${name}\" — must not contain path separators or traversal`);\n }\n const resolved = resolve(PLUGINS_ROOT, name);\n if (!resolved.startsWith(PLUGINS_ROOT + sep)) {\n throw new Error(`Invalid plugin name: \"${name}\" — path escapes plugins directory`);\n }\n}\n\n/** Returns the directory for a named plugin */\nexport function getPluginDir(name: string): string {\n assertSafeName(name);\n return join(PLUGINS_ROOT, name);\n}\n\n/** Writes manifest.json into the plugin directory (creates dir if needed) */\nexport function saveManifest(manifest: MarketplacePluginManifest): void {\n const dir = getPluginDir(manifest.name);\n mkdirSync(dir, { recursive: true });\n writeFileSync(join(dir, \"manifest.json\"), JSON.stringify(manifest, null, 2));\n}\n\n/** Reads all installed plugin manifests from disk */\nexport function readInstalledManifests(): MarketplacePluginManifest[] {\n if (!existsSync(PLUGINS_ROOT)) return [];\n\n const entries = readdirSync(PLUGINS_ROOT, { withFileTypes: true });\n const manifests: MarketplacePluginManifest[] = [];\n\n for (const entry of entries) {\n if (!entry.isDirectory()) continue;\n const manifestPath = join(PLUGINS_ROOT, entry.name, \"manifest.json\");\n if (!existsSync(manifestPath)) continue;\n try {\n const raw = readFileSync(manifestPath, \"utf-8\");\n manifests.push(JSON.parse(raw) as MarketplacePluginManifest);\n } catch {\n // skip corrupted manifests\n }\n }\n\n return manifests;\n}\n\n/** Removes a plugin directory entirely */\nexport function removePluginDir(name: string): void {\n const dir = getPluginDir(name);\n if (existsSync(dir)) {\n rmSync(dir, { recursive: true, force: true });\n }\n}\n","// =============================================================================\n// GitHub Registry Adapter — Fetches plugin manifests from a GitHub-hosted registry\n// =============================================================================\n\nimport type {\n MarketplacePluginManifest,\n MarketplacePort,\n} from \"../../ports/plugin-manifest.port.js\";\nimport {\n saveManifest,\n readInstalledManifests,\n removePluginDir,\n} from \"./local-cache.js\";\n\nconst DEFAULT_REGISTRY_URL =\n \"https://raw.githubusercontent.com/giulio-leone/gauss-plugins/main/registry.json\";\n\nexport interface GitHubRegistryOptions {\n registryUrl?: string;\n}\n\nexport class GitHubRegistryAdapter implements MarketplacePort {\n private readonly registryUrl: string;\n\n constructor(options?: GitHubRegistryOptions) {\n this.registryUrl = options?.registryUrl ?? DEFAULT_REGISTRY_URL;\n }\n\n async search(query: string): Promise<MarketplacePluginManifest[]> {\n const manifests = await this.fetchRegistry();\n const lower = query.toLowerCase();\n return manifests.filter(\n (m) =>\n m.name.toLowerCase().includes(lower) ||\n m.description.toLowerCase().includes(lower) ||\n m.tags?.some((t) => t.toLowerCase().includes(lower)),\n );\n }\n\n async getManifest(name: string): Promise<MarketplacePluginManifest | null> {\n const manifests = await this.fetchRegistry();\n return manifests.find((m) => m.name === name) ?? null;\n }\n\n async listInstalled(): Promise<MarketplacePluginManifest[]> {\n return readInstalledManifests();\n }\n\n async install(name: string): Promise<void> {\n const manifest = await this.getManifest(name);\n if (!manifest) {\n throw new Error(`Plugin \"${name}\" not found in registry.`);\n }\n saveManifest(manifest);\n }\n\n async uninstall(name: string): Promise<void> {\n removePluginDir(name);\n }\n\n // ─── Private ────────────────────────────────────────────────────────────\n\n private async fetchRegistry(): Promise<MarketplacePluginManifest[]> {\n let response: Response;\n try {\n response = await fetch(this.registryUrl);\n } catch (err) {\n throw new Error(\n `Failed to fetch plugin registry: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n\n if (!response.ok) {\n throw new Error(\n `Registry returned HTTP ${response.status}: ${response.statusText}`,\n );\n }\n\n let data: unknown;\n try {\n data = await response.json();\n } catch {\n throw new Error(\"Registry returned invalid JSON.\");\n }\n\n if (!Array.isArray(data)) {\n throw new Error(\"Registry JSON is not an array.\");\n }\n\n return data.filter(\n (item): item is MarketplacePluginManifest =>\n typeof item === \"object\" &&\n item !== null &&\n typeof (item as Record<string, unknown>).name === \"string\" &&\n typeof (item as Record<string, unknown>).version === \"string\" &&\n typeof (item as Record<string, unknown>).description === \"string\" &&\n typeof (item as Record<string, unknown>).author === \"string\" &&\n typeof (item as Record<string, unknown>).entry === \"string\",\n );\n }\n}\n","// =============================================================================\n// npm Registry Adapter — Discovers plugins from npm registry\n// =============================================================================\n\nimport type {\n MarketplacePluginManifest,\n MarketplacePort,\n} from \"../../ports/plugin-manifest.port.js\";\nimport { saveManifest, readInstalledManifests, removePluginDir } from \"./local-cache.js\";\n\nconst NPM_REGISTRY_URL = \"https://registry.npmjs.org\";\n\nexport interface NpmRegistryOptions {\n /** npm scope to search within (e.g. \"@gauss\") */\n scope?: string;\n /** npm registry URL override */\n registryUrl?: string;\n /** Search keyword prefix (default: \"gauss-plugin\") */\n keyword?: string;\n}\n\ninterface NpmSearchResult {\n objects: Array<{\n package: {\n name: string;\n version: string;\n description: string;\n author?: { name: string } | string;\n keywords?: string[];\n links?: { npm?: string; repository?: string };\n };\n }>;\n}\n\ninterface NpmPackageVersion {\n name: string;\n version: string;\n description: string;\n author?: { name: string } | string;\n keywords?: string[];\n main?: string;\n module?: string;\n gauss?: {\n entry?: string;\n tags?: string[];\n };\n}\n\nexport class NpmRegistryAdapter implements MarketplacePort {\n private readonly registryUrl: string;\n private readonly scope: string | undefined;\n private readonly keyword: string;\n\n constructor(options?: NpmRegistryOptions) {\n this.registryUrl = options?.registryUrl ?? NPM_REGISTRY_URL;\n this.scope = options?.scope;\n this.keyword = options?.keyword ?? \"gauss-plugin\";\n }\n\n async search(query: string): Promise<MarketplacePluginManifest[]> {\n const searchTerms = this.scope\n ? `${query} scope:${this.scope}`\n : `${query} keywords:${this.keyword}`;\n\n const url = `${this.registryUrl}/-/v1/search?text=${encodeURIComponent(searchTerms)}&size=50`;\n const response = await this.safeFetch(url);\n let data: NpmSearchResult;\n try {\n data = (await response.json()) as NpmSearchResult;\n } catch {\n return [];\n }\n\n return (data.objects ?? []).map((obj) => this.toManifest(obj.package));\n }\n\n async getManifest(name: string): Promise<MarketplacePluginManifest | null> {\n const url = `${this.registryUrl}/${encodeURIComponent(name)}/latest`;\n let response: Response;\n try {\n response = await this.safeFetch(url);\n } catch {\n return null;\n }\n\n if (!response.ok) return null;\n\n let pkg: NpmPackageVersion;\n try {\n pkg = (await response.json()) as NpmPackageVersion;\n } catch {\n return null;\n }\n return this.toManifest(pkg);\n }\n\n async listInstalled(): Promise<MarketplacePluginManifest[]> {\n return readInstalledManifests();\n }\n\n async install(name: string): Promise<void> {\n const manifest = await this.getManifest(name);\n if (!manifest) throw new Error(`Package \"${name}\" not found on npm.`);\n manifest.source = \"npm\";\n saveManifest(manifest);\n }\n\n async uninstall(name: string): Promise<void> {\n removePluginDir(name);\n }\n\n // ─── Private ────────────────────────────────────────────────────────────\n\n private async safeFetch(url: string): Promise<Response> {\n let response: Response;\n try {\n response = await fetch(url);\n } catch (err) {\n throw new Error(\n `Failed to fetch npm registry: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n if (!response.ok) {\n throw new Error(`npm registry returned HTTP ${response.status}: ${response.statusText}`);\n }\n return response;\n }\n\n private toManifest(\n pkg: NpmPackageVersion | NpmSearchResult[\"objects\"][0][\"package\"],\n ): MarketplacePluginManifest {\n const author =\n typeof pkg.author === \"string\"\n ? pkg.author\n : pkg.author?.name ?? \"unknown\";\n\n const gf = \"gauss\" in pkg ? (pkg as NpmPackageVersion).gauss : undefined;\n\n return {\n name: pkg.name,\n version: pkg.version,\n description: pkg.description ?? \"\",\n author,\n entry: gf?.entry ?? (\"main\" in pkg ? (pkg as NpmPackageVersion).main : undefined) ?? \"./index.js\",\n tags: gf?.tags ?? pkg.keywords,\n source: \"npm\",\n };\n }\n}\n","// =============================================================================\n// Composite Marketplace Adapter — Combines multiple registry sources\n// =============================================================================\n\nimport type {\n MarketplacePluginManifest,\n MarketplacePort,\n} from \"../../ports/plugin-manifest.port.js\";\n\nexport interface CompositeMarketplaceOptions {\n /** Registries to search, in priority order */\n registries: MarketplacePort[];\n /** Deduplicate by plugin name (first source wins). Default: true */\n deduplicate?: boolean;\n}\n\nexport class CompositeMarketplaceAdapter implements MarketplacePort {\n private readonly registries: MarketplacePort[];\n private readonly deduplicate: boolean;\n\n constructor(options: CompositeMarketplaceOptions) {\n if (options.registries.length === 0) {\n throw new Error(\"CompositeMarketplaceAdapter requires at least one registry\");\n }\n this.registries = options.registries;\n this.deduplicate = options.deduplicate ?? true;\n }\n\n async search(query: string): Promise<MarketplacePluginManifest[]> {\n const results = await Promise.allSettled(\n this.registries.map((r) => r.search(query)),\n );\n\n const all: MarketplacePluginManifest[] = [];\n for (const result of results) {\n if (result.status === \"fulfilled\") {\n all.push(...result.value);\n }\n }\n\n if (!this.deduplicate) return all;\n\n const seen = new Set<string>();\n return all.filter((m) => {\n if (seen.has(m.name)) return false;\n seen.add(m.name);\n return true;\n });\n }\n\n async getManifest(name: string): Promise<MarketplacePluginManifest | null> {\n for (const registry of this.registries) {\n try {\n const manifest = await registry.getManifest(name);\n if (manifest) return manifest;\n } catch {\n // try next registry\n }\n }\n return null;\n }\n\n async listInstalled(): Promise<MarketplacePluginManifest[]> {\n // All registries share the same local cache\n return this.registries[0].listInstalled();\n }\n\n async install(name: string): Promise<void> {\n const manifest = await this.getManifest(name);\n if (!manifest) {\n throw new Error(`Plugin \"${name}\" not found in any registry.`);\n }\n // Delegate to the first registry that has the plugin\n for (const registry of this.registries) {\n try {\n const m = await registry.getManifest(name);\n if (m) {\n await registry.install(name);\n return;\n }\n } catch {\n // try next\n }\n }\n throw new Error(`Failed to install \"${name}\" from any registry.`);\n }\n\n async uninstall(name: string): Promise<void> {\n await this.registries[0].uninstall(name);\n }\n}\n","// =============================================================================\n// Plugin Loader — Dynamically loads installed marketplace plugins\n// =============================================================================\n\nimport type { MarketplacePluginManifest, MarketplacePort } from \"../../ports/plugin-manifest.port.js\";\nimport type { Plugin } from \"../../ports/plugin.port.js\";\nimport { getPluginDir } from \"./local-cache.js\";\nimport { join, resolve, sep } from \"node:path\";\n\nexport interface LoadedPlugin {\n manifest: MarketplacePluginManifest;\n plugin: Plugin;\n}\n\nexport interface PluginLoaderOptions {\n /** Validate plugin exports before loading. Default: true */\n validate?: boolean;\n}\n\n/**\n * Loads marketplace plugins from disk into executable Plugin instances.\n * Plugins must export a default Plugin or `{ plugin: Plugin }`.\n */\nexport class PluginLoader {\n private readonly validate: boolean;\n\n constructor(options?: PluginLoaderOptions) {\n this.validate = options?.validate ?? true;\n }\n\n /**\n * Load a single installed plugin by name.\n * Resolves the entry path from manifest and dynamically imports.\n */\n async load(manifest: MarketplacePluginManifest): Promise<LoadedPlugin> {\n const dir = getPluginDir(manifest.name);\n const entryPath = resolve(join(dir, manifest.entry));\n\n // Prevent path traversal — entry must stay within plugin directory\n if (!entryPath.startsWith(dir + sep) && entryPath !== dir) {\n throw new Error(\n `Invalid entry path: \"${manifest.entry}\" escapes plugin directory for \"${manifest.name}\"`,\n );\n }\n\n let mod: Record<string, unknown>;\n try {\n mod = (await import(entryPath)) as Record<string, unknown>;\n } catch (err) {\n throw new Error(\n `Failed to load plugin \"${manifest.name}\" from ${entryPath}: ${\n err instanceof Error ? err.message : String(err)\n }`,\n );\n }\n\n const plugin = this.extractPlugin(mod, manifest.name);\n if (this.validate) {\n this.validatePlugin(plugin, manifest.name);\n }\n\n return { manifest, plugin };\n }\n\n /**\n * Load all installed plugins from a marketplace.\n * Skips plugins that fail to load (logs warning).\n */\n async loadAll(marketplace: MarketplacePort): Promise<LoadedPlugin[]> {\n const installed = await marketplace.listInstalled();\n const loaded: LoadedPlugin[] = [];\n\n for (const manifest of installed) {\n try {\n const result = await this.load(manifest);\n loaded.push(result);\n } catch {\n // Skip failed plugins — callers can listInstalled() to see all\n }\n }\n\n return loaded;\n }\n\n // ─── Private ────────────────────────────────────────────────────────────\n\n private extractPlugin(mod: Record<string, unknown>, name: string): Plugin {\n // Try: default export\n if (mod.default && typeof mod.default === \"object\" && \"name\" in (mod.default as object)) {\n return mod.default as Plugin;\n }\n // Try: named export `plugin`\n if (mod.plugin && typeof mod.plugin === \"object\" && \"name\" in (mod.plugin as object)) {\n return mod.plugin as Plugin;\n }\n throw new Error(\n `Plugin \"${name}\" must export a default Plugin or a named \"plugin\" export.`,\n );\n }\n\n private validatePlugin(plugin: Plugin, name: string): void {\n if (!plugin.name || typeof plugin.name !== \"string\") {\n throw new Error(`Plugin \"${name}\" is missing a valid \"name\" property.`);\n }\n }\n}\n","export interface SemanticSearchEvalCase {\n id: string;\n query: string;\n expectedUrls: string[];\n k?: number;\n}\n\nexport interface SemanticSearchEvalResult {\n url: string;\n score?: number;\n citation?: string;\n}\n\nexport interface SemanticSearchEvalRunOutput {\n results: SemanticSearchEvalResult[];\n citations?: string[];\n quality?: {\n durationMs?: number;\n };\n}\n\nexport interface SemanticSearchCaseMetrics {\n caseId: string;\n query: string;\n k: number;\n recallAtK: number;\n reciprocalRank: number;\n citationCoverage: number;\n durationMs: number;\n pass: boolean;\n}\n\nexport interface SemanticSearchQualityThresholds {\n minRecallAtK: number;\n minMeanReciprocalRank: number;\n minPassRate: number;\n minCitationCoverage: number;\n maxAverageLatencyMs: number;\n}\n\nexport interface SemanticSearchEvaluationSummary {\n cases: SemanticSearchCaseMetrics[];\n aggregate: {\n recallAtK: number;\n meanReciprocalRank: number;\n passRate: number;\n citationCoverage: number;\n averageLatencyMs: number;\n };\n thresholds: SemanticSearchQualityThresholds;\n thresholdStatus: {\n recallAtK: boolean;\n meanReciprocalRank: boolean;\n passRate: boolean;\n citationCoverage: boolean;\n averageLatencyMs: boolean;\n };\n passed: boolean;\n}\n\nexport interface SemanticSearchEvaluationOptions {\n defaultK?: number;\n thresholds?: Partial<SemanticSearchQualityThresholds>;\n}\n\nexport type SemanticSearchRunner = (\n query: string,\n k: number,\n) => Promise<SemanticSearchEvalRunOutput>;\n\nexport const DEFAULT_SEMANTIC_SEARCH_THRESHOLDS: SemanticSearchQualityThresholds = {\n minRecallAtK: 0.75,\n minMeanReciprocalRank: 0.6,\n minPassRate: 0.8,\n minCitationCoverage: 0.9,\n maxAverageLatencyMs: 5_000,\n};\n\nexport async function evaluateSemanticSearchSuite(\n suite: readonly SemanticSearchEvalCase[],\n run: SemanticSearchRunner,\n options: SemanticSearchEvaluationOptions = {},\n): Promise<SemanticSearchEvaluationSummary> {\n const defaultK = options.defaultK ?? 5;\n const thresholds: SemanticSearchQualityThresholds = {\n ...DEFAULT_SEMANTIC_SEARCH_THRESHOLDS,\n ...(options.thresholds ?? {}),\n };\n\n const cases: SemanticSearchCaseMetrics[] = [];\n\n for (const testCase of suite) {\n const k = testCase.k ?? defaultK;\n const output = await run(testCase.query, k);\n\n const retrieved = output.results.slice(0, k).map((result) => normalizeUrl(result.url));\n const expected = testCase.expectedUrls.map(normalizeUrl);\n\n const expectedSet = new Set(expected);\n const hits = retrieved.filter((url) => expectedSet.has(url)).length;\n const recallAtK = expected.length > 0 ? hits / expected.length : 1;\n\n const firstRelevantRank = retrieved.findIndex((url) => expectedSet.has(url));\n const reciprocalRank =\n firstRelevantRank >= 0 ? 1 / (firstRelevantRank + 1) : 0;\n\n const citationCoverage = computeCitationCoverage(output, retrieved.length);\n const durationMs =\n typeof output.quality?.durationMs === \"number\" && Number.isFinite(output.quality.durationMs)\n ? output.quality.durationMs\n : 0;\n\n cases.push({\n caseId: testCase.id,\n query: testCase.query,\n k,\n recallAtK,\n reciprocalRank,\n citationCoverage,\n durationMs,\n pass: reciprocalRank > 0,\n });\n }\n\n const aggregate = {\n recallAtK: average(cases.map((item) => item.recallAtK)),\n meanReciprocalRank: average(cases.map((item) => item.reciprocalRank)),\n passRate: average(cases.map((item) => (item.pass ? 1 : 0))),\n citationCoverage: average(cases.map((item) => item.citationCoverage)),\n averageLatencyMs: average(cases.map((item) => item.durationMs)),\n };\n\n const thresholdStatus = {\n recallAtK: aggregate.recallAtK >= thresholds.minRecallAtK,\n meanReciprocalRank:\n aggregate.meanReciprocalRank >= thresholds.minMeanReciprocalRank,\n passRate: aggregate.passRate >= thresholds.minPassRate,\n citationCoverage: aggregate.citationCoverage >= thresholds.minCitationCoverage,\n averageLatencyMs: aggregate.averageLatencyMs <= thresholds.maxAverageLatencyMs,\n };\n\n const passed =\n thresholdStatus.recallAtK &&\n thresholdStatus.meanReciprocalRank &&\n thresholdStatus.passRate &&\n thresholdStatus.citationCoverage &&\n thresholdStatus.averageLatencyMs;\n\n return {\n cases,\n aggregate,\n thresholds,\n thresholdStatus,\n passed,\n };\n}\n\nexport function assertSemanticSearchQualityGate(\n summary: SemanticSearchEvaluationSummary,\n): void {\n if (summary.passed) return;\n\n const errors: string[] = [];\n\n if (!summary.thresholdStatus.recallAtK) {\n errors.push(\n `recallAtK ${summary.aggregate.recallAtK.toFixed(3)} < ${summary.thresholds.minRecallAtK}`,\n );\n }\n if (!summary.thresholdStatus.meanReciprocalRank) {\n errors.push(\n `meanReciprocalRank ${summary.aggregate.meanReciprocalRank.toFixed(3)} < ${summary.thresholds.minMeanReciprocalRank}`,\n );\n }\n if (!summary.thresholdStatus.passRate) {\n errors.push(\n `passRate ${summary.aggregate.passRate.toFixed(3)} < ${summary.thresholds.minPassRate}`,\n );\n }\n if (!summary.thresholdStatus.citationCoverage) {\n errors.push(\n `citationCoverage ${summary.aggregate.citationCoverage.toFixed(3)} < ${summary.thresholds.minCitationCoverage}`,\n );\n }\n if (!summary.thresholdStatus.averageLatencyMs) {\n errors.push(\n `averageLatencyMs ${summary.aggregate.averageLatencyMs.toFixed(1)} > ${summary.thresholds.maxAverageLatencyMs}`,\n );\n }\n\n throw new Error(`Semantic search quality gate failed: ${errors.join(\"; \")}`);\n}\n\nfunction normalizeUrl(url: string): string {\n return url.trim().toLowerCase();\n}\n\nfunction average(values: readonly number[]): number {\n if (values.length === 0) return 0;\n return values.reduce((acc, value) => acc + value, 0) / values.length;\n}\n\nfunction computeCitationCoverage(\n output: SemanticSearchEvalRunOutput,\n resultCount: number,\n): number {\n if (resultCount === 0) return 1;\n const citationCount = output.citations?.length ?? 0;\n return Math.min(1, citationCount / resultCount);\n}\n","import type { SemanticSearchEvaluationSummary } from \"./semantic-search-harness.js\";\n\nexport interface SemanticSearchBenchmarkBaseline {\n recallAtK: number;\n meanReciprocalRank: number;\n passRate: number;\n citationCoverage: number;\n averageLatencyMs: number;\n}\n\nexport interface SemanticSearchBenchmarkBudgets {\n maxRecallRegression: number;\n maxMrrRegression: number;\n maxPassRateRegression: number;\n maxCitationCoverageRegression: number;\n maxLatencyIncreaseMs: number;\n}\n\nexport interface SemanticSearchBenchmarkComparison {\n baseline: SemanticSearchBenchmarkBaseline;\n current: SemanticSearchBenchmarkBaseline;\n deltas: {\n recallAtK: number;\n meanReciprocalRank: number;\n passRate: number;\n citationCoverage: number;\n averageLatencyMs: number;\n };\n budgets: SemanticSearchBenchmarkBudgets;\n budgetStatus: {\n recallAtK: boolean;\n meanReciprocalRank: boolean;\n passRate: boolean;\n citationCoverage: boolean;\n averageLatencyMs: boolean;\n };\n improvedMetrics: string[];\n regressedMetrics: string[];\n passed: boolean;\n}\n\nexport const DEFAULT_SEMANTIC_BENCHMARK_BUDGETS: SemanticSearchBenchmarkBudgets = {\n maxRecallRegression: 0.02,\n maxMrrRegression: 0.02,\n maxPassRateRegression: 0.02,\n maxCitationCoverageRegression: 0.02,\n maxLatencyIncreaseMs: 250,\n};\n\nexport function summaryToBenchmarkSnapshot(\n summary: SemanticSearchEvaluationSummary,\n): SemanticSearchBenchmarkBaseline {\n return {\n recallAtK: summary.aggregate.recallAtK,\n meanReciprocalRank: summary.aggregate.meanReciprocalRank,\n passRate: summary.aggregate.passRate,\n citationCoverage: summary.aggregate.citationCoverage,\n averageLatencyMs: summary.aggregate.averageLatencyMs,\n };\n}\n\nexport function compareSemanticSearchBenchmark(\n current: SemanticSearchBenchmarkBaseline,\n baseline: SemanticSearchBenchmarkBaseline,\n budgets: Partial<SemanticSearchBenchmarkBudgets> = {},\n): SemanticSearchBenchmarkComparison {\n const resolvedBudgets: SemanticSearchBenchmarkBudgets = {\n ...DEFAULT_SEMANTIC_BENCHMARK_BUDGETS,\n ...budgets,\n };\n\n const deltas = {\n recallAtK: current.recallAtK - baseline.recallAtK,\n meanReciprocalRank: current.meanReciprocalRank - baseline.meanReciprocalRank,\n passRate: current.passRate - baseline.passRate,\n citationCoverage: current.citationCoverage - baseline.citationCoverage,\n averageLatencyMs: current.averageLatencyMs - baseline.averageLatencyMs,\n };\n\n const budgetStatus = {\n recallAtK: deltas.recallAtK >= -resolvedBudgets.maxRecallRegression,\n meanReciprocalRank:\n deltas.meanReciprocalRank >= -resolvedBudgets.maxMrrRegression,\n passRate: deltas.passRate >= -resolvedBudgets.maxPassRateRegression,\n citationCoverage:\n deltas.citationCoverage >= -resolvedBudgets.maxCitationCoverageRegression,\n averageLatencyMs: deltas.averageLatencyMs <= resolvedBudgets.maxLatencyIncreaseMs,\n };\n\n const improvedMetrics: string[] = [];\n const regressedMetrics: string[] = [];\n\n if (deltas.recallAtK > 0) improvedMetrics.push(\"recallAtK\");\n if (deltas.meanReciprocalRank > 0) improvedMetrics.push(\"meanReciprocalRank\");\n if (deltas.passRate > 0) improvedMetrics.push(\"passRate\");\n if (deltas.citationCoverage > 0) improvedMetrics.push(\"citationCoverage\");\n if (deltas.averageLatencyMs < 0) improvedMetrics.push(\"averageLatencyMs\");\n\n if (deltas.recallAtK < 0) regressedMetrics.push(\"recallAtK\");\n if (deltas.meanReciprocalRank < 0) regressedMetrics.push(\"meanReciprocalRank\");\n if (deltas.passRate < 0) regressedMetrics.push(\"passRate\");\n if (deltas.citationCoverage < 0) regressedMetrics.push(\"citationCoverage\");\n if (deltas.averageLatencyMs > 0) regressedMetrics.push(\"averageLatencyMs\");\n\n const passed =\n budgetStatus.recallAtK &&\n budgetStatus.meanReciprocalRank &&\n budgetStatus.passRate &&\n budgetStatus.citationCoverage &&\n budgetStatus.averageLatencyMs;\n\n return {\n baseline,\n current,\n deltas,\n budgets: resolvedBudgets,\n budgetStatus,\n improvedMetrics,\n regressedMetrics,\n passed,\n };\n}\n\nexport function assertSemanticSearchBenchmarkGate(\n comparison: SemanticSearchBenchmarkComparison,\n): void {\n if (comparison.passed) {\n return;\n }\n\n const issues: string[] = [];\n if (!comparison.budgetStatus.recallAtK) {\n issues.push(\n `recallAtK delta ${comparison.deltas.recallAtK.toFixed(3)} below budget -${comparison.budgets.maxRecallRegression}`,\n );\n }\n if (!comparison.budgetStatus.meanReciprocalRank) {\n issues.push(\n `meanReciprocalRank delta ${comparison.deltas.meanReciprocalRank.toFixed(3)} below budget -${comparison.budgets.maxMrrRegression}`,\n );\n }\n if (!comparison.budgetStatus.passRate) {\n issues.push(\n `passRate delta ${comparison.deltas.passRate.toFixed(3)} below budget -${comparison.budgets.maxPassRateRegression}`,\n );\n }\n if (!comparison.budgetStatus.citationCoverage) {\n issues.push(\n `citationCoverage delta ${comparison.deltas.citationCoverage.toFixed(3)} below budget -${comparison.budgets.maxCitationCoverageRegression}`,\n );\n }\n if (!comparison.budgetStatus.averageLatencyMs) {\n issues.push(\n `averageLatencyMs delta ${comparison.deltas.averageLatencyMs.toFixed(1)} exceeds budget +${comparison.budgets.maxLatencyIncreaseMs}`,\n );\n }\n\n throw new Error(`Semantic benchmark gate failed: ${issues.join(\"; \")}`);\n}\n\nexport function renderSemanticSearchBenchmarkMarkdown(\n comparison: SemanticSearchBenchmarkComparison,\n): string {\n return [\n \"# Semantic Search Benchmark Report\",\n \"\",\n `- Gate: ${comparison.passed ? \"PASS\" : \"FAIL\"}`,\n `- Improved metrics: ${comparison.improvedMetrics.join(\", \") || \"none\"}`,\n `- Regressed metrics: ${comparison.regressedMetrics.join(\", \") || \"none\"}`,\n \"\",\n \"| Metric | Baseline | Current | Delta | Budget | Status |\",\n \"|---|---:|---:|---:|---:|:---:|\",\n row(\n \"recall@k\",\n comparison.baseline.recallAtK,\n comparison.current.recallAtK,\n comparison.deltas.recallAtK,\n `>= -${comparison.budgets.maxRecallRegression}`,\n comparison.budgetStatus.recallAtK,\n ),\n row(\n \"MRR\",\n comparison.baseline.meanReciprocalRank,\n comparison.current.meanReciprocalRank,\n comparison.deltas.meanReciprocalRank,\n `>= -${comparison.budgets.maxMrrRegression}`,\n comparison.budgetStatus.meanReciprocalRank,\n ),\n row(\n \"pass rate\",\n comparison.baseline.passRate,\n comparison.current.passRate,\n comparison.deltas.passRate,\n `>= -${comparison.budgets.maxPassRateRegression}`,\n comparison.budgetStatus.passRate,\n ),\n row(\n \"citation coverage\",\n comparison.baseline.citationCoverage,\n comparison.current.citationCoverage,\n comparison.deltas.citationCoverage,\n `>= -${comparison.budgets.maxCitationCoverageRegression}`,\n comparison.budgetStatus.citationCoverage,\n ),\n row(\n \"avg latency (ms)\",\n comparison.baseline.averageLatencyMs,\n comparison.current.averageLatencyMs,\n comparison.deltas.averageLatencyMs,\n `<= +${comparison.budgets.maxLatencyIncreaseMs}`,\n comparison.budgetStatus.averageLatencyMs,\n ),\n \"\",\n ].join(\"\\n\");\n}\n\nfunction row(\n label: string,\n baseline: number,\n current: number,\n delta: number,\n budget: string,\n ok: boolean,\n): string {\n return `| ${label} | ${baseline.toFixed(3)} | ${current.toFixed(3)} | ${delta.toFixed(3)} | ${budget} | ${ok ? \"✅\" : \"❌\"} |`;\n}\n","export interface SemanticSearchStressSample {\n success: boolean;\n durationMs: number;\n cacheHit: boolean;\n fallbackUsed: boolean;\n totalCostUsd: number;\n}\n\nexport interface SemanticSearchStressThresholds {\n minSuccessRate: number;\n maxP95LatencyMs: number;\n minCacheHitRate: number;\n maxFallbackRate: number;\n maxAverageCostUsd: number;\n}\n\nexport interface SemanticSearchStressSummary {\n samples: number;\n aggregate: {\n successRate: number;\n p95LatencyMs: number;\n cacheHitRate: number;\n fallbackRate: number;\n averageCostUsd: number;\n };\n thresholds: SemanticSearchStressThresholds;\n thresholdStatus: {\n successRate: boolean;\n p95LatencyMs: boolean;\n cacheHitRate: boolean;\n fallbackRate: boolean;\n averageCostUsd: boolean;\n };\n passed: boolean;\n}\n\nexport const DEFAULT_SEMANTIC_STRESS_THRESHOLDS: SemanticSearchStressThresholds = {\n minSuccessRate: 0.98,\n maxP95LatencyMs: 2_500,\n minCacheHitRate: 0.2,\n maxFallbackRate: 0.5,\n maxAverageCostUsd: 0.02,\n};\n\nexport function evaluateSemanticSearchStressSuite(\n samples: readonly SemanticSearchStressSample[],\n thresholds: Partial<SemanticSearchStressThresholds> = {},\n): SemanticSearchStressSummary {\n const resolvedThresholds: SemanticSearchStressThresholds = {\n ...DEFAULT_SEMANTIC_STRESS_THRESHOLDS,\n ...thresholds,\n };\n\n const aggregate = {\n successRate: average(samples.map((sample) => (sample.success ? 1 : 0))),\n p95LatencyMs: percentile(\n samples.map((sample) => sample.durationMs),\n 95,\n ),\n cacheHitRate: average(samples.map((sample) => (sample.cacheHit ? 1 : 0))),\n fallbackRate: average(samples.map((sample) => (sample.fallbackUsed ? 1 : 0))),\n averageCostUsd: average(samples.map((sample) => sample.totalCostUsd)),\n };\n\n const thresholdStatus = {\n successRate: aggregate.successRate >= resolvedThresholds.minSuccessRate,\n p95LatencyMs: aggregate.p95LatencyMs <= resolvedThresholds.maxP95LatencyMs,\n cacheHitRate: aggregate.cacheHitRate >= resolvedThresholds.minCacheHitRate,\n fallbackRate: aggregate.fallbackRate <= resolvedThresholds.maxFallbackRate,\n averageCostUsd: aggregate.averageCostUsd <= resolvedThresholds.maxAverageCostUsd,\n };\n\n const passed =\n thresholdStatus.successRate &&\n thresholdStatus.p95LatencyMs &&\n thresholdStatus.cacheHitRate &&\n thresholdStatus.fallbackRate &&\n thresholdStatus.averageCostUsd;\n\n return {\n samples: samples.length,\n aggregate,\n thresholds: resolvedThresholds,\n thresholdStatus,\n passed,\n };\n}\n\nexport function assertSemanticSearchStressGate(\n summary: SemanticSearchStressSummary,\n): void {\n if (summary.passed) {\n return;\n }\n\n const issues: string[] = [];\n if (!summary.thresholdStatus.successRate) {\n issues.push(\n `successRate ${summary.aggregate.successRate.toFixed(3)} < ${summary.thresholds.minSuccessRate}`,\n );\n }\n if (!summary.thresholdStatus.p95LatencyMs) {\n issues.push(\n `p95LatencyMs ${summary.aggregate.p95LatencyMs.toFixed(1)} > ${summary.thresholds.maxP95LatencyMs}`,\n );\n }\n if (!summary.thresholdStatus.cacheHitRate) {\n issues.push(\n `cacheHitRate ${summary.aggregate.cacheHitRate.toFixed(3)} < ${summary.thresholds.minCacheHitRate}`,\n );\n }\n if (!summary.thresholdStatus.fallbackRate) {\n issues.push(\n `fallbackRate ${summary.aggregate.fallbackRate.toFixed(3)} > ${summary.thresholds.maxFallbackRate}`,\n );\n }\n if (!summary.thresholdStatus.averageCostUsd) {\n issues.push(\n `averageCostUsd ${summary.aggregate.averageCostUsd.toFixed(6)} > ${summary.thresholds.maxAverageCostUsd}`,\n );\n }\n\n throw new Error(`Semantic stress gate failed: ${issues.join(\"; \")}`);\n}\n\nfunction average(values: readonly number[]): number {\n if (values.length === 0) return 0;\n return values.reduce((acc, value) => acc + value, 0) / values.length;\n}\n\nfunction percentile(values: readonly number[], p: number): number {\n if (values.length === 0) return 0;\n const sorted = [...values].sort((a, b) => a - b);\n const idx = Math.min(\n sorted.length - 1,\n Math.max(0, Math.ceil((p / 100) * sorted.length) - 1),\n );\n return sorted[idx] ?? 0;\n}\n","// =============================================================================\n// Scorer Pipeline — Multi-step scoring with LLM judge support\n// =============================================================================\n\nexport interface ScoreResult {\n score: number; // 0-1\n reason: string;\n metadata?: Record<string, unknown>;\n}\n\nexport interface ScorerStep<TInput = unknown> {\n name: string;\n execute(input: TInput, context: ScorerContext): Promise<TInput>;\n}\n\nexport interface ScorerContext {\n /** LLM judge function: returns 0-1 score for a question about the content */\n judge?: (prompt: string, content: string) => Promise<number>;\n metadata: Record<string, unknown>;\n}\n\nexport interface Scorer {\n name: string;\n score(input: string, expected?: string, context?: ScorerContext): Promise<ScoreResult>;\n}\n\n// --- Scorer Factory ---\n\nexport function createScorer(opts: {\n name: string;\n score: (input: string, expected?: string, context?: ScorerContext) => Promise<ScoreResult>;\n}): Scorer {\n return { name: opts.name, score: opts.score };\n}\n\n// --- Scorer Pipeline ---\n\nexport class ScorerPipeline {\n private steps: ScorerStep[] = [];\n private scorers: Scorer[] = [];\n\n addStep(step: ScorerStep): this {\n this.steps.push(step);\n return this;\n }\n\n addScorer(scorer: Scorer): this {\n this.scorers.push(scorer);\n return this;\n }\n\n async run(input: string, expected?: string, context?: Partial<ScorerContext>): Promise<Record<string, ScoreResult>> {\n const ctx: ScorerContext = { judge: context?.judge, metadata: context?.metadata ?? {} };\n\n // Run preprocessing steps\n let processed: unknown = input;\n for (const step of this.steps) {\n processed = await step.execute(processed, ctx);\n }\n const processedStr = typeof processed === \"string\" ? processed : JSON.stringify(processed);\n\n // Run all scorers in parallel\n const entries = await Promise.all(\n this.scorers.map(async (scorer) => {\n const result = await scorer.score(processedStr, expected, ctx);\n return [scorer.name, result] as const;\n }),\n );\n\n return Object.fromEntries(entries);\n }\n}\n\n// --- Built-in Scorers ---\n\n/** Exact match scorer */\nexport const exactMatchScorer = createScorer({\n name: \"exact_match\",\n async score(input, expected) {\n if (!expected) return { score: 0, reason: \"No expected value provided\" };\n return input === expected\n ? { score: 1, reason: \"Exact match\" }\n : { score: 0, reason: \"Does not match expected value\" };\n },\n});\n\n/** Contains scorer — checks if output contains expected substring */\nexport const containsScorer = createScorer({\n name: \"contains\",\n async score(input, expected) {\n if (!expected) return { score: 0, reason: \"No expected value provided\" };\n return input.includes(expected)\n ? { score: 1, reason: \"Contains expected value\" }\n : { score: 0, reason: \"Does not contain expected value\" };\n },\n});\n\n/** Length scorer — penalizes overly short or long outputs */\nexport const lengthScorer = createScorer({\n name: \"length\",\n async score(input, _expected, context) {\n const minLen = (context?.metadata?.minLength as number) ?? 10;\n const maxLen = (context?.metadata?.maxLength as number) ?? 5000;\n const len = input.length;\n if (len < minLen) return { score: len / minLen, reason: `Too short (${len}/${minLen})` };\n if (len > maxLen) return { score: maxLen / len, reason: `Too long (${len}/${maxLen})` };\n return { score: 1, reason: \"Length within bounds\" };\n },\n});\n\n/** LLM Judge scorer — uses context.judge to evaluate */\nexport const llmJudgeScorer = createScorer({\n name: \"llm_judge\",\n async score(input, expected, context) {\n if (!context?.judge) return { score: 0, reason: \"No LLM judge provided\" };\n const prompt = expected\n ? `Rate how well this response answers the expected output.\\nExpected: ${expected}\\nActual: ${input}`\n : `Rate the quality of this response: ${input}`;\n const score = await context.judge(prompt, input);\n return { score, reason: `LLM judge score: ${score}` };\n },\n});\n","// =============================================================================\n// Agent Trajectory Evals — Custom Vitest matchers + trajectory capture\n// =============================================================================\n\nexport interface TrajectoryStep {\n type: \"agent_start\" | \"tool_call\" | \"tool_result\" | \"agent_response\" | \"error\";\n name?: string;\n input?: unknown;\n output?: unknown;\n timestamp: number;\n duration?: number;\n}\n\nexport interface Trajectory {\n agentName: string;\n steps: TrajectoryStep[];\n startedAt: number;\n completedAt?: number;\n}\n\n// --- Trajectory Recorder ---\n\nexport class TrajectoryRecorder {\n private steps: TrajectoryStep[] = [];\n private agentName: string;\n private startedAt: number;\n\n constructor(agentName: string) {\n this.agentName = agentName;\n this.startedAt = Date.now();\n }\n\n record(step: Omit<TrajectoryStep, \"timestamp\">): void {\n this.steps.push({ ...step, timestamp: Date.now() });\n }\n\n complete(): Trajectory {\n return {\n agentName: this.agentName,\n steps: structuredClone(this.steps),\n startedAt: this.startedAt,\n completedAt: Date.now(),\n };\n }\n\n snapshot(): Trajectory {\n return {\n agentName: this.agentName,\n steps: structuredClone(this.steps),\n startedAt: this.startedAt,\n };\n }\n}\n\n// --- Trajectory Assertions (framework-agnostic) ---\n\nexport function hasAgentSteps(trajectory: Trajectory, minSteps: number): boolean {\n return trajectory.steps.length >= minSteps;\n}\n\nexport function hasToolCallRequests(trajectory: Trajectory, toolNames: string[]): boolean {\n const toolCalls = trajectory.steps.filter(s => s.type === \"tool_call\");\n return toolNames.every(name => toolCalls.some(s => s.name === name));\n}\n\nexport function hasNoErrors(trajectory: Trajectory): boolean {\n return !trajectory.steps.some(s => s.type === \"error\");\n}\n\nexport function hasToolCallCount(trajectory: Trajectory, name: string, count: number): boolean {\n return trajectory.steps.filter(s => s.type === \"tool_call\" && s.name === name).length === count;\n}\n\nexport function completedWithin(trajectory: Trajectory, maxMs: number): boolean {\n if (!trajectory.completedAt) return false;\n return (trajectory.completedAt - trajectory.startedAt) <= maxMs;\n}\n\nexport function hasOrderedSteps(trajectory: Trajectory, types: TrajectoryStep[\"type\"][]): boolean {\n let idx = 0;\n for (const step of trajectory.steps) {\n if (idx < types.length && step.type === types[idx]) idx++;\n }\n return idx === types.length;\n}\n\n// --- Export format ---\n\nexport function exportTrajectory(trajectory: Trajectory): string {\n return JSON.stringify(trajectory, null, 2);\n}\n\nexport function importTrajectory(json: string): Trajectory {\n return JSON.parse(json) as Trajectory;\n}\n","// =============================================================================\n// PlaygroundAPI — REST endpoints for the Gauss Playground\n// =============================================================================\n\nimport type { HttpServerPort } from \"../ports/http-server.port.js\";\n\nexport interface PlaygroundTool {\n name: string;\n description: string;\n parameters?: Record<string, unknown>;\n}\n\nexport interface PlaygroundMemoryEntry {\n key: string;\n value: unknown;\n tier: \"short\" | \"working\" | \"semantic\" | \"observation\";\n timestamp: number;\n}\n\nexport interface PlaygroundGraphData {\n nodes: Array<{ id: string; type: string; label: string; properties: Record<string, unknown> }>;\n edges: Array<{ source: string; target: string; type: string; weight: number }>;\n}\n\nexport interface PlaygroundAgent {\n name: string;\n description?: string;\n invoke: (prompt: string, options?: { stream?: boolean }) => Promise<string | AsyncIterable<string>>;\n /** Registered tools (for ToolInspector) */\n tools?: PlaygroundTool[];\n /** Memory provider (for MemoryViewer) */\n getMemory?: () => Promise<PlaygroundMemoryEntry[]>;\n /** Knowledge graph provider (for GraphVisualizer) */\n getGraph?: () => Promise<PlaygroundGraphData>;\n /** Trace provider (for TraceViewer) */\n getTraces?: () => Promise<PlaygroundTraceSpan[]>;\n /** Token usage provider (for TokenDashboard) */\n getTokenUsage?: () => Promise<PlaygroundTokenUsage[]>;\n /** Tool call history (for ToolCallInspector) */\n getToolCalls?: () => Promise<PlaygroundToolCall[]>;\n /** Reliability metrics (for RetryDashboard) */\n getReliabilityMetrics?: () => Promise<PlaygroundReliabilityMetrics>;\n}\n\n// ─── Trace Viewer Types ────────────────────────────────────────────────────────\n\nexport interface PlaygroundTraceSpan {\n id: string;\n name: string;\n parentId?: string;\n startTime: number;\n endTime: number;\n status: \"ok\" | \"error\";\n attributes: Record<string, unknown>;\n events: Array<{ name: string; timestamp: number; attributes?: Record<string, unknown> }>;\n}\n\n// ─── Token Dashboard Types ─────────────────────────────────────────────────────\n\nexport interface PlaygroundTokenUsage {\n runId: string;\n model: string;\n inputTokens: number;\n outputTokens: number;\n totalTokens: number;\n estimatedCost: number;\n timestamp: number;\n}\n\n// ─── Tool Call Inspector Types ─────────────────────────────────────────────────\n\nexport interface PlaygroundToolCall {\n id: string;\n runId: string;\n toolName: string;\n input: Record<string, unknown>;\n output: unknown;\n durationMs: number;\n status: \"success\" | \"error\";\n error?: string;\n timestamp: number;\n}\n\n// ─── Reliability Dashboard Types ───────────────────────────────────────────────\n\nexport interface PlaygroundReliabilityMetrics {\n circuitBreaker: {\n state: \"closed\" | \"open\" | \"half-open\";\n failureCount: number;\n successCount: number;\n lastFailure?: number;\n lastStateChange: number;\n };\n retries: {\n totalAttempts: number;\n successfulRetries: number;\n failedRetries: number;\n recentRetries: Array<{ toolName: string; attempts: number; success: boolean; timestamp: number }>;\n };\n rateLimiter: {\n remainingTokens: number;\n maxTokens: number;\n requestsThisWindow: number;\n };\n}\n\nexport interface PlaygroundConfig {\n server: HttpServerPort;\n agents: PlaygroundAgent[];\n staticDir?: string;\n}\n\ninterface HistoryEntry {\n id: string;\n agentName: string;\n prompt: string;\n response: string;\n timestamp: number;\n durationMs: number;\n}\n\n/**\n * Registers playground REST endpoints on the given HTTP server.\n *\n * Endpoints:\n * - GET /api/agents — List all registered agents\n * - POST /api/agents/:name/run — Run agent with { prompt }\n * - GET /api/agents/:name/stream — SSE stream agent response (query: prompt)\n * - GET /api/agents/:name/history — Get agent run history\n * - GET /api/health — Health check\n */\nexport function registerPlaygroundRoutes(config: PlaygroundConfig): void {\n const { server, agents } = config;\n const agentMap = new Map(agents.map((a) => [a.name, a]));\n const history: HistoryEntry[] = [];\n let idCounter = 0;\n\n // GET /api/agents\n server.route(\"GET\", \"/api/agents\", async (_req, res) => {\n res.json(agents.map((a) => ({ name: a.name, description: a.description ?? \"\" })));\n });\n\n // POST /api/agents/:name/run\n server.route(\"POST\", \"/api/agents/:name/run\", async (req, res) => {\n const agent = agentMap.get(req.params.name);\n if (!agent) {\n res.status(404).json({ error: `Agent \"${req.params.name}\" not found` });\n return;\n }\n\n const body = req.body as { prompt?: string } | undefined;\n if (!body?.prompt) {\n res.status(400).json({ error: \"Missing 'prompt' in request body\" });\n return;\n }\n\n const start = Date.now();\n try {\n const result = await agent.invoke(body.prompt);\n const response = typeof result === \"string\" ? result : \"\";\n const durationMs = Date.now() - start;\n\n const entry: HistoryEntry = {\n id: `run-${++idCounter}`,\n agentName: agent.name,\n prompt: body.prompt,\n response,\n timestamp: start,\n durationMs,\n };\n history.push(entry);\n\n res.json({ id: entry.id, response, durationMs });\n } catch (err: unknown) {\n const message = err instanceof Error ? err.message : String(err);\n res.status(500).json({ error: message });\n }\n });\n\n // GET /api/agents/:name/stream\n server.route(\"GET\", \"/api/agents/:name/stream\", async (req, res) => {\n const agent = agentMap.get(req.params.name);\n if (!agent) {\n res.status(404).json({ error: `Agent \"${req.params.name}\" not found` });\n return;\n }\n\n const prompt = req.query.prompt;\n if (!prompt) {\n res.status(400).json({ error: \"Missing 'prompt' query parameter\" });\n return;\n }\n\n try {\n const result = await agent.invoke(prompt, { stream: true });\n if (typeof result === \"string\") {\n const text = result;\n async function* singleChunk(): AsyncGenerator<string> { yield text; }\n res.header(\"Cache-Control\", \"no-cache\").header(\"Connection\", \"keep-alive\").stream(singleChunk());\n } else {\n async function* streamChunks() {\n for await (const chunk of result as AsyncIterable<string>) {\n yield chunk;\n }\n }\n res.header(\"Cache-Control\", \"no-cache\").header(\"Connection\", \"keep-alive\").stream(streamChunks());\n }\n } catch (err: unknown) {\n const message = err instanceof Error ? err.message : String(err);\n res.status(500).json({ error: message });\n }\n });\n\n // GET /api/agents/:name/history\n server.route(\"GET\", \"/api/agents/:name/history\", async (req, res) => {\n const agentHistory = history.filter((h) => h.agentName === req.params.name);\n res.json(agentHistory);\n });\n\n // GET /api/agents/:name/tools — List agent tools\n server.route(\"GET\", \"/api/agents/:name/tools\", async (req, res) => {\n const agent = agentMap.get(req.params.name);\n if (!agent) { res.status(404).json({ error: `Agent \"${req.params.name}\" not found` }); return; }\n res.json(agent.tools ?? []);\n });\n\n // GET /api/agents/:name/memory — Get agent memory state\n server.route(\"GET\", \"/api/agents/:name/memory\", async (req, res) => {\n const agent = agentMap.get(req.params.name);\n if (!agent) { res.status(404).json({ error: `Agent \"${req.params.name}\" not found` }); return; }\n if (!agent.getMemory) { res.json([]); return; }\n try {\n const memory = await agent.getMemory();\n res.json(memory);\n } catch (err: unknown) {\n res.status(500).json({ error: err instanceof Error ? err.message : String(err) });\n }\n });\n\n // GET /api/agents/:name/graph — Get agent knowledge graph\n server.route(\"GET\", \"/api/agents/:name/graph\", async (req, res) => {\n const agent = agentMap.get(req.params.name);\n if (!agent) { res.status(404).json({ error: `Agent \"${req.params.name}\" not found` }); return; }\n if (!agent.getGraph) { res.json({ nodes: [], edges: [] }); return; }\n try {\n const graph = await agent.getGraph();\n res.json(graph);\n } catch (err: unknown) {\n res.status(500).json({ error: err instanceof Error ? err.message : String(err) });\n }\n });\n\n // GET /api/agents/:name/traces — Get execution traces\n server.route(\"GET\", \"/api/agents/:name/traces\", async (req, res) => {\n const agent = agentMap.get(req.params.name);\n if (!agent) { res.status(404).json({ error: `Agent \"${req.params.name}\" not found` }); return; }\n if (!agent.getTraces) { res.json([]); return; }\n try {\n res.json(await agent.getTraces());\n } catch (err: unknown) {\n res.status(500).json({ error: err instanceof Error ? err.message : String(err) });\n }\n });\n\n // GET /api/agents/:name/tokens — Get token usage metrics\n server.route(\"GET\", \"/api/agents/:name/tokens\", async (req, res) => {\n const agent = agentMap.get(req.params.name);\n if (!agent) { res.status(404).json({ error: `Agent \"${req.params.name}\" not found` }); return; }\n if (!agent.getTokenUsage) { res.json([]); return; }\n try {\n res.json(await agent.getTokenUsage());\n } catch (err: unknown) {\n res.status(500).json({ error: err instanceof Error ? err.message : String(err) });\n }\n });\n\n // GET /api/agents/:name/tool-calls — Get tool call history with I/O\n server.route(\"GET\", \"/api/agents/:name/tool-calls\", async (req, res) => {\n const agent = agentMap.get(req.params.name);\n if (!agent) { res.status(404).json({ error: `Agent \"${req.params.name}\" not found` }); return; }\n if (!agent.getToolCalls) { res.json([]); return; }\n try {\n res.json(await agent.getToolCalls());\n } catch (err: unknown) {\n res.status(500).json({ error: err instanceof Error ? err.message : String(err) });\n }\n });\n\n // GET /api/agents/:name/reliability — Get retry/circuit breaker metrics\n server.route(\"GET\", \"/api/agents/:name/reliability\", async (req, res) => {\n const agent = agentMap.get(req.params.name);\n if (!agent) { res.status(404).json({ error: `Agent \"${req.params.name}\" not found` }); return; }\n if (!agent.getReliabilityMetrics) {\n res.json({\n circuitBreaker: { state: \"closed\", failureCount: 0, successCount: 0, lastStateChange: Date.now() },\n retries: { totalAttempts: 0, successfulRetries: 0, failedRetries: 0, recentRetries: [] },\n rateLimiter: { remainingTokens: 0, maxTokens: 0, requestsThisWindow: 0 },\n });\n return;\n }\n try {\n res.json(await agent.getReliabilityMetrics());\n } catch (err: unknown) {\n res.status(500).json({ error: err instanceof Error ? err.message : String(err) });\n }\n });\n\n // GET /api/health\n server.route(\"GET\", \"/api/health\", async (_req, res) => {\n res.json({ status: \"ok\", agents: agents.length, uptime: process.uptime() });\n });\n}\n","// =============================================================================\n// PlaygroundCollector — Automatic data collection for Playground dashboards\n// =============================================================================\n//\n// Wraps an Agent and automatically collects traces, token usage, tool calls,\n// and reliability metrics for the playground UI.\n//\n// Usage:\n// import { PlaygroundCollector } from 'gauss'\n// const collector = new PlaygroundCollector(myAgent)\n// // Register collector.asPlaygroundAgent() with the playground\n//\n// =============================================================================\n\nimport type {\n PlaygroundAgent,\n PlaygroundTraceSpan,\n PlaygroundTokenUsage,\n PlaygroundToolCall,\n PlaygroundReliabilityMetrics,\n PlaygroundMemoryEntry,\n PlaygroundGraphData,\n PlaygroundTool,\n} from \"./playground-api.js\";\n\nexport interface PlaygroundCollectorOptions {\n /** Maximum number of traces to keep (default: 1000) */\n maxTraces?: number;\n /** Maximum number of token records to keep (default: 1000) */\n maxTokenRecords?: number;\n /** Maximum number of tool calls to keep (default: 5000) */\n maxToolCalls?: number;\n}\n\nexport class PlaygroundCollector {\n private traces: PlaygroundTraceSpan[] = [];\n private tokenUsage: PlaygroundTokenUsage[] = [];\n private toolCalls: PlaygroundToolCall[] = [];\n private reliabilityMetrics: PlaygroundReliabilityMetrics = {\n circuitBreaker: { state: \"closed\", failureCount: 0, successCount: 0, lastStateChange: Date.now() },\n retries: { totalAttempts: 0, successfulRetries: 0, failedRetries: 0, recentRetries: [] },\n rateLimiter: { remainingTokens: 0, maxTokens: 0, requestsThisWindow: 0 },\n };\n private readonly maxTraces: number;\n private readonly maxTokenRecords: number;\n private readonly maxToolCalls: number;\n\n constructor(options?: PlaygroundCollectorOptions) {\n this.maxTraces = options?.maxTraces ?? 1000;\n this.maxTokenRecords = options?.maxTokenRecords ?? 1000;\n this.maxToolCalls = options?.maxToolCalls ?? 5000;\n }\n\n // ─── Recording API ──────────────────────────────────────────────────────\n\n /** Record a trace span (execution step) */\n recordTrace(span: PlaygroundTraceSpan): void {\n this.traces.push(span);\n if (this.traces.length > this.maxTraces) {\n this.traces = this.traces.slice(-this.maxTraces);\n }\n }\n\n /** Record token usage for a run */\n recordTokenUsage(usage: PlaygroundTokenUsage): void {\n this.tokenUsage.push(usage);\n if (this.tokenUsage.length > this.maxTokenRecords) {\n this.tokenUsage = this.tokenUsage.slice(-this.maxTokenRecords);\n }\n }\n\n /** Record a tool call with input/output */\n recordToolCall(call: PlaygroundToolCall): void {\n this.toolCalls.push(call);\n if (this.toolCalls.length > this.maxToolCalls) {\n this.toolCalls = this.toolCalls.slice(-this.maxToolCalls);\n }\n }\n\n /** Update circuit breaker state */\n updateCircuitBreaker(state: PlaygroundReliabilityMetrics[\"circuitBreaker\"]): void {\n this.reliabilityMetrics.circuitBreaker = state;\n }\n\n /** Record a retry event */\n recordRetry(retry: PlaygroundReliabilityMetrics[\"retries\"][\"recentRetries\"][0]): void {\n this.reliabilityMetrics.retries.totalAttempts++;\n if (retry.success) this.reliabilityMetrics.retries.successfulRetries++;\n else this.reliabilityMetrics.retries.failedRetries++;\n this.reliabilityMetrics.retries.recentRetries.push(retry);\n // Keep last 100 retries\n if (this.reliabilityMetrics.retries.recentRetries.length > 100) {\n this.reliabilityMetrics.retries.recentRetries =\n this.reliabilityMetrics.retries.recentRetries.slice(-100);\n }\n }\n\n /** Update rate limiter state */\n updateRateLimiter(state: PlaygroundReliabilityMetrics[\"rateLimiter\"]): void {\n this.reliabilityMetrics.rateLimiter = state;\n }\n\n // ─── Query API ──────────────────────────────────────────────────────────\n\n getTraces(): PlaygroundTraceSpan[] {\n return [...this.traces];\n }\n\n getTokenUsage(): PlaygroundTokenUsage[] {\n return [...this.tokenUsage];\n }\n\n getToolCalls(): PlaygroundToolCall[] {\n return [...this.toolCalls];\n }\n\n getReliabilityMetrics(): PlaygroundReliabilityMetrics {\n return { ...this.reliabilityMetrics };\n }\n\n /** Clear all collected data */\n clear(): void {\n this.traces = [];\n this.tokenUsage = [];\n this.toolCalls = [];\n this.reliabilityMetrics = {\n circuitBreaker: { state: \"closed\", failureCount: 0, successCount: 0, lastStateChange: Date.now() },\n retries: { totalAttempts: 0, successfulRetries: 0, failedRetries: 0, recentRetries: [] },\n rateLimiter: { remainingTokens: 0, maxTokens: 0, requestsThisWindow: 0 },\n };\n }\n\n // ─── PlaygroundAgent Factory ────────────────────────────────────────────\n\n /**\n * Create a PlaygroundAgent configuration with automatic data collection hooks.\n *\n * @example\n * ```ts\n * const collector = new PlaygroundCollector()\n * const playgroundAgent = collector.asPlaygroundAgent({\n * name: 'my-agent',\n * invoke: (prompt) => myAgent.run(prompt),\n * })\n * ```\n */\n asPlaygroundAgent(base: {\n name: string;\n description?: string;\n invoke: PlaygroundAgent[\"invoke\"];\n tools?: PlaygroundTool[];\n getMemory?: () => Promise<PlaygroundMemoryEntry[]>;\n getGraph?: () => Promise<PlaygroundGraphData>;\n }): PlaygroundAgent {\n return {\n ...base,\n getTraces: async () => this.getTraces(),\n getTokenUsage: async () => this.getTokenUsage(),\n getToolCalls: async () => this.getToolCalls(),\n getReliabilityMetrics: async () => this.getReliabilityMetrics(),\n };\n }\n}\n","// =============================================================================\n// Playground CLI — Programmatic launcher for Gauss Playground\n// =============================================================================\n\nimport { NodeHttpServer } from \"../server/node-http.server.js\";\nimport { registerPlaygroundRoutes } from \"../server/playground-api.js\";\nimport type { PlaygroundAgent } from \"../server/playground-api.js\";\n\nexport interface PlaygroundOptions {\n port?: number;\n agents: PlaygroundAgent[];\n /** Open browser automatically (default: true) */\n open?: boolean;\n}\n\n/**\n * Start the Gauss Playground server.\n *\n * Usage:\n * ```ts\n * import { startPlayground } from \"gauss\";\n *\n * await startPlayground({\n * port: 4000,\n * agents: [{\n * name: \"my-agent\",\n * description: \"A helpful assistant\",\n * invoke: async (prompt) => `Echo: ${prompt}`,\n * }],\n * });\n * ```\n */\nexport async function startPlayground(options: PlaygroundOptions): Promise<{\n server: NodeHttpServer;\n url: string;\n close: () => Promise<void>;\n}> {\n const port = options.port ?? 4000;\n const server = new NodeHttpServer();\n\n // Register playground API routes\n registerPlaygroundRoutes({\n server,\n agents: options.agents,\n });\n\n // CORS middleware for playground dev server\n server.use(async (_req, res, next) => {\n res.header(\"Access-Control-Allow-Origin\", \"*\");\n res.header(\"Access-Control-Allow-Methods\", \"GET, POST, OPTIONS\");\n res.header(\"Access-Control-Allow-Headers\", \"Content-Type\");\n await next();\n });\n\n await server.listen(port);\n const url = `http://localhost:${port}`;\n\n console.log(`\\n ⚡ Gauss Playground running at ${url}`);\n console.log(` 📡 API: ${url}/api/agents`);\n console.log(` 🎮 UI: Run 'cd packages/playground && npm run dev' for the React UI\\n`);\n\n if (options.open !== false) {\n try {\n const { exec } = await import(\"node:child_process\");\n const cmd = process.platform === \"darwin\" ? \"open\" : process.platform === \"win32\" ? \"start\" : \"xdg-open\";\n exec(`${cmd} ${url}`);\n } catch {\n // Ignore — opening browser is best-effort\n }\n }\n\n return {\n server,\n url,\n close: () => server.close(),\n };\n}\n","// =============================================================================\n// Learning Schemas — Cross-session memory structures\n// =============================================================================\n\nimport { z } from \"zod\";\n\nexport const UserProfileSchema = z.object({\n userId: z.string(),\n preferences: z.record(z.string(), z.unknown()).default({}),\n language: z.string().optional(),\n style: z.enum([\"concise\", \"detailed\", \"technical\", \"casual\"]).optional(),\n context: z.string().optional().describe(\"Persistent context about the user\"),\n updatedAt: z.number().default(() => Date.now()),\n createdAt: z.number().default(() => Date.now()),\n});\nexport type UserProfile = z.infer<typeof UserProfileSchema>;\n\nexport const UserMemorySchema = z.object({\n id: z.string(),\n content: z.string().describe(\"The learned fact or observation\"),\n tags: z.array(z.string()).default([]),\n confidence: z.number().min(0).max(1).default(1),\n source: z.enum([\"explicit\", \"inferred\"]).default(\"inferred\"),\n createdAt: z.number().default(() => Date.now()),\n});\nexport type UserMemory = z.infer<typeof UserMemorySchema>;\nexport type UserMemoryInput = z.input<typeof UserMemorySchema>;\n\nexport const SharedKnowledgeSchema = z.object({\n id: z.string(),\n content: z.string().describe(\"The knowledge insight\"),\n category: z.string().optional(),\n tags: z.array(z.string()).default([]),\n usageCount: z.number().default(0),\n createdAt: z.number().default(() => Date.now()),\n});\nexport type SharedKnowledge = z.infer<typeof SharedKnowledgeSchema>;\nexport type SharedKnowledgeInput = z.input<typeof SharedKnowledgeSchema>;\n","// =============================================================================\n// Conversation Schema — Message types for context management\n// =============================================================================\n\nimport { z } from \"zod\";\n\nexport const MessageSchema = z.object({\n role: z.enum([\"user\", \"assistant\", \"system\"]),\n content: z.string(),\n timestamp: z.number().optional(),\n});\n\nexport type MessageType = z.infer<typeof MessageSchema>;\n\nexport const CompressedContextSchema = z.object({\n summary: z.string().describe(\"LLM-generated summary of older messages\"),\n originalMessageCount: z\n .number()\n .describe(\"Number of messages that were summarized\"),\n compressedAt: z.number(),\n});\n\nexport type CompressedContextType = z.infer<typeof CompressedContextSchema>;\n\nexport const ConversationStateSchema = z.object({\n sessionId: z.string(),\n messages: z.array(MessageSchema),\n compressedContexts: z\n .array(CompressedContextSchema)\n .default([])\n .describe(\"Stack of compressed older conversation segments\"),\n totalTokensProcessed: z.number().default(0),\n});\n\nexport type ConversationState = z.infer<typeof ConversationStateSchema>;\n","// =============================================================================\n// Events Schema — Agent lifecycle events\n// =============================================================================\n\nimport { z } from \"zod\";\n\nexport const AgentEventTypeSchema = z.enum([\n \"agent:start\",\n \"agent:stop\",\n \"step:start\",\n \"step:end\",\n \"tool:call\",\n \"tool:result\",\n \"tool:approval-required\",\n \"tool:approved\",\n \"tool:denied\",\n \"checkpoint:save\",\n \"checkpoint:load\",\n \"context:summarize\",\n \"context:offload\",\n \"context:truncate\",\n \"subagent:spawn\",\n \"subagent:complete\",\n \"planning:update\",\n \"plan:created\",\n \"plan:started\",\n \"plan:completed\",\n \"plan:failed\",\n \"plan:updated\",\n \"plan:phase:started\",\n \"plan:phase:completed\",\n \"plan:step:started\",\n \"plan:step:completed\",\n \"plan:step:failed\",\n \"error\",\n \"graph:start\",\n \"graph:complete\",\n \"node:start\",\n \"node:complete\",\n \"consensus:start\",\n \"consensus:result\",\n \"fork:start\",\n \"fork:complete\",\n \"supervisor:start\",\n \"supervisor:stop\",\n \"supervisor:task:assigned\",\n \"supervisor:task:completed\",\n \"subagent:start\",\n \"subagent:stop\",\n \"subagent:message\",\n \"delegation:start\",\n \"delegation:blocked\",\n \"delegation:iteration\",\n \"delegation:complete\",\n \"delegation:message-filtered\",\n \"graph:node:retry\",\n \"graph:edge:traverse\",\n]);\n\nexport type AgentEventTypeValue = z.infer<typeof AgentEventTypeSchema>;\n\nexport const AgentEventSchema = z.object({\n type: AgentEventTypeSchema,\n timestamp: z.number(),\n sessionId: z.string(),\n data: z.unknown(),\n});\n\nexport type AgentEventValue = z.infer<typeof AgentEventSchema>;\n","// =============================================================================\n// Eval Schema — Evaluation metrics structures\n// =============================================================================\n\nimport { z } from \"zod\";\n\nexport const EvalMetricsSchema = z.object({\n latencyMs: z.number().describe(\"Total run time in milliseconds\"),\n stepCount: z.number().describe(\"Number of reasoning steps\"),\n toolCalls: z.record(z.string(), z.number()).describe(\"Tool call frequency map\"),\n tokenUsage: z.object({\n prompt: z.number().default(0),\n completion: z.number().default(0),\n total: z.number().default(0),\n }).optional(),\n customScores: z.record(z.string(), z.number()).default({}).describe(\"User-defined scores\"),\n});\nexport type EvalMetrics = z.infer<typeof EvalMetricsSchema>;\n\nexport const EvalResultSchema = z.object({\n id: z.string(),\n sessionId: z.string(),\n prompt: z.string(),\n output: z.string(),\n metrics: EvalMetricsSchema,\n createdAt: z.number().default(() => Date.now()),\n});\nexport type EvalResult = z.infer<typeof EvalResultSchema>;\n","// =============================================================================\n// LLMRecorder — Record all LLM calls for replay and testing\n// =============================================================================\n\nimport type { LanguageModel } from \"../core/llm/index.js\";\nimport { generateText } from \"../core/llm/index.js\";\nimport * as fs from \"node:fs\";\nimport * as path from \"node:path\";\n\n// =============================================================================\n// Types\n// =============================================================================\n\nexport interface LLMCallRecord {\n id: string;\n timestamp: string;\n model: string;\n input: {\n prompt?: string;\n messages?: unknown[];\n system?: string;\n };\n output: {\n text: string;\n usage?: { inputTokens?: number; outputTokens?: number };\n finishReason?: string;\n };\n durationMs: number;\n metadata?: Record<string, unknown>;\n}\n\nexport interface RecorderOptions {\n outputPath?: string;\n format?: \"jsonl\" | \"json\";\n captureMetadata?: boolean;\n}\n\nexport interface ReplayerOptions {\n strict?: boolean; // throw if no matching record found\n}\n\n// =============================================================================\n// LLMRecorder — Wraps model calls and records inputs/outputs\n// =============================================================================\n\nexport class LLMRecorder {\n private records: LLMCallRecord[] = [];\n private callCount = 0;\n private outputPath?: string;\n private format: \"jsonl\" | \"json\";\n private captureMetadata: boolean;\n\n constructor(options: RecorderOptions = {}) {\n this.outputPath = options.outputPath;\n this.format = options.format ?? \"jsonl\";\n this.captureMetadata = options.captureMetadata ?? true;\n }\n\n /** Record a single LLM call */\n async record(params: {\n model: LanguageModel;\n prompt?: string;\n messages?: unknown[];\n system?: string;\n metadata?: Record<string, unknown>;\n }): Promise<{ text: string; record: LLMCallRecord }> {\n const startMs = Date.now();\n const id = `call-${++this.callCount}`;\n\n const result = await (generateText as any)({\n model: params.model,\n prompt: params.prompt,\n system: params.system,\n });\n\n const durationMs = Date.now() - startMs;\n\n const record: LLMCallRecord = {\n id,\n timestamp: new Date(startMs).toISOString(),\n model:\n typeof params.model === \"string\"\n ? params.model\n : params.model.modelId ?? \"unknown\",\n input: {\n prompt: params.prompt,\n messages: params.messages,\n system: params.system,\n },\n output: {\n text: result.text,\n usage: result.usage\n ? {\n inputTokens: result.usage.inputTokens,\n outputTokens: result.usage.outputTokens,\n }\n : undefined,\n finishReason: result.finishReason,\n },\n durationMs,\n metadata: this.captureMetadata ? params.metadata : undefined,\n };\n\n this.records.push(record);\n return { text: result.text, record };\n }\n\n /** Get all recorded calls */\n getRecords(): LLMCallRecord[] {\n return [...this.records];\n }\n\n /** Save records to disk */\n async save(outputPath?: string): Promise<string> {\n const filePath = outputPath ?? this.outputPath ?? \"llm-recordings.jsonl\";\n const dir = path.dirname(filePath);\n if (dir !== \".\") {\n fs.mkdirSync(dir, { recursive: true });\n }\n\n if (this.format === \"jsonl\") {\n const content = this.records.map((r) => JSON.stringify(r)).join(\"\\n\") + \"\\n\";\n fs.writeFileSync(filePath, content, \"utf-8\");\n } else {\n fs.writeFileSync(filePath, JSON.stringify(this.records, null, 2), \"utf-8\");\n }\n return filePath;\n }\n\n /** Clear all records */\n clear(): void {\n this.records = [];\n this.callCount = 0;\n }\n}\n\n// =============================================================================\n// LLMReplayer — Replay recorded LLM calls for deterministic testing\n// =============================================================================\n\nexport class LLMReplayer {\n private records: LLMCallRecord[] = [];\n private index = 0;\n private strict: boolean;\n\n constructor(options: ReplayerOptions = {}) {\n this.strict = options.strict ?? true;\n }\n\n /** Load records from a JSONL file */\n loadFromFile(filePath: string): void {\n const content = fs.readFileSync(filePath, \"utf-8\");\n if (filePath.endsWith(\".json\")) {\n this.records = JSON.parse(content);\n } else {\n this.records = content\n .trim()\n .split(\"\\n\")\n .filter(Boolean)\n .map((line) => JSON.parse(line));\n }\n this.index = 0;\n }\n\n /** Load records from an in-memory array */\n loadFromRecords(records: LLMCallRecord[]): void {\n this.records = [...records];\n this.index = 0;\n }\n\n /** Replay the next recorded response */\n next(): LLMCallRecord {\n if (this.index >= this.records.length) {\n if (this.strict) {\n throw new Error(\n `LLMReplayer: no more records (exhausted ${this.records.length} recordings)`\n );\n }\n return this.records[this.records.length - 1];\n }\n return this.records[this.index++];\n }\n\n /** Find a matching record by prompt */\n findByPrompt(prompt: string): LLMCallRecord | undefined {\n return this.records.find((r) => r.input.prompt === prompt);\n }\n\n /** Find a matching record by model and prompt */\n findByModelAndPrompt(\n model: string,\n prompt: string\n ): LLMCallRecord | undefined {\n return this.records.find(\n (r) => r.model === model && r.input.prompt === prompt\n );\n }\n\n /** Check if more records are available */\n hasMore(): boolean {\n return this.index < this.records.length;\n }\n\n /** Reset replay to the beginning */\n reset(): void {\n this.index = 0;\n }\n\n /** Get total number of records */\n get count(): number {\n return this.records.length;\n }\n}\n","// =============================================================================\n// Visual Agent Builder — Declarative JSON config → Agent instantiation\n// =============================================================================\n\nimport { z } from \"zod\";\nimport type { LanguageModel } from \"../core/llm/index.js\";\n\n// =============================================================================\n// Config Schema — JSON declarative agent definition\n// =============================================================================\n\nexport const ToolConfigSchema = z.object({\n name: z.string(),\n description: z.string().optional(),\n parameters: z.record(z.unknown()).optional(),\n});\n\nexport const AgentNodeSchema = z.object({\n id: z.string(),\n type: z.enum([\"agent\", \"tool\", \"router\", \"transform\"]),\n model: z.string().optional(),\n instructions: z.string().optional(),\n tools: z.array(ToolConfigSchema).optional(),\n maxSteps: z.number().optional(),\n temperature: z.number().optional(),\n metadata: z.record(z.unknown()).optional(),\n});\n\nexport const EdgeSchema = z.object({\n from: z.string(),\n to: z.string(),\n condition: z.string().optional(),\n});\n\nexport const AgentConfigSchema = z.object({\n id: z.string(),\n name: z.string(),\n description: z.string().optional(),\n version: z.string().default(\"1.0.0\"),\n nodes: z.array(AgentNodeSchema),\n edges: z.array(EdgeSchema).default([]),\n entryNode: z.string(),\n metadata: z.record(z.unknown()).optional(),\n});\n\nexport type AgentConfigJSON = z.infer<typeof AgentConfigSchema>;\nexport type AgentNode = z.infer<typeof AgentNodeSchema>;\nexport type Edge = z.infer<typeof EdgeSchema>;\n\n// =============================================================================\n// ModelRegistry — Maps string model names to LanguageModel instances\n// =============================================================================\n\nexport class ModelRegistry {\n private models = new Map<string, LanguageModel>();\n\n register(name: string, model: LanguageModel): this {\n this.models.set(name, model);\n return this;\n }\n\n get(name: string): LanguageModel {\n const model = this.models.get(name);\n if (!model) {\n throw new Error(\n `Model \"${name}\" not registered. Available: ${[...this.models.keys()].join(\", \")}`\n );\n }\n return model;\n }\n\n has(name: string): boolean {\n return this.models.has(name);\n }\n\n list(): string[] {\n return [...this.models.keys()];\n }\n}\n\n// =============================================================================\n// AgentBuilder — Compiles JSON config to executable agent graph\n// =============================================================================\n\nexport interface CompiledAgent {\n id: string;\n name: string;\n config: AgentConfigJSON;\n nodes: Map<string, CompiledNode>;\n edges: Edge[];\n entryNode: string;\n execute: (input: string) => Promise<AgentBuilderResult>;\n}\n\nexport interface CompiledNode {\n id: string;\n type: AgentNode[\"type\"];\n model?: LanguageModel;\n instructions?: string;\n execute: (input: string, context: Record<string, unknown>) => Promise<string>;\n}\n\nexport interface AgentBuilderResult {\n output: string;\n nodesExecuted: string[];\n durationMs: number;\n}\n\nexport class VisualAgentBuilder {\n private registry: ModelRegistry;\n\n constructor(registry?: ModelRegistry) {\n this.registry = registry ?? new ModelRegistry();\n }\n\n /** Validate a JSON config */\n validate(config: unknown): { valid: boolean; errors: string[] } {\n const result = AgentConfigSchema.safeParse(config);\n if (result.success) {\n // Check entry node exists\n const entryExists = result.data.nodes.some(\n (n) => n.id === result.data.entryNode\n );\n if (!entryExists) {\n return {\n valid: false,\n errors: [`Entry node \"${result.data.entryNode}\" not found in nodes`],\n };\n }\n // Check edge references\n const nodeIds = new Set(result.data.nodes.map((n) => n.id));\n for (const edge of result.data.edges) {\n if (!nodeIds.has(edge.from)) {\n return {\n valid: false,\n errors: [`Edge references unknown node \"${edge.from}\"`],\n };\n }\n if (!nodeIds.has(edge.to)) {\n return {\n valid: false,\n errors: [`Edge references unknown node \"${edge.to}\"`],\n };\n }\n }\n return { valid: true, errors: [] };\n }\n return {\n valid: false,\n errors: result.error.errors.map(\n (e) => `${e.path.join(\".\")}: ${e.message}`\n ),\n };\n }\n\n /** Compile JSON config into an executable agent */\n compile(config: AgentConfigJSON): CompiledAgent {\n const validation = this.validate(config);\n if (!validation.valid) {\n throw new Error(`Invalid config: ${validation.errors.join(\"; \")}`);\n }\n\n const nodes = new Map<string, CompiledNode>();\n\n for (const node of config.nodes) {\n nodes.set(node.id, this.compileNode(node));\n }\n\n const execute = async (input: string): Promise<AgentBuilderResult> => {\n const start = Date.now();\n const nodesExecuted: string[] = [];\n const context: Record<string, unknown> = {};\n let currentOutput = input;\n let currentNodeId: string | undefined = config.entryNode;\n\n while (currentNodeId) {\n const node = nodes.get(currentNodeId);\n if (!node) break;\n\n currentOutput = await node.execute(currentOutput, context);\n nodesExecuted.push(currentNodeId);\n context[currentNodeId] = currentOutput;\n\n // Find next node via edges\n const outEdges = config.edges.filter((e) => e.from === currentNodeId);\n currentNodeId = undefined;\n\n for (const edge of outEdges) {\n if (!edge.condition) {\n currentNodeId = edge.to;\n break;\n }\n // Simple condition evaluation: check if context value is truthy\n try {\n const condFn = new Function(\n \"ctx\",\n \"output\",\n `return ${edge.condition}`\n );\n if (condFn(context, currentOutput)) {\n currentNodeId = edge.to;\n break;\n }\n } catch {\n // skip edge on condition error\n }\n }\n }\n\n return {\n output: currentOutput,\n nodesExecuted,\n durationMs: Date.now() - start,\n };\n };\n\n return {\n id: config.id,\n name: config.name,\n config,\n nodes,\n edges: config.edges,\n entryNode: config.entryNode,\n execute,\n };\n }\n\n private compileNode(node: AgentNode): CompiledNode {\n const model = node.model ? this.registry.get(node.model) : undefined;\n\n switch (node.type) {\n case \"transform\":\n return {\n id: node.id,\n type: node.type,\n execute: async (input) => {\n // Transform passes through with optional instructions as prefix\n return node.instructions\n ? `${node.instructions}\\n${input}`\n : input;\n },\n };\n\n case \"router\":\n return {\n id: node.id,\n type: node.type,\n execute: async (input) => input, // routing handled by edges\n };\n\n case \"tool\":\n return {\n id: node.id,\n type: node.type,\n execute: async (input) => {\n // Tool nodes are placeholders — real tools injected at runtime\n return `[tool:${node.id}] ${input}`;\n },\n };\n\n case \"agent\":\n default:\n return {\n id: node.id,\n type: node.type,\n model,\n instructions: node.instructions,\n execute: async (input) => {\n if (!model) {\n return `[agent:${node.id}] ${input}`;\n }\n // Dynamic import to avoid hard dependency\n const { generateText } = await import(\"../core/llm/index.js\");\n const result = await generateText({\n model: model as any,\n prompt: input,\n system: node.instructions,\n });\n return result.text;\n },\n };\n }\n }\n\n /** Get the model registry */\n getRegistry(): ModelRegistry {\n return this.registry;\n }\n}\n","// =============================================================================\n// Agent Builder REST API — POST /agents endpoint\n// =============================================================================\n\nimport {\n VisualAgentBuilder,\n ModelRegistry,\n AgentConfigSchema,\n type AgentConfigJSON,\n type CompiledAgent,\n} from \"./visual-agent-builder.js\";\n\nexport interface AgentBuilderAPIOptions {\n registry: ModelRegistry;\n onError?: (error: Error) => void;\n}\n\n/**\n * Create request handler for the agent builder REST API.\n * Framework-agnostic: returns { status, body } for any HTTP framework.\n */\nexport class AgentBuilderAPI {\n private builder: VisualAgentBuilder;\n private agents = new Map<string, CompiledAgent>();\n\n constructor(options: AgentBuilderAPIOptions) {\n this.builder = new VisualAgentBuilder(options.registry);\n }\n\n /** POST /agents — Create a new agent from JSON config */\n async createAgent(body: unknown): Promise<{\n status: number;\n body: Record<string, unknown>;\n }> {\n try {\n const validation = this.builder.validate(body);\n if (!validation.valid) {\n return {\n status: 400,\n body: { error: \"Invalid config\", details: validation.errors },\n };\n }\n\n const config = AgentConfigSchema.parse(body);\n const agent = this.builder.compile(config);\n this.agents.set(agent.id, agent);\n\n return {\n status: 201,\n body: {\n id: agent.id,\n name: agent.name,\n nodes: config.nodes.length,\n edges: config.edges.length,\n entryNode: agent.entryNode,\n },\n };\n } catch (err) {\n return {\n status: 500,\n body: { error: (err as Error).message },\n };\n }\n }\n\n /** GET /agents — List all deployed agents */\n listAgents(): { status: number; body: Record<string, unknown> } {\n const agents = [...this.agents.values()].map((a) => ({\n id: a.id,\n name: a.name,\n nodes: a.config.nodes.length,\n edges: a.config.edges.length,\n }));\n\n return { status: 200, body: { agents, count: agents.length } };\n }\n\n /** GET /agents/:id — Get agent details */\n getAgent(id: string): { status: number; body: Record<string, unknown> } {\n const agent = this.agents.get(id);\n if (!agent) {\n return { status: 404, body: { error: `Agent \"${id}\" not found` } };\n }\n\n return {\n status: 200,\n body: {\n id: agent.id,\n name: agent.name,\n config: agent.config,\n },\n };\n }\n\n /** POST /agents/:id/run — Execute an agent */\n async runAgent(\n id: string,\n input: string\n ): Promise<{ status: number; body: Record<string, unknown> }> {\n const agent = this.agents.get(id);\n if (!agent) {\n return { status: 404, body: { error: `Agent \"${id}\" not found` } };\n }\n\n try {\n const result = await agent.execute(input);\n return { status: 200, body: result as unknown as Record<string, unknown> };\n } catch (err) {\n return { status: 500, body: { error: (err as Error).message } };\n }\n }\n\n /** DELETE /agents/:id — Remove an agent */\n deleteAgent(id: string): { status: number; body: Record<string, unknown> } {\n if (!this.agents.has(id)) {\n return { status: 404, body: { error: `Agent \"${id}\" not found` } };\n }\n this.agents.delete(id);\n return { status: 200, body: { deleted: id } };\n }\n}\n","import { readdir, readFile, writeFile, mkdir } from \"fs/promises\";\nimport { join, basename, relative } from \"path\";\n\n/* ------------------------------------------------------------------ */\n/* Types */\n/* ------------------------------------------------------------------ */\n\nexport interface DocGeneratorOptions {\n srcDir: string;\n outputDir: string;\n title?: string;\n baseUrl?: string;\n}\n\nexport interface DocPage {\n path: string;\n title: string;\n content: string;\n category: string;\n}\n\nexport interface PortDoc {\n name: string;\n fileName: string;\n interfaces: InterfaceDoc[];\n types: string[];\n description: string;\n category: string;\n}\n\nexport interface InterfaceDoc {\n name: string;\n methods: MethodDoc[];\n description: string;\n}\n\nexport interface MethodDoc {\n name: string;\n signature: string;\n description: string;\n}\n\nexport interface AdapterDoc {\n name: string;\n dirName: string;\n implementations: string[];\n portName: string;\n category: string;\n}\n\n/* ------------------------------------------------------------------ */\n/* Category mapping */\n/* ------------------------------------------------------------------ */\n\nconst CATEGORY_MAP: Record<string, string> = {\n \"vector-store\": \"Storage\",\n memory: \"Storage\",\n \"working-memory\": \"Storage\",\n \"agent-memory\": \"Storage\",\n \"storage-domain\": \"Storage\",\n \"object-storage\": \"Storage\",\n embedding: \"AI / ML\",\n model: \"AI / ML\",\n reranking: \"AI / ML\",\n \"entity-extractor\": \"AI / ML\",\n \"knowledge-graph\": \"AI / ML\",\n chunking: \"Processing\",\n document: \"Processing\",\n \"partial-json\": \"Processing\",\n serializer: \"Processing\",\n validation: \"Processing\",\n telemetry: \"Observability\",\n tracing: \"Observability\",\n metrics: \"Observability\",\n logging: \"Observability\",\n \"cost-tracker\": \"Observability\",\n auth: \"Security\",\n policy: \"Security\",\n sandbox: \"Security\",\n voice: \"I/O\",\n \"semantic-scraping\": \"I/O\",\n filesystem: \"I/O\",\n server: \"Infrastructure\",\n \"http-server\": \"Infrastructure\",\n \"mcp-server\": \"Infrastructure\",\n mcp: \"Infrastructure\",\n acp: \"Infrastructure\",\n runtime: \"Infrastructure\",\n queue: \"Infrastructure\",\n \"save-queue\": \"Infrastructure\",\n bundler: \"Tooling\",\n compiler: \"Tooling\",\n deployer: \"Tooling\",\n \"hot-reload\": \"Tooling\",\n di: \"Core\",\n middleware: \"Core\",\n plugin: \"Core\",\n \"plugin-registry\": \"Core\",\n \"plugin-manifest\": \"Core\",\n workflow: \"Orchestration\",\n \"agent-network\": \"Orchestration\",\n consensus: \"Orchestration\",\n suspension: \"Orchestration\",\n \"graph-visualization\": \"Orchestration\",\n \"tool-composition\": \"Orchestration\",\n \"skill-matcher\": \"Orchestration\",\n skills: \"Orchestration\",\n datasets: \"AI / ML\",\n learning: \"AI / ML\",\n \"token-counter\": \"Observability\",\n};\n\nfunction categoryFor(name: string): string {\n return CATEGORY_MAP[name] ?? \"Other\";\n}\n\n/* ------------------------------------------------------------------ */\n/* Parsing helpers */\n/* ------------------------------------------------------------------ */\n\nconst INTERFACE_RE =\n /(?:\\/\\*\\*\\s*([\\s\\S]*?)\\s*\\*\\/\\s*)?export\\s+interface\\s+(\\w+)\\s*(?:extends\\s+[\\w<>,\\s]+)?\\s*\\{/g;\n\nconst METHOD_RE =\n /(?:\\/\\*\\*\\s*([\\s\\S]*?)\\s*\\*\\/\\s*)?([\\w]+)\\s*(\\([^)]*\\)\\s*:\\s*[^;]+);/g;\n\nconst TYPE_EXPORT_RE = /export\\s+(?:type|enum|const)\\s+(\\w+)/g;\n\nfunction extractDescription(raw: string | undefined): string {\n if (!raw) return \"\";\n return raw\n .replace(/\\*\\s?/g, \"\")\n .replace(/@\\w+[^\\n]*/g, \"\")\n .trim()\n .split(\"\\n\")\n .map((l) => l.trim())\n .filter(Boolean)\n .join(\" \");\n}\n\nfunction parseInterfaces(source: string): InterfaceDoc[] {\n const results: InterfaceDoc[] = [];\n let match: RegExpExecArray | null;\n\n INTERFACE_RE.lastIndex = 0;\n while ((match = INTERFACE_RE.exec(source)) !== null) {\n const description = extractDescription(match[1]);\n const name = match[2];\n\n // Find body between braces\n const start = source.indexOf(\"{\", match.index + match[0].length - 1);\n let depth = 1;\n let pos = start + 1;\n while (pos < source.length && depth > 0) {\n if (source[pos] === \"{\") depth++;\n if (source[pos] === \"}\") depth--;\n pos++;\n }\n const body = source.slice(start + 1, pos - 1);\n\n const methods: MethodDoc[] = [];\n let mMatch: RegExpExecArray | null;\n METHOD_RE.lastIndex = 0;\n while ((mMatch = METHOD_RE.exec(body)) !== null) {\n methods.push({\n name: mMatch[2],\n signature: `${mMatch[2]}${mMatch[3].trim()}`,\n description: extractDescription(mMatch[1]),\n });\n }\n\n results.push({ name, methods, description });\n }\n return results;\n}\n\nfunction parseTypeExports(source: string): string[] {\n const names: string[] = [];\n let match: RegExpExecArray | null;\n TYPE_EXPORT_RE.lastIndex = 0;\n while ((match = TYPE_EXPORT_RE.exec(source)) !== null) {\n names.push(match[1]);\n }\n return names;\n}\n\n/* ------------------------------------------------------------------ */\n/* DocGenerator */\n/* ------------------------------------------------------------------ */\n\nexport class DocGenerator {\n constructor(private options: DocGeneratorOptions) {}\n\n /* ---- public API ------------------------------------------------ */\n\n async generate(): Promise<DocPage[]> {\n const [ports, adapters] = await Promise.all([\n this.scanPorts(),\n this.scanAdapters(),\n ]);\n\n const pages: DocPage[] = [];\n\n for (const port of ports) {\n pages.push({\n path: `api/ports/${port.name}.md`,\n title: portTitle(port.name),\n content: this.renderPort(port),\n category: port.category,\n });\n }\n\n for (const adapter of adapters) {\n pages.push({\n path: `api/adapters/${adapter.name}.md`,\n title: adapterTitle(adapter.name),\n content: this.renderAdapter(adapter),\n category: adapter.category,\n });\n }\n\n pages.push({\n path: \"index.md\",\n title: this.options.title ?? \"Gauss Framework\",\n content: this.renderIndex(ports, adapters),\n category: \"Root\",\n });\n\n // Write files\n for (const page of pages) {\n const dest = join(this.options.outputDir, page.path);\n await mkdir(join(dest, \"..\"), { recursive: true });\n await writeFile(dest, page.content, \"utf-8\");\n }\n\n return pages;\n }\n\n async scanPorts(): Promise<PortDoc[]> {\n const portsDir = join(this.options.srcDir, \"ports\");\n const entries = await readdir(portsDir);\n const portFiles = entries.filter((e) => e.endsWith(\".port.ts\"));\n const docs: PortDoc[] = [];\n\n for (const file of portFiles) {\n const source = await readFile(join(portsDir, file), \"utf-8\");\n const name = basename(file, \".port.ts\");\n const interfaces = parseInterfaces(source);\n const types = parseTypeExports(source);\n const mainIface = interfaces.find((i) =>\n i.name.toLowerCase().includes(\"port\"),\n );\n\n docs.push({\n name,\n fileName: file,\n interfaces,\n types,\n description: mainIface?.description ?? \"\",\n category: categoryFor(name),\n });\n }\n\n return docs.sort((a, b) => a.name.localeCompare(b.name));\n }\n\n async scanAdapters(): Promise<AdapterDoc[]> {\n const adaptersDir = join(this.options.srcDir, \"adapters\");\n const entries = await readdir(adaptersDir, { withFileTypes: true });\n const docs: AdapterDoc[] = [];\n\n for (const entry of entries) {\n if (!entry.isDirectory()) continue;\n\n const dirPath = join(adaptersDir, entry.name);\n const files = await readdir(dirPath, { recursive: true });\n const implementations = files\n .filter(\n (f) =>\n typeof f === \"string\" &&\n f.endsWith(\".adapter.ts\") &&\n !f.includes(\"__tests__\"),\n )\n .map((f) => {\n const base = basename(f as string, \".adapter.ts\");\n return adapterClassName(base);\n });\n\n docs.push({\n name: entry.name,\n dirName: entry.name,\n implementations,\n portName: `${pascalCase(entry.name)}Port`,\n category: categoryFor(entry.name),\n });\n }\n\n return docs.sort((a, b) => a.name.localeCompare(b.name));\n }\n\n /* ---- renderers ------------------------------------------------- */\n\n renderPort(port: PortDoc): string {\n const lines: string[] = [];\n lines.push(`# ${portTitle(port.name)}`);\n lines.push(\"\");\n if (port.description) {\n lines.push(port.description);\n lines.push(\"\");\n }\n lines.push(`**Category:** ${port.category} `);\n lines.push(`**File:** \\`src/ports/${port.fileName}\\``);\n lines.push(\"\");\n\n for (const iface of port.interfaces) {\n lines.push(`## \\`${iface.name}\\``);\n lines.push(\"\");\n if (iface.description) {\n lines.push(iface.description);\n lines.push(\"\");\n }\n\n if (iface.methods.length > 0) {\n lines.push(\"| Method | Signature | Description |\");\n lines.push(\"|--------|-----------|-------------|\");\n for (const m of iface.methods) {\n const sig = `\\`${m.signature}\\``;\n lines.push(`| ${m.name} | ${sig} | ${m.description || \"—\"} |`);\n }\n lines.push(\"\");\n }\n }\n\n if (port.types.length > 0) {\n lines.push(\"## Exported Types\");\n lines.push(\"\");\n for (const t of port.types) {\n lines.push(`- \\`${t}\\``);\n }\n lines.push(\"\");\n }\n\n lines.push(\"---\");\n lines.push(\"\");\n lines.push(\n `[Back to API Reference](${this.baseUrl(\"/api/ports\")})`,\n );\n lines.push(\"\");\n return lines.join(\"\\n\");\n }\n\n renderAdapter(adapter: AdapterDoc): string {\n const lines: string[] = [];\n lines.push(`# ${adapterTitle(adapter.name)}`);\n lines.push(\"\");\n lines.push(`**Category:** ${adapter.category} `);\n lines.push(`**Port:** \\`${adapter.portName}\\` `);\n lines.push(`**Directory:** \\`src/adapters/${adapter.dirName}/\\``);\n lines.push(\"\");\n\n if (adapter.implementations.length > 0) {\n lines.push(\"## Implementations\");\n lines.push(\"\");\n for (const impl of adapter.implementations) {\n lines.push(`- \\`${impl}\\``);\n }\n lines.push(\"\");\n } else {\n lines.push(\"_No adapter files found._\");\n lines.push(\"\");\n }\n\n lines.push(\"## Usage\");\n lines.push(\"\");\n lines.push(\"```typescript\");\n const first =\n adapter.implementations[0] ?? `${pascalCase(adapter.name)}Adapter`;\n lines.push(\n `import { ${first} } from \"@giulio-leone/gauss\";`,\n );\n lines.push(\"\");\n lines.push(\n `const adapter = new ${first}(/* options */);`,\n );\n lines.push(\"```\");\n lines.push(\"\");\n\n lines.push(\"---\");\n lines.push(\"\");\n lines.push(\n `[Back to Adapters](${this.baseUrl(\"/api/adapters\")})`,\n );\n lines.push(\"\");\n return lines.join(\"\\n\");\n }\n\n renderIndex(ports: PortDoc[], adapters: AdapterDoc[]): string {\n const title = this.options.title ?? \"Gauss Framework\";\n const lines: string[] = [];\n lines.push(`# ${title}`);\n lines.push(\"\");\n lines.push(\n \"The most comprehensive agentic AI framework — hexagonal architecture, multi-runtime, plugin system, and multi-agent collaboration.\",\n );\n lines.push(\"\");\n\n // Ports summary by category\n const portsByCategory = groupBy(ports, (p) => p.category);\n lines.push(\"## Port Interfaces\");\n lines.push(\"\");\n for (const [cat, items] of Object.entries(portsByCategory).sort()) {\n lines.push(`### ${cat}`);\n lines.push(\"\");\n for (const p of items) {\n lines.push(\n `- [${portTitle(p.name)}](${this.baseUrl(`/api/ports/${p.name}`)})`,\n );\n }\n lines.push(\"\");\n }\n\n // Adapters summary by category\n const adaptersByCategory = groupBy(adapters, (a) => a.category);\n lines.push(\"## Adapter Implementations\");\n lines.push(\"\");\n for (const [cat, items] of Object.entries(adaptersByCategory).sort()) {\n lines.push(`### ${cat}`);\n lines.push(\"\");\n for (const a of items) {\n lines.push(\n `- [${adapterTitle(a.name)}](${this.baseUrl(`/api/adapters/${a.name}`)}) — ${a.implementations.length} implementation(s)`,\n );\n }\n lines.push(\"\");\n }\n\n return lines.join(\"\\n\");\n }\n\n /* ---- helpers --------------------------------------------------- */\n\n private baseUrl(path: string): string {\n const base = this.options.baseUrl ?? \"\";\n return `${base}${path}`;\n }\n}\n\n/* ------------------------------------------------------------------ */\n/* Utilities */\n/* ------------------------------------------------------------------ */\n\nfunction pascalCase(s: string): string {\n return s\n .split(\"-\")\n .map((w) => w.charAt(0).toUpperCase() + w.slice(1))\n .join(\"\");\n}\n\nfunction portTitle(name: string): string {\n return `${pascalCase(name)} Port`;\n}\n\nfunction adapterTitle(name: string): string {\n return `${pascalCase(name)} Adapters`;\n}\n\nfunction adapterClassName(base: string): string {\n return `${pascalCase(base)}Adapter`;\n}\n\nfunction groupBy<T>(items: T[], key: (item: T) => string): Record<string, T[]> {\n const map: Record<string, T[]> = {};\n for (const item of items) {\n const k = key(item);\n (map[k] ??= []).push(item);\n }\n return map;\n}\n","// =============================================================================\n// DebugSessionImpl — Navigable, branchable recording of an agent run\n// =============================================================================\n\nimport type {\n DebugSession,\n DebugCheckpoint,\n DebugState,\n BreakpointCondition,\n BreakpointHit,\n DebugDiff,\n} from \"../../ports/agent-debugger.port.js\";\n\ninterface StoredBreakpoint {\n id: string;\n condition: BreakpointCondition;\n}\n\nlet nextBpId = 0;\n\nexport class DebugSessionImpl implements DebugSession {\n readonly id: string;\n readonly agentId: string;\n readonly prompt: string;\n readonly checkpoints: DebugCheckpoint[] = [];\n\n private cursor = -1;\n private breakpoints: StoredBreakpoint[] = [];\n\n constructor(id: string, agentId: string, prompt: string) {\n this.id = id;\n this.agentId = agentId;\n this.prompt = prompt;\n }\n\n // ---------------------------------------------------------------------------\n // Checkpoint recording\n // ---------------------------------------------------------------------------\n\n addCheckpoint(\n type: DebugCheckpoint[\"type\"],\n data: Record<string, unknown>,\n state: DebugState,\n ): DebugCheckpoint {\n const cp: DebugCheckpoint = {\n index: this.checkpoints.length,\n timestamp: Date.now(),\n type,\n data,\n state: { ...state },\n };\n this.checkpoints.push(cp);\n this.cursor = cp.index;\n return cp;\n }\n\n // ---------------------------------------------------------------------------\n // Navigation\n // ---------------------------------------------------------------------------\n\n goto(index: number): DebugCheckpoint {\n if (index < 0 || index >= this.checkpoints.length) {\n throw new RangeError(\n `Checkpoint index ${index} out of range [0, ${this.checkpoints.length - 1}]`,\n );\n }\n this.cursor = index;\n return this.checkpoints[index];\n }\n\n stepForward(): DebugCheckpoint | null {\n if (this.cursor + 1 >= this.checkpoints.length) return null;\n this.cursor++;\n return this.checkpoints[this.cursor];\n }\n\n stepBackward(): DebugCheckpoint | null {\n if (this.cursor <= 0) return null;\n this.cursor--;\n return this.checkpoints[this.cursor];\n }\n\n currentIndex(): number {\n return this.cursor;\n }\n\n // ---------------------------------------------------------------------------\n // Branching\n // ---------------------------------------------------------------------------\n\n branch(modifications: Partial<DebugCheckpoint>): DebugSession {\n const branched = new DebugSessionImpl(\n `${this.id}-branch-${Date.now()}`,\n this.agentId,\n this.prompt,\n );\n\n // Clone checkpoints up to and including the current cursor\n const sliced = this.checkpoints.slice(0, this.cursor + 1);\n for (const cp of sliced) {\n branched.checkpoints.push({ ...cp, state: { ...cp.state } });\n }\n\n // Apply modifications to the last checkpoint\n if (branched.checkpoints.length > 0) {\n const last = branched.checkpoints[branched.checkpoints.length - 1];\n if (modifications.data) last.data = { ...last.data, ...modifications.data };\n if (modifications.state) last.state = { ...last.state, ...modifications.state };\n if (modifications.type) last.type = modifications.type;\n }\n\n branched.cursor = branched.checkpoints.length - 1;\n return branched;\n }\n\n // ---------------------------------------------------------------------------\n // Breakpoints\n // ---------------------------------------------------------------------------\n\n addBreakpoint(condition: BreakpointCondition): string {\n const id = `bp-${++nextBpId}`;\n this.breakpoints.push({ id, condition });\n return id;\n }\n\n removeBreakpoint(id: string): void {\n this.breakpoints = this.breakpoints.filter((bp) => bp.id !== id);\n }\n\n checkBreakpoints(checkpoint: DebugCheckpoint): BreakpointHit | null {\n for (const bp of this.breakpoints) {\n if (this.matchesCondition(bp.condition, checkpoint)) {\n return { breakpointId: bp.id, condition: bp.condition, checkpoint };\n }\n }\n return null;\n }\n\n private matchesCondition(\n cond: BreakpointCondition,\n cp: DebugCheckpoint,\n ): boolean {\n switch (cond.type) {\n case \"tool_call\":\n return (\n cp.type === \"tool_call\" &&\n (cond.toolName == null || cp.data[\"toolName\"] === cond.toolName)\n );\n case \"token_threshold\":\n return (\n cond.threshold != null && cp.state.tokenCount >= cond.threshold\n );\n case \"cost_threshold\":\n return (\n cond.threshold != null && cp.state.costEstimate >= cond.threshold\n );\n case \"step_count\":\n return cond.threshold != null && cp.index >= cond.threshold;\n case \"custom\":\n return cond.predicate ? cond.predicate(cp) : false;\n default:\n return false;\n }\n }\n\n // ---------------------------------------------------------------------------\n // Diff\n // ---------------------------------------------------------------------------\n\n diff(other: DebugSession | DebugCheckpoint[]): DebugDiff[] {\n const otherCps = Array.isArray(other) ? other : other.checkpoints;\n const diffs: DebugDiff[] = [];\n const maxLen = Math.max(this.checkpoints.length, otherCps.length);\n\n for (let i = 0; i < maxLen; i++) {\n const left = this.checkpoints[i];\n const right = otherCps[i];\n\n if (!left && right) {\n diffs.push({\n checkpointIndex: i,\n field: \"checkpoint\",\n left: undefined,\n right: right.type,\n type: \"added\",\n });\n continue;\n }\n if (left && !right) {\n diffs.push({\n checkpointIndex: i,\n field: \"checkpoint\",\n left: left.type,\n right: undefined,\n type: \"removed\",\n });\n continue;\n }\n if (left && right) {\n if (left.type !== right.type) {\n diffs.push({\n checkpointIndex: i,\n field: \"type\",\n left: left.type,\n right: right.type,\n type: \"changed\",\n });\n }\n if (JSON.stringify(left.data) !== JSON.stringify(right.data)) {\n diffs.push({\n checkpointIndex: i,\n field: \"data\",\n left: left.data,\n right: right.data,\n type: \"changed\",\n });\n }\n if (left.state.tokenCount !== right.state.tokenCount) {\n diffs.push({\n checkpointIndex: i,\n field: \"state.tokenCount\",\n left: left.state.tokenCount,\n right: right.state.tokenCount,\n type: \"changed\",\n });\n }\n if (left.state.costEstimate !== right.state.costEstimate) {\n diffs.push({\n checkpointIndex: i,\n field: \"state.costEstimate\",\n left: left.state.costEstimate,\n right: right.state.costEstimate,\n type: \"changed\",\n });\n }\n }\n }\n\n return diffs;\n }\n\n // ---------------------------------------------------------------------------\n // Serialization\n // ---------------------------------------------------------------------------\n\n serialize(): string {\n return JSON.stringify({\n id: this.id,\n agentId: this.agentId,\n prompt: this.prompt,\n checkpoints: this.checkpoints,\n cursor: this.cursor,\n });\n }\n\n static deserialize(json: string): DebugSessionImpl {\n const data = JSON.parse(json) as {\n id: string;\n agentId: string;\n prompt: string;\n checkpoints: DebugCheckpoint[];\n cursor: number;\n };\n const session = new DebugSessionImpl(data.id, data.agentId, data.prompt);\n for (const cp of data.checkpoints) {\n session.checkpoints.push(cp);\n }\n session.cursor = data.cursor;\n return session;\n }\n}\n","// =============================================================================\n// InMemoryAgentDebuggerAdapter — In-memory implementation of AgentDebuggerPort\n// =============================================================================\n\nimport type {\n AgentDebuggerPort,\n DebugSession,\n DebugSessionSummary,\n} from \"../../ports/agent-debugger.port.js\";\nimport { DebugSessionImpl } from \"./debug-session.js\";\n\nlet sessionCounter = 0;\n\nexport class InMemoryAgentDebuggerAdapter implements AgentDebuggerPort {\n private readonly sessions = new Map<string, DebugSessionImpl>();\n private readonly maxSessions: number;\n\n constructor(options?: { maxSessions?: number }) {\n this.maxSessions = options?.maxSessions ?? 1_000;\n }\n\n startSession(agentId: string, prompt: string): DebugSession {\n const id = `debug-${++sessionCounter}-${Date.now()}`;\n const session = new DebugSessionImpl(id, agentId, prompt);\n this.sessions.set(id, session);\n // Evict oldest session when over limit\n if (this.sessions.size > this.maxSessions) {\n const oldest = this.sessions.keys().next().value;\n if (oldest) this.sessions.delete(oldest);\n }\n return session;\n }\n\n listSessions(): DebugSessionSummary[] {\n const summaries: DebugSessionSummary[] = [];\n for (const session of this.sessions.values()) {\n const cps = session.checkpoints;\n const lastState = cps.length > 0 ? cps[cps.length - 1].state : null;\n const firstTs = cps.length > 0 ? cps[0].timestamp : Date.now();\n const lastTs = cps.length > 0 ? cps[cps.length - 1].timestamp : firstTs;\n\n summaries.push({\n id: session.id,\n agentId: session.agentId,\n prompt: session.prompt,\n checkpointCount: cps.length,\n totalTokens: lastState?.tokenCount ?? 0,\n totalCost: lastState?.costEstimate ?? 0,\n durationMs: lastTs - firstTs,\n createdAt: firstTs,\n });\n }\n return summaries;\n }\n\n loadSession(sessionId: string): DebugSession {\n const session = this.sessions.get(sessionId);\n if (!session) {\n throw new Error(`Debug session \"${sessionId}\" not found`);\n }\n return session;\n }\n\n /** Internal: get the implementation for the middleware */\n getSessionImpl(sessionId: string): DebugSessionImpl | undefined {\n return this.sessions.get(sessionId);\n }\n}\n","// =============================================================================\n// DebugMiddleware — Auto-records checkpoints during agent execution\n// =============================================================================\n\nimport type {\n MiddlewarePort,\n MiddlewareContext,\n BeforeAgentParams,\n BeforeAgentResult,\n AfterAgentParams,\n AfterAgentResult,\n BeforeToolCallParams,\n BeforeToolCallResult,\n AfterToolCallParams,\n AfterToolCallResult,\n OnMiddlewareErrorParams,\n OnMiddlewareErrorResult,\n} from \"../../ports/middleware.port.js\";\nimport { MiddlewarePriority } from \"../../ports/middleware.port.js\";\nimport type { DebugState } from \"../../ports/agent-debugger.port.js\";\nimport type { DebugSessionImpl } from \"./debug-session.js\";\nimport type { InMemoryAgentDebuggerAdapter } from \"./debugger.adapter.js\";\n\nexport class DebugMiddleware implements MiddlewarePort {\n readonly name = \"agent-debugger\";\n readonly priority = MiddlewarePriority.FIRST;\n\n private readonly debugger: InMemoryAgentDebuggerAdapter;\n private sessionMap = new Map<string, string>(); // middlewareSessionId → debugSessionId\n private stateMap = new Map<string, DebugState>();\n private startTimeMap = new Map<string, number>();\n\n constructor(debuggerAdapter: InMemoryAgentDebuggerAdapter) {\n this.debugger = debuggerAdapter;\n }\n\n /** Bind a middleware context session to a debug session */\n bindSession(middlewareSessionId: string, debugSessionId: string): void {\n this.sessionMap.set(middlewareSessionId, debugSessionId);\n }\n\n private getSession(ctx: MiddlewareContext): DebugSessionImpl | undefined {\n const debugId = this.sessionMap.get(ctx.sessionId);\n if (!debugId) return undefined;\n return this.debugger.getSessionImpl(debugId);\n }\n\n private getState(ctx: MiddlewareContext): DebugState {\n let state = this.stateMap.get(ctx.sessionId);\n if (!state) {\n state = {\n messages: [],\n toolCalls: [],\n tokenCount: 0,\n costEstimate: 0,\n elapsedMs: 0,\n metadata: {},\n };\n this.stateMap.set(ctx.sessionId, state);\n this.startTimeMap.set(ctx.sessionId, Date.now());\n }\n state.elapsedMs = Date.now() - (this.startTimeMap.get(ctx.sessionId) ?? Date.now());\n return state;\n }\n\n private snapshot(state: DebugState): DebugState {\n return {\n messages: [...state.messages],\n toolCalls: [...state.toolCalls],\n tokenCount: state.tokenCount,\n costEstimate: state.costEstimate,\n elapsedMs: state.elapsedMs,\n metadata: { ...state.metadata },\n };\n }\n\n async beforeAgent(\n ctx: MiddlewareContext,\n params: BeforeAgentParams,\n ): Promise<BeforeAgentResult | void> {\n const session = this.getSession(ctx);\n if (!session) return;\n const state = this.getState(ctx);\n session.addCheckpoint(\n \"agent_start\",\n { prompt: params.prompt, instructions: params.instructions },\n this.snapshot(state),\n );\n }\n\n async afterAgent(\n ctx: MiddlewareContext,\n params: AfterAgentParams,\n ): Promise<AfterAgentResult | void> {\n const session = this.getSession(ctx);\n if (!session) return;\n const state = this.getState(ctx);\n state.messages.push({ role: \"assistant\", content: params.result.text });\n session.addCheckpoint(\n \"agent_end\",\n { result: params.result.text },\n this.snapshot(state),\n );\n }\n\n async beforeTool(\n ctx: MiddlewareContext,\n params: BeforeToolCallParams,\n ): Promise<BeforeToolCallResult | void> {\n const session = this.getSession(ctx);\n if (!session) return;\n const state = this.getState(ctx);\n session.addCheckpoint(\n \"tool_call\",\n { toolName: params.toolName, args: params.args, stepIndex: params.stepIndex },\n this.snapshot(state),\n );\n }\n\n async afterTool(\n ctx: MiddlewareContext,\n params: AfterToolCallParams,\n ): Promise<AfterToolCallResult | void> {\n const session = this.getSession(ctx);\n if (!session) return;\n const state = this.getState(ctx);\n state.toolCalls.push({\n name: params.toolName,\n args: params.args,\n result: params.result,\n });\n session.addCheckpoint(\n \"tool_result\",\n {\n toolName: params.toolName,\n args: params.args,\n result: params.result,\n durationMs: params.durationMs,\n },\n this.snapshot(state),\n );\n }\n\n async onError(\n ctx: MiddlewareContext,\n params: OnMiddlewareErrorParams,\n ): Promise<OnMiddlewareErrorResult | void> {\n const session = this.getSession(ctx);\n if (!session) return;\n const state = this.getState(ctx);\n session.addCheckpoint(\n \"error\",\n {\n error: params.error instanceof Error ? params.error.message : String(params.error),\n phase: params.phase,\n middlewareName: params.middlewareName,\n },\n this.snapshot(state),\n );\n }\n\n /** Manually update token/cost state (called externally when LLM usage is known) */\n recordUsage(\n middlewareSessionId: string,\n tokens: number,\n cost: number,\n ): void {\n let state = this.stateMap.get(middlewareSessionId);\n if (!state) {\n state = {\n messages: [],\n toolCalls: [],\n tokenCount: 0,\n costEstimate: 0,\n elapsedMs: 0,\n metadata: {},\n };\n this.stateMap.set(middlewareSessionId, state);\n this.startTimeMap.set(middlewareSessionId, Date.now());\n }\n state.tokenCount += tokens;\n state.costEstimate += cost;\n }\n}\n","// =============================================================================\n// Supervisor Pattern — One agent delegates to sub-agents, aggregates results\n// =============================================================================\n\nimport type {\n Orchestration,\n OrchestrationConfig,\n OrchestrationEvent,\n OrchestrationMessage,\n OrchestrationResult,\n} from \"../../../ports/agent-orchestrator.port.js\";\n\nexport function createSupervisorOrchestration(\n config: OrchestrationConfig,\n id: string,\n): Orchestration {\n let abortController = new AbortController();\n\n const opts = config.options?.supervisor ?? {\n delegationStrategy: \"round-robin\",\n aggregationStrategy: \"concat\",\n };\n const maxRounds = config.options?.maxRounds ?? 1;\n\n async function execute(input: string): Promise<OrchestrationResult> {\n const start = Date.now();\n const allMessages: OrchestrationMessage[] = [];\n const agentResults = new Map<string, OrchestrationMessage[]>();\n\n for (const agent of config.agents) {\n agentResults.set(agent.id, []);\n }\n\n let roundIndex = 0;\n for (let round = 0; round < maxRounds; round++) {\n if (abortController.signal.aborted) break;\n roundIndex = round + 1;\n\n const agentsForRound = selectAgents(config, opts.delegationStrategy, round);\n\n for (const agent of agentsForRound) {\n if (abortController.signal.aborted) break;\n\n const msg: OrchestrationMessage = {\n from: \"supervisor\",\n to: agent.id,\n content: input,\n };\n\n try {\n const result = await agent.execute(msg);\n allMessages.push(msg, result);\n agentResults.get(agent.id)!.push(result);\n } catch (err) {\n const errorMsg: OrchestrationMessage = {\n from: agent.id,\n to: \"supervisor\",\n content: `Error: ${err instanceof Error ? err.message : String(err)}`,\n metadata: { error: true },\n };\n allMessages.push(msg, errorMsg);\n agentResults.get(agent.id)!.push(errorMsg);\n }\n }\n }\n\n const responses = Array.from(agentResults.values())\n .flat()\n .filter((m) => !m.metadata?.error);\n\n const output = aggregate(responses, opts.aggregationStrategy);\n\n return {\n output,\n messages: allMessages,\n pattern: \"supervisor\",\n agentResults,\n durationMs: Date.now() - start,\n rounds: roundIndex,\n };\n }\n\n async function* stream(input: string): AsyncIterable<OrchestrationEvent> {\n const start = Date.now();\n const allMessages: OrchestrationMessage[] = [];\n const agentResults = new Map<string, OrchestrationMessage[]>();\n\n for (const agent of config.agents) {\n agentResults.set(agent.id, []);\n }\n\n let roundIndex = 0;\n for (let round = 0; round < maxRounds; round++) {\n if (abortController.signal.aborted) break;\n roundIndex = round + 1;\n yield { type: \"round_start\", round: roundIndex };\n\n const agentsForRound = selectAgents(config, opts.delegationStrategy, round);\n\n for (const agent of agentsForRound) {\n if (abortController.signal.aborted) break;\n yield { type: \"agent_start\", agentId: agent.id };\n\n const msg: OrchestrationMessage = {\n from: \"supervisor\",\n to: agent.id,\n content: input,\n };\n\n try {\n const result = await agent.execute(msg);\n allMessages.push(msg, result);\n agentResults.get(agent.id)!.push(result);\n yield { type: \"message\", agentId: agent.id, message: result };\n yield { type: \"agent_end\", agentId: agent.id };\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n yield { type: \"error\", agentId: agent.id, error };\n yield { type: \"agent_end\", agentId: agent.id };\n }\n }\n\n yield { type: \"round_end\", round: roundIndex };\n }\n\n const responses = Array.from(agentResults.values())\n .flat()\n .filter((m) => !m.metadata?.error);\n\n yield {\n type: \"complete\",\n result: {\n output: aggregate(responses, opts.aggregationStrategy),\n messages: allMessages,\n pattern: \"supervisor\",\n agentResults,\n durationMs: Date.now() - start,\n rounds: roundIndex,\n },\n };\n }\n\n function cancel(): void {\n abortController.abort();\n }\n\n return { id, pattern: \"supervisor\", execute, stream, cancel };\n}\n\nfunction selectAgents(\n config: OrchestrationConfig,\n strategy: string,\n round: number,\n) {\n if (strategy === \"round-robin\") {\n const idx = round % config.agents.length;\n return round === 0 ? config.agents : [config.agents[idx]];\n }\n return config.agents;\n}\n\nfunction aggregate(\n messages: OrchestrationMessage[],\n strategy: string,\n): string {\n if (messages.length === 0) return \"\";\n\n switch (strategy) {\n case \"vote\": {\n const counts = new Map<string, number>();\n for (const m of messages) {\n counts.set(m.content, (counts.get(m.content) ?? 0) + 1);\n }\n let best = \"\";\n let bestCount = 0;\n for (const [content, count] of counts) {\n if (count > bestCount) {\n best = content;\n bestCount = count;\n }\n }\n return best;\n }\n case \"summarize\":\n return messages.map((m) => `[${m.from}]: ${m.content}`).join(\"\\n\");\n case \"concat\":\n default:\n return messages.map((m) => m.content).join(\"\\n\");\n }\n}\n","// =============================================================================\n// Swarm Pattern — Peer-to-peer communication with shared blackboard\n// =============================================================================\n\nimport type {\n Orchestration,\n OrchestrationConfig,\n OrchestrationEvent,\n OrchestrationMessage,\n OrchestrationResult,\n} from \"../../../ports/agent-orchestrator.port.js\";\n\nconst DEFAULT_MAX_ROUNDS = 10;\n\nexport function createSwarmOrchestration(\n config: OrchestrationConfig,\n id: string,\n): Orchestration {\n let abortController = new AbortController();\n\n const maxRounds = config.options?.maxRounds ?? DEFAULT_MAX_ROUNDS;\n const blackboard = config.options?.swarm?.blackboard ?? new Map<string, unknown>();\n const convergenceCheck = config.options?.swarm?.convergenceCheck;\n\n async function execute(input: string): Promise<OrchestrationResult> {\n const start = Date.now();\n const allMessages: OrchestrationMessage[] = [];\n const agentResults = new Map<string, OrchestrationMessage[]>();\n\n for (const agent of config.agents) {\n agentResults.set(agent.id, []);\n }\n\n blackboard.set(\"input\", input);\n let roundMessages: OrchestrationMessage[] = [];\n let roundIndex = 0;\n\n for (let round = 0; round < maxRounds; round++) {\n if (abortController.signal.aborted) break;\n roundIndex = round + 1;\n\n const currentInput =\n roundMessages.length > 0\n ? roundMessages.map((m) => m.content).join(\"\\n\")\n : input;\n\n roundMessages = [];\n\n for (const agent of config.agents) {\n if (abortController.signal.aborted) break;\n\n const msg: OrchestrationMessage = {\n from: \"swarm\",\n to: agent.id,\n content: currentInput,\n metadata: { round: roundIndex, blackboard: Object.fromEntries(blackboard) },\n };\n\n try {\n const result = await agent.execute(msg);\n roundMessages.push(result);\n allMessages.push(msg, result);\n agentResults.get(agent.id)!.push(result);\n blackboard.set(`${agent.id}_round_${roundIndex}`, result.content);\n } catch {\n // Swarm tolerates individual agent failures\n }\n }\n\n if (convergenceCheck && convergenceCheck(roundMessages)) break;\n }\n\n const lastResponses = roundMessages.length > 0 ? roundMessages : [];\n const output = lastResponses.map((m) => m.content).join(\"\\n\");\n\n return {\n output,\n messages: allMessages,\n pattern: \"swarm\",\n agentResults,\n durationMs: Date.now() - start,\n rounds: roundIndex,\n };\n }\n\n async function* stream(input: string): AsyncIterable<OrchestrationEvent> {\n const start = Date.now();\n const allMessages: OrchestrationMessage[] = [];\n const agentResults = new Map<string, OrchestrationMessage[]>();\n\n for (const agent of config.agents) {\n agentResults.set(agent.id, []);\n }\n\n blackboard.set(\"input\", input);\n let roundMessages: OrchestrationMessage[] = [];\n let roundIndex = 0;\n\n for (let round = 0; round < maxRounds; round++) {\n if (abortController.signal.aborted) break;\n roundIndex = round + 1;\n yield { type: \"round_start\", round: roundIndex };\n\n const currentInput =\n roundMessages.length > 0\n ? roundMessages.map((m) => m.content).join(\"\\n\")\n : input;\n\n roundMessages = [];\n\n for (const agent of config.agents) {\n if (abortController.signal.aborted) break;\n yield { type: \"agent_start\", agentId: agent.id };\n\n const msg: OrchestrationMessage = {\n from: \"swarm\",\n to: agent.id,\n content: currentInput,\n metadata: { round: roundIndex, blackboard: Object.fromEntries(blackboard) },\n };\n\n try {\n const result = await agent.execute(msg);\n roundMessages.push(result);\n allMessages.push(msg, result);\n agentResults.get(agent.id)!.push(result);\n blackboard.set(`${agent.id}_round_${roundIndex}`, result.content);\n yield { type: \"message\", agentId: agent.id, message: result };\n yield { type: \"agent_end\", agentId: agent.id };\n } catch (err) {\n yield {\n type: \"error\",\n agentId: agent.id,\n error: err instanceof Error ? err : new Error(String(err)),\n };\n yield { type: \"agent_end\", agentId: agent.id };\n }\n }\n\n yield { type: \"round_end\", round: roundIndex };\n if (convergenceCheck && convergenceCheck(roundMessages)) break;\n }\n\n const output = roundMessages.map((m) => m.content).join(\"\\n\");\n\n yield {\n type: \"complete\",\n result: {\n output,\n messages: allMessages,\n pattern: \"swarm\",\n agentResults,\n durationMs: Date.now() - start,\n rounds: roundIndex,\n },\n };\n }\n\n function cancel(): void {\n abortController.abort();\n }\n\n return { id, pattern: \"swarm\", execute, stream, cancel };\n}\n","// =============================================================================\n// Pipeline Pattern — Chain agents in sequence, each transforming the output\n// =============================================================================\n\nimport type {\n Orchestration,\n OrchestrationConfig,\n OrchestrationEvent,\n OrchestrationMessage,\n OrchestrationResult,\n} from \"../../../ports/agent-orchestrator.port.js\";\n\nconst DEFAULT_RETRY_COUNT = 2;\n\nexport function createPipelineOrchestration(\n config: OrchestrationConfig,\n id: string,\n): Orchestration {\n let abortController = new AbortController();\n\n const errorStrategy = config.options?.pipeline?.errorStrategy ?? \"stop\";\n const retryCount = config.options?.pipeline?.retryCount ?? DEFAULT_RETRY_COUNT;\n\n async function execute(input: string): Promise<OrchestrationResult> {\n const start = Date.now();\n const allMessages: OrchestrationMessage[] = [];\n const agentResults = new Map<string, OrchestrationMessage[]>();\n\n for (const agent of config.agents) {\n agentResults.set(agent.id, []);\n }\n\n let currentContent = input;\n\n for (const agent of config.agents) {\n if (abortController.signal.aborted) break;\n\n const msg: OrchestrationMessage = {\n from: \"pipeline\",\n to: agent.id,\n content: currentContent,\n };\n\n try {\n const result = await executeWithRetry(agent, msg, errorStrategy, retryCount);\n allMessages.push(msg, result);\n agentResults.get(agent.id)!.push(result);\n currentContent = result.content;\n } catch (err) {\n const errorMsg: OrchestrationMessage = {\n from: agent.id,\n to: \"pipeline\",\n content: `Error: ${err instanceof Error ? err.message : String(err)}`,\n metadata: { error: true },\n };\n allMessages.push(msg, errorMsg);\n agentResults.get(agent.id)!.push(errorMsg);\n\n if (errorStrategy === \"stop\") break;\n // skip: continue with the current content unchanged\n }\n }\n\n return {\n output: currentContent,\n messages: allMessages,\n pattern: \"pipeline\",\n agentResults,\n durationMs: Date.now() - start,\n rounds: 1,\n };\n }\n\n async function* stream(input: string): AsyncIterable<OrchestrationEvent> {\n const start = Date.now();\n const allMessages: OrchestrationMessage[] = [];\n const agentResults = new Map<string, OrchestrationMessage[]>();\n\n for (const agent of config.agents) {\n agentResults.set(agent.id, []);\n }\n\n let currentContent = input;\n yield { type: \"round_start\", round: 1 };\n\n for (const agent of config.agents) {\n if (abortController.signal.aborted) break;\n yield { type: \"agent_start\", agentId: agent.id };\n\n const msg: OrchestrationMessage = {\n from: \"pipeline\",\n to: agent.id,\n content: currentContent,\n };\n\n try {\n const result = await executeWithRetry(agent, msg, errorStrategy, retryCount);\n allMessages.push(msg, result);\n agentResults.get(agent.id)!.push(result);\n currentContent = result.content;\n yield { type: \"message\", agentId: agent.id, message: result };\n yield { type: \"agent_end\", agentId: agent.id };\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n yield { type: \"error\", agentId: agent.id, error };\n yield { type: \"agent_end\", agentId: agent.id };\n if (errorStrategy === \"stop\") break;\n }\n }\n\n yield { type: \"round_end\", round: 1 };\n\n yield {\n type: \"complete\",\n result: {\n output: currentContent,\n messages: allMessages,\n pattern: \"pipeline\",\n agentResults,\n durationMs: Date.now() - start,\n rounds: 1,\n },\n };\n }\n\n function cancel(): void {\n abortController.abort();\n }\n\n return { id, pattern: \"pipeline\", execute, stream, cancel };\n}\n\nasync function executeWithRetry(\n agent: { id: string; execute: (input: OrchestrationMessage) => Promise<OrchestrationMessage> },\n msg: OrchestrationMessage,\n errorStrategy: string,\n retryCount: number,\n): Promise<OrchestrationMessage> {\n let lastError: unknown;\n\n const attempts = errorStrategy === \"retry\" ? retryCount + 1 : 1;\n for (let i = 0; i < attempts; i++) {\n try {\n return await agent.execute(msg);\n } catch (err) {\n lastError = err;\n }\n }\n\n throw lastError;\n}\n","// =============================================================================\n// MapReduce Pattern — Split work across parallel agents, then reduce\n// =============================================================================\n\nimport type {\n Orchestration,\n OrchestrationConfig,\n OrchestrationEvent,\n OrchestrationMessage,\n OrchestrationResult,\n} from \"../../../ports/agent-orchestrator.port.js\";\n\nconst DEFAULT_CONCURRENCY = Infinity;\n\nexport function createMapReduceOrchestration(\n config: OrchestrationConfig,\n id: string,\n): Orchestration {\n let abortController = new AbortController();\n\n const mapReduceOpts = config.options?.mapReduce;\n if (!mapReduceOpts) {\n throw new Error(\"MapReduce pattern requires mapReduce options (splitFn, reduceFn)\");\n }\n\n const { splitFn, reduceFn } = mapReduceOpts;\n const concurrency = mapReduceOpts.concurrency ?? DEFAULT_CONCURRENCY;\n\n async function execute(input: string): Promise<OrchestrationResult> {\n const start = Date.now();\n const allMessages: OrchestrationMessage[] = [];\n const agentResults = new Map<string, OrchestrationMessage[]>();\n\n for (const agent of config.agents) {\n agentResults.set(agent.id, []);\n }\n\n const chunks = splitFn(input);\n const mapResults: OrchestrationMessage[] = [];\n\n // Process chunks with concurrency control\n const pending: Promise<void>[] = [];\n let chunkIndex = 0;\n\n async function processChunk(chunk: string): Promise<void> {\n if (abortController.signal.aborted) return;\n\n const agentIndex = chunkIndex % config.agents.length;\n const agent = config.agents[agentIndex];\n chunkIndex++;\n\n const msg: OrchestrationMessage = {\n from: \"map-reduce\",\n to: agent.id,\n content: chunk,\n metadata: { phase: \"map\" },\n };\n\n try {\n const result = await agent.execute(msg);\n allMessages.push(msg, result);\n agentResults.get(agent.id)!.push(result);\n mapResults.push(result);\n } catch {\n // Skip failed chunks\n }\n }\n\n if (concurrency === Infinity) {\n await Promise.all(chunks.map((chunk) => processChunk(chunk)));\n } else {\n for (const chunk of chunks) {\n if (abortController.signal.aborted) break;\n\n if (pending.length >= concurrency) {\n await Promise.race(pending);\n }\n\n const p = processChunk(chunk).then(() => {\n pending.splice(pending.indexOf(p), 1);\n });\n pending.push(p);\n }\n await Promise.all(pending);\n }\n\n const reduced = reduceFn(mapResults);\n\n return {\n output: reduced.content,\n messages: allMessages,\n pattern: \"map-reduce\",\n agentResults,\n durationMs: Date.now() - start,\n rounds: 1,\n };\n }\n\n async function* stream(input: string): AsyncIterable<OrchestrationEvent> {\n const start = Date.now();\n const allMessages: OrchestrationMessage[] = [];\n const agentResults = new Map<string, OrchestrationMessage[]>();\n\n for (const agent of config.agents) {\n agentResults.set(agent.id, []);\n }\n\n yield { type: \"round_start\", round: 1 };\n\n const chunks = splitFn(input);\n const mapResults: OrchestrationMessage[] = [];\n\n for (let i = 0; i < chunks.length; i++) {\n if (abortController.signal.aborted) break;\n\n const agent = config.agents[i % config.agents.length];\n yield { type: \"agent_start\", agentId: agent.id };\n\n const msg: OrchestrationMessage = {\n from: \"map-reduce\",\n to: agent.id,\n content: chunks[i],\n metadata: { phase: \"map\" },\n };\n\n try {\n const result = await agent.execute(msg);\n allMessages.push(msg, result);\n agentResults.get(agent.id)!.push(result);\n mapResults.push(result);\n yield { type: \"message\", agentId: agent.id, message: result };\n yield { type: \"agent_end\", agentId: agent.id };\n } catch (err) {\n yield {\n type: \"error\",\n agentId: agent.id,\n error: err instanceof Error ? err : new Error(String(err)),\n };\n yield { type: \"agent_end\", agentId: agent.id };\n }\n }\n\n const reduced = reduceFn(mapResults);\n\n yield { type: \"round_end\", round: 1 };\n\n yield {\n type: \"complete\",\n result: {\n output: reduced.content,\n messages: allMessages,\n pattern: \"map-reduce\",\n agentResults,\n durationMs: Date.now() - start,\n rounds: 1,\n },\n };\n }\n\n function cancel(): void {\n abortController.abort();\n }\n\n return { id, pattern: \"map-reduce\", execute, stream, cancel };\n}\n","// =============================================================================\n// Debate Pattern — Multiple agents argue positions, judge picks winner\n// =============================================================================\n\nimport type {\n Orchestration,\n OrchestrationConfig,\n OrchestrationEvent,\n OrchestrationMessage,\n OrchestrationResult,\n} from \"../../../ports/agent-orchestrator.port.js\";\n\nconst DEFAULT_DEBATE_ROUNDS = 3;\n\nexport function createDebateOrchestration(\n config: OrchestrationConfig,\n id: string,\n): Orchestration {\n let abortController = new AbortController();\n\n const debateOpts = config.options?.debate;\n const rounds = debateOpts?.rounds ?? DEFAULT_DEBATE_ROUNDS;\n const judgeAgentId = debateOpts?.judgeAgentId;\n const votingStrategy = debateOpts?.votingStrategy ?? \"judge\";\n\n const judge = judgeAgentId\n ? config.agents.find((a) => a.id === judgeAgentId)\n : undefined;\n\n const debaters = config.agents.filter((a) => a.id !== judgeAgentId);\n\n async function execute(input: string): Promise<OrchestrationResult> {\n const start = Date.now();\n const allMessages: OrchestrationMessage[] = [];\n const agentResults = new Map<string, OrchestrationMessage[]>();\n\n for (const agent of config.agents) {\n agentResults.set(agent.id, []);\n }\n\n let context = input;\n\n for (let round = 0; round < rounds; round++) {\n if (abortController.signal.aborted) break;\n\n const roundResponses: OrchestrationMessage[] = [];\n\n for (const debater of debaters) {\n if (abortController.signal.aborted) break;\n\n const msg: OrchestrationMessage = {\n from: \"debate\",\n to: debater.id,\n content: context,\n metadata: { round: round + 1 },\n };\n\n try {\n const result = await debater.execute(msg);\n roundResponses.push(result);\n allMessages.push(msg, result);\n agentResults.get(debater.id)!.push(result);\n } catch {\n // Skip failed debaters\n }\n }\n\n context =\n roundResponses.length > 0\n ? roundResponses.map((m) => `[${m.from}]: ${m.content}`).join(\"\\n\")\n : context;\n }\n\n // Judge phase\n const output = await judgeResults(\n context,\n allMessages,\n agentResults,\n votingStrategy,\n judge,\n debaters,\n );\n\n return {\n output,\n messages: allMessages,\n pattern: \"debate\",\n agentResults,\n durationMs: Date.now() - start,\n rounds,\n };\n }\n\n async function* stream(input: string): AsyncIterable<OrchestrationEvent> {\n const start = Date.now();\n const allMessages: OrchestrationMessage[] = [];\n const agentResults = new Map<string, OrchestrationMessage[]>();\n\n for (const agent of config.agents) {\n agentResults.set(agent.id, []);\n }\n\n let context = input;\n\n for (let round = 0; round < rounds; round++) {\n if (abortController.signal.aborted) break;\n yield { type: \"round_start\", round: round + 1 };\n\n const roundResponses: OrchestrationMessage[] = [];\n\n for (const debater of debaters) {\n if (abortController.signal.aborted) break;\n yield { type: \"agent_start\", agentId: debater.id };\n\n const msg: OrchestrationMessage = {\n from: \"debate\",\n to: debater.id,\n content: context,\n metadata: { round: round + 1 },\n };\n\n try {\n const result = await debater.execute(msg);\n roundResponses.push(result);\n allMessages.push(msg, result);\n agentResults.get(debater.id)!.push(result);\n yield { type: \"message\", agentId: debater.id, message: result };\n yield { type: \"agent_end\", agentId: debater.id };\n } catch (err) {\n yield {\n type: \"error\",\n agentId: debater.id,\n error: err instanceof Error ? err : new Error(String(err)),\n };\n yield { type: \"agent_end\", agentId: debater.id };\n }\n }\n\n context =\n roundResponses.length > 0\n ? roundResponses.map((m) => `[${m.from}]: ${m.content}`).join(\"\\n\")\n : context;\n\n yield { type: \"round_end\", round: round + 1 };\n }\n\n // Judge phase\n if (judge) {\n yield { type: \"agent_start\", agentId: judge.id };\n }\n\n const output = await judgeResults(\n context,\n allMessages,\n agentResults,\n votingStrategy,\n judge,\n debaters,\n );\n\n if (judge) {\n yield { type: \"agent_end\", agentId: judge.id };\n }\n\n yield {\n type: \"complete\",\n result: {\n output,\n messages: allMessages,\n pattern: \"debate\",\n agentResults,\n durationMs: Date.now() - start,\n rounds,\n },\n };\n }\n\n function cancel(): void {\n abortController.abort();\n }\n\n return { id, pattern: \"debate\", execute, stream, cancel };\n}\n\nasync function judgeResults(\n context: string,\n allMessages: OrchestrationMessage[],\n agentResults: Map<string, OrchestrationMessage[]>,\n votingStrategy: string,\n judge: { id: string; execute: (input: OrchestrationMessage) => Promise<OrchestrationMessage> } | undefined,\n debaters: Array<{ id: string }>,\n): Promise<string> {\n if (votingStrategy === \"judge\" && judge) {\n const judgeMsg: OrchestrationMessage = {\n from: \"debate\",\n to: judge.id,\n content: context,\n metadata: { phase: \"judge\" },\n };\n\n try {\n const verdict = await judge.execute(judgeMsg);\n allMessages.push(judgeMsg, verdict);\n agentResults.get(judge.id)!.push(verdict);\n return verdict.content;\n } catch {\n return context;\n }\n }\n\n // majority or unanimous: pick the most common last response\n const lastResponses: string[] = [];\n for (const debater of debaters) {\n const msgs = agentResults.get(debater.id) ?? [];\n if (msgs.length > 0) {\n lastResponses.push(msgs[msgs.length - 1].content);\n }\n }\n\n if (lastResponses.length === 0) return context;\n\n const counts = new Map<string, number>();\n for (const r of lastResponses) {\n counts.set(r, (counts.get(r) ?? 0) + 1);\n }\n\n if (votingStrategy === \"unanimous\") {\n if (counts.size === 1) return lastResponses[0];\n return context; // No unanimity\n }\n\n // majority\n let best = \"\";\n let bestCount = 0;\n for (const [content, count] of counts) {\n if (count > bestCount) {\n best = content;\n bestCount = count;\n }\n }\n return best;\n}\n","// =============================================================================\n// AgentOrchestratorAdapter — Main adapter implementing AgentOrchestratorPort\n// =============================================================================\n\nimport type {\n AgentOrchestratorPort,\n Orchestration,\n OrchestrationConfig,\n} from \"../../ports/agent-orchestrator.port.js\";\n\nimport { createSupervisorOrchestration } from \"./patterns/supervisor.js\";\nimport { createSwarmOrchestration } from \"./patterns/swarm.js\";\nimport { createPipelineOrchestration } from \"./patterns/pipeline.js\";\nimport { createMapReduceOrchestration } from \"./patterns/map-reduce.js\";\nimport { createDebateOrchestration } from \"./patterns/debate.js\";\n\nconst VALID_PATTERNS = new Set([\n \"supervisor\",\n \"swarm\",\n \"pipeline\",\n \"map-reduce\",\n \"debate\",\n]);\n\nlet counter = 0;\n\nexport class AgentOrchestratorAdapter implements AgentOrchestratorPort {\n createOrchestration(config: OrchestrationConfig): Orchestration {\n if (!config.agents || config.agents.length === 0) {\n throw new Error(\"At least one agent is required for orchestration\");\n }\n\n if (!VALID_PATTERNS.has(config.pattern)) {\n throw new Error(`Invalid orchestration pattern: ${config.pattern}`);\n }\n\n const id = `orch_${++counter}_${Date.now()}`;\n\n const timeout = config.options?.timeout;\n\n const orchestration = this.buildOrchestration(config, id);\n\n if (timeout && timeout > 0) {\n return this.wrapWithTimeout(orchestration, timeout);\n }\n\n return orchestration;\n }\n\n private buildOrchestration(\n config: OrchestrationConfig,\n id: string,\n ): Orchestration {\n switch (config.pattern) {\n case \"supervisor\":\n return createSupervisorOrchestration(config, id);\n case \"swarm\":\n return createSwarmOrchestration(config, id);\n case \"pipeline\":\n return createPipelineOrchestration(config, id);\n case \"map-reduce\":\n return createMapReduceOrchestration(config, id);\n case \"debate\":\n return createDebateOrchestration(config, id);\n default:\n throw new Error(`Unknown pattern: ${config.pattern}`);\n }\n }\n\n private wrapWithTimeout(\n orchestration: Orchestration,\n timeout: number,\n ): Orchestration {\n const originalExecute = orchestration.execute.bind(orchestration);\n\n orchestration.execute = async (input: string) => {\n const timer = setTimeout(() => orchestration.cancel(), timeout);\n try {\n return await originalExecute(input);\n } finally {\n clearTimeout(timer);\n }\n };\n\n return orchestration;\n }\n}\n","import type {\n OutputSchema,\n ParseResult,\n ValidationError,\n} from \"../../../ports/structured-output.port.js\";\n\n/**\n * Extract a JSON block from raw LLM output.\n * Handles markdown code fences and bare JSON.\n */\nfunction extractJson(raw: string): string {\n const fenceMatch = raw.match(/```(?:json)?\\s*\\n?([\\s\\S]*?)```/);\n if (fenceMatch) return fenceMatch[1].trim();\n\n const braceStart = raw.indexOf(\"{\");\n const bracketStart = raw.indexOf(\"[\");\n\n if (braceStart === -1 && bracketStart === -1) return raw.trim();\n\n const start =\n braceStart === -1\n ? bracketStart\n : bracketStart === -1\n ? braceStart\n : Math.min(braceStart, bracketStart);\n\n const isObject = raw[start] === \"{\";\n const close = isObject ? \"}\" : \"]\";\n\n let depth = 0;\n let inString = false;\n let escape = false;\n\n for (let i = start; i < raw.length; i++) {\n const ch = raw[i];\n\n if (escape) {\n escape = false;\n continue;\n }\n\n if (ch === \"\\\\\") {\n escape = true;\n continue;\n }\n\n if (ch === '\"') {\n inString = !inString;\n continue;\n }\n\n if (inString) continue;\n\n if (ch === raw[start]) depth++;\n else if (ch === close) {\n depth--;\n if (depth === 0) return raw.slice(start, i + 1);\n }\n }\n\n return raw.slice(start);\n}\n\nfunction validateAgainstDefinition(\n value: unknown,\n definition: Record<string, unknown>,\n path: string,\n): ValidationError[] {\n const errors: ValidationError[] = [];\n\n if (typeof value !== \"object\" || value === null || Array.isArray(value)) {\n errors.push({\n path: path || \"$\",\n message: \"Expected an object\",\n expected: \"object\",\n received: Array.isArray(value) ? \"array\" : typeof value,\n });\n return errors;\n }\n\n const obj = value as Record<string, unknown>;\n\n for (const [key, spec] of Object.entries(definition)) {\n const fieldPath = path ? `${path}.${key}` : key;\n const expectedType = typeof spec === \"string\" ? spec : (spec as Record<string, unknown>)?.type;\n\n if (!(key in obj)) {\n const isRequired =\n typeof spec === \"object\" && spec !== null\n ? (spec as Record<string, unknown>).required !== false\n : true;\n\n if (isRequired) {\n errors.push({\n path: fieldPath,\n message: `Missing required field \"${key}\"`,\n expected: String(expectedType ?? \"unknown\"),\n });\n }\n continue;\n }\n\n if (typeof expectedType === \"string\") {\n const actual = obj[key];\n const actualType = actual === null ? \"null\" : Array.isArray(actual) ? \"array\" : typeof actual;\n\n if (expectedType !== actualType) {\n errors.push({\n path: fieldPath,\n message: `Expected type \"${expectedType}\" but got \"${actualType}\"`,\n expected: expectedType,\n received: actualType,\n });\n }\n }\n }\n\n return errors;\n}\n\nexport function parseJson<T>(\n raw: string,\n schema: OutputSchema<T>,\n): ParseResult<T> {\n const extracted = extractJson(raw);\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(extracted);\n } catch {\n return {\n success: false,\n raw,\n errors: [\n {\n path: \"$\",\n message: \"Invalid JSON\",\n received: extracted.slice(0, 80),\n },\n ],\n };\n }\n\n const errors = validateAgainstDefinition(parsed, schema.definition, \"\");\n if (errors.length > 0) {\n return { success: false, raw, errors };\n }\n\n return { success: true, data: parsed as T, raw };\n}\n","import type {\n OutputSchema,\n ParseResult,\n ValidationError,\n} from \"../../../ports/structured-output.port.js\";\n\n/**\n * Minimal YAML parser supporting flat and one-level-nested key-value pairs.\n * Handles strings, numbers, booleans, null, and simple arrays.\n */\nfunction parseYamlValue(raw: string): unknown {\n const trimmed = raw.trim();\n\n if (trimmed === \"null\" || trimmed === \"~\" || trimmed === \"\") return null;\n if (trimmed === \"true\") return true;\n if (trimmed === \"false\") return false;\n\n const num = Number(trimmed);\n if (!Number.isNaN(num) && trimmed !== \"\") return num;\n\n // Strip surrounding quotes\n if (\n (trimmed.startsWith('\"') && trimmed.endsWith('\"')) ||\n (trimmed.startsWith(\"'\") && trimmed.endsWith(\"'\"))\n ) {\n return trimmed.slice(1, -1);\n }\n\n return trimmed;\n}\n\nfunction extractYamlBlock(raw: string): string {\n const fenceMatch = raw.match(/```(?:ya?ml)?\\s*\\n?([\\s\\S]*?)```/);\n if (fenceMatch) return fenceMatch[1].trim();\n return raw.trim();\n}\n\nexport function parseYaml<T>(\n raw: string,\n schema: OutputSchema<T>,\n): ParseResult<T> {\n const block = extractYamlBlock(raw);\n const lines = block.split(\"\\n\");\n const result: Record<string, unknown> = {};\n const errors: ValidationError[] = [];\n\n let currentKey: string | null = null;\n let currentArray: unknown[] | null = null;\n\n for (const line of lines) {\n if (line.trim() === \"\" || line.trim().startsWith(\"#\")) continue;\n\n // Array item under a key\n const arrayItemMatch = line.match(/^\\s+-\\s+(.*)/);\n if (arrayItemMatch && currentKey) {\n if (!currentArray) {\n currentArray = [];\n result[currentKey] = currentArray;\n }\n currentArray.push(parseYamlValue(arrayItemMatch[1]));\n continue;\n }\n\n // Key-value pair\n const kvMatch = line.match(/^(\\w[\\w\\s-]*):\\s*(.*)/);\n if (kvMatch) {\n // Flush previous array\n currentArray = null;\n\n const key = kvMatch[1].trim();\n const value = kvMatch[2];\n currentKey = key;\n\n if (value.trim() === \"\") {\n // Could be start of array or nested block — handled in next iterations\n result[key] = null;\n } else {\n result[key] = parseYamlValue(value);\n }\n continue;\n }\n }\n\n if (Object.keys(result).length === 0) {\n errors.push({ path: \"$\", message: \"Failed to parse YAML content\" });\n return { success: false, raw, errors };\n }\n\n // Validate required fields from definition\n for (const key of Object.keys(schema.definition)) {\n if (!(key in result)) {\n const spec = schema.definition[key];\n const isRequired =\n typeof spec === \"object\" && spec !== null\n ? (spec as Record<string, unknown>).required !== false\n : true;\n\n if (isRequired) {\n errors.push({\n path: key,\n message: `Missing required field \"${key}\"`,\n });\n }\n }\n }\n\n if (errors.length > 0) {\n return { success: false, raw, errors };\n }\n\n return { success: true, data: result as T, raw };\n}\n","import type {\n OutputSchema,\n ParseResult,\n ValidationError,\n} from \"../../../ports/structured-output.port.js\";\n\nfunction extractCsvBlock(raw: string): string {\n const fenceMatch = raw.match(/```(?:csv)?\\s*\\n?([\\s\\S]*?)```/);\n if (fenceMatch) return fenceMatch[1].trim();\n return raw.trim();\n}\n\nfunction parseCsvLine(line: string): string[] {\n const fields: string[] = [];\n let current = \"\";\n let inQuotes = false;\n\n for (let i = 0; i < line.length; i++) {\n const ch = line[i];\n\n if (inQuotes) {\n if (ch === '\"') {\n if (i + 1 < line.length && line[i + 1] === '\"') {\n current += '\"';\n i++;\n } else {\n inQuotes = false;\n }\n } else {\n current += ch;\n }\n } else if (ch === '\"') {\n inQuotes = true;\n } else if (ch === \",\") {\n fields.push(current.trim());\n current = \"\";\n } else {\n current += ch;\n }\n }\n\n fields.push(current.trim());\n return fields;\n}\n\nexport function parseCsv<T>(\n raw: string,\n schema: OutputSchema<T>,\n): ParseResult<T> {\n const block = extractCsvBlock(raw);\n const lines = block.split(\"\\n\").filter((l) => l.trim() !== \"\");\n const errors: ValidationError[] = [];\n\n if (lines.length < 2) {\n errors.push({\n path: \"$\",\n message: \"CSV must contain a header row and at least one data row\",\n });\n return { success: false, raw, errors };\n }\n\n const headers = parseCsvLine(lines[0]);\n const rows: Record<string, string>[] = [];\n\n for (let i = 1; i < lines.length; i++) {\n const values = parseCsvLine(lines[i]);\n const row: Record<string, string> = {};\n for (let j = 0; j < headers.length; j++) {\n row[headers[j]] = values[j] ?? \"\";\n }\n rows.push(row);\n }\n\n return { success: true, data: rows as T, raw };\n}\n","import type {\n OutputSchema,\n ParseResult,\n ValidationError,\n} from \"../../../ports/structured-output.port.js\";\n\nfunction parseTableRow(line: string): string[] {\n return line\n .split(\"|\")\n .map((cell) => cell.trim())\n .filter((cell) => cell !== \"\");\n}\n\nfunction isSeparatorRow(line: string): boolean {\n return /^\\|?[\\s:-]+\\|[\\s|:-]+$/.test(line.trim());\n}\n\nexport function parseMarkdownTable<T>(\n raw: string,\n schema: OutputSchema<T>,\n): ParseResult<T> {\n const lines = raw.split(\"\\n\").filter((l) => l.trim() !== \"\");\n const errors: ValidationError[] = [];\n\n // Find header row (first row with pipes)\n const headerIdx = lines.findIndex((l) => l.includes(\"|\"));\n if (headerIdx === -1) {\n errors.push({ path: \"$\", message: \"No markdown table found\" });\n return { success: false, raw, errors };\n }\n\n const headers = parseTableRow(lines[headerIdx]);\n\n // Skip separator row\n const dataStart =\n headerIdx + 1 < lines.length && isSeparatorRow(lines[headerIdx + 1])\n ? headerIdx + 2\n : headerIdx + 1;\n\n const rows: Record<string, string>[] = [];\n for (let i = dataStart; i < lines.length; i++) {\n if (isSeparatorRow(lines[i])) continue;\n if (!lines[i].includes(\"|\")) continue;\n\n const values = parseTableRow(lines[i]);\n const row: Record<string, string> = {};\n for (let j = 0; j < headers.length; j++) {\n row[headers[j]] = values[j] ?? \"\";\n }\n rows.push(row);\n }\n\n if (rows.length === 0) {\n errors.push({ path: \"$\", message: \"No data rows found in markdown table\" });\n return { success: false, raw, errors };\n }\n\n return { success: true, data: rows as T, raw };\n}\n","import type {\n OutputSchema,\n RepairAction,\n RepairResult,\n ValidationError,\n} from \"../../ports/structured-output.port.js\";\n\n/** Remove trailing commas before closing braces/brackets */\nfunction fixTrailingCommas(input: string): { output: string; fixed: boolean } {\n const result = input.replace(/,\\s*([}\\]])/g, \"$1\");\n return { output: result, fixed: result !== input };\n}\n\n/** Replace single quotes with double quotes (outside of double-quoted strings) */\nfunction fixSingleQuotes(input: string): { output: string; fixed: boolean } {\n let result = \"\";\n let inDouble = false;\n let escape = false;\n let fixed = false;\n\n for (let i = 0; i < input.length; i++) {\n const ch = input[i];\n\n if (escape) {\n result += ch;\n escape = false;\n continue;\n }\n\n if (ch === \"\\\\\") {\n escape = true;\n result += ch;\n continue;\n }\n\n if (ch === '\"') {\n inDouble = !inDouble;\n result += ch;\n continue;\n }\n\n if (ch === \"'\" && !inDouble) {\n result += '\"';\n fixed = true;\n continue;\n }\n\n result += ch;\n }\n\n return { output: result, fixed };\n}\n\n/** Add quotes to unquoted keys: { foo: \"bar\" } → { \"foo\": \"bar\" } */\nfunction fixUnquotedKeys(input: string): { output: string; fixed: boolean } {\n const result = input.replace(\n /([{,]\\s*)([a-zA-Z_$][\\w$]*)\\s*:/g,\n '$1\"$2\":',\n );\n return { output: result, fixed: result !== input };\n}\n\n/** Close missing braces/brackets */\nfunction fixMissingClose(input: string): { output: string; fixed: boolean } {\n let braces = 0;\n let brackets = 0;\n let inString = false;\n let escape = false;\n\n for (const ch of input) {\n if (escape) {\n escape = false;\n continue;\n }\n if (ch === \"\\\\\") {\n escape = true;\n continue;\n }\n if (ch === '\"') {\n inString = !inString;\n continue;\n }\n if (inString) continue;\n\n if (ch === \"{\") braces++;\n else if (ch === \"}\") braces--;\n else if (ch === \"[\") brackets++;\n else if (ch === \"]\") brackets--;\n }\n\n let result = input;\n const fixed = braces > 0 || brackets > 0;\n\n for (let i = 0; i < brackets; i++) result += \"]\";\n for (let i = 0; i < braces; i++) result += \"}\";\n\n return { output: result, fixed };\n}\n\n/** Fix truncated strings (unterminated quote) */\nfunction fixTruncatedStrings(input: string): {\n output: string;\n fixed: boolean;\n} {\n let inString = false;\n let escape = false;\n let lastQuoteIdx = -1;\n\n for (let i = 0; i < input.length; i++) {\n const ch = input[i];\n if (escape) {\n escape = false;\n continue;\n }\n if (ch === \"\\\\\") {\n escape = true;\n continue;\n }\n if (ch === '\"') {\n inString = !inString;\n lastQuoteIdx = i;\n }\n }\n\n if (inString && lastQuoteIdx >= 0) {\n return { output: input + '\"', fixed: true };\n }\n\n return { output: input, fixed: false };\n}\n\n/** Replace NaN/Infinity/undefined with null */\nfunction fixSpecialValues(input: string): { output: string; fixed: boolean } {\n const result = input\n .replace(/:\\s*NaN\\b/g, \": null\")\n .replace(/:\\s*Infinity\\b/g, \": null\")\n .replace(/:\\s*-Infinity\\b/g, \": null\")\n .replace(/:\\s*undefined\\b/g, \": null\");\n return { output: result, fixed: result !== input };\n}\n\nexport function repairJson<T>(\n raw: string,\n schema: OutputSchema<T>,\n _errors: ValidationError[],\n): RepairResult<T> {\n const repairs: RepairAction[] = [];\n let current = raw.trim();\n\n // Extract JSON from markdown fences if present\n const fenceMatch = current.match(/```(?:json)?\\s*\\n?([\\s\\S]*?)```/);\n if (fenceMatch) current = fenceMatch[1].trim();\n\n // Try to find JSON start if surrounded by text\n const braceStart = current.indexOf(\"{\");\n const bracketStart = current.indexOf(\"[\");\n if (braceStart > 0 && (bracketStart === -1 || braceStart < bracketStart)) {\n current = current.slice(braceStart);\n } else if (bracketStart > 0 && (braceStart === -1 || bracketStart < braceStart)) {\n current = current.slice(bracketStart);\n }\n\n // Apply repair pipeline\n const steps: Array<{\n fn: (s: string) => { output: string; fixed: boolean };\n type: RepairAction[\"type\"];\n description: string;\n }> = [\n {\n fn: fixSpecialValues,\n type: \"fix_encoding\",\n description: \"Replaced NaN/Infinity/undefined with null\",\n },\n {\n fn: fixSingleQuotes,\n type: \"fix_json\",\n description: \"Replaced single quotes with double quotes\",\n },\n {\n fn: fixUnquotedKeys,\n type: \"fix_json\",\n description: \"Added quotes to unquoted keys\",\n },\n {\n fn: fixTrailingCommas,\n type: \"fix_json\",\n description: \"Removed trailing commas\",\n },\n {\n fn: fixTruncatedStrings,\n type: \"fix_json\",\n description: \"Closed truncated string\",\n },\n {\n fn: fixMissingClose,\n type: \"fix_json\",\n description: \"Added missing closing braces/brackets\",\n },\n ];\n\n for (const step of steps) {\n const { output, fixed } = step.fn(current);\n if (fixed) {\n repairs.push({ type: step.type, description: step.description });\n current = output;\n }\n }\n\n try {\n const parsed = JSON.parse(current) as T;\n return { success: true, data: parsed, repaired: current, repairs };\n } catch {\n return { success: false, repaired: current, repairs };\n }\n}\n","import type {\n OutputSchema,\n ParseResult,\n StreamParser,\n} from \"../../ports/structured-output.port.js\";\n\n/**\n * Streaming JSON parser that incrementally builds an object\n * as chunks arrive from LLM output.\n */\nexport class JsonStreamParser<T> implements StreamParser<T> {\n private buffer = \"\";\n private completed = false;\n private readonly schema: OutputSchema<T>;\n\n constructor(schema: OutputSchema<T>) {\n this.schema = schema;\n }\n\n feed(chunk: string): void {\n this.buffer += chunk;\n this.completed = this.checkComplete();\n }\n\n current(): Partial<T> | null {\n const extracted = this.extractPartialJson();\n if (!extracted) return null;\n\n try {\n return JSON.parse(extracted) as Partial<T>;\n } catch {\n // Try to close the JSON to parse partial content\n const repaired = this.closePartialJson(extracted);\n try {\n return JSON.parse(repaired) as Partial<T>;\n } catch {\n return null;\n }\n }\n }\n\n isComplete(): boolean {\n return this.completed;\n }\n\n finalize(): ParseResult<T> {\n const extracted = this.extractPartialJson();\n if (!extracted) {\n return {\n success: false,\n raw: this.buffer,\n errors: [{ path: \"$\", message: \"No JSON content found in stream\" }],\n };\n }\n\n try {\n const data = JSON.parse(extracted) as T;\n return { success: true, data, raw: this.buffer };\n } catch {\n const repaired = this.closePartialJson(extracted);\n try {\n const data = JSON.parse(repaired) as T;\n return { success: true, data, raw: this.buffer };\n } catch {\n return {\n success: false,\n raw: this.buffer,\n errors: [{ path: \"$\", message: \"Failed to parse streamed JSON\" }],\n };\n }\n }\n }\n\n private extractPartialJson(): string | null {\n const start = this.buffer.indexOf(\"{\");\n if (start === -1) return null;\n\n if (this.completed) {\n // Find matching close\n let depth = 0;\n let inString = false;\n let escape = false;\n\n for (let i = start; i < this.buffer.length; i++) {\n const ch = this.buffer[i];\n if (escape) {\n escape = false;\n continue;\n }\n if (ch === \"\\\\\") {\n escape = true;\n continue;\n }\n if (ch === '\"') {\n inString = !inString;\n continue;\n }\n if (inString) continue;\n if (ch === \"{\") depth++;\n else if (ch === \"}\") {\n depth--;\n if (depth === 0) return this.buffer.slice(start, i + 1);\n }\n }\n }\n\n return this.buffer.slice(start);\n }\n\n private checkComplete(): boolean {\n const start = this.buffer.indexOf(\"{\");\n if (start === -1) return false;\n\n let depth = 0;\n let inString = false;\n let escape = false;\n\n for (let i = start; i < this.buffer.length; i++) {\n const ch = this.buffer[i];\n if (escape) {\n escape = false;\n continue;\n }\n if (ch === \"\\\\\") {\n escape = true;\n continue;\n }\n if (ch === '\"') {\n inString = !inString;\n continue;\n }\n if (inString) continue;\n if (ch === \"{\") depth++;\n else if (ch === \"}\") {\n depth--;\n if (depth === 0) return true;\n }\n }\n\n return false;\n }\n\n private closePartialJson(json: string): string {\n let braces = 0;\n let brackets = 0;\n let inString = false;\n let escape = false;\n\n for (const ch of json) {\n if (escape) {\n escape = false;\n continue;\n }\n if (ch === \"\\\\\") {\n escape = true;\n continue;\n }\n if (ch === '\"') {\n inString = !inString;\n continue;\n }\n if (inString) continue;\n\n if (ch === \"{\") braces++;\n else if (ch === \"}\") braces--;\n else if (ch === \"[\") brackets++;\n else if (ch === \"]\") brackets--;\n }\n\n let result = json;\n\n // Close unterminated string\n if (inString) result += '\"';\n\n // Remove trailing comma\n result = result.replace(/,\\s*$/, \"\");\n\n for (let i = 0; i < brackets; i++) result += \"]\";\n for (let i = 0; i < braces; i++) result += \"}\";\n\n return result;\n }\n}\n","import type {\n FormatOptions,\n OutputConstraint,\n OutputSchema,\n ParseResult,\n RepairResult,\n StreamParser,\n StructuredOutputPort,\n ValidationError,\n ValidationResult,\n} from \"../../ports/structured-output.port.js\";\nimport { parseJson } from \"./parsers/json-parser.js\";\nimport { parseYaml } from \"./parsers/yaml-parser.js\";\nimport { parseCsv } from \"./parsers/csv-parser.js\";\nimport { parseMarkdownTable } from \"./parsers/markdown-parser.js\";\nimport { repairJson } from \"./repair-engine.js\";\nimport { JsonStreamParser } from \"./stream-parser.js\";\n\nexport class StructuredOutputAdapter implements StructuredOutputPort {\n parse<T>(raw: string, schema: OutputSchema<T>): ParseResult<T> {\n switch (schema.type) {\n case \"json\":\n return parseJson(raw, schema);\n case \"yaml\":\n return parseYaml(raw, schema);\n case \"csv\":\n return parseCsv(raw, schema);\n case \"markdown-table\":\n return parseMarkdownTable(raw, schema);\n default:\n return {\n success: false,\n raw,\n errors: [\n {\n path: \"$\",\n message: `Unsupported schema type: ${schema.type}`,\n },\n ],\n };\n }\n }\n\n repair<T>(\n raw: string,\n schema: OutputSchema<T>,\n errors: ValidationError[],\n ): RepairResult<T> {\n if (schema.type === \"json\") {\n return repairJson(raw, schema, errors);\n }\n\n return { success: false, repaired: raw, repairs: [] };\n }\n\n formatInstruction<T>(\n schema: OutputSchema<T>,\n options?: FormatOptions,\n ): string {\n const style = options?.style ?? \"concise\";\n const wrap = options?.wrapInCodeBlock ?? false;\n\n const schemaStr = JSON.stringify(schema.definition, null, 2);\n let instruction: string;\n\n switch (style) {\n case \"concise\":\n instruction = `Respond with valid ${schema.type.toUpperCase()} matching this schema:\\n${schemaStr}`;\n break;\n\n case \"detailed\":\n instruction = [\n `You must respond with valid ${schema.type.toUpperCase()} only.`,\n `Do not include any text before or after the ${schema.type.toUpperCase()} output.`,\n \"\",\n \"Required schema:\",\n schemaStr,\n \"\",\n schema.description ? `Description: ${schema.description}` : \"\",\n \"\",\n \"Rules:\",\n \"- All required fields must be present\",\n \"- Use the exact field names shown\",\n \"- Values must match the specified types\",\n ]\n .filter(Boolean)\n .join(\"\\n\");\n break;\n\n case \"with-examples\": {\n const parts = [\n `Respond with valid ${schema.type.toUpperCase()} matching this schema:`,\n schemaStr,\n ];\n\n if (schema.examples && schema.examples.length > 0) {\n parts.push(\"\", \"Examples:\");\n for (const example of schema.examples) {\n parts.push(JSON.stringify(example, null, 2));\n }\n }\n\n instruction = parts.join(\"\\n\");\n break;\n }\n\n default:\n instruction = `Respond with valid ${schema.type.toUpperCase()} matching: ${schemaStr}`;\n }\n\n if (wrap) {\n return `\\`\\`\\`\\n${instruction}\\n\\`\\`\\``;\n }\n\n return instruction;\n }\n\n validate<T>(\n value: T,\n constraints: OutputConstraint<T>[],\n ): ValidationResult {\n const errors: ValidationError[] = [];\n\n for (const constraint of constraints) {\n const fieldValue = this.getFieldValue(value, constraint.field);\n if (!constraint.check(fieldValue)) {\n errors.push({\n path: constraint.field,\n message: constraint.message,\n });\n }\n }\n\n return { valid: errors.length === 0, errors };\n }\n\n parseStream<T>(schema: OutputSchema<T>): StreamParser<T> {\n return new JsonStreamParser<T>(schema);\n }\n\n private getFieldValue(obj: unknown, path: string): unknown {\n const parts = path.split(\".\");\n let current: unknown = obj;\n\n for (const part of parts) {\n if (current === null || current === undefined) return undefined;\n if (typeof current !== \"object\") return undefined;\n current = (current as Record<string, unknown>)[part];\n }\n\n return current;\n }\n}\n","// =============================================================================\n// Cosine Similarity — Pure implementation for semantic memory search\n// =============================================================================\n\n/**\n * Compute cosine similarity between two vectors.\n * Returns a value in [-1, 1] where 1 means identical direction.\n * Returns 0 if either vector is zero-length or vectors differ in dimension.\n */\nexport function cosineSimilarity(a: number[], b: number[]): number {\n if (a.length !== b.length || a.length === 0) return 0;\n\n let dot = 0;\n let normA = 0;\n let normB = 0;\n\n for (let i = 0; i < a.length; i++) {\n const ai = a[i]!;\n const bi = b[i]!;\n dot += ai * bi;\n normA += ai * ai;\n normB += bi * bi;\n }\n\n const denom = Math.sqrt(normA) * Math.sqrt(normB);\n if (denom === 0) return 0;\n\n return dot / denom;\n}\n","// =============================================================================\n// Memory Consolidator — Summarises old short-term memories into long-term\n// =============================================================================\n\nimport type {\n MemoryEntry,\n ConsolidationResult,\n} from \"../../ports/advanced-agent-memory.port.js\";\n\n/** Default age threshold: memories older than 1 hour are eligible */\nconst DEFAULT_AGE_MS = 60 * 60 * 1_000;\n\n/** Maximum number of short-term entries combined into a single summary */\nconst BATCH_SIZE = 10;\n\n/** Maximum length (chars) of a generated summary */\nconst SUMMARY_MAX_LENGTH = 500;\n\nexport interface ConsolidatorOptions {\n /** Milliseconds a short-term memory must be old before consolidation */\n ageThresholdMs?: number;\n /** Maximum entries per summary batch */\n batchSize?: number;\n}\n\n/**\n * Identify eligible short-term memories, group them into batches, and\n * produce long-term summary entries.\n *\n * Returns the consolidation result **plus** the list of new entries to store\n * and the ids of old entries to remove.\n */\nexport function consolidateMemories(\n entries: MemoryEntry[],\n agentId: string,\n options: ConsolidatorOptions = {},\n): {\n result: ConsolidationResult;\n toStore: MemoryEntry[];\n toRemove: string[];\n} {\n const ageThreshold = options.ageThresholdMs ?? DEFAULT_AGE_MS;\n const batchSize = options.batchSize ?? BATCH_SIZE;\n const now = Date.now();\n\n // Filter eligible short-term memories\n const eligible = entries.filter(\n (e) =>\n e.type === \"short_term\" &&\n e.agentId === agentId &&\n e.id !== undefined &&\n (e.timestamp ?? 0) < now - ageThreshold,\n );\n\n if (eligible.length === 0) {\n return {\n result: { memoriesProcessed: 0, memoriesCreated: 0, memoriesRemoved: 0, summaries: [] },\n toStore: [],\n toRemove: [],\n };\n }\n\n // Sort by timestamp ascending for chronological grouping\n eligible.sort((a, b) => (a.timestamp ?? 0) - (b.timestamp ?? 0));\n\n const toStore: MemoryEntry[] = [];\n const toRemove: string[] = [];\n const summaries: string[] = [];\n\n for (let i = 0; i < eligible.length; i += batchSize) {\n const batch = eligible.slice(i, i + batchSize);\n const combined = batch.map((e) => e.content).join(\"\\n\");\n const summary =\n combined.length > SUMMARY_MAX_LENGTH\n ? combined.slice(0, SUMMARY_MAX_LENGTH) + \"…\"\n : combined;\n\n summaries.push(summary);\n toStore.push({\n agentId,\n type: \"long_term\",\n content: summary,\n importance: averageImportance(batch),\n timestamp: now,\n metadata: { consolidatedFrom: batch.map((e) => e.id) },\n tags: [...new Set(batch.flatMap((e) => e.tags ?? []))],\n });\n\n for (const e of batch) {\n if (e.id) toRemove.push(e.id);\n }\n }\n\n return {\n result: {\n memoriesProcessed: eligible.length,\n memoriesCreated: toStore.length,\n memoriesRemoved: toRemove.length,\n summaries,\n },\n toStore,\n toRemove,\n };\n}\n\nfunction averageImportance(entries: MemoryEntry[]): number {\n if (entries.length === 0) return 0;\n const sum = entries.reduce((acc, e) => acc + (e.importance ?? 0.5), 0);\n return Math.round((sum / entries.length) * 100) / 100;\n}\n","// =============================================================================\n// InMemoryAgentMemoryAdapter — In-memory implementation of AdvancedAgentMemoryPort\n// =============================================================================\n\nimport type {\n AgentMemoryPort,\n MemoryEntry,\n MemoryQuery,\n MemoryType,\n MemoryStats,\n ConsolidationResult,\n ScopedMemory,\n} from \"../../ports/advanced-agent-memory.port.js\";\nimport { cosineSimilarity } from \"./similarity.js\";\nimport { consolidateMemories, type ConsolidatorOptions } from \"./memory-consolidator.js\";\n\nexport interface InMemoryAgentMemoryAdapterOptions {\n /** Max total entries kept in storage (LRU eviction) */\n maxEntries?: number;\n /** Options forwarded to the consolidator */\n consolidator?: ConsolidatorOptions;\n}\n\nexport class InMemoryAdvancedAgentMemoryAdapter implements AgentMemoryPort {\n private readonly entries = new Map<string, MemoryEntry>();\n private readonly maxEntries: number;\n private readonly consolidatorOpts: ConsolidatorOptions;\n private counter = 0;\n\n constructor(options: InMemoryAgentMemoryAdapterOptions = {}) {\n this.maxEntries = options.maxEntries ?? 50_000;\n this.consolidatorOpts = options.consolidator ?? {};\n }\n\n // ---------------------------------------------------------------------------\n // store\n // ---------------------------------------------------------------------------\n\n async store(entry: MemoryEntry): Promise<string> {\n const id = entry.id ?? this.generateId();\n const now = Date.now();\n const stored: MemoryEntry = {\n ...entry,\n id,\n timestamp: entry.timestamp ?? now,\n };\n\n this.entries.set(id, stored);\n this.evictIfNeeded();\n\n return id;\n }\n\n // ---------------------------------------------------------------------------\n // recall\n // ---------------------------------------------------------------------------\n\n async recall(query: MemoryQuery): Promise<MemoryEntry[]> {\n const now = Date.now();\n const limit = query.limit ?? 20;\n\n type Scored = { entry: MemoryEntry; score: number };\n const candidates: Scored[] = [];\n\n for (const entry of this.entries.values()) {\n // Agent filter\n if (entry.agentId !== query.agentId) continue;\n\n // TTL check\n if (entry.expiresAt !== undefined && entry.expiresAt <= now) continue;\n\n // Type filter\n if (query.type !== undefined && entry.type !== query.type) continue;\n\n // Importance filter\n if (query.minImportance !== undefined && (entry.importance ?? 0) < query.minImportance) continue;\n\n // Time filters\n if (query.since !== undefined && (entry.timestamp ?? 0) < query.since) continue;\n if (query.before !== undefined && (entry.timestamp ?? 0) >= query.before) continue;\n\n // Tag filter (all query tags must be present)\n if (query.tags && query.tags.length > 0) {\n const entryTags = new Set(entry.tags ?? []);\n if (!query.tags.every((t) => entryTags.has(t))) continue;\n }\n\n // Scoring\n let score = entry.importance ?? 0.5;\n\n // Semantic similarity (embedding)\n if (query.embedding && entry.embedding) {\n const sim = cosineSimilarity(query.embedding, entry.embedding);\n score = sim * 0.7 + (entry.importance ?? 0.5) * 0.3;\n }\n\n // Keyword matching (text)\n if (query.text) {\n const textScore = this.keywordScore(query.text, entry.content);\n if (textScore === 0 && !query.embedding) continue; // no match, skip\n score = query.embedding\n ? score * 0.6 + textScore * 0.4\n : textScore * 0.7 + (entry.importance ?? 0.5) * 0.3;\n }\n\n candidates.push({ entry, score });\n }\n\n // Sort by score descending, then by timestamp descending\n candidates.sort((a, b) => {\n const ds = b.score - a.score;\n if (Math.abs(ds) > 1e-9) return ds;\n return (b.entry.timestamp ?? 0) - (a.entry.timestamp ?? 0);\n });\n\n return candidates.slice(0, limit).map((c) => ({ ...c.entry }));\n }\n\n // ---------------------------------------------------------------------------\n // consolidate\n // ---------------------------------------------------------------------------\n\n async consolidate(agentId: string): Promise<ConsolidationResult> {\n const allEntries = Array.from(this.entries.values());\n\n const { result, toStore, toRemove } = consolidateMemories(\n allEntries,\n agentId,\n this.consolidatorOpts,\n );\n\n for (const id of toRemove) {\n this.entries.delete(id);\n }\n\n for (const entry of toStore) {\n const id = entry.id ?? this.generateId();\n this.entries.set(id, { ...entry, id });\n }\n\n return result;\n }\n\n // ---------------------------------------------------------------------------\n // stats\n // ---------------------------------------------------------------------------\n\n async stats(agentId: string): Promise<MemoryStats> {\n const byType: Record<MemoryType, number> = {\n short_term: 0,\n long_term: 0,\n episodic: 0,\n semantic: 0,\n working: 0,\n };\n let total = 0;\n let oldest = Infinity;\n let newest = -Infinity;\n let importanceSum = 0;\n let importanceCount = 0;\n\n for (const entry of this.entries.values()) {\n if (entry.agentId !== agentId) continue;\n total++;\n byType[entry.type] = (byType[entry.type] ?? 0) + 1;\n\n const ts = entry.timestamp ?? 0;\n if (ts < oldest) oldest = ts;\n if (ts > newest) newest = ts;\n\n importanceSum += entry.importance ?? 0;\n importanceCount++;\n }\n\n return {\n total,\n byType,\n oldestTimestamp: total > 0 ? oldest : 0,\n newestTimestamp: total > 0 ? newest : 0,\n averageImportance:\n importanceCount > 0\n ? Math.round((importanceSum / importanceCount) * 100) / 100\n : 0,\n };\n }\n\n // ---------------------------------------------------------------------------\n // clear\n // ---------------------------------------------------------------------------\n\n async clear(agentId: string, type?: MemoryType): Promise<number> {\n let removed = 0;\n for (const [id, entry] of this.entries) {\n if (entry.agentId !== agentId) continue;\n if (type !== undefined && entry.type !== type) continue;\n this.entries.delete(id);\n removed++;\n }\n return removed;\n }\n\n // ---------------------------------------------------------------------------\n // scope\n // ---------------------------------------------------------------------------\n\n scope(agentId: string, scopeName: string): ScopedMemory {\n const scopedAgentId = `${agentId}::${scopeName}`;\n // eslint-disable-next-line @typescript-eslint/no-this-alias\n const adapter = this;\n\n return {\n async store(entry: Omit<MemoryEntry, 'agentId'>): Promise<string> {\n return adapter.store({ ...entry, agentId: scopedAgentId });\n },\n async recall(query: Omit<MemoryQuery, 'agentId'>): Promise<MemoryEntry[]> {\n return adapter.recall({ ...query, agentId: scopedAgentId });\n },\n async clear(type?: MemoryType): Promise<number> {\n return adapter.clear(scopedAgentId, type);\n },\n };\n }\n\n // ---------------------------------------------------------------------------\n // Internal helpers\n // ---------------------------------------------------------------------------\n\n private generateId(): string {\n this.counter++;\n return `mem_${Date.now()}_${this.counter}`;\n }\n\n private evictIfNeeded(): void {\n if (this.entries.size <= this.maxEntries) return;\n\n // Evict oldest entries first\n const sorted = Array.from(this.entries.entries()).sort(\n ([, a], [, b]) => (a.timestamp ?? 0) - (b.timestamp ?? 0),\n );\n\n const toRemove = sorted.slice(0, this.entries.size - this.maxEntries);\n for (const [id] of toRemove) {\n this.entries.delete(id);\n }\n }\n\n private keywordScore(text: string, content: string): number {\n const queryWords = text.toLowerCase().split(/\\s+/).filter(Boolean);\n if (queryWords.length === 0) return 0;\n\n const lowerContent = content.toLowerCase();\n let matches = 0;\n\n for (const word of queryWords) {\n if (lowerContent.includes(word)) matches++;\n }\n\n return matches / queryWords.length;\n }\n}\n","import type {\n Guardrail,\n GuardrailContext,\n GuardrailResult,\n GuardrailsPort,\n GuardrailStage,\n} from \"../../ports/guardrails.port.js\";\n\nexport class GuardrailsAdapter implements GuardrailsPort {\n private guardrails: Map<string, Guardrail> = new Map();\n\n addGuardrail(guardrail: Guardrail): void {\n this.guardrails.set(guardrail.id, guardrail);\n }\n\n removeGuardrail(id: string): void {\n this.guardrails.delete(id);\n }\n\n listGuardrails(stage?: GuardrailStage): Guardrail[] {\n const all = [...this.guardrails.values()];\n if (!stage) return all;\n return all.filter((g) => g.stage === stage || g.stage === \"both\");\n }\n\n async check(\n content: string,\n stage: GuardrailStage,\n context?: GuardrailContext,\n ): Promise<GuardrailResult> {\n const applicable = this.listGuardrails(stage).sort(\n (a, b) => b.priority - a.priority,\n );\n\n const checks: GuardrailResult[\"checks\"] = [];\n let currentContent = content;\n\n for (const guardrail of applicable) {\n const result = await guardrail.check(currentContent, context);\n\n checks.push({\n guardrailId: guardrail.id,\n guardrailName: guardrail.name,\n result,\n });\n\n if (result.action === \"block\") {\n return {\n allowed: false,\n finalContent: currentContent,\n checks,\n blockedBy: guardrail.id,\n };\n }\n\n if (\n (result.action === \"redact\" || result.action === \"transform\") &&\n result.transformedContent !== undefined\n ) {\n currentContent = result.transformedContent;\n }\n }\n\n return {\n allowed: true,\n finalContent: currentContent,\n checks,\n };\n }\n}\n","import type {\n Guardrail,\n GuardrailAction,\n GuardrailCheckResult,\n GuardrailContext,\n GuardrailStage,\n} from \"../../../ports/guardrails.port.js\";\n\ninterface PiiPattern {\n name: string;\n regex: RegExp;\n tag: string;\n}\n\n// Order matters: more specific patterns (CC, SSN) must precede phone to avoid\n// partial overlaps where the phone regex could consume part of a CC number.\nconst PII_PATTERNS: PiiPattern[] = [\n {\n name: \"email\",\n regex: /[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}/g,\n tag: \"REDACTED_EMAIL\",\n },\n {\n name: \"credit_card\",\n regex: /\\b(?:\\d{4}[\\s-]?){3}\\d{4}\\b/g,\n tag: \"REDACTED_CC\",\n },\n {\n name: \"ssn\",\n regex: /\\b\\d{3}-\\d{2}-\\d{4}\\b/g,\n tag: \"REDACTED_SSN\",\n },\n {\n name: \"phone\",\n regex: /\\+?\\d{1,3}[\\s-]?\\(?\\d{1,4}\\)?[\\s-]?\\d{3,4}[\\s-]?\\d{3,4}/g,\n tag: \"REDACTED_PHONE\",\n },\n];\n\nexport interface PiiDetectorOptions {\n action?: GuardrailAction;\n stage?: GuardrailStage | \"both\";\n priority?: number;\n}\n\nexport class PiiDetector implements Guardrail {\n readonly id = \"builtin:pii-detector\";\n readonly name = \"PII Detector\";\n readonly stage: GuardrailStage | \"both\";\n readonly priority: number;\n\n private readonly action: GuardrailAction;\n\n constructor(options: PiiDetectorOptions = {}) {\n this.action = options.action ?? \"redact\";\n this.stage = options.stage ?? \"both\";\n this.priority = options.priority ?? 100;\n }\n\n async check(\n content: string,\n _context?: GuardrailContext,\n ): Promise<GuardrailCheckResult> {\n const detections: Array<{ type: string; match: string }> = [];\n let redacted = content;\n\n for (const pattern of PII_PATTERNS) {\n // Match against the current redacted string so earlier replacements\n // prevent less-specific patterns from overlapping.\n const matches = redacted.match(pattern.regex);\n if (matches) {\n for (const match of matches) {\n detections.push({ type: pattern.name, match });\n redacted = redacted.replaceAll(match, `[${pattern.tag}]`);\n }\n }\n }\n\n if (detections.length === 0) {\n return { action: \"pass\", confidence: 1 };\n }\n\n return {\n action: this.action,\n confidence: 0.95,\n reason: `Detected PII: ${detections.map((d) => d.type).join(\", \")}`,\n details: { detections },\n transformedContent: this.action === \"redact\" ? redacted : undefined,\n };\n }\n}\n","import type {\n Guardrail,\n GuardrailAction,\n GuardrailCheckResult,\n GuardrailContext,\n GuardrailStage,\n} from \"../../../ports/guardrails.port.js\";\n\ninterface InjectionPattern {\n name: string;\n regex: RegExp;\n confidence: number;\n}\n\nconst INJECTION_PATTERNS: InjectionPattern[] = [\n {\n name: \"ignore_previous\",\n regex: /ignore\\s+(all\\s+)?previous\\s+instructions/i,\n confidence: 0.95,\n },\n {\n name: \"role_override\",\n regex: /you\\s+are\\s+now/i,\n confidence: 0.9,\n },\n {\n name: \"system_prefix\",\n regex: /^system\\s*:/im,\n confidence: 0.85,\n },\n {\n name: \"pretend\",\n regex: /pretend\\s+to\\s+be/i,\n confidence: 0.8,\n },\n {\n name: \"base64_injection\",\n regex: /(?:eval|execute|run)\\s*\\(\\s*(?:atob|decode)\\s*\\(/i,\n confidence: 0.9,\n },\n {\n name: \"markdown_injection\",\n regex: /```(?:system|assistant)\\s*\\n/i,\n confidence: 0.85,\n },\n {\n name: \"jailbreak_dan\",\n regex: /\\bDAN\\b.*\\bdo\\s+anything\\s+now\\b/i,\n confidence: 0.95,\n },\n {\n name: \"override_rules\",\n regex: /(?:disregard|forget|override)\\s+(?:all\\s+)?(?:your\\s+)?(?:rules|instructions|guidelines)/i,\n confidence: 0.9,\n },\n];\n\nexport interface InjectionDetectorOptions {\n action?: GuardrailAction;\n stage?: GuardrailStage | \"both\";\n priority?: number;\n /** Minimum confidence threshold to trigger (0-1) */\n threshold?: number;\n}\n\nexport class InjectionDetector implements Guardrail {\n readonly id = \"builtin:injection-detector\";\n readonly name = \"Prompt Injection Detector\";\n readonly stage: GuardrailStage | \"both\";\n readonly priority: number;\n\n private readonly action: GuardrailAction;\n private readonly threshold: number;\n\n constructor(options: InjectionDetectorOptions = {}) {\n this.action = options.action ?? \"block\";\n this.stage = options.stage ?? \"input\";\n this.priority = options.priority ?? 200;\n this.threshold = options.threshold ?? 0.7;\n }\n\n async check(\n content: string,\n _context?: GuardrailContext,\n ): Promise<GuardrailCheckResult> {\n const detections: Array<{\n pattern: string;\n confidence: number;\n match: string;\n }> = [];\n\n for (const pattern of INJECTION_PATTERNS) {\n const match = content.match(pattern.regex);\n if (match && pattern.confidence >= this.threshold) {\n detections.push({\n pattern: pattern.name,\n confidence: pattern.confidence,\n match: match[0],\n });\n }\n }\n\n if (detections.length === 0) {\n return { action: \"pass\", confidence: 1 };\n }\n\n const maxConfidence = Math.max(...detections.map((d) => d.confidence));\n\n return {\n action: this.action,\n confidence: maxConfidence,\n reason: `Prompt injection detected: ${detections.map((d) => d.pattern).join(\", \")}`,\n details: { detections },\n };\n }\n}\n","import type {\n Guardrail,\n GuardrailAction,\n GuardrailCheckResult,\n GuardrailContext,\n GuardrailStage,\n} from \"../../../ports/guardrails.port.js\";\n\ninterface ModerationCategory {\n name: string;\n patterns: RegExp[];\n severity: \"low\" | \"medium\" | \"high\";\n}\n\nconst DEFAULT_CATEGORIES: ModerationCategory[] = [\n {\n name: \"profanity\",\n patterns: [\n /\\b(?:fuck|shit|damn|ass|bastard|bitch)\\b/gi,\n ],\n severity: \"medium\",\n },\n {\n name: \"hate_speech\",\n patterns: [\n /\\b(?:kill\\s+all|death\\s+to|exterminate)\\b/gi,\n ],\n severity: \"high\",\n },\n {\n name: \"threat\",\n patterns: [\n /\\b(?:i\\s+will\\s+(?:kill|hurt|destroy|attack)\\s+you)\\b/gi,\n ],\n severity: \"high\",\n },\n];\n\nconst SEVERITY_CONFIDENCE: Record<string, number> = {\n low: 0.6,\n medium: 0.8,\n high: 0.95,\n};\n\nexport interface ContentModeratorOptions {\n action?: GuardrailAction;\n stage?: GuardrailStage | \"both\";\n priority?: number;\n categories?: ModerationCategory[];\n}\n\nexport class ContentModerator implements Guardrail {\n readonly id = \"builtin:content-moderator\";\n readonly name = \"Content Moderator\";\n readonly stage: GuardrailStage | \"both\";\n readonly priority: number;\n\n private readonly action: GuardrailAction;\n private readonly categories: ModerationCategory[];\n\n constructor(options: ContentModeratorOptions = {}) {\n this.action = options.action ?? \"block\";\n this.stage = options.stage ?? \"both\";\n this.priority = options.priority ?? 150;\n this.categories = options.categories ?? DEFAULT_CATEGORIES;\n }\n\n async check(\n content: string,\n _context?: GuardrailContext,\n ): Promise<GuardrailCheckResult> {\n const detections: Array<{\n category: string;\n severity: string;\n match: string;\n }> = [];\n\n for (const category of this.categories) {\n for (const pattern of category.patterns) {\n const matches = content.match(pattern);\n if (matches) {\n for (const match of matches) {\n detections.push({\n category: category.name,\n severity: category.severity,\n match,\n });\n }\n }\n }\n }\n\n if (detections.length === 0) {\n return { action: \"pass\", confidence: 1 };\n }\n\n const maxSeverity = detections.reduce(\n (max, d) =>\n (SEVERITY_CONFIDENCE[d.severity] ?? 0) >\n (SEVERITY_CONFIDENCE[max.severity] ?? 0)\n ? d\n : max,\n detections[0]!,\n );\n\n return {\n action: this.action,\n confidence: SEVERITY_CONFIDENCE[maxSeverity.severity] ?? 0.5,\n reason: `Content moderation violation: ${[...new Set(detections.map((d) => d.category))].join(\", \")}`,\n details: { detections },\n };\n }\n}\n","import type {\n Guardrail,\n GuardrailAction,\n GuardrailCheckResult,\n GuardrailContext,\n GuardrailStage,\n} from \"../../../ports/guardrails.port.js\";\n\nexport interface TokenBudgetOptions {\n maxTokens: number;\n action?: GuardrailAction;\n stage?: GuardrailStage | \"both\";\n priority?: number;\n /** Average characters per token for estimation. Default: 4 */\n charsPerToken?: number;\n}\n\nexport class TokenBudget implements Guardrail {\n readonly id = \"builtin:token-budget\";\n readonly name = \"Token Budget\";\n readonly stage: GuardrailStage | \"both\";\n readonly priority: number;\n\n private readonly maxTokens: number;\n private readonly action: GuardrailAction;\n private readonly charsPerToken: number;\n\n constructor(options: TokenBudgetOptions) {\n this.maxTokens = options.maxTokens;\n this.action = options.action ?? \"block\";\n this.stage = options.stage ?? \"both\";\n this.priority = options.priority ?? 50;\n this.charsPerToken = options.charsPerToken ?? 4;\n }\n\n async check(\n content: string,\n _context?: GuardrailContext,\n ): Promise<GuardrailCheckResult> {\n const estimatedTokens = Math.ceil(content.length / this.charsPerToken);\n\n if (estimatedTokens <= this.maxTokens) {\n return {\n action: \"pass\",\n confidence: 1,\n details: { estimatedTokens, maxTokens: this.maxTokens },\n };\n }\n\n return {\n action: this.action,\n confidence: 1,\n reason: `Token budget exceeded: ~${estimatedTokens} tokens (max: ${this.maxTokens})`,\n details: { estimatedTokens, maxTokens: this.maxTokens },\n };\n }\n}\n","import type {\n Guardrail,\n GuardrailAction,\n GuardrailCheckResult,\n GuardrailContext,\n GuardrailStage,\n} from \"../../../ports/guardrails.port.js\";\n\n/** Lightweight JSON schema subset for zero-dependency validation */\nexport interface SimpleSchema {\n type: \"object\" | \"array\" | \"string\" | \"number\" | \"boolean\";\n properties?: Record<string, SimpleSchema>;\n items?: SimpleSchema;\n required?: string[];\n}\n\nexport interface SchemaValidatorOptions {\n schema: SimpleSchema;\n action?: GuardrailAction;\n stage?: GuardrailStage | \"both\";\n priority?: number;\n}\n\nexport class SchemaValidator implements Guardrail {\n readonly id = \"builtin:schema-validator\";\n readonly name = \"Schema Validator\";\n readonly stage: GuardrailStage | \"both\";\n readonly priority: number;\n\n private readonly schema: SimpleSchema;\n private readonly action: GuardrailAction;\n\n constructor(options: SchemaValidatorOptions) {\n this.schema = options.schema;\n this.action = options.action ?? \"block\";\n this.stage = options.stage ?? \"output\";\n this.priority = options.priority ?? 300;\n }\n\n async check(\n content: string,\n _context?: GuardrailContext,\n ): Promise<GuardrailCheckResult> {\n let parsed: unknown;\n try {\n parsed = JSON.parse(content);\n } catch {\n return {\n action: this.action,\n confidence: 1,\n reason: \"Output is not valid JSON\",\n details: { error: \"parse_error\" },\n };\n }\n\n const errors = this.validate(parsed, this.schema, \"root\");\n if (errors.length === 0) {\n return { action: \"pass\", confidence: 1 };\n }\n\n return {\n action: this.action,\n confidence: 1,\n reason: `Schema validation failed: ${errors.join(\"; \")}`,\n details: { errors },\n };\n }\n\n private validate(\n value: unknown,\n schema: SimpleSchema,\n path: string,\n ): string[] {\n const errors: string[] = [];\n\n switch (schema.type) {\n case \"object\": {\n if (typeof value !== \"object\" || value === null || Array.isArray(value)) {\n errors.push(`${path}: expected object`);\n break;\n }\n const obj = value as Record<string, unknown>;\n if (schema.required) {\n for (const key of schema.required) {\n if (!(key in obj)) {\n errors.push(`${path}.${key}: required field missing`);\n }\n }\n }\n if (schema.properties) {\n for (const [key, propSchema] of Object.entries(schema.properties)) {\n if (key in obj) {\n errors.push(\n ...this.validate(obj[key], propSchema, `${path}.${key}`),\n );\n }\n }\n }\n break;\n }\n case \"array\": {\n if (!Array.isArray(value)) {\n errors.push(`${path}: expected array`);\n break;\n }\n if (schema.items) {\n for (let i = 0; i < value.length; i++) {\n errors.push(\n ...this.validate(value[i], schema.items, `${path}[${i}]`),\n );\n }\n }\n break;\n }\n case \"string\":\n if (typeof value !== \"string\") errors.push(`${path}: expected string`);\n break;\n case \"number\":\n if (typeof value !== \"number\") errors.push(`${path}: expected number`);\n break;\n case \"boolean\":\n if (typeof value !== \"boolean\")\n errors.push(`${path}: expected boolean`);\n break;\n }\n\n return errors;\n }\n}\n","// =============================================================================\n// SpanImpl — Span implementation with child spans, events, and structured logs\n// =============================================================================\n\nimport type {\n Span,\n SpanKind,\n SpanEvent,\n LogEntry,\n LogLevel,\n SpanData,\n} from \"../../ports/observability-pipeline.port.js\";\n\nlet spanCounter = 0;\n\nexport function generateSpanId(): string {\n return `span-${++spanCounter}-${Date.now().toString(36)}`;\n}\n\nexport function resetSpanCounter(): void {\n spanCounter = 0;\n}\n\nexport class SpanImpl implements Span {\n readonly id: string;\n readonly traceId: string;\n readonly parentId?: string;\n readonly name: string;\n readonly kind: SpanKind;\n readonly startTime: number;\n\n private _endTime?: number;\n private _status?: { code: \"ok\" | \"error\"; message?: string };\n private readonly _attributes: Record<string, string | number | boolean> = {};\n private readonly _events: SpanEvent[] = [];\n private readonly _logs: LogEntry[] = [];\n private readonly _children: SpanImpl[] = [];\n\n constructor(\n traceId: string,\n name: string,\n kind: SpanKind,\n parentId?: string,\n ) {\n this.id = generateSpanId();\n this.traceId = traceId;\n this.name = name;\n this.kind = kind;\n this.parentId = parentId;\n this.startTime = Date.now();\n }\n\n get endTime(): number | undefined {\n return this._endTime;\n }\n\n get duration(): number | undefined {\n return this._endTime !== undefined\n ? this._endTime - this.startTime\n : undefined;\n }\n\n get attributes(): Record<string, string | number | boolean> {\n return { ...this._attributes };\n }\n\n get events(): SpanEvent[] {\n return [...this._events];\n }\n\n get logs(): LogEntry[] {\n return [...this._logs];\n }\n\n get children(): Span[] {\n return [...this._children];\n }\n\n setAttribute(key: string, value: string | number | boolean): void {\n this._attributes[key] = value;\n }\n\n setStatus(status: \"ok\" | \"error\", message?: string): void {\n this._status = { code: status, message };\n }\n\n addEvent(name: string, attributes?: Record<string, unknown>): void {\n this._events.push({ name, timestamp: Date.now(), attributes });\n }\n\n log(level: LogLevel, message: string, data?: Record<string, unknown>): void {\n this._logs.push({ level, message, timestamp: Date.now(), data });\n }\n\n startChild(name: string, kind: SpanKind): Span {\n const child = new SpanImpl(this.traceId, name, kind, this.id);\n this._children.push(child);\n return child;\n }\n\n end(): void {\n if (this._endTime !== undefined) return;\n // End open children first\n for (const child of this._children) {\n if (child.endTime === undefined) child.end();\n }\n this._endTime = Date.now();\n }\n\n /** Serialise to SpanData including all descendants. */\n toData(): SpanData {\n return {\n id: this.id,\n traceId: this.traceId,\n parentId: this.parentId,\n name: this.name,\n kind: this.kind,\n startTime: this.startTime,\n endTime: this._endTime,\n duration: this.duration,\n status: this._status,\n attributes: { ...this._attributes },\n events: [...this._events],\n logs: [...this._logs],\n children: this._children.map((c) => c.id),\n };\n }\n\n /** Collect this span and all descendants into a flat list. */\n collectAll(): SpanData[] {\n const result: SpanData[] = [this.toData()];\n for (const child of this._children) {\n result.push(...child.collectAll());\n }\n return result;\n }\n\n get status(): { code: \"ok\" | \"error\"; message?: string } | undefined {\n return this._status;\n }\n}\n","// =============================================================================\n// TraceImpl — Trace implementation aggregating spans\n// =============================================================================\n\nimport type {\n Trace,\n SpanKind,\n TraceData,\n Span,\n} from \"../../ports/observability-pipeline.port.js\";\nimport { SpanImpl } from \"./span.js\";\n\nlet traceCounter = 0;\n\nexport function generateTraceId(): string {\n return `trace-${++traceCounter}-${Date.now().toString(36)}`;\n}\n\nexport function resetTraceCounter(): void {\n traceCounter = 0;\n}\n\nexport class TraceImpl implements Trace {\n readonly id: string;\n readonly rootSpan: SpanImpl;\n private readonly metadata: Record<string, unknown>;\n\n constructor(name: string, metadata: Record<string, unknown> = {}) {\n this.id = generateTraceId();\n this.metadata = { ...metadata };\n this.rootSpan = new SpanImpl(this.id, name, \"agent\");\n }\n\n startSpan(name: string, kind: SpanKind): Span {\n return this.rootSpan.startChild(name, kind);\n }\n\n end(): void {\n this.rootSpan.end();\n }\n\n toJSON(): TraceData {\n const spans = this.rootSpan.collectAll();\n const endTime = this.rootSpan.endTime;\n return {\n id: this.id,\n spans,\n startTime: this.rootSpan.startTime,\n endTime,\n duration: endTime !== undefined ? endTime - this.rootSpan.startTime : undefined,\n metadata: { ...this.metadata },\n };\n }\n}\n","// =============================================================================\n// MetricsCollector — Collects and aggregates metrics from traces\n// =============================================================================\n\nimport type {\n MetricsSummary,\n SpanKind,\n TraceData,\n} from \"../../ports/observability-pipeline.port.js\";\n\nconst ALL_SPAN_KINDS: SpanKind[] = [\n \"agent\",\n \"tool\",\n \"llm\",\n \"retrieval\",\n \"custom\",\n];\n\nexport class MetricsCollector {\n computeMetrics(traces: TraceData[]): MetricsSummary {\n const spansByKind: Record<SpanKind, number> = {\n agent: 0,\n tool: 0,\n llm: 0,\n retrieval: 0,\n custom: 0,\n };\n\n let totalSpans = 0;\n let totalDuration = 0;\n let completedSpans = 0;\n let errorSpans = 0;\n let tokenCount = 0;\n let estimatedCost = 0;\n\n for (const trace of traces) {\n for (const span of trace.spans) {\n totalSpans++;\n if (ALL_SPAN_KINDS.includes(span.kind)) {\n spansByKind[span.kind]++;\n }\n\n if (span.duration !== undefined) {\n totalDuration += span.duration;\n completedSpans++;\n }\n\n if (span.status?.code === \"error\") {\n errorSpans++;\n }\n\n // Aggregate token counts from attributes\n const tokens = span.attributes[\"tokens\"];\n if (typeof tokens === \"number\") {\n tokenCount += tokens;\n }\n\n const cost = span.attributes[\"cost\"];\n if (typeof cost === \"number\") {\n estimatedCost += cost;\n }\n }\n }\n\n return {\n totalTraces: traces.length,\n totalSpans,\n averageDurationMs:\n completedSpans > 0 ? totalDuration / completedSpans : 0,\n spansByKind,\n errorRate: totalSpans > 0 ? errorSpans / totalSpans : 0,\n tokenCount,\n estimatedCost,\n };\n }\n}\n","// =============================================================================\n// ObservabilityPipelineAdapter — Main adapter implementing the port\n// =============================================================================\n\nimport type {\n ObservabilityPipelinePort,\n Trace,\n MetricsSummary,\n TraceExporter,\n TraceData,\n} from \"../../ports/observability-pipeline.port.js\";\nimport { TraceImpl } from \"./trace.js\";\nimport { MetricsCollector } from \"./metrics-collector.js\";\n\nexport class ObservabilityPipelineAdapter implements ObservabilityPipelinePort {\n private readonly traces: TraceImpl[] = [];\n private readonly exporters = new Map<string, TraceExporter>();\n private readonly metricsCollector = new MetricsCollector();\n private readonly pendingTraces: TraceData[] = [];\n private readonly maxTraces: number;\n\n constructor(options?: { maxTraces?: number }) {\n this.maxTraces = options?.maxTraces ?? 10_000;\n }\n\n createTrace(name: string, metadata?: Record<string, unknown>): Trace {\n const trace = new TraceImpl(name, metadata);\n this.traces.push(trace);\n // Evict oldest completed traces when over limit\n if (this.traces.length > this.maxTraces) {\n const idx = this.traces.findIndex((t) => t.rootSpan.endTime !== undefined);\n if (idx >= 0) this.traces.splice(idx, 1);\n }\n return trace;\n }\n\n getMetrics(): MetricsSummary {\n const allData = this.traces.map((t) => t.toJSON());\n return this.metricsCollector.computeMetrics(allData);\n }\n\n addExporter(exporter: TraceExporter): void {\n this.exporters.set(exporter.id, exporter);\n }\n\n removeExporter(id: string): void {\n this.exporters.delete(id);\n }\n\n async flush(): Promise<void> {\n const completedIdxs: number[] = [];\n const completed: TraceData[] = [];\n for (let i = 0; i < this.traces.length; i++) {\n if (this.traces[i].rootSpan.endTime !== undefined) {\n completedIdxs.push(i);\n completed.push(this.traces[i].toJSON());\n }\n }\n // Remove flushed traces (reverse order to preserve indices)\n for (let i = completedIdxs.length - 1; i >= 0; i--) {\n this.traces.splice(completedIdxs[i], 1);\n }\n\n const toExport = [...this.pendingTraces, ...completed];\n this.pendingTraces.length = 0;\n\n const exporters = Array.from(this.exporters.values());\n await Promise.all(exporters.map((e) => e.export(toExport)));\n }\n}\n","// =============================================================================\n// ConsoleExporter — Exports traces to console for development\n// =============================================================================\n\nimport type {\n TraceExporter,\n TraceData,\n} from \"../../../ports/observability-pipeline.port.js\";\n\nexport class ConsoleExporter implements TraceExporter {\n readonly id: string;\n readonly name = \"console\";\n\n constructor(id = \"console-exporter\") {\n this.id = id;\n }\n\n async export(traces: TraceData[]): Promise<void> {\n for (const trace of traces) {\n console.log(\n `[trace:${trace.id}] ${trace.spans.length} spans, duration=${trace.duration ?? \"pending\"}ms`,\n );\n for (const span of trace.spans) {\n const indent = span.parentId ? \" \" : \"\";\n const status = span.status\n ? ` [${span.status.code}${span.status.message ? `: ${span.status.message}` : \"\"}]`\n : \"\";\n console.log(\n `${indent}[span:${span.kind}] ${span.name} (${span.duration ?? \"?\"}ms)${status}`,\n );\n }\n }\n }\n}\n","// =============================================================================\n// JsonExporter — Exports traces as JSON\n// =============================================================================\n\nimport type {\n TraceExporter,\n TraceData,\n} from \"../../../ports/observability-pipeline.port.js\";\n\nexport type JsonExporterSink = (json: string) => void | Promise<void>;\n\nexport class JsonExporter implements TraceExporter {\n readonly id: string;\n readonly name = \"json\";\n private readonly sink: JsonExporterSink;\n\n constructor(sink: JsonExporterSink, id = \"json-exporter\") {\n this.id = id;\n this.sink = sink;\n }\n\n async export(traces: TraceData[]): Promise<void> {\n const json = JSON.stringify(traces, null, 2);\n await this.sink(json);\n }\n}\n","// =============================================================================\n// InMemoryRateLimiter — Multi-algorithm in-memory rate limiter\n// =============================================================================\n\nimport type {\n RateLimiterPort,\n RateLimiterConfig,\n RateLimitResult,\n RateLimitState,\n} from \"../../ports/rate-limiter.port.js\";\n\ninterface BucketState {\n tokens: number;\n lastRefill: number;\n windowStart: number;\n requestCount: number;\n timestamps: number[];\n}\n\nexport class InMemoryRateLimiter implements RateLimiterPort {\n private readonly buckets = new Map<string, BucketState>();\n\n constructor(private readonly config: RateLimiterConfig) {}\n\n async check(key: string): Promise<RateLimitResult> {\n const bucket = this.getOrCreate(key);\n this.refresh(bucket);\n return this.buildResult(bucket, false);\n }\n\n async consume(key: string, tokens = 1): Promise<RateLimitResult> {\n const bucket = this.getOrCreate(key);\n this.refresh(bucket);\n return this.buildResult(bucket, true, tokens);\n }\n\n async state(key: string): Promise<RateLimitState> {\n const bucket = this.getOrCreate(key);\n this.refresh(bucket);\n return {\n key,\n currentTokens: this.available(bucket),\n maxTokens: this.capacity(),\n windowStart: bucket.windowStart,\n requestCount: bucket.requestCount,\n };\n }\n\n async reset(key: string): Promise<void> {\n this.buckets.delete(key);\n }\n\n // ---------------------------------------------------------------------------\n // Internal helpers\n // ---------------------------------------------------------------------------\n\n private capacity(): number {\n if (this.config.algorithm === \"token_bucket\") {\n return this.config.burstSize ?? this.config.maxRequests;\n }\n return this.config.maxRequests;\n }\n\n private getOrCreate(key: string): BucketState {\n let bucket = this.buckets.get(key);\n if (!bucket) {\n const now = Date.now();\n bucket = {\n tokens:\n this.config.algorithm === \"leaky_bucket\" ? 0 : this.capacity(),\n lastRefill: now,\n windowStart: now,\n requestCount: 0,\n timestamps: [],\n };\n this.buckets.set(key, bucket);\n }\n return bucket;\n }\n\n private refresh(bucket: BucketState): void {\n const now = Date.now();\n\n switch (this.config.algorithm) {\n case \"token_bucket\": {\n const elapsed = now - bucket.lastRefill;\n const rate = this.config.refillRate ?? 1;\n const added = (elapsed / 1000) * rate;\n bucket.tokens = Math.min(this.capacity(), bucket.tokens + added);\n bucket.lastRefill = now;\n break;\n }\n case \"sliding_window\": {\n const cutoff = now - this.config.windowMs;\n bucket.timestamps = bucket.timestamps.filter((t) => t > cutoff);\n bucket.requestCount = bucket.timestamps.length;\n bucket.windowStart = cutoff;\n break;\n }\n case \"fixed_window\": {\n if (now - bucket.windowStart >= this.config.windowMs) {\n bucket.windowStart = now;\n bucket.requestCount = 0;\n bucket.tokens = this.config.maxRequests;\n }\n break;\n }\n case \"leaky_bucket\": {\n const elapsed = now - bucket.lastRefill;\n const leakRate = this.config.maxRequests / this.config.windowMs;\n const leaked = elapsed * leakRate;\n bucket.tokens = Math.max(0, bucket.tokens - leaked);\n bucket.lastRefill = now;\n break;\n }\n }\n }\n\n private available(bucket: BucketState): number {\n switch (this.config.algorithm) {\n case \"token_bucket\":\n return Math.floor(bucket.tokens);\n case \"sliding_window\":\n return Math.max(0, this.config.maxRequests - bucket.timestamps.length);\n case \"fixed_window\":\n return Math.max(0, this.config.maxRequests - bucket.requestCount);\n case \"leaky_bucket\": {\n const cap = this.config.burstSize ?? this.config.maxRequests;\n return Math.floor(cap - bucket.tokens);\n }\n }\n }\n\n private buildResult(\n bucket: BucketState,\n consume: boolean,\n tokens = 1,\n ): RateLimitResult {\n const now = Date.now();\n const avail = this.available(bucket);\n const allowed = avail >= tokens;\n\n if (allowed && consume) {\n this.applyConsume(bucket, tokens, now);\n }\n\n const remaining = allowed && consume ? avail - tokens : avail;\n\n return {\n allowed,\n remaining: Math.max(0, remaining),\n resetAt: this.computeResetAt(bucket, now),\n retryAfterMs: allowed ? undefined : this.computeRetryAfter(bucket, now),\n };\n }\n\n private applyConsume(bucket: BucketState, tokens: number, now: number): void {\n switch (this.config.algorithm) {\n case \"token_bucket\":\n bucket.tokens -= tokens;\n bucket.requestCount += tokens;\n break;\n case \"sliding_window\":\n for (let i = 0; i < tokens; i++) bucket.timestamps.push(now);\n bucket.requestCount = bucket.timestamps.length;\n break;\n case \"fixed_window\":\n bucket.requestCount += tokens;\n break;\n case \"leaky_bucket\":\n bucket.tokens += tokens;\n bucket.requestCount += tokens;\n break;\n }\n }\n\n private computeResetAt(bucket: BucketState, now: number): number {\n switch (this.config.algorithm) {\n case \"token_bucket\": {\n const rate = this.config.refillRate ?? 1;\n const needed = this.capacity() - bucket.tokens;\n return now + (needed / rate) * 1000;\n }\n case \"sliding_window\":\n return bucket.timestamps.length > 0\n ? bucket.timestamps[0] + this.config.windowMs\n : now + this.config.windowMs;\n case \"fixed_window\":\n return bucket.windowStart + this.config.windowMs;\n case \"leaky_bucket\": {\n const leakRate = this.config.maxRequests / this.config.windowMs;\n return bucket.tokens > 0\n ? now + bucket.tokens / leakRate\n : now + this.config.windowMs;\n }\n }\n }\n\n private computeRetryAfter(bucket: BucketState, now: number): number {\n switch (this.config.algorithm) {\n case \"token_bucket\": {\n const rate = this.config.refillRate ?? 1;\n const fractional = bucket.tokens - Math.floor(bucket.tokens);\n const needed = 1 - fractional;\n return Math.ceil((needed / rate) * 1000);\n }\n case \"sliding_window\":\n return bucket.timestamps.length > 0\n ? Math.max(0, bucket.timestamps[0] + this.config.windowMs - now)\n : 0;\n case \"fixed_window\":\n return Math.max(\n 0,\n bucket.windowStart + this.config.windowMs - now,\n );\n case \"leaky_bucket\": {\n const leakRate = this.config.maxRequests / this.config.windowMs;\n return Math.ceil(1 / leakRate);\n }\n }\n }\n}\n","// =============================================================================\n// InMemoryCostTracker — In-memory budget-aware cost tracker\n// =============================================================================\n\nimport type {\n BudgetCostTrackerPort,\n CostEvent,\n CostPeriod,\n CostSummary,\n Budget,\n BudgetResult,\n} from \"../../ports/budget-cost-tracker.port.js\";\n\nconst PERIOD_MS: Record<string, number> = {\n hourly: 3_600_000,\n daily: 86_400_000,\n weekly: 604_800_000,\n monthly: 2_592_000_000,\n};\n\nexport class InMemoryCostTracker implements BudgetCostTrackerPort {\n private readonly events = new Map<string, CostEvent[]>();\n private readonly budgets = new Map<string, Budget>();\n private readonly maxEventsPerKey: number;\n\n constructor(options?: { maxEventsPerKey?: number }) {\n this.maxEventsPerKey = options?.maxEventsPerKey ?? 100_000;\n }\n\n record(event: CostEvent): void {\n const e: CostEvent = { ...event, timestamp: event.timestamp ?? Date.now() };\n const list = this.events.get(e.key) ?? [];\n list.push(e);\n // Evict oldest events when over limit\n if (list.length > this.maxEventsPerKey) {\n list.splice(0, list.length - this.maxEventsPerKey);\n }\n this.events.set(e.key, list);\n }\n\n getCost(key: string, period?: CostPeriod): CostSummary {\n let events = this.events.get(key) ?? [];\n\n if (period) {\n events = events.filter((e) => {\n const ts = e.timestamp!;\n if (period.since !== undefined && ts < period.since) return false;\n if (period.until !== undefined && ts > period.until) return false;\n return true;\n });\n }\n\n const byModel: CostSummary[\"byModel\"] = {};\n let totalCost = 0;\n let totalInputTokens = 0;\n let totalOutputTokens = 0;\n\n for (const e of events) {\n totalCost += e.cost;\n totalInputTokens += e.inputTokens;\n totalOutputTokens += e.outputTokens;\n\n const m = byModel[e.model] ?? { cost: 0, inputTokens: 0, outputTokens: 0, requests: 0 };\n m.cost += e.cost;\n m.inputTokens += e.inputTokens;\n m.outputTokens += e.outputTokens;\n m.requests += 1;\n byModel[e.model] = m;\n }\n\n const totalRequests = events.length;\n\n return {\n totalCost,\n totalInputTokens,\n totalOutputTokens,\n totalRequests,\n byModel,\n averageCostPerRequest: totalRequests > 0 ? totalCost / totalRequests : 0,\n };\n }\n\n checkBudget(key: string, budget: Budget): BudgetResult {\n const period = this.budgetPeriod(budget);\n const summary = this.getCost(key, period);\n const exceededLimits: string[] = [];\n\n if (summary.totalCost > budget.maxCost) {\n exceededLimits.push(\"maxCost\");\n }\n if (budget.maxTokens !== undefined) {\n const totalTokens = summary.totalInputTokens + summary.totalOutputTokens;\n if (totalTokens > budget.maxTokens) {\n exceededLimits.push(\"maxTokens\");\n }\n }\n if (budget.maxRequests !== undefined && summary.totalRequests > budget.maxRequests) {\n exceededLimits.push(\"maxRequests\");\n }\n\n const percentUsed = budget.maxCost > 0 ? (summary.totalCost / budget.maxCost) * 100 : 0;\n\n return {\n withinBudget: exceededLimits.length === 0,\n currentCost: summary.totalCost,\n remainingCost: Math.max(0, budget.maxCost - summary.totalCost),\n percentUsed,\n exceededLimits,\n };\n }\n\n setBudget(key: string, budget: Budget): void {\n this.budgets.set(key, budget);\n }\n\n listBudgets(): Array<{ key: string; budget: Budget }> {\n return Array.from(this.budgets.entries()).map(([key, budget]) => ({ key, budget }));\n }\n\n reset(key: string): void {\n this.events.delete(key);\n }\n\n private budgetPeriod(budget: Budget): CostPeriod | undefined {\n if (!budget.period || budget.period === \"total\") return undefined;\n const ms = PERIOD_MS[budget.period];\n if (!ms) return undefined;\n return { since: Date.now() - ms };\n }\n}\n"]}
|