WuYongJie 1b6425b552 feat(desktop): connect native Pi sessions with scoped rules and recovery
Track the fixed PhotoCraft source baseline with the existing native client integration. Use the actual Pi SDK for normal sends, durable session recovery, demand-loaded enterprise rules and checked undoable canvas tools. Retain request identities and never resend unknown inference. Include local packaging and real-call acceptance evidence.
2026-10-22 10:49:58 +08:00

38 lines
3.4 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import fs from 'node:fs/promises';
import path from 'node:path';
import assert from 'node:assert/strict';
import { randomUUID } from 'node:crypto';
import { Native98kBroker } from '../src/native-bridge.mjs';
import { ProjectStore, atomic, digest } from '../src/store.mjs';
import { resolveRules } from '../src/rules.mjs';
import { DetailPiAgent } from '../src/agent.mjs';
const [originalConfig, outputDir] = process.argv.slice(2);
if (!originalConfig || !outputDir) throw Error('用法:<已有本地配置> <本次独立只读诊断目录>');
const output = path.resolve(outputDir), attempt = path.join(output, 'attempt.json');
if (await fs.access(attempt).then(() => true, () => false)) throw Error('此诊断任务已尝试,禁止重新发送;先检查原记录');
const prior = JSON.parse(await fs.readFile(originalConfig, 'utf8'));
const model = JSON.parse(await fs.readFile('output/pi-compatibility-20261021/public-docs/grok-4.7.json', 'utf8'))[0];
const catalog = JSON.parse(await fs.readFile('output/pi-compatibility-20261021/enterprise-rules.json', 'utf8'));
const combo = catalog.bindings.find(b => b.id === 'GJ-DESK-DNZ0385'), shop = catalog.shops.find(s => s.id === combo.shopId);
const binding = resolveRules({ brandId: shop.brandId, shopId: shop.id, categoryId: combo.categoryId }, catalog);
const headers = model.invocation.headers || {};
const config = { broker: { ...prior.broker, project: randomUUID(), invocationHeaders: headers }, binding, output, protocolMode: 'native-tools',
contract: { id: model.id, path: model.invocation.path, headers, sha256: digest(model), source: 'https://api.vip98k.com/api/v2/catalog/models', selection: 'published-current-default', price: model.pricing } };
await atomic(path.join(output, 'config.local.json'), config);
const broker = new Native98kBroker(config.broker), info = await broker.info();
assert.equal(info.model.id, model.id);
const store = await ProjectStore.open(output, { scope: info.accountScope, project: config.broker.project }, binding);
const events = [], host = await DetailPiAgent.open({ store, broker, callBudget: 3, onEvent: e => { events.push(e); if (e.type !== 'text_delta') console.log(JSON.stringify(e)); } });
await atomic(attempt, { project: config.broker.project, createdAt: new Date().toISOString(), purpose: 'new-independent-readonly-context-protocol-diagnostic', oldUnknownNotResent: true });
try {
const result = await host.prompt('这是一个新的只读函数协议验收任务。通过标准函数调用context_read读取当前项目规则,读取一次后直接用中文报告店铺、品类、模板编号和字体。不要写成invoke tool文字;不得调用其他工具,不修改任何画布或资料。', { requiredTool: 'context_read' });
assert.ok(events.some(e => e.type === 'tool_execution_end' && e.toolName === 'context_read' && !e.isError));
assert.match(result.text, /顾家/); assert.match(result.text, /电脑桌/);
await atomic(path.join(output, 'result.json'), { passed: true, model: model.id, result, events, oldUnknownNotResent: true, at: new Date().toISOString() });
console.log(JSON.stringify({ passed: true, ...result }));
} catch (error) {
await atomic(path.join(output, 'result.json'), { passed: false, error: error.message, events, inflight: host.inflight, sessionFile: host.manager.getSessionFile(), at: new Date().toISOString() });
console.error(error.message); process.exitCode = 1;
} finally { await host.dispose(); }