Skip to content

Commit ac847b5

Browse files
committed
fix(release): repair v1.68.0 renderer typecheck
1 parent ea9c4b5 commit ac847b5

46 files changed

Lines changed: 2696 additions & 506 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

internal/roadmap/coding/implementation-plan.md

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -251,16 +251,18 @@ turn start
251251
- 窄屏和宽屏下按钮文字不溢出,右侧对话不遮挡主画布。
252252
- `*.test.tsx` / view model 单测覆盖 tab 默认选择、blocked、failed、waiting action、changes ready。
253253

254-
当前状态:`in_progress / change-output-log-action current projection connected`。现有 `CanvasWorkbenchLayout` coding mode 仍是承载壳,但 `WorkspaceConversationSceneRuntime` 已把 `changeView``outputView``logView``CodingWorkbenchView` 派生:变更面板消费 projection change facts 与 file checkpoint summary,输出面板消费 commands/tests/actions/diagnostics,日志面板消费同一 projection 的文件、命令、测试、确认和诊断条目。`CodingWorkbenchOutputPanel` 已拆出 `CodingWorkbenchActionPanel``CodingWorkbenchDiagnosticPanel` 与共享状态 badge,主面板只做组合;action submit 通过 `handlePermissionResponse` 走 existing runtime action response 主链,不直连 App Server、不新增命令、不依赖 mock。诊断面板已展示 fail-closed policy 与 source event evidence 基础信息。仍未完成:完整诊断抽屉 policy/provider/evidence 聚合、GUI smoke 覆盖提交编程需求 / 查看输出 / 继续修复。
254+
当前状态:`in_progress / change-output-log-action-recovery current projection connected / runtime hook split`。现有 `CanvasWorkbenchLayout` coding mode 仍是承载壳,但 `WorkspaceConversationSceneRuntime` 已把 `changeView`、`outputView`、`logView` 从 `CodingWorkbenchView` 派生:变更面板消费 projection change facts 与 file checkpoint summary,输出面板消费 commands/tests/actions/diagnostics/recovery,日志面板消费同一 projection 的文件、命令、测试、确认和诊断条目。coding workbench 视图组装已下沉到 `workspaceConversationCodingViews.tsx`,中心 hook 只保留投影延迟、场景参数和 runtime callback 接线;`CodingWorkbenchOutputPanel` 已拆出 `CodingWorkbenchActionPanel`、`CodingWorkbenchDiagnosticPanel`、`CodingWorkbenchRecoveryPanel` 与共享状态 badge,主面板只做组合;action submit 通过 `handlePermissionResponse` 走 existing runtime action response 主链,失败继续修复通过 `handleSendFromEmptyState({ textOverride })` 走 existing send 主链,不直连 App Server、不新增命令、不依赖 mock。诊断面板已展示 fail-closed policy 与 source event evidence 基础信息。仍未完成:完整诊断抽屉 policy/provider/evidence 聚合、GUI smoke 覆盖提交编程需求 / 查看输出 / 继续修复。
255255

256256
2026-06-14 P4 增量:
257257

