mixdog 1.3.3 → 1.3.5
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/LICENSES/oh-my-pi-MIT.txt +23 -0
- package/NOTICE.md +15 -0
- package/README.md +11 -0
- package/package.json +3 -2
- package/scripts/embed-google-oauth-client.mjs +49 -0
- package/scripts/lib/test-spawn-ledger.mjs +46 -1
- package/scripts/test.mjs +5 -0
- package/src/defaults/shipped-history.json +8 -0
- package/src/defaults/skills/browser-use/SKILL.md +21 -9
- package/src/defaults/skills/setup/SKILL.md +7 -2
- package/src/defaults/skills/setup/references/actions.md +82 -27
- package/src/defaults/skills/setup/references/surfaces.md +67 -34
- package/src/defaults/skills/setup-guide/SKILL.md +3 -3
- package/src/lib/keychain-cjs.cjs +359 -29
- package/src/rules/agent-mode/AGENT_MODE.md +10 -2
- package/src/rules/agent-mode/MIXY.md +12 -0
- package/src/runtime/agent/orchestrator/agent-runtime/heartbeat-completion.mjs +193 -0
- package/src/runtime/agent/orchestrator/config.mjs +18 -0
- package/src/runtime/agent/orchestrator/mcp/client-transport.mjs +2 -2
- package/src/runtime/agent/orchestrator/mcp/client.mjs +6 -2
- package/src/runtime/agent/orchestrator/mcp/oauth-callback.mjs +31 -2
- package/src/runtime/agent/orchestrator/mcp/oauth-client.mjs +16 -3
- package/src/runtime/agent/orchestrator/mcp/oauth-login.mjs +42 -7
- package/src/runtime/agent/orchestrator/mcp/oauth-provider.mjs +21 -2
- package/src/runtime/agent/orchestrator/mcp/oauth-shared.mjs +23 -0
- package/src/runtime/agent/orchestrator/mcp/oauth.mjs +11 -1
- package/src/runtime/agent/orchestrator/providers/account-pool.mjs +68 -23
- package/src/runtime/agent/orchestrator/providers/admission-scheduler.mjs +22 -1
- package/src/runtime/agent/orchestrator/providers/anthropic-api-request.mjs +18 -5
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth-client-version.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +15 -3
- package/src/runtime/agent/orchestrator/providers/antigravity-oauth-catalog.mjs +52 -8
- package/src/runtime/agent/orchestrator/providers/antigravity-oauth.mjs +10 -1
- package/src/runtime/agent/orchestrator/providers/antigravity-request.mjs +22 -6
- package/src/runtime/agent/orchestrator/providers/antigravity-response.mjs +15 -4
- package/src/runtime/agent/orchestrator/providers/antigravity-stream.mjs +17 -2
- package/src/runtime/agent/orchestrator/providers/antigravity-transport.mjs +19 -2
- package/src/runtime/agent/orchestrator/providers/codex-client-meta.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/cursor-wire-normalization.mjs +10 -4
- package/src/runtime/agent/orchestrator/providers/cursor-wire-protobuf.mjs +10 -217
- package/src/runtime/agent/orchestrator/providers/cursor.mjs +7 -0
- package/src/runtime/agent/orchestrator/providers/devin-auth.mjs +409 -0
- package/src/runtime/agent/orchestrator/providers/devin-wire-families.mjs +187 -0
- package/src/runtime/agent/orchestrator/providers/devin-wire-identity.mjs +342 -0
- package/src/runtime/agent/orchestrator/providers/devin-wire-models.mjs +541 -0
- package/src/runtime/agent/orchestrator/providers/devin-wire-protobuf.mjs +305 -0
- package/src/runtime/agent/orchestrator/providers/devin-wire-request.mjs +558 -0
- package/src/runtime/agent/orchestrator/providers/devin-wire-schema.mjs +880 -0
- package/src/runtime/agent/orchestrator/providers/devin-wire-session.mjs +190 -0
- package/src/runtime/agent/orchestrator/providers/devin-wire-tool-args.mjs +351 -0
- package/src/runtime/agent/orchestrator/providers/devin-wire-transport.mjs +560 -0
- package/src/runtime/agent/orchestrator/providers/devin.mjs +491 -0
- package/src/runtime/agent/orchestrator/providers/effort-configuration.mjs +3 -0
- package/src/runtime/agent/orchestrator/providers/gemini-output-limit.mjs +46 -0
- package/src/runtime/agent/orchestrator/providers/gemini-reasoning-relay.mjs +30 -0
- package/src/runtime/agent/orchestrator/providers/gemini-request-body.mjs +7 -11
- package/src/runtime/agent/orchestrator/providers/gemini-retry-policy.mjs +61 -22
- package/src/runtime/agent/orchestrator/providers/gemini-sdk-request.mjs +1 -0
- package/src/runtime/agent/orchestrator/providers/gemini-stream.mjs +71 -4
- package/src/runtime/agent/orchestrator/providers/gemini.mjs +25 -2
- package/src/runtime/agent/orchestrator/providers/grok-client-version.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/lib/anthropic-request-utils.mjs +96 -5
- package/src/runtime/agent/orchestrator/providers/lib/tail-reminder-split.mjs +23 -5
- package/src/runtime/agent/orchestrator/providers/oauth-credential-probes.mjs +17 -0
- package/src/runtime/agent/orchestrator/providers/oauth-usage.mjs +39 -3
- package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/stream-state.mjs +3 -1
- package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream.mjs +2 -0
- package/src/runtime/agent/orchestrator/providers/openai-error-contract.mjs +6 -1
- package/src/runtime/agent/orchestrator/providers/opencode-go-gemini.mjs +1 -0
- package/src/runtime/agent/orchestrator/providers/provider-availability.mjs +19 -0
- package/src/runtime/agent/orchestrator/providers/registry.mjs +17 -3
- package/src/runtime/agent/orchestrator/providers/wire-protobuf-codec.mjs +368 -0
- package/src/runtime/agent/orchestrator/runtime-core/builtin-features.mjs +2 -0
- package/src/runtime/agent/orchestrator/runtime-core/orchestration.mjs +1 -1
- package/src/runtime/agent/orchestrator/runtime-core/reaction-tool-defs.mjs +133 -0
- package/src/runtime/agent/orchestrator/runtime-core/tool-catalog-data.mjs +3 -0
- package/src/runtime/agent/orchestrator/runtime-core/tool-defs.mjs +23 -5
- package/src/runtime/agent/orchestrator/runtime-core/tool-profile.mjs +35 -10
- package/src/runtime/agent/orchestrator/runtime-core/workflow/agents.mjs +57 -10
- package/src/runtime/agent/orchestrator/runtime-core/workflow/context.mjs +9 -6
- package/src/runtime/agent/orchestrator/runtime-core/workflow-ids.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/agent-loop.mjs +18 -0
- package/src/runtime/agent/orchestrator/session/agent-room.d.mts +0 -3
- package/src/runtime/agent/orchestrator/session/agent-room.mjs +10 -4
- package/src/runtime/agent/orchestrator/session/compact/runner.mjs +15 -3
- package/src/runtime/agent/orchestrator/session/eager-dispatch.mjs +5 -0
- package/src/runtime/agent/orchestrator/session/human-gate/gate.mjs +36 -4
- package/src/runtime/agent/orchestrator/session/human-gate/outbound-policy.mjs +6 -0
- package/src/runtime/agent/orchestrator/session/human-gate/store.mjs +15 -3
- package/src/runtime/agent/orchestrator/session/loop/assistant-commit.mjs +8 -0
- package/src/runtime/agent/orchestrator/session/loop/loop-state.mjs +8 -1
- package/src/runtime/agent/orchestrator/session/loop/no-tool-turn/segments.mjs +4 -1
- package/src/runtime/agent/orchestrator/session/loop/no-tool-turn.mjs +50 -2
- package/src/runtime/agent/orchestrator/session/loop/send-phase.mjs +3 -0
- package/src/runtime/agent/orchestrator/session/loop/tool-exec/before-hook.mjs +11 -2
- package/src/runtime/agent/orchestrator/session/loop/tool-phase.mjs +11 -2
- package/src/runtime/agent/orchestrator/session/loop/turn-limits.mjs +60 -0
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-commit.mjs +2 -0
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-loop-options.mjs +14 -0
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-settle.mjs +2 -1
- package/src/runtime/agent/orchestrator/session/manager/session-tool-surface.mjs +13 -0
- package/src/runtime/agent/orchestrator/session/message-ids.mjs +5 -3
- package/src/runtime/agent/orchestrator/session/message-reactions.mjs +89 -0
- package/src/runtime/agent/orchestrator/session/message-reactions.test-support.mjs +75 -0
- package/src/runtime/agent/orchestrator/session/routine-result.d.mts +0 -2
- package/src/runtime/agent/orchestrator/session/routine-result.mjs +11 -2
- package/src/runtime/agent/orchestrator/session/send-with-recovery.mjs +20 -2
- package/src/runtime/agent/orchestrator/session/store-agent-worker-header-cache.mjs +85 -0
- package/src/runtime/agent/orchestrator/session/store-agent-worker-rows.mjs +125 -12
- package/src/runtime/agent/orchestrator/session/tail-reminder-rules.mjs +11 -5
- package/src/runtime/agent/orchestrator/session/tool-batch/state.mjs +4 -0
- package/src/runtime/agent/orchestrator/session/tool-batch.mjs +5 -0
- package/src/runtime/agent/orchestrator/session/transcript-restore/restore.mjs +7 -1
- package/src/runtime/channels/lib/schedule-errors.mjs +51 -0
- package/src/runtime/channels/lib/scheduler.mjs +109 -14
- package/src/runtime/channels/lib/schedules-db.mjs +49 -0
- package/src/runtime/channels/lib/tool-dispatch.mjs +13 -0
- package/src/runtime/channels/lib/worker-main.mjs +9 -0
- package/src/runtime/office/com/com-adapter.mjs +17 -1
- package/src/runtime/office/com/office-com-host.ps1 +51 -1
- package/src/runtime/office/pdf/cfb-fixture.mjs +328 -0
- package/src/runtime/office/pdf/cfb-protection.mjs +311 -0
- package/src/runtime/office/pdf/document-preview.mjs +326 -8
- package/src/runtime/office/pdf/ooxml-crypto.mjs +469 -0
- package/src/runtime/office/pdf/ooxml-key-worker.mjs +14 -0
- package/src/runtime/office/portable/portable-soffice.mjs +45 -5
- package/src/runtime/shared/agent-room-host.mjs +1 -1
- package/src/runtime/shared/bot-hops.mjs +62 -2
- package/src/runtime/shared/config.mjs +49 -22
- package/src/runtime/shared/connector-catalog.d.mts +4 -2
- package/src/runtime/shared/connector-catalog.mjs +16 -8
- package/src/runtime/shared/developer-options.mjs +32 -1
- package/src/runtime/shared/google-oauth-client.generated.json +4 -0
- package/src/runtime/shared/google-oauth-client.mjs +34 -9
- package/src/runtime/shared/llm/anthropic-betas.mjs +7 -0
- package/src/runtime/shared/llm/anthropic-thinking-contract.mjs +12 -0
- package/src/runtime/shared/llm/provider-catalog-registry.mjs +1 -0
- package/src/runtime/shared/llm/usage-rollup.mjs +4 -383
- package/src/runtime/shared/llm/well-formed.mjs +66 -0
- package/src/runtime/shared/provider-accounts.mjs +224 -58
- package/src/runtime/shared/provider-api-key.mjs +19 -8
- package/src/runtime/shared/routine-trigger.mjs +42 -0
- package/src/runtime/shared/tool-execution-contract.mjs +2 -0
- package/src/runtime/shared/transcript-metadata.mjs +38 -0
- package/src/runtime/shared/user-data-guard.mjs +30 -2
- package/src/runtime/shared/worktrees/activity-gate.mjs +12 -5
- package/src/session-runtime/agent-home-delivery.mjs +57 -13
- package/src/session-runtime/agent-room-delivery.mjs +28 -1
- package/src/session-runtime/agent-task-sessions.mjs +292 -79
- package/src/session-runtime/agent-tool-routing.mjs +49 -4
- package/src/session-runtime/boot/begin.mjs +3 -2
- package/src/session-runtime/boot/tools.mjs +4 -0
- package/src/session-runtime/bot-chain.mjs +32 -0
- package/src/session-runtime/bot-status.mjs +7 -4
- package/src/session-runtime/channel-config-api.mjs +63 -17
- package/src/session-runtime/internal-tool-executor/reaction-tool.mjs +45 -0
- package/src/session-runtime/internal-tool-executor/workspace-tools.mjs +72 -5
- package/src/session-runtime/internal-tool-executor.mjs +4 -0
- package/src/session-runtime/mcp-glue/server-catalog.mjs +7 -1
- package/src/session-runtime/mixy-heartbeat.mjs +807 -0
- package/src/session-runtime/model-route/route-tuning.mjs +10 -6
- package/src/session-runtime/owned-automation-run.mjs +33 -12
- package/src/session-runtime/provider-auth/login.mjs +7 -0
- package/src/session-runtime/provider-models/row-hydration.mjs +13 -2
- package/src/session-runtime/routine-home-turn.mjs +33 -6
- package/src/session-runtime/schedule-session-run.mjs +7 -3
- package/src/session-runtime/services/agent-tool/close-flow.mjs +14 -2
- package/src/session-runtime/services/agent-tool/execute.mjs +6 -1
- package/src/session-runtime/services/agent-tool/job-views/agent-list.mjs +11 -2
- package/src/session-runtime/services/agent-tool/render.mjs +3 -1
- package/src/session-runtime/services/agent-tool/spawn-flow/spawn-plan.mjs +8 -12
- package/src/session-runtime/services/agent-tool/tool-def.mjs +1 -1
- package/src/session-runtime/services/channel-admin.mjs +66 -18
- package/src/session-runtime/services/channel-worker.mjs +1 -1
- package/src/session-runtime/services/provider-admin.mjs +128 -25
- package/src/session-runtime/services/schedule-access.mjs +14 -0
- package/src/session-runtime/services/usage-dashboard-model.mjs +1 -0
- package/src/session-runtime/session-create/session-options.mjs +7 -4
- package/src/session-runtime/settings-system-api.mjs +16 -1
- package/src/session-runtime/setup-tool/executor.mjs +49 -14
- package/src/session-runtime/setup-tool/extended-actions.mjs +29 -3
- package/src/session-runtime/setup-tool/settings-contract.mjs +65 -4
- package/src/session-runtime/setup-tool/tool-defs.mjs +30 -3
- package/src/session-runtime/task-session-route.mjs +99 -0
- package/src/session-runtime/tool-policy/policy-stage.mjs +5 -2
- package/src/session-runtime/tool-policy/surface-helpers.mjs +2 -3
- package/src/session-runtime/tool-surface.mjs +4 -0
- package/src/session-runtime/usage-stats-api.mjs +1 -1
- package/src/session-runtime/workflow-agents-api/agent-editor.mjs +98 -21
- package/src/session-runtime/workflow-agents-api/workflow-packs.mjs +6 -1
- package/src/session-runtime/workspace/transitions.mjs +10 -2
- package/src/standalone/daemon-session-control.mjs +88 -20
- package/src/standalone/daemon.mjs +8 -0
- package/src/standalone/session-protocol.mjs +5 -0
- package/src/standalone/session-service/agent-tree/agent-cancel.mjs +6 -2
- package/src/standalone/session-service/session-calls/session-turns.mjs +6 -0
- package/src/standalone/session-service.mjs +13 -0
- package/src/standalone/session-tool-output.mjs +8 -5
- package/src/tui/app/model-options.mjs +2 -0
- package/src/tui/dist/index.mjs +335 -172
- package/src/tui/session/notice-surface.mjs +17 -1
- package/src/tui/session/session-api/integrations.mjs +1 -0
- package/src/tui/session/session-api/lifecycle.mjs +8 -0
- package/src/tui/session/session-api/settings.mjs +14 -2
- package/src/tui/session/turn-stream.mjs +17 -1
- package/src/tui/session/turn.mjs +22 -2
- package/src/vendor/statusline/src/gateway/claude-current.mjs +0 -58
- package/src/vendor/statusline/src/gateway/route-meta.mjs +1 -361
- package/src/vendor/statusline/src/gateway/session-routes.mjs +0 -55
- package/src/vendor/statusline/scripts/lib/gateway-settings.mjs +0 -285
|
@@ -609,14 +609,47 @@ function balanceFromAnthropicSpend(spend) {
|
|
|
609
609
|
return null;
|
|
610
610
|
}
|
|
611
611
|
|
|
612
|
+
// The server's limit id, in the one spelling headers and the usage payload share.
|
|
613
|
+
const codexLimitId = (value) => (cleanString(value) || '').toLowerCase().replace(/-/g, '_');
|
|
614
|
+
|
|
615
|
+
// Model-specific limits beside the plan's own: one per server limit id
|
|
616
|
+
// (`metered_feature`), whose `limit_name` names the model it meters. Each
|
|
617
|
+
// window gates that model alone.
|
|
618
|
+
function codexAdditionalLimits(list) {
|
|
619
|
+
return (Array.isArray(list) ? list : []).flatMap((entry) => {
|
|
620
|
+
const limit = codexLimitId(entry?.metered_feature || entry?.limit_name);
|
|
621
|
+
if (!limit) return [];
|
|
622
|
+
const name = cleanString(entry.limit_name) || limit;
|
|
623
|
+
const rate = entry.rate_limit && typeof entry.rate_limit === 'object' ? entry.rate_limit : {};
|
|
624
|
+
const windows = [
|
|
625
|
+
windowFromPercent('5H', rate.primary_window || rate.primary, 'openai-codex-oauth'),
|
|
626
|
+
windowFromPercent('7D', rate.secondary_window || rate.secondary, 'openai-codex-oauth'),
|
|
627
|
+
]
|
|
628
|
+
.filter(Boolean)
|
|
629
|
+
.map((window) => ({ ...window, label: `${window.label} ${name}`, limit, models: [name.toLowerCase()] }));
|
|
630
|
+
// A limit without a usable window meters nothing we can read: its model
|
|
631
|
+
// stays under the plan's windows.
|
|
632
|
+
return windows.length ? [{ model: name.toLowerCase(), windows }] : [];
|
|
633
|
+
});
|
|
634
|
+
}
|
|
635
|
+
|
|
612
636
|
export function normalizeOpenAIWhamUsage(data) {
|
|
613
637
|
const rate = data?.rate_limit && typeof data.rate_limit === 'object' ? data.rate_limit : null;
|
|
614
638
|
if (!rate) return null;
|
|
639
|
+
const additional = codexAdditionalLimits(data.additional_rate_limits);
|
|
640
|
+
// The plan's windows gate every model that no model-specific limit meters.
|
|
641
|
+
const plan = {
|
|
642
|
+
limit: 'codex',
|
|
643
|
+
...(additional.length ? { except: additional.map((entry) => entry.model) } : {}),
|
|
644
|
+
};
|
|
615
645
|
const windows = [
|
|
616
646
|
windowFromPercent('5H', rate.primary_window || rate.primary, 'openai-codex-oauth'),
|
|
617
647
|
windowFromPercent('7D', rate.secondary_window || rate.secondary, 'openai-codex-oauth'),
|
|
618
|
-
]
|
|
648
|
+
]
|
|
649
|
+
.filter(Boolean)
|
|
650
|
+
.map((window) => ({ ...window, ...plan }));
|
|
619
651
|
if (!windows.length) return null;
|
|
652
|
+
windows.push(...additional.flatMap((entry) => entry.windows));
|
|
620
653
|
return {
|
|
621
654
|
provider: 'openai-oauth',
|
|
622
655
|
source: 'openai-codex-wham',
|
|
@@ -687,12 +720,14 @@ function anthropicLimitWindows(limits, source) {
|
|
|
687
720
|
.filter(Boolean);
|
|
688
721
|
}
|
|
689
722
|
|
|
690
|
-
// The extra-usage (pay-as-you-go) window when it is enabled, else null.
|
|
723
|
+
// The extra-usage (pay-as-you-go) window when it is enabled, else null. It is
|
|
724
|
+
// shown, never a limit: paid overage spent to its cap leaves the plan's own
|
|
725
|
+
// windows serving, so it gates no model (`models: []`).
|
|
691
726
|
function anthropicExtraUsageWindow(extraUsage) {
|
|
692
727
|
if (extraUsage?.is_enabled !== true) return null;
|
|
693
728
|
const limitUsd = num(extraUsage.monthly_limit, 0) / 100;
|
|
694
729
|
const usedUsd = num(extraUsage.used_credits, 0) / 100;
|
|
695
|
-
|
|
730
|
+
const window = windowFromPercent(
|
|
696
731
|
'EXTRA',
|
|
697
732
|
{
|
|
698
733
|
utilization: extraUsage.utilization,
|
|
@@ -702,6 +737,7 @@ function anthropicExtraUsageWindow(extraUsage) {
|
|
|
702
737
|
},
|
|
703
738
|
'anthropic-oauth-extra'
|
|
704
739
|
);
|
|
740
|
+
return window ? { ...window, models: [] } : null;
|
|
705
741
|
}
|
|
706
742
|
|
|
707
743
|
export function normalizeAnthropicUsage(data, source = 'anthropic-oauth') {
|
|
@@ -23,6 +23,8 @@ export function createCompatStreamState({
|
|
|
23
23
|
onToolCall,
|
|
24
24
|
onTextDelta,
|
|
25
25
|
onStreamItemStart,
|
|
26
|
+
// false: text stays text; only native tool_calls deltas become calls.
|
|
27
|
+
leakedToolCallRecovery = true,
|
|
26
28
|
}) {
|
|
27
29
|
const toolDedupe = createToolCallDedupe();
|
|
28
30
|
return {
|
|
@@ -49,7 +51,7 @@ export function createCompatStreamState({
|
|
|
49
51
|
rawUsage: null,
|
|
50
52
|
toolAcc: createToolCallAccumulator(),
|
|
51
53
|
streamEmitState: { emittedToolCallKeys: new Set(), emittedToolCall: false, _toolDedupe: toolDedupe },
|
|
52
|
-
leakGuard: createLeakGuard({ knownToolNames, harmony: true }),
|
|
54
|
+
leakGuard: createLeakGuard({ knownToolNames: leakedToolCallRecovery ? knownToolNames : [], harmony: true }),
|
|
53
55
|
leakedCalls: [],
|
|
54
56
|
pendingLeakedCalls: [],
|
|
55
57
|
};
|
|
@@ -44,6 +44,7 @@ export async function consumeCompatChatCompletionStream(
|
|
|
44
44
|
knownToolNames,
|
|
45
45
|
semanticIdleTimeoutMs,
|
|
46
46
|
firstByteTimeoutMs,
|
|
47
|
+
leakedToolCallRecovery = true,
|
|
47
48
|
} = {}
|
|
48
49
|
) {
|
|
49
50
|
const idleOverrideEnabled = Number.isFinite(Number(semanticIdleTimeoutMs)) && Number(semanticIdleTimeoutMs) > 0;
|
|
@@ -57,6 +58,7 @@ export async function consumeCompatChatCompletionStream(
|
|
|
57
58
|
onToolCall,
|
|
58
59
|
onTextDelta,
|
|
59
60
|
onStreamItemStart,
|
|
61
|
+
leakedToolCallRecovery,
|
|
60
62
|
});
|
|
61
63
|
reportTransport(state);
|
|
62
64
|
const iterator = stream[Symbol.asyncIterator]();
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
* headers response headers (HTTP, WS handshake, nested error.headers)
|
|
8
8
|
* retryAfterMs server advice, uncapped (Retry-After / Retry-After-Ms)
|
|
9
9
|
* resetAt epoch ms from quota reset fields (resets_at, resets_in_seconds)
|
|
10
|
+
* quotaLimit limit id from x-codex-active-limit, `-` normalized to `_`
|
|
10
11
|
*
|
|
11
12
|
* Pure: no I/O. Message text is never parsed for status or code.
|
|
12
13
|
*/
|
|
@@ -18,7 +19,7 @@ const isObject = (value) => value !== null && typeof value === 'object' && !Arra
|
|
|
18
19
|
* Parse an HTTP error body ONCE into its contract fields. `message` is the
|
|
19
20
|
* body's own message (untruncated); callers truncate for diagnostics.
|
|
20
21
|
*/
|
|
21
|
-
|
|
22
|
+
function parseErrorBody(text) {
|
|
22
23
|
let json = null;
|
|
23
24
|
try {
|
|
24
25
|
json = JSON.parse(String(text || ''));
|
|
@@ -206,6 +207,10 @@ export function applyErrorContract(err, { status, headers, code, error, event }
|
|
|
206
207
|
const wireHeaders =
|
|
207
208
|
headers ?? error?.headers ?? event?.error?.headers ?? event?.response?.error?.headers ?? event?.headers;
|
|
208
209
|
if (wireHeaders && typeof wireHeaders === 'object') err.headers = wireHeaders;
|
|
210
|
+
// The limit a refusal hit, by the server's limit id (`codex` is the plan's
|
|
211
|
+
// own; others are model-specific), so the account pool blocks only it.
|
|
212
|
+
const activeLimit = headerValue(err.headers, 'x-codex-active-limit').toLowerCase().replace(/-/g, '_');
|
|
213
|
+
if (activeLimit) err.quotaLimit = activeLimit;
|
|
209
214
|
const rawCode = code ?? error?.code ?? error?.type ?? null;
|
|
210
215
|
if (typeof rawCode === 'string' && rawCode.trim()) err.code = rawCode.trim().toLowerCase();
|
|
211
216
|
const resetAt = resetAtFrom(error, event?.error, event?.response?.error, event);
|
|
@@ -144,6 +144,7 @@ export class OpenCodeGoGeminiEngine extends GeminiProvider {
|
|
|
144
144
|
);
|
|
145
145
|
},
|
|
146
146
|
afterToolResult: geminiEndsWithFunctionResponse(contents),
|
|
147
|
+
failureUsage: geminiFailureUsage(opts, null, useModel),
|
|
147
148
|
run: async ({ signal: attemptSignal, connected }) => {
|
|
148
149
|
try {
|
|
149
150
|
opts.onStageChange?.('requesting');
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { modelProxyClientMode } from '../../../shared/model-proxy-mode.mjs';
|
|
2
|
+
import { isOAuthProviderAvailable } from './oauth-credential-probes.mjs';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Whether the named provider may be looked up or sent through right now. Remote
|
|
6
|
+
* client mode serves the PC's providers, whose availability the PC already
|
|
7
|
+
* decided; only a locally run provider answers to the local Developer option.
|
|
8
|
+
*/
|
|
9
|
+
export function providerAvailable(name) {
|
|
10
|
+
return modelProxyClientMode() || isOAuthProviderAvailable(name);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/** The error a send raises when its provider was switched off after lookup. */
|
|
14
|
+
export function providerUnavailableError(name) {
|
|
15
|
+
return Object.assign(
|
|
16
|
+
new Error(`Provider "${name}" is disabled: its Developer option was switched off before the request was sent.`),
|
|
17
|
+
{ code: 'EPROVIDERUNAVAILABLE', provider: name }
|
|
18
|
+
);
|
|
19
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { OPENAI_COMPAT_PRESETS } from './openai-compat-presets.mjs';
|
|
2
2
|
import { oauthCredentialProbeState } from './oauth-credential-probes.mjs';
|
|
3
|
+
import { providerAvailable } from './provider-availability.mjs';
|
|
3
4
|
import { refreshCatalog as refreshMetadataCatalog } from './model-catalog.mjs';
|
|
4
5
|
import { wrapProviderAdmission } from './admission-scheduler.mjs';
|
|
5
6
|
import { createAccountPoolProvider } from './account-pool.mjs';
|
|
@@ -33,6 +34,7 @@ export const OAUTH_PROVIDER_NAMES = new Set([
|
|
|
33
34
|
'command-code-oauth',
|
|
34
35
|
'mimo-oauth',
|
|
35
36
|
'cursor-oauth',
|
|
37
|
+
'devin-oauth',
|
|
36
38
|
'antigravity-oauth',
|
|
37
39
|
'opencode-go-oauth',
|
|
38
40
|
]);
|
|
@@ -176,6 +178,7 @@ const PROVIDER_MODULES = {
|
|
|
176
178
|
'command-code-oauth': ['./command-code-oauth.mjs', 'CommandCodeOAuthProvider'],
|
|
177
179
|
'mimo-oauth': ['./mimo-oauth.mjs', 'MimoOAuthProvider'],
|
|
178
180
|
'cursor-oauth': ['./cursor.mjs', 'CursorOAuthProvider'],
|
|
181
|
+
'devin-oauth': ['./devin.mjs', 'DevinOAuthProvider'],
|
|
179
182
|
'antigravity-oauth': ['./antigravity-oauth.mjs', 'AntigravityOAuthProvider'],
|
|
180
183
|
'cursor-api': ['./cursor.mjs', 'CursorApiProvider'],
|
|
181
184
|
openai: ['./openai-ws.mjs', 'OpenAIDirectProvider'],
|
|
@@ -290,6 +293,9 @@ async function _initProvidersUnsynchronized(config, signal = null, proxyChannel
|
|
|
290
293
|
const enabledResults = await Promise.all(
|
|
291
294
|
entries.map(async ([name, cfg]) => {
|
|
292
295
|
if (!cfg.enabled) return null;
|
|
296
|
+
// A dev-gated provider whose Developer option is off is never admitted,
|
|
297
|
+
// even from a config that still says enabled:true.
|
|
298
|
+
if (!providerAvailable(name)) return null;
|
|
293
299
|
// A retired provider's saved config is inert: its replacement is its own entry.
|
|
294
300
|
if (Object.hasOwn(RETIRED_PROVIDER_ALIASES, name)) return null;
|
|
295
301
|
// Idempotent reuse: an enabled provider whose config signature is
|
|
@@ -450,6 +456,9 @@ export function getProvider(requestedName) {
|
|
|
450
456
|
const name = Object.hasOwn(RETIRED_PROVIDER_ALIASES, requestedName)
|
|
451
457
|
? RETIRED_PROVIDER_ALIASES[requestedName]
|
|
452
458
|
: requestedName;
|
|
459
|
+
// Availability first: switching a dev-gated provider's option off takes
|
|
460
|
+
// effect on the next lookup, even for an already-initialized instance.
|
|
461
|
+
if (!providerAvailable(name)) return undefined;
|
|
453
462
|
const cached = providers.get(name);
|
|
454
463
|
if (cached) return cached;
|
|
455
464
|
// OAuth lazy fallback. Covers the boot-time race where the credential probe
|
|
@@ -539,7 +548,12 @@ export function providerConsumesReadWindows(name) {
|
|
|
539
548
|
export function getAllProviders() {
|
|
540
549
|
// Defensive copy — callers must not mutate the live registry or retain
|
|
541
550
|
// stale entries across re-init (initProviders rebuilds the map in place).
|
|
542
|
-
return new Map(
|
|
551
|
+
return new Map(availableProviderEntries());
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
// Live instances minus dev-gated providers whose Developer option is off.
|
|
555
|
+
function availableProviderEntries() {
|
|
556
|
+
return [...providers].filter(([name]) => providerAvailable(name));
|
|
543
557
|
}
|
|
544
558
|
|
|
545
559
|
export function disableProvider(name) {
|
|
@@ -629,7 +643,7 @@ export function refreshProviderCatalogsOnStartup() {
|
|
|
629
643
|
if (_startupCatalogRefreshPromise) return _startupCatalogRefreshPromise;
|
|
630
644
|
armNextCatalogRefresh();
|
|
631
645
|
const pending = [];
|
|
632
|
-
for (const [name, provider] of
|
|
646
|
+
for (const [name, provider] of availableProviderEntries()) {
|
|
633
647
|
const refreshFn = providerCatalogRefreshFn(provider);
|
|
634
648
|
if (!refreshFn) continue;
|
|
635
649
|
pending.push(boundedCatalogRefresh(name, provider, refreshFn, 'startup catalog refresh'));
|
|
@@ -669,7 +683,7 @@ export function refreshCatalogs(options = {}) {
|
|
|
669
683
|
const msg = error instanceof Error ? error.message : String(error);
|
|
670
684
|
process.stderr.write(`[model-catalog] metadata refresh failed: ${msg}\n`);
|
|
671
685
|
});
|
|
672
|
-
for (const [name, provider] of
|
|
686
|
+
for (const [name, provider] of availableProviderEntries()) {
|
|
673
687
|
const refreshFn = providerCatalogRefreshFn(provider);
|
|
674
688
|
if (!refreshFn) continue;
|
|
675
689
|
pending.push(metadataReady.then(() => boundedCatalogRefresh(name, provider, refreshFn, 'catalog refresh')));
|
|
@@ -0,0 +1,368 @@
|
|
|
1
|
+
// Schema-driven protobuf wire codec shared by the handwritten provider wires.
|
|
2
|
+
//
|
|
3
|
+
// A schema table maps message type names to `protobufFields([...])` rows of
|
|
4
|
+
// `[name, fieldNo, type, options]`. Types are scalars ('string', 'bytes',
|
|
5
|
+
// 'raw', 'bool', 'int', 'uint', 'double', 'float'), another message type name
|
|
6
|
+
// from the same table, or `mapOf(keyType, valueType)`. Options:
|
|
7
|
+
// repeated — the field is an array (numeric ones packed only when the
|
|
8
|
+
// codec is created with `packed: true`).
|
|
9
|
+
// presence — explicit presence (proto3 `optional` / oneof member): the value
|
|
10
|
+
// is written even when it equals the type default.
|
|
11
|
+
// 'int' covers int32/int64/enum (two's-complement varint); 'uint' covers
|
|
12
|
+
// uint32/uint64. Both decode to number.
|
|
13
|
+
// Width-specific varint types follow protobuf's per-width rules instead:
|
|
14
|
+
// 'int32' / 'enum' — integer number, truncated to 32 bits; decodes to number.
|
|
15
|
+
// 'uint32' — non-negative integer number, truncated to 32 bits; a
|
|
16
|
+
// varint longer than 5 bytes is rejected; decodes to number.
|
|
17
|
+
// 'int64' — bigint, integer number or decimal string, truncated to
|
|
18
|
+
// 64 bits; decodes to a signed bigint.
|
|
19
|
+
// 'uint64' — as int64 but negative input is rejected; decodes to an
|
|
20
|
+
// unsigned bigint.
|
|
21
|
+
// Decoded objects carry only fields seen on the wire, plus `$unknown` for
|
|
22
|
+
// unrecognised fields.
|
|
23
|
+
|
|
24
|
+
export function protobufFields(entries) {
|
|
25
|
+
return Object.fromEntries(entries.map(([name, no, type, options = {}]) => [no, { name, no, type, ...options }]));
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export const mapOf = (key, value) => ({ map: [key, value] });
|
|
29
|
+
export const repeated = Object.freeze({ repeated: true });
|
|
30
|
+
export const presence = Object.freeze({ presence: true });
|
|
31
|
+
|
|
32
|
+
const textEncoder = new TextEncoder();
|
|
33
|
+
const WIDTH_TYPES = new Set(['int32', 'enum', 'uint32', 'int64', 'uint64']);
|
|
34
|
+
const PACKABLE_TYPES = new Set(['bool', 'int', 'uint', 'double', 'float', ...WIDTH_TYPES]);
|
|
35
|
+
|
|
36
|
+
export function concatBytes(parts) {
|
|
37
|
+
const length = parts.reduce((sum, part) => sum + part.length, 0);
|
|
38
|
+
const output = new Uint8Array(length);
|
|
39
|
+
let offset = 0;
|
|
40
|
+
for (const part of parts) {
|
|
41
|
+
output.set(part, offset);
|
|
42
|
+
offset += part.length;
|
|
43
|
+
}
|
|
44
|
+
return output;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export function encodeVarint(value) {
|
|
48
|
+
let current = BigInt(value ?? 0);
|
|
49
|
+
if (current < 0) current = BigInt.asUintN(64, current);
|
|
50
|
+
const bytes = [];
|
|
51
|
+
do {
|
|
52
|
+
let byte = Number(current & 0x7fn);
|
|
53
|
+
current >>= 7n;
|
|
54
|
+
if (current) byte |= 0x80;
|
|
55
|
+
bytes.push(byte);
|
|
56
|
+
} while (current);
|
|
57
|
+
return Uint8Array.from(bytes);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export function encodeTag(no, wireType) {
|
|
61
|
+
return encodeVarint((BigInt(no) << 3n) | BigInt(wireType));
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function isDefaultScalar(value) {
|
|
65
|
+
if (value === 0 || value === 0n || value === false || value === '') return true;
|
|
66
|
+
return value instanceof Uint8Array && value.length === 0;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// `label` prefixes every error ("Cursor protobuf"). `strict` rejects wire-type
|
|
70
|
+
// mismatches, field number 0, malformed UTF-8, varints longer than 10 bytes and
|
|
71
|
+
// truncated fixed-width values instead of decoding them leniently.
|
|
72
|
+
// `omitDefaults` skips proto3 implicit-presence fields that hold their type
|
|
73
|
+
// default, which yields canonical proto3 bytes; repeated elements are always
|
|
74
|
+
// written, defaults included. `packed` encodes repeated numeric fields packed
|
|
75
|
+
// and decodes them from either packed or unpacked wire form.
|
|
76
|
+
export function createProtobufCodec(
|
|
77
|
+
schemas,
|
|
78
|
+
{ label = 'protobuf', strict = false, omitDefaults = false, packed = false } = {}
|
|
79
|
+
) {
|
|
80
|
+
// A protobuf string is data, not a text document with a disposable BOM.
|
|
81
|
+
const textDecoder = new TextDecoder('utf-8', { ignoreBOM: true, fatal: strict });
|
|
82
|
+
|
|
83
|
+
const isMessageType = (type) => typeof type === 'string' && Object.hasOwn(schemas, type);
|
|
84
|
+
|
|
85
|
+
function wireTypeFor(type) {
|
|
86
|
+
if (type === 'double') return 1;
|
|
87
|
+
if (type === 'float') return 5;
|
|
88
|
+
if (type?.map || ['string', 'bytes', 'raw'].includes(type) || isMessageType(type)) return 2;
|
|
89
|
+
return 0;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function scalarBytes(type, value) {
|
|
93
|
+
if (type === 'string') return textEncoder.encode(String(value));
|
|
94
|
+
if (type === 'bytes' || type === 'raw') return value instanceof Uint8Array ? value : new Uint8Array(value);
|
|
95
|
+
if (type === 'double' || type === 'float') {
|
|
96
|
+
const size = type === 'double' ? 8 : 4;
|
|
97
|
+
const buffer = new ArrayBuffer(size);
|
|
98
|
+
const view = new DataView(buffer);
|
|
99
|
+
if (size === 8) view.setFloat64(0, Number(value), true);
|
|
100
|
+
else view.setFloat32(0, Number(value), true);
|
|
101
|
+
return new Uint8Array(buffer);
|
|
102
|
+
}
|
|
103
|
+
if (type === 'bool') return encodeVarint(value ? 1 : 0);
|
|
104
|
+
if (type === 'int' || type === 'uint') return encodeVarint(value);
|
|
105
|
+
if (WIDTH_TYPES.has(type)) return encodeVarint(BigInt.asUintN(64, BigInt(widthValue(type, value))));
|
|
106
|
+
if (isMessageType(type)) return encodeMessage(type, value);
|
|
107
|
+
throw new Error(`Unknown ${label} type: ${type}`);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// Validated, width-truncated value of a width-specific varint field.
|
|
111
|
+
function widthValue(type, value) {
|
|
112
|
+
if (type === 'int64' || type === 'uint64') {
|
|
113
|
+
let big;
|
|
114
|
+
if (typeof value === 'bigint') big = value;
|
|
115
|
+
else if (typeof value === 'number' && Number.isInteger(value)) big = BigInt(value);
|
|
116
|
+
else if (typeof value === 'string') {
|
|
117
|
+
try {
|
|
118
|
+
big = BigInt(value);
|
|
119
|
+
} catch {
|
|
120
|
+
// Reported below with the field type.
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
if (big === undefined) throw new Error(`Invalid ${label} ${type} value: ${typeof value}`);
|
|
124
|
+
if (type === 'uint64' && big < 0n) throw new Error(`Invalid ${label} uint64 value: negative`);
|
|
125
|
+
return big;
|
|
126
|
+
}
|
|
127
|
+
if (typeof value !== 'number' || !Number.isInteger(value)) {
|
|
128
|
+
throw new Error(`Invalid ${label} ${type} value: ${typeof value}`);
|
|
129
|
+
}
|
|
130
|
+
if (type === 'uint32') {
|
|
131
|
+
if (value < 0) throw new Error(`Invalid ${label} uint32 value: negative`);
|
|
132
|
+
return value >>> 0;
|
|
133
|
+
}
|
|
134
|
+
return value | 0;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
function shouldWrite(type, value) {
|
|
138
|
+
if (value == null) return false;
|
|
139
|
+
if (WIDTH_TYPES.has(type)) return !(omitDefaults && BigInt(widthValue(type, value)) === 0n);
|
|
140
|
+
if (type === 'string') return value !== '';
|
|
141
|
+
if (omitDefaults && !isMessageType(type)) return !isDefaultScalar(value);
|
|
142
|
+
return true;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
function encodeField(no, type, value) {
|
|
146
|
+
const wireType = wireTypeFor(type);
|
|
147
|
+
const payload = scalarBytes(type, value);
|
|
148
|
+
if (wireType === 2) return concatBytes([encodeTag(no, wireType), encodeVarint(payload.length), payload]);
|
|
149
|
+
return concatBytes([encodeTag(no, wireType), payload]);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
function encodeMapField(no, [keyType, valueType], value) {
|
|
153
|
+
const parts = [];
|
|
154
|
+
for (const [key, entryValue] of Object.entries(value || {})) {
|
|
155
|
+
const entry = concatBytes([encodeField(1, keyType, key), encodeField(2, valueType, entryValue)]);
|
|
156
|
+
parts.push(concatBytes([encodeTag(no, 2), encodeVarint(entry.length), entry]));
|
|
157
|
+
}
|
|
158
|
+
return parts;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
function encodeMessage(type, value = {}) {
|
|
162
|
+
const schema = schemas[type];
|
|
163
|
+
if (!schema) throw new Error(`Unknown ${label} message: ${type}`);
|
|
164
|
+
const parts = [];
|
|
165
|
+
for (const descriptor of Object.values(schema)) {
|
|
166
|
+
const fieldValue = value[descriptor.name];
|
|
167
|
+
if (descriptor.type?.map) {
|
|
168
|
+
parts.push(...encodeMapField(descriptor.no, descriptor.type.map, fieldValue));
|
|
169
|
+
continue;
|
|
170
|
+
}
|
|
171
|
+
let values = [fieldValue];
|
|
172
|
+
if (descriptor.repeated) {
|
|
173
|
+
values = Array.isArray(fieldValue) ? fieldValue : [];
|
|
174
|
+
if (packed && PACKABLE_TYPES.has(descriptor.type)) {
|
|
175
|
+
if (values.length) {
|
|
176
|
+
const payload = concatBytes(values.map((item) => scalarBytes(descriptor.type, item)));
|
|
177
|
+
parts.push(concatBytes([encodeTag(descriptor.no, 2), encodeVarint(payload.length), payload]));
|
|
178
|
+
}
|
|
179
|
+
continue;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
for (const item of values) {
|
|
183
|
+
// A oneof's explicit empty string is a value, not an absent field;
|
|
184
|
+
// canonical proto3 keeps every repeated element.
|
|
185
|
+
const explicit = descriptor.presence || (omitDefaults && descriptor.repeated);
|
|
186
|
+
if ((explicit && item != null) || shouldWrite(descriptor.type, item)) {
|
|
187
|
+
parts.push(encodeField(descriptor.no, descriptor.type, item));
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
return concatBytes(parts);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
class ProtoReader {
|
|
195
|
+
constructor(bytes) {
|
|
196
|
+
this.bytes = bytes instanceof Uint8Array ? bytes : new Uint8Array(bytes);
|
|
197
|
+
this.offset = 0;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
get done() {
|
|
201
|
+
return this.offset >= this.bytes.length;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
varint() {
|
|
205
|
+
let value = 0n;
|
|
206
|
+
let shift = 0n;
|
|
207
|
+
while (!this.done) {
|
|
208
|
+
const byte = this.bytes[this.offset++];
|
|
209
|
+
value |= BigInt(byte & 0x7f) << shift;
|
|
210
|
+
if ((byte & 0x80) === 0) return value;
|
|
211
|
+
shift += 7n;
|
|
212
|
+
if (shift > (strict ? 63n : 70n)) throw new Error(`Invalid ${label} varint`);
|
|
213
|
+
}
|
|
214
|
+
throw new Error(`Truncated ${label} varint`);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// A 32-bit varint: at most 5 bytes, bits past 32 dropped.
|
|
218
|
+
varint32() {
|
|
219
|
+
let value = 0n;
|
|
220
|
+
for (let index = 0; index < 5; index++) {
|
|
221
|
+
if (this.done) throw new Error(`Truncated ${label} varint`);
|
|
222
|
+
const byte = this.bytes[this.offset++];
|
|
223
|
+
value |= BigInt(byte & 0x7f) << BigInt(7 * index);
|
|
224
|
+
if ((byte & 0x80) === 0) return Number(value & 0xffffffffn);
|
|
225
|
+
}
|
|
226
|
+
throw new Error(`Invalid ${label} 32-bit varint`);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
take(length) {
|
|
230
|
+
const end = this.offset + length;
|
|
231
|
+
if (end > this.bytes.length) throw new Error(`Truncated ${label} field`);
|
|
232
|
+
const value = this.bytes.subarray(this.offset, end);
|
|
233
|
+
this.offset = end;
|
|
234
|
+
return value;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
bytesValue() {
|
|
238
|
+
return this.take(Number(this.varint()));
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
skip(wireType) {
|
|
242
|
+
if (wireType === 0) this.varint();
|
|
243
|
+
else if (wireType === 1) this.take(8);
|
|
244
|
+
else if (wireType === 2) this.bytesValue();
|
|
245
|
+
else if (wireType === 5) this.take(4);
|
|
246
|
+
else throw new Error(`Unsupported ${label} wire type: ${wireType}`);
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
function decodeString(bytes) {
|
|
251
|
+
try {
|
|
252
|
+
return textDecoder.decode(bytes);
|
|
253
|
+
} catch (error) {
|
|
254
|
+
throw new Error(`Invalid ${label} UTF-8 string`, { cause: error });
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
function decodeScalar(reader, type, wireType) {
|
|
259
|
+
if (type === 'string') return decodeString(reader.bytesValue());
|
|
260
|
+
if (type === 'bytes' || type === 'raw') return new Uint8Array(reader.bytesValue());
|
|
261
|
+
if (type === 'double') {
|
|
262
|
+
if (wireType !== 1) throw new Error(`Invalid ${label} double`);
|
|
263
|
+
if (strict) {
|
|
264
|
+
const bytes = reader.take(8);
|
|
265
|
+
return new DataView(bytes.buffer, bytes.byteOffset, 8).getFloat64(0, true);
|
|
266
|
+
}
|
|
267
|
+
// Lenient read: the view is bounded by the backing buffer only.
|
|
268
|
+
const value = new DataView(reader.bytes.buffer, reader.bytes.byteOffset + reader.offset, 8).getFloat64(0, true);
|
|
269
|
+
reader.offset += 8;
|
|
270
|
+
return value;
|
|
271
|
+
}
|
|
272
|
+
if (type === 'float') {
|
|
273
|
+
if (wireType !== 5) throw new Error(`Invalid ${label} float`);
|
|
274
|
+
const bytes = reader.take(4);
|
|
275
|
+
return new DataView(bytes.buffer, bytes.byteOffset, 4).getFloat32(0, true);
|
|
276
|
+
}
|
|
277
|
+
if (type === 'bool') return reader.varint() !== 0n;
|
|
278
|
+
if (type === 'int') return Number(BigInt.asIntN(64, reader.varint()));
|
|
279
|
+
if (type === 'uint') return Number(reader.varint());
|
|
280
|
+
if (type === 'int32' || type === 'enum') return Number(BigInt.asIntN(32, reader.varint()));
|
|
281
|
+
if (type === 'uint32') return reader.varint32();
|
|
282
|
+
if (type === 'int64') return BigInt.asIntN(64, reader.varint());
|
|
283
|
+
if (type === 'uint64') return BigInt.asUintN(64, reader.varint());
|
|
284
|
+
if (isMessageType(type)) return decodeMessage(type, reader.bytesValue());
|
|
285
|
+
throw new Error(`Unknown ${label} type: ${type}`);
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
function checkWireType(descriptorName, type, wireType) {
|
|
289
|
+
if (strict && wireType !== wireTypeFor(type)) {
|
|
290
|
+
throw new Error(`Invalid ${label} wire type ${wireType} for ${descriptorName}`);
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
function decodeMapEntry(bytes, [keyType, valueType]) {
|
|
295
|
+
const reader = new ProtoReader(bytes);
|
|
296
|
+
let key = '';
|
|
297
|
+
let value = valueType === 'string' ? '' : undefined;
|
|
298
|
+
while (!reader.done) {
|
|
299
|
+
const tag = reader.varint();
|
|
300
|
+
const no = Number(tag >> 3n);
|
|
301
|
+
const wireType = Number(tag & 7n);
|
|
302
|
+
if (no === 1) {
|
|
303
|
+
checkWireType('map key', keyType, wireType);
|
|
304
|
+
key = decodeScalar(reader, keyType, wireType);
|
|
305
|
+
} else if (no === 2) {
|
|
306
|
+
checkWireType('map value', valueType, wireType);
|
|
307
|
+
value = decodeScalar(reader, valueType, wireType);
|
|
308
|
+
} else reader.skip(wireType);
|
|
309
|
+
}
|
|
310
|
+
return [String(key), value];
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
function decodePacked(bytes, type) {
|
|
314
|
+
const reader = new ProtoReader(bytes);
|
|
315
|
+
const wireType = wireTypeFor(type);
|
|
316
|
+
const values = [];
|
|
317
|
+
while (!reader.done) values.push(decodeScalar(reader, type, wireType));
|
|
318
|
+
return values;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
function decodeMessage(type, bytes) {
|
|
322
|
+
const schema = schemas[type];
|
|
323
|
+
if (!schema) throw new Error(`Unknown ${label} message: ${type}`);
|
|
324
|
+
const reader = new ProtoReader(bytes);
|
|
325
|
+
const output = {};
|
|
326
|
+
while (!reader.done) {
|
|
327
|
+
const tag = reader.varint();
|
|
328
|
+
const no = Number(tag >> 3n);
|
|
329
|
+
const wireType = Number(tag & 7n);
|
|
330
|
+
if (strict && no === 0) throw new Error(`Invalid ${label} field number 0`);
|
|
331
|
+
const descriptor = schema[no];
|
|
332
|
+
if (!descriptor) {
|
|
333
|
+
const start = reader.offset;
|
|
334
|
+
reader.skip(wireType);
|
|
335
|
+
output.$unknown ||= [];
|
|
336
|
+
output.$unknown.push({
|
|
337
|
+
no,
|
|
338
|
+
wireType,
|
|
339
|
+
data: new Uint8Array(reader.bytes.subarray(start, reader.offset)),
|
|
340
|
+
});
|
|
341
|
+
continue;
|
|
342
|
+
}
|
|
343
|
+
if (descriptor.type?.map) {
|
|
344
|
+
checkWireType(descriptor.name, descriptor.type, wireType);
|
|
345
|
+
const [key, value] = decodeMapEntry(reader.bytesValue(), descriptor.type.map);
|
|
346
|
+
output[descriptor.name] ||= {};
|
|
347
|
+
output[descriptor.name][key] = value;
|
|
348
|
+
continue;
|
|
349
|
+
}
|
|
350
|
+
if (packed && descriptor.repeated && wireType === 2 && PACKABLE_TYPES.has(descriptor.type)) {
|
|
351
|
+
output[descriptor.name] ||= [];
|
|
352
|
+
output[descriptor.name].push(...decodePacked(reader.bytesValue(), descriptor.type));
|
|
353
|
+
continue;
|
|
354
|
+
}
|
|
355
|
+
checkWireType(descriptor.name, descriptor.type, wireType);
|
|
356
|
+
const value = decodeScalar(reader, descriptor.type, wireType);
|
|
357
|
+
if (descriptor.repeated) {
|
|
358
|
+
output[descriptor.name] ||= [];
|
|
359
|
+
output[descriptor.name].push(value);
|
|
360
|
+
} else {
|
|
361
|
+
output[descriptor.name] = value;
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
return output;
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
return { encodeMessage, decodeMessage, encodeField, ProtoReader };
|
|
368
|
+
}
|
|
@@ -158,6 +158,8 @@ export function featureDisallowedToolsFor(
|
|
|
158
158
|
...(builtinFeatureActive(configLike, 'media') ? [] : ['media']),
|
|
159
159
|
...(builtinFeatureActive(configLike, 'tidy') ? [] : ['tidy']),
|
|
160
160
|
...(builtinFeatureActive(configLike, 'visualize') ? [] : ['visualize']),
|
|
161
|
+
// Bots' emoji reactions (Settings → General → Reactions); on unless turned off.
|
|
162
|
+
...(configLike?.reactions === false ? ['react'] : []),
|
|
161
163
|
];
|
|
162
164
|
// Headless exec uses the Lead surface and excludes Skill/MCP tools. When
|
|
163
165
|
// only its eager defaults remain, neither schemas nor loader guidance help.
|
|
@@ -27,7 +27,7 @@ substantial coding to a new agent task session (\`session create\`) with
|
|
|
27
27
|
a self-contained brief: start it when already requested, otherwise suggest it. Then relay the
|
|
28
28
|
result in your own words. Promise a follow-up only when the session result allows it.`;
|
|
29
29
|
|
|
30
|
-
/**
|
|
30
|
+
/** An agent-mode Lead's contact catalog intro: the user's other bots. */
|
|
31
31
|
export const MIXY_CONTACTS_INTRO = `The user's other bots. Hand one a request with \`session send\` to its chat and a
|
|
32
32
|
self-contained brief.`;
|
|
33
33
|
|