@aws-blocks/bb-agent 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (75) hide show
  1. package/LICENSE +174 -0
  2. package/README.md +801 -0
  3. package/dist/agent.aws.d.ts +7 -0
  4. package/dist/agent.aws.d.ts.map +1 -0
  5. package/dist/agent.aws.js +9 -0
  6. package/dist/agent.d.ts +121 -0
  7. package/dist/agent.d.ts.map +1 -0
  8. package/dist/agent.js +588 -0
  9. package/dist/agent.mock.d.ts +7 -0
  10. package/dist/agent.mock.d.ts.map +1 -0
  11. package/dist/agent.mock.js +12 -0
  12. package/dist/errors.d.ts +39 -0
  13. package/dist/errors.d.ts.map +1 -0
  14. package/dist/errors.js +40 -0
  15. package/dist/file-bucket-snapshot-storage.d.ts +49 -0
  16. package/dist/file-bucket-snapshot-storage.d.ts.map +1 -0
  17. package/dist/file-bucket-snapshot-storage.js +84 -0
  18. package/dist/index.aws.d.ts +5 -0
  19. package/dist/index.aws.d.ts.map +1 -0
  20. package/dist/index.aws.js +5 -0
  21. package/dist/index.browser.d.ts +4 -0
  22. package/dist/index.browser.d.ts.map +1 -0
  23. package/dist/index.browser.js +8 -0
  24. package/dist/index.cdk.d.ts +15 -0
  25. package/dist/index.cdk.d.ts.map +1 -0
  26. package/dist/index.cdk.js +60 -0
  27. package/dist/index.hooks.d.ts +122 -0
  28. package/dist/index.hooks.d.ts.map +1 -0
  29. package/dist/index.hooks.js +179 -0
  30. package/dist/index.mock.d.ts +5 -0
  31. package/dist/index.mock.d.ts.map +1 -0
  32. package/dist/index.mock.js +5 -0
  33. package/dist/index.test.d.ts +2 -0
  34. package/dist/index.test.d.ts.map +1 -0
  35. package/dist/index.test.js +864 -0
  36. package/dist/model-factory.d.ts +26 -0
  37. package/dist/model-factory.d.ts.map +1 -0
  38. package/dist/model-factory.js +197 -0
  39. package/dist/models.d.ts +83 -0
  40. package/dist/models.d.ts.map +1 -0
  41. package/dist/models.js +84 -0
  42. package/dist/providers/canned.d.ts +32 -0
  43. package/dist/providers/canned.d.ts.map +1 -0
  44. package/dist/providers/canned.js +187 -0
  45. package/dist/providers/throwing.d.ts +10 -0
  46. package/dist/providers/throwing.d.ts.map +1 -0
  47. package/dist/providers/throwing.js +16 -0
  48. package/dist/schemas.d.ts +59 -0
  49. package/dist/schemas.d.ts.map +1 -0
  50. package/dist/schemas.js +36 -0
  51. package/dist/types.d.ts +295 -0
  52. package/dist/types.d.ts.map +1 -0
  53. package/dist/types.js +3 -0
  54. package/dist/version.d.ts +3 -0
  55. package/dist/version.d.ts.map +1 -0
  56. package/dist/version.js +3 -0
  57. package/package.json +59 -0
  58. package/src/agent.aws.ts +13 -0
  59. package/src/agent.mock.ts +16 -0
  60. package/src/agent.ts +604 -0
  61. package/src/errors.ts +44 -0
  62. package/src/file-bucket-snapshot-storage.ts +85 -0
  63. package/src/index.aws.ts +7 -0
  64. package/src/index.browser.ts +10 -0
  65. package/src/index.cdk.ts +70 -0
  66. package/src/index.hooks.ts +256 -0
  67. package/src/index.mock.ts +7 -0
  68. package/src/index.test.ts +1010 -0
  69. package/src/model-factory.ts +228 -0
  70. package/src/models.ts +88 -0
  71. package/src/providers/canned.ts +205 -0
  72. package/src/providers/throwing.ts +19 -0
  73. package/src/schemas.ts +40 -0
  74. package/src/types.ts +311 -0
  75. package/src/version.ts +3 -0
