mirror of
https://github.com/openclaw/openclaw.git
synced 2026-10-03 01:29:56 +00:00
fix(agents): reject empty sessions_search queries in the tool schema (#129120)
Fixes #129054. The `sessions_search` tool schema now requires a non-empty `query` (`minLength: 1`) with a concise description, so models are told up front instead of discovering it from an error, and a blank or whitespace query returns an actionable retry message. main already rejected blank queries at execution ("query must not be empty"); this adds the schema constraint and clearer guidance. Keyword searches are unchanged. The system prompt is unchanged; the tool schema grows by about 100 compact bytes. Time-range guidance from the original PR was deferred because live runs did not show the model using it. Proof: baseline schema accepts an empty query, this change rejects it; an isolated Gateway rejects blank queries with the retry guidance and returns the same keyword results. Live gpt-5-mini runs emitted a non-empty query. Regression tests fail on main and pass here. Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: Ayaan Zaidi <hi@obviy.us>
This commit is contained in:
parent
4aa24e3a13
commit
54db277b5b
6 changed files with 54 additions and 26 deletions
|
|
@ -7,6 +7,7 @@ import { replaceSessionEntrySync } from "../../config/sessions/session-accessor.
|
|||
import type { OpenClawConfig } from "../../config/types.openclaw.js";
|
||||
import type { callGateway as gatewayCall } from "../../gateway/call.js";
|
||||
import { createSessionVisibilityChecker } from "../../plugin-sdk/session-visibility.js";
|
||||
import { normalizeToolParameters } from "../agent-tools.schema.js";
|
||||
import { describeSessionLinkRule } from "../tool-description-presets.js";
|
||||
import { compactToolOutputHint } from "../tool-schema-hints.js";
|
||||
import { createSessionsSearchTool } from "./sessions-search-tool.js";
|
||||
|
|
@ -202,6 +203,25 @@ describe("sessions_search tool", () => {
|
|||
);
|
||||
});
|
||||
|
||||
it("rejects an empty query in the schema while accepting keywords", () => {
|
||||
const tool = createTool({});
|
||||
expect(Value.Check(tool.parameters, { query: "" })).toBe(false);
|
||||
expect(Value.Check(tool.parameters, { query: "loan" })).toBe(true);
|
||||
expect(Value.Check(tool.parameters, { query: " loan " })).toBe(true);
|
||||
});
|
||||
|
||||
it.each(["openai", "google"])(
|
||||
"rejects blank execution with retry guidance after %s schema normalization",
|
||||
async (modelProvider) => {
|
||||
const tool = normalizeToolParameters(createTool({}), { modelProvider });
|
||||
for (const query of ["", " "]) {
|
||||
await expect(tool.execute!("blank-query", { query })).rejects.toThrow(
|
||||
/query must not be empty; retry with non-empty keywords/,
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
it("filters invisible hits before applying the limit", async () => {
|
||||
const requests: CallGatewayRequest[] = [];
|
||||
const tool = createTool({
|
||||
|
|
|
|||
|
|
@ -50,7 +50,11 @@ const SESSIONS_SEARCH_INDEXING_WARNING =
|
|||
|
||||
const SessionsSearchToolSchema = Type.Object({
|
||||
user: requesterProfileSchema(),
|
||||
query: Type.String({ maxLength: SESSIONS_SEARCH_MAX_QUERY_CHARS }),
|
||||
query: Type.String({
|
||||
minLength: 1,
|
||||
maxLength: SESSIONS_SEARCH_MAX_QUERY_CHARS,
|
||||
description: "Required non-empty keywords to match in past user and assistant text.",
|
||||
}),
|
||||
sessionKey: Type.Optional(Type.String()),
|
||||
limit: optionalPositiveIntegerSchema({
|
||||
maximum: SESSIONS_SEARCH_MAX_LIMIT,
|
||||
|
|
@ -310,7 +314,9 @@ export function createSessionsSearchTool(opts?: {
|
|||
const params = args as Record<string, unknown>;
|
||||
const query = readToolStringParam(params, "query") ?? "";
|
||||
if (!query) {
|
||||
throw new ToolInputError("query must not be empty");
|
||||
throw new ToolInputError(
|
||||
"query must not be empty; retry with non-empty keywords to match in past session text",
|
||||
);
|
||||
}
|
||||
if (query.length > SESSIONS_SEARCH_MAX_QUERY_CHARS) {
|
||||
throw new ToolInputError(
|
||||
|
|
|
|||
|
|
@ -1332,7 +1332,9 @@
|
|||
"type": "integer"
|
||||
},
|
||||
"query": {
|
||||
"description": "Required non-empty keywords to match in past user and assistant text.",
|
||||
"maxLength": 4096,
|
||||
"minLength": 1,
|
||||
"type": "string"
|
||||
},
|
||||
"sessionKey": {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
--- telegram-direct-codex-message-tool.md sha256=d7dfb9a21011bee9b1cd8b769cae0d29d9ebbbf1e8d96a3a84873bfa8711242e
|
||||
+++ discord-group-codex-message-tool.md sha256=71b5d8e9471f38e06145340b0c186246822fad3484100924cd3e607a0d7e14bc
|
||||
--- telegram-direct-codex-message-tool.md sha256=5c0befbd287efb1bba2f0a88b440cdfadaf5da175afb9b219dff96928564e79e
|
||||
+++ discord-group-codex-message-tool.md sha256=b5294f195059c7243fab65032ce6fb353189d5a0ea32bb08bdb30f6f2a9a96b1
|
||||
@@ -1,1 +1,1 @@
|
||||
-# Telegram Direct Codex Message Tool Turn
|
||||
+# Discord Group Codex Message Tool Turn
|
||||
|
|
@ -32,10 +32,10 @@
|
|||
- "chars": 1348,
|
||||
+ "chars": 1347,
|
||||
@@ -261,2 +261,2 @@
|
||||
- "chars": 72263,
|
||||
- "roughTokens": 18066
|
||||
+ "chars": 72861,
|
||||
+ "roughTokens": 18216
|
||||
- "chars": 72395,
|
||||
- "roughTokens": 18099
|
||||
+ "chars": 72993,
|
||||
+ "roughTokens": 18249
|
||||
@@ -265,2 +265,2 @@
|
||||
- "chars": 2992,
|
||||
- "roughTokens": 748
|
||||
|
|
@ -47,10 +47,10 @@
|
|||
+ "chars": 28695,
|
||||
+ "roughTokens": 7174
|
||||
@@ -277,2 +277,2 @@
|
||||
- "chars": 99643,
|
||||
- "roughTokens": 24911
|
||||
+ "chars": 101558,
|
||||
+ "roughTokens": 25390
|
||||
- "chars": 99775,
|
||||
- "roughTokens": 24944
|
||||
+ "chars": 101690,
|
||||
+ "roughTokens": 25423
|
||||
@@ -281,2 +281,2 @@
|
||||
- "chars": 879,
|
||||
- "roughTokens": 220
|
||||
|
|
|
|||
|
|
@ -258,8 +258,8 @@ This is the deterministic model-bound layer stack OpenClaw can snapshot for the
|
|||
"roughTokens": 0
|
||||
},
|
||||
"dynamicToolsJson": {
|
||||
"chars": 72263,
|
||||
"roughTokens": 18066
|
||||
"chars": 72395,
|
||||
"roughTokens": 18099
|
||||
},
|
||||
"openClawDeveloperInstructions": {
|
||||
"chars": 2992,
|
||||
|
|
@ -274,8 +274,8 @@ This is the deterministic model-bound layer stack OpenClaw can snapshot for the
|
|||
"roughTokens": 6845
|
||||
},
|
||||
"totalWithDynamicToolsJson": {
|
||||
"chars": 99643,
|
||||
"roughTokens": 24911
|
||||
"chars": 99775,
|
||||
"roughTokens": 24944
|
||||
},
|
||||
"userInputText": {
|
||||
"chars": 879,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
--- telegram-direct-codex-message-tool.md sha256=d7dfb9a21011bee9b1cd8b769cae0d29d9ebbbf1e8d96a3a84873bfa8711242e
|
||||
+++ telegram-heartbeat-codex-tool.md sha256=046f19e66869e2dfb9bacc08a63a493637cc2993cda89fda643e4edd8854269d
|
||||
--- telegram-direct-codex-message-tool.md sha256=5c0befbd287efb1bba2f0a88b440cdfadaf5da175afb9b219dff96928564e79e
|
||||
+++ telegram-heartbeat-codex-tool.md sha256=4483ad37d42f6fb1a62d148f1ccc7528c79b045fe34379fa6cf83954f151e2ef
|
||||
@@ -1,1 +1,1 @@
|
||||
-# Telegram Direct Codex Message Tool Turn
|
||||
+# Telegram Direct Codex Heartbeat Tool Turn
|
||||
|
|
@ -37,20 +37,20 @@
|
|||
+ "chars": 1218,
|
||||
+ "roughTokens": 305
|
||||
@@ -261,2 +258,2 @@
|
||||
- "chars": 72263,
|
||||
- "roughTokens": 18066
|
||||
+ "chars": 73756,
|
||||
+ "roughTokens": 18439
|
||||
- "chars": 72395,
|
||||
- "roughTokens": 18099
|
||||
+ "chars": 73888,
|
||||
+ "roughTokens": 18472
|
||||
@@ -273,2 +270,2 @@
|
||||
- "chars": 27378,
|
||||
- "roughTokens": 6845
|
||||
+ "chars": 27715,
|
||||
+ "roughTokens": 6929
|
||||
@@ -277,2 +274,2 @@
|
||||
- "chars": 99643,
|
||||
- "roughTokens": 24911
|
||||
+ "chars": 101473,
|
||||
+ "roughTokens": 25369
|
||||
- "chars": 99775,
|
||||
- "roughTokens": 24944
|
||||
+ "chars": 101605,
|
||||
+ "roughTokens": 25402
|
||||
@@ -281,2 +278,2 @@
|
||||
- "chars": 879,
|
||||
- "roughTokens": 220
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue