@strands-agents/sdk 0.4.0 → 0.6.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/dist/src/__fixtures__/agent-helpers.d.ts +10 -1
- package/dist/src/__fixtures__/agent-helpers.d.ts.map +1 -1
- package/dist/src/__fixtures__/agent-helpers.js +13 -2
- package/dist/src/__fixtures__/agent-helpers.js.map +1 -1
- package/dist/src/__fixtures__/metrics-helpers.d.ts +25 -0
- package/dist/src/__fixtures__/metrics-helpers.d.ts.map +1 -0
- package/dist/src/__fixtures__/metrics-helpers.js +34 -0
- package/dist/src/__fixtures__/metrics-helpers.js.map +1 -0
- package/dist/src/__fixtures__/mock-message-model.d.ts.map +1 -1
- package/dist/src/__fixtures__/mock-message-model.js +12 -0
- package/dist/src/__fixtures__/mock-message-model.js.map +1 -1
- package/dist/src/__fixtures__/mock-span.d.ts +78 -0
- package/dist/src/__fixtures__/mock-span.d.ts.map +1 -0
- package/dist/src/__fixtures__/mock-span.js +93 -0
- package/dist/src/__fixtures__/mock-span.js.map +1 -0
- package/dist/src/__fixtures__/mock-storage-provider.d.ts +5 -0
- package/dist/src/__fixtures__/mock-storage-provider.d.ts.map +1 -1
- package/dist/src/__fixtures__/mock-storage-provider.js +23 -6
- package/dist/src/__fixtures__/mock-storage-provider.js.map +1 -1
- package/dist/src/__fixtures__/slim-types.d.ts +2 -1
- package/dist/src/__fixtures__/slim-types.d.ts.map +1 -1
- package/dist/src/__fixtures__/tool-helpers.d.ts +2 -2
- package/dist/src/__fixtures__/tool-helpers.d.ts.map +1 -1
- package/dist/src/__fixtures__/tool-helpers.js +4 -4
- package/dist/src/__fixtures__/tool-helpers.js.map +1 -1
- package/dist/src/__tests__/app-state.test.d.ts +2 -0
- package/dist/src/__tests__/app-state.test.d.ts.map +1 -0
- package/dist/src/{agent/__tests__/state.test.js → __tests__/app-state.test.js} +46 -46
- package/dist/src/__tests__/app-state.test.js.map +1 -0
- package/dist/src/__tests__/mcp.test.js +129 -18
- package/dist/src/__tests__/mcp.test.js.map +1 -1
- package/dist/src/agent/__tests__/agent.test.js +119 -11
- package/dist/src/agent/__tests__/agent.test.js.map +1 -1
- package/dist/src/agent/__tests__/agent.tracer.test.d.ts +2 -0
- package/dist/src/agent/__tests__/agent.tracer.test.d.ts.map +1 -0
- package/dist/src/agent/__tests__/agent.tracer.test.js +470 -0
- package/dist/src/agent/__tests__/agent.tracer.test.js.map +1 -0
- package/dist/src/agent/agent.d.ts +79 -9
- package/dist/src/agent/agent.d.ts.map +1 -1
- package/dist/src/agent/agent.js +253 -68
- package/dist/src/agent/agent.js.map +1 -1
- package/dist/src/{agent/state.d.ts → app-state.d.ts} +7 -7
- package/dist/src/app-state.d.ts.map +1 -0
- package/dist/src/{agent/state.js → app-state.js} +6 -6
- package/dist/src/app-state.js.map +1 -0
- package/dist/src/conversation-manager/sliding-window-conversation-manager.d.ts +1 -1
- package/dist/src/conversation-manager/sliding-window-conversation-manager.js +1 -1
- package/dist/src/errors.d.ts +6 -0
- package/dist/src/errors.d.ts.map +1 -1
- package/dist/src/errors.js +9 -0
- package/dist/src/errors.js.map +1 -1
- package/dist/src/hooks/__tests__/events.test.js +2 -0
- package/dist/src/hooks/__tests__/events.test.js.map +1 -1
- package/dist/src/hooks/events.d.ts +16 -0
- package/dist/src/hooks/events.d.ts.map +1 -1
- package/dist/src/hooks/events.js.map +1 -1
- package/dist/src/hooks/index.d.ts +1 -1
- package/dist/src/hooks/index.d.ts.map +1 -1
- package/dist/src/index.d.ts +23 -7
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +19 -2
- package/dist/src/index.js.map +1 -1
- package/dist/src/mcp.d.ts +41 -0
- package/dist/src/mcp.d.ts.map +1 -1
- package/dist/src/mcp.js +60 -6
- package/dist/src/mcp.js.map +1 -1
- package/dist/src/models/__tests__/bedrock.test.js +688 -0
- package/dist/src/models/__tests__/bedrock.test.js.map +1 -1
- package/dist/src/models/__tests__/model.test.js +113 -0
- package/dist/src/models/__tests__/model.test.js.map +1 -1
- package/dist/src/models/__tests__/streaming.test.d.ts +2 -0
- package/dist/src/models/__tests__/streaming.test.d.ts.map +1 -0
- package/dist/src/models/__tests__/streaming.test.js +50 -0
- package/dist/src/models/__tests__/streaming.test.js.map +1 -0
- package/dist/src/models/bedrock.d.ts +80 -1
- package/dist/src/models/bedrock.d.ts.map +1 -1
- package/dist/src/models/bedrock.js +214 -5
- package/dist/src/models/bedrock.js.map +1 -1
- package/dist/src/models/model.d.ts +10 -0
- package/dist/src/models/model.d.ts.map +1 -1
- package/dist/src/models/model.js +58 -2
- package/dist/src/models/model.js.map +1 -1
- package/dist/src/models/streaming.d.ts +84 -3
- package/dist/src/models/streaming.d.ts.map +1 -1
- package/dist/src/models/streaming.js +26 -0
- package/dist/src/models/streaming.js.map +1 -1
- package/dist/src/multiagent/__tests__/events.test.d.ts +2 -0
- package/dist/src/multiagent/__tests__/events.test.d.ts.map +1 -0
- package/dist/src/multiagent/__tests__/events.test.js +205 -0
- package/dist/src/multiagent/__tests__/events.test.js.map +1 -0
- package/dist/src/multiagent/__tests__/graph.test.d.ts +2 -0
- package/dist/src/multiagent/__tests__/graph.test.d.ts.map +1 -0
- package/dist/src/multiagent/__tests__/graph.test.js +438 -0
- package/dist/src/multiagent/__tests__/graph.test.js.map +1 -0
- package/dist/src/multiagent/__tests__/nodes.test.js +105 -9
- package/dist/src/multiagent/__tests__/nodes.test.js.map +1 -1
- package/dist/src/multiagent/__tests__/queue.test.d.ts +2 -0
- package/dist/src/multiagent/__tests__/queue.test.d.ts.map +1 -0
- package/dist/src/multiagent/__tests__/queue.test.js +118 -0
- package/dist/src/multiagent/__tests__/queue.test.js.map +1 -0
- package/dist/src/multiagent/__tests__/swarm.test.d.ts +2 -0
- package/dist/src/multiagent/__tests__/swarm.test.d.ts.map +1 -0
- package/dist/src/multiagent/__tests__/swarm.test.js +241 -0
- package/dist/src/multiagent/__tests__/swarm.test.js.map +1 -0
- package/dist/src/multiagent/base.d.ts +25 -0
- package/dist/src/multiagent/base.d.ts.map +1 -0
- package/dist/src/multiagent/base.js +2 -0
- package/dist/src/multiagent/base.js.map +1 -0
- package/dist/src/multiagent/edge.d.ts +36 -0
- package/dist/src/multiagent/edge.d.ts.map +1 -0
- package/dist/src/multiagent/edge.js +15 -0
- package/dist/src/multiagent/edge.js.map +1 -0
- package/dist/src/multiagent/events.d.ts +129 -4
- package/dist/src/multiagent/events.d.ts.map +1 -1
- package/dist/src/multiagent/events.js +140 -2
- package/dist/src/multiagent/events.js.map +1 -1
- package/dist/src/multiagent/graph.d.ts +125 -0
- package/dist/src/multiagent/graph.d.ts.map +1 -0
- package/dist/src/multiagent/graph.js +394 -0
- package/dist/src/multiagent/graph.js.map +1 -0
- package/dist/src/multiagent/index.d.ts +12 -6
- package/dist/src/multiagent/index.d.ts.map +1 -1
- package/dist/src/multiagent/index.js +6 -3
- package/dist/src/multiagent/index.js.map +1 -1
- package/dist/src/multiagent/nodes.d.ts +66 -16
- package/dist/src/multiagent/nodes.d.ts.map +1 -1
- package/dist/src/multiagent/nodes.js +82 -24
- package/dist/src/multiagent/nodes.js.map +1 -1
- package/dist/src/multiagent/queue.d.ts +73 -0
- package/dist/src/multiagent/queue.d.ts.map +1 -0
- package/dist/src/multiagent/queue.js +72 -0
- package/dist/src/multiagent/queue.js.map +1 -0
- package/dist/src/multiagent/state.d.ts +79 -10
- package/dist/src/multiagent/state.d.ts.map +1 -1
- package/dist/src/multiagent/state.js +101 -9
- package/dist/src/multiagent/state.js.map +1 -1
- package/dist/src/multiagent/swarm.d.ts +102 -0
- package/dist/src/multiagent/swarm.d.ts.map +1 -0
- package/dist/src/multiagent/swarm.js +238 -0
- package/dist/src/multiagent/swarm.js.map +1 -0
- package/dist/src/registry/__tests__/tool-registry.test.d.ts +2 -0
- package/dist/src/registry/__tests__/tool-registry.test.d.ts.map +1 -0
- package/dist/src/registry/__tests__/tool-registry.test.js +124 -0
- package/dist/src/registry/__tests__/tool-registry.test.js.map +1 -0
- package/dist/src/registry/tool-registry.d.ts +32 -20
- package/dist/src/registry/tool-registry.d.ts.map +1 -1
- package/dist/src/registry/tool-registry.js +60 -158
- package/dist/src/registry/tool-registry.js.map +1 -1
- package/dist/src/session/__tests__/file-storage.test.node.js +75 -15
- package/dist/src/session/__tests__/file-storage.test.node.js.map +1 -1
- package/dist/src/session/__tests__/s3-storage.test.d.ts +2 -0
- package/dist/src/session/__tests__/s3-storage.test.d.ts.map +1 -0
- package/dist/src/session/__tests__/{s3-storage.test.node.js → s3-storage.test.js} +161 -75
- package/dist/src/session/__tests__/s3-storage.test.js.map +1 -0
- package/dist/src/session/__tests__/session-manager.test.d.ts +2 -0
- package/dist/src/session/__tests__/session-manager.test.d.ts.map +1 -0
- package/dist/src/session/__tests__/session-manager.test.js +461 -0
- package/dist/src/session/__tests__/session-manager.test.js.map +1 -0
- package/dist/src/session/__tests__/validation.test.js +28 -1
- package/dist/src/session/__tests__/validation.test.js.map +1 -1
- package/dist/src/session/file-storage.d.ts +53 -27
- package/dist/src/session/file-storage.d.ts.map +1 -1
- package/dist/src/session/file-storage.js +103 -52
- package/dist/src/session/file-storage.js.map +1 -1
- package/dist/src/session/index.d.ts +6 -13
- package/dist/src/session/index.d.ts.map +1 -1
- package/dist/src/session/index.js +4 -12
- package/dist/src/session/index.js.map +1 -1
- package/dist/src/session/s3-storage.d.ts +49 -20
- package/dist/src/session/s3-storage.d.ts.map +1 -1
- package/dist/src/session/s3-storage.js +120 -35
- package/dist/src/session/s3-storage.js.map +1 -1
- package/dist/src/session/session-manager.d.ts +83 -0
- package/dist/src/session/session-manager.d.ts.map +1 -0
- package/dist/src/session/session-manager.js +122 -0
- package/dist/src/session/session-manager.js.map +1 -0
- package/dist/src/session/storage.d.ts +19 -11
- package/dist/src/session/storage.d.ts.map +1 -1
- package/dist/src/session/types.d.ts +6 -18
- package/dist/src/session/types.d.ts.map +1 -1
- package/dist/src/session/validation.d.ts +7 -0
- package/dist/src/session/validation.d.ts.map +1 -1
- package/dist/src/session/validation.js +12 -0
- package/dist/src/session/validation.js.map +1 -1
- package/dist/src/structured-output/__tests__/context.test.js +13 -13
- package/dist/src/structured-output/__tests__/context.test.js.map +1 -1
- package/dist/src/structured-output/context.js +1 -1
- package/dist/src/structured-output/context.js.map +1 -1
- package/dist/src/telemetry/__tests__/config.test.d.ts +2 -0
- package/dist/src/telemetry/__tests__/config.test.d.ts.map +1 -0
- package/dist/src/telemetry/__tests__/config.test.js +40 -0
- package/dist/src/telemetry/__tests__/config.test.js.map +1 -0
- package/dist/src/telemetry/__tests__/config.test.node.d.ts +2 -0
- package/dist/src/telemetry/__tests__/config.test.node.d.ts.map +1 -0
- package/dist/src/telemetry/__tests__/config.test.node.js +103 -0
- package/dist/src/telemetry/__tests__/config.test.node.js.map +1 -0
- package/dist/src/telemetry/__tests__/json.test.d.ts +2 -0
- package/dist/src/telemetry/__tests__/json.test.d.ts.map +1 -0
- package/dist/src/telemetry/__tests__/json.test.js +89 -0
- package/dist/src/telemetry/__tests__/json.test.js.map +1 -0
- package/dist/src/telemetry/__tests__/meter.test.d.ts +2 -0
- package/dist/src/telemetry/__tests__/meter.test.d.ts.map +1 -0
- package/dist/src/telemetry/__tests__/meter.test.js +457 -0
- package/dist/src/telemetry/__tests__/meter.test.js.map +1 -0
- package/dist/src/telemetry/__tests__/tracer.test.node.d.ts +2 -0
- package/dist/src/telemetry/__tests__/tracer.test.node.d.ts.map +1 -0
- package/dist/src/telemetry/__tests__/tracer.test.node.js +611 -0
- package/dist/src/telemetry/__tests__/tracer.test.node.js.map +1 -0
- package/dist/src/telemetry/config.d.ts +82 -0
- package/dist/src/telemetry/config.d.ts.map +1 -0
- package/dist/src/telemetry/config.js +133 -0
- package/dist/src/telemetry/config.js.map +1 -0
- package/dist/src/telemetry/index.d.ts +34 -0
- package/dist/src/telemetry/index.d.ts.map +1 -0
- package/dist/src/telemetry/index.js +33 -0
- package/dist/src/telemetry/index.js.map +1 -0
- package/dist/src/telemetry/json.d.ts +11 -0
- package/dist/src/telemetry/json.d.ts.map +1 -0
- package/dist/src/telemetry/json.js +25 -0
- package/dist/src/telemetry/json.js.map +1 -0
- package/dist/src/telemetry/meter.d.ts +277 -0
- package/dist/src/telemetry/meter.d.ts.map +1 -0
- package/dist/src/telemetry/meter.js +292 -0
- package/dist/src/telemetry/meter.js.map +1 -0
- package/dist/src/telemetry/tracer.d.ts +219 -0
- package/dist/src/telemetry/tracer.d.ts.map +1 -0
- package/dist/src/telemetry/tracer.js +610 -0
- package/dist/src/telemetry/tracer.js.map +1 -0
- package/dist/src/telemetry/types.d.ts +101 -0
- package/dist/src/telemetry/types.d.ts.map +1 -0
- package/dist/src/telemetry/types.js +5 -0
- package/dist/src/{multiagent → telemetry}/types.js.map +1 -1
- package/dist/src/tools/__tests__/tool-factory.test.d.ts +2 -0
- package/dist/src/tools/__tests__/tool-factory.test.d.ts.map +1 -0
- package/dist/src/tools/__tests__/tool-factory.test.js +98 -0
- package/dist/src/tools/__tests__/tool-factory.test.js.map +1 -0
- package/dist/src/tools/__tests__/zod-tool.test-d.js +1 -1
- package/dist/src/tools/__tests__/zod-tool.test-d.js.map +1 -1
- package/dist/src/tools/__tests__/zod-tool.test.js +3 -4
- package/dist/src/tools/__tests__/zod-tool.test.js.map +1 -1
- package/dist/src/tools/function-tool.d.ts +15 -2
- package/dist/src/tools/function-tool.d.ts.map +1 -1
- package/dist/src/tools/function-tool.js +24 -0
- package/dist/src/tools/function-tool.js.map +1 -1
- package/dist/src/tools/tool-factory.d.ts +22 -0
- package/dist/src/tools/tool-factory.d.ts.map +1 -0
- package/dist/src/tools/tool-factory.js +55 -0
- package/dist/src/tools/tool-factory.js.map +1 -0
- package/dist/src/tools/tool.d.ts +1 -1
- package/dist/src/tools/tool.js +1 -1
- package/dist/src/tools/zod-tool.d.ts +55 -52
- package/dist/src/tools/zod-tool.d.ts.map +1 -1
- package/dist/src/tools/zod-tool.js +7 -61
- package/dist/src/tools/zod-tool.js.map +1 -1
- package/dist/src/tsconfig.tsbuildinfo +1 -1
- package/dist/src/types/__tests__/agent.test.js +11 -0
- package/dist/src/types/__tests__/agent.test.js.map +1 -1
- package/dist/src/types/__tests__/citations.test.d.ts +2 -0
- package/dist/src/types/__tests__/citations.test.d.ts.map +1 -0
- package/dist/src/types/__tests__/citations.test.js +104 -0
- package/dist/src/types/__tests__/citations.test.js.map +1 -0
- package/dist/src/types/__tests__/messages.test.js +26 -0
- package/dist/src/types/__tests__/messages.test.js.map +1 -1
- package/dist/src/types/agent.d.ts +10 -3
- package/dist/src/types/agent.d.ts.map +1 -1
- package/dist/src/types/agent.js +9 -0
- package/dist/src/types/agent.js.map +1 -1
- package/dist/src/types/citations.d.ts +180 -0
- package/dist/src/types/citations.d.ts.map +1 -0
- package/dist/src/types/citations.js +45 -0
- package/dist/src/types/citations.js.map +1 -0
- package/dist/src/types/messages.d.ts +9 -5
- package/dist/src/types/messages.d.ts.map +1 -1
- package/dist/src/types/messages.js +5 -1
- package/dist/src/types/messages.js.map +1 -1
- package/dist/src/vended-tools/bash/__tests__/bash.test.node.js +2 -2
- package/dist/src/vended-tools/bash/__tests__/bash.test.node.js.map +1 -1
- package/dist/src/vended-tools/bash/bash.d.ts.map +1 -1
- package/dist/src/vended-tools/bash/bash.js +1 -2
- package/dist/src/vended-tools/bash/bash.js.map +1 -1
- package/dist/src/vended-tools/file_editor/__tests__/file-editor.test.node.js +4 -4
- package/dist/src/vended-tools/file_editor/__tests__/file-editor.test.node.js.map +1 -1
- package/dist/src/vended-tools/file_editor/file-editor.js +1 -1
- package/dist/src/vended-tools/file_editor/file-editor.js.map +1 -1
- package/dist/src/vended-tools/http_request/http-request.d.ts.map +1 -1
- package/dist/src/vended-tools/http_request/http-request.js +1 -2
- package/dist/src/vended-tools/http_request/http-request.js.map +1 -1
- package/dist/src/vended-tools/notebook/__tests__/notebook.test.js +2 -2
- package/dist/src/vended-tools/notebook/__tests__/notebook.test.js.map +1 -1
- package/dist/src/vended-tools/notebook/notebook.d.ts +1 -1
- package/package.json +25 -4
- package/dist/src/agent/__tests__/state.test.d.ts +0 -2
- package/dist/src/agent/__tests__/state.test.d.ts.map +0 -1
- package/dist/src/agent/__tests__/state.test.js.map +0 -1
- package/dist/src/agent/state.d.ts.map +0 -1
- package/dist/src/agent/state.js.map +0 -1
- package/dist/src/multiagent/types.d.ts +0 -5
- package/dist/src/multiagent/types.d.ts.map +0 -1
- package/dist/src/multiagent/types.js +0 -2
- package/dist/src/registry/registry.d.ts +0 -117
- package/dist/src/registry/registry.d.ts.map +0 -1
- package/dist/src/registry/registry.js +0 -298
- package/dist/src/registry/registry.js.map +0 -1
- package/dist/src/session/__tests__/s3-storage.test.node.d.ts +0 -2
- package/dist/src/session/__tests__/s3-storage.test.node.d.ts.map +0 -1
- package/dist/src/session/__tests__/s3-storage.test.node.js.map +0 -1
|
@@ -5,6 +5,7 @@ import { BedrockModel } from '../bedrock.js';
|
|
|
5
5
|
import { ContextWindowOverflowError, ModelThrottledError } from '../../errors.js';
|
|
6
6
|
import { Message, ReasoningBlock, ToolUseBlock, ToolResultBlock, JsonBlock } from '../../types/messages.js';
|
|
7
7
|
import { TextBlock, GuardContentBlock, CachePointBlock } from '../../types/messages.js';
|
|
8
|
+
import { CitationsBlock } from '../../types/citations.js';
|
|
8
9
|
import { collectIterator } from '../../__fixtures__/model-test-helpers.js';
|
|
9
10
|
/**
|
|
10
11
|
* Helper function to mock BedrockRuntimeClient implementation with customizable config.
|
|
@@ -687,6 +688,77 @@ describe('BedrockModel', () => {
|
|
|
687
688
|
metrics: { latencyMs: 110 },
|
|
688
689
|
});
|
|
689
690
|
});
|
|
691
|
+
it('yields and validates citationsContent events correctly', async () => {
|
|
692
|
+
// Bedrock wire format uses object-key discrimination
|
|
693
|
+
const bedrockCitationsData = {
|
|
694
|
+
citations: [
|
|
695
|
+
{
|
|
696
|
+
location: { documentChar: { documentIndex: 0, start: 10, end: 50 } },
|
|
697
|
+
sourceContent: [{ text: 'source text' }],
|
|
698
|
+
source: 'doc-0',
|
|
699
|
+
title: 'Test Doc',
|
|
700
|
+
},
|
|
701
|
+
],
|
|
702
|
+
content: [{ text: 'generated text' }],
|
|
703
|
+
};
|
|
704
|
+
const mockSend = vi.fn(async () => {
|
|
705
|
+
if (stream) {
|
|
706
|
+
return {
|
|
707
|
+
stream: (async function* () {
|
|
708
|
+
yield { messageStart: { role: 'assistant' } };
|
|
709
|
+
yield { contentBlockStart: {} };
|
|
710
|
+
yield {
|
|
711
|
+
contentBlockDelta: {
|
|
712
|
+
delta: { citationsContent: bedrockCitationsData },
|
|
713
|
+
},
|
|
714
|
+
};
|
|
715
|
+
yield { contentBlockStop: {} };
|
|
716
|
+
yield { messageStop: { stopReason: 'end_turn' } };
|
|
717
|
+
yield {
|
|
718
|
+
metadata: { usage: { inputTokens: 10, outputTokens: 5, totalTokens: 15 }, metrics: { latencyMs: 100 } },
|
|
719
|
+
};
|
|
720
|
+
})(),
|
|
721
|
+
};
|
|
722
|
+
}
|
|
723
|
+
else {
|
|
724
|
+
return {
|
|
725
|
+
output: {
|
|
726
|
+
message: {
|
|
727
|
+
role: 'assistant',
|
|
728
|
+
content: [{ citationsContent: bedrockCitationsData }],
|
|
729
|
+
},
|
|
730
|
+
},
|
|
731
|
+
stopReason: 'end_turn',
|
|
732
|
+
usage: { inputTokens: 10, outputTokens: 5, totalTokens: 15 },
|
|
733
|
+
metrics: { latencyMs: 100 },
|
|
734
|
+
};
|
|
735
|
+
}
|
|
736
|
+
});
|
|
737
|
+
mockBedrockClientImplementation({ send: mockSend });
|
|
738
|
+
const provider = new BedrockModel({ stream });
|
|
739
|
+
const messages = [new Message({ role: 'user', content: [new TextBlock('Cite this.')] })];
|
|
740
|
+
const events = await collectIterator(provider.stream(messages));
|
|
741
|
+
// SDK events should use type-field discrimination
|
|
742
|
+
expect(events).toContainEqual({ role: 'assistant', type: 'modelMessageStartEvent' });
|
|
743
|
+
expect(events).toContainEqual({ type: 'modelContentBlockStartEvent' });
|
|
744
|
+
expect(events).toContainEqual({
|
|
745
|
+
type: 'modelContentBlockDeltaEvent',
|
|
746
|
+
delta: {
|
|
747
|
+
type: 'citationsDelta',
|
|
748
|
+
citations: [
|
|
749
|
+
{
|
|
750
|
+
location: { type: 'documentChar', documentIndex: 0, start: 10, end: 50 },
|
|
751
|
+
sourceContent: [{ text: 'source text' }],
|
|
752
|
+
source: 'doc-0',
|
|
753
|
+
title: 'Test Doc',
|
|
754
|
+
},
|
|
755
|
+
],
|
|
756
|
+
content: [{ text: 'generated text' }],
|
|
757
|
+
},
|
|
758
|
+
});
|
|
759
|
+
expect(events).toContainEqual({ type: 'modelContentBlockStopEvent' });
|
|
760
|
+
expect(events).toContainEqual({ stopReason: 'endTurn', type: 'modelMessageStopEvent' });
|
|
761
|
+
});
|
|
690
762
|
describe('error handling', async () => {
|
|
691
763
|
it.each([
|
|
692
764
|
{
|
|
@@ -1308,6 +1380,114 @@ describe('BedrockModel', () => {
|
|
|
1308
1380
|
});
|
|
1309
1381
|
});
|
|
1310
1382
|
});
|
|
1383
|
+
describe('citations content block formatting', () => {
|
|
1384
|
+
const mockConverseStreamCommand = vi.mocked(ConverseStreamCommand);
|
|
1385
|
+
it('maps SDK CitationLocation types to Bedrock object-key format through formatting pipeline', async () => {
|
|
1386
|
+
const provider = new BedrockModel();
|
|
1387
|
+
// SDK format uses type-field discrimination
|
|
1388
|
+
const sdkCitations = [
|
|
1389
|
+
{
|
|
1390
|
+
location: { type: 'documentChar', documentIndex: 0, start: 150, end: 300 },
|
|
1391
|
+
source: 'doc-0',
|
|
1392
|
+
sourceContent: [{ text: 'char source' }],
|
|
1393
|
+
title: 'Text Document',
|
|
1394
|
+
},
|
|
1395
|
+
{
|
|
1396
|
+
location: { type: 'documentPage', documentIndex: 0, start: 2, end: 3 },
|
|
1397
|
+
source: 'doc-0',
|
|
1398
|
+
sourceContent: [{ text: 'page source' }],
|
|
1399
|
+
title: 'PDF Document',
|
|
1400
|
+
},
|
|
1401
|
+
{
|
|
1402
|
+
location: { type: 'documentChunk', documentIndex: 1, start: 5, end: 8 },
|
|
1403
|
+
source: 'doc-1',
|
|
1404
|
+
sourceContent: [{ text: 'chunk source' }],
|
|
1405
|
+
title: 'Chunked Document',
|
|
1406
|
+
},
|
|
1407
|
+
{
|
|
1408
|
+
location: { type: 'searchResult', searchResultIndex: 0, start: 25, end: 150 },
|
|
1409
|
+
source: 'search-0',
|
|
1410
|
+
sourceContent: [{ text: 'search source' }],
|
|
1411
|
+
title: 'Search Result',
|
|
1412
|
+
},
|
|
1413
|
+
{
|
|
1414
|
+
location: { type: 'web', url: 'https://example.com/doc', domain: 'example.com' },
|
|
1415
|
+
source: 'web-0',
|
|
1416
|
+
sourceContent: [{ text: 'web source' }],
|
|
1417
|
+
title: 'Web Page',
|
|
1418
|
+
},
|
|
1419
|
+
];
|
|
1420
|
+
const messages = [
|
|
1421
|
+
new Message({
|
|
1422
|
+
role: 'assistant',
|
|
1423
|
+
content: [
|
|
1424
|
+
new CitationsBlock({
|
|
1425
|
+
citations: sdkCitations,
|
|
1426
|
+
content: [{ text: 'generated text with all citation types' }],
|
|
1427
|
+
}),
|
|
1428
|
+
],
|
|
1429
|
+
}),
|
|
1430
|
+
new Message({
|
|
1431
|
+
role: 'user',
|
|
1432
|
+
content: [new TextBlock('Follow up')],
|
|
1433
|
+
}),
|
|
1434
|
+
];
|
|
1435
|
+
collectIterator(provider.stream(messages));
|
|
1436
|
+
// Bedrock wire format uses object-key discrimination
|
|
1437
|
+
expect(mockConverseStreamCommand).toHaveBeenLastCalledWith(expect.objectContaining({
|
|
1438
|
+
messages: [
|
|
1439
|
+
{
|
|
1440
|
+
role: 'assistant',
|
|
1441
|
+
content: [
|
|
1442
|
+
{
|
|
1443
|
+
citationsContent: {
|
|
1444
|
+
citations: [
|
|
1445
|
+
{
|
|
1446
|
+
location: { documentChar: { documentIndex: 0, start: 150, end: 300 } },
|
|
1447
|
+
source: 'doc-0',
|
|
1448
|
+
sourceContent: [{ text: 'char source' }],
|
|
1449
|
+
title: 'Text Document',
|
|
1450
|
+
},
|
|
1451
|
+
{
|
|
1452
|
+
location: { documentPage: { documentIndex: 0, start: 2, end: 3 } },
|
|
1453
|
+
source: 'doc-0',
|
|
1454
|
+
sourceContent: [{ text: 'page source' }],
|
|
1455
|
+
title: 'PDF Document',
|
|
1456
|
+
},
|
|
1457
|
+
{
|
|
1458
|
+
location: { documentChunk: { documentIndex: 1, start: 5, end: 8 } },
|
|
1459
|
+
source: 'doc-1',
|
|
1460
|
+
sourceContent: [{ text: 'chunk source' }],
|
|
1461
|
+
title: 'Chunked Document',
|
|
1462
|
+
},
|
|
1463
|
+
{
|
|
1464
|
+
location: {
|
|
1465
|
+
searchResultLocation: { searchResultIndex: 0, start: 25, end: 150 },
|
|
1466
|
+
},
|
|
1467
|
+
source: 'search-0',
|
|
1468
|
+
sourceContent: [{ text: 'search source' }],
|
|
1469
|
+
title: 'Search Result',
|
|
1470
|
+
},
|
|
1471
|
+
{
|
|
1472
|
+
location: { web: { url: 'https://example.com/doc', domain: 'example.com' } },
|
|
1473
|
+
source: 'web-0',
|
|
1474
|
+
sourceContent: [{ text: 'web source' }],
|
|
1475
|
+
title: 'Web Page',
|
|
1476
|
+
},
|
|
1477
|
+
],
|
|
1478
|
+
content: [{ text: 'generated text with all citation types' }],
|
|
1479
|
+
},
|
|
1480
|
+
},
|
|
1481
|
+
],
|
|
1482
|
+
},
|
|
1483
|
+
{
|
|
1484
|
+
role: 'user',
|
|
1485
|
+
content: [{ text: 'Follow up' }],
|
|
1486
|
+
},
|
|
1487
|
+
],
|
|
1488
|
+
}));
|
|
1489
|
+
});
|
|
1490
|
+
});
|
|
1311
1491
|
describe('includeToolResultStatus configuration', async () => {
|
|
1312
1492
|
const mockConverseStreamCommand = vi.mocked(ConverseStreamCommand);
|
|
1313
1493
|
describe('when includeToolResultStatus is true', () => {
|
|
@@ -1492,5 +1672,513 @@ describe('BedrockModel', () => {
|
|
|
1492
1672
|
await expect(provider['_client'].config.region()).rejects.toThrow('Network error');
|
|
1493
1673
|
});
|
|
1494
1674
|
});
|
|
1675
|
+
describe('guardrail configuration', () => {
|
|
1676
|
+
const mockConverseStreamCommand = vi.mocked(ConverseStreamCommand);
|
|
1677
|
+
beforeEach(() => {
|
|
1678
|
+
vi.clearAllMocks();
|
|
1679
|
+
});
|
|
1680
|
+
describe('constructor', () => {
|
|
1681
|
+
it('accepts guardrailConfig in options', () => {
|
|
1682
|
+
const provider = new BedrockModel({
|
|
1683
|
+
guardrailConfig: {
|
|
1684
|
+
guardrailIdentifier: 'my-guardrail-id',
|
|
1685
|
+
guardrailVersion: '1',
|
|
1686
|
+
},
|
|
1687
|
+
});
|
|
1688
|
+
expect(provider.getConfig().guardrailConfig).toStrictEqual({
|
|
1689
|
+
guardrailIdentifier: 'my-guardrail-id',
|
|
1690
|
+
guardrailVersion: '1',
|
|
1691
|
+
});
|
|
1692
|
+
});
|
|
1693
|
+
it('accepts guardrailConfig with all options', () => {
|
|
1694
|
+
const provider = new BedrockModel({
|
|
1695
|
+
guardrailConfig: {
|
|
1696
|
+
guardrailIdentifier: 'my-guardrail-id',
|
|
1697
|
+
guardrailVersion: '1',
|
|
1698
|
+
trace: 'enabled_full',
|
|
1699
|
+
streamProcessingMode: 'sync',
|
|
1700
|
+
redaction: {
|
|
1701
|
+
input: true,
|
|
1702
|
+
inputMessage: '[Custom input redacted.]',
|
|
1703
|
+
output: true,
|
|
1704
|
+
outputMessage: '[Custom output redacted.]',
|
|
1705
|
+
},
|
|
1706
|
+
},
|
|
1707
|
+
});
|
|
1708
|
+
expect(provider.getConfig().guardrailConfig).toStrictEqual({
|
|
1709
|
+
guardrailIdentifier: 'my-guardrail-id',
|
|
1710
|
+
guardrailVersion: '1',
|
|
1711
|
+
trace: 'enabled_full',
|
|
1712
|
+
streamProcessingMode: 'sync',
|
|
1713
|
+
redaction: {
|
|
1714
|
+
input: true,
|
|
1715
|
+
inputMessage: '[Custom input redacted.]',
|
|
1716
|
+
output: true,
|
|
1717
|
+
outputMessage: '[Custom output redacted.]',
|
|
1718
|
+
},
|
|
1719
|
+
});
|
|
1720
|
+
});
|
|
1721
|
+
});
|
|
1722
|
+
describe('request formatting', () => {
|
|
1723
|
+
it('includes guardrailConfig in request with default trace', async () => {
|
|
1724
|
+
const provider = new BedrockModel({
|
|
1725
|
+
guardrailConfig: {
|
|
1726
|
+
guardrailIdentifier: 'my-guardrail-id',
|
|
1727
|
+
guardrailVersion: '1',
|
|
1728
|
+
},
|
|
1729
|
+
});
|
|
1730
|
+
const messages = [new Message({ role: 'user', content: [new TextBlock('Hello')] })];
|
|
1731
|
+
collectIterator(provider.stream(messages));
|
|
1732
|
+
expect(mockConverseStreamCommand).toHaveBeenLastCalledWith(expect.objectContaining({
|
|
1733
|
+
guardrailConfig: {
|
|
1734
|
+
guardrailIdentifier: 'my-guardrail-id',
|
|
1735
|
+
guardrailVersion: '1',
|
|
1736
|
+
trace: 'enabled',
|
|
1737
|
+
},
|
|
1738
|
+
}));
|
|
1739
|
+
});
|
|
1740
|
+
it('includes guardrailConfig in request with custom trace', async () => {
|
|
1741
|
+
const provider = new BedrockModel({
|
|
1742
|
+
guardrailConfig: {
|
|
1743
|
+
guardrailIdentifier: 'my-guardrail-id',
|
|
1744
|
+
guardrailVersion: '1',
|
|
1745
|
+
trace: 'disabled',
|
|
1746
|
+
},
|
|
1747
|
+
});
|
|
1748
|
+
const messages = [new Message({ role: 'user', content: [new TextBlock('Hello')] })];
|
|
1749
|
+
collectIterator(provider.stream(messages));
|
|
1750
|
+
expect(mockConverseStreamCommand).toHaveBeenLastCalledWith(expect.objectContaining({
|
|
1751
|
+
guardrailConfig: {
|
|
1752
|
+
guardrailIdentifier: 'my-guardrail-id',
|
|
1753
|
+
guardrailVersion: '1',
|
|
1754
|
+
trace: 'disabled',
|
|
1755
|
+
},
|
|
1756
|
+
}));
|
|
1757
|
+
});
|
|
1758
|
+
it('includes streamProcessingMode when specified', async () => {
|
|
1759
|
+
const provider = new BedrockModel({
|
|
1760
|
+
guardrailConfig: {
|
|
1761
|
+
guardrailIdentifier: 'my-guardrail-id',
|
|
1762
|
+
guardrailVersion: '1',
|
|
1763
|
+
streamProcessingMode: 'sync',
|
|
1764
|
+
},
|
|
1765
|
+
});
|
|
1766
|
+
const messages = [new Message({ role: 'user', content: [new TextBlock('Hello')] })];
|
|
1767
|
+
collectIterator(provider.stream(messages));
|
|
1768
|
+
expect(mockConverseStreamCommand).toHaveBeenLastCalledWith(expect.objectContaining({
|
|
1769
|
+
guardrailConfig: {
|
|
1770
|
+
guardrailIdentifier: 'my-guardrail-id',
|
|
1771
|
+
guardrailVersion: '1',
|
|
1772
|
+
trace: 'enabled',
|
|
1773
|
+
streamProcessingMode: 'sync',
|
|
1774
|
+
},
|
|
1775
|
+
}));
|
|
1776
|
+
});
|
|
1777
|
+
it('does not include guardrailConfig when not configured', async () => {
|
|
1778
|
+
const provider = new BedrockModel();
|
|
1779
|
+
const messages = [new Message({ role: 'user', content: [new TextBlock('Hello')] })];
|
|
1780
|
+
collectIterator(provider.stream(messages));
|
|
1781
|
+
expect(mockConverseStreamCommand).toHaveBeenLastCalledWith(expect.not.objectContaining({
|
|
1782
|
+
guardrailConfig: expect.anything(),
|
|
1783
|
+
}));
|
|
1784
|
+
});
|
|
1785
|
+
});
|
|
1786
|
+
describe('blocked guardrail detection', () => {
|
|
1787
|
+
it('detects blocked guardrail in inputAssessment', async () => {
|
|
1788
|
+
setupMockSend(async function* () {
|
|
1789
|
+
yield { messageStart: { role: 'assistant' } };
|
|
1790
|
+
yield { contentBlockStart: {} };
|
|
1791
|
+
yield { contentBlockDelta: { delta: { text: 'Hello' } } };
|
|
1792
|
+
yield { contentBlockStop: {} };
|
|
1793
|
+
yield { messageStop: { stopReason: 'guardrail_intervened' } };
|
|
1794
|
+
yield {
|
|
1795
|
+
metadata: {
|
|
1796
|
+
usage: { inputTokens: 10, outputTokens: 5, totalTokens: 15 },
|
|
1797
|
+
trace: {
|
|
1798
|
+
guardrail: {
|
|
1799
|
+
inputAssessment: {
|
|
1800
|
+
'1234': {
|
|
1801
|
+
topicPolicy: {
|
|
1802
|
+
topics: [{ name: 'Harmful', action: 'BLOCKED', detected: true }],
|
|
1803
|
+
},
|
|
1804
|
+
},
|
|
1805
|
+
},
|
|
1806
|
+
},
|
|
1807
|
+
},
|
|
1808
|
+
},
|
|
1809
|
+
};
|
|
1810
|
+
});
|
|
1811
|
+
const provider = new BedrockModel({
|
|
1812
|
+
guardrailConfig: {
|
|
1813
|
+
guardrailIdentifier: 'my-guardrail-id',
|
|
1814
|
+
guardrailVersion: '1',
|
|
1815
|
+
},
|
|
1816
|
+
});
|
|
1817
|
+
const messages = [new Message({ role: 'user', content: [new TextBlock('Hello')] })];
|
|
1818
|
+
const events = await collectIterator(provider.stream(messages));
|
|
1819
|
+
const redactEvent = events.find((e) => e.type === 'modelRedactionEvent');
|
|
1820
|
+
expect(redactEvent).toBeDefined();
|
|
1821
|
+
expect(redactEvent).toStrictEqual({
|
|
1822
|
+
type: 'modelRedactionEvent',
|
|
1823
|
+
inputRedaction: { replaceContent: '[User input redacted.]' },
|
|
1824
|
+
});
|
|
1825
|
+
});
|
|
1826
|
+
it('detects blocked guardrail in outputAssessments', async () => {
|
|
1827
|
+
setupMockSend(async function* () {
|
|
1828
|
+
yield { messageStart: { role: 'assistant' } };
|
|
1829
|
+
yield { contentBlockStart: {} };
|
|
1830
|
+
yield { contentBlockDelta: { delta: { text: 'Hello' } } };
|
|
1831
|
+
yield { contentBlockStop: {} };
|
|
1832
|
+
yield { messageStop: { stopReason: 'guardrail_intervened' } };
|
|
1833
|
+
yield {
|
|
1834
|
+
metadata: {
|
|
1835
|
+
usage: { inputTokens: 10, outputTokens: 5, totalTokens: 15 },
|
|
1836
|
+
trace: {
|
|
1837
|
+
guardrail: {
|
|
1838
|
+
outputAssessments: {
|
|
1839
|
+
'1234': {
|
|
1840
|
+
contentPolicy: {
|
|
1841
|
+
filters: [{ type: 'VIOLENCE', action: 'BLOCKED', detected: true }],
|
|
1842
|
+
},
|
|
1843
|
+
},
|
|
1844
|
+
},
|
|
1845
|
+
},
|
|
1846
|
+
},
|
|
1847
|
+
},
|
|
1848
|
+
};
|
|
1849
|
+
});
|
|
1850
|
+
const provider = new BedrockModel({
|
|
1851
|
+
guardrailConfig: {
|
|
1852
|
+
guardrailIdentifier: 'my-guardrail-id',
|
|
1853
|
+
guardrailVersion: '1',
|
|
1854
|
+
},
|
|
1855
|
+
});
|
|
1856
|
+
const messages = [new Message({ role: 'user', content: [new TextBlock('Hello')] })];
|
|
1857
|
+
const events = await collectIterator(provider.stream(messages));
|
|
1858
|
+
const redactEvent = events.find((e) => e.type === 'modelRedactionEvent');
|
|
1859
|
+
expect(redactEvent).toBeDefined();
|
|
1860
|
+
});
|
|
1861
|
+
it('does not emit redaction events when guardrail not blocked', async () => {
|
|
1862
|
+
setupMockSend(async function* () {
|
|
1863
|
+
yield { messageStart: { role: 'assistant' } };
|
|
1864
|
+
yield { contentBlockStart: {} };
|
|
1865
|
+
yield { contentBlockDelta: { delta: { text: 'Hello' } } };
|
|
1866
|
+
yield { contentBlockStop: {} };
|
|
1867
|
+
yield { messageStop: { stopReason: 'end_turn' } };
|
|
1868
|
+
yield {
|
|
1869
|
+
metadata: {
|
|
1870
|
+
usage: { inputTokens: 10, outputTokens: 5, totalTokens: 15 },
|
|
1871
|
+
trace: {
|
|
1872
|
+
guardrail: {
|
|
1873
|
+
inputAssessment: {
|
|
1874
|
+
'1234': {
|
|
1875
|
+
topicPolicy: {
|
|
1876
|
+
topics: [{ name: 'Safe', action: 'NONE', detected: false }],
|
|
1877
|
+
},
|
|
1878
|
+
},
|
|
1879
|
+
},
|
|
1880
|
+
},
|
|
1881
|
+
},
|
|
1882
|
+
},
|
|
1883
|
+
};
|
|
1884
|
+
});
|
|
1885
|
+
const provider = new BedrockModel({
|
|
1886
|
+
guardrailConfig: {
|
|
1887
|
+
guardrailIdentifier: 'my-guardrail-id',
|
|
1888
|
+
guardrailVersion: '1',
|
|
1889
|
+
},
|
|
1890
|
+
});
|
|
1891
|
+
const messages = [new Message({ role: 'user', content: [new TextBlock('Hello')] })];
|
|
1892
|
+
const events = await collectIterator(provider.stream(messages));
|
|
1893
|
+
const redactEvent = events.find((e) => e.type === 'modelRedactionEvent');
|
|
1894
|
+
expect(redactEvent).toBeUndefined();
|
|
1895
|
+
});
|
|
1896
|
+
it('does not emit redaction events without guardrailConfig', async () => {
|
|
1897
|
+
setupMockSend(async function* () {
|
|
1898
|
+
yield { messageStart: { role: 'assistant' } };
|
|
1899
|
+
yield { contentBlockStart: {} };
|
|
1900
|
+
yield { contentBlockDelta: { delta: { text: 'Hello' } } };
|
|
1901
|
+
yield { contentBlockStop: {} };
|
|
1902
|
+
yield { messageStop: { stopReason: 'guardrail_intervened' } };
|
|
1903
|
+
yield {
|
|
1904
|
+
metadata: {
|
|
1905
|
+
usage: { inputTokens: 10, outputTokens: 5, totalTokens: 15 },
|
|
1906
|
+
trace: {
|
|
1907
|
+
guardrail: {
|
|
1908
|
+
inputAssessment: {
|
|
1909
|
+
'1234': {
|
|
1910
|
+
topicPolicy: {
|
|
1911
|
+
topics: [{ name: 'Harmful', action: 'BLOCKED', detected: true }],
|
|
1912
|
+
},
|
|
1913
|
+
},
|
|
1914
|
+
},
|
|
1915
|
+
},
|
|
1916
|
+
},
|
|
1917
|
+
},
|
|
1918
|
+
};
|
|
1919
|
+
});
|
|
1920
|
+
const provider = new BedrockModel();
|
|
1921
|
+
const messages = [new Message({ role: 'user', content: [new TextBlock('Hello')] })];
|
|
1922
|
+
const events = await collectIterator(provider.stream(messages));
|
|
1923
|
+
const redactEvent = events.find((e) => e.type === 'modelRedactionEvent');
|
|
1924
|
+
expect(redactEvent).toBeUndefined();
|
|
1925
|
+
});
|
|
1926
|
+
});
|
|
1927
|
+
describe('redaction event generation', () => {
|
|
1928
|
+
it('emits input redaction with default message', async () => {
|
|
1929
|
+
setupMockSend(async function* () {
|
|
1930
|
+
yield { messageStart: { role: 'assistant' } };
|
|
1931
|
+
yield { messageStop: { stopReason: 'guardrail_intervened' } };
|
|
1932
|
+
yield {
|
|
1933
|
+
metadata: {
|
|
1934
|
+
usage: { inputTokens: 10, outputTokens: 5, totalTokens: 15 },
|
|
1935
|
+
trace: {
|
|
1936
|
+
guardrail: {
|
|
1937
|
+
inputAssessment: { '1': { topicPolicy: { topics: [{ action: 'BLOCKED', detected: true }] } } },
|
|
1938
|
+
},
|
|
1939
|
+
},
|
|
1940
|
+
},
|
|
1941
|
+
};
|
|
1942
|
+
});
|
|
1943
|
+
const provider = new BedrockModel({
|
|
1944
|
+
guardrailConfig: {
|
|
1945
|
+
guardrailIdentifier: 'id',
|
|
1946
|
+
guardrailVersion: '1',
|
|
1947
|
+
},
|
|
1948
|
+
});
|
|
1949
|
+
const events = await collectIterator(provider.stream([new Message({ role: 'user', content: [new TextBlock('Hello')] })]));
|
|
1950
|
+
expect(events).toContainEqual({
|
|
1951
|
+
type: 'modelRedactionEvent',
|
|
1952
|
+
inputRedaction: { replaceContent: '[User input redacted.]' },
|
|
1953
|
+
});
|
|
1954
|
+
});
|
|
1955
|
+
it('emits input redaction with custom message', async () => {
|
|
1956
|
+
setupMockSend(async function* () {
|
|
1957
|
+
yield { messageStart: { role: 'assistant' } };
|
|
1958
|
+
yield { messageStop: { stopReason: 'guardrail_intervened' } };
|
|
1959
|
+
yield {
|
|
1960
|
+
metadata: {
|
|
1961
|
+
usage: { inputTokens: 10, outputTokens: 5, totalTokens: 15 },
|
|
1962
|
+
trace: {
|
|
1963
|
+
guardrail: {
|
|
1964
|
+
inputAssessment: { '1': { topicPolicy: { topics: [{ action: 'BLOCKED', detected: true }] } } },
|
|
1965
|
+
},
|
|
1966
|
+
},
|
|
1967
|
+
},
|
|
1968
|
+
};
|
|
1969
|
+
});
|
|
1970
|
+
const provider = new BedrockModel({
|
|
1971
|
+
guardrailConfig: {
|
|
1972
|
+
guardrailIdentifier: 'id',
|
|
1973
|
+
guardrailVersion: '1',
|
|
1974
|
+
redaction: {
|
|
1975
|
+
inputMessage: '[Custom input message]',
|
|
1976
|
+
},
|
|
1977
|
+
},
|
|
1978
|
+
});
|
|
1979
|
+
const events = await collectIterator(provider.stream([new Message({ role: 'user', content: [new TextBlock('Hello')] })]));
|
|
1980
|
+
expect(events).toContainEqual({
|
|
1981
|
+
type: 'modelRedactionEvent',
|
|
1982
|
+
inputRedaction: { replaceContent: '[Custom input message]' },
|
|
1983
|
+
});
|
|
1984
|
+
});
|
|
1985
|
+
it('does not emit input redaction when redactInput is false', async () => {
|
|
1986
|
+
setupMockSend(async function* () {
|
|
1987
|
+
yield { messageStart: { role: 'assistant' } };
|
|
1988
|
+
yield { messageStop: { stopReason: 'guardrail_intervened' } };
|
|
1989
|
+
yield {
|
|
1990
|
+
metadata: {
|
|
1991
|
+
usage: { inputTokens: 10, outputTokens: 5, totalTokens: 15 },
|
|
1992
|
+
trace: {
|
|
1993
|
+
guardrail: {
|
|
1994
|
+
inputAssessment: { '1': { topicPolicy: { topics: [{ action: 'BLOCKED', detected: true }] } } },
|
|
1995
|
+
},
|
|
1996
|
+
},
|
|
1997
|
+
},
|
|
1998
|
+
};
|
|
1999
|
+
});
|
|
2000
|
+
const provider = new BedrockModel({
|
|
2001
|
+
guardrailConfig: {
|
|
2002
|
+
guardrailIdentifier: 'id',
|
|
2003
|
+
guardrailVersion: '1',
|
|
2004
|
+
redaction: {
|
|
2005
|
+
input: false,
|
|
2006
|
+
},
|
|
2007
|
+
},
|
|
2008
|
+
});
|
|
2009
|
+
const events = await collectIterator(provider.stream([new Message({ role: 'user', content: [new TextBlock('Hello')] })]));
|
|
2010
|
+
const inputRedactEvent = events.find((e) => e.type === 'modelRedactionEvent' && 'inputRedaction' in e);
|
|
2011
|
+
expect(inputRedactEvent).toBeUndefined();
|
|
2012
|
+
});
|
|
2013
|
+
it('emits output redaction when redactOutput is true', async () => {
|
|
2014
|
+
setupMockSend(async function* () {
|
|
2015
|
+
yield { messageStart: { role: 'assistant' } };
|
|
2016
|
+
yield { messageStop: { stopReason: 'guardrail_intervened' } };
|
|
2017
|
+
yield {
|
|
2018
|
+
metadata: {
|
|
2019
|
+
usage: { inputTokens: 10, outputTokens: 5, totalTokens: 15 },
|
|
2020
|
+
trace: {
|
|
2021
|
+
guardrail: {
|
|
2022
|
+
inputAssessment: { '1': { topicPolicy: { topics: [{ action: 'BLOCKED', detected: true }] } } },
|
|
2023
|
+
},
|
|
2024
|
+
},
|
|
2025
|
+
},
|
|
2026
|
+
};
|
|
2027
|
+
});
|
|
2028
|
+
const provider = new BedrockModel({
|
|
2029
|
+
guardrailConfig: {
|
|
2030
|
+
guardrailIdentifier: 'id',
|
|
2031
|
+
guardrailVersion: '1',
|
|
2032
|
+
redaction: {
|
|
2033
|
+
output: true,
|
|
2034
|
+
},
|
|
2035
|
+
},
|
|
2036
|
+
});
|
|
2037
|
+
const events = await collectIterator(provider.stream([new Message({ role: 'user', content: [new TextBlock('Hello')] })]));
|
|
2038
|
+
expect(events).toContainEqual({
|
|
2039
|
+
type: 'modelRedactionEvent',
|
|
2040
|
+
outputRedaction: { replaceContent: '[Assistant output redacted.]' },
|
|
2041
|
+
});
|
|
2042
|
+
});
|
|
2043
|
+
it('emits output redaction with custom message', async () => {
|
|
2044
|
+
setupMockSend(async function* () {
|
|
2045
|
+
yield { messageStart: { role: 'assistant' } };
|
|
2046
|
+
yield { messageStop: { stopReason: 'guardrail_intervened' } };
|
|
2047
|
+
yield {
|
|
2048
|
+
metadata: {
|
|
2049
|
+
usage: { inputTokens: 10, outputTokens: 5, totalTokens: 15 },
|
|
2050
|
+
trace: {
|
|
2051
|
+
guardrail: {
|
|
2052
|
+
inputAssessment: { '1': { topicPolicy: { topics: [{ action: 'BLOCKED', detected: true }] } } },
|
|
2053
|
+
},
|
|
2054
|
+
},
|
|
2055
|
+
},
|
|
2056
|
+
};
|
|
2057
|
+
});
|
|
2058
|
+
const provider = new BedrockModel({
|
|
2059
|
+
guardrailConfig: {
|
|
2060
|
+
guardrailIdentifier: 'id',
|
|
2061
|
+
guardrailVersion: '1',
|
|
2062
|
+
redaction: {
|
|
2063
|
+
output: true,
|
|
2064
|
+
outputMessage: '[Custom output message]',
|
|
2065
|
+
},
|
|
2066
|
+
},
|
|
2067
|
+
});
|
|
2068
|
+
const events = await collectIterator(provider.stream([new Message({ role: 'user', content: [new TextBlock('Hello')] })]));
|
|
2069
|
+
expect(events).toContainEqual({
|
|
2070
|
+
type: 'modelRedactionEvent',
|
|
2071
|
+
outputRedaction: { replaceContent: '[Custom output message]' },
|
|
2072
|
+
});
|
|
2073
|
+
});
|
|
2074
|
+
it('emits both input and output redaction when both are enabled', async () => {
|
|
2075
|
+
setupMockSend(async function* () {
|
|
2076
|
+
yield { messageStart: { role: 'assistant' } };
|
|
2077
|
+
yield { messageStop: { stopReason: 'guardrail_intervened' } };
|
|
2078
|
+
yield {
|
|
2079
|
+
metadata: {
|
|
2080
|
+
usage: { inputTokens: 10, outputTokens: 5, totalTokens: 15 },
|
|
2081
|
+
trace: {
|
|
2082
|
+
guardrail: {
|
|
2083
|
+
inputAssessment: { '1': { topicPolicy: { topics: [{ action: 'BLOCKED', detected: true }] } } },
|
|
2084
|
+
},
|
|
2085
|
+
},
|
|
2086
|
+
},
|
|
2087
|
+
};
|
|
2088
|
+
});
|
|
2089
|
+
const provider = new BedrockModel({
|
|
2090
|
+
guardrailConfig: {
|
|
2091
|
+
guardrailIdentifier: 'id',
|
|
2092
|
+
guardrailVersion: '1',
|
|
2093
|
+
redaction: {
|
|
2094
|
+
input: true,
|
|
2095
|
+
output: true,
|
|
2096
|
+
},
|
|
2097
|
+
},
|
|
2098
|
+
});
|
|
2099
|
+
const events = await collectIterator(provider.stream([new Message({ role: 'user', content: [new TextBlock('Hello')] })]));
|
|
2100
|
+
expect(events).toContainEqual({
|
|
2101
|
+
type: 'modelRedactionEvent',
|
|
2102
|
+
inputRedaction: { replaceContent: '[User input redacted.]' },
|
|
2103
|
+
});
|
|
2104
|
+
expect(events).toContainEqual({
|
|
2105
|
+
type: 'modelRedactionEvent',
|
|
2106
|
+
outputRedaction: { replaceContent: '[Assistant output redacted.]' },
|
|
2107
|
+
});
|
|
2108
|
+
});
|
|
2109
|
+
it('includes redactedContent from modelOutput when available', async () => {
|
|
2110
|
+
setupMockSend(async function* () {
|
|
2111
|
+
yield { messageStart: { role: 'assistant' } };
|
|
2112
|
+
yield { contentBlockStart: {} };
|
|
2113
|
+
yield { contentBlockDelta: { delta: { text: 'This content was blocked' } } };
|
|
2114
|
+
yield { contentBlockStop: {} };
|
|
2115
|
+
yield { messageStop: { stopReason: 'guardrail_intervened' } };
|
|
2116
|
+
yield {
|
|
2117
|
+
metadata: {
|
|
2118
|
+
usage: { inputTokens: 10, outputTokens: 5, totalTokens: 15 },
|
|
2119
|
+
trace: {
|
|
2120
|
+
guardrail: {
|
|
2121
|
+
modelOutput: ['This content ', 'was blocked'],
|
|
2122
|
+
outputAssessments: {
|
|
2123
|
+
'0': [{ topicPolicy: { topics: [{ action: 'BLOCKED', detected: true }] } }],
|
|
2124
|
+
},
|
|
2125
|
+
},
|
|
2126
|
+
},
|
|
2127
|
+
},
|
|
2128
|
+
};
|
|
2129
|
+
});
|
|
2130
|
+
const provider = new BedrockModel({
|
|
2131
|
+
guardrailConfig: {
|
|
2132
|
+
guardrailIdentifier: 'id',
|
|
2133
|
+
guardrailVersion: '1',
|
|
2134
|
+
redaction: {
|
|
2135
|
+
output: true,
|
|
2136
|
+
outputMessage: '[Blocked]',
|
|
2137
|
+
},
|
|
2138
|
+
},
|
|
2139
|
+
});
|
|
2140
|
+
const events = await collectIterator(provider.stream([new Message({ role: 'user', content: [new TextBlock('Hello')] })]));
|
|
2141
|
+
expect(events).toContainEqual({
|
|
2142
|
+
type: 'modelRedactionEvent',
|
|
2143
|
+
outputRedaction: {
|
|
2144
|
+
replaceContent: '[Blocked]',
|
|
2145
|
+
redactedContent: 'This content was blocked',
|
|
2146
|
+
},
|
|
2147
|
+
});
|
|
2148
|
+
});
|
|
2149
|
+
});
|
|
2150
|
+
describe('non-streaming mode', () => {
|
|
2151
|
+
it('emits redaction events in non-streaming mode when guardrail blocks', async () => {
|
|
2152
|
+
const mockSend = vi.fn(async () => ({
|
|
2153
|
+
output: {
|
|
2154
|
+
message: {
|
|
2155
|
+
role: 'assistant',
|
|
2156
|
+
content: [{ text: 'Hello' }],
|
|
2157
|
+
},
|
|
2158
|
+
},
|
|
2159
|
+
stopReason: 'guardrail_intervened',
|
|
2160
|
+
usage: { inputTokens: 10, outputTokens: 5, totalTokens: 15 },
|
|
2161
|
+
trace: {
|
|
2162
|
+
guardrail: {
|
|
2163
|
+
inputAssessment: { '1': { topicPolicy: { topics: [{ action: 'BLOCKED', detected: true }] } } },
|
|
2164
|
+
},
|
|
2165
|
+
},
|
|
2166
|
+
}));
|
|
2167
|
+
mockBedrockClientImplementation({ send: mockSend });
|
|
2168
|
+
const provider = new BedrockModel({
|
|
2169
|
+
stream: false,
|
|
2170
|
+
guardrailConfig: {
|
|
2171
|
+
guardrailIdentifier: 'id',
|
|
2172
|
+
guardrailVersion: '1',
|
|
2173
|
+
},
|
|
2174
|
+
});
|
|
2175
|
+
const events = await collectIterator(provider.stream([new Message({ role: 'user', content: [new TextBlock('Hello')] })]));
|
|
2176
|
+
expect(events).toContainEqual({
|
|
2177
|
+
type: 'modelRedactionEvent',
|
|
2178
|
+
inputRedaction: { replaceContent: '[User input redacted.]' },
|
|
2179
|
+
});
|
|
2180
|
+
});
|
|
2181
|
+
});
|
|
2182
|
+
});
|
|
1495
2183
|
});
|
|
1496
2184
|
//# sourceMappingURL=bedrock.test.js.map
|