@bogyie/opencode-kiro-plugin 0.1.0 → 0.2.2
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 +1 -0
- package/README.md +24 -32
- package/dist/config.d.ts +1 -0
- package/dist/config.js +3 -1
- package/dist/fetch-adapter.js +2 -0
- package/dist/index.d.ts +1 -1
- package/dist/kiro-transport.js +18 -0
- package/dist/model-discovery.js +20 -3
- package/dist/models.js +35 -5
- package/dist/plugin.js +8 -0
- package/dist/response-adapter.d.ts +7 -1
- package/dist/response-adapter.js +6 -0
- package/docs/e2e-validation.md +2 -2
- package/examples/opencode.jsonc +5 -14
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -15,6 +15,7 @@ Initial OpenCode Kiro provider plugin implementation.
|
|
|
15
15
|
- OpenAI-compatible request adapter for system prompts, chat history, multimodal data URL images/documents, tool specs, and tool results.
|
|
16
16
|
- OpenAI-compatible generation options for temperature, token limit, and reasoning/thinking effort are preserved as best-effort model request fields in direct fetch mode.
|
|
17
17
|
- CodeWhisperer metadata token usage is mapped to OpenAI-compatible non-streaming usage fields on a best-effort basis.
|
|
18
|
+
- CodeWhisperer reasoning content is preserved separately from assistant text as OpenAI-compatible `reasoning_content`.
|
|
18
19
|
- CodeWhisperer/Kiro transport with streaming text, tool-call deltas, configurable retry attempts, and request timeout.
|
|
19
20
|
- CLI fallback using `kiro-cli chat --no-interactive`.
|
|
20
21
|
- CLI fallback responses are wrapped as OpenAI-compatible SSE for streaming OpenCode calls and sanitized to remove terminal prompt/credits output.
|
package/README.md
CHANGED
|
@@ -10,16 +10,7 @@ After the package is published to npm, add it directly to your OpenCode config:
|
|
|
10
10
|
|
|
11
11
|
```jsonc
|
|
12
12
|
{
|
|
13
|
-
"plugin": ["@bogyie/opencode-kiro-plugin"]
|
|
14
|
-
"provider": {
|
|
15
|
-
"kiro": {
|
|
16
|
-
"models": {
|
|
17
|
-
"sonnet": {
|
|
18
|
-
"name": "Sonnet alias"
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
}
|
|
13
|
+
"plugin": ["@bogyie/opencode-kiro-plugin"]
|
|
23
14
|
}
|
|
24
15
|
```
|
|
25
16
|
|
|
@@ -34,16 +25,7 @@ Then add the plugin to your OpenCode config. See [examples/opencode.jsonc](examp
|
|
|
34
25
|
|
|
35
26
|
```jsonc
|
|
36
27
|
{
|
|
37
|
-
"plugin": ["file:/absolute/path/to/opencode-kiro-plugin"]
|
|
38
|
-
"provider": {
|
|
39
|
-
"kiro": {
|
|
40
|
-
"models": {
|
|
41
|
-
"sonnet": {
|
|
42
|
-
"name": "Sonnet alias"
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
}
|
|
28
|
+
"plugin": ["file:/absolute/path/to/opencode-kiro-plugin"]
|
|
47
29
|
}
|
|
48
30
|
```
|
|
49
31
|
|
|
@@ -92,7 +74,7 @@ Supported values:
|
|
|
92
74
|
|
|
93
75
|
## Model Churn Handling
|
|
94
76
|
|
|
95
|
-
The resolver intentionally avoids a hard whitelist.
|
|
77
|
+
The resolver intentionally avoids a hard whitelist. By default, the plugin reads the current Kiro CLI model list with `kiro-cli chat --list-models --format json`. Bundled presets are only used as UI metadata and as a fallback when discovery is unavailable.
|
|
96
78
|
|
|
97
79
|
Useful options:
|
|
98
80
|
|
|
@@ -104,13 +86,13 @@ Useful options:
|
|
|
104
86
|
{
|
|
105
87
|
"modelCacheTtlSeconds": 21600,
|
|
106
88
|
"modelDiscovery": "auto",
|
|
107
|
-
"modelDiscoveryCommand": ["kiro-cli", "models", "--json"],
|
|
89
|
+
"modelDiscoveryCommand": ["kiro-cli", "chat", "--list-models", "--format", "json"],
|
|
108
90
|
"modelAliases": {
|
|
109
|
-
"sonnet": "claude-sonnet-
|
|
110
|
-
"opus": "claude-opus-4.
|
|
91
|
+
"sonnet": "claude-sonnet-5",
|
|
92
|
+
"opus": "claude-opus-4.8"
|
|
111
93
|
},
|
|
112
94
|
"extraModels": {
|
|
113
|
-
"claude-opus-4
|
|
95
|
+
"claude-opus-4.9": {
|
|
114
96
|
"name": "Claude Opus 4.9",
|
|
115
97
|
"limit": { "context": 1000000, "output": 64000 },
|
|
116
98
|
"modalities": { "input": ["text", "image", "pdf"], "output": ["text"] },
|
|
@@ -138,9 +120,11 @@ Resolution order:
|
|
|
138
120
|
6. Hidden/manual model mapping
|
|
139
121
|
7. Optimistic pass-through unless disabled
|
|
140
122
|
|
|
141
|
-
This keeps new Kiro model ids
|
|
123
|
+
This keeps new Kiro model ids visible before the package is updated. Use `extraModels` only when a new model should appear in OpenCode's model picker but is not yet listed by your installed Kiro CLI. Set `disableModelPassThrough: true` only when you need strict model governance.
|
|
124
|
+
|
|
125
|
+
The plugin injects `provider.kiro` automatically. You only need to add `provider.kiro.models` yourself when overriding OpenCode model-picker metadata, such as a display name or context limit. Use plugin `modelAliases` for aliases that should resolve one requested model id to another.
|
|
142
126
|
|
|
143
|
-
`modelDiscoveryCommand`
|
|
127
|
+
`modelDiscoveryCommand` defaults to `["kiro-cli", "chat", "--list-models", "--format", "json"]`. Set `modelDiscovery` to `"off"` to skip runtime discovery. Discovery stdout can be a JSON array, `{ "models": [...] }`, `{ "data": [...] }`, Kiro CLI list-models JSON, Kiro CLI plain list output, or one model id per line.
|
|
144
128
|
|
|
145
129
|
## Troubleshooting
|
|
146
130
|
|
|
@@ -155,6 +139,9 @@ Direct fetch mode uses AWS SDK standard retry behavior. Tune `maxAttempts` and `
|
|
|
155
139
|
|
|
156
140
|
OpenAI-compatible `temperature`, `max_tokens`, `max_completion_tokens`, `reasoning_effort`, `reasoning.effort`, and `thinking.effort` are preserved for direct fetch mode through Kiro's `additionalModelRequestFields` path on a best-effort basis.
|
|
157
141
|
|
|
142
|
+
When Kiro emits token metadata in direct fetch mode, non-streaming responses map it to OpenAI-compatible `usage` fields.
|
|
143
|
+
When Kiro emits reasoning text, it is preserved separately from assistant text as `reasoning_content`.
|
|
144
|
+
|
|
158
145
|
For local checks:
|
|
159
146
|
|
|
160
147
|
```sh
|
|
@@ -167,13 +154,18 @@ For real Kiro/OpenCode validation, use [docs/e2e-validation.md](docs/e2e-validat
|
|
|
167
154
|
|
|
168
155
|
## Release
|
|
169
156
|
|
|
170
|
-
|
|
157
|
+
The npm package is published through npm Trusted Publishing with the GitHub Actions environment named `npm`. No `NPM_TOKEN` repository secret is required.
|
|
158
|
+
|
|
159
|
+
Configure the npm package trusted publisher to use:
|
|
160
|
+
|
|
161
|
+
- repository owner: `bogyie`
|
|
162
|
+
- repository name: `opencode-kiro-plugin`
|
|
163
|
+
- workflow filename: `npm-publish.yml`
|
|
164
|
+
- environment name: `npm`
|
|
171
165
|
|
|
172
|
-
|
|
173
|
-
2. Update `package.json` and `package-lock.json` to the release version.
|
|
174
|
-
3. Create and publish a GitHub Release whose tag matches the package version, for example `v0.1.0`.
|
|
166
|
+
To publish a new version, update `package.json` and `package-lock.json` to the release version and merge the change to `main`. `package.json.version` is the source of truth: when it changes on `main`, the `Publish npm package` workflow publishes that package version to npm and creates the matching GitHub Release tag, for example `v0.1.0`.
|
|
175
167
|
|
|
176
|
-
The
|
|
168
|
+
The workflow runs tests, typecheck, package smoke validation, `npm pack --dry-run`, and then `npm publish --access public`.
|
|
177
169
|
|
|
178
170
|
## License And References
|
|
179
171
|
|
package/dist/config.d.ts
CHANGED
|
@@ -22,6 +22,7 @@ export interface KiroPluginOptions {
|
|
|
22
22
|
}
|
|
23
23
|
export declare const DEFAULT_PROVIDER_ID = "kiro";
|
|
24
24
|
export declare const DEFAULT_REGION = "us-east-1";
|
|
25
|
+
export declare const DEFAULT_MODEL_DISCOVERY_COMMAND: readonly ["kiro-cli", "chat", "--list-models", "--format", "json"];
|
|
25
26
|
export declare const DEFAULT_MODEL_CACHE_TTL_SECONDS: number;
|
|
26
27
|
export declare const DEFAULT_MAX_ATTEMPTS = 3;
|
|
27
28
|
export declare function loadOptions(raw?: unknown): KiroPluginOptions;
|
package/dist/config.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export const DEFAULT_PROVIDER_ID = "kiro";
|
|
2
2
|
export const DEFAULT_REGION = "us-east-1";
|
|
3
|
+
export const DEFAULT_MODEL_DISCOVERY_COMMAND = ["kiro-cli", "chat", "--list-models", "--format", "json"];
|
|
3
4
|
export const DEFAULT_MODEL_CACHE_TTL_SECONDS = 6 * 60 * 60;
|
|
4
5
|
export const DEFAULT_MAX_ATTEMPTS = 3;
|
|
5
6
|
const BACKENDS = new Set(["auto", "fetch", "cli-chat", "acp"]);
|
|
@@ -53,13 +54,14 @@ export function loadOptions(raw = {}) {
|
|
|
53
54
|
const profileArn = optionalString(input.profileArn);
|
|
54
55
|
const userAgent = optionalString(input.userAgent);
|
|
55
56
|
const agentMode = optionalString(input.agentMode);
|
|
57
|
+
const modelDiscoveryCommand = "modelDiscoveryCommand" in input ? stringArray(input.modelDiscoveryCommand) : [...DEFAULT_MODEL_DISCOVERY_COMMAND];
|
|
56
58
|
return {
|
|
57
59
|
providerID: typeof input.providerID === "string" && input.providerID ? input.providerID : DEFAULT_PROVIDER_ID,
|
|
58
60
|
region: typeof input.region === "string" && input.region ? input.region : DEFAULT_REGION,
|
|
59
61
|
...(endpoint ? { endpoint } : {}),
|
|
60
62
|
backend,
|
|
61
63
|
modelDiscovery,
|
|
62
|
-
modelDiscoveryCommand
|
|
64
|
+
modelDiscoveryCommand,
|
|
63
65
|
modelCacheTtlSeconds: positiveNumber(input.modelCacheTtlSeconds, DEFAULT_MODEL_CACHE_TTL_SECONDS),
|
|
64
66
|
...(requestTimeoutMs ? { requestTimeoutMs } : {}),
|
|
65
67
|
maxAttempts: positiveInteger(input.maxAttempts, DEFAULT_MAX_ATTEMPTS),
|
package/dist/fetch-adapter.js
CHANGED
|
@@ -8,6 +8,8 @@ const unsupportedTransport = {
|
|
|
8
8
|
};
|
|
9
9
|
async function* streamGeneratedResponse(transport, request) {
|
|
10
10
|
const response = await transport.generate(request);
|
|
11
|
+
if (response.reasoning)
|
|
12
|
+
yield { type: "reasoning", text: response.reasoning, modelId: response.modelId ?? request.modelId };
|
|
11
13
|
if (response.text)
|
|
12
14
|
yield { type: "text", text: response.text, modelId: response.modelId ?? request.modelId };
|
|
13
15
|
for (const toolCall of response.toolCalls ?? [])
|
package/dist/index.d.ts
CHANGED
|
@@ -16,7 +16,7 @@ export { FALLBACK_MODELS } from "./models.js";
|
|
|
16
16
|
export { toKiroGenerateRequest } from "./request-adapter.js";
|
|
17
17
|
export type { KiroGenerateRequest, KiroModelOptions } from "./request-adapter.js";
|
|
18
18
|
export { toOpenAIChatResponse, toOpenAIChatStreamResponse } from "./response-adapter.js";
|
|
19
|
-
export type { KiroStreamEvent, KiroToolCallChunk } from "./response-adapter.js";
|
|
19
|
+
export type { KiroReasoningChunk, KiroStreamEvent, KiroToolCallChunk } from "./response-adapter.js";
|
|
20
20
|
declare const _default: {
|
|
21
21
|
id: string;
|
|
22
22
|
server: import("@opencode-ai/plugin").Plugin;
|
package/dist/kiro-transport.js
CHANGED
|
@@ -135,6 +135,7 @@ export async function collectAssistantText(stream) {
|
|
|
135
135
|
if (!stream)
|
|
136
136
|
return { text: "" };
|
|
137
137
|
let text = "";
|
|
138
|
+
let reasoning = "";
|
|
138
139
|
let modelId;
|
|
139
140
|
let usage;
|
|
140
141
|
for await (const event of stream) {
|
|
@@ -142,6 +143,9 @@ export async function collectAssistantText(stream) {
|
|
|
142
143
|
text += event.assistantResponseEvent.content ?? "";
|
|
143
144
|
modelId = event.assistantResponseEvent.modelId ?? modelId;
|
|
144
145
|
}
|
|
146
|
+
if (event.reasoningContentEvent?.text) {
|
|
147
|
+
reasoning += event.reasoningContentEvent.text;
|
|
148
|
+
}
|
|
145
149
|
usage = usageFromMetadataEvent(event) ?? usage;
|
|
146
150
|
if (event.error) {
|
|
147
151
|
throw new Error(event.error.message ?? "Kiro stream returned an error event");
|
|
@@ -149,6 +153,7 @@ export async function collectAssistantText(stream) {
|
|
|
149
153
|
}
|
|
150
154
|
return {
|
|
151
155
|
text,
|
|
156
|
+
...(reasoning ? { reasoning } : {}),
|
|
152
157
|
...(modelId ? { modelId } : {}),
|
|
153
158
|
...(usage ? { usage } : {}),
|
|
154
159
|
};
|
|
@@ -165,6 +170,12 @@ export async function* streamAssistantText(stream) {
|
|
|
165
170
|
...(event.assistantResponseEvent.modelId ? { modelId: event.assistantResponseEvent.modelId } : {}),
|
|
166
171
|
};
|
|
167
172
|
}
|
|
173
|
+
if (event.reasoningContentEvent?.text) {
|
|
174
|
+
yield {
|
|
175
|
+
type: "reasoning",
|
|
176
|
+
text: event.reasoningContentEvent.text,
|
|
177
|
+
};
|
|
178
|
+
}
|
|
168
179
|
if (event.toolUseEvent?.toolUseId && event.toolUseEvent.name) {
|
|
169
180
|
const id = event.toolUseEvent.toolUseId;
|
|
170
181
|
const current = toolInputs.get(id) ?? { name: event.toolUseEvent.name, input: "" };
|
|
@@ -196,6 +207,7 @@ export async function* streamAssistantText(stream) {
|
|
|
196
207
|
}
|
|
197
208
|
async function collectChunks(chunks, fallbackModelId) {
|
|
198
209
|
let text = "";
|
|
210
|
+
let reasoning = "";
|
|
199
211
|
let modelId;
|
|
200
212
|
let usage;
|
|
201
213
|
const toolCalls = [];
|
|
@@ -205,6 +217,11 @@ async function collectChunks(chunks, fallbackModelId) {
|
|
|
205
217
|
modelId = chunk.modelId ?? modelId;
|
|
206
218
|
continue;
|
|
207
219
|
}
|
|
220
|
+
if (chunk.type === "reasoning") {
|
|
221
|
+
reasoning += chunk.text;
|
|
222
|
+
modelId = chunk.modelId ?? modelId;
|
|
223
|
+
continue;
|
|
224
|
+
}
|
|
208
225
|
text += chunk.text;
|
|
209
226
|
modelId = chunk.modelId ?? modelId;
|
|
210
227
|
if (chunk.usage)
|
|
@@ -212,6 +229,7 @@ async function collectChunks(chunks, fallbackModelId) {
|
|
|
212
229
|
}
|
|
213
230
|
return {
|
|
214
231
|
text,
|
|
232
|
+
...(reasoning ? { reasoning } : {}),
|
|
215
233
|
modelId: modelId ?? fallbackModelId,
|
|
216
234
|
...(toolCalls.length > 0 ? { toolCalls } : {}),
|
|
217
235
|
...(usage ? { usage } : {}),
|
package/dist/model-discovery.js
CHANGED
|
@@ -6,6 +6,9 @@ function record(value) {
|
|
|
6
6
|
function stringValue(value) {
|
|
7
7
|
return typeof value === "string" && value.trim() ? value.trim() : undefined;
|
|
8
8
|
}
|
|
9
|
+
function positiveNumberValue(value) {
|
|
10
|
+
return typeof value === "number" && Number.isFinite(value) && value > 0 ? value : undefined;
|
|
11
|
+
}
|
|
9
12
|
function fromItem(item) {
|
|
10
13
|
if (typeof item === "string") {
|
|
11
14
|
const id = normalizeModelName(item);
|
|
@@ -14,16 +17,25 @@ function fromItem(item) {
|
|
|
14
17
|
const object = record(item);
|
|
15
18
|
if (!object)
|
|
16
19
|
return undefined;
|
|
17
|
-
const id = stringValue(object.id) ??
|
|
20
|
+
const id = stringValue(object.id) ??
|
|
21
|
+
stringValue(object.modelId) ??
|
|
22
|
+
stringValue(object.model_id) ??
|
|
23
|
+
stringValue(object.model) ??
|
|
24
|
+
stringValue(object.model_name) ??
|
|
25
|
+
stringValue(object.name);
|
|
18
26
|
if (!id)
|
|
19
27
|
return undefined;
|
|
20
28
|
const normalized = normalizeModelName(id);
|
|
21
29
|
if (!normalized)
|
|
22
30
|
return undefined;
|
|
23
31
|
const name = stringValue(object.name) ?? stringValue(object.displayName) ?? stringValue(object.label);
|
|
32
|
+
const contextLimit = positiveNumberValue(object.contextLimit) ?? positiveNumberValue(object.context_window_tokens);
|
|
33
|
+
const outputLimit = positiveNumberValue(object.outputLimit) ?? positiveNumberValue(object.output_limit_tokens);
|
|
24
34
|
return {
|
|
25
35
|
id: normalized,
|
|
26
36
|
...(name ? { name } : {}),
|
|
37
|
+
...(contextLimit ? { contextLimit } : {}),
|
|
38
|
+
...(outputLimit ? { outputLimit } : {}),
|
|
27
39
|
raw: item,
|
|
28
40
|
};
|
|
29
41
|
}
|
|
@@ -34,13 +46,18 @@ function fromJson(value) {
|
|
|
34
46
|
if (!object)
|
|
35
47
|
return [];
|
|
36
48
|
const items = object.models ?? object.data ?? object.items;
|
|
37
|
-
|
|
49
|
+
if (Array.isArray(items))
|
|
50
|
+
return fromJson(items);
|
|
51
|
+
const configuredModel = object["chat.defaultModel"] ?? object.defaultModel ?? object.model;
|
|
52
|
+
return configuredModel ? fromJson([configuredModel]) : [];
|
|
38
53
|
}
|
|
39
54
|
function fromLines(raw) {
|
|
40
55
|
return raw
|
|
41
56
|
.split(/\r?\n/)
|
|
42
57
|
.map((line) => line.trim())
|
|
43
|
-
.
|
|
58
|
+
.map((line) => line.replace(/^\*\s*/, ""))
|
|
59
|
+
.map((line) => /^\S+/.exec(line)?.[0] ?? "")
|
|
60
|
+
.filter((line) => line === "auto" || /[.-]/.test(line))
|
|
44
61
|
.map(fromItem)
|
|
45
62
|
.filter((item) => item !== undefined);
|
|
46
63
|
}
|
package/dist/models.js
CHANGED
|
@@ -7,31 +7,61 @@ export const FALLBACK_MODELS = {
|
|
|
7
7
|
modalities: TEXT_IMAGE_PDF,
|
|
8
8
|
tool_call: true,
|
|
9
9
|
},
|
|
10
|
+
"claude-fable-5": {
|
|
11
|
+
name: "Claude Fable 5",
|
|
12
|
+
limit: { context: 1_000_000, output: 64_000 },
|
|
13
|
+
modalities: TEXT_IMAGE_PDF,
|
|
14
|
+
tool_call: true,
|
|
15
|
+
},
|
|
16
|
+
"claude-sonnet-5": {
|
|
17
|
+
name: "Claude Sonnet 5",
|
|
18
|
+
limit: { context: 1_000_000, output: 64_000 },
|
|
19
|
+
modalities: TEXT_IMAGE_PDF,
|
|
20
|
+
tool_call: true,
|
|
21
|
+
},
|
|
10
22
|
"claude-sonnet-4": {
|
|
11
|
-
name: "Claude Sonnet 4",
|
|
23
|
+
name: "Claude Sonnet 4.0",
|
|
12
24
|
limit: { context: 200_000, output: 64_000 },
|
|
13
25
|
modalities: TEXT_IMAGE_PDF,
|
|
14
26
|
tool_call: true,
|
|
15
27
|
},
|
|
16
|
-
"claude-sonnet-4
|
|
28
|
+
"claude-sonnet-4.5": {
|
|
17
29
|
name: "Claude Sonnet 4.5",
|
|
18
30
|
limit: { context: 200_000, output: 64_000 },
|
|
19
31
|
modalities: TEXT_IMAGE_PDF,
|
|
20
32
|
tool_call: true,
|
|
21
33
|
},
|
|
22
|
-
"claude-sonnet-4
|
|
34
|
+
"claude-sonnet-4.6": {
|
|
23
35
|
name: "Claude Sonnet 4.6",
|
|
24
36
|
limit: { context: 1_000_000, output: 64_000 },
|
|
25
37
|
modalities: TEXT_IMAGE_PDF,
|
|
26
38
|
tool_call: true,
|
|
27
39
|
},
|
|
28
|
-
"claude-opus-4
|
|
40
|
+
"claude-opus-4.8": {
|
|
29
41
|
name: "Claude Opus 4.8",
|
|
42
|
+
limit: { context: 1_000_000, output: 128_000 },
|
|
43
|
+
modalities: TEXT_IMAGE_PDF,
|
|
44
|
+
tool_call: true,
|
|
45
|
+
},
|
|
46
|
+
"claude-opus-4.7": {
|
|
47
|
+
name: "Claude Opus 4.7",
|
|
48
|
+
limit: { context: 1_000_000, output: 64_000 },
|
|
49
|
+
modalities: TEXT_IMAGE_PDF,
|
|
50
|
+
tool_call: true,
|
|
51
|
+
},
|
|
52
|
+
"claude-opus-4.6": {
|
|
53
|
+
name: "Claude Opus 4.6",
|
|
30
54
|
limit: { context: 1_000_000, output: 64_000 },
|
|
31
55
|
modalities: TEXT_IMAGE_PDF,
|
|
32
56
|
tool_call: true,
|
|
33
57
|
},
|
|
34
|
-
"claude-
|
|
58
|
+
"claude-opus-4.5": {
|
|
59
|
+
name: "Claude Opus 4.5",
|
|
60
|
+
limit: { context: 200_000, output: 64_000 },
|
|
61
|
+
modalities: TEXT_IMAGE_PDF,
|
|
62
|
+
tool_call: true,
|
|
63
|
+
},
|
|
64
|
+
"claude-haiku-4.5": {
|
|
35
65
|
name: "Claude Haiku 4.5",
|
|
36
66
|
limit: { context: 200_000, output: 64_000 },
|
|
37
67
|
modalities: { input: ["text", "image"], output: ["text"] },
|
package/dist/plugin.js
CHANGED
|
@@ -21,6 +21,14 @@ function discoveredProviderModels(cache) {
|
|
|
21
21
|
model.id,
|
|
22
22
|
{
|
|
23
23
|
name: model.name ?? model.id,
|
|
24
|
+
...(model.contextLimit || model.outputLimit
|
|
25
|
+
? {
|
|
26
|
+
limit: {
|
|
27
|
+
context: model.contextLimit ?? 200_000,
|
|
28
|
+
output: model.outputLimit ?? 64_000,
|
|
29
|
+
},
|
|
30
|
+
}
|
|
31
|
+
: {}),
|
|
24
32
|
},
|
|
25
33
|
]));
|
|
26
34
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export interface KiroGenerateResponse {
|
|
2
2
|
readonly text: string;
|
|
3
|
+
readonly reasoning?: string;
|
|
3
4
|
readonly modelId?: string;
|
|
4
5
|
readonly toolCalls?: ReadonlyArray<KiroToolCallChunk>;
|
|
5
6
|
readonly usage?: {
|
|
@@ -20,6 +21,11 @@ export interface KiroToolCallChunk {
|
|
|
20
21
|
readonly arguments: string;
|
|
21
22
|
readonly modelId?: string;
|
|
22
23
|
}
|
|
23
|
-
export
|
|
24
|
+
export interface KiroReasoningChunk {
|
|
25
|
+
readonly type: "reasoning";
|
|
26
|
+
readonly text: string;
|
|
27
|
+
readonly modelId?: string;
|
|
28
|
+
}
|
|
29
|
+
export type KiroStreamEvent = KiroStreamChunk | KiroToolCallChunk | KiroReasoningChunk;
|
|
24
30
|
export declare function toOpenAIChatResponse(response: KiroGenerateResponse, model: string): Response;
|
|
25
31
|
export declare function toOpenAIChatStreamResponse(chunks: AsyncIterable<KiroStreamEvent>, model: string): Response;
|
package/dist/response-adapter.js
CHANGED
|
@@ -11,6 +11,7 @@ export function toOpenAIChatResponse(response, model) {
|
|
|
11
11
|
message: {
|
|
12
12
|
role: "assistant",
|
|
13
13
|
content: toolCalls.length > 0 ? response.text || null : response.text,
|
|
14
|
+
...(response.reasoning ? { reasoning_content: response.reasoning } : {}),
|
|
14
15
|
...(toolCalls.length > 0
|
|
15
16
|
? {
|
|
16
17
|
tool_calls: toolCalls.map((toolCall, index) => ({
|
|
@@ -70,6 +71,11 @@ export function toOpenAIChatStreamResponse(chunks, model) {
|
|
|
70
71
|
],
|
|
71
72
|
};
|
|
72
73
|
}
|
|
74
|
+
else if (chunk.type === "reasoning") {
|
|
75
|
+
if (!chunk.text)
|
|
76
|
+
continue;
|
|
77
|
+
delta = { reasoning_content: chunk.text };
|
|
78
|
+
}
|
|
73
79
|
else {
|
|
74
80
|
if (!chunk.text)
|
|
75
81
|
continue;
|
package/docs/e2e-validation.md
CHANGED
|
@@ -152,7 +152,7 @@ Before publishing, verify that new model ids can be used without a code release:
|
|
|
152
152
|
"modelAliases": {
|
|
153
153
|
"new-model": "new-model-id"
|
|
154
154
|
},
|
|
155
|
-
"modelDiscoveryCommand": ["kiro-cli", "models", "--json"]
|
|
155
|
+
"modelDiscoveryCommand": ["kiro-cli", "chat", "--list-models", "--format", "json"]
|
|
156
156
|
}
|
|
157
157
|
]
|
|
158
158
|
]
|
|
@@ -161,7 +161,7 @@ Before publishing, verify that new model ids can be used without a code release:
|
|
|
161
161
|
|
|
162
162
|
Checks:
|
|
163
163
|
|
|
164
|
-
-
|
|
164
|
+
- Confirm `kiro-cli chat --list-models --format json` succeeds and discovered models appear in provider metadata.
|
|
165
165
|
- The model appears in OpenCode provider metadata.
|
|
166
166
|
- The alias resolves to the configured id.
|
|
167
167
|
- Unknown models still pass through when `disableModelPassThrough` is false.
|
package/examples/opencode.jsonc
CHANGED
|
@@ -13,15 +13,15 @@
|
|
|
13
13
|
// "agentMode": "vibe",
|
|
14
14
|
"modelCacheTtlSeconds": 21600,
|
|
15
15
|
"modelDiscovery": "auto",
|
|
16
|
-
"modelDiscoveryCommand": [],
|
|
16
|
+
"modelDiscoveryCommand": ["kiro-cli", "chat", "--list-models", "--format", "json"],
|
|
17
17
|
"maxAttempts": 3,
|
|
18
18
|
"requestTimeoutMs": 120000,
|
|
19
19
|
"modelAliases": {
|
|
20
|
-
"sonnet": "claude-sonnet-
|
|
21
|
-
"opus": "claude-opus-4.
|
|
20
|
+
"sonnet": "claude-sonnet-5",
|
|
21
|
+
"opus": "claude-opus-4.8"
|
|
22
22
|
},
|
|
23
23
|
"extraModels": {
|
|
24
|
-
"claude-opus-4
|
|
24
|
+
"claude-opus-4.9": {
|
|
25
25
|
"name": "Claude Opus 4.9",
|
|
26
26
|
"limit": { "context": 1000000, "output": 64000 },
|
|
27
27
|
"modalities": { "input": ["text", "image", "pdf"], "output": ["text"] },
|
|
@@ -34,14 +34,5 @@
|
|
|
34
34
|
"trustAllTools": false
|
|
35
35
|
}
|
|
36
36
|
]
|
|
37
|
-
]
|
|
38
|
-
"provider": {
|
|
39
|
-
"kiro": {
|
|
40
|
-
"models": {
|
|
41
|
-
"sonnet": {
|
|
42
|
-
"name": "Claude Sonnet via Kiro"
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
}
|
|
37
|
+
]
|
|
47
38
|
}
|