Perform the full compaction exchange and rebuild the live DS4 session from * the compacted transcript. Any failure invalidates live KV because the model * may have just seen private compaction instructions that are not part of the * real conversation. */
| 7327 | /* Implement the search tool using either literal matching or POSIX regex. */ |
| 7328 | static char *agent_tool_search(agent_worker *w, const agent_tool_call *call) { |
| 7329 | (void)w; |
| 7330 | const char *query = agent_tool_arg_value(call, "query"); |
| 7331 | if (!query || !query[0]) return xstrdup("Tool error: search requires query\n"); |
| 7332 | const char *path = agent_tool_arg_value(call, "path"); |
| 7333 | if (!path || !path[0]) path = "."; |
| 7334 | const char *mode = agent_tool_arg_value(call, "mode"); |
| 7335 | agent_search_ctx ctx = { |
| 7336 | .query = query, |
| 7337 | .glob = agent_tool_arg_value(call, "glob"), |
| 7338 | .use_regex = mode && !strcmp(mode, "regex"), |
| 7339 | .case_sensitive = agent_parse_bool_default(agent_tool_arg_value(call, "case_sensitive"), true), |
| 7340 | .context = agent_parse_int_default(agent_tool_arg_value(call, "context"), 0, 0, 5), |
| 7341 | .max_results = agent_parse_int_default(agent_tool_arg_value(call, "max_results"), 50, 1, 500), |
| 7342 | }; |
| 7343 | if (ctx.use_regex) { |
| 7344 | int flags = REG_EXTENDED | REG_NOSUB; |
| 7345 | if (!ctx.case_sensitive) flags |= REG_ICASE; |
| 7346 | int rc = regcomp(&ctx.regex, query, flags); |
| 7347 | if (rc != 0) { |
| 7348 | char msg[256]; |
| 7349 | regerror(rc, &ctx.regex, msg, sizeof(msg)); |
| 7350 | agent_buf b = {0}; |
| 7351 | agent_buf_puts(&b, "Tool error: invalid regex: "); |
| 7352 | agent_buf_puts(&b, msg); |
| 7353 | agent_buf_puts(&b, "\n"); |
| 7354 | return agent_buf_take(&b); |
| 7355 | } |
| 7356 | ctx.regex_ready = true; |
| 7357 | } |
| 7358 | agent_search_path(&ctx, path, 0); |
| 7359 | if (ctx.regex_ready) regfree(&ctx.regex); |
| 7360 | if (!ctx.out.ptr) agent_buf_puts(&ctx.out, "No matches\n"); |
| 7361 | else { |
| 7362 | char hdr[96]; |
| 7363 | snprintf(hdr, sizeof(hdr), "%d match%s shown\n\n", |
| 7364 | ctx.results, ctx.results == 1 ? "" : "es"); |
| 7365 | size_t hdr_len = strlen(hdr); |
| 7366 | if (ctx.out.len + hdr_len + 1 > ctx.out.cap) { |
| 7367 | ctx.out.cap = ctx.out.len + hdr_len + 1; |
| 7368 | ctx.out.ptr = xrealloc(ctx.out.ptr, ctx.out.cap); |
| 7369 | } |
| 7370 | memmove(ctx.out.ptr + hdr_len, ctx.out.ptr, ctx.out.len + 1); |
| 7371 | memcpy(ctx.out.ptr, hdr, hdr_len); |
| 7372 | ctx.out.len += hdr_len; |
| 7373 | } |
| 7374 | return agent_buf_take(&ctx.out); |
| 7375 | } |
| 7376 | |
| 7377 | /* ============================================================================ |
| 7378 | * Browser Web Tools |
| 7379 | * ============================================================================ |
| 7380 | * |
| 7381 | * The browser subsystem lives in ds4_web.c: it owns visible Chrome and CDP. The |
| 7382 | * agent side only asks for permission, dispatches tools, and caps visit_page |
| 7383 | * output using the same "head plus temp file" shape as bash. |
| 7384 | */ |
| 7385 | |
| 7386 | #define AGENT_WEB_HEAD_BYTES (8*1024) |
no test coverage detected