ns-omp-provider-kiro 0.3.7 → 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 +550 -171
- 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=";
|
|
@@ -3566,12 +3632,177 @@ function countTokens(text) {
|
|
|
3566
3632
|
return getEncoder().encode(text).length;
|
|
3567
3633
|
}
|
|
3568
3634
|
|
|
3635
|
+
// ../kiro-core/dist/tool-name-aliases.js
|
|
3636
|
+
var TOOL_NAME_ALIASES = {
|
|
3637
|
+
// read
|
|
3638
|
+
read_file: "read",
|
|
3639
|
+
readfile: "read",
|
|
3640
|
+
fs_read: "read",
|
|
3641
|
+
view_file: "read",
|
|
3642
|
+
// write
|
|
3643
|
+
write_file: "write",
|
|
3644
|
+
writefile: "write",
|
|
3645
|
+
fs_write: "write",
|
|
3646
|
+
create_file: "write",
|
|
3647
|
+
// edit
|
|
3648
|
+
edit_file: "edit",
|
|
3649
|
+
editfile: "edit",
|
|
3650
|
+
str_replace: "edit",
|
|
3651
|
+
str_replace_editor: "edit",
|
|
3652
|
+
str_replace_based_edit_tool: "edit",
|
|
3653
|
+
apply_patch: "edit",
|
|
3654
|
+
// ls
|
|
3655
|
+
list_directory: "ls",
|
|
3656
|
+
list_dir: "ls",
|
|
3657
|
+
list_files: "ls",
|
|
3658
|
+
// find
|
|
3659
|
+
find_files: "find",
|
|
3660
|
+
file_search: "find"
|
|
3661
|
+
};
|
|
3662
|
+
function normalizeKiroToolName(name, declared) {
|
|
3663
|
+
if (!declared || declared.size === 0 || declared.has(name))
|
|
3664
|
+
return name;
|
|
3665
|
+
const alias = TOOL_NAME_ALIASES[name.toLowerCase()];
|
|
3666
|
+
return alias !== void 0 && declared.has(alias) ? alias : name;
|
|
3667
|
+
}
|
|
3668
|
+
|
|
3669
|
+
// ../kiro-core/dist/tool-use-parser.js
|
|
3670
|
+
var TAG_NAMES = ["tool_use", "tool_call", "function_call", "tool"];
|
|
3671
|
+
var FENCE2 = "```";
|
|
3672
|
+
function nextTagBlock(text, from) {
|
|
3673
|
+
let best = null;
|
|
3674
|
+
for (const name of TAG_NAMES) {
|
|
3675
|
+
const open = `<${name}>`;
|
|
3676
|
+
const close = `</${name}>`;
|
|
3677
|
+
const openStart = text.indexOf(open, from);
|
|
3678
|
+
if (openStart < 0)
|
|
3679
|
+
continue;
|
|
3680
|
+
if (best && openStart >= best.openStart)
|
|
3681
|
+
continue;
|
|
3682
|
+
const bodyStart = openStart + open.length;
|
|
3683
|
+
const closeIdx = text.indexOf(close, bodyStart);
|
|
3684
|
+
if (closeIdx < 0)
|
|
3685
|
+
continue;
|
|
3686
|
+
best = { openStart, bodyStart, closeIdx, closeEnd: closeIdx + close.length };
|
|
3687
|
+
}
|
|
3688
|
+
return best;
|
|
3689
|
+
}
|
|
3690
|
+
function fencedRanges2(text) {
|
|
3691
|
+
const ranges = [];
|
|
3692
|
+
let searchFrom = 0;
|
|
3693
|
+
while (true) {
|
|
3694
|
+
const open = text.indexOf(FENCE2, searchFrom);
|
|
3695
|
+
if (open < 0)
|
|
3696
|
+
break;
|
|
3697
|
+
const close = text.indexOf(FENCE2, open + FENCE2.length);
|
|
3698
|
+
if (close < 0) {
|
|
3699
|
+
ranges.push({ start: open, end: text.length });
|
|
3700
|
+
break;
|
|
3701
|
+
}
|
|
3702
|
+
ranges.push({ start: open, end: close + FENCE2.length });
|
|
3703
|
+
searchFrom = close + FENCE2.length;
|
|
3704
|
+
}
|
|
3705
|
+
return ranges;
|
|
3706
|
+
}
|
|
3707
|
+
function normalizeOne(value) {
|
|
3708
|
+
if (typeof value !== "object" || value === null || Array.isArray(value))
|
|
3709
|
+
return null;
|
|
3710
|
+
const record = value;
|
|
3711
|
+
const rawName = record.tool_name ?? record.name;
|
|
3712
|
+
if (typeof rawName !== "string" || rawName.length === 0)
|
|
3713
|
+
return null;
|
|
3714
|
+
const rawArgs = record.tool_input ?? record.input ?? record.arguments;
|
|
3715
|
+
if (rawArgs === void 0) {
|
|
3716
|
+
return { name: rawName, arguments: {} };
|
|
3717
|
+
}
|
|
3718
|
+
if (typeof rawArgs !== "object" || rawArgs === null || Array.isArray(rawArgs))
|
|
3719
|
+
return null;
|
|
3720
|
+
return { name: rawName, arguments: rawArgs };
|
|
3721
|
+
}
|
|
3722
|
+
function extractDescriptors(value) {
|
|
3723
|
+
if (typeof value === "object" && value !== null && !Array.isArray(value)) {
|
|
3724
|
+
const record = value;
|
|
3725
|
+
const wrapped = record.tool_calls ?? record.calls;
|
|
3726
|
+
if (Array.isArray(wrapped)) {
|
|
3727
|
+
const out = [];
|
|
3728
|
+
for (const entry of wrapped) {
|
|
3729
|
+
const one = normalizeOne(entry);
|
|
3730
|
+
if (one === null)
|
|
3731
|
+
return [];
|
|
3732
|
+
out.push(one);
|
|
3733
|
+
}
|
|
3734
|
+
return out;
|
|
3735
|
+
}
|
|
3736
|
+
}
|
|
3737
|
+
const single = normalizeOne(value);
|
|
3738
|
+
return single ? [single] : [];
|
|
3739
|
+
}
|
|
3740
|
+
function parseToolUseCalls(text) {
|
|
3741
|
+
const toolCalls = [];
|
|
3742
|
+
const removals = [];
|
|
3743
|
+
const fences = fencedRanges2(text);
|
|
3744
|
+
let cursor = 0;
|
|
3745
|
+
while (cursor < text.length) {
|
|
3746
|
+
const hit = nextTagBlock(text, cursor);
|
|
3747
|
+
if (hit === null)
|
|
3748
|
+
break;
|
|
3749
|
+
const { openStart, bodyStart, closeIdx, closeEnd } = hit;
|
|
3750
|
+
const containingFence = fences.find((range) => openStart >= range.start && openStart < range.end);
|
|
3751
|
+
if (containingFence) {
|
|
3752
|
+
cursor = containingFence.end;
|
|
3753
|
+
continue;
|
|
3754
|
+
}
|
|
3755
|
+
const braceStart = text.indexOf("{", bodyStart);
|
|
3756
|
+
if (braceStart < 0 || braceStart > closeIdx) {
|
|
3757
|
+
cursor = closeEnd;
|
|
3758
|
+
continue;
|
|
3759
|
+
}
|
|
3760
|
+
const braceEnd = findJsonEnd(text, braceStart);
|
|
3761
|
+
if (braceEnd < 0 || braceEnd > closeIdx) {
|
|
3762
|
+
cursor = closeEnd;
|
|
3763
|
+
continue;
|
|
3764
|
+
}
|
|
3765
|
+
const beforeJson = text.substring(bodyStart, braceStart).trim();
|
|
3766
|
+
const afterJson = text.substring(braceEnd + 1, closeIdx).trim();
|
|
3767
|
+
if (beforeJson.length > 0 || afterJson.length > 0) {
|
|
3768
|
+
cursor = closeEnd;
|
|
3769
|
+
continue;
|
|
3770
|
+
}
|
|
3771
|
+
let descriptors = [];
|
|
3772
|
+
try {
|
|
3773
|
+
descriptors = extractDescriptors(JSON.parse(text.substring(braceStart, braceEnd + 1)));
|
|
3774
|
+
} catch {
|
|
3775
|
+
descriptors = [];
|
|
3776
|
+
}
|
|
3777
|
+
if (descriptors.length === 0) {
|
|
3778
|
+
cursor = closeEnd;
|
|
3779
|
+
continue;
|
|
3780
|
+
}
|
|
3781
|
+
for (const descriptor of descriptors) {
|
|
3782
|
+
toolCalls.push({
|
|
3783
|
+
toolUseId: crypto.randomUUID(),
|
|
3784
|
+
name: descriptor.name,
|
|
3785
|
+
arguments: descriptor.arguments
|
|
3786
|
+
});
|
|
3787
|
+
}
|
|
3788
|
+
removals.push({ start: openStart, end: closeEnd });
|
|
3789
|
+
cursor = closeEnd;
|
|
3790
|
+
}
|
|
3791
|
+
let cleanedText = text;
|
|
3792
|
+
for (let i = removals.length - 1; i >= 0; i--) {
|
|
3793
|
+
const { start, end } = removals[i];
|
|
3794
|
+
cleanedText = cleanedText.substring(0, start) + cleanedText.substring(end);
|
|
3795
|
+
}
|
|
3796
|
+
return { toolCalls, cleanedText };
|
|
3797
|
+
}
|
|
3798
|
+
|
|
3569
3799
|
// ../kiro-core/dist/response-assembler.js
|
|
3570
3800
|
var ECHO_NOISE_PATTERN = /^\s*(continue|\.+)\s*$/i;
|
|
3571
3801
|
var KiroResponseAssembler = class {
|
|
3572
3802
|
model;
|
|
3573
3803
|
thinkingEnabled;
|
|
3574
3804
|
toolNameAliases;
|
|
3805
|
+
declaredToolNames;
|
|
3575
3806
|
pending = [];
|
|
3576
3807
|
blocks = new KiroBlockBuffer((event) => this.pending.push(event));
|
|
3577
3808
|
usage = {
|
|
@@ -3581,7 +3812,6 @@ var KiroResponseAssembler = class {
|
|
|
3581
3812
|
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 }
|
|
3582
3813
|
};
|
|
3583
3814
|
totalContent = "";
|
|
3584
|
-
lastContentData = "";
|
|
3585
3815
|
usageEvent = null;
|
|
3586
3816
|
meteringEvent = null;
|
|
3587
3817
|
receivedContextUsage = false;
|
|
@@ -3594,18 +3824,19 @@ var KiroResponseAssembler = class {
|
|
|
3594
3824
|
droppedToolCalls = [];
|
|
3595
3825
|
currentToolCall = null;
|
|
3596
3826
|
stopReason = "stop";
|
|
3597
|
-
constructor(model, thinkingEnabled, toolNameAliases) {
|
|
3827
|
+
constructor(model, thinkingEnabled, toolNameAliases, declaredToolNames) {
|
|
3598
3828
|
this.model = model;
|
|
3599
3829
|
this.thinkingEnabled = thinkingEnabled;
|
|
3600
3830
|
this.toolNameAliases = toolNameAliases;
|
|
3831
|
+
this.declaredToolNames = declaredToolNames;
|
|
3601
3832
|
}
|
|
3833
|
+
/** Wire name -> the name the host registered, then alias repair. */
|
|
3602
3834
|
originalToolName(name) {
|
|
3603
|
-
return this.toolNameAliases?.get(name) ?? name;
|
|
3835
|
+
return normalizeKiroToolName(this.toolNameAliases?.get(name) ?? name, this.declaredToolNames);
|
|
3604
3836
|
}
|
|
3605
3837
|
/** Clear per-attempt state. Only block indexes are kept. */
|
|
3606
3838
|
beginAttempt() {
|
|
3607
3839
|
this.totalContent = "";
|
|
3608
|
-
this.lastContentData = "";
|
|
3609
3840
|
this.usageEvent = null;
|
|
3610
3841
|
this.meteringEvent = null;
|
|
3611
3842
|
this.receivedContextUsage = false;
|
|
@@ -3661,10 +3892,9 @@ var KiroResponseAssembler = class {
|
|
|
3661
3892
|
break;
|
|
3662
3893
|
}
|
|
3663
3894
|
case "content": {
|
|
3664
|
-
|
|
3665
|
-
if (event.data === this.lastContentData)
|
|
3895
|
+
if (event.data === "")
|
|
3666
3896
|
break;
|
|
3667
|
-
this.
|
|
3897
|
+
this.endNativeThinking();
|
|
3668
3898
|
this.totalContent += event.data;
|
|
3669
3899
|
if (this.thinkingParser) {
|
|
3670
3900
|
this.thinkingParser.processChunk(event.data);
|
|
@@ -3703,6 +3933,14 @@ var KiroResponseAssembler = class {
|
|
|
3703
3933
|
}
|
|
3704
3934
|
case "usage": {
|
|
3705
3935
|
this.usageEvent = { ...this.usageEvent ?? {}, ...event.data };
|
|
3936
|
+
const pct = event.data.contextUsagePercentage;
|
|
3937
|
+
if (pct !== void 0) {
|
|
3938
|
+
if (this.usageEvent.inputTokens === void 0) {
|
|
3939
|
+
this.usage.input = Math.round(pct / 100 * this.model.contextWindow);
|
|
3940
|
+
}
|
|
3941
|
+
this.usage.contextPercent = pct;
|
|
3942
|
+
this.receivedContextUsage = true;
|
|
3943
|
+
}
|
|
3706
3944
|
if (debugEnabled())
|
|
3707
3945
|
debugLog("response.usageRaw", payload);
|
|
3708
3946
|
break;
|
|
@@ -3736,7 +3974,18 @@ var KiroResponseAssembler = class {
|
|
|
3736
3974
|
this.stripEchoNoise();
|
|
3737
3975
|
const responseText = this.textBlockIndex === null ? "" : this.blocks.getText(this.textBlockIndex);
|
|
3738
3976
|
const hasText2 = responseText.length > 0;
|
|
3739
|
-
|
|
3977
|
+
const wireStopReason = this.usageEvent?.rawStopReason;
|
|
3978
|
+
switch (wireStopReason) {
|
|
3979
|
+
case "MAX_TOKENS":
|
|
3980
|
+
this.stopReason = "length";
|
|
3981
|
+
break;
|
|
3982
|
+
case "END_TURN":
|
|
3983
|
+
case "TOOL_USE":
|
|
3984
|
+
this.stopReason = this.emittedToolCalls > 0 ? "toolUse" : "stop";
|
|
3985
|
+
break;
|
|
3986
|
+
default:
|
|
3987
|
+
this.stopReason = !this.receivedContextUsage && this.emittedToolCalls === 0 ? "length" : this.emittedToolCalls > 0 ? "toolUse" : "stop";
|
|
3988
|
+
}
|
|
3740
3989
|
return {
|
|
3741
3990
|
responseText,
|
|
3742
3991
|
hasText: hasText2,
|
|
@@ -3745,7 +3994,9 @@ var KiroResponseAssembler = class {
|
|
|
3745
3994
|
isEchoLoop: hasText2 && !this.sawAnyToolCalls && ECHO_NOISE_PATTERN.test(responseText),
|
|
3746
3995
|
isEmpty: !hasText2 && !this.sawAnyToolCalls,
|
|
3747
3996
|
stopReason: this.stopReason,
|
|
3748
|
-
droppedToolCalls: this.droppedToolCalls
|
|
3997
|
+
droppedToolCalls: this.droppedToolCalls,
|
|
3998
|
+
...wireStopReason !== void 0 ? { wireStopReason } : {},
|
|
3999
|
+
...this.usageEvent?.stopDetails !== void 0 ? { wireStopDetails: this.usageEvent.stopDetails } : {}
|
|
3749
4000
|
};
|
|
3750
4001
|
}
|
|
3751
4002
|
/** Drop an echo the caller decided not to retry, so it is not read as a continuation signal. */
|
|
@@ -3829,10 +4080,14 @@ var KiroResponseAssembler = class {
|
|
|
3829
4080
|
}
|
|
3830
4081
|
/**
|
|
3831
4082
|
* Extract text-dialect tool calls from content when no native tool calls
|
|
3832
|
-
* arrived.
|
|
4083
|
+
* arrived. Three dialects are recovered at this seam:
|
|
3833
4084
|
* 1. Kiro's own `[Called name with args: {...}]` bracket form.
|
|
3834
4085
|
* 2. Anthropic's `<invoke name="..."><parameter .../></invoke>` XML form,
|
|
3835
4086
|
* which opus-class models emit as plain text at high context.
|
|
4087
|
+
* 3. A JSON descriptor wrapped in `<tool_use>`, `<tool_call>`,
|
|
4088
|
+
* `<function_call>` or `<tool>` tags (upstream #163), spelled
|
|
4089
|
+
* `tool_name`/`tool_input`, `name`/`input` or `name`/`arguments`,
|
|
4090
|
+
* or wrapped in a `{"tool_calls": [...]}` array.
|
|
3836
4091
|
* Without this, the turn ends `stop` with zero tool calls — the agent loop
|
|
3837
4092
|
* sees a finished answer and an unattended session stalls with no error
|
|
3838
4093
|
* recorded anywhere.
|
|
@@ -3859,6 +4114,11 @@ var KiroResponseAssembler = class {
|
|
|
3859
4114
|
text = invokeResult.cleanedText;
|
|
3860
4115
|
recovered.push(...invokeResult.toolCalls);
|
|
3861
4116
|
}
|
|
4117
|
+
const toolUseResult = parseToolUseCalls(text);
|
|
4118
|
+
if (toolUseResult.toolCalls.length > 0) {
|
|
4119
|
+
text = toolUseResult.cleanedText;
|
|
4120
|
+
recovered.push(...toolUseResult.toolCalls);
|
|
4121
|
+
}
|
|
3862
4122
|
if (recovered.length === 0)
|
|
3863
4123
|
return;
|
|
3864
4124
|
this.blocks.setText(this.textBlockIndex, text);
|
|
@@ -4909,6 +5169,16 @@ function describeReturnedContent(kinds) {
|
|
|
4909
5169
|
}
|
|
4910
5170
|
var skipProfileResolutionForTests = false;
|
|
4911
5171
|
var TEST_PROFILE_ARN = "arn:aws:codewhisperer:us-east-1:000000000000:profile/test";
|
|
5172
|
+
function throwOnTerminalWireStop(wireStopReason, stopDetails) {
|
|
5173
|
+
switch (wireStopReason) {
|
|
5174
|
+
case "MODEL_CONTEXT_WINDOW_EXCEEDED":
|
|
5175
|
+
throw new Error("Kiro API error: context_length_exceeded (MODEL_CONTEXT_WINDOW_EXCEEDED)");
|
|
5176
|
+
case "CONTENT_FILTERED":
|
|
5177
|
+
throw new Error(`Kiro content filtered: ${clampForDiagnostic(redactSensitiveText(JSON.stringify(stopDetails ?? {})))}`);
|
|
5178
|
+
case "PAUSE_TURN":
|
|
5179
|
+
throw new Error("Kiro paused the turn (PAUSE_TURN); automatic continuation is not supported");
|
|
5180
|
+
}
|
|
5181
|
+
}
|
|
4912
5182
|
async function* streamKiro(request) {
|
|
4913
5183
|
const { model, signal } = request;
|
|
4914
5184
|
const initialAccessToken = request.accessToken;
|
|
@@ -4967,7 +5237,7 @@ async function* streamKiro(request) {
|
|
|
4967
5237
|
systemPrompt = `<thinking_mode>enabled</thinking_mode><max_thinking_length>${budget}</max_thinking_length>${systemPrompt ? `
|
|
4968
5238
|
${systemPrompt}` : ""}`;
|
|
4969
5239
|
}
|
|
4970
|
-
const assembler = new KiroResponseAssembler(model, thinkingEnabled, kiroToolNameAliases(request.tools));
|
|
5240
|
+
const assembler = new KiroResponseAssembler(model, thinkingEnabled, kiroToolNameAliases(request.tools), new Set((request.tools ?? []).map((tool) => String(tool.name))));
|
|
4971
5241
|
const usageTracking = request.usageTracking ?? KIRO_USAGE_TRACKING_DISABLED;
|
|
4972
5242
|
let retryCount = 0;
|
|
4973
5243
|
const maxRetries = 3;
|
|
@@ -5151,6 +5421,7 @@ ${systemPrompt}` : ""}`;
|
|
|
5151
5421
|
throw new Error(`Kiro API error: ${outcome.firstTokenTimedOut ? "first token" : "idle"} timeout after max retries`);
|
|
5152
5422
|
}
|
|
5153
5423
|
const summary = assembler.endTurn();
|
|
5424
|
+
throwOnTerminalWireStop(summary.wireStopReason, summary.wireStopDetails);
|
|
5154
5425
|
yield* assembler.takeEvents();
|
|
5155
5426
|
const degenerate = summary.isEmpty || summary.isEchoLoop;
|
|
5156
5427
|
if (summary.isEchoLoop)
|
|
@@ -5288,23 +5559,8 @@ async function fetchKiroUsage(credentials) {
|
|
|
5288
5559
|
}
|
|
5289
5560
|
|
|
5290
5561
|
// src/auth.ts
|
|
5291
|
-
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.";
|
|
5292
5562
|
async function loginKiro(callbacks) {
|
|
5293
|
-
|
|
5294
|
-
const existing = await resolveKiroCredentials();
|
|
5295
|
-
if (existing) {
|
|
5296
|
-
callbacks.onProgress?.(`Using the ${existing.authMethod} session from kiro-cli.`);
|
|
5297
|
-
return existing;
|
|
5298
|
-
}
|
|
5299
|
-
if (!callbacks.onPrompt) throw new Error(NO_SESSION_MESSAGE);
|
|
5300
|
-
const apiKey = (await callbacks.onPrompt({
|
|
5301
|
-
message: NO_SESSION_MESSAGE,
|
|
5302
|
-
placeholder: "ksk_\u2026",
|
|
5303
|
-
allowEmpty: true,
|
|
5304
|
-
secret: true
|
|
5305
|
-
})).trim();
|
|
5306
|
-
if (!apiKey) throw new Error(NO_SESSION_MESSAGE);
|
|
5307
|
-
return await loginKiroWithApiKey(apiKey, callbacks.onProgress);
|
|
5563
|
+
return await loginKiroFromSession(callbacks);
|
|
5308
5564
|
}
|
|
5309
5565
|
async function refreshKiroCredentials(credentials) {
|
|
5310
5566
|
return await refreshKiroToken(credentials);
|
|
@@ -5312,22 +5568,7 @@ async function refreshKiroCredentials(credentials) {
|
|
|
5312
5568
|
function getKiroApiKey(credentials) {
|
|
5313
5569
|
return credentials.access;
|
|
5314
5570
|
}
|
|
5315
|
-
|
|
5316
|
-
const stored = await resolveKiroCredentials();
|
|
5317
|
-
const region = resolveApiRegion(stored?.region);
|
|
5318
|
-
if (hostKey && (isApiKey(hostKey) || hostKey === stored?.access)) {
|
|
5319
|
-
return { accessToken: hostKey, region, ...stored?.profileArn ? { profileArn: stored.profileArn } : {} };
|
|
5320
|
-
}
|
|
5321
|
-
if (stored) {
|
|
5322
|
-
return {
|
|
5323
|
-
accessToken: stored.access,
|
|
5324
|
-
region,
|
|
5325
|
-
...stored.profileArn ? { profileArn: stored.profileArn } : {}
|
|
5326
|
-
};
|
|
5327
|
-
}
|
|
5328
|
-
if (hostKey) return { accessToken: hostKey, region };
|
|
5329
|
-
throw new Error("Kiro credentials not set. Run `kiro-cli login`, or set KIRO_API_KEY to a `ksk_` API key.");
|
|
5330
|
-
}
|
|
5571
|
+
var resolveRequestCredentials = resolveKiroRequestCredentials;
|
|
5331
5572
|
|
|
5332
5573
|
// src/models.ts
|
|
5333
5574
|
function toOmpModelConfig(model) {
|
|
@@ -5359,22 +5600,81 @@ function kiroBaseUrl(region) {
|
|
|
5359
5600
|
// src/stream.ts
|
|
5360
5601
|
import * as PiAi from "@oh-my-pi/pi-ai";
|
|
5361
5602
|
|
|
5362
|
-
//
|
|
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
|
|
5363
5646
|
function userContent(content) {
|
|
5364
|
-
if (typeof content === "string")
|
|
5647
|
+
if (typeof content === "string")
|
|
5648
|
+
return content ? [{ type: "text", text: content }] : [];
|
|
5649
|
+
if (!Array.isArray(content))
|
|
5650
|
+
return [];
|
|
5365
5651
|
const out = [];
|
|
5366
5652
|
for (const block of content) {
|
|
5367
|
-
if (block
|
|
5368
|
-
|
|
5369
|
-
|
|
5370
|
-
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") });
|
|
5371
5657
|
}
|
|
5372
5658
|
}
|
|
5373
5659
|
return out;
|
|
5374
5660
|
}
|
|
5375
|
-
|
|
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) {
|
|
5376
5674
|
const out = [];
|
|
5377
5675
|
for (const message of messages) {
|
|
5676
|
+
if (message.role === "system")
|
|
5677
|
+
continue;
|
|
5378
5678
|
if (message.role === "user" || message.role === "developer") {
|
|
5379
5679
|
out.push({ role: "user", content: userContent(message.content) });
|
|
5380
5680
|
continue;
|
|
@@ -5382,103 +5682,147 @@ function toKiroMessages(messages) {
|
|
|
5382
5682
|
if (message.role === "toolResult") {
|
|
5383
5683
|
out.push({
|
|
5384
5684
|
role: "toolResult",
|
|
5385
|
-
toolCallId: message.toolCallId,
|
|
5386
|
-
toolName: message.toolName,
|
|
5685
|
+
toolCallId: String(message.toolCallId ?? ""),
|
|
5686
|
+
toolName: String(message.toolName ?? "tool"),
|
|
5387
5687
|
content: userContent(message.content),
|
|
5388
|
-
isError: message.isError
|
|
5688
|
+
isError: message.isError === true
|
|
5389
5689
|
});
|
|
5390
5690
|
continue;
|
|
5391
5691
|
}
|
|
5692
|
+
if (message.role !== "assistant")
|
|
5693
|
+
continue;
|
|
5392
5694
|
const content = [];
|
|
5393
|
-
for (const block of message.content) {
|
|
5394
|
-
if (block
|
|
5395
|
-
|
|
5396
|
-
|
|
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") {
|
|
5397
5699
|
content.push({
|
|
5398
5700
|
type: "thinking",
|
|
5399
|
-
thinking:
|
|
5400
|
-
...
|
|
5701
|
+
thinking: block.thinking,
|
|
5702
|
+
...typeof block.thinkingSignature === "string" && block.thinkingSignature ? { thinkingSignature: block.thinkingSignature } : {}
|
|
5401
5703
|
});
|
|
5402
|
-
} else if (block
|
|
5403
|
-
const call = block;
|
|
5704
|
+
} else if (block?.type === "toolCall") {
|
|
5404
5705
|
content.push({
|
|
5405
5706
|
type: "toolCall",
|
|
5406
|
-
id:
|
|
5407
|
-
name:
|
|
5408
|
-
arguments:
|
|
5707
|
+
id: String(block.id ?? ""),
|
|
5708
|
+
name: String(block.name ?? ""),
|
|
5709
|
+
arguments: parseArguments(block.arguments)
|
|
5409
5710
|
});
|
|
5410
5711
|
}
|
|
5411
5712
|
}
|
|
5412
|
-
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
|
+
});
|
|
5413
5719
|
}
|
|
5414
5720
|
return out;
|
|
5415
5721
|
}
|
|
5416
|
-
function
|
|
5417
|
-
if (!tools?.length)
|
|
5722
|
+
function toBridgeTools(tools) {
|
|
5723
|
+
if (!tools?.length)
|
|
5724
|
+
return void 0;
|
|
5418
5725
|
return tools.map((tool) => ({
|
|
5419
5726
|
name: tool.name,
|
|
5420
|
-
description: tool.description,
|
|
5421
|
-
parameters: tool.parameters
|
|
5727
|
+
description: tool.description ?? "",
|
|
5728
|
+
parameters: tool.parameters ?? { type: "object", properties: {} },
|
|
5729
|
+
...tool.strict !== void 0 ? { strict: tool.strict } : {}
|
|
5422
5730
|
}));
|
|
5423
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
|
+
}
|
|
5424
5759
|
|
|
5425
|
-
//
|
|
5426
|
-
|
|
5427
|
-
|
|
5428
|
-
|
|
5429
|
-
|
|
5430
|
-
|
|
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]`);
|
|
5431
5779
|
}
|
|
5432
|
-
|
|
5780
|
+
return text;
|
|
5433
5781
|
}
|
|
5434
|
-
|
|
5435
|
-
|
|
5436
|
-
|
|
5437
|
-
cacheRead: 0,
|
|
5438
|
-
cacheWrite: 0,
|
|
5439
|
-
totalTokens: 0,
|
|
5440
|
-
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 }
|
|
5441
|
-
});
|
|
5442
|
-
function toKiroModel(model, region) {
|
|
5443
|
-
const known = getCachedModels(region).find((candidate) => candidate.id === model.id);
|
|
5782
|
+
|
|
5783
|
+
// ../bridge-core/dist/pi/stream.js
|
|
5784
|
+
function zeroPiUsage() {
|
|
5444
5785
|
return {
|
|
5445
|
-
|
|
5446
|
-
|
|
5447
|
-
|
|
5448
|
-
|
|
5449
|
-
|
|
5450
|
-
|
|
5451
|
-
// resolution instead of being short-circuited by a value that is really
|
|
5452
|
-
// just `model.id` again.
|
|
5453
|
-
kiroModelId: model.kiroModelId ?? "",
|
|
5454
|
-
name: model.name,
|
|
5455
|
-
reasoning: model.reasoning,
|
|
5456
|
-
input: [...model.input],
|
|
5457
|
-
cost: { ...model.cost },
|
|
5458
|
-
contextWindow: model.contextWindow ?? 2e5,
|
|
5459
|
-
maxTokens: model.maxTokens ?? 8192
|
|
5460
|
-
},
|
|
5461
|
-
region,
|
|
5462
|
-
...model.kiroProfileArn ? { profileArn: model.kiroProfileArn } : {},
|
|
5463
|
-
...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 }
|
|
5464
5792
|
};
|
|
5465
5793
|
}
|
|
5466
|
-
function
|
|
5467
|
-
|
|
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
|
+
};
|
|
5468
5824
|
(async () => {
|
|
5469
|
-
const output = {
|
|
5470
|
-
role: "assistant",
|
|
5471
|
-
content: [],
|
|
5472
|
-
api: model.api,
|
|
5473
|
-
provider: model.provider,
|
|
5474
|
-
model: model.id,
|
|
5475
|
-
usage: ZERO_USAGE(),
|
|
5476
|
-
stopReason: "stop",
|
|
5477
|
-
timestamp: Date.now()
|
|
5478
|
-
};
|
|
5479
5825
|
try {
|
|
5480
|
-
const hostKey = typeof options?.apiKey === "string" ? options.apiKey : void 0;
|
|
5481
|
-
const credentials = await resolveRequestCredentials(hostKey);
|
|
5482
5826
|
let indexes = /* @__PURE__ */ new Map();
|
|
5483
5827
|
const open = (coreIndex, block) => {
|
|
5484
5828
|
const contentIndex = output.content.length;
|
|
@@ -5487,121 +5831,114 @@ function streamKiroForOmp(model, context, options) {
|
|
|
5487
5831
|
return contentIndex;
|
|
5488
5832
|
};
|
|
5489
5833
|
const at = (coreIndex) => indexes.get(coreIndex);
|
|
5490
|
-
|
|
5491
|
-
|
|
5492
|
-
|
|
5493
|
-
|
|
5494
|
-
|
|
5495
|
-
|
|
5496
|
-
|
|
5497
|
-
|
|
5498
|
-
sessionId: options?.sessionId,
|
|
5499
|
-
signal: options?.signal,
|
|
5500
|
-
profileArn: model.kiroProfileArn ?? credentials.profileArn,
|
|
5501
|
-
// OMP renders from `partial`, so discarding blocks is a matter of
|
|
5502
|
-
// truncating the array the renderer already reads.
|
|
5503
|
-
canDiscardEmittedBlocks: true
|
|
5504
|
-
})) {
|
|
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()) {
|
|
5505
5842
|
switch (event.type) {
|
|
5506
5843
|
case "start":
|
|
5507
|
-
|
|
5844
|
+
start();
|
|
5508
5845
|
break;
|
|
5509
5846
|
case "reset":
|
|
5510
|
-
|
|
5511
|
-
|
|
5847
|
+
if (discardOnReset) {
|
|
5848
|
+
output.content = [];
|
|
5849
|
+
indexes = /* @__PURE__ */ new Map();
|
|
5850
|
+
}
|
|
5512
5851
|
break;
|
|
5513
5852
|
case "text_start": {
|
|
5853
|
+
start();
|
|
5514
5854
|
const contentIndex = open(event.index, { type: "text", text: "" });
|
|
5515
5855
|
stream.push({ type: "text_start", contentIndex, partial: output });
|
|
5516
5856
|
break;
|
|
5517
5857
|
}
|
|
5518
5858
|
case "text_delta": {
|
|
5519
5859
|
const contentIndex = at(event.index);
|
|
5520
|
-
if (contentIndex === void 0)
|
|
5860
|
+
if (contentIndex === void 0)
|
|
5861
|
+
break;
|
|
5521
5862
|
output.content[contentIndex].text += event.delta;
|
|
5522
5863
|
stream.push({ type: "text_delta", contentIndex, delta: event.delta, partial: output });
|
|
5523
5864
|
break;
|
|
5524
5865
|
}
|
|
5525
5866
|
case "text_end": {
|
|
5526
5867
|
const contentIndex = at(event.index);
|
|
5527
|
-
if (contentIndex === void 0)
|
|
5868
|
+
if (contentIndex === void 0)
|
|
5869
|
+
break;
|
|
5528
5870
|
output.content[contentIndex].text = event.text;
|
|
5529
5871
|
stream.push({ type: "text_end", contentIndex, content: event.text, partial: output });
|
|
5530
5872
|
break;
|
|
5531
5873
|
}
|
|
5532
5874
|
case "thinking_start": {
|
|
5875
|
+
start();
|
|
5533
5876
|
const contentIndex = open(event.index, { type: "thinking", thinking: "" });
|
|
5534
5877
|
stream.push({ type: "thinking_start", contentIndex, partial: output });
|
|
5535
5878
|
break;
|
|
5536
5879
|
}
|
|
5537
5880
|
case "thinking_delta": {
|
|
5538
5881
|
const contentIndex = at(event.index);
|
|
5539
|
-
if (contentIndex === void 0)
|
|
5882
|
+
if (contentIndex === void 0)
|
|
5883
|
+
break;
|
|
5540
5884
|
output.content[contentIndex].thinking += event.delta;
|
|
5541
5885
|
stream.push({ type: "thinking_delta", contentIndex, delta: event.delta, partial: output });
|
|
5542
5886
|
break;
|
|
5543
5887
|
}
|
|
5544
5888
|
case "thinking_end": {
|
|
5545
5889
|
const contentIndex = at(event.index);
|
|
5546
|
-
if (contentIndex === void 0)
|
|
5890
|
+
if (contentIndex === void 0)
|
|
5891
|
+
break;
|
|
5547
5892
|
const block = output.content[contentIndex];
|
|
5548
5893
|
block.thinking = event.thinking;
|
|
5549
|
-
if (event.signature)
|
|
5894
|
+
if (event.signature)
|
|
5895
|
+
block.thinkingSignature = event.signature;
|
|
5550
5896
|
stream.push({ type: "thinking_end", contentIndex, content: event.thinking, partial: output });
|
|
5551
5897
|
break;
|
|
5552
5898
|
}
|
|
5553
5899
|
case "tool_call_start": {
|
|
5554
|
-
|
|
5555
|
-
const contentIndex = open(event.index, toolCall);
|
|
5900
|
+
start();
|
|
5901
|
+
const contentIndex = open(event.index, { type: "toolCall", id: event.id, name: event.name, arguments: {} });
|
|
5556
5902
|
stream.push({ type: "toolcall_start", contentIndex, partial: output });
|
|
5557
5903
|
break;
|
|
5558
5904
|
}
|
|
5559
5905
|
case "tool_call_delta": {
|
|
5560
5906
|
const contentIndex = at(event.index);
|
|
5561
|
-
if (contentIndex === void 0)
|
|
5907
|
+
if (contentIndex === void 0)
|
|
5908
|
+
break;
|
|
5562
5909
|
stream.push({ type: "toolcall_delta", contentIndex, delta: event.argumentsDelta, partial: output });
|
|
5563
5910
|
break;
|
|
5564
5911
|
}
|
|
5565
5912
|
case "tool_call_end": {
|
|
5566
5913
|
const contentIndex = at(event.index);
|
|
5567
|
-
if (contentIndex === void 0)
|
|
5914
|
+
if (contentIndex === void 0)
|
|
5915
|
+
break;
|
|
5568
5916
|
const toolCall = output.content[contentIndex];
|
|
5917
|
+
toolCall.name = event.name;
|
|
5569
5918
|
toolCall.arguments = event.arguments;
|
|
5570
5919
|
stream.push({ type: "toolcall_end", contentIndex, toolCall, partial: output });
|
|
5571
5920
|
break;
|
|
5572
5921
|
}
|
|
5573
|
-
case "usage":
|
|
5574
|
-
output.usage
|
|
5575
|
-
output.usage.output = event.usage.output;
|
|
5576
|
-
output.usage.totalTokens = event.usage.totalTokens;
|
|
5577
|
-
output.usage.cacheRead = event.usage.cacheRead ?? 0;
|
|
5578
|
-
output.usage.cacheWrite = event.usage.cacheWrite ?? 0;
|
|
5579
|
-
output.usage.cost = { ...event.usage.cost };
|
|
5580
|
-
if (event.usage.contextPercent !== void 0) {
|
|
5581
|
-
output.usage.contextPercent = event.usage.contextPercent;
|
|
5582
|
-
}
|
|
5583
|
-
if (event.usage.credits !== void 0) {
|
|
5584
|
-
output.usage.credits = event.usage.credits;
|
|
5585
|
-
}
|
|
5586
|
-
if (event.usage.creditUnit !== void 0) {
|
|
5587
|
-
output.usage.creditUnit = event.usage.creditUnit;
|
|
5588
|
-
}
|
|
5589
|
-
if (event.usage.cacheEstimated !== void 0) {
|
|
5590
|
-
output.usage.cacheEstimated = event.usage.cacheEstimated;
|
|
5591
|
-
}
|
|
5922
|
+
case "usage":
|
|
5923
|
+
applyBridgeUsage(output.usage, event.usage);
|
|
5592
5924
|
break;
|
|
5593
|
-
}
|
|
5594
5925
|
case "done":
|
|
5926
|
+
start();
|
|
5595
5927
|
output.stopReason = event.stopReason;
|
|
5596
|
-
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;
|
|
5597
5934
|
stream.push({ type: "done", reason: event.stopReason, message: output });
|
|
5598
5935
|
break;
|
|
5599
5936
|
}
|
|
5600
5937
|
}
|
|
5601
5938
|
stream.end();
|
|
5602
5939
|
} catch (error2) {
|
|
5603
|
-
output.stopReason = options
|
|
5604
|
-
output.errorMessage =
|
|
5940
|
+
output.stopReason = options.signal?.aborted ? "aborted" : "error";
|
|
5941
|
+
output.errorMessage = formatError(error2);
|
|
5605
5942
|
stream.push({ type: "error", reason: output.stopReason, error: output });
|
|
5606
5943
|
stream.end();
|
|
5607
5944
|
}
|
|
@@ -5614,6 +5951,48 @@ function streamKiroForOmp(model, context, options) {
|
|
|
5614
5951
|
return stream;
|
|
5615
5952
|
}
|
|
5616
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
|
+
|
|
5617
5996
|
// src/usage.ts
|
|
5618
5997
|
function toUsageUnit(unit) {
|
|
5619
5998
|
switch (unit?.toLowerCase()) {
|
|
@@ -5755,8 +6134,8 @@ export {
|
|
|
5755
6134
|
index_default as default,
|
|
5756
6135
|
kiroUsageProvider,
|
|
5757
6136
|
streamKiroForOmp,
|
|
5758
|
-
toKiroMessages,
|
|
5759
|
-
toKiroTools,
|
|
6137
|
+
toBridgeMessages as toKiroMessages,
|
|
6138
|
+
toBridgeTools as toKiroTools,
|
|
5760
6139
|
toOmpModelConfig,
|
|
5761
6140
|
toUsageReport
|
|
5762
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",
|