@wmaurer/effect-ai-amazon-bedrock 0.2.0 → 0.4.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/CHANGELOG.md +21 -0
- package/README.md +98 -9
- package/dist/AmazonBedrockClient.d.ts +2 -2
- package/dist/AmazonBedrockClient.d.ts.map +1 -1
- package/dist/AmazonBedrockLanguageModel.d.ts +188 -25
- package/dist/AmazonBedrockLanguageModel.d.ts.map +1 -1
- package/dist/AmazonBedrockLanguageModel.js +203 -37
- package/dist/AmazonBedrockLanguageModel.js.map +1 -1
- package/dist/AmazonBedrockSchema.d.ts +240 -7
- package/dist/AmazonBedrockSchema.d.ts.map +1 -1
- package/dist/AmazonBedrockSchema.js +189 -10
- package/dist/AmazonBedrockSchema.js.map +1 -1
- package/dist/internal/errors.d.ts.map +1 -1
- package/dist/internal/errors.js +8 -0
- package/dist/internal/errors.js.map +1 -1
- package/dist/internal/guardrails.d.ts +15 -0
- package/dist/internal/guardrails.d.ts.map +1 -0
- package/dist/internal/guardrails.js +77 -0
- package/dist/internal/guardrails.js.map +1 -0
- package/dist/internal/utilities.d.ts +1 -1
- package/dist/internal/utilities.d.ts.map +1 -1
- package/dist/internal/utilities.js +4 -5
- package/dist/internal/utilities.js.map +1 -1
- package/package.json +1 -1
- package/src/AmazonBedrockClient.ts +2 -2
- package/src/AmazonBedrockLanguageModel.ts +422 -74
- package/src/AmazonBedrockSchema.ts +219 -12
- package/src/internal/errors.ts +14 -0
- package/src/internal/guardrails.ts +91 -0
- package/src/internal/utilities.ts +7 -7
|
@@ -29,13 +29,13 @@ const makeIdentifier = (name: string) => `${prefix}/${name}`
|
|
|
29
29
|
export const IntZeroOrGreater = Schema.Int.check(Schema.isGreaterThanOrEqualTo(0))
|
|
30
30
|
|
|
31
31
|
/**
|
|
32
|
-
* The
|
|
32
|
+
* The stop reasons that the Smithy model of the Converse API names.
|
|
33
33
|
*
|
|
34
34
|
* @stability unstable
|
|
35
35
|
* @category schemas
|
|
36
|
-
* @since 0.
|
|
36
|
+
* @since 0.3.0
|
|
37
37
|
*/
|
|
38
|
-
export const
|
|
38
|
+
export const KnownStopReason = Schema.Literals([
|
|
39
39
|
"end_turn",
|
|
40
40
|
"tool_use",
|
|
41
41
|
"max_tokens",
|
|
@@ -47,6 +47,29 @@ export const StopReason = Schema.Literals([
|
|
|
47
47
|
"model_context_window_exceeded"
|
|
48
48
|
])
|
|
49
49
|
|
|
50
|
+
/**
|
|
51
|
+
* The type of {@link KnownStopReason}.
|
|
52
|
+
*
|
|
53
|
+
* @stability unstable
|
|
54
|
+
* @category schemas
|
|
55
|
+
* @since 0.3.0
|
|
56
|
+
*/
|
|
57
|
+
export type KnownStopReason = typeof KnownStopReason.Type
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* The reason the model stopped generating a response.
|
|
61
|
+
*
|
|
62
|
+
* **Details**
|
|
63
|
+
*
|
|
64
|
+
* Any string decodes, so a reason that Bedrock adds later, or that a model
|
|
65
|
+
* returns outside the Smithy model, does not fail the response.
|
|
66
|
+
*
|
|
67
|
+
* @stability unstable
|
|
68
|
+
* @category schemas
|
|
69
|
+
* @since 0.1.0
|
|
70
|
+
*/
|
|
71
|
+
export const StopReason = Schema.Union([KnownStopReason, Schema.StringForLiteralAutocomplete])
|
|
72
|
+
|
|
50
73
|
/**
|
|
51
74
|
* The type of {@link StopReason}.
|
|
52
75
|
*
|
|
@@ -354,6 +377,79 @@ export class CitationsContentBlock extends Schema.Class<CitationsContentBlock>(
|
|
|
354
377
|
citations: Schema.optional(Schema.Array(Citation))
|
|
355
378
|
}) {}
|
|
356
379
|
|
|
380
|
+
/**
|
|
381
|
+
* The role a guarded text block plays in a contextual grounding check.
|
|
382
|
+
*
|
|
383
|
+
* **Details**
|
|
384
|
+
*
|
|
385
|
+
* `grounding_source` marks the documents an answer must be grounded in,
|
|
386
|
+
* `query` marks the question, and `guard_content` marks text the guardrail
|
|
387
|
+
* evaluates without a grounding role.
|
|
388
|
+
*
|
|
389
|
+
* @stability unstable
|
|
390
|
+
* @category schemas
|
|
391
|
+
* @since 0.4.0
|
|
392
|
+
*/
|
|
393
|
+
export const GuardrailConverseContentQualifier = Schema.Literals(["grounding_source", "query", "guard_content"])
|
|
394
|
+
|
|
395
|
+
/**
|
|
396
|
+
* Text that the guardrail evaluates.
|
|
397
|
+
*
|
|
398
|
+
* **Details**
|
|
399
|
+
*
|
|
400
|
+
* `qualifiers` uses `optionalKey` for the same reason as
|
|
401
|
+
* `CachePointBlock.ttl`: the block is built from `Prompt` provider options,
|
|
402
|
+
* whose values must satisfy `Schema.Json`.
|
|
403
|
+
*
|
|
404
|
+
* @stability unstable
|
|
405
|
+
* @category schemas
|
|
406
|
+
* @since 0.4.0
|
|
407
|
+
*/
|
|
408
|
+
export class GuardrailConverseTextBlock extends Schema.Class<GuardrailConverseTextBlock>(
|
|
409
|
+
makeIdentifier("GuardrailConverseTextBlock")
|
|
410
|
+
)({
|
|
411
|
+
text: Schema.String,
|
|
412
|
+
qualifiers: Schema.optionalKey(Schema.Array(GuardrailConverseContentQualifier))
|
|
413
|
+
}) {}
|
|
414
|
+
|
|
415
|
+
/**
|
|
416
|
+
* An image that the guardrail evaluates.
|
|
417
|
+
*
|
|
418
|
+
* **Details**
|
|
419
|
+
*
|
|
420
|
+
* The Smithy model allows only png and jpeg, and only `bytes` as the source.
|
|
421
|
+
* `bytes` is a Smithy blob, which the JSON protocol carries as a base64
|
|
422
|
+
* string.
|
|
423
|
+
*
|
|
424
|
+
* @stability unstable
|
|
425
|
+
* @category schemas
|
|
426
|
+
* @since 0.4.0
|
|
427
|
+
*/
|
|
428
|
+
export class GuardrailConverseImageBlock extends Schema.Class<GuardrailConverseImageBlock>(
|
|
429
|
+
makeIdentifier("GuardrailConverseImageBlock")
|
|
430
|
+
)({
|
|
431
|
+
format: Schema.Literals(["png", "jpeg"]),
|
|
432
|
+
source: Schema.Struct({ bytes: Schema.String })
|
|
433
|
+
}) {}
|
|
434
|
+
|
|
435
|
+
/**
|
|
436
|
+
* Content that the guardrail evaluates, in a message or in the system prompt.
|
|
437
|
+
*
|
|
438
|
+
* **Details**
|
|
439
|
+
*
|
|
440
|
+
* AWS models `GuardrailConverseContentBlock` as a UNION, so both members are
|
|
441
|
+
* optional here. Once a request holds one `guardContent` block, the guardrail
|
|
442
|
+
* evaluates only the guarded blocks. The model still reads every block.
|
|
443
|
+
*
|
|
444
|
+
* @stability unstable
|
|
445
|
+
* @category schemas
|
|
446
|
+
* @since 0.4.0
|
|
447
|
+
*/
|
|
448
|
+
export const GuardrailConverseContentBlock = Schema.Struct({
|
|
449
|
+
text: Schema.optional(GuardrailConverseTextBlock),
|
|
450
|
+
image: Schema.optional(GuardrailConverseImageBlock)
|
|
451
|
+
})
|
|
452
|
+
|
|
357
453
|
/**
|
|
358
454
|
* A text content block within a Converse message.
|
|
359
455
|
*
|
|
@@ -378,7 +474,8 @@ export const ContentBlock = Schema.Struct({
|
|
|
378
474
|
image: Schema.optional(ImageBlock),
|
|
379
475
|
document: Schema.optional(DocumentBlock),
|
|
380
476
|
cachePoint: Schema.optional(CachePointBlock),
|
|
381
|
-
citationsContent: Schema.optional(CitationsContentBlock)
|
|
477
|
+
citationsContent: Schema.optional(CitationsContentBlock),
|
|
478
|
+
guardContent: Schema.optional(GuardrailConverseContentBlock)
|
|
382
479
|
})
|
|
383
480
|
|
|
384
481
|
/**
|
|
@@ -398,8 +495,9 @@ export class Message extends Schema.Class<Message>(makeIdentifier("Message"))({
|
|
|
398
495
|
*
|
|
399
496
|
* **Details**
|
|
400
497
|
*
|
|
401
|
-
* AWS models `SystemContentBlock` as a UNION, so
|
|
402
|
-
* block carries
|
|
498
|
+
* AWS models `SystemContentBlock` as a UNION, so every member is optional; a
|
|
499
|
+
* block carries the system text, guarded system text, or a cache point. The
|
|
500
|
+
* guardrail evaluates the system prompt only where it is guarded.
|
|
403
501
|
*
|
|
404
502
|
* @stability unstable
|
|
405
503
|
* @category schemas
|
|
@@ -407,7 +505,8 @@ export class Message extends Schema.Class<Message>(makeIdentifier("Message"))({
|
|
|
407
505
|
*/
|
|
408
506
|
export const SystemContentBlock = Schema.Struct({
|
|
409
507
|
text: Schema.optional(Schema.String),
|
|
410
|
-
cachePoint: Schema.optional(CachePointBlock)
|
|
508
|
+
cachePoint: Schema.optional(CachePointBlock),
|
|
509
|
+
guardContent: Schema.optional(GuardrailConverseContentBlock)
|
|
411
510
|
})
|
|
412
511
|
|
|
413
512
|
/**
|
|
@@ -555,7 +654,80 @@ export const OutputConfig = Schema.Struct({
|
|
|
555
654
|
})
|
|
556
655
|
|
|
557
656
|
/**
|
|
558
|
-
*
|
|
657
|
+
* Whether Bedrock returns the guardrail trace.
|
|
658
|
+
*
|
|
659
|
+
* **Details**
|
|
660
|
+
*
|
|
661
|
+
* Bedrock's default is `disabled`. The trace holds the text that a policy
|
|
662
|
+
* matched, unmasked. `enabled_full` is in the Smithy model, and AWS does not
|
|
663
|
+
* document it.
|
|
664
|
+
*
|
|
665
|
+
* @stability unstable
|
|
666
|
+
* @category schemas
|
|
667
|
+
* @since 0.4.0
|
|
668
|
+
*/
|
|
669
|
+
export const GuardrailTrace = Schema.Literals(["enabled", "disabled", "enabled_full"])
|
|
670
|
+
|
|
671
|
+
/**
|
|
672
|
+
* How ConverseStream applies a guardrail to the streamed output.
|
|
673
|
+
*
|
|
674
|
+
* **Details**
|
|
675
|
+
*
|
|
676
|
+
* `sync`, Bedrock's default, holds back each chunk until the guardrail has
|
|
677
|
+
* evaluated it. `async` sends chunks at once, so text that the guardrail
|
|
678
|
+
* later blocks can reach the caller, and masking does not apply.
|
|
679
|
+
*
|
|
680
|
+
* @stability unstable
|
|
681
|
+
* @category schemas
|
|
682
|
+
* @since 0.4.0
|
|
683
|
+
*/
|
|
684
|
+
export const GuardrailStreamProcessingMode = Schema.Literals(["sync", "async"])
|
|
685
|
+
|
|
686
|
+
// Smithy gives the identifier and the version `default: ""`, and Bedrock cannot
|
|
687
|
+
// apply a guardrail without them, so both are required here.
|
|
688
|
+
const guardrailFields = {
|
|
689
|
+
guardrailIdentifier: Schema.String,
|
|
690
|
+
guardrailVersion: Schema.String,
|
|
691
|
+
trace: Schema.optionalKey(GuardrailTrace)
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
/**
|
|
695
|
+
* The guardrail of a Converse request.
|
|
696
|
+
*
|
|
697
|
+
* **Details**
|
|
698
|
+
*
|
|
699
|
+
* `guardrailIdentifier` is the guardrail's ID or ARN, and `guardrailVersion`
|
|
700
|
+
* is a version number or `DRAFT`. Converse has no `streamProcessingMode`, so
|
|
701
|
+
* the member is typed `never`: a ConverseStream request does not fit Converse
|
|
702
|
+
* until the mode is removed.
|
|
703
|
+
*
|
|
704
|
+
* @stability unstable
|
|
705
|
+
* @category schemas
|
|
706
|
+
* @since 0.4.0
|
|
707
|
+
*/
|
|
708
|
+
export class GuardrailConfiguration extends Schema.Class<GuardrailConfiguration>(
|
|
709
|
+
makeIdentifier("GuardrailConfiguration")
|
|
710
|
+
)({
|
|
711
|
+
...guardrailFields,
|
|
712
|
+
streamProcessingMode: Schema.optionalKey(Schema.Never)
|
|
713
|
+
}) {}
|
|
714
|
+
|
|
715
|
+
/**
|
|
716
|
+
* The guardrail of a ConverseStream request.
|
|
717
|
+
*
|
|
718
|
+
* @stability unstable
|
|
719
|
+
* @category schemas
|
|
720
|
+
* @since 0.4.0
|
|
721
|
+
*/
|
|
722
|
+
export class GuardrailStreamConfiguration extends Schema.Class<GuardrailStreamConfiguration>(
|
|
723
|
+
makeIdentifier("GuardrailStreamConfiguration")
|
|
724
|
+
)({
|
|
725
|
+
...guardrailFields,
|
|
726
|
+
streamProcessingMode: Schema.optionalKey(GuardrailStreamProcessingMode)
|
|
727
|
+
}) {}
|
|
728
|
+
|
|
729
|
+
/**
|
|
730
|
+
* The request payload for the Converse operation.
|
|
559
731
|
*
|
|
560
732
|
* **Details**
|
|
561
733
|
*
|
|
@@ -579,9 +751,30 @@ export class ConverseRequest extends Schema.Class<ConverseRequest>(makeIdentifie
|
|
|
579
751
|
toolConfig: Schema.optionalKey(ToolConfiguration),
|
|
580
752
|
inferenceConfig: Schema.optional(InferenceConfiguration),
|
|
581
753
|
outputConfig: Schema.optionalKey(OutputConfig),
|
|
582
|
-
additionalModelRequestFields: Schema.optional(Schema.Record(Schema.String, Schema.Unknown))
|
|
754
|
+
additionalModelRequestFields: Schema.optional(Schema.Record(Schema.String, Schema.Unknown)),
|
|
755
|
+
guardrailConfig: Schema.optional(GuardrailConfiguration)
|
|
583
756
|
}) {}
|
|
584
757
|
|
|
758
|
+
/**
|
|
759
|
+
* The request payload for the ConverseStream operation.
|
|
760
|
+
*
|
|
761
|
+
* **Details**
|
|
762
|
+
*
|
|
763
|
+
* The members of `ConverseRequest`, with the guardrail of a stream, which
|
|
764
|
+
* adds `streamProcessingMode`. That member is the only difference between the
|
|
765
|
+
* two operations.
|
|
766
|
+
*
|
|
767
|
+
* @stability unstable
|
|
768
|
+
* @category schemas
|
|
769
|
+
* @since 0.4.0
|
|
770
|
+
*/
|
|
771
|
+
export class ConverseStreamRequest
|
|
772
|
+
extends Schema.Class<ConverseStreamRequest>(makeIdentifier("ConverseStreamRequest"))({
|
|
773
|
+
...ConverseRequest.fields,
|
|
774
|
+
guardrailConfig: Schema.optional(GuardrailStreamConfiguration)
|
|
775
|
+
})
|
|
776
|
+
{}
|
|
777
|
+
|
|
585
778
|
// =============================================================================
|
|
586
779
|
// Response
|
|
587
780
|
// =============================================================================
|
|
@@ -611,6 +804,12 @@ export class ConverseMetrics extends Schema.Class<ConverseMetrics>(makeIdentifie
|
|
|
611
804
|
/**
|
|
612
805
|
* The response from a successful Converse call.
|
|
613
806
|
*
|
|
807
|
+
* **Details**
|
|
808
|
+
*
|
|
809
|
+
* `trace` is kept as the JSON Bedrock sent. Its Smithy tree has about 90
|
|
810
|
+
* shapes that AWS still extends, and a struct would drop every member added
|
|
811
|
+
* later.
|
|
812
|
+
*
|
|
614
813
|
* @stability unstable
|
|
615
814
|
* @category schemas
|
|
616
815
|
* @since 0.1.0
|
|
@@ -619,7 +818,8 @@ export class ConverseResponse extends Schema.Class<ConverseResponse>(makeIdentif
|
|
|
619
818
|
output: ConverseOutput,
|
|
620
819
|
usage: TokenUsage,
|
|
621
820
|
stopReason: StopReason,
|
|
622
|
-
metrics: Schema.optional(ConverseMetrics)
|
|
821
|
+
metrics: Schema.optional(ConverseMetrics),
|
|
822
|
+
trace: Schema.optional(Schema.MutableJson)
|
|
623
823
|
}) {}
|
|
624
824
|
|
|
625
825
|
// =============================================================================
|
|
@@ -800,7 +1000,13 @@ export class MessageStopEvent extends Schema.Class<MessageStopEvent>(
|
|
|
800
1000
|
}) {}
|
|
801
1001
|
|
|
802
1002
|
/**
|
|
803
|
-
* The trailing metadata event for a Converse stream, carrying usage
|
|
1003
|
+
* The trailing metadata event for a Converse stream, carrying usage, metrics,
|
|
1004
|
+
* and the trace.
|
|
1005
|
+
*
|
|
1006
|
+
* **Details**
|
|
1007
|
+
*
|
|
1008
|
+
* This is the only stream event that carries the trace. It is kept as JSON,
|
|
1009
|
+
* as in `ConverseResponse`.
|
|
804
1010
|
*
|
|
805
1011
|
* @stability unstable
|
|
806
1012
|
* @category schemas
|
|
@@ -810,7 +1016,8 @@ export class ConverseStreamMetadataEvent extends Schema.Class<ConverseStreamMeta
|
|
|
810
1016
|
makeIdentifier("ConverseStreamMetadataEvent")
|
|
811
1017
|
)({
|
|
812
1018
|
usage: TokenUsage,
|
|
813
|
-
metrics: Schema.optional(ConverseMetrics)
|
|
1019
|
+
metrics: Schema.optional(ConverseMetrics),
|
|
1020
|
+
trace: Schema.optional(Schema.MutableJson)
|
|
814
1021
|
}) {}
|
|
815
1022
|
|
|
816
1023
|
const ExceptionBody = Schema.Struct({
|
package/src/internal/errors.ts
CHANGED
|
@@ -220,9 +220,23 @@ const buildInvalidRequestDescription = (params: {
|
|
|
220
220
|
parts.push(`Response: ${truncated}`)
|
|
221
221
|
}
|
|
222
222
|
|
|
223
|
+
if (params.message && dataRetentionRejection.test(params.message)) {
|
|
224
|
+
parts.push(dataRetentionHint)
|
|
225
|
+
}
|
|
226
|
+
|
|
223
227
|
return parts.join(" ")
|
|
224
228
|
}
|
|
225
229
|
|
|
230
|
+
// Converse has no request field for the data retention mode, so the AWS message
|
|
231
|
+
// alone leaves the reader looking for one. Only an account-level setting in each
|
|
232
|
+
// region, which the control plane sets, makes such a model callable.
|
|
233
|
+
const dataRetentionRejection = /data retention mode '[^']*' is not available for this model/
|
|
234
|
+
|
|
235
|
+
const dataRetentionHint = "The account's data retention mode in this region does not allow this model." +
|
|
236
|
+
" Claude Fable 5 and 5.1 need `aws_review`." +
|
|
237
|
+
" Set the mode with the Bedrock PutAccountDataRetention operation:" +
|
|
238
|
+
" https://docs.aws.amazon.com/bedrock/latest/userguide/data-retention.html"
|
|
239
|
+
|
|
226
240
|
/**
|
|
227
241
|
* AWS sends the exception shape as `Name:http://internal.amazon.com/coral/...`.
|
|
228
242
|
* Only the part before the colon identifies it.
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import type * as Schema from "effect/Schema"
|
|
2
|
+
import type { FinishMetadata, GuardrailAction, GuardrailOutcome } from "../AmazonBedrockLanguageModel.ts"
|
|
3
|
+
|
|
4
|
+
const strength: Record<GuardrailAction, number> = { none: 0, masked: 1, blocked: 2 }
|
|
5
|
+
|
|
6
|
+
const stronger = (a: GuardrailAction, b: GuardrailAction): GuardrailAction => strength[b] > strength[a] ? b : a
|
|
7
|
+
|
|
8
|
+
const isObject = (value: unknown): value is Schema.MutableJsonObject =>
|
|
9
|
+
typeof value === "object" && value !== null && !Array.isArray(value)
|
|
10
|
+
|
|
11
|
+
const actionOf = (value: string): GuardrailAction =>
|
|
12
|
+
value === "BLOCKED" ? "blocked" : value === "ANONYMIZED" ? "masked" : "none"
|
|
13
|
+
|
|
14
|
+
const strongestAction = (value: Schema.MutableJson): GuardrailAction => {
|
|
15
|
+
let action: GuardrailAction = "none"
|
|
16
|
+
if (Array.isArray(value)) {
|
|
17
|
+
for (const item of value) {
|
|
18
|
+
action = stronger(action, strongestAction(item))
|
|
19
|
+
}
|
|
20
|
+
} else if (isObject(value)) {
|
|
21
|
+
for (const [key, member] of Object.entries(value)) {
|
|
22
|
+
action = stronger(
|
|
23
|
+
action,
|
|
24
|
+
key === "action" && typeof member === "string" ? actionOf(member) : strongestAction(member)
|
|
25
|
+
)
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
return action
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const assessSide = (assessments: ReadonlyArray<Schema.MutableJson>, policies: Array<string>): GuardrailAction => {
|
|
32
|
+
let side: GuardrailAction = "none"
|
|
33
|
+
for (const assessment of assessments) {
|
|
34
|
+
if (!isObject(assessment)) {
|
|
35
|
+
continue
|
|
36
|
+
}
|
|
37
|
+
for (const [policy, member] of Object.entries(assessment)) {
|
|
38
|
+
const action = strongestAction(member)
|
|
39
|
+
if (action !== "none" && !policies.includes(policy)) {
|
|
40
|
+
policies.push(policy)
|
|
41
|
+
}
|
|
42
|
+
side = stronger(side, action)
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return side
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/** @internal */
|
|
49
|
+
export const guardrailOutcome = (trace: Schema.MutableJson | undefined): GuardrailOutcome | null => {
|
|
50
|
+
const guardrail = isObject(trace) ? trace.guardrail : undefined
|
|
51
|
+
if (!isObject(guardrail)) {
|
|
52
|
+
return null
|
|
53
|
+
}
|
|
54
|
+
const inputAssessment = guardrail.inputAssessment
|
|
55
|
+
const outputAssessments = guardrail.outputAssessments
|
|
56
|
+
const policies: Array<string> = []
|
|
57
|
+
const input = assessSide(isObject(inputAssessment) ? Object.values(inputAssessment) : [], policies)
|
|
58
|
+
const output = assessSide(
|
|
59
|
+
isObject(outputAssessments)
|
|
60
|
+
? Object.values(outputAssessments).flatMap((chunks) => Array.isArray(chunks) ? chunks : [])
|
|
61
|
+
: [],
|
|
62
|
+
policies
|
|
63
|
+
)
|
|
64
|
+
return { input, output, policies }
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/** @internal */
|
|
68
|
+
export const finishMetadata = (stopReason: string | null, trace: Schema.MutableJson | undefined): FinishMetadata => ({
|
|
69
|
+
stopReason,
|
|
70
|
+
guardrail: guardrailOutcome(trace),
|
|
71
|
+
trace: trace ?? null
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
const isJson = (text: string): boolean => {
|
|
75
|
+
try {
|
|
76
|
+
JSON.parse(text)
|
|
77
|
+
return true
|
|
78
|
+
} catch {
|
|
79
|
+
return false
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Bedrock stops with `guardrail_intervened` both when a guardrail blocks,
|
|
85
|
+
* replacing the text with the guardrail's blocked message, and when it masks,
|
|
86
|
+
* leaving the object JSON.
|
|
87
|
+
*
|
|
88
|
+
* @internal
|
|
89
|
+
*/
|
|
90
|
+
export const blocksObject = (stopReason: string, text: string): boolean =>
|
|
91
|
+
stopReason === "guardrail_intervened" && !isJson(text)
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import type * as Response from "effect/ai/Response"
|
|
2
|
-
import * as
|
|
3
|
-
import type
|
|
2
|
+
import * as Schema from "effect/Schema"
|
|
3
|
+
import { KnownStopReason, type StopReason } from "../AmazonBedrockSchema.ts"
|
|
4
4
|
|
|
5
|
-
const
|
|
5
|
+
const isKnownStopReason = Schema.is(KnownStopReason)
|
|
6
|
+
|
|
7
|
+
const finishReasonMap: Record<KnownStopReason, Response.FinishReason> = {
|
|
6
8
|
content_filtered: "content-filter",
|
|
7
9
|
end_turn: "stop",
|
|
8
10
|
guardrail_intervened: "content-filter",
|
|
@@ -15,7 +17,5 @@ const finishReasonMap: Record<StopReason, Response.FinishReason> = {
|
|
|
15
17
|
}
|
|
16
18
|
|
|
17
19
|
/** @internal */
|
|
18
|
-
export const resolveFinishReason = (stopReason: StopReason): Response.FinishReason =>
|
|
19
|
-
|
|
20
|
-
return Predicate.isUndefined(reason) ? "unknown" : reason
|
|
21
|
-
}
|
|
20
|
+
export const resolveFinishReason = (stopReason: StopReason): Response.FinishReason =>
|
|
21
|
+
isKnownStopReason(stopReason) ? finishReasonMap[stopReason] : "other"
|