@sunerpy/opencode-kiro-auth 0.4.2 → 0.5.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/README.md +13 -0
- package/dist/core/request/response-handler.js +9 -1
- package/dist/plugin/effort.js +1 -1
- package/dist/plugin/models.d.ts +21 -0
- package/dist/plugin/models.js +34 -0
- package/dist/plugin/request.js +8 -7
- package/dist/plugin/streaming/sdk-stream-transformer.js +46 -0
- package/dist/plugin.js +95 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -192,6 +192,19 @@ Details and the full JSON example: [docs/MODELS.md](docs/MODELS.md).
|
|
|
192
192
|
> `kiro.json` instead. See
|
|
193
193
|
> [Reasoning effort](docs/CONFIGURATION.md#reasoning-effort) for details.
|
|
194
194
|
|
|
195
|
+
> **Note:** Reasoning-capable Kiro models (Claude Opus 4.x and other
|
|
196
|
+
> reasoning-capable models) stream their chain-of-thought as a separate
|
|
197
|
+
> event, which the plugin surfaces as OpenCode's own reasoning block — shown
|
|
198
|
+
> as "Thought: `<duration>`" above the final reply. No config needed. See
|
|
199
|
+
> [Reasoning display](docs/CONFIGURATION.md#reasoning-display) for details.
|
|
200
|
+
|
|
201
|
+
> **Note:** Per-request thinking level via model variants — pick
|
|
202
|
+
> `kiro-auth/claude-opus-4-8-xhigh` (or similar) straight from the model
|
|
203
|
+
> list to pin an explicit Kiro effort level for that model, no `kiro.json`
|
|
204
|
+
> edit needed. Base models like `claude-opus-4-8` remain available and keep
|
|
205
|
+
> using the global `effort` setting. See [docs/VARIANTS.md](docs/VARIANTS.md)
|
|
206
|
+
> for the full variant list and why they exist.
|
|
207
|
+
|
|
195
208
|
## Troubleshooting
|
|
196
209
|
|
|
197
210
|
Common issues — 403/AccessDeniedException with IAM Identity Center, "No
|
|
@@ -84,12 +84,16 @@ export class ResponseHandler {
|
|
|
84
84
|
async handleSdkNonStreaming(sdkResponse, model, conversationId) {
|
|
85
85
|
// For non-streaming SDK responses, collect all events
|
|
86
86
|
let content = '';
|
|
87
|
+
let reasoningContent = '';
|
|
87
88
|
const toolCalls = [];
|
|
88
89
|
let inputTokens = 0;
|
|
89
90
|
let outputTokens = 0;
|
|
90
91
|
const eventStream = sdkResponse.generateAssistantResponseResponse;
|
|
91
92
|
if (eventStream) {
|
|
92
93
|
for await (const event of eventStream) {
|
|
94
|
+
if (event.reasoningContentEvent?.text) {
|
|
95
|
+
reasoningContent += event.reasoningContentEvent.text;
|
|
96
|
+
}
|
|
93
97
|
if (event.assistantResponseEvent?.content) {
|
|
94
98
|
content += event.assistantResponseEvent.content;
|
|
95
99
|
}
|
|
@@ -102,6 +106,10 @@ export class ResponseHandler {
|
|
|
102
106
|
}
|
|
103
107
|
}
|
|
104
108
|
}
|
|
109
|
+
const message = { role: 'assistant', content };
|
|
110
|
+
if (reasoningContent) {
|
|
111
|
+
message.reasoning_content = reasoningContent;
|
|
112
|
+
}
|
|
105
113
|
const oai = {
|
|
106
114
|
id: conversationId,
|
|
107
115
|
object: 'chat.completion',
|
|
@@ -110,7 +118,7 @@ export class ResponseHandler {
|
|
|
110
118
|
choices: [
|
|
111
119
|
{
|
|
112
120
|
index: 0,
|
|
113
|
-
message
|
|
121
|
+
message,
|
|
114
122
|
finish_reason: toolCalls.length > 0 ? 'tool_calls' : 'stop'
|
|
115
123
|
}
|
|
116
124
|
],
|
package/dist/plugin/effort.js
CHANGED
|
@@ -6,7 +6,7 @@ export const EFFORT_LEVELS = ['low', 'medium', 'high', 'xhigh', 'max'];
|
|
|
6
6
|
* Models that support the 5-value effort enum (including xhigh).
|
|
7
7
|
* These models support up to 128k thinking tokens with max effort.
|
|
8
8
|
*/
|
|
9
|
-
const XHIGH_CAPABLE_MODELS = new Set(['claude-opus-4.7', 'claude-opus-4.8']);
|
|
9
|
+
const XHIGH_CAPABLE_MODELS = new Set(['claude-opus-4.7', 'claude-opus-4.8', 'claude-sonnet-5']);
|
|
10
10
|
/**
|
|
11
11
|
* Models that support the 4-value effort enum (no xhigh).
|
|
12
12
|
* xhigh requests on these models are clamped to max.
|
package/dist/plugin/models.d.ts
CHANGED
|
@@ -1,2 +1,23 @@
|
|
|
1
|
+
import type { Effort } from './types.js';
|
|
1
2
|
export declare function resolveKiroModel(model: string): string;
|
|
3
|
+
export interface ResolvedModelVariant {
|
|
4
|
+
wireId: string;
|
|
5
|
+
effort?: Effort;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Resolve a (possibly effort-variant) model id into its Kiro wire id plus an
|
|
9
|
+
* optional parsed effort level.
|
|
10
|
+
*
|
|
11
|
+
* Parse rule (unambiguous, single source of truth):
|
|
12
|
+
* An id is an effort variant ONLY IF it ends with `-<suffix>` for some suffix
|
|
13
|
+
* in EFFORT_SUFFIXES AND the id with that `-<suffix>` removed is in
|
|
14
|
+
* VARIANT_BASE_ALLOWLIST. In that case the wire id is derived SOLELY from the
|
|
15
|
+
* base via MODEL_MAPPING and the effort SOLELY from the parsed suffix.
|
|
16
|
+
*
|
|
17
|
+
* This guarantees ids like `claude-opus-4-8-thinking`, `claude-sonnet-4-5-1m`,
|
|
18
|
+
* and the plain bases (`claude-opus-4-8`) are NEVER parsed as effort variants.
|
|
19
|
+
* Non-variant ids fall through to `resolveKiroModel` (existing behavior/throw)
|
|
20
|
+
* with `effort` left undefined.
|
|
21
|
+
*/
|
|
22
|
+
export declare function resolveModelVariant(model: string): ResolvedModelVariant;
|
|
2
23
|
export declare function getContextWindowSize(model: string): number;
|
package/dist/plugin/models.js
CHANGED
|
@@ -6,6 +6,40 @@ export function resolveKiroModel(model) {
|
|
|
6
6
|
}
|
|
7
7
|
return resolved;
|
|
8
8
|
}
|
|
9
|
+
const VARIANT_BASE_ALLOWLIST = new Set([
|
|
10
|
+
'claude-opus-4-8',
|
|
11
|
+
'claude-opus-4-7',
|
|
12
|
+
'claude-sonnet-5',
|
|
13
|
+
'claude-sonnet-4-6'
|
|
14
|
+
]);
|
|
15
|
+
const EFFORT_SUFFIXES = ['low', 'medium', 'high', 'xhigh', 'max'];
|
|
16
|
+
/**
|
|
17
|
+
* Resolve a (possibly effort-variant) model id into its Kiro wire id plus an
|
|
18
|
+
* optional parsed effort level.
|
|
19
|
+
*
|
|
20
|
+
* Parse rule (unambiguous, single source of truth):
|
|
21
|
+
* An id is an effort variant ONLY IF it ends with `-<suffix>` for some suffix
|
|
22
|
+
* in EFFORT_SUFFIXES AND the id with that `-<suffix>` removed is in
|
|
23
|
+
* VARIANT_BASE_ALLOWLIST. In that case the wire id is derived SOLELY from the
|
|
24
|
+
* base via MODEL_MAPPING and the effort SOLELY from the parsed suffix.
|
|
25
|
+
*
|
|
26
|
+
* This guarantees ids like `claude-opus-4-8-thinking`, `claude-sonnet-4-5-1m`,
|
|
27
|
+
* and the plain bases (`claude-opus-4-8`) are NEVER parsed as effort variants.
|
|
28
|
+
* Non-variant ids fall through to `resolveKiroModel` (existing behavior/throw)
|
|
29
|
+
* with `effort` left undefined.
|
|
30
|
+
*/
|
|
31
|
+
export function resolveModelVariant(model) {
|
|
32
|
+
for (const suffix of EFFORT_SUFFIXES) {
|
|
33
|
+
const marker = `-${suffix}`;
|
|
34
|
+
if (model.endsWith(marker)) {
|
|
35
|
+
const base = model.slice(0, -marker.length);
|
|
36
|
+
if (VARIANT_BASE_ALLOWLIST.has(base)) {
|
|
37
|
+
return { wireId: resolveKiroModel(base), effort: suffix };
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
return { wireId: resolveKiroModel(model), effort: undefined };
|
|
42
|
+
}
|
|
9
43
|
export function getContextWindowSize(model) {
|
|
10
44
|
return isLongContextModel(model) ? 1000000 : 200000;
|
|
11
45
|
}
|
package/dist/plugin/request.js
CHANGED
|
@@ -4,16 +4,16 @@ import { KIRO_CONSTANTS, buildUrl, extractRegionFromArn } from '../constants.js'
|
|
|
4
4
|
import { buildHistory, extractToolNamesFromHistory, historyHasToolCalling, injectSystemPrompt } from '../infrastructure/transformers/history-builder.js';
|
|
5
5
|
import { findOriginalToolCall, getContentText, mergeAdjacentMessages } from '../infrastructure/transformers/message-transformer.js';
|
|
6
6
|
import { convertToolsToCodeWhisperer, deduplicateToolResults } from '../infrastructure/transformers/tool-transformer.js';
|
|
7
|
-
import { getEffectiveEffort } from './effort.js';
|
|
7
|
+
import { getEffectiveEffort, resolveEffort } from './effort.js';
|
|
8
8
|
import { convertImagesToKiroFormat, extractAllImages, extractTextFromParts } from './image-handler.js';
|
|
9
|
-
import {
|
|
9
|
+
import { resolveModelVariant } from './models.js';
|
|
10
10
|
function buildCodeWhispererRequest(body, model, auth, think = false, budget = 20000, showToast) {
|
|
11
11
|
const req = typeof body === 'string' ? JSON.parse(body) : body;
|
|
12
12
|
const { messages, tools, system } = req;
|
|
13
13
|
const convId = crypto.randomUUID();
|
|
14
14
|
if (!messages || messages.length === 0)
|
|
15
15
|
throw new Error('No messages');
|
|
16
|
-
const resolved =
|
|
16
|
+
const { wireId: resolved, effort: variantEffort } = resolveModelVariant(model);
|
|
17
17
|
const systemMsgs = messages.filter((m) => m.role === 'system');
|
|
18
18
|
const otherMsgs = messages.filter((m) => m.role !== 'system');
|
|
19
19
|
let sys = system || '';
|
|
@@ -242,7 +242,7 @@ function buildCodeWhispererRequest(body, model, auth, think = false, budget = 20
|
|
|
242
242
|
}
|
|
243
243
|
}
|
|
244
244
|
}
|
|
245
|
-
return { request, resolved, convId };
|
|
245
|
+
return { request, resolved, convId, variantEffort };
|
|
246
246
|
}
|
|
247
247
|
export function transformToCodeWhisperer(url, body, model, auth, think = false, budget = 20000) {
|
|
248
248
|
const { request, resolved, convId } = buildCodeWhispererRequest(body, model, auth, think, budget);
|
|
@@ -272,9 +272,10 @@ export function transformToCodeWhisperer(url, body, model, auth, think = false,
|
|
|
272
272
|
};
|
|
273
273
|
}
|
|
274
274
|
export function transformToSdkRequest(body, model, auth, think = false, budget = 20000, showToast, effortConfig) {
|
|
275
|
-
const { request, resolved, convId } = buildCodeWhispererRequest(body, model, auth, think, budget, showToast);
|
|
276
|
-
|
|
277
|
-
|
|
275
|
+
const { request, resolved, convId, variantEffort } = buildCodeWhispererRequest(body, model, auth, think, budget, showToast);
|
|
276
|
+
const effort = variantEffort
|
|
277
|
+
? resolveEffort(resolved, variantEffort)
|
|
278
|
+
: getEffectiveEffort(resolved, think, budget, effortConfig?.effort, effortConfig?.autoEffortMapping ?? true);
|
|
278
279
|
return {
|
|
279
280
|
conversationState: request.conversationState,
|
|
280
281
|
profileArn: request.profileArn,
|
|
@@ -24,16 +24,53 @@ export async function* transformSdkStream(sdkResponse, model, conversationId) {
|
|
|
24
24
|
let contextUsagePercentage = null;
|
|
25
25
|
const toolCalls = [];
|
|
26
26
|
let currentToolCall = null;
|
|
27
|
+
// Probe (opus-4.8): reasoning streams via `reasoningContentEvent{text,signature}` as a
|
|
28
|
+
// contiguous run BEFORE `assistantResponseEvent.content`; no `<thinking>` tags emitted.
|
|
29
|
+
// signature is metadata and ignored for rendering.
|
|
30
|
+
let reasoningStarted = false;
|
|
31
|
+
let reasoningClosed = false;
|
|
27
32
|
const eventStream = sdkResponse.generateAssistantResponseResponse;
|
|
28
33
|
if (!eventStream) {
|
|
29
34
|
throw new Error('SDK response has no event stream');
|
|
30
35
|
}
|
|
31
36
|
try {
|
|
32
37
|
for await (const event of eventStream) {
|
|
38
|
+
if (event.reasoningContentEvent?.text) {
|
|
39
|
+
const reasoningText = event.reasoningContentEvent.text;
|
|
40
|
+
if (reasoningClosed) {
|
|
41
|
+
// Defensive, normally unreached (probe: reasoning is contiguous-before-text).
|
|
42
|
+
// The stopped thinking index cannot be reused, so open a fresh one.
|
|
43
|
+
streamState.thinkingBlockIndex = null;
|
|
44
|
+
reasoningClosed = false;
|
|
45
|
+
}
|
|
46
|
+
reasoningStarted = true;
|
|
47
|
+
for (const ev of createThinkingDeltaEvents(reasoningText, streamState)) {
|
|
48
|
+
const _c = convertToOpenAI(ev, conversationId, model);
|
|
49
|
+
if (_c !== null)
|
|
50
|
+
yield _c;
|
|
51
|
+
}
|
|
52
|
+
continue;
|
|
53
|
+
}
|
|
33
54
|
if (event.assistantResponseEvent?.content) {
|
|
34
55
|
const text = event.assistantResponseEvent.content;
|
|
35
56
|
totalContent += text;
|
|
36
57
|
textOnlyContent += text;
|
|
58
|
+
if (reasoningStarted && !reasoningClosed) {
|
|
59
|
+
for (const ev of stopBlock(streamState.thinkingBlockIndex, streamState)) {
|
|
60
|
+
const _c = convertToOpenAI(ev, conversationId, model);
|
|
61
|
+
if (_c !== null)
|
|
62
|
+
yield _c;
|
|
63
|
+
}
|
|
64
|
+
reasoningClosed = true;
|
|
65
|
+
}
|
|
66
|
+
if (reasoningStarted) {
|
|
67
|
+
for (const ev of createTextDeltaEvents(text, streamState)) {
|
|
68
|
+
const _c = convertToOpenAI(ev, conversationId, model);
|
|
69
|
+
if (_c !== null)
|
|
70
|
+
yield _c;
|
|
71
|
+
}
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
37
74
|
if (!thinkingRequested) {
|
|
38
75
|
for (const ev of createTextDeltaEvents(text, streamState)) {
|
|
39
76
|
{
|
|
@@ -151,6 +188,15 @@ export async function* transformSdkStream(sdkResponse, model, conversationId) {
|
|
|
151
188
|
toolCalls.push(currentToolCall);
|
|
152
189
|
currentToolCall = null;
|
|
153
190
|
}
|
|
191
|
+
// Reasoning-only responses (reasoning but no reply text): close the thinking block.
|
|
192
|
+
if (reasoningStarted && !reasoningClosed) {
|
|
193
|
+
for (const ev of stopBlock(streamState.thinkingBlockIndex, streamState)) {
|
|
194
|
+
const _c = convertToOpenAI(ev, conversationId, model);
|
|
195
|
+
if (_c !== null)
|
|
196
|
+
yield _c;
|
|
197
|
+
}
|
|
198
|
+
reasoningClosed = true;
|
|
199
|
+
}
|
|
154
200
|
if (thinkingRequested && streamState.buffer) {
|
|
155
201
|
if (streamState.inThinking) {
|
|
156
202
|
for (const ev of createThinkingDeltaEvents(streamState.buffer, streamState)) {
|
package/dist/plugin.js
CHANGED
|
@@ -61,11 +61,56 @@ export const createKiroPlugin = (id) => async ({ client, directory }) => {
|
|
|
61
61
|
limit: { context: 1000000, output: 64000 },
|
|
62
62
|
modalities: { input: ['text', 'image', 'pdf'], output: ['text'] }
|
|
63
63
|
},
|
|
64
|
+
'claude-sonnet-4-6-low': {
|
|
65
|
+
name: 'Claude Sonnet 4.6 (low) (1.3x)',
|
|
66
|
+
limit: { context: 1000000, output: 64000 },
|
|
67
|
+
modalities: { input: ['text', 'image', 'pdf'], output: ['text'] }
|
|
68
|
+
},
|
|
69
|
+
'claude-sonnet-4-6-medium': {
|
|
70
|
+
name: 'Claude Sonnet 4.6 (medium) (1.3x)',
|
|
71
|
+
limit: { context: 1000000, output: 64000 },
|
|
72
|
+
modalities: { input: ['text', 'image', 'pdf'], output: ['text'] }
|
|
73
|
+
},
|
|
74
|
+
'claude-sonnet-4-6-high': {
|
|
75
|
+
name: 'Claude Sonnet 4.6 (high) (1.3x)',
|
|
76
|
+
limit: { context: 1000000, output: 64000 },
|
|
77
|
+
modalities: { input: ['text', 'image', 'pdf'], output: ['text'] }
|
|
78
|
+
},
|
|
79
|
+
'claude-sonnet-4-6-max': {
|
|
80
|
+
name: 'Claude Sonnet 4.6 (max) (1.3x)',
|
|
81
|
+
limit: { context: 1000000, output: 64000 },
|
|
82
|
+
modalities: { input: ['text', 'image', 'pdf'], output: ['text'] }
|
|
83
|
+
},
|
|
64
84
|
'claude-sonnet-5': {
|
|
65
85
|
name: 'Claude Sonnet 5 (1.3x)',
|
|
66
86
|
limit: { context: 1000000, output: 64000 },
|
|
67
87
|
modalities: { input: ['text', 'image', 'pdf'], output: ['text'] }
|
|
68
88
|
},
|
|
89
|
+
'claude-sonnet-5-low': {
|
|
90
|
+
name: 'Claude Sonnet 5 (low) (1.3x)',
|
|
91
|
+
limit: { context: 1000000, output: 64000 },
|
|
92
|
+
modalities: { input: ['text', 'image', 'pdf'], output: ['text'] }
|
|
93
|
+
},
|
|
94
|
+
'claude-sonnet-5-medium': {
|
|
95
|
+
name: 'Claude Sonnet 5 (medium) (1.3x)',
|
|
96
|
+
limit: { context: 1000000, output: 64000 },
|
|
97
|
+
modalities: { input: ['text', 'image', 'pdf'], output: ['text'] }
|
|
98
|
+
},
|
|
99
|
+
'claude-sonnet-5-high': {
|
|
100
|
+
name: 'Claude Sonnet 5 (high) (1.3x)',
|
|
101
|
+
limit: { context: 1000000, output: 64000 },
|
|
102
|
+
modalities: { input: ['text', 'image', 'pdf'], output: ['text'] }
|
|
103
|
+
},
|
|
104
|
+
'claude-sonnet-5-xhigh': {
|
|
105
|
+
name: 'Claude Sonnet 5 (xhigh) (1.3x)',
|
|
106
|
+
limit: { context: 1000000, output: 64000 },
|
|
107
|
+
modalities: { input: ['text', 'image', 'pdf'], output: ['text'] }
|
|
108
|
+
},
|
|
109
|
+
'claude-sonnet-5-max': {
|
|
110
|
+
name: 'Claude Sonnet 5 (max) (1.3x)',
|
|
111
|
+
limit: { context: 1000000, output: 64000 },
|
|
112
|
+
modalities: { input: ['text', 'image', 'pdf'], output: ['text'] }
|
|
113
|
+
},
|
|
69
114
|
// Claude Haiku
|
|
70
115
|
'claude-haiku-4-5': {
|
|
71
116
|
name: 'Claude Haiku 4.5 (0.4x)',
|
|
@@ -88,11 +133,61 @@ export const createKiroPlugin = (id) => async ({ client, directory }) => {
|
|
|
88
133
|
limit: { context: 1000000, output: 64000 },
|
|
89
134
|
modalities: { input: ['text', 'image', 'pdf'], output: ['text'] }
|
|
90
135
|
},
|
|
136
|
+
'claude-opus-4-7-low': {
|
|
137
|
+
name: 'Claude Opus 4.7 (low) (2.2x)',
|
|
138
|
+
limit: { context: 1000000, output: 64000 },
|
|
139
|
+
modalities: { input: ['text', 'image', 'pdf'], output: ['text'] }
|
|
140
|
+
},
|
|
141
|
+
'claude-opus-4-7-medium': {
|
|
142
|
+
name: 'Claude Opus 4.7 (medium) (2.2x)',
|
|
143
|
+
limit: { context: 1000000, output: 64000 },
|
|
144
|
+
modalities: { input: ['text', 'image', 'pdf'], output: ['text'] }
|
|
145
|
+
},
|
|
146
|
+
'claude-opus-4-7-high': {
|
|
147
|
+
name: 'Claude Opus 4.7 (high) (2.2x)',
|
|
148
|
+
limit: { context: 1000000, output: 64000 },
|
|
149
|
+
modalities: { input: ['text', 'image', 'pdf'], output: ['text'] }
|
|
150
|
+
},
|
|
151
|
+
'claude-opus-4-7-xhigh': {
|
|
152
|
+
name: 'Claude Opus 4.7 (xhigh) (2.2x)',
|
|
153
|
+
limit: { context: 1000000, output: 64000 },
|
|
154
|
+
modalities: { input: ['text', 'image', 'pdf'], output: ['text'] }
|
|
155
|
+
},
|
|
156
|
+
'claude-opus-4-7-max': {
|
|
157
|
+
name: 'Claude Opus 4.7 (max) (2.2x)',
|
|
158
|
+
limit: { context: 1000000, output: 64000 },
|
|
159
|
+
modalities: { input: ['text', 'image', 'pdf'], output: ['text'] }
|
|
160
|
+
},
|
|
91
161
|
'claude-opus-4-8': {
|
|
92
162
|
name: 'Claude Opus 4.8 (2.2x)',
|
|
93
163
|
limit: { context: 1000000, output: 64000 },
|
|
94
164
|
modalities: { input: ['text', 'image', 'pdf'], output: ['text'] }
|
|
95
165
|
},
|
|
166
|
+
'claude-opus-4-8-low': {
|
|
167
|
+
name: 'Claude Opus 4.8 (low) (2.2x)',
|
|
168
|
+
limit: { context: 1000000, output: 64000 },
|
|
169
|
+
modalities: { input: ['text', 'image', 'pdf'], output: ['text'] }
|
|
170
|
+
},
|
|
171
|
+
'claude-opus-4-8-medium': {
|
|
172
|
+
name: 'Claude Opus 4.8 (medium) (2.2x)',
|
|
173
|
+
limit: { context: 1000000, output: 64000 },
|
|
174
|
+
modalities: { input: ['text', 'image', 'pdf'], output: ['text'] }
|
|
175
|
+
},
|
|
176
|
+
'claude-opus-4-8-high': {
|
|
177
|
+
name: 'Claude Opus 4.8 (high) (2.2x)',
|
|
178
|
+
limit: { context: 1000000, output: 64000 },
|
|
179
|
+
modalities: { input: ['text', 'image', 'pdf'], output: ['text'] }
|
|
180
|
+
},
|
|
181
|
+
'claude-opus-4-8-xhigh': {
|
|
182
|
+
name: 'Claude Opus 4.8 (xhigh) (2.2x)',
|
|
183
|
+
limit: { context: 1000000, output: 64000 },
|
|
184
|
+
modalities: { input: ['text', 'image', 'pdf'], output: ['text'] }
|
|
185
|
+
},
|
|
186
|
+
'claude-opus-4-8-max': {
|
|
187
|
+
name: 'Claude Opus 4.8 (max) (2.2x)',
|
|
188
|
+
limit: { context: 1000000, output: 64000 },
|
|
189
|
+
modalities: { input: ['text', 'image', 'pdf'], output: ['text'] }
|
|
190
|
+
},
|
|
96
191
|
'claude-opus-4-8-thinking': {
|
|
97
192
|
name: 'Claude Opus 4.8 Thinking (2.2x)',
|
|
98
193
|
limit: { context: 1000000, output: 64000 },
|