feat(xai): support namespace tools and enhance tool normalization logic
- Added `namespace` tool type support, enabling nested tools to be normalized and moved to the top level. - Refactored tool normalization logic into `normalizeXAITool` for reusability and clarity. - Updated `xai_executor` test cases to validate namespace tool handling and nested tool normalization.
This commit is contained in:
@@ -55,7 +55,7 @@ func TestXAIExecutorExecuteShapesResponsesRequest(t *testing.T) {
|
||||
|
||||
_, err := exec.Execute(context.Background(), auth, cliproxyexecutor.Request{
|
||||
Model: "grok-4.3",
|
||||
Payload: []byte(`{"model":"grok-4.3","input":[{"type":"reasoning","summary":[{"type":"summary_text","text":"test"}],"content":null,"encrypted_content":null},{"role":"user","content":"hello"}],"include":["reasoning.encrypted_content"],"reasoning":{"effort":"high"},"tools":[{"type":"tool_search"},{"type":"image_generation"},{"type":"custom","name":"apply_patch"},{"type":"custom","name":"custom_lookup"},{"type":"function","name":"lookup"},{"type":"web_search","external_web_access":true,"search_content_types":["text","image"]},{"type":"namespace","name":"codex_app","description":"Tools in the codex_app namespace.","tools":[{"type":"function","name":"automation_update"},{"type":"custom","name":"namespace_custom"},{"type":"tool_search"}]}]}`),
|
||||
Payload: []byte(`{"model":"grok-4.3","input":[{"type":"reasoning","summary":[{"type":"summary_text","text":"test"}],"content":null,"encrypted_content":null},{"type":"reasoning","summary":[{"type":"summary_text","text":"second"}]},{"role":"user","content":"hello"}],"include":["reasoning.encrypted_content"],"reasoning":{"effort":"high"},"tools":[{"type":"tool_search"},{"type":"image_generation"},{"type":"custom","name":"apply_patch"},{"type":"custom","name":"custom_lookup"},{"type":"function","name":"lookup"},{"type":"web_search","external_web_access":true,"search_content_types":["text","image"]},{"type":"namespace","name":"codex_app","description":"Tools in the codex_app namespace.","tools":[{"type":"function","name":"automation_update"},{"type":"custom","name":"namespace_custom"},{"type":"tool_search"}]}]}`),
|
||||
}, cliproxyexecutor.Options{
|
||||
SourceFormat: sdktranslator.FormatOpenAIResponse,
|
||||
Stream: false,
|
||||
@@ -100,6 +100,15 @@ func TestXAIExecutorExecuteShapesResponsesRequest(t *testing.T) {
|
||||
if got := gjson.GetBytes(gotBody, "input.0.summary.0.text").String(); got != "test" {
|
||||
t.Fatalf("input.0.summary.0.text = %q, want test; body=%s", got, string(gotBody))
|
||||
}
|
||||
if got := gjson.GetBytes(gotBody, "input.0.summary.1.text").String(); got != "second" {
|
||||
t.Fatalf("input.0.summary.1.text = %q, want second; body=%s", got, string(gotBody))
|
||||
}
|
||||
if got := gjson.GetBytes(gotBody, "input.1.role").String(); got != "user" {
|
||||
t.Fatalf("input.1.role = %q, want user; body=%s", got, string(gotBody))
|
||||
}
|
||||
if gjson.GetBytes(gotBody, "input.2").Exists() {
|
||||
t.Fatalf("input.2 exists, want consecutive reasoning item merged; body=%s", string(gotBody))
|
||||
}
|
||||
tools := gjson.GetBytes(gotBody, "tools").Array()
|
||||
if len(tools) != 5 {
|
||||
t.Fatalf("tools length = %d, want 5; body=%s", len(tools), string(gotBody))
|
||||
@@ -206,7 +215,7 @@ func TestXAIExecutorExecuteStreamFiltersToolSearchTool(t *testing.T) {
|
||||
|
||||
result, err := exec.ExecuteStream(context.Background(), auth, cliproxyexecutor.Request{
|
||||
Model: "grok-4.3",
|
||||
Payload: []byte(`{"model":"grok-4.3","input":[{"type":"reasoning","summary":[{"type":"summary_text","text":"test"}],"content":null,"encrypted_content":null},{"role":"user","content":"hello"}],"tools":[{"type":"tool_search"},{"type":"image_generation"},{"type":"custom","name":"apply_patch"},{"type":"custom","name":"custom_lookup"},{"type":"function","name":"lookup"},{"type":"web_search","external_web_access":true,"search_content_types":["text","image"]},{"type":"namespace","name":"codex_app","description":"Tools in the codex_app namespace.","tools":[{"type":"function","name":"automation_update"},{"type":"custom","name":"namespace_custom"},{"type":"tool_search"}]}]}`),
|
||||
Payload: []byte(`{"model":"grok-4.3","input":[{"type":"reasoning","summary":[{"type":"summary_text","text":"test"}],"content":null,"encrypted_content":null},{"type":"reasoning","summary":[{"type":"summary_text","text":"second"}]},{"role":"user","content":"hello"},{"type":"reasoning","summary":[{"type":"summary_text","text":"separate"}]}],"tools":[{"type":"tool_search"},{"type":"image_generation"},{"type":"custom","name":"apply_patch"},{"type":"custom","name":"custom_lookup"},{"type":"function","name":"lookup"},{"type":"web_search","external_web_access":true,"search_content_types":["text","image"]},{"type":"namespace","name":"codex_app","description":"Tools in the codex_app namespace.","tools":[{"type":"function","name":"automation_update"},{"type":"custom","name":"namespace_custom"},{"type":"tool_search"}]}]}`),
|
||||
}, cliproxyexecutor.Options{
|
||||
SourceFormat: sdktranslator.FormatOpenAIResponse,
|
||||
Stream: true,
|
||||
@@ -233,6 +242,15 @@ func TestXAIExecutorExecuteStreamFiltersToolSearchTool(t *testing.T) {
|
||||
if got := gjson.GetBytes(gotBody, "input.0.summary.0.text").String(); got != "test" {
|
||||
t.Fatalf("input.0.summary.0.text = %q, want test; body=%s", got, string(gotBody))
|
||||
}
|
||||
if got := gjson.GetBytes(gotBody, "input.0.summary.1.text").String(); got != "second" {
|
||||
t.Fatalf("input.0.summary.1.text = %q, want second; body=%s", got, string(gotBody))
|
||||
}
|
||||
if got := gjson.GetBytes(gotBody, "input.1.role").String(); got != "user" {
|
||||
t.Fatalf("input.1.role = %q, want user; body=%s", got, string(gotBody))
|
||||
}
|
||||
if got := gjson.GetBytes(gotBody, "input.2.summary.0.text").String(); got != "separate" {
|
||||
t.Fatalf("input.2.summary.0.text = %q, want separate; body=%s", got, string(gotBody))
|
||||
}
|
||||
foundAutomationUpdate := false
|
||||
foundNamespaceCustom := false
|
||||
for i, tool := range tools {
|
||||
|
||||
Reference in New Issue
Block a user