221 lines
6.2 KiB
TypeScript
221 lines
6.2 KiB
TypeScript
import { describe, expect, it } from 'vitest'
|
|
import type { AgentExecutionRequest, AgentRuntime } from '../agent/runtime'
|
|
import type {
|
|
MagicNoteEntry,
|
|
MagicTodoItem
|
|
} from '../../shared/magic-notes-contracts'
|
|
import {
|
|
analyzeMagicNoteEntry,
|
|
analyzeMagicTodo
|
|
} from './magic-note-analyzer'
|
|
|
|
const entry: MagicNoteEntry = {
|
|
id: '00000000-0000-4000-8000-000000000501',
|
|
noteId: '00000000-0000-4000-8000-000000000502',
|
|
content: { version: 1, ops: [{ insert: '周五前整理发布清单\n' }] },
|
|
plainText: '周五前整理发布清单',
|
|
comments: [],
|
|
revision: 0,
|
|
createdAt: '2026-08-01T00:00:00.000Z',
|
|
updatedAt: '2026-08-01T00:00:00.000Z'
|
|
}
|
|
|
|
describe('magic note analyzer', () => {
|
|
it('uses ask mode and converts bounded JSON into comments only', async () => {
|
|
let request: AgentExecutionRequest | undefined
|
|
const runtime = {
|
|
requiresToolApproval: false,
|
|
supportsToolExecution: false,
|
|
async getStatus() {
|
|
return {
|
|
id: 'model',
|
|
label: 'Test model',
|
|
available: true,
|
|
detail: 'Ready',
|
|
supportsToolExecution: false
|
|
} as const
|
|
},
|
|
async *run(input: AgentExecutionRequest) {
|
|
request = input
|
|
yield {
|
|
requestId: input.requestId,
|
|
type: 'text',
|
|
delta:
|
|
'```json\n{"comments":[{"kind":"suggestion","content":"先列出发布检查项。"}]}\n```'
|
|
} as const
|
|
yield { requestId: input.requestId, type: 'done' } as const
|
|
},
|
|
async dispose() {}
|
|
} as AgentRuntime
|
|
|
|
const result = await analyzeMagicNoteEntry(
|
|
runtime,
|
|
entry,
|
|
{
|
|
requestId: '00000000-0000-4000-8000-000000000506',
|
|
direction: 'general',
|
|
format: 'structured'
|
|
}
|
|
)
|
|
|
|
expect(request).toMatchObject({
|
|
workMode: 'ask',
|
|
knowledgeLibraryIds: []
|
|
})
|
|
expect(request?.trustedInstructions).toContain('禁止工具调用')
|
|
expect(result).toEqual([
|
|
expect.objectContaining({
|
|
kind: 'suggestion',
|
|
content: '先列出发布检查项。'
|
|
})
|
|
])
|
|
expect(request?.prompt).toContain('不创建待办')
|
|
})
|
|
|
|
it('does not analyze image-only records', async () => {
|
|
const runtime = {} as AgentRuntime
|
|
await expect(
|
|
analyzeMagicNoteEntry(
|
|
runtime,
|
|
{
|
|
...entry,
|
|
plainText: ''
|
|
},
|
|
{
|
|
requestId: '00000000-0000-4000-8000-000000000507',
|
|
direction: 'general',
|
|
format: 'structured'
|
|
}
|
|
)
|
|
).rejects.toThrow('没有可供 AI 分析的文字')
|
|
})
|
|
|
|
it('analyzes a magic todo as comments without tool access', async () => {
|
|
let request: AgentExecutionRequest | undefined
|
|
const runtime = {
|
|
requiresToolApproval: false,
|
|
supportsToolExecution: false,
|
|
async getStatus() {
|
|
return {
|
|
id: 'model',
|
|
label: 'Test model',
|
|
available: true,
|
|
detail: 'Ready',
|
|
supportsToolExecution: false
|
|
} as const
|
|
},
|
|
async *run(input: AgentExecutionRequest) {
|
|
request = input
|
|
yield {
|
|
requestId: input.requestId,
|
|
type: 'text',
|
|
delta:
|
|
'{"comments":[{"kind":"warning","content":"验收条件还不够明确。"}]}'
|
|
} as const
|
|
yield { requestId: input.requestId, type: 'done' } as const
|
|
},
|
|
async dispose() {}
|
|
} as AgentRuntime
|
|
const todo: MagicTodoItem = {
|
|
id: '00000000-0000-4000-8000-000000000601',
|
|
noteId: '00000000-0000-4000-8000-000000000602',
|
|
entryId: '00000000-0000-4000-8000-000000000603',
|
|
noteTitle: '发布笔记',
|
|
sourceIndex: 0,
|
|
source: 'note',
|
|
title: '整理发布清单',
|
|
instructions: '核对版本、说明和构建产物。',
|
|
completed: false,
|
|
comments: [],
|
|
revision: 0,
|
|
createdAt: '2026-08-01T00:00:00.000Z',
|
|
updatedAt: '2026-08-01T00:00:00.000Z'
|
|
}
|
|
|
|
await expect(
|
|
analyzeMagicTodo(
|
|
runtime,
|
|
todo,
|
|
{
|
|
requestId: '00000000-0000-4000-8000-000000000604',
|
|
direction: 'general',
|
|
format: 'structured'
|
|
}
|
|
)
|
|
).resolves.toEqual([
|
|
expect.objectContaining({
|
|
kind: 'warning',
|
|
content: '验收条件还不够明确。'
|
|
})
|
|
])
|
|
expect(request?.workMode).toBe('ask')
|
|
expect(request?.trustedInstructions).toContain('禁止工具调用')
|
|
})
|
|
|
|
it('streams the narrative and snapshots combined comment options', async () => {
|
|
const runtime = {
|
|
requiresToolApproval: false,
|
|
supportsToolExecution: false,
|
|
async getStatus() {
|
|
return {
|
|
id: 'model',
|
|
label: 'Test model',
|
|
available: true,
|
|
detail: 'Ready',
|
|
supportsToolExecution: false
|
|
} as const
|
|
},
|
|
async *run(input: AgentExecutionRequest) {
|
|
yield {
|
|
requestId: input.requestId,
|
|
type: 'text',
|
|
delta: '可以先扩展目标读者,'
|
|
} as const
|
|
yield {
|
|
requestId: input.requestId,
|
|
type: 'text',
|
|
delta:
|
|
'再补充一个实际例子。\n<<<GOODBUDDY_STRUCTURED_COMMENTS>>>\n'
|
|
} as const
|
|
yield {
|
|
requestId: input.requestId,
|
|
type: 'text',
|
|
delta:
|
|
'{"comments":[{"kind":"suggestion","content":"补充一个读者场景。"}]}'
|
|
} as const
|
|
yield { requestId: input.requestId, type: 'done' } as const
|
|
},
|
|
async dispose() {}
|
|
} as AgentRuntime
|
|
const deltas: string[] = []
|
|
|
|
const result = await analyzeMagicNoteEntry(
|
|
runtime,
|
|
entry,
|
|
{
|
|
requestId: '00000000-0000-4000-8000-000000000508',
|
|
direction: 'expand',
|
|
format: 'combined'
|
|
},
|
|
(delta) => deltas.push(delta)
|
|
)
|
|
|
|
expect(deltas.join('')).toBe(
|
|
'可以先扩展目标读者,再补充一个实际例子。\n'
|
|
)
|
|
expect(result).toEqual([
|
|
expect.objectContaining({
|
|
kind: 'narrative',
|
|
direction: 'expand',
|
|
format: 'combined'
|
|
}),
|
|
expect.objectContaining({
|
|
kind: 'suggestion',
|
|
content: '补充一个读者场景。',
|
|
direction: 'expand',
|
|
format: 'combined'
|
|
})
|
|
])
|
|
})
|
|
})
|