258258
- `CodingWorkbenchActionPanel` 已从 `CodingWorkbenchView.actions` 渲染待确认动作,支持 command approval 的允许 / 拒绝按钮,并通过 `onRespondToAction` 复用现有 runtime callback;`submittedActionsInFlight` 会禁用按钮并显示提交中,避免重复提交。
259259
- 无法安全映射为 current `tool_confirmation` 的 action 只展示提示与请求 id,不伪造提交按钮,符合 fail-closed 交互。
260260
- `CodingWorkbenchDiagnosticPanel` 已从 `CodingWorkbenchView.diagnostics` 展示诊断标题、详情、状态、fail-closed 策略与 source event evidence id,作为后续诊断抽屉聚合的基础 surface。
261-
- 五语言 `zh-CN / zh-TW / en-US / ja-JP / ko-KR` 已补齐 coding action / diagnostics presentation 文案。
262-
- `useWorkspaceConversationSceneRuntime.tsx` 现仍超过 1000 行;本轮只做 output view callback 接线,没有继续追加业务状态机。下一刀拆分入口:把 coding workbench utility views 组装抽到 `workspaceConversationCodingViews.tsx` 或同级 presentation helper,中心 hook 只保留参数传递。
263-
- 验证证据:`npx vitest run "src/components/agent/chat/workspace/CodingWorkbenchOutputPanel.test.tsx" "src/components/agent/chat/workspace/CodingWorkbenchLogPanel.test.tsx" "src/components/agent/chat/workspace/useWorkspaceConversationSceneRuntime.test.ts" --silent=passed-only --disableConsoleIntercept` 覆盖命令 / 测试 / action submit / submitted 状态 / 诊断 evidence / hook callback 接线;`npx prettier --check ...` 覆盖 touched frontend 与五语言资源。
261+
- `codingWorkbenchRecovery.ts` 已从 `CodingWorkbenchView.commands/tests/patches/diagnostics` 聚合失败命令、失败测试、失败补丁和失败诊断,并带入相关文件与最近 file checkpoint 生成继续修复 prompt;`CodingWorkbenchRecoveryPanel` 只负责展示失败摘要和主按钮。
262+
- 继续修复按钮已通过 `workspaceConversationCodingViews.tsx -> useWorkspaceConversationSceneRuntime.tsx` 复用 `handleSendFromEmptyState({ textOverride })`,不新增 App Server method、Desktop Host command 或 mock fallback。
263+
- 五语言 `zh-CN / zh-TW / en-US / ja-JP / ko-KR` 已补齐 coding action / diagnostics / recovery presentation 文案。
264+
- `workspaceConversationCodingViews.tsx` 已成为 coding workbench presentation helper,集中构造 `CodingWorkbenchView`、session counters、session/output/log/change view 与 `handlePermissionResponse` callback 传递;`useWorkspaceConversationSceneRuntime.tsx` 从 1000 行以上收回到 1000 行以下,后续不得再向该 hook 追加 coding UI 业务逻辑。
265+
- 验证证据:`npx vitest run "src/components/agent/chat/workspace/CodingWorkbenchOutputPanel.test.tsx" "src/components/agent/chat/workspace/codingWorkbenchRecovery.unit.test.ts" "src/components/agent/chat/workspace/useWorkspaceConversationSceneRuntime.test.ts" --silent=passed-only --disableConsoleIntercept` 覆盖 projection-driven output/action/recovery、submitted 状态与 hook callback 接线;`npx eslint ... --max-warnings 0` 覆盖 touched coding workbench 文件;`npx prettier --check ...``git diff --check -- ...` 覆盖 touched frontend/i18n/roadmap 文件;`npm run verify:gui-smoke` 覆盖 renderer build、Electron host typecheck/build、App Server sidecar、Claw workbench shell ready;`npm run smoke:code-artifact-workbench-electron-fixture` 覆盖代码 artifact 会话创建、历史打开、hydrate 与 workbench 打开。全量 `tsc --noEmit` 本地仍长时间无输出,本轮不计为通过。
264266

265267
## P5:多模型 Routing 与 Profile Slot
266268

@@ -285,7 +287,26 @@ turn start
285287
- 自定义兼容端点作为 Provider Store entry 参与 registry,不写入 Coding Workbench 本地设置。
286288
- UI diagnostics 可解释当前使用哪个槽位、为什么 fallback、下一步如何配置。
287289

