Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
d16ae94
chore: pin official ACP v1 and A2A 1.0 spec snapshots in protocol-loc…
wangtsiao Jul 28, 2026
695fca8
feat(protocol): freeze canonical Item/Session/Turn/Event/Usage types …
wangtsiao Jul 28, 2026
94ecf8d
feat(protocol): allow unknown legacy git dirty flag and lumped legacy…
wangtsiao Jul 28, 2026
a869668
feat(core): add v2 rollout envelope, dual-format reader, and legacy p…
wangtsiao Jul 28, 2026
e0500f5
feat(server): add typed-items wire opt-in via initialize _meta negoti…
wangtsiao Jul 28, 2026
a87b77d
feat(core): add v2 inverse projector and persistence extras for lossl…
wangtsiao Jul 28, 2026
ef30fd0
feat(server): switch rollout writes to v2 with dual-format reads and …
wangtsiao Jul 28, 2026
2796e8a
feat(server): add SQLite event_log outbox with startup reconciliation
wangtsiao Jul 29, 2026
018d36d
feat(server): add paged session/turns/list and session/items/list his…
wangtsiao Jul 29, 2026
389de40
feat(server): add subscription API with barrier-consistent cursor replay
wangtsiao Jul 29, 2026
ee745e9
feat(server): add session/queue API with editable pre-items and steer…
wangtsiao Jul 29, 2026
a6e550b
feat(server): separate side questions from steer input
wangtsiao Jul 29, 2026
d426b83
feat(server): add two-phase session rollback
wangtsiao Jul 29, 2026
0d0523d
feat(server): complete permissions goal and usage phases
wangtsiao Jul 29, 2026
0ca540b
refactor(core): split query into deep modules and unify token estimates
wangtsiao Jul 30, 2026
b95c391
feat(tui): add /rename and /delete, and make Proposed Plan revise an
wangtsiao Jul 30, 2026
c4f7d7e
fix(tui): restore Plan mode and decision UI on session resume
wangtsiao Jul 30, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions apps/web/content/docs/using-devo/plan-mode.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -77,9 +77,9 @@ After a `Proposed Plan` appears, Devo opens a small action menu.
Choose `Implement Plan` when the plan is ready. Devo switches back to `BUILD`
mode and submits an implementation turn using that plan.

Choose `修改建议` when the plan needs changes. This is the current TUI label for
the revise-plan action. It keeps the composer in `PLAN` mode and lets you type
feedback such as:
Choose `Revise Plan` when the plan needs changes. When that option is
highlighted, type feedback directly in the menu and press Enter. Devo stays in
`PLAN` mode and submits a revise turn with your feedback, for example:

```text
Keep the config migration out of scope. Add a test for Windows paths.
Expand Down
2 changes: 1 addition & 1 deletion apps/web/content/docs/using-devo/plan-mode.zh.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ Plan Mode turn 完成后,Devo 可以在 transcript 中渲染 `Proposed Plan` c

选择 `Implement Plan` 表示计划可执行。Devo 切回 `BUILD` mode,并使用该计划提交实现 turn。

选择 `修改建议` 表示计划需要修改。这是当前 TUI 对 revise-plan action 的标签。它会保持 composer 在 `PLAN` mode,并让你输入反馈,例如:
选择 `Revise Plan` 表示计划需要修改。高亮该选项后,可直接在菜单中输入反馈并按 Enter。Devo 保持 `PLAN` mode,并用你的反馈提交 revise turn,例如:

```text
Keep the config migration out of scope. Add a test for Windows paths.
Expand Down
1 change: 1 addition & 0 deletions crates/cli/src/prompt_command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,7 @@ pub(crate) async fn run_prompt(
registry,
&runtime,
jsonl_event_callback(output_format, session_id_for_events),
devo_core::QueryOptions::default(),
)
.await;

Expand Down
6 changes: 6 additions & 0 deletions crates/client/src/acp_permissions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,7 @@ fn acp_approval_request_notification(
turn_id: Some(pending.turn_id),
item_id: Some(pending.item_id),
seq: 0,
item_seq: None,
},
item: ItemEnvelope {
item_id: pending.item_id,
Expand All @@ -236,6 +237,7 @@ fn acp_approval_decision_notification(
approval_id: params.approval_id.clone(),
decision: acp_approval_decision_label(&params.decision).to_string(),
scope: acp_approval_scope_label(&params.scope).to_string(),
decision_source: Some(devo_protocol::canonical::item::ApprovalDecisionSource::User),
};
acp_item_notification(
"item/completed",
Expand All @@ -245,6 +247,7 @@ fn acp_approval_decision_notification(
turn_id: Some(pending.turn_id),
item_id: Some(pending.item_id),
seq: 0,
item_seq: None,
},
item: ItemEnvelope {
item_id: ItemId::new(),
Expand Down Expand Up @@ -491,6 +494,7 @@ mod tests {
turn_id: Some(turn_id),
item_id: Some(item_id),
seq: 0,
item_seq: None,
}
);
assert_eq!(request_item.item.item_id, item_id);
Expand Down Expand Up @@ -559,6 +563,7 @@ mod tests {
turn_id: Some(turn_id),
item_id: Some(item_id),
seq: 0,
item_seq: None,
}
);
assert_eq!(decision_item.item.item_kind, ItemKind::ApprovalDecision);
Expand All @@ -568,6 +573,7 @@ mod tests {
approval_id: request_payload.approval_id,
decision: "approve".to_string(),
scope: "once".to_string(),
decision_source: Some(devo_protocol::canonical::item::ApprovalDecisionSource::User,),
}
);
}
Expand Down
14 changes: 14 additions & 0 deletions crates/client/src/client_core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -459,6 +459,13 @@ impl ServerClientCore {
self.request_devo("session/title/update", params).await
}

