@bitkyc08/opencodex 2.83.0 → 2.86.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +0 -4
- package/bin/ocx.mjs +61 -3
- package/gui/dist/assets/App-BjlttVLy.js +58 -0
- package/gui/dist/assets/Tray-DyR9yBee.js +1 -0
- package/gui/dist/assets/{index-BAbcj51J.css → index-BB6uK6tU.css} +1 -1
- package/gui/dist/assets/index-BMssP4k3.js +94 -0
- package/gui/dist/assets/quota-summary-D8M1bc_R.js +1 -0
- package/gui/dist/index.html +2 -2
- package/package.json +2 -3
- package/src/adapters/anthropic/beta-allowlist.ts +87 -8
- package/src/adapters/anthropic/client-identity.ts +1 -1
- package/src/adapters/anthropic/passthrough.ts +33 -4
- package/src/adapters/azure.ts +19 -1
- package/src/adapters/client-fingerprint.ts +24 -0
- package/src/adapters/coding-agent/protocol.ts +15 -8
- package/src/adapters/coding-agent/turn.ts +22 -9
- package/src/adapters/cursor/arg-codec.ts +17 -5
- package/src/adapters/cursor/catalog.ts +8 -0
- package/src/adapters/cursor/effort-map.ts +3 -0
- package/src/adapters/cursor/freeform-args.ts +75 -0
- package/src/adapters/cursor/protobuf-events.ts +36 -23
- package/src/adapters/google-antigravity-wire.ts +22 -1
- package/src/adapters/google.ts +2 -2
- package/src/adapters/ollama-native.ts +29 -1
- package/src/adapters/openai-chat/messages.ts +8 -4
- package/src/adapters/openai-chat/response-events.ts +59 -1
- package/src/adapters/openai-chat.ts +8 -5
- package/src/adapters/openai-responses/empty-assistant.ts +32 -0
- package/src/adapters/openai-responses/passthrough.ts +3 -0
- package/src/adapters/openai-responses/request-strips.ts +10 -2
- package/src/adapters/qoder/adapter.ts +56 -15
- package/src/advisor/consult.ts +220 -0
- package/src/advisor/context.ts +226 -0
- package/src/advisor/disclosure.ts +20 -0
- package/src/advisor/runtime.ts +305 -0
- package/src/advisor/settings.ts +135 -0
- package/src/advisor/state.ts +369 -0
- package/src/advisor/synthetic-tool.ts +33 -0
- package/src/bridge/errors.ts +24 -0
- package/src/bridge.ts +1 -1
- package/src/chat/inbound.ts +30 -6
- package/src/chat/outbound.ts +5 -0
- package/src/claude/context-windows.ts +54 -1
- package/src/claude/desktop-3p-library.ts +43 -3
- package/src/claude/desktop-3p.ts +22 -8
- package/src/claude/desktop-picker-profile.ts +11 -4
- package/src/claude/desktop-profile.ts +10 -1
- package/src/claude/desktop-remote-store-io.ts +5 -3
- package/src/claude/inbound.ts +121 -50
- package/src/claude/intercept/connect-proxy.ts +10 -3
- package/src/claude/intercept/local-ca.ts +8 -1
- package/src/claude/intercept/picker-ca-persistence.ts +3 -1
- package/src/claude/intercept/picker-listener.ts +49 -1
- package/src/claude/intercept/settings-no-proxy.ts +146 -0
- package/src/claude/intercept/settings.ts +101 -9
- package/src/claude/model-default-settings.ts +154 -0
- package/src/claude/model-info.ts +7 -7
- package/src/claude/outbound.ts +13 -6
- package/src/cli/account-api.ts +65 -0
- package/src/cli/account-auth.ts +26 -2
- package/src/cli/account.ts +41 -5
- package/src/cli/advisor.ts +151 -0
- package/src/cli/auxiliary-listener-preflight.ts +37 -0
- package/src/cli/capabilities-access-remote.ts +8 -0
- package/src/cli/capabilities-agents-routing.ts +18 -0
- package/src/cli/capabilities-base.ts +14 -2
- package/src/cli/catalog-command-result.ts +2 -1
- package/src/cli/chatgpt-command.ts +35 -14
- package/src/cli/claude.ts +60 -11
- package/src/cli/config-command.ts +8 -2
- package/src/cli/debug.ts +8 -0
- package/src/cli/dispatch.ts +21 -4
- package/src/cli/doctor.ts +9 -0
- package/src/cli/ensure-desktop-cold-start.ts +329 -0
- package/src/cli/export-command.ts +15 -2
- package/src/cli/help.ts +2 -1
- package/src/cli/hub-disable.ts +99 -0
- package/src/cli/hub.ts +4 -2
- package/src/cli/index.ts +26 -8
- package/src/cli/integration-plan-dto.ts +2 -0
- package/src/cli/link-child.ts +104 -0
- package/src/cli/link-enrollment.ts +96 -0
- package/src/cli/link.ts +39 -24
- package/src/cli/observe-stream.ts +6 -1
- package/src/cli/observe.ts +10 -2
- package/src/cli/provider.ts +12 -0
- package/src/cli/registry.ts +20 -7
- package/src/cli/restart-scope.ts +3 -1
- package/src/cli/runtime-api.ts +27 -2
- package/src/cli/status.ts +104 -20
- package/src/client/connect.ts +39 -4
- package/src/client/hub-client.ts +14 -7
- package/src/client/hub-state.ts +25 -14
- package/src/client/link-home.ts +248 -0
- package/src/client/link-management-relay.ts +61 -0
- package/src/client/link-relay.ts +6 -1
- package/src/client/link-status.ts +14 -0
- package/src/client/machine-api.ts +14 -7
- package/src/client/machine-listener.ts +29 -4
- package/src/clients/config-export/contracts.ts +1 -0
- package/src/clients/config-export/model-metadata.ts +3 -2
- package/src/clients/config-export/qoder.ts +93 -0
- package/src/clients/config-export.ts +59 -16
- package/src/clients/omo-role-models.ts +6 -3
- package/src/codex/agent-role-models.ts +26 -8
- package/src/codex/auth-api/account-list.ts +17 -2
- package/src/codex/auth-api/account-selection.ts +17 -7
- package/src/codex/auth-api/pool-mode-gate.ts +5 -2
- package/src/codex/auth-api/routes.ts +5 -1
- package/src/codex/auth-context.ts +79 -5
- package/src/codex/autostart-health.ts +7 -1
- package/src/codex/catalog/build-entries.ts +11 -2
- package/src/codex/catalog/bundled.ts +5 -1
- package/src/codex/catalog/configured-tiers.ts +50 -0
- package/src/codex/catalog/effort.ts +6 -3
- package/src/codex/catalog/metadata.ts +4 -2
- package/src/codex/catalog/model-hints.ts +21 -3
- package/src/codex/catalog/native-models.ts +16 -2
- package/src/codex/catalog/native-ultrafast.ts +106 -0
- package/src/codex/catalog/parsing.ts +5 -0
- package/src/codex/catalog/provider-models.ts +4 -0
- package/src/codex/catalog/retained-sync.ts +2 -0
- package/src/codex/catalog/routed-gather.ts +22 -4
- package/src/codex/catalog/vendor-context.ts +82 -0
- package/src/codex/config-write-lock.ts +40 -2
- package/src/codex/convergence.ts +2 -0
- package/src/codex/desktop-app/types.ts +2 -0
- package/src/codex/desktop-app/windows.ts +29 -16
- package/src/codex/desktop-app-restart.ts +4 -2
- package/src/codex/desktop-compatibility/certificate-service.ts +99 -0
- package/src/codex/desktop-compatibility/certificate-store.ts +193 -0
- package/src/codex/desktop-compatibility/connection-store.ts +87 -0
- package/src/codex/desktop-compatibility/installed-build.ts +55 -0
- package/src/codex/desktop-compatibility/json-body.ts +29 -0
- package/src/codex/desktop-compatibility/native-identity.ts +62 -0
- package/src/codex/desktop-compatibility/relay-listener.ts +93 -0
- package/src/codex/desktop-compatibility/routing-binding.ts +10 -0
- package/src/codex/desktop-compatibility/routing-preflight.ts +69 -0
- package/src/codex/desktop-compatibility/runtime-ownership.ts +28 -0
- package/src/codex/desktop-compatibility/runtime.ts +173 -0
- package/src/codex/desktop-compatibility/service.ts +30 -0
- package/src/codex/desktop-compatibility/startup-settings.ts +50 -0
- package/src/codex/desktop-compatibility/usage-activation.ts +86 -0
- package/src/codex/desktop-compatibility/usage-controlled-fetch.ts +59 -0
- package/src/codex/desktop-compatibility/usage-controller.ts +107 -0
- package/src/codex/desktop-compatibility/usage-policy.ts +59 -0
- package/src/codex/desktop-compatibility/usage-refresh.ts +33 -0
- package/src/codex/desktop-compatibility/usage-sse-controller.ts +86 -0
- package/src/codex/desktop-compatibility/windows-activation-source.ts +44 -0
- package/src/codex/desktop-compatibility/windows-certificate-trust.ts +81 -0
- package/src/codex/desktop-compatibility/windows-key-protection.ts +59 -0
- package/src/codex/desktop-compatibility/windows-package-command.ts +86 -0
- package/src/codex/desktop-compatibility/windows-package-launch.ts +28 -0
- package/src/codex/history-provider.ts +1 -1
- package/src/codex/inject/config-write-section.ts +4 -1
- package/src/codex/inject/remove.ts +18 -6
- package/src/codex/journal.ts +16 -1
- package/src/codex/main-account.ts +99 -15
- package/src/codex/native-main-refresh-mode.ts +217 -0
- package/src/codex/native-profile-startup.ts +4 -1
- package/src/codex/prompt-journal.ts +20 -2
- package/src/codex/prompt-layers/encoding.ts +49 -0
- package/src/codex/prompt-layers/import-source.ts +30 -0
- package/src/codex/prompt-layers/toml-edit.ts +269 -37
- package/src/codex/prompt-layers/toml-read.ts +52 -4
- package/src/codex/prompt-layers.ts +383 -20
- package/src/codex/prompt-lock-claim.ts +13 -3
- package/src/codex/prompt-lock-evidence.ts +3 -3
- package/src/codex/prompt-lock-owner.ts +14 -6
- package/src/codex/prompt-text-probe.ts +34 -5
- package/src/codex/quota.ts +13 -6
- package/src/codex/role-auto-assign.ts +2 -5
- package/src/codex/routing/active-account.ts +21 -0
- package/src/codex/routing/health-store.ts +1 -1
- package/src/codex/routing/pool-recovery.ts +79 -0
- package/src/codex/routing.ts +1 -1
- package/src/codex/runtime.ts +196 -8
- package/src/codex/shim-diagnostics.ts +6 -0
- package/src/codex/shim-overlay.ts +15 -6
- package/src/codex/shim.ts +1 -1
- package/src/combos/failover.ts +3 -0
- package/src/config/api-key-reconcile.ts +34 -0
- package/src/config/diagnostics.ts +18 -1
- package/src/config/feature-flags.ts +5 -0
- package/src/config/live-reconcile.ts +56 -29
- package/src/config/live-topology.ts +29 -0
- package/src/config/load-degrade.ts +8 -2
- package/src/config/paths.ts +13 -3
- package/src/config/salvage.ts +3 -1
- package/src/config/schema/config-schema.ts +19 -0
- package/src/config/schema/desktop-compatibility.ts +9 -0
- package/src/config/schema/leaf-validators.ts +1 -0
- package/src/generated/compatibility-version.json +713 -285
- package/src/generated/model-metadata.ts +1 -1
- package/src/grok/grpc-web.ts +23 -1
- package/src/grok/reset-coupon-ledger.ts +75 -5
- package/src/grok/reset-coupons.ts +4 -2
- package/src/integrations/catalog-refresh.ts +1 -1
- package/src/integrations/config-io.ts +20 -2
- package/src/integrations/journal.ts +15 -1
- package/src/integrations/mutation-plan.ts +14 -7
- package/src/integrations/registry.ts +52 -11
- package/src/integrations/state.ts +19 -7
- package/src/integrations/store.ts +3 -0
- package/src/integrations/target.ts +42 -5
- package/src/integrations/writer.ts +24 -7
- package/src/lib/advisor-activation.ts +16 -0
- package/src/lib/app-owned-memory-stores.ts +4 -0
- package/src/lib/app-owned-memory.ts +11 -0
- package/src/lib/background-work.ts +65 -0
- package/src/lib/bounded-file-read.ts +58 -0
- package/src/lib/bun-path-runtime.d.mts +10 -1
- package/src/lib/bun-path-runtime.mjs +62 -3
- package/src/lib/desktop-proxy-route.ts +30 -0
- package/src/lib/desktop-upstream-tunnel.ts +107 -0
- package/src/lib/errors.ts +7 -0
- package/src/lib/json-byte-size.ts +31 -0
- package/src/lib/local-internal-call-capability.ts +55 -0
- package/src/lib/optional-shutdown-hooks.ts +35 -0
- package/src/lib/outbound-credential-registry.ts +210 -0
- package/src/lib/package-tree-integrity.ts +2 -2
- package/src/lib/passive-read.ts +35 -0
- package/src/lib/shadow-call.ts +44 -5
- package/src/lib/socks5-fetch.ts +48 -71
- package/src/lib/socks5-handshake.ts +112 -0
- package/src/lib/translator-budget.ts +7 -1
- package/src/link/codex-settings.ts +155 -0
- package/src/link/management-routes.ts +89 -0
- package/src/link/remote-probe.ts +38 -0
- package/src/link/ssh-argv.ts +26 -5
- package/src/link/ssh-runner.ts +58 -27
- package/src/link/status-projection.ts +22 -4
- package/src/link/supervisor.ts +144 -49
- package/src/link/tunnel-state.ts +11 -4
- package/src/oauth/anthropic-continuity.ts +4 -3
- package/src/oauth/anthropic-identity.ts +13 -2
- package/src/oauth/anthropic-model-quota.ts +13 -1
- package/src/oauth/anthropic-routing.ts +230 -23
- package/src/oauth/anthropic.ts +18 -4
- package/src/oauth/generic-account-failover.ts +29 -5
- package/src/oauth/google-antigravity.ts +24 -7
- package/src/oauth/index.ts +28 -17
- package/src/oauth/kiro-account-identity.ts +106 -0
- package/src/oauth/kiro-device-login.ts +2 -1
- package/src/oauth/kiro.ts +55 -6
- package/src/oauth/plan.ts +29 -0
- package/src/oauth/store.ts +40 -3
- package/src/oauth/types.ts +2 -0
- package/src/plugins/loader.ts +11 -0
- package/src/protocols/codecs/chat-ir.ts +467 -0
- package/src/protocols/codecs/chat.ts +10 -1
- package/src/protocols/codecs/messages-ir.ts +500 -0
- package/src/protocols/features.ts +10 -2
- package/src/protocols/path.ts +11 -1
- package/src/protocols/plan-snapshot.ts +39 -16
- package/src/protocols/plan.ts +9 -1
- package/src/protocols/settings.ts +8 -0
- package/src/providers/anthropic-billing-ownership.ts +74 -0
- package/src/providers/anthropic-billing-recovery.ts +31 -0
- package/src/providers/anthropic-billing-refusal.ts +55 -0
- package/src/providers/anthropic-reset-admission.ts +62 -0
- package/src/providers/anthropic-reset-grant-ledger.ts +28 -6
- package/src/providers/antigravity-account-roster.ts +102 -0
- package/src/providers/antigravity-models.ts +85 -7
- package/src/providers/api-key-resolve.ts +17 -2
- package/src/providers/key-failover.ts +52 -5
- package/src/providers/model-rename-fields.ts +2 -0
- package/src/providers/model-rename-migration.ts +5 -3
- package/src/providers/model-rename-startup.ts +5 -3
- package/src/providers/quota/account-cache.ts +11 -0
- package/src/providers/quota/anthropic-account-quota.ts +4 -2
- package/src/providers/quota/report-cache.ts +14 -0
- package/src/providers/quota/vendor-probes-oauth.ts +3 -3
- package/src/providers/quota.ts +4 -1
- package/src/providers/registry/entries-core.ts +21 -20
- package/src/providers/registry/entries-extended.ts +19 -1
- package/src/providers/registry/model-seeds.ts +17 -0
- package/src/providers/request-pacing.ts +9 -0
- package/src/providers/stale-no-vision-seed-migration.ts +72 -0
- package/src/responses/compaction.ts +14 -0
- package/src/responses/parser.ts +37 -20
- package/src/responses/state.ts +32 -29
- package/src/routing/history/build-file.ts +92 -0
- package/src/routing/history/indexer.ts +248 -216
- package/src/routing/history/ingest.ts +238 -0
- package/src/routing/history/rebuild-job.ts +111 -0
- package/src/routing/history/rebuild-protocol.ts +15 -0
- package/src/routing/history/rebuild-worker.ts +34 -0
- package/src/server/admission-model-scope.ts +4 -1
- package/src/server/antigravity-direct-eligibility.ts +208 -0
- package/src/server/auth-cors.ts +46 -0
- package/src/server/chat-completions.ts +75 -9
- package/src/server/claude-messages.ts +110 -20
- package/src/server/configured-credentials.ts +194 -0
- package/src/server/index/desktop-compatibility-startup.ts +56 -0
- package/src/server/index/link-management.ts +58 -0
- package/src/server/index/optional-listeners.ts +5 -1
- package/src/server/index/serve-options.ts +15 -2
- package/src/server/index/startup-warnings.ts +9 -0
- package/src/server/index/websocket-handler.ts +9 -0
- package/src/server/index.ts +13 -10
- package/src/server/inference/client-encoder-delivery.ts +6 -5
- package/src/server/lifecycle.ts +2 -1
- package/src/server/login-shell-path.ts +146 -0
- package/src/server/management/advisor-routes.ts +191 -0
- package/src/server/management/agent-settings-routes.ts +50 -14
- package/src/server/management/anthropic-reset-grant-routes.ts +17 -1
- package/src/server/management/codex-agent-role-routes.ts +19 -6
- package/src/server/management/codex-prompt-routes.ts +136 -5
- package/src/server/management/codex-role-auto-assign.ts +1 -1
- package/src/server/management/companion-routes.ts +4 -0
- package/src/server/management/config-routes.ts +2 -2
- package/src/server/management/context.ts +4 -0
- package/src/server/management/desktop-compatibility-routes.ts +46 -0
- package/src/server/management/desktop-compatibility-runtime-routes.ts +46 -0
- package/src/server/management/desktop-compatibility-settings-routes.ts +27 -0
- package/src/server/management/grok-coupon-routes.ts +78 -27
- package/src/server/management/link-enrollment.ts +192 -0
- package/src/server/management/link-route-state.ts +185 -0
- package/src/server/management/link-routes.ts +82 -402
- package/src/server/management/model-routes.ts +2 -2
- package/src/server/management/model-rows.ts +3 -1
- package/src/server/management/protocol-settings-patch.ts +1 -0
- package/src/server/management/provider-overwrite-carry.ts +10 -0
- package/src/server/management/provider-routes.ts +1 -0
- package/src/server/management/route-registry.ts +16 -3
- package/src/server/management/shared.ts +3 -0
- package/src/server/management/sibling-guard.ts +1 -0
- package/src/server/management-api.ts +9 -1
- package/src/server/messages-antigravity-direct.ts +195 -0
- package/src/server/messages-native.ts +73 -43
- package/src/server/relay-eager.ts +2 -0
- package/src/server/request-log-filter.ts +6 -1
- package/src/server/request-log-terminal-status.ts +63 -6
- package/src/server/request-log.ts +7 -0
- package/src/server/responses/adapter-continuation.ts +35 -18
- package/src/server/responses/adapter-delivery.ts +24 -2
- package/src/server/responses/adapter-dispatch.ts +261 -81
- package/src/server/responses/advisor-plan-slot.ts +27 -0
- package/src/server/responses/advisor-slot.ts +336 -0
- package/src/server/responses/code-mode-collab-surface.ts +313 -0
- package/src/server/responses/codex-ws-exchange.ts +147 -6
- package/src/server/responses/codex-ws-wire.ts +203 -0
- package/src/server/responses/collaboration.ts +36 -7
- package/src/server/responses/compact.ts +126 -48
- package/src/server/responses/context-overflow.ts +13 -1
- package/src/server/responses/core-codex-account.ts +105 -1
- package/src/server/responses/core-combo-failure.ts +24 -1
- package/src/server/responses/core-combo.ts +28 -2
- package/src/server/responses/core-errors.ts +29 -1
- package/src/server/responses/core-lifetime.ts +2 -0
- package/src/server/responses/core-normalize.ts +11 -0
- package/src/server/responses/core-options.ts +48 -0
- package/src/server/responses/core-replay.ts +7 -4
- package/src/server/responses/core.ts +1 -1
- package/src/server/responses/deferred-collab-surface.ts +158 -0
- package/src/server/responses/deferred-send-reporter.ts +25 -0
- package/src/server/responses/fetch-helpers.ts +12 -1
- package/src/server/responses/passthrough-delivery.ts +20 -11
- package/src/server/responses/passthrough-dispatch.ts +29 -7
- package/src/server/responses/request-prepare.ts +74 -9
- package/src/server/responses/request-transport.ts +22 -8
- package/src/server/responses/run-turn-execution.ts +70 -8
- package/src/server/responses/sidecar-execution.ts +89 -5
- package/src/server/responses/terminal-guard.ts +2 -1
- package/src/server/responses/ws-upstream.ts +9 -1
- package/src/server/responses-undeclared-tool-guard.ts +30 -9
- package/src/server/startup-action-control.ts +38 -4
- package/src/server/startup-health-cache.ts +5 -0
- package/src/server/system-env-shell.ts +7 -2
- package/src/server/system-env.ts +11 -1
- package/src/service/cli.ts +5 -1
- package/src/service/desktop-startup.ts +161 -34
- package/src/service/desktop-supervision.d.mts +27 -1
- package/src/service/desktop-supervision.mjs +111 -5
- package/src/service/health-sentinel-launch.ts +176 -0
- package/src/service/health-sentinel-main.ts +466 -0
- package/src/service/health-sentinel-policy.ts +241 -0
- package/src/service/health-sentinel-probe.ts +71 -0
- package/src/service/health-sentinel-windows.ts +87 -0
- package/src/service/linux-linger.ts +20 -0
- package/src/service/logging.ts +72 -0
- package/src/tray/windows-tray.ps1 +43 -24
- package/src/types/config.ts +68 -6
- package/src/types/provider.ts +7 -0
- package/src/types/request.ts +15 -0
- package/src/types/tools.ts +2 -0
- package/src/update/async-check.ts +1 -1
- package/src/update/badge.ts +2 -2
- package/src/update/index.ts +88 -15
- package/src/update/job-supervised-restart.ts +107 -0
- package/src/update/job.ts +32 -32
- package/src/update/notify.ts +1 -1
- package/src/update/refresh-scheduler.ts +2 -2
- package/src/update/supervised-recovery.d.mts +27 -0
- package/src/update/supervised-recovery.mjs +157 -0
- package/src/usage/cache-diagnostic.ts +2 -0
- package/src/usage/expected-prices.ts +16 -0
- package/src/usage/log.ts +19 -1
- package/src/web-search/gemini-executor.ts +2 -2
- package/assets/sponsors/packycode.png +0 -0
- package/gui/dist/assets/App-Ba8uG696.js +0 -54
- package/gui/dist/assets/Tray-IImbNPRy.js +0 -1
- package/gui/dist/assets/index-BHRZdJuv.js +0 -94
- package/gui/dist/assets/quota-summary-DiJO6sYY.js +0 -1
|
@@ -0,0 +1,305 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The advisor request plan: what the optional subsystem registers into the core Responses path.
|
|
3
|
+
*
|
|
4
|
+
* Created PER REQUEST through the activated factory called by the sidecar planner — never
|
|
5
|
+
* at module load and never globally. All mutable state is request-scoped except the bounded
|
|
6
|
+
* task-scoped preflight ledger (src/advisor/state.ts).
|
|
7
|
+
*
|
|
8
|
+
* Responsibilities:
|
|
9
|
+
* - decide whether the advisor applies to this request (settings + capability of the path);
|
|
10
|
+
* - preflight: one automatic consultation ATTEMPT per task when the orientation evidence exists,
|
|
11
|
+
* claimed atomically in the ledger and injected as user-role advisory data;
|
|
12
|
+
* - manual: back the synthetic `advisor` tool guard with real consultations through the routing
|
|
13
|
+
* authority (loopback chat completion);
|
|
14
|
+
* - observability: one structured log line per consultation — proof that the advisor actually
|
|
15
|
+
* ran (worker model, advisor model, trigger, duration, status, usage).
|
|
16
|
+
*
|
|
17
|
+
* Preflight injection transport: the runtime-owned instruction is fixed developer policy;
|
|
18
|
+
* all Advisor-generated bytes are a separate JSON-quoted user-role advisory message. Manual
|
|
19
|
+
* consultations remain paired tool results. No automatic path fabricates a tool call or
|
|
20
|
+
* places Advisor output in developer/system content. User-role advice can still contain
|
|
21
|
+
* hostile recommendations; the fixed policy tells the worker how to interpret that data.
|
|
22
|
+
*/
|
|
23
|
+
import type { OcxConfig, OcxParsedRequest } from "../types";
|
|
24
|
+
import type { AdvisorPlan, AdvisorConsultOutcome } from "../server/responses/advisor-slot";
|
|
25
|
+
import { createAdvisorGuard } from "../server/responses/advisor-slot";
|
|
26
|
+
import { resolveAdvisorSettings } from "./settings";
|
|
27
|
+
import { consultAdvisor } from "./consult";
|
|
28
|
+
import { buildAdvisorTool } from "./synthetic-tool";
|
|
29
|
+
import { sanitizeLogMetadataString } from "../lib/redact";
|
|
30
|
+
import {
|
|
31
|
+
advisorLedgerKey,
|
|
32
|
+
createAdvisorPreflightLedger,
|
|
33
|
+
hasOrientationEvidence,
|
|
34
|
+
historyHasManualAdvisorResult,
|
|
35
|
+
type AdvisorPreflightLedger,
|
|
36
|
+
} from "./state";
|
|
37
|
+
import { formatAdvisorAdvice, advisorPreflightMessages, formatAdvisorUnavailable } from "./context";
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Process-local task ledger. Bounded (entries + per-state TTL) in src/advisor/state.ts; one
|
|
41
|
+
* instance per process so the claim is atomic across concurrent requests. Not durable by design
|
|
42
|
+
* — see the documented restart limitation.
|
|
43
|
+
*/
|
|
44
|
+
const sharedPreflightLedger = createAdvisorPreflightLedger();
|
|
45
|
+
|
|
46
|
+
export const ADVISOR_SHARED_LEDGER = sharedPreflightLedger;
|
|
47
|
+
|
|
48
|
+
export interface AdvisorRuntimeDeps {
|
|
49
|
+
config: Pick<OcxConfig, "advisor" | "port" | "hostname" | "apiKeys" | "unauthenticatedLoopbackListener">;
|
|
50
|
+
/** Routed worker identity for logs and the advisor payload, e.g. "deepseek-chat (provider deepseek)". */
|
|
51
|
+
workerIdentity: string;
|
|
52
|
+
workerModelId: string;
|
|
53
|
+
abortSignal?: AbortSignal;
|
|
54
|
+
/** Test seam; production always self-fetches the resolved local destination. */
|
|
55
|
+
baseUrlOverride?: string;
|
|
56
|
+
/** Test seam; production uses the process-wide ledger. */
|
|
57
|
+
ledger?: AdvisorPreflightLedger;
|
|
58
|
+
/** Deterministic clock seam for the ledger's TTL/cooldown arithmetic (tests only). */
|
|
59
|
+
now?: () => number;
|
|
60
|
+
/**
|
|
61
|
+
* Test seam: runs after a preflight claim is taken and before the consultation
|
|
62
|
+
* dispatch, so a test can revoke consent in the claim-to-outbound window.
|
|
63
|
+
*/
|
|
64
|
+
afterPreflightClaim?: () => void;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export interface AdvisorRuntimePlan extends AdvisorPlan {
|
|
68
|
+
readonly policy: "manual" | "preflight";
|
|
69
|
+
readonly toolEnabled: boolean;
|
|
70
|
+
readonly tool: import("../types").OcxTool;
|
|
71
|
+
/**
|
|
72
|
+
* The automatic preflight pass. Returns true when advice was injected. A cancelled
|
|
73
|
+
* consultation injects nothing and leaves the task eligible for a later attempt.
|
|
74
|
+
*/
|
|
75
|
+
preflightInject(parsed: OcxParsedRequest): Promise<boolean>;
|
|
76
|
+
/** Attach the stream guard for the synthetic tool to the parsed request. */
|
|
77
|
+
attachGuard(parsed: OcxParsedRequest): void;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export function createAdvisorRuntimePlan(deps: AdvisorRuntimeDeps): AdvisorRuntimePlan | null {
|
|
81
|
+
const initial = resolveAdvisorSettings(deps.config);
|
|
82
|
+
// A model is required before the synthetic tool exists. Consent is checked at every
|
|
83
|
+
// consultation against the live config, so an enabled advisor without current consent can
|
|
84
|
+
// still refuse a manual call in-band without sending task context. Disabled, or enabled
|
|
85
|
+
// with no model, stays off the path.
|
|
86
|
+
if (!initial.enabled || initial.model.trim() === "") return null;
|
|
87
|
+
const ledger = deps.ledger ?? sharedPreflightLedger;
|
|
88
|
+
const now = deps.now ?? (() => Date.now());
|
|
89
|
+
// Management PUT mutates this same config object (`config.advisor = ...`). Re-resolving
|
|
90
|
+
// at dispatch is what makes a mid-request consent revocation stop outbound transfer.
|
|
91
|
+
const liveSettings = () => resolveAdvisorSettings(deps.config);
|
|
92
|
+
|
|
93
|
+
// Request-scoped state: born here, dies with the request. Never global.
|
|
94
|
+
const fingerprints = new Set<string>();
|
|
95
|
+
let preflightUsed = false;
|
|
96
|
+
|
|
97
|
+
const taskKey = (parsed: OcxParsedRequest): string | undefined =>
|
|
98
|
+
advisorLedgerKey(parsed, deps.workerModelId);
|
|
99
|
+
|
|
100
|
+
const logConsultation = (
|
|
101
|
+
trigger: "manual" | "preflight",
|
|
102
|
+
outcome: { ok: boolean; cancelled?: boolean; durationMs: number; error?: string; usage?: { inputTokens?: number; outputTokens?: number; totalTokens?: number } },
|
|
103
|
+
advisorModel: string,
|
|
104
|
+
): void => {
|
|
105
|
+
const usage = outcome.usage
|
|
106
|
+
? ` usage=in=${outcome.usage.inputTokens ?? "?"} out=${outcome.usage.outputTokens ?? "?"}`
|
|
107
|
+
: "";
|
|
108
|
+
const status = outcome.ok ? "ok" : outcome.cancelled ? "cancelled" : "failed";
|
|
109
|
+
const errorNote = outcome.ok || outcome.cancelled
|
|
110
|
+
? ""
|
|
111
|
+
: ` error=${sanitizeLogMetadataString(outcome.error ?? "unknown", 160) ?? "unknown"}`;
|
|
112
|
+
// One structured line per consultation: model ids, timing, and a bounded status. No prompt,
|
|
113
|
+
// no tool output, no capability.
|
|
114
|
+
console.warn(
|
|
115
|
+
`[advisor] consultation ${status} trigger=${trigger} worker=${deps.workerModelId}`
|
|
116
|
+
+ ` advisor=${advisorModel} durationMs=${outcome.durationMs}${usage}${errorNote}`,
|
|
117
|
+
);
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
const runConsultation = async (
|
|
121
|
+
parsed: OcxParsedRequest,
|
|
122
|
+
reason: "manual" | "preflight",
|
|
123
|
+
question: string | undefined,
|
|
124
|
+
): Promise<AdvisorConsultOutcome> => {
|
|
125
|
+
const current = liveSettings();
|
|
126
|
+
if (!current.enabled || current.model.trim() === "") {
|
|
127
|
+
return {
|
|
128
|
+
ok: false,
|
|
129
|
+
isError: true,
|
|
130
|
+
blocked: "settings",
|
|
131
|
+
content: formatAdvisorUnavailable(
|
|
132
|
+
reason === "preflight" ? "preflight" : "manual",
|
|
133
|
+
"advisor is not configured",
|
|
134
|
+
),
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
// Consent is operator config. Task text, the worker, and the advisor cannot grant it.
|
|
138
|
+
// The live object is re-read here so a revocation after plan creation still blocks
|
|
139
|
+
// outbound transfer. No fingerprint, no ledger write, no fetch.
|
|
140
|
+
if (current.contextSharingConsent === null) {
|
|
141
|
+
console.warn(
|
|
142
|
+
`[advisor] consultation blocked trigger=${reason} reason=advisor_context_sharing_consent_required`,
|
|
143
|
+
);
|
|
144
|
+
return {
|
|
145
|
+
ok: false,
|
|
146
|
+
isError: true,
|
|
147
|
+
blocked: "consent",
|
|
148
|
+
content: formatAdvisorUnavailable(
|
|
149
|
+
"consent",
|
|
150
|
+
"advisor_context_sharing_consent_required",
|
|
151
|
+
),
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
// Same-consultation dedup within this request: identical trigger + focus returns a
|
|
155
|
+
// non-advice outcome instead of a second expert call.
|
|
156
|
+
const fingerprint = `${reason}|${question ?? ""}`;
|
|
157
|
+
let result;
|
|
158
|
+
if (fingerprints.has(fingerprint)) {
|
|
159
|
+
result = {
|
|
160
|
+
ok: false,
|
|
161
|
+
advice: "",
|
|
162
|
+
advisorModel: current.model,
|
|
163
|
+
error: "duplicate consultation request (already consulted with this focus in this request)",
|
|
164
|
+
durationMs: 0,
|
|
165
|
+
};
|
|
166
|
+
return {
|
|
167
|
+
ok: false,
|
|
168
|
+
isError: true,
|
|
169
|
+
content: formatAdvisorUnavailable(reason === "preflight" ? "preflight" : "manual", result.error),
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
fingerprints.add(fingerprint);
|
|
173
|
+
result = await consultAdvisor(
|
|
174
|
+
{
|
|
175
|
+
parsed,
|
|
176
|
+
workerIdentity: deps.workerIdentity,
|
|
177
|
+
advisorModel: current.model,
|
|
178
|
+
reason,
|
|
179
|
+
...(question !== undefined ? { question } : {}),
|
|
180
|
+
},
|
|
181
|
+
deps.config,
|
|
182
|
+
current.effort,
|
|
183
|
+
current.timeoutMs,
|
|
184
|
+
deps.abortSignal,
|
|
185
|
+
deps.baseUrlOverride,
|
|
186
|
+
);
|
|
187
|
+
logConsultation(reason, result, current.model);
|
|
188
|
+
|
|
189
|
+
if (result.ok) {
|
|
190
|
+
// A genuine result suppresses further automatic consultation for the task. Manual success
|
|
191
|
+
// settles it too: a task the worker already had advised does not need a preflight attempt.
|
|
192
|
+
if (reason === "manual") {
|
|
193
|
+
const key = taskKey(parsed);
|
|
194
|
+
// A manual consultation owns no preflight claim; this records the FACT that the task was
|
|
195
|
+
// advised, which is true whichever consultation produced the advice.
|
|
196
|
+
if (key) ledger.markAdvised(key, now());
|
|
197
|
+
}
|
|
198
|
+
return {
|
|
199
|
+
ok: true,
|
|
200
|
+
isError: false,
|
|
201
|
+
content: formatAdvisorAdvice({
|
|
202
|
+
advisorModel: result.advisorModel,
|
|
203
|
+
reason,
|
|
204
|
+
advice: result.advice,
|
|
205
|
+
channel: reason === "preflight" ? "preflight" : "manual",
|
|
206
|
+
}),
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
return {
|
|
210
|
+
ok: false,
|
|
211
|
+
isError: true,
|
|
212
|
+
...(result.cancelled ? { cancelled: true } : {}),
|
|
213
|
+
content: formatAdvisorUnavailable(reason === "preflight" ? "preflight" : "manual", result.error ?? "unavailable"),
|
|
214
|
+
};
|
|
215
|
+
};
|
|
216
|
+
|
|
217
|
+
const preflightInject = async (parsed: OcxParsedRequest): Promise<boolean> => {
|
|
218
|
+
const current = liveSettings();
|
|
219
|
+
if (current.policy !== "preflight" || preflightUsed) return false;
|
|
220
|
+
// No consent, disabled, or no model: do not claim, do not inject, do not send task context.
|
|
221
|
+
if (!current.enabled || current.model.trim() === "" || current.contextSharingConsent === null) return false;
|
|
222
|
+
// A genuine MANUAL consultation already advised this task (verifiable tool-result
|
|
223
|
+
// provenance), or the task has no orientation evidence yet: skip.
|
|
224
|
+
if (historyHasManualAdvisorResult(parsed)) return false;
|
|
225
|
+
if (!hasOrientationEvidence(parsed)) return false;
|
|
226
|
+
|
|
227
|
+
// Atomic claim. A client with a stable conversation identity participates in the
|
|
228
|
+
// process-global ledger, so concurrent requests for one task consult at most once and a
|
|
229
|
+
// settled task is not re-consulted. A client with NO stable identity stays out of the
|
|
230
|
+
// ledger on purpose: request-scoped dedup plus genuine in-history provenance are the only
|
|
231
|
+
// suppression it gets — fail-open, so two independent identity-less conversations can never
|
|
232
|
+
// suppress each other through a shared guess.
|
|
233
|
+
const key = taskKey(parsed);
|
|
234
|
+
let claimToken: string | undefined;
|
|
235
|
+
if (key) {
|
|
236
|
+
const claim = ledger.claim(key, now());
|
|
237
|
+
if (claim.state !== "claimed") return false;
|
|
238
|
+
claimToken = claim.token;
|
|
239
|
+
}
|
|
240
|
+
preflightUsed = true;
|
|
241
|
+
deps.afterPreflightClaim?.();
|
|
242
|
+
|
|
243
|
+
let outcome: AdvisorConsultOutcome;
|
|
244
|
+
try {
|
|
245
|
+
outcome = await runConsultation(parsed, "preflight", undefined);
|
|
246
|
+
} catch (error) {
|
|
247
|
+
if (key && claimToken) ledger.fail(key, claimToken, now());
|
|
248
|
+
console.warn(`[advisor] consultation failed trigger=preflight worker=${deps.workerModelId} error=plan_threw`);
|
|
249
|
+
parsed.context.messages = [
|
|
250
|
+
...parsed.context.messages,
|
|
251
|
+
{
|
|
252
|
+
role: "user",
|
|
253
|
+
content: "An automatic advisor consultation could not be completed. Continue with your own judgment.",
|
|
254
|
+
timestamp: Date.now(),
|
|
255
|
+
},
|
|
256
|
+
];
|
|
257
|
+
void error;
|
|
258
|
+
return false;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
if (outcome.blocked) {
|
|
262
|
+
// Operator revoked consent (or disabled the sidecar) after the claim: not a provider
|
|
263
|
+
// failure. Release so the task is not put on cooldown and nothing is injected.
|
|
264
|
+
if (key && claimToken) ledger.release(key, claimToken, now());
|
|
265
|
+
return false;
|
|
266
|
+
}
|
|
267
|
+
if (outcome.ok) {
|
|
268
|
+
if (key && claimToken) ledger.complete(key, claimToken, now());
|
|
269
|
+
} else if (outcome.cancelled) {
|
|
270
|
+
// Client cancellation is not a provider failure: no cooldown, the task may retry later.
|
|
271
|
+
if (key && claimToken) ledger.release(key, claimToken, now());
|
|
272
|
+
// Nothing to inject — the caller is gone or aborting; do not add noise to a live turn.
|
|
273
|
+
return false;
|
|
274
|
+
} else {
|
|
275
|
+
if (key && claimToken) ledger.fail(key, claimToken, now());
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
parsed.context.messages = [
|
|
279
|
+
...parsed.context.messages,
|
|
280
|
+
...advisorPreflightMessages(outcome.content),
|
|
281
|
+
];
|
|
282
|
+
return outcome.ok;
|
|
283
|
+
};
|
|
284
|
+
|
|
285
|
+
const plan: AdvisorPlan = {
|
|
286
|
+
consult: (parsed, reason, question) => runConsultation(parsed, reason, question),
|
|
287
|
+
// The guard's own failure/limit text goes through the same runtime-owned, marker-neutralized
|
|
288
|
+
// formatter so no guard path can emit text that looks like a genuine advice wrapper.
|
|
289
|
+
formatUnavailable: (kind, error) => formatAdvisorUnavailable(kind, error),
|
|
290
|
+
};
|
|
291
|
+
|
|
292
|
+
return {
|
|
293
|
+
policy: initial.policy,
|
|
294
|
+
// The synthetic tool is only safe where the guard can intercept: run-turn adapters own their
|
|
295
|
+
// own loops, so they get preflight support but never the tool (documented limitation).
|
|
296
|
+
toolEnabled: initial.enabled,
|
|
297
|
+
tool: buildAdvisorTool(),
|
|
298
|
+
consult: plan.consult,
|
|
299
|
+
formatUnavailable: plan.formatUnavailable,
|
|
300
|
+
preflightInject,
|
|
301
|
+
attachGuard: parsed => {
|
|
302
|
+
parsed._advisorGuard = createAdvisorGuard(plan);
|
|
303
|
+
},
|
|
304
|
+
};
|
|
305
|
+
}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The single reader of `advisor` config.
|
|
3
|
+
*
|
|
4
|
+
* Nothing else reads the `advisor` key directly: the sidecar planner, the management API and the
|
|
5
|
+
* CLI all resolve through here, so they cannot disagree about defaults or validity. Type-only
|
|
6
|
+
* config import keeps this module free of runtime edges.
|
|
7
|
+
*/
|
|
8
|
+
import type { OcxConfig } from "../types";
|
|
9
|
+
import { ADVISOR_CONTEXT_SHARING_CONSENT_VERSION } from "./disclosure";
|
|
10
|
+
|
|
11
|
+
export { ADVISOR_CONTEXT_SHARING_CONSENT_VERSION };
|
|
12
|
+
|
|
13
|
+
export type AdvisorPolicy = "manual" | "preflight";
|
|
14
|
+
|
|
15
|
+
export const ADVISOR_EFFORTS = ["low", "medium", "high", "xhigh", "max", "ultra"] as const;
|
|
16
|
+
export type AdvisorEffort = (typeof ADVISOR_EFFORTS)[number];
|
|
17
|
+
|
|
18
|
+
export const ADVISOR_POLICIES = ["manual", "preflight"] as const;
|
|
19
|
+
|
|
20
|
+
export interface AdvisorSettings {
|
|
21
|
+
enabled: boolean;
|
|
22
|
+
model: string;
|
|
23
|
+
effort: AdvisorEffort;
|
|
24
|
+
policy: AdvisorPolicy;
|
|
25
|
+
timeoutMs: number;
|
|
26
|
+
/**
|
|
27
|
+
* Current context-sharing consent, or null when absent, stale, or malformed.
|
|
28
|
+
* `enabled` does not imply this. Only the current version allows data transfer.
|
|
29
|
+
*/
|
|
30
|
+
contextSharingConsent: typeof ADVISOR_CONTEXT_SHARING_CONSENT_VERSION | null;
|
|
31
|
+
/** Where each resolved value came from, so the GUI/CLI can show real runtime state. */
|
|
32
|
+
sources: {
|
|
33
|
+
enabled: "default" | "configured";
|
|
34
|
+
model: "default" | "configured";
|
|
35
|
+
effort: "default" | "configured";
|
|
36
|
+
policy: "default" | "configured";
|
|
37
|
+
contextSharingConsent: "default" | "configured";
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export const DEFAULT_ADVISOR_SETTINGS: Readonly<AdvisorSettings> = Object.freeze({
|
|
42
|
+
enabled: false,
|
|
43
|
+
model: "",
|
|
44
|
+
effort: "max",
|
|
45
|
+
policy: "manual",
|
|
46
|
+
timeoutMs: 120_000,
|
|
47
|
+
contextSharingConsent: null,
|
|
48
|
+
sources: Object.freeze({
|
|
49
|
+
enabled: "default",
|
|
50
|
+
model: "default",
|
|
51
|
+
effort: "default",
|
|
52
|
+
policy: "default",
|
|
53
|
+
contextSharingConsent: "default",
|
|
54
|
+
}),
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
type Rec = Record<string, unknown>;
|
|
58
|
+
function isRec(value: unknown): value is Rec {
|
|
59
|
+
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export function isValidAdvisorEffort(value: unknown): value is AdvisorEffort {
|
|
63
|
+
return typeof value === "string" && (ADVISOR_EFFORTS as readonly string[]).includes(value);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export function isValidAdvisorPolicy(value: unknown): value is AdvisorPolicy {
|
|
67
|
+
return typeof value === "string" && (ADVISOR_POLICIES as readonly string[]).includes(value);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/** True only for the current context-sharing consent version. Anything else is not a grant. */
|
|
71
|
+
export function isCurrentAdvisorContextSharingConsent(
|
|
72
|
+
value: unknown,
|
|
73
|
+
): value is typeof ADVISOR_CONTEXT_SHARING_CONSENT_VERSION {
|
|
74
|
+
return value === ADVISOR_CONTEXT_SHARING_CONSENT_VERSION;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Resolve advisor settings with conservative defaults for every absent or malformed field.
|
|
79
|
+
* A malformed block resolves to fully disabled defaults rather than throwing: the advisor is
|
|
80
|
+
* optional and must never take the request path down with it.
|
|
81
|
+
*/
|
|
82
|
+
export function resolveAdvisorSettings(config: Pick<OcxConfig, "advisor">): AdvisorSettings {
|
|
83
|
+
const raw: unknown = config.advisor;
|
|
84
|
+
if (!isRec(raw)) return { ...DEFAULT_ADVISOR_SETTINGS, sources: { ...DEFAULT_ADVISOR_SETTINGS.sources } };
|
|
85
|
+
const enabled = typeof raw.enabled === "boolean" ? raw.enabled : DEFAULT_ADVISOR_SETTINGS.enabled;
|
|
86
|
+
const model = typeof raw.model === "string" ? raw.model.trim() : DEFAULT_ADVISOR_SETTINGS.model;
|
|
87
|
+
const effort = isValidAdvisorEffort(raw.effort) ? raw.effort : DEFAULT_ADVISOR_SETTINGS.effort;
|
|
88
|
+
const policy = isValidAdvisorPolicy(raw.policy) ? raw.policy : DEFAULT_ADVISOR_SETTINGS.policy;
|
|
89
|
+
const timeoutRaw = raw.timeoutMs;
|
|
90
|
+
const timeoutMs = typeof timeoutRaw === "number" && Number.isFinite(timeoutRaw) && timeoutRaw >= 1_000
|
|
91
|
+
? Math.min(Math.floor(timeoutRaw), 600_000)
|
|
92
|
+
: DEFAULT_ADVISOR_SETTINGS.timeoutMs;
|
|
93
|
+
// A present but non-current value (stale version, wrong type) resolves as no consent.
|
|
94
|
+
// The stored bytes are left untouched; this reader never writes an upgrade.
|
|
95
|
+
const consentConfigured = Object.prototype.hasOwnProperty.call(raw, "contextSharingConsent");
|
|
96
|
+
const contextSharingConsent = isCurrentAdvisorContextSharingConsent(raw.contextSharingConsent)
|
|
97
|
+
? raw.contextSharingConsent
|
|
98
|
+
: null;
|
|
99
|
+
return {
|
|
100
|
+
enabled,
|
|
101
|
+
model,
|
|
102
|
+
effort,
|
|
103
|
+
policy,
|
|
104
|
+
timeoutMs,
|
|
105
|
+
contextSharingConsent,
|
|
106
|
+
sources: {
|
|
107
|
+
enabled: typeof raw.enabled === "boolean" ? "configured" : "default",
|
|
108
|
+
model: typeof raw.model === "string" && raw.model.trim() !== "" ? "configured" : "default",
|
|
109
|
+
effort: isValidAdvisorEffort(raw.effort) ? "configured" : "default",
|
|
110
|
+
policy: isValidAdvisorPolicy(raw.policy) ? "configured" : "default",
|
|
111
|
+
contextSharingConsent: consentConfigured ? "configured" : "default",
|
|
112
|
+
},
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Whether a consultation may send task context. Requires the switch, a model, and the
|
|
118
|
+
* current context-sharing consent. `enabled` is not consent. A miss fails closed for the
|
|
119
|
+
* data transfer and leaves the worker request itself running.
|
|
120
|
+
*/
|
|
121
|
+
export function advisorRunnable(settings: AdvisorSettings): boolean {
|
|
122
|
+
return settings.enabled
|
|
123
|
+
&& settings.model.trim() !== ""
|
|
124
|
+
&& settings.contextSharingConsent === ADVISOR_CONTEXT_SHARING_CONSENT_VERSION;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Enabled, with a model, but without current consent. The management surface reports
|
|
129
|
+
* `advisor_context_sharing_consent_required` and the runtime sends no task context.
|
|
130
|
+
*/
|
|
131
|
+
export function advisorContextSharingBlocked(settings: AdvisorSettings): boolean {
|
|
132
|
+
return settings.enabled
|
|
133
|
+
&& settings.model.trim() !== ""
|
|
134
|
+
&& settings.contextSharingConsent !== ADVISOR_CONTEXT_SHARING_CONSENT_VERSION;
|
|
135
|
+
}
|