288-
当前状态:`pending`
290+
当前状态:`in_progress / App Server routing facts and read-model projection connected`
291+
292+
2026-06-14 增量:
293+
294+
- `lime-rs/crates/app-server/src/runtime_backend/model_routing.rs` 已成为 coding profile model slot diagnostics owner:解析 `harness.coding_model_slots / codingModelSlots / modelSlots` 中的 `base/coding/review/fast/local` 槽位;`coding` 槽位优先作为主 turn selection,`base` 作为 fallback,`review/fast/local` 只进入 diagnostics slots,不抢占主 coding turn owner。
295+
- `RuntimeBackend` 的 turn start 已输出增强 `routing.decision.made` payload:包含 `routingDecision / routing_decision``modelSlot / model_slot``providerReadiness / provider_readiness``serviceModelSlot`、requested/selected provider/model、fallback chain、required coding capabilities。未 ready provider 会先写 `routing.not_possible`,再 fail-closed 返回 backend error,不降级 mock、不从 Workbench 持有 key。
296+
- Provider readiness 先接入 App Server current Provider Store 事实:直传 fixture provider config 标记 `direct_provider_config`;已配置 Provider Store entry 记录 enabled/key count/provider type;非聊天 Provider、disabled provider、missing enabled key、未知 custom provider 都输出 `needs_setup / blocked` reason code。内置 runtime provider 仍按现有运行时兼容标记为 `builtin_runtime_provider`,后续 Provider Store 完整接管时再收紧。
297+
- `runtime/read_model.rs` 已把最新 `routing.decision.made / routing.fallback.applied / routing.not_possible` 聚合到 `thread_read.model_routing`,并提升 `thread_read.service_model_slot``runtime_summary.decisionSource/serviceModelSlot`,让现有 `runtimeRoutingEvidence.ts` 与 Workbench diagnostics 能消费同一事实源。
298+
299+
验证证据:
300+
301+
- `cargo fmt --manifest-path "lime-rs/Cargo.toml" -p app-server --check`
302+
- `cargo test --manifest-path "lime-rs/Cargo.toml" -p app-server runtime_backend:: -- --nocapture`
303+
- `cargo test --manifest-path "lime-rs/Cargo.toml" -p app-server runtime::tests::read_model -- --nocapture`
304+
305+
剩余风险:
306+
307+
- Provider Store 的 stable model id、alias、真实 capability tags 仍未接入 model registry metadata;当前 required/effective capabilities 先作为 routing diagnostics 输出,不做强约束假 catalog。
308+
- UI diagnostics 尚未为 provider readiness reason code 做专门分组展示;当前可通过 `thread_read.model_routing` 被现有 routing evidence/diagnostics 读取。
309+
- `model_slot.resolved` 目前以 `routing.decision.made` 内的 `modelSlot/model_slot` 等价 diagnostics fact 表达,后续如果 evidence join 需要独立事件,再补专门事件并纳入 P7 conformance。
289310

290311
## P6:External Harness Compat Adapter
291312

