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

@ -155,7 +155,10 @@ impl WebSearchClient {
return Err(xai_tool_runtime::ToolError::unauthorized(format!(
"Responses API returned 401 Unauthorized: {body}"
))
.with_details(serde_json::json!({ "tool_id" : "web_search", "status" : 401, })));
.with_details(serde_json::json!({
"tool_id": "web_search",
"status": 401,
})));
}
if !status.is_success() {
let body = response
@ -243,7 +246,10 @@ impl WebSearchClient {
return Err(xai_tool_runtime::ToolError::unauthorized(format!(
"Responses API returned 401 Unauthorized: {body}"
))
.with_details(serde_json::json!({ "tool_id" : "web_search", "status" : 401, })));
.with_details(serde_json::json!({
"tool_id": "web_search",
"status": 401,
})));
}
if !status.is_success() {
let body = response
@ -411,26 +417,56 @@ mod tests {
}
#[test]
fn test_extract_citations_empty_response() {
let response = response_from_json(serde_json::json!(
{ "id" : "resp_test", "object" : "response", "created_at" : 1234567890,
"status" : "completed", "output" : [], "model" : "test-model" }
));
let response = response_from_json(serde_json::json!({
"id": "resp_test",
"object": "response",
"created_at": 1234567890,
"status": "completed",
"output": [],
"model": "test-model"
}));
let citations = extract_citations(&response);
assert!(citations.is_empty());
}
#[test]
fn test_extract_citations_with_url_citations() {
let response = response_from_json(serde_json::json!(
{ "id" : "resp_test", "object" : "response", "created_at" : 1234567890,
"status" : "completed", "model" : "test-model", "output" : [{ "type" :
"message", "id" : "msg_1", "status" : "completed", "role" : "assistant",
"content" : [{ "type" : "output_text", "text" :
"Here is some info about Rust.", "annotations" : [{ "type" :
"url_citation", "url" : "https://www.rust-lang.org/", "title" :
"Rust Programming Language", "start_index" : 0, "end_index" : 10 }, {
"type" : "url_citation", "url" : "https://docs.rs/", "title" : "Docs.rs",
"start_index" : 11, "end_index" : 20 }] }] }] }
));
let response = response_from_json(serde_json::json!({
"id": "resp_test",
"object": "response",
"created_at": 1234567890,
"status": "completed",
"model": "test-model",
"output": [
{
"type": "message",
"id": "msg_1",
"status": "completed",
"role": "assistant",
"content": [
{
"type": "output_text",
"text": "Here is some info about Rust.",
"annotations": [
{
"type": "url_citation",
"url": "https://www.rust-lang.org/",
"title": "Rust Programming Language",
"start_index": 0,
"end_index": 10
},
{
"type": "url_citation",
"url": "https://docs.rs/",
"title": "Docs.rs",
"start_index": 11,
"end_index": 20
}
]
}
]
}
]
}));
let citations = extract_citations(&response);
assert_eq!(citations.len(), 2);
assert_eq!(citations[0], "https://www.rust-lang.org/");
@ -438,19 +474,50 @@ mod tests {
}
#[test]
fn test_extract_citations_deduplicates() {
let response = response_from_json(serde_json::json!(
{ "id" : "resp_test", "object" : "response", "created_at" : 1234567890,
"status" : "completed", "model" : "test-model", "output" : [{ "type" :
"message", "id" : "msg_1", "status" : "completed", "role" : "assistant",
"content" : [{ "type" : "output_text", "text" :
"Info with duplicate citations.", "annotations" : [{ "type" :
"url_citation", "url" : "https://example.com/page1", "title" : "Page 1",
"start_index" : 0, "end_index" : 5 }, { "type" : "url_citation", "url" :
"https://example.com/page2", "title" : "Page 2", "start_index" : 6,
"end_index" : 10 }, { "type" : "url_citation", "url" :
"https://example.com/page1", "title" : "Page 1 Again", "start_index" :
11, "end_index" : 15 }] }] }] }
));
let response = response_from_json(serde_json::json!({
"id": "resp_test",
"object": "response",
"created_at": 1234567890,
"status": "completed",
"model": "test-model",
"output": [
{
"type": "message",
"id": "msg_1",
"status": "completed",
"role": "assistant",
"content": [
{
"type": "output_text",
"text": "Info with duplicate citations.",
"annotations": [
{
"type": "url_citation",
"url": "https://example.com/page1",
"title": "Page 1",
"start_index": 0,
"end_index": 5
},
{
"type": "url_citation",
"url": "https://example.com/page2",
"title": "Page 2",
"start_index": 6,
"end_index": 10
},
{
"type": "url_citation",
"url": "https://example.com/page1",
"title": "Page 1 Again",
"start_index": 11,
"end_index": 15
}
]
}
]
}
]
}));
let citations = extract_citations(&response);
assert_eq!(citations.len(), 2);
assert_eq!(citations[0], "https://example.com/page1");
@ -458,19 +525,57 @@ mod tests {
}
#[test]
fn test_extract_citations_multiple_messages() {
let response = response_from_json(serde_json::json!(
{ "id" : "resp_test", "object" : "response", "created_at" : 1234567890,
"status" : "completed", "model" : "test-model", "output" : [{ "type" :
"message", "id" : "msg_1", "status" : "completed", "role" : "assistant",
"content" : [{ "type" : "output_text", "text" : "First message",
"annotations" : [{ "type" : "url_citation", "url" : "https://first.com/",
"title" : "First", "start_index" : 0, "end_index" : 5 }] }] }, { "type" :
"message", "id" : "msg_2", "status" : "completed", "role" : "assistant",
"content" : [{ "type" : "output_text", "text" : "Second message",
"annotations" : [{ "type" : "url_citation", "url" :
"https://second.com/", "title" : "Second", "start_index" : 0, "end_index"
: 6 }] }] }] }
));
let response = response_from_json(serde_json::json!({
"id": "resp_test",
"object": "response",
"created_at": 1234567890,
"status": "completed",
"model": "test-model",
"output": [
{
"type": "message",
"id": "msg_1",
"status": "completed",
"role": "assistant",
"content": [
{
"type": "output_text",
"text": "First message",
"annotations": [
{
"type": "url_citation",
"url": "https://first.com/",
"title": "First",
"start_index": 0,
"end_index": 5
}
]
}
]
},
{
"type": "message",
"id": "msg_2",
"status": "completed",
"role": "assistant",
"content": [
{
"type": "output_text",
"text": "Second message",
"annotations": [
{
"type": "url_citation",
"url": "https://second.com/",
"title": "Second",
"start_index": 0,
"end_index": 6
}
]
}
]
}
]
}));
let citations = extract_citations(&response);
assert_eq!(citations.len(), 2);
assert_eq!(citations[0], "https://first.com/");
@ -478,14 +583,36 @@ mod tests {
}
#[test]
fn test_extract_citations_ignores_non_url_annotations() {
let response = response_from_json(serde_json::json!(
{ "id" : "resp_test", "object" : "response", "created_at" : 1234567890,
"status" : "completed", "model" : "test-model", "output" : [{ "type" :
"message", "id" : "msg_1", "status" : "completed", "role" : "assistant",
"content" : [{ "type" : "output_text", "text" : "Some text",
"annotations" : [{ "type" : "url_citation", "url" : "https://valid.com/",
"title" : "Valid", "start_index" : 0, "end_index" : 4 }] }] }] }
));
let response = response_from_json(serde_json::json!({
"id": "resp_test",
"object": "response",
"created_at": 1234567890,
"status": "completed",
"model": "test-model",
"output": [
{
"type": "message",
"id": "msg_1",
"status": "completed",
"role": "assistant",
"content": [
{
"type": "output_text",
"text": "Some text",
"annotations": [
{
"type": "url_citation",
"url": "https://valid.com/",
"title": "Valid",
"start_index": 0,
"end_index": 4
}
]
}
]
}
]
}));
let citations = extract_citations(&response);
assert_eq!(citations.len(), 1);
assert_eq!(citations[0], "https://valid.com/");
@ -510,14 +637,24 @@ mod tests {
Mock::given(method("POST"))
.and(path("/responses"))
.and(header("Authorization", "Bearer static-key-from-config"))
.respond_with(ResponseTemplate::new(200).set_body_json(serde_json::json!(
{ "id" : "resp_test", "object" : "response", "created_at" :
1234567890, "status" : "completed", "model" : "test-model",
"output" : [{ "type" : "message", "id" : "msg_1", "status" :
"completed", "role" : "assistant", "content" : [{ "type" :
"output_text", "text" : "search result", "annotations" : []
}] }] }
)))
.respond_with(ResponseTemplate::new(200).set_body_json(serde_json::json!({
"id": "resp_test",
"object": "response",
"created_at": 1234567890,
"status": "completed",
"model": "test-model",
"output": [{
"type": "message",
"id": "msg_1",
"status": "completed",
"role": "assistant",
"content": [{
"type": "output_text",
"text": "search result",
"annotations": []
}]
}]
})))
.mount(&server)
.await;
let config = WebSearchConfig::Enabled {
@ -550,14 +687,24 @@ mod tests {
Mock::given(method("POST"))
.and(path("/responses"))
.and(header("Authorization", "Bearer fresh-key-from-provider"))
.respond_with(ResponseTemplate::new(200).set_body_json(serde_json::json!(
{ "id" : "resp_test", "object" : "response", "created_at" :
1234567890, "status" : "completed", "model" : "test-model",
"output" : [{ "type" : "message", "id" : "msg_1", "status" :
"completed", "role" : "assistant", "content" : [{ "type" :
"output_text", "text" : "fresh result", "annotations" : [] }]
}] }
)))
.respond_with(ResponseTemplate::new(200).set_body_json(serde_json::json!({
"id": "resp_test",
"object": "response",
"created_at": 1234567890,
"status": "completed",
"model": "test-model",
"output": [{
"type": "message",
"id": "msg_1",
"status": "completed",
"role": "assistant",
"content": [{
"type": "output_text",
"text": "fresh result",
"annotations": []
}]
}]
})))
.mount(&server)
.await;
let config = WebSearchConfig::Enabled {
@ -577,13 +724,28 @@ mod tests {
}
#[test]
fn test_extract_citations_no_annotations() {
let response = response_from_json(serde_json::json!(
{ "id" : "resp_test", "object" : "response", "created_at" : 1234567890,
"status" : "completed", "model" : "test-model", "output" : [{ "type" :
"message", "id" : "msg_1", "status" : "completed", "role" : "assistant",
"content" : [{ "type" : "output_text", "text" :
"Plain text with no annotations", "annotations" : [] }] }] }
));
let response = response_from_json(serde_json::json!({
"id": "resp_test",
"object": "response",
"created_at": 1234567890,
"status": "completed",
"model": "test-model",
"output": [
{
"type": "message",
"id": "msg_1",
"status": "completed",
"role": "assistant",
"content": [
{
"type": "output_text",
"text": "Plain text with no annotations",
"annotations": []
}
]
}
]
}));
let citations = extract_citations(&response);
assert!(citations.is_empty());
}