@vauban-org/agent-sdk 0.17.4 → 1.2.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/CONTRACT.md +6401 -813
- package/dist/adapters/llm/anthropic-direct.d.ts +1 -0
- package/dist/adapters/llm/anthropic-direct.d.ts.map +1 -1
- package/dist/adapters/llm/anthropic-direct.js +43 -0
- package/dist/adapters/llm/anthropic-direct.js.map +1 -1
- package/dist/adapters/llm/cascade.d.ts.map +1 -1
- package/dist/adapters/llm/cascade.js +57 -14
- package/dist/adapters/llm/cascade.js.map +1 -1
- package/dist/adapters/llm/litellm.d.ts +2 -0
- package/dist/adapters/llm/litellm.d.ts.map +1 -1
- package/dist/adapters/llm/litellm.js +44 -0
- package/dist/adapters/llm/litellm.js.map +1 -1
- package/dist/compute/difficulty-estimator.d.ts +53 -0
- package/dist/compute/difficulty-estimator.d.ts.map +1 -0
- package/dist/compute/difficulty-estimator.js +82 -0
- package/dist/compute/difficulty-estimator.js.map +1 -0
- package/dist/compute/strategies/mixture-of-agents.d.ts +40 -0
- package/dist/compute/strategies/mixture-of-agents.d.ts.map +1 -0
- package/dist/compute/strategies/mixture-of-agents.js +110 -0
- package/dist/compute/strategies/mixture-of-agents.js.map +1 -0
- package/dist/compute/strategies/tree-of-thoughts.d.ts +48 -0
- package/dist/compute/strategies/tree-of-thoughts.d.ts.map +1 -0
- package/dist/compute/strategies/tree-of-thoughts.js +242 -0
- package/dist/compute/strategies/tree-of-thoughts.js.map +1 -0
- package/dist/compute/strategies/two-phase-orient.d.ts +72 -0
- package/dist/compute/strategies/two-phase-orient.d.ts.map +1 -0
- package/dist/compute/strategies/two-phase-orient.js +85 -0
- package/dist/compute/strategies/two-phase-orient.js.map +1 -0
- package/dist/constitution/types.d.ts +10 -10
- package/dist/container/protocol.d.ts +134 -0
- package/dist/container/protocol.d.ts.map +1 -0
- package/dist/container/protocol.js +157 -0
- package/dist/container/protocol.js.map +1 -0
- package/dist/container/runtime.d.ts +140 -0
- package/dist/container/runtime.d.ts.map +1 -0
- package/dist/container/runtime.js +256 -0
- package/dist/container/runtime.js.map +1 -0
- package/dist/events/catalogue.d.ts +327 -30
- package/dist/events/catalogue.d.ts.map +1 -1
- package/dist/events/catalogue.js +18 -0
- package/dist/events/catalogue.js.map +1 -1
- package/dist/events/index.d.ts +9 -0
- package/dist/events/index.d.ts.map +1 -1
- package/dist/events/index.js +9 -0
- package/dist/events/index.js.map +1 -1
- package/dist/events/schemas/agent.completed.v1.d.ts +4 -4
- package/dist/events/schemas/agent.failed.v1.d.ts +2 -2
- package/dist/events/schemas/agent.hitl_resolved.v1.d.ts +2 -2
- package/dist/events/schemas/agent.started.v1.d.ts +2 -2
- package/dist/events/schemas/brain.skill.extracted.v1.d.ts +4 -4
- package/dist/events/schemas/cc.cost.anomaly_detected.v1.d.ts +2 -2
- package/dist/events/schemas/cc.cost.recorded.v1.d.ts +4 -4
- package/dist/events/schemas/citadel.sprint.analyzed.v1.d.ts +55 -0
- package/dist/events/schemas/citadel.sprint.analyzed.v1.d.ts.map +1 -0
- package/dist/events/schemas/citadel.sprint.analyzed.v1.js +22 -0
- package/dist/events/schemas/citadel.sprint.analyzed.v1.js.map +1 -0
- package/dist/events/schemas/citadel.sprint.closed.v1.d.ts +2 -2
- package/dist/events/schemas/forge.inbox.reply_classified.v1.d.ts +33 -0
- package/dist/events/schemas/forge.inbox.reply_classified.v1.d.ts.map +1 -0
- package/dist/events/schemas/forge.inbox.reply_classified.v1.js +15 -0
- package/dist/events/schemas/forge.inbox.reply_classified.v1.js.map +1 -0
- package/dist/events/schemas/forge.lead.qualified.v1.d.ts +2 -2
- package/dist/events/schemas/forge.outreach.sent.v1.d.ts +4 -4
- package/dist/events/schemas/incident.detected.v1.d.ts +2 -2
- package/dist/events/schemas/vauban-finance.forecast.generated.v1.d.ts +21 -0
- package/dist/events/schemas/vauban-finance.forecast.generated.v1.d.ts.map +1 -0
- package/dist/events/schemas/vauban-finance.forecast.generated.v1.js +11 -0
- package/dist/events/schemas/vauban-finance.forecast.generated.v1.js.map +1 -0
- package/dist/events/schemas/vauban-finance.trade.executed.v1.d.ts +24 -0
- package/dist/events/schemas/vauban-finance.trade.executed.v1.d.ts.map +1 -0
- package/dist/events/schemas/vauban-finance.trade.executed.v1.js +12 -0
- package/dist/events/schemas/vauban-finance.trade.executed.v1.js.map +1 -0
- package/dist/events/schemas/vauban.goal.checked.v1.d.ts +21 -0
- package/dist/events/schemas/vauban.goal.checked.v1.d.ts.map +1 -0
- package/dist/events/schemas/vauban.goal.checked.v1.js +11 -0
- package/dist/events/schemas/vauban.goal.checked.v1.js.map +1 -0
- package/dist/events/schemas/vauban.rebalancing.checked.v1.d.ts +21 -0
- package/dist/events/schemas/vauban.rebalancing.checked.v1.d.ts.map +1 -0
- package/dist/events/schemas/vauban.rebalancing.checked.v1.js +11 -0
- package/dist/events/schemas/vauban.rebalancing.checked.v1.js.map +1 -0
- package/dist/events/schemas/vauban.tax.checked.v1.d.ts +21 -0
- package/dist/events/schemas/vauban.tax.checked.v1.d.ts.map +1 -0
- package/dist/events/schemas/vauban.tax.checked.v1.js +11 -0
- package/dist/events/schemas/vauban.tax.checked.v1.js.map +1 -0
- package/dist/events/schemas/vauban.vault.analyzed.v1.d.ts +59 -0
- package/dist/events/schemas/vauban.vault.analyzed.v1.d.ts.map +1 -0
- package/dist/events/schemas/vauban.vault.analyzed.v1.js +19 -0
- package/dist/events/schemas/vauban.vault.analyzed.v1.js.map +1 -0
- package/dist/events/schemas/vauban.vault.compounded.v1.d.ts +24 -0
- package/dist/events/schemas/vauban.vault.compounded.v1.d.ts.map +1 -0
- package/dist/events/schemas/vauban.vault.compounded.v1.js +12 -0
- package/dist/events/schemas/vauban.vault.compounded.v1.js.map +1 -0
- package/dist/identity/agent-persona.d.ts +73 -0
- package/dist/identity/agent-persona.d.ts.map +1 -0
- package/dist/identity/agent-persona.js +165 -0
- package/dist/identity/agent-persona.js.map +1 -0
- package/dist/identity/persona-prompt.d.ts +25 -0
- package/dist/identity/persona-prompt.d.ts.map +1 -0
- package/dist/identity/persona-prompt.js +71 -0
- package/dist/identity/persona-prompt.js.map +1 -0
- package/dist/identity/persona-schema.d.ts +120 -0
- package/dist/identity/persona-schema.d.ts.map +1 -0
- package/dist/identity/persona-schema.js +103 -0
- package/dist/identity/persona-schema.js.map +1 -0
- package/dist/index.d.ts +37 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +29 -1
- package/dist/index.js.map +1 -1
- package/dist/loop/index.d.ts +1 -1
- package/dist/loop/index.d.ts.map +1 -1
- package/dist/loop/index.js.map +1 -1
- package/dist/loop/minimal-loop.js +293 -287
- package/dist/loop/sdk-loop.d.ts +1 -3
- package/dist/loop/sdk-loop.d.ts.map +1 -1
- package/dist/loop/sdk-loop.js +1 -1
- package/dist/loop/sdk-loop.js.map +1 -1
- package/dist/memory/episodic-rrf.d.ts +114 -0
- package/dist/memory/episodic-rrf.d.ts.map +1 -0
- package/dist/memory/episodic-rrf.js +148 -0
- package/dist/memory/episodic-rrf.js.map +1 -0
- package/dist/mesh/attenuation.d.ts +78 -0
- package/dist/mesh/attenuation.d.ts.map +1 -0
- package/dist/mesh/attenuation.js +141 -0
- package/dist/mesh/attenuation.js.map +1 -0
- package/dist/mesh/delegate.d.ts +96 -0
- package/dist/mesh/delegate.d.ts.map +1 -0
- package/dist/mesh/delegate.js +172 -0
- package/dist/mesh/delegate.js.map +1 -0
- package/dist/mesh/dispatcher.d.ts +119 -0
- package/dist/mesh/dispatcher.d.ts.map +1 -0
- package/dist/mesh/dispatcher.js +207 -0
- package/dist/mesh/dispatcher.js.map +1 -0
- package/dist/mesh/index.d.ts +12 -0
- package/dist/mesh/index.d.ts.map +1 -0
- package/dist/mesh/index.js +11 -0
- package/dist/mesh/index.js.map +1 -0
- package/dist/mesh/types.d.ts +30 -0
- package/dist/mesh/types.d.ts.map +1 -0
- package/dist/mesh/types.js +11 -0
- package/dist/mesh/types.js.map +1 -0
- package/dist/orchestration/ooda/skills.d.ts +104 -0
- package/dist/orchestration/ooda/skills.d.ts.map +1 -1
- package/dist/orchestration/ooda/skills.js +106 -0
- package/dist/orchestration/ooda/skills.js.map +1 -1
- package/dist/orchestration/ooda/types.d.ts +3 -8
- package/dist/orchestration/ooda/types.d.ts.map +1 -1
- package/dist/ports/bastion-action.contract.test.d.ts +11 -0
- package/dist/ports/bastion-action.contract.test.d.ts.map +1 -0
- package/dist/ports/bastion-action.contract.test.js +238 -0
- package/dist/ports/bastion-action.contract.test.js.map +1 -0
- package/dist/ports/bastion-action.d.ts +133 -0
- package/dist/ports/bastion-action.d.ts.map +1 -0
- package/dist/ports/bastion-action.js +73 -0
- package/dist/ports/bastion-action.js.map +1 -0
- package/dist/ports/brain.d.ts +31 -0
- package/dist/ports/brain.d.ts.map +1 -1
- package/dist/ports/brain.js +115 -1
- package/dist/ports/brain.js.map +1 -1
- package/dist/ports/citadel-action.contract.test.d.ts +11 -0
- package/dist/ports/citadel-action.contract.test.d.ts.map +1 -0
- package/dist/ports/citadel-action.contract.test.js +317 -0
- package/dist/ports/citadel-action.contract.test.js.map +1 -0
- package/dist/ports/citadel-action.d.ts +111 -0
- package/dist/ports/citadel-action.d.ts.map +1 -0
- package/dist/ports/citadel-action.js +62 -0
- package/dist/ports/citadel-action.js.map +1 -0
- package/dist/ports/compliance-contract.d.ts +123 -0
- package/dist/ports/compliance-contract.d.ts.map +1 -0
- package/dist/ports/compliance-contract.js +35 -0
- package/dist/ports/compliance-contract.js.map +1 -0
- package/dist/ports/db.d.ts +38 -0
- package/dist/ports/db.d.ts.map +1 -1
- package/dist/ports/db.js +88 -1
- package/dist/ports/db.js.map +1 -1
- package/dist/ports/delegation.contract.test.d.ts +9 -0
- package/dist/ports/delegation.contract.test.d.ts.map +1 -0
- package/dist/ports/delegation.contract.test.js +337 -0
- package/dist/ports/delegation.contract.test.js.map +1 -0
- package/dist/ports/delegation.d.ts +134 -0
- package/dist/ports/delegation.d.ts.map +1 -0
- package/dist/ports/delegation.js +105 -0
- package/dist/ports/delegation.js.map +1 -0
- package/dist/ports/event-bus.d.ts +29 -13
- package/dist/ports/event-bus.d.ts.map +1 -1
- package/dist/ports/event-bus.js +106 -1
- package/dist/ports/event-bus.js.map +1 -1
- package/dist/ports/federation.contract.test.d.ts +9 -0
- package/dist/ports/federation.contract.test.d.ts.map +1 -0
- package/dist/ports/federation.contract.test.js +279 -0
- package/dist/ports/federation.contract.test.js.map +1 -0
- package/dist/ports/federation.d.ts +140 -0
- package/dist/ports/federation.d.ts.map +1 -0
- package/dist/ports/federation.js +57 -0
- package/dist/ports/federation.js.map +1 -0
- package/dist/ports/index.d.ts +28 -2
- package/dist/ports/index.d.ts.map +1 -1
- package/dist/ports/index.js +17 -2
- package/dist/ports/index.js.map +1 -1
- package/dist/ports/llm-provider.d.ts +37 -0
- package/dist/ports/llm-provider.d.ts.map +1 -1
- package/dist/ports/llm-provider.js +99 -1
- package/dist/ports/llm-provider.js.map +1 -1
- package/dist/ports/logger.d.ts +27 -0
- package/dist/ports/logger.d.ts.map +1 -1
- package/dist/ports/logger.js +87 -0
- package/dist/ports/logger.js.map +1 -1
- package/dist/ports/manifest-registry.contract.test.d.ts +9 -0
- package/dist/ports/manifest-registry.contract.test.d.ts.map +1 -0
- package/dist/ports/manifest-registry.contract.test.js +246 -0
- package/dist/ports/manifest-registry.contract.test.js.map +1 -0
- package/dist/ports/manifest-registry.d.ts +116 -0
- package/dist/ports/manifest-registry.d.ts.map +1 -0
- package/dist/ports/manifest-registry.js +79 -0
- package/dist/ports/manifest-registry.js.map +1 -0
- package/dist/ports/observability.contract.test.d.ts +12 -0
- package/dist/ports/observability.contract.test.d.ts.map +1 -0
- package/dist/ports/observability.contract.test.js +260 -0
- package/dist/ports/observability.contract.test.js.map +1 -0
- package/dist/ports/observability.d.ts +98 -0
- package/dist/ports/observability.d.ts.map +1 -0
- package/dist/ports/observability.js +59 -0
- package/dist/ports/observability.js.map +1 -0
- package/dist/ports/outcome.d.ts +26 -0
- package/dist/ports/outcome.d.ts.map +1 -1
- package/dist/ports/outcome.js +62 -1
- package/dist/ports/outcome.js.map +1 -1
- package/dist/ports/privacy.contract.test.d.ts +12 -0
- package/dist/ports/privacy.contract.test.d.ts.map +1 -0
- package/dist/ports/privacy.contract.test.js +325 -0
- package/dist/ports/privacy.contract.test.js.map +1 -0
- package/dist/ports/privacy.d.ts +132 -0
- package/dist/ports/privacy.d.ts.map +1 -0
- package/dist/ports/privacy.js +83 -0
- package/dist/ports/privacy.js.map +1 -0
- package/dist/ports/tenant-context.contract.test.d.ts +14 -0
- package/dist/ports/tenant-context.contract.test.d.ts.map +1 -0
- package/dist/ports/tenant-context.contract.test.js +352 -0
- package/dist/ports/tenant-context.contract.test.js.map +1 -0
- package/dist/ports/tenant-context.d.ts +103 -0
- package/dist/ports/tenant-context.d.ts.map +1 -0
- package/dist/ports/tenant-context.js +48 -0
- package/dist/ports/tenant-context.js.map +1 -0
- package/dist/ports/vauban-finance-action.contract.test.d.ts +11 -0
- package/dist/ports/vauban-finance-action.contract.test.d.ts.map +1 -0
- package/dist/ports/vauban-finance-action.contract.test.js +260 -0
- package/dist/ports/vauban-finance-action.contract.test.js.map +1 -0
- package/dist/ports/vauban-finance-action.d.ts +106 -0
- package/dist/ports/vauban-finance-action.d.ts.map +1 -0
- package/dist/ports/vauban-finance-action.js +60 -0
- package/dist/ports/vauban-finance-action.js.map +1 -0
- package/dist/ports/workflow-runtime.d.ts +204 -0
- package/dist/ports/workflow-runtime.d.ts.map +1 -0
- package/dist/ports/workflow-runtime.js +72 -0
- package/dist/ports/workflow-runtime.js.map +1 -0
- package/dist/proof/cert-verify.d.ts +80 -0
- package/dist/proof/cert-verify.d.ts.map +1 -0
- package/dist/proof/cert-verify.js +178 -0
- package/dist/proof/cert-verify.js.map +1 -0
- package/dist/replay/replay.d.ts.map +1 -1
- package/dist/replay/replay.js +5 -1
- package/dist/replay/replay.js.map +1 -1
- package/dist/retry/index.d.ts +129 -0
- package/dist/retry/index.d.ts.map +1 -0
- package/dist/retry/index.js +156 -0
- package/dist/retry/index.js.map +1 -0
- package/dist/retry/presets.d.ts +39 -0
- package/dist/retry/presets.d.ts.map +1 -0
- package/dist/retry/presets.js +69 -0
- package/dist/retry/presets.js.map +1 -0
- package/dist/skill-loop/ab-runner.d.ts +67 -0
- package/dist/skill-loop/ab-runner.d.ts.map +1 -0
- package/dist/skill-loop/ab-runner.js +160 -0
- package/dist/skill-loop/ab-runner.js.map +1 -0
- package/dist/skill-loop/adoption.d.ts +67 -0
- package/dist/skill-loop/adoption.d.ts.map +1 -0
- package/dist/skill-loop/adoption.js +126 -0
- package/dist/skill-loop/adoption.js.map +1 -0
- package/dist/skill-loop/candidate.d.ts +45 -0
- package/dist/skill-loop/candidate.d.ts.map +1 -0
- package/dist/skill-loop/candidate.js +43 -0
- package/dist/skill-loop/candidate.js.map +1 -0
- package/dist/skill-loop/evaluator.d.ts +42 -0
- package/dist/skill-loop/evaluator.d.ts.map +1 -0
- package/dist/skill-loop/evaluator.js +184 -0
- package/dist/skill-loop/evaluator.js.map +1 -0
- package/dist/skill-loop/index.d.ts +27 -0
- package/dist/skill-loop/index.d.ts.map +1 -0
- package/dist/skill-loop/index.js +27 -0
- package/dist/skill-loop/index.js.map +1 -0
- package/dist/skill-loop/reflexion-replay.d.ts +87 -0
- package/dist/skill-loop/reflexion-replay.d.ts.map +1 -0
- package/dist/skill-loop/reflexion-replay.js +110 -0
- package/dist/skill-loop/reflexion-replay.js.map +1 -0
- package/dist/skill-loop/sign-off.d.ts +88 -0
- package/dist/skill-loop/sign-off.d.ts.map +1 -0
- package/dist/skill-loop/sign-off.js +146 -0
- package/dist/skill-loop/sign-off.js.map +1 -0
- package/dist/skill-loop/value-metric.d.ts +55 -0
- package/dist/skill-loop/value-metric.d.ts.map +1 -0
- package/dist/skill-loop/value-metric.js +69 -0
- package/dist/skill-loop/value-metric.js.map +1 -0
- package/dist/skill-loop/versioning.d.ts +36 -0
- package/dist/skill-loop/versioning.d.ts.map +1 -0
- package/dist/skill-loop/versioning.js +47 -0
- package/dist/skill-loop/versioning.js.map +1 -0
- package/dist/skill-manifest/anchor.d.ts +91 -0
- package/dist/skill-manifest/anchor.d.ts.map +1 -0
- package/dist/skill-manifest/anchor.js +331 -0
- package/dist/skill-manifest/anchor.js.map +1 -0
- package/dist/skill-manifest/builder.d.ts +47 -0
- package/dist/skill-manifest/builder.d.ts.map +1 -0
- package/dist/skill-manifest/builder.js +93 -0
- package/dist/skill-manifest/builder.js.map +1 -0
- package/dist/skill-manifest/index.d.ts +13 -0
- package/dist/skill-manifest/index.d.ts.map +1 -0
- package/dist/skill-manifest/index.js +9 -0
- package/dist/skill-manifest/index.js.map +1 -0
- package/dist/skill-manifest/types.d.ts +67 -0
- package/dist/skill-manifest/types.d.ts.map +1 -0
- package/dist/skill-manifest/types.js +16 -0
- package/dist/skill-manifest/types.js.map +1 -0
- package/dist/skill-manifest/verifier.d.ts +42 -0
- package/dist/skill-manifest/verifier.d.ts.map +1 -0
- package/dist/skill-manifest/verifier.js +136 -0
- package/dist/skill-manifest/verifier.js.map +1 -0
- package/dist/skills/brain-query.d.ts +4 -4
- package/dist/skills/brain-store.d.ts +6 -6
- package/dist/skills/errors.d.ts +15 -0
- package/dist/skills/errors.d.ts.map +1 -1
- package/dist/skills/errors.js +21 -0
- package/dist/skills/errors.js.map +1 -1
- package/dist/skills/hitl-request.d.ts +2 -2
- package/dist/skills/index.d.ts +3 -1
- package/dist/skills/index.d.ts.map +1 -1
- package/dist/skills/index.js +4 -1
- package/dist/skills/index.js.map +1 -1
- package/dist/skills/markdown/loader.d.ts +52 -0
- package/dist/skills/markdown/loader.d.ts.map +1 -0
- package/dist/skills/markdown/loader.js +93 -0
- package/dist/skills/markdown/loader.js.map +1 -0
- package/dist/skills/markdown/schema.d.ts +432 -0
- package/dist/skills/markdown/schema.d.ts.map +1 -0
- package/dist/skills/markdown/schema.js +121 -0
- package/dist/skills/markdown/schema.js.map +1 -0
- package/dist/skills/poc-md-loader/markdown-loader.d.ts +77 -0
- package/dist/skills/poc-md-loader/markdown-loader.d.ts.map +1 -0
- package/dist/skills/poc-md-loader/markdown-loader.js +125 -0
- package/dist/skills/poc-md-loader/markdown-loader.js.map +1 -0
- package/dist/skills/poc-md-loader/runner.d.ts +24 -0
- package/dist/skills/poc-md-loader/runner.d.ts.map +1 -0
- package/dist/skills/poc-md-loader/runner.js +57 -0
- package/dist/skills/poc-md-loader/runner.js.map +1 -0
- package/dist/skills/poc-md-loader/vitest.poc.config.d.ts +3 -0
- package/dist/skills/poc-md-loader/vitest.poc.config.d.ts.map +1 -0
- package/dist/skills/poc-md-loader/vitest.poc.config.js +13 -0
- package/dist/skills/poc-md-loader/vitest.poc.config.js.map +1 -0
- package/dist/skills/poc-md-loader/web-search/script.d.ts +33 -0
- package/dist/skills/poc-md-loader/web-search/script.d.ts.map +1 -0
- package/dist/skills/poc-md-loader/web-search/script.js +75 -0
- package/dist/skills/poc-md-loader/web-search/script.js.map +1 -0
- package/dist/skills/record-outcome.d.ts +4 -4
- package/dist/skills/send-email.d.ts.map +1 -1
- package/dist/skills/send-email.js +15 -3
- package/dist/skills/send-email.js.map +1 -1
- package/dist/skills/slack-notify.d.ts +4 -4
- package/dist/skills/starknet-balance.d.ts +1 -1
- package/dist/skills/telegram-notify.d.ts +4 -4
- package/dist/skills/web-search.d.ts +1 -1
- package/dist/testing/contracts/event-bus.contract.d.ts.map +1 -1
- package/dist/testing/contracts/event-bus.contract.js +14 -12
- package/dist/testing/contracts/event-bus.contract.js.map +1 -1
- package/dist/testing/index.d.ts +3 -0
- package/dist/testing/test-brain-port.d.ts +4 -0
- package/dist/testing/test-brain-port.d.ts.map +1 -1
- package/dist/testing/test-brain-port.js +75 -20
- package/dist/testing/test-brain-port.js.map +1 -1
- package/dist/testing/test-event-bus.d.ts.map +1 -1
- package/dist/testing/test-event-bus.js +89 -36
- package/dist/testing/test-event-bus.js.map +1 -1
- package/dist/trace/schema.d.ts +1 -1
- package/dist/trace/schema.d.ts.map +1 -1
- package/dist/trace/schema.js +1 -1
- package/dist/trace/schema.js.map +1 -1
- package/dist/verify/formal/index.d.ts +44 -0
- package/dist/verify/formal/index.d.ts.map +1 -0
- package/dist/verify/formal/index.js +98 -0
- package/dist/verify/formal/index.js.map +1 -0
- package/dist/verify/formal/policy.d.ts +105 -0
- package/dist/verify/formal/policy.d.ts.map +1 -0
- package/dist/verify/formal/policy.js +159 -0
- package/dist/verify/formal/policy.js.map +1 -0
- package/dist/verify/formal/result.d.ts +50 -0
- package/dist/verify/formal/result.d.ts.map +1 -0
- package/dist/verify/formal/result.js +21 -0
- package/dist/verify/formal/result.js.map +1 -0
- package/dist/verify/formal/solver.d.ts +67 -0
- package/dist/verify/formal/solver.d.ts.map +1 -0
- package/dist/verify/formal/solver.js +184 -0
- package/dist/verify/formal/solver.js.map +1 -0
- package/dist/verify/formal/spec-language.d.ts +80 -0
- package/dist/verify/formal/spec-language.d.ts.map +1 -0
- package/dist/verify/formal/spec-language.js +219 -0
- package/dist/verify/formal/spec-language.js.map +1 -0
- package/docs/attestation.md +199 -0
- package/docs/identity.md +193 -0
- package/package.json +22 -1
- package/src/adapters/llm/anthropic-direct.ts +51 -0
- package/src/adapters/llm/cascade.ts +64 -19
- package/src/adapters/llm/litellm.ts +49 -0
- package/src/compute/difficulty-estimator.ts +111 -0
- package/src/compute/strategies/mixture-of-agents.ts +150 -0
- package/src/compute/strategies/tree-of-thoughts.ts +293 -0
- package/src/compute/strategies/two-phase-orient.ts +147 -0
- package/src/container/protocol.ts +243 -0
- package/src/container/runtime.ts +424 -0
- package/src/db/migrations/026_formal_verify_results.sql +30 -0
- package/src/events/catalogue.ts +54 -0
- package/src/events/index.ts +9 -0
- package/src/events/schemas/citadel.sprint.analyzed.v1.ts +23 -0
- package/src/events/schemas/forge.inbox.reply_classified.v1.ts +15 -0
- package/src/events/schemas/vauban-finance.forecast.generated.v1.ts +11 -0
- package/src/events/schemas/vauban-finance.trade.executed.v1.ts +12 -0
- package/src/events/schemas/vauban.goal.checked.v1.ts +11 -0
- package/src/events/schemas/vauban.rebalancing.checked.v1.ts +11 -0
- package/src/events/schemas/vauban.tax.checked.v1.ts +11 -0
- package/src/events/schemas/vauban.vault.analyzed.v1.ts +21 -0
- package/src/events/schemas/vauban.vault.compounded.v1.ts +12 -0
- package/src/identity/agent-persona.ts +203 -0
- package/src/identity/persona-prompt.ts +84 -0
- package/src/identity/persona-schema.ts +127 -0
- package/src/index.ts +338 -1
- package/src/loop/index.ts +0 -1
- package/src/loop/sdk-loop.ts +5 -8
- package/src/memory/episodic-rrf.ts +224 -0
- package/src/mesh/attenuation.ts +190 -0
- package/src/mesh/delegate.ts +254 -0
- package/src/mesh/dispatcher.ts +301 -0
- package/src/mesh/index.ts +39 -0
- package/src/mesh/types.ts +31 -0
- package/src/orchestration/ooda/skills.ts +177 -0
- package/src/orchestration/ooda/types.ts +3 -9
- package/src/ports/bastion-action.contract.test.ts +355 -0
- package/src/ports/bastion-action.ts +198 -0
- package/src/ports/brain.ts +177 -15
- package/src/ports/citadel-action.contract.test.ts +430 -0
- package/src/ports/citadel-action.ts +174 -0
- package/src/ports/compliance-contract.ts +191 -0
- package/src/ports/db.ts +98 -0
- package/src/ports/delegation.contract.test.ts +428 -0
- package/src/ports/delegation.ts +211 -0
- package/src/ports/event-bus.ts +133 -18
- package/src/ports/federation.contract.test.ts +355 -0
- package/src/ports/federation.ts +190 -0
- package/src/ports/index.ts +186 -1
- package/src/ports/llm-provider.ts +123 -0
- package/src/ports/logger.ts +104 -0
- package/src/ports/manifest-registry.contract.test.ts +324 -0
- package/src/ports/manifest-registry.ts +188 -0
- package/src/ports/observability.contract.test.ts +315 -0
- package/src/ports/observability.ts +150 -0
- package/src/ports/outcome.ts +69 -0
- package/src/ports/privacy.contract.test.ts +413 -0
- package/src/ports/privacy.ts +207 -0
- package/src/ports/tenant-context.contract.test.ts +454 -0
- package/src/ports/tenant-context.ts +150 -0
- package/src/ports/vauban-finance-action.contract.test.ts +335 -0
- package/src/ports/vauban-finance-action.ts +166 -0
- package/src/ports/workflow-runtime.ts +327 -0
- package/src/proof/cert-verify.ts +249 -0
- package/src/replay/replay.ts +11 -8
- package/src/retry/index.ts +227 -0
- package/src/retry/presets.ts +75 -0
- package/src/skill-loop/ab-runner.ts +196 -0
- package/src/skill-loop/adoption.ts +188 -0
- package/src/skill-loop/candidate.ts +75 -0
- package/src/skill-loop/evaluator.ts +238 -0
- package/src/skill-loop/index.ts +51 -0
- package/src/skill-loop/reflexion-replay.ts +173 -0
- package/src/skill-loop/sign-off.ts +247 -0
- package/src/skill-loop/value-metric.ts +120 -0
- package/src/skill-loop/versioning.ts +75 -0
- package/src/skill-manifest/anchor.ts +401 -0
- package/src/skill-manifest/builder.ts +129 -0
- package/src/skill-manifest/index.ts +18 -0
- package/src/skill-manifest/types.ts +72 -0
- package/src/skill-manifest/verifier.ts +198 -0
- package/src/skills/errors.ts +30 -2
- package/src/skills/index.ts +19 -0
- package/src/skills/markdown/loader.ts +129 -0
- package/src/skills/markdown/schema.ts +144 -0
- package/src/skills/poc-md-loader/e2e-parity.test.ts +237 -0
- package/src/skills/poc-md-loader/markdown-loader.ts +161 -0
- package/src/skills/poc-md-loader/runner.ts +82 -0
- package/src/skills/poc-md-loader/vitest.poc.config.ts +13 -0
- package/src/skills/poc-md-loader/web-search/SKILL.md +42 -0
- package/src/skills/poc-md-loader/web-search/script.ts +109 -0
- package/src/skills/send-email.ts +15 -3
- package/src/testing/contracts/event-bus.contract.ts +16 -14
- package/src/testing/test-brain-port.ts +98 -24
- package/src/testing/test-event-bus.ts +104 -43
- package/src/trace/schema.ts +1 -1
- package/src/verify/formal/index.ts +154 -0
- package/src/verify/formal/policy.ts +253 -0
- package/src/verify/formal/result.ts +52 -0
- package/src/verify/formal/solver.ts +235 -0
- package/src/verify/formal/spec-language.ts +274 -0
package/src/ports/brain.ts
CHANGED
|
@@ -37,7 +37,12 @@ export interface BrainQueryFilters {
|
|
|
37
37
|
// ─── Tier 1: Working memory ──────────────────────────────────────────────────
|
|
38
38
|
|
|
39
39
|
export interface WorkingMemoryPort {
|
|
40
|
-
set(
|
|
40
|
+
set(
|
|
41
|
+
runId: string,
|
|
42
|
+
key: string,
|
|
43
|
+
value: unknown,
|
|
44
|
+
opts?: { ttlMs?: number }
|
|
45
|
+
): Promise<void>;
|
|
41
46
|
get(runId: string, key: string): Promise<unknown>;
|
|
42
47
|
delete(runId: string, key: string): Promise<void>;
|
|
43
48
|
}
|
|
@@ -45,8 +50,16 @@ export interface WorkingMemoryPort {
|
|
|
45
50
|
export class InMemoryWorkingMemory implements WorkingMemoryPort {
|
|
46
51
|
private store = new Map<string, { value: unknown; expiresAt: number }>();
|
|
47
52
|
|
|
48
|
-
async set(
|
|
49
|
-
|
|
53
|
+
async set(
|
|
54
|
+
runId: string,
|
|
55
|
+
key: string,
|
|
56
|
+
value: unknown,
|
|
57
|
+
opts?: { ttlMs?: number }
|
|
58
|
+
): Promise<void> {
|
|
59
|
+
this.store.set(`${runId}:${key}`, {
|
|
60
|
+
value,
|
|
61
|
+
expiresAt: Date.now() + (opts?.ttlMs ?? 300_000),
|
|
62
|
+
});
|
|
50
63
|
}
|
|
51
64
|
|
|
52
65
|
async get(runId: string, key: string): Promise<unknown> {
|
|
@@ -100,12 +113,12 @@ export interface EpisodicMemoryPort {
|
|
|
100
113
|
runId: string,
|
|
101
114
|
event: string,
|
|
102
115
|
metadata?: Record<string, unknown>,
|
|
103
|
-
opts?: { traceId?: string }
|
|
116
|
+
opts?: { traceId?: string }
|
|
104
117
|
): Promise<void>;
|
|
105
118
|
since(
|
|
106
119
|
agentId: string,
|
|
107
120
|
sinceMs: number,
|
|
108
|
-
opts?: { limit?: number }
|
|
121
|
+
opts?: { limit?: number }
|
|
109
122
|
): Promise<EpisodicMemoryEntry[]>;
|
|
110
123
|
/**
|
|
111
124
|
* Retrieve all episodic entries associated with a given OTel trace ID,
|
|
@@ -115,7 +128,10 @@ export interface EpisodicMemoryPort {
|
|
|
115
128
|
* @param opts.limit - Maximum number of entries to return (default: unbounded).
|
|
116
129
|
* @returns Entries matching traceId, oldest first.
|
|
117
130
|
*/
|
|
118
|
-
queryByTrace(
|
|
131
|
+
queryByTrace(
|
|
132
|
+
traceId: string,
|
|
133
|
+
opts?: { limit?: number }
|
|
134
|
+
): Promise<EpisodicMemoryEntry[]>;
|
|
119
135
|
}
|
|
120
136
|
|
|
121
137
|
export class InMemoryEpisodicMemory implements EpisodicMemoryPort {
|
|
@@ -126,7 +142,7 @@ export class InMemoryEpisodicMemory implements EpisodicMemoryPort {
|
|
|
126
142
|
runId: string,
|
|
127
143
|
event: string,
|
|
128
144
|
metadata?: Record<string, unknown>,
|
|
129
|
-
opts?: { traceId?: string }
|
|
145
|
+
opts?: { traceId?: string }
|
|
130
146
|
): Promise<void> {
|
|
131
147
|
this.events.push({
|
|
132
148
|
agentId,
|
|
@@ -141,7 +157,7 @@ export class InMemoryEpisodicMemory implements EpisodicMemoryPort {
|
|
|
141
157
|
async since(
|
|
142
158
|
agentId: string,
|
|
143
159
|
sinceMs: number,
|
|
144
|
-
opts?: { limit?: number }
|
|
160
|
+
opts?: { limit?: number }
|
|
145
161
|
): Promise<EpisodicMemoryEntry[]> {
|
|
146
162
|
const filtered = this.events
|
|
147
163
|
.filter((e) => e.agentId === agentId && e.timestamp >= sinceMs)
|
|
@@ -149,7 +165,10 @@ export class InMemoryEpisodicMemory implements EpisodicMemoryPort {
|
|
|
149
165
|
return opts?.limit ? filtered.slice(0, opts.limit) : filtered;
|
|
150
166
|
}
|
|
151
167
|
|
|
152
|
-
async queryByTrace(
|
|
168
|
+
async queryByTrace(
|
|
169
|
+
traceId: string,
|
|
170
|
+
opts?: { limit?: number }
|
|
171
|
+
): Promise<EpisodicMemoryEntry[]> {
|
|
153
172
|
// Insertion order is preserved (Array.filter is stable; events are pushed in order).
|
|
154
173
|
const filtered = this.events.filter((e) => e.traceId === traceId);
|
|
155
174
|
return opts?.limit ? filtered.slice(0, opts.limit) : filtered;
|
|
@@ -169,10 +188,15 @@ export class InMemorySemanticMemory implements SemanticMemoryPort {
|
|
|
169
188
|
private entries: BrainEntry[] = [];
|
|
170
189
|
|
|
171
190
|
async query(q: string, filters?: BrainQueryFilters): Promise<BrainEntry[]> {
|
|
172
|
-
let results = this.entries.filter((e) =>
|
|
173
|
-
|
|
191
|
+
let results = this.entries.filter((e) =>
|
|
192
|
+
e.content.toLowerCase().includes(q.toLowerCase())
|
|
193
|
+
);
|
|
194
|
+
if (filters?.category)
|
|
195
|
+
results = results.filter((e) => e.category === filters.category);
|
|
174
196
|
if (filters?.tags && filters.tags.length > 0) {
|
|
175
|
-
results = results.filter((e) =>
|
|
197
|
+
results = results.filter((e) =>
|
|
198
|
+
e.tags?.some((t) => filters.tags?.includes(t))
|
|
199
|
+
);
|
|
176
200
|
}
|
|
177
201
|
return filters?.limit ? results.slice(0, filters.limit) : results;
|
|
178
202
|
}
|
|
@@ -207,7 +231,11 @@ export interface ProceduralMemoryPort {
|
|
|
207
231
|
/** Register a learned skill for an agent. */
|
|
208
232
|
registerSkill(agentId: string, skill: ProceduralSkill): Promise<void>;
|
|
209
233
|
/** Share a skill with other agents. */
|
|
210
|
-
shareSkill(
|
|
234
|
+
shareSkill(
|
|
235
|
+
skillName: string,
|
|
236
|
+
fromAgentId: string,
|
|
237
|
+
toAgentIds: string[]
|
|
238
|
+
): Promise<void>;
|
|
211
239
|
}
|
|
212
240
|
|
|
213
241
|
export class InMemoryProceduralMemory implements ProceduralMemoryPort {
|
|
@@ -232,7 +260,11 @@ export class InMemoryProceduralMemory implements ProceduralMemoryPort {
|
|
|
232
260
|
this.skills.set(agentId, [...existing, skill]);
|
|
233
261
|
}
|
|
234
262
|
|
|
235
|
-
async shareSkill(
|
|
263
|
+
async shareSkill(
|
|
264
|
+
skillName: string,
|
|
265
|
+
fromAgentId: string,
|
|
266
|
+
toAgentIds: string[]
|
|
267
|
+
): Promise<void> {
|
|
236
268
|
for (const _toAgent of toAgentIds) {
|
|
237
269
|
const shared = this.shared.get(fromAgentId) ?? [];
|
|
238
270
|
if (!shared.includes(skillName)) {
|
|
@@ -242,14 +274,144 @@ export class InMemoryProceduralMemory implements ProceduralMemoryPort {
|
|
|
242
274
|
}
|
|
243
275
|
}
|
|
244
276
|
|
|
277
|
+
// ─── Typed errors ─────────────────────────────────────────────────────────────
|
|
278
|
+
|
|
279
|
+
/**
|
|
280
|
+
* Thrown when the Brain API is unreachable (connection refused, DNS failure,
|
|
281
|
+
* timeout on connect). Callers can retry with backoff or fall back to a local cache.
|
|
282
|
+
*/
|
|
283
|
+
export class BrainUnavailableError extends Error {
|
|
284
|
+
constructor(message: string, public readonly cause?: unknown) {
|
|
285
|
+
super(message);
|
|
286
|
+
this.name = "BrainUnavailableError";
|
|
287
|
+
Object.setPrototypeOf(this, new.target.prototype);
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
/**
|
|
292
|
+
* Thrown when the Brain API returns 429 (rate limit exceeded).
|
|
293
|
+
* Callers should retry after the delay indicated in the `retryAfterMs` field
|
|
294
|
+
* (extracted from the Retry-After header) or use exponential backoff.
|
|
295
|
+
*/
|
|
296
|
+
export class BrainRateLimitError extends Error {
|
|
297
|
+
/** Retry-After delay in milliseconds. Derived from the HTTP Retry-After header. */
|
|
298
|
+
readonly retryAfterMs: number;
|
|
299
|
+
|
|
300
|
+
constructor(
|
|
301
|
+
message: string,
|
|
302
|
+
retryAfterMs: number,
|
|
303
|
+
public readonly cause?: unknown
|
|
304
|
+
) {
|
|
305
|
+
super(message);
|
|
306
|
+
this.name = "BrainRateLimitError";
|
|
307
|
+
this.retryAfterMs = retryAfterMs;
|
|
308
|
+
Object.setPrototypeOf(this, new.target.prototype);
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
|
|
245
312
|
// ─── Full BrainPort (4 tiers, additive non-breaking) ─────────────────────────
|
|
246
313
|
|
|
247
314
|
export interface BrainPort {
|
|
248
315
|
archiveKnowledge(entry: BrainEntryInput): Promise<BrainEntry | null>;
|
|
249
|
-
queryKnowledge?(
|
|
316
|
+
queryKnowledge?(
|
|
317
|
+
query: string,
|
|
318
|
+
filters?: BrainQueryFilters
|
|
319
|
+
): Promise<BrainEntry[]>;
|
|
250
320
|
|
|
251
321
|
working?: WorkingMemoryPort;
|
|
252
322
|
episodic?: EpisodicMemoryPort;
|
|
253
323
|
semantic?: SemanticMemoryPort;
|
|
254
324
|
procedural?: ProceduralMemoryPort;
|
|
255
325
|
}
|
|
326
|
+
|
|
327
|
+
// ─── OTel-traced wrapper ──────────────────────────────────────────────────────
|
|
328
|
+
|
|
329
|
+
import type { Span } from "@opentelemetry/api";
|
|
330
|
+
import { SpanStatusCode, trace } from "@opentelemetry/api";
|
|
331
|
+
|
|
332
|
+
const PORT_TRACER = trace.getTracer("vauban-agent-sdk.ports", "0.1.0");
|
|
333
|
+
|
|
334
|
+
/**
|
|
335
|
+
* Wrap any BrainPort implementation with OTel spans.
|
|
336
|
+
* archiveKnowledge and queryKnowledge calls each get a span with the category
|
|
337
|
+
* and content preview. Gracefully degrades to noop spans when no OTel SDK
|
|
338
|
+
* is installed.
|
|
339
|
+
*
|
|
340
|
+
* Usage:
|
|
341
|
+
* const raw: BrainPort = buildHttpBrain(...);
|
|
342
|
+
* const traced = createTracedBrainPort(raw);
|
|
343
|
+
* await traced.archiveKnowledge({ content: "..." }) // emits "brain.archiveKnowledge" span
|
|
344
|
+
*/
|
|
345
|
+
export function createTracedBrainPort(impl: BrainPort): BrainPort {
|
|
346
|
+
return {
|
|
347
|
+
working: impl.working,
|
|
348
|
+
episodic: impl.episodic,
|
|
349
|
+
semantic: impl.semantic,
|
|
350
|
+
procedural: impl.procedural,
|
|
351
|
+
|
|
352
|
+
async archiveKnowledge(entry: BrainEntryInput): Promise<BrainEntry | null> {
|
|
353
|
+
return PORT_TRACER.startActiveSpan(
|
|
354
|
+
"brain.archiveKnowledge",
|
|
355
|
+
{
|
|
356
|
+
attributes: {
|
|
357
|
+
"brain.entry.category": entry.category ?? "unknown",
|
|
358
|
+
"brain.entry.content_preview": entry.content.slice(0, 200),
|
|
359
|
+
"brain.entry.tags": entry.tags?.join(",") ?? "",
|
|
360
|
+
"vauban.port.name": "brain",
|
|
361
|
+
},
|
|
362
|
+
},
|
|
363
|
+
async (span: Span) => {
|
|
364
|
+
try {
|
|
365
|
+
const result = await impl.archiveKnowledge(entry);
|
|
366
|
+
if (result) {
|
|
367
|
+
span.setAttribute("brain.entry.id", result.id);
|
|
368
|
+
}
|
|
369
|
+
span.setStatus({ code: SpanStatusCode.OK });
|
|
370
|
+
return result;
|
|
371
|
+
} catch (err) {
|
|
372
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
373
|
+
span.setStatus({ code: SpanStatusCode.ERROR, message });
|
|
374
|
+
if (err instanceof Error) span.recordException(err);
|
|
375
|
+
throw err;
|
|
376
|
+
} finally {
|
|
377
|
+
span.end();
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
);
|
|
381
|
+
},
|
|
382
|
+
|
|
383
|
+
async queryKnowledge(
|
|
384
|
+
query: string,
|
|
385
|
+
filters?: BrainQueryFilters
|
|
386
|
+
): Promise<BrainEntry[]> {
|
|
387
|
+
if (!impl.queryKnowledge) return [];
|
|
388
|
+
const qk = impl.queryKnowledge.bind(impl);
|
|
389
|
+
return PORT_TRACER.startActiveSpan(
|
|
390
|
+
"brain.queryKnowledge",
|
|
391
|
+
{
|
|
392
|
+
attributes: {
|
|
393
|
+
"brain.query.preview": query.slice(0, 200),
|
|
394
|
+
"brain.query.category": filters?.category ?? "none",
|
|
395
|
+
"brain.query.limit": filters?.limit ?? -1,
|
|
396
|
+
"vauban.port.name": "brain",
|
|
397
|
+
},
|
|
398
|
+
},
|
|
399
|
+
async (span: Span) => {
|
|
400
|
+
try {
|
|
401
|
+
const result = await qk(query, filters);
|
|
402
|
+
span.setAttribute("brain.query.result_count", result.length);
|
|
403
|
+
span.setStatus({ code: SpanStatusCode.OK });
|
|
404
|
+
return result;
|
|
405
|
+
} catch (err) {
|
|
406
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
407
|
+
span.setStatus({ code: SpanStatusCode.ERROR, message });
|
|
408
|
+
if (err instanceof Error) span.recordException(err);
|
|
409
|
+
throw err;
|
|
410
|
+
} finally {
|
|
411
|
+
span.end();
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
);
|
|
415
|
+
},
|
|
416
|
+
};
|
|
417
|
+
}
|
|
@@ -0,0 +1,430 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CitadelActionPort contract tests.
|
|
3
|
+
*
|
|
4
|
+
* Applied to any CitadelActionPort implementation. Tests tiered access control,
|
|
5
|
+
* state transitions, and governance claim emission.
|
|
6
|
+
*
|
|
7
|
+
* Source: vauban-gouvernance/rules/ai/tiered-gates.md + MASTER-PLAN-v5.md §1.3
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { describe, expect, test } from "vitest";
|
|
11
|
+
import {
|
|
12
|
+
CitadelTierViolationError,
|
|
13
|
+
CitadelTaskRefNotFoundError,
|
|
14
|
+
CitadelSprintNotActiveError,
|
|
15
|
+
CitadelInvalidStateTransitionError,
|
|
16
|
+
type CitadelActionPort,
|
|
17
|
+
type ActionContext,
|
|
18
|
+
type SprintInput,
|
|
19
|
+
type TaskRef,
|
|
20
|
+
type VerificationEvidence,
|
|
21
|
+
type DecisionInput,
|
|
22
|
+
} from "./citadel-action.js";
|
|
23
|
+
|
|
24
|
+
function makeActionContext(
|
|
25
|
+
overrides: Partial<ActionContext> = {}
|
|
26
|
+
): ActionContext {
|
|
27
|
+
return {
|
|
28
|
+
agentId: "test-agent-001",
|
|
29
|
+
agentTier: "T3",
|
|
30
|
+
runId: crypto.randomUUID(),
|
|
31
|
+
...overrides,
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function makeSprintInput(overrides: Partial<SprintInput> = {}): SprintInput {
|
|
36
|
+
return {
|
|
37
|
+
name: "Sprint Test",
|
|
38
|
+
goal: "Test sprint",
|
|
39
|
+
project_slug: "test-project",
|
|
40
|
+
start_date: new Date().toISOString(),
|
|
41
|
+
end_date: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000).toISOString(),
|
|
42
|
+
...overrides,
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function makeTaskRef(overrides: Partial<TaskRef> = {}): TaskRef {
|
|
47
|
+
return {
|
|
48
|
+
ref: "test-project:sprint-1:task-001",
|
|
49
|
+
project: "test-project",
|
|
50
|
+
sprint: "sprint-1",
|
|
51
|
+
task_id: "task-001",
|
|
52
|
+
...overrides,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function makeVerificationEvidence(
|
|
57
|
+
overrides: Partial<VerificationEvidence> = {}
|
|
58
|
+
): VerificationEvidence {
|
|
59
|
+
return {
|
|
60
|
+
passed: true,
|
|
61
|
+
evidence_text: "Verification scenario executed successfully",
|
|
62
|
+
evidence_hash: "abcd1234efgh5678ijkl9012mnop3456",
|
|
63
|
+
...overrides,
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function makeDecisionInput(
|
|
68
|
+
overrides: Partial<DecisionInput> = {}
|
|
69
|
+
): DecisionInput {
|
|
70
|
+
return {
|
|
71
|
+
decision: "Adopt new architecture",
|
|
72
|
+
context: "Performance issues in current stack",
|
|
73
|
+
options: ["Refactor current", "Migrate to new stack", "Hybrid approach"],
|
|
74
|
+
chosen: "Hybrid approach",
|
|
75
|
+
rationale: "Balance performance and migration cost",
|
|
76
|
+
...overrides,
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export const citadelActionPortContract = (factory: () => CitadelActionPort) => {
|
|
81
|
+
describe("CitadelActionPort contract", () => {
|
|
82
|
+
test("createSprint requires T2+ tier", async () => {
|
|
83
|
+
const port = factory();
|
|
84
|
+
const input = makeSprintInput();
|
|
85
|
+
const ctx = makeActionContext({ agentTier: "T1" });
|
|
86
|
+
|
|
87
|
+
await expect(port.createSprint(input, ctx)).rejects.toThrow(
|
|
88
|
+
CitadelTierViolationError
|
|
89
|
+
);
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
test("createSprint succeeds for T2+ agents", async () => {
|
|
93
|
+
const port = factory();
|
|
94
|
+
const input = makeSprintInput();
|
|
95
|
+
const ctx = makeActionContext({ agentTier: "T2" });
|
|
96
|
+
|
|
97
|
+
const sprintRef = await port.createSprint(input, ctx);
|
|
98
|
+
expect(sprintRef.sprint_id).toBeDefined();
|
|
99
|
+
expect(sprintRef.project_slug).toBe(input.project_slug);
|
|
100
|
+
expect(sprintRef.name).toBe(input.name);
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
test("updateTaskStatus transitions task state", async () => {
|
|
104
|
+
const port = factory();
|
|
105
|
+
const taskRef = makeTaskRef();
|
|
106
|
+
const ctx = makeActionContext({ agentTier: "T2" });
|
|
107
|
+
|
|
108
|
+
// Transition todo → in_progress
|
|
109
|
+
await port.updateTaskStatus(taskRef, "in_progress", ctx);
|
|
110
|
+
// No throw = success
|
|
111
|
+
|
|
112
|
+
// Transition in_progress → done
|
|
113
|
+
await port.updateTaskStatus(taskRef, "done", ctx);
|
|
114
|
+
// No throw = success
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
test("updateTaskStatus blocks invalid transitions", async () => {
|
|
118
|
+
const port = factory();
|
|
119
|
+
const taskRef = makeTaskRef();
|
|
120
|
+
const ctx = makeActionContext({ agentTier: "T2" });
|
|
121
|
+
|
|
122
|
+
// Walk valid path: todo → in_progress → done
|
|
123
|
+
await port.updateTaskStatus(taskRef, "in_progress", ctx);
|
|
124
|
+
await port.updateTaskStatus(taskRef, "done", ctx);
|
|
125
|
+
|
|
126
|
+
// Now try invalid: done → in_progress (must throw)
|
|
127
|
+
await expect(
|
|
128
|
+
port.updateTaskStatus(taskRef, "in_progress", ctx)
|
|
129
|
+
).rejects.toMatchObject({
|
|
130
|
+
name: "CitadelInvalidStateTransitionError",
|
|
131
|
+
current_status: "done",
|
|
132
|
+
requested_status: "in_progress",
|
|
133
|
+
});
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
test("sealSprint requires T3+ tier", async () => {
|
|
137
|
+
const port = factory();
|
|
138
|
+
const evidence = makeVerificationEvidence();
|
|
139
|
+
const ctx = makeActionContext({ agentTier: "T2" });
|
|
140
|
+
|
|
141
|
+
await expect(port.sealSprint("sprint-1", evidence, ctx)).rejects.toThrow(
|
|
142
|
+
CitadelTierViolationError
|
|
143
|
+
);
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
test("sealSprint succeeds for T3+ agents with evidence", async () => {
|
|
147
|
+
const port = factory();
|
|
148
|
+
const evidence = makeVerificationEvidence({ passed: true });
|
|
149
|
+
const ctx = makeActionContext({ agentTier: "T3" });
|
|
150
|
+
|
|
151
|
+
const claim = await port.sealSprint("sprint-1", evidence, ctx);
|
|
152
|
+
expect(claim.sprint_id).toBe("sprint-1");
|
|
153
|
+
expect(claim.sealed_at).toBeDefined();
|
|
154
|
+
expect(claim.sealed_by_agent).toBe(ctx.agentId);
|
|
155
|
+
expect(claim.verification_evidence_hash).toBe(evidence.evidence_hash);
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
test("sealSprint fails if sprint not active", async () => {
|
|
159
|
+
const port = factory();
|
|
160
|
+
const evidence = makeVerificationEvidence();
|
|
161
|
+
const ctx = makeActionContext({ agentTier: "T3" });
|
|
162
|
+
|
|
163
|
+
try {
|
|
164
|
+
// Attempting to seal a sprint that is not in active status
|
|
165
|
+
await port.sealSprint("sprint-999", evidence, ctx);
|
|
166
|
+
} catch (err) {
|
|
167
|
+
if (err instanceof CitadelSprintNotActiveError) {
|
|
168
|
+
expect(err.sprint_id).toBe("sprint-999");
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
test("sealSprint emits SealedSprintClaim with anchor_id", async () => {
|
|
174
|
+
const port = factory();
|
|
175
|
+
const evidence = makeVerificationEvidence();
|
|
176
|
+
const ctx = makeActionContext({ agentTier: "T3" });
|
|
177
|
+
|
|
178
|
+
const claim = await port.sealSprint("sprint-1", evidence, ctx);
|
|
179
|
+
// anchor_id is optional (Phase 1+ deferred), but test should verify if present
|
|
180
|
+
if (claim.anchor_id) {
|
|
181
|
+
expect(claim.anchor_id.length).toBeGreaterThan(0);
|
|
182
|
+
}
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
test("recordDecision requires T2+ tier", async () => {
|
|
186
|
+
const port = factory();
|
|
187
|
+
const decision = makeDecisionInput();
|
|
188
|
+
const ctx = makeActionContext({ agentTier: "T1" });
|
|
189
|
+
|
|
190
|
+
await expect(port.recordDecision(decision, ctx)).rejects.toThrow(
|
|
191
|
+
CitadelTierViolationError
|
|
192
|
+
);
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
test("recordDecision succeeds for T2+ agents", async () => {
|
|
196
|
+
const port = factory();
|
|
197
|
+
const decision = makeDecisionInput();
|
|
198
|
+
const ctx = makeActionContext({ agentTier: "T2" });
|
|
199
|
+
|
|
200
|
+
const claim = await port.recordDecision(decision, ctx);
|
|
201
|
+
expect(claim.decision_id).toBeDefined();
|
|
202
|
+
expect(claim.created_at).toBeDefined();
|
|
203
|
+
expect(claim.archived_to_brain).toBeDefined();
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
test("recordDecision T3+ triggers cascade hook", async () => {
|
|
207
|
+
const port = factory();
|
|
208
|
+
const decision = makeDecisionInput({
|
|
209
|
+
decision: "ADR-ECO-NNN: Architectural Decision",
|
|
210
|
+
});
|
|
211
|
+
const ctx = makeActionContext({ agentTier: "T3" });
|
|
212
|
+
|
|
213
|
+
const claim = await port.recordDecision(decision, ctx);
|
|
214
|
+
// T3+ should trigger cascade (optional, implementation-specific)
|
|
215
|
+
// Just verify claim is returned
|
|
216
|
+
expect(claim.decision_id).toBeDefined();
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
test("tier violation error includes required and actual tier", async () => {
|
|
220
|
+
const port = factory();
|
|
221
|
+
const input = makeSprintInput();
|
|
222
|
+
const ctx = makeActionContext({ agentTier: "T1" });
|
|
223
|
+
|
|
224
|
+
try {
|
|
225
|
+
await port.createSprint(input, ctx);
|
|
226
|
+
} catch (err) {
|
|
227
|
+
if (err instanceof CitadelTierViolationError) {
|
|
228
|
+
expect(err.required_tier).toBe("T2");
|
|
229
|
+
expect(err.actual_tier).toBe("T1");
|
|
230
|
+
expect(err.operation).toBeDefined();
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
test("task not found error includes task ref", async () => {
|
|
236
|
+
const port = factory();
|
|
237
|
+
const taskRef = makeTaskRef({ ref: "nonexistent:sprint-1:task-999" });
|
|
238
|
+
const ctx = makeActionContext({ agentTier: "T2" });
|
|
239
|
+
|
|
240
|
+
try {
|
|
241
|
+
await port.updateTaskStatus(taskRef, "done", ctx);
|
|
242
|
+
} catch (err) {
|
|
243
|
+
if (err instanceof CitadelTaskRefNotFoundError) {
|
|
244
|
+
expect(err.task_ref).toContain("nonexistent");
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
test("sprint not active error includes current status", async () => {
|
|
250
|
+
const port = factory();
|
|
251
|
+
const evidence = makeVerificationEvidence();
|
|
252
|
+
const ctx = makeActionContext({ agentTier: "T3" });
|
|
253
|
+
|
|
254
|
+
try {
|
|
255
|
+
await port.sealSprint("completed-sprint", evidence, ctx);
|
|
256
|
+
} catch (err) {
|
|
257
|
+
if (err instanceof CitadelSprintNotActiveError) {
|
|
258
|
+
expect(err.sprint_id).toBe("completed-sprint");
|
|
259
|
+
expect(err.current_status).toBeDefined();
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
});
|
|
263
|
+
|
|
264
|
+
test("T4 agents can seal sprints", async () => {
|
|
265
|
+
const port = factory();
|
|
266
|
+
const evidence = makeVerificationEvidence();
|
|
267
|
+
const ctx = makeActionContext({ agentTier: "T4" });
|
|
268
|
+
|
|
269
|
+
try {
|
|
270
|
+
const claim = await port.sealSprint("sprint-1", evidence, ctx);
|
|
271
|
+
expect(claim.sealed_by_agent).toBe(ctx.agentId);
|
|
272
|
+
} catch (err) {
|
|
273
|
+
// May fail for other reasons (sprint not found), but not tier violation
|
|
274
|
+
if (err instanceof CitadelTierViolationError) {
|
|
275
|
+
throw new Error("T4 should not have tier violation");
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
});
|
|
279
|
+
});
|
|
280
|
+
};
|
|
281
|
+
|
|
282
|
+
// ─── Mock implementation ──────────────────────────────────────────────────
|
|
283
|
+
|
|
284
|
+
class MockCitadelActionPort implements CitadelActionPort {
|
|
285
|
+
private sprintStates = new Map<
|
|
286
|
+
string,
|
|
287
|
+
{
|
|
288
|
+
status: "planned" | "active" | "completed";
|
|
289
|
+
tasks: Map<string, TaskStatus>;
|
|
290
|
+
}
|
|
291
|
+
>();
|
|
292
|
+
private taskStates = new Map<string, TaskStatus>();
|
|
293
|
+
|
|
294
|
+
constructor() {
|
|
295
|
+
// Pre-populate some sprint states
|
|
296
|
+
this.sprintStates.set("sprint-1", {
|
|
297
|
+
status: "active",
|
|
298
|
+
tasks: new Map([
|
|
299
|
+
["test-project:sprint-1:task-001", "todo"],
|
|
300
|
+
["test-project:sprint-1:task-002", "in_progress"],
|
|
301
|
+
]),
|
|
302
|
+
});
|
|
303
|
+
this.sprintStates.set("completed-sprint", {
|
|
304
|
+
status: "completed",
|
|
305
|
+
tasks: new Map(),
|
|
306
|
+
});
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
async createSprint(
|
|
310
|
+
input: SprintInput,
|
|
311
|
+
ctx: ActionContext
|
|
312
|
+
): Promise<SprintRef> {
|
|
313
|
+
// T2+ only
|
|
314
|
+
if (ctx.agentTier === "T1") {
|
|
315
|
+
throw new CitadelTierViolationError(
|
|
316
|
+
`T1 agents cannot create sprints`,
|
|
317
|
+
"T2",
|
|
318
|
+
ctx.agentTier,
|
|
319
|
+
"createSprint"
|
|
320
|
+
);
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
const sprintId = `sprint-${Math.floor(Math.random() * 10000)}`;
|
|
324
|
+
this.sprintStates.set(sprintId, {
|
|
325
|
+
status: "planned",
|
|
326
|
+
tasks: new Map(),
|
|
327
|
+
});
|
|
328
|
+
|
|
329
|
+
return {
|
|
330
|
+
sprint_id: sprintId,
|
|
331
|
+
project_slug: input.project_slug,
|
|
332
|
+
name: input.name,
|
|
333
|
+
created_at: new Date(),
|
|
334
|
+
};
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
async updateTaskStatus(
|
|
338
|
+
ref: TaskRef,
|
|
339
|
+
status: TaskStatus,
|
|
340
|
+
ctx: ActionContext
|
|
341
|
+
): Promise<void> {
|
|
342
|
+
// Check if task exists
|
|
343
|
+
if (!this.taskStates.has(ref.ref) && !ref.ref.startsWith("test-project")) {
|
|
344
|
+
throw new CitadelTaskRefNotFoundError(ref.ref);
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
// Get current status
|
|
348
|
+
const currentStatus = this.taskStates.get(ref.ref) || "todo";
|
|
349
|
+
|
|
350
|
+
// Validate state transitions
|
|
351
|
+
const validTransitions: Record<TaskStatus, TaskStatus[]> = {
|
|
352
|
+
todo: ["in_progress", "blocked", "rejected"],
|
|
353
|
+
in_progress: ["done", "blocked", "rejected"],
|
|
354
|
+
done: ["blocked", "rejected"],
|
|
355
|
+
blocked: ["in_progress", "rejected"],
|
|
356
|
+
rejected: [],
|
|
357
|
+
};
|
|
358
|
+
|
|
359
|
+
if (!validTransitions[currentStatus]?.includes(status)) {
|
|
360
|
+
throw new CitadelInvalidStateTransitionError(currentStatus, status);
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
this.taskStates.set(ref.ref, status);
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
async sealSprint(
|
|
367
|
+
sprintId: string,
|
|
368
|
+
evidence: VerificationEvidence,
|
|
369
|
+
ctx: ActionContext
|
|
370
|
+
): Promise<SealedSprintClaim> {
|
|
371
|
+
// T3+ only
|
|
372
|
+
if (ctx.agentTier !== "T3" && ctx.agentTier !== "T4") {
|
|
373
|
+
throw new CitadelTierViolationError(
|
|
374
|
+
`${ctx.agentTier} agents cannot seal sprints`,
|
|
375
|
+
"T3",
|
|
376
|
+
ctx.agentTier,
|
|
377
|
+
"sealSprint"
|
|
378
|
+
);
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
// Check if sprint exists and is active
|
|
382
|
+
const sprintState = this.sprintStates.get(sprintId);
|
|
383
|
+
if (!sprintState) {
|
|
384
|
+
throw new CitadelSprintNotActiveError(sprintId, "not_found");
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
if (sprintState.status !== "active") {
|
|
388
|
+
throw new CitadelSprintNotActiveError(sprintId, sprintState.status);
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
// Update sprint status to completed
|
|
392
|
+
sprintState.status = "completed";
|
|
393
|
+
|
|
394
|
+
return {
|
|
395
|
+
sprint_id: sprintId,
|
|
396
|
+
sealed_at: new Date(),
|
|
397
|
+
verification_evidence_hash: evidence.evidence_hash,
|
|
398
|
+
sealed_by_agent: ctx.agentId,
|
|
399
|
+
anchor_id: `anchor-${crypto.randomUUID()}`,
|
|
400
|
+
};
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
async recordDecision(
|
|
404
|
+
decision: DecisionInput,
|
|
405
|
+
ctx: ActionContext
|
|
406
|
+
): Promise<DecisionClaim> {
|
|
407
|
+
// T2+ only
|
|
408
|
+
if (ctx.agentTier === "T1") {
|
|
409
|
+
throw new CitadelTierViolationError(
|
|
410
|
+
`T1 agents cannot record decisions`,
|
|
411
|
+
"T2",
|
|
412
|
+
ctx.agentTier,
|
|
413
|
+
"recordDecision"
|
|
414
|
+
);
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
const cascade = ctx.agentTier === "T3" || ctx.agentTier === "T4";
|
|
418
|
+
|
|
419
|
+
return {
|
|
420
|
+
decision_id: `decision-${crypto.randomUUID()}`,
|
|
421
|
+
created_at: new Date(),
|
|
422
|
+
archived_to_brain: true,
|
|
423
|
+
cascade_triggered: cascade,
|
|
424
|
+
};
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
// ─── Default contract application ──────────────────────────────────────────
|
|
429
|
+
|
|
430
|
+
citadelActionPortContract(() => new MockCitadelActionPort());
|