@genui-a3/core 0.1.0 → 0.1.1

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 (2) hide show
  1. package/README.md +672 -1
  2. package/package.json +4 -4
package/README.md CHANGED
@@ -1 +1,672 @@
1
- # GenUI-A3
1
+ # @genui-a3/core
2
+
3
+ [![npm version](https://img.shields.io/npm/v/@genui-a3/core)](https://www.npmjs.com/package/@genui-a3/core)
4
+ [![license](https://img.shields.io/npm/l/@genui-a3/core)](https://github.com/generalui/a3/blob/main/LICENSE)
5
+
6
+ **A TypeScript framework for building multi-agent chat applications.**
7
+
8
+ Define focused agents.
9
+ Register them.
10
+ Let A3 route conversations dynamically.
11
+ No graphs.
12
+ No state machines.
13
+
14
+ ## Feature Highlights
15
+
16
+ - **Multi-agent orchestration** -- agents route to each other dynamically based on conversation context
17
+ - **Shared state** -- a single state object flows across all agents in a session
18
+ - **Structured output** -- Zod schemas validate every LLM response at runtime
19
+ - **Streaming** -- real-time token streaming via `sendStream` with AG-UI-compatible event types
20
+ - **Pluggable session stores** -- swap in-memory, AWS AgentCore, Redis, or your own store
21
+ - **Pluggable providers** -- ships with AWS Bedrock; designed for additional providers
22
+ - **TypeScript-native** -- full type safety from agent definitions to response handling
23
+ - **Dual ESM/CJS** -- works in any Node.js environment
24
+
25
+ ## Table of Contents
26
+
27
+ - [Quick Start](#quick-start)
28
+ - [Architecture at a Glance](#architecture-at-a-glance)
29
+ - [Core Concepts](#core-concepts)
30
+ - [Agent](#agent)
31
+ - [AgentRegistry](#agentregistry)
32
+ - [ChatSession](#chatsession)
33
+ - [State](#state)
34
+ - [Output Schemas](#output-schemas)
35
+ - [Routing](#routing)
36
+ - [Session Stores](#session-stores)
37
+ - [Providers](#providers)
38
+ - [Streaming](#streaming)
39
+ - [Multi-Agent Example](#multi-agent-example)
40
+ - [API Reference](#api-reference)
41
+ - [Comparison](#comparison)
42
+ - [Roadmap](#roadmap)
43
+ - [Requirements](#requirements)
44
+ - [Contributing](#contributing)
45
+ - [License](#license)
46
+
47
+ ## Quick Start
48
+
49
+ ### Install
50
+
51
+ ```bash
52
+ npm install @genui-a3/core
53
+ ```
54
+
55
+ ### Define an agent
56
+
57
+ ```typescript
58
+ import { z } from 'zod'
59
+ import { Agent, simpleAgentResponse, BaseState } from '@genui-a3/core'
60
+
61
+ interface State extends BaseState {
62
+ userName?: string
63
+ }
64
+
65
+ export const greetingAgent: Agent<State> = {
66
+ id: 'greeting',
67
+ name: 'Greeting Agent',
68
+ description: 'Greets the user and collects their name',
69
+ promptGenerator: async () => `
70
+ You are a friendly greeting agent. Your goal is to greet the user
71
+ and learn their name. Once you have their name, set goalAchieved to true.
72
+ `,
73
+ outputSchema: z.object({
74
+ userName: z.string().optional(),
75
+ }),
76
+ generateAgentResponse: simpleAgentResponse,
77
+ fitDataInGeneralFormat: (data, state) => ({ ...state, ...data }),
78
+ nextAgentSelector: (_state, goalAchieved) =>
79
+ goalAchieved ? 'end' : 'greeting',
80
+ }
81
+ ```
82
+
83
+ ### Register and run
84
+
85
+ ```typescript
86
+ import { AgentRegistry, ChatSession, MemorySessionStore } from '@genui-a3/core'
87
+
88
+ const registry = AgentRegistry.getInstance<State>()
89
+ registry.register(greetingAgent)
90
+
91
+ const session = new ChatSession<State>({
92
+ sessionId: 'demo',
93
+ store: new MemorySessionStore(),
94
+ initialAgentId: 'greeting',
95
+ initialState: { userName: undefined },
96
+ })
97
+
98
+ const response = await session.send('Hi there!')
99
+ console.log(response.responseMessage)
100
+ // => "Hello! I'd love to get to know you. What's your name?"
101
+ ```
102
+
103
+ That's it.
104
+ One agent, one session, one function call.
105
+
106
+ ## Architecture at a Glance
107
+
108
+ ```text
109
+ ┌──────────────────────────────────────────────────────────────┐
110
+ │ Your Application │
111
+ └─────────────────────────┬────────────────────────────────────┘
112
+ │ ▲
113
+ .send(message) ChatResponse
114
+ │ { responseMessage,
115
+ │ state, goalAchieved }
116
+ ▼ │
117
+ ┌──────────────────────────────────────────────────────────────┐
118
+ │ ChatSession │
119
+ │ │
120
+ │ 1. Load session from store 6. Save updated session │
121
+ │ 2. Append user message 5. Append bot message │
122
+ │ │
123
+ └───────────┬──────────────────────────────────────────────────┘
124
+ │ ▲
125
+ │ manageFlow({ agent, │ { responseMessage,
126
+ │ sessionData }) │ newState,
127
+ │ │ nextAgentId }
128
+ ▼ │
129
+ ┌──────────────────────────────────────────────────────────────┐
130
+ │ ChatFlow │
131
+ │ │
132
+ │ Looks up active agent, delegates, checks routing │
133
+ │ │
134
+ │ If nextAgent ≠ activeAgent: │
135
+ │ ┌──────────────────────────────────────────┐ │
136
+ │ │ Recursive call to manageFlow │ │
137
+ │ │ with new agent + updated state │ │
138
+ │ └──────────────────────────────────────────┘ │
139
+ │ │
140
+ └───────────┬──────────────────────────────────────────────────┘
141
+ │ ▲
142
+ │ generateAgentResponse │ { chatbotMessage,
143
+ │ ({ agent, sessionData }) │ newState,
144
+ │ │ nextAgentId }
145
+ ▼ │
146
+ ┌──────────────────────────────────────────────────────────────┐
147
+ │ Active Agent │
148
+ │ │
149
+ │ • Builds system prompt (promptGenerator) │
150
+ │ • Defines output schema (Zod) │
151
+ │ • Determines next agent (nextAgentSelector) │
152
+ │ │
153
+ └───────────┬──────────────────────────────────────────────────┘
154
+ │ ▲
155
+ │ prompt + schema │ structured JSON
156
+ ▼ │
157
+ ┌──────────────────────────────────────────────────────────────┐
158
+ │ Provider │
159
+ │ (Bedrock) │
160
+ │ │
161
+ │ • Converts Zod → JSON Schema │
162
+ │ • Merges message history │
163
+ │ • Model fallback on error │
164
+ │ │
165
+ └───────────┬──────────────────────────────────────────────────┘
166
+ │ ▲
167
+ │ API request │ API response
168
+ ▼ │
169
+ ┌──────────────────────────────────────────────────────────────┐
170
+ │ LLM │
171
+ └──────────────────────────────────────────────────────────────┘
172
+ ```
173
+
174
+ **How it flows:**
175
+
176
+ 1. Your app calls `session.send(message)` with the user's input
177
+ 1. **ChatSession** loads session data (history, state) from the configured store and appends the user message
178
+ 1. **ChatFlow** looks up the active agent and calls `generateAgentResponse`
179
+ 1. The **Agent** builds a system prompt, defines its Zod output schema, and delegates to the provider
180
+ 1. The **Provider** sends the request to the LLM and returns structured JSON
181
+ 1. The **Agent** extracts state updates and a routing decision (`nextAgentId`) from the response
182
+ 1. If the next agent differs from the active agent, ChatFlow **recursively calls `manageFlow`** with the new agent and updated state
183
+ 1. **ChatSession** appends the bot message, saves the updated session, and returns a `ChatResponse` to your app
184
+
185
+ Agents route dynamically.
186
+ There is no fixed graph.
187
+ Each agent decides whether to continue or hand off based on the conversation.
188
+
189
+ ## Core Concepts
190
+
191
+ ### Agent
192
+
193
+ An agent is the fundamental building block.
194
+ Each agent has a focused responsibility and defines how it generates responses, what structured data it extracts, and when to hand off to another agent.
195
+
196
+ ```typescript
197
+ import { z } from 'zod'
198
+ import { Agent, simpleAgentResponse, BaseState } from '@genui-a3/core'
199
+
200
+ interface MyState extends BaseState {
201
+ userName?: string
202
+ }
203
+
204
+ const greetingAgent: Agent<MyState> = {
205
+ // Identity
206
+ id: 'greeting',
207
+ name: 'Greeting Agent',
208
+ description: 'Greets the user and collects their name',
209
+
210
+ // Prompt: instructions for the LLM
211
+ promptGenerator: async () => `
212
+ You are a friendly greeting agent.
213
+ Ask the user for their name, then greet them.
214
+ Set goalAchieved to true once you know their name.
215
+ `,
216
+
217
+ // Output schema: Zod schema for structured data extraction
218
+ outputSchema: z.object({
219
+ userName: z.string().optional(),
220
+ }),
221
+
222
+ // Response generator: how to process the LLM response
223
+ generateAgentResponse: simpleAgentResponse,
224
+
225
+ // State mapper: merge extracted data into global state
226
+ fitDataInGeneralFormat: (data, state) => ({
227
+ ...state,
228
+ ...data,
229
+ }),
230
+
231
+ // Routing: decide the next agent after each turn
232
+ nextAgentSelector: (state, goalAchieved) => {
233
+ return goalAchieved ? 'next-agent' : 'greeting'
234
+ },
235
+ }
236
+ ```
237
+
238
+ **Agent properties:**
239
+
240
+ | Property | Required | Description |
241
+ |---|---|---|
242
+ | `id` | Yes | Unique identifier for the agent |
243
+ | `name` | Yes | Human-readable display name |
244
+ | `description` | Yes | What this agent does (used in agent pool prompts) |
245
+ | `promptGenerator` | Yes | Async function returning the system prompt for this agent |
246
+ | `outputSchema` | Yes | Zod schema defining structured data to extract from LLM responses |
247
+ | `generateAgentResponse` | Yes | Function that orchestrates the full response cycle |
248
+ | `fitDataInGeneralFormat` | Yes | Maps extracted LLM data into the shared state object |
249
+ | `nextAgentSelector` | No | Determines the next agent based on state and goal status |
250
+ | `transitionsTo` | No | Array of agent IDs this agent is allowed to redirect to |
251
+ | `filterHistoryStrategy` | No | Custom function to filter conversation history before sending to the LLM |
252
+ | `modelId` | No | Override the default model for this agent |
253
+
254
+ ### AgentRegistry
255
+
256
+ A singleton registry where all agents are registered before use.
257
+
258
+ ```typescript
259
+ import { AgentRegistry } from '@genui-a3/core'
260
+
261
+ const registry = AgentRegistry.getInstance<MyState>()
262
+
263
+ // Register one or many agents
264
+ registry.register(greetingAgent)
265
+ registry.register([authAgent, mainAgent, wrapUpAgent])
266
+
267
+ // Query the registry
268
+ registry.has('greeting') // true
269
+ registry.get('greeting') // Agent object
270
+ registry.getAll() // All registered agents
271
+ registry.getDescriptions() // { greeting: 'Greets the user...' }
272
+ registry.count // 4
273
+ ```
274
+
275
+ ### ChatSession
276
+
277
+ The primary interface your application uses to interact with A3.
278
+ Create a session, send messages, get responses.
279
+
280
+ ```typescript
281
+ import { ChatSession, MemorySessionStore } from '@genui-a3/core'
282
+
283
+ const session = new ChatSession<MyState>({
284
+ sessionId: 'user-123',
285
+ store: new MemorySessionStore(), // pluggable persistence
286
+ initialAgentId: 'greeting',
287
+ initialState: { userName: undefined },
288
+ })
289
+
290
+ // Send a message and get a structured response
291
+ const result = await session.send('Hello!')
292
+
293
+ result.responseMessage // "Hi there! What's your name?"
294
+ result.activeAgentId // 'greeting'
295
+ result.nextAgentId // 'greeting'
296
+ result.state // { userName: undefined }
297
+ result.goalAchieved // false
298
+ result.sessionId // 'user-123'
299
+ ```
300
+
301
+ ### State
302
+
303
+ A3 uses a shared global state object that flows across all agents in a session.
304
+ Define your state by extending `BaseState`.
305
+
306
+ ```typescript
307
+ import { BaseState } from '@genui-a3/core'
308
+
309
+ interface AppState extends BaseState {
310
+ userName?: string
311
+ isAuthenticated: boolean
312
+ currentStep: string
313
+ }
314
+ ```
315
+
316
+ Each agent's `fitDataInGeneralFormat` merges its extracted data into this shared state.
317
+ When agents switch, the full state carries over.
318
+
319
+ ### Output Schemas
320
+
321
+ Every agent defines a Zod schema for the structured data it needs to extract from LLM responses.
322
+ A3 merges this with base fields (`chatbotMessage`, `goalAchieved`, `redirectToAgent`) and validates the LLM output.
323
+
324
+ ```typescript
325
+ // Static schema
326
+ const schema = z.object({
327
+ userName: z.string().optional(),
328
+ sentiment: z.enum(['positive', 'neutral', 'negative']),
329
+ })
330
+
331
+ // Dynamic schema (based on current session state)
332
+ const dynamicSchema = (sessionData) => z.object({
333
+ userName: z.string().describe(`Current: ${sessionData.state.userName ?? 'unknown'}`),
334
+ })
335
+ ```
336
+
337
+ Schemas serve two purposes:
338
+
339
+ 1. **Instruct the LLM** on what data to extract (field names and descriptions become part of the prompt)
340
+ 1. **Validate the response** at runtime so your application always receives well-typed data
341
+
342
+ ### Routing
343
+
344
+ Agents route to each other in three ways:
345
+
346
+ **1. `nextAgentSelector`** -- Choose the next agent programmatically after each turn:
347
+
348
+ ```typescript
349
+ nextAgentSelector: (state, goalAchieved) => {
350
+ if (goalAchieved) return 'main-menu'
351
+ if (state.failedAttempts > 3) return 'escalation'
352
+ return 'auth' // stay on current agent
353
+ }
354
+ ```
355
+
356
+ **2. `redirectToAgent`** -- The LLM itself can request a redirect via the base response schema.
357
+ The agent's prompt and agent pool listing tell the LLM which agents are available.
358
+
359
+ **3. `transitionsTo`** -- Constrain which agents the LLM can redirect to:
360
+
361
+ ```typescript
362
+ const agent: Agent<MyState> = {
363
+ id: 'triage',
364
+ transitionsTo: ['billing', 'support', 'account'],
365
+ // LLM can only redirect to these three agents
366
+ // ...
367
+ }
368
+ ```
369
+
370
+ When a redirect happens, **ChatFlow recursively invokes the next agent** in the same request.
371
+ The user sees a single response, even if multiple agents were involved.
372
+
373
+ ### Session Stores
374
+
375
+ A3 uses pluggable session stores for persistence.
376
+ Any object implementing the `SessionStore` interface works.
377
+
378
+ ```typescript
379
+ interface SessionStore<TState extends BaseState> {
380
+ load(sessionId: string): Promise<SessionData<TState> | null>
381
+ save(sessionId: string, data: SessionData<TState>): Promise<void>
382
+ delete?(sessionId: string): Promise<void>
383
+ }
384
+ ```
385
+
386
+ **Built-in stores:**
387
+
388
+ | Store | Use case |
389
+ |---|---|
390
+ | `MemorySessionStore` | Development and testing (sessions lost on restart) |
391
+ | `AgentCoreMemoryStore` | AWS Bedrock AgentCore integration for persistent storage |
392
+
393
+ Custom stores are straightforward to implement for Redis, DynamoDB, PostgreSQL, or any other backend.
394
+
395
+ ### Providers
396
+
397
+ Providers handle communication with LLM backends.
398
+ A3 ships with an AWS Bedrock provider and is designed so additional providers can be added.
399
+
400
+ ```typescript
401
+ import { sendChatRequest } from '@genui-a3/core'
402
+ ```
403
+
404
+ The Bedrock provider:
405
+
406
+ - Sends structured requests via the AWS Bedrock Converse API
407
+ - Uses tool-based JSON extraction for reliable structured output
408
+ - Supports model fallback (primary model fails, falls back to secondary)
409
+ - Merges sequential same-sender messages for API compatibility
410
+ - Applies agent-specific history filtering before sending
411
+
412
+ ### Streaming
413
+
414
+ A3 supports real-time token streaming via `sendStream`.
415
+ Instead of waiting for a complete response, your application receives events as they happen.
416
+
417
+ ```typescript
418
+ for await (const event of session.sendStream('Hello!')) {
419
+ switch (event.type) {
420
+ case 'TextMessageContent':
421
+ process.stdout.write(event.delta) // real-time token output
422
+ break
423
+ case 'AgentTransition':
424
+ console.log(`${event.fromAgentId} → ${event.toAgentId}`)
425
+ break
426
+ case 'RunFinished':
427
+ console.log('Final state:', event.response.state)
428
+ break
429
+ case 'RunError':
430
+ console.error('Error:', event.error)
431
+ break
432
+ }
433
+ }
434
+ ```
435
+
436
+ **StreamEvent types:**
437
+
438
+ | Event Type | Key Fields | Description |
439
+ |---|---|---|
440
+ | `RunStarted` | `runId`, `threadId` | Stream has begun |
441
+ | `TextMessageStart` | `messageId` | A new text message is starting |
442
+ | `TextMessageContent` | `delta`, `agentId` | A text chunk from the active agent |
443
+ | `TextMessageEnd` | `messageId` | Text message complete |
444
+ | `ToolCallStart` | `toolCallId`, `toolCallName` | Tool/function call initiated |
445
+ | `ToolCallArgs` | `toolCallId`, `delta` | Tool argument chunk |
446
+ | `ToolCallEnd` | `toolCallId` | Tool call complete |
447
+ | `ToolCallResult` | `data`, `agentId` | Tool execution result with extracted data |
448
+ | `AgentTransition` | `fromAgentId`, `toAgentId` | Agent handoff occurred |
449
+ | `RunFinished` | `response` | Stream complete with final `ChatResponse` |
450
+ | `RunError` | `error`, `agentId` | Error during stream |
451
+
452
+ ## Multi-Agent Example
453
+
454
+ Three agents routing between each other, demonstrating state flowing across agent boundaries and automatic agent chaining.
455
+
456
+ ### Define the agents
457
+
458
+ ```typescript
459
+ import { z } from 'zod'
460
+ import { Agent, simpleAgentResponse, BaseState } from '@genui-a3/core'
461
+
462
+ interface AppState extends BaseState {
463
+ userName?: string
464
+ isAuthenticated: boolean
465
+ issueCategory?: string
466
+ }
467
+
468
+ // Agent 1: Greeting -- collects the user's name, then routes to auth
469
+ const greetingAgent: Agent<AppState> = {
470
+ id: 'greeting',
471
+ name: 'Greeting Agent',
472
+ description: 'Greets the user and collects their name',
473
+ promptGenerator: async () => `
474
+ Greet the user warmly. Ask for their name.
475
+ Once you have it, set goalAchieved to true.
476
+ `,
477
+ outputSchema: z.object({ userName: z.string().optional() }),
478
+ generateAgentResponse: simpleAgentResponse,
479
+ fitDataInGeneralFormat: (data, state) => ({ ...state, ...data }),
480
+ nextAgentSelector: (_state, goalAchieved) =>
481
+ goalAchieved ? 'auth' : 'greeting',
482
+ transitionsTo: ['auth'],
483
+ }
484
+
485
+ // Agent 2: Auth -- verifies identity, then routes to support
486
+ const authAgent: Agent<AppState> = {
487
+ id: 'auth',
488
+ name: 'Auth Agent',
489
+ description: 'Verifies user identity',
490
+ promptGenerator: async ({ sessionData }) => `
491
+ The user's name is ${sessionData.state.userName}.
492
+ Ask them to confirm their email to verify identity.
493
+ Set goalAchieved to true once verified.
494
+ `,
495
+ outputSchema: z.object({ isAuthenticated: z.boolean() }),
496
+ generateAgentResponse: simpleAgentResponse,
497
+ fitDataInGeneralFormat: (data, state) => ({ ...state, ...data }),
498
+ nextAgentSelector: (_state, goalAchieved) =>
499
+ goalAchieved ? 'support' : 'auth',
500
+ transitionsTo: ['support'],
501
+ }
502
+
503
+ // Agent 3: Support -- handles the user's issue
504
+ const supportAgent: Agent<AppState> = {
505
+ id: 'support',
506
+ name: 'Support Agent',
507
+ description: 'Helps resolve user issues',
508
+ promptGenerator: async ({ sessionData }) => `
509
+ The user ${sessionData.state.userName} is authenticated.
510
+ Help them with their issue. Categorize it.
511
+ Set goalAchieved when resolved.
512
+ `,
513
+ outputSchema: z.object({
514
+ issueCategory: z.string().optional(),
515
+ }),
516
+ generateAgentResponse: simpleAgentResponse,
517
+ fitDataInGeneralFormat: (data, state) => ({ ...state, ...data }),
518
+ nextAgentSelector: (_state, goalAchieved) =>
519
+ goalAchieved ? 'end' : 'support',
520
+ }
521
+ ```
522
+
523
+ ### Wire them up
524
+
525
+ ```typescript
526
+ import { AgentRegistry, ChatSession, MemorySessionStore } from '@genui-a3/core'
527
+
528
+ const registry = AgentRegistry.getInstance<AppState>()
529
+ registry.register([greetingAgent, authAgent, supportAgent])
530
+
531
+ const session = new ChatSession<AppState>({
532
+ sessionId: 'user-456',
533
+ store: new MemorySessionStore(),
534
+ initialAgentId: 'greeting',
535
+ initialState: { isAuthenticated: false },
536
+ })
537
+ ```
538
+
539
+ ### Conversation flow
540
+
541
+ ```typescript
542
+ // Turn 1: User greets, greeting agent responds
543
+ await session.send('Hello!')
544
+ // => Greeting agent asks for name
545
+
546
+ // Turn 2: User provides name, greeting agent completes and chains to auth
547
+ await session.send("I'm Alex")
548
+ // => Auth agent asks for email verification
549
+ // (greeting → auth happened automatically in one request)
550
+
551
+ // Turn 3: User verifies, auth completes and chains to support
552
+ await session.send('alex@example.com')
553
+ // => Support agent asks how it can help
554
+ // State now: { userName: 'Alex', isAuthenticated: true }
555
+
556
+ // Turn 4: Support agent handles the issue
557
+ await session.send('I need help with my billing')
558
+ // => Support agent resolves the issue
559
+ // State: { userName: 'Alex', isAuthenticated: true, issueCategory: 'billing' }
560
+ ```
561
+
562
+ Notice that:
563
+
564
+ - **State persists across agents**: `userName` set by the greeting agent is available to auth and support
565
+ - **Agent chaining is automatic**: when greeting completes, auth starts in the same request
566
+ - **Each agent has its own prompt and schema**: they extract different data but share the same state
567
+
568
+ ## API Reference
569
+
570
+ ### Core Exports
571
+
572
+ | Export | Type | Description |
573
+ |---|---|---|
574
+ | `ChatSession` | Class | Primary interface for sending messages and managing conversations |
575
+ | `AgentRegistry` | Class | Singleton registry for agent registration and lookup |
576
+ | `simpleAgentResponse` | Function | Default response generator for agents |
577
+ | `getAgentResponse` | Function | Low-level agent response pipeline (prompt, schema, LLM call, validation) |
578
+ | `manageFlow` | Function | Recursive chat flow orchestration with automatic agent chaining |
579
+ | `manageFlowStream` | Function | Streaming variant of `manageFlow` yielding `StreamEvent`s |
580
+ | `createFullOutputSchema` | Function | Merges agent schema with base response fields |
581
+ | `sendChatRequest` | Function | Sends structured requests to the LLM provider |
582
+ | `MemorySessionStore` | Class | In-memory session store for development and testing |
583
+ | `AgentCoreMemoryStore` | Class | AWS Bedrock AgentCore session store |
584
+
585
+ ### ChatSession Methods
586
+
587
+ | Method | Returns | Description |
588
+ |---|---|---|
589
+ | `send(message)` | `Promise<ChatResponse<TState>>` | Send a user message and get the agent's response |
590
+ | `sendStream(message)` | `AsyncGenerator<StreamEvent<TState>>` | Send a message and stream the response as events |
591
+ | `getSessionData()` | `Promise<SessionData<TState> \| null>` | Load current session state without sending a message |
592
+ | `getOrCreateSessionData()` | `Promise<SessionData<TState>>` | Load session or create with initial values if none exists |
593
+ | `upsertSessionData(updates)` | `Promise<void>` | Merge partial updates into the current session |
594
+ | `getHistory()` | `Promise<Message[]>` | Retrieve conversation history |
595
+ | `clear()` | `Promise<void>` | Delete the session from the store |
596
+
597
+ ### AgentRegistry Methods
598
+
599
+ | Method | Returns | Description |
600
+ |---|---|---|
601
+ | `getInstance()` | `AgentRegistry<TState>` | Get the singleton instance |
602
+ | `resetInstance()` | `void` | Reset the singleton (for testing) |
603
+ | `register(agents)` | `void` | Register one or more agents (throws on duplicate ID) |
604
+ | `unregister(id)` | `boolean` | Remove an agent by ID |
605
+ | `get(id)` | `Agent<TState> \| undefined` | Look up an agent by ID |
606
+ | `getAll()` | `Agent<TState>[]` | Get all registered agents |
607
+ | `has(id)` | `boolean` | Check if an agent is registered |
608
+ | `getDescriptions()` | `Record<string, string>` | Map of agent IDs to their descriptions |
609
+ | `clear()` | `void` | Remove all registered agents (for testing) |
610
+ | `count` | `number` | Number of registered agents (getter) |
611
+
612
+ ### ChatResponse Fields
613
+
614
+ | Field | Type | Description |
615
+ |---|---|---|
616
+ | `responseMessage` | `string` | The agent's text response to the user |
617
+ | `activeAgentId` | `string \| null` | The agent that generated this response |
618
+ | `nextAgentId` | `string \| null` | The agent that will handle the next message |
619
+ | `state` | `TState` | Updated session state after this turn |
620
+ | `goalAchieved` | `boolean` | Whether the agent considers its goal complete |
621
+ | `sessionId` | `string` | Session identifier |
622
+ | `widgets` | `object \| undefined` | Optional widget data for rich UI rendering |
623
+
624
+ ## Comparison
625
+
626
+ | Capability | GenUI A3 | LangGraph | CrewAI | AutoGen |
627
+ |---|---|---|---|---|
628
+ | **Setup complexity** | Minimal | Moderate | Moderate | High |
629
+ | **Routing model** | Dynamic (agent-driven) | Static graph | Role-based | Conversation-based |
630
+ | **State management** | Shared global state | Graph state | Shared memory | Message passing |
631
+ | **TypeScript-native** | Yes | Python-first | Python-only | Python-first |
632
+ | **Structured output** | Zod schemas | Custom parsers | Pydantic | Custom parsers |
633
+ | **Session persistence** | Pluggable stores | Custom | Custom | Custom |
634
+
635
+ ## Roadmap
636
+
637
+ - **Simplified Agent API** -- reduce agent definitions to just the essentials with sensible defaults
638
+ - **Provider Abstraction** -- first-class support for OpenAI, Anthropic, and custom providers alongside Bedrock
639
+ - **AG-UI Protocol** -- full compliance with the [ag-ui.com](https://ag-ui.com) protocol for standardized agent-to-frontend event streaming
640
+
641
+ ## Requirements
642
+
643
+ - Node.js 20.19.0+
644
+ - TypeScript 5.9+
645
+ - `zod` 4.x (included as a dependency)
646
+ - A configured LLM provider (AWS Bedrock provider included)
647
+
648
+ ## Contributing
649
+
650
+ ```bash
651
+ # Install dependencies
652
+ npm install
653
+
654
+ # Build
655
+ npm run build
656
+
657
+ # Run unit tests
658
+ npm run test:unit
659
+
660
+ # Run integration tests
661
+ npm run test:integration
662
+
663
+ # Lint
664
+ npm run lint
665
+
666
+ # Watch mode (build + example)
667
+ npm run dev
668
+ ```
669
+
670
+ ## License
671
+
672
+ ISC
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@genui-a3/core",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "Core package for the A3 agentic backend framework",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
@@ -30,9 +30,9 @@
30
30
  "example:setup": "cd example && npm i",
31
31
  "example:start": "cd example && npm run start",
32
32
  "lint": "run-p lint:project lint:markdown lint:example",
33
- "lint:example": "eslint './example/**/*.{ts,tsx}' --max-warnings=0 --cache --cache-location .eslintcache",
34
- "lint:markdown": "markdownlint-cli2 '**/*.md' '!**/no_commit/**' '!**/node_modules/**'",
35
- "lint:project": "eslint './**/*.{ts,tsx}' --ignore-pattern 'example/**' --max-warnings=0 --cache --cache-location .eslintcache",
33
+ "lint:example": "eslint './example/**/*.{ts,tsx}' './example_agent_core/**/*.{ts,tsx}' --max-warnings=0 --cache --cache-location .eslintcache",
34
+ "lint:markdown": "markdownlint-cli2 '**/*.md'",
35
+ "lint:project": "eslint './**/*.{ts,tsx}' --ignore-pattern 'example/**' --ignore-pattern 'example_agent_core/**' --max-warnings=0 --cache --cache-location .eslintcache",
36
36
  "prepublishOnly": "npm run clean && npm run build",
37
37
  "test": "run-p test:unit",
38
38
  "test:coverage": "run-p test:unit:coverage",