@tabbybyte/kimten 0.2.0 → 0.3.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/README.md CHANGED
@@ -99,7 +99,7 @@ cat.forget();
99
99
 
100
100
  ---
101
101
 
102
- ## 🧠 Mental Model
102
+ ## 💭 Mental Model
103
103
 
104
104
  Kimten is basically:
105
105
 
@@ -125,15 +125,15 @@ Each instance keeps short-term chat memory, so follow-up prompts naturally refer
125
125
  Create a new instance.
126
126
 
127
127
  #### Required
128
- * `brain` → AI SDK model instance
128
+ * 🧠 `brain` → AI SDK model instance
129
129
 
130
130
  #### Optional
131
131
 
132
- * `toys` → object map of toy (tool) definitions. Each entry is:
132
+ * 🎱 `toys` → object map of toy (tool) definitions. Each entry is:
133
133
  * object form: `{ inputSchema?, description?, strict?, execute }`
134
134
  default: `{}`
135
- * `personality` → system instructions / prompt for overall behavior description (default: `'You are a helpful assistant.'`)
136
- * `hops` → max agent loop steps (default: `10`) - prevents infinite zoomies 🌀
135
+ * 🕵️‍♂️ `personality` → system instructions / prompt for overall behavior description (default: `'You are a helpful assistant.'`)
136
+ * 🌀 `hops` → max agent loop steps (default: `10`) - prevents infinite zoomies
137
137
 
138
138
  #### Toy semantics
139
139
 
@@ -144,15 +144,17 @@ Create a new instance.
144
144
 
145
145
  #### Returns
146
146
 
147
- * `play(input, schema?)`
147
+ * `play(input, schema?, context?)`
148
148
 
149
149
  * runs the agent
150
150
  * uses short-term memory automatically
151
151
  * optional Zod schema for structured output
152
+ * optional plain object context injected into the current call prompt as JSON (with basic redaction/truncation guards)
153
+ * context is ephemeral per `play()` call and is not persisted in memory
152
154
 
153
155
  * `forget()`
154
156
 
155
- * clears short-term memory/context
157
+ * clears short-term memory
156
158
 
157
159
  ---
158
160
 
@@ -164,7 +166,7 @@ For the `brain` part, feel free to use any compatible provider and their models.
164
166
 
165
167
  ❗ Note that not all providers (and models) may work out the box with Kimten, particularly for structured output.
166
168
 
