@aws-blocks/bb-agent 0.1.2 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/DESIGN.md ADDED
@@ -0,0 +1,66 @@
1
+ # Agent — Design
2
+
3
+ Design document for the Agent Building Block. For usage, see [README.md](./README.md).
4
+
5
+ **Package:** `@aws-blocks/bb-agent`
6
+ **Type:** Composite (uses DistributedTable, Realtime, AsyncJob, FileBucket internally)
7
+ **AWS Services:** Bedrock, DynamoDB, S3, SQS, AppSync Events
8
+ **Agent Framework:** [Strands Agents SDK](https://strandsagents.com/)
9
+
10
+ ## Architecture
11
+
12
+ The Agent BB is a composite Building Block — it creates and manages 4 internal BBs:
13
+
14
+ | Internal BB | Purpose | Created when |
15
+ |-------------|---------|-------------|
16
+ | **FileBucket** | Session persistence (Strands SessionManager) | Always |
17
+ | **DistributedTable** | Frontend message history | `inferenceOnly: false` |
18
+ | **Realtime** | Streaming chunks to caller | Always |
19
+ | **AsyncJob** | Async agent execution (avoids 29s API Gateway timeout) | Always |
20
+
21
+ ```
22
+ stream() → AsyncJob.submit() → returns { channelId } immediately
23
+
24
+ AsyncJob consumer
25
+
26
+ runAgent() → Strands agent loop → publishes chunks to Realtime
27
+ → persists messages to DistributedTable
28
+ → SessionManager saves state to FileBucket
29
+ ```
30
+
31
+ ## Session Persistence
32
+
33
+ Two storage backends, same FileBucket BB:
34
+ - **AWS:** Strands' native `S3Storage` → FileBucket-provisioned S3 bucket
35
+ - **Local:** Custom `FileBucketSnapshotStorage` → FileBucket mock (mirrors S3Storage key layout exactly)
36
+
37
+ ## Infrastructure (CDK)
38
+
39
+ The CDK class mirrors the runtime's BB creation:
40
+ - **Bedrock IAM:** `InvokeModel` + `InvokeModelWithResponseStream` on all foundation models and inference profiles
41
+ - **FileBucket:** `${id}-sessions` — session snapshot storage
42
+ - **DistributedTable:** `${id}-messages` — conversation history (only when `inferenceOnly: false`)
43
+ - **Realtime:** `${id}-rt` — streaming namespace `chunks`
44
+ - **AsyncJob:** `${id}-job` — job payload: `{ message, conversationId?, channelId }`
45
+
46
+ > **Note:** Internal Building Blocks are created on the parent scope (not `this`) to ensure correct nested-scope resolution on AWS.
47
+
48
+ ## Model Providers
49
+
50
+ All providers are Strands model implementations, mapped from Blocks's `ModelConfig` via `model-factory.ts`:
51
+
52
+ | Provider | Strands Class | Use Case |
53
+ |----------|--------------|----------|
54
+ | `canned` | `CannedProvider` (custom) | Local dev — keyword-based responses with tool call support |
55
+ | `bedrock` | `BedrockModel` | AWS — Amazon Bedrock models |
56
+ | `openai-api` | `OpenAIModel` | Any OpenAI-compatible endpoint (OpenAI, Ollama, vLLM) |
57
+
58
+ ## CannedProvider
59
+
60
+ Custom Strands model provider for local development. No network, no API keys, no costs.
61
+
62
+ - Returns instant keyword-based responses (e.g., prompt contains "weather" → weather response, otherwise a default canned response)
63
+ - Streams word by word, matching the same `ModelStreamEvent` protocol as Bedrock/OpenAI
64
+ - Triggers tool calls when the prompt mentions a tool name — splits camelCase names into words (e.g., "weather" matches `getWeather`) and emits Strands `toolUse` events
65
+ - After Strands executes the tool and sends the result back, returns a fixed acknowledgment (`"I called the tool and got a result."`)
66
+ - Token usage reports zeros (no real model call)
package/README.md CHANGED
@@ -6,16 +6,17 @@ AI agent with streaming, tool calling, and conversation persistence. Powered by
6
6
 
7
7
  **Requires:** `zod` ^4.0.0 as a peer dependency. Tool parameters use Zod schemas for validation. If you see `ZodType missing properties` errors, check your zod version.
8
8
 
9
+ > Design & mock parity details: [DESIGN.md](./DESIGN.md)
10
+
9
11
  ## Quick Start
10
12
 
11
13
  ```typescript
12
14
  import { Scope } from '@aws-blocks/core';
13
- import { Agent, BedrockModels } from '@aws-blocks/bb-agent';
15
+ import { Agent } from '@aws-blocks/bb-agent';
14
16
 
15
17
  const scope = new Scope('my-app');
16
18
 
17
19
  const agent = new Agent(scope, 'support-agent', {
18
- model: { deployed: BedrockModels.DEFAULT },
19
20
  systemPrompt: 'You are a helpful support agent.',
20
21
  });
21
22
 
@@ -28,7 +29,7 @@ const result = await agent.stream('Until when are you open tomorrow?', { convers
28
29
  const done = await result.complete();
29
30
  console.log(done.text); // "We're open until 6pm tomorrow."
30
31
  ```
31
- See [Tools](#tools) for adding capabilities, [Model Configuration](#model-configuration) for provider setup, and [Local Development](#local-development) for running without AWS Bedrock.
32
+ Uses [`BedrockModels.BALANCED`](#bedrock-presets) (Claude Sonnet 4.6) by default. See [Model Configuration](#model-configuration) for other presets, [Tools](#tools) for adding capabilities, and [Local Development](#local-development) for running without AWS Bedrock.
32
33
 
33
34
  ## API
34
35
 
@@ -47,7 +48,7 @@ const agent = new Agent(scope, id, config)
47
48
  | `getPendingInterrupts(conversationId)` | `Promise<Array<...>>` | Get unanswered interrupts (for reload support). |
48
49
  | `getChannel(channelId)` | `Promise<RealtimeChannel>` | Get a Realtime channel for subscribing to chunks. |
49
50
 
50
- `stream()` submits the message to AsyncJob and returns immediately — no API Gateway timeout risk. The agent runs asynchronously and publishes chunks to Realtime.
51
+ `stream()` submits the message to AsyncJob and returns immediately — no API Gateway timeout risk. The agent runs asynchronously and publishes chunks to Realtime. The channel ID is resolved as `options.channelId || options.conversationId || crypto.randomUUID()` — empty strings are treated as unset and fall through to the next value.
51
52
 
52
53
  **Important: Subscribe before sending.** The agent starts emitting chunks immediately after `stream()` is called. If you subscribe to the channel after calling `stream()`, early chunks may be dropped. Always subscribe first, await `established`, then send:
53
54
 
@@ -138,7 +139,7 @@ The `useChat` hook only surfaces `user`, `assistant`, and `approval` messages to
138
139
 
139
140
  ### Model Configuration
140
141
 
141
- Only `deployed` is required. Local development works out of the box — the canned provider (keyword-based mock) is used automatically when no local model is specified.
142
+ Model configuration is optional. When omitted, the agent defaults to `BedrockModels.BALANCED` (Claude Sonnet 4.6) for deployment. Local development works out of the box — the canned provider (keyword-based mock) is used automatically when no local model is specified.
142
143
 
143
144
  | Option | Type | Description |
144
145
  |--------|------|-------------|
@@ -190,14 +191,14 @@ model: {
190
191
 
191
192
  #### Bedrock Presets
192
193
 
193
- Pre-configured model presets for quick setup. Names are capability-based so the underlying model can be upgraded without breaking your code. These use cross-region inference profiles work across all AWS regions:
194
+ Pre-configured model presets for quick setup. Names are capability-based so the underlying model can be upgraded without breaking your code. These use [global inference profiles](https://docs.aws.amazon.com/bedrock/latest/userguide/cross-region-inference.html)requests may be routed to any supported AWS region for optimal throughput. If your workload has data residency requirements, specify a region-scoped inference profile explicitly instead of using a preset.
194
195
 
195
196
  ```typescript
196
197
  import { Agent, BedrockModels} from '@aws-blocks/bb-agent';
197
198
 
198
199
  const agent = new Agent(scope, 'agent', {
199
200
  model: {
200
- deployed: BedrockModels.DEFAULT,
201
+ deployed: BedrockModels.BALANCED,
201
202
  },
202
203
  systemPrompt: '...',
203
204
  });
@@ -205,15 +206,15 @@ const agent = new Agent(scope, 'agent', {
205
206
 
206
207
  | Preset | Current Model | Notes |
207
208
  |--------|---------------|-------|
208
- | `BedrockModels.DEFAULT` | `us.anthropic.claude-opus-4-8-20250610-v1:0` | Highest capability. Recommended default. |
209
- | `BedrockModels.BALANCED` | `us.anthropic.claude-sonnet-4-20250514-v1:0` | Strong quality/cost balance. |
210
- | `BedrockModels.FAST` | `us.anthropic.claude-haiku-4-5-20251001-v1:0` | Fastest, lowest latency. |
211
- | `BedrockModels.BUDGET` | `us.amazon.nova-pro-v1:0` | Low cost per token with acceptable quality. |
212
- | `BedrockModels.MICRO` | `us.amazon.nova-lite-v1:0` | Ultra-cheap for simple tasks. |
209
+ | `BedrockModels.BALANCED` | `global.anthropic.claude-sonnet-4-6` | Great tool use, balanced cost. Recommended default for most workloads. |
210
+ | `BedrockModels.SMART` | `global.anthropic.claude-opus-4-8` | Highest capability for the hardest tasks. |
211
+ | `BedrockModels.FAST` | `global.anthropic.claude-haiku-4-5-20251001-v1:0` | Lowest latency, still strong capabilities. |
212
+
213
+ > **Migrating?** `DEFAULT` `BALANCED` (or `SMART` for highest capability). `BUDGET`/`MICRO` → `FAST`. The old presets are still available but deprecated. Please consider upgrading!
213
214
 
214
215
  Override inference settings with spread:
215
216
  ```typescript
216
- model: { deployed: { ...BedrockModels.DEFAULT, inferenceConfig: { temperature: 0.9, maxTokens: 8192 } } }
217
+ model: { deployed: { ...BedrockModels.BALANCED, inferenceConfig: { temperature: 0.9, maxTokens: 8192 } } }
217
218
  ```
218
219
 
219
220
  #### Ollama Presets
@@ -225,7 +226,7 @@ import { Agent, BedrockModels, OllamaModels} from '@aws-blocks/bb-agent';
225
226
 
226
227
  const agent = new Agent(scope, 'agent', {
227
228
  model: {
228
- deployed: BedrockModels.DEFAULT,
229
+ deployed: BedrockModels.BALANCED,
229
230
  local: OllamaModels.SMALL,
230
231
  },
231
232
  systemPrompt: '...',
@@ -262,7 +263,7 @@ To see detailed health check logs, pass a logger with `info` level:
262
263
  import { Logger } from '@aws-blocks/bb-logger';
263
264
 
264
265
  const agent = new Agent(scope, 'agent', {
265
- model: { deployed: BedrockModels.DEFAULT },
266
+ model: { deployed: BedrockModels.BALANCED },
266
267
  systemPrompt: '...',
267
268
  logger: new Logger(scope, 'agent-log', { level: 'info' }),
268
269
  });
@@ -541,7 +542,7 @@ The Agent BB works without a frontend — for scripts, background jobs, or serve
541
542
  import { Agent, BedrockModels } from '@aws-blocks/bb-agent';
542
543
 
543
544
  const agent = new Agent(scope, 'summarizer', {
544
- model: { deployed: BedrockModels.DEFAULT },
545
+ model: { deployed: BedrockModels.BALANCED },
545
546
  systemPrompt: 'Summarize the input concisely.',
546
547
  });
547
548
 
@@ -560,7 +561,7 @@ import { Agent, BedrockModels, InterruptError } from '@aws-blocks/bb-agent';
560
561
  import { z } from 'zod';
561
562
 
562
563
  const refundBot = new Agent(scope, 'refunds', {
563
- model: { deployed: BedrockModels.DEFAULT },
564
+ model: { deployed: BedrockModels.BALANCED },
564
565
  systemPrompt: 'You process customer refund requests.',
565
566
  tools: (tool) => ({
566
567
  issueRefund: tool({
@@ -687,7 +688,7 @@ import { Agent, BedrockModels } from '@aws-blocks/bb-agent';
687
688
  const scope = new Scope('my-app');
688
689
 
689
690
  const agent = new Agent(scope, 'chat', {
690
- model: { deployed: BedrockModels.DEFAULT },
691
+ model: { deployed: BedrockModels.BALANCED },
691
692
  systemPrompt: 'You are a helpful assistant.',
692
693
  });
693
694
 
@@ -751,7 +752,7 @@ const scope = new Scope('my-app');
751
752
  const kb = new KnowledgeBase(scope, 'docs', { source: './knowledge' });
752
753
 
753
754
  const agent = new Agent(scope, 'support', {
754
- model: { deployed: BedrockModels.DEFAULT },
755
+ model: { deployed: BedrockModels.BALANCED },
755
756
  systemPrompt: 'You are a customer support agent. Look up orders and search documentation to help the user.',
756
757
  toolContextSchema: z.object({ userId: z.string() }),
757
758
  tools: (tool) => ({
@@ -1 +1 @@
1
- {"version":3,"file":"agent.aws.d.ts","sourceRoot":"","sources":["../src/agent.aws.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAEvC,OAAO,KAAK,EAAE,WAAW,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAElE,qBAAa,KAAK,CAAC,QAAQ,GAAG,kBAAkB,CAAE,SAAQ,SAAS,CAAC,QAAQ,CAAC;gBAChE,KAAK,EAAE,WAAW,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,CAAC,QAAQ,CAAC;CAGzE"}
1
+ {"version":3,"file":"agent.aws.d.ts","sourceRoot":"","sources":["../src/agent.aws.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAEvC,OAAO,KAAK,EAAE,WAAW,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAGlE,qBAAa,KAAK,CAAC,QAAQ,GAAG,kBAAkB,CAAE,SAAQ,SAAS,CAAC,QAAQ,CAAC;gBAChE,KAAK,EAAE,WAAW,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,CAAC,QAAQ,CAAC;CAGzE"}
package/dist/agent.aws.js CHANGED
@@ -2,8 +2,9 @@
2
2
  // SPDX-License-Identifier: Apache-2.0
3
3
  import { AgentBase } from './agent.js';
4
4
  import { S3Storage } from '@strands-agents/sdk/session/s3-storage';
5
+ import { BedrockModels } from './models.js';
5
6
  export class Agent extends AgentBase {
6
7
  constructor(scope, id, config) {
7
- super(scope, id, config, config.model.deployed, (bucket) => new S3Storage({ bucket: bucket.fullId }));
8
+ super(scope, id, config, config.model?.deployed ?? BedrockModels.BALANCED, (bucket) => new S3Storage({ bucket: bucket.fullId }));
8
9
  }
9
10
  }
@@ -1 +1 @@
1
- {"version":3,"file":"agent.d.ts","sourceRoot":"","sources":["../src/agent.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"agent.d.ts","sourceRoot":"","sources":["../src/agent.ts"],"names":[],"mappings":"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"}
package/dist/agent.js CHANGED
@@ -377,7 +377,7 @@ export class AgentBase extends Scope {
377
377
  */
378
378
  async stream(message, options) {
379
379
  const conversationId = options?.conversationId;
380
- const channelId = options?.channelId ?? conversationId ?? crypto.randomUUID();
380
+ const channelId = options?.channelId || conversationId || crypto.randomUUID();
381
381
  if (!options?.userId && !this.config.inferenceOnly)
382
382
  throw blocksAgentError(AgentErrors.PersistenceRequired, 'userId is required when persistence is enabled. Pass it via options.userId.');
383
383
  const userId = options?.userId ?? 'anonymous';
@@ -405,6 +405,7 @@ export class AgentBase extends Scope {
405
405
  }
406
406
  });
407
407
  }),
408
+ toJSON() { return { channelId, channel: null }; },
408
409
  };
409
410
  }
410
411
  /**
@@ -5,7 +5,7 @@ import { FileBucketSnapshotStorage } from './file-bucket-snapshot-storage.js';
5
5
  export class Agent extends AgentBase {
6
6
  constructor(scope, id, config) {
7
7
  // Canned provider is appended as implicit last fallback for local dev
8
- const local = config.model.local;
8
+ const local = config.model?.local;
9
9
  const candidates = local ? (Array.isArray(local) ? [...local, { provider: 'canned' }] : [local, { provider: 'canned' }]) : [{ provider: 'canned' }];
10
10
  super(scope, id, config, candidates, (bucket) => new FileBucketSnapshotStorage(bucket));
11
11
  }
@@ -97,6 +97,34 @@ describe('needsApproval and interrupt mutual exclusivity', () => {
97
97
  assert.ok(result.channelId);
98
98
  });
99
99
  });
100
+ // ── AgentStreamResult.toJSON() ───────────────────────────────────────────────
101
+ describe('AgentStreamResult.toJSON()', () => {
102
+ test('serializes to { channelId, channel: null }', async () => {
103
+ const scope = new Scope('test-tojson');
104
+ const agent = new Agent(scope, 'tj', { systemPrompt: 'test', model: { deployed: { provider: 'canned' }, local: { provider: 'canned' } } });
105
+ const result = await agent.stream('hello', { userId: 'test-user' });
106
+ const serialized = JSON.parse(JSON.stringify(result));
107
+ assert.deepStrictEqual(serialized, { channelId: result.channelId, channel: null });
108
+ assert.strictEqual('complete' in serialized, false);
109
+ });
110
+ });
111
+ // ── stream() empty channelId fallback ────────────────────────────────────────
112
+ describe('stream() empty channelId fallback', () => {
113
+ test('empty channelId is treated as unset', async () => {
114
+ const scope = new Scope('test-empty-ch');
115
+ const agent = new Agent(scope, 'ec', { systemPrompt: 'test', model: { deployed: { provider: 'canned' }, local: { provider: 'canned' } } });
116
+ const result = await agent.stream('hello', { userId: 'test-user', channelId: '' });
117
+ assert.notStrictEqual(result.channelId, '');
118
+ assert.ok(result.channelId.length > 0);
119
+ });
120
+ test('empty conversationId is treated as unset', async () => {
121
+ const scope = new Scope('test-empty-conv');
122
+ const agent = new Agent(scope, 'ev', { systemPrompt: 'test', model: { deployed: { provider: 'canned' }, local: { provider: 'canned' } } });
123
+ const result = await agent.stream('hello', { userId: 'test-user', conversationId: '' });
124
+ assert.notStrictEqual(result.channelId, '');
125
+ assert.ok(result.channelId.length > 0);
126
+ });
127
+ });
100
128
  // ── tool factory enforcement (compile-time) ──────────────────────────────────
101
129
  describe('tool factory enforcement', () => {
102
130
  // Regression: AgentConfig.tools is a callback `(tool) => Record<string, AgentTool>`.
@@ -839,10 +867,17 @@ describe('checkModelHealth', () => {
839
867
  });
840
868
  });
841
869
  // ── Model Presets ─────────────────────────────────────────────────────────────
870
+ describe('default model', () => {
871
+ test('agent can be created without model config', () => {
872
+ const s = new Scope('test-default-model');
873
+ const agent = new Agent(s, 'no-model', { systemPrompt: 'test' });
874
+ assert.ok(agent);
875
+ });
876
+ });
842
877
  describe('BedrockModels presets', () => {
843
- test('DEFAULT resolves to a bedrock provider', async () => {
844
- assert.strictEqual(BedrockModels.DEFAULT.provider, 'bedrock');
845
- assert.ok(BedrockModels.DEFAULT.modelId);
878
+ test('BALANCED resolves to a bedrock provider', async () => {
879
+ assert.strictEqual(BedrockModels.BALANCED.provider, 'bedrock');
880
+ assert.ok(BedrockModels.BALANCED.modelId);
846
881
  });
847
882
  test('all presets have provider bedrock and a modelId', () => {
848
883
  for (const [name, config] of Object.entries(BedrockModels)) {
@@ -850,8 +885,8 @@ describe('BedrockModels presets', () => {
850
885
  assert.ok(config.modelId, `${name} should have a modelId`);
851
886
  }
852
887
  });
853
- test('DEFAULT flows through createStrandsModel to BedrockModel', async () => {
854
- const model = await createStrandsModel(BedrockModels.DEFAULT);
888
+ test('BALANCED flows through createStrandsModel to BedrockModel', async () => {
889
+ const model = await createStrandsModel(BedrockModels.BALANCED);
855
890
  assert.ok(model, 'should create a model instance');
856
891
  });
857
892
  });
package/dist/models.d.ts CHANGED
@@ -1,32 +1,42 @@
1
1
  /**
2
- * Pre-configured Bedrock model presets using cross-region inference profiles.
2
+ * Pre-configured Bedrock model presets using global inference profiles.
3
3
  * Names are capability-based so the underlying model can be upgraded without breaking user code.
4
+ *
5
+ * **Note:** Global inference profiles route requests to any supported AWS region for
6
+ * optimal throughput. If your workload has data residency requirements, specify a
7
+ * region-scoped inference profile explicitly.
8
+ * @see https://docs.aws.amazon.com/bedrock/latest/userguide/cross-region-inference.html
4
9
  */
5
10
  export declare const BedrockModels: {
6
- /** Highest capability and best performance. Recommended default. Currently: Claude Opus 4.8. */
7
- readonly DEFAULT: {
11
+ /** Great tool use, balanced cost good middle tier for most workloads. Currently: Claude Sonnet 4.6. */
12
+ readonly BALANCED: {
8
13
  readonly provider: "bedrock";
9
- readonly modelId: "us.anthropic.claude-opus-4-8-20250610-v1:0";
14
+ readonly modelId: "global.anthropic.claude-sonnet-4-6";
10
15
  };
11
- /** Strong quality/cost balance. Currently: Claude Sonnet 4. */
12
- readonly BALANCED: {
16
+ /** Highest capability for the hardest tasks. Currently: Claude Opus 4.8. */
17
+ readonly SMART: {
13
18
  readonly provider: "bedrock";
14
- readonly modelId: "us.anthropic.claude-sonnet-4-20250514-v1:0";
19
+ readonly modelId: "global.anthropic.claude-opus-4-8";
15
20
  };
16
- /** Fastest and lowest latency. Currently: Claude Haiku 4.5. */
21
+ /** Lowest latency, still strong capabilities. Currently: Claude Haiku 4.5. */
17
22
  readonly FAST: {
18
23
  readonly provider: "bedrock";
19
- readonly modelId: "us.anthropic.claude-haiku-4-5-20251001-v1:0";
24
+ readonly modelId: "global.anthropic.claude-haiku-4-5-20251001-v1:0";
25
+ };
26
+ /** @deprecated Use `BedrockModels.BALANCED` instead. */
27
+ readonly DEFAULT: {
28
+ readonly provider: "bedrock";
29
+ readonly modelId: "global.anthropic.claude-sonnet-4-6";
20
30
  };
21
- /** Low cost per token with acceptable quality. Currently: Amazon Nova Pro. */
31
+ /** @deprecated Use `BedrockModels.FAST` instead. */
22
32
  readonly BUDGET: {
23
33
  readonly provider: "bedrock";
24
- readonly modelId: "us.amazon.nova-pro-v1:0";
34
+ readonly modelId: "global.anthropic.claude-haiku-4-5-20251001-v1:0";
25
35
  };
26
- /** Ultra-cheap for simple tasks. Currently: Amazon Nova Lite. */
36
+ /** @deprecated Use `BedrockModels.FAST` instead. */
27
37
  readonly MICRO: {
28
38
  readonly provider: "bedrock";
29
- readonly modelId: "us.amazon.nova-lite-v1:0";
39
+ readonly modelId: "global.anthropic.claude-haiku-4-5-20251001-v1:0";
30
40
  };
31
41
  };
32
42
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"models.d.ts","sourceRoot":"","sources":["../src/models.ts"],"names":[],"mappings":"AAKA;;;GAGG;AACH,eAAO,MAAM,aAAa;IACzB,gGAAgG;;;;;IAKhG,+DAA+D;;;;;IAK/D,+DAA+D;;;;;IAK/D,8EAA8E;;;;;IAK9E,iEAAiE;;;;;CAKlB,CAAC;AAEjD;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,YAAY;IACxB,kGAAkG;;;;;;;IAOlG,gGAAgG;;;;;;;IAOhG,+FAA+F;;;;;;;IAO/F,4FAA4F;;;;;;;IAO5F,iFAAiF;;;;;;;CAOlC,CAAC"}
1
+ {"version":3,"file":"models.d.ts","sourceRoot":"","sources":["../src/models.ts"],"names":[],"mappings":"AASA;;;;;;;;GAQG;AACH,eAAO,MAAM,aAAa;IACzB,yGAAyG;;;;;IAKzG,4EAA4E;;;;;IAK5E,8EAA8E;;;;;IAM9E,wDAAwD;;;;;IAKxD,oDAAoD;;;;;IAKpD,oDAAoD;;;;;CAKL,CAAC;AAEjD;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,YAAY;IACxB,kGAAkG;;;;;;;IAOlG,gGAAgG;;;;;;;IAOhG,+FAA+F;;;;;;;IAQ/F,4FAA4F;;;;;;;IAO5F,iFAAiF;;;;;;;CAOlC,CAAC"}
package/dist/models.js CHANGED
@@ -1,34 +1,47 @@
1
1
  // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2
2
  // SPDX-License-Identifier: Apache-2.0
3
+ const BALANCED_MODEL_ID = 'global.anthropic.claude-sonnet-4-6';
4
+ const SMART_MODEL_ID = 'global.anthropic.claude-opus-4-8';
5
+ const FAST_MODEL_ID = 'global.anthropic.claude-haiku-4-5-20251001-v1:0';
3
6
  /**
4
- * Pre-configured Bedrock model presets using cross-region inference profiles.
7
+ * Pre-configured Bedrock model presets using global inference profiles.
5
8
  * Names are capability-based so the underlying model can be upgraded without breaking user code.
9
+ *
10
+ * **Note:** Global inference profiles route requests to any supported AWS region for
11
+ * optimal throughput. If your workload has data residency requirements, specify a
12
+ * region-scoped inference profile explicitly.
13
+ * @see https://docs.aws.amazon.com/bedrock/latest/userguide/cross-region-inference.html
6
14
  */
7
15
  export const BedrockModels = {
8
- /** Highest capability and best performance. Recommended default. Currently: Claude Opus 4.8. */
9
- DEFAULT: {
16
+ /** Great tool use, balanced cost good middle tier for most workloads. Currently: Claude Sonnet 4.6. */
17
+ BALANCED: {
10
18
  provider: 'bedrock',
11
- modelId: 'us.anthropic.claude-opus-4-8-20250610-v1:0',
19
+ modelId: BALANCED_MODEL_ID,
12
20
  },
13
- /** Strong quality/cost balance. Currently: Claude Sonnet 4. */
14
- BALANCED: {
21
+ /** Highest capability for the hardest tasks. Currently: Claude Opus 4.8. */
22
+ SMART: {
15
23
  provider: 'bedrock',
16
- modelId: 'us.anthropic.claude-sonnet-4-20250514-v1:0',
24
+ modelId: SMART_MODEL_ID,
17
25
  },
18
- /** Fastest and lowest latency. Currently: Claude Haiku 4.5. */
26
+ /** Lowest latency, still strong capabilities. Currently: Claude Haiku 4.5. */
19
27
  FAST: {
20
28
  provider: 'bedrock',
21
- modelId: 'us.anthropic.claude-haiku-4-5-20251001-v1:0',
29
+ modelId: FAST_MODEL_ID,
30
+ },
31
+ /** @deprecated Use `BedrockModels.BALANCED` instead. */
32
+ DEFAULT: {
33
+ provider: 'bedrock',
34
+ modelId: BALANCED_MODEL_ID,
22
35
  },
23
- /** Low cost per token with acceptable quality. Currently: Amazon Nova Pro. */
36
+ /** @deprecated Use `BedrockModels.FAST` instead. */
24
37
  BUDGET: {
25
38
  provider: 'bedrock',
26
- modelId: 'us.amazon.nova-pro-v1:0',
39
+ modelId: FAST_MODEL_ID,
27
40
  },
28
- /** Ultra-cheap for simple tasks. Currently: Amazon Nova Lite. */
41
+ /** @deprecated Use `BedrockModels.FAST` instead. */
29
42
  MICRO: {
30
43
  provider: 'bedrock',
31
- modelId: 'us.amazon.nova-lite-v1:0',
44
+ modelId: FAST_MODEL_ID,
32
45
  },
33
46
  };
34
47
  /**
@@ -61,6 +74,7 @@ export const OllamaModels = {
61
74
  apiKey: 'ollama',
62
75
  },
63
76
  /** Strong reasoning at moderate size. Currently: DeepSeek R1 14B (~9 GB, needs 16 GB VRAM). */
77
+ // TODO: DeepSeek R1 is strong at reasoning but weak at tool calling — swap to a more tool-capable model.
64
78
  MEDIUM: {
65
79
  provider: 'openai-api',
66
80
  modelId: 'deepseek-r1:14b',
package/dist/types.d.ts CHANGED
@@ -41,9 +41,9 @@ export interface AgentConfig<TContext = DefaultToolContext> {
41
41
  * The agent does inference + tools only — no conversation history.
42
42
  */
43
43
  inferenceOnly?: boolean;
44
- model: {
45
- /** Model(s) for AWS deployment. Tries candidates in order; throws if all fail. */
46
- deployed: ModelConfig | ModelConfig[];
44
+ model?: {
45
+ /** Model(s) for AWS deployment. Tries candidates in order; throws if all fail. Defaults to BedrockModels.BALANCED. */
46
+ deployed?: ModelConfig | ModelConfig[];
47
47
  /** Model(s) for local development. Tries candidates in order; canned is implicit last fallback. */
48
48
  local?: ModelConfig | ModelConfig[];
49
49
  };
@@ -235,7 +235,7 @@ export interface ToolCallRecord {
235
235
  }
236
236
  export interface StreamOptions<TContext = DefaultToolContext> {
237
237
  conversationId?: string;
238
- /** Channel ID for Realtime delivery. Defaults to conversationId or a random UUID. */
238
+ /** Channel ID for Realtime delivery. Defaults to conversationId or a random UUID. Empty strings are treated as unset. */
239
239
  channelId?: string;
240
240
  /** User ID for conversation scoping. Defaults to 'anonymous'. */
241
241
  userId?: string;
@@ -247,14 +247,33 @@ export interface StreamOptions<TContext = DefaultToolContext> {
247
247
  */
248
248
  context?: TContext;
249
249
  }
250
- /** Returned by stream(). Provides the channelId and server-side convenience methods. */
250
+ /**
251
+ * Returned by stream(). Provides the channelId and server-side convenience methods.
252
+ *
253
+ * Safe to return directly from API methods — `toJSON()` serializes to
254
+ * `{ channelId, channel: null }`. Only `channelId` is meaningful client-side;
255
+ * `channel` is explicitly `null` to signal the live handle is server-side only,
256
+ * and the `complete()` helper is dropped (functions don't serialize).
257
+ */
251
258
  export interface AgentStreamResult {
252
259
  /** Realtime channel ID where chunks are published. */
253
260
  channelId: string;
254
- /** Realtime channel handle — subscribe to streaming chunks or return to client as Transferable. */
261
+ /**
262
+ * Realtime channel handle (server-side only). Nulled by `toJSON()` — clients subscribe from `channelId` instead.
263
+ *
264
+ * @remarks
265
+ * Unlike `RealtimeChannel.toJSON()` which produces a hydratable descriptor, this is nulled
266
+ * because it's a `Promise` that can't round-trip. Clients reconstruct a subscribe-only
267
+ * channel from `channelId` via the `useChat` `subscribe` callback.
268
+ */
255
269
  channel: Promise<RealtimeChannel<AgentStreamChunk>>;
256
270
  /** Wait for the complete response (server-side). Resolves when the done chunk arrives. */
257
271
  complete: () => Promise<AgentStreamChunk>;
272
+ /** Only `{ channelId, channel: null }` is serialized when this object crosses the RPC boundary. */
273
+ toJSON(): {
274
+ channelId: string;
275
+ channel: null;
276
+ };
258
277
  }
259
278
  export interface AgentStreamChunk {
260
279
  type: 'text-delta' | 'tool-call' | 'tool-result' | 'done' | 'error' | 'interrupt';
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAC7B,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC/D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAEzD,mCAAmC;AACnC,MAAM,MAAM,SAAS,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,GAAG;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,CAAA;CAAE,GAAG,SAAS,EAAE,CAAC;AAEtG,MAAM,WAAW,WAAW;IAC3B;;;;OAIG;IACH,QAAQ,EAAE,SAAS,GAAG,YAAY,GAAG,QAAQ,CAAC;IAC9C,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,qJAAqJ;IACrJ,MAAM,CAAC,EAAE,MAAM,GAAG,CAAC,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC;IAC1C,eAAe,CAAC,EAAE,eAAe,CAAC;IAClC,UAAU,CAAC,EAAE,gBAAgB,CAAC;CAC9B;AAED,MAAM,WAAW,eAAe;IAC/B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;CACzB;AAED,MAAM,WAAW,gBAAgB;IAChC,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACxC,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC7B,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;CACzB;AAED;;;GAGG;AACH,MAAM,MAAM,kBAAkB,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;AAErD,MAAM,WAAW,WAAW,CAAC,QAAQ,GAAG,kBAAkB;IACzD;;;OAGG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,KAAK,EAAE;QACN,kFAAkF;QAClF,QAAQ,EAAE,WAAW,GAAG,WAAW,EAAE,CAAC;QACtC,mGAAmG;QACnG,KAAK,CAAC,EAAE,WAAW,GAAG,WAAW,EAAE,CAAC;KACpC,CAAC;IACF,YAAY,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;;;;;;;;OAWG;IACH,KAAK,CAAC,EAAE,WAAW,CAAC,QAAQ,CAAC,CAAC;IAC9B;;;;;;;;;;;;OAYG;IACH,iBAAiB,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IACxC,YAAY,CAAC,EAAE,yBAAyB,CAAC;IACzC,gBAAgB,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC;IAC7B;;;OAGG;IAEH,aAAa,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC;IAClC;;;;;;;;;;;;OAYG;IACH,aAAa,CAAC,EAAE,SAAS,GAAG,QAAQ,CAAC;IACrC,yGAAyG;IACzG,MAAM,CAAC,EAAE,WAAW,CAAC;CACrB;AAED;;;;;GAKG;AACH,MAAM,MAAM,yBAAyB,GAClC;IAAE,QAAQ,CAAC,EAAE,gBAAgB,CAAC,CAAC,iCAAiC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAA;CAAE,GACtF;IAAE,QAAQ,EAAE,aAAa,CAAC,CAAC,wCAAwC;IAAC,YAAY,CAAC,EAAE,MAAM,CAAC,CAAC,yCAAyC;IAAC,sBAAsB,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAE1K,+DAA+D;AAC/D,MAAM,WAAW,eAAe,CAAC,MAAM,GAAG,GAAG,EAAE,QAAQ,GAAG,kBAAkB;IAC3E,2EAA2E;IAC3E,KAAK,EAAE,MAAM,CAAC;IACd;;;;;OAKG;IACH,OAAO,EAAE,QAAQ,CAAC;IAClB;;;OAGG;IACH,SAAS,EAAE,CAAC,CAAC,GAAG,SAAS,EAAE,MAAM,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,GAAG,CAAA;KAAE,KAAK,CAAC,CAAC;CACxE;AAED,qEAAqE;AACrE,MAAM,WAAW,iBAAiB;IACjC,qCAAqC;IACrC,WAAW,EAAE,MAAM,CAAC;IACpB,4DAA4D;IAC5D,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,wFAAwF;IACxF,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,kFAAkF;IAClF,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,kGAAkG;IAClG,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,kGAAkG;IAClG,KAAK,CAAC,EAAE,GAAG,CAAC;CACZ;AAED,MAAM,WAAW,cAAc,CAAC,QAAQ,GAAG,kBAAkB,EAAE,OAAO,SAAS,CAAC,CAAC,OAAO,GAAG,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC;IACxG;;;OAGG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,OAAO,CAAC;IACpB,wIAAwI;IACxI,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,oIAAoI;IACpI,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,mLAAmL;IACnL,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,eAAe,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,QAAQ,CAAC,KAAK,IAAI,CAAC;IACxE;;;;;OAKG;IACH,OAAO,EAAE,CAAC,IAAI,EAAE,eAAe,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,QAAQ,CAAC,KAAK,OAAO,CAAC,SAAS,CAAC,CAAC;CACnF;AAED;;;;GAIG;AACH,OAAO,CAAC,MAAM,gBAAgB,EAAE,OAAO,MAAM,CAAC;AAE9C;;;GAGG;AACH,MAAM,MAAM,SAAS,CAAC,QAAQ,GAAG,kBAAkB,IAAI,cAAc,CAAC,QAAQ,EAAE,GAAG,CAAC,GAAG;IACtF,QAAQ,CAAC,CAAC,gBAAgB,CAAC,EAAE,IAAI,CAAC;CAClC,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,MAAM,WAAW,CAAC,QAAQ,GAAG,kBAAkB,IAAI,CAAC,OAAO,SAAS,CAAC,CAAC,OAAO,EAClF,IAAI,EAAE,cAAc,CAAC,QAAQ,EAAE,OAAO,CAAC,KACnC,SAAS,CAAC,QAAQ,CAAC,CAAC;AAEzB;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,MAAM,WAAW,CAAC,QAAQ,GAAG,kBAAkB,IAAI,CACxD,IAAI,EAAE,WAAW,CAAC,QAAQ,CAAC,KACvB,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAC;AAEzC,MAAM,WAAW,WAAW;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,cAAc,EAAE,CAAC;IAC5B,KAAK,CAAC,EAAE,UAAU,CAAC;CACnB;AAED,MAAM,WAAW,UAAU;IAC1B,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,cAAc;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,SAAS,CAAC;IACjB,MAAM,EAAE,SAAS,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,aAAa,CAAC,QAAQ,GAAG,kBAAkB;IAC3D,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,qFAAqF;IACrF,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,iEAAiE;IACjE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;;;OAKG;IACH,OAAO,CAAC,EAAE,QAAQ,CAAC;CACnB;AAED,wFAAwF;AACxF,MAAM,WAAW,iBAAiB;IACjC,sDAAsD;IACtD,SAAS,EAAE,MAAM,CAAC;IAClB,mGAAmG;IACnG,OAAO,EAAE,OAAO,CAAC,eAAe,CAAC,gBAAgB,CAAC,CAAC,CAAC;IACpD,0FAA0F;IAC1F,QAAQ,EAAE,MAAM,OAAO,CAAC,gBAAgB,CAAC,CAAC;CAC1C;AAED,MAAM,WAAW,gBAAgB;IAChC,IAAI,EAAE,YAAY,GAAG,WAAW,GAAG,aAAa,GAAG,MAAM,GAAG,OAAO,GAAG,WAAW,CAAC;IAClF,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,KAAK,CAAC,EAAE,UAAU,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,GAAG,CAAA;KAAE,CAAC,CAAC;CAC/D;AAGD,MAAM,WAAW,eAAe;IAC/B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,UAAU,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,OAAO;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,GAAG,WAAW,GAAG,WAAW,GAAG,aAAa,GAAG,UAAU,GAAG,WAAW,CAAC;IACpF,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,GAAG,OAAO,GAAG,OAAO,GAAG,OAAO,GAAG,UAAU,CAAC;IAC/D,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,eAAe,CAAC;CAC1B;AAED,MAAM,WAAW,YAAY;IAC5B,cAAc,EAAE,MAAM,CAAC;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CAClB"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/dist/version.d.ts CHANGED
@@ -1,3 +1,3 @@
1
1
  export declare const BB_NAME = "Agent";
2
- export declare const BB_VERSION = "0.1.2";
2
+ export declare const BB_VERSION = "0.3.0";
3
3
  //# sourceMappingURL=version.d.ts.map
package/dist/version.js CHANGED
@@ -1,3 +1,3 @@
1
1
  // Auto-generated by scripts/generate-version.mjs — do not edit manually
2
2
  export const BB_NAME = 'Agent';
3
- export const BB_VERSION = '0.1.2';
3
+ export const BB_VERSION = '0.3.0';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aws-blocks/bb-agent",
3
- "version": "0.1.2",
3
+ "version": "0.3.0",
4
4
  "author": "Amazon Web Services",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
@@ -8,6 +8,7 @@
8
8
  "dist",
9
9
  "MODELS.md",
10
10
  "README.md",
11
+ "DESIGN.md",
11
12
  "src",
12
13
  "LICENSE"
13
14
  ],
@@ -33,12 +34,12 @@
33
34
  "test": "node --test dist/index.test.js"
34
35
  },
35
36
  "dependencies": {
36
- "@aws-blocks/bb-async-job": "^0.1.1",
37
- "@aws-blocks/bb-distributed-table": "^0.1.1",
38
- "@aws-blocks/bb-file-bucket": "^0.1.1",
39
- "@aws-blocks/bb-logger": "^0.1.1",
40
- "@aws-blocks/bb-realtime": "^0.1.1",
41
- "@aws-blocks/core": "^0.1.1",
37
+ "@aws-blocks/bb-async-job": "^0.1.2",
38
+ "@aws-blocks/bb-distributed-table": "^0.1.3",
39
+ "@aws-blocks/bb-file-bucket": "^0.1.2",
40
+ "@aws-blocks/bb-logger": "^0.1.2",
41
+ "@aws-blocks/bb-realtime": "^0.1.2",
42
+ "@aws-blocks/core": "^0.1.10",
42
43
  "@aws-sdk/client-bedrock": "^3.700.0",
43
44
  "@strands-agents/sdk": "~1.3.0",
44
45
  "openai": "^6.7.0",
package/src/agent.aws.ts CHANGED
@@ -5,9 +5,10 @@ import type { ScopeParent } from '@aws-blocks/core';
5
5
  import { AgentBase } from './agent.js';
6
6
  import { S3Storage } from '@strands-agents/sdk/session/s3-storage';
7
7
  import type { AgentConfig, DefaultToolContext } from './types.js';
8
+ import { BedrockModels } from './models.js';
8
9
 
9
10
  export class Agent<TContext = DefaultToolContext> extends AgentBase<TContext> {
10
11
  constructor(scope: ScopeParent, id: string, config: AgentConfig<TContext>) {
11
- super(scope, id, config, config.model.deployed, (bucket) => new S3Storage({ bucket: bucket.fullId }));
12
+ super(scope, id, config, config.model?.deployed ?? BedrockModels.BALANCED, (bucket) => new S3Storage({ bucket: bucket.fullId }));
12
13
  }
13
14
  }
package/src/agent.mock.ts CHANGED
@@ -9,7 +9,7 @@ import type { AgentConfig, DefaultToolContext } from './types.js';
9
9
  export class Agent<TContext = DefaultToolContext> extends AgentBase<TContext> {
10
10
  constructor(scope: ScopeParent, id: string, config: AgentConfig<TContext>) {
11
11
  // Canned provider is appended as implicit last fallback for local dev
12
- const local = config.model.local;
12
+ const local = config.model?.local;
13
13
  const candidates = local ? (Array.isArray(local) ? [...local, { provider: 'canned' as const }] : [local, { provider: 'canned' as const }]) : [{ provider: 'canned' as const }];
14
14
  super(scope, id, config, candidates, (bucket) => new FileBucketSnapshotStorage(bucket));
15
15
  }
package/src/agent.ts CHANGED
@@ -403,7 +403,7 @@ export class AgentBase<TContext = DefaultToolContext> extends Scope {
403
403
  */
404
404
  async stream(message: string, options?: StreamOptions<TContext>): Promise<AgentStreamResult> {
405
405
  const conversationId = options?.conversationId;
406
- const channelId = options?.channelId ?? conversationId ?? crypto.randomUUID();
406
+ const channelId = options?.channelId || conversationId || crypto.randomUUID();
407
407
  if (!options?.userId && !this.config.inferenceOnly) throw blocksAgentError(AgentErrors.PersistenceRequired, 'userId is required when persistence is enabled. Pass it via options.userId.');
408
408
  const userId = options?.userId ?? 'anonymous';
409
409
  const context = this.resolveContext(options?.context);
@@ -428,6 +428,7 @@ export class AgentBase<TContext = DefaultToolContext> extends Scope {
428
428
  }
429
429
  });
430
430
  }),
431
+ toJSON() { return { channelId, channel: null }; },
431
432
  };
432
433
  }
433
434
 
package/src/index.test.ts CHANGED
@@ -115,6 +115,39 @@ describe('needsApproval and interrupt mutual exclusivity', () => {
115
115
  });
116
116
  });
117
117
 
118
+ // ── AgentStreamResult.toJSON() ───────────────────────────────────────────────
119
+
120
+ describe('AgentStreamResult.toJSON()', () => {
121
+ test('serializes to { channelId, channel: null }', async () => {
122
+ const scope = new Scope('test-tojson');
123
+ const agent = new Agent(scope, 'tj', { systemPrompt: 'test', model: { deployed: { provider: 'canned' }, local: { provider: 'canned' } } });
124
+ const result = await agent.stream('hello', { userId: 'test-user' });
125
+ const serialized = JSON.parse(JSON.stringify(result));
126
+ assert.deepStrictEqual(serialized, { channelId: result.channelId, channel: null });
127
+ assert.strictEqual('complete' in serialized, false);
128
+ });
129
+ });
130
+
131
+ // ── stream() empty channelId fallback ────────────────────────────────────────
132
+
133
+ describe('stream() empty channelId fallback', () => {
134
+ test('empty channelId is treated as unset', async () => {
135
+ const scope = new Scope('test-empty-ch');
136
+ const agent = new Agent(scope, 'ec', { systemPrompt: 'test', model: { deployed: { provider: 'canned' }, local: { provider: 'canned' } } });
137
+ const result = await agent.stream('hello', { userId: 'test-user', channelId: '' });
138
+ assert.notStrictEqual(result.channelId, '');
139
+ assert.ok(result.channelId.length > 0);
140
+ });
141
+
142
+ test('empty conversationId is treated as unset', async () => {
143
+ const scope = new Scope('test-empty-conv');
144
+ const agent = new Agent(scope, 'ev', { systemPrompt: 'test', model: { deployed: { provider: 'canned' }, local: { provider: 'canned' } } });
145
+ const result = await agent.stream('hello', { userId: 'test-user', conversationId: '' });
146
+ assert.notStrictEqual(result.channelId, '');
147
+ assert.ok(result.channelId.length > 0);
148
+ });
149
+ });
150
+
118
151
  // ── tool factory enforcement (compile-time) ──────────────────────────────────
119
152
 
120
153
  describe('tool factory enforcement', () => {
@@ -983,10 +1016,18 @@ describe('checkModelHealth', () => {
983
1016
 
984
1017
  // ── Model Presets ─────────────────────────────────────────────────────────────
985
1018
 
1019
+ describe('default model', () => {
1020
+ test('agent can be created without model config', () => {
1021
+ const s = new Scope('test-default-model');
1022
+ const agent = new Agent(s, 'no-model', { systemPrompt: 'test' });
1023
+ assert.ok(agent);
1024
+ });
1025
+ });
1026
+
986
1027
  describe('BedrockModels presets', () => {
987
- test('DEFAULT resolves to a bedrock provider', async () => {
988
- assert.strictEqual(BedrockModels.DEFAULT.provider, 'bedrock');
989
- assert.ok(BedrockModels.DEFAULT.modelId);
1028
+ test('BALANCED resolves to a bedrock provider', async () => {
1029
+ assert.strictEqual(BedrockModels.BALANCED.provider, 'bedrock');
1030
+ assert.ok(BedrockModels.BALANCED.modelId);
990
1031
  });
991
1032
 
992
1033
  test('all presets have provider bedrock and a modelId', () => {
@@ -996,8 +1037,8 @@ describe('BedrockModels presets', () => {
996
1037
  }
997
1038
  });
998
1039
 
999
- test('DEFAULT flows through createStrandsModel to BedrockModel', async () => {
1000
- const model = await createStrandsModel(BedrockModels.DEFAULT);
1040
+ test('BALANCED flows through createStrandsModel to BedrockModel', async () => {
1041
+ const model = await createStrandsModel(BedrockModels.BALANCED);
1001
1042
  assert.ok(model, 'should create a model instance');
1002
1043
  });
1003
1044
  });
package/src/models.ts CHANGED
@@ -3,35 +3,50 @@
3
3
 
4
4
  import type { ModelConfig } from './types.js';
5
5
 
6
+ const BALANCED_MODEL_ID = 'global.anthropic.claude-sonnet-4-6';
7
+ const SMART_MODEL_ID = 'global.anthropic.claude-opus-4-8';
8
+ const FAST_MODEL_ID = 'global.anthropic.claude-haiku-4-5-20251001-v1:0';
9
+
6
10
  /**
7
- * Pre-configured Bedrock model presets using cross-region inference profiles.
11
+ * Pre-configured Bedrock model presets using global inference profiles.
8
12
  * Names are capability-based so the underlying model can be upgraded without breaking user code.
13
+ *
14
+ * **Note:** Global inference profiles route requests to any supported AWS region for
15
+ * optimal throughput. If your workload has data residency requirements, specify a
16
+ * region-scoped inference profile explicitly.
17
+ * @see https://docs.aws.amazon.com/bedrock/latest/userguide/cross-region-inference.html
9
18
  */
10
19
  export const BedrockModels = {
11
- /** Highest capability and best performance. Recommended default. Currently: Claude Opus 4.8. */
12
- DEFAULT: {
20
+ /** Great tool use, balanced cost good middle tier for most workloads. Currently: Claude Sonnet 4.6. */
21
+ BALANCED: {
13
22
  provider: 'bedrock',
14
- modelId: 'us.anthropic.claude-opus-4-8-20250610-v1:0',
23
+ modelId: BALANCED_MODEL_ID,
15
24
  },
16
- /** Strong quality/cost balance. Currently: Claude Sonnet 4. */
17
- BALANCED: {
25
+ /** Highest capability for the hardest tasks. Currently: Claude Opus 4.8. */
26
+ SMART: {
18
27
  provider: 'bedrock',
19
- modelId: 'us.anthropic.claude-sonnet-4-20250514-v1:0',
28
+ modelId: SMART_MODEL_ID,
20
29
  },
21
- /** Fastest and lowest latency. Currently: Claude Haiku 4.5. */
30
+ /** Lowest latency, still strong capabilities. Currently: Claude Haiku 4.5. */
22
31
  FAST: {
23
32
  provider: 'bedrock',
24
- modelId: 'us.anthropic.claude-haiku-4-5-20251001-v1:0',
33
+ modelId: FAST_MODEL_ID,
34
+ },
35
+
36
+ /** @deprecated Use `BedrockModels.BALANCED` instead. */
37
+ DEFAULT: {
38
+ provider: 'bedrock',
39
+ modelId: BALANCED_MODEL_ID,
25
40
  },
26
- /** Low cost per token with acceptable quality. Currently: Amazon Nova Pro. */
41
+ /** @deprecated Use `BedrockModels.FAST` instead. */
27
42
  BUDGET: {
28
43
  provider: 'bedrock',
29
- modelId: 'us.amazon.nova-pro-v1:0',
44
+ modelId: FAST_MODEL_ID,
30
45
  },
31
- /** Ultra-cheap for simple tasks. Currently: Amazon Nova Lite. */
46
+ /** @deprecated Use `BedrockModels.FAST` instead. */
32
47
  MICRO: {
33
48
  provider: 'bedrock',
34
- modelId: 'us.amazon.nova-lite-v1:0',
49
+ modelId: FAST_MODEL_ID,
35
50
  },
36
51
  } as const satisfies Record<string, ModelConfig>;
37
52
 
@@ -65,6 +80,7 @@ export const OllamaModels = {
65
80
  apiKey: 'ollama',
66
81
  },
67
82
  /** Strong reasoning at moderate size. Currently: DeepSeek R1 14B (~9 GB, needs 16 GB VRAM). */
83
+ // TODO: DeepSeek R1 is strong at reasoning but weak at tool calling — swap to a more tool-capable model.
68
84
  MEDIUM: {
69
85
  provider: 'openai-api',
70
86
  modelId: 'deepseek-r1:14b',
package/src/types.ts CHANGED
@@ -48,9 +48,9 @@ export interface AgentConfig<TContext = DefaultToolContext> {
48
48
  * The agent does inference + tools only — no conversation history.
49
49
  */
50
50
  inferenceOnly?: boolean;
51
- model: {
52
- /** Model(s) for AWS deployment. Tries candidates in order; throws if all fail. */
53
- deployed: ModelConfig | ModelConfig[];
51
+ model?: {
52
+ /** Model(s) for AWS deployment. Tries candidates in order; throws if all fail. Defaults to BedrockModels.BALANCED. */
53
+ deployed?: ModelConfig | ModelConfig[];
54
54
  /** Model(s) for local development. Tries candidates in order; canned is implicit last fallback. */
55
55
  local?: ModelConfig | ModelConfig[];
56
56
  };
@@ -251,7 +251,7 @@ export interface ToolCallRecord {
251
251
 
252
252
  export interface StreamOptions<TContext = DefaultToolContext> {
253
253
  conversationId?: string;
254
- /** Channel ID for Realtime delivery. Defaults to conversationId or a random UUID. */
254
+ /** Channel ID for Realtime delivery. Defaults to conversationId or a random UUID. Empty strings are treated as unset. */
255
255
  channelId?: string;
256
256
  /** User ID for conversation scoping. Defaults to 'anonymous'. */
257
257
  userId?: string;
@@ -264,14 +264,30 @@ export interface StreamOptions<TContext = DefaultToolContext> {
264
264
  context?: TContext;
265
265
  }
266
266
 
267
- /** Returned by stream(). Provides the channelId and server-side convenience methods. */
267
+ /**
268
+ * Returned by stream(). Provides the channelId and server-side convenience methods.
269
+ *
270
+ * Safe to return directly from API methods — `toJSON()` serializes to
271
+ * `{ channelId, channel: null }`. Only `channelId` is meaningful client-side;
272
+ * `channel` is explicitly `null` to signal the live handle is server-side only,
273
+ * and the `complete()` helper is dropped (functions don't serialize).
274
+ */
268
275
  export interface AgentStreamResult {
269
276
  /** Realtime channel ID where chunks are published. */
270
277
  channelId: string;
271
- /** Realtime channel handle — subscribe to streaming chunks or return to client as Transferable. */
278
+ /**
279
+ * Realtime channel handle (server-side only). Nulled by `toJSON()` — clients subscribe from `channelId` instead.
280
+ *
281
+ * @remarks
282
+ * Unlike `RealtimeChannel.toJSON()` which produces a hydratable descriptor, this is nulled
283
+ * because it's a `Promise` that can't round-trip. Clients reconstruct a subscribe-only
284
+ * channel from `channelId` via the `useChat` `subscribe` callback.
285
+ */
272
286
  channel: Promise<RealtimeChannel<AgentStreamChunk>>;
273
287
  /** Wait for the complete response (server-side). Resolves when the done chunk arrives. */
274
288
  complete: () => Promise<AgentStreamChunk>;
289
+ /** Only `{ channelId, channel: null }` is serialized when this object crosses the RPC boundary. */
290
+ toJSON(): { channelId: string; channel: null };
275
291
  }
276
292
 
277
293
  export interface AgentStreamChunk {
package/src/version.ts CHANGED
@@ -1,3 +1,3 @@
1
1
  // Auto-generated by scripts/generate-version.mjs — do not edit manually
2
2
  export const BB_NAME = 'Agent';
3
- export const BB_VERSION = '0.1.2';
3
+ export const BB_VERSION = '0.3.0';