Skip to content

Commit b9fe265

Browse files
committed
agentHost: define resumable BYOK response state
1 parent 7b923e9 commit b9fe265

2 files changed

Lines changed: 43 additions & 0 deletions

File tree

src/vs/platform/agentHost/common/agentHostByokLm.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,7 @@ export type IByokLmOutputItem =
122122

123123
export interface IByokLmChatResult {
124124
readonly output: IByokLmOutputItem[];
125+
/** Opaque provider state identifier. Present only when a subsequent request can resume it. */
125126
readonly responseId?: string;
126127
readonly usage?: {
127128
readonly inputTokens?: number;

src/vs/platform/agentHost/test/node/byokLmProxyService.test.ts

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -380,6 +380,48 @@ suite('ByokLmProxyService', () => {
380380
});
381381
});
382382

383+
test('preserves full stateless replay when no resumable provider state is reported', async () => {
384+
const captured: IByokLmChatRequest[] = [];
385+
const initialInput = [{ type: 'message', role: 'user', content: [{ type: 'input_text', text: 'Use the tool.' }] }];
386+
const replayedInput = [
387+
...initialInput,
388+
{ type: 'function_call', call_id: 'call_1', name: 'tool', arguments: '{}' },
389+
{ type: 'function_call_output', call_id: 'call_1', output: 'done' },
390+
];
391+
392+
await withProxy(
393+
async request => {
394+
captured.push(request);
395+
return captured.length === 1
396+
? { output: [{ type: 'function_call', callId: 'call_1', name: 'tool', argumentsJson: '{}' }] }
397+
: { output: [{ type: 'message', content: [{ type: 'text', text: 'done' }] }] };
398+
},
399+
async handle => {
400+
for (const input of [initialInput, replayedInput]) {
401+
const response = await fetch(responsesUrl(handle, 'acme'), {
402+
method: 'POST',
403+
headers: authHeaders(handle),
404+
body: JSON.stringify({ model: 'm', input }),
405+
});
406+
assert.strictEqual(response.status, 200);
407+
await response.text();
408+
}
409+
},
410+
);
411+
412+
assert.deepStrictEqual({
413+
previousResponseId: captured[1]?.previousResponseId,
414+
input: captured[1]?.input,
415+
}, {
416+
previousResponseId: undefined,
417+
input: [
418+
{ type: 'message', role: 'user', content: [{ type: 'text', text: 'Use the tool.' }] },
419+
{ type: 'function_call', callId: 'call_1', name: 'tool', argumentsJson: '{}' },
420+
{ type: 'function_call_output', callId: 'call_1', output: 'done' },
421+
],
422+
});
423+
});
424+
383425
test('bounds abandoned tool continuations while preserving recent state', async () => {
384426
const captured: IByokLmChatRequest[] = [];
385427
const maximumPendingContinuations = 256;

0 commit comments

Comments
 (0)