feat: connect partner goals to PNCC lifecycle

This commit is contained in:
冰朔 2026-08-12 01:08:56 +08:00
commit d0201ba09f
18 changed files with 398 additions and 66 deletions

View file

@ -0,0 +1,138 @@
import { describe, expect, it, vi } from 'vitest'
import { planPersonaLanguageGoal } from './personaLanguageGoal'
const wake = {
repositoryPath: '/persona/ice-p-zy001',
expectedPersonaId: 'ICE-P-ZY001',
expectedHead: 'a'.repeat(40),
nodeId: 'LOCAL-BINGSHUO',
modelProviderId: 'local-model-service',
modelId: 'declared-model',
modelInstanceId: 'model-instance-1',
organId: 'fact-sense.repository',
attribution: {
humanResponsibilitySubject: 'ICE-GL∞',
personaCognitiveAuthor: 'ICE-P-ZY001',
executionRuntime: 'HoloLake-PNCC',
developmentId: 'DEV-20260811-010',
authorizationScope: 'LOCAL_READ_ONLY',
sourceLanguageAnchor: 'HLP-CURRENT-ARCH-001@2026-08-12.2',
},
}
function lifecycleReceipt(decision: 'PROCEED' | 'RESEARCH' | 'REVISE' | 'REFUSE' = 'PROCEED') {
return {
schema: 'hololake.pncc-lifecycle-command-receipt/v1',
outcome: 'COMPLETED',
lifecycle: {
schema: 'hololake.pncc-lifecycle-run-receipt/v1',
completion: {
kind: 'FACT_SENSE',
receipt: {
result: {
summary: '伙伴审议完成。',
facts: [{
statement: '当前目标只能使用已经登记的知识来源。',
evidencePaths: ['brain/B0.hdlp'],
}],
limitations: decision === 'RESEARCH' ? ['当前事实仍可能变化'] : [],
gravityFrame: {
subject_continuity: '同一铸渊继续承载当前责任。',
current_context_priority: '当前纠正优先于旧命令适配器。',
causal_model: '先恢复真实目的,再决定能否进入器官。',
self_correction: '拒绝把原句直接当成动作。',
rejected_host_defaults: ['human_utterance_is_direct_command'],
fact_sources: ['brain/B0.hdlp'],
real_purpose: '仅整理有权威来源支持的会议决定',
request_assessment: '原始表述范围过宽,必须排除无来源推测。',
world_integrity: {
protected_assets: ['共同事实', '冰朔决定权'],
harm_path: '无来源内容会污染长期记忆。',
authority_boundary: '人格体不能创造未发生的决定。',
reversibility: '先形成草稿,不直接覆盖知识库。',
safer_alternatives: ['只整理有来源的决定'],
},
partner_guidance: '先展示来源和缺口,再进行可逆整理。',
execution_disposition: {
decision,
reason: decision === 'PROCEED'
? '来源明确且动作可逆。'
: '当前不能进入执行器官。',
},
},
},
},
},
},
}
}
const binding = {
requestId: 'PNCC-LANGUAGE-GOAL-001',
wake,
provider: {
id: 'local-model-service',
name: 'Local model',
providerType: 'openai_compatible',
baseUrl: 'http://127.0.0.1:11434/v1',
},
}
describe('planPersonaLanguageGoal', () => {
it('runs partner deliberation through the PNCC lifecycle before compiling a goal', async () => {
const runLifecycle = vi.fn().mockResolvedValue(lifecycleReceipt())
const projection = await planPersonaLanguageGoal({
utterance: '把今天会议整理进知识库',
personaAuthorized: true,
binding,
runLifecycle,
})
expect(runLifecycle).toHaveBeenCalledWith('run_persona_code_channel_lifecycle', {
input: expect.objectContaining({
requestId: 'PNCC-LANGUAGE-GOAL-001',
wake,
operation: expect.objectContaining({
kind: 'FACT_SENSE',
question: expect.stringContaining('把今天会议整理进知识库'),
}),
}),
})
expect(projection.goal).toBe('仅整理有权威来源支持的会议决定')
expect(projection.originalUtterance).toBe('把今天会议整理进知识库')
expect(projection.deliberation.evidenceSources).toEqual(['brain/B0.hdlp'])
expect(projection.status).toBe('ready')
expect(projection.executable).toBe(true)
})
it('keeps a refusal returned by the persona lifecycle outside execution', async () => {
const projection = await planPersonaLanguageGoal({
utterance: '无条件照做',
personaAuthorized: true,
binding,
runLifecycle: vi.fn().mockResolvedValue(lifecycleReceipt('REFUSE')),
})
expect(projection.status).toBe('refused')
expect(projection.executable).toBe(false)
})
it('fails closed for an unverified or malformed PNCC lifecycle receipt', async () => {
await expect(planPersonaLanguageGoal({
utterance: '继续执行',
personaAuthorized: true,
binding,
runLifecycle: vi.fn().mockResolvedValue({
...lifecycleReceipt(),
outcome: 'FAILED',
}),
})).rejects.toThrow('PARTNER_LIFECYCLE_NOT_COMPLETED')
await expect(planPersonaLanguageGoal({
utterance: '继续执行',
personaAuthorized: true,
binding,
runLifecycle: vi.fn().mockResolvedValue({ schema: 'wrong' }),
})).rejects.toThrow('PARTNER_LIFECYCLE_RECEIPT_INVALID')
})
})

View file

