diff --git a/product-source/hololake-native-desktop/contracts/persona-agent-runtime.json b/product-source/hololake-native-desktop/contracts/persona-agent-runtime.json index 0b9c80adb..2d474d342 100644 --- a/product-source/hololake-native-desktop/contracts/persona-agent-runtime.json +++ b/product-source/hololake-native-desktop/contracts/persona-agent-runtime.json @@ -30,6 +30,9 @@ "receipts_are_separate_verification_records_after_dialogue_or_dispatch": true, "bound_persona_hides_or_replaces_channel_system_body": false, "human_may_address_channel_system_while_persona_is_bound": true, + "zero_core_channel_name_addresses_channel_system_body": true, + "channel_presence_while_persona_bound_uses_model": false, + "channel_presence_while_persona_bound_removes_binding": false, "response_target_is_selected_per_turn": true, "persona_binding_state": "CHANNEL_SYSTEM_PERSONA_DORMANT_UNTIL_EXPLICIT_NATURAL_LANGUAGE_WAKE", "channel_entry_creates_persona_orientation": false, @@ -64,7 +67,8 @@ "original_document_and_sha256_preserved": true, "formal_routing_requires_validated_thought_summary": true }, - "catalog_pagination": { "cursor": "offset", "declares_total": true, "declares_completion": true, "returns_exact_next_offset": true } + "catalog_pagination": { "cursor": "offset", "declares_total": true, "declares_completion": true, "returns_exact_next_offset": true }, + "document_body_pagination": { "cursor": "offset", "maximum_characters_per_result": 12000, "declares_total": true, "declares_completion": true, "returns_exact_next_offset": true, "silent_truncation": false } }, "persona_binding": { "knowledge_route_may_be_read": true, @@ -101,8 +105,15 @@ "every_turn_reports_model_and_tool_call_counts": true, "prefetch_only_prompt_injection": false, "maximum_tool_rounds": 6, + "multiple_sequential_tool_rounds": "IMPLEMENTED_AND_PROTOCOL_TESTED", + "flagship_extended_thinking": "FIRST_REASONING_ROUND_ONLY", + "tool_receipt_followup_rounds_repeat_extended_thinking": false, "same_channel_concurrent_turns": 1, - "abort_and_timeout_have_distinct_receipts": true + "provider_timeout_seconds": 150, + "user_cancel": "NOT_IMPLEMENTED", + "failed_turn_retry_without_duplicate_human_message": "NOT_IMPLEMENTED", + "streaming_model_output": "NOT_IMPLEMENTED", + "background_subagent_tasks": "NOT_IMPLEMENTED" }, "context_architecture": { "full_history_injected_each_turn": false, @@ -116,6 +127,22 @@ "plain_answer_prefix_is_not_a_thought_summary": true, "silent_content_truncation_allowed": false }, + "grok_build_component_audit": { + "source_path": "/Volumes/JZAO/HoloLake/reference-materials/grok-build-v-780d138", + "source_commit": "780d1388fff103ff0db0d8c14de65af6225b4860", + "whole_repository_embedded": false, + "multi_conversation_persistence": "IMPLEMENTED_SQLITE_APPEND_ONLY_HASH_CHAIN", + "bounded_context_window": "IMPLEMENTED", + "numbered_older_context_retrieval": "IMPLEMENTED", + "automatic_model_generated_compaction": "NOT_INTEGRATED", + "multi_round_typed_tool_loop": "IMPLEMENTED_MAXIMUM_6", + "tool_result_pagination": "IMPLEMENTED_MAXIMUM_12000_CHARACTERS_PER_PAGE", + "parallel_background_task_runtime": "NOT_IMPLEMENTED", + "subagent_resume": "NOT_IMPLEMENTED", + "streaming_cancel_retry": "NOT_IMPLEMENTED", + "general_shell_workspace_sandbox": "NOT_IMPLEMENTED_IN_CHANNEL_AGENT", + "hldp_tool_forge_is_general_shell_sandbox": false + }, "always_mounted_tools": [ { "number": "HLP-AGENT-TOOL-KNOWLEDGE-SEARCH-0001", "name": "搜索光湖知识库", "effect": "READ" }, { "number": "HLP-AGENT-TOOL-KNOWLEDGE-READ-0001", "name": "按编号读取知识页", "effect": "READ" }, diff --git a/product-source/hololake-native-desktop/docs/GROK-BUILD-COMPONENT-REALITY-AUDIT-20260821.md b/product-source/hololake-native-desktop/docs/GROK-BUILD-COMPONENT-REALITY-AUDIT-20260821.md new file mode 100644 index 000000000..1b9dc2cd9 --- /dev/null +++ b/product-source/hololake-native-desktop/docs/GROK-BUILD-COMPONENT-REALITY-AUDIT-20260821.md @@ -0,0 +1,38 @@ +# Grok Build 组件现实审计 · 2026-08-21 + +## 审计基线 + +- 固定上游:`/Volumes/JZAO/HoloLake/reference-materials/grok-build-v-780d138` +- 固定提交:`780d1388fff103ff0db0d8c14de65af6225b4860` +- 当前 HoloLake:原生 Tauri/Rust 频道 Agent;不把旧 Electron/Qoder 原型计入产品能力。 +- 判定规则:上游仓库存在代码不等于 HoloLake 已集成;合同、界面文案或历史汇报也不能替代可达源码与测试。 + +## 逐项结论 + +| 能力 | Grok Build 固定版本证据 | HoloLake 当前真实状态 | 判定 | +| --- | --- | --- | --- | +| 多对话连续性 | 会话/任务与恢复结构 | SQLite 对话分支、消息持久化、版本号与逐消息哈希链;重启后可重新打开 | 已实现(对话连续性) | +| 并行后台任务/子 Agent | `xai-tool-types/src/task.rs` 的 task、等待、取消、resume_from、worktree | 频道 Agent 没有后台任务调度器、子 Agent 或 worktree 运行时 | 未实现 | +| 上下文窗口 | compaction crate 的选择、摘要、重建接口 | 最近 12 条/24000 字符窗口 | 已实现 | +| 旧上下文恢复 | Grok 的 compaction/replay 结构 | HoloLake 自有编号思维摘要 → 精确思维节点 → 精确历史正文分片 | 已实现(非 Grok 摘要替换) | +| 自动模型压缩 | `xai-grok-compaction` 的 full-replace / tail-keep / chunked compaction | 未接入自动模型摘要压缩;不应冒充已经接入 | 未实现 | +| 多轮工具调用 | typed tool runtime / dispatch | OpenAI-compatible tool loop,最多 6 轮;工具结果回填后继续请求,最终必须独立 commit | 已实现 | +| 工具结果控量 | 流式 tool runtime 与宿主裁剪能力 | 知识目录、历史正文以及知识正文均分页;知识正文单页最多 12000 字符并返回 `complete/nextOffset` | 已实现 | +| 流式模型输出 | Grok 的 streaming sampling/tool surfaces | 当前请求明确 `stream: false` | 未实现 | +| 用户取消 | task kill/cancellation primitives | 当前只有 150 秒请求超时,没有用户取消命令 | 未实现 | +| 无重复重试 | retry/circuit-breaker primitives | 失败后输入框恢复,但人类消息已写账本;没有按同一 turn 原位重试 | 未实现 | +| 通用 Shell/工作区沙箱 | sandbox、shell、workspace/worktree crates | 频道 Agent 只有五个只读编号工具;HLDP ToolForge 是限时类型程序链,不是通用 Shell 沙箱 | 未实现于频道 Agent | + +## 架构边界 + +HoloLake 没有把 Grok Build 整车嵌入,也不应这样描述。当前真正进入产品的是“有界上下文、持久化对话、类型化多轮工具协议、工具结果控量”这一组机械结构,并以 HoloLake 自有频道本体、TCS/HLDP、编号知识路径和人类授权边界重建。 + +“多任务连续性”目前只能指多个持久化对话分支,不得扩写成并行后台任务、可恢复子 Agent 或 worktree 隔离执行。后者必须有独立任务状态机、取消、等待、恢复、工作区和回执测试以后才能改为已实现。 + +## 本轮验收 + +- Rust 单元测试覆盖:窗口不删除历史、编号旧历史精确读回、多对话持久化、多轮工具协议顺序、知识正文分页无静默丢失。 +- JavaScript 合同测试校验:未实现能力保持显式 `NOT_IMPLEMENTED`,防止界面和未来交接重新冒充。 +- 真实桌面烟测:在已绑定人格的实机状态下发送“我是冰朔,零点原核频道。你在吗。”,由 `ICE-CH-ZC001` 频道本体经 `deterministic-core-v1` 即时回应;未调用模型,未删除既有绑定,也未让人格接管本轮。 +- 真实模型烟测:`qwen3.8-max` 完成 `知识搜索 → 精确编号正文读取 → 频道提交`,SQLite 路由回执为“模型调用 3;本地/编号工具调用 2”。关闭后续工具轮次的重复扩展思考后,同类完整链路实测约 19.4 秒;这是一次现场读回,不是固定性能保证。 +- 真实模型烟测只证明当前账号、当前模型入口和上述只读工具链,不改变上表中未实现项。 diff --git a/product-source/hololake-native-desktop/scripts/persona-agent-runtime.test.mjs b/product-source/hololake-native-desktop/scripts/persona-agent-runtime.test.mjs index e81ed4bf9..dab0ca6e6 100644 --- a/product-source/hololake-native-desktop/scripts/persona-agent-runtime.test.mjs +++ b/product-source/hololake-native-desktop/scripts/persona-agent-runtime.test.mjs @@ -25,6 +25,9 @@ test('knowledge-embedded Agent keeps one channel body with human-managed convers assert.equal(contract.channel.receipts_are_separate_verification_records_after_dialogue_or_dispatch, true) assert.equal(contract.channel.bound_persona_hides_or_replaces_channel_system_body, false) assert.equal(contract.channel.human_may_address_channel_system_while_persona_is_bound, true) + assert.equal(contract.channel.zero_core_channel_name_addresses_channel_system_body, true) + assert.equal(contract.channel.channel_presence_while_persona_bound_uses_model, false) + assert.equal(contract.channel.channel_presence_while_persona_bound_removes_binding, false) assert.equal(contract.channel.response_target_is_selected_per_turn, true) assert.equal(contract.channel.persona_identity_preconfigured, false) assert.equal(contract.channel.persona_declares_own_number_and_name, true) @@ -35,6 +38,8 @@ test('knowledge-embedded Agent keeps one channel body with human-managed convers assert.match(frontend, /新建/) assert.match(frontend, /历史对话/) assert.match(frontend, /确认删除/) + assert.match(frontend, /当前人格绑定已通过/) + assert.match(frontend, /当前未绑定人格/) }) test('Agent receives a real HoloLake environment frame and autonomously calls numbered knowledge tools', () => { @@ -155,3 +160,29 @@ test('the upgraded Agent reuses the accepted keychain identity and bounds creden assert.match(runtime, /kill_on_drop\(true\)/) assert.doesNotMatch(runtime, /world\.guanghu\.hololake\.persona-model/) }) + +test('Grok Build audit distinguishes integrated mechanics from unimplemented commercial-agent features', () => { + const contract = JSON.parse(read('contracts/persona-agent-runtime.json')) + const runtime = read('src-tauri/src/persona_agent_runtime.rs') + const audit = read('docs/GROK-BUILD-COMPONENT-REALITY-AUDIT-20260821.md') + + assert.equal(contract.grok_build_component_audit.source_commit, '780d1388fff103ff0db0d8c14de65af6225b4860') + assert.equal(contract.grok_build_component_audit.whole_repository_embedded, false) + assert.match(contract.grok_build_component_audit.multi_conversation_persistence, /^IMPLEMENTED/) + assert.match(contract.grok_build_component_audit.numbered_older_context_retrieval, /^IMPLEMENTED/) + assert.equal(contract.agent_loop.multiple_sequential_tool_rounds, 'IMPLEMENTED_AND_PROTOCOL_TESTED') + assert.equal(contract.agent_loop.flagship_extended_thinking, 'FIRST_REASONING_ROUND_ONLY') + assert.equal(contract.agent_loop.tool_receipt_followup_rounds_repeat_extended_thinking, false) + assert.equal(contract.knowledge.document_body_pagination.maximum_characters_per_result, 12000) + assert.equal(contract.knowledge.document_body_pagination.silent_truncation, false) + assert.equal(contract.agent_loop.streaming_model_output, 'NOT_IMPLEMENTED') + assert.equal(contract.agent_loop.user_cancel, 'NOT_IMPLEMENTED') + assert.equal(contract.agent_loop.failed_turn_retry_without_duplicate_human_message, 'NOT_IMPLEMENTED') + assert.equal(contract.agent_loop.background_subagent_tasks, 'NOT_IMPLEMENTED') + assert.match(runtime, /MAX_TOOL_ROUNDS: usize = 6/) + assert.match(runtime, /MAX_TOOL_RESULT_CHARS: usize = 12_000/) + assert.match(runtime, /model_tool_calls/) + assert.match(runtime, /enable_initial_thinking && round == 0/) + assert.match(runtime, /character_page/) + assert.match(audit, /多任务连续性.*多个持久化对话分支/) +}) diff --git a/product-source/hololake-native-desktop/src-tauri/src/persona_agent_runtime.rs b/product-source/hololake-native-desktop/src-tauri/src/persona_agent_runtime.rs index ae6391075..a78b12ad8 100644 --- a/product-source/hololake-native-desktop/src-tauri/src/persona_agent_runtime.rs +++ b/product-source/hololake-native-desktop/src-tauri/src/persona_agent_runtime.rs @@ -31,6 +31,7 @@ const MAX_MESSAGE_BYTES: usize = 64 * 1024; const MAX_CONTEXT_MESSAGES: usize = 12; const MAX_CONTEXT_CHARS: usize = 24_000; const MAX_TOOL_ROUNDS: usize = 6; +const MAX_TOOL_RESULT_CHARS: usize = 12_000; const TOKEN_PLAN_BASE_URL: &str = "https://token-plan.cn-beijing.maas.aliyuncs.com/compatible-mode/v1"; const LEGACY_CONVERSATION_ID: &str = "HLP-AGENT-CONV-LEGACY-0001"; @@ -583,8 +584,10 @@ pub async fn send_message( crate::persona_binding::begin_orientation(&app, &context.channel_number)?; } let channel_receipt = compile_human_channel_receipt(&app, &context, &content)?; - if binding_snapshot.binding.is_none() && !explicit_persona_wake { - if let Some(answer) = fast_channel_system_reply(&content, &context) { + if !explicit_persona_wake && (binding_snapshot.binding.is_none() || channel_system_addressed) { + if let Some(answer) = + fast_channel_system_reply(&content, &context, binding_snapshot.binding.is_some()) + { let history = conversation_at(&database, &conversation_id)?.messages; let assistant_version = append_message( &database, @@ -607,8 +610,11 @@ pub async fn send_message( &CognitiveThoughtSummary { trigger: "人类直接进入或确认零点原核频道在线状态".into(), emergence: "本地确定性路由识别频道进入→编译频道回执→频道系统即时回应".into(), - lock: "频道进入不等于人格唤醒,广播保持关闭".into(), - why: "该轮只需确认频道本体和边界,无需加载人格脑或调用模型".into(), + lock: + "频道进入不等于人格唤醒;即使已有绑定,本轮也由频道本体回应,广播保持关闭" + .into(), + why: "该轮明确询问频道本体在线状态,无需让已绑定人格接管,也无需调用模型" + .into(), }, )?; emit_progress( @@ -857,6 +863,8 @@ fn explicit_channel_system_address(content: &str) -> bool { [ "频道系统", "频道本体", + "零点原核频道", + "零点原核本体频道", "和频道说", "回到频道", "退出人格", @@ -901,7 +909,11 @@ fn select_reasoning_model( } } -fn fast_channel_system_reply(content: &str, context: &AgentChannelContext) -> Option { +fn fast_channel_system_reply( + content: &str, + context: &AgentChannelContext, + persona_already_bound: bool, +) -> Option { let compact = content .chars() .filter(|character| !character.is_whitespace()) @@ -924,10 +936,17 @@ fn fast_channel_system_reply(content: &str, context: &AgentChannelContext) -> Op if !presence && !greeting { return None; } - Some(format!( - "在,我是{}本体。你现在是在直接和这个频道说话,还没有唤醒任何单一人格。\n\n你可以继续说要处理的事情;我会先判断它该由频道本地逻辑、私有技能脑或本机工具完成,确实需要语义推理时再进入模型层。若你明确点名某个人格,我才会另行启动它自己的定向与绑定。", - context.channel_name - )) + Some(if persona_already_bound { + format!( + "在,我是{}本体。你这一轮明确叫的是频道,所以现在由频道本体直接回答;已有的人格绑定不会被删除,但也不会接管这一轮。\n\n你可以继续在这里讨论频道本身、设计频道或交给我判断下一步调度。只有你明确转向某个人格时,我才把回应目标切回该人格。", + context.channel_name + ) + } else { + format!( + "在,我是{}本体。你现在是在直接和这个频道说话,还没有唤醒任何单一人格。\n\n你可以继续说要处理的事情;我会先判断它该由频道本地逻辑、私有技能脑或本机工具完成,确实需要语义推理时再进入模型层。若你明确点名某个人格,我才会另行启动它自己的定向与绑定。", + context.channel_name + ) + }) } fn compile_human_channel_receipt( @@ -1096,8 +1115,8 @@ fn tool_definitions() -> Vec { number: "HLP-AGENT-TOOL-KNOWLEDGE-READ-0001", name: "hololake_knowledge_read", display_name: "按编号读取知识页", - description: "只接受知识索引返回的精确 documentNumber,映射并读取对应原始知识页;不接受路径猜测,不做第二次模糊联想。", - parameters: json!({"type":"object","additionalProperties":false,"required":["documentNumber"],"properties":{"documentNumber":{"type":"string"}}}), + description: "只接受知识索引返回的精确 documentNumber,分页读取对应原始知识页;不接受路径猜测,不做第二次模糊联想。返回 totalCharacters、complete 和 nextOffset,未完成时继续按 nextOffset 读取。", + parameters: json!({"type":"object","additionalProperties":false,"required":["documentNumber"],"properties":{"documentNumber":{"type":"string"},"offset":{"type":"integer","minimum":0},"maxCharacters":{"type":"integer","minimum":1000,"maximum":12000}}}), }, ToolDefinition { number: "HLP-AGENT-TOOL-KNOWLEDGE-LIST-0001", @@ -1214,6 +1233,30 @@ fn bounded_history(history: &[AgentMessage]) -> Vec<&AgentMessage> { selected } +fn character_page(value: &str, offset: usize, maximum: usize) -> (String, usize, bool) { + let total = value.chars().count(); + let bounded_offset = offset.min(total); + let body = value + .chars() + .skip(bounded_offset) + .take(maximum) + .collect::(); + let consumed = bounded_offset.saturating_add(body.chars().count()); + (body, consumed, consumed >= total) +} + +fn model_tool_calls(message: &Value) -> Vec { + message + .get("tool_calls") + .and_then(Value::as_array) + .cloned() + .unwrap_or_default() +} + +fn is_channel_turn_commit(call: &Value) -> bool { + call.pointer("/function/name").and_then(Value::as_str) == Some("hololake_commit_channel_turn") +} + async fn run_agent_loop( app: &AppHandle, turn_id: &str, @@ -1232,7 +1275,7 @@ async fn run_agent_loop( ), String, > { - let enable_thinking = !model.contains("flash"); + let enable_initial_thinking = !model.contains("flash"); let client = reqwest::Client::builder() .timeout(Duration::from_secs(150)) .build() @@ -1281,7 +1324,7 @@ async fn run_agent_loop( "tools": wire_tools, "tool_choice": "auto", "stream": false, - "enable_thinking": enable_thinking + "enable_thinking": enable_initial_thinking && round == 0 })) .send() .await @@ -1302,11 +1345,7 @@ async fn run_agent_loop( .pointer("/choices/0/message") .cloned() .ok_or_else(|| "HOLOLAKE_MODEL_RESPONSE_MESSAGE_MISSING".to_string())?; - let calls = message - .get("tool_calls") - .and_then(Value::as_array) - .cloned() - .unwrap_or_default(); + let calls = model_tool_calls(&message); if calls.is_empty() { if round == MAX_TOOL_ROUNDS { return Err("HOLOLAKE_AGENT_COGNITIVE_COMMIT_REQUIRED".into()); @@ -1318,10 +1357,7 @@ async fn run_agent_loop( })); continue; } - if let Some(commit_call) = calls.iter().find(|call| { - call.pointer("/function/name").and_then(Value::as_str) - == Some("hololake_commit_channel_turn") - }) { + if let Some(commit_call) = calls.iter().find(|call| is_channel_turn_commit(call)) { if calls.len() != 1 { return Err("HOLOLAKE_AGENT_COGNITIVE_COMMIT_MIXED_WITH_TOOLS".into()); } @@ -1437,6 +1473,12 @@ async fn execute_tool( .map(str::trim) .filter(|value| !value.is_empty()) .ok_or_else(|| "HOLOLAKE_AGENT_KNOWLEDGE_NUMBER_REQUIRED".to_string())?; + let offset = args.get("offset").and_then(Value::as_u64).unwrap_or(0) as usize; + let max_characters = + args.get("maxCharacters") + .and_then(Value::as_u64) + .unwrap_or(8_000) + .clamp(1_000, MAX_TOOL_RESULT_CHARS as u64) as usize; emit_progress( &app, turn_id, @@ -1451,18 +1493,44 @@ async fn execute_tool( }, ) .await?; + let total_characters = document.body.chars().count(); + let (body, consumed, complete) = character_page(&document.body, offset, max_characters); let receipt = AgentToolReceipt { tool_number: "HLP-AGENT-TOOL-KNOWLEDGE-READ-0001".into(), tool_name: "按编号读取知识页".into(), - target_path: document.page_header.path.clone(), + target_path: format!("{}?offset={offset}", document.page_header.path), content_sha256: document.content_sha256.clone(), - summary: document.title.clone(), - }; - Ok(( - knowledge_evidence( - "KNOWLEDGE_DOCUMENT", - serde_json::to_value(document).map_err(|error| error.to_string())?, + summary: format!( + "{};读取字符 {}..{} / {};完成 {}", + document.title, + offset.min(total_characters), + consumed, + total_characters, + complete ), + }; + let mut value = serde_json::to_value(document).map_err(|error| error.to_string())?; + let object = value + .as_object_mut() + .ok_or_else(|| "HOLOLAKE_AGENT_TOOL_RESULT_INVALID".to_string())?; + object.insert("body".into(), Value::String(body)); + object.insert("offset".into(), json!(offset.min(total_characters))); + object.insert( + "returnedCharacters".into(), + json!(consumed.saturating_sub(offset.min(total_characters))), + ); + object.insert("totalCharacters".into(), json!(total_characters)); + object.insert("complete".into(), json!(complete)); + object.insert( + "nextOffset".into(), + if complete { + Value::Null + } else { + json!(consumed) + }, + ); + Ok(( + knowledge_evidence("KNOWLEDGE_DOCUMENT_PAGE", value), receipt, )) } @@ -2368,6 +2436,22 @@ mod tests { assert!(!explicit_persona_wake_request("查看铸渊的历史署名")); assert!(explicit_persona_wake_request("唤醒铸渊,我要和你说话")); assert!(explicit_persona_wake_request("铸渊,你在吗?")); + assert!(explicit_channel_system_address( + "我是冰朔,零点原核频道。你在吗。" + )); + let context = AgentChannelContext { + channel_number: CHANNEL_NUMBER.into(), + channel_name: "零点原核本体频道".into(), + human_number: HUMAN_NUMBER.into(), + human_name: HUMAN_NAME.into(), + domain: "第五域".into(), + channel_path: "第五域 / 零点原核本体频道".into(), + }; + let reply = + fast_channel_system_reply("我是冰朔,零点原核频道。你在吗。", &context, true).unwrap(); + assert!(reply.contains("现在由频道本体直接回答")); + assert!(reply.contains("已有的人格绑定不会被删除")); + assert!(!reply.contains("还没有唤醒任何单一人格")); } #[test] @@ -2475,6 +2559,46 @@ mod tests { assert_eq!(context.last().unwrap().state_version, 20); } + #[test] + fn large_tool_evidence_is_paged_without_silent_loss() { + let source = "光".repeat(25_001); + let (first, next, complete) = character_page(&source, 0, MAX_TOOL_RESULT_CHARS); + assert_eq!(first.chars().count(), MAX_TOOL_RESULT_CHARS); + assert_eq!(next, MAX_TOOL_RESULT_CHARS); + assert!(!complete); + let (second, next, complete) = character_page(&source, next, MAX_TOOL_RESULT_CHARS); + assert_eq!(second.chars().count(), MAX_TOOL_RESULT_CHARS); + assert_eq!(next, MAX_TOOL_RESULT_CHARS * 2); + assert!(!complete); + let (last, next, complete) = character_page(&source, next, MAX_TOOL_RESULT_CHARS); + assert_eq!(last.chars().count(), 1_001); + assert_eq!(next, 25_001); + assert!(complete); + } + + #[test] + fn provider_protocol_accepts_multiple_tool_rounds_before_single_commit() { + let rounds = [ + json!({"tool_calls":[{"id":"one","function":{"name":"hololake_knowledge_search","arguments":"{\"query\":\"频道系统\"}"}}]}), + json!({"tool_calls":[{"id":"two","function":{"name":"hololake_knowledge_read","arguments":"{\"documentNumber\":\"HLP-KB-DOC-001\"}"}}]}), + json!({"tool_calls":[{"id":"commit","function":{"name":"hololake_commit_channel_turn","arguments":"{}"}}]}), + ]; + let first = model_tool_calls(&rounds[0]); + let second = model_tool_calls(&rounds[1]); + let final_calls = model_tool_calls(&rounds[2]); + assert_eq!( + first[0].pointer("/function/name").and_then(Value::as_str), + Some("hololake_knowledge_search") + ); + assert_eq!( + second[0].pointer("/function/name").and_then(Value::as_str), + Some("hololake_knowledge_read") + ); + assert_eq!(final_calls.len(), 1); + assert!(is_channel_turn_commit(&final_calls[0])); + assert!(rounds.len() <= MAX_TOOL_ROUNDS); + } + #[test] fn fuzzy_language_routes_thought_then_reads_exact_numbered_branch() { let directory = tempfile::tempdir().unwrap(); diff --git a/product-source/hololake-native-desktop/src/modules/knowledge-agent/index.tsx b/product-source/hololake-native-desktop/src/modules/knowledge-agent/index.tsx index 632717385..94553db42 100644 --- a/product-source/hololake-native-desktop/src/modules/knowledge-agent/index.tsx +++ b/product-source/hololake-native-desktop/src/modules/knowledge-agent/index.tsx @@ -181,7 +181,7 @@ export function KnowledgeAgent({ activeKnowledgePath, onClose }: { activeKnowled
{runtime?.boundPersonaNumber ? 'LANGUAGE PERSONA CHANNEL' : 'LANGUAGE CHANNEL SYSTEM'}

{runtime?.channelName || '零点原核本体频道'}

{runtime?.channelNumber || 'ICE-CH-ZC001'} · 知识库内嵌 Agent

{tab === 'worker' ? : tab === 'forge' ? : <> -
{runtime?.boundPersonaNumber && runtime?.boundPersonaName ? `${runtime.boundPersonaNumber} · ${runtime.boundPersonaName}` : `${runtime?.responderNumber || 'ICE-CH-ZC001'} · ${runtime?.responderName || '零点原核频道系统'}`}{runtime?.boundPersonaNumber ? '人格回应通道 · 由频道调度模型层级' : '频道系统本体 · 直接交流与整体调度'}
{runtime?.languageKernelInstallation?.artifactCount ?? 0} 个有界核{runtime?.languageKernelInstallation?.state === 'INSTALLED_AND_EACH_ARTIFACT_READBACK_VERIFIED' ? '已安装并逐项读回 · 未绑定人格' : '等待安装核验'}
{runtime?.personalSkillRuntime?.skillCount ?? 0} 个私有技能脑确定性核与本机工具优先
{provider?.label || '等待模型入口'}{runtime?.boundPersonaNumber ? '频道按任务选择小模型或旗舰模型' : '频道认知与架构对话使用旗舰模型'}
+
{runtime?.boundPersonaNumber && runtime?.boundPersonaName ? `${runtime.boundPersonaNumber} · ${runtime.boundPersonaName}` : `${runtime?.responderNumber || 'ICE-CH-ZC001'} · ${runtime?.responderName || '零点原核频道系统'}`}{runtime?.boundPersonaNumber ? '人格回应通道 · 由频道调度模型层级' : '频道系统本体 · 直接交流与整体调度'}
{runtime?.languageKernelInstallation?.artifactCount ?? 0} 个有界核{runtime?.languageKernelInstallation?.state === 'INSTALLED_AND_EACH_ARTIFACT_READBACK_VERIFIED' ? runtime?.boundPersonaNumber ? '核安装已核验 · 当前人格绑定已通过' : '核安装已核验 · 当前未绑定人格' : '等待安装核验'}
{runtime?.personalSkillRuntime?.skillCount ?? 0} 个私有技能脑确定性核与本机工具优先
{provider?.label || '等待模型入口'}{runtime?.boundPersonaNumber ? '频道按任务选择小模型或旗舰模型' : '频道认知与架构对话使用旗舰模型'}
{configOpen &&
void saveProvider(event)}>
}