@tabbybyte/kimten 0.1.1 → 0.1.3

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 +61 -27
  2. package/lib/tools.js +41 -7
  3. package/package.json +2 -2
package/README.md CHANGED
@@ -54,11 +54,17 @@ Perfect for:
54
54
  Feed the cat some treats:
55
55
 
56
56
  ```bash
57
- npm i kimten ai zod @ai-sdk/openai
57
+ npm i @tabbybyte/kimten ai zod @ai-sdk/openai
58
58
  ```
59
59
 
60
60
  That’s it. No ceremony. No rituals. 🍗
61
61
 
62
+ ### Requirements
63
+
64
+ - Node `>=22`
65
+ - AI SDK Core `>=6`
66
+ - Zod `>=3`
67
+
62
68
  ---
63
69
 
64
70
  ## 🚀 Usage
@@ -68,7 +74,7 @@ Summon your little helper (with or without `toys`) and let it `play`.
68
74
  ```js
69
75
  import { openai } from '@ai-sdk/openai'; // or, any other provider
70
76
  import { z } from 'zod';
71
- import Kimten from 'kimten';
77
+ import Kimten from '@tabbybyte/kimten';
72
78
 
73
79
  const cat = Kimten({
74
80
  brain: openai('gpt-4o-mini'), // or, any other available model
@@ -145,11 +151,20 @@ Create a new cat.
145
151
 
146
152
  ### Optional (extra whiskers)
147
153
 
148
- * `toys` → object map of async functions (tools the model may call), default: `{}`
154
+ * `toys` → object map of tool definitions. Each entry can be:
155
+ * async function shorthand: `async (args) => result`
156
+ * object form: `{ inputSchema?, description?, strict?, execute }`
157
+ default: `{}`
149
158
  * `personality` → system prompt / behavior description (default: `"You are a helpful assistant."`)
150
159
  * `hops` → max agent loop steps (default: `10`)
151
160
  prevents infinite zoomies 🌀
152
161
 
162
+ ### Tool semantics (important)
163
+
164
+ - Tool inputs are validated only if you provide `inputSchema` (shorthand tools accept anything).
165
+ - Tool results should be JSON-serializable; `undefined` becomes `null`.
166
+ - If a tool throws, Kimten returns `{ error, toolName }` as the tool result (it does not re-throw).
167
+
153
168
  ### Returns
154
169
 
155
170
  * `play(input, schema?)`
@@ -164,10 +179,18 @@ Create a new cat.
164
179
 
165
180
  ---
166
181
 
167
- ## 🧩 Design Philosophy
182
+ ## 🧩 Design Philosophy & Vibes
168
183
 
169
184
  Kimten intentionally avoids “big agent framework energy”.
170
185
 
186
+ It’s meant to be:
187
+
188
+ * small
189
+ * opinionated
190
+ * dependency-light
191
+ * short-term memory by design
192
+ * easy to embed anywhere
193
+
171
194
  No:
172
195
 
173
196
  * streaming APIs
@@ -177,6 +200,7 @@ No:
177
200
  * persistence/storage
178
201
  * hidden background processes
179
202
  * TypeScript runtime/build nonsense
203
+ * full fledged orchestration system
180
204
 
181
205
  If you need those… use something heavier.
182
206
 
@@ -194,7 +218,7 @@ Refer to https://ai-sdk.dev/docs/foundations/providers-and-models
194
218
 
195
219
  ### Add tools freely
196
220
 
197
- Tools are just async functions:
221
+ Tools can stay simple:
198
222
 
199
223
  ```js
200
224
  toys: {
@@ -207,6 +231,38 @@ toys: {
207
231
 
208
232
  The model decides when to use them.
209
233
 
234
+ For stronger arg validation and better tool selection, use object form:
235
+
236
+ ```js
237
+ import { z } from 'zod';
238
+
239
+ toys: {
240
+ add: {
241
+ description: 'Add two numbers.',
242
+ inputSchema: z.object({ a: z.number(), b: z.number() }),
243
+ async execute({ a, b }) {
244
+ return a + b;
245
+ },
246
+ },
247
+ }
248
+ ```
249
+
250
+ ### Small “real” example
251
+
252
+ ```js
253
+ toys: {
254
+ fetchJson: {
255
+ description: 'Fetch JSON from a URL (GET).',
256
+ inputSchema: z.object({ url: z.string().url() }),
257
+ async execute({ url }) {
258
+ const res = await fetch(url);
259
+ if (!res.ok) throw new Error(`HTTP ${res.status}`);
260
+ return res.json();
261
+ },
262
+ },
263
+ }
264
+ ```
265
+
210
266
  ### Structured output = sanity
211
267
 
212
268
  Use Zod schemas whenever possible.
@@ -223,28 +279,6 @@ Cats don’t hold grudges (or context). 🐾
223
279
 
224
280
  ---
225
281
 
226
- ## 🐾 Vibes
227
-
228
- Kimten is:
229
-
230
- * small
231
- * opinionated
232
- * dependency-light
233
- * short-memory by design
234
- * easy to embed anywhere
235
-
236
- It’s not trying to be LangChain or a full orchestration system.
237
-
238
- It’s just a cat.
239
-
240
- A helpful one.
241
-
242
- In your terminal.
243
-
244
- Typing. 🐈‍⬛
245
-
246
- ---
247
-
248
282
  ## License
249
283
 
250
284
  MIT
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.3",
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+",