feat: ship skill and MCP workflows with signed updater for v0.0.7
This commit is contained in:
1 parent
1b52df0603
commit
a01085c656
136 files changed
+18646
-217
No files matched your search
@@ -92,7 +92,7 @@ function resetStore(): void {
|
||||
})
|
||||
}
|
||||
|
||||
function installFakeWindow(send: (payload: { sessionId: string; text: string }) => Promise<SendResult>): void {
|
||||
function installFakeWindow(send: (payload: Parameters<typeof window.ycode.chat.send>[0]) => Promise<SendResult>): void {
|
||||
const api = {
|
||||
session: {
|
||||
list: async () => [session],
|
||||
@@ -718,7 +718,7 @@ async function testEarlyOrderedEventsAndDuplicateGuard(): Promise<void> {
|
||||
const firstSend = useChatStore.getState().send('question')
|
||||
assert.equal(useChatStore.getState().sending, true, 'sending should cover the pending IPC request')
|
||||
assert.equal(useChatStore.getState().messages.length, 0, 'early events wait for the send result placeholder')
|
||||
await useChatStore.getState().send('duplicate')
|
||||
await assert.rejects(useChatStore.getState().send('duplicate'), /提交/)
|
||||
assert.equal(sendCalls, 1, 'a second send must be ignored while the first send is pending')
|
||||
|
||||
response.resolve(result)
|
||||
@@ -929,7 +929,32 @@ async function testParallelSessionsAndStaleLoads(): Promise<void> {
|
||||
assert.equal(useChatStore.getState().messages[0].content, 'fast', 'stale session fetch cannot replace a newer selection')
|
||||
}
|
||||
|
||||
async function testNativeSegmentBoundaryBeforeSendResponse(): Promise<void> {
|
||||
resetStore()
|
||||
const gate = deferred<SendResult>()
|
||||
installFakeWindow(async () => gate.promise)
|
||||
const sending = useChatStore.getState().send('root')
|
||||
const runId = 'native-segment'
|
||||
const root = sendResult(runId)
|
||||
useChatStore.getState().applyEvent({ runId, sessionId: session.id, sequence: 1, type: 'text', delta: 'root answer' })
|
||||
const guide: ChatMessage = { id: 'guide-user', role: 'user', content: 'guidance', createdAt: 12, status: 'done' }
|
||||
const answer: ChatMessage = { id: 'guide-assistant', role: 'assistant', content: '', createdAt: 13, status: 'streaming', requestId: runId }
|
||||
useChatStore.getState().observeRun({ ...root, sessionId: session.id, sequence: 2, segmentBoundary: true,
|
||||
assistantMessageId: answer.id, userMessage: guide, messages: [root.userMessage,
|
||||
{ id: root.assistantMessageId, role: 'assistant', content: 'root answer', createdAt: 11, status: 'done' }, guide, answer] })
|
||||
useChatStore.getState().applyEvent({ runId, sessionId: session.id, sequence: 3, type: 'text', delta: 'guide answer' })
|
||||
gate.resolve(root)
|
||||
await sending
|
||||
useChatStore.getState().applyEvent({ runId, sessionId: session.id, sequence: 4, type: 'done', content: 'guide answer', tools: [] })
|
||||
const messages = useChatStore.getState().messages
|
||||
assert.equal(messages.find(message => message.id === root.assistantMessageId)?.content, 'root answer')
|
||||
assert.equal(messages.find(message => message.id === answer.id)?.content, 'guide answer')
|
||||
assert.equal(messages.find(message => message.id === answer.id)?.status, 'done')
|
||||
assert.equal(useChatStore.getState().running, null)
|
||||
}
|
||||
|
||||
async function main(): Promise<void> {
|
||||
await testNativeSegmentBoundaryBeforeSendResponse()
|
||||
resetStore()
|
||||
let inlinePayload: Parameters<typeof window.ycode.chat.send>[0] | undefined
|
||||
installFakeWindow(async payload => { inlinePayload = payload; return sendResult('inline-layout') })
|
||||
@@ -947,6 +972,26 @@ async function main(): Promise<void> {
|
||||
installFakeWindow(async () => { referenceOnlySends++; return sendResult('skill-only') })
|
||||
await useChatStore.getState().send('', { skillIds: ['skill'] })
|
||||
assert.equal(referenceOnlySends, 2, 'a skill-only draft must reach IPC')
|
||||
let capabilityPayload: Parameters<typeof window.ycode.chat.send>[0] | undefined
|
||||
resetStore()
|
||||
installFakeWindow(async payload => { capabilityPayload = payload; return sendResult('mcp-only') })
|
||||
await useChatStore.getState().send('', { mcpServerIds: ['server'] })
|
||||
assert.deepEqual(capabilityPayload?.mcpServerIds, ['server'], 'an MCP-only draft must reach IPC with its selected server')
|
||||
resetStore()
|
||||
installFakeWindow(async payload => { capabilityPayload = payload; return sendResult('compact-only') })
|
||||
await useChatStore.getState().send('/compact', { command: 'compact' })
|
||||
assert.equal(capabilityPayload?.command, 'compact', 'a command-only draft must reach IPC as a native command')
|
||||
|
||||
resetStore()
|
||||
useChatStore.setState({ currentSessionId: null, messages: [], draftContext: {}, draftId: 7 })
|
||||
const deferredResult = deferred<SendResult>()
|
||||
installFakeWindow(async () => deferredResult.promise)
|
||||
const optimisticSend = useChatStore.getState().send('', { skillIds: ['optimistic-skill'], mcpServerIds: ['optimistic-server'] })
|
||||
const optimisticUser = useChatStore.getState().messages.find(message => message.role === 'user')
|
||||
assert.deepEqual(optimisticUser?.skills?.map(item => item.id), ['optimistic-skill'], 'the optimistic user message must retain selected skill metadata')
|
||||
assert.deepEqual(optimisticUser?.mcpServerIds, ['optimistic-server'], 'the optimistic user message must retain MCP selection metadata')
|
||||
deferredResult.resolve(sendResult('optimistic-mcp'))
|
||||
await optimisticSend
|
||||
await testFailedCreatedSessionIsRemoved()
|
||||
await testFailedCreatedSessionWithMessagesIsRetained()
|
||||
await testUnsafeCleanupDoesNotMasqueradeAsHome()
|
||||
|
||||
Reference in new issue
Block a user