Spawn a shell command into its own process group so bash_stop/timeout can * kill grandchildren created by the shell, not just the /bin/sh wrapper. */
| 6806 | |
| 6807 | agent_dsml_parser_free(&p); |
| 6808 | } |
| 6809 | |
| 6810 | static void test_agent_glm_tool_parser_multiple_adjacent_calls(void) { |
| 6811 | const char *text = |
| 6812 | "<tool_call>list<arg_key>path</arg_key><arg_value>.</arg_value></tool_call>\n" |
| 6813 | "<tool_call>bash<arg_key>command</arg_key><arg_value>pwd</arg_value></tool_call>"; |
| 6814 | agent_dsml_parser p = { |
| 6815 | .syntax = AGENT_TOOL_SYNTAX_GLM, |
| 6816 | .state = AGENT_DSML_SEARCH, |
| 6817 | }; |
| 6818 | |
| 6819 | agent_dsml_feed(&p, text, strlen(text)); |
| 6820 | agent_dsml_finish(&p); |
| 6821 | |
| 6822 | AGENT_TEST_ASSERT(p.state == AGENT_DSML_DONE); |
| 6823 | AGENT_TEST_ASSERT(p.calls.len == 2); |
| 6824 | AGENT_TEST_ASSERT(p.calls.v[0].name && !strcmp(p.calls.v[0].name, "list")); |
| 6825 | AGENT_TEST_ASSERT(!strcmp(agent_tool_arg_value(&p.calls.v[0], "path"), ".")); |
| 6826 | AGENT_TEST_ASSERT(p.calls.v[1].name && !strcmp(p.calls.v[1].name, "bash")); |
| 6827 | AGENT_TEST_ASSERT(!strcmp(agent_tool_arg_value(&p.calls.v[1], "command"), "pwd")); |
| 6828 | |
| 6829 | agent_dsml_parser_free(&p); |
| 6830 | } |
| 6831 | |
| 6832 | static void test_agent_glm_stream_tool_call_chunked(void) { |
| 6833 | const char *chunks[] = { |
| 6834 | "intro ", |
| 6835 | "<to", |
| 6836 | "ol_call>bash<arg_key>command</arg_key><arg_value>printf hi</arg", |
| 6837 | "_value><arg_key>refresh_sec</arg_key><arg_value>1</arg_value></tool_call>", |
| 6838 | }; |
| 6839 | agent_dsml_parser p; |
| 6840 | char *out = agent_test_stream_capture(AGENT_TOOL_SYNTAX_GLM, |
| 6841 | chunks, |
| 6842 | sizeof(chunks)/sizeof(chunks[0]), |
| 6843 | &p, |
| 6844 | NULL); |
| 6845 | |
| 6846 | AGENT_TEST_ASSERT(p.state == AGENT_DSML_DONE); |
| 6847 | AGENT_TEST_ASSERT(p.calls.len == 1); |
| 6848 | AGENT_TEST_ASSERT(p.calls.v[0].name && !strcmp(p.calls.v[0].name, "bash")); |
| 6849 | AGENT_TEST_ASSERT(!strcmp(agent_tool_arg_value(&p.calls.v[0], "command"), |
| 6850 | "printf hi")); |
| 6851 | AGENT_TEST_ASSERT(strstr(out, "intro ") != NULL); |
| 6852 | AGENT_TEST_ASSERT(strstr(out, "printf hi") != NULL); |
| 6853 | AGENT_TEST_ASSERT(strstr(out, "<tool_call>") == NULL); |
| 6854 | AGENT_TEST_ASSERT(strstr(out, "<arg_key>") == NULL); |
| 6855 | AGENT_TEST_ASSERT(strstr(out, "</arg_value>") == NULL); |
| 6856 | |
| 6857 | free(out); |
| 6858 | agent_dsml_parser_free(&p); |
| 6859 | } |
| 6860 | |
| 6861 | static void test_agent_glm_stream_ignores_tool_inside_think(void) { |
| 6862 | const char *chunks[] = { |
| 6863 | "<think>plan <tool", |
| 6864 | "_call>bash<arg_key>command</arg_key><arg_value>printf hi</arg_value></tool_call>", |
| 6865 | "</think>done", |
no test coverage detected