ns-dsh-llm-kiro 0.1.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/LICENSE +22 -0
- package/README.md +70 -0
- package/dist/adapter.d.ts +26 -0
- package/dist/adapter.js +185 -0
- package/dist/adapter.js.map +1 -0
- package/dist/errors.d.ts +10 -0
- package/dist/errors.js +39 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +48 -0
- package/dist/index.js +79 -0
- package/dist/index.js.map +1 -0
- package/dist/messages.d.ts +26 -0
- package/dist/messages.js +85 -0
- package/dist/messages.js.map +1 -0
- package/package.json +65 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 ngosangns
|
|
4
|
+
Copyright (c) 2025-2026 Mike O'Brien (pi-provider-kiro)
|
|
5
|
+
|
|
6
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
7
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
8
|
+
in the Software without restriction, including without limitation the rights
|
|
9
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
10
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
11
|
+
furnished to do so, subject to the following conditions:
|
|
12
|
+
|
|
13
|
+
The above copyright notice and this permission notice shall be included in all
|
|
14
|
+
copies or substantial portions of the Software.
|
|
15
|
+
|
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
17
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
18
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
19
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
20
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
21
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
22
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# ns-dsh-llm-kiro
|
|
2
|
+
|
|
3
|
+
Kiro (AWS CodeWhisperer/Q) as a provider route in the
|
|
4
|
+
[DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness).
|
|
5
|
+
|
|
6
|
+
Kiro speaks its own streaming protocol — AWS event-stream framing over
|
|
7
|
+
`generateAssistantResponse` — which no configurable route can describe, so this
|
|
8
|
+
registers a real `LlmAdapter` rather than a profile on a generic one.
|
|
9
|
+
|
|
10
|
+
## Install
|
|
11
|
+
|
|
12
|
+
Not on npm yet — install from a clone of
|
|
13
|
+
[ns-kiro-provider](https://github.com/ngosangns/ns-kiro-provider):
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
kiro-cli login
|
|
17
|
+
pnpm install && pnpm -r build
|
|
18
|
+
dsh plugin --profile <profile> add link:$PWD/packages/dsh-llm-kiro
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
`link:` rather than a tarball because `ns-dsh-llm-kiro` depends on the unpublished
|
|
22
|
+
`ns-kiro-core`; the link resolves it out of the workspace.
|
|
23
|
+
|
|
24
|
+
Add the row to that profile's `cordis.patch.yml`:
|
|
25
|
+
|
|
26
|
+
```yaml
|
|
27
|
+
- insert:
|
|
28
|
+
- id: llm-kiro
|
|
29
|
+
name: 'ns-dsh-llm-kiro'
|
|
30
|
+
config:
|
|
31
|
+
provider: kiro
|
|
32
|
+
|
|
33
|
+
- id: agent-default-model
|
|
34
|
+
config:
|
|
35
|
+
provider: kiro
|
|
36
|
+
model: claude-sonnet-4-6
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Verify the composition, then run:
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
dsh --profile <profile> --dump-config | grep -A3 llm-kiro
|
|
43
|
+
dsh --profile <profile> "what changed in this repo?"
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Configuration
|
|
47
|
+
|
|
48
|
+
| Key | Default | Meaning |
|
|
49
|
+
| --- | --- | --- |
|
|
50
|
+
| `provider` | `kiro` | Provider route the adapter registers under |
|
|
51
|
+
| `displayName` | `Kiro` | Name shown in model selectors |
|
|
52
|
+
| `region` | derived | Kiro API region; derived from the credential when absent |
|
|
53
|
+
|
|
54
|
+
## Notes
|
|
55
|
+
|
|
56
|
+
- Sessions come from the machine. The adapter reads the kiro-cli store or the
|
|
57
|
+
Kiro IDE token file, refreshes on expiry, and writes the refresh back. It runs
|
|
58
|
+
no browser flow of its own.
|
|
59
|
+
- Images are sent when the deployment mounts the `attachments` service, and
|
|
60
|
+
dropped otherwise — the plugin does not require that service, so a text-only
|
|
61
|
+
profile still boots.
|
|
62
|
+
- Kiro's failure vocabulary is mapped onto the Harness routing codes
|
|
63
|
+
(`AUTH`, `RATE_LIMIT`, `OVERLOADED`, `QUOTA_EXCEEDED`, `CONTEXT_OVERFLOW`,
|
|
64
|
+
`TIMEOUT`), so the loop's retry policy sees a classified failure rather than
|
|
65
|
+
provider prose.
|
|
66
|
+
- A degenerate response is retried inside the adapter only while nothing has
|
|
67
|
+
been delivered: the Harness assembler cannot un-deliver a block, so a response
|
|
68
|
+
already streamed out is settled rather than replayed.
|
|
69
|
+
|
|
70
|
+
Part of [ns-kiro-provider](https://github.com/ngosangns/ns-kiro-provider).
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { AttachmentStore } from "@deepseek-ai/dsh-attachment";
|
|
2
|
+
import { type GenerateOptions, LlmAdapter, type LlmModelInfo, type LlmProviderInfo, type LlmResolvedModelInfo, type StreamChunk } from "@deepseek-ai/dsh-llm";
|
|
3
|
+
import { type KiroCredentials } from "ns-kiro-core";
|
|
4
|
+
/** What the plugin resolves per request and freezes for the duration of one call. */
|
|
5
|
+
export interface KiroAdapterOptions {
|
|
6
|
+
/** The route this adapter is registered under. */
|
|
7
|
+
provider: string;
|
|
8
|
+
/** Human-readable provider name for selectors and diagnostics. */
|
|
9
|
+
displayName: string;
|
|
10
|
+
/** Resolve the current session; called once per request. */
|
|
11
|
+
credentials: () => Promise<KiroCredentials>;
|
|
12
|
+
/** Optional durable attachment service, resolved at request time. */
|
|
13
|
+
attachments?: () => AttachmentStore | undefined;
|
|
14
|
+
/** Region override; absent derives it from the credential. */
|
|
15
|
+
region?: string;
|
|
16
|
+
}
|
|
17
|
+
export declare class KiroAdapter extends LlmAdapter {
|
|
18
|
+
private readonly options;
|
|
19
|
+
constructor(options: KiroAdapterOptions);
|
|
20
|
+
providerInfo(provider: string): LlmProviderInfo;
|
|
21
|
+
listModels(provider: string): Promise<readonly LlmModelInfo[]>;
|
|
22
|
+
resolveModel(provider: string, model: string): Promise<LlmResolvedModelInfo>;
|
|
23
|
+
stream(options: GenerateOptions): AsyncIterable<StreamChunk>;
|
|
24
|
+
private streamInner;
|
|
25
|
+
private catalog;
|
|
26
|
+
}
|
package/dist/adapter.js
ADDED
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
// ABOUTME: The Harness LLM seam over kiro-core.
|
|
2
|
+
import { LlmAdapter, LlmError, } from "@deepseek-ai/dsh-llm";
|
|
3
|
+
import { getCachedModels, resolveApiRegion, streamKiro, } from "ns-kiro-core";
|
|
4
|
+
import { toLlmError } from "./errors.js";
|
|
5
|
+
import { toKiroMessages } from "./messages.js";
|
|
6
|
+
const EFFORT_NAMES = {
|
|
7
|
+
minimal: "Minimal",
|
|
8
|
+
low: "Low",
|
|
9
|
+
medium: "Medium",
|
|
10
|
+
high: "High",
|
|
11
|
+
xhigh: "Extra high",
|
|
12
|
+
max: "Maximum",
|
|
13
|
+
};
|
|
14
|
+
export class KiroAdapter extends LlmAdapter {
|
|
15
|
+
options;
|
|
16
|
+
constructor(options) {
|
|
17
|
+
super();
|
|
18
|
+
this.options = options;
|
|
19
|
+
}
|
|
20
|
+
providerInfo(provider) {
|
|
21
|
+
return { id: provider, name: this.options.displayName };
|
|
22
|
+
}
|
|
23
|
+
async listModels(provider) {
|
|
24
|
+
return this.catalog().map((model) => ({
|
|
25
|
+
provider,
|
|
26
|
+
id: model.id,
|
|
27
|
+
name: model.name,
|
|
28
|
+
inputModalities: model.input.filter((modality) => modality === "text" || modality === "image"),
|
|
29
|
+
}));
|
|
30
|
+
}
|
|
31
|
+
async resolveModel(provider, model) {
|
|
32
|
+
const known = this.catalog().find((candidate) => candidate.id === model);
|
|
33
|
+
if (!known)
|
|
34
|
+
throw new LlmError(`Unknown Kiro model: ${model}`, "UNKNOWN_MODEL");
|
|
35
|
+
return {
|
|
36
|
+
provider,
|
|
37
|
+
id: known.id,
|
|
38
|
+
name: known.name,
|
|
39
|
+
inputModalities: known.input.filter((modality) => modality === "text" || modality === "image"),
|
|
40
|
+
context: { contextWindow: known.contextWindow },
|
|
41
|
+
defaultMaxTokens: known.maxTokens,
|
|
42
|
+
...(known.efforts?.length
|
|
43
|
+
? {
|
|
44
|
+
reasoning: {
|
|
45
|
+
efforts: known.efforts.map((effort) => ({
|
|
46
|
+
id: effort,
|
|
47
|
+
name: EFFORT_NAMES[effort],
|
|
48
|
+
})),
|
|
49
|
+
},
|
|
50
|
+
}
|
|
51
|
+
: {}),
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
async *stream(options) {
|
|
55
|
+
try {
|
|
56
|
+
yield* this.streamInner(options);
|
|
57
|
+
}
|
|
58
|
+
catch (error) {
|
|
59
|
+
// `LlmRuntime.stream()` normalizes a throw into a terminal finish, but only
|
|
60
|
+
// after this generator has surfaced it. Converting here is what gives the
|
|
61
|
+
// loop a routing code instead of Kiro's raw wording.
|
|
62
|
+
throw toLlmError(error);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
async *streamInner(options) {
|
|
66
|
+
const credentials = await this.options.credentials();
|
|
67
|
+
const region = this.options.region ?? resolveApiRegion(credentials.region);
|
|
68
|
+
const model = this.catalog(region).find((candidate) => candidate.id === options.model);
|
|
69
|
+
if (!model)
|
|
70
|
+
throw new LlmError(`Unknown Kiro model: ${options.model}`, "UNKNOWN_MODEL");
|
|
71
|
+
const projected = await toKiroMessages(options.messages, {
|
|
72
|
+
attachments: this.options.attachments?.(),
|
|
73
|
+
signal: options.signal,
|
|
74
|
+
});
|
|
75
|
+
// The Harness passes the system prompt as a request field, but a history it
|
|
76
|
+
// replays may also carry `system`-role messages. Both are real system text,
|
|
77
|
+
// so they are joined rather than one silently winning.
|
|
78
|
+
const system = [options.system, projected.system].filter((part) => !!part).join("\n\n") || undefined;
|
|
79
|
+
const tools = options.tools?.map((tool) => ({
|
|
80
|
+
name: tool.name,
|
|
81
|
+
description: tool.description,
|
|
82
|
+
parameters: tool.parameters,
|
|
83
|
+
}));
|
|
84
|
+
const openBlocks = new Set();
|
|
85
|
+
for await (const event of streamKiro({
|
|
86
|
+
model: { ...model, region, ...(credentials.profileArn ? { profileArn: credentials.profileArn } : {}) },
|
|
87
|
+
messages: projected.messages,
|
|
88
|
+
systemPrompt: system,
|
|
89
|
+
tools,
|
|
90
|
+
effort: options.reasoningEffort,
|
|
91
|
+
accessToken: credentials.access,
|
|
92
|
+
sessionId: options.sessionId,
|
|
93
|
+
signal: options.signal,
|
|
94
|
+
profileArn: credentials.profileArn,
|
|
95
|
+
// The Harness assembler has no way to un-deliver a block, so the core must
|
|
96
|
+
// settle a degenerate response rather than replay over one already sent.
|
|
97
|
+
canDiscardEmittedBlocks: false,
|
|
98
|
+
})) {
|
|
99
|
+
switch (event.type) {
|
|
100
|
+
case "text_start":
|
|
101
|
+
openBlocks.add(event.index);
|
|
102
|
+
yield { type: "block-start", index: event.index, blockType: "text" };
|
|
103
|
+
break;
|
|
104
|
+
case "text_delta":
|
|
105
|
+
yield { type: "text-delta", index: event.index, text: event.delta };
|
|
106
|
+
break;
|
|
107
|
+
case "text_end":
|
|
108
|
+
openBlocks.delete(event.index);
|
|
109
|
+
yield { type: "block-end", index: event.index, block: { type: "text", text: event.text } };
|
|
110
|
+
break;
|
|
111
|
+
case "thinking_start":
|
|
112
|
+
openBlocks.add(event.index);
|
|
113
|
+
yield { type: "block-start", index: event.index, blockType: "reasoning" };
|
|
114
|
+
break;
|
|
115
|
+
case "thinking_delta":
|
|
116
|
+
yield { type: "reasoning-delta", index: event.index, text: event.delta };
|
|
117
|
+
break;
|
|
118
|
+
case "thinking_end":
|
|
119
|
+
openBlocks.delete(event.index);
|
|
120
|
+
yield { type: "block-end", index: event.index, block: { type: "reasoning", text: event.thinking } };
|
|
121
|
+
break;
|
|
122
|
+
case "tool_call_start":
|
|
123
|
+
openBlocks.add(event.index);
|
|
124
|
+
yield { type: "block-start", index: event.index, blockType: "tool-call" };
|
|
125
|
+
yield {
|
|
126
|
+
type: "tool-call-delta",
|
|
127
|
+
index: event.index,
|
|
128
|
+
id: event.id,
|
|
129
|
+
name: event.name,
|
|
130
|
+
argumentsDelta: "",
|
|
131
|
+
};
|
|
132
|
+
break;
|
|
133
|
+
case "tool_call_delta":
|
|
134
|
+
yield {
|
|
135
|
+
type: "tool-call-delta",
|
|
136
|
+
index: event.index,
|
|
137
|
+
id: event.id,
|
|
138
|
+
argumentsDelta: event.argumentsDelta,
|
|
139
|
+
};
|
|
140
|
+
break;
|
|
141
|
+
case "tool_call_end":
|
|
142
|
+
openBlocks.delete(event.index);
|
|
143
|
+
yield {
|
|
144
|
+
type: "block-end",
|
|
145
|
+
index: event.index,
|
|
146
|
+
block: {
|
|
147
|
+
type: "tool-call",
|
|
148
|
+
id: event.id,
|
|
149
|
+
name: event.name,
|
|
150
|
+
arguments: JSON.stringify(event.arguments),
|
|
151
|
+
},
|
|
152
|
+
};
|
|
153
|
+
break;
|
|
154
|
+
case "usage":
|
|
155
|
+
yield {
|
|
156
|
+
type: "usage",
|
|
157
|
+
usage: { inputTokens: event.usage.input, outputTokens: event.usage.output },
|
|
158
|
+
};
|
|
159
|
+
break;
|
|
160
|
+
case "done":
|
|
161
|
+
yield {
|
|
162
|
+
type: "finish",
|
|
163
|
+
reason: event.stopReason === "toolUse"
|
|
164
|
+
? { kind: "tool-calls" }
|
|
165
|
+
: event.stopReason === "length"
|
|
166
|
+
? { kind: "max-tokens" }
|
|
167
|
+
: { kind: "stop" },
|
|
168
|
+
};
|
|
169
|
+
break;
|
|
170
|
+
// `start` needs no chunk, and `reset` cannot happen: this adapter tells
|
|
171
|
+
// the core it can never discard a delivered block.
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
// A block the core opened but never closed would leave the assembler waiting
|
|
175
|
+
// for content that is not coming. That is only reachable if the core adds an
|
|
176
|
+
// exit path before its terminal events, so close them rather than trust it.
|
|
177
|
+
for (const index of openBlocks) {
|
|
178
|
+
yield { type: "block-end", index, block: { type: "text", text: "" } };
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
catalog(region) {
|
|
182
|
+
return getCachedModels(region ?? this.options.region ?? "us-east-1");
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
//# sourceMappingURL=adapter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"adapter.js","sourceRoot":"","sources":["../src/adapter.ts"],"names":[],"mappings":"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"}
|
package/dist/errors.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { LlmError } from "@deepseek-ai/dsh-llm";
|
|
2
|
+
/**
|
|
3
|
+
* Classify a core failure for the Harness.
|
|
4
|
+
*
|
|
5
|
+
* The core throws `Error` with Kiro's own wording because it serves two hosts
|
|
6
|
+
* with different error types. This is where that wording becomes one of the
|
|
7
|
+
* Harness's routing codes — the loop branches on `code`, so a mislabelled
|
|
8
|
+
* failure either retries forever or gives up on something transient.
|
|
9
|
+
*/
|
|
10
|
+
export declare function toLlmError(error: unknown): LlmError;
|
package/dist/errors.js
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
// ABOUTME: Maps Kiro's failure vocabulary onto the Harness LlmError taxonomy.
|
|
2
|
+
import { LlmError } from "@deepseek-ai/dsh-llm";
|
|
3
|
+
import { isCapacityError, isNonRetryableBodyError, KIRO_REASON_CODES } from "ns-kiro-core";
|
|
4
|
+
const STATUS_PATTERN = /Kiro API error: (\d{3})\b/;
|
|
5
|
+
/**
|
|
6
|
+
* Classify a core failure for the Harness.
|
|
7
|
+
*
|
|
8
|
+
* The core throws `Error` with Kiro's own wording because it serves two hosts
|
|
9
|
+
* with different error types. This is where that wording becomes one of the
|
|
10
|
+
* Harness's routing codes — the loop branches on `code`, so a mislabelled
|
|
11
|
+
* failure either retries forever or gives up on something transient.
|
|
12
|
+
*/
|
|
13
|
+
export function toLlmError(error) {
|
|
14
|
+
if (error instanceof LlmError)
|
|
15
|
+
return error;
|
|
16
|
+
const cause = error instanceof Error ? error : undefined;
|
|
17
|
+
const message = cause?.message ?? String(error);
|
|
18
|
+
if (cause?.name === "AbortError")
|
|
19
|
+
return new LlmError(message, "ABORTED", { cause });
|
|
20
|
+
const status = Number(STATUS_PATTERN.exec(message)?.[1]);
|
|
21
|
+
const options = { cause, ...(Number.isFinite(status) ? { status } : {}) };
|
|
22
|
+
if (message.includes("context_length_exceeded"))
|
|
23
|
+
return new LlmError(message, "CONTEXT_OVERFLOW", options);
|
|
24
|
+
if (message.includes(KIRO_REASON_CODES.MONTHLY_REQUEST_COUNT) || isNonRetryableBodyError(message)) {
|
|
25
|
+
return new LlmError(message, "QUOTA_EXCEEDED", options);
|
|
26
|
+
}
|
|
27
|
+
if (isCapacityError(message))
|
|
28
|
+
return new LlmError(message, "OVERLOADED", options);
|
|
29
|
+
if (message.includes(KIRO_REASON_CODES.USER_REQUEST_RATE_EXCEEDED) || status === 429) {
|
|
30
|
+
return new LlmError(message, "RATE_LIMIT", options);
|
|
31
|
+
}
|
|
32
|
+
if (message.includes("credentials not set") || status === 401 || status === 403) {
|
|
33
|
+
return new LlmError(message, "AUTH", options);
|
|
34
|
+
}
|
|
35
|
+
if (message.includes("timeout"))
|
|
36
|
+
return new LlmError(message, "TIMEOUT", options);
|
|
37
|
+
return new LlmError(message, "PROVIDER_ERROR", options);
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAE9E,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAChD,OAAO,EAAE,eAAe,EAAE,uBAAuB,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAE3F,MAAM,cAAc,GAAG,2BAA2B,CAAC;AAEnD;;;;;;;GAOG;AACH,MAAM,UAAU,UAAU,CAAC,KAAc;IACvC,IAAI,KAAK,YAAY,QAAQ;QAAE,OAAO,KAAK,CAAC;IAC5C,MAAM,KAAK,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC;IACzD,MAAM,OAAO,GAAG,KAAK,EAAE,OAAO,IAAI,MAAM,CAAC,KAAK,CAAC,CAAC;IAEhD,IAAI,KAAK,EAAE,IAAI,KAAK,YAAY;QAAE,OAAO,IAAI,QAAQ,CAAC,OAAO,EAAE,SAAS,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC;IAErF,MAAM,MAAM,GAAG,MAAM,CAAC,cAAc,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IACzD,MAAM,OAAO,GAAG,EAAE,KAAK,EAAE,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;IAE1E,IAAI,OAAO,CAAC,QAAQ,CAAC,yBAAyB,CAAC;QAAE,OAAO,IAAI,QAAQ,CAAC,OAAO,EAAE,kBAAkB,EAAE,OAAO,CAAC,CAAC;IAC3G,IAAI,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAC,qBAAqB,CAAC,IAAI,uBAAuB,CAAC,OAAO,CAAC,EAAE,CAAC;QAClG,OAAO,IAAI,QAAQ,CAAC,OAAO,EAAE,gBAAgB,EAAE,OAAO,CAAC,CAAC;IAC1D,CAAC;IACD,IAAI,eAAe,CAAC,OAAO,CAAC;QAAE,OAAO,IAAI,QAAQ,CAAC,OAAO,EAAE,YAAY,EAAE,OAAO,CAAC,CAAC;IAClF,IAAI,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAC,0BAA0B,CAAC,IAAI,MAAM,KAAK,GAAG,EAAE,CAAC;QACrF,OAAO,IAAI,QAAQ,CAAC,OAAO,EAAE,YAAY,EAAE,OAAO,CAAC,CAAC;IACtD,CAAC;IACD,IAAI,OAAO,CAAC,QAAQ,CAAC,qBAAqB,CAAC,IAAI,MAAM,KAAK,GAAG,IAAI,MAAM,KAAK,GAAG,EAAE,CAAC;QAChF,OAAO,IAAI,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC;IAChD,CAAC;IACD,IAAI,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC;QAAE,OAAO,IAAI,QAAQ,CAAC,OAAO,EAAE,SAAS,EAAE,OAAO,CAAC,CAAC;IAClF,OAAO,IAAI,QAAQ,CAAC,OAAO,EAAE,gBAAgB,EAAE,OAAO,CAAC,CAAC;AAC1D,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Kiro adapter plugin for the DeepSeek Harness LLM seam.
|
|
3
|
+
*
|
|
4
|
+
* Kiro speaks its own streaming protocol — AWS event-stream framing over
|
|
5
|
+
* `generateAssistantResponse` — which no configurable route can describe, so
|
|
6
|
+
* this registers a real adapter rather than a profile on a generic one.
|
|
7
|
+
*
|
|
8
|
+
* Sessions come from the machine: `kiro-cli login` (Builder ID, IAM Identity
|
|
9
|
+
* Center, Google, GitHub, enterprise OIDC) or the Kiro IDE. This plugin reads
|
|
10
|
+
* that session, refreshes it when it expires, and writes the refresh back so
|
|
11
|
+
* both tools stay on the same token.
|
|
12
|
+
*
|
|
13
|
+
* ```yaml
|
|
14
|
+
* - id: llm-kiro
|
|
15
|
+
* name: 'dsh-llm-kiro'
|
|
16
|
+
* config:
|
|
17
|
+
* provider: kiro
|
|
18
|
+
* region: us-east-1
|
|
19
|
+
* ```
|
|
20
|
+
*
|
|
21
|
+
* @module dsh-llm-kiro
|
|
22
|
+
*/
|
|
23
|
+
import type { Context } from "@deepseek-ai/cordis";
|
|
24
|
+
import z from "@deepseek-ai/schemastery";
|
|
25
|
+
export { KiroAdapter, type KiroAdapterOptions } from "./adapter.js";
|
|
26
|
+
export { toLlmError } from "./errors.js";
|
|
27
|
+
export { toKiroMessages } from "./messages.js";
|
|
28
|
+
export declare const name = "llm-kiro";
|
|
29
|
+
/**
|
|
30
|
+
* Only `llm` is a hard dependency. Cordis's object form of `inject` maps a
|
|
31
|
+
* service name to intercept config rather than marking it optional, and reading
|
|
32
|
+
* an uninjected service throws — so the optional attachment store is picked up
|
|
33
|
+
* through a scoped `ctx.inject` inside {@link apply} instead.
|
|
34
|
+
*/
|
|
35
|
+
export declare const inject: string[];
|
|
36
|
+
export interface Config {
|
|
37
|
+
/** Provider route to register the adapter under. */
|
|
38
|
+
provider: string;
|
|
39
|
+
/** Display name for selectors and status labels. */
|
|
40
|
+
displayName: string;
|
|
41
|
+
/**
|
|
42
|
+
* Kiro API region. Absent derives it from the credential, which is what a
|
|
43
|
+
* single-account machine wants; pin it when one account spans regions.
|
|
44
|
+
*/
|
|
45
|
+
region?: string;
|
|
46
|
+
}
|
|
47
|
+
export declare const Config: z<Config>;
|
|
48
|
+
export declare function apply(ctx: Context, config: Config): void;
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Kiro adapter plugin for the DeepSeek Harness LLM seam.
|
|
3
|
+
*
|
|
4
|
+
* Kiro speaks its own streaming protocol — AWS event-stream framing over
|
|
5
|
+
* `generateAssistantResponse` — which no configurable route can describe, so
|
|
6
|
+
* this registers a real adapter rather than a profile on a generic one.
|
|
7
|
+
*
|
|
8
|
+
* Sessions come from the machine: `kiro-cli login` (Builder ID, IAM Identity
|
|
9
|
+
* Center, Google, GitHub, enterprise OIDC) or the Kiro IDE. This plugin reads
|
|
10
|
+
* that session, refreshes it when it expires, and writes the refresh back so
|
|
11
|
+
* both tools stay on the same token.
|
|
12
|
+
*
|
|
13
|
+
* ```yaml
|
|
14
|
+
* - id: llm-kiro
|
|
15
|
+
* name: 'dsh-llm-kiro'
|
|
16
|
+
* config:
|
|
17
|
+
* provider: kiro
|
|
18
|
+
* region: us-east-1
|
|
19
|
+
* ```
|
|
20
|
+
*
|
|
21
|
+
* @module dsh-llm-kiro
|
|
22
|
+
*/
|
|
23
|
+
import { LlmError } from "@deepseek-ai/dsh-llm";
|
|
24
|
+
import z from "@deepseek-ai/schemastery";
|
|
25
|
+
import { isExpired, refreshKiroToken, resolveKiroCredentials } from "ns-kiro-core";
|
|
26
|
+
import { KiroAdapter } from "./adapter.js";
|
|
27
|
+
export { KiroAdapter } from "./adapter.js";
|
|
28
|
+
export { toLlmError } from "./errors.js";
|
|
29
|
+
export { toKiroMessages } from "./messages.js";
|
|
30
|
+
export const name = "llm-kiro";
|
|
31
|
+
/**
|
|
32
|
+
* Only `llm` is a hard dependency. Cordis's object form of `inject` maps a
|
|
33
|
+
* service name to intercept config rather than marking it optional, and reading
|
|
34
|
+
* an uninjected service throws — so the optional attachment store is picked up
|
|
35
|
+
* through a scoped `ctx.inject` inside {@link apply} instead.
|
|
36
|
+
*/
|
|
37
|
+
export const inject = ["llm"];
|
|
38
|
+
export const Config = z.object({
|
|
39
|
+
provider: z.string().default("kiro").description("Provider route to register the adapter under."),
|
|
40
|
+
displayName: z.string().default("Kiro").description("Display name shown in model selectors."),
|
|
41
|
+
region: z.string().description("Kiro API region; derived from the credential when absent."),
|
|
42
|
+
});
|
|
43
|
+
/**
|
|
44
|
+
* Resolve the current session for one request.
|
|
45
|
+
*
|
|
46
|
+
* Sessions are re-read rather than cached: kiro-cli rotates the token from
|
|
47
|
+
* another process, and a cached copy would send a token the service has already
|
|
48
|
+
* replaced. The read is a local file, so the cost is not worth the staleness.
|
|
49
|
+
*/
|
|
50
|
+
async function currentCredentials() {
|
|
51
|
+
const credentials = await resolveKiroCredentials();
|
|
52
|
+
if (!credentials) {
|
|
53
|
+
throw new LlmError("No Kiro session found. Sign in with `kiro-cli login`, or install the Kiro IDE and sign in there.", "MISSING_CREDENTIAL");
|
|
54
|
+
}
|
|
55
|
+
return isExpired(credentials) ? refreshKiroToken(credentials) : credentials;
|
|
56
|
+
}
|
|
57
|
+
export function apply(ctx, config) {
|
|
58
|
+
// Held here rather than read per request: a deployment without the attachment
|
|
59
|
+
// service never mounts it, and reading an uninjected service throws. The
|
|
60
|
+
// scoped fiber below sets it while the service exists and clears it when the
|
|
61
|
+
// service goes away, so an image-capable deployment gains image support
|
|
62
|
+
// without a text-only one failing to boot.
|
|
63
|
+
let attachments;
|
|
64
|
+
ctx.inject(["attachments"], (scope) => {
|
|
65
|
+
attachments = scope.attachments;
|
|
66
|
+
scope.effect(() => () => {
|
|
67
|
+
attachments = undefined;
|
|
68
|
+
}, "dsh-llm-kiro attachment store");
|
|
69
|
+
});
|
|
70
|
+
const adapter = new KiroAdapter({
|
|
71
|
+
provider: config.provider,
|
|
72
|
+
displayName: config.displayName,
|
|
73
|
+
credentials: currentCredentials,
|
|
74
|
+
attachments: () => attachments,
|
|
75
|
+
...(config.region ? { region: config.region } : {}),
|
|
76
|
+
});
|
|
77
|
+
ctx.llm.registerAdapter([config.provider], adapter);
|
|
78
|
+
}
|
|
79
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAIH,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAChD,OAAO,CAAC,MAAM,0BAA0B,CAAC;AACzC,OAAO,EAAE,SAAS,EAAwB,gBAAgB,EAAE,sBAAsB,EAAE,MAAM,cAAc,CAAC;AACzG,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAE3C,OAAO,EAAE,WAAW,EAA2B,MAAM,cAAc,CAAC;AACpE,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAE/C,MAAM,CAAC,MAAM,IAAI,GAAG,UAAU,CAAC;AAE/B;;;;;GAKG;AACH,MAAM,CAAC,MAAM,MAAM,GAAG,CAAC,KAAK,CAAC,CAAC;AAc9B,MAAM,CAAC,MAAM,MAAM,GAAc,CAAC,CAAC,MAAM,CAAC;IACxC,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,WAAW,CAAC,+CAA+C,CAAC;IACjG,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,WAAW,CAAC,wCAAwC,CAAC;IAC7F,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,WAAW,CAAC,2DAA2D,CAAC;CAC5F,CAAC,CAAC;AAEH;;;;;;GAMG;AACH,KAAK,UAAU,kBAAkB;IAC/B,MAAM,WAAW,GAAG,MAAM,sBAAsB,EAAE,CAAC;IACnD,IAAI,CAAC,WAAW,EAAE,CAAC;QACjB,MAAM,IAAI,QAAQ,CAChB,kGAAkG,EAClG,oBAAoB,CACrB,CAAC;IACJ,CAAC;IACD,OAAO,SAAS,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,gBAAgB,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC;AAC9E,CAAC;AAED,MAAM,UAAU,KAAK,CAAC,GAAY,EAAE,MAAc;IAChD,8EAA8E;IAC9E,yEAAyE;IACzE,6EAA6E;IAC7E,wEAAwE;IACxE,2CAA2C;IAC3C,IAAI,WAAwC,CAAC;IAC7C,GAAG,CAAC,MAAM,CAAC,CAAC,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,EAAE;QACpC,WAAW,GAAG,KAAK,CAAC,WAAW,CAAC;QAChC,KAAK,CAAC,MAAM,CACV,GAAG,EAAE,CAAC,GAAG,EAAE;YACT,WAAW,GAAG,SAAS,CAAC;QAC1B,CAAC,EACD,+BAA+B,CAChC,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,MAAM,OAAO,GAAG,IAAI,WAAW,CAAC;QAC9B,QAAQ,EAAE,MAAM,CAAC,QAAQ;QACzB,WAAW,EAAE,MAAM,CAAC,WAAW;QAC/B,WAAW,EAAE,kBAAkB;QAC/B,WAAW,EAAE,GAAG,EAAE,CAAC,WAAW;QAC9B,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KACpD,CAAC,CAAC;IAEH,GAAG,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC,CAAC;AACtD,CAAC"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { AttachmentStore } from "@deepseek-ai/dsh-attachment";
|
|
2
|
+
import type { Message } from "@deepseek-ai/dsh-llm";
|
|
3
|
+
import type { KiroMessage } from "ns-kiro-core";
|
|
4
|
+
/**
|
|
5
|
+
* Harness images live in the attachment service, so their bytes are read here
|
|
6
|
+
* rather than carried on the block. A store is optional: without one the images
|
|
7
|
+
* are dropped and the rest of the turn still reaches the model, which is the
|
|
8
|
+
* behaviour a text-only deployment wants.
|
|
9
|
+
*/
|
|
10
|
+
export interface MessageProjectionContext {
|
|
11
|
+
attachments?: AttachmentStore;
|
|
12
|
+
signal?: AbortSignal;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Flatten one Harness history into the neutral shape.
|
|
16
|
+
*
|
|
17
|
+
* Two structural differences drive the whole mapping. The Harness has no
|
|
18
|
+
* `toolResult` role — a result is a `tool-result` block inside a user message —
|
|
19
|
+
* so those blocks are lifted into their own neutral messages. And its system
|
|
20
|
+
* prompt travels as a `system`-role message rather than a request field, so
|
|
21
|
+
* system text is returned separately for the caller to pass as the system slot.
|
|
22
|
+
*/
|
|
23
|
+
export declare function toKiroMessages(messages: readonly Message[], context?: MessageProjectionContext): Promise<{
|
|
24
|
+
messages: KiroMessage[];
|
|
25
|
+
system?: string;
|
|
26
|
+
}>;
|
package/dist/messages.js
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
// ABOUTME: Projects the Harness conversation vocabulary onto the neutral one kiro-core reads.
|
|
2
|
+
async function userContent(blocks, context) {
|
|
3
|
+
const out = [];
|
|
4
|
+
for (const block of blocks) {
|
|
5
|
+
if (block.type === "text")
|
|
6
|
+
out.push({ type: "text", text: block.text });
|
|
7
|
+
else if (block.type === "reasoning")
|
|
8
|
+
out.push({ type: "text", text: block.text });
|
|
9
|
+
else if (block.type === "image" && context.attachments) {
|
|
10
|
+
const stored = await context.attachments.readImage(block.attachment, context.signal);
|
|
11
|
+
out.push({
|
|
12
|
+
type: "image",
|
|
13
|
+
data: Buffer.from(stored.data).toString("base64"),
|
|
14
|
+
mimeType: block.attachment.mediaType,
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
return out;
|
|
19
|
+
}
|
|
20
|
+
function isToolResult(block) {
|
|
21
|
+
return block.type === "tool-result";
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Flatten one Harness history into the neutral shape.
|
|
25
|
+
*
|
|
26
|
+
* Two structural differences drive the whole mapping. The Harness has no
|
|
27
|
+
* `toolResult` role — a result is a `tool-result` block inside a user message —
|
|
28
|
+
* so those blocks are lifted into their own neutral messages. And its system
|
|
29
|
+
* prompt travels as a `system`-role message rather than a request field, so
|
|
30
|
+
* system text is returned separately for the caller to pass as the system slot.
|
|
31
|
+
*/
|
|
32
|
+
export async function toKiroMessages(messages, context = {}) {
|
|
33
|
+
const out = [];
|
|
34
|
+
const systemParts = [];
|
|
35
|
+
for (const message of messages) {
|
|
36
|
+
if (message.role === "system") {
|
|
37
|
+
for (const block of message.content)
|
|
38
|
+
if (block.type === "text")
|
|
39
|
+
systemParts.push(block.text);
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
if (message.role === "assistant") {
|
|
43
|
+
const content = [];
|
|
44
|
+
for (const block of message.content) {
|
|
45
|
+
if (block.type === "text")
|
|
46
|
+
content.push({ type: "text", text: block.text });
|
|
47
|
+
else if (block.type === "reasoning")
|
|
48
|
+
content.push({ type: "thinking", thinking: block.text });
|
|
49
|
+
else if (block.type === "tool-call") {
|
|
50
|
+
let args;
|
|
51
|
+
try {
|
|
52
|
+
args = JSON.parse(block.arguments || "{}");
|
|
53
|
+
}
|
|
54
|
+
catch {
|
|
55
|
+
// A stored call whose arguments no longer parse is still part of the
|
|
56
|
+
// exchange the model must see; sending it with empty arguments keeps
|
|
57
|
+
// the call/result pairing Kiro validates, which dropping would break.
|
|
58
|
+
args = {};
|
|
59
|
+
}
|
|
60
|
+
content.push({ type: "toolCall", id: block.id, name: block.name, arguments: args });
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
out.push({ role: "assistant", content });
|
|
64
|
+
continue;
|
|
65
|
+
}
|
|
66
|
+
const results = message.content.filter(isToolResult);
|
|
67
|
+
const plain = message.content.filter((block) => !isToolResult(block));
|
|
68
|
+
if (plain.length > 0)
|
|
69
|
+
out.push({ role: "user", content: await userContent(plain, context) });
|
|
70
|
+
for (const result of results) {
|
|
71
|
+
out.push({
|
|
72
|
+
role: "toolResult",
|
|
73
|
+
toolCallId: result.toolCallId,
|
|
74
|
+
// The Harness correlates a result by id alone and carries no tool name
|
|
75
|
+
// on the block. Kiro's wire format does not read the name back either —
|
|
76
|
+
// `toolUseId` is the whole pairing — so a placeholder is honest here.
|
|
77
|
+
toolName: "tool",
|
|
78
|
+
content: await userContent(result.content, context),
|
|
79
|
+
isError: result.isError === true,
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
return { messages: out, ...(systemParts.length > 0 ? { system: systemParts.join("\n\n") } : {}) };
|
|
84
|
+
}
|
|
85
|
+
//# sourceMappingURL=messages.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"messages.js","sourceRoot":"","sources":["../src/messages.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "ns-dsh-llm-kiro",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "DeepSeek Harness LLM adapter for the Kiro API (AWS CodeWhisperer/Q)",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"default": "./dist/index.js"
|
|
12
|
+
},
|
|
13
|
+
"./package.json": "./package.json"
|
|
14
|
+
},
|
|
15
|
+
"license": "MIT",
|
|
16
|
+
"repository": {
|
|
17
|
+
"type": "git",
|
|
18
|
+
"url": "git+https://github.com/ngosangns/ns-kiro-provider.git",
|
|
19
|
+
"directory": "packages/dsh-llm-kiro"
|
|
20
|
+
},
|
|
21
|
+
"keywords": [
|
|
22
|
+
"deepseek-harness",
|
|
23
|
+
"dsh",
|
|
24
|
+
"dsh-plugin",
|
|
25
|
+
"cordis",
|
|
26
|
+
"kiro",
|
|
27
|
+
"aws",
|
|
28
|
+
"codewhisperer",
|
|
29
|
+
"ai",
|
|
30
|
+
"llm"
|
|
31
|
+
],
|
|
32
|
+
"files": [
|
|
33
|
+
"dist",
|
|
34
|
+
"README.md"
|
|
35
|
+
],
|
|
36
|
+
"dependencies": {
|
|
37
|
+
"@deepseek-ai/schemastery": "^3.18.1",
|
|
38
|
+
"ns-kiro-core": "0.1.0"
|
|
39
|
+
},
|
|
40
|
+
"peerDependencies": {
|
|
41
|
+
"@deepseek-ai/cordis": "^4.0.1",
|
|
42
|
+
"@deepseek-ai/dsh-attachment": ">=0.1.1-rc.1 <0.2.0",
|
|
43
|
+
"@deepseek-ai/dsh-credentials": ">=0.1.1-rc.1 <0.2.0",
|
|
44
|
+
"@deepseek-ai/dsh-llm": ">=0.1.1-rc.1 <0.2.0"
|
|
45
|
+
},
|
|
46
|
+
"peerDependenciesMeta": {
|
|
47
|
+
"@deepseek-ai/dsh-attachment": {
|
|
48
|
+
"optional": true
|
|
49
|
+
},
|
|
50
|
+
"@deepseek-ai/dsh-credentials": {
|
|
51
|
+
"optional": true
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
"devDependencies": {
|
|
55
|
+
"@deepseek-ai/cordis": "4.0.1",
|
|
56
|
+
"@deepseek-ai/dsh-attachment": "0.1.1-rc.1",
|
|
57
|
+
"@deepseek-ai/dsh-credentials": "0.1.1-rc.1",
|
|
58
|
+
"@deepseek-ai/dsh-llm": "0.1.1-rc.1",
|
|
59
|
+
"@types/node": "^22.10.0"
|
|
60
|
+
},
|
|
61
|
+
"scripts": {
|
|
62
|
+
"build": "tsc -p tsconfig.json",
|
|
63
|
+
"check": "tsc -p tsconfig.json --noEmit && tsc -p tsconfig.test.json"
|
|
64
|
+
}
|
|
65
|
+
}
|