test/completion-config-max-tokens-tag.test.js
Rama master · réplica de lectura del repositorio original.
import { describe, it } from 'node:test';
import assert from 'node:assert/strict';
import { buildGetChatMessageRequest, __testing } from '../src/devin-connect.js';
import { parseFields, getField } from '../src/proto.js';
// CompletionConfiguration — #2 = max_tokens, #3 = max_newlines.
//
// History: the encoder once had max_tokens and max_newlines transposed — #2
// received the 128000 context window and #3 received the caller's output cap, so
// the cap never reached the field that enforces it. The swap was fixed; the
// follow-up cleanup removed the context-window input from this builder entirely:
// #3 carries max_newlines (an explicit value, else the calibrated default), and a
// context window is never written to it. The default stays on the wire — the
// request layout is wire-compared.
//
// These assertions are byte-level on purpose. A test that reads the same struct
// the encoder writes cannot distinguish a swap; the tag byte is the thing at stake.
const TOKEN = 'devin-session-token$test.jwt.sig';
const { buildCompletionConfig } = __testing;
// varint tags: (field << 3) | wireType 0 → #2 = 0x10, #3 = 0x18.
const TAG_MAX_TOKENS = 0x10;
const TAG_MAX_NEWLINES = 0x18;
function completionConfigOf(proto) {
return parseFields(getField(parseFields(proto), 8, 2).value);
}
describe('CompletionConfiguration tag map — #2 = max_tokens, #3 = max_newlines', () => {
it('places maxTokens at #2 and max_newlines at #3 — the context window never rides #3', () => {
const buf = buildCompletionConfig({ maxTokens: 777, maxNewlines: 64000 });
const fields = parseFields(buf);
assert.equal(getField(fields, 2, 0).value, 777, '#2 must carry the output cap');
assert.equal(getField(fields, 3, 0).value, 64000, '#3 must carry the explicit max_newlines');
// The context window is not a CompletionConfiguration member: a caller-supplied
// value must not surface at #3 (only the calibrated max_newlines default does).
const ctx = parseFields(buildCompletionConfig({ maxTokens: 777, contextWindow: 64000 }));
assert.equal(getField(ctx, 3, 0).value, 128000, 'contextWindow must not reach #3');
assert.notEqual(getField(ctx, 3, 0).value, 64000);
});
it('emits the literal tag bytes 0x10 (#2) then 0x18 (#3), in that order', () => {
// Values chosen to be single-byte varints so the tag/value pairs are exact:
// 0x10 0x07 = #2 varint 7, 0x18 0x09 = #3 varint 9.
const buf = buildCompletionConfig({ maxTokens: 7, maxNewlines: 9 });
const i2 = buf.indexOf(Buffer.from([TAG_MAX_TOKENS, 7]));
const i3 = buf.indexOf(Buffer.from([TAG_MAX_NEWLINES, 9]));
assert.ok(i2 >= 0, `expected tag 0x10 + value 7 in ${buf.toString('hex')}`);
assert.ok(i3 >= 0, `expected tag 0x18 + value 9 in ${buf.toString('hex')}`);
assert.ok(i2 < i3, 'field order must stay ascending (#2 before #3)');
// The swap's signature: the cap must NOT appear behind the #3 tag.
assert.equal(buf.indexOf(Buffer.from([TAG_MAX_NEWLINES, 7])), -1,
'output cap must not ride max_newlines (#3) — that is the swapped wire');
assert.equal(buf.indexOf(Buffer.from([TAG_MAX_TOKENS, 9])), -1,
'max_newlines must not ride max_tokens (#2)');
});
it('a defaulted call does NOT get capped below the repo output convention, and #3 keeps the calibrated default', () => {
// The regression this pins: once #2 became the ENFORCED cap, the old 4096 default
// would silently truncate every caller that names no max_tokens — and there are
// real ones (/v1/responses without max_output_tokens; chat callers passing only
// temperature). An earlier revision of this test asserted 4096 here, i.e. it
// defended the defect. 8192 is the repo-wide convention (config.js MAX_TOKENS,
// `|| 8192` in handlers/messages.js and handlers/gemini.js).
const fields = parseFields(buildCompletionConfig({}));
assert.equal(getField(fields, 2, 0).value, 8192, 'wire default cap on #2');
assert.equal(getField(fields, 3, 0).value, 128000, 'calibrated max_newlines default on #3');
assert.notEqual(getField(fields, 2, 0).value, 4096,
'a defaulted call must not ship the old dead-constant cap as a real limit');
});
it('a caller cap of 256 is enforceable and overrides the wire default', () => {
// Pre-fix, #2 was always the context window, so the encoded max_tokens was
// 128000 regardless of what the caller asked for.
const fields = parseFields(buildCompletionConfig({ maxTokens: 256 }));
assert.equal(getField(fields, 2, 0).value, 256);
assert.notEqual(getField(fields, 2, 0).value, 128000);
});
it('end-to-end: max_tokens from a request reaches #8.#2 on the real wire', () => {
const proto = buildGetChatMessageRequest({
token: TOKEN, model: 'm',
messages: [{ role: 'user', content: 'x' }],
completion: { maxTokens: 1024 },
});
const comp = completionConfigOf(proto);
assert.equal(getField(comp, 2, 0).value, 1024);
assert.equal(getField(comp, 3, 0).value, 128000, 'a defaulted completion keeps the calibrated #3');
const explicit = completionConfigOf(buildGetChatMessageRequest({
token: TOKEN, model: 'm',
messages: [{ role: 'user', content: 'x' }],
completion: { maxNewlines: 3 },
}));
assert.equal(getField(explicit, 3, 0).value, 3, 'an explicit max_newlines is honoured end-to-end');
});
it('the swap does not disturb the neighbouring calibrated fields', () => {
// #1, #5 temperature, #7 top_k and #8 top_p come from a working live capture;
// only #2/#3 were re-tagged.
const comp = completionConfigOf(buildGetChatMessageRequest({
token: TOKEN, model: 'm',
messages: [{ role: 'user', content: 'x' }],
completion: { maxTokens: 64, temperature: 0.7, topP: 0.5, topK: 100 },
}));
assert.equal(getField(comp, 1, 0).value, 1);
assert.equal(getField(comp, 7, 0).value, 100);
assert.ok(Math.abs(getField(comp, 5, 1).value.readDoubleLE(0) - 0.7) < 1e-9);
assert.ok(Math.abs(getField(comp, 8, 1).value.readDoubleLE(0) - 0.5) < 1e-9);
});
});