create-walle 0.10.1 → 0.10.2
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 +4 -0
- package/lib/owner-write-safety.js +135 -0
- package/lib/public-runtime.js +13 -5
- package/lib/release-schema.json +3 -2
- package/lib/runtime-closure-policy.json +6 -4
- package/package.json +1 -1
- package/template/bin/deps-doctor.js +1 -1
- package/template/bin/node-bin.sh +11 -0
- package/template/coding-task-manager/api-prompts.js +10 -22
- package/template/coding-task-manager/bin/claude-hook.js +7 -3
- package/template/coding-task-manager/bin/claude-table-parity.js +307 -0
- package/template/coding-task-manager/bin/conversation-storage-auto-migration-lib.js +16 -1
- package/template/coding-task-manager/bin/conversation-storage-generation-evidence.js +9 -2
- package/template/coding-task-manager/bin/conversation-storage-service-entry-lib.js +16 -1
- package/template/coding-task-manager/bin/conversation-storage-walle-owner.js +247 -0
- package/template/coding-task-manager/bin/ctm-machine-pair.js +160 -0
- package/template/coding-task-manager/bin/lead-wait-census.js +1348 -0
- package/template/coding-task-manager/bin/repair-foreign-clone.js +564 -0
- package/template/coding-task-manager/bin/repair-resume-echo-titles.js +248 -0
- package/template/coding-task-manager/bin/write-lock-bench.js +111 -0
- package/template/coding-task-manager/db.js +705 -286
- package/template/coding-task-manager/git-utils.js +44 -0
- package/template/coding-task-manager/lib/adopted-host-redial.js +4 -0
- package/template/coding-task-manager/lib/agent-presets.js +15 -0
- package/template/coding-task-manager/lib/agent-title-apply.js +88 -0
- package/template/coding-task-manager/lib/agent-title-backfill-read.js +92 -0
- package/template/coding-task-manager/lib/api/host-stats.js +98 -0
- package/template/coding-task-manager/lib/api/ingress.js +35 -12
- package/template/coding-task-manager/lib/api/machine-pairing.js +285 -0
- package/template/coding-task-manager/lib/api/machine-pool.js +307 -0
- package/template/coding-task-manager/lib/api/machines.js +461 -0
- package/template/coding-task-manager/lib/api/misc-ops.js +20 -5
- package/template/coding-task-manager/lib/api/providers.js +53 -6
- package/template/coding-task-manager/lib/api/resume-from-store.js +25 -0
- package/template/coding-task-manager/lib/api/sessions.js +160 -8
- package/template/coding-task-manager/lib/api/transcript-history.js +17 -4
- package/template/coding-task-manager/lib/api/worktrees.js +38 -37
- package/template/coding-task-manager/lib/approval-drift.js +16 -1
- package/template/coding-task-manager/lib/approval-logical-frame.js +5 -1
- package/template/coding-task-manager/lib/approval-scope.js +68 -4
- package/template/coding-task-manager/lib/auth-context.js +32 -2
- package/template/coding-task-manager/lib/auth-rate-limit.js +41 -1
- package/template/coding-task-manager/lib/auth-rules.js +186 -45
- package/template/coding-task-manager/lib/broadcast-serialize.js +2 -1
- package/template/coding-task-manager/lib/browser-session-broker.js +9 -1
- package/template/coding-task-manager/lib/browser-use-adapter.js +33 -2
- package/template/coding-task-manager/lib/claude-markdown-ansi.js +27 -85
- package/template/coding-task-manager/lib/claude-session-title.js +6 -30
- package/template/coding-task-manager/lib/claude-table-layout.js +322 -0
- package/template/coding-task-manager/lib/client-diag-handler.js +5 -0
- package/template/coding-task-manager/lib/codex-config-guard.js +33 -3
- package/template/coding-task-manager/lib/codex-harness-qualification.js +12 -0
- package/template/coding-task-manager/lib/codex-launch-health.js +29 -2
- package/template/coding-task-manager/lib/codex-link-preparation.js +9 -8
- package/template/coding-task-manager/lib/codex-paths.js +2 -1
- package/template/coding-task-manager/lib/coding-agent-models.js +21 -30
- package/template/coding-task-manager/lib/coding-session-model-adapters.js +27 -2
- package/template/coding-task-manager/lib/coding-session-model-projection.js +5 -0
- package/template/coding-task-manager/lib/coding-session-model-runtime.js +1 -2
- package/template/coding-task-manager/lib/coding-session-model-state.js +10 -0
- package/template/coding-task-manager/lib/coding-session-model-sync-state.js +0 -1
- package/template/coding-task-manager/lib/conversation-import/cursor-guard-owner.js +10 -0
- package/template/coding-task-manager/lib/create/resolve-launch-params.js +8 -1
- package/template/coding-task-manager/lib/ctm-boot-lifecycle.js +17 -1
- package/template/coding-task-manager/lib/db-domain-tables.js +7 -0
- package/template/coding-task-manager/lib/db-domains.js +21 -2
- package/template/coding-task-manager/lib/db-owner-op-registry.js +7 -0
- package/template/coding-task-manager/lib/db-schema-source-files.js +1 -0
- package/template/coding-task-manager/lib/feature-manifest.js +1 -1
- package/template/coding-task-manager/lib/fs-watcher.js +3 -2
- package/template/coding-task-manager/lib/harness-history-transition.js +3 -3
- package/template/coding-task-manager/lib/headless-inflight-ops.js +203 -0
- package/template/coding-task-manager/lib/headless-missing-reply.js +42 -0
- package/template/coding-task-manager/lib/headless-term-service.js +55 -17
- package/template/coding-task-manager/lib/host-control-dial.js +167 -0
- package/template/coding-task-manager/lib/host-handoff-orchestrator.js +16 -2
- package/template/coding-task-manager/lib/host-handoff.js +51 -13
- package/template/coding-task-manager/lib/host-health-ledger.js +164 -12
- package/template/coding-task-manager/lib/host-self-truth-watchdog.js +4 -0
- package/template/coding-task-manager/lib/host-stats.js +328 -0
- package/template/coding-task-manager/lib/host-threadpool-evacuation.js +160 -0
- package/template/coding-task-manager/lib/host-threadpool-monitor.js +14 -1
- package/template/coding-task-manager/lib/hosted-input-dispatch.js +203 -0
- package/template/coding-task-manager/lib/hosted-sync-worker.js +113 -5
- package/template/coding-task-manager/lib/instance-id-ownership-manifest.js +4 -0
- package/template/coding-task-manager/lib/instance-manifest-runtime.js +3 -0
- package/template/coding-task-manager/lib/instance-manifest.js +13 -1
- package/template/coding-task-manager/lib/instance-sync-status.js +15 -0
- package/template/coding-task-manager/lib/launch-model-override.js +160 -1
- package/template/coding-task-manager/lib/launch-plan-worker.js +59 -2
- package/template/coding-task-manager/lib/lead-model-switch-runtime.js +57 -4
- package/template/coding-task-manager/lib/lead-model-switch.js +3 -2
- package/template/coding-task-manager/lib/lead-model-transition-store.js +61 -3
- package/template/coding-task-manager/lib/legacy-draft-cancellation-recovery.js +111 -0
- package/template/coding-task-manager/lib/login-tripwire.js +1 -0
- package/template/coding-task-manager/lib/machine-pairing.js +238 -0
- package/template/coding-task-manager/lib/machine-pool.js +409 -0
- package/template/coding-task-manager/lib/machine-registry.js +749 -0
- package/template/coding-task-manager/lib/machine-self.js +66 -0
- package/template/coding-task-manager/lib/main-thread-lint-exemptions.json +52 -4
- package/template/coding-task-manager/lib/media-journal-control-reader.js +473 -0
- package/template/coding-task-manager/lib/media-journal.js +84 -27
- package/template/coding-task-manager/lib/media-store-options.js +43 -15
- package/template/coding-task-manager/lib/migrations/v56-host-samples-and-machine-pool.js +76 -0
- package/template/coding-task-manager/lib/mirror-feed-sanitize.js +12 -3
- package/template/coding-task-manager/lib/model-proxy/anthropic-face.js +4 -0
- package/template/coding-task-manager/lib/model-proxy/chat-response-translators.js +3 -0
- package/template/coding-task-manager/lib/model-proxy/handoff.js +494 -0
- package/template/coding-task-manager/lib/model-proxy/lead-worker-picks.js +25 -0
- package/template/coding-task-manager/lib/model-proxy/native-lead-listener.js +61 -7
- package/template/coding-task-manager/lib/model-proxy/proxy-cli.js +200 -0
- package/template/coding-task-manager/lib/model-proxy/proxy-instance-record.js +257 -0
- package/template/coding-task-manager/lib/model-proxy/stream-accounting.js +205 -0
- package/template/coding-task-manager/lib/model-proxy/tokens.js +78 -0
- package/template/coding-task-manager/lib/model-proxy/upstream-outcome.js +9 -0
- package/template/coding-task-manager/lib/native-history-control.js +2 -2
- package/template/coding-task-manager/lib/native-lead-settings-client.js +2 -1
- package/template/coding-task-manager/lib/native-lead-tls.js +18 -4
- package/template/coding-task-manager/lib/oauth-proxy-supervisor.js +628 -64
- package/template/coding-task-manager/lib/owner-action-manifest-data.json +14 -0
- package/template/coding-task-manager/lib/painted-row-recorder.js +9 -1
- package/template/coding-task-manager/lib/prompt-submission-contract.js +21 -1
- package/template/coding-task-manager/lib/provider-login-broker.js +192 -9
- package/template/coding-task-manager/lib/provider-login-capture.js +153 -0
- package/template/coding-task-manager/lib/queue-draft-status-overlay.js +36 -0
- package/template/coding-task-manager/lib/raw-codex-history-window.js +5 -3
- package/template/coding-task-manager/lib/read-pool-client.js +5 -2
- package/template/coding-task-manager/lib/read-pool-op-registry.js +10 -1
- package/template/coding-task-manager/lib/recent-catalog-query.js +26 -0
- package/template/coding-task-manager/lib/recent-session-catalog-response.js +9 -0
- package/template/coding-task-manager/lib/remote-command-context.js +12 -0
- package/template/coding-task-manager/lib/remote-command-runtime.js +13 -1
- package/template/coding-task-manager/lib/remote-machine-catalog.js +1062 -0
- package/template/coding-task-manager/lib/remote-machine-create.js +693 -0
- package/template/coding-task-manager/lib/remote-machine-link.js +939 -0
- package/template/coding-task-manager/lib/remote-machine-proxy.js +520 -0
- package/template/coding-task-manager/lib/remote-session-forward.js +306 -0
- package/template/coding-task-manager/lib/remote-submission-status.js +6 -0
- package/template/coding-task-manager/lib/restart-outcome-truth.js +20 -3
- package/template/coding-task-manager/lib/restart-preflight.js +9 -2
- package/template/coding-task-manager/lib/restore-backoff-gate.js +10 -2
- package/template/coding-task-manager/lib/restore-prepare-retry.js +12 -5
- package/template/coding-task-manager/lib/restore-resume-batch.js +22 -1
- package/template/coding-task-manager/lib/resume-blocked-wire.js +62 -1
- package/template/coding-task-manager/lib/resume-cwd.js +13 -0
- package/template/coding-task-manager/lib/resume-from-store.js +12 -1
- package/template/coding-task-manager/lib/resume-origin-facts.js +38 -1
- package/template/coding-task-manager/lib/resume-preflight.js +21 -16
- package/template/coding-task-manager/lib/review-repo-admission.js +39 -6
- package/template/coding-task-manager/lib/review-repo-registry.js +17 -0
- package/template/coding-task-manager/lib/root-delivery-runtime.js +72 -15
- package/template/coding-task-manager/lib/root-delivery-selection.js +37 -1
- package/template/coding-task-manager/lib/root-prompt-admission.js +33 -2
- package/template/coding-task-manager/lib/root-prompt-flow.js +167 -33
- package/template/coding-task-manager/lib/scrollback-archive-store.js +7 -4
- package/template/coding-task-manager/lib/session-analysis-memory.js +2 -0
- package/template/coding-task-manager/lib/session-create/codex-native-provider-gate.js +218 -0
- package/template/coding-task-manager/lib/session-create/codex-resume-exit-classify.js +52 -0
- package/template/coding-task-manager/lib/session-create/delegate-worker.js +95 -6
- package/template/coding-task-manager/lib/session-create/identity.js +20 -1
- package/template/coding-task-manager/lib/session-create/prepared.js +69 -1
- package/template/coding-task-manager/lib/session-create/provider-launch-context.js +77 -0
- package/template/coding-task-manager/lib/session-create/provider-process.js +34 -37
- package/template/coding-task-manager/lib/session-create/response.js +30 -12
- package/template/coding-task-manager/lib/session-create/transcript.js +13 -4
- package/template/coding-task-manager/lib/session-create/worker-continuation.js +43 -1
- package/template/coding-task-manager/lib/session-create/worker-notices.js +94 -5
- package/template/coding-task-manager/lib/session-create/worker-observability.js +99 -7
- package/template/coding-task-manager/lib/session-create/worker-stop.js +11 -3
- package/template/coding-task-manager/lib/session-create/worker-wait-watcher.js +315 -0
- package/template/coding-task-manager/lib/session-geometry-authority-handler.js +10 -1
- package/template/coding-task-manager/lib/session-host-manager.js +152 -206
- package/template/coding-task-manager/lib/session-jobs.js +17 -9
- package/template/coding-task-manager/lib/session-lifecycle.js +18 -0
- package/template/coding-task-manager/lib/session-model-action-preconditions.js +9 -0
- package/template/coding-task-manager/lib/session-resource-sampler.js +19 -9
- package/template/coding-task-manager/lib/session-standup.js +67 -4
- package/template/coding-task-manager/lib/session-status-ledger.js +42 -3
- package/template/coding-task-manager/lib/session-status-runtime.js +45 -1
- package/template/coding-task-manager/lib/session-title-mirror.js +25 -57
- package/template/coding-task-manager/lib/session-transcript-trash.js +8 -1
- package/template/coding-task-manager/lib/startup-pointer-write.js +57 -0
- package/template/coding-task-manager/lib/state-sync/painted-frame-field.js +11 -0
- package/template/coding-task-manager/lib/storage/coding-session-model-store.js +21 -22
- package/template/coding-task-manager/lib/surviving-owner-bootstrap.js +7 -2
- package/template/coding-task-manager/lib/surviving-owner-recovery.js +2 -1
- package/template/coding-task-manager/lib/terminal-draft-http-status.js +25 -0
- package/template/coding-task-manager/lib/transcript-archiver.js +229 -229
- package/template/coding-task-manager/lib/transcript-frame-cache.js +12 -2
- package/template/coding-task-manager/lib/transcript-guard-job.js +55 -4
- package/template/coding-task-manager/lib/transcript-link.js +77 -0
- package/template/coding-task-manager/lib/transcript-manifest-store.js +8 -4
- package/template/coding-task-manager/lib/transcript-source.js +8 -3
- package/template/coding-task-manager/lib/transcript-store.js +40 -0
- package/template/coding-task-manager/lib/tunnel-lane-governor.js +6 -3
- package/template/coding-task-manager/lib/typing-interaction-trace.js +92 -0
- package/template/coding-task-manager/lib/typing-worker-stages.js +60 -0
- package/template/coding-task-manager/lib/visible-revision-watchdog.js +8 -12
- package/template/coding-task-manager/lib/wake-skip-reasons.js +46 -0
- package/template/coding-task-manager/lib/walle-supervisor.js +98 -14
- package/template/coding-task-manager/lib/worker-failure-classify.js +13 -1
- package/template/coding-task-manager/lib/ws/state-sync.js +19 -2
- package/template/coding-task-manager/lib/ws/terminal-attach.js +32 -1
- package/template/coding-task-manager/lib/ws-router.js +68 -1
- package/template/coding-task-manager/lib/ws-send-admission.js +22 -4
- package/template/coding-task-manager/oauth-proxy.js +99 -55
- package/template/coding-task-manager/package-lock.json +24 -0
- package/template/coding-task-manager/package.json +3 -0
- package/template/coding-task-manager/providers/codex-mcp-extract.js +121 -19
- package/template/coding-task-manager/providers/codex-mcp.js +14 -5
- package/template/coding-task-manager/public/css/app.css +279 -1
- package/template/coding-task-manager/public/css/reviews.css +4 -0
- package/template/coding-task-manager/public/index.html +294 -223
- package/template/coding-task-manager/public/js/app/machines-page.js +1252 -0
- package/template/coding-task-manager/public/js/app/models-tab.js +546 -36
- package/template/coding-task-manager/public/js/app/worktrees-panel.js +7 -5
- package/template/coding-task-manager/public/js/background-work.js +13 -7
- package/template/coding-task-manager/public/js/coding-session-model-presentation.js +44 -4
- package/template/coding-task-manager/public/js/core/session-commands.js +676 -0
- package/template/coding-task-manager/public/js/core/session-selectors.js +5 -1
- package/template/coding-task-manager/public/js/history-app-seam.js +26 -2
- package/template/coding-task-manager/public/js/history-painted-rows.js +17 -2
- package/template/coding-task-manager/public/js/history-reader-park.js +13 -1
- package/template/coding-task-manager/public/js/history-scroller.js +187 -9
- package/template/coding-task-manager/public/js/history-transcript-pages.js +5 -5
- package/template/coding-task-manager/public/js/machine-pool-shared.js +436 -0
- package/template/coding-task-manager/public/js/private-state-scope.js +31 -3
- package/template/coding-task-manager/public/js/prompt-submission-client.js +173 -8
- package/template/coding-task-manager/public/js/prompt-submission-tray.js +281 -0
- package/template/coding-task-manager/public/js/queue-panel-submission-reconcile.js +174 -1
- package/template/coding-task-manager/public/js/reviews.js +7 -3
- package/template/coding-task-manager/public/js/root-draft-lifetime.js +139 -2
- package/template/coding-task-manager/public/js/root-queue-builder-lifetime.js +16 -0
- package/template/coding-task-manager/public/js/row-join.js +4 -2
- package/template/coding-task-manager/public/js/session-model-picker.js +1 -1
- package/template/coding-task-manager/public/js/session-search-utils.js +46 -19
- package/template/coding-task-manager/public/js/state-sync-client.js +4 -0
- package/template/coding-task-manager/public/js/terminal/runtime-02.js +16 -7
- package/template/coding-task-manager/public/js/terminal/runtime-03.js +41 -0
- package/template/coding-task-manager/public/js/terminal/runtime-04.js +41 -4
- package/template/coding-task-manager/public/js/terminal/runtime-12.js +52 -2
- package/template/coding-task-manager/public/js/terminal/runtime-16.js +12 -12
- package/template/coding-task-manager/public/js/terminal/runtime-18.js +14 -0
- package/template/coding-task-manager/public/js/terminal/runtime-19.js +8 -4
- package/template/coding-task-manager/public/js/terminal/runtime-20.js +210 -73
- package/template/coding-task-manager/public/js/terminal/runtime-21.js +19 -6
- package/template/coding-task-manager/public/js/terminal/runtime-22.js +86 -0
- package/template/coding-task-manager/public/js/terminal-history-viewport.js +1 -1
- package/template/coding-task-manager/public/js/terminal-wheel.js +39 -2
- package/template/coding-task-manager/public/js/walle/chat-conversation.js +11 -3
- package/template/coding-task-manager/public/js/walle-session.js +30 -7
- package/template/coding-task-manager/public/m/app.css +226 -8
- package/template/coding-task-manager/public/m/app.js +502 -9
- package/template/coding-task-manager/public/m/index.html +38 -1
- package/template/coding-task-manager/public/m/machines.js +1313 -0
- package/template/coding-task-manager/public/m/pool-failover.js +391 -0
- package/template/coding-task-manager/public/m/private-queue-actions.js +26 -7
- package/template/coding-task-manager/public/m/sw.js +5 -0
- package/template/coding-task-manager/queue-engine.js +13 -0
- package/template/coding-task-manager/server/approvals.js +5 -6
- package/template/coding-task-manager/server/boot.js +136 -17
- package/template/coding-task-manager/server.js +902 -239
- package/template/coding-task-manager/session-integrity.js +7 -9
- package/template/coding-task-manager/workers/db-owner-worker.js +53 -7
- package/template/coding-task-manager/workers/read-pool-worker.js +17 -6
- package/template/coding-task-manager/workers/session-host-pool-process.js +18 -4
- package/template/coding-task-manager/workers/session-host-process.js +14 -3
- package/template/coding-task-manager/workers/transcript-archive-worker.js +1 -1
- package/template/coding-task-manager/workers/worktree-worker.js +34 -0
- package/template/package-lock.json +2 -2
- package/template/package.json +1 -1
- package/template/scripts/conversation-storage-v2-migration.js +78 -11
- package/template/shared/conversation-storage-v2-contract.js +42 -6
- package/template/shared/fixtures/worker-status-payloads.json +392 -0
- package/template/shared/git-remote-key.js +83 -0
- package/template/shared/host-identity.js +98 -2
- package/template/shared/owner-write-safety.js +135 -0
- package/template/shared/public-runtime.js +13 -5
- package/template/shared/release-schema.json +3 -2
- package/template/shared/report-citations.js +14 -0
- package/template/shared/sqlite-write-lock.js +361 -223
- package/template/shared/storage/contract.js +35 -3
- package/template/wall-e/agent.js +21 -0
- package/template/wall-e/api-walle.js +5 -0
- package/template/wall-e/bin/brain-purge-legacy-ctm.js +3 -2
- package/template/wall-e/bin/walle-mcp-stdio.js +12 -6
- package/template/wall-e/brain/helper-rules-schema.js +129 -0
- package/template/wall-e/brain/migrations.js +51 -22
- package/template/wall-e/brain/model-deployment-facts.js +31 -1
- package/template/wall-e/brain/owner-call-whitelist.js +16 -0
- package/template/wall-e/brain/schema-ensures.js +22 -0
- package/template/wall-e/brain.js +1 -1
- package/template/wall-e/coding/journal-dispatcher.js +51 -0
- package/template/wall-e/coding/session-journal.js +28 -40
- package/template/wall-e/coding-orchestrator.js +23 -26
- package/template/wall-e/http/auth.js +18 -1
- package/template/wall-e/http/blog-views-api.js +318 -0
- package/template/wall-e/http/helper-rules-api.js +321 -0
- package/template/wall-e/http/model-proxy-providers.js +3 -1
- package/template/wall-e/http/telemetry-api.js +12 -0
- package/template/wall-e/lib/blog-view-policy.js +88 -0
- package/template/wall-e/lib/blog-view-store.js +169 -0
- package/template/wall-e/lib/client-config-lock.js +2 -1
- package/template/wall-e/lib/coding-journal-writer-child-client.js +67 -18
- package/template/wall-e/lib/error-kinds.js +10 -1
- package/template/wall-e/lib/feature-manifest.js +1 -1
- package/template/wall-e/lib/helper-rules/cell-state.js +123 -0
- package/template/wall-e/lib/helper-rules/evaluate.js +357 -0
- package/template/wall-e/lib/helper-rules/explore-rubric.md +12 -0
- package/template/wall-e/lib/helper-rules/grade.js +277 -0
- package/template/wall-e/lib/helper-rules/label.js +247 -0
- package/template/wall-e/lib/helper-rules/lead-call-hook.js +522 -0
- package/template/wall-e/lib/helper-rules/store.js +667 -0
- package/template/wall-e/lib/mcp-integration.js +5 -6
- package/template/wall-e/lib/runtime-worker-pool.js +1 -0
- package/template/wall-e/lib/scheduler-worker-jobs.js +6 -0
- package/template/wall-e/lib/telemetry-db-schema.js +37 -0
- package/template/wall-e/lib/telemetry-process-client.js +76 -1
- package/template/wall-e/llm/default-fallback.js +4 -0
- package/template/wall-e/llm/model-catalog.js +13 -4
- package/template/wall-e/llm/model-roles.js +6 -0
- package/template/wall-e/llm/portkey-http.js +150 -0
- package/template/wall-e/llm/portkey-sync.js +15 -145
- package/template/wall-e/llm/worker-mcp-routing.js +61 -0
- package/template/wall-e/llm/worker-route.js +43 -1
- package/template/wall-e/loops/brain-custom-writes.js +45 -0
- package/template/wall-e/mcp-protocol-contract.js +41 -1
- package/template/wall-e/mcp-server.js +13 -2
- package/template/wall-e/mcp-worker-schemas.js +20 -2
- package/template/wall-e/memory/ctm-context-client.js +25 -5
- package/template/wall-e/shared/release-schema.json +3 -2
- package/template/wall-e/shared/sqlite-write-lock.js +361 -223
- package/template/wall-e/shared/storage/contract.js +35 -3
- package/template/wall-e/skills/_templates/delegate-worker/VERSION +1 -1
- package/template/wall-e/skills/_templates/delegate-worker/released-sha256.json +6 -0
- package/template/wall-e/skills/_templates/delegate-worker/templates/claude/SKILL.md +7 -2
- package/template/wall-e/skills/_templates/delegate-worker/templates/codex/SKILL.md +7 -2
- package/template/wall-e/tools/local-tools.js +6 -4
- package/template/wall-e/workers/brain-owner-worker.js +9 -0
- package/template/wall-e/workers/coding-journal-writer-child.js +8 -1
- package/template/wall-e/workers/telemetry-worker.js +8 -0
|
@@ -13,13 +13,12 @@ const {
|
|
|
13
13
|
portkeyKeyFingerprint,
|
|
14
14
|
} = require('./portkey');
|
|
15
15
|
const { scaleDecimal, canonicalRateNumber } = require('../../shared/usage-pricing');
|
|
16
|
-
const { redactSecrets } = require('./provider-error');
|
|
17
16
|
const { findSupportedModel } = require('./supported-models');
|
|
18
17
|
const { isDecideOnlyModel } = require('./decide-only');
|
|
19
18
|
const { generateRouteGroups } = require('./route-groups');
|
|
20
19
|
const { scheduleRebuild } = require('./model-identity');
|
|
21
20
|
const { notifyModelRegistryChanged } = require('../lib/ctm-model-registry-notify');
|
|
22
|
-
const {
|
|
21
|
+
const { fetchJsonOrError, safeJson, _setRetrySleepForTest } = require('./portkey-http');
|
|
23
22
|
|
|
24
23
|
const PORTKEY_SYNC_INTERVAL_MS = 60 * 60 * 1000;
|
|
25
24
|
const PORTKEY_SYNC_INITIAL_DELAY_MS = 15 * 1000;
|
|
@@ -28,10 +27,6 @@ const PORTKEY_CONTROL_PLANE_URL = 'https://api.portkey.ai/v1';
|
|
|
28
27
|
const PORTKEY_PRICING_BASE_URL = 'https://configs.portkey.ai/pricing';
|
|
29
28
|
const PORTKEY_DISCOVERY_PAGE_SIZE = 50;
|
|
30
29
|
const PORTKEY_CATALOG_PAGE_SIZE = 500;
|
|
31
|
-
// D-2: TOTAL attempts for a transient failure, with the backoff between them.
|
|
32
|
-
const PORTKEY_REQUEST_ATTEMPTS = 3;
|
|
33
|
-
const PORTKEY_RETRY_DELAYS_MS = [1000, 3000];
|
|
34
|
-
const PORTKEY_RETRY_AFTER_MAX_MS = 30 * 1000;
|
|
35
30
|
|
|
36
31
|
// D-9: vendor names Wall-E has a dedicated LLM adapter for. A discovered
|
|
37
32
|
// provider whose vendor slug does not resolve to one of these keeps its own
|
|
@@ -96,141 +91,6 @@ function inferGatewayCapabilities(providerType, model = {}) {
|
|
|
96
91
|
return supported?.capabilities || (isDecideOnlyModel({ providerType, modelId: id }) ? ['decide'] : ['chat']);
|
|
97
92
|
}
|
|
98
93
|
|
|
99
|
-
// WP-1 review R6: this is the ONLY request budget in the Portkey path, and it
|
|
100
|
-
// is per REQUEST, not per host — callers that must bound a whole host (the
|
|
101
|
-
// resolver) also cap the number of pages. There is deliberately no
|
|
102
|
-
// AbortController+setTimeout fallback when `AbortSignal.timeout` is missing:
|
|
103
|
-
// that would be a recovery timer, which `stabilization-lint` requires to be
|
|
104
|
-
// registered in release/ownership-registry.json and which this feature's
|
|
105
|
-
// design forbids. `AbortSignal.timeout` is Node >= 17.3 and this repo pins
|
|
106
|
-
// v25.2.1, so the fallback branch below is unreachable in practice; if it is
|
|
107
|
-
// ever reached the request is unbounded and the caller's page cap is what
|
|
108
|
-
// stops it.
|
|
109
|
-
function withTimeout(timeoutMs) {
|
|
110
|
-
if (typeof AbortSignal !== 'undefined' && AbortSignal.timeout && Number.isFinite(timeoutMs)) {
|
|
111
|
-
return { signal: AbortSignal.timeout(timeoutMs) };
|
|
112
|
-
}
|
|
113
|
-
return {};
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
async function safeJson(response) {
|
|
117
|
-
try { return await response.json(); } catch { return null; /* expected: non-JSON or empty error body; callers fall back to a generic message */ }
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
// D-2 test seam: when set, createRetryPolicy uses it instead of the kernel's
|
|
121
|
-
// own registered timer. null (default) means "use the kernel sleep".
|
|
122
|
-
let _retrySleepOverride = null;
|
|
123
|
-
|
|
124
|
-
function _setRetrySleepForTest(fn) {
|
|
125
|
-
_retrySleepOverride = typeof fn === 'function' ? fn : null;
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
// D-1: TRANSIENT iff no response at all (status 0) or 408/429/5xx; every other
|
|
129
|
-
// status (3xx/401/403/AB03/033/other 4xx) is DEFINITIVE and never retried.
|
|
130
|
-
function isTransientStatus(status) {
|
|
131
|
-
if (status === 0) return true;
|
|
132
|
-
const code = Number(status);
|
|
133
|
-
return code === 408 || code === 429 || (code >= 500 && code <= 599);
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
// D-2: honour Retry-After only as integer seconds ≤ 30 s; else fixed backoff.
|
|
137
|
-
function retryAfterMs(response) {
|
|
138
|
-
if (!response || typeof response.headers?.get !== 'function') return null;
|
|
139
|
-
const raw = response.headers.get('retry-after');
|
|
140
|
-
if (raw == null) return null;
|
|
141
|
-
const seconds = Number(String(raw).trim());
|
|
142
|
-
if (!Number.isFinite(seconds) || seconds < 0) return null;
|
|
143
|
-
const ms = seconds * 1000;
|
|
144
|
-
return ms <= PORTKEY_RETRY_AFTER_MAX_MS ? ms : null;
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
function errorCodeFromBody(body) {
|
|
148
|
-
if (!body || typeof body !== 'object') return '';
|
|
149
|
-
if (body.data && body.data.errorCode) return String(body.data.errorCode);
|
|
150
|
-
if (body.error && body.error.code) return String(body.error.code);
|
|
151
|
-
return '';
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
function errorMessageFromBody(body, fallback) {
|
|
155
|
-
if (body && typeof body === 'object') {
|
|
156
|
-
if (body.data && body.data.message) return String(body.data.message);
|
|
157
|
-
if (body.message) return String(body.message);
|
|
158
|
-
}
|
|
159
|
-
return fallback;
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
// `redirect: 'manual'` is the DEFAULT here, for EVERY request in the Portkey
|
|
163
|
-
// path — not only the resolver's probe (final review, finding #3). Every one
|
|
164
|
-
// carries the full gateway key in `x-portkey-api-key`, and undici keeps that
|
|
165
|
-
// header across a cross-origin redirect, so following a 3xx would hand the key
|
|
166
|
-
// to a host the user never named (the axios GHSA-jr5f-v2jv-69x6 class). With
|
|
167
|
-
// `manual` a 3xx is not followed and `response.ok` is false, so it surfaces as
|
|
168
|
-
// `{ok:false, status:3xx}` — a verdict, never a second request.
|
|
169
|
-
// `fetchInit` (WP-1): extra init the CALLER owns — today the resolver's
|
|
170
|
-
// per-host AbortController signal. Spread last so it replaces withTimeout's.
|
|
171
|
-
// D-2: ONE attempt; returns today's ok/failure shape plus the response's
|
|
172
|
-
// Retry-After (null when the fetch threw — a transport failure has no headers).
|
|
173
|
-
async function fetchJsonOnce(fetchFn, url, { headers, timeoutMs, fallbackMessage, fetchInit } = {}) {
|
|
174
|
-
try {
|
|
175
|
-
const response = await fetchFn(url, { headers, redirect: 'manual', ...withTimeout(timeoutMs), ...(fetchInit || {}) });
|
|
176
|
-
const body = await safeJson(response);
|
|
177
|
-
if (response.ok) return { result: { ok: true, status: response.status, body }, retryAfter: null };
|
|
178
|
-
return {
|
|
179
|
-
result: {
|
|
180
|
-
ok: false,
|
|
181
|
-
status: response.status,
|
|
182
|
-
code: errorCodeFromBody(body),
|
|
183
|
-
message: redactSecrets(errorMessageFromBody(body, fallbackMessage(response.status))),
|
|
184
|
-
},
|
|
185
|
-
retryAfter: retryAfterMs(response),
|
|
186
|
-
};
|
|
187
|
-
} catch (err) {
|
|
188
|
-
// D-1: no HTTP response at all (status 0 — transport/timeout) is transient.
|
|
189
|
-
const message = err && err.message ? err.message : String(err);
|
|
190
|
-
return { result: { ok: false, status: 0, code: '', message: redactSecrets(message) }, retryAfter: null };
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
// D-2: transient failures are retried through wall-e's ONE retry engine
|
|
195
|
-
// (lib/kernel/retry-policy.js); a caller owning its own abort signal (the
|
|
196
|
-
// resolver's single probe) is single-shot and never retries.
|
|
197
|
-
async function fetchJsonOrError(fetchFn, url, opts = {}) {
|
|
198
|
-
if (opts.fetchInit) {
|
|
199
|
-
const { result } = await fetchJsonOnce(fetchFn, url, opts);
|
|
200
|
-
if (result.ok) return result;
|
|
201
|
-
const transient = isTransientStatus(result.status);
|
|
202
|
-
return transient ? { ...result, transient, attempts: 1 } : { ...result, transient };
|
|
203
|
-
}
|
|
204
|
-
let nextDelay = null;
|
|
205
|
-
let lastAttempt = 1;
|
|
206
|
-
const policyOptions = {
|
|
207
|
-
maxAttempts: PORTKEY_REQUEST_ATTEMPTS,
|
|
208
|
-
jitter: 0,
|
|
209
|
-
delayFn: (attempt) => nextDelay ?? PORTKEY_RETRY_DELAYS_MS[attempt - 1],
|
|
210
|
-
classify: (err) => (err && err.portkeyTransient ? 'transient' : 'permanent'),
|
|
211
|
-
layer: 'portkey-sync',
|
|
212
|
-
operation: 'fetch',
|
|
213
|
-
};
|
|
214
|
-
// Only override the kernel's own registered timer when a test seam is set.
|
|
215
|
-
if (_retrySleepOverride) policyOptions.sleep = (ms) => _retrySleepOverride(ms);
|
|
216
|
-
const policy = createRetryPolicy(policyOptions);
|
|
217
|
-
try {
|
|
218
|
-
return await policy.run(async (attempt) => {
|
|
219
|
-
const { result, retryAfter } = await fetchJsonOnce(fetchFn, url, opts);
|
|
220
|
-
if (result.ok || !isTransientStatus(result.status)) {
|
|
221
|
-
return result.ok ? result : { ...result, transient: false };
|
|
222
|
-
}
|
|
223
|
-
nextDelay = retryAfter;
|
|
224
|
-
lastAttempt = attempt;
|
|
225
|
-
throw Object.assign(new Error(result.message), { portkeyTransient: true, result });
|
|
226
|
-
});
|
|
227
|
-
} catch (err) {
|
|
228
|
-
// Only our transient sentinel is converted; anything else propagates.
|
|
229
|
-
if (!err || !err.portkeyTransient) throw err;
|
|
230
|
-
return { ...err.result, transient: true, attempts: lastAttempt };
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
|
|
234
94
|
// D-3: per-integration data-plane listing, scoped by the '@slug' header —
|
|
235
95
|
// never a virtual key.
|
|
236
96
|
async function listPortkeyModelsForIntegration({ baseUrl, apiKey, slug, fetchFn = fetch, timeoutMs = 8000 }) {
|
|
@@ -308,6 +168,7 @@ async function listPortkeyCatalogModels({
|
|
|
308
168
|
let total = Infinity;
|
|
309
169
|
let seen = 0;
|
|
310
170
|
let pages = 0;
|
|
171
|
+
let last = {}; // WP-0: last page's HTTP status + raw body.total ride along as evidence for catalog_empty
|
|
311
172
|
while (seen < total && pages < maxPages) {
|
|
312
173
|
const url = `${root}/models?offset=${offset}&limit=${pageSize}`;
|
|
313
174
|
const result = await fetchJsonOrError(fetchFn, url, {
|
|
@@ -319,6 +180,7 @@ async function listPortkeyCatalogModels({
|
|
|
319
180
|
if (!result.ok) return result;
|
|
320
181
|
const data = Array.isArray(result.body?.data) ? result.body.data : [];
|
|
321
182
|
total = Number.isFinite(result.body?.total) ? result.body.total : data.length;
|
|
183
|
+
last = { status: typeof result.status === 'number' ? result.status : null, total: Number.isFinite(result.body?.total) ? result.body.total : null };
|
|
322
184
|
for (const model of data) {
|
|
323
185
|
const id = String(model.id || '').trim();
|
|
324
186
|
const match = id.match(/^@([^/]+)\/(.+)$/);
|
|
@@ -332,7 +194,7 @@ async function listPortkeyCatalogModels({
|
|
|
332
194
|
if (!data.length) break;
|
|
333
195
|
offset += pageSize;
|
|
334
196
|
}
|
|
335
|
-
return { ok: true, bySlug };
|
|
197
|
+
return { ok: true, bySlug, status: last.status ?? null, total: last.total ?? null };
|
|
336
198
|
}
|
|
337
199
|
|
|
338
200
|
function extractPortkeyPricing(modelConfig = {}) {
|
|
@@ -474,9 +336,10 @@ function upsertIntegrationRow(brain, gateway, provider, rows, now) {
|
|
|
474
336
|
return { rowId, slug, type: vendorType, enabled };
|
|
475
337
|
}
|
|
476
338
|
|
|
477
|
-
// D-4:
|
|
478
|
-
// it refreshes rows and disables omitted ones ('manual' rows excepted).
|
|
479
|
-
//
|
|
339
|
+
// D-4/D-6: a NON-EMPTY `ok` listing (catalog or passthrough) is authoritative —
|
|
340
|
+
// it refreshes rows and disables omitted ones ('manual' rows excepted). An empty
|
|
341
|
+
// `ok` listing for an integration with ≥1 enabled row never reaches here: it is
|
|
342
|
+
// reported as `catalog_empty` (D-6, 2026-10-22 incident). Transient failures too (D-3).
|
|
480
343
|
function upsertLiveModels(brain, rowInfo, models, verificationStatus, now) {
|
|
481
344
|
const seenIds = new Set();
|
|
482
345
|
let imported = 0;
|
|
@@ -520,6 +383,13 @@ async function syncModelsForIntegration(brain, gateway, rowInfo, catalog, { fetc
|
|
|
520
383
|
|
|
521
384
|
if (catalog.ok) {
|
|
522
385
|
models = catalog.bySlug.get(rowInfo.slug) || [];
|
|
386
|
+
// D-6 (WP-0): a zero-model ok listing never disables rows enabled now (the control plane timed
|
|
387
|
+
// out while the catalog still answered 200, 2026-10-22) — report it via the error branch below.
|
|
388
|
+
const enabledNow = models.length ? 0 : (brain.listModelsByProvider?.(rowInfo.rowId) || []).length;
|
|
389
|
+
if (enabledNow > 0) {
|
|
390
|
+
console.warn(`[portkey-sync] catalog_empty slug=${rowInfo.slug} row=${rowInfo.rowId} enabled=${enabledNow} status=${catalog.status ?? 200} total=${catalog.total ?? 'n/a'} data=0`);
|
|
391
|
+
listError = { ok: false, status: catalog.status ?? 200, code: 'catalog_empty', message: `Portkey catalog listed 0 models for ${rowInfo.slug} while ${enabledNow} are enabled; rows kept` };
|
|
392
|
+
}
|
|
523
393
|
} else if (catalog.transient) {
|
|
524
394
|
// D-3: a transient catalog failure says nothing about this integration's
|
|
525
395
|
// models — report and change NOTHING (never swap in a passthrough listing;
|
|
@@ -268,6 +268,63 @@ function callerDoorBearerOk(req) {
|
|
|
268
268
|
return require('../http/auth').requireBearer(req, strFlag('WALL_E_API_TOKEN', ''));
|
|
269
269
|
}
|
|
270
270
|
|
|
271
|
+
// WP-5b (lead-cost routing §6.2/§6.7): the rule cell decides whether a wait parks the watcher.
|
|
272
|
+
// 'off' is a user veto (D-18: final, and silent ticks cannot move it), 'silent' is an off cell
|
|
273
|
+
// still collecting 1-in-10 ticks (D-16), and CTM's default 'on' is returned as null so an
|
|
274
|
+
// unchanged request keeps its exact shape (`watch=` is omitted entirely). A route wait starts
|
|
275
|
+
// no watcher (WP-1), and a wait whose worker has no recorded route has no cell to read.
|
|
276
|
+
const WATCH_ORDER = Object.freeze({ off: 0, silent: 1, on: 2 });
|
|
277
|
+
const WATCH_OFF_CELL = 'off';
|
|
278
|
+
|
|
279
|
+
function _helperRulesDb() {
|
|
280
|
+
try {
|
|
281
|
+
// lib/brain-events is the one legal way to the db handle from llm/ (dependency-rules.json).
|
|
282
|
+
return require('../lib/brain-events').getDb();
|
|
283
|
+
} catch {
|
|
284
|
+
// expected: the brain is not initialized (a bare unit call) -- a missing handle reads 'on'
|
|
285
|
+
return null;
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
function _watchModeOfRoute(route, db) {
|
|
290
|
+
const { readCell, readCellState } = require('../lib/helper-rules/store');
|
|
291
|
+
const cellKey = `wait-watch|default|${route}`;
|
|
292
|
+
const row = readCell(db, cellKey);
|
|
293
|
+
if (row && Number(row.user_veto) === 1) return 'off';
|
|
294
|
+
return readCellState(db, cellKey) === WATCH_OFF_CELL ? 'silent' : 'on';
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
/**
|
|
298
|
+
* The `watch` mode one wait request carries, or null to omit the parameter (CTM's default
|
|
299
|
+
* 'on'). `hook` is lib/helper-rules/lead-call-hook.js and `db` the brain handle — both
|
|
300
|
+
* injectable so a test can drive the cell state directly.
|
|
301
|
+
*/
|
|
302
|
+
function watchModeFor(args = {}, hook = require('../lib/helper-rules/lead-call-hook'), db = _helperRulesDb()) {
|
|
303
|
+
const routes = new Set();
|
|
304
|
+
if (args.route) return null; // a route wait starts no watcher (WP-1)
|
|
305
|
+
try {
|
|
306
|
+
if (args.ctm_session_id) {
|
|
307
|
+
const entry = hook.workerRouteOf(args.ctm_session_id);
|
|
308
|
+
if (!entry || !entry.route) return null; // unknown -> 'on'
|
|
309
|
+
routes.add(entry.route);
|
|
310
|
+
} else {
|
|
311
|
+
for (const worker of hook.leadWorkersOf(args.parent_agent_session_id) || []) {
|
|
312
|
+
if (worker && worker.route) routes.add(worker.route);
|
|
313
|
+
}
|
|
314
|
+
if (!routes.size) return null; // nothing recorded -> 'on'
|
|
315
|
+
}
|
|
316
|
+
} catch {
|
|
317
|
+
// expected: the hook cannot answer -- 'on' is the fail-open default, never a failed wait
|
|
318
|
+
return null;
|
|
319
|
+
}
|
|
320
|
+
let mode = 'on';
|
|
321
|
+
for (const route of routes) {
|
|
322
|
+
const next = _watchModeOfRoute(route, db);
|
|
323
|
+
if (WATCH_ORDER[next] < WATCH_ORDER[mode]) mode = next; // the most restrictive route wins
|
|
324
|
+
}
|
|
325
|
+
return mode === 'on' ? null : mode;
|
|
326
|
+
}
|
|
327
|
+
|
|
271
328
|
// WP-5 (lead-aware wait, D-12, §6.5 E): one place decides which CTM call a worker
|
|
272
329
|
// status/wait tool makes and caps any report text it carries. It lives here, outside
|
|
273
330
|
// mcp-server.js's frozen ceiling: a named worker reads/waits on that worker alone with the
|
|
@@ -281,15 +338,19 @@ async function resolveWorkerWaitResult(ctmContextClient, toolName, args, reportT
|
|
|
281
338
|
if (isWait && args.route && args.ctm_session_id) {
|
|
282
339
|
return { error: 'wait_args_conflict', detail: 'ctm_session_id and route are mutually exclusive' };
|
|
283
340
|
}
|
|
341
|
+
// WP-5b: the watcher mode rides the WAIT request only (a plain status read starts none).
|
|
342
|
+
const watch = isWait ? watchModeFor(args) : null;
|
|
284
343
|
if (args.ctm_session_id) {
|
|
285
344
|
result = await ctmContextClient.workerStatus(args.ctm_session_id, {
|
|
286
345
|
timeoutMs: args.timeout_ms || 30000, includeReport: true, waitMs,
|
|
287
346
|
leadAgentSessionId: isWait ? args.parent_agent_session_id : undefined,
|
|
347
|
+
...(watch ? { watch } : {}),
|
|
288
348
|
});
|
|
289
349
|
} else if (isWait) {
|
|
290
350
|
result = await ctmContextClient.waitForWorkers({
|
|
291
351
|
leadAgentSessionId: args.parent_agent_session_id, waitMs, timeoutMs: args.timeout_ms || 30000,
|
|
292
352
|
...(args.route ? { route: String(args.route) } : {}),
|
|
353
|
+
...(watch ? { watch } : {}),
|
|
293
354
|
});
|
|
294
355
|
} else {
|
|
295
356
|
result = await ctmContextClient.workerStatus(args.ctm_session_id, { timeoutMs: args.timeout_ms || 30000, includeReport: true });
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
// gateway can sit behind any hostname).
|
|
13
13
|
|
|
14
14
|
const { parseCustomHeaders, isPortkeyRouteRow, portkeyRequestHeaders } = require('./portkey');
|
|
15
|
-
const { providerReasoningParams } = require('../../shared/reasoning-control');
|
|
15
|
+
const { providerReasoningParams, resolveReasoningControl } = require('../../shared/reasoning-control');
|
|
16
16
|
const { validateModelDeployments, canonicalJson } = require('../../shared/coding-model-deployment');
|
|
17
17
|
const crypto = require('node:crypto');
|
|
18
18
|
|
|
@@ -165,6 +165,45 @@ function routeReasoningLevelsForRow(row) {
|
|
|
165
165
|
return routeReasoningLevels(reasoningParamsForRoute(normalizeRowType(row), upstreamApisForRow(row).upstream_apis));
|
|
166
166
|
}
|
|
167
167
|
|
|
168
|
+
/** The Claude Code --effort vocabulary (code.claude.com/docs/en/model-config). Frozen; display order. */
|
|
169
|
+
const CLAUDE_CLI_EFFORT_LEVELS = Object.freeze(['low', 'medium', 'high', 'xhigh', 'max']);
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* D-1: the CLI effort levels a (route, wire model) pair can carry.
|
|
173
|
+
* - upstream_apis includes 'anthropic-messages' -> CLAUDE_CLI_EFFORT_LEVELS
|
|
174
|
+
* filtered to the Claude matrix for `model_id`
|
|
175
|
+
* (resolveReasoningControl({ providerType: 'anthropic', modelId }).values;
|
|
176
|
+
* a 'fixed' control, or an unparseable id, yields []).
|
|
177
|
+
* A passthrough anthropic-messages route relays the Claude CLI's own
|
|
178
|
+
* `output_config.effort` verbatim, so the CLI vocabulary -- not the
|
|
179
|
+
* chat-translate fragment map, which is empty for this wire shape -- is
|
|
180
|
+
* the truth here.
|
|
181
|
+
* - otherwise -> routeReasoningLevels(reasoningParamsForRoute(type,
|
|
182
|
+
* upstream_apis)) unchanged (D-4): the chat-translate fragment producer
|
|
183
|
+
* still decides for every other upstream API.
|
|
184
|
+
* Always returns a NEW array; never null; never throws on garbage input.
|
|
185
|
+
* @param {{ type?: string, upstream_apis?: string[], model_id?: string }} [args]
|
|
186
|
+
* @returns {string[]}
|
|
187
|
+
*/
|
|
188
|
+
function routeModelReasoningLevels(args) {
|
|
189
|
+
// Tolerate a null/undefined/garbage argument container: callers project rows
|
|
190
|
+
// from the brain and a malformed row must read as "no levels", never throw.
|
|
191
|
+
const { type = '', upstream_apis = [], model_id = '' } = (args && typeof args === 'object' && !Array.isArray(args)) ? args : {};
|
|
192
|
+
const apis = Array.isArray(upstream_apis) ? upstream_apis : [];
|
|
193
|
+
if (apis.indexOf(ANTHROPIC_MESSAGES_API) !== -1) {
|
|
194
|
+
const control = resolveReasoningControl({ providerType: 'anthropic', modelId: model_id });
|
|
195
|
+
const allowed = new Set((Array.isArray(control?.values) ? control.values : []).map((option) => option?.value));
|
|
196
|
+
return CLAUDE_CLI_EFFORT_LEVELS.filter((level) => allowed.has(level));
|
|
197
|
+
}
|
|
198
|
+
return routeReasoningLevels(reasoningParamsForRoute(String(type || '').toLowerCase(), apis));
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/** Row convenience, mirrors routeReasoningLevelsForRow. */
|
|
202
|
+
function routeModelReasoningLevelsForRow(row, modelId) {
|
|
203
|
+
const { upstream_apis } = upstreamApisForRow(row);
|
|
204
|
+
return routeModelReasoningLevels({ type: normalizeRowType(row), upstream_apis, model_id: modelId });
|
|
205
|
+
}
|
|
206
|
+
|
|
168
207
|
function publicWorkerCapability(row) {
|
|
169
208
|
const capabilities = row.capabilities || JSON.parse(row.capabilities_json || '{}');
|
|
170
209
|
const expired = row.state === 'unknown';
|
|
@@ -312,4 +351,7 @@ module.exports = {
|
|
|
312
351
|
reasoningParamsForRoute,
|
|
313
352
|
routeReasoningLevels,
|
|
314
353
|
routeReasoningLevelsForRow,
|
|
354
|
+
CLAUDE_CLI_EFFORT_LEVELS,
|
|
355
|
+
routeModelReasoningLevels,
|
|
356
|
+
routeModelReasoningLevelsForRow,
|
|
315
357
|
};
|
|
@@ -594,6 +594,44 @@ function finishConversationBootstrap({ state, batchLimit = 500 } = {}) {
|
|
|
594
594
|
}).immediate();
|
|
595
595
|
}
|
|
596
596
|
|
|
597
|
+
// Lead-cost routing WP-5a (design §6.6/§6.8, contract §2): the helper-rules record's four
|
|
598
|
+
// writes. lib/helper-rules/store.js owns the SQL and takes the handle; these wrappers are
|
|
599
|
+
// what brainWrite resolves — same function on the direct (RW) path and on the owner-routed
|
|
600
|
+
// path (workers/brain-owner-worker.js's CUSTOM_BRAIN_CALLS). WP-6 adds the fifth
|
|
601
|
+
// (helperRulesSetGrade): the spot-check grader's verdict on one explore row; round 2 WP-2 adds
|
|
602
|
+
// the two below it (D-5's close-by-worker and D-5/D-6's relabel).
|
|
603
|
+
function helperRulesRecordOutcome(outcome) {
|
|
604
|
+
return require('../lib/helper-rules/store').recordOutcome(brain.getDb(), outcome);
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
function helperRulesCloseOutcome(id, patch) {
|
|
608
|
+
return require('../lib/helper-rules/store').closeOutcome(brain.getDb(), id, patch);
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
// Round 2 WP-2 (§6.4 S-16): D-5's close path is keyed on the row's worker_id, so a Wall-E
|
|
612
|
+
// restart, an evicted in-memory map or a second process cannot orphan an open row.
|
|
613
|
+
function helperRulesCloseOutcomeByWorker(workerId, patch) {
|
|
614
|
+
return require('../lib/helper-rules/store').closeOutcomeByWorker(brain.getDb(), workerId, patch);
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
// Round 2 WP-2 (§6.4 S-16): the one-time relabel + D-6 recovery pass (idempotent — the second
|
|
618
|
+
// run changes nothing). The daily tick calls it too.
|
|
619
|
+
function helperRulesRelabel(options) {
|
|
620
|
+
return require('../lib/helper-rules/store').relabel(brain.getDb(), options);
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
function helperRulesSetCellState(cellKey, options) {
|
|
624
|
+
return require('../lib/helper-rules/store').setCellState(brain.getDb(), cellKey, options);
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
function helperRulesDailyTick() {
|
|
628
|
+
return require('../lib/helper-rules/store').dailyTick(brain.getDb());
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
function helperRulesSetGrade(id, gradeJson) {
|
|
632
|
+
return require('../lib/helper-rules/store').setGrade(brain.getDb(), id, gradeJson);
|
|
633
|
+
}
|
|
634
|
+
|
|
597
635
|
module.exports = {
|
|
598
636
|
failConversationExtraction,
|
|
599
637
|
markMemoriesExtractionSkipped,
|
|
@@ -620,4 +658,11 @@ module.exports = {
|
|
|
620
658
|
ingestUpdateMemoryContent,
|
|
621
659
|
runDbOptimizeMigration,
|
|
622
660
|
recordProviderHealthStatus,
|
|
661
|
+
helperRulesRecordOutcome,
|
|
662
|
+
helperRulesCloseOutcome,
|
|
663
|
+
helperRulesSetCellState,
|
|
664
|
+
helperRulesDailyTick,
|
|
665
|
+
helperRulesSetGrade,
|
|
666
|
+
helperRulesCloseOutcomeByWorker,
|
|
667
|
+
helperRulesRelabel,
|
|
623
668
|
};
|
|
@@ -28,12 +28,47 @@ const SERVER_INSTRUCTIONS = [
|
|
|
28
28
|
'`worker_started` already launched a separate worker: wait on it and review its report -- a process start is never task completion.',
|
|
29
29
|
"Keep the lead's own model and account.",
|
|
30
30
|
'Read-only census and review work can be delegated the same way with `worker_profile: "review"`: the worker cannot edit files, and you keep the verdict.',
|
|
31
|
+
'Wait on workers with walle_worker_wait and omit wait_ms; it wakes on a finished, failed, resumed or stuck worker, on a question, and when your user types -- never sleep-and-check or wrap it in a short-yield script.',
|
|
31
32
|
'',
|
|
32
33
|
'This guidance is advice, not enforcement: it never authorizes spawning extra agents on your own initiative, and Wall-E cannot intercept or reroute native `spawn_agent` calls you make without it.',
|
|
33
34
|
'',
|
|
34
35
|
"Use Wall-E memory before public web search or guesswork for private, remembered, or work-context questions: prior sessions, decisions, preferences, people, projects, documents, and the user's own style. `walle_context_hint` gives cheap preflight routing, `walle_lookup_context` one-shot private context, `walle_route_query` a routing verdict when unsure, and `walle_memory_status` connection health. In Codex, prefer `CODEX_THREAD_ID` over `CTM_SESSION_ID` for current-session lookups.",
|
|
35
36
|
].join('\n');
|
|
36
37
|
|
|
38
|
+
// WP-4 (lead-cost-routing-round1-2026-10-21.html §6.4 "Lead: exploration hand-off"): the block a
|
|
39
|
+
// lead harness receives ONLY while its `explore` rule cell is 'on' or 'probe' (lib/helper-rules/
|
|
40
|
+
// cell-state.js reads it; WP-5 owns the cell's storage and the switch). It is appended to
|
|
41
|
+
// SERVER_INSTRUCTIONS, never merged into it, so SERVER_INSTRUCTIONS stays the stable text every
|
|
42
|
+
// brain serves and the first 512 characters never move.
|
|
43
|
+
//
|
|
44
|
+
// Like the routing guidance above, this is ADVICE: the lead keeps the verdict, a review worker
|
|
45
|
+
// cannot edit files, and nothing here authorizes delegation the user did not ask for.
|
|
46
|
+
const EXPLORE_GUIDANCE = [
|
|
47
|
+
'## Lead: exploration hand-off',
|
|
48
|
+
'- If the question you are answering will take more than two reads and is not the exact lines you are about to edit,',
|
|
49
|
+
' hand it off before the third read. Write the brief FIRST, then call',
|
|
50
|
+
' walle_delegate_implementation({ brief_path, cwd, agent, worker_profile: "review" }) with no model or route.',
|
|
51
|
+
' If the result is resolved_native, run your own read-only sub-agent with the same brief instead.',
|
|
52
|
+
' Brief (four fields, nothing else):',
|
|
53
|
+
' Question: <one sentence>',
|
|
54
|
+
' Known so far: <facts you already have, with file:line>',
|
|
55
|
+
' Start from: <paths you already know matter> (optional)',
|
|
56
|
+
' Stop when: <the condition that answers the question>',
|
|
57
|
+
' Expected report (<= 600 words): a table of file:line + a <=5-line quote per row; INFERENCE marks; a "not found" row is valid.',
|
|
58
|
+
'- Check the report before using it: at least one file:line row and the Stop-when condition addressed. If not, or the',
|
|
59
|
+
' worker failed, read it yourself once. Never hand the same question off twice.',
|
|
60
|
+
"- Trust the report's file:line facts; re-read only the lines you will change.",
|
|
61
|
+
].join('\n');
|
|
62
|
+
|
|
63
|
+
// The one builder both transports call with the state their reader resolved; 'off' (and anything
|
|
64
|
+
// unrecognized) serves SERVER_INSTRUCTIONS byte-for-byte, so the guidance is switchable per lead
|
|
65
|
+
// harness without a restart and without a second copy of the text.
|
|
66
|
+
function buildServerInstructions({ explore = 'on' } = {}) {
|
|
67
|
+
return (explore === 'on' || explore === 'probe')
|
|
68
|
+
? `${SERVER_INSTRUCTIONS}\n\n${EXPLORE_GUIDANCE}`
|
|
69
|
+
: SERVER_INSTRUCTIONS;
|
|
70
|
+
}
|
|
71
|
+
|
|
37
72
|
// WP-2 correction (lead review): the managed agent-instruction block is the SECOND surface of the
|
|
38
73
|
// same shared guidance, so its owner lives here too -- one pure builder owning the full text, with
|
|
39
74
|
// no I/O, no filesystem and no dependencies (the two host-derived values arrive as arguments).
|
|
@@ -123,7 +158,10 @@ function handleProtocolMessage(message, options = {}) {
|
|
|
123
158
|
serverInfo: SERVER_INFO,
|
|
124
159
|
// WP-2: shared guidance every transport serves verbatim (MCP initialize result
|
|
125
160
|
// instructions) -- never a per-transport variant, so stdio and HTTP cannot drift.
|
|
126
|
-
|
|
161
|
+
// WP-4: the lead harness's exploration hand-off block rides on top ONLY when the
|
|
162
|
+
// transport resolved its `explore` cell (options.leadGuidance); with no option the
|
|
163
|
+
// reply is SERVER_INSTRUCTIONS, exactly as before this rule existed.
|
|
164
|
+
instructions: options.leadGuidance ? buildServerInstructions(options.leadGuidance) : SERVER_INSTRUCTIONS,
|
|
127
165
|
}),
|
|
128
166
|
},
|
|
129
167
|
};
|
|
@@ -142,11 +180,13 @@ function handleProtocolMessage(message, options = {}) {
|
|
|
142
180
|
|
|
143
181
|
module.exports = {
|
|
144
182
|
CAPABILITIES,
|
|
183
|
+
EXPLORE_GUIDANCE,
|
|
145
184
|
PROTOCOL_VERSION,
|
|
146
185
|
SERVER_INFO,
|
|
147
186
|
SERVER_INSTRUCTIONS,
|
|
148
187
|
SUPPORTED_PROTOCOL_VERSIONS,
|
|
149
188
|
buildManagedAgentInstructions,
|
|
189
|
+
buildServerInstructions,
|
|
150
190
|
handleProtocolMessage,
|
|
151
191
|
mcpError,
|
|
152
192
|
mcpResponse,
|
|
@@ -3,6 +3,8 @@ const fs = require('node:fs');
|
|
|
3
3
|
const path = require('node:path');
|
|
4
4
|
const { randomUUID: uuidv4 } = require('node:crypto');
|
|
5
5
|
const brain = require('./brain');
|
|
6
|
+
const { leadGuidanceForMessage } = require('./lib/helper-rules/cell-state');
|
|
7
|
+
const { recordLeadToolCall } = require('./lib/helper-rules/lead-call-hook'); // WP-5b §6.7: one-line lead-tool hook (S-11/S-13)
|
|
6
8
|
const { brainWrite } = require('./loops/brain-write');
|
|
7
9
|
const { normalizeKnowledgeCategory } = require('./brain/knowledge-categories');
|
|
8
10
|
const ctmSessionContext = require('./memory/ctm-session-context');
|
|
@@ -848,15 +850,22 @@ async function executeTool(name, args = {}, context = {}) {
|
|
|
848
850
|
// high-confidence or non-identity match, matching the test plan's
|
|
849
851
|
// "delegate with a 1.0 row never calls it" case.
|
|
850
852
|
if (typeof identityVerified === 'boolean') result.identity_verified = identityVerified;
|
|
853
|
+
recordLeadToolCall({ agentSessionId: args.parent_agent_session_id, tool: name, args, result, at: Date.now() });
|
|
851
854
|
return result;
|
|
852
855
|
}
|
|
853
856
|
case 'walle_worker_status': case 'walle_worker_wait': {
|
|
854
857
|
// WP-5 (D-12): the branching (named worker vs whole-set wait vs the no-identity
|
|
855
858
|
// 400 result) and the report-text cap live in worker-mcp-routing.js's
|
|
856
859
|
// resolveWorkerWaitResult -- mcp-server.js is at its frozen line ceiling.
|
|
857
|
-
|
|
860
|
+
const result = await resolveWorkerWaitResult(ctmContextClient, name, args, WORKER_STATUS_REPORT_TEXT_CAP_BYTES);
|
|
861
|
+
recordLeadToolCall({ agentSessionId: args.parent_agent_session_id, tool: name, args, result, at: Date.now() });
|
|
862
|
+
return result;
|
|
863
|
+
}
|
|
864
|
+
case 'walle_stop_worker': {
|
|
865
|
+
const result = await resolveWorkerStopResult(ctmContextClient, args);
|
|
866
|
+
recordLeadToolCall({ agentSessionId: args.parent_agent_session_id, tool: name, args, result, at: Date.now() });
|
|
867
|
+
return result;
|
|
858
868
|
}
|
|
859
|
-
case 'walle_stop_worker': return resolveWorkerStopResult(ctmContextClient, args);
|
|
860
869
|
case 'walle_resume_worker': {
|
|
861
870
|
const result = await ctmContextClient.resumeWorker(args.ctm_session_id, args.message, {
|
|
862
871
|
timeoutMs: args.timeout_ms || 30000, clientMessageId: args.client_message_id,
|
|
@@ -866,6 +875,7 @@ async function executeTool(name, args = {}, context = {}) {
|
|
|
866
875
|
// (worker-continuation.js) -- undefined leaves the key out, as parentAgentSessionId does.
|
|
867
876
|
callerToolUseId: args.caller_tool_use_id,
|
|
868
877
|
});
|
|
878
|
+
recordLeadToolCall({ agentSessionId: args.parent_agent_session_id, tool: name, args, result, at: Date.now() });
|
|
869
879
|
return projectWorkerResumeResult(result, { ctmSessionId: args.ctm_session_id });
|
|
870
880
|
}
|
|
871
881
|
case 'walle_list_sources': {
|
|
@@ -2734,6 +2744,7 @@ async function handleMcpMessage(msg, context = {}) {
|
|
|
2734
2744
|
// that do not need a response. Stdio keeps this false and proxies future
|
|
2735
2745
|
// notification methods here instead of silently swallowing them.
|
|
2736
2746
|
acceptAnyNotification: true,
|
|
2747
|
+
leadGuidance: leadGuidanceForMessage(msg, brain), // WP-4 §6.4: gates the exploration hand-off block
|
|
2737
2748
|
});
|
|
2738
2749
|
if (control.handled) return control.result;
|
|
2739
2750
|
|
|
@@ -342,6 +342,15 @@ const WORKER_STATUS_OUTPUT_SCHEMA = {
|
|
|
342
342
|
// §6.4): which source report_text came from: report, last_message, or a successful
|
|
343
343
|
// final provider result (status stays exited and report_present stays false).
|
|
344
344
|
report_source: { type: ['string', 'null'], enum: ['report', 'last_message', 'final_result', null] },
|
|
345
|
+
// lead-cost routing round 2 D-3: the distinct `file:line` citation count of the text
|
|
346
|
+
// report_source names -- null on a non-terminal status, never gated by include_report.
|
|
347
|
+
report_citation_rows: { type: ['integer', 'null'], minimum: 0 },
|
|
348
|
+
// lead-cost routing round 2 D-3: the character count of that same text (after the 64 KiB
|
|
349
|
+
// byte cap), null on a non-terminal status.
|
|
350
|
+
report_chars: { type: ['integer', 'null'], minimum: 0 },
|
|
351
|
+
// lead-cost routing round 2 D-3: present only when the report/last-message read threw --
|
|
352
|
+
// the error code (or 'read_failed'), with both counts at 0.
|
|
353
|
+
report_read_error: { type: 'string' },
|
|
345
354
|
last_message_path: { type: 'string' },
|
|
346
355
|
retention: WORKER_RETENTION_SCHEMA, poll_after_ms: { type: 'integer', minimum: 0 }, execution_profile: { type: 'object' }, // M-7 retention; WP-7 D-8 poll hint
|
|
347
356
|
// Worker budget ledger (WP-3, delegate-codex-lessons §5 D-2/D-6): task-scoped provider
|
|
@@ -422,7 +431,16 @@ const WORKER_WAIT_OUTPUT_SCHEMA = {
|
|
|
422
431
|
properties: {
|
|
423
432
|
...WORKER_STATUS_OUTPUT_SCHEMA.properties,
|
|
424
433
|
waited_ms: { type: 'integer', minimum: 0 },
|
|
425
|
-
|
|
434
|
+
// WP-1 (D-3/D-4): 'watcher' = the parked wait's watcher saw the worker stuck, looping or
|
|
435
|
+
// asking a question; 'watcher_unavailable' = it failed twice in a row and the lead is back
|
|
436
|
+
// to plain-code wakes.
|
|
437
|
+
woke_on: { type: 'string', enum: ['terminal', 'generation', 'advisory', 'timeout', 'user_input', 'route_clear', 'watcher', 'watcher_unavailable'] },
|
|
438
|
+
watcher_reason: { type: ['string', 'null'] },
|
|
439
|
+
watcher_decisions: { type: 'array', items: { type: 'object', additionalProperties: true } },
|
|
440
|
+
// WP-2 (session-stops-mid-job-2026-10-24.html §6 D-9): non-null while a worker this wait
|
|
441
|
+
// covered is still live -- it names that worker and says to call walle_worker_wait again
|
|
442
|
+
// (or walle_stop_worker); null once every worker of the wait is terminal.
|
|
443
|
+
lead_next_step: { type: ['string', 'null'] },
|
|
426
444
|
route: { type: 'string' },
|
|
427
445
|
admission: { type: ['object', 'null'], additionalProperties: true },
|
|
428
446
|
worker: { type: 'object', additionalProperties: true },
|
|
@@ -435,7 +453,7 @@ const WORKER_WAIT_OUTPUT_SCHEMA = {
|
|
|
435
453
|
|
|
436
454
|
const WORKER_WAIT_TOOL = {
|
|
437
455
|
name: 'walle_worker_wait',
|
|
438
|
-
description: 'Block until a delegated worker reaches a terminal state or starts a new generation, or until wait_ms elapses (or, with route, until that route hold ends); returns the walle_worker_status payload plus woke_on. Use this instead of sleep loops or polling the report file.',
|
|
456
|
+
description: 'Block until a delegated worker reaches a terminal state or starts a new generation, or until wait_ms elapses (or, with route, until that route hold ends); returns the walle_worker_status payload plus woke_on. Use this instead of sleep loops or polling the report file, or when a watcher sees the worker stuck, looping or asking a question, or when your user types.',
|
|
439
457
|
inputSchema: {
|
|
440
458
|
type: 'object',
|
|
441
459
|
properties: {
|