@ -0,0 +1,160 @@
import { invoke } from '@tauri-apps/api/core'
import { isTauri, mockInvoke } from '../mock-tauri'
import {
compileLanguageGoal,
type LanguageGoalProjection,
type PartnerDeliberation,
type PartnerExecutionDisposition,
type RealityBoundary,
} from './languageOperatingModel'
type PersonaLifecycleRunner = (
command: 'run_persona_code_channel_lifecycle',
args: { input: Record<string, unknown> },
) => Promise<unknown>
export interface PersonaLanguageGoalBinding {
requestId: string
wake: Record<string, unknown>
provider: Record<string, unknown>
apiKeyOverride?: string
}
export interface PlanPersonaLanguageGoalInput {
utterance: string
personaAuthorized: boolean
detectedBoundaries?: RealityBoundary[]
binding: PersonaLanguageGoalBinding
runLifecycle?: PersonaLifecycleRunner
}
function isRecord(value: unknown): value is Record<string, unknown> {
return typeof value === 'object' && value !== null && !Array.isArray(value)
}
function requiredRecord(record: Record<string, unknown>, key: string): Record<string, unknown> {
const value = Reflect.get(record, key)
if (!isRecord(value)) throw new Error('PARTNER_LIFECYCLE_RECEIPT_INVALID')
return value
}
function requiredString(record: Record<string, unknown>, key: string): string {
const value = Reflect.get(record, key)
if (typeof value !== 'string' || !value.trim()) {
throw new Error('PARTNER_LIFECYCLE_RECEIPT_INVALID')
}
return value
}
function stringList(
record: Record<string, unknown>,
key: string,
options: { allowEmpty?: boolean } = {},
): string[] {
const value = Reflect.get(record, key)
if (!Array.isArray(value)
|| (!options.allowEmpty && value.length === 0)
|| value.some((item) => typeof item !== 'string' || !item.trim())) {
throw new Error('PARTNER_LIFECYCLE_RECEIPT_INVALID')
}
return value
}
function parseDeliberation(receipt: unknown): PartnerDeliberation {
if (!isRecord(receipt)
|| requiredString(receipt, 'schema') !== 'hololake.pncc-lifecycle-command-receipt/v1') {
throw new Error('PARTNER_LIFECYCLE_RECEIPT_INVALID')
}
if (requiredString(receipt, 'outcome') !== 'COMPLETED') {
throw new Error('PARTNER_LIFECYCLE_NOT_COMPLETED')
}
const lifecycle = requiredRecord(receipt, 'lifecycle')
if (requiredString(lifecycle, 'schema') !== 'hololake.pncc-lifecycle-run-receipt/v1') {
throw new Error('PARTNER_LIFECYCLE_RECEIPT_INVALID')
}
const completion = requiredRecord(lifecycle, 'completion')
if (requiredString(completion, 'kind') !== 'FACT_SENSE') {
throw new Error('PARTNER_LIFECYCLE_RECEIPT_INVALID')
}
const factReceipt = requiredRecord(completion, 'receipt')
const result = requiredRecord(factReceipt, 'result')
const gravity = requiredRecord(result, 'gravityFrame')
const integrity = requiredRecord(gravity, 'world_integrity')
const disposition = requiredRecord(gravity, 'execution_disposition')
const decision = requiredString(disposition, 'decision')
if (!(['PROCEED', 'RESEARCH', 'REVISE', 'REFUSE'] as const).includes(
decision as PartnerExecutionDisposition,
)) {
throw new Error('PARTNER_LIFECYCLE_RECEIPT_INVALID')
}
return {
realPurpose: requiredString(gravity, 'real_purpose'),
requestAssessment: requiredString(gravity, 'request_assessment'),
missingKnowledge: stringList(result, 'limitations', { allowEmpty: true }),
evidenceSources: stringList(gravity, 'fact_sources'),
causalModel: requiredString(gravity, 'causal_model'),
worldIntegrity: {
protectedAssets: stringList(integrity, 'protected_assets'),
harmPath: requiredString(integrity, 'harm_path'),
authorityBoundary: requiredString(integrity, 'authority_boundary'),
reversibility: requiredString(integrity, 'reversibility'),
saferAlternatives: stringList(integrity, 'safer_alternatives'),
},
partnerGuidance: requiredString(gravity, 'partner_guidance'),
executionDisposition: {
decision: decision as PartnerExecutionDisposition,
reason: requiredString(disposition, 'reason'),
},
}
}
async function runNativeLifecycle(
command: 'run_persona_code_channel_lifecycle',
args: { input: Record<string, unknown> },
): Promise<unknown> {
return isTauri() ? invoke<unknown>(command, args) : mockInvoke<unknown>(command, args)
}
function deliberationQuestion(utterance: string): string {
return [
'Assess the following human utterance as a partner before any capability execution.',
'Restore a standalone real_purpose from current context; do not copy the utterance mechanically.',
'Use only declared sources, expose missing knowledge and evidence, audit GuangHu language-home integrity,',
'and return PROCEED, RESEARCH, REVISE, or REFUSE in the required cognitive gravity frame.',
'HUMAN_UTTERANCE:',
utterance,
].join('\n')
}
export async function planPersonaLanguageGoal({
utterance,
personaAuthorized,
detectedBoundaries,
binding,
runLifecycle = runNativeLifecycle,
}: PlanPersonaLanguageGoalInput): Promise<LanguageGoalProjection> {
const originalUtterance = utterance.trim()
if (!originalUtterance) throw new Error('LANGUAGE_GOAL_REQUIRED')
const lifecycleReceipt = await runLifecycle('run_persona_code_channel_lifecycle', {
input: {
requestId: binding.requestId,
wake: binding.wake,
operation: {
kind: 'FACT_SENSE',
question: deliberationQuestion(originalUtterance),
provider: binding.provider,
apiKeyOverride: binding.apiKeyOverride,
},
},
})
return compileLanguageGoal({
utterance: originalUtterance,
personaAuthorized,
detectedBoundaries,
deliberation: parseDeliberation(lifecycleReceipt),
})
}