@namzu/bedrock 4.0.0 → 4.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/CHANGELOG.md +29 -0
  2. package/package.json +12 -2
  3. package/dist/__tests__/bedrock.test.d.ts +0 -2
  4. package/dist/__tests__/bedrock.test.d.ts.map +0 -1
  5. package/dist/__tests__/bedrock.test.js +0 -94
  6. package/dist/__tests__/bedrock.test.js.map +0 -1
  7. package/dist/__tests__/error-taxonomy.test.d.ts +0 -17
  8. package/dist/__tests__/error-taxonomy.test.d.ts.map +0 -1
  9. package/dist/__tests__/error-taxonomy.test.js +0 -204
  10. package/dist/__tests__/error-taxonomy.test.js.map +0 -1
  11. package/dist/__tests__/model-reachability.test.d.ts +0 -2
  12. package/dist/__tests__/model-reachability.test.d.ts.map +0 -1
  13. package/dist/__tests__/model-reachability.test.js +0 -64
  14. package/dist/__tests__/model-reachability.test.js.map +0 -1
  15. package/dist/__tests__/prompt-cache.test.d.ts +0 -2
  16. package/dist/__tests__/prompt-cache.test.d.ts.map +0 -1
  17. package/dist/__tests__/prompt-cache.test.js +0 -68
  18. package/dist/__tests__/prompt-cache.test.js.map +0 -1
  19. package/dist/__tests__/thinking-refused.test.d.ts +0 -2
  20. package/dist/__tests__/thinking-refused.test.d.ts.map +0 -1
  21. package/dist/__tests__/thinking-refused.test.js +0 -35
  22. package/dist/__tests__/thinking-refused.test.js.map +0 -1
  23. package/dist/__tests__/tool-choice-none.test.d.ts +0 -2
  24. package/dist/__tests__/tool-choice-none.test.d.ts.map +0 -1
  25. package/dist/__tests__/tool-choice-none.test.js +0 -76
  26. package/dist/__tests__/tool-choice-none.test.js.map +0 -1
  27. package/dist/__tests__/tool-content-blocks.test.d.ts +0 -2
  28. package/dist/__tests__/tool-content-blocks.test.d.ts.map +0 -1
  29. package/dist/__tests__/tool-content-blocks.test.js +0 -92
  30. package/dist/__tests__/tool-content-blocks.test.js.map +0 -1
  31. package/dist/__tests__/tool-schema-dialect.test.d.ts +0 -2
  32. package/dist/__tests__/tool-schema-dialect.test.d.ts.map +0 -1
  33. package/dist/__tests__/tool-schema-dialect.test.js +0 -98
  34. package/dist/__tests__/tool-schema-dialect.test.js.map +0 -1
  35. package/dist/__tests__/vision.test.d.ts +0 -2
  36. package/dist/__tests__/vision.test.d.ts.map +0 -1
  37. package/dist/__tests__/vision.test.js +0 -77
  38. package/dist/__tests__/vision.test.js.map +0 -1
  39. package/src/__tests__/bedrock.test.ts +0 -103
  40. package/src/__tests__/error-taxonomy.test.ts +0 -248
  41. package/src/__tests__/model-reachability.test.ts +0 -74
  42. package/src/__tests__/prompt-cache.test.ts +0 -81
  43. package/src/__tests__/thinking-refused.test.ts +0 -44
  44. package/src/__tests__/tool-choice-none.test.ts +0 -87
  45. package/src/__tests__/tool-content-blocks.test.ts +0 -119
  46. package/src/__tests__/tool-schema-dialect.test.ts +0 -108
  47. package/src/__tests__/vision.test.ts +0 -98
