mirror of
https://github.com/codewhale-hq/Codewhale.git
synced 2026-11-11 01:51:34 -10:00
Merge pull request #5944 from gaord/fix/fleet-bash-schema-null
fix(tui): stop fleet readonly schema probe from auto-vivifying null enums
This commit is contained in:
4 files changed
+97
-2
No files matched your search
@@ -565,6 +565,14 @@ Reports and reproductions that shaped this release:
|
||||
|
||||
### Fixed
|
||||
|
||||
- Read-only Fleet workers no longer send `"action": {"enum": null}` in their
|
||||
projected `bash` schema. The read-only projection probed the action enum
|
||||
with a mutating index, which auto-vivified the key on schemas that have no
|
||||
action property, and strict OpenAI-compatible validators then rejected the
|
||||
whole request (`null is not of type "array"`). The probe is non-mutating
|
||||
now, in both the read-only projection and the `Run` arm next to it, and a
|
||||
regression test walks the whole projected catalog for nulls
|
||||
(#5944, thanks @gaord).
|
||||
- Fast typing no longer corrupts the composer. The paste-burst heuristic ran
|
||||
on every session until a real bracketed paste arrived, holding, buffering,
|
||||
retro-grabbing, and absorbing Enter on timing guesses; it is now
|
||||
|
||||
@@ -565,6 +565,14 @@ Reports and reproductions that shaped this release:
|
||||
|
||||
### Fixed
|
||||
|
||||
- Read-only Fleet workers no longer send `"action": {"enum": null}` in their
|
||||
projected `bash` schema. The read-only projection probed the action enum
|
||||
with a mutating index, which auto-vivified the key on schemas that have no
|
||||
action property, and strict OpenAI-compatible validators then rejected the
|
||||
whole request (`null is not of type "array"`). The probe is non-mutating
|
||||
now, in both the read-only projection and the `Run` arm next to it, and a
|
||||
regression test walks the whole projected catalog for nulls
|
||||
(#5944, thanks @gaord).
|
||||
- Fast typing no longer corrupts the composer. The paste-burst heuristic ran
|
||||
on every session until a real bracketed paste arrived, holding, buffering,
|
||||
retro-grabbing, and absorbing Enter on timing guesses; it is now
|
||||
|
||||
@@ -505,12 +505,24 @@ fn project_readonly_evidence_schema(name: &str, schema: &mut Value) {
|
||||
if name == "Run" {
|
||||
// The shared classifier remains authoritative for `args`; the schema
|
||||
// removes the only field that can name verifier programs.
|
||||
if let Some(properties) = schema["properties"].as_object_mut() {
|
||||
if let Some(properties) = schema.get_mut("properties").and_then(Value::as_object_mut) {
|
||||
properties.remove("commands");
|
||||
}
|
||||
return;
|
||||
}
|
||||
let Some(actions) = schema["properties"]["action"]["enum"].as_array_mut() else {
|
||||
// Probe with `pointer_mut`, never `schema["properties"]["action"]["enum"]`:
|
||||
// serde_json's IndexMut auto-vivifies missing keys by inserting Null, so
|
||||
// the old probe left `properties.action = {"enum": null}` inside schemas
|
||||
// that have no action property (e.g. lowercase `bash`). Strict
|
||||
// OpenAI-compatible validators then reject the whole request with
|
||||
// `Invalid schema for function 'bash': null is not of type "array"`
|
||||
// (observed on Fleet read-only workers; see registry tests).
|
||||
// The same probe idiom lives in `tools/subagent` (grep `pointer_mut(
|
||||
// "/properties/action/enum")`); keep the two sites greppable as one.
|
||||
let Some(actions) = schema
|
||||
.pointer_mut("/properties/action/enum")
|
||||
.and_then(Value::as_array_mut)
|
||||
else {
|
||||
return;
|
||||
};
|
||||
match name {
|
||||
|
||||
@@ -1803,3 +1803,70 @@ fn a_builder_upgrade_replaces_the_tool_instead_of_registering_it_twice() {
|
||||
"the upgrade still adds apply_patch"
|
||||
);
|
||||
}
|
||||
|
||||
/// Regression probe for the fleet-52663788 class of provider 400
|
||||
/// (`Invalid schema for function 'bash': null is not of type "array"`):
|
||||
/// a read-only Fleet worker (reviewer) projects its tool schemas before the
|
||||
/// wire; no projected schema may carry a JSON null, because strict
|
||||
/// OpenAI-compatible validators reject null where arrays/objects are typed.
|
||||
#[test]
|
||||
fn fleet_readonly_reviewer_wire_catalog_carries_no_null_schema_fields() {
|
||||
use crate::tools::spec::{
|
||||
ToolMutationAuthority, ToolShellAuthority, ToolVerificationAuthority,
|
||||
};
|
||||
|
||||
fn collect_null_paths(value: &Value, path: String, out: &mut Vec<String>) {
|
||||
match value {
|
||||
Value::Null => out.push(path),
|
||||
Value::Object(map) => {
|
||||
for (key, child) in map {
|
||||
collect_null_paths(child, format!("{path}.{key}"), out);
|
||||
}
|
||||
}
|
||||
Value::Array(items) => {
|
||||
for (index, child) in items.iter().enumerate() {
|
||||
collect_null_paths(child, format!("{path}[{index}]"), out);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
let tmp = tempdir().expect("tempdir");
|
||||
let reviewer_authority = ToolAuthorityEnvelope {
|
||||
schema_version: 1,
|
||||
owner: "reviewer".to_string(),
|
||||
authority: ToolMutationAuthority::ReadOnly,
|
||||
network_access: Some(false),
|
||||
shell: ToolShellAuthority::ReadOnly,
|
||||
verification: ToolVerificationAuthority::None,
|
||||
writable_roots: Vec::new(),
|
||||
writable_files: Vec::new(),
|
||||
coordination_contracts: Vec::new(),
|
||||
};
|
||||
let context = ToolContext::new(tmp.path().to_path_buf())
|
||||
.with_tool_authority(reviewer_authority)
|
||||
.expect("reviewer authority");
|
||||
|
||||
let registry = ToolRegistryBuilder::new()
|
||||
.with_file_tools()
|
||||
.with_foreground_shell_tools()
|
||||
.with_search_tools()
|
||||
.build(context);
|
||||
let tools = registry.to_api_tools();
|
||||
assert!(
|
||||
tools.iter().any(|tool| tool.name == "bash"),
|
||||
"reviewer keeps classifier-bounded bash"
|
||||
);
|
||||
|
||||
for tool in &tools {
|
||||
let mut nulls = Vec::new();
|
||||
collect_null_paths(&tool.input_schema, "$".to_string(), &mut nulls);
|
||||
assert!(
|
||||
nulls.is_empty(),
|
||||
"tool {} schema carries null at {nulls:?}: {}",
|
||||
tool.name,
|
||||
tool.input_schema
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user