@desplega.ai/agent-swarm 1.131.0 → 1.133.1
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/README.md +2 -2
- package/dist/{actions-w53mbns9.js → actions-cskpayd7.js} +11 -9
- package/dist/{anthropic-messages-rjmd2e7n.js → anthropic-messages-tpxtbx7b.js} +28 -12
- package/dist/{app-m9gwqsqv.js → app-ang77nbb.js} +8 -6
- package/dist/{assistant-bp65m6f3.js → assistant-b4exebdw.js} +16 -13
- package/dist/{azure-openai-responses-c0yjmbfd.js → azure-openai-responses-m3921t4y.js} +8 -8
- package/dist/{boot-reembed-62p0at2k.js → boot-reembed-ps2aftpb.js} +9 -7
- package/dist/{boot-reembed-xmfp6wdh.js → boot-reembed-znyk3nxb.js} +10 -8
- package/dist/{boot-scrub-logs-rr8q2dms.js → boot-scrub-logs-2ax3xgz1.js} +7 -5
- package/dist/{claude-adapter-2y47mrkd.js → claude-adapter-3ct8kgxw.js} +13 -9
- package/dist/{claude-managed-adapter-gv19tdew.js → claude-managed-adapter-akx4ntf2.js} +2 -2
- package/dist/{cli-t1xze5qh.js → cli-13w2hwkh.js} +1 -1
- package/dist/{cli-efxfnq6q.js → cli-1532szb1.js} +8 -6
- package/dist/{cli-d2tfkcga.js → cli-23d3rseb.js} +33 -17
- package/dist/{cli-nm5gtp1x.js → cli-2a75z9c5.js} +196 -7
- package/dist/{cli-fywms69x.js → cli-2t30rj0d.js} +1 -1
- package/dist/{cli-cvgjwnh1.js → cli-3c3tdgab.js} +10 -10
- package/dist/{cli-pm6xbh84.js → cli-3zzxa9jz.js} +46 -16
- package/dist/{cli-cdeg08wx.js → cli-4k6233gc.js} +1 -1
- package/dist/{cli-t55yw3a1.js → cli-5p2tz05r.js} +2 -2
- package/dist/{cli-0rcyq6d9.js → cli-5z2yhzvd.js} +125 -47
- package/dist/{cli-3kf51j15.js → cli-6zfq31nj.js} +9 -3
- package/dist/{cli-er3a4bb0.js → cli-8m9de10a.js} +6 -1
- package/dist/{cli-gm9cbhbq.js → cli-8t14vg9w.js} +27 -8
- package/dist/{cli-72q8m8gk.js → cli-9nfc2es8.js} +6 -6
- package/dist/{cli-5ze9rv97.js → cli-9ta3pwms.js} +11 -4
- package/dist/{cli-78xwvkhj.js → cli-avr0ns7z.js} +2 -2
- package/dist/{cli-n6h8qt8n.js → cli-c897wyhw.js} +12 -7
- package/dist/{cli-2q72qz2s.js → cli-dgk20ft7.js} +15 -6
- package/dist/cli-et1bbwqf.js +13 -0
- package/dist/{cli-bqw0mt1n.js → cli-f5w27pj3.js} +3 -3
- package/dist/{cli-2wadx7p2.js → cli-f8dre4bz.js} +2 -2
- package/dist/{cli-e7ckcg4v.js → cli-ftwpv451.js} +170 -387
- package/dist/{cli-g6b8x1h8.js → cli-g854s2dw.js} +1 -1
- package/dist/{cli-5kx36evn.js → cli-ggmdxeqa.js} +13 -8
- package/dist/cli-hkwfe3qj.js +530 -0
- package/dist/{cli-5dsbcjjw.js → cli-jqwnqx9m.js} +1 -1
- package/dist/{cli-9dr5qzc0.js → cli-ny122vh4.js} +21 -10
- package/dist/{cli-5v4rw6yd.js → cli-pvzqhbs9.js} +2 -2
- package/dist/cli-pzq5rjym.js +15 -0
- package/dist/{cli-xpxde7rm.js → cli-qes8ef67.js} +48 -30
- package/dist/{cli-sajgpkqg.js → cli-qs9hhsvb.js} +1723 -325
- package/dist/cli-qys3rhhz.js +27 -0
- package/dist/{cli-rzbpmxdr.js → cli-r6tpm37h.js} +2 -2
- package/dist/{cli-qv61hp37.js → cli-rch80c76.js} +2 -2
- package/dist/{cli-0258203w.js → cli-rpp0x4zy.js} +137 -17
- package/dist/{cli-5n6e5yfn.js → cli-s1k0wxhe.js} +12 -7
- package/dist/{cli-psh3c4va.js → cli-sfd9v7sj.js} +1 -1
- package/dist/{cli-70xqj0z3.js → cli-sh3ytsyj.js} +49 -39
- package/dist/{cli-zsspvvm2.js → cli-w1mp9jy7.js} +1 -1
- package/dist/{cli-d3x3x1c9.js → cli-xdb4mpnp.js} +2 -2
- package/dist/{cli-57khth04.js → cli-xmyqv00z.js} +120 -4
- package/dist/{cli-yw8vghx2.js → cli-xv8t8p3c.js} +65 -32
- package/dist/{cli-f1am9szv.js → cli-xxv5pn4f.js} +1 -1
- package/dist/{cli-t76vw5db.js → cli-y08jvxzx.js} +601 -140
- package/dist/{cli-a4jzdpa3.js → cli-zfbf3srj.js} +650 -245
- package/dist/{cli-a40rnf71.js → cli-zmq89k34.js} +6 -6
- package/dist/{cli-qmdnhpej.js → cli-zr9q011v.js} +23 -13
- package/dist/cli.js +22 -22
- package/dist/{codex-adapter-d24q75wk.js → codex-adapter-bef93pq4.js} +9 -7
- package/dist/{codex-hook-hq54t9ft.js → codex-hook-e8dba65p.js} +3 -2
- package/dist/{codex-session-runner-g50vcsex.js → codex-session-runner-5pkxys7x.js} +9 -7
- package/dist/{commands-c3nrc5hg.js → commands-e23s1bff.js} +9 -7
- package/dist/{db-nt7fg3tw.js → db-m3nabatn.js} +17 -5
- package/dist/{google-generative-ai-hysrd8qx.js → google-generative-ai-8maw55xh.js} +11 -8
- package/dist/{google-vertex-p5arrga0.js → google-vertex-8vjqmx8g.js} +11 -8
- package/dist/{handlers-fkr6swat.js → handlers-akazedvr.js} +16 -13
- package/dist/{hook-77wpvnjc.js → hook-ze4cpf0v.js} +55 -41
- package/dist/{hook-g019yehy.js → hook-zfqyyenw.js} +10 -7
- package/dist/{http-jewj0syk.js → http-sja0n6kw.js} +730 -150
- package/dist/index-0gr8vd6k.js +39 -0
- package/dist/{index-7n2xpbd4.js → index-354vkhdv.js} +154 -74
- package/dist/{index-070v4eyb.js → index-5qthek5t.js} +2 -3
- package/dist/{index-hfvggd0z.js → index-95t3cqq5.js} +16 -14
- package/dist/{index-9znhar3x.js → index-sea66619.js} +3 -4
- package/dist/{index-6gm5he8h.js → index-vpn36mma.js} +15 -13
- package/dist/{keepalive-j0fjvqfd.js → keepalive-3sp3meqj.js} +16 -10
- package/dist/{lead-1n8x30xe.js → lead-mefeewkf.js} +39 -36
- package/dist/{maintenance-gvev11sa.js → maintenance-8tbrbjfg.js} +10 -8
- package/dist/mistral-conversations-00zrp7g4.js +717 -0
- package/dist/{oauth-refresh-sweep-s9ecsvh0.js → oauth-refresh-sweep-srjwjz6m.js} +8 -6
- package/dist/{onboard-pvm5b38w.js → onboard-mt2tgyjg.js} +7 -7
- package/dist/{openai-codex-responses-5g27pd6f.js → openai-codex-responses-map32h2s.js} +18 -18
- package/dist/{openai-completions-3vkmfz2a.js → openai-completions-w871b1cq.js} +12 -11
- package/dist/{openai-responses-dg4t7j7a.js → openai-responses-b0j7xnw8.js} +15 -12
- package/dist/{opencode-adapter-1gm38aba.js → opencode-adapter-b39jefcj.js} +5 -3
- package/dist/{openrouter-images-g3gm8931.js → openrouter-images-srfkywy0.js} +4 -4
- package/dist/{otel-impl-p6jvgd9c.js → otel-impl-z6pxt3j9.js} +224 -9
- package/dist/{pi-mono-adapter-t091s27g.js → pi-mono-adapter-btvqmj58.js} +1138 -408
- package/dist/{pricing-refresh-k49rcyed.js → pricing-refresh-kyq8cezh.js} +9 -7
- package/dist/{rbac-roles-cr80g96t.js → rbac-roles-3ryfrfna.js} +8 -6
- package/dist/{rbac-roles-30pspvy7.js → rbac-roles-6qfvbee1.js} +9 -7
- package/dist/{render-v2-xm457ng1.js → render-v2-p61ppjey.js} +8 -6
- package/dist/{seed-pricing-yhpv35fr.js → seed-pricing-j56bbj4y.js} +8 -6
- package/dist/{setup-nytnmwwr.js → setup-tpr6c1kn.js} +2 -2
- package/dist/{worker-msytr2cw.js → worker-9w1v0mbb.js} +39 -36
- package/openapi.json +542 -16
- package/package.json +6 -6
- package/src/be/budget-refusal-notify.ts +14 -7
- package/src/be/db-queries/task-artifacts.ts +182 -0
- package/src/be/db.ts +783 -169
- package/src/be/events.ts +5 -0
- package/src/be/migrations/130_scratch_script_retention_grace.sql +6 -0
- package/src/be/migrations/131_session_logs_created_at_index.sql +2 -0
- package/src/be/migrations/132_multi_runtime_instances.sql +44 -0
- package/src/be/migrations/133_workflow_run_trigger_type.sql +12 -0
- package/src/be/migrations/135_backfill_task_pull_request_attachments.sql +228 -0
- package/src/be/migrations/136_task_requester_provenance.sql +37 -0
- package/src/be/migrations/137_memory_retrieval_composite_index.sql +1 -0
- package/src/be/multi-runtime.ts +430 -0
- package/src/be/scripts/db.ts +43 -1
- package/src/be/scripts/extract-schema.ts +3 -1
- package/src/be/scripts/retention.ts +164 -0
- package/src/be/scripts/run-saved.ts +16 -1
- package/src/be/scripts/typecheck.ts +3 -2
- package/src/be/seed-skills/index.ts +7 -0
- package/src/be/steering.ts +1 -1
- package/src/be/swarm-config-guard.ts +18 -0
- package/src/commands/credential-wait.ts +54 -0
- package/src/commands/onboard/steps/core-credentials.tsx +1 -1
- package/src/commands/onboard/steps/custom-templates.tsx +1 -1
- package/src/commands/onboard/steps/harness-credentials.tsx +1 -1
- package/src/commands/onboard/steps/health-check.tsx +1 -1
- package/src/commands/onboard/steps/start.tsx +1 -1
- package/src/commands/profile-sync-audit.ts +56 -0
- package/src/commands/profile-sync.ts +287 -15
- package/src/commands/provider-credentials.ts +46 -19
- package/src/commands/runner.ts +196 -33
- package/src/commands/templates.ts +22 -0
- package/src/github/handlers.ts +55 -9
- package/src/heartbeat/heartbeat.ts +71 -12
- package/src/hooks/hook.ts +49 -33
- package/src/http/active-sessions.ts +11 -1
- package/src/http/agents.ts +261 -30
- package/src/http/all-routes.ts +1 -0
- package/src/http/config.ts +13 -2
- package/src/http/core.ts +102 -4
- package/src/http/db-query-bounded.ts +313 -0
- package/src/http/db-query-shared.ts +249 -0
- package/src/http/db-query.ts +54 -42
- package/src/http/events.ts +2 -0
- package/src/http/index.ts +27 -2
- package/src/http/mcp-bridge.ts +37 -3
- package/src/http/mcp.ts +12 -0
- package/src/http/memory.ts +13 -2
- package/src/http/openapi.ts +1 -0
- package/src/http/poll.ts +70 -27
- package/src/http/route-def.ts +43 -9
- package/src/http/schedules.ts +2 -2
- package/src/http/scripts.ts +31 -4
- package/src/http/session-data.ts +44 -0
- package/src/http/tasks.ts +2 -2
- package/src/http/users.ts +74 -52
- package/src/http/webhooks.ts +5 -2
- package/src/http/workflows.ts +1 -4
- package/src/http/x.ts +14 -0
- package/src/integrations/kapso/inbound.ts +1 -1
- package/src/jira/outbound.ts +39 -8
- package/src/jira/webhook-lifecycle.ts +13 -2
- package/src/linear/outbound.ts +43 -10
- package/src/oauth/keepalive.ts +13 -2
- package/src/prompts/base-prompt.ts +1 -1
- package/src/prompts/session-templates.ts +45 -7
- package/src/providers/claude-adapter.ts +6 -0
- package/src/providers/claude-managed-models.ts +34 -10
- package/src/providers/codex-adapter.ts +6 -0
- package/src/providers/opencode-adapter.ts +6 -0
- package/src/providers/pi-mono-adapter.ts +8 -0
- package/src/providers/pricing-sources.md +24 -0
- package/src/queue-stall-alarm.ts +216 -0
- package/src/scheduler/scheduler.ts +7 -0
- package/src/script-workflows/executor.ts +2 -1
- package/src/scripts-runtime/executors/native.ts +2 -1
- package/src/scripts-runtime/executors/types.ts +5 -0
- package/src/scripts-runtime/loader.ts +5 -0
- package/src/scripts-runtime/swarm-config.ts +8 -0
- package/src/scripts-runtime/swarm-sdk.ts +7 -0
- package/src/scripts-runtime/types/stdlib.d.ts +1 -0
- package/src/scripts-runtime/types/swarm-sdk.d.ts +1 -0
- package/src/tests/budget-claim-gate.test.ts +20 -0
- package/src/tests/claude-adapter.test.ts +32 -0
- package/src/tests/claude-managed-adapter.test.ts +38 -7
- package/src/tests/codex-adapter.test.ts +30 -0
- package/src/tests/create-task-validation.test.ts +128 -0
- package/src/tests/credential-wait.test.ts +67 -1
- package/src/tests/db-query.test.ts +711 -2
- package/src/tests/http-api-integration.test.ts +81 -0
- package/src/tests/http-users.test.ts +166 -1
- package/src/tests/identity-field-budget.test.ts +176 -0
- package/src/tests/mcp-tools-user.test.ts +34 -0
- package/src/tests/mcp-user-route.test.ts +17 -0
- package/src/tests/metrics-http.test.ts +44 -0
- package/src/tests/multi-runtime-registration.test.ts +2703 -0
- package/src/tests/openapi-response-contract.test.ts +24 -0
- package/src/tests/openapi-route-headers.test.ts +83 -0
- package/src/tests/opencode-adapter.test.ts +40 -0
- package/src/tests/outbound-listener-rejection.test.ts +138 -0
- package/src/tests/pi-mono-adapter.test.ts +98 -0
- package/src/tests/profile-sync-warning.test.ts +277 -0
- package/src/tests/profile-sync.test.ts +232 -6
- package/src/tests/prompt-template-session.test.ts +32 -3
- package/src/tests/queue-stall-alarm.test.ts +226 -0
- package/src/tests/requester-comms.test.ts +32 -0
- package/src/tests/runner-requester-profile.test.ts +38 -0
- package/src/tests/sandboxed-process.test.ts +45 -0
- package/src/tests/schedule-target-type.test.ts +38 -0
- package/src/tests/script-connections.test.ts +16 -3
- package/src/tests/scripts-external-api.test.ts +8 -3
- package/src/tests/scripts-http.test.ts +12 -0
- package/src/tests/scripts-retention.test.ts +384 -0
- package/src/tests/scripts-runtime-identity.test.ts +375 -0
- package/src/tests/scripts-runtime.test.ts +4 -3
- package/src/tests/sdk-allowlist.test.ts +47 -0
- package/src/tests/send-task-requested-by.test.ts +9 -0
- package/src/tests/session-costs.test.ts +506 -1
- package/src/tests/shutdown-error-scrubbing.test.ts +92 -0
- package/src/tests/steering-core.test.ts +28 -0
- package/src/tests/task-artifacts.test.ts +386 -0
- package/src/tests/task-attachments-schema.test.ts +17 -1
- package/src/tests/task-completion-idempotency.test.ts +57 -0
- package/src/tests/task-pull-request-backfill-migration.test.ts +321 -0
- package/src/tests/update-profile-api.test.ts +67 -39
- package/src/tests/update-profile-auth.test.ts +48 -4
- package/src/tests/user-attribution-migration.test.ts +54 -0
- package/src/tests/user-identity.test.ts +72 -0
- package/src/tests/workflow-async-v2.test.ts +39 -1
- package/src/tests/workflow-http-v2.test.ts +3 -2
- package/src/tests/workflow-mcp-trigger-schema.test.ts +52 -3
- package/src/tests/workflow-retry-v2.test.ts +45 -1
- package/src/tests/workflow-swarm-script.test.ts +14 -5
- package/src/tools/db-query.ts +18 -8
- package/src/tools/get-task-details.ts +24 -3
- package/src/tools/manage-user.ts +36 -3
- package/src/tools/poll-task.ts +93 -14
- package/src/tools/script-common.ts +5 -0
- package/src/tools/send-task.ts +1 -4
- package/src/tools/store-progress.ts +13 -2
- package/src/tools/swarm-config/delete-config.ts +9 -0
- package/src/tools/swarm-config/set-config.ts +3 -2
- package/src/tools/task-action.ts +30 -0
- package/src/tools/task-tool-ctx.ts +8 -1
- package/src/tools/update-profile.ts +16 -21
- package/src/tools/utils.ts +5 -0
- package/src/tools/workflows/trigger-workflow.ts +7 -1
- package/src/types.ts +165 -1
- package/src/utils/github-pull-request.ts +76 -0
- package/src/utils/identity-field-budget.ts +73 -0
- package/src/utils/multi-runtime.ts +20 -0
- package/src/utils/requester-comms.ts +24 -0
- package/src/utils/sandboxed-process.ts +40 -14
- package/src/workflows/engine.ts +22 -2
- package/src/workflows/executors/swarm-script.ts +24 -1
- package/src/workflows/resume.ts +19 -11
- package/src/workflows/retry-poller.ts +1 -0
- package/src/workflows/triggers.ts +4 -0
- package/templates/schedules/daily-compounding-reflection/content.md +12 -3
- package/templates/skills/db-query-guidance/config.json +14 -0
- package/templates/skills/db-query-guidance/content.md +57 -0
- package/dist/cli-3te4jdkm.js +0 -225
- package/dist/cli-bmze986d.js +0 -7
- package/dist/cli-kh3ba2zf.js +0 -607
- package/dist/index-hp1kdbjj.js +0 -36
- package/dist/mistral-conversations-81fwav0j.js +0 -30578
- package/dist/otel-nqa12wf3.js +0 -3149
- package/dist/{pi-messages-tqj8q6b9.js → pi-messages-sssy32x4.js} +3 -3
|
@@ -444,35 +444,62 @@ export async function buildCredStatusReport(
|
|
|
444
444
|
}
|
|
445
445
|
|
|
446
446
|
/**
|
|
447
|
-
*
|
|
448
|
-
*
|
|
449
|
-
*
|
|
450
|
-
*
|
|
447
|
+
* Strict PUT of credential readiness to the API: propagates network errors
|
|
448
|
+
* and non-2xx responses. The post-credential-wait boot path uses this — after
|
|
449
|
+
* a stale-runtime revival this write is the only transition out of
|
|
450
|
+
* `waiting_for_credentials`, so the caller must be able to observe (and
|
|
451
|
+
* retry) a failure instead of proceeding as though it landed.
|
|
451
452
|
*
|
|
452
453
|
* Posts to the existing `PUT /api/agents/:id/credential-status` endpoint
|
|
453
|
-
* which (per migration 055)
|
|
454
|
-
*
|
|
455
|
-
*
|
|
454
|
+
* which (per migration 055) accepts an optional `cred_status` field. `ready`
|
|
455
|
+
* and `missing` are always included so legacy `agents.credentialMissing` and
|
|
456
|
+
* `agents.status='waiting_for_credentials'` keep tracking; the snapshot is
|
|
457
|
+
* optional so a hiccup while building it cannot lose the transition.
|
|
458
|
+
*/
|
|
459
|
+
export async function sendCredStatusReport(
|
|
460
|
+
apiUrl: string,
|
|
461
|
+
apiKey: string,
|
|
462
|
+
agentId: string,
|
|
463
|
+
runtimeInstanceId: string | undefined,
|
|
464
|
+
report: { ready: boolean; missing: string[]; credStatus?: AgentCredStatus },
|
|
465
|
+
): Promise<void> {
|
|
466
|
+
const res = await fetch(`${apiUrl}/api/agents/${encodeURIComponent(agentId)}/credential-status`, {
|
|
467
|
+
method: "PUT",
|
|
468
|
+
headers: {
|
|
469
|
+
Authorization: `Bearer ${apiKey}`,
|
|
470
|
+
"X-Agent-ID": agentId,
|
|
471
|
+
...(runtimeInstanceId ? { "X-Runtime-Instance-ID": runtimeInstanceId } : {}),
|
|
472
|
+
"Content-Type": "application/json",
|
|
473
|
+
},
|
|
474
|
+
body: JSON.stringify({
|
|
475
|
+
ready: report.ready,
|
|
476
|
+
missing: report.missing,
|
|
477
|
+
...(report.credStatus ? { cred_status: report.credStatus } : {}),
|
|
478
|
+
}),
|
|
479
|
+
});
|
|
480
|
+
if (!res.ok) {
|
|
481
|
+
const body = await res.text().catch(() => "");
|
|
482
|
+
throw new Error(`credential-status report failed: ${res.status} ${body}`.trim());
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
/**
|
|
487
|
+
* Fire-and-forget wrapper around {@link sendCredStatusReport}. Used by the
|
|
488
|
+
* post-task cache-miss path (`runner.ts`), where a stale dashboard is
|
|
489
|
+
* acceptable and blocking the worker is not.
|
|
456
490
|
*/
|
|
457
491
|
export async function reportCredStatus(
|
|
458
492
|
apiUrl: string,
|
|
459
493
|
apiKey: string,
|
|
460
494
|
agentId: string,
|
|
495
|
+
runtimeInstanceId: string | undefined,
|
|
461
496
|
credStatus: AgentCredStatus,
|
|
462
497
|
): Promise<void> {
|
|
463
498
|
try {
|
|
464
|
-
await
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
"X-Agent-ID": agentId,
|
|
469
|
-
"Content-Type": "application/json",
|
|
470
|
-
},
|
|
471
|
-
body: JSON.stringify({
|
|
472
|
-
ready: credStatus.ready,
|
|
473
|
-
missing: credStatus.missing,
|
|
474
|
-
cred_status: credStatus,
|
|
475
|
-
}),
|
|
499
|
+
await sendCredStatusReport(apiUrl, apiKey, agentId, runtimeInstanceId, {
|
|
500
|
+
ready: credStatus.ready,
|
|
501
|
+
missing: credStatus.missing,
|
|
502
|
+
credStatus,
|
|
476
503
|
});
|
|
477
504
|
} catch (err) {
|
|
478
505
|
console.warn(`[cred-status] POST failed (non-fatal): ${err}`);
|
package/src/commands/runner.ts
CHANGED
|
@@ -65,9 +65,15 @@ import { interpolate } from "../utils/template.ts";
|
|
|
65
65
|
import { detectVcsProvider } from "../vcs/index.ts";
|
|
66
66
|
import { validateJsonSchema } from "../workflows/json-schema-validator.ts";
|
|
67
67
|
import { buildContextPreamble, buildResumeContextPreamble } from "./context-preamble.ts";
|
|
68
|
-
import {
|
|
68
|
+
import {
|
|
69
|
+
awaitCredentials,
|
|
70
|
+
BootMaxWaitExceededError,
|
|
71
|
+
EX_CONFIG,
|
|
72
|
+
retryBootStep,
|
|
73
|
+
} from "./credential-wait.ts";
|
|
69
74
|
import {
|
|
70
75
|
contentSha256,
|
|
76
|
+
prependProfileSyncRejectionBanner,
|
|
71
77
|
resolveClaudeMdPath,
|
|
72
78
|
syncProfileFilesToServer,
|
|
73
79
|
writeIdentityBaselines,
|
|
@@ -80,6 +86,7 @@ import {
|
|
|
80
86
|
isCredCheckDisabled,
|
|
81
87
|
reportCredStatus,
|
|
82
88
|
reportLatestModel,
|
|
89
|
+
sendCredStatusReport,
|
|
83
90
|
} from "./provider-credentials.ts";
|
|
84
91
|
import {
|
|
85
92
|
type ResumeSessionCandidate,
|
|
@@ -481,6 +488,13 @@ export interface ApiConfig {
|
|
|
481
488
|
apiUrl: string;
|
|
482
489
|
apiKey: string;
|
|
483
490
|
agentId: string;
|
|
491
|
+
/**
|
|
492
|
+
* Per-boot identity for this worker PROCESS, as opposed to `agentId` (the
|
|
493
|
+
* logical agent). Sent as the X-Runtime-Instance-ID header on ping/close so
|
|
494
|
+
* a server can track this process's liveness and retire only this runtime.
|
|
495
|
+
* Servers ignore it unless MULTI_RUNTIME_ENABLED.
|
|
496
|
+
*/
|
|
497
|
+
runtimeInstanceId?: string;
|
|
484
498
|
}
|
|
485
499
|
|
|
486
500
|
export interface SteeringDispatchState {
|
|
@@ -589,6 +603,9 @@ async function pingServer(config: ApiConfig, _role: string): Promise<void> {
|
|
|
589
603
|
if (config.apiKey) {
|
|
590
604
|
headers.Authorization = `Bearer ${config.apiKey}`;
|
|
591
605
|
}
|
|
606
|
+
if (config.runtimeInstanceId) {
|
|
607
|
+
headers["X-Runtime-Instance-ID"] = config.runtimeInstanceId;
|
|
608
|
+
}
|
|
592
609
|
|
|
593
610
|
try {
|
|
594
611
|
await fetch(`${config.apiUrl}/ping`, {
|
|
@@ -608,6 +625,9 @@ async function closeAgent(config: ApiConfig, role: string): Promise<void> {
|
|
|
608
625
|
if (config.apiKey) {
|
|
609
626
|
headers.Authorization = `Bearer ${config.apiKey}`;
|
|
610
627
|
}
|
|
628
|
+
if (config.runtimeInstanceId) {
|
|
629
|
+
headers["X-Runtime-Instance-ID"] = config.runtimeInstanceId;
|
|
630
|
+
}
|
|
611
631
|
|
|
612
632
|
try {
|
|
613
633
|
console.log(`[${role}] Marking agent as offline...`);
|
|
@@ -2448,6 +2468,7 @@ async function registerActiveSession(
|
|
|
2448
2468
|
triggerType: session.triggerType,
|
|
2449
2469
|
taskDescription: session.taskDescription,
|
|
2450
2470
|
runnerSessionId: session.runnerSessionId,
|
|
2471
|
+
runtimeInstanceId: config.runtimeInstanceId,
|
|
2451
2472
|
}),
|
|
2452
2473
|
});
|
|
2453
2474
|
} catch {
|
|
@@ -2563,7 +2584,14 @@ interface Trigger {
|
|
|
2563
2584
|
text?: string;
|
|
2564
2585
|
}>;
|
|
2565
2586
|
cursorUpdates?: Array<{ channelId: string; ts: string }>; // Deferred cursor commits for channel_activity
|
|
2566
|
-
requestedBy?: {
|
|
2587
|
+
requestedBy?: {
|
|
2588
|
+
name: string;
|
|
2589
|
+
email?: string;
|
|
2590
|
+
role?: string;
|
|
2591
|
+
notes?: string;
|
|
2592
|
+
/** Structured communication preferences from `users.metadata.comms`. */
|
|
2593
|
+
comms?: { tone?: string; language?: string; verbosity?: string };
|
|
2594
|
+
};
|
|
2567
2595
|
// Phase 4 — budget_refused fields. The server emits this envelope from
|
|
2568
2596
|
// /api/poll and MCP task-action accept when an admission gate refuses to
|
|
2569
2597
|
// let the agent claim a task. Worker reads cause + reset/spend/budget for
|
|
@@ -2581,6 +2609,8 @@ interface PollOptions {
|
|
|
2581
2609
|
apiUrl: string;
|
|
2582
2610
|
apiKey: string;
|
|
2583
2611
|
agentId: string;
|
|
2612
|
+
/** Identifies the polling process so a retired runtime is not given work. */
|
|
2613
|
+
runtimeInstanceId?: string;
|
|
2584
2614
|
pollInterval: number;
|
|
2585
2615
|
pollTimeout: number;
|
|
2586
2616
|
since?: string; // Optional: for filtering finished tasks
|
|
@@ -2591,15 +2621,24 @@ type RequesterProfile = NonNullable<Trigger["requestedBy"]>;
|
|
|
2591
2621
|
export async function buildRequesterProfilePrompt(
|
|
2592
2622
|
requestedBy: RequesterProfile | undefined,
|
|
2593
2623
|
): Promise<string> {
|
|
2594
|
-
|
|
2595
|
-
|
|
2596
|
-
|
|
2624
|
+
const comms = requestedBy?.comms;
|
|
2625
|
+
const commsParts = [
|
|
2626
|
+
comms?.tone ? `tone: ${comms.tone}` : undefined,
|
|
2627
|
+
comms?.language ? `language: ${comms.language}` : undefined,
|
|
2628
|
+
comms?.verbosity ? `verbosity: ${comms.verbosity}` : undefined,
|
|
2629
|
+
].filter((part): part is string => Boolean(part));
|
|
2630
|
+
if (!requestedBy?.role && !requestedBy?.notes && commsParts.length === 0) return "";
|
|
2631
|
+
|
|
2632
|
+
const commsSection =
|
|
2633
|
+
commsParts.length > 0 ? `\nTheir communication preferences: ${commsParts.join(", ")}.` : "";
|
|
2634
|
+
const notes = requestedBy?.notes?.trim();
|
|
2597
2635
|
const notesSection = notes
|
|
2598
2636
|
? `\nTheir stated notes for how you should respond and act:\n${notes}`
|
|
2599
2637
|
: "";
|
|
2600
2638
|
const result = await resolveTemplateAsync("task.requester.profile", {
|
|
2601
|
-
requester_name: requestedBy
|
|
2602
|
-
requester_role_suffix: requestedBy
|
|
2639
|
+
requester_name: requestedBy?.name ?? "",
|
|
2640
|
+
requester_role_suffix: requestedBy?.role ? ` (${requestedBy.role})` : "",
|
|
2641
|
+
requester_comms_section: commsSection,
|
|
2603
2642
|
requester_notes_section: notesSection,
|
|
2604
2643
|
});
|
|
2605
2644
|
|
|
@@ -2623,6 +2662,7 @@ async function registerAgent(opts: {
|
|
|
2623
2662
|
* haven't migrated to passing it explicitly.
|
|
2624
2663
|
*/
|
|
2625
2664
|
harnessProvider?: ProviderName;
|
|
2665
|
+
runtimeInstanceId?: string;
|
|
2626
2666
|
}): Promise<{ serverCapabilities?: string[] }> {
|
|
2627
2667
|
const headers: Record<string, string> = {
|
|
2628
2668
|
"Content-Type": "application/json",
|
|
@@ -2654,6 +2694,7 @@ async function registerAgent(opts: {
|
|
|
2654
2694
|
maxTasks: opts.maxTasks,
|
|
2655
2695
|
provider,
|
|
2656
2696
|
harness_provider: harnessProvider,
|
|
2697
|
+
runtimeInstanceId: opts.runtimeInstanceId,
|
|
2657
2698
|
}),
|
|
2658
2699
|
});
|
|
2659
2700
|
|
|
@@ -2702,6 +2743,9 @@ async function pollForTriggerOnce(opts: PollOptions): Promise<Trigger | null> {
|
|
|
2702
2743
|
const headers: Record<string, string> = {
|
|
2703
2744
|
"X-Agent-ID": opts.agentId,
|
|
2704
2745
|
};
|
|
2746
|
+
if (opts.runtimeInstanceId) {
|
|
2747
|
+
headers["X-Runtime-Instance-ID"] = opts.runtimeInstanceId;
|
|
2748
|
+
}
|
|
2705
2749
|
if (opts.apiKey) {
|
|
2706
2750
|
headers.Authorization = `Bearer ${opts.apiKey}`;
|
|
2707
2751
|
}
|
|
@@ -3395,7 +3439,12 @@ async function spawnProviderProcess(
|
|
|
3395
3439
|
function bufferEvent(evt: BufferedEvent) {
|
|
3396
3440
|
eventBuffer.push(evt);
|
|
3397
3441
|
if (eventBuffer.length >= EVENT_BUFFER_MAX) {
|
|
3398
|
-
flushEvents()
|
|
3442
|
+
flushEvents().catch((err) =>
|
|
3443
|
+
console.error(
|
|
3444
|
+
"[runner] event flush failed:",
|
|
3445
|
+
scrubSecrets(err instanceof Error ? err.message : String(err)),
|
|
3446
|
+
),
|
|
3447
|
+
);
|
|
3399
3448
|
}
|
|
3400
3449
|
}
|
|
3401
3450
|
|
|
@@ -4086,7 +4135,12 @@ async function checkCompletedProcesses(
|
|
|
4086
4135
|
cancelledSignaled?.delete(taskId);
|
|
4087
4136
|
|
|
4088
4137
|
if (apiConfig) {
|
|
4089
|
-
removeActiveSession(apiConfig, taskId)
|
|
4138
|
+
removeActiveSession(apiConfig, taskId).catch((err) =>
|
|
4139
|
+
console.error(
|
|
4140
|
+
"[runner] active-session removal failed:",
|
|
4141
|
+
scrubSecrets(err instanceof Error ? err.message : String(err)),
|
|
4142
|
+
),
|
|
4143
|
+
);
|
|
4090
4144
|
}
|
|
4091
4145
|
|
|
4092
4146
|
// Detect VCS before finishing — last chance to link a PR
|
|
@@ -4699,8 +4753,16 @@ export async function runAgent(config: RunnerConfig, opts: RunnerOptions) {
|
|
|
4699
4753
|
let lastBedrockRefreshAt = 0;
|
|
4700
4754
|
const BEDROCK_REFRESH_INTERVAL_MS = 5 * 60 * 1000;
|
|
4701
4755
|
|
|
4756
|
+
// Fresh per boot and shared by registration, ping, and close: a restarted
|
|
4757
|
+
// process is a new runtime, but one process presents one identity.
|
|
4758
|
+
const runtimeInstanceId = crypto.randomUUID();
|
|
4759
|
+
|
|
4760
|
+
// Session MCP configs are built in provider adapters, which read this to
|
|
4761
|
+
// stamp the runtime identity onto worker tool calls.
|
|
4762
|
+
process.env.SWARM_RUNTIME_INSTANCE_ID = runtimeInstanceId;
|
|
4763
|
+
|
|
4702
4764
|
// Create API config for ping/close
|
|
4703
|
-
const apiConfig: ApiConfig = { apiUrl, apiKey, agentId };
|
|
4765
|
+
const apiConfig: ApiConfig = { apiUrl, apiKey, agentId, runtimeInstanceId };
|
|
4704
4766
|
|
|
4705
4767
|
// Setup graceful shutdown handlers with API config and runner state access
|
|
4706
4768
|
setupShutdownHandlers(role, apiConfig, () => state);
|
|
@@ -4821,22 +4883,32 @@ export async function runAgent(config: RunnerConfig, opts: RunnerOptions) {
|
|
|
4821
4883
|
}
|
|
4822
4884
|
};
|
|
4823
4885
|
|
|
4824
|
-
/**
|
|
4886
|
+
/** Register this boot's runtime with the current live state; propagates failure. */
|
|
4887
|
+
const registerCurrentRuntime = async () => {
|
|
4888
|
+
const reg = await registerAgent({
|
|
4889
|
+
apiUrl,
|
|
4890
|
+
apiKey,
|
|
4891
|
+
agentId,
|
|
4892
|
+
name: agentName,
|
|
4893
|
+
role,
|
|
4894
|
+
isLead,
|
|
4895
|
+
capabilities,
|
|
4896
|
+
maxTasks: state.maxConcurrent,
|
|
4897
|
+
harnessProvider: state.harnessProvider,
|
|
4898
|
+
runtimeInstanceId,
|
|
4899
|
+
});
|
|
4900
|
+
lastServerCapsRefreshAt = Date.now();
|
|
4901
|
+
await applyServerCapabilities(reg.serverCapabilities);
|
|
4902
|
+
};
|
|
4903
|
+
|
|
4904
|
+
/**
|
|
4905
|
+
* Best-effort wrapper for the periodic/fire-and-forget callers: the
|
|
4906
|
+
* dashboard tolerates a missed refresh. Recovery paths that must observe
|
|
4907
|
+
* failure use registerCurrentRuntime directly.
|
|
4908
|
+
*/
|
|
4825
4909
|
const reregisterAgent = async () => {
|
|
4826
4910
|
try {
|
|
4827
|
-
|
|
4828
|
-
apiUrl,
|
|
4829
|
-
apiKey,
|
|
4830
|
-
agentId,
|
|
4831
|
-
name: agentName,
|
|
4832
|
-
role,
|
|
4833
|
-
isLead,
|
|
4834
|
-
capabilities,
|
|
4835
|
-
maxTasks: state.maxConcurrent,
|
|
4836
|
-
harnessProvider: state.harnessProvider,
|
|
4837
|
-
});
|
|
4838
|
-
lastServerCapsRefreshAt = Date.now();
|
|
4839
|
-
await applyServerCapabilities(reg.serverCapabilities);
|
|
4911
|
+
await registerCurrentRuntime();
|
|
4840
4912
|
} catch (err) {
|
|
4841
4913
|
console.warn(`[${role}] [config] Re-register failed (non-fatal): ${err}`);
|
|
4842
4914
|
}
|
|
@@ -4852,6 +4924,7 @@ export async function runAgent(config: RunnerConfig, opts: RunnerOptions) {
|
|
|
4852
4924
|
capabilities,
|
|
4853
4925
|
maxTasks: maxConcurrent,
|
|
4854
4926
|
harnessProvider: bootProvider,
|
|
4927
|
+
runtimeInstanceId,
|
|
4855
4928
|
});
|
|
4856
4929
|
lastServerCapsRefreshAt = Date.now();
|
|
4857
4930
|
// Rebuilds the prompt immediately: the initial build above ran before
|
|
@@ -4918,6 +4991,7 @@ export async function runAgent(config: RunnerConfig, opts: RunnerOptions) {
|
|
|
4918
4991
|
headers: {
|
|
4919
4992
|
Authorization: `Bearer ${apiKey}`,
|
|
4920
4993
|
"X-Agent-ID": agentId,
|
|
4994
|
+
"X-Runtime-Instance-ID": runtimeInstanceId,
|
|
4921
4995
|
"Content-Type": "application/json",
|
|
4922
4996
|
},
|
|
4923
4997
|
body: JSON.stringify({ ready: status.ready, missing: status.missing }),
|
|
@@ -4934,16 +5008,71 @@ export async function runAgent(config: RunnerConfig, opts: RunnerOptions) {
|
|
|
4934
5008
|
throw err;
|
|
4935
5009
|
}
|
|
4936
5010
|
|
|
5011
|
+
// Re-register before reporting readiness or doing any work. A worker
|
|
5012
|
+
// blocked on credentials is not usable execution capacity, so its runtime
|
|
5013
|
+
// is allowed to expire during the wait rather than being kept alive
|
|
5014
|
+
// artificially — but once it can work again the server has to know, or
|
|
5015
|
+
// its pings and polls would reference a runtime that no longer exists
|
|
5016
|
+
// until the periodic refresh (up to 5 min later) happened to fix it.
|
|
5017
|
+
// Same per-boot runtime id, so this refreshes the original row instead of
|
|
5018
|
+
// creating a second one. Ordering matters: a readiness report sent while
|
|
5019
|
+
// the row is still stale is dropped (only a live runtime may report), and
|
|
5020
|
+
// the revival preserves credential_ready — reporting first would leave
|
|
5021
|
+
// the agent parked on waiting_for_credentials forever. Best-effort is not
|
|
5022
|
+
// enough here for the same reason: a swallowed transient failure would
|
|
5023
|
+
// still let the report target the stale row, so recovery retries and
|
|
5024
|
+
// treats exhaustion like boot-registration failure.
|
|
5025
|
+
try {
|
|
5026
|
+
await retryBootStep(registerCurrentRuntime, {
|
|
5027
|
+
label: "runtime re-registration",
|
|
5028
|
+
log: (line) => console.warn(`[${role}] ${line}`),
|
|
5029
|
+
});
|
|
5030
|
+
} catch (error) {
|
|
5031
|
+
console.error(`[${role}] Failed to re-register after credential wait: ${error}`);
|
|
5032
|
+
process.exit(1);
|
|
5033
|
+
}
|
|
5034
|
+
|
|
4937
5035
|
// Migration 055: build the full snapshot (presence + live test) once
|
|
4938
5036
|
// creds are ready and POST it to the agent row. Status endpoint reads
|
|
4939
5037
|
// this instead of running predicates server-side. Always uses the
|
|
4940
5038
|
// *current* state.harnessProvider in case it flipped during the wait.
|
|
5039
|
+
// The snapshot build stays best-effort — its live test can hiccup, and
|
|
5040
|
+
// that must not lose the readiness transition below.
|
|
5041
|
+
let bootCredSnapshot: Awaited<ReturnType<typeof buildCredStatusReport>> | undefined;
|
|
4941
5042
|
try {
|
|
4942
|
-
|
|
4943
|
-
|
|
5043
|
+
bootCredSnapshot = await buildCredStatusReport(
|
|
5044
|
+
state.harnessProvider,
|
|
5045
|
+
process.env,
|
|
5046
|
+
{},
|
|
5047
|
+
"boot",
|
|
5048
|
+
);
|
|
4944
5049
|
} catch (err) {
|
|
4945
|
-
|
|
4946
|
-
|
|
5050
|
+
console.warn(`[${role}] cred_status boot snapshot failed (non-fatal): ${err}`);
|
|
5051
|
+
}
|
|
5052
|
+
|
|
5053
|
+
// The readiness write is the only transition out of
|
|
5054
|
+
// waiting_for_credentials after a stale-runtime revival (the wait's final
|
|
5055
|
+
// tick targeted the pre-registration row, and revival preserves the old
|
|
5056
|
+
// credential_ready) — so like the registration above, it retries and
|
|
5057
|
+
// treats exhaustion as a failed boot rather than proceeding parked.
|
|
5058
|
+
try {
|
|
5059
|
+
await retryBootStep(
|
|
5060
|
+
() =>
|
|
5061
|
+
sendCredStatusReport(apiUrl, apiKey, agentId, runtimeInstanceId, {
|
|
5062
|
+
// The snapshot's verdict when it built; otherwise the wait's own
|
|
5063
|
+
// conclusion (it only returns once credentials are ready).
|
|
5064
|
+
ready: bootCredSnapshot?.ready ?? true,
|
|
5065
|
+
missing: bootCredSnapshot?.missing ?? [],
|
|
5066
|
+
credStatus: bootCredSnapshot,
|
|
5067
|
+
}),
|
|
5068
|
+
{
|
|
5069
|
+
label: "credential readiness report",
|
|
5070
|
+
log: (line) => console.warn(`[${role}] ${line}`),
|
|
5071
|
+
},
|
|
5072
|
+
);
|
|
5073
|
+
} catch (error) {
|
|
5074
|
+
console.error(`[${role}] Failed to report credential readiness after recovery: ${error}`);
|
|
5075
|
+
process.exit(1);
|
|
4947
5076
|
}
|
|
4948
5077
|
}
|
|
4949
5078
|
|
|
@@ -5291,6 +5420,15 @@ export async function runAgent(config: RunnerConfig, opts: RunnerOptions) {
|
|
|
5291
5420
|
}
|
|
5292
5421
|
}
|
|
5293
5422
|
|
|
5423
|
+
const resumeWithSyncWarning = await prependProfileSyncRejectionBanner(resumePrompt, {
|
|
5424
|
+
...apiConfig,
|
|
5425
|
+
claudeMdPath: resolveClaudeMdPath([state.harnessProvider]),
|
|
5426
|
+
});
|
|
5427
|
+
resumePrompt = resumeWithSyncWarning.prompt;
|
|
5428
|
+
if (resumeWithSyncWarning.injected) {
|
|
5429
|
+
console.warn(`[${role}] Injected persisted profile sync rejection warning`);
|
|
5430
|
+
}
|
|
5431
|
+
|
|
5294
5432
|
// Resolve provider-aware resume: prefer own session, then parent.
|
|
5295
5433
|
const resumeCandidates: ResumeSessionCandidate[] = [
|
|
5296
5434
|
{
|
|
@@ -5428,7 +5566,12 @@ export async function runAgent(config: RunnerConfig, opts: RunnerOptions) {
|
|
|
5428
5566
|
triggerType: "task_resumed",
|
|
5429
5567
|
taskDescription: task.task?.slice(0, 200),
|
|
5430
5568
|
runnerSessionId: resumeRunnerSessionId,
|
|
5431
|
-
})
|
|
5569
|
+
}).catch((err) =>
|
|
5570
|
+
console.error(
|
|
5571
|
+
"[runner] active-session registration failed:",
|
|
5572
|
+
scrubSecrets(err instanceof Error ? err.message : String(err)),
|
|
5573
|
+
),
|
|
5574
|
+
);
|
|
5432
5575
|
console.log(
|
|
5433
5576
|
`[${role}] Resumed task ${task.id.slice(0, 8)} (${state.activeTasks.size}/${state.maxConcurrent} active)`,
|
|
5434
5577
|
);
|
|
@@ -5522,7 +5665,7 @@ export async function runAgent(config: RunnerConfig, opts: RunnerOptions) {
|
|
|
5522
5665
|
if (currentHarness !== cachedCredHarnessProvider) {
|
|
5523
5666
|
cachedCredHarnessProvider = currentHarness;
|
|
5524
5667
|
buildCredStatusReport(currentHarness, process.env, {}, "post_task")
|
|
5525
|
-
.then((snap) => reportCredStatus(apiUrl, apiKey, agentId, snap))
|
|
5668
|
+
.then((snap) => reportCredStatus(apiUrl, apiKey, agentId, runtimeInstanceId, snap))
|
|
5526
5669
|
.catch((err) =>
|
|
5527
5670
|
console.warn(`[${role}] cred_status post_task report failed (non-fatal): ${err}`),
|
|
5528
5671
|
);
|
|
@@ -5538,7 +5681,7 @@ export async function runAgent(config: RunnerConfig, opts: RunnerOptions) {
|
|
|
5538
5681
|
// account state. One bounded AWS round-trip per tick.
|
|
5539
5682
|
lastBedrockRefreshAt = Date.now();
|
|
5540
5683
|
buildCredStatusReport(currentHarness, process.env, {}, "post_task")
|
|
5541
|
-
.then((snap) => reportCredStatus(apiUrl, apiKey, agentId, snap))
|
|
5684
|
+
.then((snap) => reportCredStatus(apiUrl, apiKey, agentId, runtimeInstanceId, snap))
|
|
5542
5685
|
.catch((err) =>
|
|
5543
5686
|
console.warn(`[${role}] bedrock enumeration refresh failed (non-fatal): ${err}`),
|
|
5544
5687
|
);
|
|
@@ -5554,7 +5697,12 @@ export async function runAgent(config: RunnerConfig, opts: RunnerOptions) {
|
|
|
5554
5697
|
if (!task.workingDir) continue;
|
|
5555
5698
|
|
|
5556
5699
|
vcsCheckTimestamps.set(taskId, now);
|
|
5557
|
-
detectVcsForTask(apiUrl, apiKey, taskId, task.workingDir)
|
|
5700
|
+
detectVcsForTask(apiUrl, apiKey, taskId, task.workingDir).catch((err) =>
|
|
5701
|
+
console.error(
|
|
5702
|
+
"[runner] VCS detection failed:",
|
|
5703
|
+
scrubSecrets(err instanceof Error ? err.message : String(err)),
|
|
5704
|
+
),
|
|
5705
|
+
);
|
|
5558
5706
|
}
|
|
5559
5707
|
|
|
5560
5708
|
// Check for cancelled tasks and signal their subprocesses. Deliberately
|
|
@@ -5631,6 +5779,7 @@ export async function runAgent(config: RunnerConfig, opts: RunnerOptions) {
|
|
|
5631
5779
|
apiKey,
|
|
5632
5780
|
agentId,
|
|
5633
5781
|
pollInterval: PollIntervalMs,
|
|
5782
|
+
runtimeInstanceId,
|
|
5634
5783
|
pollTimeout: effectiveTimeout,
|
|
5635
5784
|
});
|
|
5636
5785
|
|
|
@@ -5739,6 +5888,15 @@ export async function runAgent(config: RunnerConfig, opts: RunnerOptions) {
|
|
|
5739
5888
|
}
|
|
5740
5889
|
}
|
|
5741
5890
|
|
|
5891
|
+
const triggerWithSyncWarning = await prependProfileSyncRejectionBanner(triggerPrompt, {
|
|
5892
|
+
...apiConfig,
|
|
5893
|
+
claudeMdPath: resolveClaudeMdPath([state.harnessProvider]),
|
|
5894
|
+
});
|
|
5895
|
+
triggerPrompt = triggerWithSyncWarning.prompt;
|
|
5896
|
+
if (triggerWithSyncWarning.injected) {
|
|
5897
|
+
console.warn(`[${role}] Injected persisted profile sync rejection warning`);
|
|
5898
|
+
}
|
|
5899
|
+
|
|
5742
5900
|
// Resolve provider-aware resume for child tasks with parentTaskId.
|
|
5743
5901
|
let resumeSessionId: string | undefined;
|
|
5744
5902
|
if (taskObj?.parentTaskId) {
|
|
@@ -5990,7 +6148,12 @@ export async function runAgent(config: RunnerConfig, opts: RunnerOptions) {
|
|
|
5990
6148
|
triggerType: trigger.type,
|
|
5991
6149
|
taskDescription: taskDesc,
|
|
5992
6150
|
runnerSessionId: taskRunnerSessionId,
|
|
5993
|
-
})
|
|
6151
|
+
}).catch((err) =>
|
|
6152
|
+
console.error(
|
|
6153
|
+
"[runner] active-session registration failed:",
|
|
6154
|
+
scrubSecrets(err instanceof Error ? err.message : String(err)),
|
|
6155
|
+
),
|
|
6156
|
+
);
|
|
5994
6157
|
|
|
5995
6158
|
console.log(
|
|
5996
6159
|
`[${role}] Started task ${runningTask.taskId.slice(0, 8)} (${state.activeTasks.size}/${state.maxConcurrent} active, trigger: ${trigger.type})`,
|
|
@@ -50,6 +50,28 @@ Accept if you have capacity and skills. Reject with a reason if you cannot handl
|
|
|
50
50
|
category: "task_lifecycle",
|
|
51
51
|
});
|
|
52
52
|
|
|
53
|
+
registerTemplate({
|
|
54
|
+
eventType: "task.profile_sync_rejection",
|
|
55
|
+
header: "",
|
|
56
|
+
defaultBody: `=== PERSISTED PROFILE SYNC REJECTION ===
|
|
57
|
+
A {{timestamp}} sync of {{field_label}} did not reach the database. Disk size: {{disk_size}}; DB size: {{db_size}}; budget: {{budget}}; delta: {{delta}}.
|
|
58
|
+
Audit event: {{event_id}}. {{recovery_guidance}}
|
|
59
|
+
=== END PROFILE SYNC REJECTION ===
|
|
60
|
+
|
|
61
|
+
`,
|
|
62
|
+
variables: [
|
|
63
|
+
{ name: "timestamp", description: "UTC timestamp of the rejected sync" },
|
|
64
|
+
{ name: "field_label", description: "Profile field and its harness-specific file path" },
|
|
65
|
+
{ name: "disk_size", description: "Rejected local file size" },
|
|
66
|
+
{ name: "db_size", description: "Stored database field size" },
|
|
67
|
+
{ name: "budget", description: "Configured field budget" },
|
|
68
|
+
{ name: "delta", description: "Signed size delta" },
|
|
69
|
+
{ name: "event_id", description: "Persisted audit event ID" },
|
|
70
|
+
{ name: "recovery_guidance", description: "Accurate field-specific recovery instructions" },
|
|
71
|
+
],
|
|
72
|
+
category: "task_lifecycle",
|
|
73
|
+
});
|
|
74
|
+
|
|
53
75
|
registerTemplate({
|
|
54
76
|
eventType: "task.trigger.unread_mentions",
|
|
55
77
|
header: "",
|
package/src/github/handlers.ts
CHANGED
|
@@ -4,6 +4,7 @@ import { findUserByExternalId } from "../be/users";
|
|
|
4
4
|
import { resolveTemplate } from "../prompts/resolver";
|
|
5
5
|
import { githubContextKey } from "../tasks/context-key";
|
|
6
6
|
import { createTaskWithSiblingAwareness } from "../tasks/sibling-awareness";
|
|
7
|
+
import { scrubSecrets } from "../utils/secret-scrubber";
|
|
7
8
|
import { getInstallationToken } from "./app";
|
|
8
9
|
import {
|
|
9
10
|
detectMention,
|
|
@@ -280,7 +281,12 @@ export async function handlePullRequest(
|
|
|
280
281
|
}
|
|
281
282
|
|
|
282
283
|
if (installation?.id) {
|
|
283
|
-
addIssueReaction(repository.full_name, pr.number, "eyes", installation.id)
|
|
284
|
+
addIssueReaction(repository.full_name, pr.number, "eyes", installation.id).catch((err) =>
|
|
285
|
+
console.error(
|
|
286
|
+
"[GitHub] failed to add issue reaction:",
|
|
287
|
+
scrubSecrets(err instanceof Error ? err.message : String(err)),
|
|
288
|
+
),
|
|
289
|
+
);
|
|
284
290
|
}
|
|
285
291
|
|
|
286
292
|
return { created: true, taskId: task.id };
|
|
@@ -388,7 +394,12 @@ export async function handlePullRequest(
|
|
|
388
394
|
}
|
|
389
395
|
|
|
390
396
|
if (installation?.id) {
|
|
391
|
-
addIssueReaction(repository.full_name, pr.number, "eyes", installation.id)
|
|
397
|
+
addIssueReaction(repository.full_name, pr.number, "eyes", installation.id).catch((err) =>
|
|
398
|
+
console.error(
|
|
399
|
+
"[GitHub] failed to add issue reaction:",
|
|
400
|
+
scrubSecrets(err instanceof Error ? err.message : String(err)),
|
|
401
|
+
),
|
|
402
|
+
);
|
|
392
403
|
}
|
|
393
404
|
|
|
394
405
|
return { created: true, taskId: task.id };
|
|
@@ -488,7 +499,12 @@ export async function handlePullRequest(
|
|
|
488
499
|
}
|
|
489
500
|
|
|
490
501
|
if (installation?.id) {
|
|
491
|
-
addIssueReaction(repository.full_name, pr.number, "eyes", installation.id)
|
|
502
|
+
addIssueReaction(repository.full_name, pr.number, "eyes", installation.id).catch((err) =>
|
|
503
|
+
console.error(
|
|
504
|
+
"[GitHub] failed to add issue reaction:",
|
|
505
|
+
scrubSecrets(err instanceof Error ? err.message : String(err)),
|
|
506
|
+
),
|
|
507
|
+
);
|
|
492
508
|
}
|
|
493
509
|
|
|
494
510
|
return { created: true, taskId: task.id };
|
|
@@ -577,7 +593,12 @@ export async function handlePullRequest(
|
|
|
577
593
|
|
|
578
594
|
// Add 👀 reaction to acknowledge the mention
|
|
579
595
|
if (installation?.id) {
|
|
580
|
-
addIssueReaction(repository.full_name, pr.number, "eyes", installation.id)
|
|
596
|
+
addIssueReaction(repository.full_name, pr.number, "eyes", installation.id).catch((err) =>
|
|
597
|
+
console.error(
|
|
598
|
+
"[GitHub] failed to add issue reaction:",
|
|
599
|
+
scrubSecrets(err instanceof Error ? err.message : String(err)),
|
|
600
|
+
),
|
|
601
|
+
);
|
|
581
602
|
}
|
|
582
603
|
|
|
583
604
|
return { created: true, taskId: task.id };
|
|
@@ -657,7 +678,12 @@ export async function handleIssue(
|
|
|
657
678
|
}
|
|
658
679
|
|
|
659
680
|
if (installation?.id) {
|
|
660
|
-
addIssueReaction(repository.full_name, issue.number, "eyes", installation.id)
|
|
681
|
+
addIssueReaction(repository.full_name, issue.number, "eyes", installation.id).catch((err) =>
|
|
682
|
+
console.error(
|
|
683
|
+
"[GitHub] failed to add issue reaction:",
|
|
684
|
+
scrubSecrets(err instanceof Error ? err.message : String(err)),
|
|
685
|
+
),
|
|
686
|
+
);
|
|
661
687
|
}
|
|
662
688
|
|
|
663
689
|
return { created: true, taskId: task.id };
|
|
@@ -753,7 +779,12 @@ export async function handleIssue(
|
|
|
753
779
|
}
|
|
754
780
|
|
|
755
781
|
if (installation?.id) {
|
|
756
|
-
addIssueReaction(repository.full_name, issue.number, "eyes", installation.id)
|
|
782
|
+
addIssueReaction(repository.full_name, issue.number, "eyes", installation.id).catch((err) =>
|
|
783
|
+
console.error(
|
|
784
|
+
"[GitHub] failed to add issue reaction:",
|
|
785
|
+
scrubSecrets(err instanceof Error ? err.message : String(err)),
|
|
786
|
+
),
|
|
787
|
+
);
|
|
757
788
|
}
|
|
758
789
|
|
|
759
790
|
return { created: true, taskId: task.id };
|
|
@@ -824,7 +855,12 @@ export async function handleIssue(
|
|
|
824
855
|
|
|
825
856
|
// Add 👀 reaction to acknowledge the mention
|
|
826
857
|
if (installation?.id) {
|
|
827
|
-
addIssueReaction(repository.full_name, issue.number, "eyes", installation.id)
|
|
858
|
+
addIssueReaction(repository.full_name, issue.number, "eyes", installation.id).catch((err) =>
|
|
859
|
+
console.error(
|
|
860
|
+
"[GitHub] failed to add issue reaction:",
|
|
861
|
+
scrubSecrets(err instanceof Error ? err.message : String(err)),
|
|
862
|
+
),
|
|
863
|
+
);
|
|
828
864
|
}
|
|
829
865
|
|
|
830
866
|
return { created: true, taskId: task.id };
|
|
@@ -932,7 +968,12 @@ export async function handleComment(
|
|
|
932
968
|
|
|
933
969
|
// Add 👀 reaction to the comment to acknowledge the mention
|
|
934
970
|
if (installation?.id) {
|
|
935
|
-
addReaction(repository.full_name, comment.id, "eyes", installation.id)
|
|
971
|
+
addReaction(repository.full_name, comment.id, "eyes", installation.id).catch((err) =>
|
|
972
|
+
console.error(
|
|
973
|
+
"[GitHub] failed to add comment reaction:",
|
|
974
|
+
scrubSecrets(err instanceof Error ? err.message : String(err)),
|
|
975
|
+
),
|
|
976
|
+
);
|
|
936
977
|
}
|
|
937
978
|
|
|
938
979
|
return { created: true, taskId: task.id };
|
|
@@ -1240,7 +1281,12 @@ export async function handlePullRequestReview(
|
|
|
1240
1281
|
|
|
1241
1282
|
// Add reaction to acknowledge the review
|
|
1242
1283
|
if (installation?.id) {
|
|
1243
|
-
addIssueReaction(repository.full_name, pr.number, "eyes", installation.id)
|
|
1284
|
+
addIssueReaction(repository.full_name, pr.number, "eyes", installation.id).catch((err) =>
|
|
1285
|
+
console.error(
|
|
1286
|
+
"[GitHub] failed to add issue reaction:",
|
|
1287
|
+
scrubSecrets(err instanceof Error ? err.message : String(err)),
|
|
1288
|
+
),
|
|
1289
|
+
);
|
|
1244
1290
|
}
|
|
1245
1291
|
|
|
1246
1292
|
return { created: true, taskId: task.id };
|