@humwick/server 0.130.2 → 0.130.3
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/bundled/prompts/manifest.json +1 -0
- package/bundled/prompts/task.hydration.md +1 -1
- package/bundled/roles/builder.md +1 -1
- package/docs/guides/sub-coordinators.md +12 -5
- package/docs/guides/tools-coordination.md +1 -0
- package/docs/guides/workflows.md +16 -0
- package/docs/openapi.json +73 -4
- package/package.json +8 -7
- package/public/assets/{MessageBubble-BWLqMGKG.js → MessageBubble-Bq9kr21N.js} +2 -2
- package/public/assets/{PlanGraphPanel-3TlIQpjk.js → PlanGraphPanel-Dqiroy06.js} +2 -2
- package/public/assets/{TraceView-Wimm0Czv.js → TraceView-DYU962-H.js} +2 -2
- package/public/assets/{VaultDecisionCard-Bau_vNax.js → VaultDecisionCard-DhPfzioE.js} +2 -2
- package/public/assets/{activity-CrSurn-r.js → activity-DzCcQTee.js} +2 -2
- package/public/assets/{agent-lineage-CknAJKcb.js → agent-lineage-SgDt9i3T.js} +2 -2
- package/public/assets/agent-liveness-Bq-s73jW.js +2 -0
- package/public/assets/{agent-name-DKbiIhBo.js → agent-name-CcY3Aijy.js} +2 -2
- package/public/assets/{agent-profiles-DwF6EQ4R.js → agent-profiles-cxtRBn6O.js} +2 -2
- package/public/assets/{agent-project-badge-Diz4Sjjb.js → agent-project-badge-DGYbIhaI.js} +2 -2
- package/public/assets/{agent-tools-CRhpRQza.js → agent-tools-DHbftV0N.js} +2 -2
- package/public/assets/{agent-type-icon-LrUEU3lB.js → agent-type-icon-CY113sp-.js} +2 -2
- package/public/assets/{agents-B-v66C-4.js → agents-BPzY7IlQ.js} +2 -2
- package/public/assets/{analytics-BqCb-LKi.js → analytics-DENFPv_a.js} +2 -2
- package/public/assets/{artifact-viewer-kf4pGuAR.js → artifact-viewer-KRvSc7sl.js} +2 -2
- package/public/assets/{artifacts-DJevXcvg.js → artifacts-C9gSmL3s.js} +2 -2
- package/public/assets/{artifacts-D32zyw4Y.js → artifacts-DT-HkI5O.js} +2 -2
- package/public/assets/{automation-BpRajx_5.js → automation-BsmjQhKD.js} +2 -2
- package/public/assets/{backlog-D_UjTdzX.js → backlog-8NYH_62t.js} +2 -2
- package/public/assets/{busy-health-N3VEh4ao.js → busy-health-D3hwvYb4.js} +2 -2
- package/public/assets/{channels-9jopungq.js → channels-DCJ5WL7O.js} +2 -2
- package/public/assets/{chat-CSXrTB3C.js → chat-DAIl357U.js} +3 -3
- package/public/assets/{code-preview-p1NnmqK0.js → code-preview-CzrZfr9U.js} +2 -2
- package/public/assets/{connectors-CZdqlDNL.js → connectors-xTxtlyou.js} +2 -2
- package/public/assets/{cosmos-BgdsE4dG.js → cosmos-BpebFLK2.js} +2 -2
- package/public/assets/{crate-agent-30aXTKva.js → crate-agent-BHvI5wXC.js} +2 -2
- package/public/assets/{dependency-graph-B_jvw2GE.js → dependency-graph-DGT0o3wJ.js} +2 -2
- package/public/assets/{deploys-DoN6bAb5.js → deploys-hqWOHSHE.js} +2 -2
- package/public/assets/{display-BrKWFGJz.js → display-CDeH4I8T.js} +2 -2
- package/public/assets/{files-D6XEu8Ng.js → files-BTeGVmTg.js} +2 -2
- package/public/assets/{fleet-C7jQWbw2.js → fleet-DgXtNgCa.js} +2 -2
- package/public/assets/{fleet-metrics-BiDs3MLx.js → fleet-metrics-BHEt5yc_.js} +2 -2
- package/public/assets/{formatted-body-CQBwc1fb.js → formatted-body-MLtodyPp.js} +3 -3
- package/public/assets/{formatted-body-impl-DyG0WsQS.js → formatted-body-impl-CAe664Z8.js} +2 -2
- package/public/assets/{host-providers-dialog-DKaW31dN.js → host-providers-dialog-mapF4Fj9.js} +2 -2
- package/public/assets/{index-CRHep3M9.js → index-CqqgOI5R.js} +5 -5
- package/public/assets/{insights-CzrtkpOE.js → insights-DNyf7IzF.js} +2 -2
- package/public/assets/{integrations-aVsUmigt.js → integrations-DlYOHq7T.js} +2 -2
- package/public/assets/{issue-ref-chip-BnSlM_95.js → issue-ref-chip-CeWBNWn7.js} +2 -2
- package/public/assets/{log-viewer-qe7Ee47Z.js → log-viewer-Cib8nqdE.js} +2 -2
- package/public/assets/{maintenance-NfjqFZAk.js → maintenance-DSn1cPm7.js} +2 -2
- package/public/assets/{managed-agents-BiH0HgaE.js → managed-agents-C3CkM81m.js} +2 -2
- package/public/assets/{markdown-preview-BixaT3Xr.js → markdown-preview-W4VQQPAv.js} +3 -3
- package/public/assets/{markdown-preview-impl-DNGlWIS3.js → markdown-preview-impl-CMsTdhjq.js} +2 -2
- package/public/assets/{memory-DNsCl6UX.js → memory-BV17qtO4.js} +2 -2
- package/public/assets/{messages-DopU1L1X.js → messages-Bm_1AqSA.js} +2 -2
- package/public/assets/{orchestrators-Cq7ckLQT.js → orchestrators-Dg-vfP09.js} +2 -2
- package/public/assets/{overview-C1DCTzzV.js → overview-DcYCrvlr.js} +2 -2
- package/public/assets/{pairs-DE_m6rrE.js → pairs-8o9nuG3V.js} +2 -2
- package/public/assets/{profile-icon-B3rfh77F.js → profile-icon-BsRyBMea.js} +2 -2
- package/public/assets/{project-profile-instructions-DQWZE0kA.js → project-profile-instructions-DETKFn_E.js} +2 -2
- package/public/assets/{projects-Br2Bd2h1.js → projects-M_m6AHws.js} +2 -2
- package/public/assets/{prompt-settings-BKvFsvGD.js → prompt-settings-C_mNCgeL.js} +2 -2
- package/public/assets/provider-display-BEeLXC_D.js +2 -0
- package/public/assets/{registry-Cw38_6gW.js → registry-DDHHHE5N.js} +2 -2
- package/public/assets/run-card-Dt4I4jaP.js +2 -0
- package/public/assets/{secrets-DxI-vzSq.js → secrets-BkVwxI5O.js} +2 -2
- package/public/assets/{service-access-settings-D9s_VJbd.js → service-access-settings-Crq-6a-B.js} +2 -2
- package/public/assets/{settings-CKZTVGIx.js → settings-CYcavMFu.js} +2 -2
- package/public/assets/shipping-H6gzEeZB.js +2 -0
- package/public/assets/{stats-DyUBKyWI.js → stats-BJVeWkpV.js} +2 -2
- package/public/assets/{status-dot-DYqlEUhJ.js → status-dot-BcHyw1Vw.js} +2 -2
- package/public/assets/store-DKPDIZBe.js +9 -0
- package/public/assets/{tasks-Bh7Chr4-.js → tasks-qJjlQPpx.js} +2 -2
- package/public/assets/{teams-bowI7qVY.js → teams-Cd5Sk1uX.js} +2 -2
- package/public/assets/{terminal-viewer-BgVLHdsU.js → terminal-viewer-CpY5_m7W.js} +3 -3
- package/public/assets/{terminal-viewer-impl-Dz22UPy6.js → terminal-viewer-impl-DI_2llFR.js} +2 -2
- package/public/assets/{use-agent-terminal-DSQQ-iY7.js → use-agent-terminal-0yJA_buM.js} +2 -2
- package/public/assets/{use-decisions-samMQhQf.js → use-decisions-uJXHf34W.js} +2 -2
- package/public/assets/{use-project-list-59LheVP7.js → use-project-list-CpWl6eHQ.js} +2 -2
- package/public/assets/{use-selectors-BZa25xEB.js → use-selectors-BdxBW8mL.js} +2 -2
- package/public/assets/{user-avatar-DHxlvUvV.js → user-avatar-3IndfpOc.js} +2 -2
- package/public/assets/{versioned-prompt-editor-BmED5DnJ.js → versioned-prompt-editor-CIVg7XB1.js} +2 -2
- package/public/assets/{work-queue-CSvpuNLz.js → work-queue-B9rnLwHZ.js} +2 -2
- package/public/assets/{workflow-marker-DAZcj5qt.js → workflow-marker-X8wxyhzC.js} +2 -2
- package/public/assets/{workflows-DdmxRSyg.js → workflows-o5YyMFW7.js} +2 -2
- package/public/assets/{workspaces-BxeKfVuF.js → workspaces-CzEGoAng.js} +2 -2
- package/public/cosmos.html +4 -4
- package/public/index.html +28 -28
- package/runner/plugins/claude/.claude-plugin/plugin.json +1 -1
- package/runner/src/adapters/claude-headless.ts +1 -1
- package/runner/src/adapters/claude-launch-exit.ts +26 -0
- package/runner/src/adapters/claude-session-probe.ts +1 -1
- package/runner/src/adapters/claude-tmux.ts +38 -10
- package/runner/src/adapters/claude.ts +28 -75
- package/runner/src/adapters/provider-quota-harvest.ts +20 -71
- package/runner/src/agent-runner/lifecycle-milestones.ts +2 -2
- package/runner/src/agent-runner/liveness-exchange.ts +104 -0
- package/runner/src/claude-system-prompt.ts +49 -0
- package/runner/src/launch-assembly.ts +14 -10
- package/runner/src/profile-home.ts +1 -1
- package/runner/src/project-instructions.ts +2 -2
- package/runner/src/provider-command.ts +18 -0
- package/runner/src/provider-setup.ts +2 -1
- package/runner/src/runner-core.ts +14 -15
- package/runner/src/runner-helpers.ts +0 -8
- package/runner/src/session-scratch.ts +6 -2
- package/runner/test-support/provisioning-context.ts +4 -2
- package/runner/test-support/runner-harness.ts +2 -1
- package/scripts/steward-policy-cleanup.ts +2 -2
- package/src/agent-authz.ts +2 -2
- package/src/agent-drive-arbiter.ts +3 -8
- package/src/agent-exit-cleanup-async.ts +2 -2
- package/src/agent-exit-cleanup.ts +23 -19
- package/src/agent-lifecycle-events.ts +112 -85
- package/src/agent-ref.ts +3 -2
- package/src/agent-status-events.ts +43 -14
- package/src/auth/password.ts +4 -3
- package/src/auth/session-refresh.ts +1 -1
- package/src/auth/session.test-fixture.ts +2 -2
- package/src/auth/session.ts +7 -7
- package/src/automations/crud.ts +8 -81
- package/src/automations/dispatch.ts +33 -58
- package/src/automations/index.ts +1 -1
- package/src/automations/persistence.ts +65 -0
- package/src/automations/precheck.ts +18 -16
- package/src/automations/read-async.ts +11 -0
- package/src/automations/reconcile.ts +30 -39
- package/src/automations/storage.ts +33 -10
- package/src/automations/write-async.ts +33 -0
- package/src/branch-land-notice.ts +3 -3
- package/src/branch-landed.ts +25 -23
- package/src/bus.ts +21 -19
- package/src/cd-deploy-notify.ts +2 -2
- package/src/ci/notifications.ts +4 -4
- package/src/ci/root-missing.ts +3 -3
- package/src/ci/transition-notify.ts +5 -5
- package/src/claude-app/oauth-http.ts +3 -3
- package/src/cli/workflow.ts +12 -3
- package/src/commands-db.ts +4 -4
- package/src/commands-write.ts +8 -0
- package/src/compaction-watch.ts +10 -8
- package/src/config-store-write.ts +2 -2
- package/src/config.ts +4 -11
- package/src/connectors.ts +10 -8
- package/src/context-advisory.ts +22 -21
- package/src/db/agent-action-write.ts +36 -0
- package/src/db/agent-control-async.ts +9 -0
- package/src/db/agent-control-write.ts +49 -0
- package/src/db/agent-effort-observe.ts +22 -0
- package/src/db/agent-meta.ts +14 -3
- package/src/db/agents-async.ts +8 -5
- package/src/db/agents.ts +15 -12
- package/src/db/auth-identities.ts +2 -2
- package/src/db/automation-read-ops.ts +11 -0
- package/src/db/automation-write-ops.ts +46 -0
- package/src/db/blackboard.ts +2 -2
- package/src/db/browser-session-write.ts +32 -0
- package/src/db/bus-outbox-write-ops.ts +3 -1
- package/src/db/checkout-refresh-schema.ts +47 -0
- package/src/db/checkout-refresh.ts +5 -5
- package/src/db/command-agent-profile-backfill.ts +39 -0
- package/src/db/command-agent-profiles.ts +5 -1
- package/src/db/command-retention.ts +126 -0
- package/src/db/commands-planner-stats.test-fixture.ts +8 -0
- package/src/db/commands-read-ops.ts +16 -0
- package/src/db/connection.ts +1 -182
- package/src/db/context-carry-write.ts +74 -0
- package/src/db/continuations.ts +4 -4
- package/src/db/db-error-registry.ts +12 -0
- package/src/db/gateway.ts +26 -133
- package/src/db/history-retention-ops.ts +13 -0
- package/src/db/inbox-async.ts +2 -2
- package/src/db/inbox-read-ops.ts +1 -1
- package/src/db/inbox.ts +9 -3
- package/src/db/issue-associations.ts +2 -2
- package/src/db/issue-refs-async.ts +4 -1
- package/src/db/issue-refs-read-ops.ts +6 -0
- package/src/db/issue-refs.ts +8 -8
- package/src/db/kernel-event-log-schema.ts +2 -0
- package/src/db/land-boundaries.ts +51 -5
- package/src/db/land-gate-attestations.ts +2 -2
- package/src/db/landing-receipts.ts +2 -2
- package/src/db/lifecycle-context-write.ts +5 -0
- package/src/db/lifecycle-tail-async.ts +76 -0
- package/src/db/lifecycle-tail-write-ops.ts +62 -0
- package/src/db/lifecycle-write-window.ts +2 -1
- package/src/db/lineage-pair-dedupe-sql.ts +3 -3
- package/src/db/main-connection-mode.ts +11 -0
- package/src/db/main-connection-writes.ts +20 -2
- package/src/db/maintenance-job-runs-async.ts +2 -2
- package/src/db/maintenance-job-write-ops.ts +1 -1
- package/src/db/maintenance-pauses.ts +2 -2
- package/src/db/message-send.ts +4 -0
- package/src/db/messages.ts +31 -25
- package/src/db/migrations.ts +18 -1
- package/src/db/notification-write-ops.ts +19 -0
- package/src/db/operator-answer-write.ts +19 -0
- package/src/db/orchestrators.ts +10 -4
- package/src/db/pairs-async.ts +22 -1
- package/src/db/pairs-write-ops.ts +8 -3
- package/src/db/pairs.ts +41 -48
- package/src/db/plan-dispatch-schema.ts +5 -1
- package/src/db/plan-ready-notices.ts +43 -0
- package/src/db/plan-tools-include-migration.ts +36 -0
- package/src/db/plans-write-ops.ts +2 -0
- package/src/db/presence-buffer.ts +5 -0
- package/src/db/presence-loop.ts +18 -23
- package/src/db/presence-write.ts +0 -6
- package/src/db/project-entries-async.ts +14 -0
- package/src/db/project-entries-read-ops.ts +5 -1
- package/src/db/project-entries-write-ops.ts +8 -0
- package/src/db/project-entries.ts +15 -12
- package/src/db/project-journal.ts +2 -2
- package/src/db/project-trust-approvals.ts +2 -2
- package/src/db/prompt-templates.ts +4 -4
- package/src/db/read-op-marshaling-fixtures.ts +18 -0
- package/src/db/read-ops.ts +4 -0
- package/src/db/retention.ts +13 -2
- package/src/db/review-publish-write.ts +8 -0
- package/src/db/runtime-admin-async.ts +19 -0
- package/src/db/runtime-admin-write-ops.ts +36 -0
- package/src/db/runtime-tail-async.ts +288 -0
- package/src/db/runtime-tail-write-ops.ts +97 -0
- package/src/db/schema.ts +4 -1
- package/src/db/spawn-budget.ts +5 -0
- package/src/db/spawn-delegation.ts +1 -11
- package/src/db/sql-audit-indexes.ts +3 -0
- package/src/db/stats-async.ts +5 -3
- package/src/db/task-entity.ts +5 -4
- package/src/db/team-claim-policy.ts +60 -0
- package/src/db/teams-async.ts +4 -0
- package/src/db/teams-write-ops.ts +4 -0
- package/src/db/terminal-events.ts +15 -0
- package/src/db/timer-cutover-bodies.ts +292 -0
- package/src/db/timer-cutover-core.ts +37 -278
- package/src/db/timer-cutover-state.ts +40 -0
- package/src/db/timer-cutover-write-ops.ts +1 -40
- package/src/db/token-db-write-ops.ts +2 -0
- package/src/db/token-standing-async.ts +12 -0
- package/src/db/token-standing.ts +6 -9
- package/src/db/token-usage-retention.ts +33 -0
- package/src/db/token-usage-write-ops.ts +1 -1
- package/src/db/token-usage.ts +4 -1
- package/src/db/user-invites-async.ts +13 -0
- package/src/db/user-invites.ts +3 -3
- package/src/db/users.ts +14 -6
- package/src/db/workspaces.ts +8 -5
- package/src/db/write-ops.ts +31 -12
- package/src/db/writer-fault-seam.ts +2 -9
- package/src/db/writer-fault-test-ops.ts +18 -0
- package/src/db/writer-gateway.ts +42 -46
- package/src/dev.ts +8 -3
- package/src/event-loop-lag.ts +4 -2
- package/src/event-loop-yield.ts +2 -2
- package/src/events.ts +10 -8
- package/src/host-provider-store.ts +5 -4
- package/src/hub-metrics-report.ts +5 -1
- package/src/hub-metrics.ts +38 -18
- package/src/injection-sweep-pacing.ts +6 -8
- package/src/land-gate-notifications.ts +11 -10
- package/src/land-gate-queue-progress.ts +3 -3
- package/src/land-settle-dispatch.ts +52 -92
- package/src/lifecycle-context-pressure.ts +11 -10
- package/src/lifecycle-manager.ts +104 -98
- package/src/maintenance/breaker.ts +18 -16
- package/src/maintenance/checkout-refresh.ts +18 -1
- package/src/maintenance/critical-job-watchdog.ts +3 -3
- package/src/maintenance/events.ts +3 -3
- package/src/maintenance/history-retention-job.ts +30 -0
- package/src/maintenance/jobs.ts +29 -67
- package/src/maintenance/long-running-work.ts +3 -1
- package/src/maintenance/offline-agent-prune-job.ts +28 -0
- package/src/maintenance/orphaned-sessions.ts +5 -4
- package/src/maintenance/pauses.ts +4 -10
- package/src/maintenance/plan-ready-notice-job.ts +71 -0
- package/src/maintenance/scheduler.ts +18 -13
- package/src/maintenance/stalled-delivery-pager.ts +4 -4
- package/src/maintenance/teams.ts +19 -30
- package/src/maintenance/workspaces.ts +17 -27
- package/src/managed-policy-escalation.ts +7 -7
- package/src/managed-policy.ts +3 -3
- package/src/managed-provider-gate.ts +5 -4
- package/src/managed-spawn-reservation.ts +5 -4
- package/src/mcp/index.ts +8 -8
- package/src/mcp/output-descriptions.ts +1 -1
- package/src/mcp/presentation.ts +2 -1
- package/src/mcp/runtime-output.ts +6 -1
- package/src/mcp/self-care-visibility.ts +2 -2
- package/src/mcp/spawn-targets-matrix.ts +10 -1
- package/src/mcp/tool-groups.ts +3 -2
- package/src/mcp/tool-roles.ts +81 -0
- package/src/mcp/tools-workspace.ts +1 -1
- package/src/mcp-blackboard-tools.ts +6 -5
- package/src/mcp-decision-tools.ts +7 -7
- package/src/mcp-egress-tools.ts +10 -9
- package/src/mcp-issue-activity-tools.ts +2 -2
- package/src/mcp-issue-association-tools.ts +4 -4
- package/src/mcp-issue-ref-tools.ts +3 -3
- package/src/mcp-merge-tools.ts +5 -5
- package/src/mcp-notification-subscription-tools.ts +14 -15
- package/src/mcp-output-levels.test-fixture.ts +1 -1
- package/src/mcp-profile-trust-tools.ts +1 -1
- package/src/mcp-project-journal-tools.ts +4 -12
- package/src/mcp-project-tools.ts +17 -18
- package/src/mcp-routing-policy-tools.ts +3 -2
- package/src/mcp-team-tools.ts +6 -6
- package/src/mcp-workflow-tools.ts +5 -3
- package/src/memory-area-injection.ts +13 -12
- package/src/memory-boundary-capture.ts +6 -6
- package/src/memory-injection.ts +45 -43
- package/src/merge-pause-maintenance.ts +5 -4
- package/src/notification-router.ts +44 -17
- package/src/notify.ts +5 -5
- package/src/observed-reset-refresh.ts +4 -4
- package/src/operator-alarm.ts +2 -5
- package/src/project-ingest.ts +6 -6
- package/src/project-instructions.ts +8 -1
- package/src/project-trust.ts +12 -11
- package/src/prompt-resolver.ts +3 -3
- package/src/provider-quota-async.ts +5 -7
- package/src/provider-timeline-event.ts +4 -7
- package/src/quota-band-delivery.ts +2 -2
- package/src/recipe-runner.ts +4 -3
- package/src/retention-config-store.ts +4 -3
- package/src/reviewer-pipeline.ts +11 -10
- package/src/routes/_route.ts +4 -4
- package/src/routes/_shared.ts +13 -12
- package/src/routes/agent-effort.ts +5 -5
- package/src/routes/agent-heartbeat-quota.ts +23 -0
- package/src/routes/agent-keep.ts +1 -1
- package/src/routes/agent-reporting.ts +1 -1
- package/src/routes/agent-self-effort.ts +5 -5
- package/src/routes/agent-sessions.ts +24 -24
- package/src/routes/agents-spawn.ts +1 -1
- package/src/routes/agents.ts +17 -119
- package/src/routes/auth.ts +14 -15
- package/src/routes/authority-audit.ts +2 -2
- package/src/routes/automations.ts +6 -5
- package/src/routes/channel-binding-delete.ts +1 -1
- package/src/routes/channel-output.ts +3 -3
- package/src/routes/claude-api-budget.ts +5 -5
- package/src/routes/commands-listing.ts +1 -1
- package/src/routes/commands.ts +29 -27
- package/src/routes/context-resets.ts +2 -2
- package/src/routes/coordinator-teams.ts +1 -1
- package/src/routes/decisions.ts +2 -2
- package/src/routes/host-secret-files.ts +1 -1
- package/src/routes/hosts.ts +11 -11
- package/src/routes/inbox.ts +3 -2
- package/src/routes/index.ts +2 -1
- package/src/routes/integrations.ts +9 -7
- package/src/routes/issue-activity.ts +2 -2
- package/src/routes/issue-associations.ts +4 -4
- package/src/routes/issue-refs.ts +3 -3
- package/src/routes/kernel-timers-operator.ts +1 -1
- package/src/routes/memory.ts +1 -1
- package/src/routes/merges.ts +11 -11
- package/src/routes/messages.ts +23 -17
- package/src/routes/orchestrator-bootstrap.ts +1 -1
- package/src/routes/orchestrator-host-registration.ts +2 -0
- package/src/routes/orchestrator-host-utilization.ts +2 -2
- package/src/routes/orchestrator-proxy.ts +2 -2
- package/src/routes/orchestrator.ts +27 -18
- package/src/routes/pairs.ts +8 -8
- package/src/routes/project-profile-instructions.ts +1 -1
- package/src/routes/project-trust.ts +1 -1
- package/src/routes/projects.ts +16 -16
- package/src/routes/prompt-templates.ts +12 -12
- package/src/routes/provider-quotas.ts +10 -10
- package/src/routes/run-command.ts +1 -1
- package/src/routes/secrets-backup.ts +2 -2
- package/src/routes/secrets-import.ts +1 -1
- package/src/routes/secrets-vault.ts +7 -7
- package/src/routes/settings.ts +1 -1
- package/src/routes/shipping.ts +9 -1
- package/src/routes/spawn-policy.ts +8 -7
- package/src/routes/sse.ts +2 -2
- package/src/routes/team-templates.ts +7 -7
- package/src/routes/teams.ts +10 -10
- package/src/routes/tokens.ts +18 -17
- package/src/routes/users.ts +24 -24
- package/src/routes/viewer-read.ts +3 -3
- package/src/routes/web-tool-calls.ts +4 -4
- package/src/routes/workflows.ts +2 -2
- package/src/routes/workspaces.ts +17 -16
- package/src/routing-policy-push.ts +6 -6
- package/src/runtime-grant.ts +17 -11
- package/src/runtime-tokens.ts +20 -28
- package/src/secrets-broker/config.ts +1 -1
- package/src/secrets-broker/service.ts +2 -2
- package/src/security.ts +3 -1
- package/src/self-resume-carry.ts +21 -110
- package/src/self-resume-supersede.ts +4 -3
- package/src/self-resume.ts +54 -66
- package/src/server-background.ts +1 -1
- package/src/server.ts +21 -22
- package/src/services/agent-action.ts +12 -31
- package/src/services/agent-effort.ts +7 -32
- package/src/services/agent-hang-watchdog-job.ts +2 -2
- package/src/services/agent-heartbeat.ts +166 -0
- package/src/services/agent-reporting.ts +1 -1
- package/src/services/browser-inventory.ts +3 -3
- package/src/services/browser-session-state.ts +3 -2
- package/src/services/browser-session.ts +21 -27
- package/src/services/bus-command-update.ts +9 -9
- package/src/services/checkout-refresh-state.ts +1 -0
- package/src/services/checkout-refresh.test-fixture.ts +3 -2
- package/src/services/command-host.ts +7 -2
- package/src/services/coordinator-digest.ts +3 -2
- package/src/services/dispatch-command.ts +12 -13
- package/src/services/effective-launch-driver.ts +14 -9
- package/src/services/host-changed-paths.test-fixture.ts +5 -6
- package/src/services/host-project-readiness.ts +2 -2
- package/src/services/host-providers.ts +1 -1
- package/src/services/host-utilization.ts +9 -9
- package/src/services/idle-agent-digest.ts +17 -12
- package/src/services/idle-epics.ts +4 -4
- package/src/services/interrupt-agent.ts +12 -9
- package/src/services/issue-activity.ts +3 -3
- package/src/services/issue-associations.ts +15 -18
- package/src/services/issue-lifecycle-comments.ts +3 -2
- package/src/services/issue-lifecycle.ts +14 -13
- package/src/services/issue-refs.ts +4 -5
- package/src/services/kernel-timers-cutover-chaos-worker.ts +1 -1
- package/src/services/kernel-timers-ingress-chaos-worker.ts +6 -1
- package/src/services/kernel-timers-ingress.ts +3 -3
- package/src/services/kernel-timers-message-authority-chaos-worker.ts +3 -10
- package/src/services/kernel-timers-operator-chaos-worker.ts +3 -2
- package/src/services/kernel-timers-outbox.ts +1 -1
- package/src/services/kernel-timers-stage10-operator.ts +1 -1
- package/src/services/kernel-timers.ts +4 -3
- package/src/services/land-gate-placement.ts +11 -2
- package/src/services/land-issue-relations.ts +5 -4
- package/src/services/land-restart-retry.ts +7 -6
- package/src/services/landed-ancestry.ts +6 -5
- package/src/services/legacy-landing-host.ts +4 -1
- package/src/services/legacy-landing-recovery.ts +8 -6
- package/src/services/managed-running.ts +17 -17
- package/src/services/memory-areas.ts +3 -3
- package/src/services/merge-pause.ts +9 -15
- package/src/services/operator-decisions.ts +37 -41
- package/src/services/orchestrator-registration-recovery.ts +6 -2
- package/src/services/orchestrator-upgrade.ts +14 -12
- package/src/services/permission-decision.ts +4 -3
- package/src/services/plan-ci-notice.ts +1 -1
- package/src/services/plan-conformance.ts +4 -4
- package/src/services/plan-dispatch-policy.ts +10 -3
- package/src/services/plan-dispatch.ts +35 -14
- package/src/services/plan-graph.ts +39 -261
- package/src/services/plan-import.ts +1 -1
- package/src/services/plan-live-bindings.ts +8 -37
- package/src/services/plan-task-create.ts +1 -1
- package/src/services/plan-terminal-refs.ts +2 -12
- package/src/services/plan-wake-digest.ts +8 -3
- package/src/services/profile-trust.ts +2 -2
- package/src/services/project.ts +11 -10
- package/src/services/prompt-templates.ts +6 -5
- package/src/services/provider-hold-nudge.ts +9 -9
- package/src/services/provider-hold-record.ts +13 -12
- package/src/services/provider-state-audit.ts +19 -18
- package/src/services/provisioning-harness/driver.ts +1 -1
- package/src/services/provisioning-harness/fixture-matrix.ts +3 -3
- package/src/services/provisioning-harness/lifecycle.ts +24 -22
- package/src/services/provisioning-harness/prepare.ts +16 -17
- package/src/services/rate-limit-resume.ts +10 -9
- package/src/services/red-main-auto-revert.ts +7 -5
- package/src/services/red-main-controller-deps.ts +20 -3
- package/src/services/red-main-incident.ts +3 -1
- package/src/services/red-main-quarantine.ts +2 -3
- package/src/services/register-agent.ts +22 -22
- package/src/services/restart-project-role.ts +1 -1
- package/src/services/restart-spawn.ts +17 -16
- package/src/services/review-publish.ts +7 -24
- package/src/services/review-ref-reconcile.ts +29 -38
- package/src/services/runtime-dependency-alert.ts +27 -0
- package/src/services/scheduler-command.ts +11 -9
- package/src/services/scheduler.ts +5 -5
- package/src/services/self-effort-grant.ts +5 -25
- package/src/services/send-message.ts +16 -33
- package/src/services/shutdown-agent.ts +17 -14
- package/src/services/spawn-agent.ts +12 -41
- package/src/services/spawn-chain-inspector.ts +1 -1
- package/src/services/spawn-cwd-placement.ts +21 -5
- package/src/services/spawn-issue-activity.ts +8 -6
- package/src/services/spawn-launch.ts +17 -1
- package/src/services/spawn-loss-escalation.ts +1 -1
- package/src/services/spawn-registration-watchdog.ts +2 -2
- package/src/services/spawn-repo-probe.ts +7 -5
- package/src/services/spawn-tree-cleanup.ts +7 -8
- package/src/services/steward-reaper.ts +4 -4
- package/src/services/task-context-hydration.ts +25 -1
- package/src/services/task-delivery.ts +20 -34
- package/src/services/task-entity.ts +40 -203
- package/src/services/task-issue-link.ts +13 -20
- package/src/services/task-issue-weave.ts +12 -11
- package/src/services/task-lifecycle.ts +27 -31
- package/src/services/task-repo-cwd.ts +37 -0
- package/src/services/task-review-hold.ts +4 -17
- package/src/services/task-semantic-events.ts +13 -11
- package/src/services/task-state-reconcile.ts +3 -4
- package/src/services/task-validation.ts +2 -2
- package/src/services/team-templates.ts +5 -5
- package/src/services/team.ts +31 -98
- package/src/services/terminal-provider-exit.ts +6 -5
- package/src/services/timer-message-fire-chaos-worker.ts +7 -3
- package/src/services/timer-message-fire-outbox.ts +1 -1
- package/src/services/transient-agent-reaper.ts +22 -19
- package/src/services/turn-reconcile-audit.ts +9 -9
- package/src/services/user-onboarding.ts +8 -6
- package/src/services/user-profile.ts +6 -9
- package/src/services/work-finality.ts +16 -4
- package/src/services/workflow-auto-start.ts +2 -1
- package/src/services/workflow-caller.ts +61 -4
- package/src/services/workflow-child-proof-worker.ts +1 -1
- package/src/services/workflow-control-proof-worker.ts +1 -1
- package/src/services/workflow-coordinator.ts +8 -2
- package/src/services/workflow-decisions.ts +5 -5
- package/src/services/workflow-deferred-cleanup.ts +1 -1
- package/src/services/workflow-effect-driver.ts +42 -19
- package/src/services/workflow-effects.ts +41 -27
- package/src/services/workflow-pins.ts +7 -4
- package/src/services/workflow-reconcile.ts +1 -0
- package/src/services/workflow-resume-pins.ts +3 -3
- package/src/services/workflow-routing-defaults.ts +18 -0
- package/src/services/workflow-run-view.ts +4 -3
- package/src/services/workflow-run.test-fixture.ts +1 -1
- package/src/services/workflow-runs.ts +34 -22
- package/src/services/workflow-supervisor-state.ts +21 -1
- package/src/services/workflow-supervisor.ts +4 -3
- package/src/services/workspace-recovery.ts +4 -3
- package/src/spawn-admission.ts +10 -2
- package/src/spawn-placement.ts +27 -9
- package/src/spawn-targets.ts +8 -8
- package/src/sse-agent-status.ts +15 -6
- package/src/sse.ts +49 -24
- package/src/startup-context-injection.ts +61 -57
- package/src/steward-handoff.ts +4 -3
- package/src/steward-policy-cleanup.ts +9 -8
- package/src/steward.ts +2 -2
- package/src/task-dispatch-live.ts +5 -2
- package/src/task-dispatcher.ts +2 -2
- package/src/token-db.ts +2 -2
- package/src/token-usage-async.ts +2 -4
- package/src/user-awaiting-reply.ts +5 -5
- package/src/workspace-actions.ts +24 -29
- package/src/workspace-auto-merge.ts +14 -12
- package/src/workspace-changed-paths-client.ts +16 -5
- package/src/workspace-cleanup-stale.ts +30 -7
- package/src/workspace-command-settle.ts +24 -16
- package/src/workspace-config.ts +1 -1
- package/src/workspace-conflict-resolver.ts +9 -7
- package/src/workspace-dead-owner-recovery.ts +5 -4
- package/src/workspace-escalation.ts +12 -11
- package/src/workspace-human-escalation.ts +3 -3
- package/src/workspace-land-gate-watchdog.ts +3 -3
- package/src/workspace-land-refusal.ts +20 -0
- package/src/workspace-land-stopped.ts +1 -0
- package/src/workspace-merge.ts +10 -26
- package/src/workspace-nothing-to-land-notice.ts +2 -2
- package/src/workspace-orphans.ts +18 -37
- package/src/workspace-pr-completion.ts +10 -8
- package/src/workspace-rekey.ts +3 -3
- package/src/workspace-steward-failure.ts +2 -2
- package/src/workspace-steward-wake.ts +2 -2
- package/public/assets/agent-liveness-CaNwK0Zf.js +0 -2
- package/public/assets/provider-display-DsuWMvVL.js +0 -2
- package/public/assets/run-card-CpKqRbhg.js +0 -2
- package/public/assets/shipping-B9YtnwtG.js +0 -2
- package/public/assets/store-DcClXLH0.js +0 -9
- package/runner/src/agent-runner/http-liveness.ts +0 -85
- package/src/db/on-loop-write-transaction.ts +0 -34
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { setConfigAsync } from "./config-store-write";
|
|
2
|
+
import { createCommandAsync } from "./commands-write";
|
|
1
3
|
import { contextInjectUnsupported, launchContextIsUserMessage, launchContextSurvivesCompact, launchSystemPromptAppend } from "./context-injection-channel";
|
|
2
4
|
import { stripAgentCore } from "@humwick/sdk/prompt-template-defaults";
|
|
3
5
|
import { renderAgentCore } from "./agent-core";
|
|
@@ -26,10 +28,10 @@ import { renderAgentCore } from "./agent-core";
|
|
|
26
28
|
// inputs are gathered by the shared `resolveAgentSpawnInstructionInputs` (spawn-instruction-
|
|
27
29
|
// inputs.ts), the same resolver the restart projection uses, so the two cannot drift.
|
|
28
30
|
//
|
|
29
|
-
// • DELTA-GATED AT COMPACT. A
|
|
30
|
-
// block is skipped (hashed; launch prompt read
|
|
31
|
-
// seam). No skip when launch text rides user messages (OpenCode family, Codex:
|
|
32
|
-
// drops them)
|
|
31
|
+
// • DELTA-GATED AT CLEAR AND COMPACT. A persistent system prompt survives both a native compact
|
|
32
|
+
// and a /clear, so an unchanged block is skipped (hashed; launch prompt read, like the memory
|
|
33
|
+
// seam; #3782). No skip when launch text rides user messages (OpenCode family, Codex:
|
|
34
|
+
// compaction drops them). Re-injects on persistent-system-prompt providers strip the
|
|
33
35
|
// core (their context re-delivers it); the rest re-injects.
|
|
34
36
|
//
|
|
35
37
|
// PROVIDER-AGNOSTIC: delivery is an `agent.injectContext` command (declared `context.inject`); a
|
|
@@ -38,15 +40,14 @@ import { renderAgentCore } from "./agent-core";
|
|
|
38
40
|
|
|
39
41
|
import { createHash } from "node:crypto";
|
|
40
42
|
import { errMessage, isRelayInjectionCategory, stringValue } from "@humwick/sdk";
|
|
41
|
-
import {
|
|
43
|
+
import { findLaunchPromptCommandForAgent } from "./commands-db";
|
|
42
44
|
import { emitCommandEvent } from "./command-events";
|
|
43
45
|
import { REAP_INTERVAL_MS } from "./config";
|
|
44
|
-
import { getConfig
|
|
46
|
+
import { getConfig } from "./config-store";
|
|
45
47
|
import { agentPrincipalUserId, findMessageByIdempotencyKey, getAgent } from "./db";
|
|
46
48
|
import { resolveCanonicalHost } from "./host-identity";
|
|
47
49
|
import { memorySeamForAgent } from "./memory-seam";
|
|
48
|
-
import {
|
|
49
|
-
import { composeSpawnInstructionsWithEvents, stripHumwickIdentitySection, type ComposedSpawnInstructions } from "./project-instructions";
|
|
50
|
+
import { composeSpawnInstructionsWithEvents, stripRelayOwnedSections, type ComposedSpawnInstructions } from "./project-instructions";
|
|
50
51
|
import { resolveAgentSpawnInstructionInputs } from "./services/spawn-instruction-inputs";
|
|
51
52
|
import { INJECTION_SWEEP_BACKLOG_INTERVAL_MS, pacedInjectionSweep } from "./injection-sweep-pacing";
|
|
52
53
|
import { isSqliteBusyError } from "./db/connection";
|
|
@@ -106,8 +107,8 @@ export function readStartupContextInjectionState(agentId: string): StartupContex
|
|
|
106
107
|
return getConfig<StartupContextInjectionState>(STARTUP_CONTEXT_NAMESPACE, agentId)?.value ?? null;
|
|
107
108
|
}
|
|
108
109
|
|
|
109
|
-
export function recordStartupContextInjectionState(agentId: string, state: StartupContextInjectionState): void {
|
|
110
|
-
|
|
110
|
+
export async function recordStartupContextInjectionState(agentId: string, state: StartupContextInjectionState): Promise<void> {
|
|
111
|
+
(await setConfigAsync(STARTUP_CONTEXT_NAMESPACE, agentId, state, "startup-context-injection"));
|
|
111
112
|
}
|
|
112
113
|
|
|
113
114
|
/** #2171 — the machine this agent runs on, named the way the spawn named it (see the call site).
|
|
@@ -163,12 +164,14 @@ export function composeStartupContextForAgent(agent: AgentCard): ComposedSpawnIn
|
|
|
163
164
|
* A prior inject rode the summarized transcript, so the recorded delivery hash proves delivery,
|
|
164
165
|
* not survival — trusting it lets a summarized-away block skip forever. The launch prompt rode
|
|
165
166
|
* the preserved system prompt, so only it proves the block is still there. Unresolvable ⇒ null
|
|
166
|
-
* ⇒ re-inject, never skip. (Mirrors launchBakedMemoryHash/launchBakedJournalHash.)
|
|
167
|
+
* ⇒ re-inject, never skip. (Mirrors launchBakedMemoryHash/launchBakedJournalHash.) The strip must
|
|
168
|
+
* remove EVERY relay-owned section (identity, memory, journal): a leftover journal block made this
|
|
169
|
+
* hash never match a real coordinator launch, so every /clear re-injected the full charter (#3782).
|
|
167
170
|
*/
|
|
168
171
|
function launchBakedStartupHash(agent: AgentCard): string | null {
|
|
169
172
|
const prompt = launchSystemPromptAppend(findLaunchPromptCommandForAgent(agent.id, stringValue(agent.meta?.spawnRequestId)));
|
|
170
173
|
if (!prompt) return null;
|
|
171
|
-
const portion = normalizeStartupBlock(
|
|
174
|
+
const portion = normalizeStartupBlock(stripRelayOwnedSections(prompt));
|
|
172
175
|
return portion ? startupBlockHash(portion) : null;
|
|
173
176
|
}
|
|
174
177
|
|
|
@@ -180,7 +183,7 @@ function launchBakedStartupHash(agent: AgentCard): string | null {
|
|
|
180
183
|
* outcome (unchanged block, provider cannot inject, nothing composable, nothing to inject), always
|
|
181
184
|
* reported in a `relay-injection` event rather than inferred from silence.
|
|
182
185
|
*/
|
|
183
|
-
export function enqueueStartupContextInjectionAfterContextCommand(command: Command, now: number = Date.now()): Command | null {
|
|
186
|
+
export async function enqueueStartupContextInjectionAfterContextCommand(command: Command, now: number = Date.now()): Promise<Command | null> {
|
|
184
187
|
// A lifecycle command's status is the runner's confirmation verdict, not proof that the
|
|
185
188
|
// destructive boundary did not happen. In particular, a clear-inject that cannot confirm its
|
|
186
189
|
// `/clear` may have committed and is deliberately settled failed so the continuation beside this
|
|
@@ -197,28 +200,29 @@ export function enqueueStartupContextInjectionAfterContextCommand(command: Comma
|
|
|
197
200
|
const composed = composeStartupContextForAgent(agent);
|
|
198
201
|
|
|
199
202
|
if (contextInjectUnsupported(agent)) {
|
|
200
|
-
emitStartupSkip(agent, event, "inject-unsupported", command, now);
|
|
203
|
+
(await emitStartupSkip(agent, event, "inject-unsupported", command, now));
|
|
201
204
|
return null;
|
|
202
205
|
}
|
|
203
206
|
if (!composed) {
|
|
204
207
|
// No profile prompt to recompose (not a spawn provider). Reported once so an operator can tell
|
|
205
208
|
// it apart from a broken seam.
|
|
206
|
-
emitStartupSkip(agent, event, "not-composable", command, now);
|
|
209
|
+
(await emitStartupSkip(agent, event, "not-composable", command, now));
|
|
207
210
|
return null;
|
|
208
211
|
}
|
|
209
212
|
|
|
210
213
|
const block = composed.systemPromptAppend?.trim() ? composed.systemPromptAppend : "";
|
|
211
214
|
const hash = startupBlockHash(block);
|
|
212
215
|
if (!block) {
|
|
213
|
-
emitStartupSkip(agent, event, "nothing-to-inject", command, now);
|
|
216
|
+
(await emitStartupSkip(agent, event, "nothing-to-inject", command, now));
|
|
214
217
|
return null;
|
|
215
218
|
}
|
|
216
219
|
|
|
217
|
-
//
|
|
218
|
-
//
|
|
219
|
-
//
|
|
220
|
-
|
|
221
|
-
|
|
220
|
+
// #3782 — a persistent system prompt (Claude's --append-system-prompt) survives BOTH a native
|
|
221
|
+
// compact and a /clear, so a block still equal to the launch-baked one is already above: skip.
|
|
222
|
+
// A changed charter (hash differs), an unresolvable launch prompt, or a provider whose launch
|
|
223
|
+
// text rides summarizable parts / user messages (OpenCode, Codex) re-injects at either boundary.
|
|
224
|
+
if (launchContextSurvivesCompact(agent) && launchBakedStartupHash(agent) === hash) {
|
|
225
|
+
(await emitStartupSkip(agent, event, "unchanged", command, now));
|
|
222
226
|
return null;
|
|
223
227
|
}
|
|
224
228
|
|
|
@@ -233,7 +237,7 @@ export function enqueueStartupContextInjectionAfterContextCommand(command: Comma
|
|
|
233
237
|
// Delivered WITH the superseding note; hashed and gated on the canonical block (note excluded), so
|
|
234
238
|
// the gate cannot loop.
|
|
235
239
|
const content = `${STARTUP_CONTEXT_SUPERSEDE_NOTICE}\n\n${injectBlock}`;
|
|
236
|
-
const inject =
|
|
240
|
+
const inject = (await createCommandAsync({
|
|
237
241
|
type: "agent.injectContext",
|
|
238
242
|
source: "system",
|
|
239
243
|
target: command.target,
|
|
@@ -252,13 +256,13 @@ export function enqueueStartupContextInjectionAfterContextCommand(command: Comma
|
|
|
252
256
|
...(command.type === "agent.clearContext" ? { afterClearCommandId: command.id } : { afterCompactCommandId: command.id }),
|
|
253
257
|
},
|
|
254
258
|
},
|
|
255
|
-
});
|
|
259
|
+
}));
|
|
256
260
|
emitCommandEvent(inject, "command.requested");
|
|
257
261
|
|
|
258
262
|
// Anti-lie: queueing a command is not injecting a charter. The detailed per-block "injected"
|
|
259
263
|
// events move to settleStartupContextInjectionCommand, where the runner has reported success.
|
|
260
264
|
// This one row makes pending work visible without claiming the provider has it already.
|
|
261
|
-
emitRelayInjectionEvent({
|
|
265
|
+
(await emitRelayInjectionEvent({
|
|
262
266
|
agentId: agent.id,
|
|
263
267
|
category: "context",
|
|
264
268
|
summary: `startup context re-injection queued after ${event}`,
|
|
@@ -273,7 +277,7 @@ export function enqueueStartupContextInjectionAfterContextCommand(command: Comma
|
|
|
273
277
|
},
|
|
274
278
|
timestamp: now,
|
|
275
279
|
idempotencyKey: `startup-context-injection-queued:${agent.id}:${inject.id}`,
|
|
276
|
-
});
|
|
280
|
+
}));
|
|
277
281
|
return inject;
|
|
278
282
|
}
|
|
279
283
|
|
|
@@ -283,45 +287,45 @@ export function enqueueStartupContextInjectionAfterContextCommand(command: Comma
|
|
|
283
287
|
* ownership and cwd→project resolution, so a throw here must NOT take the rest of the settle chain
|
|
284
288
|
* down with it; it is reported on the agent's timeline instead.
|
|
285
289
|
*/
|
|
286
|
-
export function settleStartupContextInjectionAfterContextCommand(command: Command, now: number = Date.now()): Command | null {
|
|
290
|
+
export async function settleStartupContextInjectionAfterContextCommand(command: Command, now: number = Date.now()): Promise<Command | null> {
|
|
287
291
|
try {
|
|
288
|
-
const inject = enqueueStartupContextInjectionAfterContextCommand(command, now);
|
|
289
|
-
settleStartupContextInjectionCommand(command, now);
|
|
292
|
+
const inject = (await enqueueStartupContextInjectionAfterContextCommand(command, now));
|
|
293
|
+
(await settleStartupContextInjectionCommand(command, now));
|
|
290
294
|
return inject;
|
|
291
295
|
} catch (error) {
|
|
292
|
-
emitRelayInjectionEvent({
|
|
296
|
+
(await emitRelayInjectionEvent({
|
|
293
297
|
agentId: command.target,
|
|
294
298
|
category: "context",
|
|
295
299
|
summary: `startup-context re-injection failed to compose after ${command.type === "agent.compact" ? "compact" : command.type === "agent.clearContext" ? "clear" : command.type}: ${errMessage(error)}`,
|
|
296
300
|
detail: { source: "startup-context", agentId: command.target, commandId: command.id, failed: true },
|
|
297
301
|
timestamp: now,
|
|
298
302
|
idempotencyKey: `startup-context-injection-error:${command.target}:${command.id}`,
|
|
299
|
-
});
|
|
303
|
+
}));
|
|
300
304
|
return null;
|
|
301
305
|
}
|
|
302
306
|
}
|
|
303
307
|
|
|
304
|
-
function emitStartupSkip(
|
|
308
|
+
async function emitStartupSkip(
|
|
305
309
|
agent: AgentCard,
|
|
306
310
|
event: StartupContextInjectionEvent,
|
|
307
311
|
skipped: StartupContextInjectionSkip,
|
|
308
312
|
command: Command,
|
|
309
313
|
now: number,
|
|
310
|
-
): void {
|
|
314
|
+
): Promise<void> {
|
|
311
315
|
const summaries: Record<StartupContextInjectionSkip, string> = {
|
|
312
316
|
unchanged: `startup context unchanged after ${event} — re-injection skipped`,
|
|
313
317
|
"inject-unsupported": `startup context NOT re-injected after ${event}: provider declares context.inject:false (spawn-time block only)`,
|
|
314
318
|
"nothing-to-inject": `startup context resolved nothing to inject after ${event}`,
|
|
315
319
|
"not-composable": `startup context not recomposable after ${event}: agent has no spawn-provider profile prompt`,
|
|
316
320
|
};
|
|
317
|
-
emitRelayInjectionEvent({
|
|
321
|
+
(await emitRelayInjectionEvent({
|
|
318
322
|
agentId: agent.id,
|
|
319
323
|
category: "context",
|
|
320
324
|
summary: summaries[skipped],
|
|
321
325
|
detail: { source: "startup-context", event, agentId: agent.id, skipped, commandId: command.id },
|
|
322
326
|
timestamp: now,
|
|
323
327
|
idempotencyKey: `startup-context-injection-skip:${agent.id}:${command.id}`,
|
|
324
|
-
});
|
|
328
|
+
}));
|
|
325
329
|
}
|
|
326
330
|
|
|
327
331
|
/**
|
|
@@ -331,7 +335,7 @@ function emitStartupSkip(
|
|
|
331
335
|
* Recording on success makes the gate self-healing — a failed delivery leaves the previous hash and
|
|
332
336
|
* the next boundary retries.
|
|
333
337
|
*/
|
|
334
|
-
export function settleStartupContextInjectionCommand(command: Command, now: number = Date.now()): void {
|
|
338
|
+
export async function settleStartupContextInjectionCommand(command: Command, now: number = Date.now()): Promise<void> {
|
|
335
339
|
if (command.type !== "agent.injectContext" || command.status !== "succeeded") return;
|
|
336
340
|
if (command.params.reason !== STARTUP_CONTEXT_INJECTION_REASON) return;
|
|
337
341
|
const startup = command.params.startupContext;
|
|
@@ -339,12 +343,12 @@ export function settleStartupContextInjectionCommand(command: Command, now: numb
|
|
|
339
343
|
const record = startup as Record<string, unknown>;
|
|
340
344
|
const hash = typeof record.hash === "string" ? record.hash : undefined;
|
|
341
345
|
if (hash === undefined) return;
|
|
342
|
-
recordStartupContextInjectionState(command.target, {
|
|
346
|
+
(await recordStartupContextInjectionState(command.target, {
|
|
343
347
|
hash,
|
|
344
348
|
event: record.event === "clear" ? "clear" : "compact",
|
|
345
349
|
at: now,
|
|
346
|
-
});
|
|
347
|
-
emitStartupContextDeliveredEvents(command, record, now);
|
|
350
|
+
}));
|
|
351
|
+
(await emitStartupContextDeliveredEvents(command, record, now));
|
|
348
352
|
}
|
|
349
353
|
|
|
350
354
|
/** Preserve only enough of the composition for the success-side audit event. The actual charter
|
|
@@ -379,12 +383,12 @@ function queuedStartupBlockEvents(record: Record<string, unknown>): Array<{ cate
|
|
|
379
383
|
});
|
|
380
384
|
}
|
|
381
385
|
|
|
382
|
-
function emitStartupContextDeliveredEvents(command: Command, record: Record<string, unknown>, now: number): void {
|
|
386
|
+
async function emitStartupContextDeliveredEvents(command: Command, record: Record<string, unknown>, now: number): Promise<void> {
|
|
383
387
|
const event: StartupContextInjectionEvent = record.event === "clear" ? "clear" : "compact";
|
|
384
388
|
const boundaryCommandId = stringValue(record.afterClearCommandId) ?? stringValue(record.afterCompactCommandId) ?? command.correlationId;
|
|
385
389
|
for (const [index, blockEvent] of queuedStartupBlockEvents(record).entries()) {
|
|
386
390
|
const source = stringValue(blockEvent.detail.source) ?? "startup-context";
|
|
387
|
-
emitRelayInjectionEvent({
|
|
391
|
+
(await emitRelayInjectionEvent({
|
|
388
392
|
agentId: command.target,
|
|
389
393
|
category: blockEvent.category,
|
|
390
394
|
summary: `re-injected after ${event}: ${blockEvent.summary}`,
|
|
@@ -397,26 +401,26 @@ function emitStartupContextDeliveredEvents(command: Command, record: Record<stri
|
|
|
397
401
|
},
|
|
398
402
|
timestamp: now,
|
|
399
403
|
idempotencyKey: `startup-context-injection-delivered:${command.target}:${command.id}:${source}:${index}`,
|
|
400
|
-
});
|
|
404
|
+
}));
|
|
401
405
|
}
|
|
402
406
|
}
|
|
403
407
|
|
|
404
408
|
/** A failed startup-context composer must not make a maintenance tick throw or block every later
|
|
405
409
|
* candidate. The reactive settle has the same containment in its public wrapper. */
|
|
406
|
-
function containedStartupContextInjection(command: Command, now: number): { inject: Command | null; composeFailed: boolean } {
|
|
410
|
+
async function containedStartupContextInjection(command: Command, now: number): Promise<{ inject: Command | null; composeFailed: boolean }> {
|
|
407
411
|
try {
|
|
408
|
-
return { inject: enqueueStartupContextInjectionAfterContextCommand(command, now), composeFailed: false };
|
|
412
|
+
return { inject: (await enqueueStartupContextInjectionAfterContextCommand(command, now)), composeFailed: false };
|
|
409
413
|
} catch (error) {
|
|
410
414
|
// #2712 — a held write lock is contention, not a compose failure: defer, never count it.
|
|
411
415
|
if (isSqliteBusyError(error)) throw error;
|
|
412
|
-
emitRelayInjectionEvent({
|
|
416
|
+
(await emitRelayInjectionEvent({
|
|
413
417
|
agentId: command.target,
|
|
414
418
|
category: "context",
|
|
415
419
|
summary: `startup-context re-injection failed to compose after ${command.type === "agent.compact" ? "compact" : "clear"}: ${errMessage(error)}`,
|
|
416
420
|
detail: { source: "startup-context", agentId: command.target, commandId: command.id, failed: true },
|
|
417
421
|
timestamp: now,
|
|
418
422
|
idempotencyKey: `startup-context-injection-error:${command.target}:${command.id}`,
|
|
419
|
-
});
|
|
423
|
+
}));
|
|
420
424
|
return { inject: null, composeFailed: true };
|
|
421
425
|
}
|
|
422
426
|
}
|
|
@@ -428,11 +432,11 @@ function containedStartupContextInjection(command: Command, now: number): { inje
|
|
|
428
432
|
* prompt's context; collapsing the two would silently strand the clear's charter recovery. The
|
|
429
433
|
* shared attempt ledger is keyed by boundary correlation id, so it is both the idempotency fence
|
|
430
434
|
* and the retry state — there is no second per-agent collapse to keep in sync with it. */
|
|
431
|
-
export function sweepMissedStartupContextInjections(now: number = Date.now(), signal?: AbortSignal): { enqueuedCommandIds: string[]; aborted?: true } {
|
|
435
|
+
export async function sweepMissedStartupContextInjections(now: number = Date.now(), signal?: AbortSignal): Promise<{ enqueuedCommandIds: string[]; aborted?: true }> {
|
|
432
436
|
const enqueuedCommandIds: string[] = [];
|
|
433
437
|
for (const command of sweepableBoundaryCommands(now, signal)) {
|
|
434
438
|
if (signal?.aborted) break;
|
|
435
|
-
sweepStartupBoundary(command, now, enqueuedCommandIds);
|
|
439
|
+
(await sweepStartupBoundary(command, now, enqueuedCommandIds));
|
|
436
440
|
}
|
|
437
441
|
return { enqueuedCommandIds, ...(signal?.aborted ? { aborted: true as const } : {}) };
|
|
438
442
|
}
|
|
@@ -441,24 +445,24 @@ export function sweepMissedStartupContextInjections(now: number = Date.now(), si
|
|
|
441
445
|
* macrotask each. */
|
|
442
446
|
async function sweepMissedStartupContextInjectionsPaced(now: number, signal?: AbortSignal): Promise<{ enqueuedCommandIds: string[]; aborted?: true; moreWork?: true }> {
|
|
443
447
|
const enqueuedCommandIds: string[] = [];
|
|
444
|
-
const { moreWork } = await pacedInjectionSweep(() => sweepableBoundaryCommands(now, signal), (command) => sweepStartupBoundary(command, now, enqueuedCommandIds), signal);
|
|
448
|
+
const { moreWork } = await pacedInjectionSweep(() => sweepableBoundaryCommands(now, signal), async (command) => (await sweepStartupBoundary(command, now, enqueuedCommandIds)), signal);
|
|
445
449
|
return { enqueuedCommandIds, ...(signal?.aborted ? { aborted: true as const } : {}), ...(moreWork ? { moreWork: true as const } : {}) };
|
|
446
450
|
}
|
|
447
451
|
|
|
448
|
-
function sweepStartupBoundary(command: Command, now: number, enqueuedCommandIds: string[]): void {
|
|
452
|
+
async function sweepStartupBoundary(command: Command, now: number, enqueuedCommandIds: string[]): Promise<void> {
|
|
449
453
|
const { decision, attempts } = injectionAttemptDecision(command, STARTUP_CONTEXT_INJECTION_REASON);
|
|
450
454
|
if (decision === "in-flight") return;
|
|
451
455
|
if (decision === "exhausted") {
|
|
452
|
-
notifyStartupContextInjectionExhausted(command, attempts, now);
|
|
456
|
+
(await notifyStartupContextInjectionExhausted(command, attempts, now));
|
|
453
457
|
return;
|
|
454
458
|
}
|
|
455
459
|
if (attempts === 0 && (startupSweepAlreadyDecided(command) || startupBoundaryAlreadyDecided(command))) return;
|
|
456
|
-
const { inject, composeFailed } = containedStartupContextInjection(command, now);
|
|
460
|
+
const { inject, composeFailed } = (await containedStartupContextInjection(command, now));
|
|
457
461
|
if (inject) {
|
|
458
462
|
enqueuedCommandIds.push(inject.id);
|
|
459
463
|
return;
|
|
460
464
|
}
|
|
461
|
-
rememberStartupSweepDecision(command, composeFailed, now);
|
|
465
|
+
(await rememberStartupSweepDecision(command, composeFailed, now));
|
|
462
466
|
}
|
|
463
467
|
|
|
464
468
|
/**
|
|
@@ -477,32 +481,32 @@ function startupSweepAlreadyDecided(command: Command): boolean {
|
|
|
477
481
|
return sweptStartupBoundaryDecisions.get(command.id)?.done ?? false;
|
|
478
482
|
}
|
|
479
483
|
|
|
480
|
-
function rememberStartupSweepDecision(command: Command, composeFailed: boolean, now: number): void {
|
|
484
|
+
async function rememberStartupSweepDecision(command: Command, composeFailed: boolean, now: number): Promise<void> {
|
|
481
485
|
const held = sweptStartupBoundaryDecisions.get(command.id);
|
|
482
486
|
const composeFailures = (held?.composeFailures ?? 0) + (composeFailed ? 1 : 0);
|
|
483
487
|
const done = !composeFailed || composeFailures >= MAX_INJECTION_ATTEMPTS;
|
|
484
488
|
if (sweptStartupBoundaryDecisions.size >= MAX_SWEPT_STARTUP_DECISIONS && !held) sweptStartupBoundaryDecisions.clear();
|
|
485
489
|
sweptStartupBoundaryDecisions.set(command.id, { composeFailures, done });
|
|
486
|
-
if (composeFailed && done) notifyStartupContextInjectionExhausted(command, composeFailures, now, "compose");
|
|
490
|
+
if (composeFailed && done) (await notifyStartupContextInjectionExhausted(command, composeFailures, now, "compose"));
|
|
487
491
|
}
|
|
488
492
|
|
|
489
493
|
function startupBoundaryAlreadyDecided(command: Command): boolean {
|
|
490
494
|
return findMessageByIdempotencyKey(command.target, `startup-context-injection-skip:${command.target}:${command.id}`) !== null;
|
|
491
495
|
}
|
|
492
496
|
|
|
493
|
-
function notifyStartupContextInjectionExhausted(command: Command, attempts: number, now: number, kind: "delivery" | "compose" = "delivery"): void {
|
|
497
|
+
async function notifyStartupContextInjectionExhausted(command: Command, attempts: number, now: number, kind: "delivery" | "compose" = "delivery"): Promise<void> {
|
|
494
498
|
const idempotencyKey = `startup-context-injection-exhausted${kind === "compose" ? "-compose" : ""}:${command.target}:${command.id}`;
|
|
495
499
|
if (findMessageByIdempotencyKey(command.target, idempotencyKey)) return;
|
|
496
500
|
const event = command.type === "agent.compact" ? "compact" : "clear";
|
|
497
501
|
const what = kind === "compose" ? "failed to compose" : "could not be delivered";
|
|
498
|
-
emitRelayInjectionEvent({
|
|
502
|
+
(await emitRelayInjectionEvent({
|
|
499
503
|
agentId: command.target,
|
|
500
504
|
category: "context",
|
|
501
505
|
summary: `startup-context re-injection gave up after ${attempts} attempt(s) at a ${event} boundary — it ${what}, so this agent may be running without its current profile charter`,
|
|
502
506
|
detail: { source: "startup-context", agentId: command.target, commandId: command.id, event, attempts, exhausted: kind },
|
|
503
507
|
timestamp: now,
|
|
504
508
|
idempotencyKey,
|
|
505
|
-
});
|
|
509
|
+
}));
|
|
506
510
|
}
|
|
507
511
|
|
|
508
512
|
export const STARTUP_CONTEXT_INJECTION_SWEEP_JOB = {
|
package/src/steward-handoff.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
+
import { mergeAgentMetaAsync } from "./db/agents-async";
|
|
1
2
|
import { stringValue } from "@humwick/sdk";
|
|
2
3
|
import { getManagedAgentState, getSpawnPolicy } from "./config-store";
|
|
3
|
-
import { getAgent, getWorkspace, listWorkspaces,
|
|
4
|
+
import { getAgent, getWorkspace, listWorkspaces, patchWorkspaceMetadataAsync } from "./db";
|
|
4
5
|
import { agentGenerationKey } from "./db/agent-shutdown-in-flight";
|
|
5
6
|
import { getLifecycleManager } from "./lifecycle-manager";
|
|
6
7
|
import { isProvenStewardAgent, stewardHandoffReleased } from "./steward-provenance";
|
|
@@ -23,6 +24,6 @@ export async function finishWorkspaceStewardHandoff(workspace: WorkspaceRecord):
|
|
|
23
24
|
if (!boundAgent && !boundSpawn && claimant !== agent.id) return;
|
|
24
25
|
await patchWorkspaceMetadataAsync(workspace.id, { stewardClaim: null, stewardHandoffEndedAt: Date.now() });
|
|
25
26
|
if (listWorkspaces().some(ws => ws.id !== workspace.id && workspaceActiveClaim(ws)?.by === agent.id)) return;
|
|
26
|
-
const command = getLifecycleManager().stopAgent(policy, true, "steward-handoff-ended");
|
|
27
|
-
if (command)
|
|
27
|
+
const command = await getLifecycleManager().stopAgent(policy, true, "steward-handoff-ended");
|
|
28
|
+
if (command) (await mergeAgentMetaAsync(agent.id, { stewardReleasedGeneration: agentGenerationKey(agent) }, { instanceId: agent.instanceId, epoch: agent.epoch }));
|
|
28
29
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { setConfigAsync, deleteConfigAsync } from "./config-store-write";
|
|
1
2
|
// #1955 — ONE-SHOT, IDEMPOTENT cleanup of the steward spawn-policy rows a live relay accumulated
|
|
2
3
|
// before #1623/#1953/#1955. Pure planning here; `scripts/steward-policy-cleanup.ts` is the operator
|
|
3
4
|
// CLI (DRY RUN by default). Nothing in the running relay calls this — it is deliberately manual,
|
|
@@ -21,7 +22,7 @@
|
|
|
21
22
|
// so a second run over the applied state plans nothing. Safe to re-run.
|
|
22
23
|
|
|
23
24
|
import { canonicalRepoRoot, legacyStewardPolicyNames, repoStewardPolicyName } from "./steward-identity";
|
|
24
|
-
import {
|
|
25
|
+
import { getSpawnPolicy, listSpawnPolicies } from "./config-store";
|
|
25
26
|
import { listWorkspaces } from "./db";
|
|
26
27
|
import { basename } from "node:path";
|
|
27
28
|
import type { SpawnPolicy } from "./types";
|
|
@@ -151,10 +152,10 @@ export interface StewardPolicyCleanupResult {
|
|
|
151
152
|
* precondition, so a plan built against a state the live relay has since changed degrades to a skip
|
|
152
153
|
* rather than clobbering the newer row.
|
|
153
154
|
*/
|
|
154
|
-
export function applyStewardPolicyCleanup(
|
|
155
|
+
export async function applyStewardPolicyCleanup(
|
|
155
156
|
plan: StewardPolicyCleanupPlan,
|
|
156
157
|
opts: { dryRun: boolean; updatedBy?: string },
|
|
157
|
-
): StewardPolicyCleanupResult {
|
|
158
|
+
): Promise<StewardPolicyCleanupResult> {
|
|
158
159
|
const updatedBy = opts.updatedBy ?? "steward-policy-cleanup-1955";
|
|
159
160
|
const log: string[] = [];
|
|
160
161
|
let applied = 0;
|
|
@@ -184,9 +185,9 @@ export function applyStewardPolicyCleanup(
|
|
|
184
185
|
// A stop recorded on EITHER half survives the merge — never lift an operator's stop (same
|
|
185
186
|
// rule as the provision-time collapse in steward.ts).
|
|
186
187
|
if (action.carriesStop && into.enabled !== false) {
|
|
187
|
-
|
|
188
|
+
(await setConfigAsync("spawn-policy", into.name, { ...into, enabled: false }, updatedBy));
|
|
188
189
|
}
|
|
189
|
-
|
|
190
|
+
(await deleteConfigAsync("spawn-policy", action.policy, updatedBy));
|
|
190
191
|
applied++;
|
|
191
192
|
}
|
|
192
193
|
continue;
|
|
@@ -199,8 +200,8 @@ export function applyStewardPolicyCleanup(
|
|
|
199
200
|
}
|
|
200
201
|
log.push(`RENAME ${action.policy} -> ${action.into} (cwd ${action.cwdFrom} -> ${action.cwdTo})`);
|
|
201
202
|
if (!opts.dryRun) {
|
|
202
|
-
|
|
203
|
-
|
|
203
|
+
(await setConfigAsync("spawn-policy", action.into, { ...current, name: action.into, ...repoDerivedFields(action.repoRoot) }, updatedBy));
|
|
204
|
+
(await deleteConfigAsync("spawn-policy", action.policy, updatedBy));
|
|
204
205
|
applied++;
|
|
205
206
|
}
|
|
206
207
|
continue;
|
|
@@ -213,7 +214,7 @@ export function applyStewardPolicyCleanup(
|
|
|
213
214
|
}
|
|
214
215
|
log.push(`CWD ${action.policy}: ${action.cwdFrom} -> ${action.cwdTo}`);
|
|
215
216
|
if (!opts.dryRun) {
|
|
216
|
-
|
|
217
|
+
(await setConfigAsync("spawn-policy", action.policy, { ...current, ...repoDerivedFields(action.repoRoot) }, updatedBy));
|
|
217
218
|
applied++;
|
|
218
219
|
}
|
|
219
220
|
}
|
package/src/steward.ts
CHANGED
|
@@ -153,7 +153,7 @@ async function collapseLegacyStewardPolicies(canonicalName: string, repoRoot: st
|
|
|
153
153
|
}
|
|
154
154
|
if (legacy.enabled === false) inheritedEnabled = false;
|
|
155
155
|
await deleteConfigAsync("spawn-policy", legacyName, "steward-legacy-collapse");
|
|
156
|
-
getLifecycleManager().onConfigChanged("spawn-policy", legacyName);
|
|
156
|
+
(await getLifecycleManager().onConfigChanged("spawn-policy", legacyName));
|
|
157
157
|
console.warn(`[steward] collapsed legacy steward policy '${legacyName}' into '${canonicalName}' (#1955)`);
|
|
158
158
|
}
|
|
159
159
|
return inheritedEnabled;
|
|
@@ -195,6 +195,6 @@ export async function ensureRepoStewardAsync(repoRoot: string, owningOrchestrato
|
|
|
195
195
|
if (existing && !stewardPolicyDiffers(existing.value, desired)) return name;
|
|
196
196
|
|
|
197
197
|
await setConfigAsync("spawn-policy", name, desired, "steward-autoprovision");
|
|
198
|
-
getLifecycleManager().onConfigChanged("spawn-policy", name);
|
|
198
|
+
(await getLifecycleManager().onConfigChanged("spawn-policy", name));
|
|
199
199
|
return name;
|
|
200
200
|
}
|
|
@@ -5,18 +5,20 @@ import { listOrchestratorsAsync } from "./db/orchestrators-async";
|
|
|
5
5
|
import { listHostViewsAsync } from "./db/hosts-async";
|
|
6
6
|
import { providerQuotaBandsFor, advertisedProvidersFrom } from "./spawn-targets";
|
|
7
7
|
import { dispatchPolicyFor } from "./routing-policy-store";
|
|
8
|
-
import { providerPlacementReady } from "./spawn-placement";
|
|
8
|
+
import { providerPlacementReady, spawnHostCapAdmission } from "./spawn-placement";
|
|
9
9
|
import { apiOverflowContextAsync, CLAUDE_API_PROVIDER } from "./claude-api-overflow";
|
|
10
10
|
import { apiExpiryPaceAsync } from "./claude-api-expiry";
|
|
11
11
|
import { liveTargetAdmission } from "./dispatch-availability";
|
|
12
12
|
|
|
13
13
|
/** Reader-gateway shell for production callers. The ranking core remains the pure sync function. */
|
|
14
|
-
export type DispatchSnapshot = DispatchContext & Required<Pick<DispatchContext, "now" | "catalog" | "bands" | "policy" | "preferences" | "advertisedProviders" | "targetAvailable">> & { probeUncertainty: Set<string
|
|
14
|
+
export type DispatchSnapshot = DispatchContext & Required<Pick<DispatchContext, "now" | "catalog" | "bands" | "policy" | "preferences" | "advertisedProviders" | "targetAvailable">> & { probeUncertainty: Set<string>; pinnedHostAtAgentCap?: boolean };
|
|
15
15
|
|
|
16
16
|
export async function captureDispatchContext(ctx: Omit<DispatchContext, "policy" | "bands" | "catalog"> = {}): Promise<DispatchSnapshot> {
|
|
17
17
|
const now = ctx.now ?? Date.now();
|
|
18
18
|
const [snapshot, orchestrators, hostViews] = await Promise.all([providerQuotaRoutingSnapshotAsync(now), listOrchestratorsAsync(), listHostViewsAsync()]);
|
|
19
19
|
const { targetAdmission: assess, targetUnavailableReason } = liveTargetAdmission(orchestrators, hostViews, snapshot.catalog, ctx.orchestratorId, ctx.spawnCap);
|
|
20
|
+
const pinnedHost = orchestrators.find(host => host.id === ctx.orchestratorId);
|
|
21
|
+
const pinnedView = pinnedHost && hostViews.find(view => view.id === pinnedHost.hostId);
|
|
20
22
|
const probeUncertainty = new Set<string>();
|
|
21
23
|
const targetAdmission = (target: Parameters<typeof assess>[0]) => {
|
|
22
24
|
const result = assess(target);
|
|
@@ -42,6 +44,7 @@ export async function captureDispatchContext(ctx: Omit<DispatchContext, "policy"
|
|
|
42
44
|
targetUnavailableReason,
|
|
43
45
|
targetAdmission,
|
|
44
46
|
probeUncertainty,
|
|
47
|
+
pinnedHostAtAgentCap: Boolean(pinnedView && spawnHostCapAdmission(ctx.spawnCap)(pinnedView)),
|
|
45
48
|
bands,
|
|
46
49
|
policy: dispatchPolicyFor(snapshot.policy),
|
|
47
50
|
catalog: snapshot.catalog,
|
package/src/task-dispatcher.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { isOpenAiApiModel } from "@humwick/sdk";
|
|
1
|
+
import { isOpenAiApiModel, ValidationError } from "@humwick/sdk";
|
|
2
2
|
// #839 — the declarative task dispatcher.
|
|
3
3
|
//
|
|
4
4
|
// A pure function from (Task work-shape + live system state) → a concrete spawn
|
|
@@ -311,7 +311,7 @@ export function dispatchTask(shape: TaskDispatch | undefined, pin: DispatchPin =
|
|
|
311
311
|
if (ctx.mustResolveAvailable && bandRank(bandFor(target.provider, bands)) > bandRank("normal")) warnings.push(`[CRITICAL] mustResolveAvailable: degraded to ${target.provider} (${bandFor(target.provider, bands)} band). Contention likely.`);
|
|
312
312
|
}
|
|
313
313
|
if (ctx.targetAvailable && !ctx.targetAvailable(target)) {
|
|
314
|
-
throw new
|
|
314
|
+
throw new ValidationError(ctx.targetUnavailableReason?.(target) ?? `No eligible online host runs ${target.provider}/${target.model ?? "default"}${target.effort ? ` at effort ${target.effort}` : ""}.`);
|
|
315
315
|
}
|
|
316
316
|
if (factors.preferences) factors.preferences = { ...factors.preferences, excluded: preferenceExclusions(preferences, factors.ranking, (p) => eligibility(p) ?? (!advertised.has(p) ? "not-advertised" : undefined)) };
|
|
317
317
|
// Record the FINAL provider's band + the chosen model's window for transparency.
|
package/src/token-db.ts
CHANGED
|
@@ -324,8 +324,8 @@ export function getTokenProfile(id: string): TokenProfile | null {
|
|
|
324
324
|
return row ? rowToProfile(row) : null;
|
|
325
325
|
}
|
|
326
326
|
|
|
327
|
-
export function upsertTokenProfile(input: CreateTokenProfileInput): TokenProfile {
|
|
328
|
-
const now =
|
|
327
|
+
export function upsertTokenProfile(input: CreateTokenProfileInput, submittedAt: number = Date.now()): TokenProfile {
|
|
328
|
+
const now = submittedAt;
|
|
329
329
|
const id = input.id ?? slugify(input.name);
|
|
330
330
|
const existing = getTokenProfile(id);
|
|
331
331
|
if (existing?.builtIn) throw new Error("built-in token profiles cannot be modified");
|
package/src/token-usage-async.ts
CHANGED
|
@@ -5,12 +5,10 @@ import type { Message } from "./types";
|
|
|
5
5
|
// of src/db directly (the transport-thinness ratchet, #348).
|
|
6
6
|
import { getGateway } from "./db/gateway.ts";
|
|
7
7
|
import type { SpawnBudgetReadback, WorkflowRunBudgetReadback } from "./db/spawn-budget.ts";
|
|
8
|
-
import type { aggregateSessionTokenUsage, recordSessionTokenUsage, SessionTokenUsageAggregate
|
|
8
|
+
import type { aggregateSessionTokenUsage, recordSessionTokenUsage, SessionTokenUsageAggregate } from "./db/token-usage.ts";
|
|
9
9
|
|
|
10
10
|
export const recordSessionTokenUsageAsync = async (input: Parameters<typeof recordSessionTokenUsage>[0]) => {
|
|
11
|
-
const { budgetNotices, ...result } = await getGateway().write("tokenUsage.record", { input }, { critical: false }) as unknown as {
|
|
12
|
-
record: SessionTokenUsageRecord;
|
|
13
|
-
inserted: boolean;
|
|
11
|
+
const { budgetNotices, ...result } = await getGateway().write("tokenUsage.record", { input }, { critical: false }) as unknown as ReturnType<typeof recordSessionTokenUsage> & {
|
|
14
12
|
budgetNotices: Message[];
|
|
15
13
|
};
|
|
16
14
|
publishBudgetNotices(budgetNotices);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
+
import { framed } from "./hub-metrics";
|
|
1
2
|
import { userSinkId, canonicalHumanAgentId } from "@humwick/sdk";
|
|
2
3
|
import { listUsers } from "./db/users";
|
|
3
|
-
import { listPendingReplyObligationsAsync } from "./db/message-reads-async";
|
|
4
|
-
import { getLatestMessageIdAsync } from "./db/message-reads-async";
|
|
4
|
+
import { listPendingReplyObligationsAsync, getLatestMessageIdAsync } from "./db/message-reads-async";
|
|
5
5
|
import { optedInNotificationRecipients } from "./db/notification-subscriptions";
|
|
6
6
|
import { routeNotification } from "./notification-router";
|
|
7
7
|
import { subscribeRelayEvents } from "./events";
|
|
@@ -12,7 +12,7 @@ export async function reconcileUserAwaitingReply(previous?: string): Promise<str
|
|
|
12
12
|
const [pending, latestId] = await Promise.all([Promise.all(listUsers().map(user => listPendingReplyObligationsAsync(canonicalHumanAgentId(userSinkId(user.id)), 1, true))).then(rows => rows.flat()), getLatestMessageIdAsync()]);
|
|
13
13
|
const signature = JSON.stringify([recipients, pending.length > 0]);
|
|
14
14
|
if (signature === previous) return signature;
|
|
15
|
-
routeNotification({
|
|
15
|
+
await routeNotification({
|
|
16
16
|
type: "user.awaiting_reply", scope: {}, recipients: [],
|
|
17
17
|
message: {
|
|
18
18
|
body: pending.length ? "The operator has an unanswered message." : "The operator has no unanswered messages.",
|
|
@@ -30,13 +30,13 @@ export function startUserAwaitingReply(): () => void {
|
|
|
30
30
|
const unsubscribe = subscribeRelayEvents(event => {
|
|
31
31
|
if (event.type.startsWith("message.") && event.data.to !== "hue:office") dirty = true;
|
|
32
32
|
});
|
|
33
|
-
const timer = setInterval(() => {
|
|
33
|
+
const timer = setInterval(framed("timer user-awaiting-reply", () => {
|
|
34
34
|
ticks++;
|
|
35
35
|
if ((!dirty && ticks % 30 !== 0) || running) return;
|
|
36
36
|
dirty = false; running = true;
|
|
37
37
|
void reconcileUserAwaitingReply(signature).then(value => { signature = value; }).catch(error => {
|
|
38
38
|
dirty = true; console.error("user.awaiting_reply reconciliation failed", error);
|
|
39
39
|
}).finally(() => { running = false; });
|
|
40
|
-
}, 1000);
|
|
40
|
+
}), 1000);
|
|
41
41
|
return () => { clearInterval(timer); unsubscribe(); };
|
|
42
42
|
}
|