mixdog 0.9.148 → 0.9.149
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 +1 -1
- package/src/rules/shared/30-exploration.md +3 -0
- package/src/runtime/agent/orchestrator/providers/openai-codex-identity.test.mjs +32 -9
- package/src/runtime/agent/orchestrator/providers/openai-codex-metadata.mjs +78 -33
- package/src/runtime/agent/orchestrator/providers/openai-codex-model.mjs +21 -0
- package/src/runtime/agent/orchestrator/providers/openai-oauth-http-sse.mjs +3 -0
- package/src/runtime/agent/orchestrator/providers/openai-oauth-ws.mjs +92 -29
- package/src/runtime/agent/orchestrator/providers/openai-oauth.mjs +220 -50
- package/src/runtime/agent/orchestrator/providers/openai-responses-payload.mjs +112 -9
- package/src/runtime/agent/orchestrator/providers/openai-ws-pool.mjs +7 -27
- package/src/runtime/agent/orchestrator/providers/retry-classifier.mjs +11 -0
- package/src/runtime/agent/orchestrator/session/manager/ask-session.mjs +43 -5
- package/src/runtime/agent/orchestrator/session/manager/session-lifecycle.mjs +2 -0
- package/src/runtime/agent/orchestrator/tools/builtin/builtin-tools.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/builtin/list-tool-integrity.test.mjs +14 -0
- package/src/runtime/agent/orchestrator/tools/builtin/list-tool.mjs +2 -2
- package/src/runtime/shared/pristine-execution-contract.json +0 -1
- package/src/session-runtime/session-lifecycle.mjs +9 -0
- package/src/standalone/agent-tool/spawn-flow.mjs +4 -4
|
@@ -461,6 +461,42 @@ export async function askSession(sessionId, prompt, context, onToolCall, cwdOver
|
|
|
461
461
|
effectiveContextWindowPercent: contextMeta.effectiveContextWindowPercent,
|
|
462
462
|
autoCompactTokenLimit: contextMeta.autoCompactTokenLimit,
|
|
463
463
|
};
|
|
464
|
+
const effectiveCwd = cwdOverride || session.cwd;
|
|
465
|
+
if (session.sessionStartMetaInjected !== true
|
|
466
|
+
&& !hasUserConversationMessage(session.messages)) {
|
|
467
|
+
refreshSessionBp3Environment(session, effectiveCwd);
|
|
468
|
+
}
|
|
469
|
+
let _startupProviderPrewarm = null;
|
|
470
|
+
if (session.provider === 'openai-oauth'
|
|
471
|
+
&& Number(session.totalInputTokens || 0) === 0
|
|
472
|
+
&& !session.providerState
|
|
473
|
+
&& typeof provider.prewarmWsTransportForSession === 'function') {
|
|
474
|
+
try {
|
|
475
|
+
_startupProviderPrewarm = Promise.resolve(
|
|
476
|
+
provider.prewarmWsTransportForSession({
|
|
477
|
+
sessionId,
|
|
478
|
+
session,
|
|
479
|
+
messages: filterModelVisibleSessionMessages(session.messages),
|
|
480
|
+
model: session.model,
|
|
481
|
+
tools: session.tools,
|
|
482
|
+
effort: session.effort || null,
|
|
483
|
+
fast: session.fast === true,
|
|
484
|
+
modelParameters: session.modelParameters || {},
|
|
485
|
+
selectedContextWindow: session.selectedContextWindow || session.contextWindow || null,
|
|
486
|
+
promptCacheKey: session.promptCacheKey || null,
|
|
487
|
+
providerCacheKey: session.promptCacheKey || null,
|
|
488
|
+
...(session.providerCacheOpts || {}),
|
|
489
|
+
...(codexWireSendOpts(session, {
|
|
490
|
+
requestKind: 'prewarm',
|
|
491
|
+
turnId: _codexTurnId,
|
|
492
|
+
startedAtMs: _turnCheckpointStartedAt,
|
|
493
|
+
}) || {}),
|
|
494
|
+
}),
|
|
495
|
+
).catch(() => false);
|
|
496
|
+
} catch {
|
|
497
|
+
_startupProviderPrewarm = null;
|
|
498
|
+
}
|
|
499
|
+
}
|
|
464
500
|
// Cap caller-supplied / prefetched context so an oversized
|
|
465
501
|
// payload can't blow the session token budget before the
|
|
466
502
|
// first model call. 32 KB ~ 8k tokens at the 4 B/tok
|
|
@@ -489,11 +525,6 @@ export async function askSession(sessionId, prompt, context, onToolCall, cwdOver
|
|
|
489
525
|
if (explicitPrefetchResult) {
|
|
490
526
|
_contextBlock += `# Prefetch\n${_capCtx(explicitPrefetchResult)}\n\n`;
|
|
491
527
|
}
|
|
492
|
-
const effectiveCwd = cwdOverride || session.cwd;
|
|
493
|
-
if (session.sessionStartMetaInjected !== true
|
|
494
|
-
&& !hasUserConversationMessage(session.messages)) {
|
|
495
|
-
refreshSessionBp3Environment(session, effectiveCwd);
|
|
496
|
-
}
|
|
497
528
|
const historyMessages = filterModelVisibleSessionMessages(session.messages);
|
|
498
529
|
const beforeCount = historyMessages.length + 1;
|
|
499
530
|
const promptTextForMetrics = promptContentText(prompt);
|
|
@@ -576,6 +607,13 @@ export async function askSession(sessionId, prompt, context, onToolCall, cwdOver
|
|
|
576
607
|
},
|
|
577
608
|
});
|
|
578
609
|
} catch { /* trace must never break the ask path */ }
|
|
610
|
+
if (_startupProviderPrewarm) {
|
|
611
|
+
try {
|
|
612
|
+
await runAbortable(turnSignal, () => _startupProviderPrewarm);
|
|
613
|
+
} catch {
|
|
614
|
+
throwIfAborted(turnSignal);
|
|
615
|
+
}
|
|
616
|
+
}
|
|
579
617
|
const agentLoop = await runAbortable(turnSignal, () => _getAgentLoop());
|
|
580
618
|
const _trackTextDelta = (chunk) => {
|
|
581
619
|
_turnInterruption.recordTextDelta(chunk);
|
|
@@ -46,6 +46,7 @@ import {
|
|
|
46
46
|
} from '../approval-mode.mjs';
|
|
47
47
|
import { describeShellStartupPolicy } from '../../tools/builtin/runtime-capabilities.mjs';
|
|
48
48
|
import { captureOriginalUserCwd } from '../../../../shared/user-cwd.mjs';
|
|
49
|
+
import { refreshSessionBp3Environment } from './prompt-utils.mjs';
|
|
49
50
|
|
|
50
51
|
function buildSessionProviderCacheOpts(providerName, sessionId, agent = null) {
|
|
51
52
|
// Keep this in sync with createSession's provider-cache policy: only
|
|
@@ -477,6 +478,7 @@ export function createSession(opts) {
|
|
|
477
478
|
ownerSessionId: opts.ownerSessionId || null,
|
|
478
479
|
clientHostPid: opts.clientHostPid || null,
|
|
479
480
|
};
|
|
481
|
+
refreshSessionBp3Environment(session, opts.cwd);
|
|
480
482
|
// In-process registry + async debounced save: same-process create → load
|
|
481
483
|
// reads live memory; disk flush is for cross-process / restart durability.
|
|
482
484
|
setLiveSession(session);
|
|
@@ -244,7 +244,7 @@ export const BUILTIN_TOOLS = [
|
|
|
244
244
|
},
|
|
245
245
|
hidden: { type: 'boolean', description: 'Include dotfiles.' },
|
|
246
246
|
meta: { type: 'boolean', description: 'Per-entry size bytes, UTC mtime, octal mode.' },
|
|
247
|
-
limit: { type: 'integer', minimum: 0, description: 'Max entries; default
|
|
247
|
+
limit: { type: 'integer', minimum: 0, description: 'Max entries; default 100; 0 unlimited.' },
|
|
248
248
|
offset: { type: 'integer', minimum: 0, description: 'Entry offset.' },
|
|
249
249
|
},
|
|
250
250
|
required: [],
|
|
@@ -32,6 +32,20 @@ test('aborted list work cannot poison the result cache', async () => {
|
|
|
32
32
|
}
|
|
33
33
|
});
|
|
34
34
|
|
|
35
|
+
test('list defaults to a 100-entry page with an offset continuation', async () => {
|
|
36
|
+
const root = await mkdtemp(join(tmpdir(), 'mixdog-list-default-page-'));
|
|
37
|
+
try {
|
|
38
|
+
await Promise.all(Array.from({ length: 101 }, (_, index) => (
|
|
39
|
+
writeFile(join(root, `entry-${String(index).padStart(3, '0')}.txt`), 'ok')
|
|
40
|
+
)));
|
|
41
|
+
const out = await executeListTool({ path: root, hidden: true }, process.cwd());
|
|
42
|
+
assert.equal(out.split('\n').filter((line) => line.endsWith('\tfile')).length, 100);
|
|
43
|
+
assert.match(out, /\[entries 1-100 of 101; pass offset:100 to continue\]/);
|
|
44
|
+
} finally {
|
|
45
|
+
await rm(root, { recursive: true, force: true });
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
|
|
35
49
|
test('root readdir failures are errors, stay uncached, and mark a repeatedly failing runtime worker unhealthy', async () => {
|
|
36
50
|
const originalRuntimeWorkerPid = process.env.MIXDOG_SESSION_RUNTIME_WORKER_PID;
|
|
37
51
|
const roots = [];
|
|
@@ -100,7 +100,7 @@ function recordDirectoryWalkTelemetry(options, status, walkResult, warningCount
|
|
|
100
100
|
};
|
|
101
101
|
}
|
|
102
102
|
|
|
103
|
-
// A/B override surface for the default result caps (stock: list
|
|
103
|
+
// A/B override surface for the default result caps (stock: list 100, tree 200,
|
|
104
104
|
// fuzzy find 25). Env-gated so bench variants can match competitor-style
|
|
105
105
|
// generous caps without changing the shipped defaults.
|
|
106
106
|
function _listDefaultHeadLimit(fallback) {
|
|
@@ -256,7 +256,7 @@ export async function executeListTool(args, workDir, options = {}) {
|
|
|
256
256
|
const hidden = Boolean(args.hidden);
|
|
257
257
|
const sort = ['name', 'mtime', 'size'].includes(args.sort) ? args.sort : 'name';
|
|
258
258
|
const typeFilter = ['any', 'file', 'dir'].includes(args.type) ? args.type : 'any';
|
|
259
|
-
const headLimit = normalizeListHeadLimit(args.head_limit, _listDefaultHeadLimit(
|
|
259
|
+
const headLimit = normalizeListHeadLimit(args.head_limit, _listDefaultHeadLimit(100));
|
|
260
260
|
const offset = typeof args.offset === 'number' && args.offset > 0 ? args.offset : 0;
|
|
261
261
|
const needsGlobalStat = sort === 'mtime' || sort === 'size';
|
|
262
262
|
const includeNoise = Boolean(args.include_noise);
|
|
@@ -333,6 +333,15 @@ export function createSessionLifecycle({
|
|
|
333
333
|
throwIfAborted(signal);
|
|
334
334
|
// best-effort: ordinary hook failure never breaks session create
|
|
335
335
|
}
|
|
336
|
+
if (rt.session.provider === 'openai-oauth'
|
|
337
|
+
&& Number(rt.session.totalInputTokens || 0) === 0
|
|
338
|
+
&& !rt.session.providerState
|
|
339
|
+
&& typeof providerImpl.prewarmWsTransportForSession === 'function') {
|
|
340
|
+
void Promise.resolve(providerImpl.prewarmWsTransportForSession({
|
|
341
|
+
sessionId: rt.session.id,
|
|
342
|
+
session: rt.session,
|
|
343
|
+
})).catch(() => {});
|
|
344
|
+
}
|
|
336
345
|
throwIfAborted(signal);
|
|
337
346
|
bootProfile('session:create:ready', {
|
|
338
347
|
ms: (performance.now() - startedAt).toFixed(1),
|
|
@@ -337,10 +337,10 @@ export function createSpawnFlow({
|
|
|
337
337
|
const spec = spawnSessionSpec(plan, args, context);
|
|
338
338
|
const { session, effectiveCwd } = prepareAgentSession(spec);
|
|
339
339
|
bindSpawnedSession(session, plan);
|
|
340
|
-
// Spawn prewarm
|
|
341
|
-
//
|
|
342
|
-
//
|
|
343
|
-
//
|
|
340
|
+
// Spawn prewarm builds the materialized stable prompt and keeps the
|
|
341
|
+
// resulting Codex-style client handle reserved for the first turn.
|
|
342
|
+
// Fire-and-forget: failures fall back to the lazy per-send handshake.
|
|
343
|
+
// MIXDOG_AGENT_SPAWN_WS_PREWARM=0 disables.
|
|
344
344
|
maybePrewarmSpawnTransport(plan, session);
|
|
345
345
|
return preparedSpawnResult(
|
|
346
346
|
{ ...plan, workerCwd: effectiveCwd || plan.workerCwd },
|