@sunerpy/opencode-kiro-auth 0.13.7 → 0.13.8

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.
@@ -14,6 +14,19 @@ import { RetryStrategy } from './retry-strategy.js';
14
14
  import { SdkEventStreamIterationError, UpstreamUnexpectedError } from './stream-error.js';
15
15
  const KIRO_API_PATTERN = /^(https?:\/\/)?q\.[a-z0-9-]+\.amazonaws\.com/;
16
16
  const REAUTH_FAILURE_COOLDOWN_MS = 60000;
17
+ function describeError(error, depth = 0) {
18
+ if (!(error instanceof Error))
19
+ return String(error);
20
+ const code = error.code;
21
+ return {
22
+ name: error.name,
23
+ message: error.message,
24
+ ...(code !== undefined ? { code } : {}),
25
+ ...(depth < 2 && error.cause !== undefined
26
+ ? { cause: describeError(error.cause, depth + 1) }
27
+ : {})
28
+ };
29
+ }
17
30
  export class RequestHandler {
18
31
  accountManager;
19
32
  config;
@@ -244,6 +257,15 @@ export class RequestHandler {
244
257
  region: sdkPrep.region
245
258
  }),
246
259
  onUpstreamWaitEnd: endUpstreamWait,
260
+ onIterationError: (error, afterCompletionMetadata) => logger.warn('Kiro SDK event stream iteration failed', {
261
+ model,
262
+ effectiveModel: sdkPrep.effectiveModel,
263
+ region: sdkPrep.region,
264
+ platform: process.platform,
265
+ afterCompletionMetadata,
266
+ recovered: afterCompletionMetadata,
267
+ error: describeError(error)
268
+ }),
247
269
  onComplete: completeRequest,
248
270
  onTerminal: cleanupRequest,
249
271
  onCancel: (reason) => requestController.abort(reason),
@@ -3,6 +3,7 @@ export interface SdkResponseLifecycle {
3
3
  signal?: AbortSignal;
4
4
  onUpstreamWaitStart?: () => void;
5
5
  onUpstreamWaitEnd?: () => void;
6
+ onIterationError?: (error: unknown, afterCompletionMetadata: boolean) => void;
6
7
  onComplete?: () => void | Promise<void>;
7
8
  onTerminal?: () => void;
8
9
  onCancel?: (reason: unknown) => void;
@@ -11,13 +11,22 @@ async function closeIterator(iterator) {
11
11
  }
12
12
  catch { }
13
13
  }
14
- function wrapSdkEventStream(sdkResponse, signal, onUpstreamWaitStart, onUpstreamWaitEnd) {
14
+ function isCompletionMetadataEvent(event) {
15
+ if (typeof event !== 'object' || event === null || !('metadataEvent' in event))
16
+ return false;
17
+ const metadata = event.metadataEvent;
18
+ if (typeof metadata !== 'object' || metadata === null || !('tokenUsage' in metadata))
19
+ return false;
20
+ return typeof metadata.tokenUsage === 'object' && metadata.tokenUsage !== null;
21
+ }
22
+ function wrapSdkEventStream(sdkResponse, signal, onUpstreamWaitStart, onUpstreamWaitEnd, onIterationError) {
15
23
  const eventStream = sdkResponse.generateAssistantResponseResponse;
16
24
  if (!eventStream || typeof eventStream[Symbol.asyncIterator] !== 'function') {
17
25
  return { response: sdkResponse, closeRaw: async () => { } };
18
26
  }
19
27
  const rawIterator = eventStream[Symbol.asyncIterator]();
20
28
  let closed = false;
29
+ let completionMetadataSeen = false;
21
30
  const closeRaw = async () => {
22
31
  if (closed)
23
32
  return;
@@ -57,11 +66,20 @@ function wrapSdkEventStream(sdkResponse, signal, onUpstreamWaitStart, onUpstream
57
66
  const wrappedIterator = {
58
67
  async next() {
59
68
  try {
60
- return await nextRaw();
69
+ const result = await nextRaw();
70
+ if (!result.done && isCompletionMetadataEvent(result.value)) {
71
+ completionMetadataSeen = true;
72
+ }
73
+ return result;
61
74
  }
62
75
  catch (error) {
63
76
  if (signal?.aborted)
64
77
  throw abortReason(signal);
78
+ onIterationError?.(error, completionMetadataSeen);
79
+ if (completionMetadataSeen) {
80
+ await closeRaw();
81
+ return { done: true, value: undefined };
82
+ }
65
83
  throw new SdkEventStreamIterationError(error);
66
84
  }
67
85
  },
@@ -119,7 +137,7 @@ export class ResponseHandler {
119
137
  }), { headers: { 'Content-Type': 'text/event-stream' } });
120
138
  }
121
139
  async handleSdkStreaming(sdkResponse, model, conversationId, lifecycle) {
122
- const wrapped = wrapSdkEventStream(sdkResponse, lifecycle.signal, lifecycle.onUpstreamWaitStart, lifecycle.onUpstreamWaitEnd);
140
+ const wrapped = wrapSdkEventStream(sdkResponse, lifecycle.signal, lifecycle.onUpstreamWaitStart, lifecycle.onUpstreamWaitEnd, lifecycle.onIterationError);
123
141
  const transformed = transformSdkStream(wrapped.response, model, conversationId);
124
142
  const buffered = [];
125
143
  let firstSemantic;
@@ -228,7 +246,7 @@ export class ResponseHandler {
228
246
  const toolCalls = [];
229
247
  let inputTokens = 0;
230
248
  let outputTokens = 0;
231
- const wrapped = wrapSdkEventStream(sdkResponse, lifecycle.signal, lifecycle.onUpstreamWaitStart, lifecycle.onUpstreamWaitEnd);
249
+ const wrapped = wrapSdkEventStream(sdkResponse, lifecycle.signal, lifecycle.onUpstreamWaitStart, lifecycle.onUpstreamWaitEnd, lifecycle.onIterationError);
232
250
  const eventStream = wrapped.response.generateAssistantResponseResponse;
233
251
  if (eventStream) {
234
252
  try {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sunerpy/opencode-kiro-auth",
3
- "version": "0.13.7",
3
+ "version": "0.13.8",
4
4
  "description": "OpenCode plugin for AWS Kiro (CodeWhisperer) providing access to Claude models",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",