Track where generation is inside a DSML tool call. This is intentionally a * forgiving recognizer, not a validator: malformed DSML still gets parsed later * by the normal tool-call parser. Here we only need enough state to decide * whether the next token belongs to protocol syntax or arbitrary payload. */
| 5461 | request_free(r); |
| 5462 | return false; |
| 5463 | } |
| 5464 | } else if (!json_skip_value(&p)) { |
| 5465 | free(key); |
| 5466 | goto bad; |
| 5467 | } |
| 5468 | free(key); |
| 5469 | json_ws(&p); |
| 5470 | if (*p == ',') p++; |
| 5471 | json_ws(&p); |
| 5472 | } |
| 5473 | if (*p != '}') goto bad; |
| 5474 | if (!got_input) { |
| 5475 | snprintf(err, errlen, "missing input"); |
| 5476 | chat_msgs_free(&msgs); |
| 5477 | buf_free(&loaded_tool_schemas); |
| 5478 | free(instructions); |
| 5479 | free(tool_schemas); |
| 5480 | request_free(r); |
| 5481 | return false; |
| 5482 | } |
| 5483 | /* instructions in the Responses API replaces any system message — for Codex |
| 5484 | * it carries the full agent system prompt. Prepend it so render produces a |
| 5485 | * standard system+chat layout. */ |
| 5486 | if (instructions && instructions[0]) { |
| 5487 | chat_msg msg = {0}; |
| 5488 | msg.role = xstrdup("system"); |
| 5489 | msg.content = instructions; |
| 5490 | instructions = NULL; |
| 5491 | /* Insert at the head so it precedes the conversation. */ |
| 5492 | chat_msgs_push(&msgs, msg); |
| 5493 | if (msgs.len > 1) { |
| 5494 | chat_msg tmp = msgs.v[msgs.len - 1]; |
| 5495 | for (int i = msgs.len - 1; i > 0; i--) msgs.v[i] = msgs.v[i - 1]; |
| 5496 | msgs.v[0] = tmp; |
| 5497 | } |
| 5498 | } |
| 5499 | buf combined_tool_schemas = {0}; |
| 5500 | if (tool_schemas && tool_schemas[0]) buf_puts(&combined_tool_schemas, tool_schemas); |
| 5501 | if (loaded_tool_schemas.len) { |
| 5502 | if (combined_tool_schemas.len) buf_putc(&combined_tool_schemas, '\n'); |
| 5503 | buf_append(&combined_tool_schemas, loaded_tool_schemas.ptr, |
| 5504 | loaded_tool_schemas.len); |
| 5505 | } |
| 5506 | const char *active_tool_schemas = |
| 5507 | (!tool_choice_none && combined_tool_schemas.len) ? |
| 5508 | combined_tool_schemas.ptr : NULL; |
| 5509 | r->has_tools = active_tool_schemas && active_tool_schemas[0]; |
| 5510 | if (!got_thinking && model_alias_disables_thinking(r->model)) thinking_enabled = false; |
| 5511 | if (!got_thinking && model_alias_enables_thinking(r->model)) thinking_enabled = true; |
| 5512 | r->think_mode = ds4_think_mode_for_context( |
| 5513 | think_mode_from_enabled(thinking_enabled, reasoning_effort), ctx_size); |
| 5514 | if (!responses_validate_tool_outputs(s, &msgs, r->think_mode, |
| 5515 | &r->responses_requires_live_tool_state, |
| 5516 | &r->responses_requires_live_reasoning, |
| 5517 | err, errlen)) { |
| 5518 | chat_msgs_free(&msgs); |
| 5519 | buf_free(&combined_tool_schemas); |
| 5520 | buf_free(&loaded_tool_schemas); |