Merge pull request #1714 from QwenLM/feat/sdk-support-resume

feat(query): add support for resuming sessions with session ID
This commit is contained in:
tanzhenxin 2026-02-05 16:26:53 +08:00 committed by GitHub
commit 90b529b44c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 54 additions and 1 deletions

View file

@ -91,7 +91,7 @@ export class Query implements AsyncIterable<SDKMessage> {
) {
this.transport = transport;
this.options = options;
this.sessionId = randomUUID();
this.sessionId = options.resume ?? randomUUID();
this.inputStream = new Stream<SDKMessage>();
this.abortController = options.abortController ?? new AbortController();
this.isSingleTurn = singleTurn;

View file

@ -57,6 +57,7 @@ export function query({
allowedTools: options.allowedTools,
authType: options.authType,
includePartialMessages: options.includePartialMessages,
resume: options.resume,
});
const queryOptions: QueryOptions = {

View file

@ -178,6 +178,10 @@ export class ProcessTransport implements Transport {
args.push('--include-partial-messages');
}
if (this.options.resume) {
args.push('--resume', this.options.resume);
}
return args;
}

View file

@ -164,6 +164,7 @@ export const QueryOptionsSchema = z
)
.optional(),
includePartialMessages: z.boolean().optional(),
resume: z.string().optional(),
timeout: TimeoutConfigSchema.optional(),
})
.strict();

View file

@ -25,6 +25,7 @@ export type TransportOptions = {
allowedTools?: string[];
authType?: string;
includePartialMessages?: boolean;
resume?: string;
};
type ToolInput = Record<string, unknown>;
@ -402,6 +403,13 @@ export interface QueryOptions {
*/
includePartialMessages?: boolean;
/**
* Resume a previous session by providing its session ID.
* This is equivalent to using the `--resume` flag in the Qwen CLI.
* @example '123e4567-e89b-12d3-a456-426614174000'
*/
resume?: string;
/**
* Timeout configuration for various SDK operations.
* All values are in milliseconds.

View file

@ -191,6 +191,32 @@ describe('ProcessTransport', () => {
);
});
it('should include --resume argument when provided', () => {
mockPrepareSpawnInfo.mockReturnValue({
command: 'qwen',
args: [],
type: 'native',
originalInput: 'qwen',
});
mockSpawn.mockReturnValue(mockChildProcess);
const options: TransportOptions = {
pathToQwenExecutable: 'qwen',
resume: '123e4567-e89b-12d3-a456-426614174000',
};
new ProcessTransport(options);
expect(mockSpawn).toHaveBeenCalledWith(
'qwen',
expect.arrayContaining([
'--resume',
'123e4567-e89b-12d3-a456-426614174000',
]),
expect.any(Object),
);
});
it('should throw if aborted before initialization', () => {
mockPrepareSpawnInfo.mockReturnValue({
command: 'qwen',

View file

@ -329,6 +329,19 @@ describe('Query', () => {
await transport2.close();
});
it('should use resume parameter as session ID if provided', async () => {
const resumeId = '123e4567-e89b-12d3-a456-426614174000';
const query = new Query(transport, {
cwd: '/test',
resume: resumeId,
});
expect(query.getSessionId()).toBe(resumeId);
await respondToInitialize(transport, query);
await query.close();
});
it('should handle initialization errors', async () => {
const query = new Query(transport, {
cwd: '/test',