ns-omp-provider-kiro 0.3.8 → 0.3.9
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 +6 -3
- package/dist/auth.d.ts +4 -27
- package/dist/index.js +334 -160
- package/dist/messages.d.ts +1 -10
- package/dist/stream.d.ts +1 -13
- package/package.json +5 -4
package/README.md
CHANGED
|
@@ -17,8 +17,8 @@ To build from a clone instead — for developing this package or
|
|
|
17
17
|
`ns-kiro-core` before a release — install from the path:
|
|
18
18
|
|
|
19
19
|
```bash
|
|
20
|
-
git clone git@github.com:ngosangns/ns-
|
|
21
|
-
cd ns-
|
|
20
|
+
git clone git@github.com:ngosangns/ns-bridge.git
|
|
21
|
+
cd ns-bridge && pnpm install && pnpm -r build
|
|
22
22
|
omp plugin install ./packages/omp-provider-kiro
|
|
23
23
|
```
|
|
24
24
|
|
|
@@ -59,4 +59,7 @@ upstream shows up without a release here.
|
|
|
59
59
|
- `KIRO_DEBUG=1` writes a full request/response trace to
|
|
60
60
|
`~/.ns-kiro-provider/logs/kiro-debug.log`, with credentials redacted.
|
|
61
61
|
|
|
62
|
-
|
|
62
|
+
This is the recommended Kiro path in OMP. `ns-omp-provider` can also register a
|
|
63
|
+
`kiro` provider, but leaves it off by default so the two never fight over the id.
|
|
64
|
+
|
|
65
|
+
Part of [ns-bridge](https://github.com/ngosangns/ns-bridge).
|
package/dist/auth.d.ts
CHANGED
|
@@ -1,31 +1,8 @@
|
|
|
1
1
|
import type { OAuthCredentials, OAuthLoginCallbacks } from "@oh-my-pi/pi-ai";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
* supports already lands a session in the kiro-cli store or the Kiro IDE token
|
|
5
|
-
* file, so this reads one of those and refreshes it. The one credential with no
|
|
6
|
-
* browser step — an API key — is accepted directly.
|
|
7
|
-
*/
|
|
2
|
+
import { type ResolvedKiroRequestCredentials, resolveKiroRequestCredentials } from "ns-kiro-core";
|
|
3
|
+
export type { ResolvedKiroRequestCredentials };
|
|
8
4
|
export declare function loginKiro(callbacks: OAuthLoginCallbacks): Promise<OAuthCredentials>;
|
|
9
5
|
export declare function refreshKiroCredentials(credentials: OAuthCredentials): Promise<OAuthCredentials>;
|
|
10
6
|
export declare function getKiroApiKey(credentials: OAuthCredentials): string;
|
|
11
|
-
/**
|
|
12
|
-
export
|
|
13
|
-
accessToken: string;
|
|
14
|
-
region: string;
|
|
15
|
-
profileArn?: string;
|
|
16
|
-
}
|
|
17
|
-
/**
|
|
18
|
-
* Decide which credential a request or catalog fetch runs on.
|
|
19
|
-
*
|
|
20
|
-
* The key OMP resolves for the provider is the session this package returned
|
|
21
|
-
* from `/login kiro` — but it is also `$KIRO_API_KEY` verbatim when that
|
|
22
|
-
* variable is unset, and Kiro answers a bogus bearer with a 403 the core then
|
|
23
|
-
* has to recover from. So a host key is trusted only when it is recognizably a
|
|
24
|
-
* Kiro credential; anything else defers to the store, which is where the
|
|
25
|
-
* session actually lives.
|
|
26
|
-
*
|
|
27
|
-
* The stored record also carries the region and the profile ARN, and passing
|
|
28
|
-
* the ARN skips the ListAvailableProfiles round trip that a social login cannot
|
|
29
|
-
* answer anyway.
|
|
30
|
-
*/
|
|
31
|
-
export declare function resolveRequestCredentials(hostKey: string | undefined): Promise<ResolvedKiroRequestCredentials>;
|
|
7
|
+
/** See {@link resolveKiroRequestCredentials}: which credential one request or catalog fetch runs on. */
|
|
8
|
+
export declare const resolveRequestCredentials: typeof resolveKiroRequestCredentials;
|
package/dist/index.js
CHANGED
|
@@ -2862,6 +2862,72 @@ function syntheticToolResultEntry(toolUseIds, modelId) {
|
|
|
2862
2862
|
};
|
|
2863
2863
|
}
|
|
2864
2864
|
|
|
2865
|
+
// ../kiro-core/dist/host-auth.js
|
|
2866
|
+
init_endpoints();
|
|
2867
|
+
init_oauth();
|
|
2868
|
+
var KIRO_NO_SESSION_MESSAGE = "No Kiro session found. Sign in with `kiro-cli login` (Builder ID, IAM Identity Center, Google, or GitHub), then run /login kiro again \u2014 or paste a Kiro API key below.";
|
|
2869
|
+
async function loginKiroFromSession(callbacks) {
|
|
2870
|
+
callbacks.onProgress?.("Looking for an existing Kiro session\u2026");
|
|
2871
|
+
const existing = await resolveKiroCredentials();
|
|
2872
|
+
if (existing) {
|
|
2873
|
+
callbacks.onProgress?.(`Using the ${existing.authMethod} session from kiro-cli.`);
|
|
2874
|
+
return existing;
|
|
2875
|
+
}
|
|
2876
|
+
if (!callbacks.onPrompt)
|
|
2877
|
+
throw new Error(KIRO_NO_SESSION_MESSAGE);
|
|
2878
|
+
const apiKey = (await callbacks.onPrompt({
|
|
2879
|
+
message: KIRO_NO_SESSION_MESSAGE,
|
|
2880
|
+
placeholder: "ksk_\u2026",
|
|
2881
|
+
allowEmpty: true,
|
|
2882
|
+
secret: true
|
|
2883
|
+
})).trim();
|
|
2884
|
+
if (!apiKey)
|
|
2885
|
+
throw new Error(KIRO_NO_SESSION_MESSAGE);
|
|
2886
|
+
return loginKiroWithApiKey(apiKey, callbacks.onProgress);
|
|
2887
|
+
}
|
|
2888
|
+
async function resolveKiroRequestCredentials(hostKey) {
|
|
2889
|
+
const stored = await resolveKiroCredentials();
|
|
2890
|
+
const region = resolveApiRegion(stored?.region);
|
|
2891
|
+
if (hostKey && (isApiKey(hostKey) || hostKey === stored?.access)) {
|
|
2892
|
+
return { accessToken: hostKey, region, ...stored?.profileArn ? { profileArn: stored.profileArn } : {} };
|
|
2893
|
+
}
|
|
2894
|
+
if (stored) {
|
|
2895
|
+
return {
|
|
2896
|
+
accessToken: stored.access,
|
|
2897
|
+
region,
|
|
2898
|
+
...stored.profileArn ? { profileArn: stored.profileArn } : {}
|
|
2899
|
+
};
|
|
2900
|
+
}
|
|
2901
|
+
if (hostKey)
|
|
2902
|
+
return { accessToken: hostKey, region };
|
|
2903
|
+
throw new Error("Kiro credentials not set. Run `kiro-cli login`, or set KIRO_API_KEY to a `ksk_` API key.");
|
|
2904
|
+
}
|
|
2905
|
+
|
|
2906
|
+
// ../kiro-core/dist/host-model.js
|
|
2907
|
+
init_models();
|
|
2908
|
+
function toKiroModelForHost(model, region) {
|
|
2909
|
+
const known = getCachedModels(region).find((candidate) => candidate.id === model.id);
|
|
2910
|
+
return {
|
|
2911
|
+
...known ?? {
|
|
2912
|
+
id: model.id,
|
|
2913
|
+
// No fallback to `model.id`: that dash-spelled local id is not a valid
|
|
2914
|
+
// Kiro wire id. `""` is falsy, so `resolveKiroModel` runs its own
|
|
2915
|
+
// cache/bootstrap/dot-normalize resolution instead of being
|
|
2916
|
+
// short-circuited by a value that is really just `model.id` again.
|
|
2917
|
+
kiroModelId: model.kiroModelId ?? "",
|
|
2918
|
+
name: model.name,
|
|
2919
|
+
reasoning: model.reasoning,
|
|
2920
|
+
input: [...model.input],
|
|
2921
|
+
cost: { ...model.cost },
|
|
2922
|
+
contextWindow: model.contextWindow ?? 2e5,
|
|
2923
|
+
maxTokens: model.maxTokens ?? 8192
|
|
2924
|
+
},
|
|
2925
|
+
region,
|
|
2926
|
+
...model.kiroProfileArn ? { profileArn: model.kiroProfileArn } : {},
|
|
2927
|
+
...model.additionalModelRequestFieldsSchema ? { additionalModelRequestFieldsSchema: model.additionalModelRequestFieldsSchema } : {}
|
|
2928
|
+
};
|
|
2929
|
+
}
|
|
2930
|
+
|
|
2865
2931
|
// ../kiro-core/dist/invoke-tool-parser.js
|
|
2866
2932
|
var INVOKE_OPEN_ANCHORED = /^<invoke name="([\w-]+)">/;
|
|
2867
2933
|
var INVOKE_OPEN_SEARCH = "<invoke name=";
|
|
@@ -5493,23 +5559,8 @@ async function fetchKiroUsage(credentials) {
|
|
|
5493
5559
|
}
|
|
5494
5560
|
|
|
5495
5561
|
// src/auth.ts
|
|
5496
|
-
var NO_SESSION_MESSAGE = "No Kiro session found. Sign in with `kiro-cli login` (Builder ID, IAM Identity Center, Google, or GitHub), then run /login kiro again \u2014 or paste a Kiro API key below.";
|
|
5497
5562
|
async function loginKiro(callbacks) {
|
|
5498
|
-
|
|
5499
|
-
const existing = await resolveKiroCredentials();
|
|
5500
|
-
if (existing) {
|
|
5501
|
-
callbacks.onProgress?.(`Using the ${existing.authMethod} session from kiro-cli.`);
|
|
5502
|
-
return existing;
|
|
5503
|
-
}
|
|
5504
|
-
if (!callbacks.onPrompt) throw new Error(NO_SESSION_MESSAGE);
|
|
5505
|
-
const apiKey = (await callbacks.onPrompt({
|
|
5506
|
-
message: NO_SESSION_MESSAGE,
|
|
5507
|
-
placeholder: "ksk_\u2026",
|
|
5508
|
-
allowEmpty: true,
|
|
5509
|
-
secret: true
|
|
5510
|
-
})).trim();
|
|
5511
|
-
if (!apiKey) throw new Error(NO_SESSION_MESSAGE);
|
|
5512
|
-
return await loginKiroWithApiKey(apiKey, callbacks.onProgress);
|
|
5563
|
+
return await loginKiroFromSession(callbacks);
|
|
5513
5564
|
}
|
|
5514
5565
|
async function refreshKiroCredentials(credentials) {
|
|
5515
5566
|
return await refreshKiroToken(credentials);
|
|
@@ -5517,22 +5568,7 @@ async function refreshKiroCredentials(credentials) {
|
|
|
5517
5568
|
function getKiroApiKey(credentials) {
|
|
5518
5569
|
return credentials.access;
|
|
5519
5570
|
}
|
|
5520
|
-
|
|
5521
|
-
const stored = await resolveKiroCredentials();
|
|
5522
|
-
const region = resolveApiRegion(stored?.region);
|
|
5523
|
-
if (hostKey && (isApiKey(hostKey) || hostKey === stored?.access)) {
|
|
5524
|
-
return { accessToken: hostKey, region, ...stored?.profileArn ? { profileArn: stored.profileArn } : {} };
|
|
5525
|
-
}
|
|
5526
|
-
if (stored) {
|
|
5527
|
-
return {
|
|
5528
|
-
accessToken: stored.access,
|
|
5529
|
-
region,
|
|
5530
|
-
...stored.profileArn ? { profileArn: stored.profileArn } : {}
|
|
5531
|
-
};
|
|
5532
|
-
}
|
|
5533
|
-
if (hostKey) return { accessToken: hostKey, region };
|
|
5534
|
-
throw new Error("Kiro credentials not set. Run `kiro-cli login`, or set KIRO_API_KEY to a `ksk_` API key.");
|
|
5535
|
-
}
|
|
5571
|
+
var resolveRequestCredentials = resolveKiroRequestCredentials;
|
|
5536
5572
|
|
|
5537
5573
|
// src/models.ts
|
|
5538
5574
|
function toOmpModelConfig(model) {
|
|
@@ -5564,22 +5600,81 @@ function kiroBaseUrl(region) {
|
|
|
5564
5600
|
// src/stream.ts
|
|
5565
5601
|
import * as PiAi from "@oh-my-pi/pi-ai";
|
|
5566
5602
|
|
|
5567
|
-
//
|
|
5603
|
+
// ../bridge-core/dist/pi/transcript.js
|
|
5604
|
+
function isSystemMessage(message) {
|
|
5605
|
+
return message?.role === "system";
|
|
5606
|
+
}
|
|
5607
|
+
function contentText(content) {
|
|
5608
|
+
if (typeof content === "string")
|
|
5609
|
+
return content;
|
|
5610
|
+
if (!Array.isArray(content))
|
|
5611
|
+
return "";
|
|
5612
|
+
return content.map((part) => part && typeof part === "object" && part.type === "text" ? String(part.text ?? "") : "").filter((text) => text.length > 0).join("\n");
|
|
5613
|
+
}
|
|
5614
|
+
function getCurrentTools(messages) {
|
|
5615
|
+
const tools = /* @__PURE__ */ new Map();
|
|
5616
|
+
for (const message of messages) {
|
|
5617
|
+
if (!isSystemMessage(message))
|
|
5618
|
+
continue;
|
|
5619
|
+
for (const tool of message.toolsRemoved ?? [])
|
|
5620
|
+
tools.delete(tool.name);
|
|
5621
|
+
for (const tool of message.toolsAdded ?? [])
|
|
5622
|
+
tools.set(tool.name, tool);
|
|
5623
|
+
}
|
|
5624
|
+
return [...tools.values()];
|
|
5625
|
+
}
|
|
5626
|
+
function getCurrentSystemPrompt(messages) {
|
|
5627
|
+
const content = [];
|
|
5628
|
+
const sections = /* @__PURE__ */ new Map();
|
|
5629
|
+
for (const message of messages) {
|
|
5630
|
+
if (!isSystemMessage(message))
|
|
5631
|
+
continue;
|
|
5632
|
+
const text = contentText(message.content);
|
|
5633
|
+
if (text.length > 0)
|
|
5634
|
+
content.push(text);
|
|
5635
|
+
for (const [name, value] of Object.entries(message.sections ?? {})) {
|
|
5636
|
+
if (value === null)
|
|
5637
|
+
sections.delete(name);
|
|
5638
|
+
else
|
|
5639
|
+
sections.set(name, value);
|
|
5640
|
+
}
|
|
5641
|
+
}
|
|
5642
|
+
return [content.join("\n\n"), ...sections.values()].filter((part) => part.length > 0).join("\n\n");
|
|
5643
|
+
}
|
|
5644
|
+
|
|
5645
|
+
// ../bridge-core/dist/pi/context.js
|
|
5568
5646
|
function userContent(content) {
|
|
5569
|
-
if (typeof content === "string")
|
|
5647
|
+
if (typeof content === "string")
|
|
5648
|
+
return content ? [{ type: "text", text: content }] : [];
|
|
5649
|
+
if (!Array.isArray(content))
|
|
5650
|
+
return [];
|
|
5570
5651
|
const out = [];
|
|
5571
5652
|
for (const block of content) {
|
|
5572
|
-
if (block
|
|
5573
|
-
|
|
5574
|
-
|
|
5575
|
-
out.push({ type: "image", data:
|
|
5653
|
+
if (block?.type === "text" && typeof block.text === "string")
|
|
5654
|
+
out.push({ type: "text", text: block.text });
|
|
5655
|
+
else if (block?.type === "image" && typeof block.data === "string") {
|
|
5656
|
+
out.push({ type: "image", data: block.data, mimeType: String(block.mimeType ?? "image/png") });
|
|
5576
5657
|
}
|
|
5577
5658
|
}
|
|
5578
5659
|
return out;
|
|
5579
5660
|
}
|
|
5580
|
-
|
|
5661
|
+
var STOP_REASONS = /* @__PURE__ */ new Set(["stop", "length", "toolUse", "error", "aborted"]);
|
|
5662
|
+
function parseArguments(value) {
|
|
5663
|
+
if (typeof value === "string") {
|
|
5664
|
+
try {
|
|
5665
|
+
const parsed = JSON.parse(value || "{}");
|
|
5666
|
+
return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : {};
|
|
5667
|
+
} catch {
|
|
5668
|
+
return {};
|
|
5669
|
+
}
|
|
5670
|
+
}
|
|
5671
|
+
return value && typeof value === "object" ? value : {};
|
|
5672
|
+
}
|
|
5673
|
+
function toBridgeMessages(messages) {
|
|
5581
5674
|
const out = [];
|
|
5582
5675
|
for (const message of messages) {
|
|
5676
|
+
if (message.role === "system")
|
|
5677
|
+
continue;
|
|
5583
5678
|
if (message.role === "user" || message.role === "developer") {
|
|
5584
5679
|
out.push({ role: "user", content: userContent(message.content) });
|
|
5585
5680
|
continue;
|
|
@@ -5587,103 +5682,147 @@ function toKiroMessages(messages) {
|
|
|
5587
5682
|
if (message.role === "toolResult") {
|
|
5588
5683
|
out.push({
|
|
5589
5684
|
role: "toolResult",
|
|
5590
|
-
toolCallId: message.toolCallId,
|
|
5591
|
-
toolName: message.toolName,
|
|
5685
|
+
toolCallId: String(message.toolCallId ?? ""),
|
|
5686
|
+
toolName: String(message.toolName ?? "tool"),
|
|
5592
5687
|
content: userContent(message.content),
|
|
5593
|
-
isError: message.isError
|
|
5688
|
+
isError: message.isError === true
|
|
5594
5689
|
});
|
|
5595
5690
|
continue;
|
|
5596
5691
|
}
|
|
5692
|
+
if (message.role !== "assistant")
|
|
5693
|
+
continue;
|
|
5597
5694
|
const content = [];
|
|
5598
|
-
for (const block of message.content) {
|
|
5599
|
-
if (block
|
|
5600
|
-
|
|
5601
|
-
|
|
5695
|
+
for (const block of Array.isArray(message.content) ? message.content : []) {
|
|
5696
|
+
if (block?.type === "text" && typeof block.text === "string")
|
|
5697
|
+
content.push({ type: "text", text: block.text });
|
|
5698
|
+
else if (block?.type === "thinking" && typeof block.thinking === "string") {
|
|
5602
5699
|
content.push({
|
|
5603
5700
|
type: "thinking",
|
|
5604
|
-
thinking:
|
|
5605
|
-
...
|
|
5701
|
+
thinking: block.thinking,
|
|
5702
|
+
...typeof block.thinkingSignature === "string" && block.thinkingSignature ? { thinkingSignature: block.thinkingSignature } : {}
|
|
5606
5703
|
});
|
|
5607
|
-
} else if (block
|
|
5608
|
-
const call = block;
|
|
5704
|
+
} else if (block?.type === "toolCall") {
|
|
5609
5705
|
content.push({
|
|
5610
5706
|
type: "toolCall",
|
|
5611
|
-
id:
|
|
5612
|
-
name:
|
|
5613
|
-
arguments:
|
|
5707
|
+
id: String(block.id ?? ""),
|
|
5708
|
+
name: String(block.name ?? ""),
|
|
5709
|
+
arguments: parseArguments(block.arguments)
|
|
5614
5710
|
});
|
|
5615
5711
|
}
|
|
5616
5712
|
}
|
|
5617
|
-
out.push({
|
|
5713
|
+
out.push({
|
|
5714
|
+
role: "assistant",
|
|
5715
|
+
content,
|
|
5716
|
+
...message.stopReason && STOP_REASONS.has(message.stopReason) ? { stopReason: message.stopReason } : {},
|
|
5717
|
+
...typeof message.responseId === "string" && message.responseId ? { responseId: message.responseId } : {}
|
|
5718
|
+
});
|
|
5618
5719
|
}
|
|
5619
5720
|
return out;
|
|
5620
5721
|
}
|
|
5621
|
-
function
|
|
5622
|
-
if (!tools?.length)
|
|
5722
|
+
function toBridgeTools(tools) {
|
|
5723
|
+
if (!tools?.length)
|
|
5724
|
+
return void 0;
|
|
5623
5725
|
return tools.map((tool) => ({
|
|
5624
5726
|
name: tool.name,
|
|
5625
|
-
description: tool.description,
|
|
5626
|
-
parameters: tool.parameters
|
|
5727
|
+
description: tool.description ?? "",
|
|
5728
|
+
parameters: tool.parameters ?? { type: "object", properties: {} },
|
|
5729
|
+
...tool.strict !== void 0 ? { strict: tool.strict } : {}
|
|
5627
5730
|
}));
|
|
5628
5731
|
}
|
|
5732
|
+
function resolveSystemPrompt(context) {
|
|
5733
|
+
const parts = [];
|
|
5734
|
+
const declared = context.systemPrompt;
|
|
5735
|
+
if (typeof declared === "string")
|
|
5736
|
+
parts.push(declared);
|
|
5737
|
+
else if (Array.isArray(declared))
|
|
5738
|
+
parts.push(...declared.filter((part) => typeof part === "string"));
|
|
5739
|
+
const fromTranscript = getCurrentSystemPrompt(context.messages);
|
|
5740
|
+
if (fromTranscript)
|
|
5741
|
+
parts.push(fromTranscript);
|
|
5742
|
+
const joined = parts.filter((part) => part.trim().length > 0).join("\n\n");
|
|
5743
|
+
return joined || void 0;
|
|
5744
|
+
}
|
|
5745
|
+
function resolveTools(context) {
|
|
5746
|
+
if (context.tools?.length)
|
|
5747
|
+
return [...context.tools];
|
|
5748
|
+
return getCurrentTools(context.messages);
|
|
5749
|
+
}
|
|
5750
|
+
function toBridgeContext(context) {
|
|
5751
|
+
const systemPrompt = resolveSystemPrompt(context);
|
|
5752
|
+
const tools = toBridgeTools(resolveTools(context));
|
|
5753
|
+
return {
|
|
5754
|
+
...systemPrompt ? { systemPrompt } : {},
|
|
5755
|
+
messages: toBridgeMessages(context.messages),
|
|
5756
|
+
...tools ? { tools } : {}
|
|
5757
|
+
};
|
|
5758
|
+
}
|
|
5629
5759
|
|
|
5630
|
-
//
|
|
5631
|
-
|
|
5632
|
-
|
|
5633
|
-
|
|
5634
|
-
|
|
5635
|
-
|
|
5760
|
+
// ../bridge-core/dist/types.js
|
|
5761
|
+
var BRIDGE_EFFORT_ORDER = ["minimal", "low", "medium", "high", "xhigh", "max"];
|
|
5762
|
+
|
|
5763
|
+
// ../bridge-core/dist/pi/models.js
|
|
5764
|
+
var EFFORTS = new Set(BRIDGE_EFFORT_ORDER);
|
|
5765
|
+
function toBridgeEffort(reasoning) {
|
|
5766
|
+
return typeof reasoning === "string" && EFFORTS.has(reasoning) ? reasoning : void 0;
|
|
5767
|
+
}
|
|
5768
|
+
|
|
5769
|
+
// ../bridge-core/dist/errors.js
|
|
5770
|
+
var SECRET_PATTERNS = [
|
|
5771
|
+
/(authorization\s*[:=]\s*)(bearer\s+)?[^\s,;"']+/gi,
|
|
5772
|
+
/(bearer\s+)[A-Za-z0-9._~+/=$-]{12,}/gi,
|
|
5773
|
+
/\b(ksk_|devin-session-token\$|sk-)[A-Za-z0-9._~+/=$-]{8,}/g
|
|
5774
|
+
];
|
|
5775
|
+
function formatErrorMessage(error2) {
|
|
5776
|
+
let text = error2 instanceof Error ? error2.message || error2.name : String(error2);
|
|
5777
|
+
for (const pattern of SECRET_PATTERNS) {
|
|
5778
|
+
text = text.replace(pattern, (_match, prefix) => `${prefix ?? ""}[redacted]`);
|
|
5636
5779
|
}
|
|
5637
|
-
|
|
5780
|
+
return text;
|
|
5638
5781
|
}
|
|
5639
|
-
|
|
5640
|
-
|
|
5641
|
-
|
|
5642
|
-
cacheRead: 0,
|
|
5643
|
-
cacheWrite: 0,
|
|
5644
|
-
totalTokens: 0,
|
|
5645
|
-
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 }
|
|
5646
|
-
});
|
|
5647
|
-
function toKiroModel(model, region) {
|
|
5648
|
-
const known = getCachedModels(region).find((candidate) => candidate.id === model.id);
|
|
5782
|
+
|
|
5783
|
+
// ../bridge-core/dist/pi/stream.js
|
|
5784
|
+
function zeroPiUsage() {
|
|
5649
5785
|
return {
|
|
5650
|
-
|
|
5651
|
-
|
|
5652
|
-
|
|
5653
|
-
|
|
5654
|
-
|
|
5655
|
-
|
|
5656
|
-
// resolution instead of being short-circuited by a value that is really
|
|
5657
|
-
// just `model.id` again.
|
|
5658
|
-
kiroModelId: model.kiroModelId ?? "",
|
|
5659
|
-
name: model.name,
|
|
5660
|
-
reasoning: model.reasoning,
|
|
5661
|
-
input: [...model.input],
|
|
5662
|
-
cost: { ...model.cost },
|
|
5663
|
-
contextWindow: model.contextWindow ?? 2e5,
|
|
5664
|
-
maxTokens: model.maxTokens ?? 8192
|
|
5665
|
-
},
|
|
5666
|
-
region,
|
|
5667
|
-
...model.kiroProfileArn ? { profileArn: model.kiroProfileArn } : {},
|
|
5668
|
-
...model.additionalModelRequestFieldsSchema ? { additionalModelRequestFieldsSchema: model.additionalModelRequestFieldsSchema } : {}
|
|
5786
|
+
input: 0,
|
|
5787
|
+
output: 0,
|
|
5788
|
+
cacheRead: 0,
|
|
5789
|
+
cacheWrite: 0,
|
|
5790
|
+
totalTokens: 0,
|
|
5791
|
+
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 }
|
|
5669
5792
|
};
|
|
5670
5793
|
}
|
|
5671
|
-
function
|
|
5672
|
-
|
|
5794
|
+
function applyBridgeUsage(target, usage) {
|
|
5795
|
+
target.input = usage.input;
|
|
5796
|
+
target.output = usage.output;
|
|
5797
|
+
target.totalTokens = usage.totalTokens;
|
|
5798
|
+
target.cacheRead = usage.cacheRead ?? 0;
|
|
5799
|
+
target.cacheWrite = usage.cacheWrite ?? 0;
|
|
5800
|
+
target.cost = { ...usage.cost };
|
|
5801
|
+
if (usage.contextPercent !== void 0)
|
|
5802
|
+
target.contextPercent = usage.contextPercent;
|
|
5803
|
+
if (usage.credits !== void 0)
|
|
5804
|
+
target.credits = usage.credits;
|
|
5805
|
+
if (usage.creditUnit !== void 0)
|
|
5806
|
+
target.creditUnit = usage.creditUnit;
|
|
5807
|
+
if (usage.cacheEstimated !== void 0)
|
|
5808
|
+
target.cacheEstimated = usage.cacheEstimated;
|
|
5809
|
+
}
|
|
5810
|
+
function streamToPi(options) {
|
|
5811
|
+
const stream = options.createStream();
|
|
5812
|
+
const formatError = options.formatError ?? formatErrorMessage;
|
|
5813
|
+
const discardOnReset = options.discardOnReset ?? true;
|
|
5814
|
+
const output = {
|
|
5815
|
+
role: "assistant",
|
|
5816
|
+
content: [],
|
|
5817
|
+
api: options.model.api,
|
|
5818
|
+
provider: options.model.provider,
|
|
5819
|
+
model: options.model.id,
|
|
5820
|
+
usage: zeroPiUsage(),
|
|
5821
|
+
stopReason: "stop",
|
|
5822
|
+
timestamp: Date.now()
|
|
5823
|
+
};
|
|
5673
5824
|
(async () => {
|
|
5674
|
-
const output = {
|
|
5675
|
-
role: "assistant",
|
|
5676
|
-
content: [],
|
|
5677
|
-
api: model.api,
|
|
5678
|
-
provider: model.provider,
|
|
5679
|
-
model: model.id,
|
|
5680
|
-
usage: ZERO_USAGE(),
|
|
5681
|
-
stopReason: "stop",
|
|
5682
|
-
timestamp: Date.now()
|
|
5683
|
-
};
|
|
5684
5825
|
try {
|
|
5685
|
-
const hostKey = typeof options?.apiKey === "string" ? options.apiKey : void 0;
|
|
5686
|
-
const credentials = await resolveRequestCredentials(hostKey);
|
|
5687
5826
|
let indexes = /* @__PURE__ */ new Map();
|
|
5688
5827
|
const open = (coreIndex, block) => {
|
|
5689
5828
|
const contentIndex = output.content.length;
|
|
@@ -5692,121 +5831,114 @@ function streamKiroForOmp(model, context, options) {
|
|
|
5692
5831
|
return contentIndex;
|
|
5693
5832
|
};
|
|
5694
5833
|
const at = (coreIndex) => indexes.get(coreIndex);
|
|
5695
|
-
|
|
5696
|
-
|
|
5697
|
-
|
|
5698
|
-
|
|
5699
|
-
|
|
5700
|
-
|
|
5701
|
-
|
|
5702
|
-
|
|
5703
|
-
sessionId: options?.sessionId,
|
|
5704
|
-
signal: options?.signal,
|
|
5705
|
-
profileArn: model.kiroProfileArn ?? credentials.profileArn,
|
|
5706
|
-
// OMP renders from `partial`, so discarding blocks is a matter of
|
|
5707
|
-
// truncating the array the renderer already reads.
|
|
5708
|
-
canDiscardEmittedBlocks: true
|
|
5709
|
-
})) {
|
|
5834
|
+
let started = false;
|
|
5835
|
+
const start = () => {
|
|
5836
|
+
if (started)
|
|
5837
|
+
return;
|
|
5838
|
+
started = true;
|
|
5839
|
+
stream.push({ type: "start", partial: output });
|
|
5840
|
+
};
|
|
5841
|
+
for await (const event of await options.events()) {
|
|
5710
5842
|
switch (event.type) {
|
|
5711
5843
|
case "start":
|
|
5712
|
-
|
|
5844
|
+
start();
|
|
5713
5845
|
break;
|
|
5714
5846
|
case "reset":
|
|
5715
|
-
|
|
5716
|
-
|
|
5847
|
+
if (discardOnReset) {
|
|
5848
|
+
output.content = [];
|
|
5849
|
+
indexes = /* @__PURE__ */ new Map();
|
|
5850
|
+
}
|
|
5717
5851
|
break;
|
|
5718
5852
|
case "text_start": {
|
|
5853
|
+
start();
|
|
5719
5854
|
const contentIndex = open(event.index, { type: "text", text: "" });
|
|
5720
5855
|
stream.push({ type: "text_start", contentIndex, partial: output });
|
|
5721
5856
|
break;
|
|
5722
5857
|
}
|
|
5723
5858
|
case "text_delta": {
|
|
5724
5859
|
const contentIndex = at(event.index);
|
|
5725
|
-
if (contentIndex === void 0)
|
|
5860
|
+
if (contentIndex === void 0)
|
|
5861
|
+
break;
|
|
5726
5862
|
output.content[contentIndex].text += event.delta;
|
|
5727
5863
|
stream.push({ type: "text_delta", contentIndex, delta: event.delta, partial: output });
|
|
5728
5864
|
break;
|
|
5729
5865
|
}
|
|
5730
5866
|
case "text_end": {
|
|
5731
5867
|
const contentIndex = at(event.index);
|
|
5732
|
-
if (contentIndex === void 0)
|
|
5868
|
+
if (contentIndex === void 0)
|
|
5869
|
+
break;
|
|
5733
5870
|
output.content[contentIndex].text = event.text;
|
|
5734
5871
|
stream.push({ type: "text_end", contentIndex, content: event.text, partial: output });
|
|
5735
5872
|
break;
|
|
5736
5873
|
}
|
|
5737
5874
|
case "thinking_start": {
|
|
5875
|
+
start();
|
|
5738
5876
|
const contentIndex = open(event.index, { type: "thinking", thinking: "" });
|
|
5739
5877
|
stream.push({ type: "thinking_start", contentIndex, partial: output });
|
|
5740
5878
|
break;
|
|
5741
5879
|
}
|
|
5742
5880
|
case "thinking_delta": {
|
|
5743
5881
|
const contentIndex = at(event.index);
|
|
5744
|
-
if (contentIndex === void 0)
|
|
5882
|
+
if (contentIndex === void 0)
|
|
5883
|
+
break;
|
|
5745
5884
|
output.content[contentIndex].thinking += event.delta;
|
|
5746
5885
|
stream.push({ type: "thinking_delta", contentIndex, delta: event.delta, partial: output });
|
|
5747
5886
|
break;
|
|
5748
5887
|
}
|
|
5749
5888
|
case "thinking_end": {
|
|
5750
5889
|
const contentIndex = at(event.index);
|
|
5751
|
-
if (contentIndex === void 0)
|
|
5890
|
+
if (contentIndex === void 0)
|
|
5891
|
+
break;
|
|
5752
5892
|
const block = output.content[contentIndex];
|
|
5753
5893
|
block.thinking = event.thinking;
|
|
5754
|
-
if (event.signature)
|
|
5894
|
+
if (event.signature)
|
|
5895
|
+
block.thinkingSignature = event.signature;
|
|
5755
5896
|
stream.push({ type: "thinking_end", contentIndex, content: event.thinking, partial: output });
|
|
5756
5897
|
break;
|
|
5757
5898
|
}
|
|
5758
5899
|
case "tool_call_start": {
|
|
5759
|
-
|
|
5760
|
-
const contentIndex = open(event.index, toolCall);
|
|
5900
|
+
start();
|
|
5901
|
+
const contentIndex = open(event.index, { type: "toolCall", id: event.id, name: event.name, arguments: {} });
|
|
5761
5902
|
stream.push({ type: "toolcall_start", contentIndex, partial: output });
|
|
5762
5903
|
break;
|
|
5763
5904
|
}
|
|
5764
5905
|
case "tool_call_delta": {
|
|
5765
5906
|
const contentIndex = at(event.index);
|
|
5766
|
-
if (contentIndex === void 0)
|
|
5907
|
+
if (contentIndex === void 0)
|
|
5908
|
+
break;
|
|
5767
5909
|
stream.push({ type: "toolcall_delta", contentIndex, delta: event.argumentsDelta, partial: output });
|
|
5768
5910
|
break;
|
|
5769
5911
|
}
|
|
5770
5912
|
case "tool_call_end": {
|
|
5771
5913
|
const contentIndex = at(event.index);
|
|
5772
|
-
if (contentIndex === void 0)
|
|
5914
|
+
if (contentIndex === void 0)
|
|
5915
|
+
break;
|
|
5773
5916
|
const toolCall = output.content[contentIndex];
|
|
5917
|
+
toolCall.name = event.name;
|
|
5774
5918
|
toolCall.arguments = event.arguments;
|
|
5775
5919
|
stream.push({ type: "toolcall_end", contentIndex, toolCall, partial: output });
|
|
5776
5920
|
break;
|
|
5777
5921
|
}
|
|
5778
|
-
case "usage":
|
|
5779
|
-
output.usage
|
|
5780
|
-
output.usage.output = event.usage.output;
|
|
5781
|
-
output.usage.totalTokens = event.usage.totalTokens;
|
|
5782
|
-
output.usage.cacheRead = event.usage.cacheRead ?? 0;
|
|
5783
|
-
output.usage.cacheWrite = event.usage.cacheWrite ?? 0;
|
|
5784
|
-
output.usage.cost = { ...event.usage.cost };
|
|
5785
|
-
if (event.usage.contextPercent !== void 0) {
|
|
5786
|
-
output.usage.contextPercent = event.usage.contextPercent;
|
|
5787
|
-
}
|
|
5788
|
-
if (event.usage.credits !== void 0) {
|
|
5789
|
-
output.usage.credits = event.usage.credits;
|
|
5790
|
-
}
|
|
5791
|
-
if (event.usage.creditUnit !== void 0) {
|
|
5792
|
-
output.usage.creditUnit = event.usage.creditUnit;
|
|
5793
|
-
}
|
|
5794
|
-
if (event.usage.cacheEstimated !== void 0) {
|
|
5795
|
-
output.usage.cacheEstimated = event.usage.cacheEstimated;
|
|
5796
|
-
}
|
|
5922
|
+
case "usage":
|
|
5923
|
+
applyBridgeUsage(output.usage, event.usage);
|
|
5797
5924
|
break;
|
|
5798
|
-
}
|
|
5799
5925
|
case "done":
|
|
5926
|
+
start();
|
|
5800
5927
|
output.stopReason = event.stopReason;
|
|
5801
|
-
if (event.
|
|
5928
|
+
if (event.responseId)
|
|
5929
|
+
output.responseId = event.responseId;
|
|
5930
|
+
if (event.upstreamModel && event.upstreamModel !== output.model)
|
|
5931
|
+
output.responseModel = event.upstreamModel;
|
|
5932
|
+
if (event.errorMessage)
|
|
5933
|
+
output.errorMessage = event.errorMessage;
|
|
5802
5934
|
stream.push({ type: "done", reason: event.stopReason, message: output });
|
|
5803
5935
|
break;
|
|
5804
5936
|
}
|
|
5805
5937
|
}
|
|
5806
5938
|
stream.end();
|
|
5807
5939
|
} catch (error2) {
|
|
5808
|
-
output.stopReason = options
|
|
5809
|
-
output.errorMessage =
|
|
5940
|
+
output.stopReason = options.signal?.aborted ? "aborted" : "error";
|
|
5941
|
+
output.errorMessage = formatError(error2);
|
|
5810
5942
|
stream.push({ type: "error", reason: output.stopReason, error: output });
|
|
5811
5943
|
stream.end();
|
|
5812
5944
|
}
|
|
@@ -5819,6 +5951,48 @@ function streamKiroForOmp(model, context, options) {
|
|
|
5819
5951
|
return stream;
|
|
5820
5952
|
}
|
|
5821
5953
|
|
|
5954
|
+
// src/stream.ts
|
|
5955
|
+
function newEventStream() {
|
|
5956
|
+
const runtime = PiAi;
|
|
5957
|
+
if (typeof runtime.AssistantMessageEventStream === "function") return new runtime.AssistantMessageEventStream();
|
|
5958
|
+
if (typeof runtime.createAssistantMessageEventStream === "function") {
|
|
5959
|
+
return runtime.createAssistantMessageEventStream();
|
|
5960
|
+
}
|
|
5961
|
+
throw new Error("This omp build exposes no AssistantMessageEventStream; omp-provider-kiro needs omp >= 18.1.");
|
|
5962
|
+
}
|
|
5963
|
+
function toKiroModel(model, region) {
|
|
5964
|
+
return toKiroModelForHost(model, region);
|
|
5965
|
+
}
|
|
5966
|
+
function streamKiroForOmp(model, context, options) {
|
|
5967
|
+
return streamToPi({
|
|
5968
|
+
model,
|
|
5969
|
+
createStream: newEventStream,
|
|
5970
|
+
signal: options?.signal,
|
|
5971
|
+
formatError: formatSafeError,
|
|
5972
|
+
// OMP renders from `partial`, so discarding blocks is a matter of
|
|
5973
|
+
// truncating the array the renderer already reads.
|
|
5974
|
+
discardOnReset: true,
|
|
5975
|
+
events: async () => {
|
|
5976
|
+
const hostKey = typeof options?.apiKey === "string" ? options.apiKey : void 0;
|
|
5977
|
+
const credentials = await resolveRequestCredentials(hostKey);
|
|
5978
|
+
const region = model.kiroRegion ?? getKiroRegionFromEndpoint(model.baseUrl) ?? credentials.region;
|
|
5979
|
+
const neutral = toBridgeContext(context);
|
|
5980
|
+
return streamKiro({
|
|
5981
|
+
model: toKiroModel(model, region),
|
|
5982
|
+
messages: neutral.messages,
|
|
5983
|
+
systemPrompt: neutral.systemPrompt,
|
|
5984
|
+
tools: neutral.tools,
|
|
5985
|
+
effort: toBridgeEffort(options?.reasoning),
|
|
5986
|
+
accessToken: credentials.accessToken,
|
|
5987
|
+
sessionId: options?.sessionId,
|
|
5988
|
+
signal: options?.signal,
|
|
5989
|
+
profileArn: model.kiroProfileArn ?? credentials.profileArn,
|
|
5990
|
+
canDiscardEmittedBlocks: true
|
|
5991
|
+
});
|
|
5992
|
+
}
|
|
5993
|
+
});
|
|
5994
|
+
}
|
|
5995
|
+
|
|
5822
5996
|
// src/usage.ts
|
|
5823
5997
|
function toUsageUnit(unit) {
|
|
5824
5998
|
switch (unit?.toLowerCase()) {
|
|
@@ -5960,8 +6134,8 @@ export {
|
|
|
5960
6134
|
index_default as default,
|
|
5961
6135
|
kiroUsageProvider,
|
|
5962
6136
|
streamKiroForOmp,
|
|
5963
|
-
toKiroMessages,
|
|
5964
|
-
toKiroTools,
|
|
6137
|
+
toBridgeMessages as toKiroMessages,
|
|
6138
|
+
toBridgeTools as toKiroTools,
|
|
5965
6139
|
toOmpModelConfig,
|
|
5966
6140
|
toUsageReport
|
|
5967
6141
|
};
|
package/dist/messages.d.ts
CHANGED
|
@@ -1,10 +1 @@
|
|
|
1
|
-
|
|
2
|
-
import type { KiroMessage, KiroTool } from "ns-kiro-core";
|
|
3
|
-
/**
|
|
4
|
-
* OMP carries block kinds this provider has no wire slot for — redacted
|
|
5
|
-
* thinking, Anthropic fallback markers, verbatim server-tool blocks. They are
|
|
6
|
-
* dropped rather than flattened into text: Kiro would read invented markup back
|
|
7
|
-
* as the model's own prior speech.
|
|
8
|
-
*/
|
|
9
|
-
export declare function toKiroMessages(messages: Message[]): KiroMessage[];
|
|
10
|
-
export declare function toKiroTools(tools: Tool[] | undefined): KiroTool[] | undefined;
|
|
1
|
+
export { toBridgeMessages as toKiroMessages, toBridgeTools as toKiroTools } from "ns-bridge-core/pi";
|
package/dist/stream.d.ts
CHANGED
|
@@ -7,18 +7,6 @@ export type KiroBackedModel = Model<Api> & {
|
|
|
7
7
|
kiroProfileArn?: string;
|
|
8
8
|
additionalModelRequestFieldsSchema?: Record<string, unknown>;
|
|
9
9
|
};
|
|
10
|
-
/**
|
|
11
|
-
* Rebuild the core's model descriptor from what OMP hands back at request time.
|
|
12
|
-
*
|
|
13
|
-
* OMP's registry keeps its own `Model`, built from the config this provider
|
|
14
|
-
* registered, so the catalog entry is looked up again here rather than carried
|
|
15
|
-
* through: the ladder and the request-fields schema decide effort mapping, and
|
|
16
|
-
* a request must use the same ones the catalog advertised.
|
|
17
|
-
*
|
|
18
|
-
* Looks up the region's authenticated cache, not the static bootstrap list:
|
|
19
|
-
* models discovered only through the authenticated catalog (no bootstrap
|
|
20
|
-
* entry) would otherwise miss this lookup and fall through to guessing a wire
|
|
21
|
-
* id from the dash-spelled local `id`, which Kiro rejects as `INVALID_MODEL_ID`.
|
|
22
|
-
*/
|
|
10
|
+
/** Rebuild the core's model descriptor from what OMP hands back at request time (see kiro-core). */
|
|
23
11
|
export declare function toKiroModel(model: KiroBackedModel, region: string): KiroModel;
|
|
24
12
|
export declare function streamKiroForOmp(model: Model<Api>, context: Context, options?: SimpleStreamOptions): AssistantMessageEventStream;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ns-omp-provider-kiro",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.9",
|
|
4
4
|
"description": "OMP (oh-my-pi) provider plugin: adds Kiro (AWS CodeWhisperer/Q) models via your kiro-cli login",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
"license": "MIT",
|
|
9
9
|
"repository": {
|
|
10
10
|
"type": "git",
|
|
11
|
-
"url": "git+https://github.com/ngosangns/ns-
|
|
11
|
+
"url": "git+https://github.com/ngosangns/ns-bridge.git",
|
|
12
12
|
"directory": "packages/omp-provider-kiro"
|
|
13
13
|
},
|
|
14
14
|
"keywords": [
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
"README.md"
|
|
38
38
|
],
|
|
39
39
|
"dependencies": {
|
|
40
|
-
"ns-kiro-core": "0.3.
|
|
40
|
+
"ns-kiro-core": "0.3.9"
|
|
41
41
|
},
|
|
42
42
|
"peerDependencies": {
|
|
43
43
|
"@oh-my-pi/pi-ai": ">=18.2.0",
|
|
@@ -54,7 +54,8 @@
|
|
|
54
54
|
"devDependencies": {
|
|
55
55
|
"@oh-my-pi/pi-ai": "18.2.7",
|
|
56
56
|
"@oh-my-pi/pi-coding-agent": "18.2.7",
|
|
57
|
-
"@types/node": "^22.20.4"
|
|
57
|
+
"@types/node": "^22.20.4",
|
|
58
|
+
"ns-bridge-core": "0.1.0"
|
|
58
59
|
},
|
|
59
60
|
"scripts": {
|
|
60
61
|
"build": "esbuild src/index.ts --bundle --platform=node --format=esm --outfile=dist/index.js --banner:js=\"import{createRequire as __kiroCreateRequire}from'node:module';const require=__kiroCreateRequire(import.meta.url);\" --external:@oh-my-pi/pi-ai --external:@oh-my-pi/pi-catalog --external:@oh-my-pi/pi-coding-agent --external:@oh-my-pi/pi-tui && tsc -p tsconfig.json --emitDeclarationOnly",
|