diff --git a/codex-rs/core/src/tools/code_mode_description.rs b/codex-rs/core/src/tools/code_mode_description.rs index c5657fcac..b7722aeb7 100644 --- a/codex-rs/core/src/tools/code_mode_description.rs +++ b/codex-rs/core/src/tools/code_mode_description.rs @@ -75,10 +75,10 @@ fn append_code_mode_sample( output_type: String, ) -> String { let declaration = format!( - "declare const tools: {{\n {}\n}};", + "declare const tools: {{ {} }};", render_code_mode_tool_declaration(tool_name, input_name, input_type, output_type) ); - format!("{description}\n\nCode mode declaration:\n```ts\n{declaration}\n```") + format!("{description}\n\nexec tool declaration:\n```ts\n{declaration}\n```") } fn render_code_mode_tool_declaration( @@ -87,28 +87,10 @@ fn render_code_mode_tool_declaration( input_type: String, output_type: String, ) -> String { - let input_type = indent_multiline_type(&input_type, 2); - let output_type = indent_multiline_type(&output_type, 2); let tool_name = normalize_code_mode_identifier(tool_name); format!("{tool_name}({input_name}: {input_type}): Promise<{output_type}>;") } -fn indent_multiline_type(type_name: &str, spaces: usize) -> String { - let indent = " ".repeat(spaces); - type_name - .lines() - .enumerate() - .map(|(index, line)| { - if index == 0 { - line.to_string() - } else { - format!("{indent}{line}") - } - }) - .collect::>() - .join("\n") -} - pub(crate) fn normalize_code_mode_identifier(tool_key: &str) -> String { let mut identifier = String::new(); @@ -134,10 +116,10 @@ pub(crate) fn normalize_code_mode_identifier(tool_key: &str) -> String { } fn render_json_schema_to_typescript(schema: &JsonValue) -> String { - render_json_schema_to_typescript_inner(schema, 0) + render_json_schema_to_typescript_inner(schema) } -fn render_json_schema_to_typescript_inner(schema: &JsonValue, indent: usize) -> String { +fn render_json_schema_to_typescript_inner(schema: &JsonValue) -> String { match schema { JsonValue::Bool(true) => "unknown".to_string(), JsonValue::Bool(false) => "never".to_string(), @@ -160,7 +142,7 @@ fn render_json_schema_to_typescript_inner(schema: &JsonValue, indent: usize) -> if let Some(variants) = map.get(key).and_then(serde_json::Value::as_array) { let rendered = variants .iter() - .map(|variant| render_json_schema_to_typescript_inner(variant, indent)) + .map(render_json_schema_to_typescript_inner) .collect::>(); if !rendered.is_empty() { return rendered.join(" | "); @@ -171,7 +153,7 @@ fn render_json_schema_to_typescript_inner(schema: &JsonValue, indent: usize) -> if let Some(variants) = map.get("allOf").and_then(serde_json::Value::as_array) { let rendered = variants .iter() - .map(|variant| render_json_schema_to_typescript_inner(variant, indent)) + .map(render_json_schema_to_typescript_inner) .collect::>(); if !rendered.is_empty() { return rendered.join(" & "); @@ -183,9 +165,7 @@ fn render_json_schema_to_typescript_inner(schema: &JsonValue, indent: usize) -> let rendered = types .iter() .filter_map(serde_json::Value::as_str) - .map(|schema_type| { - render_json_schema_type_keyword(map, schema_type, indent) - }) + .map(|schema_type| render_json_schema_type_keyword(map, schema_type)) .collect::>(); if !rendered.is_empty() { return rendered.join(" | "); @@ -193,7 +173,7 @@ fn render_json_schema_to_typescript_inner(schema: &JsonValue, indent: usize) -> } if let Some(schema_type) = schema_type.as_str() { - return render_json_schema_type_keyword(map, schema_type, indent); + return render_json_schema_type_keyword(map, schema_type); } } @@ -201,11 +181,11 @@ fn render_json_schema_to_typescript_inner(schema: &JsonValue, indent: usize) -> || map.contains_key("additionalProperties") || map.contains_key("required") { - return render_json_schema_object(map, indent); + return render_json_schema_object(map); } if map.contains_key("items") || map.contains_key("prefixItems") { - return render_json_schema_array(map, indent); + return render_json_schema_array(map); } "unknown".to_string() @@ -217,29 +197,28 @@ fn render_json_schema_to_typescript_inner(schema: &JsonValue, indent: usize) -> fn render_json_schema_type_keyword( map: &serde_json::Map, schema_type: &str, - indent: usize, ) -> String { match schema_type { "string" => "string".to_string(), "number" | "integer" => "number".to_string(), "boolean" => "boolean".to_string(), "null" => "null".to_string(), - "array" => render_json_schema_array(map, indent), - "object" => render_json_schema_object(map, indent), + "array" => render_json_schema_array(map), + "object" => render_json_schema_object(map), _ => "unknown".to_string(), } } -fn render_json_schema_array(map: &serde_json::Map, indent: usize) -> String { +fn render_json_schema_array(map: &serde_json::Map) -> String { if let Some(items) = map.get("items") { - let item_type = render_json_schema_to_typescript_inner(items, indent + 2); + let item_type = render_json_schema_to_typescript_inner(items); return format!("Array<{item_type}>"); } if let Some(items) = map.get("prefixItems").and_then(serde_json::Value::as_array) { let item_types = items .iter() - .map(|item| render_json_schema_to_typescript_inner(item, indent + 2)) + .map(render_json_schema_to_typescript_inner) .collect::>(); if !item_types.is_empty() { return format!("[{}]", item_types.join(", ")); @@ -249,7 +228,7 @@ fn render_json_schema_array(map: &serde_json::Map, indent: us "unknown[]".to_string() } -fn render_json_schema_object(map: &serde_json::Map, indent: usize) -> String { +fn render_json_schema_object(map: &serde_json::Map) -> String { let required = map .get("required") .and_then(serde_json::Value::as_array) @@ -268,7 +247,6 @@ fn render_json_schema_object(map: &serde_json::Map, indent: u let mut sorted_properties = properties.iter().collect::>(); sorted_properties.sort_unstable_by(|(name_a, _), (name_b, _)| name_a.cmp(name_b)); - let mut lines = sorted_properties .into_iter() .map(|(name, value)| { @@ -278,11 +256,8 @@ fn render_json_schema_object(map: &serde_json::Map, indent: u "?" }; let property_name = render_json_schema_property_name(name); - let property_type = render_json_schema_to_typescript_inner(value, indent + 2); - format!( - "{}{property_name}{optional}: {property_type};", - " ".repeat(indent + 2) - ) + let property_type = render_json_schema_to_typescript_inner(value); + format!("{property_name}{optional}: {property_type};") }) .collect::>(); @@ -290,24 +265,21 @@ fn render_json_schema_object(map: &serde_json::Map, indent: u let additional_type = match additional_properties { JsonValue::Bool(true) => Some("unknown".to_string()), JsonValue::Bool(false) => None, - value => Some(render_json_schema_to_typescript_inner(value, indent + 2)), + value => Some(render_json_schema_to_typescript_inner(value)), }; if let Some(additional_type) = additional_type { - lines.push(format!( - "{}[key: string]: {additional_type};", - " ".repeat(indent + 2) - )); + lines.push(format!("[key: string]: {additional_type};")); } } else if properties.is_empty() { - lines.push(format!("{}[key: string]: unknown;", " ".repeat(indent + 2))); + lines.push("[key: string]: unknown;".to_string()); } if lines.is_empty() { return "{}".to_string(); } - format!("{{\n{}\n{}}}", lines.join("\n"), " ".repeat(indent)) + format!("{{ {} }}", lines.join(" ")) } fn render_json_schema_property_name(name: &str) -> String { diff --git a/codex-rs/core/src/tools/code_mode_description_tests.rs b/codex-rs/core/src/tools/code_mode_description_tests.rs index d014fc409..034a1e3f3 100644 --- a/codex-rs/core/src/tools/code_mode_description_tests.rs +++ b/codex-rs/core/src/tools/code_mode_description_tests.rs @@ -17,7 +17,7 @@ fn render_json_schema_to_typescript_renders_object_properties() { assert_eq!( render_json_schema_to_typescript(&schema), - "{\n path: string;\n recursive?: boolean;\n}" + "{ path: string; recursive?: boolean; }" ); } @@ -52,7 +52,7 @@ fn render_json_schema_to_typescript_renders_additional_properties() { assert_eq!( render_json_schema_to_typescript(&schema), - "{\n tags?: Array;\n [key: string]: number;\n}" + "{ tags?: Array; [key: string]: number; }" ); } @@ -71,7 +71,7 @@ fn render_json_schema_to_typescript_sorts_object_properties() { assert_eq!( render_json_schema_to_typescript(&schema), - "{\n _meta?: string;\n content: Array;\n isError?: boolean;\n structuredContent?: string;\n}" + "{ _meta?: string; content: Array; isError?: boolean; structuredContent?: string; }" ); } @@ -85,7 +85,7 @@ fn append_code_mode_sample_uses_global_tools_for_valid_identifiers() { "{ foo: string }".to_string(), "unknown".to_string(), ), - "desc\n\nCode mode declaration:\n```ts\ndeclare const tools: {\n mcp__ologs__get_profile(args: { foo: string }): Promise;\n};\n```" + "desc\n\nexec tool declaration:\n```ts\ndeclare const tools: { mcp__ologs__get_profile(args: { foo: string }): Promise; };\n```" ); } @@ -99,6 +99,6 @@ fn append_code_mode_sample_normalizes_invalid_identifiers() { "{ foo: string }".to_string(), "unknown".to_string(), ), - "desc\n\nCode mode declaration:\n```ts\ndeclare const tools: {\n mcp__rmcp__echo_tool(args: { foo: string }): Promise;\n};\n```" + "desc\n\nexec tool declaration:\n```ts\ndeclare const tools: { mcp__rmcp__echo_tool(args: { foo: string }): Promise; };\n```" ); } diff --git a/codex-rs/core/src/tools/spec_tests.rs b/codex-rs/core/src/tools/spec_tests.rs index e56abbd29..c8dd7f21e 100644 --- a/codex-rs/core/src/tools/spec_tests.rs +++ b/codex-rs/core/src/tools/spec_tests.rs @@ -2432,7 +2432,7 @@ fn code_mode_augments_builtin_tool_descriptions_with_typed_sample() { assert_eq!( description, - "View a local image from the filesystem (only use if given a full filepath by the user, and the image isn't already attached to the thread context within tags).\n\nCode mode declaration:\n```ts\ndeclare const tools: {\n view_image(args: {\n path: string;\n }): Promise;\n};\n```" + "View a local image from the filesystem (only use if given a full filepath by the user, and the image isn't already attached to the thread context within tags).\n\nexec tool declaration:\n```ts\ndeclare const tools: { view_image(args: { path: string; }): Promise; };\n```" ); } @@ -2484,7 +2484,7 @@ fn code_mode_augments_mcp_tool_descriptions_with_namespaced_sample() { assert_eq!( description, - "Echo text\n\nCode mode declaration:\n```ts\ndeclare const tools: {\n mcp__sample__echo(args: {\n message: string;\n }): Promise<{\n _meta?: unknown;\n content: Array;\n isError?: boolean;\n structuredContent?: unknown;\n }>;\n};\n```" + "Echo text\n\nexec tool declaration:\n```ts\ndeclare const tools: { mcp__sample__echo(args: { message: string; }): Promise<{ _meta?: unknown; content: Array; isError?: boolean; structuredContent?: unknown; }>; };\n```" ); } diff --git a/codex-rs/core/tests/suite/code_mode.rs b/codex-rs/core/tests/suite/code_mode.rs index 5b2fe6376..6db519dd1 100644 --- a/codex-rs/core/tests/suite/code_mode.rs +++ b/codex-rs/core/tests/suite/code_mode.rs @@ -1828,7 +1828,7 @@ text(JSON.stringify(tool)); parsed, serde_json::json!({ "name": "view_image", - "description": "View a local image from the filesystem (only use if given a full filepath by the user, and the image isn't already attached to the thread context within tags).\n\nCode mode declaration:\n```ts\ndeclare const tools: {\n view_image(args: {\n path: string;\n }): Promise;\n};\n```", + "description": "View a local image from the filesystem (only use if given a full filepath by the user, and the image isn't already attached to the thread context within tags).\n\nexec tool declaration:\n```ts\ndeclare const tools: { view_image(args: { path: string; }): Promise; };\n```", }) ); @@ -1863,7 +1863,7 @@ text(JSON.stringify(tool)); parsed, serde_json::json!({ "name": "mcp__rmcp__echo", - "description": "Echo back the provided message and include environment data.\n\nCode mode declaration:\n```ts\ndeclare const tools: {\n mcp__rmcp__echo(args: {\n env_var?: string;\n message: string;\n }): Promise<{\n _meta?: unknown;\n content: Array;\n isError?: boolean;\n structuredContent?: unknown;\n }>;\n};\n```", + "description": "Echo back the provided message and include environment data.\n\nexec tool declaration:\n```ts\ndeclare const tools: { mcp__rmcp__echo(args: { env_var?: string; message: string; }): Promise<{ _meta?: unknown; content: Array; isError?: boolean; structuredContent?: unknown; }>; };\n```", }) );