167
- 💡 Refer to the AI SDK docs: **[providers and models](https://ai-sdk.dev/docs/foundations/providers-and-models)**.
169
+ 💡 Refer to the AI SDK docs for details: **[providers and models](https://ai-sdk.dev/docs/foundations/providers-and-models)**.
168
170
 
169
171
  ### Add toys freely
170
172
 
package/index.d.ts CHANGED
@@ -21,8 +21,12 @@ export type KimtenConfig = {
21
21
  };
22
22
 
23
23
  export type KimtenAgent = {
24
- play(input: string): Promise<string>;
25
- play<S extends ZodTypeAny>(input: string, schema: S): Promise<ZodInfer<S>>;
24
+ play(input: string, schema?: null, context?: Record<string, unknown> | null): Promise<string>;
25
+ play<S extends ZodTypeAny>(
26
+ input: string,
27
+ schema: S,
28
+ context?: Record<string, unknown> | null
29
+ ): Promise<ZodInfer<S>>;
26
30
  forget(): void;
27
31
  };
28
32
 
package/lib/kimten.js CHANGED
@@ -3,6 +3,7 @@ import { createMemory } from './memory.js';
3
3
  import { normalizeToys } from './tools.js';
4
4
 
5
5
  const DEFAULT_PERSONALITY = 'You are a helpful assistant.';
6
+ const CONTEXT_CHAR_LIMIT = 4000;
6
7
 
7
8
  /**
8
9
  * @typedef {import('zod').ZodTypeAny} ZodSchema
@@ -59,7 +60,7 @@ const DEFAULT_PERSONALITY = 'You are a helpful assistant.';
59
60
  * Returned Kimten instance.
60
61
  *
61
62
  * @typedef {object} KimtenAgent
62
- * @property {(input: string, schema?: ZodSchema | null) => Promise<any>} play Run the agent loop.
63
+ * @property {(input: string, schema?: ZodSchema | null, context?: Record<string, unknown> | null) => Promise<any>} play Run the agent loop.
63
64
  * @property {() => void} forget Clear short-term memory.
64
65
  */
65
66
 
@@ -91,6 +92,45 @@ function validateConfig(config) {
91
92
  };
92
93
  }
93
94
 
95
+ function serializeContext(context) {
96
+ if (context === null || context === undefined) {
97
+ return '';
98
+ }
99
+
100
+ if (typeof context !== 'object' || Array.isArray(context)) {
101
+ throw new TypeError('Kimten play(input, schema, context) expects context to be a plain object when provided.');
102
+ }
103
+
104
+ const redacted = JSON.stringify(
105
+ context,
106
+ (key, value) => {
107
+ const lowered = String(key).toLowerCase();
108
+ if (
109
+ lowered.includes('password') ||
110
+ lowered.includes('token') ||
111
+ lowered.includes('secret') ||
112
+ lowered.includes('apikey') ||
113
+ lowered.includes('api_key')
114
+ ) {
115
+ return '[REDACTED]';
116
+ }
117
+
118
+ return value;
119
+ },
120
+ 2
121
+ );
122
+
123
+ if (typeof redacted !== 'string') {
124
+ return '';
125
+ }
126
+
127
+ if (redacted.length <= CONTEXT_CHAR_LIMIT) {
128
+ return redacted;
129
+ }
130
+
131
+ return `${redacted.slice(0, CONTEXT_CHAR_LIMIT)}\n...(truncated)`;
132
+ }
133
+
94
134
  /**
95
135
  * Create a tiny tool-using agent with short-term memory.
96
136
  *
@@ -143,19 +183,41 @@ export function Kimten(config) {
143
183
  *
144
184
  * @param {string} input
145
185
  * @param {ZodSchema | null} [schema]
186
+ * @param {Record<string, unknown> | null} [context]
146
187
  * @returns {Promise<any>}
147
188
  */
148
- async function play(input, schema = null) {
189
+ async function play(input, schema = null, context = null) {
149
190
  if (typeof input !== 'string') {
150
191
  throw new TypeError('Kimten play(input) expects input to be a string.');
151
192
  }
152
193
 
194
+ // Serialize provided context (redacts sensitive keys and truncates if too long).
195
+ const serializedContext = serializeContext(context);
196
+
197
+ // If we have context, embed it before the user's message so the agent sees both.
198
+ const effectiveInput = serializedContext
199
+ ? `Context (JSON):\n${serializedContext}\n\nUser message:\n${input}`
200
+ : input;
201
+
202
+ // Store the raw user message (no context) in short-term memory.
153
203
  memory.add({ role: 'user', content: input });
154
204
 
205
+ // Retrieve conversation so far from memory.
206
+ const fetchedMessages = memory.list();
207
+
208
+ // If the last message is the user message we just added, we may need to replace it with
209
+ // a version that includes the serialized context, so the agent can see that information.
210
+ // This way we keep the raw user message in memory, but provide the agent with the enriched version.
211
+ const lastMessage = fetchedMessages[fetchedMessages.length - 1];
212
+ const messages = serializedContext && lastMessage?.role === 'user'
213
+ ? [...fetchedMessages.slice(0, -1), { ...lastMessage, content: effectiveInput }]
214
+ : fetchedMessages;
215
+
216
+ // Choose a structured agent when a schema is provided, otherwise use the text agent.
155
217
  const agent = schema ? getStructuredAgent(schema) : textAgent;
156
- const result = await agent.generate({
157
- messages: memory.list(),
158
- });
218
+
219
+ // Run the agent loop with the prepared messages.
220
+ const result = await agent.generate({ messages });
159
221
 
160
222
  const assistantContent =
161
223
  schema
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tabbybyte/kimten",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },