Synced from monorepo
Synced from monorepo Changes: - Temporarily disable session share link creation in the TUI - Do not approve plan on empty Enter from the revise prompt - Expose chat product Skills via ACP available_commands_update - Return immediately from a blocking wait on an already-completed ACP task - Split headless pager module for clearer structure - Stop git worktree prune from removing user registrations on resume - Use compaction sampler tokenizer for item token counts - Opt-in extra root CAs via GROK_EXTRA_CA_BUNDLE - Cancel all session subagents when the user stops - Let the session persistence actor exit when its session ends - Make fullscreen terminal resize much cheaper on long sessions - Report honestly from kill_task when an ACP task does not exist - Hide /usage for external-auth deployments - Forward the history-load trailer’s computer_reason to the client - Remove ineffective no-op tool reminder - Declare slash-command screen-mode support in one place - Keep settings enum picker on the committed value until Enter - Reap a PTY’s full process tree - Stream tool calls from headless mode over ACP - Bridge gateway task lifecycle to ACP for chat session background tasks - Don’t warn about truncated history on a suppressed replay - Fit full-replace summarizer input and recover on context-length errors - Stop dropping agents over an unrecognized frontmatter color - Add /undo as a slash alias for /rewind - Harden sleep/wake token-refresh paths against forced re-login - Add session/list ACP method - Give each sampling backend its own conversion module - Treat an unenrolled child process as a lint error - Suppress the cancelled marker on send-now wake turns - Stop tearing down Roslyn on every edit, and read C# diagnostics Source-Revision: 2a28b4a86cfc4a4c133c35b7fc2a6a9964387c39
This commit is contained in:
parent
500129c714
commit
dd04f397b1
367 changed files with 29489 additions and 10051 deletions
|
|
@ -342,12 +342,13 @@ impl SessionFlags {
|
|||
if meta.is_empty() { None } else { Some(meta) }
|
||||
}
|
||||
}
|
||||
/// Workspace-bind `_meta` keys forbidden on chat create/load: backend owns
|
||||
/// workspace for `kind=chat`; the client must not bind Direct/envId/attach.
|
||||
/// Workspace-bind `_meta` keys **always** forbidden on chat create/load.
|
||||
///
|
||||
/// `x.ai/cloud_existing_workspace` is intentionally omitted: scrub keeps it
|
||||
/// iff `x.ai/local_workspace.mode == "attach"`.
|
||||
pub(super) const CHAT_FORBIDDEN_WORKSPACE_BIND_KEYS: &[&str] = &[
|
||||
"envId",
|
||||
"x.ai/cloud_server_id",
|
||||
"x.ai/cloud_existing_workspace",
|
||||
];
|
||||
/// Stamp `_meta["x.ai/session"].kind = "chat"` and strip Build `agentProfile` (K12).
|
||||
pub(super) fn apply_chat_kind_meta(meta: &mut Option<acp::Meta>) {
|
||||
|
|
@ -355,7 +356,23 @@ pub(super) fn apply_chat_kind_meta(meta: &mut Option<acp::Meta>) {
|
|||
obj.insert("x.ai/session".into(), serde_json::json!({ "kind": "chat" }));
|
||||
obj.remove("agentProfile");
|
||||
}
|
||||
/// Shared chat create/load/worktree meta finalize: kind + local stamp + scrub.
|
||||
pub(super) fn finalize_chat_session_meta(
|
||||
meta: &mut Option<acp::Meta>,
|
||||
is_chat_path: bool,
|
||||
#[allow(unused_variables)]
|
||||
session_flags: &SessionFlags,
|
||||
) {
|
||||
if !is_chat_path {
|
||||
return;
|
||||
}
|
||||
apply_chat_kind_meta(meta);
|
||||
scrub_chat_workspace_bind_meta(meta);
|
||||
}
|
||||
/// Remove client workspace-bind keys from chat create/load meta (defense in depth).
|
||||
///
|
||||
/// Narrow scrub exception: keep `x.ai/cloud_existing_workspace` when local
|
||||
/// intent is attach. Never keep `envId` or Direct hub `x.ai/cloud_server_id`.
|
||||
pub(super) fn scrub_chat_workspace_bind_meta(meta: &mut Option<acp::Meta>) {
|
||||
let Some(obj) = meta.as_mut() else {
|
||||
return;
|
||||
|
|
@ -363,6 +380,9 @@ pub(super) fn scrub_chat_workspace_bind_meta(meta: &mut Option<acp::Meta>) {
|
|||
for key in CHAT_FORBIDDEN_WORKSPACE_BIND_KEYS {
|
||||
obj.remove(*key);
|
||||
}
|
||||
{
|
||||
obj.remove("x.ai/cloud_existing_workspace");
|
||||
}
|
||||
}
|
||||
/// Metadata returned from effect execution so the event loop can patch
|
||||
/// state that requires a spawned task handle (e.g., auth AbortHandle).
|
||||
|
|
|
|||
|
|
@ -142,9 +142,7 @@ pub(crate) fn execute(
|
|||
#[allow(unused_mut)]
|
||||
let mut meta = session_flags.to_meta();
|
||||
let is_chat_path = chat_kind || session_flags.chat_mode;
|
||||
if is_chat_path {
|
||||
apply_chat_kind_meta(&mut meta);
|
||||
}
|
||||
finalize_chat_session_meta(&mut meta, is_chat_path, session_flags);
|
||||
if let Some(ref mid) = model_id {
|
||||
meta.get_or_insert_with(acp::Meta::new)
|
||||
.insert("modelId".into(), serde_json::json!(mid.0));
|
||||
|
|
@ -238,13 +236,11 @@ pub(crate) fn execute(
|
|||
let tx = acp_tx.clone();
|
||||
let cwd = cwd.to_path_buf();
|
||||
let mut meta = session_flags.to_meta();
|
||||
if chat_kind || session_flags.chat_mode {
|
||||
meta.get_or_insert_with(acp::Meta::new)
|
||||
.insert(
|
||||
"x.ai/session".into(),
|
||||
serde_json::json!({ "kind": "chat" }),
|
||||
);
|
||||
}
|
||||
finalize_chat_session_meta(
|
||||
&mut meta,
|
||||
chat_kind || session_flags.chat_mode,
|
||||
session_flags,
|
||||
);
|
||||
if let Some(ref mid) = model_id {
|
||||
meta.get_or_insert_with(acp::Meta::new)
|
||||
.insert("modelId".into(), serde_json::json!(mid.0));
|
||||
|
|
@ -520,10 +516,7 @@ pub(crate) fn execute(
|
|||
let tx = acp_tx.clone();
|
||||
let mut meta = session_flags.to_meta();
|
||||
let is_chat_path = chat_kind || session_flags.chat_mode;
|
||||
if is_chat_path {
|
||||
apply_chat_kind_meta(&mut meta);
|
||||
scrub_chat_workspace_bind_meta(&mut meta);
|
||||
}
|
||||
finalize_chat_session_meta(&mut meta, is_chat_path, session_flags);
|
||||
if let Some(true) = session_flags.restore_code {
|
||||
meta.get_or_insert_with(acp::Meta::new)
|
||||
.insert("x.ai/restore_code".into(), serde_json::Value::Bool(true));
|
||||
|
|
|
|||
|
|
@ -1979,7 +1979,7 @@ fn to_meta_chat_mode_stamps_kind_and_omits_agent_profile() {
|
|||
..Default::default()
|
||||
};
|
||||
let meta = flags.to_meta().expect("chat_mode must emit meta");
|
||||
assert_eq!(meta["x.ai/session"]["kind"], "chat");
|
||||
assert_eq!(meta["x.ai/session"] ["kind"], "chat");
|
||||
assert!(
|
||||
meta.get("agentProfile").is_none(),
|
||||
"K12: chat mode must omit Build agentProfile"
|
||||
|
|
@ -2006,7 +2006,7 @@ fn load_meta_chat_kind_alone_stamps_kind_and_strips_profile() {
|
|||
scrub_chat_workspace_bind_meta(&mut meta);
|
||||
}
|
||||
let meta = meta.expect("chat_kind must produce meta");
|
||||
assert_eq!(meta["x.ai/session"]["kind"], "chat");
|
||||
assert_eq!(meta["x.ai/session"] ["kind"], "chat");
|
||||
assert!(
|
||||
meta.get("agentProfile").is_none(),
|
||||
"entry chat_kind must strip Build agentProfile"
|
||||
|
|
@ -2025,6 +2025,10 @@ fn assert_chat_meta_has_no_workspace_bind_keys(meta: &serde_json::Value) {
|
|||
"chat meta must not include workspace-bind key {key:?}: {meta}"
|
||||
);
|
||||
}
|
||||
assert!(
|
||||
meta.get("x.ai/cloud_existing_workspace").is_none(),
|
||||
"chat meta without attach must not include existing workspace: {meta}"
|
||||
);
|
||||
}
|
||||
#[test]
|
||||
fn chat_create_meta_never_includes_workspace_bind_keys_when_cloud_fields_set() {
|
||||
|
|
@ -2036,7 +2040,7 @@ fn chat_create_meta_never_includes_workspace_bind_keys_when_cloud_fields_set() {
|
|||
apply_chat_kind_meta(&mut meta);
|
||||
scrub_chat_workspace_bind_meta(&mut meta);
|
||||
let meta = meta.expect("chat create must emit meta");
|
||||
assert_eq!(meta["x.ai/session"]["kind"], "chat");
|
||||
assert_eq!(meta["x.ai/session"] ["kind"], "chat");
|
||||
assert_chat_meta_has_no_workspace_bind_keys(
|
||||
&serde_json::Value::Object(meta.clone()),
|
||||
);
|
||||
|
|
@ -2060,7 +2064,7 @@ fn chat_load_meta_never_includes_workspace_bind_keys() {
|
|||
}
|
||||
scrub_chat_workspace_bind_meta(&mut meta);
|
||||
let meta = meta.expect("chat load must emit meta");
|
||||
assert_eq!(meta["x.ai/session"]["kind"], "chat");
|
||||
assert_eq!(meta["x.ai/session"] ["kind"], "chat");
|
||||
assert_chat_meta_has_no_workspace_bind_keys(
|
||||
&serde_json::Value::Object(meta.clone()),
|
||||
);
|
||||
|
|
|
|||
Loading…
Reference in a new issue