@theokit/sdk 2.13.0 → 2.14.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 +12 -0
- package/dist/a2a/index.cjs +120 -1
- package/dist/a2a/index.cjs.map +1 -1
- package/dist/a2a/index.js +120 -1
- package/dist/a2a/index.js.map +1 -1
- package/dist/cron.cjs +110 -1
- package/dist/cron.cjs.map +1 -1
- package/dist/cron.js +110 -1
- package/dist/cron.js.map +1 -1
- package/dist/define-tool.d.ts +8 -0
- package/dist/eval.cjs +113 -4
- package/dist/eval.cjs.map +1 -1
- package/dist/eval.js +113 -4
- package/dist/eval.js.map +1 -1
- package/dist/index.cjs +115 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +35 -0
- package/dist/index.d.ts +35 -0
- package/dist/index.js +115 -2
- package/dist/index.js.map +1 -1
- package/dist/internal/llm/hermes-tool-extract.d.ts +1 -0
- package/dist/sanitize/coerce.d.cts +1 -0
- package/dist/sanitize/coerce.d.ts +1 -0
- package/dist/sanitize/index.cjs +119 -0
- package/dist/sanitize/index.cjs.map +1 -0
- package/dist/sanitize/index.d.cts +9 -0
- package/dist/sanitize/index.d.ts +9 -0
- package/dist/sanitize/index.js +116 -0
- package/dist/sanitize/index.js.map +1 -0
- package/dist/sanitize/sanitize-tool-input.d.cts +11 -0
- package/dist/sanitize/sanitize-tool-input.d.ts +11 -0
- package/dist/sanitize/types.d.cts +39 -0
- package/dist/sanitize/types.d.ts +39 -0
- package/package.json +13 -2
package/dist/index.d.cts
CHANGED
|
@@ -863,6 +863,34 @@ interface DefineProviderOptions {
|
|
|
863
863
|
*/
|
|
864
864
|
declare function defineProvider(profile: ProviderProfile, opts?: DefineProviderOptions): Plugin;
|
|
865
865
|
|
|
866
|
+
/**
|
|
867
|
+
* Options for {@link sanitizeToolInput}. Trim is the only default-on rung — coercion and JSON
|
|
868
|
+
* repair change a value's representation, so they are opt-in (the SDK's "values are strings; Zod
|
|
869
|
+
* coerces" boundary; see `define-tool.ts` doc-comment).
|
|
870
|
+
*
|
|
871
|
+
* @public
|
|
872
|
+
*/
|
|
873
|
+
interface SanitizeOptions {
|
|
874
|
+
/** Trim leading/trailing whitespace from string values. Default `true`. */
|
|
875
|
+
trim?: boolean;
|
|
876
|
+
/** Coerce string values to typed values (`"5"`→`5`, `"true"`→`true`, `"null"`→`null`, JSON). Default `false`. */
|
|
877
|
+
coerce?: boolean;
|
|
878
|
+
/** Repair-then-parse malformed JSON-looking string values (via `jsonrepair`). Default `false`. */
|
|
879
|
+
repairJson?: boolean;
|
|
880
|
+
/**
|
|
881
|
+
* Optional Zod schema. When it is a `z.object(...)`, coercion is schema-aware: each TOP-LEVEL
|
|
882
|
+
* field is coerced only toward a candidate its field-schema accepts (so a `z.string()` field
|
|
883
|
+
* keeps `"5"` as a string). Non-object schemas (union/record) fall back to heuristic coercion.
|
|
884
|
+
* Note: with `deep: true`, nested fields always use heuristic coercion (the schema is not
|
|
885
|
+
* descended into).
|
|
886
|
+
*/
|
|
887
|
+
schema?: ZodType;
|
|
888
|
+
/** Recurse into nested objects/arrays. Default `false` (shallow). */
|
|
889
|
+
deep?: boolean;
|
|
890
|
+
/** Max recursion depth when `deep` is set. Default `8`. */
|
|
891
|
+
maxDepth?: number;
|
|
892
|
+
}
|
|
893
|
+
|
|
866
894
|
/**
|
|
867
895
|
* Spec accepted by {@link defineTool}. `inputSchema` is a Zod schema; the
|
|
868
896
|
* `handler` argument type is inferred via `z.infer<T>` — no `as` casts.
|
|
@@ -878,6 +906,13 @@ interface DefineToolSpec<T extends ZodType> {
|
|
|
878
906
|
inputSchema: T;
|
|
879
907
|
/** Handler invoked with the parsed input. Type is inferred via `z.infer<T>`. */
|
|
880
908
|
handler: (input: z.infer<T>) => string | Promise<string>;
|
|
909
|
+
/**
|
|
910
|
+
* Sanitize the raw model-emitted args BEFORE schema validation (`@theokit/sdk/sanitize`).
|
|
911
|
+
* `true` trims whitespace; an object opts into coercion / JSON-repair. Coercion is schema-aware
|
|
912
|
+
* against this tool's `inputSchema`. Absent ⇒ args reach validation untouched. Sanitize is
|
|
913
|
+
* hygiene, not a validity bypass — a genuinely invalid arg still raises `ZodError`.
|
|
914
|
+
*/
|
|
915
|
+
sanitize?: boolean | SanitizeOptions;
|
|
881
916
|
}
|
|
882
917
|
/**
|
|
883
918
|
* Type-safe builder for {@link CustomTool}. Converts a Zod schema to JSON
|
package/dist/index.d.ts
CHANGED
|
@@ -863,6 +863,34 @@ interface DefineProviderOptions {
|
|
|
863
863
|
*/
|
|
864
864
|
declare function defineProvider(profile: ProviderProfile, opts?: DefineProviderOptions): Plugin;
|
|
865
865
|
|
|
866
|
+
/**
|
|
867
|
+
* Options for {@link sanitizeToolInput}. Trim is the only default-on rung — coercion and JSON
|
|
868
|
+
* repair change a value's representation, so they are opt-in (the SDK's "values are strings; Zod
|
|
869
|
+
* coerces" boundary; see `define-tool.ts` doc-comment).
|
|
870
|
+
*
|
|
871
|
+
* @public
|
|
872
|
+
*/
|
|
873
|
+
interface SanitizeOptions {
|
|
874
|
+
/** Trim leading/trailing whitespace from string values. Default `true`. */
|
|
875
|
+
trim?: boolean;
|
|
876
|
+
/** Coerce string values to typed values (`"5"`→`5`, `"true"`→`true`, `"null"`→`null`, JSON). Default `false`. */
|
|
877
|
+
coerce?: boolean;
|
|
878
|
+
/** Repair-then-parse malformed JSON-looking string values (via `jsonrepair`). Default `false`. */
|
|
879
|
+
repairJson?: boolean;
|
|
880
|
+
/**
|
|
881
|
+
* Optional Zod schema. When it is a `z.object(...)`, coercion is schema-aware: each TOP-LEVEL
|
|
882
|
+
* field is coerced only toward a candidate its field-schema accepts (so a `z.string()` field
|
|
883
|
+
* keeps `"5"` as a string). Non-object schemas (union/record) fall back to heuristic coercion.
|
|
884
|
+
* Note: with `deep: true`, nested fields always use heuristic coercion (the schema is not
|
|
885
|
+
* descended into).
|
|
886
|
+
*/
|
|
887
|
+
schema?: ZodType;
|
|
888
|
+
/** Recurse into nested objects/arrays. Default `false` (shallow). */
|
|
889
|
+
deep?: boolean;
|
|
890
|
+
/** Max recursion depth when `deep` is set. Default `8`. */
|
|
891
|
+
maxDepth?: number;
|
|
892
|
+
}
|
|
893
|
+
|
|
866
894
|
/**
|
|
867
895
|
* Spec accepted by {@link defineTool}. `inputSchema` is a Zod schema; the
|
|
868
896
|
* `handler` argument type is inferred via `z.infer<T>` — no `as` casts.
|
|
@@ -878,6 +906,13 @@ interface DefineToolSpec<T extends ZodType> {
|
|
|
878
906
|
inputSchema: T;
|
|
879
907
|
/** Handler invoked with the parsed input. Type is inferred via `z.infer<T>`. */
|
|
880
908
|
handler: (input: z.infer<T>) => string | Promise<string>;
|
|
909
|
+
/**
|
|
910
|
+
* Sanitize the raw model-emitted args BEFORE schema validation (`@theokit/sdk/sanitize`).
|
|
911
|
+
* `true` trims whitespace; an object opts into coercion / JSON-repair. Coercion is schema-aware
|
|
912
|
+
* against this tool's `inputSchema`. Absent ⇒ args reach validation untouched. Sanitize is
|
|
913
|
+
* hygiene, not a validity bypass — a genuinely invalid arg still raises `ZodError`.
|
|
914
|
+
*/
|
|
915
|
+
sanitize?: boolean | SanitizeOptions;
|
|
881
916
|
}
|
|
882
917
|
/**
|
|
883
918
|
* Type-safe builder for {@link CustomTool}. Converts a Zod schema to JSON
|
package/dist/index.js
CHANGED
|
@@ -13424,6 +13424,115 @@ function toOllamaTools(tools) {
|
|
|
13424
13424
|
}
|
|
13425
13425
|
}));
|
|
13426
13426
|
}
|
|
13427
|
+
var cachedJsonrepair;
|
|
13428
|
+
function loadJsonrepair() {
|
|
13429
|
+
if (cachedJsonrepair === void 0) {
|
|
13430
|
+
const req = createRequire(import.meta.url);
|
|
13431
|
+
cachedJsonrepair = req("jsonrepair").jsonrepair;
|
|
13432
|
+
}
|
|
13433
|
+
return cachedJsonrepair;
|
|
13434
|
+
}
|
|
13435
|
+
function isPlainObject(v) {
|
|
13436
|
+
return v !== null && typeof v === "object" && !Array.isArray(v);
|
|
13437
|
+
}
|
|
13438
|
+
function toFiniteNumber(raw) {
|
|
13439
|
+
if (raw === "") return void 0;
|
|
13440
|
+
const n = Number(raw);
|
|
13441
|
+
return Number.isFinite(n) && String(n) === raw ? n : void 0;
|
|
13442
|
+
}
|
|
13443
|
+
function tryJson(raw, repair) {
|
|
13444
|
+
const t = raw.trimStart();
|
|
13445
|
+
if (!(t.startsWith("{") || t.startsWith("["))) return void 0;
|
|
13446
|
+
try {
|
|
13447
|
+
return JSON.parse(repair ? loadJsonrepair()(t) : t);
|
|
13448
|
+
} catch {
|
|
13449
|
+
return void 0;
|
|
13450
|
+
}
|
|
13451
|
+
}
|
|
13452
|
+
function heuristicCoerce(raw, repairJson) {
|
|
13453
|
+
if (raw === "true") return true;
|
|
13454
|
+
if (raw === "false") return false;
|
|
13455
|
+
if (raw === "null") return null;
|
|
13456
|
+
const n = toFiniteNumber(raw);
|
|
13457
|
+
if (n !== void 0) return n;
|
|
13458
|
+
const json = tryJson(raw, false) ?? (repairJson ? tryJson(raw, true) : void 0);
|
|
13459
|
+
return json === void 0 ? raw : json;
|
|
13460
|
+
}
|
|
13461
|
+
function coerceCandidates(raw, repairJson) {
|
|
13462
|
+
const out = [];
|
|
13463
|
+
if (raw === "true") out.push(true);
|
|
13464
|
+
else if (raw === "false") out.push(false);
|
|
13465
|
+
else if (raw === "null") out.push(null);
|
|
13466
|
+
const n = toFiniteNumber(raw);
|
|
13467
|
+
if (n !== void 0) out.push(n);
|
|
13468
|
+
const json = tryJson(raw, false) ?? (repairJson ? tryJson(raw, true) : void 0);
|
|
13469
|
+
if (json !== void 0) out.push(json);
|
|
13470
|
+
out.push(raw);
|
|
13471
|
+
return out;
|
|
13472
|
+
}
|
|
13473
|
+
function objectShape(schema) {
|
|
13474
|
+
const shape = schema?.shape;
|
|
13475
|
+
return shape !== null && typeof shape === "object" ? shape : void 0;
|
|
13476
|
+
}
|
|
13477
|
+
|
|
13478
|
+
// src/sanitize/sanitize-tool-input.ts
|
|
13479
|
+
function applyTrim(key2, value, ctx) {
|
|
13480
|
+
const trimmed = value.trim();
|
|
13481
|
+
if (trimmed !== value) ctx.notes.push(`trimmed "${key2}"`);
|
|
13482
|
+
return trimmed;
|
|
13483
|
+
}
|
|
13484
|
+
function applyCoerce(key2, raw, ctx) {
|
|
13485
|
+
const field = ctx.shape?.[key2];
|
|
13486
|
+
let coerced = raw;
|
|
13487
|
+
if (field) {
|
|
13488
|
+
for (const candidate of coerceCandidates(raw, ctx.repairJson)) {
|
|
13489
|
+
if (field.safeParse(candidate).success) {
|
|
13490
|
+
coerced = candidate;
|
|
13491
|
+
break;
|
|
13492
|
+
}
|
|
13493
|
+
}
|
|
13494
|
+
} else {
|
|
13495
|
+
coerced = heuristicCoerce(raw, ctx.repairJson);
|
|
13496
|
+
}
|
|
13497
|
+
if (coerced !== raw) ctx.notes.push(`coerced "${key2}"`);
|
|
13498
|
+
return coerced;
|
|
13499
|
+
}
|
|
13500
|
+
function applyRepair(key2, value, ctx) {
|
|
13501
|
+
const repaired = tryJson(value, true);
|
|
13502
|
+
if (repaired === void 0) return value;
|
|
13503
|
+
ctx.notes.push(`repaired json "${key2}"`);
|
|
13504
|
+
return repaired;
|
|
13505
|
+
}
|
|
13506
|
+
function sanitizeString(key2, value, ctx) {
|
|
13507
|
+
let out = ctx.trim ? applyTrim(key2, value, ctx) : value;
|
|
13508
|
+
if (ctx.coerce && typeof out === "string") out = applyCoerce(key2, out, ctx);
|
|
13509
|
+
if (ctx.repairJson && !ctx.coerce && typeof out === "string") out = applyRepair(key2, out, ctx);
|
|
13510
|
+
return out;
|
|
13511
|
+
}
|
|
13512
|
+
function walk(input, ctx, depth) {
|
|
13513
|
+
const out = {};
|
|
13514
|
+
for (const [key2, value] of Object.entries(input)) {
|
|
13515
|
+
if (typeof value === "string") out[key2] = sanitizeString(key2, value, ctx);
|
|
13516
|
+
else if (ctx.deep && depth < ctx.maxDepth && isPlainObject(value))
|
|
13517
|
+
out[key2] = walk(value, ctx, depth + 1);
|
|
13518
|
+
else out[key2] = value;
|
|
13519
|
+
}
|
|
13520
|
+
return out;
|
|
13521
|
+
}
|
|
13522
|
+
function sanitizeToolInput(input, options) {
|
|
13523
|
+
if (!isPlainObject(input)) return { value: input, changed: false, notes: [] };
|
|
13524
|
+
const ctx = {
|
|
13525
|
+
trim: options?.trim ?? true,
|
|
13526
|
+
coerce: options?.coerce ?? false,
|
|
13527
|
+
repairJson: options?.repairJson ?? false,
|
|
13528
|
+
deep: options?.deep ?? false,
|
|
13529
|
+
maxDepth: options?.maxDepth ?? 8,
|
|
13530
|
+
shape: objectShape(options?.schema),
|
|
13531
|
+
notes: []
|
|
13532
|
+
};
|
|
13533
|
+
const value = walk(input, ctx, 0);
|
|
13534
|
+
return { value, changed: ctx.notes.length > 0, notes: ctx.notes };
|
|
13535
|
+
}
|
|
13427
13536
|
|
|
13428
13537
|
// src/internal/llm/hermes-tool-extract.ts
|
|
13429
13538
|
var HERMES_BLOCK = /<function=\s*([^>\s]+)\s*>([\s\S]*?)<\/tool_call>/g;
|
|
@@ -13451,7 +13560,7 @@ function parseHermesParams(inner) {
|
|
|
13451
13560
|
if (key2 === void 0 || value === void 0) continue;
|
|
13452
13561
|
input[key2.trim()] = value;
|
|
13453
13562
|
}
|
|
13454
|
-
return input;
|
|
13563
|
+
return sanitizeToolInput(input, { trim: true }).value;
|
|
13455
13564
|
}
|
|
13456
13565
|
|
|
13457
13566
|
// src/internal/llm/openai.ts
|
|
@@ -18172,7 +18281,11 @@ function defineTool(spec) {
|
|
|
18172
18281
|
description: spec.description,
|
|
18173
18282
|
inputSchema,
|
|
18174
18283
|
handler: async (input) => {
|
|
18175
|
-
const
|
|
18284
|
+
const raw = spec.sanitize ? sanitizeToolInput(input, {
|
|
18285
|
+
...spec.sanitize === true ? {} : spec.sanitize,
|
|
18286
|
+
schema: spec.inputSchema
|
|
18287
|
+
}).value : input;
|
|
18288
|
+
const parsed = spec.inputSchema.parse(raw);
|
|
18176
18289
|
return await spec.handler(parsed);
|
|
18177
18290
|
}
|
|
18178
18291
|
};
|