Synced from monorepo

Changes:
- Non-blocking coding-data sharing upsell banner
- Consolidate remediation in Doctor
- Auto mode defers fail-closed gate asks to the classifier
- Coalesce marketplace list fetches
- Allow removing a marketplace source by name
- Contain hung git marketplace sources (timeouts, non-blocking refresh, unbrick modal)
- Label failed workspace RPCs with error_kind
- Drop redundant explicit tonic/prost deps from xai-grok-shell
- Report real exit codes for completed background shells
- Narrow the date-rollover reminder to date-bearing templates
- Wire toolOverrides through the session and agent
- Security: Bash(git:*) allowlist matches whole command chain by prefix
- Split prompt-trigger telemetry and record classifier provenance
- Raise connectors-manager timeout to 60s
- Auto classifier honors recorded approvals for repeat actions
- Apply doctor fixes in the TUI
- Auto-mode classifier timeouts prompt instead of silently denying
- Scope subagent completion drains to the owning session
- Add the toolOverrides wire types
- Set client_identifier=grok-agent-sdk
- Accept both spellings of the workspace-teleport kill switch
- Persist one-shot occurrence journal
- Stop turns that poll the exact same tool call 16x in a row
- Copy compaction checkpoint files when forking sessions
- Auto-focus permission prompt from scrollback
- Esc cancels the running turn in non-vim and minimal modes
- List Ctrl+Z undo and redo in keyboard shortcuts
- Out-of-process macOS mic capture
- Show active auth mode on session-info
- Install the npm binary under $GROK_HOME
- Remove hover/click dead zones between dashboard items
- Route startup warnings to doctor
- Document [feedback.user] author identity config
- Extend bang command timeout
- Close combine-queued edit-hold race
- Integrate relocation recovery
- Expose privacy notice rollout flag
- Break harness discovery ref cycle so connections can idle-evict
- Shift/Alt+Enter inserts newline when editing a queued prompt
- Gate project Claude permissions on folder trust
- Echo response.create.event_id on response.created
- Toast when session creation fails from disk full
- Add shared test process lifecycle
- Enable dynamic workflows by default
- Add relocation transaction state machine
- Add shared test sandbox
- Surface auth failures on model-switch compact
- Persist durable scheduler expiry
- Confirm before removing extensions-modal items
- Re-run compact and prompt after login when compact hit expired auth
- Recap sends hosted tools under backend search
This commit is contained in:
grokkybara[bot] 2026-07-22 19:18:53 +01:00
commit a5727c5960
482 changed files with 37627 additions and 13402 deletions

View file

