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(); }