@genui/a3-create 0.1.36

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 (91) hide show
  1. package/README.md +123 -0
  2. package/dist/index.js +684 -0
  3. package/package.json +52 -0
  4. package/template/.cursor/rules/example-app.mdc +9 -0
  5. package/template/CLAUDE.md +121 -0
  6. package/template/README.md +20 -0
  7. package/template/_gitignore +36 -0
  8. package/template/app/ThemeProvider.tsx +17 -0
  9. package/template/app/agents/age.ts +25 -0
  10. package/template/app/agents/greeting.ts +30 -0
  11. package/template/app/agents/index.ts +57 -0
  12. package/template/app/agents/onboarding/index.ts +15 -0
  13. package/template/app/agents/onboarding/prompt.ts +59 -0
  14. package/template/app/agents/registry.ts +17 -0
  15. package/template/app/agents/state.ts +10 -0
  16. package/template/app/api/agui/route.ts +56 -0
  17. package/template/app/api/chat/route.ts +35 -0
  18. package/template/app/api/stream/route.ts +57 -0
  19. package/template/app/apple-icon-dark.png +0 -0
  20. package/template/app/apple-icon.png +0 -0
  21. package/template/app/components/atoms/AgentNode.tsx +56 -0
  22. package/template/app/components/atoms/AppLogo.tsx +44 -0
  23. package/template/app/components/atoms/ChatContainer.tsx +13 -0
  24. package/template/app/components/atoms/ChatHeader.tsx +49 -0
  25. package/template/app/components/atoms/MarkdownRenderer.tsx +134 -0
  26. package/template/app/components/atoms/MessageBubble.tsx +21 -0
  27. package/template/app/components/atoms/TransitionEdge.tsx +49 -0
  28. package/template/app/components/atoms/index.ts +7 -0
  29. package/template/app/components/molecules/ChatInput.tsx +94 -0
  30. package/template/app/components/molecules/ChatMessage.tsx +45 -0
  31. package/template/app/components/molecules/index.ts +2 -0
  32. package/template/app/components/organisms/AgentGraph.tsx +75 -0
  33. package/template/app/components/organisms/AguiChat.tsx +133 -0
  34. package/template/app/components/organisms/Chat.tsx +88 -0
  35. package/template/app/components/organisms/ChatMessageList.tsx +35 -0
  36. package/template/app/components/organisms/ExamplePageLayout.tsx +118 -0
  37. package/template/app/components/organisms/OnboardingChat.tsx +24 -0
  38. package/template/app/components/organisms/Sidebar.tsx +147 -0
  39. package/template/app/components/organisms/SidebarLayout.tsx +58 -0
  40. package/template/app/components/organisms/StateViewer.tsx +126 -0
  41. package/template/app/components/organisms/StreamChat.tsx +173 -0
  42. package/template/app/components/organisms/index.ts +10 -0
  43. package/template/app/constants/chat.ts +52 -0
  44. package/template/app/constants/paths.ts +1 -0
  45. package/template/app/constants/ui.ts +61 -0
  46. package/template/app/examples/agui/page.tsx +26 -0
  47. package/template/app/examples/chat/page.tsx +26 -0
  48. package/template/app/examples/page.tsx +106 -0
  49. package/template/app/examples/stream/page.tsx +26 -0
  50. package/template/app/favicon-dark.ico +0 -0
  51. package/template/app/favicon.ico +0 -0
  52. package/template/app/icon.svg +13 -0
  53. package/template/app/layout.tsx +36 -0
  54. package/template/app/lib/actions/restartSession.ts +10 -0
  55. package/template/app/lib/getAgentGraphData.ts +43 -0
  56. package/template/app/lib/getGraphLayout.ts +99 -0
  57. package/template/app/lib/hooks/useRestart.ts +33 -0
  58. package/template/app/lib/parseTransitionTargets.ts +140 -0
  59. package/template/app/lib/providers/anthropic.ts +12 -0
  60. package/template/app/lib/providers/bedrock.ts +12 -0
  61. package/template/app/lib/providers/openai.ts +10 -0
  62. package/template/app/onboarding/page.tsx +21 -0
  63. package/template/app/page.tsx +16 -0
  64. package/template/app/styled.d.ts +6 -0
  65. package/template/app/theme.ts +22 -0
  66. package/template/docs/A3-README.md +121 -0
  67. package/template/docs/API-REFERENCE.md +85 -0
  68. package/template/docs/ARCHITECTURE.md +84 -0
  69. package/template/docs/CORE-CONCEPTS.md +347 -0
  70. package/template/docs/CUSTOM_LOGGING.md +36 -0
  71. package/template/docs/CUSTOM_PROVIDERS.md +642 -0
  72. package/template/docs/CUSTOM_STORES.md +228 -0
  73. package/template/docs/PROVIDER-ANTHROPIC.md +45 -0
  74. package/template/docs/PROVIDER-BEDROCK.md +45 -0
  75. package/template/docs/PROVIDER-OPENAI.md +47 -0
  76. package/template/docs/PROVIDERS.md +124 -0
  77. package/template/docs/QUICK-START-EXAMPLES.md +197 -0
  78. package/template/docs/RESILIENCE.md +226 -0
  79. package/template/docs/TRANSITIONS.md +245 -0
  80. package/template/docs/WIDGETS.md +331 -0
  81. package/template/docs/contributing/LOGGING.md +104 -0
  82. package/template/docs/designs/a3-gtm-strategy.md +280 -0
  83. package/template/docs/designs/a3-platform-vision.md +276 -0
  84. package/template/next-env.d.ts +6 -0
  85. package/template/next.config.mjs +15 -0
  86. package/template/package.json +41 -0
  87. package/template/public/android-chrome-192x192.png +0 -0
  88. package/template/public/android-chrome-512x512.png +0 -0
  89. package/template/public/site.webmanifest +11 -0
  90. package/template/scripts/dev.mjs +29 -0
  91. package/template/tsconfig.json +47 -0
