mixdog 0.9.0 → 0.9.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +10 -3
- package/scripts/_bench-cwc.json +20 -0
- package/scripts/agent-loop-policy-test.mjs +37 -0
- package/scripts/agent-parallel-smoke.mjs +54 -10
- package/scripts/background-task-meta-smoke.mjs +1 -1
- package/scripts/bench-run.mjs +262 -0
- package/scripts/compact-smoke.mjs +12 -0
- package/scripts/compact-trigger-migration-smoke.mjs +67 -1
- package/scripts/ingest-pure-conversation-smoke.mjs +148 -0
- package/scripts/internal-comms-bench.mjs +727 -0
- package/scripts/internal-comms-smoke.mjs +75 -0
- package/scripts/lead-workflow-smoke.mjs +4 -4
- package/scripts/live-worker-smoke.mjs +9 -9
- package/scripts/output-style-bench.mjs +285 -0
- package/scripts/output-style-smoke.mjs +13 -10
- package/scripts/patch-replay.mjs +90 -0
- package/scripts/provider-stream-stall-test.mjs +276 -0
- package/scripts/provider-toolcall-test.mjs +599 -1
- package/scripts/routing-corpus.mjs +281 -0
- package/scripts/session-bench.mjs +1526 -0
- package/scripts/session-diag.mjs +595 -0
- package/scripts/session-ingest-smoke.mjs +2 -2
- package/scripts/task-bench.mjs +207 -0
- package/scripts/tool-failures.mjs +6 -6
- package/scripts/tool-smoke.mjs +306 -66
- package/scripts/toolcall-args-test.mjs +81 -0
- package/src/agents/debugger/AGENT.md +4 -4
- package/src/agents/heavy-worker/AGENT.md +4 -2
- package/src/agents/reviewer/AGENT.md +4 -4
- package/src/agents/worker/AGENT.md +4 -2
- package/src/app.mjs +10 -6
- package/src/defaults/{hidden-roles.json → agents.json} +7 -7
- package/src/examples/schedules/SCHEDULE.example.md +32 -0
- package/src/examples/webhooks/WEBHOOK.example.md +40 -0
- package/src/headless-role.mjs +14 -14
- package/src/help.mjs +1 -0
- package/src/lib/mixdog-debug.cjs +0 -22
- package/src/lib/plugin-paths.cjs +1 -7
- package/src/lib/rules-builder.cjs +34 -56
- package/src/mixdog-session-runtime.mjs +710 -319
- package/src/output-styles/default.md +12 -7
- package/src/output-styles/minimal.md +25 -0
- package/src/output-styles/oneline.md +21 -0
- package/src/output-styles/simple.md +10 -9
- package/src/repl.mjs +12 -4
- package/src/rules/agent/00-common.md +7 -5
- package/src/rules/agent/30-explorer.md +7 -8
- package/src/rules/lead/01-general.md +3 -1
- package/src/rules/lead/lead-tool.md +7 -0
- package/src/rules/shared/01-tool.md +17 -12
- package/src/runtime/agent/orchestrator/agent-runtime/agent-dispatch.mjs +90 -32
- package/src/runtime/agent/orchestrator/agent-runtime/agent-loop-policy.mjs +32 -0
- package/src/runtime/agent/orchestrator/agent-runtime/agent-progress-watchdog.mjs +18 -6
- package/src/runtime/agent/orchestrator/agent-runtime/cache-strategy.mjs +23 -20
- package/src/runtime/agent/orchestrator/agent-runtime/session-builder.mjs +48 -14
- package/src/runtime/agent/orchestrator/agent-trace.mjs +87 -12
- package/src/runtime/agent/orchestrator/config.mjs +3 -0
- package/src/runtime/agent/orchestrator/context/collect.mjs +131 -67
- package/src/runtime/agent/orchestrator/{internal-roles.mjs → internal-agents.mjs} +72 -72
- package/src/runtime/agent/orchestrator/internal-tools.mjs +13 -26
- package/src/runtime/agent/orchestrator/mcp/client.mjs +94 -16
- package/src/runtime/agent/orchestrator/providers/anthropic-betas.mjs +7 -0
- package/src/runtime/agent/orchestrator/providers/anthropic-effort.mjs +188 -0
- package/src/runtime/agent/orchestrator/providers/anthropic-leaked-toolcall.mjs +444 -0
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +359 -106
- package/src/runtime/agent/orchestrator/providers/anthropic.mjs +63 -51
- package/src/runtime/agent/orchestrator/providers/api-usage.mjs +27 -20
- package/src/runtime/agent/orchestrator/providers/gemini.mjs +184 -17
- package/src/runtime/agent/orchestrator/providers/grok-oauth.mjs +8 -1
- package/src/runtime/agent/orchestrator/providers/model-catalog.mjs +18 -8
- package/src/runtime/agent/orchestrator/providers/openai-compat-stream.mjs +210 -21
- package/src/runtime/agent/orchestrator/providers/openai-compat.mjs +86 -30
- package/src/runtime/agent/orchestrator/providers/openai-oauth-ws.mjs +254 -280
- package/src/runtime/agent/orchestrator/providers/openai-oauth.mjs +191 -50
- package/src/runtime/agent/orchestrator/providers/openai-ws.mjs +18 -0
- package/src/runtime/agent/orchestrator/providers/opencode-go-usage.mjs +11 -5
- package/src/runtime/agent/orchestrator/providers/registry.mjs +2 -1
- package/src/runtime/agent/orchestrator/providers/retry-classifier.mjs +265 -1
- package/src/runtime/agent/orchestrator/session/compact.mjs +560 -51
- package/src/runtime/agent/orchestrator/session/context-utils.mjs +250 -3
- package/src/runtime/agent/orchestrator/session/loop.mjs +394 -132
- package/src/runtime/agent/orchestrator/session/manager.mjs +217 -170
- package/src/runtime/agent/orchestrator/session/store.mjs +4 -4
- package/src/runtime/agent/orchestrator/session/tool-envelope.mjs +61 -0
- package/src/runtime/agent/orchestrator/session/tool-result-offload.mjs +5 -0
- package/src/runtime/agent/orchestrator/stall-policy.mjs +63 -15
- package/src/runtime/agent/orchestrator/tools/bash-session.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/builtin/arg-guard.mjs +194 -32
- package/src/runtime/agent/orchestrator/tools/builtin/arg-guard.test.mjs +143 -0
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool.mjs +1 -44
- package/src/runtime/agent/orchestrator/tools/builtin/builtin-tools.mjs +34 -18
- package/src/runtime/agent/orchestrator/tools/builtin/external-tool-adapters.mjs +0 -0
- package/src/runtime/agent/orchestrator/tools/builtin/list-formatting.mjs +10 -0
- package/src/runtime/agent/orchestrator/tools/builtin/list-tool.mjs +5 -4
- package/src/runtime/agent/orchestrator/tools/builtin/path-utils.mjs +15 -0
- package/src/runtime/agent/orchestrator/tools/builtin/read-args.mjs +9 -44
- package/src/runtime/agent/orchestrator/tools/builtin/read-constants.mjs +2 -1
- package/src/runtime/agent/orchestrator/tools/builtin/read-formatting.mjs +13 -4
- package/src/runtime/agent/orchestrator/tools/builtin/read-tool.mjs +10 -17
- package/src/runtime/agent/orchestrator/tools/builtin/search-tool.mjs +18 -2
- package/src/runtime/agent/orchestrator/tools/builtin/shell-output.mjs +3 -2
- package/src/runtime/agent/orchestrator/tools/builtin/tool-output-limit.mjs +10 -0
- package/src/runtime/agent/orchestrator/tools/builtin.mjs +59 -1
- package/src/runtime/agent/orchestrator/tools/code-graph-tool-defs.mjs +5 -5
- package/src/runtime/agent/orchestrator/tools/code-graph.mjs +4076 -3985
- package/src/runtime/agent/orchestrator/tools/patch.mjs +116 -2
- package/src/runtime/channels/backends/discord.mjs +99 -9
- package/src/runtime/channels/backends/telegram.mjs +501 -0
- package/src/runtime/channels/index.mjs +441 -1254
- package/src/runtime/channels/lib/cli-worker-host.mjs +1 -8
- package/src/runtime/channels/lib/config.mjs +54 -3
- package/src/runtime/channels/lib/drop-trace.mjs +1 -1
- package/src/runtime/channels/lib/executor.mjs +0 -3
- package/src/runtime/channels/lib/format.mjs +4 -2
- package/src/runtime/channels/lib/memory-client.mjs +0 -38
- package/src/runtime/channels/lib/output-forwarder.mjs +77 -71
- package/src/runtime/channels/lib/runtime-paths.mjs +29 -6
- package/src/runtime/channels/lib/scheduler.mjs +1 -1
- package/src/runtime/channels/lib/session-discovery.mjs +0 -4
- package/src/runtime/channels/lib/telegram-format.mjs +283 -0
- package/src/runtime/channels/lib/tool-format.mjs +1 -2
- package/src/runtime/channels/lib/transcript-discovery.mjs +20 -11
- package/src/runtime/channels/lib/webhook.mjs +59 -31
- package/src/runtime/channels/tool-defs.mjs +1 -1
- package/src/runtime/lib/keychain-cjs.cjs +0 -1
- package/src/runtime/memory/data/runtime-manifest.json +6 -7
- package/src/runtime/memory/index.mjs +187 -43
- package/src/runtime/memory/lib/agent-ipc.mjs +2 -2
- package/src/runtime/memory/lib/core-memory-store.mjs +1 -1
- package/src/runtime/memory/lib/llm-worker-host.mjs +0 -4
- package/src/runtime/memory/lib/memory-cycle1.mjs +1 -1
- package/src/runtime/memory/lib/memory-cycle2.mjs +9 -6
- package/src/runtime/memory/lib/memory-cycle3.mjs +1 -1
- package/src/runtime/memory/lib/memory-ops-policy.mjs +0 -1
- package/src/runtime/memory/lib/memory.mjs +101 -4
- package/src/runtime/memory/lib/pg/adapter.mjs +139 -15
- package/src/runtime/memory/lib/runtime-fetcher.mjs +43 -18
- package/src/runtime/memory/lib/session-ingest.mjs +116 -7
- package/src/runtime/memory/lib/trace-store.mjs +69 -22
- package/src/runtime/memory/tool-defs.mjs +6 -3
- package/src/runtime/search/index.mjs +2 -7
- package/src/runtime/search/lib/config.mjs +0 -4
- package/src/runtime/search/lib/state.mjs +1 -15
- package/src/runtime/search/lib/web-tools.mjs +0 -1
- package/src/runtime/shared/channel-notification-routing.mjs +12 -0
- package/src/runtime/shared/channel-notification-routing.test.mjs +45 -0
- package/src/runtime/shared/child-spawn-gate.mjs +0 -6
- package/src/runtime/shared/config.mjs +9 -0
- package/src/runtime/shared/llm/http-agent.mjs +12 -5
- package/src/runtime/shared/schedules-store.mjs +21 -19
- package/src/runtime/shared/tool-surface.mjs +98 -13
- package/src/runtime/shared/transcript-writer.mjs +129 -0
- package/src/runtime/shared/update-checker.mjs +214 -0
- package/src/standalone/agent-tool.mjs +255 -109
- package/src/standalone/channel-admin.mjs +133 -40
- package/src/standalone/channel-worker.mjs +8 -291
- package/src/standalone/explore-tool.mjs +2 -2
- package/src/standalone/memory-runtime-proxy.mjs +3 -1
- package/src/standalone/provider-admin.mjs +11 -0
- package/src/standalone/seeds.mjs +1 -11
- package/src/standalone/usage-dashboard.mjs +1 -1
- package/src/tui/App.jsx +2137 -750
- package/src/tui/components/ConfirmBar.jsx +47 -0
- package/src/tui/components/ContextPanel.jsx +5 -3
- package/src/tui/components/ItemRightHintOverprint.jsx +54 -0
- package/src/tui/components/Markdown.jsx +22 -98
- package/src/tui/components/Message.jsx +14 -35
- package/src/tui/components/Picker.jsx +87 -12
- package/src/tui/components/PromptInput.jsx +146 -9
- package/src/tui/components/QueuedCommands.jsx +1 -1
- package/src/tui/components/SlashCommandPalette.jsx +8 -5
- package/src/tui/components/Spinner.jsx +7 -7
- package/src/tui/components/StatusLine.jsx +40 -21
- package/src/tui/components/TextEntryPanel.jsx +51 -7
- package/src/tui/components/ToolExecution.jsx +177 -100
- package/src/tui/components/TurnDone.jsx +4 -4
- package/src/tui/components/UsagePanel.jsx +1 -1
- package/src/tui/components/tool-output-format.mjs +312 -40
- package/src/tui/components/tool-output-format.test.mjs +180 -1
- package/src/tui/display-width.mjs +69 -0
- package/src/tui/display-width.test.mjs +35 -0
- package/src/tui/dist/index.mjs +7324 -2393
- package/src/tui/engine.mjs +287 -126
- package/src/tui/index.jsx +117 -7
- package/src/tui/keyboard-protocol.mjs +42 -0
- package/src/tui/lib/voice-recorder.mjs +453 -0
- package/src/tui/markdown/format-token.mjs +354 -142
- package/src/tui/markdown/format-token.test.mjs +155 -17
- package/src/tui/markdown/measure-rendered-rows.mjs +85 -0
- package/src/tui/markdown/render-ansi.test.mjs +1 -1
- package/src/tui/markdown/streaming-markdown.mjs +167 -0
- package/src/tui/markdown/streaming-markdown.test.mjs +70 -0
- package/src/tui/markdown/table-layout.mjs +9 -9
- package/src/tui/paste-attachments.mjs +0 -11
- package/src/tui/prompt-history-store.mjs +129 -0
- package/src/tui/prompt-history-store.test.mjs +52 -0
- package/src/tui/statusline-ansi-bridge.test.mjs +3 -3
- package/src/tui/theme.mjs +41 -647
- package/src/tui/themes/base.mjs +86 -0
- package/src/tui/themes/basic.mjs +85 -0
- package/src/tui/themes/catppuccin.mjs +72 -0
- package/src/tui/themes/dracula.mjs +70 -0
- package/src/tui/themes/everforest.mjs +71 -0
- package/src/tui/themes/gruvbox.mjs +71 -0
- package/src/tui/themes/index.mjs +71 -0
- package/src/tui/themes/indigo.mjs +78 -0
- package/src/tui/themes/kanagawa.mjs +80 -0
- package/src/tui/themes/light.mjs +81 -0
- package/src/tui/themes/nord.mjs +72 -0
- package/src/tui/themes/onedark.mjs +16 -0
- package/src/tui/themes/rosepine.mjs +70 -0
- package/src/tui/themes/teal.mjs +81 -0
- package/src/tui/themes/tokyonight.mjs +79 -0
- package/src/tui/themes/utils.mjs +106 -0
- package/src/tui/themes/warm.mjs +79 -0
- package/src/tui/transcript-tool-failures.mjs +13 -2
- package/src/ui/markdown.mjs +1 -1
- package/src/ui/model-display.mjs +2 -2
- package/src/ui/statusline.mjs +26 -27
- package/src/vendor/statusline/bin/statusline-lib.mjs +0 -623
- package/src/vendor/statusline/bin/statusline-route.mjs +5 -12
- package/src/vendor/statusline/src/gateway/claude-current.mjs +3 -3
- package/src/vendor/statusline/src/gateway/route-meta.mjs +30 -16
- package/src/workflows/default/WORKFLOW.md +39 -12
- package/src/workflows/sequential/WORKFLOW.md +46 -0
- package/src/workflows/solo/WORKFLOW.md +7 -0
- package/vendor/ink/build/display-width.js +62 -0
- package/vendor/ink/build/ink.js +154 -20
- package/vendor/ink/build/measure-text.js +4 -1
- package/vendor/ink/build/output.js +115 -9
- package/vendor/ink/build/render-node-to-output.js +4 -1
- package/vendor/ink/build/render.js +4 -0
- package/src/hooks/lib/permission-rules.cjs +0 -170
- package/src/hooks/lib/settings-loader.cjs +0 -112
- package/src/lib/hook-pipe-path.cjs +0 -10
- package/src/output-styles/extreme-simple.md +0 -20
- package/src/rules/lead/04-workflow.md +0 -51
- package/src/runtime/channels/lib/hook-pipe-server.mjs +0 -671
- package/src/workflows/default/workflow.json +0 -13
- package/src/workflows/solo/workflow.json +0 -7
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { createRequire } from 'node:module';
|
|
2
2
|
import { createHash } from 'crypto';
|
|
3
3
|
import { loadConfig } from '../config.mjs';
|
|
4
|
-
import { withRetry } from './retry-classifier.mjs';
|
|
4
|
+
import { shouldFallbackTransport, withRetry } from './retry-classifier.mjs';
|
|
5
|
+
import { getLlmDispatcher, preconnect } from '../../../shared/llm/http-agent.mjs';
|
|
5
6
|
import { sendViaWebSocket } from './openai-oauth-ws.mjs';
|
|
6
7
|
import {
|
|
7
8
|
consumeCompatChatCompletionStream,
|
|
@@ -32,6 +33,17 @@ import {
|
|
|
32
33
|
customToolCallFromResponseItem,
|
|
33
34
|
} from './custom-tool-wire.mjs';
|
|
34
35
|
import { OPENAI_COMPAT_PRESETS } from './openai-compat-presets.mjs';
|
|
36
|
+
|
|
37
|
+
const requireOpenAI = createRequire(import.meta.url);
|
|
38
|
+
let _OpenAI = null;
|
|
39
|
+
|
|
40
|
+
function loadOpenAI() {
|
|
41
|
+
if (!_OpenAI) {
|
|
42
|
+
const mod = requireOpenAI('openai');
|
|
43
|
+
_OpenAI = mod.default || mod.OpenAI || mod;
|
|
44
|
+
}
|
|
45
|
+
return _OpenAI;
|
|
46
|
+
}
|
|
35
47
|
export { OPENAI_COMPAT_PRESETS } from './openai-compat-presets.mjs';
|
|
36
48
|
const PRESETS = OPENAI_COMPAT_PRESETS;
|
|
37
49
|
const MODEL_LIST_TIMEOUT_MS = resolveTimeoutMs(
|
|
@@ -246,33 +258,14 @@ function _envFlag(name, fallback = true) {
|
|
|
246
258
|
return !['0', 'false', 'off', 'no'].includes(String(raw).toLowerCase());
|
|
247
259
|
}
|
|
248
260
|
|
|
261
|
+
// xAI WS→HTTP transport fallback → shared shouldFallbackTransport
|
|
262
|
+
// (retry-classifier.mjs). Identical deny-order + allow-list; the per-provider
|
|
263
|
+
// env flag is computed here and passed via `enabled`.
|
|
249
264
|
function _shouldFallbackXaiWsToHttp(err, signal) {
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
const status = Number(err?.httpStatus || err?.status || 0);
|
|
255
|
-
if (status === 401 || status === 403 || status === 404 || status === 429) return false;
|
|
256
|
-
if (status >= 500 && status < 600) return true;
|
|
257
|
-
const code = String(err?.code || '');
|
|
258
|
-
if (['EWSACQUIRETIMEOUT', 'ETIMEDOUT', 'ESOCKETTIMEDOUT', 'ECONNRESET', 'EAI_AGAIN', 'ENOTFOUND', 'EAI_NODATA', 'ECONNREFUSED', 'ENETUNREACH', 'EHOSTUNREACH', 'EPIPE'].includes(code)) {
|
|
259
|
-
return true;
|
|
260
|
-
}
|
|
261
|
-
const classifier = String(err?.retryClassifier || err?.midstreamClassifier || '');
|
|
262
|
-
if ([
|
|
263
|
-
'timeout', 'reset', 'dns', 'refused', 'network', 'acquire_timeout', 'http_5xx',
|
|
264
|
-
'first_byte_timeout', 'first_meaningful_timeout',
|
|
265
|
-
'ws_1006', 'ws_1011', 'ws_1012', 'ws_1000', 'ws_4000', 'agent_stall', 'stream_stalled',
|
|
266
|
-
'response_failed_disconnected', 'response_failed_network', 'response_failed_auth_expired',
|
|
267
|
-
'ws_send_failed',
|
|
268
|
-
].includes(classifier)) {
|
|
269
|
-
return true;
|
|
270
|
-
}
|
|
271
|
-
if (/^http_5\d\d$/.test(classifier)) return true;
|
|
272
|
-
if (err?.firstByteTimeout) return true;
|
|
273
|
-
if (err?.firstMeaningfulTimeout) return true;
|
|
274
|
-
const msg = String(err?.message || '');
|
|
275
|
-
return /opening handshake has timed out|socket hang up|acquire timed out|no first server event|no meaningful output/i.test(msg);
|
|
265
|
+
return shouldFallbackTransport(err, {
|
|
266
|
+
signal,
|
|
267
|
+
enabled: _envFlag('MIXDOG_XAI_WS_HTTP_FALLBACK', true),
|
|
268
|
+
});
|
|
276
269
|
}
|
|
277
270
|
|
|
278
271
|
function useXaiResponsesWebSocketWarmup(opts, config, { previousResponseId, instructions, rawTools }) {
|
|
@@ -989,6 +982,25 @@ function nativeResponsesTools(opts) {
|
|
|
989
982
|
? opts.nativeTools.filter(t => t && typeof t === 'object')
|
|
990
983
|
: [];
|
|
991
984
|
}
|
|
985
|
+
// Known tool-name sets for the leaked-tool-call guard, derived from the exact
|
|
986
|
+
// request body so a recovered leaked call is only synthesized when it names a
|
|
987
|
+
// tool the model was actually offered. Chat tools nest the name under
|
|
988
|
+
// `function.name`; Responses tools carry a top-level `name`.
|
|
989
|
+
function knownToolNamesFromOpenAITools(tools) {
|
|
990
|
+
return new Set(
|
|
991
|
+
(Array.isArray(tools) ? tools : [])
|
|
992
|
+
.map((t) => (typeof t?.function?.name === 'string' ? t.function.name
|
|
993
|
+
: typeof t?.name === 'string' ? t.name : null))
|
|
994
|
+
.filter(Boolean),
|
|
995
|
+
);
|
|
996
|
+
}
|
|
997
|
+
function knownToolNamesFromResponsesTools(tools) {
|
|
998
|
+
return new Set(
|
|
999
|
+
(Array.isArray(tools) ? tools : [])
|
|
1000
|
+
.map((t) => (typeof t?.name === 'string' ? t.name : null))
|
|
1001
|
+
.filter(Boolean),
|
|
1002
|
+
);
|
|
1003
|
+
}
|
|
992
1004
|
export function parseToolCalls(choice, label) {
|
|
993
1005
|
const calls = choice.message?.tool_calls;
|
|
994
1006
|
if (!calls?.length)
|
|
@@ -1217,10 +1229,20 @@ export class OpenAICompatProvider {
|
|
|
1217
1229
|
// extraHeaders behave exactly as before.
|
|
1218
1230
|
this.defaultHeaders = { ...(preset?.extraHeaders || {}), ...(config.extraHeaders || {}) };
|
|
1219
1231
|
this.defaultModel = preset?.defaultModel || 'default';
|
|
1220
|
-
this.client = new
|
|
1232
|
+
this.client = new (loadOpenAI())({
|
|
1221
1233
|
baseURL,
|
|
1222
1234
|
apiKey,
|
|
1223
1235
|
defaultHeaders: this.defaultHeaders,
|
|
1236
|
+
// The SDK's own retry loop (default 2) would nest underneath our
|
|
1237
|
+
// withRetry wrapper and multiply tail latency on a transient
|
|
1238
|
+
// backend. We own retry/backoff via withRetry, so disable the SDK's.
|
|
1239
|
+
maxRetries: 0,
|
|
1240
|
+
// Force the shared long-keepalive undici dispatcher to be installed
|
|
1241
|
+
// globally (setGlobalDispatcher) so the SDK's global fetch rides a
|
|
1242
|
+
// warm socket pool instead of Node's short-keepalive default. The
|
|
1243
|
+
// return value is undefined once installed globally; the option is
|
|
1244
|
+
// a harmless no-op then.
|
|
1245
|
+
fetchOptions: { dispatcher: getLlmDispatcher() },
|
|
1224
1246
|
});
|
|
1225
1247
|
}
|
|
1226
1248
|
reloadApiKey() {
|
|
@@ -1235,10 +1257,12 @@ export class OpenAICompatProvider {
|
|
|
1235
1257
|
this.baseURL = baseURL;
|
|
1236
1258
|
this.apiKey = newKey;
|
|
1237
1259
|
this.defaultHeaders = { ...(preset?.extraHeaders || {}), ...(this.config.extraHeaders || {}) };
|
|
1238
|
-
this.client = new
|
|
1260
|
+
this.client = new (loadOpenAI())({
|
|
1239
1261
|
baseURL,
|
|
1240
1262
|
apiKey: newKey,
|
|
1241
1263
|
defaultHeaders: this.defaultHeaders,
|
|
1264
|
+
maxRetries: 0,
|
|
1265
|
+
fetchOptions: { dispatcher: getLlmDispatcher() },
|
|
1242
1266
|
});
|
|
1243
1267
|
}
|
|
1244
1268
|
} catch { /* best effort */ }
|
|
@@ -1258,6 +1282,11 @@ export class OpenAICompatProvider {
|
|
|
1258
1282
|
async _doSend(messages, model, tools, sendOpts) {
|
|
1259
1283
|
const useModel = model || this.defaultModel;
|
|
1260
1284
|
const opts = sendOpts || {};
|
|
1285
|
+
// Re-warm a kept-alive socket to the provider origin before the turn so
|
|
1286
|
+
// the request hot path lands on a live socket instead of paying a cold
|
|
1287
|
+
// TLS handshake after an idle gap. Fire-and-forget; never awaited. This
|
|
1288
|
+
// mirrors anthropic-oauth's send()-start preconnect.
|
|
1289
|
+
preconnect(this.baseURL);
|
|
1261
1290
|
if (this.name === 'xai' && useXaiResponsesApi(opts, this.config)) {
|
|
1262
1291
|
if (useXaiResponsesWebSocket(opts, this.config)) {
|
|
1263
1292
|
try {
|
|
@@ -1358,6 +1387,11 @@ export class OpenAICompatProvider {
|
|
|
1358
1387
|
({ signal: openSignal }) => this.client.chat.completions.create(params, { signal: openSignal }),
|
|
1359
1388
|
{
|
|
1360
1389
|
signal: attemptSignal,
|
|
1390
|
+
// Single attempt: this inner wrapper exists only to
|
|
1391
|
+
// apply the first-byte per-attempt timeout. Retry is
|
|
1392
|
+
// owned by the outer withRetry — nesting retry loops
|
|
1393
|
+
// here multiplied tail latency (5x5).
|
|
1394
|
+
maxAttempts: 1,
|
|
1361
1395
|
perAttemptTimeoutMs: PROVIDER_FIRST_BYTE_TIMEOUT_MS,
|
|
1362
1396
|
perAttemptLabel: `${this.name} first byte`,
|
|
1363
1397
|
},
|
|
@@ -1370,6 +1404,10 @@ export class OpenAICompatProvider {
|
|
|
1370
1404
|
onToolCall: opts.onToolCall,
|
|
1371
1405
|
onTextDelta: opts.onTextDelta,
|
|
1372
1406
|
parseToolCalls,
|
|
1407
|
+
// Known tool names for the leaked-tool-call guard:
|
|
1408
|
+
// recovered leaked calls only synthesize when they name
|
|
1409
|
+
// a tool actually offered to this request.
|
|
1410
|
+
knownToolNames: knownToolNamesFromOpenAITools(params.tools),
|
|
1373
1411
|
});
|
|
1374
1412
|
},
|
|
1375
1413
|
{
|
|
@@ -1453,6 +1491,13 @@ export class OpenAICompatProvider {
|
|
|
1453
1491
|
model: response.model || useModel,
|
|
1454
1492
|
toolCalls,
|
|
1455
1493
|
stopReason,
|
|
1494
|
+
// P1 audit fix: a text-only completion that hit finish_reason=
|
|
1495
|
+
// 'length' (no tool calls, so not thrown above as
|
|
1496
|
+
// ProviderIncompleteError) previously returned as an ordinary
|
|
1497
|
+
// success with no signal that the content is a mid-sentence
|
|
1498
|
+
// cutoff. Flag it so loop.mjs can surface a one-line warning
|
|
1499
|
+
// instead of silently treating a truncated answer as complete.
|
|
1500
|
+
...(stopReason === 'length' && (assembled.content || '').length > 0 ? { truncated: true } : {}),
|
|
1456
1501
|
...(reasoningContent ? { reasoningContent } : {}),
|
|
1457
1502
|
usage: response.usage ? (() => {
|
|
1458
1503
|
const input = response.usage.prompt_tokens ?? response.usage.input_tokens ?? 0;
|
|
@@ -1535,6 +1580,9 @@ export class OpenAICompatProvider {
|
|
|
1535
1580
|
({ signal: openSignal }) => this.client.responses.create(params, { signal: openSignal }),
|
|
1536
1581
|
{
|
|
1537
1582
|
signal: attemptSignal,
|
|
1583
|
+
// Single attempt: first-byte timeout only; retry
|
|
1584
|
+
// is owned by the outer withRetry (see chat path).
|
|
1585
|
+
maxAttempts: 1,
|
|
1538
1586
|
perAttemptTimeoutMs: PROVIDER_FIRST_BYTE_TIMEOUT_MS,
|
|
1539
1587
|
perAttemptLabel: 'xai responses first byte',
|
|
1540
1588
|
},
|
|
@@ -1548,6 +1596,7 @@ export class OpenAICompatProvider {
|
|
|
1548
1596
|
onTextDelta: opts.onTextDelta,
|
|
1549
1597
|
parseResponsesToolCalls,
|
|
1550
1598
|
responseOutputText,
|
|
1599
|
+
knownToolNames: knownToolNamesFromResponsesTools(params.tools),
|
|
1551
1600
|
});
|
|
1552
1601
|
},
|
|
1553
1602
|
{
|
|
@@ -1617,6 +1666,10 @@ export class OpenAICompatProvider {
|
|
|
1617
1666
|
model: response.model || useModel,
|
|
1618
1667
|
toolCalls,
|
|
1619
1668
|
stopReason: streamed.stopReason || null,
|
|
1669
|
+
// P1 audit fix: mirror the chat-completions truncated flag for
|
|
1670
|
+
// the xAI Responses HTTP path — a max-output cutoff with real
|
|
1671
|
+
// content must not look identical to a clean stop.
|
|
1672
|
+
...(streamed.stopReason === 'length' && (streamed.content || '').length > 0 ? { truncated: true } : {}),
|
|
1620
1673
|
citations: searchSources.citations.length ? searchSources.citations : undefined,
|
|
1621
1674
|
webSearchCalls: searchSources.webSearchCalls.length ? searchSources.webSearchCalls : undefined,
|
|
1622
1675
|
providerState: {
|
|
@@ -1772,6 +1825,9 @@ export class OpenAICompatProvider {
|
|
|
1772
1825
|
model: result.model || useModel,
|
|
1773
1826
|
toolCalls: result.toolCalls,
|
|
1774
1827
|
stopReason: result.stopReason || null,
|
|
1828
|
+
// P1 audit fix: same truncated signal as the HTTP path (see
|
|
1829
|
+
// _doSendXaiResponses above) for the WebSocket transport.
|
|
1830
|
+
...(result.stopReason === 'length' && (result.content || '').length > 0 ? { truncated: true } : {}),
|
|
1775
1831
|
providerState: {
|
|
1776
1832
|
...(opts.providerState || {}),
|
|
1777
1833
|
xaiResponses: {
|