mirror of
https://github.com/QwenLM/qwen-code.git
synced 2026-07-21 06:54:12 +00:00
188 lines
5.5 KiB
TypeScript
188 lines
5.5 KiB
TypeScript
import { describe, expect, it } from 'vitest';
|
|
import type {
|
|
DaemonTranscriptBlock,
|
|
DaemonTranscriptState,
|
|
} from '@qwen-code/webui/daemon-react-sdk';
|
|
import { extractPendingPermission } from './transcriptAdapter';
|
|
|
|
function state(blocks: DaemonTranscriptBlock[]): DaemonTranscriptState {
|
|
return {
|
|
blocks,
|
|
blockIndexById: Object.fromEntries(
|
|
blocks.map((block, index) => [block.id, index]),
|
|
),
|
|
activeAssistantBlockByParent: {},
|
|
activeThoughtBlockByParent: {},
|
|
toolBlockByCallId: {},
|
|
trimmedToolNotificationByCallId: {},
|
|
permissionBlockByRequestId: {},
|
|
toolProgress: {},
|
|
nextOrdinal: blocks.length,
|
|
now: Date.now(),
|
|
maxBlocks: 1000,
|
|
awaitingResync: false,
|
|
resyncRequiredCount: 0,
|
|
};
|
|
}
|
|
|
|
describe('extractPendingPermission', () => {
|
|
it('extracts pending AskUserQuestion options and raw input', () => {
|
|
const permission = {
|
|
id: 'perm-1',
|
|
kind: 'permission',
|
|
requestId: 'request-1',
|
|
sessionId: 'session-1',
|
|
title: 'Ask user 1 question',
|
|
options: [
|
|
{
|
|
optionId: 'proceed_once',
|
|
label: 'Submit',
|
|
raw: { kind: 'allow_once', name: 'Submit' },
|
|
},
|
|
{
|
|
optionId: 'cancel',
|
|
label: 'Cancel',
|
|
raw: { kind: 'reject_once', name: 'Cancel' },
|
|
},
|
|
],
|
|
toolCall: {
|
|
rawInput: {
|
|
questions: [
|
|
{
|
|
header: '姓名',
|
|
question: '请问学生姓名是什么?',
|
|
options: [{ label: '张三', description: '示例姓名' }],
|
|
},
|
|
],
|
|
},
|
|
},
|
|
preview: { kind: 'generic' },
|
|
createdAt: 1,
|
|
updatedAt: 1,
|
|
} as DaemonTranscriptBlock;
|
|
|
|
expect(extractPendingPermission(state([permission]).blocks)).toMatchObject({
|
|
id: 'request-1',
|
|
sessionId: 'session-1',
|
|
title: 'Ask user 1 question',
|
|
options: [
|
|
{ id: 'proceed_once', label: 'Submit', kind: 'allow_once' },
|
|
{ id: 'cancel', label: 'Cancel', kind: 'reject_once' },
|
|
],
|
|
rawInput: {
|
|
questions: [
|
|
{
|
|
header: '姓名',
|
|
question: '请问学生姓名是什么?',
|
|
options: [{ label: '张三', description: '示例姓名' }],
|
|
},
|
|
],
|
|
},
|
|
});
|
|
});
|
|
|
|
it('extracts toolCallId from toolCall.toolCallId', () => {
|
|
const permission = {
|
|
id: 'perm-tc1',
|
|
kind: 'permission',
|
|
sessionId: 'session-1',
|
|
requestId: 'request-tc1',
|
|
resolved: undefined,
|
|
title: 'Bash: ls',
|
|
options: [{ optionId: 'allow', label: 'Allow', raw: {} }],
|
|
toolCall: { toolCallId: 'call-abc', rawInput: {} },
|
|
preview: { kind: 'generic' },
|
|
createdAt: 1,
|
|
updatedAt: 1,
|
|
clientReceivedAt: 1,
|
|
} as DaemonTranscriptBlock;
|
|
|
|
const result = extractPendingPermission(state([permission]).blocks);
|
|
expect(result?.toolCallId).toBe('call-abc');
|
|
});
|
|
|
|
it('falls back to toolCall.id when toolCallId is absent', () => {
|
|
const permission = {
|
|
id: 'perm-tc2',
|
|
kind: 'permission',
|
|
sessionId: 'session-1',
|
|
requestId: 'request-tc2',
|
|
resolved: undefined,
|
|
title: 'Bash: pwd',
|
|
options: [{ optionId: 'allow', label: 'Allow', raw: {} }],
|
|
toolCall: { id: 'call-xyz', rawInput: {} },
|
|
preview: { kind: 'generic' },
|
|
createdAt: 1,
|
|
updatedAt: 1,
|
|
clientReceivedAt: 1,
|
|
} as DaemonTranscriptBlock;
|
|
|
|
const result = extractPendingPermission(state([permission]).blocks);
|
|
expect(result?.toolCallId).toBe('call-xyz');
|
|
});
|
|
|
|
it('extracts the canonical toolName from toolCall._meta', () => {
|
|
const permission = {
|
|
id: 'perm-agent',
|
|
kind: 'permission',
|
|
sessionId: 'session-1',
|
|
requestId: 'request-agent',
|
|
resolved: undefined,
|
|
title: 'Agent: probe agent kind',
|
|
options: [{ optionId: 'allow', label: 'Allow', raw: {} }],
|
|
toolCall: {
|
|
toolCallId: 'call-agent',
|
|
kind: 'other',
|
|
_meta: { toolName: 'agent' },
|
|
rawInput: {},
|
|
},
|
|
preview: { kind: 'generic' },
|
|
createdAt: 1,
|
|
updatedAt: 1,
|
|
clientReceivedAt: 1,
|
|
} as DaemonTranscriptBlock;
|
|
|
|
const result = extractPendingPermission(state([permission]).blocks);
|
|
expect(result?.toolName).toBe('agent');
|
|
});
|
|
|
|
it('leaves toolName undefined when _meta is absent', () => {
|
|
const permission = {
|
|
id: 'perm-no-meta',
|
|
kind: 'permission',
|
|
sessionId: 'session-1',
|
|
requestId: 'request-no-meta',
|
|
resolved: undefined,
|
|
title: 'Bash: ls',
|
|
options: [{ optionId: 'allow', label: 'Allow', raw: {} }],
|
|
toolCall: { toolCallId: 'call-bash', rawInput: {} },
|
|
preview: { kind: 'generic' },
|
|
createdAt: 1,
|
|
updatedAt: 1,
|
|
clientReceivedAt: 1,
|
|
} as DaemonTranscriptBlock;
|
|
|
|
const result = extractPendingPermission(state([permission]).blocks);
|
|
expect(result?.toolName).toBeUndefined();
|
|
});
|
|
|
|
it('returns undefined toolCallId when toolCall has neither field', () => {
|
|
const permission = {
|
|
id: 'perm-tc3',
|
|
kind: 'permission',
|
|
sessionId: 'session-1',
|
|
requestId: 'request-tc3',
|
|
resolved: undefined,
|
|
title: 'Read: file',
|
|
options: [{ optionId: 'allow', label: 'Allow', raw: {} }],
|
|
toolCall: { rawInput: {} },
|
|
preview: { kind: 'generic' },
|
|
createdAt: 1,
|
|
updatedAt: 1,
|
|
clientReceivedAt: 1,
|
|
} as DaemonTranscriptBlock;
|
|
|
|
const result = extractPendingPermission(state([permission]).blocks);
|
|
expect(result?.toolCallId).toBeUndefined();
|
|
});
|
|
});
|