pub(crate) async fn session_delete(
&mut self,
params: AcpDeleteSessionParams,
) -> Result<AcpDeleteSessionResult> {
self.request(ACP_SESSION_DELETE_METHOD, params).await
}

pub(crate) async fn session_metadata_update(
&mut self,
params: SessionMetadataUpdateParams,
Expand Down Expand Up @@ -949,6 +956,8 @@ fn format_protocol_error_code(code: &ProtocolErrorCode) -> &'static str {
ProtocolErrorCode::ForkTurnNotFound => "fork_turn_not_found",
ProtocolErrorCode::ForkTurnNotStable => "fork_turn_not_stable",
ProtocolErrorCode::PermissionDenied => "permission_denied",
ProtocolErrorCode::CursorExpired => "cursor_expired",
ProtocolErrorCode::QueueItemNotFound => "queue_item_not_found",
ProtocolErrorCode::WorkspaceUnavailable => "workspace_unavailable",
ProtocolErrorCode::InheritedSegmentWriteFailed => "inherited_segment_write_failed",
ProtocolErrorCode::ForkRetentionRequired => "fork_retention_required",
Expand All @@ -963,6 +972,9 @@ fn format_protocol_error_code(code: &ProtocolErrorCode) -> &'static str {
ProtocolErrorCode::InvalidContentParts => "invalid_content_parts",
ProtocolErrorCode::InvalidMentions => "invalid_mentions",
ProtocolErrorCode::WorkspaceRestoreFailedToStart => "workspace_restore_failed_to_start",
ProtocolErrorCode::RestorePlanNotFound => "restore_plan_not_found",
ProtocolErrorCode::RestorePlanExpired => "restore_plan_expired",
ProtocolErrorCode::WorkspaceVersionConflict => "workspace_version_conflict",
ProtocolErrorCode::InternalError => "internal_error",
}
}
Expand Down Expand Up @@ -1034,6 +1046,7 @@ fn acp_session_metadata_from_start_params(
last_query_usage: None,
last_query_total_tokens: 0,
status: SessionRuntimeStatus::Idle,
collaboration_mode: Default::default(),
}
}

Expand Down Expand Up @@ -1071,6 +1084,7 @@ fn acp_session_metadata_from_session_info(session_info: &AcpSessionInfo) -> Sess
last_query_usage: None,
last_query_total_tokens: 0,
status: SessionRuntimeStatus::Idle,
collaboration_mode: Default::default(),
}
}

Expand Down
10 changes: 10 additions & 0 deletions crates/client/src/stdio.rs
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,13 @@ impl StdioServerClient {
self.core.session_title_update(params).await
}

pub async fn session_delete(
&mut self,
params: AcpDeleteSessionParams,
) -> Result<AcpDeleteSessionResult> {
self.core.session_delete(params).await
}

pub async fn session_metadata_update(
&mut self,
params: SessionMetadataUpdateParams,
Expand Down Expand Up @@ -672,6 +679,7 @@ mod tests {
last_query_usage: None,
last_query_total_tokens: 0,
status: SessionRuntimeStatus::Idle,
collaboration_mode: Default::default(),
};
assert_eq!(session, expected);

Expand Down Expand Up @@ -763,6 +771,7 @@ mod tests {
last_query_usage: None,
last_query_total_tokens: 0,
status: SessionRuntimeStatus::Idle,
collaboration_mode: Default::default(),
}]
);

Expand Down Expand Up @@ -812,6 +821,7 @@ mod tests {
last_query_usage: None,
last_query_total_tokens: 0,
status: SessionRuntimeStatus::Idle,
collaboration_mode: Default::default(),
};
let mut stdout_lines = BufReader::new(stdout).lines();

Expand Down
9 changes: 9 additions & 0 deletions crates/client/src/websocket.rs
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,15 @@ impl WebSocketServerClient {
self.core.request_devo("session/title/update", params).await
}

pub async fn session_delete(
&mut self,
params: AcpDeleteSessionParams,
) -> Result<AcpDeleteSessionResult> {
self.core
.request(devo_protocol::ACP_SESSION_DELETE_METHOD, params)
.await
}

pub async fn session_metadata_update(
&mut self,
params: SessionMetadataUpdateParams,
Expand Down
Loading
Loading