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 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-kiro-provider.git
21
- cd ns-kiro-provider && pnpm install && pnpm -r build
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
- Part of [ns-kiro-provider](https://github.com/ngosangns/ns-kiro-provider).
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
- * v0.1 establishes no browser flow of its own. Every interactive method Kiro
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
- /** The token, region, and profile one request runs on. */
12
- export interface ResolvedKiroRequestCredentials {
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
- this.endNativeThinking();
3665
- if (event.data === this.lastContentData)
3895
+ if (event.data === "")
3666
3896
  break;
3667
- this.lastContentData = event.data;
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
- this.stopReason = !this.receivedContextUsage && this.emittedToolCalls === 0 ? "length" : this.emittedToolCalls > 0 ? "toolUse" : "stop";
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. Two dialects are recovered at this seam:
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
- callbacks.onProgress?.("Looking for an existing Kiro session\u2026");
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
- async function resolveRequestCredentials(hostKey) {
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
- // src/messages.ts
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") return content ? [{ type: "text", text: content }] : [];
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.type === "text") out.push({ type: "text", text: block.text });
5368
- else if (block.type === "image") {
5369
- const image = block;
5370
- out.push({ type: "image", data: image.data, mimeType: image.mimeType });
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
- function toKiroMessages(messages) {
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.type === "text") content.push({ type: "text", text: block.text });
5395
- else if (block.type === "thinking") {
5396
- const thinking = block;
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: thinking.thinking,
5400
- ...thinking.thinkingSignature ? { thinkingSignature: thinking.thinkingSignature } : {}
5701
+ thinking: block.thinking,
5702
+ ...typeof block.thinkingSignature === "string" && block.thinkingSignature ? { thinkingSignature: block.thinkingSignature } : {}
5401
5703
  });
5402
- } else if (block.type === "toolCall") {
5403
- const call = block;
5704
+ } else if (block?.type === "toolCall") {
5404
5705
  content.push({
5405
5706
  type: "toolCall",
5406
- id: call.id,
5407
- name: call.name,
5408
- arguments: typeof call.arguments === "string" ? JSON.parse(call.arguments) : call.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({ role: "assistant", content, stopReason: message.stopReason });
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 toKiroTools(tools) {
5417
- if (!tools?.length) return void 0;
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
- // src/stream.ts
5426
- function newEventStream() {
5427
- const runtime = PiAi;
5428
- if (typeof runtime.AssistantMessageEventStream === "function") return new runtime.AssistantMessageEventStream();
5429
- if (typeof runtime.createAssistantMessageEventStream === "function") {
5430
- return runtime.createAssistantMessageEventStream();
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
- throw new Error("This omp build exposes no AssistantMessageEventStream; omp-provider-kiro needs omp >= 18.1.");
5780
+ return text;
5433
5781
  }
5434
- var ZERO_USAGE = () => ({
5435
- input: 0,
5436
- output: 0,
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
- ...known ?? {
5446
- id: model.id,
5447
- // No fallback to `model.id`: that dash-spelled local id is not a valid
5448
- // Kiro wire id. Falls back to `""` rather than `model.id` — falsy, so
5449
- // `resolveKiroModel`'s `if (exactKiroModelId) return exactKiroModelId`
5450
- // treats it as no override and runs its own cache/bootstrap/dot-normalize
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 streamKiroForOmp(model, context, options) {
5467
- const stream = newEventStream();
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
- const region = model.kiroRegion ?? getKiroRegionFromEndpoint(model.baseUrl) ?? credentials.region;
5491
- for await (const event of streamKiro({
5492
- model: toKiroModel(model, region),
5493
- messages: toKiroMessages(context.messages),
5494
- systemPrompt: context.systemPrompt?.join("\n\n"),
5495
- tools: toKiroTools(context.tools),
5496
- effort: options?.reasoning,
5497
- accessToken: credentials.accessToken,
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
- stream.push({ type: "start", partial: output });
5844
+ start();
5508
5845
  break;
5509
5846
  case "reset":
5510
- output.content = [];
5511
- indexes = /* @__PURE__ */ new Map();
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) break;
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) break;
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) break;
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) break;
5890
+ if (contentIndex === void 0)
5891
+ break;
5547
5892
  const block = output.content[contentIndex];
5548
5893
  block.thinking = event.thinking;
5549
- if (event.signature) block.thinkingSignature = 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
- const toolCall = { type: "toolCall", id: event.id, name: event.name, arguments: {} };
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) break;
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) break;
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.input = event.usage.input;
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.errorMessage) output.errorMessage = event.errorMessage;
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?.signal?.aborted ? "aborted" : "error";
5604
- output.errorMessage = formatSafeError(error2);
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
  };
@@ -1,10 +1 @@
1
- import type { Message, Tool } from "@oh-my-pi/pi-ai";
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.7",
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-kiro-provider.git",
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.7"
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",