@sunerpy/opencode-kiro-auth 0.13.3 → 0.13.5

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.
@@ -75,22 +75,26 @@ export class RequestHandler {
75
75
  else
76
76
  inboundSignal?.addEventListener('abort', abortFromInbound, { once: true });
77
77
  let timeout;
78
- const refreshRequestDeadline = () => {
78
+ const beginUpstreamWait = (phase, timeoutMs) => {
79
79
  if (requestController.signal.aborted)
80
80
  return;
81
81
  if (timeout)
82
82
  clearDeadlineTimeout(timeout);
83
- timeout = setDeadlineTimeout(() => requestController.abort(new DOMException('Kiro request timed out', 'TimeoutError')), this.config.request_timeout_ms);
83
+ timeout = setDeadlineTimeout(() => requestController.abort(new DOMException(`Kiro request timed out waiting for ${phase}`, 'TimeoutError')), timeoutMs);
84
+ };
85
+ const endUpstreamWait = () => {
86
+ if (!timeout)
87
+ return;
88
+ clearDeadlineTimeout(timeout);
89
+ timeout = undefined;
84
90
  };
85
- refreshRequestDeadline();
86
91
  let requestCleanupDone = false;
87
92
  let responseOwnsLifecycle = false;
88
93
  const cleanupRequest = () => {
89
94
  if (requestCleanupDone)
90
95
  return;
91
96
  requestCleanupDone = true;
92
- if (timeout)
93
- clearDeadlineTimeout(timeout);
97
+ endUpstreamWait();
94
98
  inboundSignal?.removeEventListener('abort', abortFromInbound);
95
99
  };
96
100
  const signal = requestController.signal;
@@ -196,15 +200,22 @@ export class RequestHandler {
196
200
  this.handleSuccessfulRequest(acc);
197
201
  await this.usageTracker.syncUsage(acc, auth, isCurrentAttempt);
198
202
  };
199
- const sdkResponse = await client.send(command, { abortSignal: signal });
203
+ let sdkResponse;
204
+ beginUpstreamWait('SDK response', this.config.sdk_response_timeout_ms);
205
+ try {
206
+ sdkResponse = await client.send(command, { abortSignal: signal });
207
+ }
208
+ finally {
209
+ endUpstreamWait();
210
+ }
200
211
  sendResolved = true;
201
- refreshRequestDeadline();
202
212
  if (apiTimestamp) {
203
213
  this.logSdkResponse(sdkPrep, apiTimestamp);
204
214
  }
205
215
  const response = await this.responseHandler.handleSdkSuccess(sdkResponse, model, sdkPrep.conversationId, sdkPrep.streaming, {
206
216
  signal,
207
- onActivity: refreshRequestDeadline,
217
+ onUpstreamWaitStart: () => beginUpstreamWait('stream event', this.config.request_timeout_ms),
218
+ onUpstreamWaitEnd: endUpstreamWait,
208
219
  onComplete: completeRequest,
209
220
  onTerminal: cleanupRequest,
210
221
  onCancel: (reason) => requestController.abort(reason),
@@ -1,7 +1,8 @@
1
1
  import { SdkEventStreamIterationError } from './stream-error.js';
2
2
  export interface SdkResponseLifecycle {
3
3
  signal?: AbortSignal;
4
- onActivity?: () => void;
4
+ onUpstreamWaitStart?: () => void;
5
+ onUpstreamWaitEnd?: () => void;
5
6
  onComplete?: () => void | Promise<void>;
6
7
  onTerminal?: () => void;
7
8
  onCancel?: (reason: unknown) => void;
@@ -11,7 +11,7 @@ async function closeIterator(iterator) {
11
11
  }
12
12
  catch { }
13
13
  }
14
- function wrapSdkEventStream(sdkResponse, signal, onActivity) {
14
+ function wrapSdkEventStream(sdkResponse, signal, onUpstreamWaitStart, onUpstreamWaitEnd) {
15
15
  const eventStream = sdkResponse.generateAssistantResponseResponse;
16
16
  if (!eventStream || typeof eventStream[Symbol.asyncIterator] !== 'function') {
17
17
  return { response: sdkResponse, closeRaw: async () => { } };
@@ -25,33 +25,34 @@ function wrapSdkEventStream(sdkResponse, signal, onActivity) {
25
25
  await closeIterator(rawIterator);
26
26
  };
27
27
  const nextRaw = async () => {
28
- const recordActivity = (result) => {
29
- if (!result.done)
30
- onActivity?.();
31
- return result;
32
- };
33
- if (!signal)
34
- return rawIterator.next().then(recordActivity);
35
- if (signal.aborted) {
28
+ if (signal?.aborted) {
36
29
  await closeRaw();
37
30
  throw abortReason(signal);
38
31
  }
39
- return new Promise((resolve, reject) => {
40
- let settled = false;
41
- const settle = (callback) => {
42
- if (settled)
43
- return;
44
- settled = true;
45
- signal.removeEventListener('abort', onAbort);
46
- callback();
47
- };
48
- const onAbort = () => {
49
- void closeRaw();
50
- settle(() => reject(abortReason(signal)));
51
- };
52
- signal.addEventListener('abort', onAbort, { once: true });
53
- Promise.resolve(rawIterator.next()).then((result) => settle(() => resolve(recordActivity(result))), (error) => settle(() => reject(error)));
54
- });
32
+ onUpstreamWaitStart?.();
33
+ try {
34
+ if (!signal)
35
+ return await rawIterator.next();
36
+ return await new Promise((resolve, reject) => {
37
+ let settled = false;
38
+ const settle = (callback) => {
39
+ if (settled)
40
+ return;
41
+ settled = true;
42
+ signal.removeEventListener('abort', onAbort);
43
+ callback();
44
+ };
45
+ const onAbort = () => {
46
+ void closeRaw();
47
+ settle(() => reject(abortReason(signal)));
48
+ };
49
+ signal.addEventListener('abort', onAbort, { once: true });
50
+ Promise.resolve(rawIterator.next()).then((result) => settle(() => resolve(result)), (error) => settle(() => reject(error)));
51
+ });
52
+ }
53
+ finally {
54
+ onUpstreamWaitEnd?.();
55
+ }
55
56
  };
56
57
  const wrappedIterator = {
57
58
  async next() {
@@ -118,7 +119,7 @@ export class ResponseHandler {
118
119
  }), { headers: { 'Content-Type': 'text/event-stream' } });
119
120
  }
120
121
  async handleSdkStreaming(sdkResponse, model, conversationId, lifecycle) {
121
- const wrapped = wrapSdkEventStream(sdkResponse, lifecycle.signal, lifecycle.onActivity);
122
+ const wrapped = wrapSdkEventStream(sdkResponse, lifecycle.signal, lifecycle.onUpstreamWaitStart, lifecycle.onUpstreamWaitEnd);
122
123
  const transformed = transformSdkStream(wrapped.response, model, conversationId);
123
124
  const buffered = [];
124
125
  let firstSemantic;
@@ -227,7 +228,7 @@ export class ResponseHandler {
227
228
  const toolCalls = [];
228
229
  let inputTokens = 0;
229
230
  let outputTokens = 0;
230
- const wrapped = wrapSdkEventStream(sdkResponse, lifecycle.signal, lifecycle.onActivity);
231
+ const wrapped = wrapSdkEventStream(sdkResponse, lifecycle.signal, lifecycle.onUpstreamWaitStart, lifecycle.onUpstreamWaitEnd);
231
232
  const eventStream = wrapped.response.generateAssistantResponseResponse;
232
233
  if (eventStream) {
233
234
  try {
@@ -1,10 +1,8 @@
1
1
  interface RetryConfig {
2
2
  max_request_iterations: number;
3
- request_timeout_ms: number;
4
3
  }
5
4
  interface RetryContext {
6
5
  iterations: number;
7
- startTime: number;
8
6
  }
9
7
  export declare class RetryStrategy {
10
8
  private config;
@@ -11,18 +11,11 @@ export class RetryStrategy {
11
11
  error: `Exceeded max iterations (${this.config.max_request_iterations})`
12
12
  };
13
13
  }
14
- if (Date.now() - context.startTime > this.config.request_timeout_ms) {
15
- return {
16
- canContinue: false,
17
- error: 'Request timeout'
18
- };
19
- }
20
14
  return { canContinue: true };
21
15
  }
22
16
  createContext() {
23
17
  return {
24
- iterations: 0,
25
- startTime: Date.now()
18
+ iterations: 0
26
19
  };
27
20
  }
28
21
  }
@@ -135,6 +135,7 @@ function applyEnvOverrides(config) {
135
135
  rate_limit_retry_delay_ms: parseNumberEnv(env.KIRO_RATE_LIMIT_RETRY_DELAY_MS, config.rate_limit_retry_delay_ms),
136
136
  rate_limit_max_retries: parseNumberEnv(env.KIRO_RATE_LIMIT_MAX_RETRIES, config.rate_limit_max_retries),
137
137
  max_request_iterations: parseNumberEnv(env.KIRO_MAX_REQUEST_ITERATIONS, config.max_request_iterations),
138
+ sdk_response_timeout_ms: parseNumberEnv(env.KIRO_SDK_RESPONSE_TIMEOUT_MS, config.sdk_response_timeout_ms),
138
139
  request_timeout_ms: parseNumberEnv(env.KIRO_REQUEST_TIMEOUT_MS, config.request_timeout_ms),
139
140
  token_expiry_buffer_ms: parseNumberEnv(env.KIRO_TOKEN_EXPIRY_BUFFER_MS, config.token_expiry_buffer_ms),
140
141
  usage_sync_max_retries: parseNumberEnv(env.KIRO_USAGE_SYNC_MAX_RETRIES, config.usage_sync_max_retries),
@@ -55,6 +55,15 @@ export declare const KiroConfigSchema: z.ZodObject<{
55
55
  rate_limit_retry_delay_ms: z.ZodDefault<z.ZodNumber>;
56
56
  rate_limit_max_retries: z.ZodDefault<z.ZodNumber>;
57
57
  max_request_iterations: z.ZodDefault<z.ZodNumber>;
58
+ /**
59
+ * Maximum wait for client.send() to return the initial SDK response.
60
+ * High-effort models can legitimately take several minutes before the
61
+ * event stream becomes available.
62
+ */
63
+ sdk_response_timeout_ms: z.ZodDefault<z.ZodNumber>;
64
+ /**
65
+ * Maximum inactivity while waiting for the next upstream stream event.
66
+ */
58
67
  request_timeout_ms: z.ZodDefault<z.ZodNumber>;
59
68
  token_expiry_buffer_ms: z.ZodDefault<z.ZodNumber>;
60
69
  /**
@@ -104,6 +113,7 @@ export declare const KiroConfigSchema: z.ZodObject<{
104
113
  rate_limit_retry_delay_ms: number;
105
114
  rate_limit_max_retries: number;
106
115
  max_request_iterations: number;
116
+ sdk_response_timeout_ms: number;
107
117
  request_timeout_ms: number;
108
118
  token_expiry_buffer_ms: number;
109
119
  token_keepalive_enabled: boolean;
@@ -137,6 +147,7 @@ export declare const KiroConfigSchema: z.ZodObject<{
137
147
  rate_limit_retry_delay_ms?: number | undefined;
138
148
  rate_limit_max_retries?: number | undefined;
139
149
  max_request_iterations?: number | undefined;
150
+ sdk_response_timeout_ms?: number | undefined;
140
151
  request_timeout_ms?: number | undefined;
141
152
  token_expiry_buffer_ms?: number | undefined;
142
153
  token_keepalive_enabled?: boolean | undefined;
@@ -87,6 +87,15 @@ export const KiroConfigSchema = z.object({
87
87
  rate_limit_retry_delay_ms: z.number().min(1000).max(60000).default(5000),
88
88
  rate_limit_max_retries: z.number().min(0).max(10).default(3),
89
89
  max_request_iterations: z.number().min(5).max(1000).default(20),
90
+ /**
91
+ * Maximum wait for client.send() to return the initial SDK response.
92
+ * High-effort models can legitimately take several minutes before the
93
+ * event stream becomes available.
94
+ */
95
+ sdk_response_timeout_ms: z.number().min(30000).max(600000).default(300000),
96
+ /**
97
+ * Maximum inactivity while waiting for the next upstream stream event.
98
+ */
90
99
  request_timeout_ms: z.number().min(30000).max(600000).default(120000),
91
100
  token_expiry_buffer_ms: z.number().min(30000).max(300000).default(300000),
92
101
  /**
@@ -137,6 +146,7 @@ export const DEFAULT_CONFIG = {
137
146
  rate_limit_retry_delay_ms: 5000,
138
147
  rate_limit_max_retries: 3,
139
148
  max_request_iterations: 20,
149
+ sdk_response_timeout_ms: 300000,
140
150
  request_timeout_ms: 120000,
141
151
  token_expiry_buffer_ms: 300000,
142
152
  token_keepalive_enabled: false,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sunerpy/opencode-kiro-auth",
3
- "version": "0.13.3",
3
+ "version": "0.13.5",
4
4
  "description": "OpenCode plugin for AWS Kiro (CodeWhisperer) providing access to Claude models",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",