@devxiyang/agent-kernel 0.0.2 → 0.0.4

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 devxiyang
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,60 +1,45 @@
1
1
  # agent-kernel
2
2
 
3
- `agent-kernel` is a TypeScript library that provides a provider-agnostic agent runtime:
4
- - a persistent/in-memory conversation kernel
5
- - an event-driven agent loop with tool execution and parameter validation
6
- - a reusable async event stream primitive
7
-
8
- ## Core Concepts
9
-
10
- - `Agent`: stateful runtime that orchestrates model calls, tool execution, and event emission.
11
- - `Kernel`: conversation state store (in-memory or persisted), with branching and compaction support.
12
- - `StreamFn`: provider adapter contract you implement it once for any LLM backend.
13
- - `AgentTool`: executable unit with a TypeBox schema for parameter validation and provider schema generation.
14
-
15
- ## Project Structure
16
-
17
- ```text
18
- src/
19
- core/
20
- agent/
21
- kernel/
22
- event-stream.ts
23
- index.ts
24
- ```
25
-
26
- ## Feature Map
27
-
28
- - Provider-agnostic runtime via `StreamFn`
29
- - Real-time events (`text_delta`, `tool_call`, `tool_result`, `step_done`, etc.)
30
- - Tool execution loop with automatic parameter validation (TypeBox + `Value.Parse`)
31
- - Validation errors returned as `tool_result` so the LLM can self-correct
32
- - Persistent sessions via `createAgent({ session: { dir, sessionId } })`
33
- - Conversation compaction via `kernel.compact(fromId, toId, summaryText)`
34
- - Strong TypeScript types — `execute` input is inferred from the TypeBox schema
35
- - **Parallel tool execution** — run all tool calls in a single turn concurrently
36
- - **Tool timeout** — per-call deadline; timed-out tools return an error result automatically
37
- - **Auto-compaction hook** — `onContextFull` fires when the context window is full
38
- - **Stream error retry** — automatic retry with fixed delay for transient LLM errors
39
- - **Session metadata** — attach a `title` (or any custom field) to a session; read it back from `listSessions`
3
+ [![npm version](https://img.shields.io/npm/v/@devxiyang/agent-kernel)](https://www.npmjs.com/package/@devxiyang/agent-kernel)
4
+ [![npm downloads](https://img.shields.io/npm/dm/@devxiyang/agent-kernel)](https://www.npmjs.com/package/@devxiyang/agent-kernel)
5
+ [![license](https://img.shields.io/npm/l/@devxiyang/agent-kernel)](./LICENSE)
6
+ [![TypeScript](https://img.shields.io/badge/TypeScript-5.x-blue)](https://www.typescriptlang.org/)
7
+
8
+ A provider-agnostic agent runtime for TypeScript. Bring your own LLM — `agent-kernel` handles the loop, tool execution, event streaming, and conversation persistence.
9
+
10
+ ## Features
11
+
12
+ - **Provider-agnostic** — implement one `StreamFn` adapter for any LLM backend (OpenAI, Anthropic, Vercel AI SDK, etc.)
13
+ - **Real-time event stream** `text_delta`, `tool_call`, `tool_result`, `step_done`, and more
14
+ - **Typed tool execution** — TypeBox schemas drive runtime validation, coercion, and LLM schema generation
15
+ - **Parallel tool execution** — run all tool calls in a turn concurrently
16
+ - **Tool timeout** — per-call deadline; timed-out tools return an error result the LLM can handle
17
+ - **Persistent sessions** — optional file-backed conversation history, survives restarts
18
+ - **Conversation compaction** — replace old entries with a summary to stay within context limits
19
+ - **Auto-compaction hook** — `onContextFull` fires when the token budget is reached
20
+ - **Steering & follow-up** — inject messages mid-run without re-prompting
21
+ - **Stream error retry** — automatic retry with configurable delay for transient LLM errors
22
+ - **Session metadata** — attach titles and custom fields to sessions; query with `listSessions`
23
+ - **Kernel cache** — LRU + TTL in-memory cache for session kernels
40
24
 
41
25
  ## Install
42
26
 
43
27
  ```bash
44
28
  npm install @devxiyang/agent-kernel
45
- npm install @sinclair/typebox
46
- npm install openai # if using OpenAI SDK adapter
47
- npm install ai @ai-sdk/openai # if using Vercel AI SDK adapter
48
29
  ```
49
30
 
50
- ## Module Index
31
+ `@sinclair/typebox` is a required peer dependency for tool parameter schemas:
51
32
 
52
- - `@devxiyang/agent-kernel` — root export (agent APIs + `EventStream`)
53
- - `@devxiyang/agent-kernel/agent` — direct agent module
54
- - `@devxiyang/agent-kernel/kernel` — kernel module (`createKernel`, kernel types)
55
- - `@devxiyang/agent-kernel/event-stream` — `EventStream`
33
+ ```bash
34
+ npm install @sinclair/typebox
35
+ ```
56
36
 
57
- ---
37
+ Optional — install the LLM SDK of your choice:
38
+
39
+ ```bash
40
+ npm install openai # OpenAI SDK
41
+ npm install ai @ai-sdk/openai # Vercel AI SDK
42
+ ```
58
43
 
59
44
  ## Quick Start
60
45
 
@@ -62,7 +47,7 @@ npm install ai @ai-sdk/openai # if using Vercel AI SDK adapter
62
47
  import { Type } from '@sinclair/typebox'
63
48
  import { createAgent, type StreamFn, type AgentTool } from '@devxiyang/agent-kernel'
64
49
 
65
- // Minimal echo stream (replace with a real provider adapter)
50
+ // 1. Implement StreamFn for your LLM provider (see adapter examples below)
66
51
  const stream: StreamFn = async (messages, _tools, onEvent) => {
67
52
  const last = messages.filter((m) => m.role === 'user').at(-1)
68
53
  const reply = `Echo: ${typeof last?.content === 'string' ? last.content : '[multi-part]'}`
@@ -74,34 +59,357 @@ const stream: StreamFn = async (messages, _tools, onEvent) => {
74
59
  }
75
60
  }
76
61
 
77
- const getTimeSchema = Type.Object({})
78
-
62
+ // 2. Define tools
79
63
  const tools: AgentTool[] = [
80
64
  {
81
65
  name: 'get_time',
82
66
  description: 'Returns the current UTC time as an ISO string.',
83
- parameters: getTimeSchema,
67
+ parameters: Type.Object({}),
84
68
  execute: async () => ({ content: new Date().toISOString(), isError: false }),
85
69
  },
86
70
  ]
87
71
 
72
+ // 3. Create agent and subscribe to events
88
73
  const agent = createAgent({ stream, tools, maxSteps: 8 })
89
74
 
90
75
  agent.subscribe((event) => {
91
76
  if (event.type === 'text_delta') process.stdout.write(event.delta)
92
77
  })
93
78
 
79
+ // 4. Send a message and wait for completion
94
80
  agent.prompt({ type: 'user', payload: { parts: [{ type: 'text', text: 'What time is it?' }] } })
95
81
  await agent.waitForIdle()
96
82
  ```
97
83
 
84
+ ## Module Index
85
+
86
+ | Import path | Contents |
87
+ |---|---|
88
+ | `@devxiyang/agent-kernel` | `Agent`, `createAgent`, `runLoop`, `wrapTool`, `EventStream`, all types |
89
+ | `@devxiyang/agent-kernel/agent` | Agent module only |
90
+ | `@devxiyang/agent-kernel/kernel` | `createKernel`, `KernelCache`, `listSessions`, `deleteSession`, `updateSessionMeta`, kernel types |
91
+ | `@devxiyang/agent-kernel/event-stream` | `EventStream` |
92
+
93
+ ## Core Concepts
94
+
95
+ | Concept | Description |
96
+ |---|---|
97
+ | `Agent` | Stateful runtime — orchestrates the model loop, tool execution, and event emission |
98
+ | `Kernel` | Conversation store (in-memory or file-backed) with branching and compaction |
99
+ | `KernelCache` | LRU + TTL cache for reusing kernel instances across requests |
100
+ | `StreamFn` | Provider adapter — one function that calls your LLM and emits stream events |
101
+ | `AgentTool` | Executable unit with a TypeBox schema for validation and provider schema generation |
102
+ | `EventStream` | Async-iterable push stream primitive used internally by the loop |
103
+
104
+ ---
105
+
106
+ ## Agent API
107
+
108
+ ### Sending messages
109
+
110
+ ```ts
111
+ // Start a new run (throws if agent is already running)
112
+ agent.prompt(entry)
113
+
114
+ // Send a message — the agent decides whether to start a new run or queue it
115
+ // Safe to call whether the agent is idle or running
116
+ agent.followUp(entry)
117
+ ```
118
+
119
+ Use `followUp` when you don't want to manage the agent's running state yourself. It starts a new run when idle and queues the message for the next run otherwise. `prompt` is a lower-level method that gives you explicit control: it throws if the agent is already running, forcing you to decide between `followUp` and `steer`.
120
+
121
+ ### Steering (mid-run interruption)
122
+
123
+ `steer` injects a message that the loop picks up *between tool calls* in the current run. Unlike `followUp`, it interrupts the current turn rather than waiting for the run to finish.
124
+
125
+ ```ts
126
+ // Safe to call while the agent is running
127
+ agent.steer({ type: 'user', payload: { parts: [{ type: 'text', text: 'Actually, focus only on security.' }] } })
128
+ ```
129
+
130
+ When a steering message arrives, the loop skips any remaining tool calls in the current batch (writing `"Skipped: user interrupted."` results to keep the conversation consistent) and immediately processes the steering message.
131
+
132
+ **`steer` vs `followUp`**
133
+
134
+ | | `followUp` | `steer` |
135
+ |---|---|---|
136
+ | When processed | After the current run ends | Between tool calls in the current run |
137
+ | Effect | Continues the outer loop | Interrupts the current tool batch |
138
+ | Use case | Next user turn | Real-time redirection mid-task |
139
+
140
+ ### Waiting for completion
141
+
142
+ ```ts
143
+ await agent.waitForIdle()
144
+ ```
145
+
146
+ Resolves when the agent is truly idle — no running loop and no queued follow-up messages. Useful in request-response contexts (e.g., IPC handlers) where the caller needs to wait for all events to be dispatched before returning.
147
+
148
+ ```ts
149
+ // IPC handler pattern
150
+ async function handleMessage(entry: AgentEntry) {
151
+ agent.followUp(entry)
152
+ await agent.waitForIdle()
153
+ // all events have been dispatched to subscribers
154
+ }
155
+ ```
156
+
157
+ If a subscriber calls `followUp` inside an `agent_end` handler, `waitForIdle` will continue waiting for that follow-up run to finish as well.
158
+
159
+ ### Recovery
160
+
161
+ ```ts
162
+ // Resume after an error or abort, or drain queued follow-up/steering messages
163
+ // Throws if already running or nothing to continue from
164
+ agent.continue()
165
+ ```
166
+
167
+ ### Aborting and resetting
168
+
169
+ ```ts
170
+ agent.abort() // cancel the current run (no-op if idle)
171
+ agent.reset() // clear all queues and transient state (throws if running)
172
+ ```
173
+
174
+ ### Subscribing to events
175
+
176
+ ```ts
177
+ const unsubscribe = agent.subscribe((event) => {
178
+ switch (event.type) {
179
+ case 'agent_start': /* run began */ break
180
+ case 'turn_start': /* LLM call starting */ break
181
+ case 'text_delta': /* streaming text chunk */ break
182
+ case 'reasoning_delta': /* streaming reasoning chunk */ break
183
+ case 'tool_call': /* tool invocation */ break
184
+ case 'tool_update': /* partial tool progress */ break
185
+ case 'tool_result': /* tool finished */ break
186
+ case 'message_end': /* assistant message committed */ break
187
+ case 'step_done': /* step usage stats */ break
188
+ case 'turn_end': /* turn finished with tool results */ break
189
+ case 'agent_end': /* run finished (check event.error) */ break
190
+ }
191
+ })
192
+
193
+ // Stop receiving events
194
+ unsubscribe()
195
+ ```
196
+
197
+ ### Inspecting state
198
+
199
+ ```ts
200
+ const { isRunning, streamEntry, pendingToolCalls, error } = agent.state
201
+
202
+ // Access the underlying kernel
203
+ const entries = agent.kernel.read()
204
+ ```
205
+
206
+ ---
207
+
208
+ ## Kernel
209
+
210
+ The `Kernel` is the conversation store. It holds the full message history as an in-memory linked tree and optionally persists it to `kernel.jsonl`.
211
+
212
+ ### Creating a kernel
213
+
214
+ ```ts
215
+ import { createKernel } from '@devxiyang/agent-kernel/kernel'
216
+
217
+ // In-memory only (useful for testing)
218
+ const kernel = createKernel()
219
+
220
+ // File-backed — loads from disk if session exists
221
+ const kernel = createKernel({
222
+ dir: './.agent-sessions',
223
+ sessionId: 'my-session',
224
+ meta: { title: 'Code review assistant' },
225
+ })
226
+ ```
227
+
228
+ ### Reading conversation history
229
+
230
+ ```ts
231
+ // All entries on the current branch (root → leaf)
232
+ const entries = kernel.read()
233
+
234
+ // Most recent entry (or null if empty)
235
+ const last = kernel.peek()
236
+
237
+ // Build provider-agnostic messages for passing to StreamFn
238
+ const messages = kernel.buildMessages()
239
+ ```
240
+
241
+ ### Appending entries
242
+
243
+ ```ts
244
+ kernel.append({ type: 'user', payload: { parts: [{ type: 'text', text: 'Hello' }] } })
245
+ ```
246
+
247
+ The `Agent` calls `append` automatically during the loop. Call it directly only when working with a bare kernel outside of an agent.
248
+
249
+ ### Context budget
250
+
251
+ ```ts
252
+ // Set a token limit; onContextFull fires when contextSize >= limit
253
+ kernel.budget.set(80_000)
254
+
255
+ console.log(kernel.contextSize) // input tokens from the last assistant entry
256
+ console.log(kernel.budget.limit) // current limit
257
+ console.log(kernel.budget.used) // same as contextSize
258
+ ```
259
+
260
+ ### Compaction
261
+
262
+ Replace a range of entries with a summary to reduce context size:
263
+
264
+ ```ts
265
+ const entries = kernel.read()
266
+ // Compact the first half of the conversation
267
+ kernel.compact(
268
+ entries[0].id,
269
+ entries[Math.floor(entries.length / 2)].id,
270
+ 'Summary: discussed project setup and requirements.',
271
+ )
272
+ ```
273
+
274
+ Compaction rewrites `kernel.jsonl` to the clean current branch and appends a divider to `log.jsonl`.
275
+
276
+ ### Branching
277
+
278
+ ```ts
279
+ // Rewind the conversation to a past entry (discards entries after toId in memory)
280
+ kernel.branch(toId)
281
+ ```
282
+
283
+ ### Session files
284
+
285
+ Each session writes three files to `<dir>/<sessionId>/`:
286
+
287
+ | File | Contents |
288
+ |---|---|
289
+ | `kernel.jsonl` | Current branch only; rewritten on compaction |
290
+ | `log.jsonl` | Append-only full history; never compacted; used for UI display |
291
+ | `meta.json` | Session metadata (`createdAt`, `title`, custom fields) |
292
+
293
+ ---
294
+
295
+ ## KernelCache
296
+
297
+ When an agent handles multiple sessions, recreating a `Kernel` from `kernel.jsonl` on every request adds unnecessary I/O. `KernelCache` keeps hot kernels in memory with LRU eviction and TTL expiry.
298
+
299
+ ```ts
300
+ import { KernelCache } from '@devxiyang/agent-kernel/kernel'
301
+
302
+ const cache = new KernelCache({
303
+ dir: './.agent-sessions',
304
+ maxSize: 100, // keep at most 100 kernels in memory (default: 50)
305
+ ttl: 15 * 60_000, // evict after 15 min of inactivity (default: 30 min)
306
+ })
307
+ ```
308
+
309
+ ### Per-request pattern
310
+
311
+ ```ts
312
+ async function handleRequest(sessionId: string, text: string) {
313
+ // Kernel is reused across requests; Agent is lightweight, created fresh each time
314
+ const kernel = cache.get(sessionId)
315
+ const agent = new Agent(kernel, { stream, tools, maxSteps: 8 })
316
+
317
+ agent.subscribe(event => { /* forward events to client */ })
318
+
319
+ agent.followUp({ type: 'user', payload: { parts: [{ type: 'text', text }] } })
320
+ await agent.waitForIdle()
321
+ }
322
+ ```
323
+
324
+ The `Agent` is cheap to construct (no I/O, no async work) so creating one per request is fine. Only the `Kernel` — which holds the in-memory conversation tree — benefits from caching.
325
+
326
+ ### Cache API
327
+
328
+ ```ts
329
+ // Get or create a kernel for sessionId; updates LRU order and resets TTL
330
+ const kernel = cache.get(sessionId)
331
+
332
+ // Optionally pass metadata written to meta.json on first creation
333
+ const kernel = cache.get(sessionId, { title: 'My session' })
334
+
335
+ // Remove a specific session from cache (kernel.jsonl is not touched)
336
+ cache.evict(sessionId)
337
+
338
+ // Remove all cached kernels
339
+ cache.clear()
340
+
341
+ // Number of kernels currently cached
342
+ cache.size
343
+ ```
344
+
345
+ ---
346
+
347
+ ## Persistent Sessions
348
+
349
+ ```ts
350
+ import { createAgent } from '@devxiyang/agent-kernel'
351
+
352
+ const agent = createAgent({
353
+ stream, tools, maxSteps: 8,
354
+ session: {
355
+ dir: './.agent-sessions',
356
+ sessionId: 'my-session',
357
+ meta: { title: 'Code review assistant' },
358
+ },
359
+ })
360
+
361
+ agent.prompt({ type: 'user', payload: { parts: [{ type: 'text', text: 'Summarize our last discussion.' }] } })
362
+ await agent.waitForIdle()
363
+
364
+ // Manual compaction when context grows
365
+ const entries = agent.kernel.read()
366
+ if (entries.length > 12) {
367
+ agent.kernel.compact(entries[0].id, entries[8].id, 'Summary of earlier context.')
368
+ }
369
+ ```
370
+
371
+ ## Session Management
372
+
373
+ ```ts
374
+ import { listSessions, deleteSession, updateSessionMeta } from '@devxiyang/agent-kernel/kernel'
375
+
376
+ // List all sessions, sorted by most recently updated
377
+ const sessions = listSessions('./.agent-sessions')
378
+ // [
379
+ // { sessionId: 'my-session', updatedAt: 1740000000000, messageCount: 12,
380
+ // meta: { createdAt: 1739999000000, title: 'Code review assistant' } },
381
+ // ]
382
+
383
+ // Rename a session
384
+ updateSessionMeta('./.agent-sessions', 'my-session', { title: 'New title' })
385
+
386
+ // Delete a session
387
+ deleteSession('./.agent-sessions', 'my-session')
388
+ ```
389
+
390
+ All functions are safe to call on non-existent paths — `listSessions` returns `[]`, the others are silent no-ops.
391
+
392
+ ### `SessionInfo` type
393
+
394
+ ```ts
395
+ type SessionMeta = {
396
+ createdAt: number // Unix ms — set once, never overwritten
397
+ title?: string
398
+ }
399
+
400
+ type SessionInfo = {
401
+ sessionId: string
402
+ updatedAt: number // log.jsonl mtime in milliseconds
403
+ messageCount: number // entries in log.jsonl
404
+ meta: SessionMeta | null
405
+ }
406
+ ```
407
+
98
408
  ---
99
409
 
100
410
  ## Defining Tools
101
411
 
102
- Tools carry their TypeBox schema in `parameters`. The loop validates and coerces LLM-supplied
103
- arguments before calling `execute`; validation errors are returned as `tool_result` so the LLM
104
- can retry with corrected parameters.
412
+ TypeBox schemas in `parameters` drive both runtime validation and the JSON Schema passed to the LLM. The `execute` input type is inferred — no manual annotation needed.
105
413
 
106
414
  ```ts
107
415
  import { Type } from '@sinclair/typebox'
@@ -112,7 +420,6 @@ const searchSchema = Type.Object({
112
420
  limit: Type.Optional(Type.Number({ description: 'Max results (default 10)' })),
113
421
  })
114
422
 
115
- // typeof searchSchema drives the input type — no manual annotation needed
116
423
  const searchTool: AgentTool<typeof searchSchema> = {
117
424
  name: 'search_docs',
118
425
  description: 'Search project documentation by query.',
@@ -128,16 +435,12 @@ const searchTool: AgentTool<typeof searchSchema> = {
128
435
  }
129
436
  ```
130
437
 
131
- `parameters` is a standard JSON Schema at runtime (TypeBox schemas are JSON Schema), so
132
- provider adapters can pass `tool.parameters` directly to any LLM API.
438
+ Validation errors are returned as `isError: true` tool results so the LLM can self-correct.
133
439
 
134
440
  ---
135
441
 
136
442
  ## Implementing a `StreamFn`
137
443
 
138
- `StreamFn` receives the current conversation messages and the full tool list on every call.
139
- Use `tools` to generate the provider-specific schema — no hardcoding needed.
140
-
141
444
  ```ts
142
445
  type StreamFn = (
143
446
  messages: AgentMessage[],
@@ -147,30 +450,27 @@ type StreamFn = (
147
450
  ) => Promise<LLMStepResult>
148
451
  ```
149
452
 
453
+ The function receives the full conversation and tool list on every call. Use `tool.parameters` (plain JSON Schema) to generate provider-specific tool definitions.
454
+
150
455
  ---
151
456
 
152
- ## Example: OpenAI SDK Adapter
457
+ ## Adapter Examples
153
458
 
154
- Uses the OpenAI Responses API. Tools are converted from TypeBox schemas on every call.
459
+ ### OpenAI SDK
155
460
 
156
461
  ```ts
157
462
  import OpenAI from 'openai'
158
- import type { AgentMessage, StreamFn, ToolCallInfo } from '@devxiyang/agent-kernel'
463
+ import type { StreamFn, ToolCallInfo } from '@devxiyang/agent-kernel'
159
464
 
160
465
  const client = new OpenAI({ apiKey: process.env.OPENAI_API_KEY })
161
466
 
162
- function toOpenAIMessages(messages: AgentMessage[]) {
163
- return messages.map((m) => ({
164
- role: m.role as 'user' | 'assistant' | 'tool',
165
- content: typeof m.content === 'string' ? m.content : JSON.stringify(m.content),
166
- }))
167
- }
168
-
169
467
  export const openaiStream: StreamFn = async (messages, tools, onEvent, signal) => {
170
468
  const response = await client.responses.create({
171
469
  model: 'gpt-4o',
172
- input: toOpenAIMessages(messages),
173
- // TypeBox schemas are plain JSON Schema — pass them directly
470
+ input: messages.map((m) => ({
471
+ role: m.role as 'user' | 'assistant' | 'tool',
472
+ content: typeof m.content === 'string' ? m.content : JSON.stringify(m.content),
473
+ })),
174
474
  tools: tools.map((t) => ({
175
475
  type: 'function' as const,
176
476
  name: t.name,
@@ -218,70 +518,21 @@ export const openaiStream: StreamFn = async (messages, tools, onEvent, signal) =
218
518
  },
219
519
  }
220
520
  }
221
-
222
- // Usage
223
- import { Type } from '@sinclair/typebox'
224
- import { createAgent } from '@devxiyang/agent-kernel'
225
-
226
- const searchSchema = Type.Object({
227
- query: Type.String({ description: 'Search query string' }),
228
- })
229
-
230
- const agent = createAgent({
231
- stream: openaiStream,
232
- tools: [
233
- {
234
- name: 'search_docs',
235
- description: 'Search project documentation by query.',
236
- parameters: searchSchema,
237
- execute: async (_id, input) => ({
238
- content: `Results for: ${input.query}`,
239
- isError: false,
240
- }),
241
- },
242
- ],
243
- maxSteps: 10,
244
- })
245
-
246
- agent.subscribe((e) => { if (e.type === 'text_delta') process.stdout.write(e.delta) })
247
- agent.prompt({ type: 'user', payload: { parts: [{ type: 'text', text: 'Find compact API docs' }] } })
248
- await agent.waitForIdle()
249
521
  ```
250
522
 
251
- ---
252
-
253
- ## Example: Vercel AI SDK v6 Adapter
254
-
255
- Uses `streamText` from `ai`. Tools without an `execute` function are returned as tool calls
256
- for our loop to handle. `jsonSchema()` wraps TypeBox schemas as AI SDK-compatible schemas.
523
+ ### Vercel AI SDK
257
524
 
258
525
  ```ts
259
526
  import { streamText, jsonSchema, tool } from 'ai'
260
527
  import { openai } from '@ai-sdk/openai'
261
- import type { AgentMessage, StreamFn, ToolCallInfo } from '@devxiyang/agent-kernel'
262
-
263
- function toAISDKMessages(messages: AgentMessage[]) {
264
- return messages.map((m) => {
265
- if (m.role === 'tool') {
266
- // tool_result entries — AI SDK expects role 'tool'
267
- const payload = m.content as { toolCallId: string; content: string }
268
- return { role: 'tool' as const, content: [{ type: 'tool-result' as const, toolCallId: payload.toolCallId, result: payload.content }] }
269
- }
270
- return {
271
- role: m.role as 'user' | 'assistant',
272
- content: typeof m.content === 'string' ? m.content : JSON.stringify(m.content),
273
- }
274
- })
275
- }
528
+ import type { StreamFn, ToolCallInfo } from '@devxiyang/agent-kernel'
276
529
 
277
530
  export const aiSdkStream: StreamFn = async (messages, tools, onEvent, signal) => {
278
- // Build AI SDK tool definitions — no execute, our loop handles execution
279
531
  const aiTools = Object.fromEntries(
280
532
  tools.map((t) => [
281
533
  t.name,
282
534
  tool({
283
535
  description: t.description,
284
- // jsonSchema() accepts any plain JSON Schema — TypeBox schemas qualify
285
536
  inputSchema: t.parameters ? jsonSchema(t.parameters) : jsonSchema({ type: 'object', properties: {} }),
286
537
  }),
287
538
  ]),
@@ -289,9 +540,12 @@ export const aiSdkStream: StreamFn = async (messages, tools, onEvent, signal) =>
289
540
 
290
541
  const result = streamText({
291
542
  model: openai('gpt-4o'),
292
- messages: toAISDKMessages(messages),
543
+ messages: messages.map((m) => ({
544
+ role: m.role as 'user' | 'assistant',
545
+ content: typeof m.content === 'string' ? m.content : JSON.stringify(m.content),
546
+ })),
293
547
  tools: aiTools,
294
- maxSteps: 1, // one LLM call per StreamFn invocation; our kernel loops
548
+ maxSteps: 1,
295
549
  abortSignal: signal,
296
550
  })
297
551
 
@@ -326,200 +580,87 @@ export const aiSdkStream: StreamFn = async (messages, tools, onEvent, signal) =>
326
580
  },
327
581
  }
328
582
  }
329
-
330
- // Usage
331
- import { Type } from '@sinclair/typebox'
332
- import { createAgent } from '@devxiyang/agent-kernel'
333
-
334
- const searchSchema = Type.Object({
335
- query: Type.String({ description: 'Search query string' }),
336
- })
337
-
338
- const agent = createAgent({
339
- stream: aiSdkStream,
340
- tools: [
341
- {
342
- name: 'search_docs',
343
- description: 'Search project documentation by query.',
344
- parameters: searchSchema,
345
- execute: async (_id, input) => ({
346
- content: `Results for: ${input.query}`,
347
- isError: false,
348
- }),
349
- },
350
- ],
351
- maxSteps: 10,
352
- })
353
-
354
- agent.subscribe((e) => { if (e.type === 'text_delta') process.stdout.write(e.delta) })
355
- agent.prompt({ type: 'user', payload: { parts: [{ type: 'text', text: 'Find compact API docs' }] } })
356
- await agent.waitForIdle()
357
583
  ```
358
584
 
359
585
  ---
360
586
 
361
- ## Advanced Agent Options
587
+ ## Advanced Options
362
588
 
363
589
  ### Parallel Tool Execution
364
590
 
365
- By default tools run sequentially. Set `parallelTools: true` to run all tool calls in a turn concurrently with `Promise.allSettled`. If a steering message arrives after all tools complete, their results are discarded and replaced with skipped markers.
591
+ Run all tool calls in a turn concurrently. If a steering message arrives after execution, results are discarded and replaced with skipped markers.
366
592
 
367
593
  ```ts
368
- const agent = createAgent({
369
- stream, tools, maxSteps: 10,
370
- parallelTools: true,
371
- })
594
+ const agent = createAgent({ stream, tools, maxSteps: 10, parallelTools: true })
372
595
  ```
373
596
 
374
597
  ### Tool Timeout
375
598
 
376
- Set a per-tool execution deadline in milliseconds. Tools that exceed it return an `isError: true` result so the LLM can handle the failure gracefully.
599
+ Per-call deadline in milliseconds. Timed-out tools return `isError: true` so the LLM can handle the failure.
377
600
 
378
601
  ```ts
379
- const agent = createAgent({
380
- stream, tools, maxSteps: 10,
381
- toolTimeout: 15_000, // 15 s per tool call
382
- })
383
- ```
384
-
385
- ### Auto-Compaction Hook (`onContextFull`)
386
-
387
- Fires after a step when `kernel.contextSize >= kernel.budget.limit`. The callback is responsible for compacting the kernel; the loop just provides the hook.
388
-
389
- ```ts
390
- const agent = createAgent({
391
- stream, tools, maxSteps: 10,
392
- onContextFull: async (kernel) => {
393
- const entries = kernel.read()
394
- const from = entries[0].id
395
- const to = entries[Math.floor(entries.length / 2)].id
396
- kernel.compact(from, to, 'Earlier context summarised.')
397
- },
398
- })
399
-
400
- agent.kernel.budget.set(80_000) // tokens — trigger at 80 k input tokens
602
+ const agent = createAgent({ stream, tools, maxSteps: 10, toolTimeout: 15_000 })
401
603
  ```
402
604
 
403
- Only fires when `budget.limit` is explicitly set (the default is `Infinity`).
404
-
405
605
  ### Stream Error Retry
406
606
 
407
- Automatically retry transient LLM errors with a fixed delay. Abort signals are respected — no retry happens after abort.
607
+ Retry transient LLM errors with a fixed delay. Abort signals are respected — no retry after abort.
408
608
 
409
609
  ```ts
410
610
  const agent = createAgent({
411
611
  stream, tools, maxSteps: 10,
412
- retryOnError: {
413
- maxAttempts: 3, // total attempts including the first
414
- delayMs: 500,
415
- },
612
+ retryOnError: { maxAttempts: 3, delayMs: 500 },
416
613
  })
417
614
  ```
418
615
 
419
- Only `stream()` calls are retried; tool execution is not affected.
616
+ ### Auto-Compaction (`onContextFull`)
420
617
 
421
- ---
422
-
423
- ## Persistent Session + Kernel Compaction
618
+ Fires after a step when `kernel.contextSize >= kernel.budget.limit`. Set `kernel.budget` to activate.
424
619
 
425
620
  ```ts
426
- import { createAgent } from '@devxiyang/agent-kernel'
427
-
428
621
  const agent = createAgent({
429
- stream: openaiStream, // or aiSdkStream
430
- tools: [],
431
- maxSteps: 8,
432
- session: {
433
- dir: './.agent-sessions',
434
- sessionId: 'demo-session-001',
622
+ stream, tools, maxSteps: 10,
623
+ onContextFull: async (kernel) => {
624
+ const entries = kernel.read()
625
+ kernel.compact(entries[0].id, entries[Math.floor(entries.length / 2)].id, 'Earlier context summarised.')
435
626
  },
436
627
  })
437
628
 
438
- agent.prompt({ type: 'user', payload: { parts: [{ type: 'text', text: 'Summarize our last discussion.' }] } })
439
- await agent.waitForIdle()
440
-
441
- // Compact old entries when context grows
442
- const entries = agent.kernel.read()
443
- if (entries.length > 12) {
444
- const fromId = entries[0].id
445
- const toId = entries[Math.min(8, entries.length - 1)].id
446
- agent.kernel.compact(fromId, toId, 'Summary of earlier context and decisions.')
447
- }
629
+ agent.kernel.budget.set(80_000) // trigger at 80 k input tokens
448
630
  ```
449
631
 
450
- Session files are written under `./.agent-sessions/<sessionId>/` (`kernel.jsonl`, `log.jsonl`).
451
-
452
632
  ---
453
633
 
454
- ## Session Management
634
+ ## Tool Hooks (`wrapTool`)
455
635
 
456
- `listSessions`, `deleteSession`, and `updateSessionMeta` are standalone utilities for CLI and Web API use cases.
636
+ Intercept tool calls before or after execution without modifying the original tool.
457
637
 
458
638
  ```ts
459
- import {
460
- listSessions,
461
- deleteSession,
462
- updateSessionMeta,
463
- } from '@devxiyang/agent-kernel/kernel'
464
-
465
- // List all sessions, sorted by most recently updated
466
- const sessions = listSessions('./.agent-sessions')
467
- // [
468
- // { sessionId: 'demo-001', updatedAt: 1740000000000, messageCount: 12,
469
- // meta: { createdAt: 1739999000000, title: 'My first session' } },
470
- // { sessionId: 'demo-002', updatedAt: 1739000000000, messageCount: 4,
471
- // meta: { createdAt: 1738999000000 } },
472
- // ]
473
-
474
- // Delete a session
475
- deleteSession('./.agent-sessions', 'demo-001')
639
+ import { wrapTool } from '@devxiyang/agent-kernel'
476
640
 
477
- // Update a session's metadata (merge — never overwrites createdAt)
478
- updateSessionMeta('./.agent-sessions', 'demo-002', { title: 'Renamed session' })
479
- ```
480
-
481
- ### Session Metadata
482
-
483
- Pass `meta` when creating a session to set an initial title or other fields. `createdAt` is set automatically on first creation and is never overwritten.
484
-
485
- ```ts
486
- const agent = createAgent({
487
- stream, tools, maxSteps: 8,
488
- session: {
489
- dir: './.agent-sessions',
490
- sessionId: 'my-session',
491
- meta: { title: 'Code review assistant' },
641
+ const guardedTool = wrapTool(myTool, {
642
+ before: async (toolCallId, toolName, input) => {
643
+ if (!isAllowed(input)) return { action: 'block', reason: 'Not permitted.' }
644
+ },
645
+ after: async (toolCallId, toolName, result) => {
646
+ return { content: redact(result.content) }
492
647
  },
493
648
  })
494
649
  ```
495
650
 
496
- `SessionMeta` and `SessionInfo` types:
497
-
498
- ```ts
499
- type SessionMeta = {
500
- createdAt: number // Unix ms — set once at creation
501
- title?: string
502
- }
503
-
504
- type SessionInfo = {
505
- sessionId: string // directory name used as session ID
506
- updatedAt: number // log.jsonl mtime in milliseconds
507
- messageCount: number // number of entries in log.jsonl
508
- meta: SessionMeta | null
509
- }
510
- ```
511
-
512
- All functions are safe to call on non-existent paths — `listSessions` returns `[]`,
513
- `deleteSession` and `updateSessionMeta` are silent no-ops when the session does not exist.
651
+ `before` can return `{ action: 'block', reason }` to skip execution; the reason is returned as `isError: true`. `after` can override `content`, `isError`, or `details`.
514
652
 
515
653
  ---
516
654
 
517
- ## Build Output
518
-
519
- Compiled files and type declarations are generated into `dist/`.
655
+ ## Build & Test
520
656
 
521
657
  ```bash
522
- npm run build # compile TypeScript to dist/
658
+ npm run build # compile TypeScript dist/
523
659
  npm run typecheck # type-check without emitting
524
660
  npm test # run unit tests (vitest)
661
+ npm run test:watch # watch mode
525
662
  ```
663
+
664
+ ## License
665
+
666
+ [MIT](./LICENSE)
@@ -107,7 +107,7 @@ export declare class Agent {
107
107
  * Throws if called while running — abort() first.
108
108
  */
109
109
  reset(): void;
110
- /** Resolves when the agent finishes its current run (or immediately if idle). */
110
+ /** Resolves when the agent is truly idle (no running loop, no queued follow-ups). */
111
111
  waitForIdle(): Promise<void>;
112
112
  private _run;
113
113
  private _consume;
@@ -1 +1 @@
1
- {"version":3,"file":"agent.d.ts","sourceRoot":"","sources":["../../../src/core/agent/agent.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"agent.d.ts","sourceRoot":"","sources":["../../../src/core/agent/agent.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,WAAW,CAAA;AAG3D,OAAO,KAAK,EACV,UAAU,EACV,UAAU,EAEV,YAAY,EACZ,SAAS,EACT,QAAQ,EAER,SAAS,EACV,MAAM,SAAS,CAAA;AAIhB,MAAM,WAAW,UAAU;IACzB,qDAAqD;IACrD,SAAS,EAAS,OAAO,CAAA;IACzB,mEAAmE;IACnE,WAAW,EAAO,UAAU,GAAG,IAAI,CAAA;IACnC,yCAAyC;IACzC,gBAAgB,EAAE,GAAG,CAAC,MAAM,CAAC,CAAA;IAC7B,4DAA4D;IAC5D,KAAK,EAAa,MAAM,GAAG,IAAI,CAAA;CAChC;AAID;;;;;;GAMG;AACH,qBAAa,KAAK;IAChB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAa;IAErC,OAAO,CAAC,OAAO,CAAoB;IACnC,OAAO,CAAC,MAAM,CAAwB;IACtC,OAAO,CAAC,SAAS,CAAgB;IACjC,OAAO,CAAC,iBAAiB,CAAkC;IAC3D,OAAO,CAAC,UAAU,CAAkC;IACpD,OAAO,CAAC,aAAa,CAAe;IACpC,OAAO,CAAC,aAAa,CAAe;IACpC,OAAO,CAAC,cAAc,CAAkC;IACxD,OAAO,CAAC,cAAc,CAAkC;IACxD,OAAO,CAAC,YAAY,CAAkC;IACtD,OAAO,CAAC,aAAa,CAAkC;IAEvD,OAAO,CAAC,gBAAgB,CAA+B;IACvD,OAAO,CAAC,eAAe,CAAiD;IAExE,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAmB;IAClD,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAmB;IAClD,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAyC;IAGpE,OAAO,CAAC,YAAY,CAA8B;IAClD,OAAO,CAAC,WAAW,CAAW;IAC9B,OAAO,CAAC,gBAAgB,CAAO;IAC/B,OAAO,CAAC,gBAAgB,CAAqB;IAC7C,OAAO,CAAC,iBAAiB,CAAoB;IAC7C,OAAO,CAAC,MAAM,CAAgC;gBAElC,MAAM,EAAE,WAAW,EAAE,OAAO,EAAE,YAAY;IAiBtD,4EAA4E;IAC5E,IAAI,MAAM,IAAI,WAAW,CAAwB;IAEjD,yDAAyD;IACzD,IAAI,KAAK,IAAI,UAAU,CAOtB;IAID,yEAAyE;IACzE,SAAS,CAAC,MAAM,EAAE,QAAQ,GAAG,IAAI;IACjC,2DAA2D;IAC3D,QAAQ,CAAC,KAAK,EAAE,SAAS,EAAE,GAAG,IAAI;IAClC,8EAA8E;IAC9E,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI;IACnC,gEAAgE;IAChE,eAAe,CAAC,IAAI,EAAE,SAAS,GAAG,IAAI;IACtC,iEAAiE;IACjE,eAAe,CAAC,IAAI,EAAE,SAAS,GAAG,IAAI;IAItC;;;OAGG;IACH,SAAS,CAAC,EAAE,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,GAAG,MAAM,IAAI;IAOtD;;;OAGG;IACH,MAAM,CAAC,OAAO,EAAE,UAAU,GAAG,UAAU,EAAE,GAAG,IAAI;IAahD;;;;OAIG;IACH,QAAQ,IAAI,IAAI;IA0BhB;;;;OAIG;IACH,KAAK,CAAC,OAAO,EAAE,UAAU,GAAG,UAAU,EAAE,GAAG,IAAI;IAI/C;;;;OAIG;IACH,QAAQ,CAAC,OAAO,EAAE,UAAU,GAAG,UAAU,EAAE,GAAG,IAAI;IAMlD,oDAAoD;IACpD,KAAK,IAAI,IAAI;IAMb;;;;OAIG;IACH,KAAK,IAAI,IAAI;IAiBb,qFAAqF;IAC/E,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC;IAQlC,OAAO,CAAC,IAAI;YAqBE,QAAQ;IAsBtB,OAAO,CAAC,YAAY;IAmDpB,OAAO,CAAC,kBAAkB;YAWZ,cAAc;YAOd,cAAc;CAM7B;AAID,MAAM,WAAW,mBAAoB,SAAQ,YAAY;IACvD,8DAA8D;IAC9D,OAAO,CAAC,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,aAAa,CAAC,MAAM,CAAC,CAAA;KAAE,CAAA;CAC3E;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,mBAAmB,GAAG,KAAK,CAI/D"}
@@ -175,13 +175,13 @@ export class Agent {
175
175
  this._error = null;
176
176
  }
177
177
  // ── Wait ────────────────────────────────────────────────────────────────
178
- /** Resolves when the agent finishes its current run (or immediately if idle). */
178
+ /** Resolves when the agent is truly idle (no running loop, no queued follow-ups). */
179
179
  async waitForIdle() {
180
- if (this._runningPromise) {
180
+ while (this._runningPromise) {
181
181
  try {
182
182
  await this._runningPromise;
183
183
  }
184
- catch { /* caller handles errors via subscribe */ }
184
+ catch { /* errors propagate via subscribe */ }
185
185
  }
186
186
  }
187
187
  // ── Private ─────────────────────────────────────────────────────────────
@@ -219,6 +219,9 @@ export class Agent {
219
219
  finally {
220
220
  this._abortController = null;
221
221
  this._runningPromise = null;
222
+ if (this._followUpQueue.length > 0) {
223
+ this._run();
224
+ }
222
225
  }
223
226
  }
224
227
  _handleEvent(event) {
@@ -1 +1 @@
1
- {"version":3,"file":"agent.js","sourceRoot":"","sources":["../../../src/core/agent/agent.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAGH,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAA;AACxC,OAAO,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAA;AAyBhC,gFAAgF;AAEhF;;;;;;GAMG;AACH,MAAM,OAAO,KAAK;IACC,OAAO,CAAa;IAE7B,OAAO,CAAoB;IAC3B,MAAM,CAAwB;IAC9B,SAAS,CAAgB;IACzB,iBAAiB,CAAkC;IACnD,UAAU,CAAkC;IAC5C,aAAa,CAAe;IAC5B,aAAa,CAAe;IAC5B,cAAc,CAAkC;IAChD,cAAc,CAAkC;IAChD,YAAY,CAAkC;IAC9C,aAAa,CAAkC;IAE/C,gBAAgB,GAA2B,IAAI,CAAA;IAC/C,eAAe,GAA6C,IAAI,CAAA;IAEvD,cAAc,GAAiB,EAAE,CAAA;IACjC,cAAc,GAAiB,EAAE,CAAA;IACjC,UAAU,GAAG,IAAI,GAAG,EAA+B,CAAA;IAEpE,0EAA0E;IAClE,YAAY,GAA0B,IAAI,CAAA;IAC1C,WAAW,GAAS,EAAE,CAAA;IACtB,gBAAgB,GAAK,EAAE,CAAA;IACvB,gBAAgB,GAAmB,EAAE,CAAA;IACrC,iBAAiB,GAAG,IAAI,GAAG,EAAU,CAAA;IACrC,MAAM,GAA4B,IAAI,CAAA;IAE9C,YAAY,MAAmB,EAAE,OAAqB;QACpD,IAAI,CAAC,OAAO,GAAa,MAAM,CAAA;QAC/B,IAAI,CAAC,OAAO,GAAa,OAAO,CAAC,MAAM,CAAA;QACvC,IAAI,CAAC,MAAM,GAAc,OAAO,CAAC,KAAK,CAAA;QACtC,IAAI,CAAC,SAAS,GAAW,OAAO,CAAC,QAAQ,CAAA;QACzC,IAAI,CAAC,iBAAiB,GAAG,OAAO,CAAC,gBAAgB,CAAA;QACjD,IAAI,CAAC,UAAU,GAAU,OAAO,CAAC,SAAS,CAAA;QAC1C,IAAI,CAAC,aAAa,GAAO,OAAO,CAAC,YAAY,IAAI,eAAe,CAAA;QAChE,IAAI,CAAC,aAAa,GAAO,OAAO,CAAC,YAAY,IAAI,eAAe,CAAA;QAChE,IAAI,CAAC,cAAc,GAAM,OAAO,CAAC,aAAa,CAAA;QAC9C,IAAI,CAAC,cAAc,GAAM,OAAO,CAAC,aAAa,CAAA;QAC9C,IAAI,CAAC,YAAY,GAAQ,OAAO,CAAC,WAAW,CAAA;QAC5C,IAAI,CAAC,aAAa,GAAO,OAAO,CAAC,YAAY,CAAA;IAC/C,CAAC;IAED,0EAA0E;IAE1E,4EAA4E;IAC5E,IAAI,MAAM,KAAkB,OAAO,IAAI,CAAC,OAAO,CAAA,CAAC,CAAC;IAEjD,yDAAyD;IACzD,IAAI,KAAK;QACP,OAAO;YACL,SAAS,EAAS,IAAI,CAAC,gBAAgB,KAAK,IAAI;YAChD,WAAW,EAAO,IAAI,CAAC,YAAY;YACnC,gBAAgB,EAAE,IAAI,CAAC,iBAAiB;YACxC,KAAK,EAAa,IAAI,CAAC,MAAM;SAC9B,CAAA;IACH,CAAC;IAED,4EAA4E;IAE5E,yEAAyE;IACzE,SAAS,CAAC,MAAgB,IAAe,IAAI,CAAC,OAAO,GAAG,MAAM,CAAA,CAAC,CAAC;IAChE,2DAA2D;IAC3D,QAAQ,CAAC,KAAkB,IAAc,IAAI,CAAC,MAAM,GAAG,KAAK,CAAA,CAAC,CAAC;IAC9D,8EAA8E;IAC9E,WAAW,CAAC,QAAgB,IAAa,IAAI,CAAC,SAAS,GAAG,QAAQ,CAAA,CAAC,CAAC;IACpE,gEAAgE;IAChE,eAAe,CAAC,IAAe,IAAU,IAAI,CAAC,aAAa,GAAG,IAAI,CAAA,CAAC,CAAC;IACpE,iEAAiE;IACjE,eAAe,CAAC,IAAe,IAAU,IAAI,CAAC,aAAa,GAAG,IAAI,CAAA,CAAC,CAAC;IAEpE,2EAA2E;IAE3E;;;OAGG;IACH,SAAS,CAAC,EAA+B;QACvC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;QACvB,OAAO,GAAG,EAAE,GAAG,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC,CAAA,CAAC,CAAC,CAAA;IAC7C,CAAC;IAED,2EAA2E;IAE3E;;;OAGG;IACH,MAAM,CAAC,OAAkC;QACvC,IAAI,IAAI,CAAC,KAAK,CAAC,SAAS,EAAE,CAAC;YACzB,MAAM,IAAI,KAAK,CAAC,wEAAwE,CAAC,CAAA;QAC3F,CAAC;QAED,KAAK,MAAM,KAAK,IAAI,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC;YACjE,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;QAC5B,CAAC;QAED,IAAI,CAAC,MAAM,GAAG,IAAI,CAAA;QAClB,IAAI,CAAC,IAAI,EAAE,CAAA;IACb,CAAC;IAED;;;;OAIG;IACH,QAAQ;QACN,IAAI,IAAI,CAAC,KAAK,CAAC,SAAS,EAAE,CAAC;YACzB,MAAM,IAAI,KAAK,CAAC,2BAA2B,CAAC,CAAA;QAC9C,CAAC;QAED,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,CAAA;QACrC,IAAI,CAAC,SAAS,EAAE,CAAC;YACf,MAAM,IAAI,KAAK,CAAC,0DAA0D,CAAC,CAAA;QAC7E,CAAC;QAED,MAAM,SAAS,GAAG,IAAI,CAAC,cAAc,CAAC,MAAM,GAAG,CAAC,IAAI,IAAI,CAAC,cAAc,CAAC,MAAM,GAAG,CAAC,CAAA;QAElF,IAAI,SAAS,CAAC,IAAI,KAAK,WAAW,EAAE,CAAC;YACnC,MAAM,EAAE,UAAU,EAAE,GAAG,SAAS,CAAC,OAAO,CAAA;YACxC,MAAM,WAAW,GAAG,UAAU,KAAK,OAAO,IAAI,UAAU,KAAK,SAAS,CAAA;YACtE,IAAI,CAAC,WAAW,IAAI,CAAC,SAAS,EAAE,CAAC;gBAC/B,MAAM,IAAI,KAAK,CAAC,6DAA6D,CAAC,CAAA;YAChF,CAAC;QACH,CAAC;QAED,IAAI,CAAC,MAAM,GAAG,IAAI,CAAA;QAClB,IAAI,CAAC,IAAI,EAAE,CAAA;IACb,CAAC;IAED,2EAA2E;IAE3E;;;;OAIG;IACH,KAAK,CAAC,OAAkC;QACtC,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAA;IAC7E,CAAC;IAED;;;;OAIG;IACH,QAAQ,CAAC,OAAkC;QACzC,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAA;IAC7E,CAAC;IAED,2EAA2E;IAE3E,oDAAoD;IACpD,KAAK;QACH,IAAI,CAAC,gBAAgB,EAAE,KAAK,EAAE,CAAA;IAChC,CAAC;IAED,4EAA4E;IAE5E;;;;OAIG;IACH,KAAK;QACH,IAAI,IAAI,CAAC,KAAK,CAAC,SAAS,EAAE,CAAC;YACzB,MAAM,IAAI,KAAK,CAAC,iDAAiD,CAAC,CAAA;QACpE,CAAC;QAED,IAAI,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC,CAAC,CAAA;QAC7B,IAAI,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC,CAAC,CAAA;QAC7B,IAAI,CAAC,YAAY,GAAQ,IAAI,CAAA;QAC7B,IAAI,CAAC,WAAW,GAAS,EAAE,CAAA;QAC3B,IAAI,CAAC,gBAAgB,GAAK,EAAE,CAAA;QAC5B,IAAI,CAAC,gBAAgB,GAAI,EAAE,CAAA;QAC3B,IAAI,CAAC,iBAAiB,GAAG,IAAI,GAAG,EAAE,CAAA;QAClC,IAAI,CAAC,MAAM,GAAc,IAAI,CAAA;IAC/B,CAAC;IAED,2EAA2E;IAE3E,iFAAiF;IACjF,KAAK,CAAC,WAAW;QACf,IAAI,IAAI,CAAC,eAAe,EAAE,CAAC;YACzB,IAAI,CAAC;gBAAC,MAAM,IAAI,CAAC,eAAe,CAAA;YAAC,CAAC;YAAC,MAAM,CAAC,CAAC,yCAAyC,CAAC,CAAC;QACxF,CAAC;IACH,CAAC;IAED,2EAA2E;IAEnE,IAAI;QACV,IAAI,CAAC,gBAAgB,GAAG,IAAI,eAAe,EAAE,CAAA;QAE7C,MAAM,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,OAAO,EAAE;YACxC,MAAM,EAAe,IAAI,CAAC,OAAO;YACjC,KAAK,EAAgB,IAAI,CAAC,MAAM;YAChC,QAAQ,EAAa,IAAI,CAAC,SAAS;YACnC,MAAM,EAAe,IAAI,CAAC,gBAAgB,CAAC,MAAM;YACjD,gBAAgB,EAAK,IAAI,CAAC,iBAAiB;YAC3C,SAAS,EAAY,IAAI,CAAC,UAAU;YACpC,mBAAmB,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,cAAc,EAAE;YAChD,mBAAmB,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,cAAc,EAAE;YAChD,aAAa,EAAQ,IAAI,CAAC,cAAc;YACxC,aAAa,EAAQ,IAAI,CAAC,cAAc;YACxC,WAAW,EAAU,IAAI,CAAC,YAAY;YACtC,YAAY,EAAS,IAAI,CAAC,aAAa;SACxC,CAAC,CAAA;QAEF,IAAI,CAAC,eAAe,GAAG,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAA;IACnD,CAAC;IAEO,KAAK,CAAC,QAAQ,CACpB,MAAsE;QAEtE,IAAI,CAAC;YACH,IAAI,KAAK,EAAE,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;gBACjC,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC,CAAA;gBACxB,KAAK,MAAM,EAAE,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;oBACjC,EAAE,CAAC,KAAK,CAAC,CAAA;gBACX,CAAC;YACH,CAAC;YACD,OAAO,MAAM,MAAM,CAAC,MAAM,EAAE,CAAA;QAC9B,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,SAAS,CAAA;QAClB,CAAC;gBAAS,CAAC;YACT,IAAI,CAAC,gBAAgB,GAAG,IAAI,CAAA;YAC5B,IAAI,CAAC,eAAe,GAAI,IAAI,CAAA;QAC9B,CAAC;IACH,CAAC;IAEO,YAAY,CAAC,KAAiB;QACpC,QAAQ,KAAK,CAAC,IAAI,EAAE,CAAC;YACnB,KAAK,YAAY;gBACf,IAAI,CAAC,WAAW,GAAQ,EAAE,CAAA;gBAC1B,IAAI,CAAC,gBAAgB,GAAI,EAAE,CAAA;gBAC3B,IAAI,CAAC,gBAAgB,GAAG,EAAE,CAAA;gBAC1B,IAAI,CAAC,YAAY,GAAO,IAAI,CAAA;gBAC5B,MAAK;YAEP,KAAK,YAAY;gBACf,IAAI,CAAC,WAAW,IAAI,KAAK,CAAC,KAAK,CAAA;gBAC/B,IAAI,CAAC,kBAAkB,EAAE,CAAA;gBACzB,MAAK;YAEP,KAAK,iBAAiB;gBACpB,IAAI,CAAC,gBAAgB,IAAI,KAAK,CAAC,KAAK,CAAA;gBACpC,IAAI,CAAC,kBAAkB,EAAE,CAAA;gBACzB,MAAK;YAEP,KAAK,WAAW;gBACd,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC;oBACzB,UAAU,EAAE,KAAK,CAAC,UAAU;oBAC5B,QAAQ,EAAI,KAAK,CAAC,QAAQ;oBAC1B,KAAK,EAAO,KAAK,CAAC,KAAK;iBACxB,CAAC,CAAA;gBACF,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,KAAK,CAAC,UAAU,CAAC,CAAA;gBAC5C,IAAI,CAAC,kBAAkB,EAAE,CAAA;gBACzB,MAAK;YAEP,KAAK,aAAa;gBAChB,IAAI,CAAC,iBAAiB,CAAC,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,CAAA;gBAC/C,MAAK;YAEP,KAAK,aAAa;gBAChB,IAAI,CAAC,YAAY,GAAG,IAAI,CAAA;gBACxB,MAAK;YAEP,KAAK,UAAU;gBACb,IAAI,CAAC,YAAY,GAAG,IAAI,CAAA;gBACxB,MAAK;YAEP,KAAK,WAAW;gBACd,IAAI,CAAC,YAAY,GAAQ,IAAI,CAAA;gBAC7B,IAAI,CAAC,iBAAiB,GAAG,IAAI,GAAG,EAAE,CAAA;gBAClC,IAAI,KAAK,CAAC,KAAK,EAAE,CAAC;oBAChB,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC,KAAK,CAAA;gBAC3B,CAAC;gBACD,MAAK;QACT,CAAC;IACH,CAAC;IAEO,kBAAkB;QACxB,IAAI,CAAC,YAAY,GAAG;YAClB,IAAI,EAAK,WAAW;YACpB,OAAO,EAAE;gBACP,IAAI,EAAO,IAAI,CAAC,WAAW;gBAC3B,SAAS,EAAG,IAAI,CAAC,gBAAgB,IAAI,SAAS;gBAC9C,SAAS,EAAE,IAAI,CAAC,gBAAgB;aACjC;SACF,CAAA;IACH,CAAC;IAEO,KAAK,CAAC,cAAc;QAC1B,IAAI,IAAI,CAAC,cAAc,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,EAAE,CAAA;QAC/C,OAAO,IAAI,CAAC,aAAa,KAAK,eAAe;YAC3C,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC;YAClC,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC,CAAC,CAAA;IACnC,CAAC;IAEO,KAAK,CAAC,cAAc;QAC1B,IAAI,IAAI,CAAC,cAAc,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,EAAE,CAAA;QAC/C,OAAO,IAAI,CAAC,aAAa,KAAK,eAAe;YAC3C,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC;YAClC,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC,CAAC,CAAA;IACnC,CAAC;CACF;AASD;;;GAGG;AACH,MAAM,UAAU,WAAW,CAAC,OAA4B;IACtD,MAAM,EAAE,OAAO,EAAE,GAAG,YAAY,EAAE,GAAG,OAAO,CAAA;IAC5C,MAAM,MAAM,GAAG,YAAY,CAAC,OAAO,CAAC,CAAA;IACpC,OAAO,IAAI,KAAK,CAAC,MAAM,EAAE,YAAY,CAAC,CAAA;AACxC,CAAC"}
1
+ {"version":3,"file":"agent.js","sourceRoot":"","sources":["../../../src/core/agent/agent.ts"],"names":[],"mappings":"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"}
@@ -7,6 +7,8 @@
7
7
  export type { Usage, DataContent, TextPart, ImagePart, AudioPart, VideoPart, FilePart, ContentPart, ImageMediaType, AudioMediaType, VideoMediaType, FileMediaType, StopReason, ToolCallInfo, AgentEntry, AgentMessage, StoredEntry, AppendResult, CompactionEntry, TokenBudget, AgentKernel, KernelOptions, SessionMeta, } from './types';
8
8
  export { COMPACTION_TYPE } from './types';
9
9
  export { createKernel } from './kernel';
10
+ export type { KernelCacheOptions } from './kernel-cache';
11
+ export { KernelCache } from './kernel-cache';
10
12
  export type { SessionInfo } from './session-store';
11
13
  export { listSessions, deleteSession, updateSessionMeta } from './session-store';
12
14
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/core/kernel/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,YAAY,EACV,KAAK,EACL,WAAW,EACX,QAAQ,EACR,SAAS,EACT,SAAS,EACT,SAAS,EACT,QAAQ,EACR,WAAW,EACX,cAAc,EACd,cAAc,EACd,cAAc,EACd,aAAa,EACb,UAAU,EACV,YAAY,EACZ,UAAU,EACV,YAAY,EACZ,WAAW,EACX,YAAY,EACZ,eAAe,EACf,WAAW,EACX,WAAW,EACX,aAAa,EACb,WAAW,GACZ,MAAM,SAAS,CAAA;AAEhB,OAAO,EAAE,eAAe,EAAE,MAAM,SAAS,CAAA;AAEzC,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAA;AAEvC,YAAY,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAA;AAClD,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/core/kernel/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,YAAY,EACV,KAAK,EACL,WAAW,EACX,QAAQ,EACR,SAAS,EACT,SAAS,EACT,SAAS,EACT,QAAQ,EACR,WAAW,EACX,cAAc,EACd,cAAc,EACd,cAAc,EACd,aAAa,EACb,UAAU,EACV,YAAY,EACZ,UAAU,EACV,YAAY,EACZ,WAAW,EACX,YAAY,EACZ,eAAe,EACf,WAAW,EACX,WAAW,EACX,aAAa,EACb,WAAW,GACZ,MAAM,SAAS,CAAA;AAEhB,OAAO,EAAE,eAAe,EAAE,MAAM,SAAS,CAAA;AAEzC,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAA;AAEvC,YAAY,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAA;AACxD,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAA;AAE5C,YAAY,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAA;AAClD,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAA"}
@@ -6,5 +6,6 @@
6
6
  */
7
7
  export { COMPACTION_TYPE } from './types';
8
8
  export { createKernel } from './kernel';
9
+ export { KernelCache } from './kernel-cache';
9
10
  export { listSessions, deleteSession, updateSessionMeta } from './session-store';
10
11
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/core/kernel/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AA4BH,OAAO,EAAE,eAAe,EAAE,MAAM,SAAS,CAAA;AAEzC,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAA;AAGvC,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/core/kernel/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AA4BH,OAAO,EAAE,eAAe,EAAE,MAAM,SAAS,CAAA;AAEzC,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAA;AAGvC,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAA;AAG5C,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAA"}
@@ -0,0 +1,37 @@
1
+ import type { AgentKernel, KernelOptions } from './types';
2
+ export interface KernelCacheOptions {
3
+ /** Base directory for session persistence (passed to createKernel). */
4
+ dir: string;
5
+ /** Maximum number of kernels to keep in memory. LRU eviction. Default: 50 */
6
+ maxSize?: number;
7
+ /** Milliseconds of inactivity before a kernel is evicted. Default: 30 minutes */
8
+ ttl?: number;
9
+ /** Injectable time source for testing. Defaults to performance or Date. */
10
+ perf?: {
11
+ now(): number;
12
+ };
13
+ }
14
+ /**
15
+ * In-memory LRU cache of AgentKernel instances keyed by sessionId.
16
+ *
17
+ * Kernels are expensive to recreate because loadFromFile replays kernel.jsonl
18
+ * on every cold start. KernelCache keeps hot sessions in memory and evicts
19
+ * them by LRU order or TTL, falling back to file-based restore on cache miss.
20
+ */
21
+ export declare class KernelCache {
22
+ private readonly _dir;
23
+ private readonly _cache;
24
+ constructor(options: KernelCacheOptions);
25
+ /**
26
+ * Return the cached kernel for sessionId, or create one from disk.
27
+ * Updates LRU order and TTL on every call.
28
+ */
29
+ get(sessionId: string, meta?: KernelOptions['meta']): AgentKernel;
30
+ /** Remove a specific session from the cache. */
31
+ evict(sessionId: string): void;
32
+ /** Remove all cached kernels. */
33
+ clear(): void;
34
+ /** Number of kernels currently in cache. */
35
+ get size(): number;
36
+ }
37
+ //# sourceMappingURL=kernel-cache.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"kernel-cache.d.ts","sourceRoot":"","sources":["../../../src/core/kernel/kernel-cache.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,SAAS,CAAA;AAIzD,MAAM,WAAW,kBAAkB;IACjC,uEAAuE;IACvE,GAAG,EAAE,MAAM,CAAA;IACX,6EAA6E;IAC7E,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,iFAAiF;IACjF,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,2EAA2E;IAC3E,IAAI,CAAC,EAAE;QAAE,GAAG,IAAI,MAAM,CAAA;KAAE,CAAA;CACzB;AAID;;;;;;GAMG;AACH,qBAAa,WAAW;IACtB,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAU;IAC/B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA+B;gBAE1C,OAAO,EAAE,kBAAkB;IASvC;;;OAGG;IACH,GAAG,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,aAAa,CAAC,MAAM,CAAC,GAAG,WAAW;IASjE,gDAAgD;IAChD,KAAK,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;IAI9B,iCAAiC;IACjC,KAAK,IAAI,IAAI;IAIb,4CAA4C;IAC5C,IAAI,IAAI,IAAI,MAAM,CAEjB;CACF"}
@@ -0,0 +1,47 @@
1
+ import { LRUCache } from 'lru-cache';
2
+ import { createKernel } from './kernel';
3
+ // ─── KernelCache ──────────────────────────────────────────────────────────────
4
+ /**
5
+ * In-memory LRU cache of AgentKernel instances keyed by sessionId.
6
+ *
7
+ * Kernels are expensive to recreate because loadFromFile replays kernel.jsonl
8
+ * on every cold start. KernelCache keeps hot sessions in memory and evicts
9
+ * them by LRU order or TTL, falling back to file-based restore on cache miss.
10
+ */
11
+ export class KernelCache {
12
+ _dir;
13
+ _cache;
14
+ constructor(options) {
15
+ this._dir = options.dir;
16
+ this._cache = new LRUCache({
17
+ max: options.maxSize ?? 50,
18
+ ttl: options.ttl ?? 30 * 60 * 1000,
19
+ ...(options.perf && { perf: options.perf }),
20
+ });
21
+ }
22
+ /**
23
+ * Return the cached kernel for sessionId, or create one from disk.
24
+ * Updates LRU order and TTL on every call.
25
+ */
26
+ get(sessionId, meta) {
27
+ const cached = this._cache.get(sessionId);
28
+ if (cached)
29
+ return cached;
30
+ const kernel = createKernel({ dir: this._dir, sessionId, meta });
31
+ this._cache.set(sessionId, kernel);
32
+ return kernel;
33
+ }
34
+ /** Remove a specific session from the cache. */
35
+ evict(sessionId) {
36
+ this._cache.delete(sessionId);
37
+ }
38
+ /** Remove all cached kernels. */
39
+ clear() {
40
+ this._cache.clear();
41
+ }
42
+ /** Number of kernels currently in cache. */
43
+ get size() {
44
+ return this._cache.size;
45
+ }
46
+ }
47
+ //# sourceMappingURL=kernel-cache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"kernel-cache.js","sourceRoot":"","sources":["../../../src/core/kernel/kernel-cache.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAA;AACpC,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAA;AAgBvC,iFAAiF;AAEjF;;;;;;GAMG;AACH,MAAM,OAAO,WAAW;IACL,IAAI,CAAU;IACd,MAAM,CAA+B;IAEtD,YAAY,OAA2B;QACrC,IAAI,CAAC,IAAI,GAAK,OAAO,CAAC,GAAG,CAAA;QACzB,IAAI,CAAC,MAAM,GAAG,IAAI,QAAQ,CAAsB;YAC9C,GAAG,EAAG,OAAO,CAAC,OAAO,IAAI,EAAE;YAC3B,GAAG,EAAG,OAAO,CAAC,GAAG,IAAQ,EAAE,GAAG,EAAE,GAAG,IAAI;YACvC,GAAG,CAAC,OAAO,CAAC,IAAI,IAAI,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,CAAC;SAC5C,CAAC,CAAA;IACJ,CAAC;IAED;;;OAGG;IACH,GAAG,CAAC,SAAiB,EAAE,IAA4B;QACjD,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,SAAS,CAAC,CAAA;QACzC,IAAI,MAAM;YAAE,OAAO,MAAM,CAAA;QAEzB,MAAM,MAAM,GAAG,YAAY,CAAC,EAAE,GAAG,EAAE,IAAI,CAAC,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;QAChE,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,SAAS,EAAE,MAAM,CAAC,CAAA;QAClC,OAAO,MAAM,CAAA;IACf,CAAC;IAED,gDAAgD;IAChD,KAAK,CAAC,SAAiB;QACrB,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,CAAA;IAC/B,CAAC;IAED,iCAAiC;IACjC,KAAK;QACH,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAA;IACrB,CAAC;IAED,4CAA4C;IAC5C,IAAI,IAAI;QACN,OAAO,IAAI,CAAC,MAAM,CAAC,IAAI,CAAA;IACzB,CAAC;CACF"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@devxiyang/agent-kernel",
3
- "version": "0.0.2",
3
+ "version": "0.0.4",
4
4
  "description": "Agent kernel and loop library",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -52,6 +52,7 @@
52
52
  "vitest": "^4.0.18"
53
53
  },
54
54
  "dependencies": {
55
- "@sinclair/typebox": "^0.34.48"
55
+ "@sinclair/typebox": "^0.34.48",
56
+ "lru-cache": "^11.2.6"
56
57
  }
57
58
  }