Synced from monorepo
Changes: - Persist submitter identity for /feedback - Let custom models use rotating tokens from named auth providers - Template stale tool/param name literals in server-native descriptions - Minimal mode commits thinking in full, lookups as one-liners - Tighten durable append internals - Nudge model to end turn on no-op bash commands - Per-fetch signing nonce in the managed-config envelope, with a server-side replay probe - Include working tree in startup status
This commit is contained in:
parent
ba76b0a683
commit
a881e6703f
140 changed files with 6746 additions and 2377 deletions
|
|
@ -560,12 +560,10 @@ mod tests {
|
|||
match output {
|
||||
ToolOutputWire::Mcp { blocks } => {
|
||||
assert_eq!(blocks.len(), 2);
|
||||
assert!(
|
||||
matches!(&blocks[0], McpBlock::Text { text } if text == "result text")
|
||||
);
|
||||
assert!(
|
||||
matches!(&blocks[1], McpBlock::Image { mime_type, .. } if mime_type == "image/png")
|
||||
);
|
||||
assert!(matches!(&blocks[0], McpBlock::Text { text }
|
||||
if text == "result text"));
|
||||
assert!(matches!(&blocks[1], McpBlock::Image { mime_type, .. }
|
||||
if mime_type == "image/png"));
|
||||
}
|
||||
other => panic!("expected Mcp blocks, got {other:?}"),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -233,7 +233,8 @@ mod tests {
|
|||
});
|
||||
let notif = HubNotification::parse(&value).expect("should parse as Unknown, not None");
|
||||
assert!(
|
||||
matches!(notif, HubNotification::Unknown { ref method, .. } if method == "tool.notification"),
|
||||
matches!(notif, HubNotification::Unknown { ref method, .. }
|
||||
if method == "tool.notification"),
|
||||
"tool.notification without envelope session_id should fall back to Unknown, got {notif:?}"
|
||||
);
|
||||
}
|
||||
|
|
@ -273,7 +274,8 @@ mod tests {
|
|||
});
|
||||
let notif = HubNotification::parse(&value).expect("should parse as Unknown, not None");
|
||||
assert!(
|
||||
matches!(notif, HubNotification::Unknown { ref method, .. } if method == "tools_changed"),
|
||||
matches!(notif, HubNotification::Unknown { ref method, .. }
|
||||
if method == "tools_changed"),
|
||||
"malformed tools_changed should fall back to Unknown, got {notif:?}"
|
||||
);
|
||||
}
|
||||
|
|
@ -355,7 +357,8 @@ mod tests {
|
|||
});
|
||||
let notif = HubNotification::parse(&value).expect("should parse as Unknown, not None");
|
||||
assert!(
|
||||
matches!(notif, HubNotification::Unknown { ref method, .. } if method == "tool.notification"),
|
||||
matches!(notif, HubNotification::Unknown { ref method, .. }
|
||||
if method == "tool.notification"),
|
||||
"malformed tool.notification should fall back to Unknown, got {notif:?}"
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -53,7 +53,8 @@ fn tool_id_rejects_disallowed_characters() {
|
|||
] {
|
||||
let err = ToolId::new(bad).unwrap_err();
|
||||
assert!(
|
||||
matches!(err, IdError::InvalidFormat { ref value } if value == bad),
|
||||
matches!(err, IdError::InvalidFormat { ref value }
|
||||
if value == bad),
|
||||
"expected InvalidFormat for {bad:?}, got {err:?}"
|
||||
);
|
||||
}
|
||||
|
|
@ -73,7 +74,8 @@ fn tool_id_rejects_empty_segments_around_separator() {
|
|||
for bad in [":foo", "foo:", ":"] {
|
||||
let err = ToolId::new(bad).unwrap_err();
|
||||
assert!(
|
||||
matches!(err, IdError::InvalidFormat { ref value } if value == bad),
|
||||
matches!(err, IdError::InvalidFormat { ref value }
|
||||
if value == bad),
|
||||
"expected InvalidFormat for {bad:?}, got {err:?}"
|
||||
);
|
||||
}
|
||||
|
|
@ -103,7 +105,8 @@ fn server_id_rejects_reserved_auto_prefix() {
|
|||
for bad in ["auto:my-server", "auto:", "auto:tool:read_file"] {
|
||||
let err = ServerId::new(bad).unwrap_err();
|
||||
assert!(
|
||||
matches!(err, IdError::ReservedPrefix { ref value } if value == bad),
|
||||
matches!(err, IdError::ReservedPrefix { ref value }
|
||||
if value == bad),
|
||||
"expected ReservedPrefix for {bad:?}, got {err:?}"
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -534,7 +534,8 @@ mod tests {
|
|||
]);
|
||||
let blocks = extract_content_blocks(&v);
|
||||
assert_eq!(blocks.len(), 2);
|
||||
assert!(matches!(&blocks[0], ContentBlock::Text { text } if text == "a"));
|
||||
assert!(matches!(&blocks[0], ContentBlock::Text { text }
|
||||
if text == "a"));
|
||||
assert!(matches!(&blocks[1], ContentBlock::Image { .. }));
|
||||
}
|
||||
|
||||
|
|
@ -652,7 +653,8 @@ mod tests {
|
|||
assert_eq!(blocks.len(), 2);
|
||||
// First block is the remainder text (field order in JSON objects
|
||||
// is not guaranteed, so just check it's Text and non-empty).
|
||||
assert!(matches!(&blocks[0], ContentBlock::Text { text } if text.contains("summary")));
|
||||
assert!(matches!(&blocks[0], ContentBlock::Text { text }
|
||||
if text.contains("summary")));
|
||||
assert!(matches!(&blocks[1], ContentBlock::Image { .. }));
|
||||
}
|
||||
|
||||
|
|
@ -668,7 +670,8 @@ mod tests {
|
|||
let blocks = extract_content_blocks(&v);
|
||||
// results field → 2 blocks extracted, metadata → remainder text.
|
||||
assert_eq!(blocks.len(), 3);
|
||||
assert!(matches!(&blocks[0], ContentBlock::Text { text } if text.contains("metadata")));
|
||||
assert!(matches!(&blocks[0], ContentBlock::Text { text }
|
||||
if text.contains("metadata")));
|
||||
assert_eq!(blocks[1], ContentBlock::Text { text: "a".into() });
|
||||
assert_eq!(blocks[2], ContentBlock::Text { text: "b".into() });
|
||||
}
|
||||
|
|
|
|||
|
|
@ -45,16 +45,16 @@ fn invalid_arguments_round_trips_message_and_details() {
|
|||
fn not_found_maps_to_tool_not_found() {
|
||||
let err = ToolError::not_found(tid("missing"), "tool 'missing' not registered");
|
||||
let wire: ToolErrorWire = err.into();
|
||||
assert!(matches!(wire, ToolErrorWire::ToolNotFound { tool_id } if tool_id == tid("missing")));
|
||||
assert!(matches!(wire, ToolErrorWire::ToolNotFound { tool_id }
|
||||
if tool_id == tid("missing")));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn permission_denied_round_trips_reason() {
|
||||
let err = ToolError::permission_denied("not authorised for write");
|
||||
let wire: ToolErrorWire = err.into();
|
||||
assert!(
|
||||
matches!(wire, ToolErrorWire::PermissionDenied { reason } if reason == "not authorised for write")
|
||||
);
|
||||
assert!(matches!(wire, ToolErrorWire::PermissionDenied { reason }
|
||||
if reason == "not authorised for write"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -93,7 +93,8 @@ fn timeout_with_details() {
|
|||
fn cancelled_round_trips_tool_id() {
|
||||
let err = ToolError::cancelled(tid("paused"), "user cancelled");
|
||||
let wire: ToolErrorWire = err.into();
|
||||
assert!(matches!(wire, ToolErrorWire::Cancelled { tool_id } if tool_id == tid("paused")));
|
||||
assert!(matches!(wire, ToolErrorWire::Cancelled { tool_id }
|
||||
if tool_id == tid("paused")));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
|||
Loading…
Reference in a new issue