@ -887,10 +887,7 @@ impl AgentBuilder {
}
let matched = removed.iter().any(|&id| tool_id_eq(d, id));
if !matched {
tracing::warn!(
agent = % definition.name, tool = % d,
"disallowedTools entry matched nothing"
);
tracing::warn!(agent = %definition.name, tool = %d, "disallowedTools entry matched nothing");
}
}
}
@ -933,8 +930,8 @@ impl AgentBuilder {
}
if !recognized_but_unavailable.is_empty() {
tracing::debug!(
agent = % definition.name, recognized_but_unavailable = ?
recognized_but_unavailable,
agent = %definition.name,
recognized_but_unavailable = ?recognized_but_unavailable,
"tools allowlist named recognized tools that aren't enabled; ignoring them"
);
}
@ -945,14 +942,12 @@ impl AgentBuilder {
|| (has_agent_entry && task_deps.contains(&short_tool_name(&tc.id)))
|| matches!(tc.kind, Some(ToolKind::SearchTool | ToolKind::UseTool))
});
tracing::debug!(
agent = % definition.name, allowed = ? definition.tools,
"tools allowlist applied"
);
tracing::debug!(agent = %definition.name, allowed = ?definition.tools, "tools allowlist applied");
} else {
tracing::warn!(
agent = % definition.name, unresolved = ? unresolved, allowed = ?
definition.tools,
agent = %definition.name,
unresolved = ?unresolved,
allowed = ?definition.tools,
"tools allowlist had unmappable entries; keeping full grok toolset"
);
}
@ -1195,13 +1190,15 @@ impl AgentBuilder {
let mut hosted_tools = Vec::new();
if use_backend_search {
if web_search_enabled && definition.hosted_tool_allowed("web_search") {
hosted_tools.push(xai_grok_sampling_types::HostedTool::WebSearch {
allowed_domains: None,
});
hosted_tools.push(xai_grok_sampling_types::HostedTool::WebSearch { options: None });
}
if definition.hosted_tool_allowed("x_search") {
hosted_tools.push(xai_grok_sampling_types::HostedTool::XSearch);
hosted_tools.push(xai_grok_sampling_types::HostedTool::XSearch { options: None });
}
xai_grok_sampling_types::apply_tool_overrides(
&mut hosted_tools,
definition.tool_overrides.as_ref(),
);
}
#[allow(clippy::arc_with_non_send_sync)]
let tool_bridge = Arc::new(tool_bridge);
@ -1485,16 +1482,14 @@ mod tests {
&subagents,
&["zeta".to_string(), "alpha".to_string(), "alpha".to_string()],
);
assert!(
desc
.contains("If the user explicitly asks for the model of a subagent/task, you may ONLY use model slugs from this list:\n\
assert!(desc.contains(
"If the user explicitly asks for the model of a subagent/task, you may ONLY use model slugs from this list:\n\
- alpha\n\
- zeta")
);
assert!(
desc
.contains("If the user does not explicitly request a model, omit `${{ params.task.model }}` to inherit the parent model.")
);
- zeta"
));
assert!(desc.contains(
"If the user does not explicitly request a model, omit `${{ params.task.model }}` to inherit the parent model."
));
assert!(!desc.contains("Available model slugs:"));
assert!(!desc.contains(concat!("grok", " models")));
}
@ -1946,10 +1941,11 @@ mod tests {
use xai_grok_tools::types::resources::Params;
let mut definition = crate::config::AgentDefinition::default_grok_build();
definition.tools = vec!["run_terminal_cmd".into()];
let bash_params = serde_json::json!(
{ "max_timeout_secs" : 36_000.0, "auto_background_on_timeout" : true,
"allow_background_operator" : false, }
)
let bash_params = serde_json::json!({
"max_timeout_secs": 36_000.0,
"auto_background_on_timeout": true,
"allow_background_operator": false,
})
.as_object()
.unwrap()
.clone();
@ -2313,6 +2309,7 @@ mod tests {
web_search_enabled: bool,
backend_search_enabled: bool,
disallowed_tools: &[&str],
tool_overrides: Option<xai_grok_sampling_types::ToolOverrides>,
) -> crate::agent::Agent {
use xai_grok_tools::computer::local::LocalTerminalBackend;
use xai_grok_tools::implementations::web_search::WebSearchConfig;
@ -2330,6 +2327,7 @@ mod tests {
};
let mut def = crate::config::AgentDefinition::default_grok_build();
def.disallowed_tools = disallowed_tools.iter().map(|s| s.to_string()).collect();
def.tool_overrides = tool_overrides;
AgentBuilder::new(
std::env::temp_dir(),
Arc::new(LocalTerminalBackend::new()),
@ -2344,7 +2342,7 @@ mod tests {
}
#[tokio::test]
async fn disallowed_web_search_strips_function_and_hosted_tools() {
let agent = build_with_web_search(true, true, &["web_search"]).await;
let agent = build_with_web_search(true, true, &["web_search"], None).await;
let hosted = agent.hosted_tools();
assert!(
!hosted
@ -2355,7 +2353,7 @@ mod tests {
assert!(
hosted
.iter()
.any(|t| matches!(t, xai_grok_sampling_types::HostedTool::XSearch)),
.any(|t| matches!(t, xai_grok_sampling_types::HostedTool::XSearch { .. })),
"XSearch must remain when only web_search is disallowed, got: {hosted:?}"
);
let has_web_search_fn = agent
@ -2372,7 +2370,7 @@ mod tests {
/// hosted tools appear and `backend_search_enabled()` is true.
#[tokio::test]
async fn hosted_tools_populated_when_backend_search_and_web_search_enabled() {
let agent = build_with_web_search(true, true, &[]).await;
let agent = build_with_web_search(true, true, &[], None).await;
assert!(agent.backend_search_enabled());
let hosted = agent.hosted_tools();
assert!(
@ -2384,7 +2382,7 @@ mod tests {
assert!(
hosted
.iter()
.any(|t| matches!(t, xai_grok_sampling_types::HostedTool::XSearch)),
.any(|t| matches!(t, xai_grok_sampling_types::HostedTool::XSearch { .. })),
"expected XSearch hosted tool, got: {hosted:?}"
);
}
@ -2392,7 +2390,7 @@ mod tests {
/// WebSearch requires the web-search config.
#[tokio::test]
async fn hosted_tools_only_xsearch_when_web_search_disabled() {
let agent = build_with_web_search(false, true, &[]).await;
let agent = build_with_web_search(false, true, &[], None).await;
let hosted = agent.hosted_tools();
assert!(
!hosted
@ -2403,7 +2401,7 @@ mod tests {
assert!(
hosted
.iter()
.any(|t| matches!(t, xai_grok_sampling_types::HostedTool::XSearch)),
.any(|t| matches!(t, xai_grok_sampling_types::HostedTool::XSearch { .. })),
"expected XSearch hosted tool, got: {hosted:?}"
);
}
@ -2411,8 +2409,35 @@ mod tests {
/// of web-search config.
#[tokio::test]
async fn hosted_tools_empty_when_backend_search_disabled() {
let agent = build_with_web_search(true, false, &[]).await;
let agent = build_with_web_search(true, false, &[], None).await;
assert!(!agent.backend_search_enabled());
assert!(agent.hosted_tools().is_empty());
}
#[tokio::test]
async fn hosted_tools_bake_definition_tool_overrides_into_options() {
let x_search = xai_grok_sampling_types::XSearchOptions {
date_bound: Some(
xai_grok_sampling_types::SearchDateBound::new(None, Some("2024-03-15".into()))
.unwrap(),
),
};
let agent = build_with_web_search(
true,
true,
&[],
Some(xai_grok_sampling_types::ToolOverrides {
x_search: Some(x_search.clone()),
web_search: None,
}),
)
.await;
assert!(
agent
.hosted_tools()
.contains(&xai_grok_sampling_types::HostedTool::XSearch {
options: Some(x_search),
}),
"definition tool_overrides must be applied to HostedTool options"
);
}
}