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.
69 lines
5.9 KiB
JavaScript
69 lines
5.9 KiB
JavaScript
import fs from 'node:fs/promises';
|
||
import path from 'node:path';
|
||
import assert from 'node:assert/strict';
|
||
import { createHash } from 'node:crypto';
|
||
import { atomic, digest } from '../src/store.mjs';
|
||
import { auditResponse } from '../src/response-audit.mjs';
|
||
|
||
const root = path.resolve('output/pi-compatibility-20261021');
|
||
const model = JSON.parse(await fs.readFile(path.join(root, 'public-docs/grok-4.7.json'), 'utf8'))[0];
|
||
const inventory = new Set(model.invocation.supported_fields.map(f => f.name));
|
||
const configs = ['native-default-probe', 'long-context'];
|
||
const records = [], stages = [], transcript = ['# 本地Pi真实对话验收', '', '产品信息为明确标记的虚构验收资料;店铺、品类及规则来自真实素材库目录和企业知识库。另有80条构造历史未列入下文,也未计入真实API对话轮数。', ''];
|
||
let originalUnknown;
|
||
for (const name of configs) {
|
||
const dir = path.join(root, name), config = JSON.parse(await fs.readFile(path.join(dir, 'config.local.json'), 'utf8'));
|
||
const result = JSON.parse(await fs.readFile(path.join(dir, name === 'long-context' ? 'accepted-A.json' : 'result.json'), 'utf8'));
|
||
assert.notEqual(result.passed, false);
|
||
const sessionFile = result.sessionFile || result.result.sessionFile;
|
||
const relative = path.relative(config.output, sessionFile), scope = relative.split(path.sep)[0];
|
||
assert.match(scope, /^[a-f0-9]{64}$/);
|
||
const accountDir = path.join(config.broker.profile, 'jiansun/accounts', scope);
|
||
const old = JSON.parse(await fs.readFile(path.join(accountDir, 'pi-validation/4db803c6-9c09-42e7-bfb8-fbf819659210/requests/0447b17b-1c45-4902-a6a5-18357a3e2a3f.json'), 'utf8'));
|
||
assert.equal(old.phase, 'unknown');
|
||
originalUnknown = { id: old.id, requestId: old.requestId, phase: old.phase, createdAt: old.createdAt, recordSha256: digest(old), reposted: false };
|
||
const requestDir = path.join(accountDir, 'pi-validation', config.broker.project, 'requests');
|
||
const storeDir = path.dirname(path.dirname(sessionFile));
|
||
for (const file of await fs.readdir(requestDir)) {
|
||
const r = JSON.parse(await fs.readFile(path.join(requestDir, file), 'utf8'));
|
||
assert.equal(r.phase, 'complete'); assert.equal(r.terminal, true);
|
||
assert.notEqual(r.id, old.id); assert.notEqual(r.bodyHash, old.bodyHash);
|
||
const body = JSON.parse(await fs.readFile(path.join(storeDir, 'payloads', r.id + '.json'), 'utf8'));
|
||
assert.equal(createHash('sha256').update(JSON.stringify(body)).digest('hex'), r.bodyHash);
|
||
const unsupported = Object.keys(body).filter(k => !inventory.has(k));
|
||
assert.deepEqual(unsupported, []);
|
||
assert.deepEqual(Object.fromEntries(r.invocationHeaders || []), model.invocation.headers);
|
||
const raw = Buffer.from(r.raw, 'base64').toString('utf8'), audit = auditResponse(raw, r.model.protocol);
|
||
let usage;
|
||
for (const line of raw.split(/\r?\n/)) if (line.startsWith('data:')) { try { const v = JSON.parse(line.slice(5)); usage = v.usage || usage; } catch { /* SSE terminal. */ } }
|
||
records.push({ task: name, id: r.id, customerRequestId: r.requestId, phase: r.phase, bodyHashMatches: true, unsupportedFields: unsupported,
|
||
requestChars: JSON.stringify(body).length, requestBytes: Buffer.byteLength(JSON.stringify(body)), usage,
|
||
toolNames: audit.calls.map(c => c.name), finish: audit.finishes, nativeFunctionCalls: audit.calls.length, literalEos: audit.literalEos });
|
||
}
|
||
}
|
||
for (const phase of ['A', 'B', 'C']) {
|
||
const stage = JSON.parse(await fs.readFile(path.join(root, 'long-context', `accepted-${phase}.json`), 'utf8'));
|
||
stages.push({ phase, processId: stage.processId, realApiDialogueTurns: stage.realUserTurns, modelSteps: stage.turns.reduce((n, t) => n + t.rounds, 0), constructedHistoryMessages: stage.seededMessages,
|
||
compaction: Boolean(stage.compaction), tokensBeforeCompaction: stage.compaction?.tokensBefore, sessionFile: stage.sessionFile });
|
||
transcript.push(`## 阶段${phase} · 进程${stage.processId}`, '');
|
||
// A turn record stores the final response in text; the exact prompt stays in its attempt file.
|
||
for (const turn of stage.turns) {
|
||
const attempt = JSON.parse(await fs.readFile(path.join(root, 'long-context', `${phase}-${turn.id}-attempt.json`), 'utf8'));
|
||
transcript.push(`**用户 ${phase}-${turn.id}**:${attempt.text}`, '', `**Agent**:${turn.text}`, '');
|
||
}
|
||
if (stage.compaction) transcript.push('本阶段结束后已压缩会话,下一阶段由新进程读取同一会话文件。', '');
|
||
}
|
||
assert.equal(new Set(records.map(r => r.id)).size, records.length);
|
||
assert.equal(new Set(stages.map(s => s.processId)).size, 3);
|
||
assert.equal(new Set(stages.map(s => s.sessionFile)).size, 1);
|
||
const report = { at: new Date().toISOString(), model: model.id, protocol: 'native-tools', newGenerationRequests: records.length,
|
||
requestsWithNativeFunctionCall: records.filter(r => r.nativeFunctionCalls).length, newUnknownRequests: 0, originalUnknown,
|
||
realApiDialogueTurns: stages.reduce((n, s) => n + s.realApiDialogueTurns, 0), constructedHistoryMessages: stages.reduce((n, s) => n + s.constructedHistoryMessages, 0),
|
||
compactions: stages.filter(s => s.compaction).length, crossProcessRestarts: 2, maxPromptTokens: Math.max(...records.map(r => r.usage?.prompt_tokens || 0)),
|
||
contractSource: 'https://api.vip98k.com/api/v2/catalog/models', requestBodiesMatchNativeHash: true, publishedFieldsOnly: true, stages, records };
|
||
await atomic(path.join(root, 'final-live-summary.json'), report);
|
||
await fs.writeFile(path.join(root, 'long-context-transcript.md'), transcript.join('\n'));
|
||
console.log(JSON.stringify({ model: report.model, generationRequests: records.length, nativeFunctionRequests: report.requestsWithNativeFunctionCall, realDialogueTurns: report.realApiDialogueTurns,
|
||
constructedHistoryMessages: report.constructedHistoryMessages, compactions: report.compactions, restarts: report.crossProcessRestarts, maxPromptTokens: report.maxPromptTokens,
|
||
newUnknownRequests: 0, originalUnknownStillHeld: true, requestBodiesMatchNativeHash: true, publishedFieldsOnly: true }));
|