@@ -0,0 +1,228 @@
1
+ # Creating a Custom Session Store
2
+
3
+ This guide walks you through implementing a custom `SessionStore` so A3 can persist sessions to any backend — DynamoDB, Redis, PostgreSQL, or anything else.
4
+
5
+ ## When to Create a Custom Store
6
+
7
+ Create a custom store when you need:
8
+
9
+ 1. **Production persistence** — sessions that survive process restarts (the built-in `MemorySessionStore` doesn't)
10
+ 1. **Shared storage** — multiple server instances reading/writing the same sessions (e.g. behind a load balancer)
11
+ 1. **TTL / expiration** — automatic cleanup of stale sessions
12
+ 1. **Audit or compliance** — durable session records with timestamps
13
+
14
+ ## The SessionStore Interface
15
+
16
+ Every store implements the `SessionStore` interface from `@genui/a3`:
17
+
18
+ ```typescript
19
+ import { SessionData, BaseState, BaseChatContext } from '@genui/a3'
20
+
21
+ interface SessionStore<
22
+ TState extends BaseState = BaseState,
23
+ TContext extends BaseChatContext = BaseChatContext,
24
+ > {
25
+ /** Load session data, returns null if not found */
26
+ load(sessionId: string): Promise<SessionData<TState, TContext> | null>
27
+
28
+ /** Save session data */
29
+ save(sessionId: string, data: SessionData<TState, TContext>): Promise<void>
30
+
31
+ /** Delete a session (optional) */
32
+ delete?(sessionId: string): Promise<void>
33
+ }
34
+ ```
35
+
36
+ | Method | Required | Description |
37
+ |---|---|---|
38
+ | `load(sessionId)` | Yes | Retrieve session data by ID. Return `null` if no session exists. |
39
+ | `save(sessionId, data)` | Yes | Persist the full `SessionData` object. Called after every turn. |
40
+ | `delete(sessionId)` | No | Remove a session. Useful for cleanup, logout, or TTL expiration. |
41
+
42
+ ## SessionData Structure
43
+
44
+ `SessionData` is the object your store serializes and deserializes:
45
+
46
+ ```typescript
47
+ interface SessionData<
48
+ TState extends BaseState = BaseState,
49
+ TContext extends BaseChatContext = BaseChatContext,
50
+ > {
51
+ sessionId: string
52
+ messages: Conversation // Array of Message objects (full chat history)
53
+ conversationHistory?: Conversation // Previous messages when re-authenticating
54
+ activeAgentId: AgentId | null // Currently active agent
55
+ state: TState // Shared state across all agents
56
+ chatContext: TContext // Context variables for the current session
57
+ }
58
+ ```
59
+
60
+ | Field | Description |
61
+ |---|---|
62
+ | `sessionId` | Unique identifier for the session |
63
+ | `messages` | Full conversation history (user and assistant messages) |
64
+ | `conversationHistory` | Optional backup of previous messages (used during re-authentication flows) |
65
+ | `activeAgentId` | The agent that will handle the next user message, or `null` |
66
+ | `state` | Shared typed state flowing across all agents — your `TState` extension of `BaseState` |
67
+ | `chatContext` | Session-level context — your `TContext` extension of `BaseChatContext` |
68
+
69
+ ## Implementing a Custom Store
70
+
71
+ ### Step 1: Implement `load`
72
+
73
+ Retrieve the session from your backend and deserialize it.
74
+ Return `null` if the session doesn't exist.
75
+
76
+ ```typescript
77
+ async load(sessionId: string): Promise<SessionData<TState, TContext> | null> {
78
+ const raw = await this.client.get(sessionId)
79
+ return raw ? JSON.parse(raw) : null
80
+ }
81
+ ```
82
+
83
+ ### Step 2: Implement `save`
84
+
85
+ Serialize the `SessionData` and write it to your backend.
86
+ This is called after every turn, so it must handle both inserts and updates.
87
+
88
+ ```typescript
89
+ async save(sessionId: string, data: SessionData<TState, TContext>): Promise<void> {
90
+ await this.client.set(sessionId, JSON.stringify(data))
91
+ }
92
+ ```
93
+
94
+ ### Step 3: Implement `delete` (optional)
95
+
96
+ Remove a session from your backend.
97
+ If your backend supports TTL natively, you may not need this.
98
+
99
+ ```typescript
100
+ async delete(sessionId: string): Promise<void> {
101
+ await this.client.delete(sessionId)
102
+ }
103
+ ```
104
+
105
+ ## Example: DynamoDB Store
106
+
107
+ A complete, copy-pasteable implementation using the AWS SDK v3:
108
+
109
+ ```typescript
110
+ import { GetCommand, PutCommand, DeleteCommand } from '@aws-sdk/lib-dynamodb'
111
+ import type { DynamoDBDocumentClient } from '@aws-sdk/lib-dynamodb'
112
+ import type { SessionStore, SessionData, BaseState, BaseChatContext } from '@genui/a3'
113
+
114
+ export class DynamoSessionStore<
115
+ TState extends BaseState = BaseState,
116
+ TContext extends BaseChatContext = BaseChatContext,
117
+ > implements SessionStore<TState, TContext> {
118
+ private tableName: string
119
+ private client: DynamoDBDocumentClient
120
+
121
+ constructor(client: DynamoDBDocumentClient, tableName: string) {
122
+ this.client = client
123
+ this.tableName = tableName
124
+ }
125
+
126
+ async load(sessionId: string): Promise<SessionData<TState, TContext> | null> {
127
+ const result = await this.client.send(
128
+ new GetCommand({
129
+ TableName: this.tableName,
130
+ Key: { id: sessionId },
131
+ }),
132
+ )
133
+
134
+ if (!result.Item?.data) {
135
+ return null
136
+ }
137
+
138
+ return JSON.parse(result.Item.data as string) as SessionData<TState, TContext>
139
+ }
140
+
141
+ async save(sessionId: string, data: SessionData<TState, TContext>): Promise<void> {
142
+ await this.client.send(
143
+ new PutCommand({
144
+ TableName: this.tableName,
145
+ Item: {
146
+ id: sessionId,
147
+ data: JSON.stringify(data),
148
+ updatedAt: new Date().toISOString(),
149
+ },
150
+ }),
151
+ )
152
+ }
153
+
154
+ async delete(sessionId: string): Promise<void> {
155
+ await this.client.send(
156
+ new DeleteCommand({
157
+ TableName: this.tableName,
158
+ Key: { id: sessionId },
159
+ }),
160
+ )
161
+ }
162
+ }
163
+ ```
164
+
165
+ ## Using Your Store
166
+
167
+ Pass your store to `ChatSession` via the `store` option:
168
+
169
+ ```typescript
170
+ import { ChatSession } from '@genui/a3'
171
+ import { createBedrockProvider } from '@genui/a3-bedrock'
172
+ import { DynamoDBDocumentClient } from '@aws-sdk/lib-dynamodb'
173
+ import { DynamoDBClient } from '@aws-sdk/client-dynamodb'
174
+ import { DynamoSessionStore } from './dynamoSessionStore'
175
+
176
+ const dynamoClient = DynamoDBDocumentClient.from(new DynamoDBClient({}))
177
+
178
+ const session = new ChatSession({
179
+ sessionId: 'user-123',
180
+ store: new DynamoSessionStore(dynamoClient, 'my-sessions-table'),
181
+ initialAgentId: 'greeting',
182
+ provider: createBedrockProvider({ models: ['us.anthropic.claude-sonnet-4-5-20250929-v1:0'] }),
183
+ })
184
+
185
+ const result = await session.send({ message: 'Hello!' })
186
+ ```
187
+
188
+ ## Gotchas and Tips
189
+
190
+ ### Serialization
191
+
192
+ `SessionData` contains plain objects and arrays — `JSON.stringify` / `JSON.parse` works for most backends.
193
+ If your state includes `Date` objects, `Map`, `Set`, or class instances, you'll need a custom serializer (e.g. `superjson`).
194
+
195
+ ### TTL and Expiration
196
+
197
+ A3 doesn't manage TTL.
198
+ Use your backend's native TTL feature (e.g. DynamoDB TTL, Redis `EXPIRE`) and set it in `save`.
199
+
200
+ ### Concurrency
201
+
202
+ `save` is called after every turn.
203
+ If a user sends rapid messages, two `save` calls may race.
204
+ For most backends (Redis `SET`, DynamoDB `PutItem`) last-write-wins is fine.
205
+ If you need stronger guarantees, use conditional writes or optimistic locking.
206
+
207
+ ### Typing
208
+
209
+ `SessionStore` is generic over `TState` and `TContext`.
210
+ Type your store class to match your application's state:
211
+
212
+ ```typescript
213
+ const store = new DynamoSessionStore<MyAppState, MyAppContext>(client, 'sessions')
214
+ ```
215
+
216
+ ### Store is Optional
217
+
218
+ `ChatSession` works without a store — sessions live only in the `ChatSession` instance's memory.
219
+ If you omit `store`, session data is never persisted and is lost when the instance is garbage collected.
220
+
221
+ ## Reference
222
+
223
+ | File | Description |
224
+ |---|---|
225
+ | `src/types/storage.ts` | `SessionStore` interface |
226
+ | `src/types/session.ts` | `SessionData`, `BaseState`, `BaseChatContext` interfaces |
227
+ | `src/stores/memoryStore.ts` | `MemorySessionStore` — built-in in-memory implementation |
228
+ | `src/core/chatSession.ts` | `ChatSession` — where stores are consumed |
@@ -0,0 +1,45 @@
1
+ # @genui/a3-anthropic
2
+
3
+ Anthropic provider for the [A3 agentic framework](https://www.npmjs.com/package/@genui/a3).
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ npm install @genui/a3-anthropic @genui/a3
9
+ ```
10
+
11
+ ## Quick Start
12
+
13
+ ```typescript
14
+ import { createAnthropicProvider } from '@genui/a3-anthropic'
15
+
16
+ const provider = createAnthropicProvider({
17
+ models: ['claude-sonnet-4-5-20250929', 'claude-haiku-4-5-20251001'],
18
+ apiKey: process.env.ANTHROPIC_API_KEY, // optional, defaults to ANTHROPIC_API_KEY env var
19
+ })
20
+ ```
21
+
22
+ ## Configuration
23
+
24
+ `createAnthropicProvider(config)` communicates with the Anthropic Messages API using the [Vercel AI SDK](https://sdk.vercel.ai/providers/ai-sdk-providers/anthropic) (`@ai-sdk/anthropic`) for structured output.
25
+
26
+ | Option | Type | Required | Description |
27
+ |---|---|---|---|
28
+ | `models` | `string[]` | Yes | Model IDs in preference order (first = primary, rest = fallbacks) |
29
+ | `apiKey` | `string` | No | API key. Defaults to `ANTHROPIC_API_KEY` env var |
30
+ | `baseURL` | `string` | No | Custom base URL for the Anthropic API |
31
+ | `resilience` | `ResilienceConfig` | No | Retry, backoff, and timeout settings. Uses defaults if omitted |
32
+
33
+ ## Behaviour
34
+
35
+ - Uses the Vercel AI SDK's `Output.object()` for structured output — Zod schema conversion and partial JSON parsing handled internally
36
+ - **Streaming** yields text deltas in real-time via partial object tracking, then emits a validated tool-call result at the end
37
+ - **Appends a `"Continue"` user message** if the last message has an assistant role, to satisfy the alternating-role requirement
38
+
39
+ ## Prerequisites
40
+
41
+ An Anthropic API key, either passed directly or set as `ANTHROPIC_API_KEY`.
42
+
43
+ ## Documentation
44
+
45
+ See the [Providers documentation](https://github.com/generalui/a3/blob/main/docs/PROVIDERS.md) for model fallback, per-agent overrides, the provider interface, and more.
@@ -0,0 +1,45 @@
1
+ # @genui/a3-bedrock
2
+
3
+ AWS Bedrock provider for the [A3 agentic framework](https://www.npmjs.com/package/@genui/a3).
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ npm install @genui/a3-bedrock @genui/a3
9
+ ```
10
+
11
+ ## Quick Start
12
+
13
+ ```typescript
14
+ import { createBedrockProvider } from '@genui/a3-bedrock'
15
+
16
+ const provider = createBedrockProvider({
17
+ models: ['us.anthropic.claude-sonnet-4-5-20250929-v1:0'],
18
+ region: 'us-east-1', // optional, defaults to AWS SDK default
19
+ })
20
+ ```
21
+
22
+ ## Configuration
23
+
24
+ `createBedrockProvider(config)` communicates with AWS Bedrock via the [Converse API](https://docs.aws.amazon.com/bedrock/latest/APIReference/API_runtime_Converse.html).
25
+
26
+ | Option | Type | Required | Description |
27
+ |---|---|---|---|
28
+ | `models` | `string[]` | Yes | Model IDs in preference order (first = primary, rest = fallbacks) |
29
+ | `region` | `string` | No | AWS region. Defaults to AWS SDK default |
30
+ | `resilience` | `ResilienceConfig` | No | Retry, backoff, and timeout settings. Uses defaults if omitted |
31
+
32
+ ## Behaviour
33
+
34
+ - Uses **tool-based JSON extraction** (`structuredResponse` tool) for reliable structured output
35
+ - **Streaming** yields text deltas in real-time, then emits a validated tool-call result at the end
36
+ - **Merges sequential same-role messages** to satisfy Bedrock's alternating-role requirement
37
+ - **Prepends an initial user message** (`"Hi"`) so the conversation always starts with a user turn
38
+
39
+ ## Prerequisites
40
+
41
+ AWS credentials configured via environment variables, IAM role, or AWS profile — the same setup the AWS SDK expects.
42
+
43
+ ## Documentation
44
+
45
+ See the [Providers documentation](https://github.com/generalui/a3/blob/main/docs/PROVIDERS.md) for model fallback, per-agent overrides, the provider interface, and more.
@@ -0,0 +1,47 @@
1
+ # @genui/a3-openai
2
+
3
+ OpenAI provider for the [A3 agentic framework](https://www.npmjs.com/package/@genui/a3).
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ npm install @genui/a3-openai @genui/a3
9
+ ```
10
+
11
+ ## Quick Start
12
+
13
+ ```typescript
14
+ import { createOpenAIProvider } from '@genui/a3-openai'
15
+
16
+ const provider = createOpenAIProvider({
17
+ models: ['gpt-4o', 'gpt-4o-mini'],
18
+ apiKey: process.env.OPENAI_API_KEY, // optional, defaults to OPENAI_API_KEY env var
19
+ })
20
+ ```
21
+
22
+ ## Configuration
23
+
24
+ `createOpenAIProvider(config)` communicates with the OpenAI Chat Completions API using [structured output](https://platform.openai.com/docs/guides/structured-outputs) (`response_format: json_schema`).
25
+
26
+ | Option | Type | Required | Description |
27
+ |---|---|---|---|
28
+ | `models` | `string[]` | Yes | Model IDs in preference order (first = primary, rest = fallbacks) |
29
+ | `apiKey` | `string` | No | API key. Defaults to `OPENAI_API_KEY` env var |
30
+ | `baseURL` | `string` | No | Custom base URL for Azure OpenAI or compatible endpoints |
31
+ | `organization` | `string` | No | OpenAI organization ID |
32
+ | `resilience` | `ResilienceConfig` | No | Retry, backoff, and timeout settings. Uses defaults if omitted |
33
+
34
+ ## Behaviour
35
+
36
+ - Uses **structured output** (`response_format` with `json_schema`) — no tool calls required
37
+ - **Enforces strict schemas** automatically (`additionalProperties: false`, all properties `required`)
38
+ - **Streaming** extracts `chatbotMessage` text progressively from the JSON response via a character-level state machine, yielding text deltas in real-time
39
+ - Detects **truncated responses** (`finish_reason: length`) and surfaces them as errors
40
+
41
+ ## Prerequisites
42
+
43
+ An OpenAI API key, either passed directly or set as `OPENAI_API_KEY`.
44
+
45
+ ## Documentation
46
+
47
+ See the [Providers documentation](https://github.com/generalui/a3/blob/main/docs/PROVIDERS.md) for model fallback, per-agent overrides, the provider interface, and more.
@@ -0,0 +1,124 @@
1
+ # Providers
2
+
3
+ LLM provider implementations for the A3 agentic framework.
4
+
5
+ A provider is a thin adapter that connects A3 to an LLM API.
6
+ Its job is to convert A3's provider-agnostic request format into the LLM's API format, send the request, and convert the response back into A3's expected format (JSON string for blocking, AG-UI events for streaming).
7
+
8
+ A3 ships with **AWS Bedrock**, **Anthropic**, and **OpenAI** providers out of the box.
9
+ All three support blocking and streaming modes, model fallback, and structured output via Zod schemas.
10
+
11
+ For information on specific providers, please see their documentation:
12
+
13
+ - [AWS Bedrock (`@genui/a3-bedrock`)](https://www.npmjs.com/package/@genui/a3-bedrock)
14
+ - [Anthropic (`@genui/a3-anthropic`)](https://www.npmjs.com/package/@genui/a3-anthropic)
15
+ - [OpenAI (`@genui/a3-openai`)](https://www.npmjs.com/package/@genui/a3-openai)
16
+
17
+ To connect A3 to an LLM that isn't covered by the built-in providers, see [Creating a Custom Provider](./CUSTOM_PROVIDERS.md).
18
+
19
+ ## Use with A3
20
+
21
+ ```typescript
22
+ import { ChatSession, MemorySessionStore } from '@genui/a3'
23
+
24
+ const session = new ChatSession({
25
+ sessionId: 'user-123',
26
+ store: new MemorySessionStore(),
27
+ initialAgentId: 'greeting',
28
+ initialState: {},
29
+ provider, // any provider from above
30
+ })
31
+
32
+ // Blocking
33
+ const response = await session.send({ message: 'Hello!' })
34
+
35
+ // Streaming
36
+ for await (const event of session.send({ message: 'Hello!', stream: true })) {
37
+ console.log(event)
38
+ }
39
+ ```
40
+
41
+ ## Model Fallback
42
+
43
+ All providers support automatic model fallback.
44
+ List models in order of preference:
45
+
46
+ ```typescript
47
+ const provider = createBedrockProvider({
48
+ models: [
49
+ 'us.anthropic.claude-sonnet-4-5-20250929-v1:0', // primary
50
+ 'us.anthropic.claude-haiku-4-5-20251001-v1:0', // fallback
51
+ ],
52
+ })
53
+ ```
54
+
55
+ If the primary model fails, the provider automatically retries with the next model in the list.
56
+ If all models fail, the last error is thrown.
57
+
58
+ All providers include built-in resilience: automatic retries with exponential backoff, per-request and total timeouts, and model fallback.
59
+ See the [Resilience documentation](./RESILIENCE.md) for configuration options and defaults.
60
+
61
+ ## Per-Agent Provider Override
62
+
63
+ Each agent can override the session-level provider:
64
+
65
+ ```typescript
66
+ import { createOpenAIProvider } from '@genui/a3-openai'
67
+ import { createBedrockProvider } from '@genui/a3-bedrock'
68
+
69
+ // Session uses Bedrock by default
70
+ const session = new ChatSession({
71
+ provider: createBedrockProvider({ models: ['us.anthropic.claude-sonnet-4-5-20250929-v1:0'] }),
72
+ // ...
73
+ })
74
+
75
+ // This agent uses OpenAI instead
76
+ const premiumAgent = {
77
+ id: 'premium',
78
+ description: 'Handles premium tier requests using GPT-4o',
79
+ provider: createOpenAIProvider({ models: ['gpt-4o'] }),
80
+ // ...
81
+ }
82
+ ```
83
+
84
+ ## Provider Interface
85
+
86
+ All providers implement the `Provider` interface from `@genui/a3`:
87
+
88
+ | Member | Description |
89
+ |---|---|
90
+ | `sendRequest(request)` | Blocking request → `Promise<ProviderResponse>` |
91
+ | `sendRequestStream(request)` | Streaming request → `AsyncGenerator<StreamEvent>` |
92
+ | `name` | Human-readable name (`'bedrock'`, `'anthropic'`, or `'openai'`) |
93
+
94
+ To create a custom provider, implement this interface and pass it to `ChatSession` or an individual agent.
95
+ See [Creating a Custom Provider](./CUSTOM_PROVIDERS.md) for a step-by-step guide.
96
+
97
+ ## Packages
98
+
99
+ Each provider is a separate npm package.
100
+ Install the one(s) you need:
101
+
102
+ ```bash
103
+ npm install @genui/a3-bedrock @genui/a3
104
+ npm install @genui/a3-openai @genui/a3
105
+ npm install @genui/a3-anthropic @genui/a3
106
+ ```
107
+
108
+ | Package | Export | Description |
109
+ |---|---|---|
110
+ | `@genui/a3-bedrock` | `createBedrockProvider` | Factory function returning a Bedrock `Provider` |
111
+ | `@genui/a3-bedrock` | `BedrockProviderConfig` | TypeScript config interface |
112
+ | `@genui/a3-anthropic` | `createAnthropicProvider` | Factory function returning an Anthropic `Provider` |
113
+ | `@genui/a3-anthropic` | `AnthropicProviderConfig` | TypeScript config interface |
114
+ | `@genui/a3-openai` | `createOpenAIProvider` | Factory function returning an OpenAI `Provider` |
115
+ | `@genui/a3-openai` | `OpenAIProviderConfig` | TypeScript config interface |
116
+
117
+ ## Requirements
118
+
119
+ - Node.js 20.19.0+
120
+ - TypeScript 5.9+
121
+ - `@genui/a3` (peer dependency)
122
+ - **Bedrock**: AWS credentials configured in the environment
123
+ - **Anthropic**: `ANTHROPIC_API_KEY` environment variable or `apiKey` config option
124
+ - **OpenAI**: `OPENAI_API_KEY` environment variable or `apiKey` config option
@@ -0,0 +1,197 @@
1
+ # Quick Start
2
+
3
+ The fastest way to get started with A3 is using the interactive CLI. It scaffolds a full Next.js application, configures your LLM providers, and installs dependencies.
4
+
5
+ ```bash
6
+ npx @genui/a3-create@latest
7
+ ```
8
+
9
+ Follow the prompts to name your project and provide your API keys. Once finished:
10
+
11
+ ```bash
12
+ cd your-project-name
13
+ npm run dev
14
+ ```
15
+
16
+ For more details on the CLI, see the [@genui/a3-create README](https://www.npmjs.com/package/@genui/a3-create).
17
+
18
+ ---
19
+
20
+ ## Manual Installation
21
+
22
+ If you are adding A3 to an existing project or prefer a manual setup, follow these steps.
23
+
24
+ ### Install
25
+
26
+ ```bash
27
+ npm install @genui/a3
28
+ ```
29
+
30
+ ## Define an agent
31
+
32
+ ```typescript
33
+ import { z } from 'zod'
34
+ import { Agent, BaseState } from '@genui/a3'
35
+
36
+ interface State extends BaseState {
37
+ userName?: string
38
+ }
39
+
40
+ export const greetingAgent: Agent<State> = {
41
+ id: 'greeting',
42
+ name: 'Greeting Agent',
43
+ description: 'Greets the user and collects their name',
44
+ prompt: async () => `
45
+ You are a friendly greeting agent. Your goal is to greet the user
46
+ and learn their name. Once you have their name, set goalAchieved to true.
47
+ `,
48
+ outputSchema: z.object({
49
+ userName: z.string().optional(),
50
+ }),
51
+ // `transition` is optional. When omitted, the agent stays active by default
52
+ }
53
+ ```
54
+
55
+ ## Register and run
56
+
57
+ ```typescript
58
+ import { AgentRegistry, ChatSession, MemorySessionStore } from '@genui/a3'
59
+ import { createBedrockProvider } from '@genui/a3-bedrock'
60
+
61
+ const registry = AgentRegistry.getInstance<State>()
62
+ registry.register(greetingAgent)
63
+
64
+ const provider = createBedrockProvider({
65
+ models: ['us.anthropic.claude-sonnet-4-5-20250929-v1:0'],
66
+ })
67
+
68
+ const session = new ChatSession<State>({
69
+ sessionId: 'demo',
70
+ store: new MemorySessionStore(),
71
+ initialAgentId: 'greeting',
72
+ initialState: { userName: undefined },
73
+ provider,
74
+ })
75
+
76
+ const response = await session.send({ message: 'Hi there!' })
77
+ console.log(response.responseMessage)
78
+ // => "Hello! I'd love to get to know you. What's your name?"
79
+ ```
80
+
81
+ That's it.
82
+ One agent, one session, one function call.
83
+
84
+ ## Multi-Agent Example
85
+
86
+ Here's a pattern with three agents that route between each other, demonstrating how state flows across agent boundaries.
87
+
88
+ ### Define the agents
89
+
90
+ ```typescript
91
+ import { z } from 'zod'
92
+ import { Agent, BaseState } from '@genui/a3'
93
+
94
+ interface AppState extends BaseState {
95
+ userName?: string
96
+ isAuthenticated: boolean
97
+ issueCategory?: string
98
+ }
99
+
100
+ // Agent 1: Greeting -- collects the user's name, then routes to auth
101
+ const greetingAgent: Agent<AppState> = {
102
+ id: 'greeting',
103
+ name: 'Greeting Agent',
104
+ description: 'Greets the user and collects their name',
105
+ prompt: async () => `
106
+ Greet the user warmly. Ask for their name.
107
+ Once you have it, set goalAchieved to true.
108
+ `,
109
+ outputSchema: z.object({ userName: z.string().optional() }),
110
+ transition: (_state, goalAchieved) =>
111
+ goalAchieved ? 'auth' : 'greeting',
112
+ }
113
+
114
+ // Agent 2: Auth -- verifies identity, then routes to support
115
+ const authAgent: Agent<AppState> = {
116
+ id: 'auth',
117
+ name: 'Auth Agent',
118
+ description: 'Verifies user identity',
119
+ prompt: async ({ sessionData }) => `
120
+ The user's name is ${sessionData.state.userName}.
121
+ Ask them to confirm their email to verify identity.
122
+ Set goalAchieved to true once verified.
123
+ `,
124
+ outputSchema: z.object({ isAuthenticated: z.boolean() }),
125
+ transition: (_state, goalAchieved) =>
126
+ goalAchieved ? 'support' : 'auth',
127
+ }
128
+
129
+ // Agent 3: Support -- handles the user's issue
130
+ const supportAgent: Agent<AppState> = {
131
+ id: 'support',
132
+ name: 'Support Agent',
133
+ description: 'Helps resolve user issues',
134
+ prompt: async ({ sessionData }) => `
135
+ The user ${sessionData.state.userName} is authenticated.
136
+ Help them with their issue. Categorize it.
137
+ Set goalAchieved when resolved.
138
+ `,
139
+ outputSchema: z.object({
140
+ issueCategory: z.string().optional(),
141
+ }),
142
+ // `transition` is optional. If omitted, the flow of the interaction will stay in this agent.
143
+ }
144
+ ```
145
+
146
+ ### Wire them up
147
+
148
+ ```typescript
149
+ import { AgentRegistry, ChatSession, MemorySessionStore } from '@genui/a3'
150
+ import { createBedrockProvider } from '@genui/a3-bedrock'
151
+
152
+ const registry = AgentRegistry.getInstance<AppState>()
153
+ registry.register([greetingAgent, authAgent, supportAgent])
154
+
155
+ const provider = createBedrockProvider({
156
+ models: ['us.anthropic.claude-sonnet-4-5-20250929-v1:0'],
157
+ })
158
+
159
+ const session = new ChatSession<AppState>({
160
+ sessionId: 'user-456',
161
+ store: new MemorySessionStore(),
162
+ initialAgentId: 'greeting',
163
+ initialState: { isAuthenticated: false },
164
+ provider,
165
+ })
166
+ ```
167
+
168
+ ### Conversation flow
169
+
170
+ ```typescript
171
+ // Turn 1: User greets, greeting agent responds
172
+ await session.send({ message: 'Hello!' })
173
+ // => Greeting agent asks for name
174
+
175
+ // Turn 2: User provides name, greeting agent completes and chains to auth
176
+ await session.send({ message: "I'm Alex" })
177
+ // => Auth agent asks for email verification
178
+ // (greeting → auth happened automatically in one request)
179
+
180
+ // Turn 3: User verifies, auth completes and chains to support
181
+ await session.send({ message: 'alex@example.com' })
182
+ // => Support agent asks how it can help
183
+ // State now: { userName: 'Alex', isAuthenticated: true }
184
+
185
+ // Turn 4: Support agent handles the issue
186
+ await session.send({ message: 'I need help with my billing' })
187
+ // => Support agent resolves the issue
188
+ // State: { userName: 'Alex', isAuthenticated: true, issueCategory: 'billing' }
189
+ ```
190
+
191
+ Notice that:
192
+
193
+ - **State persists across agents**: `userName` set by the greeting agent is available to auth and support
194
+ - **Agent chaining is automatic**: when greeting completes, auth starts in the same request
195
+ - **Each agent has its own prompt and schema**: they extract different data but share the same state
196
+
197
+ For non-deterministic routing (LLM-driven agent selection), see [Transitions](./TRANSITIONS.md#non-deterministic-agentid).