@oar-sh/oar 0.9.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/.github/extensions/web-relay/README.md +190 -0
- package/.github/extensions/web-relay/extension.mjs +972 -0
- package/.github/extensions/web-relay/model-api/model-switching.mjs +338 -0
- package/.github/extensions/web-relay/polling/heartbeat.mjs +55 -0
- package/.github/extensions/web-relay/polling/polling-loop.mjs +1105 -0
- package/.github/extensions/web-relay/runtime/api-client.mjs +34 -0
- package/.github/extensions/web-relay/runtime/banner-state.mjs +126 -0
- package/.github/extensions/web-relay/runtime/config-loader.mjs +104 -0
- package/.github/extensions/web-relay/runtime/debug-log.mjs +27 -0
- package/.github/extensions/web-relay/runtime/send-and-wait-errors.mjs +170 -0
- package/.github/extensions/web-relay/runtime/session-binding.mjs +78 -0
- package/.github/extensions/web-relay/runtime/session-io.mjs +349 -0
- package/.github/extensions/web-relay/runtime/session-join-retry.mjs +44 -0
- package/.github/extensions/web-relay/runtime/session-registry.mjs +29 -0
- package/.github/extensions/web-relay/runtime/session-runtime-manager.mjs +156 -0
- package/.github/extensions/web-relay/runtime/session-sync-bridge.mjs +74 -0
- package/.github/extensions/web-relay/runtime/worker-websocket-link.mjs +325 -0
- package/.github/extensions/web-relay/runtime/workspace-root.mjs +55 -0
- package/.github/extensions/web-relay/server-lifecycle/managed-server.mjs +386 -0
- package/.github/extensions/web-relay/skills/prompt-context.mjs +160 -0
- package/.github/extensions/web-relay/skills/question-bridge.mjs +141 -0
- package/.github/extensions/web-relay/skills/question-routing-hooks.mjs +463 -0
- package/.github/extensions/web-relay/skills/reasoning-stream.mjs +285 -0
- package/.github/extensions/web-relay/skills/subagent-lifecycle.mjs +345 -0
- package/.github/extensions/web-relay/skills/tool-activity.mjs +243 -0
- package/.github/extensions/web-relay/utils/process-utils.mjs +25 -0
- package/.github/extensions/web-relay/utils/token-generation.mjs +58 -0
- package/CHANGELOG.md +25 -0
- package/LICENSE +21 -0
- package/README.md +717 -0
- package/bin/bat/oar.bat +46 -0
- package/bin/oar.js +665 -0
- package/package.json +68 -0
- package/server/README.md +1379 -0
- package/server/claude-worker/claude-attachments.mjs +134 -0
- package/server/claude-worker/claude-preview-tool.mjs +57 -0
- package/server/claude-worker/claude-sdk-adapter.mjs +420 -0
- package/server/claude-worker/claude-session-process.mjs +2391 -0
- package/server/claude-worker/claude-session-test-harness.mjs +236 -0
- package/server/claude-worker/claude-session-worker.mjs +186 -0
- package/server/claude-worker/claude-transcript-relocator.mjs +189 -0
- package/server/claude-worker/claude-turn-publisher.mjs +291 -0
- package/server/claude-worker/fixtures/workflow-run-record.json +1 -0
- package/server/claude-worker/sdk-message-normalizer.mjs +629 -0
- package/server/claude-worker/workflow-progress-digest.mjs +269 -0
- package/server/copilot-sdk-runtime.mjs +126 -0
- package/server/copilot-worker/copilot-attachments.mjs +97 -0
- package/server/copilot-worker/copilot-byok-provider.mjs +121 -0
- package/server/copilot-worker/copilot-continuation-signals.mjs +349 -0
- package/server/copilot-worker/copilot-plan-board.mjs +110 -0
- package/server/copilot-worker/copilot-prompt-context.mjs +86 -0
- package/server/copilot-worker/copilot-question-bridge.mjs +216 -0
- package/server/copilot-worker/copilot-sdk-adapter.mjs +494 -0
- package/server/copilot-worker/copilot-sdk-event-normalizer.mjs +800 -0
- package/server/copilot-worker/copilot-sdk-session-process.mjs +1729 -0
- package/server/copilot-worker/copilot-sdk-session-worker.mjs +167 -0
- package/server/copilot-worker/copilot-sdk-test-harness.mjs +329 -0
- package/server/copilot-worker/fixtures/abort-turn.json +588 -0
- package/server/copilot-worker/fixtures/ask-user-turn.json +1154 -0
- package/server/copilot-worker/fixtures/background-timer-continuation.json +445 -0
- package/server/copilot-worker/fixtures/background-timer-turn.json +497 -0
- package/server/copilot-worker/fixtures/happy-turn.json +566 -0
- package/server/copilot-worker/fixtures/quota-turn.json +647 -0
- package/server/copilot-worker/fixtures/reasoning-turn.json +625 -0
- package/server/copilot-worker/fixtures/resume-turn.json +700 -0
- package/server/copilot-worker/fixtures/subagent-turn.json +1378 -0
- package/server/copilot-worker/fixtures/tool-permission-turn.json +1293 -0
- package/server/cursor-worker/cursor-ask-user-tool.mjs +83 -0
- package/server/cursor-worker/cursor-attachments.mjs +88 -0
- package/server/cursor-worker/cursor-context-usage.mjs +85 -0
- package/server/cursor-worker/cursor-preview-tool.mjs +44 -0
- package/server/cursor-worker/cursor-sdk-adapter.mjs +554 -0
- package/server/cursor-worker/cursor-session-worker.mjs +145 -0
- package/server/cursor-worker/cursor-subagent-roster.mjs +81 -0
- package/server/cursor-worker/cursor-turn-runner.mjs +717 -0
- package/server/cursor-worker/sdk-message-normalizer.mjs +485 -0
- package/server/db-schema.mjs +932 -0
- package/server/features.mjs +106 -0
- package/server/grok-worker/acp-client.mjs +434 -0
- package/server/grok-worker/acp-host-services.mjs +277 -0
- package/server/grok-worker/grok-context-usage.mjs +77 -0
- package/server/grok-worker/grok-sdk-adapter.mjs +334 -0
- package/server/grok-worker/grok-session-worker.mjs +145 -0
- package/server/grok-worker/grok-turn-runner.mjs +523 -0
- package/server/grok-worker/sdk-message-normalizer.mjs +311 -0
- package/server/migrations/0001-add-structured-answer.mjs +80 -0
- package/server/migrations/0002-recent-workspace-roots-path-key.mjs +121 -0
- package/server/migrations/0003-push-subscriptions.mjs +87 -0
- package/server/public/app/action-confirmations.js +267 -0
- package/server/public/app/activity-replay-state.mjs +149 -0
- package/server/public/app/api-client.js +1082 -0
- package/server/public/app/ask-user-view.js +545 -0
- package/server/public/app/attachments-view.js +2112 -0
- package/server/public/app/auto-compact-window-options.mjs +59 -0
- package/server/public/app/background-tasks-view.mjs +494 -0
- package/server/public/app/bootstrap.js +4347 -0
- package/server/public/app/claude-auth-ui.js +394 -0
- package/server/public/app/claude-thinking-options.mjs +38 -0
- package/server/public/app/cli-install-ui.js +455 -0
- package/server/public/app/code-copy.mjs +85 -0
- package/server/public/app/composer-attachment-cache.mjs +151 -0
- package/server/public/app/composer-control-state.mjs +107 -0
- package/server/public/app/composer-paste.mjs +132 -0
- package/server/public/app/context-tier-options.mjs +68 -0
- package/server/public/app/context-usage-view.mjs +338 -0
- package/server/public/app/conversation-draft-timestamp-utils.mjs +11 -0
- package/server/public/app/conversation-preferences.mjs +91 -0
- package/server/public/app/conversation-provider-indicator.mjs +88 -0
- package/server/public/app/conversation-view.js +2898 -0
- package/server/public/app/cwd-menu-placement.mjs +85 -0
- package/server/public/app/cwd-picker.js +605 -0
- package/server/public/app/emoji-view.js +101 -0
- package/server/public/app/external-link-policy.mjs +80 -0
- package/server/public/app/file-preview-navigation.mjs +51 -0
- package/server/public/app/font-scaling.js +262 -0
- package/server/public/app/git-changes-view.js +339 -0
- package/server/public/app/git-diff-model.mjs +109 -0
- package/server/public/app/grok-auth-ui.js +387 -0
- package/server/public/app/image-downscale.mjs +174 -0
- package/server/public/app/in-flight-snapshot.mjs +40 -0
- package/server/public/app/infinite-loader.js +164 -0
- package/server/public/app/journal-view.js +1141 -0
- package/server/public/app/known-cwd-options.mjs +41 -0
- package/server/public/app/launch-cwd-path.mjs +23 -0
- package/server/public/app/live-message-dedupe.mjs +57 -0
- package/server/public/app/message-search-view.js +242 -0
- package/server/public/app/model-selector-options.mjs +31 -0
- package/server/public/app/model-vision-support.mjs +56 -0
- package/server/public/app/new-conversation-model-choice.mjs +67 -0
- package/server/public/app/plan-usage-view.mjs +307 -0
- package/server/public/app/preview-cards.mjs +273 -0
- package/server/public/app/preview-command.mjs +103 -0
- package/server/public/app/push-settings.js +370 -0
- package/server/public/app/pwa-install.js +456 -0
- package/server/public/app/question-schema-view.mjs +71 -0
- package/server/public/app/reasoning-effort-labels.mjs +42 -0
- package/server/public/app/relay-board-view.js +117 -0
- package/server/public/app/relay-dot-state.mjs +69 -0
- package/server/public/app/relay-error-ctas.mjs +52 -0
- package/server/public/app/relay-prompt-sanitizer.mjs +114 -0
- package/server/public/app/relay-thoughts.mjs +98 -0
- package/server/public/app/relay-watchdog-policy.mjs +29 -0
- package/server/public/app/repo-browser-preferences.mjs +79 -0
- package/server/public/app/repo-browser-tree-state.mjs +97 -0
- package/server/public/app/router.js +657 -0
- package/server/public/app/selection-guard.mjs +93 -0
- package/server/public/app/settings-modal.js +1484 -0
- package/server/public/app/settings-tabs.js +129 -0
- package/server/public/app/slash-autocomplete.mjs +188 -0
- package/server/public/app/slash-commands.mjs +183 -0
- package/server/public/app/socket-handlers.js +703 -0
- package/server/public/app/status-store.mjs +242 -0
- package/server/public/app/status-view.mjs +315 -0
- package/server/public/app/store.js +1454 -0
- package/server/public/app/stream-state.mjs +73 -0
- package/server/public/app/streaming-dom-patch.mjs +23 -0
- package/server/public/app/sync-outbox.mjs +208 -0
- package/server/public/app/tap-actions.js +62 -0
- package/server/public/app/thread-order.mjs +54 -0
- package/server/public/app/tmux-inspector-view.js +422 -0
- package/server/public/app/transcript-separators.mjs +282 -0
- package/server/public/app-icon-192.png +0 -0
- package/server/public/app-icon-512.png +0 -0
- package/server/public/app-icon.svg +4 -0
- package/server/public/favicon.ico +0 -0
- package/server/public/index.html +5743 -0
- package/server/public/manifest.webmanifest +32 -0
- package/server/public/sw.js +307 -0
- package/server/relay-exit-codes.mjs +4 -0
- package/server/relay-self-restart.mjs +170 -0
- package/server/relay-tools.md +27 -0
- package/server/relay.mjs +1026 -0
- package/server/repositories/image-conversation-repository.mjs +317 -0
- package/server/repositories/message-repository.mjs +434 -0
- package/server/repositories/question-repository.mjs +161 -0
- package/server/repositories/session-repository.mjs +320 -0
- package/server/repositories/share-visibility-statements.mjs +24 -0
- package/server/routes/ask-user-routes.mjs +292 -0
- package/server/routes/cache-routes.mjs +44 -0
- package/server/routes/git-routes.mjs +92 -0
- package/server/routes/messages-routes-test-harness.mjs +111 -0
- package/server/routes/messages-routes.mjs +7107 -0
- package/server/routes/preview-routes.mjs +108 -0
- package/server/routes/push-routes.mjs +59 -0
- package/server/routes/relay-board-routes.mjs +268 -0
- package/server/routes/sessions-routes.mjs +6150 -0
- package/server/server-runtime.mjs +7463 -0
- package/server/server.js +24 -0
- package/server/services/ask-user-routing-service.mjs +117 -0
- package/server/services/cache-rebuild-service.mjs +236 -0
- package/server/services/claude-auth-service.mjs +578 -0
- package/server/services/claude-context-usage.mjs +240 -0
- package/server/services/claude-session-root-service.mjs +228 -0
- package/server/services/cli-install-service.mjs +1152 -0
- package/server/services/cli-process-runner.mjs +181 -0
- package/server/services/cloudflared-tunnel-service.mjs +358 -0
- package/server/services/context-snapshot-service.mjs +499 -0
- package/server/services/context-usage-view.mjs +160 -0
- package/server/services/conversation-preferences-service.mjs +208 -0
- package/server/services/cursor-dashboard-usage.mjs +217 -0
- package/server/services/cursor-session-root-service.mjs +62 -0
- package/server/services/delete-archive-service.mjs +154 -0
- package/server/services/drives-path-helpers.mjs +66 -0
- package/server/services/fixtures/claude-auth-stub.sh +62 -0
- package/server/services/fixtures/cli-install-stub.sh +75 -0
- package/server/services/fixtures/grok-stub.sh +86 -0
- package/server/services/generated-image-cleanup-service.mjs +114 -0
- package/server/services/git-changes-service.mjs +195 -0
- package/server/services/github-billing-usage.mjs +133 -0
- package/server/services/grok-auth-service.mjs +593 -0
- package/server/services/grok-billing-usage.mjs +120 -0
- package/server/services/image-context-service.mjs +106 -0
- package/server/services/image-operation-service.mjs +135 -0
- package/server/services/keyed-mutex-service.mjs +82 -0
- package/server/services/mime-sniffer.mjs +118 -0
- package/server/services/oar-cli-helpers.mjs +109 -0
- package/server/services/oar-state-migration-service.mjs +243 -0
- package/server/services/plan-usage-claude.mjs +387 -0
- package/server/services/plan-usage-contract.mjs +271 -0
- package/server/services/plan-usage-copilot.mjs +421 -0
- package/server/services/plan-usage-cursor.mjs +566 -0
- package/server/services/plan-usage-grok.mjs +436 -0
- package/server/services/plan-usage-service.mjs +487 -0
- package/server/services/preview-health-probe.mjs +82 -0
- package/server/services/preview-proxy-server.mjs +498 -0
- package/server/services/preview-registry-service.mjs +457 -0
- package/server/services/preview-static-handler.mjs +237 -0
- package/server/services/provider-model-selection.mjs +91 -0
- package/server/services/provider-reasoning-effort.mjs +94 -0
- package/server/services/push-active-device-service.mjs +57 -0
- package/server/services/push-dispatch-service.mjs +459 -0
- package/server/services/rate-limit-service.mjs +63 -0
- package/server/services/relay-bridge-owner-service.mjs +84 -0
- package/server/services/relay-cli-launcher-service.mjs +209 -0
- package/server/services/relay-prompt-sanitizer.mjs +137 -0
- package/server/services/relay-queue-gate-service.mjs +38 -0
- package/server/services/relay-restart-orchestrator-service.mjs +935 -0
- package/server/services/relay-singleton-guard.mjs +124 -0
- package/server/services/safe-served-content.mjs +57 -0
- package/server/services/sdk-session-import-service.mjs +271 -0
- package/server/services/sdk-session-sync-service.mjs +207 -0
- package/server/services/session-history-refresh-service.mjs +497 -0
- package/server/services/session-transcript-service.mjs +419 -0
- package/server/services/session-worker-launch-service.mjs +786 -0
- package/server/services/session-worker-process-service.mjs +319 -0
- package/server/services/session-worker-registry-service.mjs +194 -0
- package/server/services/session-worker-stop-service.mjs +141 -0
- package/server/services/session-worker-supervisor-service.mjs +898 -0
- package/server/services/session-worker-websocket-service.mjs +483 -0
- package/server/services/ssh-tunnel-manager-service.mjs +423 -0
- package/server/services/status-event-service.mjs +158 -0
- package/server/services/tmux-inspector-access-policy.mjs +77 -0
- package/server/services/tmux-inspector-socket-service.mjs +191 -0
- package/server/services/tmux-inspector-stream-service.mjs +552 -0
- package/server/services/tunnel-worker-path-guard.mjs +107 -0
- package/server/services/upload-sweep.mjs +60 -0
- package/server/services/usage-snapshot-helpers.mjs +209 -0
- package/server/services/windows-autostart-service.mjs +115 -0
- package/server/services/workspace-root-defaults-service.mjs +34 -0
- package/server/services/workspace-root-path-policy.mjs +196 -0
- package/server/services/workspace-root-relaunch-service.mjs +132 -0
- package/server/services/workspace-symlink-guard.mjs +54 -0
- package/server/tools/capture-proxy.mjs +173 -0
- package/server/tty-console-bootstrap.mjs +75 -0
- package/server/uploads/README.md +36 -0
- package/server/uploads/image_input.md +540 -0
- package/server/windows-terminal-launcher.mjs +29 -0
- package/server/workspace-root.mjs +87 -0
- package/shared/ask-user-bridge.mjs +131 -0
- package/shared/auto-compact-window.mjs +116 -0
- package/shared/background-task-timeout.mjs +52 -0
- package/shared/claude-thinking.mjs +101 -0
- package/shared/context-window-fallbacks.mjs +148 -0
- package/shared/control-poller.mjs +115 -0
- package/shared/empty-turn-completion.mjs +20 -0
- package/shared/model-catalog-freshness.mjs +11 -0
- package/shared/model-descriptors.mjs +118 -0
- package/shared/model-id.mjs +147 -0
- package/shared/model-refresh.mjs +24 -0
- package/shared/openai-reasoning.mjs +13 -0
- package/shared/plan-lines.mjs +13 -0
- package/shared/preview-instructions.mjs +77 -0
- package/shared/preview-tool-core.mjs +191 -0
- package/shared/provider-routing.mjs +29 -0
- package/shared/question-schema.mjs +315 -0
- package/shared/question-timeout.mjs +18 -0
- package/shared/stream-emit-gating.mjs +28 -0
- package/shared/subagent-run-id.mjs +17 -0
- package/shared/thought-cap.mjs +13 -0
- package/shared/tool-activity.mjs +98 -0
- package/shared/turn-ceiling.mjs +53 -0
- package/shared/worker-bootstrap.mjs +44 -0
- package/shared/worker-crash-guard.mjs +60 -0
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// Managed providers (OpenAI, Claude, Cursor, Grok) own their own model
|
|
4
|
+
// catalogs: the Copilot catalog does not know these ids, so an explicit
|
|
5
|
+
// selection must be resolved against the provider list alone. Resolving it
|
|
6
|
+
// through the shared catalog first is what let a Cursor request fall back to
|
|
7
|
+
// the global current model (e.g. "claude-opus-5") whenever the requested id
|
|
8
|
+
// was missing from that catalog.
|
|
9
|
+
|
|
10
|
+
export const AUTO_MODEL_SENTINEL = 'auto';
|
|
11
|
+
|
|
12
|
+
export function normalizeProviderModelId(value) {
|
|
13
|
+
return String(value || '').trim();
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function isAutoModelId(value) {
|
|
17
|
+
return normalizeProviderModelId(value).toLowerCase() === AUTO_MODEL_SENTINEL;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// Availability lists are assembled from settings and discovery, which preserve
|
|
21
|
+
// the provider's casing. Matching is case-insensitive, but the canonical entry
|
|
22
|
+
// is what gets bound and persisted so every later comparison lines up.
|
|
23
|
+
// Callers hold their catalogs as arrays or as Sets built for the older
|
|
24
|
+
// case-sensitive checks, so both are accepted.
|
|
25
|
+
function toModelList(availableModels) {
|
|
26
|
+
if (Array.isArray(availableModels)) return availableModels;
|
|
27
|
+
if (availableModels && typeof availableModels[Symbol.iterator] === 'function') return Array.from(availableModels);
|
|
28
|
+
return [];
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function buildCanonicalModelIndex(availableModels = []) {
|
|
32
|
+
const index = new Map();
|
|
33
|
+
for (const value of toModelList(availableModels)) {
|
|
34
|
+
const canonical = normalizeProviderModelId(value);
|
|
35
|
+
if (!canonical) continue;
|
|
36
|
+
const key = canonical.toLowerCase();
|
|
37
|
+
if (!index.has(key)) index.set(key, canonical);
|
|
38
|
+
}
|
|
39
|
+
return index;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export function canonicalProviderModelId(requestedModel, availableModels = []) {
|
|
43
|
+
const requested = normalizeProviderModelId(requestedModel);
|
|
44
|
+
if (!requested) return '';
|
|
45
|
+
return buildCanonicalModelIndex(availableModels).get(requested.toLowerCase()) || '';
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export function isProviderModelAvailable(requestedModel, availableModels = []) {
|
|
49
|
+
return canonicalProviderModelId(requestedModel, availableModels) !== '';
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Resolution outcomes:
|
|
53
|
+
// matched — the request named an available model (canonical casing returned)
|
|
54
|
+
// default — no model was requested (blank or "auto"), so the provider default applies
|
|
55
|
+
// ok:false — the request named a model this provider does not offer; callers reject
|
|
56
|
+
export function resolveProviderModelSelection({
|
|
57
|
+
requestedModel = '',
|
|
58
|
+
availableModels = [],
|
|
59
|
+
configuredModel = '',
|
|
60
|
+
} = {}) {
|
|
61
|
+
const requested = normalizeProviderModelId(requestedModel);
|
|
62
|
+
const configured = normalizeProviderModelId(configuredModel);
|
|
63
|
+
const index = buildCanonicalModelIndex([configured, ...toModelList(availableModels)]);
|
|
64
|
+
|
|
65
|
+
if (!requested || isAutoModelId(requested)) {
|
|
66
|
+
return {
|
|
67
|
+
ok: true,
|
|
68
|
+
model: configured,
|
|
69
|
+
requestedModel: requested,
|
|
70
|
+
source: 'default',
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const canonical = index.get(requested.toLowerCase());
|
|
75
|
+
if (canonical) {
|
|
76
|
+
return {
|
|
77
|
+
ok: true,
|
|
78
|
+
model: canonical,
|
|
79
|
+
requestedModel: requested,
|
|
80
|
+
source: 'matched',
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
return {
|
|
85
|
+
ok: false,
|
|
86
|
+
model: '',
|
|
87
|
+
requestedModel: requested,
|
|
88
|
+
source: 'unavailable',
|
|
89
|
+
availableModels: Array.from(index.values()),
|
|
90
|
+
};
|
|
91
|
+
}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
import { openAIReasoningEffortsForModel } from '../../shared/openai-reasoning.mjs';
|
|
4
|
+
|
|
5
|
+
// 'ultracode' is not an Agent SDK EffortLevel: it is a relay-side sentinel for
|
|
6
|
+
// the SDK's session-scoped `ultracode` settings flag (xhigh effort plus
|
|
7
|
+
// standing workflow orchestration). It rides the effort ladder end to end —
|
|
8
|
+
// selector option, queue column, message field — and only the Claude worker
|
|
9
|
+
// translates it into `effort: 'xhigh'` + `settings: { ultracode: true }`.
|
|
10
|
+
// It must never be sent as an `effort`/`effortLevel` value: the CLI's schema
|
|
11
|
+
// silently discards unknown levels.
|
|
12
|
+
export const CLAUDE_ULTRACODE_EFFORT = 'ultracode';
|
|
13
|
+
export const DEFAULT_CLAUDE_REASONING_EFFORTS = Object.freeze(['none', 'low', 'medium', 'high', 'xhigh', 'max', CLAUDE_ULTRACODE_EFFORT]);
|
|
14
|
+
export const DEFAULT_GROK_REASONING_EFFORTS = Object.freeze(['none', 'low', 'medium', 'high']);
|
|
15
|
+
|
|
16
|
+
// Ultracode requires an xhigh-capable model (the SDK's stated gate), so the
|
|
17
|
+
// tier is derived from a model's discovered efforts rather than discovery —
|
|
18
|
+
// `supportedModels()` never reports it. Idempotent: augmenting an
|
|
19
|
+
// already-augmented ladder is a no-op.
|
|
20
|
+
export function withClaudeUltracodeTier(efforts) {
|
|
21
|
+
const levels = (Array.isArray(efforts) ? efforts : []).map(normalizeEffort).filter(Boolean);
|
|
22
|
+
if (!levels.includes('xhigh') || levels.includes(CLAUDE_ULTRACODE_EFFORT)) return levels;
|
|
23
|
+
return [...levels, CLAUDE_ULTRACODE_EFFORT];
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function normalizeEffort(value) {
|
|
27
|
+
return String(value || '').trim().toLowerCase();
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function effortsForModel(effortsByModel, model) {
|
|
31
|
+
const key = normalizeEffort(model);
|
|
32
|
+
if (!key || !effortsByModel || typeof effortsByModel !== 'object') return null;
|
|
33
|
+
const efforts = effortsByModel[key];
|
|
34
|
+
return Array.isArray(efforts) ? efforts.map(normalizeEffort).filter(Boolean) : null;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Returns the tiers a provider/model pair accepts, or null when the tiers are
|
|
38
|
+
// unknown. null is not "no reasoning": Cursor models that predate effort
|
|
39
|
+
// discovery must pass the request through so the worker can validate it against
|
|
40
|
+
// the live model params instead of the relay silently disabling thinking.
|
|
41
|
+
export function supportedReasoningEffortsForProviderModel({
|
|
42
|
+
providerType = '',
|
|
43
|
+
model = '',
|
|
44
|
+
cursorSettings = null,
|
|
45
|
+
claudeSettings = null,
|
|
46
|
+
grokSettings = null,
|
|
47
|
+
reasoningByModel = null,
|
|
48
|
+
} = {}) {
|
|
49
|
+
const provider = normalizeEffort(providerType);
|
|
50
|
+
if (provider === 'cursor') return effortsForModel(cursorSettings?.effortsByModel, model);
|
|
51
|
+
if (provider === 'claude') {
|
|
52
|
+
return effortsForModel(claudeSettings?.effortsByModel, model) || [...DEFAULT_CLAUDE_REASONING_EFFORTS];
|
|
53
|
+
}
|
|
54
|
+
if (provider === 'grok') {
|
|
55
|
+
return effortsForModel(grokSettings?.effortsByModel, model) || [...DEFAULT_GROK_REASONING_EFFORTS];
|
|
56
|
+
}
|
|
57
|
+
if (provider === 'openai' || provider === 'openai-image') {
|
|
58
|
+
const efforts = openAIReasoningEffortsForModel(model);
|
|
59
|
+
return Array.isArray(efforts) && efforts.length ? efforts.map(normalizeEffort).filter(Boolean) : null;
|
|
60
|
+
}
|
|
61
|
+
return effortsForModel(reasoningByModel, model);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Mirrors the per-turn rules on the message path so a New Chat selection and
|
|
65
|
+
// the first send agree: a supported tier is kept, an unsupported one clamps to
|
|
66
|
+
// the provider's off-switch, an unstated one takes the provider default, and an
|
|
67
|
+
// unknown tier list passes through.
|
|
68
|
+
//
|
|
69
|
+
// `strict` reproduces the one provider that refuses rather than clamps: OpenAI
|
|
70
|
+
// answers an unsupported effort with a 400, so bootstrap must not store a value
|
|
71
|
+
// the first send would reject.
|
|
72
|
+
export function resolveProviderReasoningEffort({
|
|
73
|
+
requestedEffort = '',
|
|
74
|
+
supportedEfforts = null,
|
|
75
|
+
strict = false,
|
|
76
|
+
} = {}) {
|
|
77
|
+
const requested = normalizeEffort(requestedEffort);
|
|
78
|
+
const supported = Array.isArray(supportedEfforts)
|
|
79
|
+
? supportedEfforts.map(normalizeEffort).filter(Boolean)
|
|
80
|
+
: null;
|
|
81
|
+
if (!supported) return { ok: true, effort: requested, supported: [] };
|
|
82
|
+
const providerDefault = supported.includes('none') ? 'none' : (supported[0] || '');
|
|
83
|
+
if (!requested) return { ok: true, effort: providerDefault, supported };
|
|
84
|
+
if (supported.includes(requested)) return { ok: true, effort: requested, supported };
|
|
85
|
+
if (strict) {
|
|
86
|
+
return {
|
|
87
|
+
ok: false,
|
|
88
|
+
effort: '',
|
|
89
|
+
supported,
|
|
90
|
+
error: `Reasoning effort "${requested}" is not supported`,
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
return { ok: true, effort: providerDefault, supported };
|
|
94
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Active-device tracking for push suppression.
|
|
5
|
+
*
|
|
6
|
+
* "Active" means: a connected socket whose client explicitly reported itself
|
|
7
|
+
* visible via a `device_visibility` heartbeat within the staleness window. A
|
|
8
|
+
* connected socket alone is not enough — the client keeps its transport open
|
|
9
|
+
* for a grace period after backgrounding, so a pocketed phone can hold a live
|
|
10
|
+
* socket for tens of seconds.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
export const DEVICE_VISIBILITY_STALE_MS = 90_000;
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* @param {object} options
|
|
17
|
+
* @param {() => Iterable<import('socket.io').Socket>} options.getSockets connected sockets of the main namespace
|
|
18
|
+
* @param {number} [options.staleMs]
|
|
19
|
+
* @param {() => number} [options.now]
|
|
20
|
+
*/
|
|
21
|
+
export function createActiveDeviceTracker({ getSockets, staleMs = DEVICE_VISIBILITY_STALE_MS, now = () => Date.now() }) {
|
|
22
|
+
/**
|
|
23
|
+
* Bind visibility tracking to a freshly connected socket. Call from the
|
|
24
|
+
* io `connection` handler.
|
|
25
|
+
*/
|
|
26
|
+
function registerSocket(socket) {
|
|
27
|
+
if (!socket) return;
|
|
28
|
+
if (socket.recovered === true && socket.data) {
|
|
29
|
+
// connectionStateRecovery restores socket.data from the recovered
|
|
30
|
+
// session, so a phone that slept with deviceVisible=true would come back
|
|
31
|
+
// still claiming to be visible and suppress push for every device.
|
|
32
|
+
// Reset and wait for the client's connect-time heartbeat (one round
|
|
33
|
+
// trip). The staleness window below is the independent second guard.
|
|
34
|
+
socket.data.deviceVisible = false;
|
|
35
|
+
}
|
|
36
|
+
socket.on('device_visibility', (payload = {}) => {
|
|
37
|
+
const deviceId = String(payload?.deviceId || '').trim();
|
|
38
|
+
if (deviceId) socket.data.deviceId = deviceId;
|
|
39
|
+
socket.data.deviceVisible = payload?.visible === true;
|
|
40
|
+
socket.data.deviceVisibleAt = now();
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function hasActiveDevice() {
|
|
45
|
+
for (const socket of getSockets()) {
|
|
46
|
+
if (!socket || socket.connected === false) continue;
|
|
47
|
+
if (socket.data?.deviceVisible !== true) continue;
|
|
48
|
+
const visibleAt = Number(socket.data?.deviceVisibleAt || 0);
|
|
49
|
+
if (!Number.isFinite(visibleAt) || visibleAt <= 0) continue;
|
|
50
|
+
if ((now() - visibleAt) > staleMs) continue;
|
|
51
|
+
return true;
|
|
52
|
+
}
|
|
53
|
+
return false;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return { registerSocket, hasActiveDevice };
|
|
57
|
+
}
|