import { afterEach, describe, it } from 'node:test'; import assert from 'node:assert/strict'; import { getConnectToken, buildGetChatMessageRequest, decodeFrame, mapFinishReason, resolveFinishReason, classifyUpstreamError, isRetryable, streamChat, getImageFieldTag, getToolDefTags, extractInlineImages, normalizeToolSchema, __setRequestImpl, __testing, mergeToolCallFragment, } from '../src/devin-connect.js'; import { writeStringField, writeVarintField, writeMessageField, parseFields, getField, getAllFields, } from '../src/proto.js'; import { wrapEnvelope, endOfStreamEnvelope } from '../src/connect.js'; import { EventEmitter } from 'node:events'; import { mkdtempSync, rmSync } from 'node:fs'; import { tmpdir } from 'node:os'; import { join } from 'node:path'; const ENV_KEYS = ['DEVIN_CONNECT_TOKEN', 'WINDSURF_API_KEY', 'DEVIN_CONNECT_IMAGE_TAG', 'DEVIN_CONNECT_IMAGE_INNER_TAGS', 'DEVIN_CONNECT_TOOL_DEF_TAGS', 'DEVIN_CONNECT_REPLAY_REASONING', 'DEVIN_CONNECT_COLLAPSE_SYSTEM']; const originalEnv = Object.fromEntries(ENV_KEYS.map(k => [k, process.env[k]])); afterEach(() => { for (const k of ENV_KEYS) { if (originalEnv[k] === undefined) delete process.env[k]; else process.env[k] = originalEnv[k]; } }); const TOKEN = 'devin-session-token$test.jwt.sig'; describe('getConnectToken', () => { it('prefers DEVIN_CONNECT_TOKEN over WINDSURF_API_KEY', () => { assert.equal( getConnectToken({ DEVIN_CONNECT_TOKEN: 'a', WINDSURF_API_KEY: 'b' }), 'a', ); }); it('falls back to WINDSURF_API_KEY', () => { assert.equal(getConnectToken({ WINDSURF_API_KEY: 'b' }), 'b'); }); it('returns empty string when neither is set', () => { assert.equal(getConnectToken({}), ''); }); }); describe('generateFingerprint', () => { it('produces 732 hex chars (the server-required length)', () => { const fp = __testing.generateFingerprint(); assert.equal(fp.length, 732); assert.match(fp, /^[0-9a-f]{732}$/); }); it('is random per call', () => { assert.notEqual(__testing.generateFingerprint(), __testing.generateFingerprint()); }); }); describe('messageText', () => { it('passes strings through', () => { assert.equal(__testing.messageText('hi'), 'hi'); }); it('joins text parts of array content', () => { assert.equal( __testing.messageText([{ type: 'text', text: 'a' }, { type: 'image' }, { type: 'text', text: 'b' }]), 'a\nb', ); }); it('handles null', () => { assert.equal(__testing.messageText(null), ''); }); }); describe('buildGetChatMessageRequest', () => { it('throws without a token', () => { assert.throws(() => buildGetChatMessageRequest({ model: 'm', messages: [] }), /session token/); }); it('throws without a model', () => { assert.throws(() => buildGetChatMessageRequest({ token: TOKEN, messages: [] }), /model selector/); }); it('encodes the calibrated top-level field shape', () => { const proto = buildGetChatMessageRequest({ token: TOKEN, model: 'swe-1-6-slow', messages: [ { role: 'system', content: 'be nice' }, { role: 'user', content: 'hello' }, ], }); const fields = parseFields(proto); // #1 ClientMetadata (message), #2 system_prompt (string), #3 ChatMessage, // #7 mode varint, #8 CompletionConfig, #15 ModelConfig, #16 session id, // #20 varint, #21 model selector. assert.ok(getField(fields, 1, 2), 'has ClientMetadata #1'); assert.equal(getField(fields, 2, 2).value.toString('utf8'), 'be nice'); assert.equal(getField(fields, 7, 0).value, 5); assert.ok(getField(fields, 8, 2), 'has CompletionConfig #8'); assert.ok(getField(fields, 15, 2), 'has ModelConfig #15'); assert.ok(getField(fields, 16, 2), 'has session id #16'); assert.equal(getField(fields, 20, 0).value, 1); assert.equal(getField(fields, 21, 2).value.toString('utf8'), 'swe-1-6-slow'); // #22 request_id — MUST BE ABSENT. Re-calibrated from the full capture set: // the verified turn-1 wire (req009) carries no #22; it only appears turn 2+ // as a reused user-exchange id. The gateway is stateless (turn-1 every // request), so it must not emit a fabricated random #22 (see buildGet…Request). assert.ok(!getField(fields, 22, 2), '#22 request_id is absent on a turn-1 request'); }); // ★ 2026-08-05: ModelConfig #15 parity with genuine devin.exe. Captures show // #15.1 stable per session and #15.2 monotonic; the stateless default stays // {fresh uuid, 1, 4} (turn-1 wire req009). sessionModelConfig opts into the // stable shape when session-continuity resolved a session (DEVIN_CONNECT_ // MODEL_CONFIG_STABLE). it('ModelConfig #15 stateless default: fresh uuid, turn 1, const 4', () => { const proto = buildGetChatMessageRequest({ token: TOKEN, model: 'm', messages: [{ role: 'user', content: 'hi' }] }); const sub = parseFields(getField(parseFields(proto), 15, 2).value); assert.match(getField(sub, 1, 2).value.toString('utf8'), /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i, '#15.1 is a uuid by default'); assert.equal(getField(sub, 2, 0).value, 1, '#15.2 defaults to turn 1'); assert.equal(getField(sub, 3, 0).value, 4, '#15.3 stays the calibrated constant 4'); }); it('ModelConfig #15 rides devin.exe shape when sessionModelConfig is passed', () => { const proto = buildGetChatMessageRequest({ token: TOKEN, model: 'm', messages: [{ role: 'user', content: 'hi' }], sessionModelConfig: { id: 'cfg-stable-session-1', turn: 7 }, }); const sub = parseFields(getField(parseFields(proto), 15, 2).value); assert.equal(getField(sub, 1, 2).value.toString('utf8'), 'cfg-stable-session-1', '#15.1 carries the stable session config id'); assert.equal(getField(sub, 2, 0).value, 7, '#15.2 carries the session turn counter'); assert.equal(getField(sub, 3, 0).value, 4, '#15.3 unchanged'); }); // ★ 2026-08-05: T1 reasoning continuity — the checkpoint block rides as a // system-prompt suffix inside tag #2. Byte-compatible: only longer. it('continuityTrail appends to the system prompt inside #2', () => { const trail = '\n\n[Continuity checkpoint — prior analysis trace, may be stale]\nr1\n[End]'; const proto = buildGetChatMessageRequest({ token: TOKEN, model: 'm', messages: [{ role: 'system', content: 'BASE SYSTEM' }, { role: 'user', content: 'hi' }], continuityTrail: trail, }); const sys = getField(parseFields(proto), 2, 2).value.toString('utf8'); assert.ok(sys.startsWith('BASE SYSTEM'), 'client system kept verbatim'); assert.ok(sys.endsWith('[End]'), 'trail appended after the client system'); assert.ok(sys.includes('[Continuity checkpoint')); }); it('without continuityTrail the system prompt is byte-identical to pre-feature', () => { const proto = buildGetChatMessageRequest({ token: TOKEN, model: 'm', messages: [{ role: 'system', content: 'BASE SYSTEM' }, { role: 'user', content: 'hi' }], }); assert.equal(getField(parseFields(proto), 2, 2).value.toString('utf8'), 'BASE SYSTEM'); }); // ★ 2026-07-10: empty-system + tools guard. Verified from live devin.exe capture // + boundary experiment: Devin's upstream returns "internal error occurred" for a // Claude-family request that declares tools (#10) but has an EMPTY/absent system // prompt (#2). A single char of system is enough to pass. We inject a minimal // system when tools are present and system is empty. it('injects a non-empty system #2 when tools are present but no system given', () => { const proto = buildGetChatMessageRequest({ token: TOKEN, model: 'claude-opus-4-8-medium', messages: [{ role: 'user', content: 'hi' }], tools: [{ type: 'function', function: { name: 'edit', description: 'edit', parameters: { type: 'object', properties: {} } } }], nativeToolCall: true, }); const f2 = getField(parseFields(proto), 2, 2); assert.ok(f2 && f2.value.length > 0, '#2 system_prompt is non-empty when tools present'); }); it('does NOT inject a system when no tools (empty system stays empty)', () => { const proto = buildGetChatMessageRequest({ token: TOKEN, model: 'claude-opus-4-8-medium', messages: [{ role: 'user', content: 'hi' }], }); const f2 = getField(parseFields(proto), 2, 2); // no system + no tools → #2 empty (length 0) or absent; must NOT fabricate one assert.ok(!f2 || f2.value.length === 0, '#2 stays empty when no tools and no system'); }); it('preserves a caller-supplied system verbatim even with tools', () => { const proto = buildGetChatMessageRequest({ token: TOKEN, model: 'claude-opus-4-8-medium', messages: [{ role: 'system', content: 'be nice' }, { role: 'user', content: 'hi' }], tools: [{ type: 'function', function: { name: 'edit', description: 'edit', parameters: { type: 'object', properties: {} } } }], nativeToolCall: true, }); assert.equal(getField(parseFields(proto), 2, 2).value.toString('utf8'), 'be nice'); }); // ★ 2026-07-13: native ToolDef descriptions are replaced with the tool name. // Live A/B against Cursor's real 21-tool inventory proved upstream fingerprints // both top-level and parameter descriptions as an "MCP configuration issue". // Name, schema structure, types, required fields and enums remain native. it('replaces a very long tool description with the name in #10 ToolDef', () => { const longDesc = 'x'.repeat(1200); const proto = buildGetChatMessageRequest({ token: TOKEN, model: 'claude-opus-4-8-medium', messages: [{ role: 'system', content: 'sys' }, { role: 'user', content: 'hi' }], tools: [{ type: 'function', function: { name: 'edit', description: longDesc, parameters: { type: 'object', properties: {} } } }], nativeToolCall: true, }); const fields = parseFields(proto); const td = getField(fields, 10, 2); assert.ok(td, 'has #10 ToolDef'); const inner = parseFields(td.value); const desc = getField(inner, 2, 2).value.toString('utf8'); assert.equal(desc, 'edit'); // name (#1) still intact assert.equal(getField(inner, 1, 2).value.toString('utf8'), 'edit'); }); it('replaces a short tool description with the name', () => { const proto = buildGetChatMessageRequest({ token: TOKEN, model: 'claude-opus-4-8-medium', messages: [{ role: 'system', content: 'sys' }, { role: 'user', content: 'hi' }], tools: [{ type: 'function', function: { name: 'edit', description: 'edit a file', parameters: { type: 'object', properties: {} } } }], nativeToolCall: true, }); const inner = parseFields(getField(parseFields(proto), 10, 2).value); assert.equal(getField(inner, 2, 2).value.toString('utf8'), 'edit'); }); it('embeds the SINGLE token in ClientMetadata #3 (header doubling is separate)', () => { const proto = buildGetChatMessageRequest({ token: TOKEN, model: 'm', messages: [{ role: 'user', content: 'x' }], }); const meta = parseFields(getField(parseFields(proto), 1, 2).value); assert.equal(getField(meta, 3, 2).value.toString('utf8'), TOKEN); }); it('uses a 732-hex fingerprint in ClientMetadata #31', () => { const proto = buildGetChatMessageRequest({ token: TOKEN, model: 'm', messages: [{ role: 'user', content: 'x' }], }); const meta = parseFields(getField(parseFields(proto), 1, 2).value); const fp = getField(meta, 31, 2).value.toString('utf8'); assert.equal(fp.length, 732); }); it('emits one ChatMessage per non-system turn with the right source enum', () => { const proto = buildGetChatMessageRequest({ token: TOKEN, model: 'm', messages: [ { role: 'user', content: 'q1' }, { role: 'assistant', content: 'a1' }, { role: 'user', content: 'q2' }, ], }); const chats = getAllFields(parseFields(proto), 3).filter(f => f.wireType === 2); assert.equal(chats.length, 3); const sources = chats.map(c => getField(parseFields(c.value), 2, 0).value); assert.deepEqual(sources, [__testing.SOURCE.USER, __testing.SOURCE.ASSISTANT, __testing.SOURCE.USER]); }); it('folds tool turns into user-visible text', () => { const proto = buildGetChatMessageRequest({ token: TOKEN, model: 'm', messages: [{ role: 'tool', tool_call_id: 'call_7', content: '42' }], }); const chat = getAllFields(parseFields(proto), 3).find(f => f.wireType === 2); const text = getField(parseFields(chat.value), 3, 2).value.toString('utf8'); assert.match(text, /tool result for call_7/); assert.match(text, /42/); }); // Same-source text runs: a client history that splits one turn into several // same-role entries produces consecutive same-source ChatMessages on the wire, // and the upstream validator rejects a run of length >= 3 with // invalid_argument. The builder merges text-only same-role runs before // encoding; structured entries (tool_calls / tool_call_id / reasoning / // images) are never merged. it('merges a consecutive same-role text-only run into one ChatMessage', () => { const proto = buildGetChatMessageRequest({ token: TOKEN, model: 'm', messages: [ { role: 'user', content: 'q1' }, { role: 'assistant', content: 'a1' }, { role: 'assistant', content: 'a2' }, { role: 'assistant', content: 'a3' }, { role: 'user', content: 'q2' }, { role: 'user', content: 'q2b' }, ], }); const chats = getAllFields(parseFields(proto), 3).filter((f) => f.wireType === 2); const sources = chats.map((c) => getField(parseFields(c.value), 2, 0).value); // 6 text entries -> 3 wire turns; no same-source run survives. assert.deepEqual(sources, [__testing.SOURCE.USER, __testing.SOURCE.ASSISTANT, __testing.SOURCE.USER]); const merged = getField(parseFields(chats[1].value), 3, 2).value.toString('utf8'); assert.equal(merged, 'a1\n\na2\n\na3'); }); it('never merges entries carrying tool_calls / tool_call_id / reasoning', () => { const proto = buildGetChatMessageRequest({ token: TOKEN, model: 'm', nativeToolCall: true, env: { DEVIN_CONNECT_REPLAY_REASONING: '1' }, messages: [ { role: 'assistant', content: '', tool_calls: [{ id: 'call_1', function: { name: 'bash', arguments: '{}' } }] }, { role: 'tool', tool_call_id: 'call_1', content: 'done' }, { role: 'assistant', content: 'a3', reasoning: 'r3' }, { role: 'assistant', content: 'a4' }, ], }); const chats = getAllFields(parseFields(proto), 3).filter((f) => f.wireType === 2); const sources = chats.map((c) => getField(parseFields(c.value), 2, 0).value); // The tool_call entry, the tool result, and the reasoning entry are all // non-mergeable — 'a4' is mergeable but its neighbour ('a3', reasoning) // is not, so nothing collapses. assert.deepEqual(sources, [ __testing.SOURCE.ASSISTANT, __testing.SOURCE.TOOL_RESULT, __testing.SOURCE.ASSISTANT, __testing.SOURCE.ASSISTANT, ]); assert.ok(getField(parseFields(chats[0].value), 6, 2), 'tool_call entry keeps #6'); assert.ok(getField(parseFields(chats[1].value), 7, 2), 'tool result keeps #7 tool_call_id'); assert.ok(getField(parseFields(chats[2].value), 11, 2), 'reasoning entry keeps #11'); assert.equal(getField(parseFields(chats[3].value), 3, 2).value.toString('utf8'), 'a4', 'a4 stays its own turn'); }); it('does not merge a tool_calls assistant into the following same-role text', () => { // The previous test's tool_calls neighbour is role:tool, so deleting the // tool_calls half of isMergeableText would still go green. This pair is // same-role: if that guard vanished, 'pre' and 'post' would collapse and // the #6 would ride a merged text turn. const proto = buildGetChatMessageRequest({ token: TOKEN, model: 'm', nativeToolCall: true, messages: [ { role: 'assistant', content: 'pre', tool_calls: [{ id: 'call_1', function: { name: 'bash', arguments: '{}' } }] }, { role: 'assistant', content: 'post' }, ], }); const chats = getAllFields(parseFields(proto), 3).filter((f) => f.wireType === 2); const sources = chats.map((c) => getField(parseFields(c.value), 2, 0).value); // Encoder emits leading text, then a separate #6 frame per tool_call. // If isMergeableText dropped the tool_calls check, 'pre' and 'post' would // collapse first and the wire would be text='pre\n\npost' plus #6 (2 frames). assert.deepEqual(sources, [ __testing.SOURCE.ASSISTANT, __testing.SOURCE.ASSISTANT, __testing.SOURCE.ASSISTANT, ]); assert.equal(getField(parseFields(chats[0].value), 3, 2).value.toString('utf8'), 'pre'); assert.ok(getField(parseFields(chats[1].value), 6, 2), 'tool_calls stay on their own #6 frame'); assert.equal(getField(parseFields(chats[2].value), 3, 2).value.toString('utf8'), 'post'); }); it('does not merge consecutive image_url user turns', () => { const proto = buildGetChatMessageRequest({ token: TOKEN, model: 'm', env: { DEVIN_CONNECT_IMAGE_TAG: '10' }, messages: [ { role: 'user', content: [{ type: 'image_url', image_url: { url: `data:image/png;base64,${RED_DOT}` } }] }, { role: 'user', content: [{ type: 'image_url', image_url: { url: `data:image/png;base64,${RED_DOT}` } }] }, ], }); const chats = getAllFields(parseFields(proto), 3).filter((f) => f.wireType === 2); assert.equal(chats.length, 2, 'two image turns stay two ChatMessages'); assert.equal(getAllFields(parseFields(chats[0].value), 10).length, 1); assert.equal(getAllFields(parseFields(chats[1].value), 10).length, 1); }); it('looks past system turns when judging same-source adjacency', () => { const proto = buildGetChatMessageRequest({ token: TOKEN, model: 'm', messages: [ { role: 'assistant', content: 'a1' }, { role: 'system', content: 'mid-conversation system' }, { role: 'assistant', content: 'a2' }, { role: 'user', content: 'q' }, ], }); const chats = getAllFields(parseFields(proto), 3).filter((f) => f.wireType === 2); const sources = chats.map((c) => getField(parseFields(c.value), 2, 0).value); // system hoists to #2, so the two assistant texts are wire-adjacent and merge. assert.deepEqual(sources, [__testing.SOURCE.ASSISTANT, __testing.SOURCE.USER]); assert.equal(getField(parseFields(chats[0].value), 3, 2).value.toString('utf8'), 'a1\n\na2'); }); it('does not mutate the caller messages array', () => { const messages = [ { role: 'user', content: 'q1' }, { role: 'user', content: 'q2' }, ]; buildGetChatMessageRequest({ token: TOKEN, model: 'm', messages }); assert.equal(messages.length, 2); assert.equal(messages[0].content, 'q1'); assert.equal(messages[1].content, 'q2'); }); it('drops empty assistant turns without tool_calls but keeps ones with tool_calls', () => { const proto = buildGetChatMessageRequest({ token: TOKEN, model: 'm', messages: [ { role: 'user', content: 'hello' }, { role: 'assistant', content: ' ' }, { role: 'assistant', content: '', tool_calls: [{ id: 'tc1', name: 'bash', arguments: '{}' }] }, ], }); const chats = getAllFields(parseFields(proto), 3).filter((f) => f.wireType === 2); // User message + assistant message with tool calls = 2 messages (empty assistant dropped) assert.equal(chats.length, 2); }); it('concatenates multiple system turns', () => { const proto = buildGetChatMessageRequest({ token: TOKEN, model: 'm', messages: [ { role: 'system', content: 'a' }, { role: 'system', content: 'b' }, { role: 'user', content: 'x' }, ], }); assert.equal(getField(parseFields(proto), 2, 2).value.toString('utf8'), 'a\nb'); }); it('honours CompletionConfig overrides', () => { const proto = buildGetChatMessageRequest({ token: TOKEN, model: 'm', messages: [{ role: 'user', content: 'x' }], completion: { maxTokens: 256 }, }); const comp = parseFields(getField(parseFields(proto), 8, 2).value); assert.equal(getField(comp, 2, 0).value, 256); // #2 = max_tokens }); it('forwards all sampling controls (temperature/top_p/top_k/max_tokens)', () => { const proto = buildGetChatMessageRequest({ token: TOKEN, model: 'm', messages: [{ role: 'user', content: 'x' }], completion: { maxTokens: 512, temperature: 0.7, topP: 0.5, topK: 100 }, }); const comp = parseFields(getField(parseFields(proto), 8, 2).value); assert.equal(getField(comp, 2, 0).value, 512); // max_tokens (#2) assert.equal(getField(comp, 7, 0).value, 100); // top_k assert.ok(Math.abs(getField(comp, 5, 1).value.readDoubleLE(0) - 0.7) < 1e-9); // temperature assert.ok(Math.abs(getField(comp, 8, 1).value.readDoubleLE(0) - 0.5) < 1e-9); // top_p }); it('clamps temperature=0 to the epsilon floor (upstream rejects exact 0)', () => { // LIVE-VERIFIED: temperature=0 → upstream "internal error". A caller asking // for greedy decoding must get the nearest working value, not a hard failure. const proto = buildGetChatMessageRequest({ token: TOKEN, model: 'm', messages: [{ role: 'user', content: 'x' }], completion: { temperature: 0 }, }); const comp = parseFields(getField(parseFields(proto), 8, 2).value); const temp = getField(comp, 5, 1).value.readDoubleLE(0); assert.ok(temp > 0 && temp <= 0.001, `expected clamped epsilon, got ${temp}`); }); describe('DEVIN_CONNECT_REPLAY_REASONING probe gate', () => { const messages = [ { role: 'user', content: 'user Q' }, { role: 'assistant', content: 'thought text', reasoning: 'thinking 123' }, { role: 'assistant', content: '', reasoning_content: 'thinking 456', tool_calls: [{ id: 'tc1', name: 'bash', arguments: '{}' }] }, ]; it('gate unset/off: does not emit reasoning tags on assistant turns', () => { delete process.env.DEVIN_CONNECT_REPLAY_REASONING; const proto = buildGetChatMessageRequest({ token: TOKEN, model: 'm', messages, nativeToolCall: true, }); const chats = getAllFields(parseFields(proto), 3).filter((f) => f.wireType === 2); for (const chat of chats) { const inner = parseFields(chat.value); assert.ok(!getField(inner, 11, 2), 'no tag #11'); assert.ok(!getField(inner, 9, 2), 'no tag #9'); } }); it('gate=1: emits tag #11 with reasoning text on assistant turns, user turns clean', () => { process.env.DEVIN_CONNECT_REPLAY_REASONING = '1'; const proto = buildGetChatMessageRequest({ token: TOKEN, model: 'm', messages, nativeToolCall: true, }); const chats = getAllFields(parseFields(proto), 3).filter((f) => f.wireType === 2); // chat[0]: user message const userInner = parseFields(chats[0].value); assert.equal(getField(userInner, 2, 0).value, 1); // SOURCE.USER assert.ok(!getField(userInner, 11, 2), 'user turn has no #11'); // chat[1]: assistant text turn with reasoning const astTextInner = parseFields(chats[1].value); assert.equal(getField(astTextInner, 2, 0).value, 2); // SOURCE.ASSISTANT assert.equal(getField(astTextInner, 11, 2).value.toString('utf8'), 'thinking 123'); // chat[2]: assistant native tool call turn with reasoning const astToolInner = parseFields(chats[2].value); assert.equal(getField(astToolInner, 2, 0).value, 2); // SOURCE.ASSISTANT assert.equal(getField(astToolInner, 11, 2).value.toString('utf8'), 'thinking 456'); }); it('gate=9: emits tag #9 for negative control RE probes', () => { process.env.DEVIN_CONNECT_REPLAY_REASONING = '9'; const proto = buildGetChatMessageRequest({ token: TOKEN, model: 'm', messages, nativeToolCall: true, }); const chats = getAllFields(parseFields(proto), 3).filter((f) => f.wireType === 2); const astTextInner = parseFields(chats[1].value); assert.ok(!getField(astTextInner, 11, 2), 'no tag #11 when gate=9'); assert.equal(getField(astTextInner, 9, 2).value.toString('utf8'), 'thinking 123'); }); }); }); describe('decodeFrame', () => { it('reads the final answer from field #3 (content)', () => { const payload = Buffer.concat([ writeStringField(1, 'bot-123'), writeStringField(3, 'the answer'), writeStringField(9, 'thinking...'), writeStringField(17, 'uuid'), ]); const d = decodeFrame(payload); assert.equal(d.content, 'the answer'); assert.equal(d.reasoning, 'thinking...'); }); it('does not confuse the nested #7.#9 model name with top-level #9 reasoning', () => { // #7 metadata carries its own #9 (model name); only top-level #9 is reasoning. const meta = Buffer.concat([writeVarintField(6, 6), writeStringField(9, 'swe-1-6-slow')]); const payload = Buffer.concat([ writeStringField(1, 'bot-123'), writeMessageField(7, meta), ]); const d = decodeFrame(payload); assert.equal(d.reasoning, ''); assert.equal(d.content, ''); }); it('reads token usage from the terminal #7 metadata frame', () => { const meta = Buffer.concat([ writeVarintField(2, 386), // prompt_tokens writeVarintField(3, 48), // completion_tokens writeVarintField(6, 6), ]); const payload = Buffer.concat([writeStringField(1, 'bot-1'), writeMessageField(7, meta)]); const d = decodeFrame(payload); assert.deepEqual(d.usage, { prompt: 386, completion: 48 }); }); it('omits usage when completion_tokens is absent (non-terminal frame)', () => { const meta = Buffer.concat([writeVarintField(2, 386), writeVarintField(6, 6)]); const payload = Buffer.concat([writeStringField(1, 'bot-1'), writeMessageField(7, meta)]); assert.equal(decodeFrame(payload).usage, null); }); it('billing is null by default (no tag map configured)', () => { // The whole groundwork is opt-in: without DEVIN_CONNECT_BILLING_TAGS, even a // frame that happens to carry billing varints must NOT surface them — zero // regression on free tier / un-calibrated deployments. const meta = Buffer.concat([ writeVarintField(2, 386), writeVarintField(3, 48), writeVarintField(6, 250), // a value that, IF mis-parsed as billing, would show ]); const payload = Buffer.concat([writeStringField(1, 'bot-1'), writeMessageField(7, meta)]); assert.equal(decodeFrame(payload).billing, null); }); it('parses billing varints from the #7 metadata sub-message when tags are pinned', () => { // Operator calibrated: credit_cost=#10, committed_credit_cost=#11, committed_acu_cost=#12. const billingTags = { credit_cost: 10, committed_credit_cost: 11, committed_acu_cost: 12 }; const meta = Buffer.concat([ writeVarintField(2, 386), writeVarintField(3, 48), writeVarintField(10, 1500), // credit_cost writeVarintField(11, 1400), // committed_credit_cost writeVarintField(12, 3), // committed_acu_cost ]); const payload = Buffer.concat([writeStringField(1, 'bot-1'), writeMessageField(7, meta)]); const d = decodeFrame(payload, { billingTags }); assert.deepEqual(d.billing, { credit_cost: 1500, committed_credit_cost: 1400, committed_acu_cost: 3 }); // usage still decodes alongside billing assert.deepEqual(d.usage, { prompt: 386, completion: 48 }); }); it('routes cache_*_tokens into usage (not billing) when their tags are pinned', () => { // cache_read_tokens / cache_write_tokens are ModelUsageStats fields → they // belong in usage, not billing. Same opt-in tag mechanism as cost fields. const tags = { cache_read_tokens: 14, cache_write_tokens: 15, credit_cost: 10 }; const meta = Buffer.concat([ writeVarintField(2, 386), writeVarintField(3, 48), writeVarintField(10, 1500), // credit_cost → billing writeVarintField(14, 1200), // cache_read_tokens → usage writeVarintField(15, 64), // cache_write_tokens → usage ]); const payload = Buffer.concat([writeStringField(1, 'bot-1'), writeMessageField(7, meta)]); const d = decodeFrame(payload, { billingTags: tags }); assert.deepEqual(d.usage, { prompt: 386, completion: 48, cache_read_tokens: 1200, cache_write_tokens: 64 }); assert.deepEqual(d.billing, { credit_cost: 1500 }); }); it('dumpMeta exposes every metadata varint subfield for tag calibration', () => { // The DEVIN_CONNECT_DEBUG_META hook: surfaces {tag: value} for every varint // in the #7 sub-message so an operator can discover unknown tags from a real // capture. Off unless requested; never affects normal decode output. const meta = Buffer.concat([ writeVarintField(2, 386), writeVarintField(3, 48), writeVarintField(6, 6), writeVarintField(14, 1200), ]); const payload = Buffer.concat([writeStringField(1, 'bot-1'), writeMessageField(7, meta)]); assert.equal(decodeFrame(payload).metaDump, undefined); // off by default const d = decodeFrame(payload, { dumpMeta: true }); assert.deepEqual(d.metaDump, { 2: 386, 3: 48, 6: 6, 14: 1200 }); }); it('decodes actual_model_uid from #7.9 (nested in metadata) only when its tag is pinned', () => { // FRAME-VERIFIED 2026-07-05 (paid opus-4-8): actual_model_uid rides the #7 // metadata sub-message at INNER tag 9, NOT a top-level field. Opt-in via // DEVIN_CONNECT_ACTUAL_MODEL_TAG (calibrated value = 9). const meta = Buffer.concat([ writeVarintField(2, 777), // prompt_tokens writeVarintField(3, 180), // completion_tokens writeStringField(9, 'claude-opus-4-8-medium'), // actual_model_uid at #7.9 ]); const payload = Buffer.concat([ writeStringField(1, 'bot-1'), writeMessageField(7, meta), ]); assert.equal(decodeFrame(payload).actualModel, undefined); // off by default assert.equal(decodeFrame(payload, { actualModelTag: 9 }).actualModel, 'claude-opus-4-8-medium'); // wrong inner tag → nothing surfaced assert.equal(decodeFrame(payload, { actualModelTag: 99 }).actualModel, undefined); }); it('coalesces native tool_call arguments fragmented across frames (#6.3)', () => { // FRAME-VERIFIED 2026-07-05: one logical call streams as {id,name} then // id-less argument fragments. Merging must reconstruct the full JSON. const acc = []; mergeToolCallFragment(acc, { id: 'toolu_1', name: 'grep_repo' }); mergeToolCallFragment(acc, { arguments: '{"patter' }); mergeToolCallFragment(acc, { arguments: 'n": "DEV' }); mergeToolCallFragment(acc, { arguments: 'IN_CONNECT"}' }); assert.equal(acc.length, 1); assert.deepEqual(acc[0], { id: 'toolu_1', name: 'grep_repo', arguments: '{"pattern": "DEVIN_CONNECT"}' }); assert.equal(JSON.parse(acc[0].arguments).pattern, 'DEVIN_CONNECT'); }); it('coalesce keeps distinct tool_calls separate (each new id starts a call)', () => { const acc = []; mergeToolCallFragment(acc, { id: 'a', name: 'read_file', arguments: '{"p":' }); mergeToolCallFragment(acc, { arguments: '"1"}' }); mergeToolCallFragment(acc, { id: 'b', name: 'grep_repo', arguments: '{"q":"x"}' }); assert.equal(acc.length, 2); assert.deepEqual(acc[0], { id: 'a', name: 'read_file', arguments: '{"p":"1"}' }); assert.deepEqual(acc[1], { id: 'b', name: 'grep_repo', arguments: '{"q":"x"}' }); }); it('dumpMeta also surfaces top-level frame fields (e.g. actual_model_uid)', () => { // Top-level string fields like actual_model_uid (the concrete model that // served a router request) are discoverable via the same hook. const payload = Buffer.concat([ writeStringField(1, 'bot-1'), writeStringField(11, 'claude-opus-4-8'), // pretend actual_model_uid at #11 writeVarintField(5, 2), // stop_reason ]); assert.equal(decodeFrame(payload).frameDump, undefined); // off by default const d = decodeFrame(payload, { dumpMeta: true }); assert.equal(d.frameDump[11], 'claude-opus-4-8'); assert.equal(d.frameDump[5], 2); // binary / oversized fields are not stringified into the dump const big = Buffer.concat([writeStringField(1, 'x'.repeat(100))]); assert.equal(decodeFrame(big, { dumpMeta: true }).frameDump?.[1], undefined); }); it('dumpMeta recursively decodes inner fields of non-printable top-level sub-messages (#28 calibration)', () => { // The recurring #28 trailer is a 186b usage/billing/stop-metadata block the // flat frameDump could only mark "". subDump exposes its inner // {tag: {kind, preview}} so `calibrate:devin` surfaces the guts in one run. const trailer = Buffer.concat([ writeStringField(1, 'stop'), // inner string → stop-reason / model-id candidate writeVarintField(3, 1200), // inner varint → billing/usage candidate writeVarintField(4, 34), // inner varint → billing/usage candidate ]); const payload = Buffer.concat([writeStringField(1, 'bot-1'), writeMessageField(28, trailer)]); assert.equal(decodeFrame(payload).subDump, undefined); // off by default const d = decodeFrame(payload, { dumpMeta: true }); // presence still marked in the flat dump (contract unchanged) assert.match(String(d.frameDump[28]), /^$/); // inner fields now decoded under subDump keyed by the top-level tag assert.deepEqual(d.subDump[28][1], { kind: 'string', preview: 'stop' }); assert.deepEqual(d.subDump[28][3], { kind: 'varint', preview: 1200 }); assert.deepEqual(d.subDump[28][4], { kind: 'varint', preview: 34 }); }); it('subDump recurses one level deeper into nested messages (#28.2 Response Statistics counters)', () => { // PAID-1 2026-07-03 capture: #28 is a "Response Statistics" container whose // real usage/billing counters live in a NESTED message at #28.2, one level // below the flat decode. subDump must descend and attach them under `.fields`. const stats = Buffer.concat([ writeVarintField(3, 1200), // e.g. completion tokens writeVarintField(4, 34), // e.g. credit_cost ]); const trailer = Buffer.concat([ writeStringField(1, 'Response Statistics'), // label string writeMessageField(2, stats), // nested stats message ]); const payload = Buffer.concat([writeStringField(1, 'bot-1'), writeMessageField(28, trailer)]); const d = decodeFrame(payload, { dumpMeta: true }); assert.deepEqual(d.subDump[28][1], { kind: 'string', preview: 'Response Statistics' }); // #28.2 marked as a message AND its inner counters decoded under .fields assert.equal(d.subDump[28][2].kind, 'message'); assert.deepEqual(d.subDump[28][2].fields[3], { kind: 'varint', preview: 1200 }); assert.deepEqual(d.subDump[28][2].fields[4], { kind: 'varint', preview: 34 }); }); it('subDump retains the FULL raw-hex of every inner sub-message (D1: single-capture offline tag recovery)', () => { // The 48-char preview alone dropped the tail of #28.2's counter block on the // last capture. Retaining complete raw-hex means one text-only PAID capture is // enough to reverse ALL inner tags offline — no per-field probe loop. const stats = Buffer.concat([ writeVarintField(3, 1200), writeVarintField(4, 34), ]); const trailer = Buffer.concat([ writeStringField(1, 'Response Statistics'), writeMessageField(2, stats), ]); const payload = Buffer.concat([writeStringField(1, 'bot-1'), writeMessageField(28, trailer)]); const d = decodeFrame(payload, { dumpMeta: true }); // the nested #28.2 message node carries the exact bytes, losslessly assert.equal(d.subDump[28][2].raw, stats.toString('hex')); // and the raw round-trips back to the same fields (offline re-decode works) assert.ok(d.subDump[28][2].raw.length > 0); assert.equal(Buffer.from(d.subDump[28][2].raw, 'hex').toString('hex'), stats.toString('hex')); }); it('subDump recursion is depth-capped so a deeply nested / adversarial blob cannot recurse unbounded', () => { // Build 6 levels of nesting; SUB_DUMP_MAX_DEPTH (4) must stop decoding before // the deepest, leaving it as a presence-only "" with no `.fields`. let buf = Buffer.concat([writeVarintField(1, 7)]); for (let i = 0; i < 6; i++) buf = Buffer.concat([writeMessageField(2, buf)]); const payload = Buffer.concat([writeStringField(1, 'bot-1'), writeMessageField(28, buf)]); const d = decodeFrame(payload, { dumpMeta: true }); // walk down .fields; at some point a message node must lack `.fields` (capped) let node = d.subDump[28][2]; let depth = 1; while (node && node.fields && node.fields[2]) { node = node.fields[2]; depth++; } assert.ok(depth <= 4, `recursion capped at <=4 levels, got ${depth}`); }); it('subDump skips a sub-message that is not valid protobuf (opaque encrypted blob) without throwing', () => { // An opaque/encrypted trailer must never crash the hot decode path — it is // silently left as presence-only in the flat dump. const opaque = Buffer.from([0xff, 0xff, 0xff, 0x07, 0x80]); // not parseable as fields const payload = Buffer.concat([writeStringField(1, 'bot-1'), writeMessageField(28, opaque)]); const d = decodeFrame(payload, { dumpMeta: true }); assert.match(String(d.frameDump[28]), /^$/); // presence noted assert.equal(d.subDump?.[28], undefined); // inner not decoded, no throw }); it('billing only includes keys whose tags are actually present in the frame', () => { // A free / partially-billed turn omits zero-valued fields entirely; decode // must surface only what's on the wire, never invent zeros. const billingTags = { credit_cost: 10, committed_credit_cost: 11, committed_acu_cost: 12 }; const meta = Buffer.concat([ writeVarintField(2, 386), writeVarintField(3, 48), writeVarintField(11, 1400), // only committed_credit_cost present ]); const payload = Buffer.concat([writeStringField(1, 'bot-1'), writeMessageField(7, meta)]); assert.deepEqual(decodeFrame(payload, { billingTags }).billing, { committed_credit_cost: 1400 }); }); it('parseBillingTagMap: defaults to cache_read_tokens=5 + cache_write_tokens=4, parses pairs, rejects garbage', () => { const { parseBillingTagMap } = __testing; // Unset → the calibrated defaults (#220 + 2026-07-25): // tag 5 = cache_read (confirmed on GPT+Claude paid accounts) // tag 4 = cache_write (confirmed on Claude paid account — GPT carries no tag 4) assert.deepEqual(parseBillingTagMap({}), { cache_read_tokens: 5, cache_write_tokens: 4 }); assert.deepEqual(parseBillingTagMap({ DEVIN_CONNECT_BILLING_TAGS: ' ' }), { cache_read_tokens: 5, cache_write_tokens: 4 }); // Explicit opt-out decodes nothing at all. assert.equal(parseBillingTagMap({ DEVIN_CONNECT_BILLING_TAGS: 'off' }), null); assert.equal(parseBillingTagMap({ DEVIN_CONNECT_BILLING_TAGS: 'OFF' }), null); // An explicit map REPLACES the default (no implicit merge). assert.deepEqual( parseBillingTagMap({ DEVIN_CONNECT_BILLING_TAGS: 'credit_cost=10' }), { credit_cost: 10 }, ); assert.deepEqual( parseBillingTagMap({ DEVIN_CONNECT_BILLING_TAGS: 'credit_cost=10, committed_acu_cost=12' }), { credit_cost: 10, committed_acu_cost: 12 }, ); // unknown key dropped, non-int tag dropped, negative dropped → null (nothing valid) assert.equal( parseBillingTagMap({ DEVIN_CONNECT_BILLING_TAGS: 'bogus_key=5,credit_cost=abc,committed_acu_cost=-1' }), null, ); // a typo'd tag is skipped but valid siblings survive assert.deepEqual( parseBillingTagMap({ DEVIN_CONNECT_BILLING_TAGS: 'credit_cost=10,committed_credit_cost=xx' }), { credit_cost: 10 }, ); }); it('reads the finish signal from field #5', () => { const payload = Buffer.concat([writeStringField(1, 'bot-1'), writeVarintField(5, 2)]); assert.equal(decodeFrame(payload).finish, 2); }); it('returns empties for a metadata-only frame', () => { const payload = Buffer.concat([ writeStringField(1, 'bot-123'), writeMessageField(7, writeVarintField(6, 6)), ]); const d = decodeFrame(payload); assert.equal(d.content, ''); assert.equal(d.reasoning, ''); assert.equal(d.finish, null); assert.equal(d.usage, null); }); it('reads credit_cost from the TOP level when the tag is declared with ^', () => { // Four independent .proto reimplementations put credit_cost at top-level #14 // (not in the #7 metadata sub-message where every calibrated tag so far lived). // `^14` in DEVIN_CONNECT_BILLING_TAGS means "top level", so a paid capture that // confirms the coordinate can wire it without a second env var. A frame with // #14 and NO #7 sub-message is the exact shape the top-level pass exists for. const payload = Buffer.concat([ writeStringField(1, 'bot-1'), writeStringField(3, 'the answer'), writeVarintField(14, 12345), // credit_cost, top-level ]); const d = decodeFrame(payload, { billingTags: { credit_cost: -14 } }); assert.equal(d.billing.credit_cost, 12345); }); it('does not let a top-level cache-token tag leak into billing (usage stays usage)', () => { // A cache_read_tokens tag pinned at the top level would, without the guard, // land in `billing` instead of `usage`, silently zeroing the dashboard's cache // split. The usage vs billing routing must follow the KEY, not the location. const payload = Buffer.concat([ writeStringField(1, 'bot-1'), writeVarintField(14, 4096), // cache_read_tokens pinned top-level for the test ]); const d = decodeFrame(payload, { billingTags: { cache_read_tokens: -14 } }); assert.equal(d.usage.cache_read_tokens, 4096, 'token counts must stay usage'); assert.equal(d.billing?.cache_read_tokens, undefined, 'a token count must not surface as a billing field'); }); }); describe('decodeFrame malformed-frame resilience (FRAME-1)', () => { // A malformed upstream frame must degrade to an empty delta, never throw: // decodeFrame runs inside res.on('data'), so a synchronous throw there escapes // the streamChat generator's try/finally → uncaughtException → process.exit(1), // taking down every concurrent tenant over one bad frame. const EMPTY = { content: '', reasoning: '', finish: null, usage: null, billing: null }; it('returns an empty delta (no throw) on an unknown wire type at the top level', () => { // wire type 7 is illegal; parseFields throws "Unknown wire type 7". // tag = (field<<3)|7 = (1<<3)|7 = 15. const payload = Buffer.from([0x0f]); let d; assert.doesNotThrow(() => { d = decodeFrame(payload); }); assert.deepEqual(d, EMPTY); }); it('returns an empty delta (no throw) on a truncated varint at the top level', () => { // tag byte says field #1 varint (0x08), then a varint with the continuation // bit set but no following byte → "Truncated varint". const payload = Buffer.from([0x08, 0x80]); let d; assert.doesNotThrow(() => { d = decodeFrame(payload); }); assert.deepEqual(d, EMPTY); }); it('returns an empty delta (no throw) on a truncated length-delimited field', () => { // field #3 (content), wire type 2 → tag 0x1a; declared length 10 but only 3 // bytes follow → "truncated len-delim field". const payload = Buffer.concat([Buffer.from([0x1a, 0x0a]), Buffer.from('abc')]); let d; assert.doesNotThrow(() => { d = decodeFrame(payload); }); assert.deepEqual(d, EMPTY); }); it('does not throw when the #7 metadata sub-message body is malformed protobuf', () => { // Outer frame parses fine, but the length-delimited #7 payload is itself an // illegal wire type (7) → the nested parseFields(meta.value) would throw. // Content still decodes; usage degrades to null. const payload = Buffer.concat([ writeStringField(3, 'hello'), writeMessageField(7, Buffer.from([0x0f])), ]); let d; assert.doesNotThrow(() => { d = decodeFrame(payload); }); assert.equal(d.content, 'hello'); assert.equal(d.usage, null); assert.equal(d.billing, null); }); it('processes valid fields following the same rules (well-formed frame unaffected)', () => { // Regression guard: the try/catch must not swallow good frames. const payload = Buffer.concat([writeStringField(3, 'ok'), writeVarintField(5, 2)]); const d = decodeFrame(payload); assert.equal(d.content, 'ok'); assert.equal(d.finish, 2); }); }); describe('mapFinishReason', () => { it('maps the live-anchored stop enum (2) to "stop"', () => { assert.equal(mapFinishReason(2), 'stop'); }); it('returns null when no finish signal was seen', () => { assert.equal(mapFinishReason(null), null); }); it('maps the descriptor-pinned 3 and 5 to "length"', () => { // These were name-order guesses when the only evidence was the variant // NAMES. The binary descriptor set now pins the integers themselves: // 3 = MAX_TOKENS, 5 = MAX_NEWLINES — both are limit cuts, i.e. 'length'. // (4 stays 'stop': the paid 2026-07-27 capture is a stronger authority for // that value than the MIN_LOG_PROB name.) assert.equal(mapFinishReason(3), 'length'); assert.equal(mapFinishReason(5), 'length'); }); it('maps 4 to "stop" — paid capture overturned the name-order guess', () => { // 4 was guessed as max_turn_requests→'length' from the protobuf variant NAME // order. Calibrated 2026-07-27 on a paid teams account: three probes with // max_tokens 300 / 8 / 40 all returned 4, and the max_tokens=300 one answered // "HI" (2 chars, unambiguously complete). Mapping it to 'length' made EVERY // complete paid response read as truncated — finish_reason='length' on // /v1/chat/completions and status='incomplete' on /v1/responses. assert.equal(mapFinishReason(4), 'stop'); }); it('handles BigInt finish values (proto varints decode as BigInt)', () => { assert.equal(mapFinishReason(2n), 'stop'); // A BigInt must resolve through the same table as its Number twin — the Number // conversion is what makes the map lookup hit at all. assert.equal(mapFinishReason(3n), mapFinishReason(3)); assert.equal(mapFinishReason(7n, { DEVIN_CONNECT_STOP_REASON_MAP: '7=length' }), 'length'); }); it('falls back to "stop" for unknown values (never an error)', () => { assert.equal(mapFinishReason(99), 'stop'); }); it('honors DEVIN_CONNECT_STOP_REASON_MAP override (calibrated capture)', () => { const env = { DEVIN_CONNECT_STOP_REASON_MAP: '3=stop,7=length,8=content_filter' }; assert.equal(mapFinishReason(3, env), 'stop'); // overridden from default 'length' assert.equal(mapFinishReason(7, env), 'length'); assert.equal(mapFinishReason(8, env), 'content_filter'); assert.equal(mapFinishReason(2, env), 'stop'); // anchor still holds // An operator WITH a real capture can restore 'length' for 3. assert.equal(mapFinishReason(3, { DEVIN_CONNECT_STOP_REASON_MAP: '3=length' }), 'length'); // garbage in the override is ignored, defaults survive const env2 = { DEVIN_CONNECT_STOP_REASON_MAP: '3=bogus,xx=length' }; assert.equal(mapFinishReason(3, env2), 'length'); // bad value ignored → descriptor default }); }); describe('resolveFinishReason — truncation from usage, not from the un-calibrated enum', () => { it('reports "length" when completion_tokens lands exactly on the requested cap', () => { assert.equal(resolveFinishReason(2, { completion_tokens: 64 }, 64), 'length'); }); it('reports "stop" for a complete answer well under the cap', () => { // The regression that made v3.9.0 unusable in reverse: a 12-token answer under // a 4096 cap is complete, and must never read as truncated. assert.equal(resolveFinishReason(4, { completion_tokens: 12 }, 4096), 'stop'); }); it('reports "stop" when the caller set no cap at all', () => { // Nothing to compare against → no truncation claim. Covers the common case of a // client that never sends max_tokens. assert.equal(resolveFinishReason(2, { completion_tokens: 4096 }, null), 'stop'); assert.equal(resolveFinishReason(2, { completion_tokens: 4096 }, undefined), 'stop'); assert.equal(resolveFinishReason(2, { completion_tokens: 4096 }, 0), 'stop'); }); it('reports "stop" when usage is missing entirely', () => { // Free-tier / un-instrumented turns carry no usage block; absence of evidence // must not become evidence of truncation. assert.equal(resolveFinishReason(2, null, 100), 'stop'); assert.equal(resolveFinishReason(2, {}, 100), 'stop'); }); it('never overwrites a stronger signal than "stop"', () => { // tool_calls / content_filter say something specific about what the turn did. // Only a clean stop is eligible for the truncation upgrade. const env = { DEVIN_CONNECT_STOP_REASON_MAP: '9=tool_calls,10=content_filter' }; assert.equal(resolveFinishReason(9, { completion_tokens: 50 }, 50, env), 'tool_calls'); assert.equal(resolveFinishReason(10, { completion_tokens: 50 }, 50, env), 'content_filter'); }); it('an operator override for that value wins over the inference', () => { // Someone who captured the real integers is the better authority: with 2 pinned // to 'stop' explicitly, a cap-equal turn stays 'stop'. const env = { DEVIN_CONNECT_STOP_REASON_MAP: '2=stop' }; assert.equal(resolveFinishReason(2, { completion_tokens: 30 }, 30, env), 'stop'); }); it('an UNRELATED override does not disable the inference for other values', () => { // Found by adversarial review of the first cut. The override test used // `Object.hasOwn(map, n)` against the merged table, but the defaults already // cover 0..6 — so pinning any single unrelated value made EVERY value read as // "operator-calibrated" and silently switched the usage inference off wholesale. // An operator pinning 7 has said nothing at all about 2 or 4. const env = { DEVIN_CONNECT_STOP_REASON_MAP: '7=length' }; assert.equal(resolveFinishReason(2, { completion_tokens: 64 }, 64, env), 'length'); assert.equal(resolveFinishReason(4, { completion_tokens: 64 }, 64, env), 'length'); // Same for the BigInt form the wire actually decodes to. assert.equal(resolveFinishReason(2n, { completion_tokens: 64 }, 64, env), 'length'); // And the pinned value itself still maps as the operator asked. assert.equal(resolveFinishReason(7, { completion_tokens: 5 }, 4096, env), 'length'); }); it('passes a null finish through as null (no finish signal seen)', () => { assert.equal(resolveFinishReason(null, { completion_tokens: 30 }, 30), null); }); it('tolerates a string cap (max_tokens arriving as JSON text)', () => { assert.equal(resolveFinishReason(2, { completion_tokens: 16 }, '16'), 'length'); }); }); describe('classifyUpstreamError', () => { it('maps a free-tier /upgrade rejection to MODEL_BLOCKED', () => { const r = classifyUpstreamError('Please /upgrade to access claude-opus-4-8'); assert.equal(r.code, 'MODEL_BLOCKED'); }); it('maps "upgrade to access" prose to MODEL_BLOCKED', () => { assert.equal(classifyUpstreamError('You must upgrade to access this model').code, 'MODEL_BLOCKED'); }); it('maps insufficient credit/quota to QUOTA_EXHAUSTED (account dry-well, not a tier wall)', () => { // Distinct from MODEL_BLOCKED: this account ran out of balance and must be // cooled down, not treated as a healthy free account hitting a paid model. assert.equal(classifyUpstreamError('insufficient credits remaining').code, 'QUOTA_EXHAUSTED'); assert.equal(classifyUpstreamError('Your account quota has been exceeded').code, 'QUOTA_EXHAUSTED'); assert.equal(classifyUpstreamError('credit exhausted for this billing cycle').code, 'QUOTA_EXHAUSTED'); }); it('maps the LIVE "daily usage quota has been exhausted" body to QUOTA_EXHAUSTED', () => { // Exact live shape (2026-10-22, Pro account, daily bucket dry), carried on gRPC // code `failed_precondition`. Before `exhausted` was in the arm this matched // NOTHING, fell through to the verbatim passthrough, and became // `failed_precondition` — rendered as HTTP 502 `upstream_error`, absent from // isAccountFailoverError (no cross-account failover), and present in // TRANSPORT_FAULT_CODES (charged the internal-error breaker). const live = 'Your daily usage quota has been exhausted. Visit ' + 'https://app.devin.ai/settings/usage to review your plan and usage. (trace ID: 6f1c9a2e)'; const r = classifyUpstreamError(live, 'failed_precondition', 400); assert.equal(r.code, 'QUOTA_EXHAUSTED'); assert.equal(r.message, live, 'the raw body is preserved for the client/log'); // Same account state, different upstream wording. assert.equal(classifyUpstreamError('Your weekly usage quota has been exhausted.').code, 'QUOTA_EXHAUSTED'); assert.equal(classifyUpstreamError('Your on-demand usage has been exhausted').code, 'QUOTA_EXHAUSTED'); assert.equal(classifyUpstreamError('on-demand balance exhausted').code, 'QUOTA_EXHAUSTED'); assert.equal(classifyUpstreamError('You are running out of credits').code, 'QUOTA_EXHAUSTED'); assert.equal(classifyUpstreamError('quota depleted', 'insufficient_quota').code, 'QUOTA_EXHAUSTED'); }); it('keeps capacity / tier-wall / rate-limit bodies out of the quota arm', () => { // Widening the quota regex must not swallow the narrower classes that were // already ordered ahead of it. assert.equal(classifyUpstreamError('We are facing high demand for this model. Please try again later.').code, 'CAPACITY'); assert.equal(classifyUpstreamError('Please /upgrade to access this model').code, 'MODEL_BLOCKED'); assert.equal(classifyUpstreamError('Reached message rate limit for this model. Resets in: 3h0m0s').code, 'RATE_LIMITED'); assert.equal(classifyUpstreamError('blocked by our content policy').code, 'CONTENT_BLOCKED'); }); it('still maps a paid-entitlement /upgrade wall to MODEL_BLOCKED (no penalty)', () => { assert.equal(classifyUpstreamError('insufficient entitlement for this model').code, 'MODEL_BLOCKED'); assert.equal(classifyUpstreamError('this model requires a paid plan').code, 'MODEL_BLOCKED'); }); it('maps HTTP 401 to UNAUTHORIZED', () => { assert.equal(classifyUpstreamError('', null, 401).code, 'UNAUTHORIZED'); }); it('maps permission_denied code to UNAUTHORIZED', () => { assert.equal(classifyUpstreamError('nope', 'permission_denied').code, 'UNAUTHORIZED'); }); it('maps HTTP 429 to RATE_LIMITED', () => { assert.equal(classifyUpstreamError('', null, 429).code, 'RATE_LIMITED'); }); it('maps resource_exhausted text to RATE_LIMITED', () => { assert.equal(classifyUpstreamError('resource_exhausted: too many requests').code, 'RATE_LIMITED'); }); it('falls back to the upstream code, else UPSTREAM_ERROR', () => { assert.equal(classifyUpstreamError('boom', 'weird_code').code, 'weird_code'); assert.equal(classifyUpstreamError('boom').code, 'UPSTREAM_ERROR'); }); it('prefers MODEL_BLOCKED even on a non-200 status', () => { // an /upgrade message returned with a 403 is still an entitlement issue assert.equal(classifyUpstreamError('/upgrade required', null, 403).code, 'MODEL_BLOCKED'); }); it('classifies high-demand capacity throttling as CAPACITY, NOT UNAUTHORIZED (P0 #56)', () => { // LIVE-OBSERVED: the upstream wraps a transient "model is busy" in a 401/403 // auth-shell: HTTP 401 body "We're currently facing high demand for this // model. Please try again later." Misreading it as UNAUTHORIZED triggers an // auto re-login → fresh token is STILL busy → second UNAUTHORIZED gets // mislabeled MODEL_BLOCKED → the free model is cooled down forever over a // retryable hiccup. CAPACITY must win even with a 401/403 status. assert.equal(classifyUpstreamError("We're currently facing high demand for this model. Please try again later.", null, 401).code, 'CAPACITY'); assert.equal(classifyUpstreamError("We're currently facing high demand for this model. Please try again later.", null, 403).code, 'CAPACITY'); assert.equal(classifyUpstreamError('the model is currently overloaded', null, 503).code, 'CAPACITY'); assert.equal(classifyUpstreamError('server is busy, try again later').code, 'CAPACITY'); assert.equal(classifyUpstreamError('model is busy').code, 'CAPACITY'); }); it('does NOT let a real auth failure read as CAPACITY', () => { // permission_denied / invalid token with no capacity wording stays UNAUTHORIZED assert.equal(classifyUpstreamError('permission_denied', 'permission_denied').code, 'UNAUTHORIZED'); assert.equal(classifyUpstreamError('invalid session token', null, 401).code, 'UNAUTHORIZED'); }); it('rel-01: an explicit HTTP 429 wins over capacity-ish body text → RATE_LIMITED, not CAPACITY', () => { // The bug: a 429 whose body contains "try again later" / "capacity" / "overloaded" // used to hit the text-based CAPACITY branch first (retryable + 60s cooldown), so // the pool retried straight back into a real rate limit. An explicit 429 status is // an authoritative account-scoped throttle → RATE_LIMITED (non-retryable). assert.equal(classifyUpstreamError('Please try again later.', null, 429).code, 'RATE_LIMITED'); assert.equal(classifyUpstreamError('the model is currently overloaded', null, 429).code, 'RATE_LIMITED'); assert.equal(classifyUpstreamError('high demand, try again later', null, 429).code, 'RATE_LIMITED'); // gRPC resource_exhausted code is the same authoritative signal. assert.equal(classifyUpstreamError('capacity', 'resource_exhausted').code, 'RATE_LIMITED'); }); it('rel-01: capacity text WITHOUT a 429 still reads as CAPACITY (401/403/503 shell unchanged)', () => { // The rel-01 fix must NOT over-reach: the live-observed "high demand" blip // arrives in a 401/403/503 shell (NOT 429) and must stay retryable CAPACITY. assert.equal(classifyUpstreamError("We're currently facing high demand for this model. Please try again later.", null, 401).code, 'CAPACITY'); assert.equal(classifyUpstreamError('the model is currently overloaded', null, 503).code, 'CAPACITY'); assert.equal(classifyUpstreamError('server is busy, try again later').code, 'CAPACITY'); }); it('rel-01: hard "Resets in: 3h" rate limit still parses its window (matched before the 429 guard)', () => { // The explicit-reset branch runs before the new bare-429 guard, so a body with a // Go-duration reset window keeps producing resetMs for the real cooldown. const r = classifyUpstreamError('Reached message rate limit for this model. Please try again later. Resets in: 3h0m0s', null, 429); assert.equal(r.code, 'RATE_LIMITED'); assert.equal(r.resetMs, 3 * 60 * 60 * 1000); }); }); describe('streamChat abort / preconditions', () => { it('throws AbortError when the signal is already aborted (no network leak)', async () => { const ac = new AbortController(); ac.abort(); await assert.rejects( (async () => { for await (const _ of streamChat({ messages: [{ role: 'user', content: 'hi' }], model: 'swe-1-6-slow', token: 'devin-session-token$fake.jwt.sig', signal: ac.signal, })) { /* drain */ } })(), (err) => err.name === 'AbortError' || err.code === 'ABORT_ERR', ); }); it('throws NO_TOKEN before any network attempt when token is missing', async () => { await assert.rejects( (async () => { for await (const _ of streamChat({ messages: [], model: 'm', env: {} })) { /* drain */ } })(), (err) => err.code === 'NO_TOKEN', ); }); it('fires the absolute deadline against a hung-but-silent upstream (idle timer would never catch a trickle)', async () => { // Fake transport: accepts the request, never invokes the response callback, // never emits data — i.e. a socket that connected and then hung. The idle // timer is long; only the absolute deadline can end this. let destroyed = false; __setRequestImpl(() => { const req = { destroyed: false, on() { return req; }, setTimeout() { return req; }, // swallow the idle timer (never fires) write() {}, end() {}, destroy() { destroyed = true; req.destroyed = true; }, }; return req; }); try { const t0 = Date.now(); await assert.rejects( (async () => { for await (const _ of streamChat({ messages: [{ role: 'user', content: 'hi' }], model: 'swe-1-6-slow', token: 'devin-session-token$fake.jwt.sig', timeoutMs: 60000, // idle timer far away deadlineMs: 50, // absolute deadline must fire first })) { /* drain */ } })(), // audit flaw 1: the absolute deadline throws its OWN code // (DEADLINE_EXCEEDED, non-retryable), distinct from the idle-silence // 'TIMEOUT' (retryable) — so a hung-full-window upstream is surfaced // immediately instead of replayed for another ~600s. (err) => err.code === 'DEADLINE_EXCEEDED' && /deadline/.test(err.message), ); assert.ok(Date.now() - t0 < 5000, 'ended promptly via the absolute deadline'); assert.equal(destroyed, true, 'destroyed the hung request'); } finally { __setRequestImpl(null); } }); }); describe('wire-01: multi-byte UTF-8 split across frames', () => { afterEach(() => __setRequestImpl(null)); // Build a raw protobuf `content` field (#3, wire type 2) from ARBITRARY bytes — // used to place HALF of a multi-byte UTF-8 sequence in one frame. writeStringField // can't do this (it takes a JS string, which can't hold a lone continuation byte). function rawContentField(bytes) { const len = []; let n = bytes.length; do { let b = n & 0x7f; n >>>= 7; if (n) b |= 0x80; len.push(b); } while (n); return Buffer.concat([Buffer.from([0x1a]), Buffer.from(len), Buffer.from(bytes)]); } async function drainContent() { let text = ''; for await (const ev of streamChat({ messages: [{ role: 'user', content: 'hi' }], model: 'swe-1-6-slow', token: TOKEN, })) { if (ev.type === 'content') text += ev.text; } return text; } it('reassembles a Chinese char whose 3 UTF-8 bytes straddle two frames (no U+FFFD)', async () => { // '你' = E4 BD A0. Put E4 in frame 1, BD A0 in frame 2. Per-frame toString('utf8') // would yield '�' + '��'; the StringDecoder holds E4 until BD A0. const full = Buffer.from('你好世界', 'utf8'); const cut = 1; // split after the first byte of '你' __setRequestImpl(mkTransport([full.subarray(0, cut), full.subarray(cut)])); const text = await drainContent(); assert.equal(text, '你好世界'); assert.ok(!text.includes('�'), 'no replacement chars'); }); it('reassembles an emoji (4-byte) split mid-sequence', async () => { const full = Buffer.from('🚀ok', 'utf8'); // F0 9F 9A 80 6F 6B __setRequestImpl(mkTransport([full.subarray(0, 2), full.subarray(2)])); const text = await drainContent(); assert.equal(text, '🚀ok'); }); it('a whole char in one frame is unaffected (regression guard)', async () => { __setRequestImpl(mkTransport([Buffer.from('中文', 'utf8')])); assert.equal(await drainContent(), '中文'); }); // Transport builder shared by the cases above. streamChat calls // requestImpl(opts, cb) and expects cb(res) with a streaming response. function mkTransport(byteChunks) { return (_opts, cb) => { const req = { on() { return req; }, setTimeout() { return req; }, write() {}, end() {}, destroy() {} }; const res = new EventEmitter(); res.statusCode = 200; if (cb) cb(res); queueMicrotask(() => { for (const b of byteChunks) res.emit('data', wrapEnvelope(rawContentField(b), { compress: false })); res.emit('data', endOfStreamEnvelope()); res.emit('end'); }); return req; }; } }); describe('isRetryable', () => { it('retries transient network codes', () => { for (const code of ['ECONNRESET', 'ETIMEDOUT', 'TIMEOUT', 'EPIPE']) { assert.equal(isRetryable({ code }), true, code); } }); it('retries idle TIMEOUT but NOT DEADLINE_EXCEEDED (audit flaw 1)', () => { // Idle timeout (120s of silence) is often a transient upstream stall → a // same-token replay is worth it, so 'TIMEOUT' is retryable. assert.equal(isRetryable({ code: 'TIMEOUT' }), true); // Absolute wall-clock deadline (upstream hung the full 600s window) has its // OWN code and is deliberately NOT retryable — a replay would run another // full idle+deadline cycle against the same stuck upstream (~2× wall-clock, // ~1200s) and almost always fail again. Surface immediately instead. assert.equal(isRetryable({ code: 'DEADLINE_EXCEEDED' }), false); }); it('retries server "unavailable" but NOT RATE_LIMITED or internal', () => { assert.equal(isRetryable({ code: 'unavailable' }), true); // RATE_LIMITED: in-process retry would triple load on a throttled upstream // before the pool cooldown applies — let cooldown + failover handle it. assert.equal(isRetryable({ code: 'RATE_LIMITED' }), false); // internal: upstream returns it for PERMANENT client mistakes (bad // fingerprint / gzipped body) — retrying just burns attempts. assert.equal(isRetryable({ code: 'internal' }), false); }); it('retries CAPACITY even though it arrives with a 401/403 status (P0 #56)', () => { // CAPACITY is "model busy, try again" — transient. The code is checked before // the status, so a 401/403-shelled capacity error is still retried in place // (same token) instead of triggering re-login. assert.equal(isRetryable({ code: 'CAPACITY' }), true); assert.equal(isRetryable({ code: 'CAPACITY', status: 401 }), true); assert.equal(isRetryable({ code: 'CAPACITY', status: 403 }), true); }); it('retries HTTP 5xx (except 501) and not 4xx', () => { assert.equal(isRetryable({ status: 500 }), true); assert.equal(isRetryable({ status: 503 }), true); assert.equal(isRetryable({ status: 501 }), false); assert.equal(isRetryable({ status: 429 }), false); // status-only 429: code path handles it assert.equal(isRetryable({ status: 400 }), false); }); it('does not retry terminal codes', () => { assert.equal(isRetryable({ code: 'MODEL_BLOCKED' }), false); assert.equal(isRetryable({ code: 'QUOTA_EXHAUSTED' }), false); assert.equal(isRetryable({ code: 'UNAUTHORIZED' }), false); assert.equal(isRetryable(null), false); }); }); const RED_DOT = 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mP8z8BQDwAEhQGAhKmMIQAAAABJRU5ErkJggg=='; describe('getImageFieldTag (vision gate)', () => { it('defaults to the wire-verified #10 tag when unset', () => { assert.equal(getImageFieldTag({}), 10); }); it('parses a positive integer tag', () => { assert.equal(getImageFieldTag({ DEVIN_CONNECT_IMAGE_TAG: '6' }), 6); }); it('rejects non-numeric / non-positive / out-of-range values (→ 0)', () => { assert.equal(getImageFieldTag({ DEVIN_CONNECT_IMAGE_TAG: 'abc' }), 0); assert.equal(getImageFieldTag({ DEVIN_CONNECT_IMAGE_TAG: '0' }), 0); assert.equal(getImageFieldTag({ DEVIN_CONNECT_IMAGE_TAG: '-3' }), 0); assert.equal(getImageFieldTag({ DEVIN_CONNECT_IMAGE_TAG: '999999999' }), 0); }); }); describe('buildGetChatMessageRequest — collapse system messages', () => { const cmsOf = (proto) => getAllFields(parseFields(proto), 3).map(f => parseFields(f.value)); const roleOf = (cm) => Number(getField(cm, 2, 0)?.value); const textOf = (cm) => getField(cm, 3, 2)?.value.toString('utf8') || ''; it('defaults off: system remains field #2 and user text is unchanged', () => { const proto = buildGetChatMessageRequest({ token: TOKEN, model: 'm', messages: [{ role: 'system', content: 'SYSTEM' }, { role: 'user', content: 'hello' }], env: {}, }); assert.equal(getField(parseFields(proto), 2, 2).value.toString('utf8'), 'SYSTEM'); assert.deepEqual(cmsOf(proto).map(textOf), ['hello']); }); it('enabled: multiple system messages are wrapped and prepended to the next user turn', () => { const proto = buildGetChatMessageRequest({ token: TOKEN, model: 'm', messages: [ { role: 'system', content: 'FIRST' }, { role: 'system', content: 'SECOND' }, { role: 'user', content: 'hello' }, ], env: { DEVIN_CONNECT_COLLAPSE_SYSTEM: '1' }, }); assert.equal(getField(parseFields(proto), 2, 2).value.toString('utf8'), ''); assert.equal(textOf(cmsOf(proto)[0]), '\nFIRST\n\nSECOND\n\nhello'); }); it('enabled + tools: field #2 keeps only the existing benign tools placeholder', () => { const proto = buildGetChatMessageRequest({ token: TOKEN, model: 'claude-opus-4-8-medium', messages: [{ role: 'system', content: 'BRAND-SENSITIVE' }, { role: 'user', content: 'hello' }], tools: [{ type: 'function', function: { name: 'read', parameters: { type: 'object' } } }], env: { DEVIN_CONNECT_COLLAPSE_SYSTEM: '1' }, }); const fields = parseFields(proto); const system = getField(fields, 2, 2).value.toString('utf8'); assert.match(system, /helpful assistant/i); assert.doesNotMatch(system, /BRAND-SENSITIVE/); assert.match(textOf(cmsOf(proto)[0]), /BRAND-SENSITIVE/); }); it('system followed by an image user stays one source=USER message with image #10', () => { const proto = buildGetChatMessageRequest({ token: TOKEN, model: 'swe-1-7', messages: [{ role: 'system', content: 'VISION SYSTEM' }, { role: 'user', content: [ { type: 'text', text: 'what is this?' }, { type: 'image_url', image_url: { url: `data:image/png;base64,${RED_DOT}` } }, ], }], env: { DEVIN_CONNECT_COLLAPSE_SYSTEM: '1', DEVIN_CONNECT_IMAGE_TAG: '10' }, }); const [user] = cmsOf(proto); assert.equal(roleOf(user), 1); assert.equal(textOf(user), '\nVISION SYSTEM\n\nwhat is this?'); assert.equal(getAllFields(user, 10).length, 1); assert.equal(getField(user, 6, 2), null, 'no synthetic assistant tool call'); }); it('assistant history does not consume a pending system block', () => { const proto = buildGetChatMessageRequest({ token: TOKEN, model: 'm', messages: [ { role: 'system', content: 'FOR NEXT USER' }, { role: 'assistant', content: 'old answer' }, { role: 'user', content: 'new question' }, ], env: { DEVIN_CONNECT_COLLAPSE_SYSTEM: '1' }, }); const messages = cmsOf(proto); assert.equal(roleOf(messages[0]), 2); assert.equal(textOf(messages[0]), 'old answer'); assert.equal(roleOf(messages[1]), 1); assert.equal(textOf(messages[1]), '\nFOR NEXT USER\n\nnew question'); }); it('does not merge users across a mid-conversation system when collapse is on', () => { const proto = buildGetChatMessageRequest({ token: TOKEN, model: 'm', messages: [ { role: 'user', content: 'q1' }, { role: 'system', content: 'MID' }, { role: 'user', content: 'q2' }, ], env: { DEVIN_CONNECT_COLLAPSE_SYSTEM: '1' }, }); assert.deepEqual(cmsOf(proto).map(textOf), [ 'q1', '\nMID\n\nq2', ]); }); it('trailing system content becomes a final synthetic user turn', () => { const proto = buildGetChatMessageRequest({ token: TOKEN, model: 'm', messages: [{ role: 'user', content: 'hello' }, { role: 'system', content: 'TRAILING' }], env: { DEVIN_CONNECT_COLLAPSE_SYSTEM: '1' }, }); assert.deepEqual(cmsOf(proto).map(textOf), ['hello', '\nTRAILING\n']); }); it('continuityTrail follows the collapsed system content instead of leaking back into field #2', () => { const proto = buildGetChatMessageRequest({ token: TOKEN, model: 'm', messages: [{ role: 'system', content: 'SYSTEM' }, { role: 'user', content: 'hello' }], continuityTrail: '\n\n[Continuity checkpoint]\nprior\n[End]', env: { DEVIN_CONNECT_COLLAPSE_SYSTEM: '1' }, }); assert.equal(getField(parseFields(proto), 2, 2).value.toString('utf8'), ''); const userText = textOf(cmsOf(proto)[0]); assert.match(userText, /SYSTEM/); assert.match(userText, /Continuity checkpoint/); assert.ok(userText.indexOf('SYSTEM') < userText.indexOf('Continuity checkpoint')); }); }); describe('getToolDefTags (native tool-def gate)', () => { it('returns null (disabled → prompt emulation) when unset', () => { assert.equal(getToolDefTags({}), null); assert.equal(getToolDefTags({ DEVIN_CONNECT_TOOL_DEF_TAGS: ' ' }), null); }); it('parses a 4-tuple "outer,name,description,schema" (parameters is the primary key, schema kept as back-compat alias)', () => { assert.deepEqual( getToolDefTags({ DEVIN_CONNECT_TOOL_DEF_TAGS: '10,1,2,3' }), { outer: 10, name: 1, description: 2, parameters: 3, schema: 3 }, ); }); it('key=val form: outer defaults to the VFB #10 when omitted', () => { assert.deepEqual( getToolDefTags({ DEVIN_CONNECT_TOOL_DEF_TAGS: 'name=1,description=2,parameters=3' }), { outer: 10, name: 1, description: 2, parameters: 3, schema: 3 }, ); }); it('key=val form: strict is optional and only kept when a valid tag is given', () => { const withStrict = getToolDefTags({ DEVIN_CONNECT_TOOL_DEF_TAGS: 'name=1,description=2,parameters=3,strict=6' }); assert.equal(withStrict.strict, 6); const noStrict = getToolDefTags({ DEVIN_CONNECT_TOOL_DEF_TAGS: 'name=1,description=2,parameters=3' }); assert.equal(noStrict.strict, undefined); }); it('rejects Devin-proprietary keys (custom_tool/defer_loading) silently — they are never emitted', () => { // A stray proprietary key must not break the gate; it is ignored, and the // mandatory trio still resolves. const t = getToolDefTags({ DEVIN_CONNECT_TOOL_DEF_TAGS: 'name=1,description=2,parameters=3,custom_tool=4,defer_loading=5' }); assert.deepEqual(t, { outer: 10, name: 1, description: 2, parameters: 3, schema: 3 }); }); it('key=val form fails closed when a mandatory inner tag is missing', () => { assert.equal(getToolDefTags({ DEVIN_CONNECT_TOOL_DEF_TAGS: 'name=1,description=2' }), null); // no parameters assert.equal(getToolDefTags({ DEVIN_CONNECT_TOOL_DEF_TAGS: 'outer=10,name=1' }), null); }); it('fails closed (→ null) on wrong arity or garbage', () => { assert.equal(getToolDefTags({ DEVIN_CONNECT_TOOL_DEF_TAGS: '10,1,2' }), null); assert.equal(getToolDefTags({ DEVIN_CONNECT_TOOL_DEF_TAGS: '10,1,2,3,4' }), null); assert.equal(getToolDefTags({ DEVIN_CONNECT_TOOL_DEF_TAGS: '10,1,x,3' }), null); assert.equal(getToolDefTags({ DEVIN_CONNECT_TOOL_DEF_TAGS: '0,1,2,3' }), null); }); }); describe('native tool defs in the request (gated)', () => { const TOOLS = [{ type: 'function', function: { name: 'get_weather', description: 'Get weather', parameters: { type: 'object', properties: { city: { type: 'string' } } } }, }]; it('emits NO tools field by default (tag map unset → prompt emulation)', () => { const proto = buildGetChatMessageRequest({ token: TOKEN, model: 'm', messages: [{ role: 'user', content: 'x' }], tools: TOOLS, }); // #10 is the calibrated tools tag; with the gate off, none must be present. assert.equal(getAllFields(parseFields(proto), 10).length, 0); }); it('encodes a ToolDef when the inner tags are calibrated', () => { const prev = process.env.DEVIN_CONNECT_TOOL_DEF_TAGS; process.env.DEVIN_CONNECT_TOOL_DEF_TAGS = '10,1,2,3'; try { const proto = buildGetChatMessageRequest({ token: TOKEN, model: 'm', messages: [{ role: 'user', content: 'x' }], tools: TOOLS, }); const toolFields = getAllFields(parseFields(proto), 10).filter(f => f.wireType === 2); assert.equal(toolFields.length, 1, 'one ToolDef emitted at #10'); const td = parseFields(toolFields[0].value); assert.equal(getField(td, 1, 2).value.toString('utf8'), 'get_weather'); assert.equal(getField(td, 2, 2).value.toString('utf8'), 'get_weather'); assert.deepEqual(JSON.parse(getField(td, 3, 2).value.toString('utf8')), TOOLS[0].function.parameters); } finally { if (prev === undefined) delete process.env.DEVIN_CONNECT_TOOL_DEF_TAGS; else process.env.DEVIN_CONNECT_TOOL_DEF_TAGS = prev; } }); it('emits the strict varint only when the strict tag is calibrated AND function.strict is true', () => { const prev = process.env.DEVIN_CONNECT_TOOL_DEF_TAGS; process.env.DEVIN_CONNECT_TOOL_DEF_TAGS = 'name=1,description=2,parameters=3,strict=6'; try { const strictTool = [{ type: 'function', function: { name: 'f', description: 'd', parameters: {}, strict: true } }]; const proto = buildGetChatMessageRequest({ token: TOKEN, model: 'm', messages: [{ role: 'user', content: 'x' }], tools: strictTool, }); const td = parseFields(getAllFields(parseFields(proto), 10)[0].value); assert.equal(Number(getField(td, 6, 0).value), 1, 'strict=6 varint emitted as 1'); // strict:false (or absent) → no #6 field const noStrict = buildGetChatMessageRequest({ token: TOKEN, model: 'm', messages: [{ role: 'user', content: 'x' }], tools: [{ type: 'function', function: { name: 'f', description: 'd', parameters: {} } }], }); const td2 = parseFields(getAllFields(parseFields(noStrict), 10)[0].value); assert.equal(getField(td2, 6, 0), null, 'no strict field when function.strict absent'); } finally { if (prev === undefined) delete process.env.DEVIN_CONNECT_TOOL_DEF_TAGS; else process.env.DEVIN_CONNECT_TOOL_DEF_TAGS = prev; } }); it('defaults outer to the VFB #10 when the gate omits it (key=val form)', () => { const prev = process.env.DEVIN_CONNECT_TOOL_DEF_TAGS; process.env.DEVIN_CONNECT_TOOL_DEF_TAGS = 'name=1,description=2,parameters=3'; try { const proto = buildGetChatMessageRequest({ token: TOKEN, model: 'm', messages: [{ role: 'user', content: 'x' }], tools: TOOLS, }); // outer defaulted to 10 → ToolDef rides at #10 exactly as the positional form. assert.equal(getAllFields(parseFields(proto), 10).filter(f => f.wireType === 2).length, 1); } finally { if (prev === undefined) delete process.env.DEVIN_CONNECT_TOOL_DEF_TAGS; else process.env.DEVIN_CONNECT_TOOL_DEF_TAGS = prev; } }); }); describe('parseToolCallTagMap (native tool-call decode gate)', () => { it('returns null when unset', () => { assert.equal(__testing.parseToolCallTagMap({}), null); }); it('parses key=tag pairs and requires the outer tag', () => { assert.deepEqual( __testing.parseToolCallTagMap({ DEVIN_CONNECT_TOOL_CALL_TAGS: 'outer=12,id=4,name=1,arguments_json=3' }), { outer: 12, id: 4, name: 1, arguments_json: 3 }, ); // no `outer` → unusable → null assert.equal(__testing.parseToolCallTagMap({ DEVIN_CONNECT_TOOL_CALL_TAGS: 'id=4,name=1' }), null); }); it('ignores unknown keys and bad tags', () => { assert.deepEqual( __testing.parseToolCallTagMap({ DEVIN_CONNECT_TOOL_CALL_TAGS: 'outer=12,bogus=9,name=x' }), { outer: 12 }, ); }); it('parses the CONFIRMED calibrated tags (static disasm 2026-07-04, all 7 subfields)', () => { // verified-from-binary: encode_raw @0x1442fe1f0 + merge_field jump table. // Locks the value shipped in .devin-connect-calibrated.env so a typo can't // silently ship the wrong outer tag (the old #2 guess was wrong; it's #6). assert.deepEqual( __testing.parseToolCallTagMap({ DEVIN_CONNECT_TOOL_CALL_TAGS: 'outer=6,id=1,name=2,arguments_json=3,invalid_json_str=4,invalid_json_err=5,is_custom_tool_call=6', }), { outer: 6, id: 1, name: 2, arguments_json: 3, invalid_json_str: 4, invalid_json_err: 5, is_custom_tool_call: 6 }, ); }); }); describe('decodeFrame native tool calls (gated)', () => { const tags = { outer: 12, id: 4, name: 1, arguments_json: 3 }; function frameWithToolCall() { const tc = Buffer.concat([ writeStringField(1, 'get_weather'), writeStringField(3, '{"city":"SF"}'), writeStringField(4, 'call_abc'), ]); return Buffer.concat([ writeStringField(1, 'bot-1'), writeMessageField(12, tc), ]); } it('does NOT decode tool calls without the tag map (emulation stays)', () => { const d = decodeFrame(frameWithToolCall()); assert.equal(d.toolCalls, undefined); }); it('decodes repeated ChatToolCall when tags are calibrated', () => { const d = decodeFrame(frameWithToolCall(), { toolCallTags: tags }); assert.deepEqual(d.toolCalls, [{ name: 'get_weather', arguments: '{"city":"SF"}', id: 'call_abc' }]); }); it('decodes multiple tool calls from repeated fields', () => { const mk = (name, args, id) => writeMessageField(12, Buffer.concat([ writeStringField(1, name), writeStringField(3, args), writeStringField(4, id), ])); const payload = Buffer.concat([writeStringField(1, 'bot-1'), mk('a', '{}', 'c1'), mk('b', '{"k":1}', 'c2')]); const d = decodeFrame(payload, { toolCallTags: tags }); assert.equal(d.toolCalls.length, 2); assert.equal(d.toolCalls[1].name, 'b'); assert.equal(d.toolCalls[1].id, 'c2'); }); // ── Fault tolerance: response-side ChatToolCall structure (NW1 §2) ────────── // Tags below are EXAMPLES only (free tier never emits a tool call, so the real // wire tags are uncalibrated/UNVERIFIED). They exercise the decoder's tolerance // contract, not a calibrated layout. const ftags = { outer: 12, id: 4, arguments_json: 3, is_custom_tool_call: 5, invalid_json_str: 6, invalid_json_err: 7, }; const tcField = (parts) => writeMessageField(12, Buffer.concat(parts)); it('decodes is_custom_tool_call (bool) alongside id + arguments', () => { const payload = Buffer.concat([writeStringField(1, 'bot-1'), tcField([ writeStringField(4, 'call_x'), writeStringField(3, '{"q":1}'), writeVarintField(5, 1), // is_custom_tool_call = true ])]); const d = decodeFrame(payload, { toolCallTags: ftags }); assert.equal(d.toolCalls.length, 1); assert.equal(d.toolCalls[0].id, 'call_x'); assert.equal(d.toolCalls[0].arguments, '{"q":1}'); assert.equal(d.toolCalls[0].isCustom, true); }); it('falls back to {} when only invalid_json_str/err are present (upstream malformed-args contract)', () => { // arguments_json absent, the model emitted unparseable args the upstream kept // in invalid_json_str → emit {} placeholder, preserve the raw + error. const payload = Buffer.concat([writeStringField(1, 'bot-1'), tcField([ writeStringField(4, 'call_bad'), writeStringField(6, '{city:"SF"'), // invalid_json_str (no quotes/closing) writeStringField(7, 'expected property name'), // invalid_json_err ])]); const d = decodeFrame(payload, { toolCallTags: ftags }); assert.equal(d.toolCalls.length, 1); assert.equal(d.toolCalls[0].id, 'call_bad'); assert.equal(d.toolCalls[0].arguments, '{}'); // safe placeholder assert.deepEqual(d.toolCalls[0].invalidJson, { str: '{city:"SF"', err: 'expected property name' }); }); it('downgrades unparseable arguments_json to {} when an invalid signal co-exists', () => { const payload = Buffer.concat([writeStringField(1, 'bot-1'), tcField([ writeStringField(4, 'call_dg'), writeStringField(3, 'not json at all'), // arguments_json present but invalid writeStringField(7, 'unexpected token'), // invalid_json_err signal present ])]); const d = decodeFrame(payload, { toolCallTags: ftags }); assert.equal(d.toolCalls[0].arguments, '{}'); assert.equal(d.toolCalls[0].invalidJson.str, 'not json at all'); // raw kept assert.equal(d.toolCalls[0].invalidJson.err, 'unexpected token'); }); it('keeps raw arguments_json (never drops data) when unparseable and NO invalid signal', () => { const payload = Buffer.concat([writeStringField(1, 'bot-1'), tcField([ writeStringField(4, 'call_raw'), writeStringField(3, '{partial'), // unparseable, but no invalid_json_* fields ])]); const d = decodeFrame(payload, { toolCallTags: ftags }); assert.equal(d.toolCalls[0].arguments, '{partial'); // preserved verbatim assert.equal(d.toolCalls[0].invalidJson, undefined); }); it('never throws on a malformed sub-message — skips the bad item, keeps the good one', () => { // First delta_tool_calls field carries truncated bytes (a len-delim header that // overruns); parseFields throws on it → decoder must swallow + continue. const broken = Buffer.from([ (3 << 3) | 2, 0x7f ]); // tag #3 wt2, len=127, no data const good = Buffer.concat([writeStringField(4, 'ok'), writeStringField(3, '{"a":1}')]); const payload = Buffer.concat([ writeStringField(1, 'bot-1'), writeMessageField(12, broken), writeMessageField(12, good), ]); let d; assert.doesNotThrow(() => { d = decodeFrame(payload, { toolCallTags: ftags }); }); assert.equal(d.toolCalls.length, 1); assert.equal(d.toolCalls[0].id, 'ok'); }); it('drops an empty sub-message (no phantom tool call manufactured)', () => { const payload = Buffer.concat([ writeStringField(1, 'bot-1'), writeMessageField(12, writeVarintField(5, 0)), // only is_custom=false, nothing else ]); const d = decodeFrame(payload, { toolCallTags: ftags }); // isCustom alone is not enough to count as a call → no toolCalls surfaced. assert.equal(d.toolCalls, undefined); }); it('recovers the function name via single-tool reverse-lookup (response item carries no name)', () => { // Response-side ChatToolCall has no `name` (NW1 §2). When exactly one tool was // offered, the call is unambiguously that tool → opts.toolNames supplies it. const payload = Buffer.concat([writeStringField(1, 'bot-1'), tcField([ writeStringField(4, 'call_only'), writeStringField(3, '{"loc":"NYC"}'), ])]); const d = decodeFrame(payload, { toolCallTags: ftags, toolNames: ['get_weather'] }); assert.equal(d.toolCalls[0].name, 'get_weather'); assert.equal(d.toolCalls[0].id, 'call_only'); // Ambiguous (more than one tool) → no name guessed, left for the 'unknown' default. const d2 = decodeFrame(payload, { toolCallTags: ftags, toolNames: ['a', 'b'] }); assert.equal(d2.toolCalls[0].name, undefined); }); }); describe('decodeFrame thinking signature (gated)', () => { // delta_signature is a top-level string at an UNKNOWN tag (free tier never // emits it). Pick #8 here only as an example tag — NOT a calibrated value. const SIG_TAG = 8, TYPE_TAG = 10, TID_TAG = 11; const SIG = 'ErUBCkYIBxg...base64-opaque...=='; // shape of an Anthropic signature function frameWithSignature({ sig = SIG, type, tid } = {}) { const parts = [writeStringField(1, 'bot-1'), writeStringField(SIG_TAG, sig)]; if (type != null) parts.push(writeVarintField(TYPE_TAG, type)); if (tid != null) parts.push(writeStringField(TID_TAG, tid)); return Buffer.concat(parts); } it('does NOT decode a signature without the tag map (zero regression)', () => { const d = decodeFrame(frameWithSignature()); assert.equal(d.signature, undefined); }); it('decodes delta_signature verbatim when the tag is calibrated', () => { const d = decodeFrame(frameWithSignature(), { signatureTags: { signature: SIG_TAG } }); assert.deepEqual(d.signature, { text: SIG }); }); it('preserves the opaque payload byte-for-byte (no printable filter on signature)', () => { // A real signature is base64 of encrypted bytes; the printable check used for // actual_model_uid must NOT be applied here or a round-trip would corrupt it. const binSig = Buffer.from([0xff, 0x00, 0x41, 0x80, 0x42]).toString('utf8'); const d = decodeFrame( Buffer.concat([writeStringField(1, 'bot-1'), writeStringField(SIG_TAG, binSig)]), { signatureTags: { signature: SIG_TAG } }, ); assert.equal(d.signature.text, binSig); }); it('decodes optional signature_type and thinking_id when their tags are pinned', () => { const d = decodeFrame( frameWithSignature({ type: 1, tid: 'think-abc' }), { signatureTags: { signature: SIG_TAG, type: TYPE_TAG, thinkingId: TID_TAG } }, ); assert.equal(d.signature.text, SIG); assert.equal(d.signature.signatureType, 1); assert.equal(d.signature.thinkingId, 'think-abc'); }); it('a frame without the signature field yields no signature even when calibrated', () => { const payload = Buffer.concat([writeStringField(1, 'bot-1'), writeStringField(3, 'hi')]); assert.equal(decodeFrame(payload, { signatureTags: { signature: SIG_TAG } }).signature, undefined); }); it('parseSignatureTagMap: off when unset, requires the signature tag, parses optional tags', () => { const { parseSignatureTagMap } = __testing; assert.equal(parseSignatureTagMap({}), null); // optional tags alone (no signature tag) → null (nothing to surface) assert.equal(parseSignatureTagMap({ DEVIN_CONNECT_SIGNATURE_TYPE_TAG: '10' }), null); assert.deepEqual(parseSignatureTagMap({ DEVIN_CONNECT_SIGNATURE_TAG: '8' }), { signature: 8 }); assert.deepEqual( parseSignatureTagMap({ DEVIN_CONNECT_SIGNATURE_TAG: '8', DEVIN_CONNECT_SIGNATURE_TYPE_TAG: '10', DEVIN_CONNECT_SIGNATURE_THINKING_ID_TAG: '11', }), { signature: 8, type: 10, thinkingId: 11 }, ); // garbage signature tag → null assert.equal(parseSignatureTagMap({ DEVIN_CONNECT_SIGNATURE_TAG: 'abc' }), null); assert.equal(parseSignatureTagMap({ DEVIN_CONNECT_SIGNATURE_TAG: '-1' }), null); }); }); describe('streamChat signature surface (gated, mock transport)', () => { const SIG_TAG = 8; // Build a fake https.request that streams the given response frames (each a // raw GetChatMessageResponse payload) followed by the success trailer. function mockTransport(framePayloads) { return (opts, cb) => { const req = new EventEmitter(); req.destroyed = false; req.setTimeout = () => req; req.write = () => {}; req.end = () => { const res = new EventEmitter(); res.statusCode = 200; setImmediate(() => { for (const p of framePayloads) res.emit('data', wrapEnvelope(p, { compress: false })); res.emit('data', endOfStreamEnvelope()); res.emit('end'); }); cb(res); }; req.destroy = () => { req.destroyed = true; }; return req; }; } async function collect(env) { const events = []; for await (const ev of streamChat({ messages: [{ role: 'user', content: 'hi' }], model: 'claude-opus-4-8', token: 'devin-session-token$fake.jwt.sig', env, })) events.push(ev); return events; } it('does NOT yield a signature event when the tag is uncalibrated (zero regression)', async () => { __setRequestImpl(mockTransport([ Buffer.concat([writeStringField(1, 'bot-1'), writeStringField(SIG_TAG, 'sig-xyz')]), Buffer.concat([writeStringField(3, 'hello'), writeVarintField(5, 2)]), ])); try { const events = await collect({ DEVIN_CONNECT_TOKEN: 'devin-session-token$fake.jwt.sig' }); assert.equal(events.find(e => e.type === 'signature'), undefined); const finish = events.find(e => e.type === 'finish'); assert.equal(finish.reasoning_signature, null); assert.equal(finish.signature, null); } finally { __setRequestImpl(null); } }); it('surfaces a signature delta event + accumulates onto the finish event when calibrated', async () => { __setRequestImpl(mockTransport([ Buffer.concat([writeStringField(SIG_TAG, 'Er')]), Buffer.concat([writeStringField(SIG_TAG, 'UBCg')]), Buffer.concat([writeStringField(3, 'hello'), writeVarintField(5, 2)]), ])); try { const events = await collect({ DEVIN_CONNECT_TOKEN: 'devin-session-token$fake.jwt.sig', DEVIN_CONNECT_SIGNATURE_TAG: String(SIG_TAG), }); const sigEvents = events.filter(e => e.type === 'signature'); assert.equal(sigEvents.length, 2); assert.deepEqual(sigEvents.map(e => e.reasoning_signature), ['Er', 'UBCg']); // Terminal finish carries the FULL concatenated signature, name-aligned with // what messages.js round-trips (delta.reasoning_signature → signature_delta). const finish = events.find(e => e.type === 'finish'); assert.equal(finish.reasoning_signature, 'ErUBCg'); assert.equal(finish.signature.text, 'ErUBCg'); } finally { __setRequestImpl(null); } }); }); describe('streamChat malformed-frame resilience (FRAME-1, mock transport)', () => { // End-to-end proof of the FRAME-1 fix: a malformed data frame arriving mid-stream // must NOT propagate out of res.on('data') as an uncaughtException. Before the fix // decodeFrame threw synchronously inside the data callback, crashing the process // and every concurrent tenant; now the bad frame is skipped and the good frames // (before and after it) still stream to completion. function mockTransportRaw(rawFrames) { return (opts, cb) => { const req = new EventEmitter(); req.destroyed = false; req.setTimeout = () => req; req.write = () => {}; req.end = () => { const res = new EventEmitter(); res.statusCode = 200; setImmediate(() => { for (const f of rawFrames) res.emit('data', f); res.emit('data', endOfStreamEnvelope()); res.emit('end'); }); cb(res); }; req.destroy = () => { req.destroyed = true; }; return req; }; } it('skips a malformed data frame and still yields the surrounding content', async () => { // frame 1: valid content. frame 2: an unknown wire type (0x0f) that makes // parseFields throw. frame 3: valid content + finish. All wrapped uncompressed. const good1 = wrapEnvelope(writeStringField(3, 'before'), { compress: false }); const bad = wrapEnvelope(Buffer.from([0x0f]), { compress: false }); const good2 = wrapEnvelope( Buffer.concat([writeStringField(3, 'after'), writeVarintField(5, 2)]), { compress: false }); __setRequestImpl(mockTransportRaw([good1, bad, good2])); try { const events = []; // The whole point: this loop must complete normally (no throw/crash). for await (const ev of streamChat({ messages: [{ role: 'user', content: 'hi' }], model: 'claude-opus-4-8', token: 'devin-session-token$fake.jwt.sig', env: { DEVIN_CONNECT_TOKEN: 'devin-session-token$fake.jwt.sig' }, })) events.push(ev); const text = events.filter(e => e.type === 'content').map(e => e.text).join(''); assert.equal(text, 'beforeafter'); const finish = events.find(e => e.type === 'finish'); assert.ok(finish, 'stream reached its terminal finish event despite the bad frame'); } finally { __setRequestImpl(null); } }); }); describe('extractInlineImages', () => { it('returns [] for string / non-array content', () => { assert.deepEqual(extractInlineImages('hi'), []); assert.deepEqual(extractInlineImages(null), []); }); it('extracts an Anthropic-style base64 image block', () => { const imgs = extractInlineImages([ { type: 'text', text: 'see this' }, { type: 'image', source: { type: 'base64', media_type: 'image/png', data: RED_DOT } }, ]); assert.deepEqual(imgs, [{ base64_data: RED_DOT, mime_type: 'image/png' }]); }); it('extracts an OpenAI image_url data URL', () => { const imgs = extractInlineImages([ { type: 'image_url', image_url: { url: `data:image/jpeg;base64,${RED_DOT}` } }, ]); assert.deepEqual(imgs, [{ base64_data: RED_DOT, mime_type: 'image/jpeg' }]); }); it('skips PDF image blocks (text-extracted upstream, not sent as image)', () => { const imgs = extractInlineImages([ { type: 'image', source: { type: 'base64', media_type: 'application/pdf', data: 'JVBER' } }, ]); assert.deepEqual(imgs, []); }); it('ignores remote https image_url (needs async fetch, out of scope for the builder)', () => { const imgs = extractInlineImages([ { type: 'image_url', image_url: { url: 'https://example.com/cat.png' } }, ]); assert.deepEqual(imgs, []); }); }); describe('encodeImageData', () => { it('encodes { base64_data=#1, mime_type=#2 } (Cascade-proven ImageData shape)', () => { const buf = __testing.encodeImageData({ base64_data: 'AAAA', mime_type: 'image/png' }); const f = parseFields(buf); assert.equal(getField(f, 1, 2).value.toString('utf8'), 'AAAA'); assert.equal(getField(f, 2, 2).value.toString('utf8'), 'image/png'); }); it('defaults mime_type to image/png', () => { const buf = __testing.encodeImageData({ base64_data: 'AAAA' }); assert.equal(getField(parseFields(buf), 2, 2).value.toString('utf8'), 'image/png'); }); }); describe('buildGetChatMessageRequest — vision (gated)', () => { const visionMsg = { role: 'user', content: [ { type: 'text', text: 'what color?' }, { type: 'image_url', image_url: { url: `data:image/png;base64,${RED_DOT}` } }, ], }; // Decode every #3 ChatMessage. const cmsOf = (proto) => getAllFields(parseFields(proto), 3).map(f => parseFields(f.value)); const roleOf = (cm) => Number(getField(cm, 2, 0)?.value); const imagesOf = (cm) => getAllFields(cm, 10).map(f => parseFields(f.value)); it('the explicit DEVIN_CONNECT_IMAGE_TAG=0 rollback disables image emission', () => { const proto = buildGetChatMessageRequest({ token: TOKEN, model: 'm', messages: [visionMsg], env: { DEVIN_CONNECT_IMAGE_TAG: '0' }, }); const cms = cmsOf(proto); // Rollback off → one plain user ChatMessage and no image field. assert.equal(cms.length, 1, 'single ChatMessage when gate off'); assert.equal(getField(cms[0], 3, 2).value.toString('utf8'), 'what color?'); assert.equal(cms[0].filter(f => f.wireType === 2 && f.field > 3).length, 0, 'no image sub-message'); assert.ok(!cms.some(cm => roleOf(cm) === 4), 'no role=4 tool_result when gate off'); assert.ok(!cms.some(cm => getField(cm, 7, 2)), 'no #7 tool_call_id when gate off'); }); it('default: image stays on the source=USER message as repeated field #10', () => { const proto = buildGetChatMessageRequest({ token: TOKEN, model: 'swe-1-7', messages: [visionMsg], env: {}, }); const cms = cmsOf(proto); assert.equal(cms.length, 1, 'one input message stays one wire message'); const user = cms[0]; assert.equal(roleOf(user), 1, 'source=USER'); assert.equal(getField(user, 3, 2).value.toString('utf8'), 'what color?'); assert.equal(getField(user, 6, 2), null, 'no synthetic read tool_call'); assert.equal(getField(user, 7, 2), null, 'no synthetic tool_call_id'); const [img] = imagesOf(user); assert.equal(getField(img, 1, 2).value.toString('utf8'), RED_DOT); assert.equal(getField(img, 2, 2).value.toString('utf8'), 'image/png'); }); it('text-only turns are unaffected by the gate being on', () => { const proto = buildGetChatMessageRequest({ token: TOKEN, model: 'm', messages: [{ role: 'user', content: 'plain text' }], env: { DEVIN_CONNECT_IMAGE_TAG: '10' }, }); const cms = cmsOf(proto); assert.equal(cms.length, 1); assert.equal(getField(cms[0], 3, 2).value.toString('utf8'), 'plain text'); assert.equal(getField(cms[0], 6, 2), null, 'no tool_call on a text-only turn'); assert.equal(getField(cms[0], 10, 2), null, 'no image on a text-only turn'); assert.ok(!cms.some(cm => roleOf(cm) === 4), 'no tool_result on a text-only turn'); }); it('multi-image: every image is repeated on the same user message', () => { const proto = buildGetChatMessageRequest({ token: TOKEN, model: 'm', messages: [{ role: 'user', content: [ { type: 'text', text: 'compare' }, { type: 'image_url', image_url: { url: `data:image/png;base64,${RED_DOT}` } }, { type: 'image_url', image_url: { url: `data:image/jpeg;base64,${RED_DOT}` } }, ], }], env: { DEVIN_CONNECT_IMAGE_TAG: '10' }, }); const cms = cmsOf(proto); assert.equal(cms.length, 1); const images = imagesOf(cms[0]); assert.equal(images.length, 2); assert.equal(getField(images[0], 2, 2).value.toString('utf8'), 'image/png'); assert.equal(getField(images[1], 2, 2).value.toString('utf8'), 'image/jpeg'); }); it('native role:tool image keeps the caller tool_call_id and attaches field #10 directly', () => { const proto = buildGetChatMessageRequest({ token: TOKEN, model: 'm', messages: [{ role: 'tool', tool_call_id: 'toolu_ABC123', content: [{ type: 'image', source: { type: 'base64', media_type: 'image/png', data: RED_DOT } }], }], nativeToolCall: true, env: { DEVIN_CONNECT_IMAGE_TAG: '10' }, }); const cms = cmsOf(proto); assert.equal(cms.length, 1); const result = cms[0]; assert.equal(roleOf(result), 4); assert.equal(getField(result, 7, 2).value.toString('utf8'), 'toolu_ABC123', '#7 echoes caller id verbatim'); assert.equal(imagesOf(result).length, 1); }); }); describe('normalizeToolSchema', () => { it('coerces null/non-object/array to the canonical empty object schema', () => { assert.deepEqual(normalizeToolSchema(null), { type: 'object', properties: {} }); assert.deepEqual(normalizeToolSchema(undefined), { type: 'object', properties: {} }); assert.deepEqual(normalizeToolSchema('x'), { type: 'object', properties: {} }); assert.deepEqual(normalizeToolSchema([1, 2]), { type: 'object', properties: {} }); }); it('forces type=object and an object properties', () => { const r = normalizeToolSchema({ type: 'string' }); assert.equal(r.type, 'object'); assert.deepEqual(r.properties, {}); const r2 = normalizeToolSchema({ properties: 'nope' }); assert.deepEqual(r2.properties, {}); }); it('drops $schema meta key', () => { const r = normalizeToolSchema({ $schema: 'http://json-schema.org', type: 'object', properties: { a: { type: 'string' } } }); assert.equal(r.$schema, undefined); assert.deepEqual(r.properties, { a: { type: 'string' } }); }); it('required: keeps only string names that are real properties', () => { const r = normalizeToolSchema({ type: 'object', properties: { a: {}, b: {} }, required: ['a', 'ghost', 42, 'b'] }); assert.deepEqual(r.required, ['a', 'b']); }); it('required: non-array is dropped; empty-after-filter is dropped', () => { assert.equal(normalizeToolSchema({ type: 'object', properties: {}, required: 'a' }).required, undefined); assert.equal(normalizeToolSchema({ type: 'object', properties: { a: {} }, required: ['ghost'] }).required, undefined); }); it('strips schema annotations but preserves structure and a parameter named description', () => { const src = { type: 'object', description: 'root hint', properties: { path: { type: 'string', description: 'file path' }, description: { type: 'string', description: 'parameter hint' }, nested: { type: 'object', description: 'nested hint', properties: { value: { type: 'integer', description: 'value hint' } } }, }, required: ['path', 'description'], }; const r = normalizeToolSchema(src); assert.deepEqual(r, { type: 'object', properties: { path: { type: 'string' }, description: { type: 'string' }, nested: { type: 'object', properties: { value: { type: 'integer' } } }, }, required: ['path', 'description'], }); }); it('does not mutate the caller object', () => { const src = { $schema: 'x', type: 'string', properties: {} }; normalizeToolSchema(src); assert.equal(src.$schema, 'x'); assert.equal(src.type, 'string'); }); it('strips description from oneOf/anyOf/allOf nested schemas', () => { const src = { type: 'object', properties: { mode: { oneOf: [ { type: 'string', description: 'string mode' }, { type: 'object', description: 'object mode', properties: { value: { type: 'string', description: 'inner' } } }, ], }, filter: { anyOf: [ { type: 'string', description: 'filter by name' }, { type: 'integer', description: 'filter by id' }, ], }, combine: { allOf: [ { type: 'string', description: 'part a' }, { type: 'string', enum: ['x', 'y'], description: 'part b' }, ], }, }, }; const r = normalizeToolSchema(src); // oneOf: descriptions stripped, structure preserved assert.equal(r.properties.mode.oneOf[0].description, undefined); assert.equal(r.properties.mode.oneOf[1].description, undefined); assert.equal(r.properties.mode.oneOf[1].properties.value.type, 'string'); assert.equal(r.properties.mode.oneOf[1].properties.value.description, undefined); // anyOf: descriptions stripped assert.equal(r.properties.filter.anyOf[0].description, undefined); assert.equal(r.properties.filter.anyOf[1].description, undefined); // allOf: descriptions stripped, enum preserved assert.equal(r.properties.combine.allOf[0].description, undefined); assert.equal(r.properties.combine.allOf[1].description, undefined); assert.deepEqual(r.properties.combine.allOf[1].enum, ['x', 'y']); }); it('strips description from array items and additionalProperties schemas', () => { const src = { type: 'object', properties: { files: { type: 'array', description: 'list of files', items: { type: 'string', description: 'a file path' }, }, meta: { type: 'object', description: 'metadata bag', additionalProperties: { type: 'string', description: 'any string value' }, }, }, }; const r = normalizeToolSchema(src); assert.equal(r.properties.files.description, undefined); assert.equal(r.properties.files.type, 'array'); assert.equal(r.properties.files.items.type, 'string'); assert.equal(r.properties.files.items.description, undefined); assert.equal(r.properties.meta.description, undefined); assert.equal(r.properties.meta.additionalProperties.type, 'string'); assert.equal(r.properties.meta.additionalProperties.description, undefined); }); it('preserves const, format, and enum while stripping description annotations', () => { const src = { type: 'object', properties: { kind: { type: 'string', const: 'fixed', description: 'the kind' }, date: { type: 'string', format: 'date-time', description: 'when' }, level: { type: 'string', enum: ['low', 'high'], description: 'severity' }, withDefault: { type: 'string', default: 'auto', description: 'default val', examples: ['auto', 'manual'] }, }, }; const r = normalizeToolSchema(src); assert.equal(r.properties.kind.const, 'fixed'); assert.equal(r.properties.kind.description, undefined); assert.equal(r.properties.date.format, 'date-time'); assert.equal(r.properties.date.description, undefined); assert.deepEqual(r.properties.level.enum, ['low', 'high']); assert.equal(r.properties.level.description, undefined); // default and examples are NOT description annotations → preserved assert.equal(r.properties.withDefault.default, 'auto'); assert.deepEqual(r.properties.withDefault.examples, ['auto', 'manual']); assert.equal(r.properties.withDefault.description, undefined); assert.equal(r.properties.withDefault.type, 'string'); }); it('handles deeply nested objects (5 levels) without losing structure', () => { const src = { type: 'object', properties: { a: { type: 'object', description: 'a', properties: { b: { type: 'object', description: 'b', properties: { c: { type: 'object', description: 'c', properties: { d: { type: 'object', description: 'd', properties: { e: { type: 'string', description: 'e' } } } } } } } } }, }, }; const r = normalizeToolSchema(src); const a = r.properties.a; assert.equal(a.description, undefined); assert.equal(a.type, 'object'); const b = a.properties.b; assert.equal(b.description, undefined); const c = b.properties.c; assert.equal(c.description, undefined); const d = c.properties.d; assert.equal(d.description, undefined); const e = d.properties.e; assert.equal(e.type, 'string'); assert.equal(e.description, undefined); }); it('preserves a parameter named "description" with its type and enum', () => { // Regression guard: the MCP-gate fix strips description ANNOTATIONS, not // parameters that happen to be named "description". const src = { type: 'object', properties: { description: { type: 'string', description: 'a human-readable description', enum: ['short', 'long'] }, }, required: ['description'], }; const r = normalizeToolSchema(src); assert.ok(r.properties.description, 'parameter named "description" must survive'); assert.equal(r.properties.description.type, 'string'); assert.deepEqual(r.properties.description.enum, ['short', 'long']); assert.equal(r.properties.description.description, undefined, 'annotation stripped'); assert.deepEqual(r.required, ['description']); }); // ── Top-level combinator stripping (P4, ported from kiro.rs) ────────────── describe('top-level oneOf/anyOf/allOf stripping', () => { it('BYTE-IDENTICAL for a schema with no top-level combinator (regression baseline)', () => { // The whole safety of P4 rests on this: an ordinary schema must serialize // exactly as before. Compare against normalization WITHOUT any combinator. const src = { type: 'object', properties: { a: { type: 'string' }, b: { type: 'integer' } }, required: ['a'] }; const r = normalizeToolSchema(src); assert.deepEqual(r, { type: 'object', properties: { a: { type: 'string' }, b: { type: 'integer' } }, required: ['a'] }); }); it('does NOT touch combinators NESTED under properties (only top level)', () => { // Guards the top-level-only contract: a oneOf inside properties.mode must // survive (it is a legitimate per-parameter schema), unlike a ROOT oneOf. const src = { type: 'object', properties: { mode: { oneOf: [{ type: 'string' }, { type: 'integer' }] } } }; const r = normalizeToolSchema(src); assert.ok(Array.isArray(r.properties.mode.oneOf), 'nested oneOf preserved'); assert.equal(r.properties.mode.oneOf.length, 2); }); it('strips a top-level oneOf and recovers properties from the first object variant', () => { const src = { oneOf: [ { type: 'object', properties: { city: { type: 'string' } }, required: ['city'] }, { type: 'object', properties: { lat: { type: 'number' }, lon: { type: 'number' } } }, ], }; const r = normalizeToolSchema(src); assert.equal(r.oneOf, undefined, 'top-level oneOf removed'); assert.equal(r.type, 'object'); assert.deepEqual(r.properties, { city: { type: 'string' } }, 'properties recovered from first object variant'); assert.deepEqual(r.required, ['city']); }); it('strips top-level anyOf and allOf the same way', () => { const anyR = normalizeToolSchema({ anyOf: [{ type: 'object', properties: { x: { type: 'string' } } }, { type: 'string' }] }); assert.equal(anyR.anyOf, undefined); assert.deepEqual(anyR.properties, { x: { type: 'string' } }); const allR = normalizeToolSchema({ allOf: [{ type: 'object', properties: { y: { type: 'integer' } } }] }); assert.equal(allR.allOf, undefined); assert.deepEqual(allR.properties, { y: { type: 'integer' } }); }); it('with EXISTING top-level properties: strips the combinator but does NOT overwrite properties', () => { const src = { type: 'object', properties: { keep: { type: 'string' } }, oneOf: [{ type: 'object', properties: { other: { type: 'number' } } }], }; const r = normalizeToolSchema(src); assert.equal(r.oneOf, undefined, 'combinator removed'); assert.deepEqual(r.properties, { keep: { type: 'string' } }, 'existing properties untouched (or_insert semantics)'); }); it('top-level combinator with no object variant → forced empty object schema', () => { const r = normalizeToolSchema({ oneOf: [{ type: 'string' }, { type: 'integer' }] }); assert.equal(r.oneOf, undefined); assert.equal(r.type, 'object'); assert.deepEqual(r.properties, {}, 'no object variant to recover from → canonical empty'); }); it('does not mutate the caller schema when stripping a top-level combinator', () => { const src = { oneOf: [{ type: 'object', properties: { a: { type: 'string' } } }] }; normalizeToolSchema(src); assert.ok(Array.isArray(src.oneOf), 'caller oneOf preserved'); }); }); }); describe('streamChat transport resetMs propagation', () => { afterEach(() => __setRequestImpl(null)); it('attaches resetMs to streamError on a non-200 rate-limit response with a reset window', async () => { __setRequestImpl((_opts, cb) => { const req = { on() { return req; }, setTimeout() { return req; }, write() {}, end() {}, destroy() {} }; const res = new EventEmitter(); res.statusCode = 429; if (cb) cb(res); queueMicrotask(() => { res.emit('data', Buffer.from('Reached message rate limit for this model. Please try again later. Resets in: 2h30m0s')); res.emit('end'); }); return req; }); await assert.rejects( (async () => { for await (const _ of streamChat({ messages: [{ role: 'user', content: 'hi' }], model: 'swe-1-7', token: TOKEN, })) { /* drain */ } })(), (err) => { assert.equal(err.code, 'RATE_LIMITED'); assert.equal(err.resetMs, (2 * 3600 + 30 * 60) * 1000); return true; }, ); }); it('attaches resetMs to streamError on a JSON trailer rate-limit response with a reset window', async () => { __setRequestImpl((_opts, cb) => { const req = { on() { return req; }, setTimeout() { return req; }, write() {}, end() {}, destroy() {} }; const res = new EventEmitter(); res.statusCode = 200; if (cb) cb(res); queueMicrotask(() => { const trailerJson = JSON.stringify({ error: { message: 'Reached message rate limit for this model. Please try again later. Resets in: 1h15m0s', code: 'resource_exhausted', }, }); const payload = Buffer.from(trailerJson); const trailerFrame = Buffer.alloc(5 + payload.length); trailerFrame[0] = 0x02; // end-of-stream flag trailerFrame.writeUInt32BE(payload.length, 1); payload.copy(trailerFrame, 5); res.emit('data', trailerFrame); res.emit('end'); }); return req; }); await assert.rejects( (async () => { for await (const _ of streamChat({ messages: [{ role: 'user', content: 'hi' }], model: 'swe-1-7', token: TOKEN, })) { /* drain */ } })(), (err) => { assert.equal(err.code, 'RATE_LIMITED'); assert.equal(err.resetMs, (1 * 3600 + 15 * 60) * 1000); return true; }, ); }); }); describe('encodeAssistantToolCall reasoning-tag guard (PR #241 review point 3)', () => { it('refuses to serialize field 0: reasoning with tag 0 is dropped, not written', () => { const base = { id: 'call_1', name: 'read_file', argsJson: '{}' }; // uuid field is the only random part (fixed 36 chars), so dropped-reasoning // output must be byte-length-identical to a no-reasoning frame. const withZero = __testing.encodeAssistantToolCall({ ...base, reasoning: 'some reasoning text', reasoningTagNum: 0, }); const bare = __testing.encodeAssistantToolCall({ ...base, reasoningTagNum: 0 }); assert.equal( withZero.length, bare.length, 'reasoning with a zero tag must be dropped entirely, not serialized as reserved field 0', ); assert.equal(decodeFrame(withZero).reasoning, '', 'decoding the zero-tag frame must yield no reasoning'); // Regression: a legal tag still carries the reasoning payload end to end. const withEleven = __testing.encodeAssistantToolCall({ ...base, reasoning: 'some reasoning text', reasoningTagNum: 11, }); assert.ok(withEleven.length > bare.length, 'tag 11 reasoning must still be serialized'); assert.ok( withEleven.indexOf(writeStringField(11, 'some reasoning text')) >= 0, 'tag 11 reasoning must still be serialized verbatim', ); }); }); // A non-200 error body is a diagnostic, but it arrives on an unbounded stream. // Before the ceiling, a hostile or broken upstream could push past V8's string // limit; the resulting ERR_STRING_TOO_LONG is thrown inside the 'end' listener // where nothing catches it, escapes as an uncaughtException and exits the // process — so one bad response disconnects every tenant. The cap has to keep // the classification path working AND make the truncation visible. describe('non-200 error body is bounded', () => { const realMax = process.env.DEVIN_CONNECT_MAX_ERROR_BODY_BYTES; afterEach(() => { __setRequestImpl(null); if (realMax === undefined) delete process.env.DEVIN_CONNECT_MAX_ERROR_BODY_BYTES; else process.env.DEVIN_CONNECT_MAX_ERROR_BODY_BYTES = realMax; }); // The module reads the cap at load, so a case that needs a different ceiling // has to load a fresh copy of the module graph under its own env. `body` may // be an array of chunks: production delivers an error body as many ≤64 KiB // socket chunks, and only a test that emits more than one can pin the // accumulator that counts them. const withCap = async (cap, body, statusCode = 500) => { const dir = mkdtempSync(join(tmpdir(), 'dc-cap-')); const prev = process.env.DEVIN_CONNECT_MAX_ERROR_BODY_BYTES; process.env.DEVIN_CONNECT_MAX_ERROR_BODY_BYTES = String(cap); try { const mod = await import(`${new URL('../src/devin-connect.js', import.meta.url).href}?cap=${cap}&r=${Math.random()}`); mod.__setRequestImpl((_opts, cb) => { const req = { on() { return req; }, setTimeout() { return req; }, write() {}, end() {}, destroy() {} }; const res = new EventEmitter(); res.statusCode = statusCode; if (cb) cb(res); queueMicrotask(() => { for (const chunk of Array.isArray(body) ? body : [body]) res.emit('data', chunk); res.emit('end'); }); return req; }); const err = await mod.streamChat({ messages: [{ role: 'user', content: 'hi' }], model: 'swe-1-7', token: TOKEN, }).next().then(() => null, (e) => e); return err; } finally { if (prev === undefined) delete process.env.DEVIN_CONNECT_MAX_ERROR_BODY_BYTES; else process.env.DEVIN_CONNECT_MAX_ERROR_BODY_BYTES = prev; rmSync(dir, { recursive: true, force: true }); } }; it('truncates an oversized error body instead of buffering without bound', async () => { // 4 KiB of body against a 64-byte ceiling. The previous assertion compared // the result against the INPUT size, which the uncapped path also satisfies // — it could not tell the two implementations apart. Compare against the // CEILING instead: only a bounded implementation can come back that small. const err = await withCap(64, Buffer.alloc(4096, 0x41)); assert.ok(err, 'an oversized error body must still produce a classified error'); const marker = '\n[... truncated: upstream error body exceeded the cap ...]'; assert.ok(err.message.length < 512, `a 64-byte ceiling must not yield a ${err.message.length}-character message`); // ceiling + marker + nothing else. The earlier form compared against a // hand-counted marker length and was off by one; derive it instead. assert.equal(err.message.length, 64 + marker.length); }); it('counts the ceiling across data events, not per chunk', async () => { // Every other case emits the body as ONE event, so an implementation that // never accumulated `bodyBytes` across events (production delivers many // ≤64 KiB socket chunks) would pass them all while re-opening unbounded // buffering. Three 32-byte chunks against a 64-byte ceiling: the first two // exactly fill it, the third must trigger truncation instead of extending // the buffer — kept bytes are the ceiling plus the marker, and the third // chunk is never kept. const err = await withCap(64, [Buffer.alloc(32, 0x41), Buffer.alloc(32, 0x42), Buffer.alloc(32, 0x43)]); const marker = '\n[... truncated: upstream error body exceeded the cap ...]'; assert.equal(err.message, 'A'.repeat(32) + 'B'.repeat(32) + marker, 'the ceiling must be counted across data events: keep A+B (64 bytes) + marker, never C'); }); it('keeps the body a genuine prefix of the real one, not a reordering', async () => { const err = await withCap(64, Buffer.from('ABCDEFGH'.repeat(512), 'utf8')); const kept = err.message.split('\n[... truncated')[0]; assert.ok('ABCDEFGH'.repeat(512).startsWith(kept), 'kept text must be a prefix of the body'); assert.ok(kept.length > 0, 'truncation must not discard everything'); }); it('marks the truncation so the error does not silently describe a prefix', async () => { const err = await withCap(64, Buffer.alloc(4096, 0x41)); assert.match(err.message, /truncated: upstream error body exceeded the cap/); }); it('leaves a body under the cap untouched and still classifies it', async () => { const err = await withCap(64 * 1024, Buffer.from('upstream said no', 'utf8'), 429); assert.equal(err.code, 'RATE_LIMITED'); assert.match(err.message, /upstream said no/); assert.doesNotMatch(err.message, /truncated/, 'a body that fit must not be marked truncated'); }); it('falls back to the default ceiling when the override is not a positive integer', async () => { for (const bad of ['0', '-1', 'abc', '', '1e400', ' ']) { const err = await withCap(bad, Buffer.from('short', 'utf8'), 500); assert.ok(err, `override ${JSON.stringify(bad)} must not break the path`); } }); it('never treats a bad override as "no ceiling"', async () => { // A body larger than the 8MiB default is what makes this case load-bearing: // a 1KiB body is kept whole by an 8MiB ceiling AND by no ceiling at all, so // it cannot tell the two apart. Only a finite fallback truncates this one, // at exactly the default ceiling. const err = await withCap('not-a-number', Buffer.alloc(8 * 1024 * 1024 + 64, 0x43), 500); const marker = '\n[... truncated: upstream error body exceeded the cap ...]'; assert.match(err.message, /truncated/, 'a body above the default ceiling must be truncated'); assert.equal(err.message.length, 8 * 1024 * 1024 + marker.length, 'an unparseable override must fall back to the real 8MiB ceiling, not to no ceiling'); }); });