@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,76 +0,0 @@
1
- import { describe, expect, it } from 'vitest';
2
- import { toBedrockToolConfig } from '../client.js';
3
- /**
4
- * `toolChoice: 'none'` means the model must not call a tool. This driver
5
- * mapped it to the wire's "auto", which means the model MAY — the exact
6
- * opposite of what the caller asked for, and silent.
7
- *
8
- * The runtime relies on it: an advisory consultation passes `'none'` so the
9
- * advisor answers in prose. Under this driver the advisor could emit a tool
10
- * call instead, into a turn with no executor waiting for one.
11
- *
12
- * The fix is not a better mapping. Every version of every wire format
13
- * agrees a model cannot call a tool it was never given, so `'none'` sends
14
- * no tools at all — a guarantee rather than a request.
15
- */
16
- const TOOLS = [
17
- {
18
- type: 'function',
19
- function: { name: 'read', description: 'read a file', parameters: { type: 'object' } },
20
- },
21
- ];
22
- describe("a caller that said 'none' gets no tools on the wire", () => {
23
- it('omits the tool config entirely', () => {
24
- expect(toBedrockToolConfig({ model: 'm', messages: [], tools: TOOLS, toolChoice: 'none' })).toBe(undefined);
25
- });
26
- it('omits it even when the history contains tool blocks', () => {
27
- const config = toBedrockToolConfig({
28
- model: 'm',
29
- messages: [
30
- {
31
- role: 'assistant',
32
- content: null,
33
- toolCalls: [{ id: 'c1', type: 'function', function: { name: 'read', arguments: '{}' } }],
34
- },
35
- { role: 'tool', content: 'ok', toolCallId: 'c1' },
36
- ],
37
- toolChoice: 'none',
38
- });
39
- expect(config).toBe(undefined);
40
- });
41
- });
42
- describe('the other choices still reach the wire unchanged', () => {
43
- it('maps auto', () => {
44
- const config = toBedrockToolConfig({
45
- model: 'm',
46
- messages: [],
47
- tools: TOOLS,
48
- toolChoice: 'auto',
49
- });
50
- expect(config?.toolChoice).toEqual({ auto: {} });
51
- expect(config?.tools).toHaveLength(1);
52
- });
53
- it('maps required', () => {
54
- const config = toBedrockToolConfig({
55
- model: 'm',
56
- messages: [],
57
- tools: TOOLS,
58
- toolChoice: 'required',
59
- });
60
- expect(config?.toolChoice).toEqual({ any: {} });
61
- });
62
- it('maps a named tool', () => {
63
- const config = toBedrockToolConfig({
64
- model: 'm',
65
- messages: [],
66
- tools: TOOLS,
67
- toolChoice: { type: 'function', function: { name: 'read' } },
68
- });
69
- expect(config?.toolChoice).toEqual({ tool: { name: 'read' } });
70
- });
71
- it('defaults to auto when the caller said nothing', () => {
72
- const config = toBedrockToolConfig({ model: 'm', messages: [], tools: TOOLS });
73
- expect(config?.toolChoice).toEqual({ auto: {} });
74
- });
75
- });
76
- //# sourceMappingURL=tool-choice-none.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"tool-choice-none.test.js","sourceRoot":"","sources":["../../src/__tests__/tool-choice-none.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAA;AAE7C,OAAO,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAA;AAElD;;;;;;;;;;;;GAYG;AAEH,MAAM,KAAK,GAAG;IACb;QACC,IAAI,EAAE,UAAmB;QACzB,QAAQ,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,aAAa,EAAE,UAAU,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE;KACtF;CACD,CAAA;AAED,QAAQ,CAAC,qDAAqD,EAAE,GAAG,EAAE;IACpE,EAAE,CAAC,gCAAgC,EAAE,GAAG,EAAE;QACzC,MAAM,CACL,mBAAmB,CAAC,EAAE,KAAK,EAAE,GAAG,EAAE,QAAQ,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,EAAE,CAAC,CACnF,CAAC,IAAI,CAAC,SAAS,CAAC,CAAA;IAClB,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,qDAAqD,EAAE,GAAG,EAAE;QAC9D,MAAM,MAAM,GAAG,mBAAmB,CAAC;YAClC,KAAK,EAAE,GAAG;YACV,QAAQ,EAAE;gBACT;oBACC,IAAI,EAAE,WAAW;oBACjB,OAAO,EAAE,IAAI;oBACb,SAAS,EAAE,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,UAAU,EAAE,QAAQ,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,EAAE,CAAC;iBACxF;gBACD,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE;aACQ;YAC1D,UAAU,EAAE,MAAM;SAClB,CAAC,CAAA;QAEF,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAA;IAC/B,CAAC,CAAC,CAAA;AACH,CAAC,CAAC,CAAA;AAEF,QAAQ,CAAC,kDAAkD,EAAE,GAAG,EAAE;IACjE,EAAE,CAAC,WAAW,EAAE,GAAG,EAAE;QACpB,MAAM,MAAM,GAAG,mBAAmB,CAAC;YAClC,KAAK,EAAE,GAAG;YACV,QAAQ,EAAE,EAAE;YACZ,KAAK,EAAE,KAAK;YACZ,UAAU,EAAE,MAAM;SAClB,CAAC,CAAA;QACF,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,CAAA;QAChD,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAA;IACtC,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,eAAe,EAAE,GAAG,EAAE;QACxB,MAAM,MAAM,GAAG,mBAAmB,CAAC;YAClC,KAAK,EAAE,GAAG;YACV,QAAQ,EAAE,EAAE;YACZ,KAAK,EAAE,KAAK;YACZ,UAAU,EAAE,UAAU;SACtB,CAAC,CAAA;QACF,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC,OAAO,CAAC,EAAE,GAAG,EAAE,EAAE,EAAE,CAAC,CAAA;IAChD,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,mBAAmB,EAAE,GAAG,EAAE;QAC5B,MAAM,MAAM,GAAG,mBAAmB,CAAC;YAClC,KAAK,EAAE,GAAG;YACV,QAAQ,EAAE,EAAE;YACZ,KAAK,EAAE,KAAK;YACZ,UAAU,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE,QAAQ,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE;SAC5D,CAAC,CAAA;QACF,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,CAAC,CAAA;IAC/D,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,+CAA+C,EAAE,GAAG,EAAE;QACxD,MAAM,MAAM,GAAG,mBAAmB,CAAC,EAAE,KAAK,EAAE,GAAG,EAAE,QAAQ,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAA;QAC9E,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,CAAA;IACjD,CAAC,CAAC,CAAA;AACH,CAAC,CAAC,CAAA"}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=tool-content-blocks.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"tool-content-blocks.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/tool-content-blocks.test.ts"],"names":[],"mappings":""}
@@ -1,92 +0,0 @@
1
- import { describe, expect, it } from 'vitest';
2
- import { toBedrockMessages } from '../client.js';
3
- /**
4
- * A tool result carrying content blocks was `JSON.stringify`d into the
5
- * text field, so a screenshot reached the model as a wall of quoted base64:
6
- * unreadable, and paid for by the character.
7
- *
8
- * This driver does not map image content — `supportsVision` is false and
9
- * says so — which makes the honest form the SDK's named placeholder. It
10
- * reports what was there and how big it was, so the model knows something
11
- * was withheld rather than believing it saw a JSON object.
12
- */
13
- const PNG = 'iVBORw0KGgo=';
14
- function toolResultFor(content) {
15
- const messages = toBedrockMessages([
16
- { role: 'user', content: 'take a shot' },
17
- {
18
- role: 'assistant',
19
- content: null,
20
- toolCalls: [
21
- { id: 'call_1', type: 'function', function: { name: 'screenshot', arguments: '{}' } },
22
- ],
23
- },
24
- { role: 'tool', toolCallId: 'call_1', content },
25
- ]);
26
- const block = messages
27
- .flatMap((m) => m.content ?? [])
28
- .find((b) => b.toolResult);
29
- return block.toolResult;
30
- }
31
- function textOf(result) {
32
- const content = result.content;
33
- return content.map((c) => c.text ?? '').join('\n');
34
- }
35
- describe('a tool result the wire cannot carry is described, not dumped', () => {
36
- it('names the media type and size instead of the payload', () => {
37
- const text = textOf(toolResultFor([{ type: 'image', mediaType: 'image/png', data: PNG }]));
38
- expect(text).toContain('image/png');
39
- expect(text).toMatch(/\d+(\.\d+)? (B|KB|MB)/);
40
- });
41
- it('does not put the base64 payload in the text', () => {
42
- const text = textOf(toolResultFor([{ type: 'image', mediaType: 'image/png', data: 'A'.repeat(2048) }]));
43
- // The bug in one assertion: the payload used to be JSON-quoted into
44
- // the text field, so the model paid for 2048 unreadable characters.
45
- expect(text).not.toContain('A'.repeat(64));
46
- });
47
- it('keeps the text blocks that sit alongside', () => {
48
- const text = textOf(toolResultFor([
49
- { type: 'text', text: 'captured the window' },
50
- { type: 'image', mediaType: 'image/png', data: PNG },
51
- ]));
52
- expect(text).toContain('captured the window');
53
- expect(text).toContain('image/png');
54
- });
55
- it('names a document by its filename', () => {
56
- const text = textOf(toolResultFor([
57
- { type: 'document', mediaType: 'application/pdf', data: 'JVBER', name: 'lease.pdf' },
58
- ]));
59
- expect(text).toContain('lease.pdf');
60
- expect(text).toContain('application/pdf');
61
- });
62
- });
63
- describe('the plain cases are unchanged', () => {
64
- it('passes a string result straight through', () => {
65
- expect(textOf(toolResultFor('just text'))).toBe('just text');
66
- });
67
- it('passes text-only blocks through as their text', () => {
68
- expect(textOf(toolResultFor([{ type: 'text', text: 'only words' }]))).toBe('only words');
69
- });
70
- it('answers the tool call it was given', () => {
71
- expect(toolResultFor('x').toolUseId).toBe('call_1');
72
- });
73
- it('groups results answering one turn into a single message', () => {
74
- const messages = toBedrockMessages([
75
- { role: 'user', content: 'read both' },
76
- {
77
- role: 'assistant',
78
- content: null,
79
- toolCalls: [
80
- { id: 'call_1', type: 'function', function: { name: 'read', arguments: '{}' } },
81
- { id: 'call_2', type: 'function', function: { name: 'read', arguments: '{}' } },
82
- ],
83
- },
84
- { role: 'tool', toolCallId: 'call_1', content: 'one' },
85
- { role: 'tool', toolCallId: 'call_2', content: 'two' },
86
- ]);
87
- const resultTurns = messages.filter((m) => (m.content ?? []).every((b) => b.toolResult));
88
- expect(resultTurns).toHaveLength(1);
89
- expect(resultTurns[0]?.content).toHaveLength(2);
90
- });
91
- });
92
- //# sourceMappingURL=tool-content-blocks.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"tool-content-blocks.test.js","sourceRoot":"","sources":["../../src/__tests__/tool-content-blocks.test.ts"],"names":[],"mappings":"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"}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=tool-schema-dialect.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"tool-schema-dialect.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/tool-schema-dialect.test.ts"],"names":[],"mappings":""}
@@ -1,98 +0,0 @@
1
- import { findDraft07Only } from '@namzu/sdk';
2
- import { describe, expect, it } from 'vitest';
3
- import { toBedrockToolConfig } from '../client.js';
4
- /**
5
- * Converse carries Claude, so it carries Claude's schema dialect too.
6
- *
7
- * The kernel renders tool schemas as draft-07, where a tuple is
8
- * `items: [a, b]`. Anthropic's serving layer validates `input_schema` as JSON
9
- * Schema 2020-12, where that spelling is invalid — the tuple has to be
10
- * `prefixItems` — and it rejects the whole request rather than ignoring the
11
- * field, so one tuple-shaped tool takes down every tool in the call.
12
- *
13
- * That fix landed on the direct Anthropic driver and on the HTTP driver's
14
- * Anthropic branch, and this driver was missed. It reaches the same models
15
- * through a different front door; the validation happens in the same place.
16
- *
17
- * The conversion follows the MODEL, not the endpoint, because Converse is
18
- * multi-vendor: `meta.llama*` and `mistral.*` come through this same function,
19
- * and nothing establishes that they read 2020-12. Converting their schemas
20
- * would be trading a known break for an unmeasured one.
21
- */
22
- const TUPLE_TOOL = [
23
- {
24
- type: 'function',
25
- function: {
26
- name: 'read',
27
- description: 'reads',
28
- parameters: {
29
- type: 'object',
30
- properties: {
31
- // What `z.tuple([z.number(), z.number()])` renders to.
32
- readRange: {
33
- type: 'array',
34
- items: [{ type: 'number' }, { type: 'number' }],
35
- minItems: 2,
36
- maxItems: 2,
37
- },
38
- },
39
- },
40
- },
41
- },
42
- ];
43
- function rangeOf(model) {
44
- const config = toBedrockToolConfig({ model, messages: [], tools: TUPLE_TOOL });
45
- const json = config?.tools?.[0]?.toolSpec?.inputSchema?.json;
46
- const properties = json.properties;
47
- return properties.readRange;
48
- }
49
- function schemaOf(model) {
50
- const config = toBedrockToolConfig({ model, messages: [], tools: TUPLE_TOOL });
51
- return config?.tools?.[0]?.toolSpec?.inputSchema?.json;
52
- }
53
- describe('a tuple reaches Claude on Converse in the dialect Claude reads', () => {
54
- it.each([
55
- ['anthropic.claude-sonnet-4-20250514', 'a bare vendor id'],
56
- ['us.anthropic.claude-sonnet-4-5-20250929-v1:0', 'behind an inference profile'],
57
- ['EU.Anthropic.Claude-Opus-4-1-v1:0', 'in whatever case the caller wrote'],
58
- ])('converts for %s (%s)', (model) => {
59
- expect(findDraft07Only(schemaOf(model))).toEqual([]);
60
- const range = rangeOf(model);
61
- expect(range.prefixItems).toHaveLength(2);
62
- expect(range.items).toBeUndefined();
63
- });
64
- it('leaves another vendor on this wire alone', () => {
65
- // Not timidity — the absence of a measurement. Anthropic's requirement
66
- // was measured against its own wire; no such reading exists for these,
67
- // and converting on a guess swaps a known break for an unknown one.
68
- const range = rangeOf('meta.llama3-70b-instruct-v1:0');
69
- expect(range.items).toHaveLength(2);
70
- expect(range.prefixItems).toBeUndefined();
71
- });
72
- it('does not disturb a schema with no tuple in it', () => {
73
- const config = toBedrockToolConfig({
74
- model: 'anthropic.claude-sonnet-4-20250514',
75
- messages: [],
76
- tools: [
77
- {
78
- type: 'function',
79
- function: {
80
- name: 'ls',
81
- description: 'lists',
82
- parameters: {
83
- type: 'object',
84
- properties: { path: { type: 'string' } },
85
- required: ['path'],
86
- },
87
- },
88
- },
89
- ],
90
- });
91
- expect(config?.tools?.[0]?.toolSpec?.inputSchema?.json).toEqual({
92
- type: 'object',
93
- properties: { path: { type: 'string' } },
94
- required: ['path'],
95
- });
96
- });
97
- });
98
- //# sourceMappingURL=tool-schema-dialect.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"tool-schema-dialect.test.js","sourceRoot":"","sources":["../../src/__tests__/tool-schema-dialect.test.ts"],"names":[],"mappings":"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"}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=vision.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"vision.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/vision.test.ts"],"names":[],"mappings":""}
@@ -1,77 +0,0 @@
1
- import { describe, expect, it } from 'vitest';
2
- import { BEDROCK_CAPABILITIES, toBedrockMessages } from '../client.js';
3
- /**
4
- * This driver does not map image attachments, and says so.
5
- *
6
- * That is a legitimate state — a driver may ship without a wire shape —
7
- * but only while the claim and the code agree. The failure this pins is
8
- * drift in either direction: flipping the flag without writing the mapping
9
- * makes the runtime stop warning about images that still vanish, and
10
- * writing the mapping without flipping the flag makes it keep warning
11
- * about images that now arrive.
12
- *
13
- * The runtime reads the flag and warns (or fails under `strictCapabilities`)
14
- * before the request is built, so the flag is the contract.
15
- */
16
- const PNG = 'iVBORw0KGgo=';
17
- function contentFor(attachments) {
18
- const messages = toBedrockMessages([
19
- { role: 'user', content: 'what is this', attachments },
20
- ]);
21
- return messages[0]?.content;
22
- }
23
- describe('the capability claim and the mapper agree', () => {
24
- it('declares that images are not mapped', () => {
25
- expect(BEDROCK_CAPABILITIES.supportsVision).toBe(false);
26
- });
27
- it('declares that documents are not mapped', () => {
28
- expect(BEDROCK_CAPABILITIES.supportsDocuments).toBe(false);
29
- });
30
- it('sends no image block, matching the claim', () => {
31
- const content = contentFor([{ type: 'image', data: PNG, mediaType: 'image/png' }]);
32
- const blocks = content;
33
- expect(blocks.some((b) => 'image' in b)).toBe(false);
34
- });
35
- it('does not smuggle the payload into the text either', () => {
36
- const content = contentFor([{ type: 'image', data: 'A'.repeat(2048), mediaType: 'image/png' }]);
37
- // Dropping is the declared behaviour. Stringifying it into the
38
- // prompt would be worse than dropping: unreadable, and billed.
39
- expect(JSON.stringify(content)).not.toContain('A'.repeat(64));
40
- });
41
- it('still sends the message text', () => {
42
- const content = contentFor([{ type: 'image', data: PNG, mediaType: 'image/png' }]);
43
- const blocks = content;
44
- expect(blocks.some((b) => b.text === 'what is this')).toBe(true);
45
- });
46
- it('leaves a plain message untouched', () => {
47
- const messages = toBedrockMessages([
48
- { role: 'user', content: 'no attachments' },
49
- ]);
50
- expect(messages[0]?.content).toEqual([{ text: 'no attachments' }]);
51
- });
52
- });
53
- describe('what the driver does map is unaffected', () => {
54
- it('maps tool calls, which is what this driver is for', () => {
55
- const messages = toBedrockMessages([
56
- { role: 'user', content: 'read it' },
57
- {
58
- role: 'assistant',
59
- content: null,
60
- toolCalls: [
61
- { id: 'call_1', type: 'function', function: { name: 'read', arguments: '{"p":1}' } },
62
- ],
63
- },
64
- ]);
65
- const toolUse = (messages[1]?.content ?? []).find((b) => b.toolUse);
66
- expect(toolUse.toolUse.name).toBe('read');
67
- expect(toolUse.toolUse.input).toEqual({ p: 1 });
68
- });
69
- it('drops system messages from the turn list', () => {
70
- const messages = toBedrockMessages([
71
- { role: 'system', content: 'be terse' },
72
- { role: 'user', content: 'hi' },
73
- ]);
74
- expect(messages.map((m) => m.role)).toEqual(['user']);
75
- });
76
- });
77
- //# sourceMappingURL=vision.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"vision.test.js","sourceRoot":"","sources":["../../src/__tests__/vision.test.ts"],"names":[],"mappings":"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"}
@@ -1,103 +0,0 @@
1
- import { DuplicateProviderError, ProviderRegistry } from '@namzu/sdk'
2
- import { beforeEach, describe, expect, it } from 'vitest'
3
- import { BEDROCK_CAPABILITIES, BedrockProvider, registerBedrock } from '../index.js'
4
-
5
- // Ensure a clean slate between tests. The sdk pre-registers 'mock' on import
6
- // via its sideEffects whitelist; we only need to clear 'bedrock' to make
7
- // re-registration deterministic across tests.
8
- beforeEach(() => {
9
- if (ProviderRegistry.isSupported('bedrock')) {
10
- ProviderRegistry.unregister('bedrock')
11
- }
12
- })
13
-
14
- describe('@namzu/bedrock', () => {
15
- describe('registerBedrock()', () => {
16
- it("adds 'bedrock' to the ProviderRegistry", () => {
17
- expect(ProviderRegistry.isSupported('bedrock')).toBe(false)
18
- registerBedrock()
19
- expect(ProviderRegistry.isSupported('bedrock')).toBe(true)
20
- expect(ProviderRegistry.listTypes()).toContain('bedrock')
21
- })
22
-
23
- it('throws DuplicateProviderError when called twice without options', () => {
24
- registerBedrock()
25
- expect(() => registerBedrock()).toThrowError(DuplicateProviderError)
26
- })
27
-
28
- it('allows re-registration when { replace: true } is passed', () => {
29
- registerBedrock()
30
- expect(() => registerBedrock({ replace: true })).not.toThrow()
31
- expect(ProviderRegistry.isSupported('bedrock')).toBe(true)
32
- })
33
-
34
- it('exposes capabilities through the registry after registration', () => {
35
- registerBedrock()
36
- const caps = ProviderRegistry.getCapabilities('bedrock')
37
- expect(caps).toEqual(BEDROCK_CAPABILITIES)
38
- })
39
- })
40
-
41
- describe('BEDROCK_CAPABILITIES', () => {
42
- it('declares the expected capability flags', () => {
43
- expect(BEDROCK_CAPABILITIES).toEqual({
44
- supportsTools: true,
45
- supportsStreaming: true,
46
- supportsFunctionCalling: true,
47
- supportsVision: false,
48
- supportsDocuments: false,
49
- })
50
- })
51
-
52
- it('is exposed on the provider instance for runtime negotiation', () => {
53
- const provider = new BedrockProvider({ region: 'us-east-1' })
54
- expect(provider.capabilities).toEqual(BEDROCK_CAPABILITIES)
55
- })
56
- })
57
-
58
- it('keeps the Namzu enforcement hint out of the Bedrock command', async () => {
59
- const provider = new BedrockProvider({ region: 'us-east-1' })
60
- let commandInput: Record<string, unknown> | undefined
61
- ;(provider as unknown as { client: unknown }).client = {
62
- send: async (command: { input: Record<string, unknown> }) => {
63
- commandInput = command.input
64
- return {
65
- $metadata: { requestId: 'request-test' },
66
- stream: (async function* () {})(),
67
- }
68
- },
69
- }
70
-
71
- for await (const _chunk of provider.chatStream({
72
- model: 'anthropic.claude-sonnet-5-v1:0',
73
- messages: [{ role: 'user', content: 'edit' }],
74
- tools: [
75
- {
76
- type: 'function',
77
- function: {
78
- name: 'edit',
79
- description: 'Edit',
80
- parameters: { type: 'object' },
81
- },
82
- },
83
- ],
84
- enforceToolInputSchema: ['edit'],
85
- })) {
86
- // Drain the empty test stream.
87
- }
88
-
89
- expect(commandInput).not.toHaveProperty('enforceToolInputSchema')
90
- expect(commandInput?.toolConfig).toEqual({
91
- tools: [
92
- {
93
- toolSpec: {
94
- name: 'edit',
95
- description: 'Edit',
96
- inputSchema: { json: { type: 'object' } },
97
- },
98
- },
99
- ],
100
- toolChoice: { auto: {} },
101
- })
102
- })
103
- })