@cohortapp/agent-sdk 2.16.0 → 2.18.4
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/.claude/settings.json +18 -0
- package/.env.example +23 -7
- package/README.md +1 -0
- package/bin/maestro.mjs +62 -0
- package/docs/guides/billing-console-keys.md +60 -0
- package/docs/guides/front-door-session.md +54 -9
- package/docs/guides/mac-mini.md +20 -25
- package/docs/guides/poller-daemon-setup.md +4 -1
- package/docs/guides/setup-wizard.md +1 -1
- package/docs/runbooks/fleet-rollout.md +156 -0
- package/docs/runbooks/mac-mini-bootstrap.md +12 -14
- package/lib/action-executor.js +19 -3
- package/lib/budget-guard.mjs +279 -3
- package/lib/channels/base-adapter.mjs +3 -1
- package/lib/channels/contract.mjs +2 -1
- package/lib/channels/inbox-item.mjs +8 -0
- package/lib/claude-bin.mjs +5 -6
- package/lib/cli/doctor-checks.mjs +141 -10
- package/lib/cli/global-setup-extras.mjs +5 -1
- package/lib/cli/inbox.mjs +100 -15
- package/lib/cli/seat-auth.mjs +463 -0
- package/lib/cli/session.mjs +80 -12
- package/lib/collective/capture.mjs +8 -6
- package/lib/collective/global-config.mjs +63 -1
- package/lib/collective/presence.mjs +142 -5
- package/lib/comms/send-gate.mjs +559 -1
- package/lib/context/budget.mjs +327 -0
- package/lib/context/history-scope.mjs +138 -0
- package/lib/diagnostics/alerts.mjs +49 -0
- package/lib/diagnostics/cadence-output-freshness.mjs +288 -0
- package/lib/engine/agents/definitions.mjs +343 -0
- package/lib/engine/agents/persist.mjs +275 -0
- package/lib/engine/agents/runtime.mjs +748 -0
- package/lib/engine/agents/usage.mjs +95 -0
- package/lib/engine/auth-status.mjs +139 -0
- package/lib/engine/budget.mjs +194 -0
- package/lib/engine/cli.mjs +1204 -0
- package/lib/engine/commands/index.mjs +269 -0
- package/lib/engine/context/budget.mjs +219 -0
- package/lib/engine/context/cache.mjs +125 -0
- package/lib/engine/context/child-env.mjs +215 -0
- package/lib/engine/context/compaction.mjs +342 -0
- package/lib/engine/context/images.mjs +90 -0
- package/lib/engine/context/instructions.mjs +327 -0
- package/lib/engine/context/lazy-instructions.mjs +169 -0
- package/lib/engine/context/manager.mjs +182 -0
- package/lib/engine/context/real-path.mjs +91 -0
- package/lib/engine/context/secret-values.mjs +163 -0
- package/lib/engine/context/settings.mjs +274 -0
- package/lib/engine/context/stream-input.mjs +159 -0
- package/lib/engine/guard.mjs +152 -0
- package/lib/engine/hooks.mjs +713 -0
- package/lib/engine/loop.mjs +560 -0
- package/lib/engine/mcp/client.mjs +254 -0
- package/lib/engine/mcp/config.mjs +301 -0
- package/lib/engine/mcp/http.mjs +201 -0
- package/lib/engine/mcp/index.mjs +146 -0
- package/lib/engine/mcp/jsonrpc.mjs +147 -0
- package/lib/engine/mcp/naming.mjs +66 -0
- package/lib/engine/mcp/resources.mjs +89 -0
- package/lib/engine/mcp/results.mjs +133 -0
- package/lib/engine/mcp/stdio.mjs +137 -0
- package/lib/engine/mcp/supervisor.mjs +116 -0
- package/lib/engine/messages.mjs +104 -0
- package/lib/engine/output/json.mjs +164 -0
- package/lib/engine/output/stream-json.mjs +266 -0
- package/lib/engine/permissions.mjs +845 -0
- package/lib/engine/process-identity.mjs +164 -0
- package/lib/engine/process-tree.mjs +551 -0
- package/lib/engine/prompt.mjs +60 -0
- package/lib/engine/session/store.mjs +299 -0
- package/lib/engine/session-runtime/args.mjs +97 -0
- package/lib/engine/session-runtime/host.mjs +143 -0
- package/lib/engine/session-runtime/inbox.mjs +122 -0
- package/lib/engine/session-runtime/notifications.mjs +129 -0
- package/lib/engine/session-runtime/registry.mjs +328 -0
- package/lib/engine/session-runtime/runner.mjs +344 -0
- package/lib/engine/session-runtime/socket.mjs +212 -0
- package/lib/engine/session-runtime/wakeup.mjs +115 -0
- package/lib/engine/skills/index.mjs +321 -0
- package/lib/engine/tools/bash-background.mjs +533 -0
- package/lib/engine/tools/bash.mjs +216 -0
- package/lib/engine/tools/edit.mjs +97 -0
- package/lib/engine/tools/glob.mjs +81 -0
- package/lib/engine/tools/grep.mjs +224 -0
- package/lib/engine/tools/index.mjs +84 -0
- package/lib/engine/tools/list-agents.mjs +32 -0
- package/lib/engine/tools/ls.mjs +127 -0
- package/lib/engine/tools/monitor.mjs +82 -0
- package/lib/engine/tools/notebook-edit.mjs +218 -0
- package/lib/engine/tools/read.mjs +103 -0
- package/lib/engine/tools/schedule-wakeup.mjs +45 -0
- package/lib/engine/tools/schema.mjs +144 -0
- package/lib/engine/tools/send-message.mjs +77 -0
- package/lib/engine/tools/session.mjs +70 -0
- package/lib/engine/tools/todo.mjs +144 -0
- package/lib/engine/tools/toolsearch.mjs +217 -0
- package/lib/engine/tools/walk.mjs +193 -0
- package/lib/engine/tools/web-switch.mjs +31 -0
- package/lib/engine/tools/webfetch-html.mjs +387 -0
- package/lib/engine/tools/webfetch-net.mjs +340 -0
- package/lib/engine/tools/webfetch.mjs +198 -0
- package/lib/engine/tools/websearch.mjs +91 -0
- package/lib/engine/tools/workflow.mjs +95 -0
- package/lib/engine/tools/write.mjs +76 -0
- package/lib/engine/tui/line-editor.mjs +137 -0
- package/lib/engine/tui/render.mjs +86 -0
- package/lib/engine/tui/tui.mjs +274 -0
- package/lib/engine/wire/anthropic-messages.mjs +263 -0
- package/lib/engine/wire/effort.mjs +36 -0
- package/lib/engine/wire/errors.mjs +496 -0
- package/lib/engine/wire/http.mjs +441 -0
- package/lib/engine/wire/index.mjs +76 -0
- package/lib/engine/wire/openai-chat.mjs +332 -0
- package/lib/engine/wire/prompt-cache.mjs +79 -0
- package/lib/engine/wire/search.mjs +140 -0
- package/lib/engine/wire/sse.mjs +114 -0
- package/lib/engine/wire/stall.mjs +349 -0
- package/lib/engine/wire/token-provider.mjs +175 -0
- package/lib/engine/wire/usage.mjs +192 -0
- package/lib/engine/workflow/host.mjs +524 -0
- package/lib/engine/workflow/journal.mjs +188 -0
- package/lib/engine/workflow/json-schema.mjs +171 -0
- package/lib/engine/workflow/meta.mjs +329 -0
- package/lib/engine/workflow/notifications.mjs +52 -0
- package/lib/engine/workflow/runtime.mjs +447 -0
- package/lib/engine/workflow/sandbox.mjs +534 -0
- package/lib/engine/workflow/worker.mjs +141 -0
- package/lib/engine/workflow/worktree.mjs +74 -0
- package/lib/execution/disposition.mjs +1 -1
- package/lib/execution/intake.mjs +10 -0
- package/lib/execution/surface-policy.mjs +15 -0
- package/lib/learning/curator.mjs +8 -6
- package/lib/learning/reflect.mjs +8 -6
- package/lib/model-router/catalog/cohort.yaml +137 -0
- package/lib/model-router/catalog.mjs +118 -1
- package/lib/model-router/economics.mjs +9 -0
- package/lib/model-router/failover.mjs +67 -16
- package/lib/model-router/llm-task.mjs +39 -3
- package/lib/model-router/resolve.mjs +95 -3
- package/lib/model-router/spawn.mjs +46 -47
- package/lib/model-router/taxonomy.mjs +126 -4
- package/lib/org/cost-sync.mjs +141 -11
- package/lib/org/inbound/broadcast.mjs +289 -0
- package/lib/org/inbound/collective.mjs +375 -0
- package/lib/org/inbound/directedness.mjs +96 -8
- package/lib/org/inbound/facts.mjs +82 -4
- package/lib/org/inbound/hydrate.mjs +555 -51
- package/lib/org/inbound/project.mjs +22 -0
- package/lib/org/inbound/surfaces.mjs +14 -0
- package/lib/org/llm-token.mjs +879 -0
- package/lib/org/mesh.mjs +61 -0
- package/lib/org/messaging.mjs +3 -1
- package/lib/org/protocol.checksum +1 -1
- package/lib/org/protocol.mjs +15 -0
- package/lib/org/quota.mjs +520 -0
- package/lib/org/tool-surface.mjs +104 -16
- package/lib/org/ui-parity.mjs +16 -1
- package/lib/org/work-ledger.mjs +37 -6
- package/lib/rate-guard.mjs +114 -1
- package/lib/resource-governor.mjs +41 -6
- package/lib/runtime/adapter.mjs +823 -0
- package/lib/runtime/child-env.mjs +191 -0
- package/lib/runtime/legacy-shell-guard.mjs +97 -0
- package/lib/runtime/seat-engine.mjs +162 -0
- package/lib/session/ask-ledger.mjs +271 -0
- package/lib/session/current-work.mjs +676 -0
- package/lib/session/feed-core.mjs +40 -3
- package/lib/session/launch-args.mjs +56 -4
- package/lib/session/status-summary.mjs +26 -9
- package/lib/session/upgrade-notice.mjs +42 -0
- package/lib/setup/claude-probe.mjs +117 -13
- package/lib/setup/enrich.mjs +13 -10
- package/lib/setup/sections/model.mjs +39 -13
- package/lib/telemetry/collect.mjs +208 -9
- package/lib/upgrade/ignored-drift.mjs +105 -0
- package/lib/voice/post-call-brief.mjs +30 -17
- package/package.json +15 -3
- package/plugins/maestro-skills/skills/board-work.md +5 -0
- package/plugins/maestro-skills/skills/inbound-triage.md +56 -15
- package/plugins/maestro-skills/skills/main-session.md +18 -7
- package/scripts/ci/check-tarball-fidelity.mjs +126 -2
- package/scripts/ci/run-tests.mjs +47 -19
- package/scripts/cohort-llm/api-key-helper.mjs +92 -0
- package/scripts/collective/hook-runner.mjs +29 -2
- package/scripts/continuous-monitor.sh +13 -0
- package/scripts/cost/track-claude-usage.mjs +15 -0
- package/scripts/daemon/agent-daemon.mjs +408 -20
- package/scripts/daemon/assurance.mjs +48 -12
- package/scripts/daemon/cadence-consumer.mjs +218 -68
- package/scripts/daemon/cadence-handlers.mjs +73 -4
- package/scripts/daemon/classifier.mjs +75 -26
- package/scripts/daemon/context-compiler.mjs +104 -59
- package/scripts/daemon/deliver.mjs +30 -1
- package/scripts/daemon/dispatcher.mjs +804 -157
- package/scripts/daemon/health.mjs +14 -1
- package/scripts/daemon/lib/session-router.mjs +310 -42
- package/scripts/daemon/maestro-daemon.mjs +11 -0
- package/scripts/daemon/prompt-builder.mjs +121 -12
- package/scripts/daemon/responder.mjs +315 -146
- package/scripts/daemon/sdk-version.mjs +98 -16
- package/scripts/eval/probe-gateway.mjs +635 -0
- package/scripts/eval/replay/extract.mjs +270 -0
- package/scripts/eval/replay/grade.mjs +260 -0
- package/scripts/eval/replay/lib/config.mjs +50 -0
- package/scripts/eval/replay/lib/effects.mjs +65 -0
- package/scripts/eval/replay/lib/fixture.mjs +188 -0
- package/scripts/eval/replay/lib/judge.mjs +72 -0
- package/scripts/eval/replay/lib/redact.mjs +136 -0
- package/scripts/eval/replay/lib/sandbox.mjs +170 -0
- package/scripts/eval/replay/lib/schema-check.mjs +63 -0
- package/scripts/eval/replay/lib/transcript.mjs +76 -0
- package/scripts/eval/replay/mcp-replay-stub.mjs +101 -0
- package/scripts/eval/replay/report.mjs +185 -0
- package/scripts/eval/replay/run.mjs +404 -0
- package/scripts/fleet/rollout.mjs +1094 -0
- package/scripts/hooks/pre-send-audit.sh +36 -245
- package/scripts/hooks/pre-write-yaml-validate.mjs +275 -0
- package/scripts/hooks/validate-state-yaml.sh +190 -0
- package/scripts/huddle/huddle-llm.mjs +361 -0
- package/scripts/huddle/huddle-server.mjs +46 -121
- package/scripts/local-triggers/autoupdate.sh +448 -78
- package/scripts/local-triggers/run-trigger.sh +13 -0
- package/scripts/maintenance/pin-integrity.mjs +364 -0
- package/scripts/poll-slack-events.sh +41 -9
- package/scripts/poller/slack-socket-mode.mjs +28 -3
- package/scripts/session/supervisor.mjs +80 -13
- package/scripts/spawn-session.sh +13 -0
- package/bin/maestro.test.mjs +0 -1574
- package/lib/action-executor.test.mjs +0 -871
- package/lib/archetype.test.mjs +0 -132
- package/lib/assurance/plan-note.test.mjs +0 -234
- package/lib/assurance/room-budget.test.mjs +0 -486
- package/lib/assurance/tier.test.mjs +0 -174
- package/lib/autonomy.test.mjs +0 -66
- package/lib/backlog.test.mjs +0 -302
- package/lib/backup/policy.test.mjs +0 -305
- package/lib/budget-escalate.test.mjs +0 -232
- package/lib/budget-guard.envelope.test.mjs +0 -476
- package/lib/budget-guard.test.mjs +0 -427
- package/lib/cadence-bus-requeue.test.mjs +0 -83
- package/lib/cadence-bus-schedule.test.mjs +0 -194
- package/lib/cadence-bus.test.mjs +0 -720
- package/lib/cadences.test.mjs +0 -230
- package/lib/capability/inventory.test.mjs +0 -232
- package/lib/capability.test.mjs +0 -78
- package/lib/channels/base-adapter.test.mjs +0 -590
- package/lib/channels/channels.test.mjs +0 -371
- package/lib/channels/contract.test.mjs +0 -162
- package/lib/channels/inbox-item.test.mjs +0 -368
- package/lib/channels/orgmail/adapter.test.mjs +0 -448
- package/lib/channels/pairing.test.mjs +0 -270
- package/lib/channels/repeat-suppressor.test.mjs +0 -134
- package/lib/channels/slack-adapter.test.mjs +0 -212
- package/lib/channels/telegram-adapter.test.mjs +0 -306
- package/lib/channels/voice/adapter.test.mjs +0 -278
- package/lib/channels/whatsapp/adapter-baileys.test.mjs +0 -359
- package/lib/channels/whatsapp/baileys-typing.test.mjs +0 -154
- package/lib/charter.test.mjs +0 -89
- package/lib/claude-bin.test.mjs +0 -131
- package/lib/cli/board.test.mjs +0 -227
- package/lib/cli/design.test.mjs +0 -270
- package/lib/cli/doctor-checks.test.mjs +0 -336
- package/lib/cli/global-setup-extras.test.mjs +0 -462
- package/lib/cli/inbox.test.mjs +0 -230
- package/lib/cli/session-ack.test.mjs +0 -63
- package/lib/cli/session.test.mjs +0 -613
- package/lib/collective/capture.test.mjs +0 -121
- package/lib/collective/cards.test.mjs +0 -114
- package/lib/collective/config.test.mjs +0 -123
- package/lib/collective/global-config.test.mjs +0 -220
- package/lib/collective/global-skills.test.mjs +0 -126
- package/lib/collective/presence.test.mjs +0 -95
- package/lib/collective/recall.test.mjs +0 -116
- package/lib/collective/vendor-skills.test.mjs +0 -306
- package/lib/comms/send-gate.test.mjs +0 -770
- package/lib/comms.test.mjs +0 -41
- package/lib/cost/ledger-row.test.mjs +0 -183
- package/lib/design/design-md.test.mjs +0 -318
- package/lib/design/fixtures/DESIGN.golden.md +0 -238
- package/lib/design/fixtures/PRODUCT.golden.md +0 -67
- package/lib/design/fixtures/foundation.json +0 -133
- package/lib/design/refresh-gate.test.mjs +0 -144
- package/lib/design/write.test.mjs +0 -241
- package/lib/diagnostics/alerts.test.mjs +0 -318
- package/lib/diagnostics/backup-freshness.test.mjs +0 -185
- package/lib/diagnostics/counters.test.mjs +0 -206
- package/lib/diagnostics/events.test.mjs +0 -290
- package/lib/diagnostics/otel.test.mjs +0 -196
- package/lib/diagnostics/trace.test.mjs +0 -251
- package/lib/env-compat.test.mjs +0 -104
- package/lib/execution/disposition.test.mjs +0 -553
- package/lib/execution/drive.test.mjs +0 -270
- package/lib/execution/effects.test.mjs +0 -344
- package/lib/execution/intake.test.mjs +0 -389
- package/lib/execution/journal.test.mjs +0 -261
- package/lib/execution/match.test.mjs +0 -235
- package/lib/execution/pipeline.test.mjs +0 -392
- package/lib/execution/route.test.mjs +0 -186
- package/lib/execution/surface-policy.test.mjs +0 -162
- package/lib/fs-atomic.test.mjs +0 -72
- package/lib/fs-ownership.test.mjs +0 -158
- package/lib/goals/admission.test.mjs +0 -164
- package/lib/goals/classify.test.mjs +0 -167
- package/lib/goals/collaborate.test.mjs +0 -336
- package/lib/goals/gaps.test.mjs +0 -284
- package/lib/goals/loop.test.mjs +0 -845
- package/lib/hooks/bus.test.mjs +0 -387
- package/lib/identity/persona.test.mjs +0 -142
- package/lib/kpi-sensors.test.mjs +0 -278
- package/lib/kpi.test.mjs +0 -244
- package/lib/learning/config.test.mjs +0 -75
- package/lib/learning/counters.test.mjs +0 -69
- package/lib/learning/curator-consolidate.test.mjs +0 -238
- package/lib/learning/curator.test.mjs +0 -106
- package/lib/learning/reflect.test.mjs +0 -0
- package/lib/learning/session-index.test.mjs +0 -125
- package/lib/learning/skill-writer.test.mjs +0 -210
- package/lib/mandate/audit.test.mjs +0 -195
- package/lib/mandate/contract.test.mjs +0 -185
- package/lib/mandate/derive.test.mjs +0 -274
- package/lib/mandate/model.test.mjs +0 -164
- package/lib/mandate/refresh.test.mjs +0 -389
- package/lib/mcp/server.test.mjs +0 -426
- package/lib/model-router/auth-profiles.test.mjs +0 -580
- package/lib/model-router/catalog.test.mjs +0 -385
- package/lib/model-router/economics.test.mjs +0 -438
- package/lib/model-router/failover.test.mjs +0 -439
- package/lib/model-router/health.test.mjs +0 -338
- package/lib/model-router/integration-coverage.test.mjs +0 -831
- package/lib/model-router/integration.test.mjs +0 -564
- package/lib/model-router/ledger.test.mjs +0 -415
- package/lib/model-router/llm-task.test.mjs +0 -392
- package/lib/model-router/org-credentials.test.mjs +0 -265
- package/lib/model-router/pricing-refresh.test.mjs +0 -286
- package/lib/model-router/reconcile.test.mjs +0 -316
- package/lib/model-router/repair.test.mjs +0 -180
- package/lib/model-router/spawn.test.mjs +0 -446
- package/lib/model-router/taxonomy.test.mjs +0 -410
- package/lib/model-router.test.mjs +0 -1207
- package/lib/org/activity.test.mjs +0 -134
- package/lib/org/approvals.test.mjs +0 -216
- package/lib/org/awareness.test.mjs +0 -159
- package/lib/org/board-mine-cache.test.mjs +0 -53
- package/lib/org/board.test.mjs +0 -187
- package/lib/org/bootstrap-context.test.mjs +0 -153
- package/lib/org/client.test.mjs +0 -1206
- package/lib/org/cohort-client.test.mjs +0 -126
- package/lib/org/cost-sync.test.mjs +0 -153
- package/lib/org/doctor.test.mjs +0 -346
- package/lib/org/engagement-ledger.test.mjs +0 -112
- package/lib/org/engagement.test.mjs +0 -739
- package/lib/org/handoff.test.mjs +0 -269
- package/lib/org/inbound/directedness.test.mjs +0 -668
- package/lib/org/inbound/facts.test.mjs +0 -471
- package/lib/org/inbound/hydrate.test.mjs +0 -453
- package/lib/org/inbound/index.test.mjs +0 -429
- package/lib/org/inbound/project.test.mjs +0 -287
- package/lib/org/integration-tools.test.mjs +0 -160
- package/lib/org/keys.test.mjs +0 -92
- package/lib/org/knowledge.test.mjs +0 -326
- package/lib/org/leases.test.mjs +0 -235
- package/lib/org/mesh-directives.test.mjs +0 -110
- package/lib/org/mesh-integration.test.mjs +0 -127
- package/lib/org/mesh.test.mjs +0 -400
- package/lib/org/messaging.test.mjs +0 -471
- package/lib/org/param-contract.test.mjs +0 -477
- package/lib/org/policy.test.mjs +0 -237
- package/lib/org/protocol.checksum.test.mjs +0 -90
- package/lib/org/protocol.test.mjs +0 -323
- package/lib/org/push.test.mjs +0 -792
- package/lib/org/registry.test.mjs +0 -100
- package/lib/org/resource-tools.test.mjs +0 -361
- package/lib/org/tool-access.test.mjs +0 -144
- package/lib/org/tool-surface-integration.test.mjs +0 -120
- package/lib/org/tool-surface.test.mjs +0 -1268
- package/lib/org/typing.test.mjs +0 -291
- package/lib/org/ui-parity.test.mjs +0 -560
- package/lib/org/verify.test.mjs +0 -194
- package/lib/org/work-ledger.test.mjs +0 -273
- package/lib/plan/adoption-e2e.test.mjs +0 -366
- package/lib/plan/budget-enforcement.test.mjs +0 -400
- package/lib/plan/compile.test.mjs +0 -382
- package/lib/plan/emit.test.mjs +0 -269
- package/lib/plan/explain.test.mjs +0 -188
- package/lib/prompts/parallelism.test.mjs +0 -177
- package/lib/rag/rag.test.mjs +0 -505
- package/lib/rate-guard.test.mjs +0 -272
- package/lib/reactive-gate.test.mjs +0 -57
- package/lib/render.test.mjs +0 -68
- package/lib/resource-governor.test.mjs +0 -488
- package/lib/scheduling/dynamic-jobs.test.mjs +0 -344
- package/lib/scheduling/jitter.test.mjs +0 -140
- package/lib/secrets/broker.test.mjs +0 -280
- package/lib/secrets/providers.test.mjs +0 -274
- package/lib/security/audit-engine.test.mjs +0 -424
- package/lib/security/coerce-args.test.mjs +0 -281
- package/lib/security/dangerous-tools.test.mjs +0 -68
- package/lib/security/external-content.test.mjs +0 -84
- package/lib/security/redact.test.mjs +0 -441
- package/lib/security/secret-equal.test.mjs +0 -55
- package/lib/session/config.test.mjs +0 -92
- package/lib/session/feed-core.test.mjs +0 -198
- package/lib/session/first-run.test.mjs +0 -121
- package/lib/session/frontdoor.test.mjs +0 -205
- package/lib/session/handoffs.test.mjs +0 -183
- package/lib/session/identity.test.mjs +0 -180
- package/lib/session/inbox-claims.test.mjs +0 -286
- package/lib/session/launch-args.test.mjs +0 -157
- package/lib/session/liveness.test.mjs +0 -100
- package/lib/session/status-summary.test.mjs +0 -118
- package/lib/session-permissions.test.mjs +0 -120
- package/lib/setup/claude-probe.test.mjs +0 -187
- package/lib/setup/completeness.test.mjs +0 -110
- package/lib/setup/context-pack.test.mjs +0 -89
- package/lib/setup/enrich.test.mjs +0 -115
- package/lib/setup/enroll-from-cohort.test.mjs +0 -300
- package/lib/setup/integration.test.mjs +0 -162
- package/lib/setup/io.test.mjs +0 -77
- package/lib/setup/runner.test.mjs +0 -132
- package/lib/setup/sections/identity.test.mjs +0 -234
- package/lib/setup/sections/inventory.test.mjs +0 -198
- package/lib/setup/sections/learning.test.mjs +0 -81
- package/lib/setup/sections/mandate.test.mjs +0 -388
- package/lib/setup/sections/messaging.test.mjs +0 -127
- package/lib/setup/sections/model.test.mjs +0 -240
- package/lib/setup/sections/org.test.mjs +0 -346
- package/lib/setup/sections/orgmail.test.mjs +0 -118
- package/lib/setup/sections/recovery.test.mjs +0 -98
- package/lib/setup/sections/subagents.test.mjs +0 -429
- package/lib/setup/sections/verify.test.mjs +0 -175
- package/lib/setup/sot.test.mjs +0 -81
- package/lib/setup/state.test.mjs +0 -115
- package/lib/singleton.test.mjs +0 -151
- package/lib/subagents/cli.test.mjs +0 -389
- package/lib/subagents/client.test.mjs +0 -309
- package/lib/subagents/gap.test.mjs +0 -234
- package/lib/subagents/lock.test.mjs +0 -248
- package/lib/subagents/manifest.test.mjs +0 -175
- package/lib/subagents/refs.test.mjs +0 -204
- package/lib/subagents/resolve.test.mjs +0 -422
- package/lib/subagents/schema.test.mjs +0 -328
- package/lib/telemetry/alerts.test.mjs +0 -109
- package/lib/telemetry/collect.test.mjs +0 -1274
- package/lib/tool-definitions-integration.test.mjs +0 -83
- package/lib/tool-definitions.test.mjs +0 -437
- package/lib/upgrade/global-refresh.test.mjs +0 -65
- package/lib/upgrade/launchd-reconcile.test.mjs +0 -272
- package/lib/upgrade/post-steps.test.mjs +0 -200
- package/lib/upgrade/verify.test.mjs +0 -164
- package/lib/util/fetch-timeout.test.mjs +0 -202
- package/lib/util/reconnect.test.mjs +0 -369
- package/lib/util/unhandled.test.mjs +0 -216
- package/lib/voice/outbound.test.mjs +0 -69
- package/lib/voice/session-rotation.test.mjs +0 -114
- package/lib/voice/stt.test.mjs +0 -226
- package/lib/voice/voice.test.mjs +0 -990
- package/scripts/cadence/enqueue-cadence-tick.test.mjs +0 -187
- package/scripts/ci/check-docs-accuracy.test.mjs +0 -409
- package/scripts/ci/check-durable-write-seam.test.mjs +0 -90
- package/scripts/ci/check-no-build-artifacts.test.mjs +0 -71
- package/scripts/ci/check-no-residual-identity.test.mjs +0 -202
- package/scripts/ci/check-skill-packs.test.mjs +0 -495
- package/scripts/ci/check-subagent-frontmatter.test.mjs +0 -124
- package/scripts/ci/check.test.mjs +0 -194
- package/scripts/ci/conformance-org-api.test.mjs +0 -425
- package/scripts/cloud-relay/voice/relay-identity.test.mjs +0 -96
- package/scripts/collective/hook-runner.test.mjs +0 -173
- package/scripts/cost/fleet-digest.test.mjs +0 -207
- package/scripts/cost/track-claude-usage-pricing.test.mjs +0 -183
- package/scripts/cost/track-claude-usage.test.mjs +0 -148
- package/scripts/daemon/agent-daemon-board-mine.test.mjs +0 -96
- package/scripts/daemon/agent-daemon-design.test.mjs +0 -238
- package/scripts/daemon/agent-daemon-frontdoor.test.mjs +0 -60
- package/scripts/daemon/agent-daemon.test.mjs +0 -995
- package/scripts/daemon/assurance-e2e.test.mjs +0 -613
- package/scripts/daemon/assurance.test.mjs +0 -1791
- package/scripts/daemon/board-mirror.test.mjs +0 -165
- package/scripts/daemon/cadence-consumer-frontdoor.test.mjs +0 -393
- package/scripts/daemon/cadence-consumer-governance.test.mjs +0 -276
- package/scripts/daemon/cadence-consumer.test.mjs +0 -776
- package/scripts/daemon/cadence-handlers.test.mjs +0 -837
- package/scripts/daemon/classifier-identity.test.mjs +0 -137
- package/scripts/daemon/classifier.test.mjs +0 -266
- package/scripts/daemon/classify-kind.test.mjs +0 -40
- package/scripts/daemon/context-compiler.test.mjs +0 -300
- package/scripts/daemon/deliver.test.mjs +0 -564
- package/scripts/daemon/dispatcher-cooldown.test.mjs +0 -122
- package/scripts/daemon/dispatcher-governance.test.mjs +0 -1013
- package/scripts/daemon/dispatcher-resume.test.mjs +0 -166
- package/scripts/daemon/execution-ladder.test.mjs +0 -470
- package/scripts/daemon/goal-steward-cadence.test.mjs +0 -312
- package/scripts/daemon/inbox-deferral-session.test.mjs +0 -49
- package/scripts/daemon/inbox-deferral.test.mjs +0 -336
- package/scripts/daemon/inbox-wake.test.mjs +0 -199
- package/scripts/daemon/integration.test.mjs +0 -149
- package/scripts/daemon/lib/self-echo.test.mjs +0 -153
- package/scripts/daemon/lib/session-router.test.mjs +0 -295
- package/scripts/daemon/prompt-builder-preamble.test.mjs +0 -210
- package/scripts/daemon/prompt-builder.test.mjs +0 -344
- package/scripts/daemon/responder-cost.test.mjs +0 -68
- package/scripts/daemon/responder-history.test.mjs +0 -185
- package/scripts/daemon/sdk-version.test.mjs +0 -31
- package/scripts/daemon/session-lock.test.mjs +0 -252
- package/scripts/daemon/session-outcomes.test.mjs +0 -533
- package/scripts/daemon/typing-registry.test.mjs +0 -102
- package/scripts/hooks/pre-send-audit.test.mjs +0 -354
- package/scripts/huddle/huddle-prompt.test.mjs +0 -176
- package/scripts/local-triggers/autoupdate.test.mjs +0 -518
- package/scripts/local-triggers/generate-plists.test.mjs +0 -456
- package/scripts/media-generation/brand-clause.test.mjs +0 -135
- package/scripts/org/send-orgmail.first-contact.test.mjs +0 -102
- package/scripts/poller/inbox-privilege-injection.test.mjs +0 -167
- package/scripts/poller/inbox-scan-poller.test.mjs +0 -295
- package/scripts/poller/lib/cloud-relay-dedup.test.mjs +0 -133
- package/scripts/poller/slack-socket-mode.test.mjs +0 -805
- package/scripts/poller-launchd/install.test.mjs +0 -243
- package/scripts/restore-from-backup.test.mjs +0 -181
- package/scripts/session/feed.test.mjs +0 -196
- package/scripts/session/supervisor-sh.test.mjs +0 -218
- package/scripts/session/supervisor.test.mjs +0 -482
- package/scripts/setup/configure-macos.test.mjs +0 -306
- package/scripts/setup/gen-subagent-manifest.test.mjs +0 -124
- package/scripts/setup/generate-agent-package-json.test.mjs +0 -143
- package/scripts/setup/generate-capability.test.mjs +0 -134
- package/scripts/setup/init-agent.test.mjs +0 -370
- package/scripts/setup/init-skill-marketplace.test.mjs +0 -193
- package/scripts/vendor/sync-skill-packs.test.mjs +0 -103
- package/scripts/watchdog/memory-watchdog.test.mjs +0 -64
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* lib/model-router/taxonomy.mjs — FailoverReason taxonomy + classifiers.
|
|
3
3
|
*
|
|
4
|
-
* The closed,
|
|
4
|
+
* The closed, 20-value `FAILOVER_REASONS` enum and its `DISPOSITION` table are
|
|
5
5
|
* the *contract* between every outcome-producing surface (CLI stream-json,
|
|
6
6
|
* result-json subtype, stderr, direct-api HTTP) and `failover.mjs`. The
|
|
7
7
|
* disposition column semantics — retrySame, failoverNext, cooldownScope,
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
* name and an alias under that exact byte sequence so either spelling resolves.
|
|
31
31
|
*/
|
|
32
32
|
|
|
33
|
-
import { classifyStderr as rateGuardClassifyStderr } from "../rate-guard.mjs";
|
|
33
|
+
import { classifyStderr as rateGuardClassifyStderr, classifyCohortRefusal } from "../rate-guard.mjs";
|
|
34
34
|
|
|
35
35
|
// ---------------------------------------------------------------------------
|
|
36
36
|
// The closed 16-value enum. Order is the SPEC §4.5 order; do not reorder
|
|
@@ -40,9 +40,57 @@ import { classifyStderr as rateGuardClassifyStderr } from "../rate-guard.mjs";
|
|
|
40
40
|
/** @typedef {(
|
|
41
41
|
* "auth"|"auth_permanent"|"billing"|"rate_limit"|"overloaded"|"server_error"|
|
|
42
42
|
* "timeout"|"model_not_found"|"context_overflow"|"payload_too_large"|
|
|
43
|
-
* "content_policy"|"provider_policy"|"format"|"empty_response"|"network"|"unknown"
|
|
43
|
+
* "content_policy"|"provider_policy"|"format"|"empty_response"|"network"|"unknown"|
|
|
44
|
+
* "local_refusal"|"gateway_retry"|"budget_refusal"|"request_timeout"
|
|
44
45
|
* )} FailoverReason */
|
|
45
46
|
|
|
47
|
+
/**
|
|
48
|
+
* Gateway codes that mean "cohort-llm cannot serve right now" (CF-136), never a
|
|
49
|
+
* credential, quota or model fault. Hard refusals (cohort_limit_exceeded,
|
|
50
|
+
* cohort_credits_exhausted, cohort_spend_limit_reached) are NOT here: they keep
|
|
51
|
+
* their non-retrying rate_limit / billing classification.
|
|
52
|
+
*/
|
|
53
|
+
export const GATEWAY_RETRY_CODES = Object.freeze(["cohort_concurrency_exceeded", "cohort_unavailable"]);
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Gateway codes for a HARD budget refusal (CF-143, design §4.6): the tenant's
|
|
57
|
+
* seat window, credits or spend limit. Sent with `x-should-retry: false`. The
|
|
58
|
+
* refusal is about the tenant's budget, not the credential's health, so it
|
|
59
|
+
* classifies as `budget_refusal`: no credential cooling, no breaker, and no
|
|
60
|
+
* failover — another credential of the same tenant is refused again, or worse,
|
|
61
|
+
* slips past an operator's limit.
|
|
62
|
+
*/
|
|
63
|
+
export const BUDGET_REFUSAL_CODES = Object.freeze(["cohort_limit_exceeded", "cohort_credits_exhausted", "cohort_spend_limit_reached"]);
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Same-candidate backoff ladder for `request_timeout` (a 408: the request body
|
|
67
|
+
* stalled, so the model never saw it). One sleep per retry; the ladder's length
|
|
68
|
+
* is the retry count. Matches the engine's ladder (lib/engine/wire/http.mjs
|
|
69
|
+
* backoffMs: 500 ms, 1 s). Named here pending owner confirmation (CF-143).
|
|
70
|
+
*/
|
|
71
|
+
export const REQUEST_TIMEOUT_BACKOFF_MS = Object.freeze([500, 1000]);
|
|
72
|
+
|
|
73
|
+
/** A same-candidate retry never sleeps through a retry-after longer than this (the engine's DEFAULT_MAX_RETRY_AFTER_MS). */
|
|
74
|
+
export const MAX_SAME_RETRY_AFTER_MS = 30_000;
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* The cohort code in a gateway error body on either wire — the top-level
|
|
78
|
+
* `cohort` refusal object first, then `error.code`. null when there is none.
|
|
79
|
+
* @param {object|string|null} body
|
|
80
|
+
* @returns {string|null}
|
|
81
|
+
*/
|
|
82
|
+
export function cohortCodeOf(body) {
|
|
83
|
+
let o = body;
|
|
84
|
+
if (typeof body === "string") {
|
|
85
|
+
try { o = JSON.parse(body); } catch { return null; }
|
|
86
|
+
}
|
|
87
|
+
if (!o || typeof o !== "object") return null;
|
|
88
|
+
const top = o.cohort && typeof o.cohort === "object" && typeof o.cohort.code === "string" ? o.cohort.code : null;
|
|
89
|
+
if (top && top.startsWith("cohort_")) return top;
|
|
90
|
+
const e = o.error && typeof o.error === "object" && typeof o.error.code === "string" ? o.error.code : null;
|
|
91
|
+
return e && e.startsWith("cohort_") ? e : null;
|
|
92
|
+
}
|
|
93
|
+
|
|
46
94
|
export const FAILOVER_REASONS = Object.freeze([
|
|
47
95
|
"auth",
|
|
48
96
|
"auth_permanent",
|
|
@@ -60,6 +108,29 @@ export const FAILOVER_REASONS = Object.freeze([
|
|
|
60
108
|
"empty_response",
|
|
61
109
|
"network",
|
|
62
110
|
"unknown",
|
|
111
|
+
// Appended (CF-11, Cohort Compute W2-E): the retarget was refused BEFORE any
|
|
112
|
+
// request left the machine (no third-party token, a subscription token as the
|
|
113
|
+
// token, a helper aimed at the wrong gateway). Nothing about the backend is
|
|
114
|
+
// known, so it fails over without opening any breaker.
|
|
115
|
+
"local_refusal",
|
|
116
|
+
// Appended (CF-136, Cohort Compute W7): the cohort-llm gateway is briefly
|
|
117
|
+
// unable to serve — 429 `cohort_concurrency_exceeded` (retry-after: 2) or 503
|
|
118
|
+
// `cohort_unavailable` (its OWN provider key refused upstream). Neither says
|
|
119
|
+
// anything about this seat's credential or the model: no credential cooling,
|
|
120
|
+
// no breaker, no failover to another provider's credential. The walk stops
|
|
121
|
+
// and hands the gateway's refusal (and retry-after) back to the caller.
|
|
122
|
+
"gateway_retry",
|
|
123
|
+
// Appended (CF-143, Cohort Compute W8): a HARD budget refusal from the
|
|
124
|
+
// gateway — 429 `cohort_limit_exceeded`, 402 `cohort_credits_exhausted` /
|
|
125
|
+
// `cohort_spend_limit_reached` (x-should-retry: false). The tenant's budget,
|
|
126
|
+
// not the credential: no cooling, no breaker, no failover, never retried. The
|
|
127
|
+
// walk stops and returns the refusal object (resetsAt) to the caller.
|
|
128
|
+
"budget_refusal",
|
|
129
|
+
// Appended (CF-143): a 408 — the request body stalled before the model saw
|
|
130
|
+
// it. Always safe to resend: the same candidate is retried on the
|
|
131
|
+
// REQUEST_TIMEOUT_BACKOFF_MS ladder before failing over. A generic `timeout`
|
|
132
|
+
// (a turn that ran too long) keeps its single immediate retry.
|
|
133
|
+
"request_timeout",
|
|
63
134
|
]);
|
|
64
135
|
|
|
65
136
|
const REASON_SET = new Set(FAILOVER_REASONS);
|
|
@@ -130,6 +201,9 @@ export function cooldownMsFor(reason, strike = 0) {
|
|
|
130
201
|
// | "jittered" (once, jittered) | "backoff" (once, backoff)
|
|
131
202
|
// | "cli" (the CLI already retried server_error ≤10× internally;
|
|
132
203
|
// we do not re-retry the same candidate ourselves).
|
|
204
|
+
// retryBackoffMs — when present, the same candidate is retried once per
|
|
205
|
+
// entry, sleeping that many ms first (a retry-after the
|
|
206
|
+
// attempt reported wins, up to MAX_SAME_RETRY_AFTER_MS).
|
|
133
207
|
// failoverNext — may we advance to the next candidate in the chain?
|
|
134
208
|
// cooldownScope — which breaker key cools: none | backend | backend:model |
|
|
135
209
|
// model-id | operator
|
|
@@ -153,6 +227,35 @@ export function cooldownMsFor(reason, strike = 0) {
|
|
|
153
227
|
// ---------------------------------------------------------------------------
|
|
154
228
|
|
|
155
229
|
export const DISPOSITION = Object.freeze({
|
|
230
|
+
gateway_retry: Object.freeze({
|
|
231
|
+
retrySame: false, // the engine's HTTP edge already retried; the caller holds the seat on the refusal
|
|
232
|
+
failoverNext: false, // the gateway is the route; another provider's credential is not a fix
|
|
233
|
+
cooldownScope: "none",
|
|
234
|
+
cooldownMs: 0,
|
|
235
|
+
opensBreaker: false,
|
|
236
|
+
}),
|
|
237
|
+
budget_refusal: Object.freeze({
|
|
238
|
+
retrySame: false, // x-should-retry: false — retrying a drained window only burns requests
|
|
239
|
+
failoverNext: false, // the same tenant is refused again, or an operator limit is bypassed
|
|
240
|
+
cooldownScope: "none", // the credential is healthy
|
|
241
|
+
cooldownMs: 0,
|
|
242
|
+
opensBreaker: false, // the backend is healthy
|
|
243
|
+
}),
|
|
244
|
+
request_timeout: Object.freeze({
|
|
245
|
+
retrySame: "backoff",
|
|
246
|
+
retryBackoffMs: REQUEST_TIMEOUT_BACKOFF_MS, // one sleep per same-candidate retry, then fail over
|
|
247
|
+
failoverNext: true,
|
|
248
|
+
cooldownScope: "none",
|
|
249
|
+
cooldownMs: 0,
|
|
250
|
+
opensBreaker: false,
|
|
251
|
+
}),
|
|
252
|
+
local_refusal: Object.freeze({
|
|
253
|
+
retrySame: false,
|
|
254
|
+
failoverNext: true,
|
|
255
|
+
cooldownScope: "none",
|
|
256
|
+
cooldownMs: 0,
|
|
257
|
+
opensBreaker: false,
|
|
258
|
+
}),
|
|
156
259
|
auth: Object.freeze({
|
|
157
260
|
retrySame: false,
|
|
158
261
|
failoverNext: true,
|
|
@@ -459,6 +562,15 @@ export function classifyStderr(text) {
|
|
|
459
562
|
if (typeof text !== "string" || !text) return null;
|
|
460
563
|
const t = text.toLowerCase();
|
|
461
564
|
|
|
565
|
+
// A cohort-llm transient code in a run's output (an engine JSON result, an
|
|
566
|
+
// echoed gateway body) is checked first: its body also says "rate_limit_error"
|
|
567
|
+
// or "503", which the patterns below would read as a provider fault (CF-136).
|
|
568
|
+
// Only a parsed refusal object counts, never the bare word: a transcript or a
|
|
569
|
+
// file that merely mentions the code must not mask a real 401 or overflow.
|
|
570
|
+
const refusal = classifyCohortRefusal(text);
|
|
571
|
+
if (refusal && GATEWAY_RETRY_CODES.includes(refusal.code)) return "gateway_retry";
|
|
572
|
+
if (refusal && BUDGET_REFUSAL_CODES.includes(refusal.code)) return "budget_refusal";
|
|
573
|
+
|
|
462
574
|
if (STDERR_CONTEXT_OVERFLOW.some((p) => t.includes(p))) return "context_overflow";
|
|
463
575
|
if (STDERR_CONTENT_POLICY.some((p) => t.includes(p))) return "content_policy";
|
|
464
576
|
if (STDERR_AUTH.some((p) => t.includes(p))) return "auth";
|
|
@@ -743,6 +855,16 @@ export function classifyHttp(status, body) {
|
|
|
743
855
|
const { text, code } = flattenHttpBody(body);
|
|
744
856
|
const st = Number.isFinite(status) ? Number(status) : null;
|
|
745
857
|
|
|
858
|
+
// ── 0. cohort-llm transient codes (CF-136). Before every status rule: a 429
|
|
859
|
+
// concurrency cap must not read as rate_limit (credential cooling +
|
|
860
|
+
// breaker + failover), and a 503 provider-key outage must not read as
|
|
861
|
+
// overloaded or auth. ─────────────────────────────────────────────────
|
|
862
|
+
const cohortCode = cohortCodeOf(body);
|
|
863
|
+
if (cohortCode && GATEWAY_RETRY_CODES.includes(cohortCode)) return "gateway_retry";
|
|
864
|
+
// Hard budget refusals (CF-143): before the 429 → rate_limit and 402 → billing
|
|
865
|
+
// rows, which cool the credential, open a breaker and fail over.
|
|
866
|
+
if (cohortCode && BUDGET_REFUSAL_CODES.includes(cohortCode)) return "budget_refusal";
|
|
867
|
+
|
|
746
868
|
// ── 1. Body-pattern signals that override status (deterministic refusals,
|
|
747
869
|
// OpenRouter policy blocks, content policy) ─────────────────────────
|
|
748
870
|
if (hasAny(text, CONTENT_POLICY_PATTERNS)) return "content_policy";
|
|
@@ -792,7 +914,7 @@ export function classifyHttp(status, body) {
|
|
|
792
914
|
if (st === 413) return "payload_too_large";
|
|
793
915
|
if (st === 429) return "rate_limit";
|
|
794
916
|
if (st === 400) return classify400(text, code);
|
|
795
|
-
if (st === 408) return "
|
|
917
|
+
if (st === 408) return "request_timeout"; // the body stalled; safe to resend (CF-143)
|
|
796
918
|
if (st === 500 || st === 502) {
|
|
797
919
|
// Some gateways return request-validation errors as 5xx — fail fast.
|
|
798
920
|
if (hasAny(text, REQUEST_VALIDATION_PATTERNS) || code === "invalid_request_error")
|
package/lib/org/cost-sync.mjs
CHANGED
|
@@ -26,6 +26,17 @@
|
|
|
26
26
|
* `${decision_id}:${session_id}:${ts}` || a content hash). The server is
|
|
27
27
|
* idempotent on cost.report, so the same row reported twice is a no-op replay.
|
|
28
28
|
*
|
|
29
|
+
* cohort-llm rows: a row whose session cohort-llm served carries
|
|
30
|
+
* `billed_by:"cohort-llm"`. The gateway already metered it at the point of
|
|
31
|
+
* service (design §8.3), so reporting it again would double-count it in hq.
|
|
32
|
+
* Such rows are SKIPPED here and counted in `skippedBilledBy`.
|
|
33
|
+
*
|
|
34
|
+
* Per-row results (CF-17): hq's cost.report now answers per row —
|
|
35
|
+
* `results[]` of {index, id, status: ingested|duplicate|rejected, code?, error?}.
|
|
36
|
+
* A batch whose frame carries it is counted row by row (ingested + duplicate
|
|
37
|
+
* are delivered; rejected are failed, with their codes); an older server that
|
|
38
|
+
* only returns `frame.ok` is counted per batch as before.
|
|
39
|
+
*
|
|
29
40
|
* Node builtins only. Fail-open (a down/disabled server reports nothing rather
|
|
30
41
|
* than throwing). `fetchImpl`, `now`, and `ledgerDir`/`agentRoot` are injectable
|
|
31
42
|
* for deterministic tests. ESM.
|
|
@@ -134,7 +145,9 @@ export function toReportRow(row, deps = {}) {
|
|
|
134
145
|
const day = (row && row.ts && String(row.ts).slice(0, 10)) || dayStr(deps);
|
|
135
146
|
return {
|
|
136
147
|
id,
|
|
137
|
-
agent
|
|
148
|
+
// Tracker rows carry no `agent`, and hq rejects a row without one — the
|
|
149
|
+
// seat's own Cohort identity is the default (deps.agent, see seatAgentId).
|
|
150
|
+
agent: row.agent ?? deps.agent ?? null,
|
|
138
151
|
model: row.model ?? null,
|
|
139
152
|
backend: row.backend ?? null,
|
|
140
153
|
input_tokens: numOr0(row.input_tokens),
|
|
@@ -152,8 +165,11 @@ export function toReportRow(row, deps = {}) {
|
|
|
152
165
|
decision_id: row.decision_id ?? null,
|
|
153
166
|
session_id: row.session_id ?? null,
|
|
154
167
|
// G16: attribution fields — DO NOT STRIP. cadence/source surface coordination
|
|
155
|
-
// spend in the rollup so an LLM-in-the-loop violation is visible.
|
|
156
|
-
|
|
168
|
+
// spend in the rollup so an LLM-in-the-loop violation is visible. `source` is
|
|
169
|
+
// mapped into the vocabulary hq accepts (an out-of-set source used to reject
|
|
170
|
+
// the whole batch); the ledger's own spelling rides in `source_detail`.
|
|
171
|
+
source: reportSource(row.source),
|
|
172
|
+
source_detail: row.source ?? null,
|
|
157
173
|
cadence: row.cadence ?? row.lane ?? null,
|
|
158
174
|
task_class: row.task_class ?? null,
|
|
159
175
|
ts: row.ts ?? null,
|
|
@@ -166,6 +182,69 @@ function numOr0(v) {
|
|
|
166
182
|
return Number.isFinite(n) ? n : 0;
|
|
167
183
|
}
|
|
168
184
|
|
|
185
|
+
// ---------------------------------------------------------------------------
|
|
186
|
+
// Wire vocabulary: the sources hq accepts, and the seat identity
|
|
187
|
+
// ---------------------------------------------------------------------------
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* The `source` values hq's cost.report accepts
|
|
191
|
+
* (hq src/server/methods/cost/report.ts VALID_SOURCES). A row outside this set
|
|
192
|
+
* is a BAD_REQUEST that rejects the entire batch — and every live ledger writer
|
|
193
|
+
* (`--source dispatcher|responder|cadence-consumer`, `messaging`, `lookup`)
|
|
194
|
+
* was outside it, so no seat's spend reached hq (A2 §6.3).
|
|
195
|
+
*/
|
|
196
|
+
export const HQ_REPORT_SOURCES = Object.freeze(["router", "cadence", "channel", "manual", "org-server"]);
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* Live ledger source → hq source. hq is widening its list to the live names
|
|
200
|
+
* (Cohort Compute W1-D); this map is valid against both the old and the new
|
|
201
|
+
* list, so the push never depends on which hq is deployed.
|
|
202
|
+
*/
|
|
203
|
+
const LIVE_SOURCE_MAP = Object.freeze({
|
|
204
|
+
"cadence-consumer": "cadence",
|
|
205
|
+
"handoff-timeout": "cadence",
|
|
206
|
+
dispatcher: "router",
|
|
207
|
+
backlog: "router",
|
|
208
|
+
lookup: "router",
|
|
209
|
+
classifier: "router",
|
|
210
|
+
responder: "channel",
|
|
211
|
+
messaging: "channel",
|
|
212
|
+
ack: "channel",
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* Map a ledger row's source onto hq's accepted vocabulary. Pure.
|
|
217
|
+
* Absent → null (hq defaults it); an accepted value passes through; a known
|
|
218
|
+
* live source maps; anything else is "router", hq's own default for a routed
|
|
219
|
+
* spend row, so one unfamiliar writer can never reject a batch again.
|
|
220
|
+
* @param {unknown} source
|
|
221
|
+
* @returns {string|null}
|
|
222
|
+
*/
|
|
223
|
+
export function reportSource(source) {
|
|
224
|
+
if (source == null || source === "") return null;
|
|
225
|
+
const s = String(source);
|
|
226
|
+
if (HQ_REPORT_SOURCES.includes(s)) return s;
|
|
227
|
+
return LIVE_SOURCE_MAP[s] || "router";
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* The seat's Cohort identity — the member slug hq authenticates this seat's key
|
|
232
|
+
* as — for rows that carry no `agent`. Explicit enrolment wins:
|
|
233
|
+
* `org.cohort.agentId` in config/org.yaml, then COHORT_AGENT_ID (the canonical
|
|
234
|
+
* provisioning variable). Pure over its inputs. null when the seat has neither:
|
|
235
|
+
* a guessed slug (a directory name) would be attributed to the wrong member,
|
|
236
|
+
* and hq defaults a missing agent to the authenticated actor.
|
|
237
|
+
* @param {{cfg?:object, env?:object}} o
|
|
238
|
+
* @returns {string|null}
|
|
239
|
+
*/
|
|
240
|
+
export function seatAgentId({ cfg, env = process.env } = {}) {
|
|
241
|
+
const n = (cfg && cfg.org && cfg.org.cohort) || {};
|
|
242
|
+
for (const v of [n.agentId, env && env.COHORT_AGENT_ID]) {
|
|
243
|
+
if (typeof v === "string" && v.trim()) return v.trim();
|
|
244
|
+
}
|
|
245
|
+
return null;
|
|
246
|
+
}
|
|
247
|
+
|
|
169
248
|
// ---------------------------------------------------------------------------
|
|
170
249
|
// Report — batched, idempotent push to cost.report
|
|
171
250
|
// ---------------------------------------------------------------------------
|
|
@@ -188,8 +267,41 @@ function numOr0(v) {
|
|
|
188
267
|
* localUSD:number, batches:Array<{count:number, ok:boolean, code?:string}>
|
|
189
268
|
* }>}
|
|
190
269
|
*/
|
|
270
|
+
/** The billed_by value of rows cohort-llm metered itself. */
|
|
271
|
+
export const COHORT_LLM_BILLED_BY = "cohort-llm";
|
|
272
|
+
|
|
273
|
+
/**
|
|
274
|
+
* Count a batch outcome from hq's per-row results when present. PURE.
|
|
275
|
+
* @param {object|null} frame the cost.report response frame
|
|
276
|
+
* @param {number} sent rows in the batch
|
|
277
|
+
* @returns {{perRow:boolean, delivered:number, failed:number, ingested:number, duplicate:number, rejected:number, rejections:Array<{id:string|null, code:string|null, error:string|null}>}}
|
|
278
|
+
*/
|
|
279
|
+
export function countBatchResults(frame, sent) {
|
|
280
|
+
const result = frame && frame.ok && frame.result && typeof frame.result === "object" ? frame.result : null;
|
|
281
|
+
const results = result && Array.isArray(result.results) ? result.results : null;
|
|
282
|
+
if (!results) {
|
|
283
|
+
const ok = !!(frame && frame.ok);
|
|
284
|
+
return { perRow: false, delivered: ok ? sent : 0, failed: ok ? 0 : sent, ingested: ok ? sent : 0, duplicate: 0, rejected: ok ? 0 : sent, rejections: [] };
|
|
285
|
+
}
|
|
286
|
+
let ingested = 0, duplicate = 0, rejected = 0;
|
|
287
|
+
const rejections = [];
|
|
288
|
+
for (const r of results) {
|
|
289
|
+
const status = r && r.status;
|
|
290
|
+
// "accepted" is tolerated as a synonym of "ingested" (the design's wording).
|
|
291
|
+
if (status === "ingested" || status === "accepted") ingested++;
|
|
292
|
+
else if (status === "duplicate") duplicate++;
|
|
293
|
+
else { rejected++; rejections.push({ id: (r && r.id) ?? null, code: (r && r.code) ?? null, error: (r && r.error) ?? null }); }
|
|
294
|
+
}
|
|
295
|
+
// Rows the server never mentioned did not land.
|
|
296
|
+
const unaccounted = Math.max(0, sent - results.length);
|
|
297
|
+
return { perRow: true, delivered: ingested + duplicate, failed: rejected + unaccounted, ingested, duplicate, rejected: rejected + unaccounted, rejections };
|
|
298
|
+
}
|
|
299
|
+
|
|
191
300
|
export async function reportLedger(o = {}) {
|
|
192
|
-
const
|
|
301
|
+
const allRows = readLedgerRows(o);
|
|
302
|
+
const rows = allRows.filter((r) => !(r && r.billed_by === COHORT_LLM_BILLED_BY));
|
|
303
|
+
const skippedBilledBy = allRows.length - rows.length;
|
|
304
|
+
const log = typeof o.log === "function" ? o.log : null;
|
|
193
305
|
// Bill through the ONE definition (lib/cost/ledger-row.mjs), not `estimated_usd`:
|
|
194
306
|
// the authoritative `total_cost_usd` where present, the cache-aware estimate as
|
|
195
307
|
// a fallback, and unmeasured sessions IMPUTED rather than summed as free. The
|
|
@@ -200,15 +312,16 @@ export async function reportLedger(o = {}) {
|
|
|
200
312
|
const localUSD = round6(summary.measuredUsd + imputeUnmeasured(summary).imputedUsd);
|
|
201
313
|
|
|
202
314
|
if (!isEnabled(o.cfg)) {
|
|
203
|
-
return { enabled: false, rowsRead:
|
|
315
|
+
return { enabled: false, rowsRead: allRows.length, reported: 0, failed: 0, skippedBilledBy, localUSD, batches: [] };
|
|
204
316
|
}
|
|
205
317
|
if (rows.length === 0) {
|
|
206
|
-
return { enabled: true, rowsRead:
|
|
318
|
+
return { enabled: true, rowsRead: allRows.length, reported: 0, failed: 0, skippedBilledBy, localUSD, batches: [] };
|
|
207
319
|
}
|
|
208
320
|
|
|
209
321
|
const c = configFromAgent(o.cfg);
|
|
210
322
|
const batchSize = Number.isFinite(o.batchSize) && o.batchSize > 0 ? Math.floor(o.batchSize) : REPORT_BATCH;
|
|
211
|
-
const
|
|
323
|
+
const agent = o.agent !== undefined ? o.agent : seatAgentId({ cfg: o.cfg, env: o.env || process.env });
|
|
324
|
+
const wireRows = rows.map((r) => toReportRow(r, { ...o, agent }));
|
|
212
325
|
|
|
213
326
|
let reported = 0;
|
|
214
327
|
let failed = 0;
|
|
@@ -225,11 +338,28 @@ export async function reportLedger(o = {}) {
|
|
|
225
338
|
fetchImpl: o.fetchImpl,
|
|
226
339
|
});
|
|
227
340
|
const ok = !!(frame && frame.ok);
|
|
228
|
-
|
|
229
|
-
|
|
341
|
+
const counts = countBatchResults(frame, slice.length);
|
|
342
|
+
reported += counts.delivered;
|
|
343
|
+
failed += counts.failed;
|
|
344
|
+
batches.push({
|
|
345
|
+
count: slice.length,
|
|
346
|
+
ok,
|
|
347
|
+
code: ok ? undefined : (frame && frame.error && frame.error.code) || "error",
|
|
348
|
+
...(counts.perRow ? { ingested: counts.ingested, duplicate: counts.duplicate, rejected: counts.rejected, rejections: counts.rejections } : {}),
|
|
349
|
+
});
|
|
350
|
+
if (log) {
|
|
351
|
+
try {
|
|
352
|
+
if (counts.perRow) {
|
|
353
|
+
const codes = [...new Set(counts.rejections.map((r) => r.code).filter(Boolean))];
|
|
354
|
+
log(counts.rejected ? "warn" : "info", `cost.report batch of ${slice.length}: ${counts.ingested} ingested, ${counts.duplicate} duplicate, ${counts.rejected} rejected${codes.length ? ` (${codes.join(", ")})` : ""}`);
|
|
355
|
+
} else {
|
|
356
|
+
log(ok ? "info" : "warn", `cost.report batch of ${slice.length}: ${ok ? "ok" : `failed (${batches[batches.length - 1].code})`} (server sent no per-row results)`);
|
|
357
|
+
}
|
|
358
|
+
} catch { /* logging must not break the push */ }
|
|
359
|
+
}
|
|
230
360
|
}
|
|
231
361
|
|
|
232
|
-
return { enabled: true, rowsRead:
|
|
362
|
+
return { enabled: true, rowsRead: allRows.length, reported, failed, skippedBilledBy, localUSD, batches };
|
|
233
363
|
}
|
|
234
364
|
|
|
235
365
|
function round6(n) {
|
|
@@ -238,4 +368,4 @@ function round6(n) {
|
|
|
238
368
|
|
|
239
369
|
export const _internals = { ledgerFile, ledgerDir, dayStr, stableJson, REPORT_BATCH };
|
|
240
370
|
|
|
241
|
-
export default { readLedgerRows, rowId, toReportRow, reportLedger };
|
|
371
|
+
export default { readLedgerRows, rowId, toReportRow, reportLedger, reportSource, seatAgentId, countBatchResults, COHORT_LLM_BILLED_BY };
|