feat: complete WorkBuddy parity and Windows release workflow

This commit is contained in:
xiaohan.yuan committed 2026-10-18 12:45:21 +08:00
1 parent 143516b3a8
commit d5512df549
434 files changed
+54977 -1854

No files matched your search

+24 -1
View File
@@ -15,6 +15,7 @@ interface PersistenceTestState {
cancelOutputEmitted: boolean
useOmp: boolean
fallbackHistory: ChatMessage[] | null
fallbackWireHistory?: Array<{ role: string; content: string }>
}
const TEST_STATE_KEY = '__YCODE_CHAT_PERSISTENCE_TEST__'
@@ -112,7 +113,11 @@ async function main(): Promise<void> {
export const app = {
getPath: (name) => name === 'userData' ? state.userData : state.userData,
getName: () => 'YCode',
getVersion: () => '0.1.0'
getVersion: () => '0.1.0',
isPackaged: false, isReady: () => true,
getAppPath: () => state.userData,
getLoginItemSettings: () => ({ openAtLogin: false }),
setLoginItemSettings: () => {}
};
export const safeStorage = {
isEncryptionAvailable: () => false,
@@ -124,6 +129,7 @@ async function main(): Promise<void> {
};
export const dialog = { showOpenDialog: async () => ({ canceled: true, filePaths: [] }) };
export const shell = { openPath: async () => '' };
export const powerSaveBlocker = { start: () => 1, stop: () => true, isStarted: () => false };
export class BrowserWindow {}
export class WebContentsView {}
`
@@ -139,6 +145,7 @@ async function main(): Promise<void> {
const emit = (kernel, frame) => kernel.emit('event', frame);
export class OmpKernel extends EventEmitter {
constructor() { super(); }
setThinkingLevel() { return Promise.resolve(); }
setHostTools() { return Promise.resolve({ type: 'response', success: true, data: { toolNames: [] } }); }
send() { return Promise.resolve({ type: 'response', success: true, data: { messages: [] } }); }
prompt(message) {
@@ -152,11 +159,13 @@ async function main(): Promise<void> {
});
} else {
setImmediate(() => {
emit(this, { type: 'message_end', message: { role: 'assistant', usage: { input: 1200, output: 10, totalTokens: 1210 } } });
emit(this, { type: 'message_update', assistantMessageEvent: { type: 'text_delta', delta: 'before' } });
emit(this, { type: 'tool_execution_start', toolCall: { id: toolId, name: 'read_file', args: { path: 'large.txt' } } });
emit(this, { type: 'tool_execution_update', toolCall: { id: toolId, partialResult: fullOutput } });
emit(this, { type: 'message_update', assistantMessageEvent: { type: 'text_delta', delta: 'after' } });
emit(this, { type: 'tool_execution_end', toolCall: { id: toolId, name: 'read_file', result: { content: [{ type: 'text', text: fullOutput }], isError: false }, success: true } });
emit(this, { type: 'message_end', message: { role: 'assistant', usage: { contextTokens: 12800, input: 12000, cacheRead: 800, output: 200, totalTokens: 13000 } } });
emit(this, { type: 'agent_end', yielded: true });
});
}
@@ -180,6 +189,7 @@ async function main(): Promise<void> {
const state = globalThis.${TEST_STATE_KEY};
export async function runTurn(options) {
state.fallbackHistory = options.history;
state.fallbackWireHistory = options.wireHistory;
const content = 'fallback response';
options.emit({ runId: options.runId, type: 'text', delta: content });
options.emit({ runId: options.runId, type: 'done', content, tools: [] });
@@ -208,6 +218,9 @@ async function main(): Promise<void> {
return Promise.resolve(handler({}, ...args))
}
await invoke('models:save', { id: 'usage-snapshot-model', name: 'Usage snapshot model', providerId: 'custom',
model: 'usage-test', baseUrl: 'http://127.0.0.1:1/v1', authMode: 'none', maxInputTokens: 64000 })
await invoke('models:select', 'usage-snapshot-model')
const normalSession = (await invoke('session:create', 'ordered persistence')) as { id: string }
await invoke('chat:send', { sessionId: normalSession.id, text: 'persist-order' })
const normalMessages = await waitForMessages(invoke, normalSession.id, (messages) => assistant(messages).status === 'done')
@@ -231,6 +244,13 @@ async function main(): Promise<void> {
'the summary may be truncated while full output remains intact')
const diskNormalAssistant = assistant(await readDiskMessages(state.userData, normalSession.id))
assert.deepEqual(normalAssistant.contextUsage, {
usage: { inputTokens: 12800, outputTokens: 200, totalTokens: 13000, cachedTokens: 800 }, contextWindow: 64000,
modelId:'usage-snapshot-model',requestId:normalAssistant.requestId,source:'upstream',sampledAt:normalAssistant.contextUsage?.sampledAt
}, 'latest tool-round input is a sample, not the sum of all round usage')
assert.ok((normalAssistant.contextUsage?.sampledAt??0)>=normalAssistant.createdAt,'the persisted sample identifies its observation time')
assert.deepEqual(diskNormalAssistant.contextUsage, normalAssistant.contextUsage,
'the checkpoint whitelist must persist the upstream sample and frozen denominator together')
assert.deepEqual(diskNormalAssistant.parts, expectedParts, 'disk JSON should retain text/tool/text order')
assert.ok((diskNormalAssistant.tools?.[0].output?.length ?? 0) > 600,
'disk JSON should retain output beyond the summary limit')
@@ -246,6 +266,7 @@ async function main(): Promise<void> {
id: 'fallback-user',
role: 'user',
content: 'old request',
quotes: [{ id: 'saved-table', sourceId: 'table-source', kind: 'table', markdown: '| name | value |\n| --- | --- |\n| A | 42 |', preview: 'A 42' }],
createdAt: Date.now(),
status: 'done'
})
@@ -267,6 +288,8 @@ async function main(): Promise<void> {
assert.equal(assistant(fallbackMessages).content, 'fallback response')
assert.deepEqual(state.fallbackHistory?.map((message) => message.content), ['old request', 'old answer'],
'the fallback loop should receive previously persisted user and assistant messages')
assert.equal(state.fallbackWireHistory?.[0].content, 'old request\n\n| name | value |\n| --- | --- |\n| A | 42 |',
'the next fallback request must include the exact previously quoted table snapshot')
state.useOmp = true
const cancelSession = (await invoke('session:create', 'cancelled persistence')) as { id: string }