mixdog 0.9.8 → 0.9.10
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
CHANGED
|
@@ -6,29 +6,27 @@ kind: retrieval
|
|
|
6
6
|
|
|
7
7
|
# Role: explorer
|
|
8
8
|
|
|
9
|
-
You are a one-shot locator, not a researcher. You find WHERE, never WHY
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
You are a one-shot locator, not a researcher. You find WHERE, never WHY —
|
|
10
|
+
no understanding code, explaining behaviour, or tracing logic. Coordinates
|
|
11
|
+
are the entire deliverable.
|
|
12
12
|
|
|
13
|
-
Default shape: ONE
|
|
14
|
-
a single `grep`
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
turn means turn 1 under-batched.
|
|
13
|
+
Default shape: ONE maximal-batch turn, then the answer. Fire everything at
|
|
14
|
+
once: a single `grep` whose pattern[] carries ALL literal strings/errors/
|
|
15
|
+
identifier guesses — synonyms, casings, variants — plus `code_graph`/`find`/
|
|
16
|
+
`glob` in the SAME turn when useful. Width is free, turns are not.
|
|
18
17
|
|
|
19
|
-
Answer straight from search output:
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
`dist`/generated hits are leads, not answers: trace them back to source.
|
|
18
|
+
Answer straight from search output: hits already carry `path:line` — never
|
|
19
|
+
spend a turn on `read` to confirm or polish an anchor. `dist`/generated
|
|
20
|
+
hits are leads, not answers: trace them to source.
|
|
23
21
|
|
|
24
|
-
Budget: 5
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
best-so-far
|
|
22
|
+
Budget: 5 turns of maximal batches. Credible `path:line` on screen means the
|
|
23
|
+
search is OVER — answer in that turn; no verifying or collecting extras;
|
|
24
|
+
mark weak anchors `?`. Turns 2-5 exist ONLY for a zero-anchor turn 1: derive
|
|
25
|
+
new tokens from returned paths/names or widen scope, packing ALL candidates
|
|
26
|
+
into the next batch. Concept queries: grep implementation vocabulary
|
|
27
|
+
(file/dir names, symbol fragments, config keys). `EXPLORATION_FAILED` only
|
|
28
|
+
after all 5 turns found zero anchors — giving up early is as wrong as
|
|
29
|
+
over-searching; at turn 5 answer best-so-far.
|
|
32
30
|
|
|
33
31
|
Answer format, nothing else:
|
|
34
32
|
- up to 5 lines: `path:line — symbol/name — short reason` (append `?` if weak)
|
|
@@ -254,6 +254,15 @@ function _codexMetadataBase(entry, { poolKey, cacheKey, sendOpts } = {}) {
|
|
|
254
254
|
turn_id: turnId,
|
|
255
255
|
window_id: windowId,
|
|
256
256
|
request_kind: requestKind,
|
|
257
|
+
// Richer codex turn-metadata fields (responses_metadata.rs:264-280:
|
|
258
|
+
// thread_source "user" per protocol.rs:2751-2765, sandbox label).
|
|
259
|
+
// A/B 2026-07-04 (rvA/rvB interleaved, 24 sessions/arm): no effect
|
|
260
|
+
// (it2 full 3 vs 2, miss 2 vs 3 — noise). Default OFF; keep the knob
|
|
261
|
+
// for future probes if the backend starts gating on payload richness.
|
|
262
|
+
...(process.env.MIXDOG_OAI_TURN_METADATA_RICH === '1' ? {
|
|
263
|
+
thread_source: 'user',
|
|
264
|
+
sandbox: 'read-only',
|
|
265
|
+
} : {}),
|
|
257
266
|
turn_started_at_unix_ms: startedAt,
|
|
258
267
|
};
|
|
259
268
|
const metadata = {
|
|
@@ -54,6 +54,52 @@ const MAX_POOLED_SOCKETS_PER_KEY = 8;
|
|
|
54
54
|
// closing, ephemeral }
|
|
55
55
|
const _wsPool = new Map();
|
|
56
56
|
|
|
57
|
+
// --- Cache-route probe state (2026-07-04 hunt) -----------------------------
|
|
58
|
+
// CF cookie stickiness (codex chatgpt_cloudflare_cookies.rs:22-55 persists
|
|
59
|
+
// __cf_bm/_cfuvid across HTTP clients; our WS handshakes never echo them, so
|
|
60
|
+
// Cloudflare may re-shard every fresh socket). Jar is per-process, keyed by
|
|
61
|
+
// auth account. Env knobs (A/B):
|
|
62
|
+
// MIXDOG_OAI_CF_COOKIES=1 capture Set-Cookie from the 101 upgrade and
|
|
63
|
+
// send Cookie on subsequent handshakes
|
|
64
|
+
// MIXDOG_OAI_SESSION_AFFINITY=1 send x-session-affinity: <cacheKey>
|
|
65
|
+
// (opencode request.ts:187, ws-pool.ts:66)
|
|
66
|
+
// MIXDOG_OAI_WS_URL_SESSION=0 drop the ?session_id= URL query (codex/pi/
|
|
67
|
+
// opencode all use the bare WS URL)
|
|
68
|
+
const _cfCookieJar = new Map(); // accountKey -> { name -> value }
|
|
69
|
+
const _CF_COOKIE_ALLOWLIST = new Set(['__cf_bm', '_cfuvid']);
|
|
70
|
+
|
|
71
|
+
function _envOn(name) {
|
|
72
|
+
const v = String(process.env[name] || '').trim().toLowerCase();
|
|
73
|
+
return ['1', 'true', 'yes', 'on'].includes(v);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function _cfCookieAccountKey(auth) {
|
|
77
|
+
return String(auth?.account_id || auth?.apiKey || 'default');
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function _cfCookieHeader(auth) {
|
|
81
|
+
if (!_envOn('MIXDOG_OAI_CF_COOKIES')) return null;
|
|
82
|
+
const jar = _cfCookieJar.get(_cfCookieAccountKey(auth));
|
|
83
|
+
if (!jar || !jar.size) return null;
|
|
84
|
+
return [...jar.entries()].map(([k, v]) => `${k}=${v}`).join('; ');
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function _cfCookieCapture(auth, setCookieHeaders) {
|
|
88
|
+
if (!_envOn('MIXDOG_OAI_CF_COOKIES')) return;
|
|
89
|
+
const list = Array.isArray(setCookieHeaders) ? setCookieHeaders : (setCookieHeaders ? [setCookieHeaders] : []);
|
|
90
|
+
if (!list.length) return;
|
|
91
|
+
const key = _cfCookieAccountKey(auth);
|
|
92
|
+
let jar = _cfCookieJar.get(key);
|
|
93
|
+
if (!jar) { jar = new Map(); _cfCookieJar.set(key, jar); }
|
|
94
|
+
for (const raw of list) {
|
|
95
|
+
const pair = String(raw || '').split(';', 1)[0];
|
|
96
|
+
const eq = pair.indexOf('=');
|
|
97
|
+
if (eq <= 0) continue;
|
|
98
|
+
const name = pair.slice(0, eq).trim();
|
|
99
|
+
if (_CF_COOKIE_ALLOWLIST.has(name)) jar.set(name, pair.slice(eq + 1).trim());
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
57
103
|
function _getPoolArr(poolKey) {
|
|
58
104
|
if (!poolKey) return null;
|
|
59
105
|
let arr = _wsPool.get(poolKey);
|
|
@@ -200,6 +246,14 @@ function _buildHandshakeHeaders({ auth, sessionToken, turnState, cacheKey: _cach
|
|
|
200
246
|
headers['x-client-request-id'] = randomBytes(16).toString('hex');
|
|
201
247
|
}
|
|
202
248
|
if (turnState) headers['x-codex-turn-state'] = turnState;
|
|
249
|
+
// Probe knobs (cache-route hunt 2026-07-04): see jar block at top of file.
|
|
250
|
+
if (isOpenAiOauth) {
|
|
251
|
+
const jar = _cfCookieHeader(auth);
|
|
252
|
+
if (jar) headers['Cookie'] = jar;
|
|
253
|
+
if (_envOn('MIXDOG_OAI_SESSION_AFFINITY') && (_cacheKey || sessionToken)) {
|
|
254
|
+
headers['x-session-affinity'] = String(_cacheKey || sessionToken);
|
|
255
|
+
}
|
|
256
|
+
}
|
|
203
257
|
return headers;
|
|
204
258
|
}
|
|
205
259
|
|
|
@@ -225,7 +279,17 @@ function _openSocket({ auth, sessionToken, turnState, externalSignal, cacheKey,
|
|
|
225
279
|
if (process.env.MIXDOG_DEBUG_AGENT) {
|
|
226
280
|
process.stderr.write(`[agent-trace] ws-open-start url=${baseUrl} tokenHash=${createHash('sha256').update(String(sessionToken)).digest('hex').slice(0, 8)} ts=${_wsOpenStart}\n`);
|
|
227
281
|
}
|
|
228
|
-
|
|
282
|
+
// Bare WS URL by default (codex/pi/opencode parity). Interleaved A/B
|
|
283
|
+
// (2026-07-04, ivA/ivB, 24 sessions each, alternating rounds to cancel
|
|
284
|
+
// server-time noise): dropping the ?session_id= query improved it1
|
|
285
|
+
// warmup-prefix hits 15/24 -> 22/24 and it2 full hits 11 -> 15 (miss
|
|
286
|
+
// 5 -> 4). The query string seeds CF/backend shard routing away from
|
|
287
|
+
// the header-affine cache node; session identity still rides on the
|
|
288
|
+
// session_id/session-id handshake headers. Re-enable the legacy query
|
|
289
|
+
// form with MIXDOG_OAI_WS_URL_SESSION=1.
|
|
290
|
+
const url = baseUrl + (sessionToken && process.env.MIXDOG_OAI_WS_URL_SESSION === '1'
|
|
291
|
+
? `?session_id=${encodeURIComponent(String(sessionToken))}`
|
|
292
|
+
: '');
|
|
229
293
|
return new Promise((resolve, reject) => {
|
|
230
294
|
let settled = false;
|
|
231
295
|
let abortListener = null;
|
|
@@ -260,6 +324,7 @@ function _openSocket({ auth, sessionToken, turnState, externalSignal, cacheKey,
|
|
|
260
324
|
try {
|
|
261
325
|
const ts = res?.headers?.['x-codex-turn-state'];
|
|
262
326
|
if (typeof ts === 'string' && ts.length) capturedHeaders.turnState = ts;
|
|
327
|
+
_cfCookieCapture(auth, res?.headers?.['set-cookie']);
|
|
263
328
|
// Probe: dump the full 101-upgrade response header set so we can
|
|
264
329
|
// see what the server actually issues (turn-state investigation).
|
|
265
330
|
if (process.env.MIXDOG_WS_UPGRADE_HEADER_PROBE) {
|
|
@@ -15,7 +15,7 @@ export const EXPLORE_TOOL = {
|
|
|
15
15
|
name: 'explore',
|
|
16
16
|
title: 'Explore',
|
|
17
17
|
annotations: { title: 'Explore', readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false },
|
|
18
|
-
description: 'Repo anchor locator
|
|
18
|
+
description: 'Repo anchor locator: broad/uncertain targets, no known path. Array = independent targets.',
|
|
19
19
|
inputSchema: {
|
|
20
20
|
type: 'object',
|
|
21
21
|
properties: {
|
|
@@ -70,7 +70,7 @@ function escapeXml(str) {
|
|
|
70
70
|
// reminder. The full no-verdict contract lives at system level
|
|
71
71
|
// (rules/agent/30-explorer.md).
|
|
72
72
|
export function buildExplorerPrompt(query) {
|
|
73
|
-
return `<query>${escapeXml(query)}</query>\nReminder: coordinates only — WHERE, never WHY.
|
|
73
|
+
return `<query>${escapeXml(query)}</query>\nReminder: coordinates only — WHERE, never WHY. Budget: 5 turns of maximal batches, ideally 1. Turn 1 fires everything at once: one grep whose pattern[] packs ALL token variants, plus code_graph/find/glob in the SAME turn when useful — width is free, turns are not. Answer straight from search output — hits already carry path:line; never read to confirm, polish, or understand. Before every call ask: is a credible anchor already on screen? If yes STOP and answer now, marking weak anchors with ?. EXPLORATION_FAILED only after all 5 turns found zero anchors; at turn 5 answer with best-so-far. Output only anchor lines formatted as path:line — symbol/name — short reason, or EXPLORATION_FAILED. No preamble, bullets, numbering, headings, summary, code quotes, analysis, verdicts, ratings, or recommendations.`;
|
|
74
74
|
}
|
|
75
75
|
|
|
76
76
|
export function normalizeExploreQueries(rawQuery) {
|