Skip to content

Commit e10dd49

Browse files
committed
test(runtime): pin the strict-relay contract for stream usage requests
Every OpenAI-compatible chat request asks for `stream_options.include_usage`. A relay that rejects the field answers 400; the runtime surfaces that as the provider's own error and does not resend without the field. A connection that cannot report usage has no context baseline, and the user should learn that from the error, not from a compaction that never happens. Refs #4559 Generated-by: Claude Code Claude-Session: https://claude.ai/code/session_014ajaRxC4jydavY9nYUFj5J
1 parent 13c0683 commit e10dd49

1 file changed

Lines changed: 50 additions & 0 deletions

File tree

packages/runtime/src/__tests__/provider-conformance.test.ts

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1164,6 +1164,56 @@ describe('models.dev provider conformance', () => {
11641164
assert.equal(usage.totalTokens, 9);
11651165
});
11661166

1167+
test('a relay that rejects stream_options fails loudly with the provider error, no silent retry', async () => {
1168+
// The usage request is the contract, not a best effort. A strict relay
1169+
// that does not know `stream_options` answers 400; the runtime surfaces
1170+
// that answer as the provider's own error and does not resend without
1171+
// the field, because a connection that cannot report usage has no context
1172+
// baseline and the user should learn that from the error, not from a
1173+
// compaction that never happens (#4559).
1174+
let requests = 0;
1175+
let requestBody: Record<string, unknown> | undefined;
1176+
const server = await startJsonServer(async (request, response) => {
1177+
requests += 1;
1178+
requestBody = JSON.parse(await readBody(request)) as Record<string, unknown>;
1179+
respondJson(response, 400, {
1180+
error: {
1181+
message: 'Unrecognized request argument supplied: stream_options',
1182+
type: 'invalid_request_error',
1183+
param: 'stream_options',
1184+
code: null,
1185+
},
1186+
});
1187+
});
1188+
const connection: LlmConnection = {
1189+
slug: 'strict-relay',
1190+
name: 'Strict relay',
1191+
providerType: 'openai-compatible',
1192+
baseUrl: `${server.url}/v1`,
1193+
defaultModel: 'relay-model',
1194+
enabled: true,
1195+
createdAt: 1,
1196+
updatedAt: 1,
1197+
};
1198+
1199+
const result = streamText({
1200+
model: getAIModel({ connection, apiKey: 'test-key', modelId: 'relay-model' }),
1201+
prompt: 'Reply ok.',
1202+
});
1203+
1204+
// The AI SDK reports a failed request as an `error` stream part, which is
1205+
// what the runtime's send loop reads and surfaces as the provider error.
1206+
const errors: unknown[] = [];
1207+
for await (const part of result.fullStream) {
1208+
if (part.type === 'error') errors.push(part.error);
1209+
}
1210+
assert.equal(errors.length, 1);
1211+
const message = errors[0] instanceof Error ? errors[0].message : String(errors[0]);
1212+
assert.match(message, /stream_options/);
1213+
assert.deepEqual(requestBody?.stream_options, { include_usage: true });
1214+
assert.equal(requests, 1);
1215+
});
1216+
11671217
test('Hugging Face discovers tool-capable routed models and preserves its two-stage OpenAI wire', async () => {
11681218
const discoveredModelId = 'openai/gpt-oss-120b';
11691219
const modelId = `${discoveredModelId}:preferred`;

0 commit comments

Comments
 (0)