@theokit/sdk-tools 0.28.0 → 0.29.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,33 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.29.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [#859](https://github.com/usetheokit/theokit-sdk/pull/859) [`0b76797`](https://github.com/usetheokit/theokit-sdk/commit/0b767975a8076a82c7834b5b11a032083fd06a51) Thanks [@usetheodev](https://github.com/usetheodev)! - `createGoalTool`, from the `@theokit/sdk-tools/goal` subpath, adds a `goal` tool that keeps one
8
+ standing goal per session across turns, for an objective that outlives a single turn (a checklist
9
+ stays with `todolist`). Its actions are `set`, `get`, `complete` and `clear`. `set` replaces an
10
+ existing goal and returns the previous text; `complete` on a finished goal is refused. Goals are
11
+ keyed by the run's `ctx.threadId`, so one tool object serves many sessions, and calls without a
12
+ thread id share one default goal. The goal lives in memory only and does not survive a restart.
13
+ Goal text is trimmed and capped at 2000 characters by default (`maxGoalChars`); every failure is a
14
+ typed result (`missing_goal`, `goal_too_long`, `no_goal`, `already_done`, `invalid_action`), never
15
+ a throw. It ships from its own subpath rather than the package root, so the root bundle stays
16
+ within its gzip budget.
17
+
18
+ - [#859](https://github.com/usetheokit/theokit-sdk/pull/859) [`9a4adbf`](https://github.com/usetheokit/theokit-sdk/commit/9a4adbf4d751049d46ccd00dbfba1e3d02f7e0ab) Thanks [@usetheodev](https://github.com/usetheodev)! - `@theokit/sdk-tools/web-search-adapters` adds two providers for `createWebSearchTool`:
19
+ `createTavilyWebSearchAdapter` (a bearer-key POST; the key comes from `{ apiKey }` or
20
+ `TAVILY_API_KEY`) and `createSearxngWebSearchAdapter` (a keyless GET against your own instance;
21
+ the base URL comes from `{ baseUrl }` or `SEARXNG_BASE_URL`, and the instance must have the json
22
+ format enabled). Both reject on a non-OK status, so the tool reports `search_failed`, and return an
23
+ empty list for a 200 body without results. They ship from their own subpath so the root bundle
24
+ stays inside its size budget. The request and response shapes follow each provider's public
25
+ documentation and were not exercised against a live service.
26
+
27
+ ### Patch Changes
28
+
29
+ - [#859](https://github.com/usetheokit/theokit-sdk/pull/859) [`9024a16`](https://github.com/usetheokit/theokit-sdk/commit/9024a16627657411c8be0d5e367f665f3e07c9a6) Thanks [@usetheodev](https://github.com/usetheodev)! - Add `structured_output`, a built-in tool that returns the model's object only when it validates against the consumer's zod schema, imported from the subpath `@theokit/sdk-tools/structured-output` (`createStructuredOutputTool({ schema })`). A valid call returns `{ ok: true, output }` with the parsed value; an invalid or non-object call returns the typed `invalid_structured_output` result with up to `maxIssues` `{ path, message }` issues and the full `issue_count`, and never throws. A schema that is not an object, or a `maxIssues` that is not a positive integer, fails at construction. The tool does not end the agent turn: the host stops on `ok: true`.
30
+
3
31
  ## 0.28.0
4
32
 
5
33
  ### Minor Changes
package/dist/goal.cjs ADDED
@@ -0,0 +1,84 @@
1
+ 'use strict';
2
+
3
+ // src/goal.ts
4
+ var DEFAULT_MAX_GOAL_CHARS = 2e3;
5
+ var DEFAULT_SESSION = "__default__";
6
+ function ok(data) {
7
+ return JSON.stringify({ ok: true, ...data });
8
+ }
9
+ function fail(error) {
10
+ return JSON.stringify({ ok: false, error });
11
+ }
12
+ function readMaxGoalChars(options) {
13
+ const max = options?.maxGoalChars ?? DEFAULT_MAX_GOAL_CHARS;
14
+ if (!Number.isInteger(max) || max <= 0) {
15
+ throw new RangeError(`createGoalTool: maxGoalChars must be a positive integer, got ${max}`);
16
+ }
17
+ return max;
18
+ }
19
+ function createGoalTool(options) {
20
+ const maxGoalChars = readMaxGoalChars(options);
21
+ const goals = /* @__PURE__ */ new Map();
22
+ function handleSet(key, input) {
23
+ const text = typeof input.goal === "string" ? input.goal.trim() : "";
24
+ if (text === "") return fail("missing_goal");
25
+ if (text.length > maxGoalChars) return fail("goal_too_long");
26
+ const previous = goals.get(key);
27
+ const goal = { text, status: "active", setAt: Date.now() };
28
+ goals.set(key, goal);
29
+ if (previous === void 0) return ok({ goal, replaced: false });
30
+ return ok({ goal, replaced: true, previous: previous.text });
31
+ }
32
+ function handleComplete(key) {
33
+ const goal = goals.get(key);
34
+ if (goal === void 0) return fail("no_goal");
35
+ if (goal.status === "done") return fail("already_done");
36
+ goal.status = "done";
37
+ goal.completedAt = Date.now();
38
+ return ok({ goal });
39
+ }
40
+ function handle(input, key) {
41
+ const fields = typeof input === "object" && input !== null ? input : {};
42
+ switch (fields.action) {
43
+ case "set":
44
+ return handleSet(key, fields);
45
+ case "get":
46
+ return ok({ goal: goals.get(key) ?? null });
47
+ case "complete":
48
+ return handleComplete(key);
49
+ case "clear":
50
+ goals.delete(key);
51
+ return ok({ goal: null });
52
+ default:
53
+ return fail("invalid_action");
54
+ }
55
+ }
56
+ return {
57
+ name: "goal",
58
+ description: `Keep ONE standing goal for the current session, read back across turns. Use it when the user states an objective that spans many turns, and check it with 'get' before deciding you are finished; use todolist for the steps toward it. Actions: 'set' (store the goal text, at most ${maxGoalChars} characters after trimming, replacing any existing goal and returning it as previous), 'get' (current goal or null), 'complete' (mark it done), 'clear' (drop it). Returns { ok, goal } with goal = { text, status, setAt, completedAt }; failures are { ok: false, error } with error one of missing_goal, goal_too_long, no_goal, already_done, invalid_action.`,
59
+ inputSchema: {
60
+ type: "object",
61
+ properties: {
62
+ action: {
63
+ type: "string",
64
+ enum: ["set", "get", "complete", "clear"],
65
+ description: "The action to perform."
66
+ },
67
+ goal: {
68
+ type: "string",
69
+ description: "The goal text (required for 'set')."
70
+ }
71
+ },
72
+ required: ["action"]
73
+ },
74
+ handler: (input, ctx) => handle(input, ctx?.threadId ?? DEFAULT_SESSION),
75
+ getGoal: (threadId) => {
76
+ const goal = goals.get(threadId ?? DEFAULT_SESSION);
77
+ return goal === void 0 ? null : { ...goal };
78
+ }
79
+ };
80
+ }
81
+
82
+ exports.createGoalTool = createGoalTool;
83
+ //# sourceMappingURL=goal.cjs.map
84
+ //# sourceMappingURL=goal.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/goal.ts"],"names":[],"mappings":";;;AA+CA,IAAM,sBAAA,GAAyB,GAAA;AAC/B,IAAM,eAAA,GAAkB,aAAA;AAExB,SAAS,GAAG,IAAA,EAAuC;AACjD,EAAA,OAAO,KAAK,SAAA,CAAU,EAAE,IAAI,IAAA,EAAM,GAAG,MAAM,CAAA;AAC7C;AAEA,SAAS,KAAK,KAAA,EAAuB;AACnC,EAAA,OAAO,KAAK,SAAA,CAAU,EAAE,EAAA,EAAI,KAAA,EAAO,OAAO,CAAA;AAC5C;AAEA,SAAS,iBAAiB,OAAA,EAAoD;AAC5E,EAAA,MAAM,GAAA,GAAM,SAAS,YAAA,IAAgB,sBAAA;AACrC,EAAA,IAAI,CAAC,MAAA,CAAO,SAAA,CAAU,GAAG,CAAA,IAAK,OAAO,CAAA,EAAG;AACtC,IAAA,MAAM,IAAI,UAAA,CAAW,CAAA,6DAAA,EAAgE,GAAG,CAAA,CAAE,CAAA;AAAA,EAC5F;AACA,EAAA,OAAO,GAAA;AACT;AAQO,SAAS,eAAe,OAAA,EAA2C;AACxE,EAAA,MAAM,YAAA,GAAe,iBAAiB,OAAO,CAAA;AAC7C,EAAA,MAAM,KAAA,uBAAY,GAAA,EAAuB;AAEzC,EAAA,SAAS,SAAA,CAAU,KAAa,KAAA,EAAwC;AACtE,IAAA,MAAM,IAAA,GAAO,OAAO,KAAA,CAAM,IAAA,KAAS,WAAW,KAAA,CAAM,IAAA,CAAK,MAAK,GAAI,EAAA;AAClE,IAAA,IAAI,IAAA,KAAS,EAAA,EAAI,OAAO,IAAA,CAAK,cAAc,CAAA;AAC3C,IAAA,IAAI,IAAA,CAAK,MAAA,GAAS,YAAA,EAAc,OAAO,KAAK,eAAe,CAAA;AAC3D,IAAA,MAAM,QAAA,GAAW,KAAA,CAAM,GAAA,CAAI,GAAG,CAAA;AAC9B,IAAA,MAAM,IAAA,GAAkB,EAAE,IAAA,EAAM,MAAA,EAAQ,UAAU,KAAA,EAAO,IAAA,CAAK,KAAI,EAAE;AACpE,IAAA,KAAA,CAAM,GAAA,CAAI,KAAK,IAAI,CAAA;AACnB,IAAA,IAAI,QAAA,KAAa,QAAW,OAAO,EAAA,CAAG,EAAE,IAAA,EAAM,QAAA,EAAU,OAAO,CAAA;AAC/D,IAAA,OAAO,EAAA,CAAG,EAAE,IAAA,EAAM,QAAA,EAAU,MAAM,QAAA,EAAU,QAAA,CAAS,MAAM,CAAA;AAAA,EAC7D;AAEA,EAAA,SAAS,eAAe,GAAA,EAAqB;AAC3C,IAAA,MAAM,IAAA,GAAO,KAAA,CAAM,GAAA,CAAI,GAAG,CAAA;AAC1B,IAAA,IAAI,IAAA,KAAS,MAAA,EAAW,OAAO,IAAA,CAAK,SAAS,CAAA;AAC7C,IAAA,IAAI,IAAA,CAAK,MAAA,KAAW,MAAA,EAAQ,OAAO,KAAK,cAAc,CAAA;AACtD,IAAA,IAAA,CAAK,MAAA,GAAS,MAAA;AACd,IAAA,IAAA,CAAK,WAAA,GAAc,KAAK,GAAA,EAAI;AAC5B,IAAA,OAAO,EAAA,CAAG,EAAE,IAAA,EAAM,CAAA;AAAA,EACpB;AAEA,EAAA,SAAS,MAAA,CAAO,OAAgB,GAAA,EAAqB;AACnD,IAAA,MAAM,SAAU,OAAO,KAAA,KAAU,YAAY,KAAA,KAAU,IAAA,GAAO,QAAQ,EAAC;AAIvE,IAAA,QAAQ,OAAO,MAAA;AAAQ,MACrB,KAAK,KAAA;AACH,QAAA,OAAO,SAAA,CAAU,KAAK,MAAM,CAAA;AAAA,MAC9B,KAAK,KAAA;AACH,QAAA,OAAO,EAAA,CAAG,EAAE,IAAA,EAAM,KAAA,CAAM,IAAI,GAAG,CAAA,IAAK,MAAM,CAAA;AAAA,MAC5C,KAAK,UAAA;AACH,QAAA,OAAO,eAAe,GAAG,CAAA;AAAA,MAC3B,KAAK,OAAA;AACH,QAAA,KAAA,CAAM,OAAO,GAAG,CAAA;AAChB,QAAA,OAAO,EAAA,CAAG,EAAE,IAAA,EAAM,IAAA,EAAM,CAAA;AAAA,MAC1B;AACE,QAAA,OAAO,KAAK,gBAAgB,CAAA;AAAA;AAChC,EACF;AAEA,EAAA,OAAO;AAAA,IACL,IAAA,EAAM,MAAA;AAAA,IACN,WAAA,EACE,wRAGG,YAAY,CAAA,iWAAA,CAAA;AAAA,IAIjB,WAAA,EAAa;AAAA,MACX,IAAA,EAAM,QAAA;AAAA,MACN,UAAA,EAAY;AAAA,QACV,MAAA,EAAQ;AAAA,UACN,IAAA,EAAM,QAAA;AAAA,UACN,IAAA,EAAM,CAAC,KAAA,EAAO,KAAA,EAAO,YAAY,OAAO,CAAA;AAAA,UACxC,WAAA,EAAa;AAAA,SACf;AAAA,QACA,IAAA,EAAM;AAAA,UACJ,IAAA,EAAM,QAAA;AAAA,UACN,WAAA,EAAa;AAAA;AACf,OACF;AAAA,MACA,QAAA,EAAU,CAAC,QAAQ;AAAA,KACrB;AAAA,IACA,OAAA,EAAS,CAAC,KAAA,EAAkB,GAAA,KAC1B,OAAO,KAAA,EAAO,GAAA,EAAK,YAAY,eAAe,CAAA;AAAA,IAChD,OAAA,EAAS,CAAC,QAAA,KAAwC;AAChD,MAAA,MAAM,IAAA,GAAO,KAAA,CAAM,GAAA,CAAI,QAAA,IAAY,eAAe,CAAA;AAClD,MAAA,OAAO,IAAA,KAAS,MAAA,GAAY,IAAA,GAAO,EAAE,GAAG,IAAA,EAAK;AAAA,IAC/C;AAAA,GACF;AACF","file":"goal.cjs","sourcesContent":["/**\n * `goal` — one standing goal per session, kept across turns.\n *\n * Actions:\n * - set(goal) → set the goal, replacing any existing one (reports `previous`)\n * - get() → read the current goal, or null\n * - complete() → mark the goal done\n * - clear() → drop the goal\n *\n * State is keyed by `ctx.threadId`, as in `todolist` (#119). Calls without a thread id share one\n * default session, so a multi-session host that forgets to thread the id merges its users' goals.\n * The goal lives in memory only and dies with the process.\n */\n\n/** A session's goal: its text, whether it is still active, and when it was set and completed. */\nexport interface GoalState {\n text: string;\n status: \"active\" | \"done\";\n setAt: number;\n completedAt?: number;\n}\n\n/** Options for {@link createGoalTool}. */\nexport interface CreateGoalToolOptions {\n /** Longest goal text accepted, after trimming. A positive integer; defaults to 2000. */\n maxGoalChars?: number;\n}\n\n/**\n * The `goal` tool object. Hand-built like `todolist`: `inputSchema` is a plain JSON Schema value\n * and `handler` is synchronous. `getGoal` is a test seam onto the state the handler mutates.\n */\nexport interface GoalTool {\n name: string;\n description: string;\n inputSchema: unknown;\n handler: (input: GoalInput, ctx?: { threadId?: string }) => string;\n /** A session's goal (defaults to the no-threadId session), or null when none is set. */\n getGoal: (threadId?: string) => GoalState | null;\n}\n\ntype GoalInput =\n | { action: \"set\"; goal: string }\n | { action: \"get\" }\n | { action: \"complete\" }\n | { action: \"clear\" };\n\nconst DEFAULT_MAX_GOAL_CHARS = 2000;\nconst DEFAULT_SESSION = \"__default__\";\n\nfunction ok(data: Record<string, unknown>): string {\n return JSON.stringify({ ok: true, ...data });\n}\n\nfunction fail(error: string): string {\n return JSON.stringify({ ok: false, error });\n}\n\nfunction readMaxGoalChars(options: CreateGoalToolOptions | undefined): number {\n const max = options?.maxGoalChars ?? DEFAULT_MAX_GOAL_CHARS;\n if (!Number.isInteger(max) || max <= 0) {\n throw new RangeError(`createGoalTool: maxGoalChars must be a positive integer, got ${max}`);\n }\n return max;\n}\n\n/**\n * Build the `goal` tool: the agent's one standing objective for a session, read back in later turns.\n *\n * Failures are typed, never thrown: `missing_goal`, `goal_too_long`, `no_goal`, `already_done` and\n * `invalid_action`. Only an invalid `maxGoalChars` throws, at construction.\n */\nexport function createGoalTool(options?: CreateGoalToolOptions): GoalTool {\n const maxGoalChars = readMaxGoalChars(options);\n const goals = new Map<string, GoalState>();\n\n function handleSet(key: string, input: Record<string, unknown>): string {\n const text = typeof input.goal === \"string\" ? input.goal.trim() : \"\";\n if (text === \"\") return fail(\"missing_goal\");\n if (text.length > maxGoalChars) return fail(\"goal_too_long\");\n const previous = goals.get(key);\n const goal: GoalState = { text, status: \"active\", setAt: Date.now() };\n goals.set(key, goal);\n if (previous === undefined) return ok({ goal, replaced: false });\n return ok({ goal, replaced: true, previous: previous.text });\n }\n\n function handleComplete(key: string): string {\n const goal = goals.get(key);\n if (goal === undefined) return fail(\"no_goal\");\n if (goal.status === \"done\") return fail(\"already_done\");\n goal.status = \"done\";\n goal.completedAt = Date.now();\n return ok({ goal });\n }\n\n function handle(input: unknown, key: string): string {\n const fields = (typeof input === \"object\" && input !== null ? input : {}) as Record<\n string,\n unknown\n >;\n switch (fields.action) {\n case \"set\":\n return handleSet(key, fields);\n case \"get\":\n return ok({ goal: goals.get(key) ?? null });\n case \"complete\":\n return handleComplete(key);\n case \"clear\":\n goals.delete(key);\n return ok({ goal: null });\n default:\n return fail(\"invalid_action\");\n }\n }\n\n return {\n name: \"goal\",\n description:\n \"Keep ONE standing goal for the current session, read back across turns. Use it when the user \" +\n \"states an objective that spans many turns, and check it with 'get' before deciding you are \" +\n \"finished; use todolist for the steps toward it. Actions: 'set' (store the goal text, at most \" +\n `${maxGoalChars} characters after trimming, replacing any existing goal and returning it as ` +\n \"previous), 'get' (current goal or null), 'complete' (mark it done), 'clear' (drop it). Returns \" +\n \"{ ok, goal } with goal = { text, status, setAt, completedAt }; failures are { ok: false, error } \" +\n \"with error one of missing_goal, goal_too_long, no_goal, already_done, invalid_action.\",\n inputSchema: {\n type: \"object\" as const,\n properties: {\n action: {\n type: \"string\",\n enum: [\"set\", \"get\", \"complete\", \"clear\"],\n description: \"The action to perform.\",\n },\n goal: {\n type: \"string\",\n description: \"The goal text (required for 'set').\",\n },\n },\n required: [\"action\"],\n },\n handler: (input: GoalInput, ctx?: { threadId?: string }): string =>\n handle(input, ctx?.threadId ?? DEFAULT_SESSION),\n getGoal: (threadId?: string): GoalState | null => {\n const goal = goals.get(threadId ?? DEFAULT_SESSION);\n return goal === undefined ? null : { ...goal };\n },\n };\n}\n"]}
@@ -0,0 +1,58 @@
1
+ /**
2
+ * `goal` — one standing goal per session, kept across turns.
3
+ *
4
+ * Actions:
5
+ * - set(goal) → set the goal, replacing any existing one (reports `previous`)
6
+ * - get() → read the current goal, or null
7
+ * - complete() → mark the goal done
8
+ * - clear() → drop the goal
9
+ *
10
+ * State is keyed by `ctx.threadId`, as in `todolist` (#119). Calls without a thread id share one
11
+ * default session, so a multi-session host that forgets to thread the id merges its users' goals.
12
+ * The goal lives in memory only and dies with the process.
13
+ */
14
+ /** A session's goal: its text, whether it is still active, and when it was set and completed. */
15
+ interface GoalState {
16
+ text: string;
17
+ status: "active" | "done";
18
+ setAt: number;
19
+ completedAt?: number;
20
+ }
21
+ /** Options for {@link createGoalTool}. */
22
+ interface CreateGoalToolOptions {
23
+ /** Longest goal text accepted, after trimming. A positive integer; defaults to 2000. */
24
+ maxGoalChars?: number;
25
+ }
26
+ /**
27
+ * The `goal` tool object. Hand-built like `todolist`: `inputSchema` is a plain JSON Schema value
28
+ * and `handler` is synchronous. `getGoal` is a test seam onto the state the handler mutates.
29
+ */
30
+ interface GoalTool {
31
+ name: string;
32
+ description: string;
33
+ inputSchema: unknown;
34
+ handler: (input: GoalInput, ctx?: {
35
+ threadId?: string;
36
+ }) => string;
37
+ /** A session's goal (defaults to the no-threadId session), or null when none is set. */
38
+ getGoal: (threadId?: string) => GoalState | null;
39
+ }
40
+ type GoalInput = {
41
+ action: "set";
42
+ goal: string;
43
+ } | {
44
+ action: "get";
45
+ } | {
46
+ action: "complete";
47
+ } | {
48
+ action: "clear";
49
+ };
50
+ /**
51
+ * Build the `goal` tool: the agent's one standing objective for a session, read back in later turns.
52
+ *
53
+ * Failures are typed, never thrown: `missing_goal`, `goal_too_long`, `no_goal`, `already_done` and
54
+ * `invalid_action`. Only an invalid `maxGoalChars` throws, at construction.
55
+ */
56
+ declare function createGoalTool(options?: CreateGoalToolOptions): GoalTool;
57
+
58
+ export { type CreateGoalToolOptions, type GoalState, type GoalTool, createGoalTool };
package/dist/goal.d.ts ADDED
@@ -0,0 +1,58 @@
1
+ /**
2
+ * `goal` — one standing goal per session, kept across turns.
3
+ *
4
+ * Actions:
5
+ * - set(goal) → set the goal, replacing any existing one (reports `previous`)
6
+ * - get() → read the current goal, or null
7
+ * - complete() → mark the goal done
8
+ * - clear() → drop the goal
9
+ *
10
+ * State is keyed by `ctx.threadId`, as in `todolist` (#119). Calls without a thread id share one
11
+ * default session, so a multi-session host that forgets to thread the id merges its users' goals.
12
+ * The goal lives in memory only and dies with the process.
13
+ */
14
+ /** A session's goal: its text, whether it is still active, and when it was set and completed. */
15
+ interface GoalState {
16
+ text: string;
17
+ status: "active" | "done";
18
+ setAt: number;
19
+ completedAt?: number;
20
+ }
21
+ /** Options for {@link createGoalTool}. */
22
+ interface CreateGoalToolOptions {
23
+ /** Longest goal text accepted, after trimming. A positive integer; defaults to 2000. */
24
+ maxGoalChars?: number;
25
+ }
26
+ /**
27
+ * The `goal` tool object. Hand-built like `todolist`: `inputSchema` is a plain JSON Schema value
28
+ * and `handler` is synchronous. `getGoal` is a test seam onto the state the handler mutates.
29
+ */
30
+ interface GoalTool {
31
+ name: string;
32
+ description: string;
33
+ inputSchema: unknown;
34
+ handler: (input: GoalInput, ctx?: {
35
+ threadId?: string;
36
+ }) => string;
37
+ /** A session's goal (defaults to the no-threadId session), or null when none is set. */
38
+ getGoal: (threadId?: string) => GoalState | null;
39
+ }
40
+ type GoalInput = {
41
+ action: "set";
42
+ goal: string;
43
+ } | {
44
+ action: "get";
45
+ } | {
46
+ action: "complete";
47
+ } | {
48
+ action: "clear";
49
+ };
50
+ /**
51
+ * Build the `goal` tool: the agent's one standing objective for a session, read back in later turns.
52
+ *
53
+ * Failures are typed, never thrown: `missing_goal`, `goal_too_long`, `no_goal`, `already_done` and
54
+ * `invalid_action`. Only an invalid `maxGoalChars` throws, at construction.
55
+ */
56
+ declare function createGoalTool(options?: CreateGoalToolOptions): GoalTool;
57
+
58
+ export { type CreateGoalToolOptions, type GoalState, type GoalTool, createGoalTool };
package/dist/goal.js ADDED
@@ -0,0 +1,82 @@
1
+ // src/goal.ts
2
+ var DEFAULT_MAX_GOAL_CHARS = 2e3;
3
+ var DEFAULT_SESSION = "__default__";
4
+ function ok(data) {
5
+ return JSON.stringify({ ok: true, ...data });
6
+ }
7
+ function fail(error) {
8
+ return JSON.stringify({ ok: false, error });
9
+ }
10
+ function readMaxGoalChars(options) {
11
+ const max = options?.maxGoalChars ?? DEFAULT_MAX_GOAL_CHARS;
12
+ if (!Number.isInteger(max) || max <= 0) {
13
+ throw new RangeError(`createGoalTool: maxGoalChars must be a positive integer, got ${max}`);
14
+ }
15
+ return max;
16
+ }
17
+ function createGoalTool(options) {
18
+ const maxGoalChars = readMaxGoalChars(options);
19
+ const goals = /* @__PURE__ */ new Map();
20
+ function handleSet(key, input) {
21
+ const text = typeof input.goal === "string" ? input.goal.trim() : "";
22
+ if (text === "") return fail("missing_goal");
23
+ if (text.length > maxGoalChars) return fail("goal_too_long");
24
+ const previous = goals.get(key);
25
+ const goal = { text, status: "active", setAt: Date.now() };
26
+ goals.set(key, goal);
27
+ if (previous === void 0) return ok({ goal, replaced: false });
28
+ return ok({ goal, replaced: true, previous: previous.text });
29
+ }
30
+ function handleComplete(key) {
31
+ const goal = goals.get(key);
32
+ if (goal === void 0) return fail("no_goal");
33
+ if (goal.status === "done") return fail("already_done");
34
+ goal.status = "done";
35
+ goal.completedAt = Date.now();
36
+ return ok({ goal });
37
+ }
38
+ function handle(input, key) {
39
+ const fields = typeof input === "object" && input !== null ? input : {};
40
+ switch (fields.action) {
41
+ case "set":
42
+ return handleSet(key, fields);
43
+ case "get":
44
+ return ok({ goal: goals.get(key) ?? null });
45
+ case "complete":
46
+ return handleComplete(key);
47
+ case "clear":
48
+ goals.delete(key);
49
+ return ok({ goal: null });
50
+ default:
51
+ return fail("invalid_action");
52
+ }
53
+ }
54
+ return {
55
+ name: "goal",
56
+ description: `Keep ONE standing goal for the current session, read back across turns. Use it when the user states an objective that spans many turns, and check it with 'get' before deciding you are finished; use todolist for the steps toward it. Actions: 'set' (store the goal text, at most ${maxGoalChars} characters after trimming, replacing any existing goal and returning it as previous), 'get' (current goal or null), 'complete' (mark it done), 'clear' (drop it). Returns { ok, goal } with goal = { text, status, setAt, completedAt }; failures are { ok: false, error } with error one of missing_goal, goal_too_long, no_goal, already_done, invalid_action.`,
57
+ inputSchema: {
58
+ type: "object",
59
+ properties: {
60
+ action: {
61
+ type: "string",
62
+ enum: ["set", "get", "complete", "clear"],
63
+ description: "The action to perform."
64
+ },
65
+ goal: {
66
+ type: "string",
67
+ description: "The goal text (required for 'set')."
68
+ }
69
+ },
70
+ required: ["action"]
71
+ },
72
+ handler: (input, ctx) => handle(input, ctx?.threadId ?? DEFAULT_SESSION),
73
+ getGoal: (threadId) => {
74
+ const goal = goals.get(threadId ?? DEFAULT_SESSION);
75
+ return goal === void 0 ? null : { ...goal };
76
+ }
77
+ };
78
+ }
79
+
80
+ export { createGoalTool };
81
+ //# sourceMappingURL=goal.js.map
82
+ //# sourceMappingURL=goal.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/goal.ts"],"names":[],"mappings":"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","file":"goal.js","sourcesContent":["/**\n * `goal` — one standing goal per session, kept across turns.\n *\n * Actions:\n * - set(goal) → set the goal, replacing any existing one (reports `previous`)\n * - get() → read the current goal, or null\n * - complete() → mark the goal done\n * - clear() → drop the goal\n *\n * State is keyed by `ctx.threadId`, as in `todolist` (#119). Calls without a thread id share one\n * default session, so a multi-session host that forgets to thread the id merges its users' goals.\n * The goal lives in memory only and dies with the process.\n */\n\n/** A session's goal: its text, whether it is still active, and when it was set and completed. */\nexport interface GoalState {\n text: string;\n status: \"active\" | \"done\";\n setAt: number;\n completedAt?: number;\n}\n\n/** Options for {@link createGoalTool}. */\nexport interface CreateGoalToolOptions {\n /** Longest goal text accepted, after trimming. A positive integer; defaults to 2000. */\n maxGoalChars?: number;\n}\n\n/**\n * The `goal` tool object. Hand-built like `todolist`: `inputSchema` is a plain JSON Schema value\n * and `handler` is synchronous. `getGoal` is a test seam onto the state the handler mutates.\n */\nexport interface GoalTool {\n name: string;\n description: string;\n inputSchema: unknown;\n handler: (input: GoalInput, ctx?: { threadId?: string }) => string;\n /** A session's goal (defaults to the no-threadId session), or null when none is set. */\n getGoal: (threadId?: string) => GoalState | null;\n}\n\ntype GoalInput =\n | { action: \"set\"; goal: string }\n | { action: \"get\" }\n | { action: \"complete\" }\n | { action: \"clear\" };\n\nconst DEFAULT_MAX_GOAL_CHARS = 2000;\nconst DEFAULT_SESSION = \"__default__\";\n\nfunction ok(data: Record<string, unknown>): string {\n return JSON.stringify({ ok: true, ...data });\n}\n\nfunction fail(error: string): string {\n return JSON.stringify({ ok: false, error });\n}\n\nfunction readMaxGoalChars(options: CreateGoalToolOptions | undefined): number {\n const max = options?.maxGoalChars ?? DEFAULT_MAX_GOAL_CHARS;\n if (!Number.isInteger(max) || max <= 0) {\n throw new RangeError(`createGoalTool: maxGoalChars must be a positive integer, got ${max}`);\n }\n return max;\n}\n\n/**\n * Build the `goal` tool: the agent's one standing objective for a session, read back in later turns.\n *\n * Failures are typed, never thrown: `missing_goal`, `goal_too_long`, `no_goal`, `already_done` and\n * `invalid_action`. Only an invalid `maxGoalChars` throws, at construction.\n */\nexport function createGoalTool(options?: CreateGoalToolOptions): GoalTool {\n const maxGoalChars = readMaxGoalChars(options);\n const goals = new Map<string, GoalState>();\n\n function handleSet(key: string, input: Record<string, unknown>): string {\n const text = typeof input.goal === \"string\" ? input.goal.trim() : \"\";\n if (text === \"\") return fail(\"missing_goal\");\n if (text.length > maxGoalChars) return fail(\"goal_too_long\");\n const previous = goals.get(key);\n const goal: GoalState = { text, status: \"active\", setAt: Date.now() };\n goals.set(key, goal);\n if (previous === undefined) return ok({ goal, replaced: false });\n return ok({ goal, replaced: true, previous: previous.text });\n }\n\n function handleComplete(key: string): string {\n const goal = goals.get(key);\n if (goal === undefined) return fail(\"no_goal\");\n if (goal.status === \"done\") return fail(\"already_done\");\n goal.status = \"done\";\n goal.completedAt = Date.now();\n return ok({ goal });\n }\n\n function handle(input: unknown, key: string): string {\n const fields = (typeof input === \"object\" && input !== null ? input : {}) as Record<\n string,\n unknown\n >;\n switch (fields.action) {\n case \"set\":\n return handleSet(key, fields);\n case \"get\":\n return ok({ goal: goals.get(key) ?? null });\n case \"complete\":\n return handleComplete(key);\n case \"clear\":\n goals.delete(key);\n return ok({ goal: null });\n default:\n return fail(\"invalid_action\");\n }\n }\n\n return {\n name: \"goal\",\n description:\n \"Keep ONE standing goal for the current session, read back across turns. Use it when the user \" +\n \"states an objective that spans many turns, and check it with 'get' before deciding you are \" +\n \"finished; use todolist for the steps toward it. Actions: 'set' (store the goal text, at most \" +\n `${maxGoalChars} characters after trimming, replacing any existing goal and returning it as ` +\n \"previous), 'get' (current goal or null), 'complete' (mark it done), 'clear' (drop it). Returns \" +\n \"{ ok, goal } with goal = { text, status, setAt, completedAt }; failures are { ok: false, error } \" +\n \"with error one of missing_goal, goal_too_long, no_goal, already_done, invalid_action.\",\n inputSchema: {\n type: \"object\" as const,\n properties: {\n action: {\n type: \"string\",\n enum: [\"set\", \"get\", \"complete\", \"clear\"],\n description: \"The action to perform.\",\n },\n goal: {\n type: \"string\",\n description: \"The goal text (required for 'set').\",\n },\n },\n required: [\"action\"],\n },\n handler: (input: GoalInput, ctx?: { threadId?: string }): string =>\n handle(input, ctx?.threadId ?? DEFAULT_SESSION),\n getGoal: (threadId?: string): GoalState | null => {\n const goal = goals.get(threadId ?? DEFAULT_SESSION);\n return goal === undefined ? null : { ...goal };\n },\n };\n}\n"]}
package/dist/index.d.cts CHANGED
@@ -2,6 +2,8 @@ import { CustomTool, ConfigurationError } from '@theokit/sdk';
2
2
  import { FilesystemProvider } from '@theokit/sdk/filesystem';
3
3
  import { SandboxProvider } from '@theokit/sdk/sandbox';
4
4
  import { InteractiveProvider } from '@theokit/sdk/interactive';
5
+ import { W as WebSearchCallback } from './web-search-CE82zZVl.cjs';
6
+ export { C as CreateWebSearchToolOptions, a as WebSearchResult, c as createWebSearchTool } from './web-search-CE82zZVl.cjs';
5
7
 
6
8
  /**
7
9
  * `apply_patch` — built-in tool for coding agents.
@@ -1714,64 +1716,6 @@ interface CreateWebFetchToolOptions {
1714
1716
  */
1715
1717
  declare function createWebFetchTool(opts?: CreateWebFetchToolOptions): CustomTool;
1716
1718
 
1717
- /**
1718
- * `web_search` — built-in tool for coding agents.
1719
- *
1720
- * Accepts a search callback via DIP (consumer provides the search
1721
- * provider). The tool itself is provider-agnostic.
1722
- *
1723
- * Return shape (always a JSON string):
1724
- * - `{ ok: true, results: Array<{ title, url, snippet }> }`
1725
- * - `{ ok: false, error: 'search_failed' | 'no_provider' }`
1726
- */
1727
-
1728
- interface WebSearchResult {
1729
- title: string;
1730
- url: string;
1731
- snippet: string;
1732
- }
1733
- /**
1734
- * The search provider {@link createWebSearchTool} calls.
1735
- *
1736
- * `maxResults` is what the caller asked for, not a limit you must enforce — the tool slices the array
1737
- * itself — but returning far more than asked wastes the round trip that produced them.
1738
- *
1739
- * Reject the promise to signal a failed search: the tool turns a rejection into
1740
- * `{ ok: false, error: "search_failed" }` and never lets it escape into the agent turn. Resolving
1741
- * with `[]` says something different — that the search ran and found nothing.
1742
- */
1743
- type WebSearchCallback = (query: string, maxResults: number) => Promise<WebSearchResult[]>;
1744
- /**
1745
- * Options for {@link createWebSearchTool}. `search` is required: the tool ships no provider of its
1746
- * own, and the two adapters in this package — {@link createBraveWebSearchAdapter} and
1747
- * {@link createGenericHttpSearchAdapter} — exist to fill it.
1748
- */
1749
- interface CreateWebSearchToolOptions {
1750
- /** M76 — name exposed to the model. Omitted => today's literal (additive). The name is a contract:
1751
- * the approval key, what the model sees and what telemetry records. */
1752
- name?: string;
1753
- /** M76 — description exposed to the model. Omitted => today's literal (additive). */
1754
- description?: string;
1755
- /** Search provider callback — consumer injects the implementation. */
1756
- search: WebSearchCallback;
1757
- /** Default max results if not specified by the LLM. */
1758
- defaultMaxResults?: number;
1759
- }
1760
- /**
1761
- * Build the `web_search` tool over a caller-supplied provider.
1762
- *
1763
- * The tool holds no API key and talks to no service; everything network-facing lives in the `search`
1764
- * callback, which is why one tool serves Brave, a self-hosted endpoint, or a fixture in a test. Use
1765
- * it to find pages and `web_fetch` to read one — results carry a snippet, not a body.
1766
- *
1767
- * The model's `max_results` (1..20) wins over `defaultMaxResults`, and the list is sliced to it even
1768
- * when the provider returns more. A rejecting provider yields `{ ok: false, error: "search_failed" }`
1769
- * with its message attached; a provider resolving `[]` yields `{ ok: true, results: [] }`. The two
1770
- * are different signals, so an adapter that swallows its own failures — as
1771
- * {@link createGenericHttpSearchAdapter} deliberately does — reports the first as the second.
1772
- */
1773
- declare function createWebSearchTool(opts: CreateWebSearchToolOptions): CustomTool;
1774
-
1775
1719
  /**
1776
1720
  * Brave Search adapter for `createWebSearchTool` (M3-7).
1777
1721
  *
@@ -1912,4 +1856,4 @@ interface CreateWriteFileToolOptions {
1912
1856
  */
1913
1857
  declare function createWriteFileTool(opts: CreateWriteFileToolOptions): CustomTool;
1914
1858
 
1915
- export { CatastrophicCommandError, type CommandPolicy, ContextMatchError, type ContextMatchReason, type CreateApplyPatchToolOptions, type CreateBraveWebSearchAdapterOptions, type CreateCurrentTimeToolOptions, type CreateEditFileToolOptions, type CreateGenericHttpSearchAdapterOptions, type CreateGitDiffToolOptions, type CreateGitStatusToolOptions, type CreateGlobToolOptions, type CreateInteractiveShellToolOptions, type CreateListDirToolOptions, type CreateReadFileToolOptions, type CreateRunVitestToolOptions, type CreateSearchTextToolOptions, type CreateShellToolOptions, type CreateTextToSpeechToolOptions, type CreateViewImageToolOptions, type CreateWebFetchToolOptions, type CreateWebSearchToolOptions, type CreateWriteFileToolOptions, DEFAULT_MAX_AUDIO_BYTES, DEFAULT_MAX_IMAGE_BYTES, DEFAULT_MAX_TEXT_CHARS, DEFAULT_TOOL_GUIDANCE, type EnvContextOptions, type PlanModeTool, type PlanModeToolOptions, type PlanModeToolWithStore, type PlanNode, type QuestionTool, type QuestionToolOptions, ReadTracker, ReasoningTools, RedirectBlockedError, type RepoMapOptions, type ResolveAndScreenOptions, type ScreenedFetchOptions, type SessionArtifactStore, type SessionArtifactStoreOptions, SsrfBlockedError, type SynthesizedAudio, type TextToSpeechCallback, type TextToSpeechResult, type TodoItem, type TodolistTool, type ToolGuidanceMap, type TruncationMode, type TruncationOptions, type TruncationResult, type VitestSummary, type WebSearchCallback, type WebSearchResult, buildEnvContext, buildRepoMap, catastrophicShellReason, commandDenialReason, createApplyPatchTool, createBraveWebSearchAdapter, createCurrentTimeTool, createEditFileTool, createGenericHttpSearchAdapter, createGitDiffTool, createGitStatusTool, createGlobTool, createInteractiveShellTool, createListDirTool, createPlanModeTool, createQuestionTool, createReadFileTool, createRunVitestTool, createSearchTextTool, createSessionArtifactStore, createShellTool, createTextToSpeechTool, createTodolistTool, createUpdatePlanTool, createViewImageTool, createWebFetchTool, createWebSearchTool, createWriteFileTool, createWriteStdinTool, denyCatastrophicCommands, formatCode, formatDiff, formatError, formatFileList, injectGuidance, isBlockedIp, isCommandAllowed, renderToolList, replaceUnique, resolveAndScreen, screenedFetch, todoItemsToPlanNodes, truncateOutput, withDefaultGuidance, withDescription, withName, withShellExitGuidance, withToolResultGuidance };
1859
+ export { CatastrophicCommandError, type CommandPolicy, ContextMatchError, type ContextMatchReason, type CreateApplyPatchToolOptions, type CreateBraveWebSearchAdapterOptions, type CreateCurrentTimeToolOptions, type CreateEditFileToolOptions, type CreateGenericHttpSearchAdapterOptions, type CreateGitDiffToolOptions, type CreateGitStatusToolOptions, type CreateGlobToolOptions, type CreateInteractiveShellToolOptions, type CreateListDirToolOptions, type CreateReadFileToolOptions, type CreateRunVitestToolOptions, type CreateSearchTextToolOptions, type CreateShellToolOptions, type CreateTextToSpeechToolOptions, type CreateViewImageToolOptions, type CreateWebFetchToolOptions, type CreateWriteFileToolOptions, DEFAULT_MAX_AUDIO_BYTES, DEFAULT_MAX_IMAGE_BYTES, DEFAULT_MAX_TEXT_CHARS, DEFAULT_TOOL_GUIDANCE, type EnvContextOptions, type PlanModeTool, type PlanModeToolOptions, type PlanModeToolWithStore, type PlanNode, type QuestionTool, type QuestionToolOptions, ReadTracker, ReasoningTools, RedirectBlockedError, type RepoMapOptions, type ResolveAndScreenOptions, type ScreenedFetchOptions, type SessionArtifactStore, type SessionArtifactStoreOptions, SsrfBlockedError, type SynthesizedAudio, type TextToSpeechCallback, type TextToSpeechResult, type TodoItem, type TodolistTool, type ToolGuidanceMap, type TruncationMode, type TruncationOptions, type TruncationResult, type VitestSummary, WebSearchCallback, buildEnvContext, buildRepoMap, catastrophicShellReason, commandDenialReason, createApplyPatchTool, createBraveWebSearchAdapter, createCurrentTimeTool, createEditFileTool, createGenericHttpSearchAdapter, createGitDiffTool, createGitStatusTool, createGlobTool, createInteractiveShellTool, createListDirTool, createPlanModeTool, createQuestionTool, createReadFileTool, createRunVitestTool, createSearchTextTool, createSessionArtifactStore, createShellTool, createTextToSpeechTool, createTodolistTool, createUpdatePlanTool, createViewImageTool, createWebFetchTool, createWriteFileTool, createWriteStdinTool, denyCatastrophicCommands, formatCode, formatDiff, formatError, formatFileList, injectGuidance, isBlockedIp, isCommandAllowed, renderToolList, replaceUnique, resolveAndScreen, screenedFetch, todoItemsToPlanNodes, truncateOutput, withDefaultGuidance, withDescription, withName, withShellExitGuidance, withToolResultGuidance };
package/dist/index.d.ts CHANGED
@@ -2,6 +2,8 @@ import { CustomTool, ConfigurationError } from '@theokit/sdk';
2
2
  import { FilesystemProvider } from '@theokit/sdk/filesystem';
3
3
  import { SandboxProvider } from '@theokit/sdk/sandbox';
4
4
  import { InteractiveProvider } from '@theokit/sdk/interactive';
5
+ import { W as WebSearchCallback } from './web-search-CE82zZVl.js';
6
+ export { C as CreateWebSearchToolOptions, a as WebSearchResult, c as createWebSearchTool } from './web-search-CE82zZVl.js';
5
7
 
6
8
  /**
7
9
  * `apply_patch` — built-in tool for coding agents.
@@ -1714,64 +1716,6 @@ interface CreateWebFetchToolOptions {
1714
1716
  */
1715
1717
  declare function createWebFetchTool(opts?: CreateWebFetchToolOptions): CustomTool;
1716
1718
 
1717
- /**
1718
- * `web_search` — built-in tool for coding agents.
1719
- *
1720
- * Accepts a search callback via DIP (consumer provides the search
1721
- * provider). The tool itself is provider-agnostic.
1722
- *
1723
- * Return shape (always a JSON string):
1724
- * - `{ ok: true, results: Array<{ title, url, snippet }> }`
1725
- * - `{ ok: false, error: 'search_failed' | 'no_provider' }`
1726
- */
1727
-
1728
- interface WebSearchResult {
1729
- title: string;
1730
- url: string;
1731
- snippet: string;
1732
- }
1733
- /**
1734
- * The search provider {@link createWebSearchTool} calls.
1735
- *
1736
- * `maxResults` is what the caller asked for, not a limit you must enforce — the tool slices the array
1737
- * itself — but returning far more than asked wastes the round trip that produced them.
1738
- *
1739
- * Reject the promise to signal a failed search: the tool turns a rejection into
1740
- * `{ ok: false, error: "search_failed" }` and never lets it escape into the agent turn. Resolving
1741
- * with `[]` says something different — that the search ran and found nothing.
1742
- */
1743
- type WebSearchCallback = (query: string, maxResults: number) => Promise<WebSearchResult[]>;
1744
- /**
1745
- * Options for {@link createWebSearchTool}. `search` is required: the tool ships no provider of its
1746
- * own, and the two adapters in this package — {@link createBraveWebSearchAdapter} and
1747
- * {@link createGenericHttpSearchAdapter} — exist to fill it.
1748
- */
1749
- interface CreateWebSearchToolOptions {
1750
- /** M76 — name exposed to the model. Omitted => today's literal (additive). The name is a contract:
1751
- * the approval key, what the model sees and what telemetry records. */
1752
- name?: string;
1753
- /** M76 — description exposed to the model. Omitted => today's literal (additive). */
1754
- description?: string;
1755
- /** Search provider callback — consumer injects the implementation. */
1756
- search: WebSearchCallback;
1757
- /** Default max results if not specified by the LLM. */
1758
- defaultMaxResults?: number;
1759
- }
1760
- /**
1761
- * Build the `web_search` tool over a caller-supplied provider.
1762
- *
1763
- * The tool holds no API key and talks to no service; everything network-facing lives in the `search`
1764
- * callback, which is why one tool serves Brave, a self-hosted endpoint, or a fixture in a test. Use
1765
- * it to find pages and `web_fetch` to read one — results carry a snippet, not a body.
1766
- *
1767
- * The model's `max_results` (1..20) wins over `defaultMaxResults`, and the list is sliced to it even
1768
- * when the provider returns more. A rejecting provider yields `{ ok: false, error: "search_failed" }`
1769
- * with its message attached; a provider resolving `[]` yields `{ ok: true, results: [] }`. The two
1770
- * are different signals, so an adapter that swallows its own failures — as
1771
- * {@link createGenericHttpSearchAdapter} deliberately does — reports the first as the second.
1772
- */
1773
- declare function createWebSearchTool(opts: CreateWebSearchToolOptions): CustomTool;
1774
-
1775
1719
  /**
1776
1720
  * Brave Search adapter for `createWebSearchTool` (M3-7).
1777
1721
  *
@@ -1912,4 +1856,4 @@ interface CreateWriteFileToolOptions {
1912
1856
  */
1913
1857
  declare function createWriteFileTool(opts: CreateWriteFileToolOptions): CustomTool;
1914
1858
 
1915
- export { CatastrophicCommandError, type CommandPolicy, ContextMatchError, type ContextMatchReason, type CreateApplyPatchToolOptions, type CreateBraveWebSearchAdapterOptions, type CreateCurrentTimeToolOptions, type CreateEditFileToolOptions, type CreateGenericHttpSearchAdapterOptions, type CreateGitDiffToolOptions, type CreateGitStatusToolOptions, type CreateGlobToolOptions, type CreateInteractiveShellToolOptions, type CreateListDirToolOptions, type CreateReadFileToolOptions, type CreateRunVitestToolOptions, type CreateSearchTextToolOptions, type CreateShellToolOptions, type CreateTextToSpeechToolOptions, type CreateViewImageToolOptions, type CreateWebFetchToolOptions, type CreateWebSearchToolOptions, type CreateWriteFileToolOptions, DEFAULT_MAX_AUDIO_BYTES, DEFAULT_MAX_IMAGE_BYTES, DEFAULT_MAX_TEXT_CHARS, DEFAULT_TOOL_GUIDANCE, type EnvContextOptions, type PlanModeTool, type PlanModeToolOptions, type PlanModeToolWithStore, type PlanNode, type QuestionTool, type QuestionToolOptions, ReadTracker, ReasoningTools, RedirectBlockedError, type RepoMapOptions, type ResolveAndScreenOptions, type ScreenedFetchOptions, type SessionArtifactStore, type SessionArtifactStoreOptions, SsrfBlockedError, type SynthesizedAudio, type TextToSpeechCallback, type TextToSpeechResult, type TodoItem, type TodolistTool, type ToolGuidanceMap, type TruncationMode, type TruncationOptions, type TruncationResult, type VitestSummary, type WebSearchCallback, type WebSearchResult, buildEnvContext, buildRepoMap, catastrophicShellReason, commandDenialReason, createApplyPatchTool, createBraveWebSearchAdapter, createCurrentTimeTool, createEditFileTool, createGenericHttpSearchAdapter, createGitDiffTool, createGitStatusTool, createGlobTool, createInteractiveShellTool, createListDirTool, createPlanModeTool, createQuestionTool, createReadFileTool, createRunVitestTool, createSearchTextTool, createSessionArtifactStore, createShellTool, createTextToSpeechTool, createTodolistTool, createUpdatePlanTool, createViewImageTool, createWebFetchTool, createWebSearchTool, createWriteFileTool, createWriteStdinTool, denyCatastrophicCommands, formatCode, formatDiff, formatError, formatFileList, injectGuidance, isBlockedIp, isCommandAllowed, renderToolList, replaceUnique, resolveAndScreen, screenedFetch, todoItemsToPlanNodes, truncateOutput, withDefaultGuidance, withDescription, withName, withShellExitGuidance, withToolResultGuidance };
1859
+ export { CatastrophicCommandError, type CommandPolicy, ContextMatchError, type ContextMatchReason, type CreateApplyPatchToolOptions, type CreateBraveWebSearchAdapterOptions, type CreateCurrentTimeToolOptions, type CreateEditFileToolOptions, type CreateGenericHttpSearchAdapterOptions, type CreateGitDiffToolOptions, type CreateGitStatusToolOptions, type CreateGlobToolOptions, type CreateInteractiveShellToolOptions, type CreateListDirToolOptions, type CreateReadFileToolOptions, type CreateRunVitestToolOptions, type CreateSearchTextToolOptions, type CreateShellToolOptions, type CreateTextToSpeechToolOptions, type CreateViewImageToolOptions, type CreateWebFetchToolOptions, type CreateWriteFileToolOptions, DEFAULT_MAX_AUDIO_BYTES, DEFAULT_MAX_IMAGE_BYTES, DEFAULT_MAX_TEXT_CHARS, DEFAULT_TOOL_GUIDANCE, type EnvContextOptions, type PlanModeTool, type PlanModeToolOptions, type PlanModeToolWithStore, type PlanNode, type QuestionTool, type QuestionToolOptions, ReadTracker, ReasoningTools, RedirectBlockedError, type RepoMapOptions, type ResolveAndScreenOptions, type ScreenedFetchOptions, type SessionArtifactStore, type SessionArtifactStoreOptions, SsrfBlockedError, type SynthesizedAudio, type TextToSpeechCallback, type TextToSpeechResult, type TodoItem, type TodolistTool, type ToolGuidanceMap, type TruncationMode, type TruncationOptions, type TruncationResult, type VitestSummary, WebSearchCallback, buildEnvContext, buildRepoMap, catastrophicShellReason, commandDenialReason, createApplyPatchTool, createBraveWebSearchAdapter, createCurrentTimeTool, createEditFileTool, createGenericHttpSearchAdapter, createGitDiffTool, createGitStatusTool, createGlobTool, createInteractiveShellTool, createListDirTool, createPlanModeTool, createQuestionTool, createReadFileTool, createRunVitestTool, createSearchTextTool, createSessionArtifactStore, createShellTool, createTextToSpeechTool, createTodolistTool, createUpdatePlanTool, createViewImageTool, createWebFetchTool, createWriteFileTool, createWriteStdinTool, denyCatastrophicCommands, formatCode, formatDiff, formatError, formatFileList, injectGuidance, isBlockedIp, isCommandAllowed, renderToolList, replaceUnique, resolveAndScreen, screenedFetch, todoItemsToPlanNodes, truncateOutput, withDefaultGuidance, withDescription, withName, withShellExitGuidance, withToolResultGuidance };
@@ -0,0 +1,52 @@
1
+ 'use strict';
2
+
3
+ var sdk = require('@theokit/sdk');
4
+
5
+ // src/structured-output.ts
6
+ var DEFAULT_MAX_ISSUES = 10;
7
+ var DEFAULT_DESCRIPTION = "Return your final answer as an object matching this tool's input schema. If the result reports invalid_structured_output, fix the listed issues and call again.";
8
+ function requireMaxIssues(value) {
9
+ if (!Number.isInteger(value) || value <= 0) {
10
+ throw new RangeError(
11
+ `createStructuredOutputTool: maxIssues must be a positive integer, got ${value}`
12
+ );
13
+ }
14
+ return value;
15
+ }
16
+ function validate(schema, input, maxIssues) {
17
+ const parsed = schema.safeParse(input);
18
+ if (parsed.success) return { ok: true, output: parsed.data };
19
+ const all = parsed.error.issues;
20
+ return {
21
+ ok: false,
22
+ error: "invalid_structured_output",
23
+ issue_count: all.length,
24
+ issues: all.slice(0, maxIssues).map((issue) => ({
25
+ path: issue.path.map(String).join("."),
26
+ message: issue.message
27
+ }))
28
+ };
29
+ }
30
+ function createStructuredOutputTool(opts) {
31
+ const maxIssues = requireMaxIssues(opts.maxIssues ?? DEFAULT_MAX_ISSUES);
32
+ const base = sdk.Tool.create({
33
+ name: opts.name ?? "structured_output",
34
+ description: opts.description ?? DEFAULT_DESCRIPTION,
35
+ inputSchema: opts.schema,
36
+ handler: () => ""
37
+ });
38
+ const type = base.inputSchema.type;
39
+ if (type !== "object") {
40
+ throw new TypeError(
41
+ `createStructuredOutputTool: schema must be an object schema, got type ${String(type)}`
42
+ );
43
+ }
44
+ return {
45
+ ...base,
46
+ handler: (input) => JSON.stringify(validate(opts.schema, input, maxIssues))
47
+ };
48
+ }
49
+
50
+ exports.createStructuredOutputTool = createStructuredOutputTool;
51
+ //# sourceMappingURL=structured-output.cjs.map
52
+ //# sourceMappingURL=structured-output.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/structured-output.ts"],"names":["Tool"],"mappings":";;;;;AA2BA,IAAM,kBAAA,GAAqB,EAAA;AAE3B,IAAM,mBAAA,GACJ,iKAAA;AA+BF,SAAS,iBAAiB,KAAA,EAAuB;AAC/C,EAAA,IAAI,CAAC,MAAA,CAAO,SAAA,CAAU,KAAK,CAAA,IAAK,SAAS,CAAA,EAAG;AAC1C,IAAA,MAAM,IAAI,UAAA;AAAA,MACR,yEAAyE,KAAK,CAAA;AAAA,KAChF;AAAA,EACF;AACA,EAAA,OAAO,KAAA;AACT;AAEA,SAAS,QAAA,CAAS,MAAA,EAAmB,KAAA,EAAgB,SAAA,EAA2C;AAC9F,EAAA,MAAM,MAAA,GAAS,MAAA,CAAO,SAAA,CAAU,KAAK,CAAA;AACrC,EAAA,IAAI,MAAA,CAAO,SAAS,OAAO,EAAE,IAAI,IAAA,EAAM,MAAA,EAAQ,OAAO,IAAA,EAAK;AAC3D,EAAA,MAAM,GAAA,GAAM,OAAO,KAAA,CAAM,MAAA;AACzB,EAAA,OAAO;AAAA,IACL,EAAA,EAAI,KAAA;AAAA,IACJ,KAAA,EAAO,2BAAA;AAAA,IACP,aAAa,GAAA,CAAI,MAAA;AAAA,IACjB,MAAA,EAAQ,IAAI,KAAA,CAAM,CAAA,EAAG,SAAS,CAAA,CAAE,GAAA,CAAI,CAAC,KAAA,MAAW;AAAA,MAC9C,MAAM,KAAA,CAAM,IAAA,CAAK,IAAI,MAAM,CAAA,CAAE,KAAK,GAAG,CAAA;AAAA,MACrC,SAAS,KAAA,CAAM;AAAA,KACjB,CAAE;AAAA,GACJ;AACF;AASO,SAAS,2BAA2B,IAAA,EAAqD;AAC9F,EAAA,MAAM,SAAA,GAAY,gBAAA,CAAiB,IAAA,CAAK,SAAA,IAAa,kBAAkB,CAAA;AACvE,EAAA,MAAM,IAAA,GAAOA,SAAK,MAAA,CAAO;AAAA,IACvB,IAAA,EAAM,KAAK,IAAA,IAAQ,mBAAA;AAAA,IACnB,WAAA,EAAa,KAAK,WAAA,IAAe,mBAAA;AAAA,IACjC,aAAa,IAAA,CAAK,MAAA;AAAA,IAClB,SAAS,MAAM;AAAA,GAChB,CAAA;AACD,EAAA,MAAM,IAAA,GAAQ,KAAK,WAAA,CAAmC,IAAA;AACtD,EAAA,IAAI,SAAS,QAAA,EAAU;AACrB,IAAA,MAAM,IAAI,SAAA;AAAA,MACR,CAAA,sEAAA,EAAyE,MAAA,CAAO,IAAI,CAAC,CAAA;AAAA,KACvF;AAAA,EACF;AACA,EAAA,OAAO;AAAA,IACL,GAAG,IAAA;AAAA,IACH,OAAA,EAAS,CAAC,KAAA,KAAmB,IAAA,CAAK,SAAA,CAAU,SAAS,IAAA,CAAK,MAAA,EAAQ,KAAA,EAAO,SAAS,CAAC;AAAA,GACrF;AACF","file":"structured-output.cjs","sourcesContent":["/**\n * `structured_output` — hands the host the model's object only when it validates against the\n * consumer's zod schema.\n *\n * The model sees the schema as the tool's JSON Schema and calls the tool with its answer. The\n * handler runs the full zod contract (refinements and transforms included, which the JSON Schema\n * only approximates) and never throws: a failed parse becomes a typed result the model can act on.\n *\n * Return shape (always a JSON string):\n * - `{ ok: true, output }` with `output` the parsed value, defaults and transforms applied\n * - `{ ok: false, error: \"invalid_structured_output\", issue_count, issues }` with at most\n * `maxIssues` issues, each `{ path, message }`, and `issue_count` the full count\n *\n * The tool does not end the agent turn: `CustomTool` has no terminal flag, so the host stops on\n * the first `ok: true` result.\n *\n * Limits, accepted and stated: \"never throws\" holds for synchronous schemas whose parsed value is\n * JSON-serialisable. An async refinement makes `safeParse` throw, and a transform that yields a\n * BigInt or a cycle makes the serialisation throw; both are the consumer's schema, and the error\n * surfaces as the tool error the SDK reports for any throwing handler.\n */\n\nimport type { CustomTool } from \"@theokit/sdk\";\nimport { Tool } from \"@theokit/sdk\";\nimport type { z } from \"zod\";\n\n/** Default ceiling on the issues returned to the model. A default, not a measured limit. */\nconst DEFAULT_MAX_ISSUES = 10;\n\nconst DEFAULT_DESCRIPTION =\n \"Return your final answer as an object matching this tool's input schema. \" +\n \"If the result reports invalid_structured_output, fix the listed issues and call again.\";\n\n/** Options for {@link createStructuredOutputTool}. `schema` is required and must describe an object. */\nexport interface CreateStructuredOutputToolOptions {\n /** The zod schema the model's object must satisfy. Its JSON Schema must have `type: \"object\"`. */\n schema: z.ZodType;\n /** Name exposed to the model. Omitted ⇒ `structured_output`. */\n name?: string;\n /** Description exposed to the model. Omitted ⇒ a literal telling the model to retry on issues. */\n description?: string;\n /** Most issues returned in one failure. Omitted ⇒ 10. */\n maxIssues?: number;\n}\n\n/** One validation issue: the dotted path to the field (empty for the root) and zod's message. */\nexport interface StructuredOutputIssue {\n path: string;\n message: string;\n}\n\n/** The tool's result, before it is serialised to the JSON string the handler returns. */\nexport type StructuredOutputResult =\n | { ok: true; output: unknown }\n | {\n ok: false;\n error: \"invalid_structured_output\";\n issue_count: number;\n issues: StructuredOutputIssue[];\n };\n\nfunction requireMaxIssues(value: number): number {\n if (!Number.isInteger(value) || value <= 0) {\n throw new RangeError(\n `createStructuredOutputTool: maxIssues must be a positive integer, got ${value}`,\n );\n }\n return value;\n}\n\nfunction validate(schema: z.ZodType, input: unknown, maxIssues: number): StructuredOutputResult {\n const parsed = schema.safeParse(input);\n if (parsed.success) return { ok: true, output: parsed.data };\n const all = parsed.error.issues;\n return {\n ok: false,\n error: \"invalid_structured_output\",\n issue_count: all.length,\n issues: all.slice(0, maxIssues).map((issue) => ({\n path: issue.path.map(String).join(\".\"),\n message: issue.message,\n })),\n };\n}\n\n/**\n * Build a `structured_output` tool over `schema`.\n *\n * @throws TypeError when the schema's JSON Schema is not `type: \"object\"` (provider tool inputs\n * must be objects; a top-level union, intersection or recursive `$ref` is refused too);\n * RangeError when `maxIssues` is not a positive integer.\n */\nexport function createStructuredOutputTool(opts: CreateStructuredOutputToolOptions): CustomTool {\n const maxIssues = requireMaxIssues(opts.maxIssues ?? DEFAULT_MAX_ISSUES);\n const base = Tool.create({\n name: opts.name ?? \"structured_output\",\n description: opts.description ?? DEFAULT_DESCRIPTION,\n inputSchema: opts.schema,\n handler: () => \"\",\n });\n const type = (base.inputSchema as { type?: unknown }).type;\n if (type !== \"object\") {\n throw new TypeError(\n `createStructuredOutputTool: schema must be an object schema, got type ${String(type)}`,\n );\n }\n return {\n ...base,\n handler: (input: unknown) => JSON.stringify(validate(opts.schema, input, maxIssues)),\n };\n}\n"]}