@tabbybyte/kimten 0.1.1 → 0.1.2

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.
Files changed (3) hide show
  1. package/README.md +21 -2
  2. package/lib/tools.js +41 -7
  3. package/package.json +2 -2
package/README.md CHANGED
@@ -145,7 +145,10 @@ Create a new cat.
145
145
 
146
146
  ### Optional (extra whiskers)
147
147
 
148
- * `toys` → object map of async functions (tools the model may call), default: `{}`
148
+ * `toys` → object map of tool definitions. Each entry can be:
149
+ * async function shorthand: `async (args) => result`
150
+ * object form: `{ inputSchema?, description?, strict?, execute }`
151
+ default: `{}`
149
152
  * `personality` → system prompt / behavior description (default: `"You are a helpful assistant."`)
150
153
  * `hops` → max agent loop steps (default: `10`)
151
154
  prevents infinite zoomies 🌀
@@ -194,7 +197,7 @@ Refer to https://ai-sdk.dev/docs/foundations/providers-and-models
194
197
 
195
198
  ### Add tools freely
196
199
 
197
- Tools are just async functions:
200
+ Tools can stay simple:
198
201
 
199
202
  ```js
200
203
  toys: {
@@ -207,6 +210,22 @@ toys: {
207
210
 
208
211
  The model decides when to use them.
209
212
 
213
+ For stronger arg validation and better tool selection, use object form:
214
+
215
+ ```js
216
+ import { z } from 'zod';
217
+
218
+ toys: {
219
+ add: {
220
+ description: 'Add two numbers.',
221
+ inputSchema: z.object({ a: z.number(), b: z.number() }),
222
+ async execute({ a, b }) {
223
+ return a + b;
224
+ },
225
+ },
226
+ }
227
+ ```
228
+
210
229
  ### Structured output = sanity
211
230
 
212
231
  Use Zod schemas whenever possible.
package/lib/tools.js CHANGED
@@ -16,21 +16,21 @@ export function normalizeToys(toys) {
16
16
  }
17
17
 
18
18
  if (!isPlainObject(toys)) {
19
- throw new TypeError('Kimten config "toys" must be an object map of functions.');
19
+ throw new TypeError('Kimten config "toys" must be an object map of functions or tool definitions.');
20
20
  }
21
21
 
22
22
  const wrapped = {};
23
23
 
24
- for (const [name, fn] of Object.entries(toys)) {
25
- if (typeof fn !== 'function') {
26
- throw new TypeError(`Kimten tool "${name}" must be a function.`);
27
- }
24
+ for (const [name, entry] of Object.entries(toys)) {
25
+ const definition = normalizeToyDefinition(name, entry);
28
26
 
29
27
  wrapped[name] = tool({
30
- inputSchema: z.any(),
28
+ inputSchema: definition.inputSchema,
29
+ ...(definition.description ? { description: definition.description } : {}),
30
+ ...(definition.strict !== undefined ? { strict: definition.strict } : {}),
31
31
  async execute(args) {
32
32
  try {
33
- const result = await fn(args);
33
+ const result = await definition.execute(args);
34
34
  return toJsonSafe(result);
35
35
  } catch (error) {
36
36
  return {
@@ -45,6 +45,40 @@ export function normalizeToys(toys) {
45
45
  return wrapped;
46
46
  }
47
47
 
48
+ function normalizeToyDefinition(name, entry) {
49
+ if (typeof entry === 'function') {
50
+ return {
51
+ inputSchema: z.any(),
52
+ execute: entry,
53
+ };
54
+ }
55
+
56
+ if (!isPlainObject(entry)) {
57
+ throw new TypeError(
58
+ `Kimten tool "${name}" must be a function or an object with execute(args).`
59
+ );
60
+ }
61
+
62
+ if (typeof entry.execute !== 'function') {
63
+ throw new TypeError(`Kimten tool "${name}" object form must include execute(args).`);
64
+ }
65
+
66
+ if (entry.description !== undefined && typeof entry.description !== 'string') {
67
+ throw new TypeError(`Kimten tool "${name}" description must be a string when provided.`);
68
+ }
69
+
70
+ if (entry.strict !== undefined && typeof entry.strict !== 'boolean') {
71
+ throw new TypeError(`Kimten tool "${name}" strict must be a boolean when provided.`);
72
+ }
73
+
74
+ return {
75
+ inputSchema: entry.inputSchema ?? z.any(),
76
+ execute: entry.execute,
77
+ description: entry.description,
78
+ strict: entry.strict,
79
+ };
80
+ }
81
+
48
82
  function toJsonSafe(value) {
49
83
  if (value === undefined) {
50
84
  return null;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@tabbybyte/kimten",
3
- "version": "0.1.1",
4
- "publishConfig": {
3
+ "version": "0.1.2",
4
+ "publishConfig": {
5
5
  "access": "public"
6
6
  },
7
7
  "description": "A micro-agent library: thin wrapper over the Agent interface from Vercel's AI SDK Core v6+",