lime-rs/crates/app-server-protocol/schema/json/app_server_protocol.schemas.json

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14041,6 +14041,18 @@
1404114041
"ProjectGitDiffResponse": {
1404214042
"$schema": "https://json-schema.org/draft/2020-12/schema",
1404314043
"properties": {
14044+
"comparisonBaseRef": {
14045+
"type": [
14046+
"null",
14047+
"string"
14048+
]
14049+
},
14050+
"currentRef": {
14051+
"type": [
14052+
"null",
14053+
"string"
14054+
]
14055+
},
1404414056
"hasGitRepository": {
1404514057
"type": "boolean"
1404614058
},

lime-rs/crates/app-server-protocol/schema/json/v0/ProjectGitDiffResponse.json

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,18 @@
11
{
22
"$schema": "https://json-schema.org/draft/2020-12/schema",
33
"properties": {
4+
"comparisonBaseRef": {
5+
"type": [
6+
"null",
7+
"string"
8+
]
9+
},
10+
"currentRef": {
11+
"type": [
12+
"null",
13+
"string"
14+
]
15+
},
416
"hasGitRepository": {
517
"type": "boolean"
618
},

lime-rs/crates/app-server-protocol/src/protocol/v0/project_git.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,10 @@ pub struct ProjectGitDiffResponse {
9292
#[serde(default, skip_serializing_if = "Option::is_none")]
9393
pub repository_root: Option<String>,
9494
pub has_git_repository: bool,
95+
#[serde(default, skip_serializing_if = "Option::is_none")]
96+
pub current_ref: Option<String>,
97+
#[serde(default, skip_serializing_if = "Option::is_none")]
98+
pub comparison_base_ref: Option<String>,
9599
pub patch: String,
96100
#[serde(default)]
97101
pub uncommitted_file_count: u32,

lime-rs/crates/app-server/src/runtime/read_model.rs

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,10 @@ fn latest_turn_error_message(stored: &StoredSession, turn_id: Option<&str>) -> O
195195

196196
fn runtime_thread_read_from_stored_session(stored: &StoredSession) -> serde_json::Value {
197197
let coding_activity = coding_activity_projection::coding_activity_from_events(stored);
198+
let model_routing = latest_model_routing_from_events(&stored.events);
199+
let service_model_slot = model_routing
200+
.as_ref()
201+
.and_then(|routing| string_field(routing, &["serviceModelSlot", "service_model_slot"]));
198202
let latest_turn_status = stored
199203
.turns
200204
.last()
@@ -228,6 +232,8 @@ fn runtime_thread_read_from_stored_session(stored: &StoredSession) -> serde_json
228232
"tool_calls": tool_calls_from_events(&stored.events),
229233
"commands": coding_activity.commands,
230234
"tests": coding_activity.tests,
235+
"model_routing": model_routing.clone(),
236+
"service_model_slot": service_model_slot.clone(),
231237
"artifacts": artifact_projection::stored_artifact_summaries_for_turn(stored, None),
232238
"outputs": output_refs::read_model_outputs(stored.output_blobs.values(), None),
233239
"diagnostics": {
@@ -240,10 +246,91 @@ fn runtime_thread_read_from_stored_session(stored: &StoredSession) -> serde_json
240246
"runtime_summary": {
241247
"latestTurnStatus": latest_turn_status,
242248
"latestTurnErrorMessage": latest_turn_error_message,
249+
"decisionSource": model_routing
250+
.as_ref()
251+
.and_then(|routing| string_field(routing, &["decisionSource", "decision_source"])),
252+
"serviceModelSlot": service_model_slot,
243253
},
244254
})
245255
}
246256

257+
fn latest_model_routing_from_events(events: &[AgentEvent]) -> Option<serde_json::Value> {
258+
events
259+
.iter()
260+
.rev()
261+
.find(|event| {
262+
matches!(
263+
event.event_type.as_str(),
264+
"routing.decision.made" | "routing.fallback.applied" | "routing.not_possible"
265+
)
266+
})
267+
.map(model_routing_from_event)
268+
}
269+
270+
fn model_routing_from_event(event: &AgentEvent) -> serde_json::Value {
271+
let mut routing = event
272+
.payload
273+
.get("routingDecision")
274+
.or_else(|| event.payload.get("routing_decision"))
275+
.and_then(|value| value.as_object())
276+
.cloned()
277+
.unwrap_or_else(|| event.payload.as_object().cloned().unwrap_or_default());
278+
279+
merge_optional_payload_value(&mut routing, &event.payload, "modelSlot", "modelSlot");
280+
merge_optional_payload_value(&mut routing, &event.payload, "model_slot", "model_slot");
281+
merge_optional_payload_value(
282+
&mut routing,
283+
&event.payload,
284+
"providerReadiness",
285+
"providerReadiness",
286+
);
287+
merge_optional_payload_value(
288+
&mut routing,
289+
&event.payload,
290+
"provider_readiness",
291+
"provider_readiness",
292+
);
293+
routing.insert(
294+
"sourceEventId".to_string(),
295+
serde_json::Value::String(event.event_id.clone()),
296+
);
297+
routing.insert(
298+
"source_event_id".to_string(),
299+
serde_json::Value::String(event.event_id.clone()),
300+
);
301+
routing.insert(
302+
"sourceEventType".to_string(),
303+
serde_json::Value::String(event.event_type.clone()),
304+
);
305+
routing.insert(
306+
"source_event_type".to_string(),
307+
serde_json::Value::String(event.event_type.clone()),
308+
);
309+
routing.insert(
310+
"timestamp".to_string(),
311+
serde_json::Value::String(event.timestamp.clone()),
312+
);
313+
if event.event_type == "routing.not_possible" {
314+
routing.insert(
315+
"status".to_string(),
316+
serde_json::Value::String("blocked".to_string()),
317+
);
318+
}
319+
320+
serde_json::Value::Object(routing)
321+
}
322+
323+
fn merge_optional_payload_value(
324+
routing: &mut serde_json::Map<String, serde_json::Value>,
325+
payload: &serde_json::Value,
326+
output_key: &str,
327+
payload_key: &str,
328+
) {
329+
if let Some(value) = payload.get(payload_key) {
330+
routing.insert(output_key.to_string(), value.clone());
331+
}
332+
}
333+
247334
pub(super) fn replayed_action_required_from_stored_session(
248335
stored: &StoredSession,
249336
request_id: &str,

lime-rs/crates/app-server/src/runtime/service_projection.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,8 @@ pub(super) fn project_git_diff_from_service(
7474
root_path: diff.root_path,
7575
repository_root: diff.repository_root,
7676
has_git_repository: diff.has_git_repository,
77+
current_ref: diff.current_ref,
78+
comparison_base_ref: diff.comparison_base_ref,
7779
patch: diff.patch,
7880
uncommitted_file_count: diff.uncommitted_file_count,
7981
}

0 commit comments

Comments
 (0)