opencode-crs-bedrock 1.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.
package/README.md ADDED
@@ -0,0 +1,206 @@
1
+ # opencode-crs-bedrock
2
+
3
+ OpenCode plugin for FeedMob CRS (Claude Relay Service) proxy to AWS Bedrock Anthropic models.
4
+
5
+ ## Why This Plugin?
6
+
7
+ When using CRS to proxy requests to AWS Bedrock's Anthropic models, the response format differs from the native Anthropic API in ways that break `@ai-sdk/anthropic`:
8
+
9
+ | Issue | What CRS/Bedrock Returns | What SDK Expects |
10
+ |-------|--------------------------|------------------|
11
+ | Model IDs | `us.anthropic.claude-sonnet-4-20250514-v1:0` | `claude-sonnet-4-20250514` |
12
+ | Message start | `{type: "message", ...}` | `{type: "message_start", message: {...}}` |
13
+ | Tool calls | Missing `content_block_start` events | `content_block_start` with tool name and ID |
14
+ | Block close | Missing `content_block_stop` events | `content_block_stop` before `message_delta` |
15
+
16
+ This plugin transforms the CRS response stream to match what the Anthropic SDK expects.
17
+
18
+ ## Features
19
+
20
+ - **SSE Stream Transformation** - Fixes discriminator validation errors
21
+ - **Tool Name Inference** - Buffers tool call deltas and infers correct tool name from parameters
22
+ - **Event Injection** - Adds missing `content_block_start` and `content_block_stop` events
23
+ - **Model ID Mapping** - Converts Bedrock model IDs to standard Anthropic format
24
+ - **API Key Auth** - Uses `x-api-key` header (bypasses SDK's `sk-ant-` validation)
25
+
26
+ ## Installation
27
+
28
+ ### Local Development
29
+
30
+ Reference directly in your OpenCode config:
31
+
32
+ ```json
33
+ {
34
+ "plugin": [
35
+ "file:///path/to/opencode-crs-bedrock"
36
+ ]
37
+ }
38
+ ```
39
+
40
+ ### From npm (when published)
41
+
42
+ ```bash
43
+ npm install -g opencode-crs-bedrock
44
+ ```
45
+
46
+ ## Configuration
47
+
48
+ ### 1. Set Environment Variables
49
+
50
+ ```bash
51
+ export ANTHROPIC_BASE_URL=https://your-crs-endpoint.com/api
52
+ export ANTHROPIC_AUTH_TOKEN=cr_your_api_key_here
53
+ ```
54
+
55
+ Add to your shell profile (`~/.bashrc`, `~/.zshrc`) to persist.
56
+
57
+ ### 2. Create OpenCode Config
58
+
59
+ Create `opencode.json` in your project or `~/.config/opencode/opencode.json` globally:
60
+
61
+ ```json
62
+ {
63
+ "$schema": "https://opencode.ai/config.json",
64
+ "plugin": [
65
+ "opencode-crs-bedrock"
66
+ ],
67
+ "provider": {
68
+ "crs": {
69
+ "npm": "@ai-sdk/anthropic",
70
+ "options": {
71
+ "baseURL": "{env:ANTHROPIC_BASE_URL}",
72
+ "apiKey": "{env:ANTHROPIC_AUTH_TOKEN}"
73
+ },
74
+ "models": {
75
+ "claude-opus-4-5": {
76
+ "name": "Opus 4.5 [CRS]",
77
+ "limit": { "context": 200000, "output": 64000 },
78
+ "modalities": { "input": ["text", "image", "pdf"], "output": ["text"] },
79
+ "variants": {
80
+ "low": { "thinkingConfig": { "thinkingBudget": 8192 } },
81
+ "max": { "thinkingConfig": { "thinkingBudget": 32768 } }
82
+ }
83
+ },
84
+ "claude-sonnet-4-5": {
85
+ "name": "Sonnet 4.5 [CRS]",
86
+ "modalities": { "input": ["text", "image", "pdf"], "output": ["text"] },
87
+ "variants": {
88
+ "low": { "thinkingConfig": { "thinkingBudget": 8192 } },
89
+ "max": { "thinkingConfig": { "thinkingBudget": 32768 } }
90
+ }
91
+ }
92
+ }
93
+ }
94
+ }
95
+ }
96
+ ```
97
+
98
+ ### 3. Use the Model
99
+
100
+ ```bash
101
+ # Interactive mode
102
+ opencode
103
+
104
+ # Or direct run with default model
105
+ opencode run -m crs/claude-sonnet-4-5 "Hello, world!"
106
+
107
+ # Use with thinking budget variants
108
+ opencode run -m crs/claude-opus-4-5:low "Simple task" # 8K thinking tokens
109
+ opencode run -m crs/claude-opus-4-5:max "Complex task" # 32K thinking tokens
110
+ ```
111
+
112
+ ## Model Configuration
113
+
114
+ ### Context Limits
115
+
116
+ - **Opus 4.5**: 200K context, 64K output tokens
117
+ - **Sonnet 4.5**: Default limits (inherited from SDK)
118
+
119
+ ### Extended Thinking
120
+
121
+ Both models support extended thinking with configurable budgets via variants:
122
+
123
+ - **`:low`** - 8,192 thinking tokens for simpler tasks
124
+ - **`:max`** - 32,768 thinking tokens for complex reasoning
125
+
126
+ Use variants by appending `:variant` to the model ID (e.g., `crs/claude-opus-4-5:max`).
127
+
128
+ ### Modalities
129
+
130
+ All models support:
131
+ - **Input**: text, images, PDF documents
132
+ - **Output**: text
133
+
134
+ ## Supported Models
135
+
136
+ Models available through CRS/Bedrock:
137
+
138
+ | Model ID | Bedrock ID |
139
+ |----------|------------|
140
+ | `claude-sonnet-4-20250514` | `us.anthropic.claude-sonnet-4-20250514-v1:0` |
141
+ | `claude-opus-4-20250514` | `us.anthropic.claude-opus-4-20250514-v1:0` |
142
+ | `claude-3-5-sonnet-20241022` | `us.anthropic.claude-3-5-sonnet-20241022-v2:0` |
143
+ | `claude-3-5-haiku-20241022` | `us.anthropic.claude-3-5-haiku-20241022-v1:0` |
144
+ | `claude-3-opus-20240229` | `us.anthropic.claude-3-opus-20240229-v1:0` |
145
+
146
+ ## Debugging
147
+
148
+ Enable debug logging to see SSE transformation details:
149
+
150
+ ```bash
151
+ CRS_DEBUG_SSE=true opencode
152
+ ```
153
+
154
+ Example output:
155
+ ```
156
+ [CRS-SSE] Event: message_start Data: {"type":"message","id":"msg_123"...}
157
+ [CRS-SSE] Event: content_block_delta Data: {"index":1,"delta":{"type":"input_json_delta"...}}
158
+ [CRS-SSE] Buffering tool delta, accumulated: {"query": "bitcoin price"
159
+ [CRS-SSE] Flushing pending tool block 1 with inferred name: websearch
160
+ ```
161
+
162
+ ## How Tool Name Inference Works
163
+
164
+ CRS/Bedrock doesn't send `content_block_start` for tool calls, so the plugin:
165
+
166
+ 1. **Detects tool deltas** - When `input_json_delta` arrives without a prior `content_block_start`
167
+ 2. **Buffers deltas** - Accumulates the JSON until complete
168
+ 3. **Infers tool name** - Matches accumulated JSON keys against tool schemas
169
+ 4. **Emits events** - Sends `content_block_start` with inferred name, then buffered deltas
170
+
171
+ The inference scores each tool by:
172
+ - +1 for each matching parameter key
173
+ - -1 for each unknown key
174
+ - +10 bonus if all required parameters present
175
+
176
+ ## Troubleshooting
177
+
178
+ ### "Invalid input: expected array, received undefined"
179
+
180
+ This error means tool name inference failed. Enable debug logging to see which tool was inferred.
181
+
182
+ ### API Key Format
183
+
184
+ CRS API keys start with `cr_`. The plugin uses the `x-api-key` header instead of the standard Anthropic auth.
185
+
186
+ ### Connection Issues
187
+
188
+ 1. Verify environment variables:
189
+ ```bash
190
+ echo $ANTHROPIC_BASE_URL
191
+ echo $ANTHROPIC_AUTH_TOKEN
192
+ ```
193
+
194
+ 2. Test the endpoint:
195
+ ```bash
196
+ curl -H "x-api-key: $ANTHROPIC_AUTH_TOKEN" "$ANTHROPIC_BASE_URL/v1/messages"
197
+ ```
198
+
199
+ 3. Enable debug logging:
200
+ ```bash
201
+ CRS_DEBUG_SSE=true opencode run -m crs/claude-sonnet-4-5 "test"
202
+ ```
203
+
204
+ ## License
205
+
206
+ MIT
package/bun.lock ADDED
@@ -0,0 +1,19 @@
1
+ {
2
+ "lockfileVersion": 1,
3
+ "configVersion": 1,
4
+ "workspaces": {
5
+ "": {
6
+ "name": "opencode-crs-bedrock",
7
+ "dependencies": {
8
+ "@opencode-ai/plugin": "*",
9
+ },
10
+ },
11
+ },
12
+ "packages": {
13
+ "@opencode-ai/plugin": ["@opencode-ai/plugin@1.1.23", "", { "dependencies": { "@opencode-ai/sdk": "1.1.23", "zod": "4.1.8" } }, "sha512-O/iLSKOUuzD95UWhj9y/tEuycPEBv36de0suHXXqeYLWZLZ16DAUSKR+YG7rvRjJS0sbn4biVMw+k7XXk/oxiQ=="],
14
+
15
+ "@opencode-ai/sdk": ["@opencode-ai/sdk@1.1.23", "", {}, "sha512-YjN9ogzkLol92s+/iARXRop9/5oFIezUkvWVay12u1IM6A/WJs50DeKl3oL0x4a68P1a5tI5gD98dLnk2+AlsA=="],
16
+
17
+ "zod": ["zod@4.1.8", "", {}, "sha512-5R1P+WwQqmmMIEACyzSvo4JXHY5WiAFHRMg+zBZKgKS+Q1viRa0C1hmUKtHltoIFKtIdki3pRxkmpP74jnNYHQ=="],
18
+ }
19
+ }