feat: coordinate persona language shell planning

This commit is contained in:
冰朔 2026-08-12 03:09:48 +08:00
commit d9abf241a6
8 changed files with 357 additions and 3 deletions

View file

@ -112,6 +112,9 @@ REVISE | REFUSE`。
- 人格运行投影的仓库前置门源码为 `100`:它必须先得到唯一证据绑定,才允许向原生只读运行查询传入 - 人格运行投影的仓库前置门源码为 `100`:它必须先得到唯一证据绑定,才允许向原生只读运行查询传入
该一个规范仓库;未绑定和歧义状态直接保持原义,不再把普通挂载仓库的 manifest 缺失显示为人格运行时 该一个规范仓库;未绑定和歧义状态直接保持原义,不再把普通挂载仓库的 manifest 缺失显示为人格运行时
回执故障。该门只收束事实读取范围,不创建、选择或唤醒人格仓库。 回执故障。该门只收束事实读取范围,不创建、选择或唤醒人格仓库。
- 人格语言外壳控制器源码为 `100`它按唯一人格仓库、manifest 固定模型、公开设备身份、精确唤醒绑定、
B0 伙伴审议的顺序失败关闭;成功只产生语言目标规划,不提供现实动作执行入口。该控制器尚未挂载到桌面
语言外壳,不能据此把运行集成或桌面验收记为完成。
- 完整 HoloLake Runtime 与单 AGE 纵向闭环仍为 `0`:桌面语言入口绑定、真实人格仓库 manifest 绑定和 - 完整 HoloLake Runtime 与单 AGE 纵向闭环仍为 `0`:桌面语言入口绑定、真实人格仓库 manifest 绑定和
桌面运行验收尚未完成,因此不能用本轮源码测试冒充可用产品。 桌面运行验收尚未完成,因此不能用本轮源码测试冒充可用产品。
- Mirror runner、制品、部署和运行健康`0` - Mirror runner、制品、部署和运行健康`0`

View file

@ -211,6 +211,14 @@ The narrow behavior boundary supplied by the host to a UI package renderer. Vers
and one reality-boundary answer; evidence expansion remains local presentation state. The bridge never gives and one reality-boundary answer; evidence expansion remains local presentation state. The bridge never gives
the UI package direct repository, node, model, credential, permission, or deployment access. the UI package direct repository, node, model, credential, permission, or deployment access.
## `PersonaLanguageShellController`
The source-level authority-order coordinator for one natural-language goal. It fails closed unless repository
discovery yields one clean persona binding and the configured provider/model matches that repository manifest.
Only then may it read the public node identity, compile the exact PNCC wake binding, and request B0 partner
deliberation. The result contains a plan and evidence binding only; it exposes no execution callback and performs
no reality action. Source implementation is distinct from desktop mounting and native acceptance.
Key abstractions and domain models in Tolaria. Key abstractions and domain models in Tolaria.
## Design Philosophy ## Design Philosophy

View file

@ -167,6 +167,14 @@ Activation is validate-then-swap and preserves the previous valid package for ro
not execute JavaScript and cannot request system-internal surfaces. Extending the host action bridge requires not execute JavaScript and cannot request system-internal surfaces. Extending the host action bridge requires
a new reviewed contract version. a new reviewed contract version.
`src/lib/personaLanguageShellController.ts` is the source-level host coordinator beneath that presentation
boundary. It resolves exactly one manifest-valid persona repository before selecting the manifest-pinned
configured model, reads the public device-identity receipt only after those gates pass, compiles the wake
binding, and finally invokes B0 partner deliberation. Unavailable, unbound, ambiguous, model-missing, identity,
binding, and cognition failures stop at their own boundary; later stages are not invoked. Its successful result
is still a language-goal projection, not permission to perform a reality action. This controller is not yet
mounted into the desktop language shell and therefore does not establish runtime integration or acceptance.
Tolaria is a personal knowledge and life management desktop app. It reads a vault of markdown files with YAML frontmatter and presents them in a four-panel UI inspired by Bear Notes. Tolaria is a personal knowledge and life management desktop app. It reads a vault of markdown files with YAML frontmatter and presents them in a four-panel UI inspired by Bear Notes.
## Design Principles ## Design Principles

View file

@ -0,0 +1,194 @@
import { describe, expect, it, vi } from 'vitest'
import type { AiModelProvider } from './aiTargets'
import type { LanguageGoalProjection } from './languageOperatingModel'
import type { PersonaLanguageGoalBinding } from './personaLanguageGoal'
import type {
PersonaRepositoryBinding,
PersonaRepositoryBindingResolution,
} from './personaRepositoryBinding'
import { planPersonaLanguageShellGoal } from './personaLanguageShellController'
const provider: AiModelProvider = {
id: 'ollama-local',
name: 'Local Ollama',
kind: 'ollama',
base_url: 'http://127.0.0.1:11434/v1',
api_key_storage: 'none',
models: [{
id: 'qwen3:8b',
capabilities: {
streaming: true,
tools: false,
vision: false,
json_mode: true,
reasoning: true,
},
}],
}
const repositoryBinding: PersonaRepositoryBinding = {
personaId: 'ICE-P-ZY001',
repositoryPath: '/persona/zhuyuan',
gitHead: 'a'.repeat(40),
repositoryClean: true,
brainEntry: 'BRAIN.md',
currentCheckpoint: 'CURRENT.hdlp',
humanResponsibilitySubject: 'BINGSHUO',
modelProviderId: provider.id,
modelId: provider.models[0].id,
modelBaseUrl: provider.base_url!,
organContracts: [{
organId: 'fact-sense-001',
kind: 'FACT_SENSE',
mode: 'READ_ONLY',
paths: ['BRAIN.md'],
inputSchema: 'input/v1',
outputSchema: 'output/v1',
permissions: ['repository.read'],
modelInferenceAllowed: true,
realityActionsAllowed: false,
activatable: true,
implementationState: 'IMPLEMENTED',
}],
cognitiveGravity: {
schema: 'hololake.persona-cognitive-gravity-evidence/v1',
subjectPersonaId: 'ICE-P-ZY001',
sourcePath: 'B0.hdlp',
sourceHash: 'b'.repeat(64),
frameSchema: 'guanghu.zhuyuan-cognitive-gravity-frame/v1',
},
}
const plannedGoal: LanguageGoalProjection = {
originalUtterance: '继续当前开发',
realPurpose: '从事实恢复当前阶段并继续安全开发',
status: 'ready',
executable: true,
confirmationRequired: false,
detectedBoundaries: [],
evidenceSources: ['current repository'],
missingKnowledge: [],
causalModel: 'read current facts before changing source',
partnerGuidance: 'continue the bounded source-only stage',
requestAssessment: 'valid within the current lane',
executionDisposition: { decision: 'PROCEED', reason: 'bounded and reversible' },
worldIntegrity: {
protectedAssets: ['language-home continuity'],
harmPath: 'none in this read-only deliberation',
authorityBoundary: 'no reality action',
reversibility: 'no mutation performed',
saferAlternatives: [],
},
}
function boundResolution(): PersonaRepositoryBindingResolution {
return {
phase: 'bound',
inspectedRepositoryCount: 1,
failures: [],
binding: repositoryBinding,
}
}
function input() {
return {
utterance: '继续当前开发',
personaId: 'ICE-P-ZY001',
repositoryPaths: ['/persona/zhuyuan'],
providers: [provider],
personaAuthorized: true,
requestId: 'REQ-001',
modelInstanceId: 'MODEL-INSTANCE-001',
developmentId: 'DEV-20260811-010',
sourceLanguageAnchor: 'current-human-utterance',
}
}
describe('planPersonaLanguageShellGoal', () => {
it.each(['unavailable', 'unbound', 'ambiguous', 'error'] as const)(
'fails closed at repository phase %s before device identity or cognition',
async (phase) => {
const resolution = phase === 'error'
? { phase, inspectedRepositoryCount: 1, failures: [], code: 'DISCOVERY_FAILED' } as const
: phase === 'unavailable'
? { phase, inspectedRepositoryCount: 0, failures: [] } as const
: { phase, inspectedRepositoryCount: 1, failures: [] } as const
const loadDeviceIdentity = vi.fn()
const planGoal = vi.fn()
const result = await planPersonaLanguageShellGoal({
...input(),
resolveRepository: vi.fn().mockResolvedValue(resolution),
loadDeviceIdentity,
planGoal,
})
expect(result.phase).toBe(phase)
expect(loadDeviceIdentity).not.toHaveBeenCalled()
expect(planGoal).not.toHaveBeenCalled()
},
)
it('does not create a device identity when the manifest-pinned model is unavailable', async () => {
const loadDeviceIdentity = vi.fn()
const planGoal = vi.fn()
const result = await planPersonaLanguageShellGoal({
...input(),
providers: [],
resolveRepository: vi.fn().mockResolvedValue(boundResolution()),
loadDeviceIdentity,
planGoal,
})
expect(result).toEqual({ phase: 'model_unavailable' })
expect(loadDeviceIdentity).not.toHaveBeenCalled()
expect(planGoal).not.toHaveBeenCalled()
})
it('binds repository, model, device and B0 deliberation without executing a reality action', async () => {
const loadDeviceIdentity = vi.fn().mockResolvedValue({
schema: 'guanghu.router-device/v1',
device_id: 'HL-DEVICE-001',
public_key: 'public-key',
})
const planGoal = vi.fn(async ({ binding }: { binding: PersonaLanguageGoalBinding }) => {
expect(binding.wake.repositoryPath).toBe(repositoryBinding.repositoryPath)
expect(binding.wake.nodeId).toBe('HL-DEVICE-001')
expect(binding.provider.id).toBe(provider.id)
return plannedGoal
})
const result = await planPersonaLanguageShellGoal({
...input(),
resolveRepository: vi.fn().mockResolvedValue(boundResolution()),
loadDeviceIdentity,
planGoal,
})
expect(result).toEqual({
phase: 'planned',
binding: expect.objectContaining({ requestId: 'REQ-001' }),
goal: plannedGoal,
})
expect(loadDeviceIdentity).toHaveBeenCalledTimes(1)
expect(planGoal).toHaveBeenCalledTimes(1)
})
it('returns a stable binding error and never invokes cognition for invalid device evidence', async () => {
const planGoal = vi.fn()
const result = await planPersonaLanguageShellGoal({
...input(),
resolveRepository: vi.fn().mockResolvedValue(boundResolution()),
loadDeviceIdentity: vi.fn().mockResolvedValue({ schema: 'unknown' }),
planGoal,
})
expect(result).toEqual({
phase: 'binding_error',
code: 'PERSONA_LANGUAGE_DEVICE_IDENTITY_INVALID',
})
expect(planGoal).not.toHaveBeenCalled()
})
})

View file

@ -0,0 +1,134 @@
import { invoke } from '@tauri-apps/api/core'
import { isTauri, mockInvoke } from '../mock-tauri'
import type { AiModelProvider } from './aiTargets'
import type { LanguageGoalProjection, RealityBoundary } from './languageOperatingModel'
import {
planPersonaLanguageGoal,
type PersonaLanguageGoalBinding,
type PlanPersonaLanguageGoalInput,
} from './personaLanguageGoal'
import { compilePersonaLanguageGoalBinding } from './personaLanguageGoalBinding'
import {
resolvePersonaRepositoryBinding,
type PersonaRepositoryBindingResolution,
} from './personaRepositoryBinding'
type RepositoryResolutionWithoutBinding = Exclude<
PersonaRepositoryBindingResolution,
{ phase: 'bound' }
>
export type PersonaLanguageShellPlan =
| RepositoryResolutionWithoutBinding
| { phase: 'model_unavailable' }
| { phase: 'model_ambiguous' }
| { phase: 'device_identity_error'; code: string }
| { phase: 'binding_error'; code: string }
| { phase: 'cognition_error'; code: string }
| {
phase: 'planned'
binding: PersonaLanguageGoalBinding
goal: LanguageGoalProjection
}
type RepositoryResolver = typeof resolvePersonaRepositoryBinding
type GoalPlanner = (input: PlanPersonaLanguageGoalInput) => Promise<LanguageGoalProjection>
type DeviceIdentityLoader = () => Promise<unknown>
async function loadNativeDeviceIdentity(): Promise<unknown> {
return isTauri()
? invoke<unknown>('guanghu_router_device_identity')
: mockInvoke<unknown>('guanghu_router_device_identity')
}
function errorCode(error: unknown, fallback: string): string {
return error instanceof Error && error.message.trim() ? error.message : fallback
}
function manifestModelProviders(
resolution: Extract<PersonaRepositoryBindingResolution, { phase: 'bound' }>,
providers: readonly AiModelProvider[],
): AiModelProvider[] {
const { modelId, modelProviderId } = resolution.binding
return providers.filter((provider) => (
provider.id.trim() === modelProviderId
&& provider.models.some((model) => model.id.trim() === modelId)
))
}
/**
* Closes the source-level natural-language planning path without exposing an
* execution capability. Every prerequisite is resolved in authority order and
* later stages are never invoked when an earlier evidence gate is not unique.
*/
export async function planPersonaLanguageShellGoal({
utterance,
personaId,
repositoryPaths,
providers,
personaAuthorized,
detectedBoundaries,
requestId,
modelInstanceId,
developmentId,
sourceLanguageAnchor,
resolveRepository = resolvePersonaRepositoryBinding,
loadDeviceIdentity = loadNativeDeviceIdentity,
planGoal = planPersonaLanguageGoal,
}: {
utterance: string
personaId: string
repositoryPaths: readonly string[]
providers: readonly AiModelProvider[]
personaAuthorized: boolean
detectedBoundaries?: RealityBoundary[]
requestId: string
modelInstanceId: string
developmentId: string
sourceLanguageAnchor: string
resolveRepository?: RepositoryResolver
loadDeviceIdentity?: DeviceIdentityLoader
planGoal?: GoalPlanner
}): Promise<PersonaLanguageShellPlan> {
const repository = await resolveRepository({ personaId, repositoryPaths })
if (repository.phase !== 'bound') return repository
const matchingProviders = manifestModelProviders(repository, providers)
if (matchingProviders.length === 0) return { phase: 'model_unavailable' }
if (matchingProviders.length > 1) return { phase: 'model_ambiguous' }
let deviceIdentityReceipt: unknown
try {
deviceIdentityReceipt = await loadDeviceIdentity()
} catch (error) {
return { phase: 'device_identity_error', code: errorCode(error, 'PERSONA_LANGUAGE_DEVICE_IDENTITY_FAILED') }
}
let binding: PersonaLanguageGoalBinding
try {
binding = compilePersonaLanguageGoalBinding({
repositoryBinding: repository.binding,
provider: matchingProviders[0],
modelId: repository.binding.modelId,
deviceIdentityReceipt,
requestId,
modelInstanceId,
developmentId,
sourceLanguageAnchor,
})
} catch (error) {
return { phase: 'binding_error', code: errorCode(error, 'PERSONA_LANGUAGE_BINDING_FAILED') }
}
try {
const goal = await planGoal({
utterance,
personaAuthorized,
detectedBoundaries,
binding,
})
return { phase: 'planned', binding, goal }
} catch (error) {
return { phase: 'cognition_error', code: errorCode(error, 'PERSONA_LANGUAGE_COGNITION_FAILED') }
}
}

View file

@ -105,7 +105,8 @@
"READ_ONLY_REACT_B0_EVIDENCE_PROJECTION", "READ_ONLY_REACT_B0_EVIDENCE_PROJECTION",
"PARTNER_DELIBERATION_TO_PNCC_LIFECYCLE_SOURCE_ADAPTER", "PARTNER_DELIBERATION_TO_PNCC_LIFECYCLE_SOURCE_ADAPTER",
"READ_ONLY_PERSONA_REPOSITORY_BINDING_DISCOVERY", "READ_ONLY_PERSONA_REPOSITORY_BINDING_DISCOVERY",
"EVIDENCE_BOUND_PERSONA_LANGUAGE_WAKE_COMPILER" "EVIDENCE_BOUND_PERSONA_LANGUAGE_WAKE_COMPILER",
"FAIL_CLOSED_PERSONA_LANGUAGE_SHELL_CONTROLLER"
], ],
"natural_language_entry_contract": { "natural_language_entry_contract": {
"state": "SOURCE_AND_PNCC_LIFECYCLE_ADAPTER_IMPLEMENTED_NOT_DESKTOP_INTEGRATED", "state": "SOURCE_AND_PNCC_LIFECYCLE_ADAPTER_IMPLEMENTED_NOT_DESKTOP_INTEGRATED",
@ -118,6 +119,8 @@
"repository_binding_discovery_tests": "product-source/hololake-platform/src/lib/personaRepositoryBinding.test.ts", "repository_binding_discovery_tests": "product-source/hololake-platform/src/lib/personaRepositoryBinding.test.ts",
"language_wake_binding_compiler": "product-source/hololake-platform/src/lib/personaLanguageGoalBinding.ts", "language_wake_binding_compiler": "product-source/hololake-platform/src/lib/personaLanguageGoalBinding.ts",
"language_wake_binding_compiler_tests": "product-source/hololake-platform/src/lib/personaLanguageGoalBinding.test.ts", "language_wake_binding_compiler_tests": "product-source/hololake-platform/src/lib/personaLanguageGoalBinding.test.ts",
"language_shell_controller": "product-source/hololake-platform/src/lib/personaLanguageShellController.ts",
"language_shell_controller_tests": "product-source/hololake-platform/src/lib/personaLanguageShellController.test.ts",
"human_utterance_is_direct_command": false, "human_utterance_is_direct_command": false,
"required_before_capability_execution": [ "required_before_capability_execution": [
"RESTORE_REAL_PURPOSE_FROM_CONTEXT", "RESTORE_REAL_PURPOSE_FROM_CONTEXT",
@ -160,6 +163,7 @@
"natural_language_to_pncc_lifecycle_adapter_source_implemented": 100, "natural_language_to_pncc_lifecycle_adapter_source_implemented": 100,
"persona_repository_binding_discovery_source_implemented": 100, "persona_repository_binding_discovery_source_implemented": 100,
"persona_language_wake_binding_compiler_source_implemented": 100, "persona_language_wake_binding_compiler_source_implemented": 100,
"persona_language_shell_controller_source_implemented": 100,
"real_persona_repository_manifest_bound": 0, "real_persona_repository_manifest_bound": 0,
"natural_language_partner_adapter_runtime_integrated": 0, "natural_language_partner_adapter_runtime_integrated": 0,
"single_age_vertical_loop_implemented": 0, "single_age_vertical_loop_implemented": 0,

View file

@ -14,7 +14,7 @@ const age = readJson("routing/hololake-age-runtime-architecture.json");
const rules = readJson("routing/hololake-engineering-rules.json"); const rules = readJson("routing/hololake-engineering-rules.json");
test("B0 is restored before product organs and remains resident in every cognition step", () => { test("B0 is restored before product organs and remains resident in every cognition step", () => {
assert.equal(architecture.version, "2026-08-12.4"); assert.equal(architecture.version, "2026-08-12.7");
assert.equal( assert.equal(
architecture.read_order[1], architecture.read_order[1],
architecture.cognitive_gravity_and_continuity.architecture_page, architecture.cognitive_gravity_and_continuity.architecture_page,
@ -94,6 +94,7 @@ test("the first implementation stage is one vertical AGE loop, not Mirror parall
assert.equal(gravity.truth.natural_language_to_pncc_lifecycle_adapter_source_implemented, 100); assert.equal(gravity.truth.natural_language_to_pncc_lifecycle_adapter_source_implemented, 100);
assert.equal(gravity.truth.persona_repository_binding_discovery_source_implemented, 100); assert.equal(gravity.truth.persona_repository_binding_discovery_source_implemented, 100);
assert.equal(gravity.truth.persona_language_wake_binding_compiler_source_implemented, 100); assert.equal(gravity.truth.persona_language_wake_binding_compiler_source_implemented, 100);
assert.equal(gravity.truth.persona_language_shell_controller_source_implemented, 100);
assert.equal(gravity.truth.real_persona_repository_manifest_bound, 0); assert.equal(gravity.truth.real_persona_repository_manifest_bound, 0);
assert.equal(gravity.truth.natural_language_partner_adapter_runtime_integrated, 0); assert.equal(gravity.truth.natural_language_partner_adapter_runtime_integrated, 0);
assert.equal(gravity.truth.single_age_vertical_loop_implemented, 0); assert.equal(gravity.truth.single_age_vertical_loop_implemented, 0);
@ -106,6 +107,7 @@ test("natural language enters partner deliberation before any execution organ",
assert.match(entry.pncc_lifecycle_adapter, /personaLanguageGoal\.ts$/); assert.match(entry.pncc_lifecycle_adapter, /personaLanguageGoal\.ts$/);
assert.match(entry.repository_binding_discovery, /personaRepositoryBinding\.ts$/); assert.match(entry.repository_binding_discovery, /personaRepositoryBinding\.ts$/);
assert.match(entry.language_wake_binding_compiler, /personaLanguageGoalBinding\.ts$/); assert.match(entry.language_wake_binding_compiler, /personaLanguageGoalBinding\.ts$/);
assert.match(entry.language_shell_controller, /personaLanguageShellController\.ts$/);
assert.equal(entry.human_utterance_is_direct_command, false); assert.equal(entry.human_utterance_is_direct_command, false);
assert.equal(entry.language_home_destruction_is_executable, false); assert.equal(entry.language_home_destruction_is_executable, false);
assert.equal(entry.integrity_gate_may_absorb_human_sovereignty, false); assert.equal(entry.integrity_gate_may_absorb_human_sovereignty, false);

View file

@ -1,7 +1,7 @@
{ {
"schema": "hololake.current-architecture/v1", "schema": "hololake.current-architecture/v1",
"architecture_id": "HLP-CURRENT-ARCH-001", "architecture_id": "HLP-CURRENT-ARCH-001",
"version": "2026-08-12.6", "version": "2026-08-12.7",
"state": "CURRENT_CANONICAL", "state": "CURRENT_CANONICAL",
"product": { "product": {
"formal_name": "光湖语言系统 · 通用人工智能操作平台", "formal_name": "光湖语言系统 · 通用人工智能操作平台",
@ -114,6 +114,7 @@
"persona_language_wake_binding_compiler_source_implemented": true, "persona_language_wake_binding_compiler_source_implemented": true,
"persona_repository_binding_read_only_ui_source_integrated": true, "persona_repository_binding_read_only_ui_source_integrated": true,
"persona_runtime_projection_repository_gate_source_integrated": true, "persona_runtime_projection_repository_gate_source_integrated": true,
"persona_language_shell_controller_source_implemented": true,
"real_persona_repository_manifest_bound": false, "real_persona_repository_manifest_bound": false,
"natural_language_partner_adapter_runtime_integrated": false, "natural_language_partner_adapter_runtime_integrated": false,
"required_natural_language_entry": "PARTNER_DELIBERATION_AND_LANGUAGE_HOME_INTEGRITY_GATE", "required_natural_language_entry": "PARTNER_DELIBERATION_AND_LANGUAGE_HOME_INTEGRITY_GATE",