@@ -0,0 +1,85 @@
1
+ // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2
+ // SPDX-License-Identifier: Apache-2.0
3
+
4
+ import type { SnapshotStorage, SnapshotLocation, Snapshot, SnapshotManifest } from '@strands-agents/sdk';
5
+ import type { FileBucket } from '@aws-blocks/bb-file-bucket';
6
+
7
+ /**
8
+ * SnapshotStorage backed by FileBucket BB.
9
+ * Used locally — on AWS, Strands' native S3Storage talks to the same bucket directly.
10
+ *
11
+ * Mirrors the Strands S3Storage implementation exactly so that local and AWS
12
+ * produce identical key layouts. If S3Storage changes, update this to match.
13
+ *
14
+ * Key layout (same as S3Storage):
15
+ * <sessionId>/scopes/<scope>/<scopeId>/snapshots/snapshot_latest.json
16
+ * <sessionId>/scopes/<scope>/<scopeId>/snapshots/immutable_history/snapshot_<uuid>.json
17
+ * <sessionId>/scopes/<scope>/<scopeId>/snapshots/manifest.json
18
+ *
19
+ * @see https://strandsagents.com/docs/user-guide/concepts/agents/session-management/#s3sessionmanager--s3storage
20
+ * @see https://strandsagents.com/docs/user-guide/concepts/agents/session-management
21
+ */
22
+ export class FileBucketSnapshotStorage implements SnapshotStorage {
23
+ constructor(private bucket: FileBucket) {}
24
+
25
+ /** Base path for a scope's snapshots folder. */
26
+ private basePath(location: SnapshotLocation): string {
27
+ return `${location.sessionId}/scopes/${location.scope}/${location.scopeId}/snapshots`;
28
+ }
29
+
30
+ async saveSnapshot(params: { location: SnapshotLocation; snapshotId: string; isLatest: boolean; snapshot: Snapshot }): Promise<void> {
31
+ const data = JSON.stringify(params.snapshot, null, 2);
32
+ if (params.isLatest) {
33
+ // Overwrite the mutable latest snapshot
34
+ await this.bucket.put(`${this.basePath(params.location)}/snapshot_latest.json`, data);
35
+ } else {
36
+ // Append-only immutable checkpoint
37
+ await this.bucket.put(`${this.basePath(params.location)}/immutable_history/snapshot_${params.snapshotId}.json`, data);
38
+ }
39
+ }
40
+
41
+ async loadSnapshot(params: { location: SnapshotLocation; snapshotId?: string }): Promise<Snapshot | null> {
42
+ const path = params.snapshotId
43
+ ? `${this.basePath(params.location)}/immutable_history/snapshot_${params.snapshotId}.json`
44
+ : `${this.basePath(params.location)}/snapshot_latest.json`;
45
+ const file = await this.bucket.get(path);
46
+ if (!file) return null;
47
+ return JSON.parse(file.body.toString());
48
+ }
49
+
50
+ async listSnapshotIds(params: { location: SnapshotLocation; limit?: number; startAfter?: string }): Promise<string[]> {
51
+ const prefix = `${this.basePath(params.location)}/immutable_history/`;
52
+ const ids: string[] = [];
53
+ let pastCursor = !params.startAfter;
54
+ for await (const file of this.bucket.scan({ prefix })) {
55
+ const match = file.path.match(/snapshot_([\w-]+)\.json$/);
56
+ if (!match) continue;
57
+ const id = match[1];
58
+ if (!pastCursor) {
59
+ if (id === params.startAfter) pastCursor = true;
60
+ continue;
61
+ }
62
+ ids.push(id);
63
+ if (params.limit && ids.length >= params.limit) break;
64
+ }
65
+ return ids;
66
+ }
67
+
68
+ async deleteSession(params: { sessionId: string }): Promise<void> {
69
+ const paths: string[] = [];
70
+ for await (const file of this.bucket.scan({ prefix: `${params.sessionId}/` })) {
71
+ paths.push(file.path);
72
+ }
73
+ if (paths.length > 0) await this.bucket.deleteBatch(paths);
74
+ }
75
+
76
+ async loadManifest(params: { location: SnapshotLocation }): Promise<SnapshotManifest> {
77
+ const file = await this.bucket.get(`${this.basePath(params.location)}/manifest.json`);
78
+ if (!file) return { schemaVersion: '1.0', updatedAt: new Date().toISOString() };
79
+ return JSON.parse(file.body.toString());
80
+ }
81
+
82
+ async saveManifest(params: { location: SnapshotLocation; manifest: SnapshotManifest }): Promise<void> {
83
+ await this.bucket.put(`${this.basePath(params.location)}/manifest.json`, JSON.stringify(params.manifest, null, 2));
84
+ }
85
+ }
@@ -0,0 +1,7 @@
1
+ // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2
+ // SPDX-License-Identifier: Apache-2.0
3
+
4
+ export { Agent } from './agent.aws.js';
5
+ export { AgentErrors, InterruptError } from './errors.js';
6
+ export { BedrockModels, OllamaModels } from './models.js';
7
+ export type { AgentConfig, AgentResult, AgentStreamChunk, AgentStreamResult, ToolDefinition, AgentTool, ToolFactory, ToolsConfig, ToolHandlerArgs, DefaultToolContext, InterruptResponse, ToolCallRecord, ModelConfig, StreamOptions, Message, Conversation, JSONValue, TokenUsage } from './types.js';
@@ -0,0 +1,10 @@
1
+ // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2
+ // SPDX-License-Identifier: Apache-2.0
3
+
4
+ import { AgentErrors, blocksAgentError } from './errors.js';
5
+
6
+ export class Agent {
7
+ constructor(..._args: any[]) {
8
+ throw blocksAgentError(AgentErrors.BrowserNotSupported, 'Agent can only be instantiated on the server.');
9
+ }
10
+ }
@@ -0,0 +1,70 @@
1
+ // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2
+ // SPDX-License-Identifier: Apache-2.0
3
+
4
+ import { PolicyStatement } from 'aws-cdk-lib/aws-iam';
5
+ import { Scope } from '@aws-blocks/core/cdk';
6
+ import type { ScopeParent } from '@aws-blocks/core';
7
+ import { DistributedTable } from '@aws-blocks/bb-distributed-table';
8
+ import { Realtime } from '@aws-blocks/bb-realtime';
9
+ import { AsyncJob } from '@aws-blocks/bb-async-job';
10
+ import { FileBucket } from '@aws-blocks/bb-file-bucket';
11
+ import { messageSchema, conversationSchema, agentStreamChunkSchema } from './schemas.js';
12
+ import { z } from 'zod';
13
+
14
+ export { AgentErrors } from './errors.js';
15
+ export { BedrockModels, OllamaModels } from './models.js';
16
+
17
+ const jobPayloadSchema = z.object({
18
+ message: z.string(),
19
+ conversationId: z.string().optional(),
20
+ });
21
+
22
+ export class Agent extends Scope {
23
+ /**
24
+ * CDK layer for the Agent BB.
25
+ * Mirrors the runtime's BB creation so CDK discovers and provisions all resources.
26
+ *
27
+ * TODO: scope Bedrock IAM grant to specific modelId from config
28
+ * TODO: guardrails CDK provisioning
29
+ */
30
+ constructor(scope: ScopeParent, id: string, config?: any) {
31
+ super(id, { parent: scope });
32
+
33
+ this.handler.addToRolePolicy(new PolicyStatement({
34
+ actions: ['bedrock:InvokeModel', 'bedrock:InvokeModelWithResponseStream', 'bedrock:GetFoundationModel', 'bedrock:ListFoundationModels', 'bedrock:GetInferenceProfile'],
35
+ resources: [
36
+ 'arn:aws:bedrock:*::foundation-model/*',
37
+ 'arn:aws:bedrock:*:*:inference-profile/*',
38
+ ],
39
+ }));
40
+
41
+ // Propagate `removalPolicy` to the sessions bucket so customers can
42
+ // opt sandbox stacks into clean teardown. Without it, CDK's RETAIN
43
+ // default applies (production-safe) and `cdk destroy` will fail on
44
+ // a non-empty bucket — same pattern as FileBucket / KnowledgeBase.
45
+ // ID shortened to keep S3 bucket names within the 63-char limit
46
+ new FileBucket(this, 'sn', { removalPolicy: config?.removalPolicy });
47
+
48
+ if (!config?.inferenceOnly) {
49
+ new DistributedTable(this, 'convos', {
50
+ schema: conversationSchema,
51
+ key: { partitionKey: 'userId', sortKey: 'conversationId' },
52
+ });
53
+ new DistributedTable(this, 'messages', {
54
+ schema: messageSchema,
55
+ key: { partitionKey: 'conversationId', sortKey: 'messageId' },
56
+ });
57
+ }
58
+
59
+ new Realtime(this, 'rt', {
60
+ namespaces: {
61
+ chunks: { schema: agentStreamChunkSchema },
62
+ },
63
+ });
64
+
65
+ new AsyncJob(this, 'job', {
66
+ schema: jobPayloadSchema,
67
+ handler: async () => {},
68
+ });
69
+ }
70
+ }
@@ -0,0 +1,256 @@
1
+ // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2
+ // SPDX-License-Identifier: Apache-2.0
3
+
4
+ /**
5
+ * Client hooks for Agent BB.
6
+ *
7
+ * useChat() provides state management for agent conversations.
8
+ * Works with any framework — not React-specific (no JSX, no React imports).
9
+ *
10
+ * Flow:
11
+ * 1. Subscribe to Realtime channel + await established
12
+ * 2. Load existing history from DB
13
+ * 3. Show history — any in-flight chunks are caught by the subscription
14
+ * 4. User sends message — chunks arrive via the already-open subscription
15
+ */
16
+
17
+ import type { AgentStreamChunk } from './types.js';
18
+
19
+ export type { AgentStreamChunk } from './types.js';
20
+
21
+ /** A message in the conversation (for UI rendering). */
22
+ export interface ChatMessage {
23
+ id: string;
24
+ role: 'user' | 'assistant' | 'approval';
25
+ content: string;
26
+ metadata?: Record<string, any>;
27
+ }
28
+
29
+ /** Options for creating a chat instance. */
30
+ export interface UseChatOptions {
31
+ api: {
32
+ sendMessage(conversationId: string, message: string, channelId: string): Promise<void>;
33
+ createConversation(): Promise<{ conversationId: string }>;
34
+ getConversation(id: string): Promise<{ messages: { role: string; content: string; metadata?: Record<string, any> }[] }>;
35
+ resume?(channelId: string, responses: Array<{ interruptId: string; approved: boolean; trust?: boolean; toolName?: string; input?: any }>, conversationId?: string): Promise<void>;
36
+ getPendingInterrupts?(conversationId: string): Promise<{ interrupts: Array<{ id: string; name: string; reason?: any }> }>;
37
+ };
38
+ /**
39
+ * Subscribe to a Realtime channel. Must return an object with:
40
+ * - unsubscribe(): stop receiving messages
41
+ * - established: Promise that resolves when the WS subscription is confirmed
42
+ */
43
+ subscribe: (channelId: string, handler: (chunk: AgentStreamChunk) => void) => Promise<{ unsubscribe(): void; established: Promise<void> }>;
44
+ /** Called whenever the message list changes. */
45
+ onMessagesChange?: (messages: ChatMessage[]) => void;
46
+ /** Called whenever loading state changes. */
47
+ onLoadingChange?: (isLoading: boolean) => void;
48
+ /** Called on each streaming chunk. */
49
+ onChunk?: (chunk: AgentStreamChunk) => void;
50
+ /** Called when the agent encounters an error. */
51
+ onError?: (error: string) => void;
52
+ /** Called when the agent needs human approval before continuing. */
53
+ onInterrupt?: (interrupts: Array<{ id: string; name: string; reason?: any }>) => void;
54
+ }
55
+
56
+ /** Returned by useChat(). */
57
+ export interface ChatInstance {
58
+ /** Send a message. Creates a conversation and subscribes if needed. */
59
+ sendMessage(text: string): Promise<void>;
60
+ /** Respond to an interrupt (tool approval). Resumes the agent. */
61
+ respondToInterrupt(responses: Array<{ interruptId: string; approved: boolean; trust?: boolean; toolName?: string; input?: any }>): Promise<void>;
62
+ /** Current messages. */
63
+ getMessages(): ChatMessage[];
64
+ /** Whether the agent is currently responding. */
65
+ isLoading(): boolean;
66
+ /** Current conversation ID (null until first message). */
67
+ getConversationId(): string | null;
68
+ /** Open a conversation: subscribe to Realtime, then load history. */
69
+ loadConversation(conversationId: string): Promise<void>;
70
+ /** Clean up the active subscription. */
71
+ destroy(): void;
72
+ }
73
+
74
+ let messageCounter = 0;
75
+ function nextId(): string {
76
+ return `msg-${++messageCounter}-${Date.now()}`;
77
+ }
78
+
79
+ /**
80
+ * Create a chat instance for managing agent conversations.
81
+ *
82
+ * @example
83
+ * ```typescript
84
+ * const chat = useChat({
85
+ * api: {
86
+ * sendMessage: (convId, msg, chId) => api.agentStream(msg, convId, chId),
87
+ * createConversation: () => api.agentCreateConversationId(),
88
+ * getConversation: (id) => api.agentGetConversation(id),
89
+ * },
90
+ * subscribe: async (channelId, handler) => {
91
+ * const result = await api.agentGetChannel(channelId);
92
+ * return result.channel.subscribe(handler);
93
+ * },
94
+ * onMessagesChange: (msgs) => renderMessages(msgs),
95
+ * onLoadingChange: (loading) => updateSpinner(loading),
96
+ * });
97
+ *
98
+ * await chat.loadConversation('conv-123');
99
+ * await chat.sendMessage('Hello!');
100
+ * ```
101
+ */
102
+ export function useChat(options: UseChatOptions): ChatInstance {
103
+ let messages: ChatMessage[] = [];
104
+ let loading = false;
105
+ let conversationId: string | null = null;
106
+ let activeSub: { unsubscribe(): void } | null = null;
107
+ let assistantId: string | null = null;
108
+ let assistantText = '';
109
+
110
+ /** Handle a chunk from the Realtime subscription. */
111
+ function handleChunk(chunk: AgentStreamChunk) {
112
+ options.onChunk?.(chunk);
113
+
114
+ if (chunk.type === 'text-delta' && chunk.text && assistantId) {
115
+ assistantText += chunk.text;
116
+ messages = messages.map(m => m.id === assistantId ? { ...m, content: assistantText } : m);
117
+ options.onMessagesChange?.(messages);
118
+ }
119
+
120
+ if (chunk.type === 'done') {
121
+ if (chunk.text && assistantId) {
122
+ messages = messages.map(m => m.id === assistantId ? { ...m, content: chunk.text! } : m);
123
+ options.onMessagesChange?.(messages);
124
+ }
125
+ loading = false;
126
+ options.onLoadingChange?.(loading);
127
+ }
128
+
129
+ if (chunk.type === 'error') {
130
+ loading = false;
131
+ options.onLoadingChange?.(loading);
132
+ options.onError?.(chunk.error ?? 'Unknown error');
133
+ }
134
+
135
+ if (chunk.type === 'interrupt' && chunk.interrupts) {
136
+ // Remove empty assistant placeholder (no text was generated before interrupt)
137
+ if (assistantId) {
138
+ const assistant = messages.find(m => m.id === assistantId);
139
+ if (assistant && !assistant.content) {
140
+ messages = messages.filter(m => m.id !== assistantId);
141
+ options.onMessagesChange?.(messages);
142
+ }
143
+ }
144
+ assistantId = null;
145
+ loading = false;
146
+ options.onLoadingChange?.(loading);
147
+ options.onInterrupt?.(chunk.interrupts);
148
+ }
149
+ }
150
+
151
+ /** Subscribe to a conversation's Realtime channel and wait for WS confirmation. Retries with fresh token on auth failure. */
152
+ async function ensureSubscribed(channelId: string) {
153
+ if (activeSub) { activeSub.unsubscribe(); activeSub = null; }
154
+
155
+ const sub = await options.subscribe(channelId, handleChunk);
156
+ try {
157
+ await sub.established;
158
+ } catch (err) {
159
+ console.warn('Subscription failed, retrying with fresh token:', err);
160
+ sub.unsubscribe();
161
+ const retrySub = await options.subscribe(channelId, handleChunk);
162
+ await retrySub.established;
163
+ activeSub = retrySub;
164
+ return;
165
+ }
166
+ activeSub = sub;
167
+ }
168
+
169
+ return {
170
+ async sendMessage(text: string) {
171
+ if (loading) return;
172
+ // Create conversation + subscribe on first message
173
+ if (!conversationId) {
174
+ const result = await options.api.createConversation();
175
+ conversationId = result.conversationId;
176
+ await ensureSubscribed(conversationId);
177
+ }
178
+
179
+ // Subscribe if not already (e.g., sendMessage without loadConversation)
180
+ if (!activeSub) {
181
+ await ensureSubscribed(conversationId);
182
+ }
183
+
184
+ // Add user message + assistant placeholder
185
+ const userMsg: ChatMessage = { id: nextId(), role: 'user', content: text };
186
+ const aMsg: ChatMessage = { id: nextId(), role: 'assistant', content: '' };
187
+ assistantId = aMsg.id;
188
+ assistantText = '';
189
+ messages = [...messages, userMsg, aMsg];
190
+ options.onMessagesChange?.(messages);
191
+ loading = true;
192
+ options.onLoadingChange?.(loading);
193
+
194
+ // Submit — chunks arrive via the already-open subscription
195
+ await options.api.sendMessage(conversationId, text, conversationId);
196
+ },
197
+
198
+ async respondToInterrupt(responses: Array<{ interruptId: string; approved: boolean; trust?: boolean; toolName?: string; input?: any }>) {
199
+ if (loading) return;
200
+ if (!conversationId) throw new Error('No active conversation');
201
+ // Add approval messages to chat immediately
202
+ for (const r of responses) {
203
+ messages = [...messages, { id: nextId(), role: 'approval' as const, content: r.approved ? 'Approved' : 'Denied', metadata: { approved: r.approved, trust: r.trust, toolName: r.toolName, input: r.input } }];
204
+ }
205
+ // Reuse existing empty assistant placeholder or create one
206
+ const existingEmpty = messages.find(m => m.role === 'assistant' && !m.content);
207
+ if (existingEmpty) {
208
+ assistantId = existingEmpty.id;
209
+ } else {
210
+ const aMsg: ChatMessage = { id: nextId(), role: 'assistant', content: '' };
211
+ assistantId = aMsg.id;
212
+ messages = [...messages, aMsg];
213
+ }
214
+ assistantText = '';
215
+ options.onMessagesChange?.(messages);
216
+ loading = true;
217
+ options.onLoadingChange?.(loading);
218
+ if (!options.api.resume) throw new Error('respondToInterrupt requires api.resume to be configured');
219
+ await options.api.resume(conversationId, responses, conversationId);
220
+ },
221
+
222
+ getMessages() { return messages; },
223
+ isLoading() { return loading; },
224
+ getConversationId() { return conversationId; },
225
+
226
+ async loadConversation(id: string) {
227
+ conversationId = id;
228
+
229
+ // 1. Subscribe FIRST — catch any in-flight chunks
230
+ await ensureSubscribed(id);
231
+
232
+ // 2. THEN load history from DB
233
+ // TODO: buffer chunks received between subscribe and history load, then deduplicate/merge
234
+ const { messages: history } = await options.api.getConversation(id);
235
+ messages = history
236
+ .filter(m => m.role === 'user' || m.role === 'assistant' || m.role === 'approval')
237
+ .map(m => ({
238
+ id: nextId(),
239
+ role: m.role as 'user' | 'assistant' | 'approval',
240
+ content: m.content,
241
+ metadata: m.metadata,
242
+ }));
243
+ options.onMessagesChange?.(messages);
244
+
245
+ // Check for pending interrupts (e.g., user left mid-approval)
246
+ if (options.api.getPendingInterrupts) {
247
+ const { interrupts } = await options.api.getPendingInterrupts(id);
248
+ if (interrupts.length) options.onInterrupt?.(interrupts);
249
+ }
250
+ },
251
+
252
+ destroy() {
253
+ if (activeSub) { activeSub.unsubscribe(); activeSub = null; }
254
+ },
255
+ };
256
+ }
@@ -0,0 +1,7 @@
1
+ // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2
+ // SPDX-License-Identifier: Apache-2.0
3
+
4
+ export { Agent } from './agent.mock.js';
5
+ export { AgentErrors, InterruptError } from './errors.js';
6
+ export { BedrockModels, OllamaModels } from './models.js';
7
+ export type { AgentConfig, AgentResult, AgentStreamChunk, AgentStreamResult, ToolDefinition, AgentTool, ToolFactory, ToolsConfig, ToolHandlerArgs, DefaultToolContext, InterruptResponse, ToolCallRecord, ModelConfig, StreamOptions, Message, Conversation, JSONValue, TokenUsage } from './types.js';