@@ -1,108 +0,0 @@
1
- import { findDraft07Only } from '@namzu/sdk'
2
- import { describe, expect, it } from 'vitest'
3
-
4
- import { toBedrockToolConfig } from '../client.js'
5
-
6
- /**
7
- * Converse carries Claude, so it carries Claude's schema dialect too.
8
- *
9
- * The kernel renders tool schemas as draft-07, where a tuple is
10
- * `items: [a, b]`. Anthropic's serving layer validates `input_schema` as JSON
11
- * Schema 2020-12, where that spelling is invalid — the tuple has to be
12
- * `prefixItems` — and it rejects the whole request rather than ignoring the
13
- * field, so one tuple-shaped tool takes down every tool in the call.
14
- *
15
- * That fix landed on the direct Anthropic driver and on the HTTP driver's
16
- * Anthropic branch, and this driver was missed. It reaches the same models
17
- * through a different front door; the validation happens in the same place.
18
- *
19
- * The conversion follows the MODEL, not the endpoint, because Converse is
20
- * multi-vendor: `meta.llama*` and `mistral.*` come through this same function,
21
- * and nothing establishes that they read 2020-12. Converting their schemas
22
- * would be trading a known break for an unmeasured one.
23
- */
24
-
25
- const TUPLE_TOOL = [
26
- {
27
- type: 'function' as const,
28
- function: {
29
- name: 'read',
30
- description: 'reads',
31
- parameters: {
32
- type: 'object',
33
- properties: {
34
- // What `z.tuple([z.number(), z.number()])` renders to.
35
- readRange: {
36
- type: 'array',
37
- items: [{ type: 'number' }, { type: 'number' }],
38
- minItems: 2,
39
- maxItems: 2,
40
- },
41
- },
42
- },
43
- },
44
- },
45
- ]
46
-
47
- function rangeOf(model: string): Record<string, unknown> {
48
- const config = toBedrockToolConfig({ model, messages: [], tools: TUPLE_TOOL })
49
- const json = config?.tools?.[0]?.toolSpec?.inputSchema?.json as Record<string, unknown>
50
- const properties = json.properties as Record<string, Record<string, unknown>>
51
- return properties.readRange as Record<string, unknown>
52
- }
53
-
54
- function schemaOf(model: string): Record<string, unknown> {
55
- const config = toBedrockToolConfig({ model, messages: [], tools: TUPLE_TOOL })
56
- return config?.tools?.[0]?.toolSpec?.inputSchema?.json as Record<string, unknown>
57
- }
58
-
59
- describe('a tuple reaches Claude on Converse in the dialect Claude reads', () => {
60
- it.each([
61
- ['anthropic.claude-sonnet-4-20250514', 'a bare vendor id'],
62
- ['us.anthropic.claude-sonnet-4-5-20250929-v1:0', 'behind an inference profile'],
63
- ['EU.Anthropic.Claude-Opus-4-1-v1:0', 'in whatever case the caller wrote'],
64
- ])('converts for %s (%s)', (model) => {
65
- expect(findDraft07Only(schemaOf(model))).toEqual([])
66
-
67
- const range = rangeOf(model)
68
- expect(range.prefixItems).toHaveLength(2)
69
- expect(range.items).toBeUndefined()
70
- })
71
-
72
- it('leaves another vendor on this wire alone', () => {
73
- // Not timidity — the absence of a measurement. Anthropic's requirement
74
- // was measured against its own wire; no such reading exists for these,
75
- // and converting on a guess swaps a known break for an unknown one.
76
- const range = rangeOf('meta.llama3-70b-instruct-v1:0')
77
-
78
- expect(range.items).toHaveLength(2)
79
- expect(range.prefixItems).toBeUndefined()
80
- })
81
-
82
- it('does not disturb a schema with no tuple in it', () => {
83
- const config = toBedrockToolConfig({
84
- model: 'anthropic.claude-sonnet-4-20250514',
85
- messages: [],
86
- tools: [
87
- {
88
- type: 'function',
89
- function: {
90
- name: 'ls',
91
- description: 'lists',
92
- parameters: {
93
- type: 'object',
94
- properties: { path: { type: 'string' } },
95
- required: ['path'],
96
- },
97
- },
98
- },
99
- ],
100
- })
101
-
102
- expect(config?.tools?.[0]?.toolSpec?.inputSchema?.json).toEqual({
103
- type: 'object',
104
- properties: { path: { type: 'string' } },
105
- required: ['path'],
106
- })
107
- })
108
- })
@@ -1,98 +0,0 @@
1
- import type { ChatCompletionParams } from '@namzu/sdk'
2
- import { describe, expect, it } from 'vitest'
3
-
4
- import { BEDROCK_CAPABILITIES, toBedrockMessages } from '../client.js'
5
-
6
- /**
7
- * This driver does not map image attachments, and says so.
8
- *
9
- * That is a legitimate state — a driver may ship without a wire shape —
10
- * but only while the claim and the code agree. The failure this pins is
11
- * drift in either direction: flipping the flag without writing the mapping
12
- * makes the runtime stop warning about images that still vanish, and
13
- * writing the mapping without flipping the flag makes it keep warning
14
- * about images that now arrive.
15
- *
16
- * The runtime reads the flag and warns (or fails under `strictCapabilities`)
17
- * before the request is built, so the flag is the contract.
18
- */
19
-
20
- const PNG = 'iVBORw0KGgo='
21
-
22
- function contentFor(attachments: unknown[]): unknown {
23
- const messages = toBedrockMessages([
24
- { role: 'user', content: 'what is this', attachments },
25
- ] as unknown as ChatCompletionParams['messages'])
26
- return messages[0]?.content
27
- }
28
-
29
- describe('the capability claim and the mapper agree', () => {
30
- it('declares that images are not mapped', () => {
31
- expect(BEDROCK_CAPABILITIES.supportsVision).toBe(false)
32
- })
33
-
34
- it('declares that documents are not mapped', () => {
35
- expect(BEDROCK_CAPABILITIES.supportsDocuments).toBe(false)
36
- })
37
-
38
- it('sends no image block, matching the claim', () => {
39
- const content = contentFor([{ type: 'image', data: PNG, mediaType: 'image/png' }])
40
- const blocks = content as Record<string, unknown>[]
41
-
42
- expect(blocks.some((b) => 'image' in b)).toBe(false)
43
- })
44
-
45
- it('does not smuggle the payload into the text either', () => {
46
- const content = contentFor([{ type: 'image', data: 'A'.repeat(2048), mediaType: 'image/png' }])
47
-
48
- // Dropping is the declared behaviour. Stringifying it into the
49
- // prompt would be worse than dropping: unreadable, and billed.
50
- expect(JSON.stringify(content)).not.toContain('A'.repeat(64))
51
- })
52
-
53
- it('still sends the message text', () => {
54
- const content = contentFor([{ type: 'image', data: PNG, mediaType: 'image/png' }])
55
- const blocks = content as Array<{ text?: string }>
56
-
57
- expect(blocks.some((b) => b.text === 'what is this')).toBe(true)
58
- })
59
-
60
- it('leaves a plain message untouched', () => {
61
- const messages = toBedrockMessages([
62
- { role: 'user', content: 'no attachments' },
63
- ] as ChatCompletionParams['messages'])
64
-
65
- expect(messages[0]?.content).toEqual([{ text: 'no attachments' }])
66
- })
67
- })
68
-
69
- describe('what the driver does map is unaffected', () => {
70
- it('maps tool calls, which is what this driver is for', () => {
71
- const messages = toBedrockMessages([
72
- { role: 'user', content: 'read it' },
73
- {
74
- role: 'assistant',
75
- content: null,
76
- toolCalls: [
77
- { id: 'call_1', type: 'function', function: { name: 'read', arguments: '{"p":1}' } },
78
- ],
79
- },
80
- ] as unknown as ChatCompletionParams['messages'])
81
-
82
- const toolUse = (messages[1]?.content ?? []).find(
83
- (b) => (b as { toolUse?: unknown }).toolUse,
84
- ) as { toolUse: { name: string; input: unknown } }
85
-
86
- expect(toolUse.toolUse.name).toBe('read')
87
- expect(toolUse.toolUse.input).toEqual({ p: 1 })
88
- })
89
-
90
- it('drops system messages from the turn list', () => {
91
- const messages = toBedrockMessages([
92
- { role: 'system', content: 'be terse' },
93
- { role: 'user', content: 'hi' },
94
- ] as ChatCompletionParams['messages'])
95
-
96
- expect(messages.map((m) => m.role)).toEqual(['user'])
97
- })
98
- })