@open-mercato/ai-assistant 0.4.11-develop.2384.32517eccbc → 0.4.11-develop.2516.30653cfe18
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/dist/modules/ai_assistant/lib/api-discovery-tools.js +10 -2
- package/dist/modules/ai_assistant/lib/api-discovery-tools.js.map +2 -2
- package/dist/modules/ai_assistant/lib/api-endpoint-index.js +13 -2
- package/dist/modules/ai_assistant/lib/api-endpoint-index.js.map +2 -2
- package/dist/modules/ai_assistant/lib/codemode-tools.js +10 -2
- package/dist/modules/ai_assistant/lib/codemode-tools.js.map +2 -2
- package/dist/modules/ai_assistant/lib/opencode-client.js +73 -25
- package/dist/modules/ai_assistant/lib/opencode-client.js.map +2 -2
- package/package.json +4 -4
- package/src/modules/ai_assistant/lib/__tests__/opencode-client.test.ts +76 -0
- package/src/modules/ai_assistant/lib/api-discovery-tools.ts +11 -1
- package/src/modules/ai_assistant/lib/api-endpoint-index.ts +15 -2
- package/src/modules/ai_assistant/lib/codemode-tools.ts +11 -1
- package/src/modules/ai_assistant/lib/opencode-client.ts +64 -14
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { OpenCodeClient } from '../opencode-client'
|
|
2
|
+
|
|
3
|
+
describe('OpenCodeClient.subscribeToEvents', () => {
|
|
4
|
+
const originalFetch = global.fetch
|
|
5
|
+
let originalSseEnv: string | undefined
|
|
6
|
+
|
|
7
|
+
beforeEach(() => {
|
|
8
|
+
originalSseEnv = process.env.OPENCODE_SSE_CONNECT_TIMEOUT_MS
|
|
9
|
+
process.env.OPENCODE_SSE_CONNECT_TIMEOUT_MS = '25'
|
|
10
|
+
})
|
|
11
|
+
|
|
12
|
+
afterEach(() => {
|
|
13
|
+
global.fetch = originalFetch
|
|
14
|
+
if (originalSseEnv === undefined) {
|
|
15
|
+
delete process.env.OPENCODE_SSE_CONNECT_TIMEOUT_MS
|
|
16
|
+
} else {
|
|
17
|
+
process.env.OPENCODE_SSE_CONNECT_TIMEOUT_MS = originalSseEnv
|
|
18
|
+
}
|
|
19
|
+
})
|
|
20
|
+
|
|
21
|
+
const waitFor = async (predicate: () => boolean, timeoutMs = 500): Promise<void> => {
|
|
22
|
+
const deadline = Date.now() + timeoutMs
|
|
23
|
+
while (!predicate()) {
|
|
24
|
+
if (Date.now() > deadline) throw new Error('waitFor: predicate never became true')
|
|
25
|
+
await new Promise((r) => setTimeout(r, 10))
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
it('invokes onError with the connect-timeout reason when the deadline elapses before the SSE handshake', async () => {
|
|
30
|
+
global.fetch = jest.fn((_input, init) => {
|
|
31
|
+
return new Promise((_resolve, reject) => {
|
|
32
|
+
const signal = (init as RequestInit | undefined)?.signal
|
|
33
|
+
if (!signal) return
|
|
34
|
+
signal.addEventListener('abort', () => {
|
|
35
|
+
const err = new Error('Aborted')
|
|
36
|
+
;(err as Error & { name: string }).name = 'AbortError'
|
|
37
|
+
reject(err)
|
|
38
|
+
})
|
|
39
|
+
})
|
|
40
|
+
}) as unknown as typeof fetch
|
|
41
|
+
|
|
42
|
+
const client = new OpenCodeClient({ baseUrl: 'http://opencode.local' })
|
|
43
|
+
const onError = jest.fn()
|
|
44
|
+
|
|
45
|
+
client.subscribeToEvents(() => {}, onError)
|
|
46
|
+
|
|
47
|
+
await waitFor(() => onError.mock.calls.length > 0)
|
|
48
|
+
|
|
49
|
+
expect(onError).toHaveBeenCalledTimes(1)
|
|
50
|
+
const err = onError.mock.calls[0][0] as Error
|
|
51
|
+
expect(err.message).toMatch(/OpenCode SSE connection timed out after \d+ms/)
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
it('does not invoke onError when the caller disposes the stream before it connects', async () => {
|
|
55
|
+
global.fetch = jest.fn((_input, init) => {
|
|
56
|
+
return new Promise((_resolve, reject) => {
|
|
57
|
+
const signal = (init as RequestInit | undefined)?.signal
|
|
58
|
+
if (!signal) return
|
|
59
|
+
signal.addEventListener('abort', () => {
|
|
60
|
+
const err = new Error('Aborted')
|
|
61
|
+
;(err as Error & { name: string }).name = 'AbortError'
|
|
62
|
+
reject(err)
|
|
63
|
+
})
|
|
64
|
+
})
|
|
65
|
+
}) as unknown as typeof fetch
|
|
66
|
+
|
|
67
|
+
const client = new OpenCodeClient({ baseUrl: 'http://opencode.local' })
|
|
68
|
+
const onError = jest.fn()
|
|
69
|
+
|
|
70
|
+
const dispose = client.subscribeToEvents(() => {}, onError)
|
|
71
|
+
dispose()
|
|
72
|
+
await new Promise((r) => setTimeout(r, 10))
|
|
73
|
+
|
|
74
|
+
expect(onError).not.toHaveBeenCalled()
|
|
75
|
+
})
|
|
76
|
+
})
|
|
@@ -16,6 +16,15 @@ import {
|
|
|
16
16
|
searchEndpoints,
|
|
17
17
|
simplifyRequestBodySchema,
|
|
18
18
|
} from './api-endpoint-index'
|
|
19
|
+
import { fetchWithTimeout, resolveTimeoutMs } from '@open-mercato/shared/lib/http/fetchWithTimeout'
|
|
20
|
+
|
|
21
|
+
const DEFAULT_AI_API_REQUEST_TIMEOUT_MS = 30_000
|
|
22
|
+
|
|
23
|
+
function resolveAiApiRequestTimeoutMs(): number {
|
|
24
|
+
const raw = process.env.AI_API_REQUEST_TIMEOUT_MS
|
|
25
|
+
const parsed = raw ? Number.parseInt(raw, 10) : undefined
|
|
26
|
+
return resolveTimeoutMs(parsed, DEFAULT_AI_API_REQUEST_TIMEOUT_MS)
|
|
27
|
+
}
|
|
19
28
|
|
|
20
29
|
/**
|
|
21
30
|
* Load API discovery tools into the registry
|
|
@@ -194,10 +203,11 @@ Confirm with user before POST/PUT/DELETE operations.`,
|
|
|
194
203
|
|
|
195
204
|
// Execute request
|
|
196
205
|
try {
|
|
197
|
-
const response = await
|
|
206
|
+
const response = await fetchWithTimeout(url, {
|
|
198
207
|
method,
|
|
199
208
|
headers,
|
|
200
209
|
body: requestBody ? JSON.stringify(requestBody) : undefined,
|
|
210
|
+
timeoutMs: resolveAiApiRequestTimeoutMs(),
|
|
201
211
|
})
|
|
202
212
|
|
|
203
213
|
const responseText = await response.text()
|
|
@@ -9,6 +9,7 @@ import { buildOpenApiDocument } from '@open-mercato/shared/lib/openapi'
|
|
|
9
9
|
import type { Module } from '@open-mercato/shared/modules/registry'
|
|
10
10
|
import type { SearchService } from '@open-mercato/search/service'
|
|
11
11
|
import type { IndexableRecord } from '@open-mercato/search/types'
|
|
12
|
+
import { fetchWithTimeout, resolveTimeoutMs } from '@open-mercato/shared/lib/http/fetchWithTimeout'
|
|
12
13
|
import {
|
|
13
14
|
API_ENDPOINT_ENTITY_ID,
|
|
14
15
|
GLOBAL_TENANT_ID,
|
|
@@ -17,6 +18,14 @@ import {
|
|
|
17
18
|
computeEndpointsChecksum,
|
|
18
19
|
} from './api-endpoint-index-config'
|
|
19
20
|
|
|
21
|
+
const DEFAULT_OPENAPI_FETCH_TIMEOUT_MS = 10_000
|
|
22
|
+
|
|
23
|
+
function resolveOpenapiFetchTimeoutMs(): number {
|
|
24
|
+
const raw = process.env.AI_OPENAPI_FETCH_TIMEOUT_MS
|
|
25
|
+
const parsed = raw ? Number.parseInt(raw, 10) : undefined
|
|
26
|
+
return resolveTimeoutMs(parsed, DEFAULT_OPENAPI_FETCH_TIMEOUT_MS)
|
|
27
|
+
}
|
|
28
|
+
|
|
20
29
|
/**
|
|
21
30
|
* Indexed API endpoint structure
|
|
22
31
|
*/
|
|
@@ -208,7 +217,9 @@ async function loadRawOpenApiSpec(): Promise<OpenApiDocument | null> {
|
|
|
208
217
|
'http://localhost:3000'
|
|
209
218
|
|
|
210
219
|
try {
|
|
211
|
-
const response = await
|
|
220
|
+
const response = await fetchWithTimeout(`${baseUrl}/api/docs/openapi`, {
|
|
221
|
+
timeoutMs: resolveOpenapiFetchTimeoutMs(),
|
|
222
|
+
})
|
|
212
223
|
if (response.ok) {
|
|
213
224
|
const doc = (await response.json()) as OpenApiDocument
|
|
214
225
|
console.error('[API Index] Raw OpenAPI spec fetched via HTTP')
|
|
@@ -320,7 +331,9 @@ async function parseApiEndpointsFromHttp(): Promise<ApiEndpoint[]> {
|
|
|
320
331
|
|
|
321
332
|
try {
|
|
322
333
|
console.error(`[API Index] Fetching OpenAPI spec from ${openApiUrl}...`)
|
|
323
|
-
const response = await
|
|
334
|
+
const response = await fetchWithTimeout(openApiUrl, {
|
|
335
|
+
timeoutMs: resolveOpenapiFetchTimeoutMs(),
|
|
336
|
+
})
|
|
324
337
|
|
|
325
338
|
if (!response.ok) {
|
|
326
339
|
console.error(`[API Index] Failed to fetch OpenAPI spec: ${response.status} ${response.statusText}`)
|
|
@@ -28,6 +28,15 @@ import {
|
|
|
28
28
|
buildSearchLabel,
|
|
29
29
|
incrementToolCallCount,
|
|
30
30
|
} from './session-memory'
|
|
31
|
+
import { fetchWithTimeout, resolveTimeoutMs } from '@open-mercato/shared/lib/http/fetchWithTimeout'
|
|
32
|
+
|
|
33
|
+
const DEFAULT_AI_API_REQUEST_TIMEOUT_MS = 30_000
|
|
34
|
+
|
|
35
|
+
function resolveAiApiRequestTimeoutMs(): number {
|
|
36
|
+
const raw = process.env.AI_API_REQUEST_TIMEOUT_MS
|
|
37
|
+
const parsed = raw ? Number.parseInt(raw, 10) : undefined
|
|
38
|
+
return resolveTimeoutMs(parsed, DEFAULT_AI_API_REQUEST_TIMEOUT_MS)
|
|
39
|
+
}
|
|
31
40
|
|
|
32
41
|
/**
|
|
33
42
|
* Cached spec object combining OpenAPI paths + entity schemas.
|
|
@@ -823,10 +832,11 @@ function createApiRequestFn(
|
|
|
823
832
|
if (ctx.organizationId) headers['X-Organization-Id'] = ctx.organizationId
|
|
824
833
|
|
|
825
834
|
// Execute request using host fetch (not sandbox)
|
|
826
|
-
const response = await
|
|
835
|
+
const response = await fetchWithTimeout(url, {
|
|
827
836
|
method: normalizedMethod,
|
|
828
837
|
headers,
|
|
829
838
|
body: requestBody ? JSON.stringify(requestBody) : undefined,
|
|
839
|
+
timeoutMs: resolveAiApiRequestTimeoutMs(),
|
|
830
840
|
})
|
|
831
841
|
|
|
832
842
|
const responseText = await response.text()
|
|
@@ -5,6 +5,16 @@
|
|
|
5
5
|
* OpenCode is used as an AI agent that can execute MCP tools.
|
|
6
6
|
*/
|
|
7
7
|
import { readJsonSafe } from '@open-mercato/shared/lib/http/readJsonSafe'
|
|
8
|
+
import { fetchWithTimeout, resolveTimeoutMs } from '@open-mercato/shared/lib/http/fetchWithTimeout'
|
|
9
|
+
|
|
10
|
+
const DEFAULT_OPENCODE_REQUEST_TIMEOUT_MS = 30_000
|
|
11
|
+
const DEFAULT_OPENCODE_SSE_CONNECT_TIMEOUT_MS = 15_000
|
|
12
|
+
|
|
13
|
+
function resolveOpencodeTimeoutMs(envVar: string, fallback: number): number {
|
|
14
|
+
const raw = process.env[envVar]
|
|
15
|
+
const parsed = raw ? Number.parseInt(raw, 10) : undefined
|
|
16
|
+
return resolveTimeoutMs(parsed, fallback)
|
|
17
|
+
}
|
|
8
18
|
|
|
9
19
|
export type OpenCodeClientConfig = {
|
|
10
20
|
baseUrl: string
|
|
@@ -132,6 +142,22 @@ export class OpenCodeClient {
|
|
|
132
142
|
onError?: (error: Error) => void
|
|
133
143
|
): () => void {
|
|
134
144
|
const controller = new AbortController()
|
|
145
|
+
const connectTimeoutMs = resolveOpencodeTimeoutMs(
|
|
146
|
+
'OPENCODE_SSE_CONNECT_TIMEOUT_MS',
|
|
147
|
+
DEFAULT_OPENCODE_SSE_CONNECT_TIMEOUT_MS,
|
|
148
|
+
)
|
|
149
|
+
const connectTimeoutReason = new Error(
|
|
150
|
+
`OpenCode SSE connection timed out after ${connectTimeoutMs}ms`,
|
|
151
|
+
)
|
|
152
|
+
let connectTimer: ReturnType<typeof setTimeout> | null = setTimeout(() => {
|
|
153
|
+
controller.abort(connectTimeoutReason)
|
|
154
|
+
}, connectTimeoutMs)
|
|
155
|
+
const clearConnectTimer = () => {
|
|
156
|
+
if (connectTimer !== null) {
|
|
157
|
+
clearTimeout(connectTimer)
|
|
158
|
+
connectTimer = null
|
|
159
|
+
}
|
|
160
|
+
}
|
|
135
161
|
|
|
136
162
|
const connect = async () => {
|
|
137
163
|
try {
|
|
@@ -142,6 +168,7 @@ export class OpenCodeClient {
|
|
|
142
168
|
},
|
|
143
169
|
signal: controller.signal,
|
|
144
170
|
})
|
|
171
|
+
clearConnectTimer()
|
|
145
172
|
|
|
146
173
|
if (!res.ok || !res.body) {
|
|
147
174
|
throw new Error(`SSE connection failed: ${res.status}`)
|
|
@@ -173,23 +200,33 @@ export class OpenCodeClient {
|
|
|
173
200
|
}
|
|
174
201
|
}
|
|
175
202
|
} catch (error) {
|
|
176
|
-
|
|
177
|
-
|
|
203
|
+
clearConnectTimer()
|
|
204
|
+
if ((error as Error).name === 'AbortError') {
|
|
205
|
+
const reason = (controller.signal as AbortSignal & { reason?: unknown }).reason
|
|
206
|
+
if (reason === connectTimeoutReason) {
|
|
207
|
+
onError?.(connectTimeoutReason)
|
|
208
|
+
}
|
|
209
|
+
return
|
|
178
210
|
}
|
|
211
|
+
onError?.(error as Error)
|
|
179
212
|
}
|
|
180
213
|
}
|
|
181
214
|
|
|
182
215
|
connect()
|
|
183
216
|
|
|
184
|
-
return () =>
|
|
217
|
+
return () => {
|
|
218
|
+
clearConnectTimer()
|
|
219
|
+
controller.abort()
|
|
220
|
+
}
|
|
185
221
|
}
|
|
186
222
|
|
|
187
223
|
/**
|
|
188
224
|
* Check OpenCode server health.
|
|
189
225
|
*/
|
|
190
226
|
async health(): Promise<OpenCodeHealth> {
|
|
191
|
-
const res = await
|
|
227
|
+
const res = await fetchWithTimeout(`${this.baseUrl}/global/health`, {
|
|
192
228
|
headers: this.headers,
|
|
229
|
+
timeoutMs: resolveOpencodeTimeoutMs('OPENCODE_REQUEST_TIMEOUT_MS', DEFAULT_OPENCODE_REQUEST_TIMEOUT_MS),
|
|
193
230
|
})
|
|
194
231
|
|
|
195
232
|
if (!res.ok) {
|
|
@@ -205,8 +242,9 @@ export class OpenCodeClient {
|
|
|
205
242
|
* Get MCP server connection status.
|
|
206
243
|
*/
|
|
207
244
|
async mcpStatus(): Promise<OpenCodeMcpStatus> {
|
|
208
|
-
const res = await
|
|
245
|
+
const res = await fetchWithTimeout(`${this.baseUrl}/mcp`, {
|
|
209
246
|
headers: this.headers,
|
|
247
|
+
timeoutMs: resolveOpencodeTimeoutMs('OPENCODE_REQUEST_TIMEOUT_MS', DEFAULT_OPENCODE_REQUEST_TIMEOUT_MS),
|
|
210
248
|
})
|
|
211
249
|
|
|
212
250
|
if (!res.ok) {
|
|
@@ -222,10 +260,11 @@ export class OpenCodeClient {
|
|
|
222
260
|
* Create a new conversation session.
|
|
223
261
|
*/
|
|
224
262
|
async createSession(): Promise<OpenCodeSession> {
|
|
225
|
-
const res = await
|
|
263
|
+
const res = await fetchWithTimeout(`${this.baseUrl}/session`, {
|
|
226
264
|
method: 'POST',
|
|
227
265
|
headers: this.headers,
|
|
228
266
|
body: JSON.stringify({}),
|
|
267
|
+
timeoutMs: resolveOpencodeTimeoutMs('OPENCODE_REQUEST_TIMEOUT_MS', DEFAULT_OPENCODE_REQUEST_TIMEOUT_MS),
|
|
229
268
|
})
|
|
230
269
|
|
|
231
270
|
if (!res.ok) {
|
|
@@ -242,8 +281,9 @@ export class OpenCodeClient {
|
|
|
242
281
|
* Get an existing session by ID.
|
|
243
282
|
*/
|
|
244
283
|
async getSession(sessionId: string): Promise<OpenCodeSession> {
|
|
245
|
-
const res = await
|
|
284
|
+
const res = await fetchWithTimeout(`${this.baseUrl}/session/${sessionId}`, {
|
|
246
285
|
headers: this.headers,
|
|
286
|
+
timeoutMs: resolveOpencodeTimeoutMs('OPENCODE_REQUEST_TIMEOUT_MS', DEFAULT_OPENCODE_REQUEST_TIMEOUT_MS),
|
|
247
287
|
})
|
|
248
288
|
|
|
249
289
|
if (!res.ok) {
|
|
@@ -273,10 +313,14 @@ export class OpenCodeClient {
|
|
|
273
313
|
body.model = options.model
|
|
274
314
|
}
|
|
275
315
|
|
|
276
|
-
const res = await
|
|
316
|
+
const res = await fetchWithTimeout(`${this.baseUrl}/session/${sessionId}/message`, {
|
|
277
317
|
method: 'POST',
|
|
278
318
|
headers: this.headers,
|
|
279
319
|
body: JSON.stringify(body),
|
|
320
|
+
timeoutMs: resolveOpencodeTimeoutMs(
|
|
321
|
+
'OPENCODE_SEND_MESSAGE_TIMEOUT_MS',
|
|
322
|
+
resolveOpencodeTimeoutMs('OPENCODE_REQUEST_TIMEOUT_MS', DEFAULT_OPENCODE_REQUEST_TIMEOUT_MS),
|
|
323
|
+
),
|
|
280
324
|
})
|
|
281
325
|
|
|
282
326
|
if (!res.ok) {
|
|
@@ -293,10 +337,11 @@ export class OpenCodeClient {
|
|
|
293
337
|
* Set authentication credentials for a provider.
|
|
294
338
|
*/
|
|
295
339
|
async setAuth(providerId: string, apiKey: string): Promise<void> {
|
|
296
|
-
const res = await
|
|
340
|
+
const res = await fetchWithTimeout(`${this.baseUrl}/auth/${providerId}`, {
|
|
297
341
|
method: 'PUT',
|
|
298
342
|
headers: this.headers,
|
|
299
343
|
body: JSON.stringify({ type: 'api', key: apiKey }),
|
|
344
|
+
timeoutMs: resolveOpencodeTimeoutMs('OPENCODE_REQUEST_TIMEOUT_MS', DEFAULT_OPENCODE_REQUEST_TIMEOUT_MS),
|
|
300
345
|
})
|
|
301
346
|
|
|
302
347
|
if (!res.ok) {
|
|
@@ -308,8 +353,9 @@ export class OpenCodeClient {
|
|
|
308
353
|
* Get current configuration.
|
|
309
354
|
*/
|
|
310
355
|
async getConfig(): Promise<Record<string, unknown>> {
|
|
311
|
-
const res = await
|
|
356
|
+
const res = await fetchWithTimeout(`${this.baseUrl}/config`, {
|
|
312
357
|
headers: this.headers,
|
|
358
|
+
timeoutMs: resolveOpencodeTimeoutMs('OPENCODE_REQUEST_TIMEOUT_MS', DEFAULT_OPENCODE_REQUEST_TIMEOUT_MS),
|
|
313
359
|
})
|
|
314
360
|
|
|
315
361
|
if (!res.ok) {
|
|
@@ -325,8 +371,9 @@ export class OpenCodeClient {
|
|
|
325
371
|
* Get pending questions that need user response.
|
|
326
372
|
*/
|
|
327
373
|
async getPendingQuestions(): Promise<OpenCodeQuestion[]> {
|
|
328
|
-
const res = await
|
|
374
|
+
const res = await fetchWithTimeout(`${this.baseUrl}/question`, {
|
|
329
375
|
headers: this.headers,
|
|
376
|
+
timeoutMs: resolveOpencodeTimeoutMs('OPENCODE_REQUEST_TIMEOUT_MS', DEFAULT_OPENCODE_REQUEST_TIMEOUT_MS),
|
|
330
377
|
})
|
|
331
378
|
|
|
332
379
|
if (!res.ok) {
|
|
@@ -366,10 +413,11 @@ export class OpenCodeClient {
|
|
|
366
413
|
|
|
367
414
|
console.log('[OpenCode Client] Answering question', questionId, 'with body:', JSON.stringify(body))
|
|
368
415
|
|
|
369
|
-
const res = await
|
|
416
|
+
const res = await fetchWithTimeout(`${this.baseUrl}/question/${questionId}/reply`, {
|
|
370
417
|
method: 'POST',
|
|
371
418
|
headers: this.headers,
|
|
372
419
|
body: JSON.stringify(body),
|
|
420
|
+
timeoutMs: resolveOpencodeTimeoutMs('OPENCODE_REQUEST_TIMEOUT_MS', DEFAULT_OPENCODE_REQUEST_TIMEOUT_MS),
|
|
373
421
|
})
|
|
374
422
|
|
|
375
423
|
const responseText = await res.text()
|
|
@@ -386,9 +434,10 @@ export class OpenCodeClient {
|
|
|
386
434
|
async rejectQuestion(questionId: string): Promise<void> {
|
|
387
435
|
console.log('[OpenCode Client] Rejecting question', questionId)
|
|
388
436
|
|
|
389
|
-
const res = await
|
|
437
|
+
const res = await fetchWithTimeout(`${this.baseUrl}/question/${questionId}/reject`, {
|
|
390
438
|
method: 'POST',
|
|
391
439
|
headers: this.headers,
|
|
440
|
+
timeoutMs: resolveOpencodeTimeoutMs('OPENCODE_REQUEST_TIMEOUT_MS', DEFAULT_OPENCODE_REQUEST_TIMEOUT_MS),
|
|
392
441
|
})
|
|
393
442
|
|
|
394
443
|
if (!res.ok) {
|
|
@@ -403,8 +452,9 @@ export class OpenCodeClient {
|
|
|
403
452
|
*/
|
|
404
453
|
async getSessionStatus(sessionId: string): Promise<{ status: string; questionId?: string }> {
|
|
405
454
|
try {
|
|
406
|
-
const res = await
|
|
455
|
+
const res = await fetchWithTimeout(`${this.baseUrl}/session/${sessionId}/status`, {
|
|
407
456
|
headers: this.headers,
|
|
457
|
+
timeoutMs: resolveOpencodeTimeoutMs('OPENCODE_REQUEST_TIMEOUT_MS', DEFAULT_OPENCODE_REQUEST_TIMEOUT_MS),
|
|
408
458
|
})
|
|
409
459
|
|
|
410
460
|
if (res.ok) {
|