@vauban-org/agent-sdk 1.0.0 → 1.3.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 +6918 -742
- 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 +46 -46
- 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 +6 -6
- package/dist/events/schemas/citadel.sprint.closed.v1.d.ts +2 -2
- package/dist/events/schemas/forge.inbox.reply_classified.v1.d.ts +6 -6
- 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.goal.checked.v1.d.ts +2 -2
- package/dist/events/schemas/vauban.rebalancing.checked.v1.d.ts +2 -2
- package/dist/events/schemas/vauban.tax.checked.v1.d.ts +2 -2
- package/dist/events/schemas/vauban.vault.analyzed.v1.d.ts +6 -6
- 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 +41 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +31 -1
- package/dist/index.js.map +1 -1
- package/dist/loop/minimal-loop.js +293 -287
- 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/agent.d.ts.map +1 -1
- package/dist/orchestration/ooda/agent.js +36 -0
- package/dist/orchestration/ooda/agent.js.map +1 -1
- 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 +11 -0
- 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 -0
- 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/_secrets.d.ts +16 -0
- package/dist/skills/_secrets.d.ts.map +1 -0
- package/dist/skills/_secrets.js +20 -0
- package/dist/skills/_secrets.js.map +1 -0
- package/dist/skills/alpaca-quote.d.ts +2 -2
- package/dist/skills/alpaca-quote.d.ts.map +1 -1
- package/dist/skills/alpaca-quote.js +51 -20
- package/dist/skills/alpaca-quote.js.map +1 -1
- 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 +2 -2
- package/dist/skills/send-email.d.ts.map +1 -1
- package/dist/skills/send-email.js +4 -3
- package/dist/skills/send-email.js.map +1 -1
- package/dist/skills/slack-notify.d.ts +4 -4
- package/dist/skills/slack-notify.d.ts.map +1 -1
- package/dist/skills/slack-notify.js +52 -21
- package/dist/skills/slack-notify.js.map +1 -1
- package/dist/skills/starknet-balance.d.ts +1 -1
- package/dist/skills/telegram-notify.d.ts +4 -4
- package/dist/skills/telegram-notify.d.ts.map +1 -1
- package/dist/skills/telegram-notify.js +48 -19
- package/dist/skills/telegram-notify.js.map +1 -1
- package/dist/skills/web-search.d.ts +1 -1
- package/dist/skills/web-search.d.ts.map +1 -1
- package/dist/skills/web-search.js +85 -40
- package/dist/skills/web-search.js.map +1 -1
- package/dist/telemetry/bus.d.ts +54 -0
- package/dist/telemetry/bus.d.ts.map +1 -0
- package/dist/telemetry/bus.js +159 -0
- package/dist/telemetry/bus.js.map +1 -0
- package/dist/telemetry/index.d.ts +35 -0
- package/dist/telemetry/index.d.ts.map +1 -0
- package/dist/telemetry/index.js +30 -0
- package/dist/telemetry/index.js.map +1 -0
- package/dist/telemetry/port.d.ts +121 -0
- package/dist/telemetry/port.d.ts.map +1 -0
- package/dist/telemetry/port.js +48 -0
- package/dist/telemetry/port.js.map +1 -0
- package/dist/telemetry/sinks/otlp.d.ts +45 -0
- package/dist/telemetry/sinks/otlp.d.ts.map +1 -0
- package/dist/telemetry/sinks/otlp.js +195 -0
- package/dist/telemetry/sinks/otlp.js.map +1 -0
- package/dist/telemetry/sinks/sqlite.d.ts +32 -0
- package/dist/telemetry/sinks/sqlite.d.ts.map +1 -0
- package/dist/telemetry/sinks/sqlite.js +170 -0
- package/dist/telemetry/sinks/sqlite.js.map +1 -0
- package/dist/telemetry/sinks/stdout.d.ts +22 -0
- package/dist/telemetry/sinks/stdout.d.ts.map +1 -0
- package/dist/telemetry/sinks/stdout.js +38 -0
- package/dist/telemetry/sinks/stdout.js.map +1 -0
- 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/docs/telemetry/migration.md +155 -0
- package/docs/telemetry/overview.md +154 -0
- package/docs/telemetry/privacy.md +127 -0
- package/docs/telemetry/sinks/cc.md +155 -0
- package/docs/telemetry/sinks/otlp.md +146 -0
- package/docs/telemetry/sinks/sqlite.md +126 -0
- package/docs/telemetry/sinks/stdout.md +82 -0
- package/package.json +18 -2
- 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/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 +368 -2
- 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/agent.ts +50 -0
- package/src/orchestration/ooda/skills.ts +177 -0
- package/src/orchestration/ooda/types.ts +12 -0
- 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 -0
- 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/_secrets.ts +25 -0
- package/src/skills/alpaca-quote.ts +68 -23
- 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 +4 -3
- package/src/skills/slack-notify.ts +73 -30
- package/src/skills/telegram-notify.ts +70 -24
- package/src/skills/web-search.ts +132 -50
- package/src/telemetry/bus.test.ts +231 -0
- package/src/telemetry/bus.ts +241 -0
- package/src/telemetry/index.ts +49 -0
- package/src/telemetry/port.ts +160 -0
- package/src/telemetry/sinks/otlp.test.ts +146 -0
- package/src/telemetry/sinks/otlp.ts +250 -0
- package/src/telemetry/sinks/sqlite.test.ts +121 -0
- package/src/telemetry/sinks/sqlite.ts +260 -0
- package/src/telemetry/sinks/stdout.test.ts +109 -0
- package/src/telemetry/sinks/stdout.ts +59 -0
- 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
|
@@ -0,0 +1,293 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* src/compute/strategies/tree-of-thoughts.ts
|
|
3
|
+
*
|
|
4
|
+
* Tree-of-Thoughts (ToT) compute strategy.
|
|
5
|
+
*
|
|
6
|
+
* Reference: Yao et al. 2023, "Tree of Thoughts: Deliberate Problem Solving
|
|
7
|
+
* with Large Language Models", arXiv:2305.10601.
|
|
8
|
+
*
|
|
9
|
+
* Algorithm (paper §3):
|
|
10
|
+
* 1. Build a tree of partial-solution states, root = empty/initial state.
|
|
11
|
+
* 2. Expand each node into up to `branchFactor` children via the generator.
|
|
12
|
+
* 3. Evaluate each state with a lightweight heuristic (no extra LLM call).
|
|
13
|
+
* 4. BFS expands level-by-level; DFS goes depth-first with backtracking
|
|
14
|
+
* when score < pruning threshold.
|
|
15
|
+
* 5. Bound total expansions by `maxCalls` (== generator-call budget).
|
|
16
|
+
* 6. Return the highest-scoring leaf output.
|
|
17
|
+
*
|
|
18
|
+
* Default state-evaluator (no LLM):
|
|
19
|
+
* - string outputs : monotone progress score based on length (caps at 200)
|
|
20
|
+
* - number outputs : closeness to plausible-answer band [0, 100]
|
|
21
|
+
* - other : 0.5 (neutral)
|
|
22
|
+
*
|
|
23
|
+
* @experimental Public-experimental API per `contract-stability.md` (sprint-582).
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
import type { ComputeContext, Strategy, StrategyResult } from "../types.js";
|
|
27
|
+
|
|
28
|
+
// ─── Public types ────────────────────────────────────────────────────────────
|
|
29
|
+
|
|
30
|
+
export type ToTSearchPolicy = "bfs" | "dfs";
|
|
31
|
+
|
|
32
|
+
export interface ToTConfig {
|
|
33
|
+
/** BFS or DFS. Default: "bfs". */
|
|
34
|
+
searchPolicy: ToTSearchPolicy;
|
|
35
|
+
/** Max tree depth (steps). Default: 3. */
|
|
36
|
+
maxDepth: number;
|
|
37
|
+
/** Max branching factor (children per node). Default: 3. */
|
|
38
|
+
branchFactor: number;
|
|
39
|
+
/** Hard cap on total generator calls. Default: maxDepth * branchFactor. */
|
|
40
|
+
maxCalls: number;
|
|
41
|
+
/** State evaluator → score in [0,1]. Default: heuristic on output shape. */
|
|
42
|
+
evaluateState?: (state: unknown) => number;
|
|
43
|
+
/** Prune any node whose evaluator score is below this. Default: 0.2. */
|
|
44
|
+
pruneThreshold: number;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const STRATEGY_NAME = "tree-of-thoughts";
|
|
48
|
+
|
|
49
|
+
const VALID_POLICIES: ReadonlySet<string> = new Set(["bfs", "dfs"]);
|
|
50
|
+
|
|
51
|
+
// ─── Default evaluator ───────────────────────────────────────────────────────
|
|
52
|
+
|
|
53
|
+
function defaultEvaluator(state: unknown): number {
|
|
54
|
+
if (typeof state === "string") {
|
|
55
|
+
const len = state.length;
|
|
56
|
+
if (len === 0) return 0;
|
|
57
|
+
// Monotone, saturates at 200 chars → 1.0
|
|
58
|
+
return Math.min(1, len / 200);
|
|
59
|
+
}
|
|
60
|
+
if (typeof state === "number" && Number.isFinite(state)) {
|
|
61
|
+
if (state < 0 || state > 200) return 0.1;
|
|
62
|
+
// Centered around 50 for plausibility (synthetic-task heuristic)
|
|
63
|
+
return 0.5 + 0.5 * (1 / (1 + Math.abs(state - 50)));
|
|
64
|
+
}
|
|
65
|
+
return 0.5;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// ─── Helpers ─────────────────────────────────────────────────────────────────
|
|
69
|
+
|
|
70
|
+
function throwIfAborted(signal: AbortSignal | undefined): void {
|
|
71
|
+
if (signal?.aborted) {
|
|
72
|
+
throw signal.reason instanceof Error
|
|
73
|
+
? signal.reason
|
|
74
|
+
: new DOMException("Aborted", "AbortError");
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
interface TreeNode<O> {
|
|
79
|
+
state: O;
|
|
80
|
+
depth: number;
|
|
81
|
+
score: number;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// ─── Strategy factory ────────────────────────────────────────────────────────
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Construct a Tree-of-Thoughts {@link Strategy}.
|
|
88
|
+
*
|
|
89
|
+
* @throws RangeError when `maxDepth`, `branchFactor`, or `maxCalls` is < 1.
|
|
90
|
+
* @throws Error when `searchPolicy` is not "bfs" or "dfs".
|
|
91
|
+
*/
|
|
92
|
+
export function treeOfThoughtsStrategy<TInput, TOutput>(
|
|
93
|
+
config?: Partial<ToTConfig>,
|
|
94
|
+
): Strategy<TInput, TOutput> {
|
|
95
|
+
const searchPolicy: ToTSearchPolicy = config?.searchPolicy ?? "bfs";
|
|
96
|
+
const maxDepth = config?.maxDepth ?? 3;
|
|
97
|
+
const branchFactor = config?.branchFactor ?? 3;
|
|
98
|
+
const maxCalls = config?.maxCalls ?? maxDepth * branchFactor;
|
|
99
|
+
const pruneThreshold = config?.pruneThreshold ?? 0.2;
|
|
100
|
+
const evaluateState = config?.evaluateState ?? defaultEvaluator;
|
|
101
|
+
|
|
102
|
+
if (!Number.isInteger(maxDepth) || maxDepth < 1) {
|
|
103
|
+
throw new RangeError(`treeOfThoughtsStrategy: maxDepth must be >=1, got ${maxDepth}`);
|
|
104
|
+
}
|
|
105
|
+
if (!Number.isInteger(branchFactor) || branchFactor < 1) {
|
|
106
|
+
throw new RangeError(`treeOfThoughtsStrategy: branchFactor must be >=1, got ${branchFactor}`);
|
|
107
|
+
}
|
|
108
|
+
if (!Number.isInteger(maxCalls) || maxCalls < 1) {
|
|
109
|
+
throw new RangeError(`treeOfThoughtsStrategy: maxCalls must be >=1, got ${maxCalls}`);
|
|
110
|
+
}
|
|
111
|
+
if (!VALID_POLICIES.has(searchPolicy)) {
|
|
112
|
+
throw new Error(
|
|
113
|
+
`treeOfThoughtsStrategy: searchPolicy must be "bfs" or "dfs", got "${searchPolicy}"`,
|
|
114
|
+
);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const strategyLabel = `${STRATEGY_NAME}-${searchPolicy}`;
|
|
118
|
+
|
|
119
|
+
return {
|
|
120
|
+
name: strategyLabel,
|
|
121
|
+
|
|
122
|
+
async run(
|
|
123
|
+
input: TInput,
|
|
124
|
+
generator: (input: TInput, ctx: ComputeContext) => Promise<TOutput>,
|
|
125
|
+
ctx: ComputeContext = {},
|
|
126
|
+
): Promise<StrategyResult<TOutput>> {
|
|
127
|
+
const start = performance.now();
|
|
128
|
+
const signal = ctx.signal;
|
|
129
|
+
throwIfAborted(signal);
|
|
130
|
+
|
|
131
|
+
const childCtx: ComputeContext = signal ? { signal } : {};
|
|
132
|
+
|
|
133
|
+
let callsUsed = 0;
|
|
134
|
+
const allLeaves: TreeNode<TOutput>[] = [];
|
|
135
|
+
const allScores: number[] = [];
|
|
136
|
+
|
|
137
|
+
// Helper: expand one parent into up to branchFactor children.
|
|
138
|
+
// Each child = 1 generator call.
|
|
139
|
+
const expandNode = async (
|
|
140
|
+
_parent: TreeNode<TOutput> | null,
|
|
141
|
+
depth: number,
|
|
142
|
+
): Promise<TreeNode<TOutput>[]> => {
|
|
143
|
+
const childrenToMake = Math.min(branchFactor, maxCalls - callsUsed);
|
|
144
|
+
if (childrenToMake <= 0) return [];
|
|
145
|
+
|
|
146
|
+
// Parallel sampling at this level.
|
|
147
|
+
throwIfAborted(signal);
|
|
148
|
+
const samples = await Promise.all(
|
|
149
|
+
Array.from({ length: childrenToMake }, () => generator(input, childCtx)),
|
|
150
|
+
);
|
|
151
|
+
callsUsed += childrenToMake;
|
|
152
|
+
|
|
153
|
+
const nodes: TreeNode<TOutput>[] = samples.map((state) => {
|
|
154
|
+
const score = clamp01(evaluateState(state));
|
|
155
|
+
return { state, depth, score };
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
for (const n of nodes) allScores.push(n.score);
|
|
159
|
+
|
|
160
|
+
// Pruned nodes are still recorded as leaves (score known) but not expanded.
|
|
161
|
+
return nodes;
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
if (searchPolicy === "bfs") {
|
|
165
|
+
// ── BFS ───────────────────────────────────────────────────────────
|
|
166
|
+
let frontier: TreeNode<TOutput>[] = [];
|
|
167
|
+
|
|
168
|
+
// Depth-1 children from root.
|
|
169
|
+
const initial = await expandNode(null, 1);
|
|
170
|
+
frontier = initial;
|
|
171
|
+
// Leaves at maxDepth or pruned go into allLeaves.
|
|
172
|
+
for (const n of initial) {
|
|
173
|
+
if (n.depth >= maxDepth || n.score < pruneThreshold) {
|
|
174
|
+
allLeaves.push(n);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
while (frontier.length > 0 && callsUsed < maxCalls) {
|
|
179
|
+
// Filter out pruned/leaf nodes — only expand survivors.
|
|
180
|
+
const survivors = frontier.filter((n) => n.score >= pruneThreshold && n.depth < maxDepth);
|
|
181
|
+
if (survivors.length === 0) break;
|
|
182
|
+
|
|
183
|
+
const nextFrontier: TreeNode<TOutput>[] = [];
|
|
184
|
+
for (const parent of survivors) {
|
|
185
|
+
if (callsUsed >= maxCalls) break;
|
|
186
|
+
const children = await expandNode(parent, parent.depth + 1);
|
|
187
|
+
for (const c of children) {
|
|
188
|
+
if (c.depth >= maxDepth || c.score < pruneThreshold) {
|
|
189
|
+
allLeaves.push(c);
|
|
190
|
+
} else {
|
|
191
|
+
nextFrontier.push(c);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// If BFS terminates with un-expanded frontier (budget hit), those are leaves too.
|
|
197
|
+
if (callsUsed >= maxCalls) {
|
|
198
|
+
for (const n of nextFrontier) allLeaves.push(n);
|
|
199
|
+
break;
|
|
200
|
+
}
|
|
201
|
+
frontier = nextFrontier;
|
|
202
|
+
}
|
|
203
|
+
// Any remaining frontier nodes at end-of-budget = leaves.
|
|
204
|
+
for (const n of frontier) {
|
|
205
|
+
if (!allLeaves.includes(n)) allLeaves.push(n);
|
|
206
|
+
}
|
|
207
|
+
} else {
|
|
208
|
+
// ── DFS with backtracking ─────────────────────────────────────────
|
|
209
|
+
const stack: TreeNode<TOutput>[] = [];
|
|
210
|
+
const initial = await expandNode(null, 1);
|
|
211
|
+
// Push so highest score is explored first.
|
|
212
|
+
const sortedInitial = [...initial].sort((a, b) => b.score - a.score);
|
|
213
|
+
stack.push(...sortedInitial.reverse()); // reverse so highest pops first
|
|
214
|
+
|
|
215
|
+
for (const n of initial) {
|
|
216
|
+
if (n.depth >= maxDepth || n.score < pruneThreshold) {
|
|
217
|
+
allLeaves.push(n);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
while (stack.length > 0 && callsUsed < maxCalls) {
|
|
222
|
+
const node = stack.pop();
|
|
223
|
+
if (!node) break;
|
|
224
|
+
// Backtrack if pruned or terminal.
|
|
225
|
+
if (node.score < pruneThreshold || node.depth >= maxDepth) {
|
|
226
|
+
// Already recorded as leaf above (or will be).
|
|
227
|
+
if (!allLeaves.includes(node)) allLeaves.push(node);
|
|
228
|
+
continue;
|
|
229
|
+
}
|
|
230
|
+
// Expand survivor.
|
|
231
|
+
const children = await expandNode(node, node.depth + 1);
|
|
232
|
+
const sortedChildren = [...children].sort((a, b) => b.score - a.score);
|
|
233
|
+
for (const c of sortedChildren.reverse()) {
|
|
234
|
+
if (c.depth >= maxDepth || c.score < pruneThreshold) {
|
|
235
|
+
allLeaves.push(c);
|
|
236
|
+
} else {
|
|
237
|
+
stack.push(c);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
// Any unexplored stack nodes = leaves (budget-bound).
|
|
242
|
+
for (const n of stack) {
|
|
243
|
+
if (!allLeaves.includes(n)) allLeaves.push(n);
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
// ── Pick highest-scoring leaf ─────────────────────────────────────
|
|
248
|
+
if (allLeaves.length === 0) {
|
|
249
|
+
// Should never happen: root expansion always produces ≥1 leaf
|
|
250
|
+
// unless maxCalls=0 (which we reject). Defensive fallback.
|
|
251
|
+
const fallback = await generator(input, childCtx);
|
|
252
|
+
callsUsed++;
|
|
253
|
+
allScores.push(clamp01(evaluateState(fallback)));
|
|
254
|
+
const latency_ms = performance.now() - start;
|
|
255
|
+
return {
|
|
256
|
+
result: fallback,
|
|
257
|
+
metadata: {
|
|
258
|
+
strategy: strategyLabel,
|
|
259
|
+
candidates: 1,
|
|
260
|
+
verifier_scores: allScores,
|
|
261
|
+
cost: { calls: callsUsed },
|
|
262
|
+
latency_ms,
|
|
263
|
+
},
|
|
264
|
+
};
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
let best = allLeaves[0];
|
|
268
|
+
for (let i = 1; i < allLeaves.length; i++) {
|
|
269
|
+
const n = allLeaves[i] as TreeNode<TOutput>;
|
|
270
|
+
if (n.score > best.score) best = n;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
const latency_ms = performance.now() - start;
|
|
274
|
+
return {
|
|
275
|
+
result: best.state,
|
|
276
|
+
metadata: {
|
|
277
|
+
strategy: strategyLabel,
|
|
278
|
+
candidates: callsUsed,
|
|
279
|
+
verifier_scores: allScores,
|
|
280
|
+
cost: { calls: callsUsed },
|
|
281
|
+
latency_ms,
|
|
282
|
+
},
|
|
283
|
+
};
|
|
284
|
+
},
|
|
285
|
+
};
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
function clamp01(x: number): number {
|
|
289
|
+
if (!Number.isFinite(x)) return 0;
|
|
290
|
+
if (x < 0) return 0;
|
|
291
|
+
if (x > 1) return 1;
|
|
292
|
+
return x;
|
|
293
|
+
}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* src/compute/strategies/two-phase-orient.ts
|
|
3
|
+
*
|
|
4
|
+
* Two-Phase Orient pattern.
|
|
5
|
+
*
|
|
6
|
+
* Phase 1 — Orient: read-only context gathering, produces an orientation state.
|
|
7
|
+
* Phase 2 — Act: state-mutating execution driven by the orientation.
|
|
8
|
+
*
|
|
9
|
+
* The separation enforces a hard OODA discipline:
|
|
10
|
+
* - Phase 1 has no side effects; it may be retried cheaply on failure.
|
|
11
|
+
* - Phase 2 consumes the orientation and may be retried up to `maxActRetries`.
|
|
12
|
+
*
|
|
13
|
+
* Error semantics:
|
|
14
|
+
* - `TwoPhaseOrientError` (phase: "orient") — Phase 1 threw; Phase 2 is never reached.
|
|
15
|
+
* - `TwoPhaseOrientError` (phase: "act") — Phase 2 exhausted all retries.
|
|
16
|
+
* - Each Phase 2 retry attempt is tracked in `retriesUsed` (0 = first attempt succeeded).
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
// ---------------------------------------------------------------------------
|
|
20
|
+
// Error
|
|
21
|
+
// ---------------------------------------------------------------------------
|
|
22
|
+
|
|
23
|
+
export class TwoPhaseOrientError extends Error {
|
|
24
|
+
readonly phase: "orient" | "act";
|
|
25
|
+
readonly cause: unknown;
|
|
26
|
+
readonly retriesUsed: number;
|
|
27
|
+
|
|
28
|
+
constructor(
|
|
29
|
+
phase: "orient" | "act",
|
|
30
|
+
cause: unknown,
|
|
31
|
+
retriesUsed: number,
|
|
32
|
+
message: string
|
|
33
|
+
) {
|
|
34
|
+
super(message);
|
|
35
|
+
this.name = "TwoPhaseOrientError";
|
|
36
|
+
this.phase = phase;
|
|
37
|
+
this.cause = cause;
|
|
38
|
+
this.retriesUsed = retriesUsed;
|
|
39
|
+
// Restore prototype chain (tsc targets < ES2022)
|
|
40
|
+
Object.setPrototypeOf(this, TwoPhaseOrientError.prototype);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// ---------------------------------------------------------------------------
|
|
45
|
+
// Config + return type
|
|
46
|
+
// ---------------------------------------------------------------------------
|
|
47
|
+
|
|
48
|
+
export interface TwoPhaseOrientConfig<C, O, R> {
|
|
49
|
+
/**
|
|
50
|
+
* Phase 1: orientation (read-only, observe + analyse).
|
|
51
|
+
* Receives the raw context and returns an orientation state.
|
|
52
|
+
* Must not produce observable side effects.
|
|
53
|
+
*/
|
|
54
|
+
orient: (context: C) => Promise<O>;
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Phase 2: act on the orientation.
|
|
58
|
+
* Receives both the orientation produced by Phase 1 and the original context.
|
|
59
|
+
* Returns the final result.
|
|
60
|
+
*/
|
|
61
|
+
act: (orientation: O, context: C) => Promise<R>;
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Maximum number of times Phase 2 may be retried after a recoverable failure.
|
|
65
|
+
* `maxActRetries = 1` means one initial attempt + one retry = 2 total attempts.
|
|
66
|
+
* Default: 1.
|
|
67
|
+
* Must be a non-negative integer; values < 0 are treated as 0.
|
|
68
|
+
*/
|
|
69
|
+
maxActRetries?: number;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export interface TwoPhaseOrientResult<O, R> {
|
|
73
|
+
orientation: O;
|
|
74
|
+
result: R;
|
|
75
|
+
/** Number of Phase-2 retries consumed (0 = succeeded on first attempt). */
|
|
76
|
+
retriesUsed: number;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// ---------------------------------------------------------------------------
|
|
80
|
+
// Implementation
|
|
81
|
+
// ---------------------------------------------------------------------------
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Executes the Two-Phase Orient pattern.
|
|
85
|
+
*
|
|
86
|
+
* @param config Wiring for both phases + optional retry cap.
|
|
87
|
+
* @param context Opaque context forwarded to both `orient` and `act`.
|
|
88
|
+
*
|
|
89
|
+
* @throws {TwoPhaseOrientError} When Phase 1 throws (phase: "orient") or
|
|
90
|
+
* Phase 2 exhausts all retries (phase: "act").
|
|
91
|
+
*
|
|
92
|
+
* @example
|
|
93
|
+
* ```ts
|
|
94
|
+
* const { orientation, result, retriesUsed } = await runTwoPhaseOrient(
|
|
95
|
+
* {
|
|
96
|
+
* orient: async (ctx) => await gatherSignals(ctx),
|
|
97
|
+
* act: async (orient, ctx) => await executeDecision(orient, ctx),
|
|
98
|
+
* },
|
|
99
|
+
* requestContext,
|
|
100
|
+
* );
|
|
101
|
+
* ```
|
|
102
|
+
*/
|
|
103
|
+
export async function runTwoPhaseOrient<C, O, R>(
|
|
104
|
+
config: TwoPhaseOrientConfig<C, O, R>,
|
|
105
|
+
context: C
|
|
106
|
+
): Promise<TwoPhaseOrientResult<O, R>> {
|
|
107
|
+
const maxRetries = Math.max(0, Math.floor(config.maxActRetries ?? 1));
|
|
108
|
+
|
|
109
|
+
// ── Phase 1: Orient ───────────────────────────────────────────────────────
|
|
110
|
+
let orientation: O;
|
|
111
|
+
try {
|
|
112
|
+
orientation = await config.orient(context);
|
|
113
|
+
} catch (err) {
|
|
114
|
+
throw new TwoPhaseOrientError(
|
|
115
|
+
"orient",
|
|
116
|
+
err,
|
|
117
|
+
0,
|
|
118
|
+
`TwoPhaseOrient Phase 1 (orient) failed: ${
|
|
119
|
+
err instanceof Error ? err.message : String(err)
|
|
120
|
+
}`
|
|
121
|
+
);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// ── Phase 2: Act (with retries) ───────────────────────────────────────────
|
|
125
|
+
let lastActError: unknown;
|
|
126
|
+
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
127
|
+
try {
|
|
128
|
+
const result = await config.act(orientation, context);
|
|
129
|
+
return { orientation, result, retriesUsed: attempt };
|
|
130
|
+
} catch (err) {
|
|
131
|
+
lastActError = err;
|
|
132
|
+
// Continue to next attempt if retries remain.
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// All attempts exhausted.
|
|
137
|
+
throw new TwoPhaseOrientError(
|
|
138
|
+
"act",
|
|
139
|
+
lastActError,
|
|
140
|
+
maxRetries,
|
|
141
|
+
`TwoPhaseOrient Phase 2 (act) failed after ${maxRetries + 1} attempt(s): ${
|
|
142
|
+
lastActError instanceof Error
|
|
143
|
+
? lastActError.message
|
|
144
|
+
: String(lastActError)
|
|
145
|
+
}`
|
|
146
|
+
);
|
|
147
|
+
}
|
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Container Execution Protocol — standard contract for running automations
|
|
3
|
+
* inside containers or as local binaries.
|
|
4
|
+
*
|
|
5
|
+
* Contract:
|
|
6
|
+
*
|
|
7
|
+
* Input (via env vars):
|
|
8
|
+
* VAUBAN_EXECUTION_ID — unique execution identifier (UUID)
|
|
9
|
+
* VAUBAN_AUTOMATION_NAME — automation name (kebab-case)
|
|
10
|
+
* VAUBAN_INPUT — JSON-encoded input parameters
|
|
11
|
+
* VAUBAN_TIMEOUT — timeout in seconds
|
|
12
|
+
* VAUBAN_MODE — execution mode (default: "execute")
|
|
13
|
+
*
|
|
14
|
+
* Output (via stdout, last non-empty line, JSON):
|
|
15
|
+
* { "status": "completed", "output": <any> }
|
|
16
|
+
* { "status": "failed", "error": { "code": "...", "message": "...", "details"?: <any> } }
|
|
17
|
+
*
|
|
18
|
+
* Diagnostics (via stderr, optional, one JSON object per line):
|
|
19
|
+
* { "level": "info", "message": "...", "timestamp": "..." }
|
|
20
|
+
* { "progress": 0.5, "message": "..." }
|
|
21
|
+
*
|
|
22
|
+
* @public @since 1.2.0
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Reserved environment variable names. All caller env merged on top must NOT
|
|
27
|
+
* shadow these keys, or the automation's view of its own context becomes
|
|
28
|
+
* undefined.
|
|
29
|
+
*
|
|
30
|
+
* @public
|
|
31
|
+
*/
|
|
32
|
+
export const PROTOCOL_ENV = {
|
|
33
|
+
EXECUTION_ID: "VAUBAN_EXECUTION_ID",
|
|
34
|
+
AUTOMATION_NAME: "VAUBAN_AUTOMATION_NAME",
|
|
35
|
+
INPUT: "VAUBAN_INPUT",
|
|
36
|
+
TIMEOUT: "VAUBAN_TIMEOUT",
|
|
37
|
+
MODE: "VAUBAN_MODE",
|
|
38
|
+
} as const;
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Default protocol mode set when caller does not specify one.
|
|
42
|
+
* @public
|
|
43
|
+
*/
|
|
44
|
+
export const DEFAULT_PROTOCOL_MODE = "execute";
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Final status reported by a container/binary on stdout.
|
|
48
|
+
* @public
|
|
49
|
+
*/
|
|
50
|
+
export type ProtocolStatus = "completed" | "failed";
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Discriminated union of protocol outputs parsed from stdout.
|
|
54
|
+
* @public
|
|
55
|
+
*/
|
|
56
|
+
export type ProtocolResult<T = unknown> =
|
|
57
|
+
| { readonly status: "completed"; readonly output: T }
|
|
58
|
+
| {
|
|
59
|
+
readonly status: "failed";
|
|
60
|
+
readonly error: {
|
|
61
|
+
readonly code: string;
|
|
62
|
+
readonly message: string;
|
|
63
|
+
readonly details?: unknown;
|
|
64
|
+
};
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Outcome of an execution attempt, combining protocol result with timing,
|
|
69
|
+
* captured logs, and propagated metadata.
|
|
70
|
+
*
|
|
71
|
+
* @public
|
|
72
|
+
*/
|
|
73
|
+
export interface ExecutionResult<T = unknown> {
|
|
74
|
+
readonly executionId: string;
|
|
75
|
+
readonly automationName: string;
|
|
76
|
+
readonly status: "completed" | "failed" | "timeout";
|
|
77
|
+
readonly input: unknown;
|
|
78
|
+
readonly output?: T;
|
|
79
|
+
readonly error?: {
|
|
80
|
+
code: string;
|
|
81
|
+
message: string;
|
|
82
|
+
details?: unknown;
|
|
83
|
+
};
|
|
84
|
+
readonly startedAt: Date;
|
|
85
|
+
readonly completedAt: Date;
|
|
86
|
+
readonly durationMs: number;
|
|
87
|
+
readonly logs: ReadonlyArray<{
|
|
88
|
+
readonly level: string;
|
|
89
|
+
readonly message: string;
|
|
90
|
+
readonly timestamp: string;
|
|
91
|
+
}>;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Thrown when stdout does not contain a parseable protocol result on its last
|
|
96
|
+
* non-empty line.
|
|
97
|
+
*
|
|
98
|
+
* @public
|
|
99
|
+
*/
|
|
100
|
+
export class ProtocolParseError extends Error {
|
|
101
|
+
readonly rawTail: string;
|
|
102
|
+
constructor(reason: string, rawTail: string) {
|
|
103
|
+
super(`container-protocol: ${reason}`);
|
|
104
|
+
this.name = "ProtocolParseError";
|
|
105
|
+
this.rawTail = rawTail;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Build the protocol's environment variables. Caller `extraEnv` is merged
|
|
111
|
+
* AFTER protocol env, so it cannot accidentally override reserved keys.
|
|
112
|
+
*
|
|
113
|
+
* @public
|
|
114
|
+
*/
|
|
115
|
+
export function buildProtocolEnv(args: {
|
|
116
|
+
executionId: string;
|
|
117
|
+
automationName: string;
|
|
118
|
+
input: unknown;
|
|
119
|
+
timeoutSeconds: number;
|
|
120
|
+
mode?: string;
|
|
121
|
+
extraEnv?: Readonly<Record<string, string>>;
|
|
122
|
+
}): Record<string, string> {
|
|
123
|
+
const env: Record<string, string> = {};
|
|
124
|
+
if (args.extraEnv) {
|
|
125
|
+
for (const [k, v] of Object.entries(args.extraEnv)) {
|
|
126
|
+
env[k] = v;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
env[PROTOCOL_ENV.EXECUTION_ID] = args.executionId;
|
|
130
|
+
env[PROTOCOL_ENV.AUTOMATION_NAME] = args.automationName;
|
|
131
|
+
env[PROTOCOL_ENV.INPUT] = JSON.stringify(args.input);
|
|
132
|
+
env[PROTOCOL_ENV.TIMEOUT] = String(args.timeoutSeconds);
|
|
133
|
+
env[PROTOCOL_ENV.MODE] = args.mode ?? DEFAULT_PROTOCOL_MODE;
|
|
134
|
+
return env;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Parse the last non-empty line of stdout as a {@link ProtocolResult}.
|
|
139
|
+
*
|
|
140
|
+
* @throws {@link ProtocolParseError} when stdout is empty, has no JSON tail,
|
|
141
|
+
* or the JSON does not match the protocol shape.
|
|
142
|
+
*
|
|
143
|
+
* @public
|
|
144
|
+
*/
|
|
145
|
+
export function parseProtocolOutput<T = unknown>(
|
|
146
|
+
stdout: string
|
|
147
|
+
): ProtocolResult<T> {
|
|
148
|
+
const trimmed = stdout.trim();
|
|
149
|
+
if (trimmed.length === 0) {
|
|
150
|
+
throw new ProtocolParseError("stdout is empty", "");
|
|
151
|
+
}
|
|
152
|
+
const lines = trimmed.split("\n");
|
|
153
|
+
const lastLine = lines[lines.length - 1]!.trim();
|
|
154
|
+
if (lastLine.length === 0) {
|
|
155
|
+
throw new ProtocolParseError(
|
|
156
|
+
"last stdout line is empty",
|
|
157
|
+
trimmed.slice(-200)
|
|
158
|
+
);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
let parsed: unknown;
|
|
162
|
+
try {
|
|
163
|
+
parsed = JSON.parse(lastLine);
|
|
164
|
+
} catch {
|
|
165
|
+
throw new ProtocolParseError(
|
|
166
|
+
"last stdout line is not valid JSON",
|
|
167
|
+
lastLine.slice(0, 500)
|
|
168
|
+
);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
if (typeof parsed !== "object" || parsed === null || !("status" in parsed)) {
|
|
172
|
+
throw new ProtocolParseError(
|
|
173
|
+
"protocol JSON missing 'status' field",
|
|
174
|
+
lastLine.slice(0, 500)
|
|
175
|
+
);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
const obj = parsed as Record<string, unknown>;
|
|
179
|
+
const status = obj["status"];
|
|
180
|
+
|
|
181
|
+
if (status === "completed") {
|
|
182
|
+
return { status: "completed", output: (obj["output"] ?? null) as T };
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
if (status === "failed") {
|
|
186
|
+
const err = (obj["error"] as Record<string, unknown> | undefined) ?? {};
|
|
187
|
+
const code =
|
|
188
|
+
typeof err["code"] === "string" ? (err["code"] as string) : "UNKNOWN";
|
|
189
|
+
const message =
|
|
190
|
+
typeof err["message"] === "string"
|
|
191
|
+
? (err["message"] as string)
|
|
192
|
+
: "(no message)";
|
|
193
|
+
const details = err["details"];
|
|
194
|
+
return { status: "failed", error: { code, message, details } };
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
throw new ProtocolParseError(
|
|
198
|
+
`unknown protocol status: ${String(status)}`,
|
|
199
|
+
lastLine.slice(0, 500)
|
|
200
|
+
);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* Parse stderr lines as JSON log entries when possible; fall back to plain
|
|
205
|
+
* text wrapped at level "info". Used by {@link ContainerRuntime} to populate
|
|
206
|
+
* `ExecutionResult.logs`.
|
|
207
|
+
*
|
|
208
|
+
* @public
|
|
209
|
+
*/
|
|
210
|
+
export function parseStderrLogs(stderr: string): Array<{
|
|
211
|
+
level: string;
|
|
212
|
+
message: string;
|
|
213
|
+
timestamp: string;
|
|
214
|
+
}> {
|
|
215
|
+
const logs: Array<{ level: string; message: string; timestamp: string }> = [];
|
|
216
|
+
const lines = stderr.split("\n");
|
|
217
|
+
for (const raw of lines) {
|
|
218
|
+
const line = raw.trim();
|
|
219
|
+
if (line.length === 0) continue;
|
|
220
|
+
try {
|
|
221
|
+
const obj = JSON.parse(line) as Record<string, unknown>;
|
|
222
|
+
logs.push({
|
|
223
|
+
level:
|
|
224
|
+
typeof obj["level"] === "string" ? (obj["level"] as string) : "info",
|
|
225
|
+
message:
|
|
226
|
+
typeof obj["message"] === "string"
|
|
227
|
+
? (obj["message"] as string)
|
|
228
|
+
: line.slice(0, 500),
|
|
229
|
+
timestamp:
|
|
230
|
+
typeof obj["timestamp"] === "string"
|
|
231
|
+
? (obj["timestamp"] as string)
|
|
232
|
+
: new Date().toISOString(),
|
|
233
|
+
});
|
|
234
|
+
} catch {
|
|
235
|
+
logs.push({
|
|
236
|
+
level: "info",
|
|
237
|
+
message: line.slice(0, 500),
|
|
238
|
+
timestamp: new Date().toISOString(),
|
|
239
|
+
});
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
return logs;
|
|
243
|
+
}
|