@letta-ai/letta-agent-sdk 0.3.2 → 0.3.3

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.
Files changed (49) hide show
  1. package/AGENTS.md +47 -0
  2. package/README.md +17 -0
  3. package/dist/client-entry.js +800 -732
  4. package/dist/client-entry.js.map +8 -5
  5. package/dist/cloud-sandbox.d.ts +33 -0
  6. package/dist/cloud-sandbox.d.ts.map +1 -0
  7. package/dist/cloud-session.d.ts.map +1 -1
  8. package/dist/index.d.ts +1 -1
  9. package/dist/index.d.ts.map +1 -1
  10. package/dist/index.js +799 -732
  11. package/dist/index.js.map +9 -6
  12. package/dist/remote-client-session-core.d.ts +6 -93
  13. package/dist/remote-client-session-core.d.ts.map +1 -1
  14. package/dist/remote-session-protocol.d.ts +130 -0
  15. package/dist/remote-session-protocol.d.ts.map +1 -0
  16. package/dist/remote-turn-coordinator.d.ts +49 -0
  17. package/dist/remote-turn-coordinator.d.ts.map +1 -0
  18. package/dist/types.d.ts +2 -20
  19. package/dist/types.d.ts.map +1 -1
  20. package/package.json +5 -2
  21. package/src/app-server-management.ts +641 -0
  22. package/src/app-server-session.ts +948 -0
  23. package/src/cli-resolver.ts +46 -0
  24. package/src/client-base.ts +482 -0
  25. package/src/client-entry.ts +31 -0
  26. package/src/client.ts +138 -0
  27. package/src/cloud-management.ts +360 -0
  28. package/src/cloud-sandbox.ts +117 -0
  29. package/src/cloud-session.ts +1313 -0
  30. package/src/index.ts +440 -0
  31. package/src/interactiveToolPolicy.ts +62 -0
  32. package/src/local-app-server-session.ts +39 -0
  33. package/src/local-app-server.ts +137 -0
  34. package/src/management-types.ts +133 -0
  35. package/src/management.ts +206 -0
  36. package/src/protocol.ts +249 -0
  37. package/src/remote-client-session-core.ts +786 -0
  38. package/src/remote-session-protocol.ts +660 -0
  39. package/src/remote-turn-coordinator.ts +505 -0
  40. package/src/remote.ts +177 -0
  41. package/src/repositories.ts +340 -0
  42. package/src/request-ids.ts +33 -0
  43. package/src/session.ts +1638 -0
  44. package/src/stream-events.ts +88 -0
  45. package/src/tool-helpers.ts +147 -0
  46. package/src/transport.ts +484 -0
  47. package/src/types.ts +1328 -0
  48. package/src/validation.ts +223 -0
  49. package/src/websocket.ts +22 -0
package/dist/index.js CHANGED
@@ -1,3 +1,4 @@
1
+ // Generated bundle. Canonical modules are published under src/ and maintained in the letta-agent-sdk repository.
1
2
  import { createRequire } from "node:module";
2
3
  var __create = Object.create;
3
4
  var __getProtoOf = Object.getPrototypeOf;
@@ -5730,7 +5731,7 @@ function buildCanUseToolContext(request, requestId) {
5730
5731
  return context;
5731
5732
  }
5732
5733
 
5733
- // src/remote-client-session-core.ts
5734
+ // src/remote-session-protocol.ts
5734
5735
  var FAILURE_STOP_REASONS = new Set([
5735
5736
  "error",
5736
5737
  "llm_api_error",
@@ -6125,219 +6126,607 @@ function normalizeSendMessage(message) {
6125
6126
  return message;
6126
6127
  }
6127
6128
 
6128
- class RemoteClientSessionCore {
6129
- mode;
6130
- controller = null;
6131
- runtime = null;
6132
- initialized = false;
6133
- closed = false;
6134
- activeTurnStartedAt = 0;
6135
- _agentId = null;
6136
- _sessionId = null;
6137
- _conversationId = null;
6138
- _model = "";
6139
- _modelSettings = null;
6129
+ // src/remote-turn-coordinator.ts
6130
+ class RemoteTurnCoordinator {
6140
6131
  label;
6141
6132
  requestTimeoutMs;
6142
- initializePromise = null;
6133
+ onDeviceStatus;
6143
6134
  streamQueue = [];
6144
6135
  streamResolvers = [];
6145
- removeMessageHandler = null;
6146
6136
  activeTurn = null;
6147
6137
  pendingTurns = [];
6148
6138
  nextTurnId = 0;
6149
6139
  messageCounter = 0;
6150
6140
  clientMessageCounter = 0;
6151
- toolNames;
6152
- deviceStatusListeners = new Set;
6153
- deviceStatusRefreshCancels = new Set;
6154
- constructor(mode, config) {
6155
- this.mode = mode;
6141
+ closed = false;
6142
+ _activeTurnStartedAt = 0;
6143
+ constructor(config) {
6156
6144
  this.label = config.label;
6157
6145
  this.requestTimeoutMs = config.requestTimeoutMs;
6146
+ this.onDeviceStatus = config.onDeviceStatus;
6158
6147
  }
6159
- async initialize() {
6160
- if (this.closed) {
6161
- throw new Error("Session is closed");
6162
- }
6163
- if (this.initializePromise) {
6164
- return this.initializePromise;
6165
- }
6166
- if (this.initialized) {
6167
- throw new Error("Session already initialized");
6168
- }
6169
- const attempt = this.performInitialize();
6170
- const memo = attempt.catch((error) => {
6171
- this.cleanupFailedInitialize();
6172
- throw error;
6173
- }).finally(() => {
6174
- if (this.initializePromise === memo) {
6175
- this.initializePromise = null;
6176
- }
6177
- });
6178
- this.initializePromise = memo;
6179
- return memo;
6180
- }
6181
- async performInitialize() {
6182
- const init = await this.initializeRuntimeController();
6183
- this.controller = init.controller;
6184
- this.runtime = init.runtime;
6185
- this._agentId = init.runtime.agent_id;
6186
- this._conversationId = init.runtime.conversation_id;
6187
- this._sessionId = `${init.runtime.agent_id}:${init.runtime.conversation_id}`;
6188
- this._modelSettings = init.modelSettings ?? null;
6189
- this._model = typeof init.model === "string" ? init.model : typeof this._modelSettings?.model === "string" ? this._modelSettings.model : "";
6190
- this.toolNames = init.tools;
6191
- this.removeMessageHandler = this.controller.onMessage(this.handleProtocolMessage);
6192
- await this.afterRuntimeInitialized();
6193
- await this.applyPostInitializeOptions();
6194
- if (this.closed) {
6195
- throw new Error("Session is closed");
6196
- }
6197
- this.initialized = true;
6198
- const initMessage = {
6199
- type: "init",
6200
- agentId: init.runtime.agent_id,
6201
- sessionId: this._sessionId,
6202
- conversationId: init.runtime.conversation_id,
6203
- model: this._model
6204
- };
6205
- if (this.toolNames !== undefined)
6206
- initMessage.tools = this.toolNames;
6207
- if (init.skillSources !== undefined) {
6208
- initMessage.skillSources = init.skillSources;
6209
- }
6210
- return initMessage;
6211
- }
6212
- cleanupFailedInitialize() {
6213
- this.removeMessageHandler?.();
6214
- this.removeMessageHandler = null;
6215
- this.controller?.close();
6216
- this.controller = null;
6217
- this.onCoreClose();
6218
- this.runtime = null;
6219
- this._agentId = null;
6220
- this._conversationId = null;
6221
- this._sessionId = null;
6222
- this._modelSettings = null;
6223
- this._model = "";
6224
- this.toolNames = undefined;
6225
- this.initialized = false;
6148
+ get activeTurnStartedAt() {
6149
+ return this._activeTurnStartedAt;
6226
6150
  }
6227
- async send(message) {
6228
- if (!this.initialized) {
6229
- await this.initialize();
6230
- }
6231
- if (!this.controller || !this.runtime) {
6232
- throw new Error("Session is not initialized");
6233
- }
6234
- await this.beforeTurn();
6235
- const turn = this.trackSentTurn(this.runtime);
6236
- try {
6237
- this.controller.sendTurnMessage(this.runtime, message, {
6238
- clientMessageId: turn.clientMessageId
6239
- });
6240
- } catch (error) {
6241
- this.removeTrackedTurn(turn);
6242
- throw error;
6243
- }
6151
+ hasInFlightTurn() {
6152
+ return this.activeTurn !== null || this.pendingTurns.length > 0;
6244
6153
  }
6245
- async runTurn(message, _options = {}) {
6246
- if (this.activeTurn || this.pendingTurns.length > 0) {
6247
- throw new Error(`A turn is already in flight for this ${this.label} session. Use send() and stream() to let the listener queue messages.`);
6248
- }
6249
- await this.send(message);
6250
- for await (const msg of this.stream()) {
6251
- if (msg.type === "result") {
6252
- return msg;
6253
- }
6254
- }
6255
- return {
6256
- type: "result",
6257
- success: false,
6258
- error: "stream_closed",
6259
- errorCode: "stream_closed",
6260
- recoverable: false,
6261
- errorDetail: "Stream ended before terminal result",
6262
- durationMs: Date.now() - this.activeTurnStartedAt,
6263
- conversationId: this._conversationId
6154
+ trackSentTurn(runtime) {
6155
+ const turn = {
6156
+ id: ++this.nextTurnId,
6157
+ runtime,
6158
+ clientMessageId: `sdk-message-${Date.now()}-${++this.clientMessageCounter}`,
6159
+ queuedAt: Date.now(),
6160
+ startedAt: 0,
6161
+ assistantText: "",
6162
+ runIds: new Set,
6163
+ observedTurnEvidence: false,
6164
+ observedRequiresApprovalStop: false,
6165
+ abortRequested: false,
6166
+ timeout: null
6264
6167
  };
6265
- }
6266
- async* stream() {
6267
- while (true) {
6268
- const msg = await this.nextMessage();
6269
- if (!msg)
6270
- break;
6271
- yield msg;
6272
- if (msg.type === "result")
6273
- break;
6168
+ if (this.activeTurn) {
6169
+ this.pendingTurns.push(turn);
6170
+ } else {
6171
+ this.activateTurn(turn);
6274
6172
  }
6173
+ return turn;
6275
6174
  }
6276
- async abort() {
6277
- if (!this.initialized)
6278
- return;
6279
- if (!this.controller || !this.runtime)
6175
+ removeTrackedTurn(turn) {
6176
+ if (turn.timeout)
6177
+ clearTimeout(turn.timeout);
6178
+ if (this.activeTurn === turn) {
6179
+ this.activeTurn = null;
6280
6180
  return;
6181
+ }
6182
+ const index = this.pendingTurns.indexOf(turn);
6183
+ if (index !== -1)
6184
+ this.pendingTurns.splice(index, 1);
6185
+ }
6186
+ markAbortRequested() {
6281
6187
  if (this.activeTurn)
6282
6188
  this.activeTurn.abortRequested = true;
6283
- await this.controller.abort(this.runtime);
6284
6189
  }
6285
- async sendCommand(command, options) {
6286
- if (!this.initialized) {
6287
- await this.initialize();
6288
- }
6289
- if (!this.controller) {
6290
- throw new Error("Session is not initialized");
6190
+ handleProtocolMessage(message, runtime) {
6191
+ if (!sameRuntime2(message, runtime))
6192
+ return;
6193
+ const statusRecord = deviceStatusRecord(message);
6194
+ if (statusRecord) {
6195
+ const status = toSessionDeviceStatus(statusRecord);
6196
+ if (status)
6197
+ this.onDeviceStatus(status);
6198
+ return;
6291
6199
  }
6292
- if (!command || typeof command !== "object" || Array.isArray(command)) {
6293
- throw new Error("Invalid command. Expected a protocol command object.");
6200
+ if (message.type === "update_queue") {
6201
+ const sdkMessage2 = {
6202
+ type: "queue_update",
6203
+ queue: queueItems(message)
6204
+ };
6205
+ this.enqueue(sdkMessage2);
6206
+ return;
6294
6207
  }
6295
- if (typeof command.type !== "string" || command.type.length === 0) {
6296
- throw new Error("Invalid command. Expected a non-empty type.");
6208
+ if (message.type === "update_loop_status") {
6209
+ this.handleLoopStatusMessage(message);
6210
+ return;
6297
6211
  }
6298
- if (!options || !options.responseType && !options.predicate && options.timeoutMs === undefined) {
6299
- this.controller.send(command);
6212
+ const delta = streamDeltaRecord(message);
6213
+ if (!delta)
6300
6214
  return;
6215
+ const active = this.activateNextTurnFromProtocol();
6216
+ if (active) {
6217
+ active.observedTurnEvidence = true;
6218
+ const runId = streamDeltaRunId2(delta);
6219
+ if (runId)
6220
+ active.runIds.add(runId);
6301
6221
  }
6302
- const { type, ...body } = command;
6303
- const response = await this.controller.request(type, body, {
6304
- ...options.timeoutMs !== undefined ? { timeoutMs: options.timeoutMs } : {},
6305
- predicate: options.predicate ? (message) => options.predicate?.(message) === true : options.responseType ? (message) => message.type === options.responseType : undefined
6222
+ const sdkMessage = this.transformStreamDelta(delta);
6223
+ if (sdkMessage)
6224
+ this.enqueue(sdkMessage);
6225
+ this.handleTurnTerminalDelta(delta, sdkMessage);
6226
+ }
6227
+ nextMessage() {
6228
+ const next = this.streamQueue.shift();
6229
+ if (next)
6230
+ return Promise.resolve(next);
6231
+ if (this.closed)
6232
+ return Promise.resolve(null);
6233
+ return new Promise((resolve) => {
6234
+ this.streamResolvers.push(resolve);
6306
6235
  });
6307
- return response;
6308
6236
  }
6309
- async listModels() {
6310
- if (!this.initialized) {
6311
- await this.initialize();
6312
- }
6313
- if (!this.controller) {
6314
- throw new Error("Session is not initialized");
6237
+ close() {
6238
+ if (this.closed)
6239
+ return;
6240
+ this.closed = true;
6241
+ if (this.activeTurn?.timeout)
6242
+ clearTimeout(this.activeTurn.timeout);
6243
+ for (const turn of this.pendingTurns) {
6244
+ if (turn.timeout)
6245
+ clearTimeout(turn.timeout);
6315
6246
  }
6316
- return this.controller.listModels();
6247
+ this.activeTurn = null;
6248
+ this.pendingTurns.length = 0;
6249
+ this.resolveAll(null);
6317
6250
  }
6318
- async updateModel(update) {
6319
- if (!this.initialized) {
6320
- await this.initialize();
6321
- }
6322
- if (!this.controller || !this.runtime) {
6323
- throw new Error("Session is not initialized");
6251
+ activateTurn(turn) {
6252
+ this.activeTurn = turn;
6253
+ turn.startedAt = Date.now();
6254
+ this._activeTurnStartedAt = turn.startedAt;
6255
+ if (this.requestTimeoutMs !== undefined) {
6256
+ turn.timeout = setTimeout(() => {
6257
+ this.failTurn(turn, `Timed out waiting for ${this.label} turn`);
6258
+ }, this.requestTimeoutMs);
6259
+ turn.timeout.unref?.();
6324
6260
  }
6325
- return this.applyModelUpdate(update);
6326
6261
  }
6327
- async applyModelUpdate(update) {
6328
- if (!this.controller || !this.runtime) {
6329
- throw new Error("Session is not initialized");
6330
- }
6331
- const normalized = normalizeUpdateModelInput(update);
6332
- const payload = await this.resolveUpdateModelPayload(normalized);
6333
- const result = await this.controller.updateModel(this.runtime, payload);
6334
- if (result.modelHandle !== undefined) {
6335
- this._model = result.modelHandle;
6336
- } else if (payload.model_handle !== undefined) {
6337
- this._model = payload.model_handle;
6338
- } else if (typeof result.modelSettings?.model === "string") {
6339
- this._model = result.modelSettings.model;
6340
- }
6262
+ activateNextTurnFromProtocol() {
6263
+ if (this.activeTurn)
6264
+ return this.activeTurn;
6265
+ const next = this.pendingTurns.shift();
6266
+ if (!next)
6267
+ return null;
6268
+ this.activateTurn(next);
6269
+ return next;
6270
+ }
6271
+ failTurn(turn, detail) {
6272
+ if (this.activeTurn !== turn)
6273
+ return;
6274
+ this.enqueue({
6275
+ type: "error",
6276
+ message: detail,
6277
+ errorCode: "error",
6278
+ stopReason: "error",
6279
+ errorDetail: detail,
6280
+ recoverable: false
6281
+ });
6282
+ this.completeActiveTurn({
6283
+ runtime: turn.runtime,
6284
+ stopReason: "error",
6285
+ runIds: [...turn.runIds],
6286
+ success: false,
6287
+ detail,
6288
+ errorCode: "error"
6289
+ });
6290
+ }
6291
+ completeActiveTurn(turn) {
6292
+ const active = this.activeTurn;
6293
+ if (!active)
6294
+ return;
6295
+ if (active.timeout) {
6296
+ clearTimeout(active.timeout);
6297
+ active.timeout = null;
6298
+ }
6299
+ this.enqueue(this.resultFromTurn(turn, active));
6300
+ this.activeTurn = null;
6301
+ }
6302
+ handleLoopStatusMessage(message) {
6303
+ const status = loopStatusValue(message);
6304
+ if (!status)
6305
+ return;
6306
+ const activeRunIds = loopStatusRunIds(message);
6307
+ const sdkMessage = {
6308
+ type: "loop_status",
6309
+ status,
6310
+ activeRunIds
6311
+ };
6312
+ this.enqueue(sdkMessage);
6313
+ const active = this.activeTurn;
6314
+ if (!active)
6315
+ return;
6316
+ for (const runId of activeRunIds)
6317
+ active.runIds.add(runId);
6318
+ const hadTurnEvidence = active.observedTurnEvidence || active.observedRequiresApprovalStop;
6319
+ if (!hadTurnEvidence)
6320
+ return;
6321
+ if (status === "WAITING_ON_APPROVAL") {
6322
+ this.completeActiveTurn({
6323
+ runtime: active.runtime,
6324
+ stopReason: "requires_approval",
6325
+ runIds: [...active.runIds]
6326
+ });
6327
+ return;
6328
+ }
6329
+ if (status === "WAITING_ON_INPUT" && active.abortRequested) {
6330
+ this.completeActiveTurn({
6331
+ runtime: active.runtime,
6332
+ stopReason: "interrupted",
6333
+ runIds: [...active.runIds],
6334
+ success: false,
6335
+ detail: "Interrupted",
6336
+ errorCode: "interrupted"
6337
+ });
6338
+ return;
6339
+ }
6340
+ if (status === "WAITING_ON_INPUT" && active.observedTurnEvidence) {
6341
+ this.completeActiveTurn({
6342
+ runtime: active.runtime,
6343
+ stopReason: null,
6344
+ runIds: [...active.runIds]
6345
+ });
6346
+ }
6347
+ }
6348
+ handleTurnTerminalDelta(delta, sdkMessage) {
6349
+ const active = this.activeTurn;
6350
+ if (!active)
6351
+ return;
6352
+ const messageType = streamDeltaMessageType2(delta);
6353
+ if (messageType === "stop_reason") {
6354
+ const stopReason = streamDeltaStopReason2(delta) ?? null;
6355
+ if (stopReason === "requires_approval") {
6356
+ active.observedRequiresApprovalStop = true;
6357
+ return;
6358
+ }
6359
+ this.completeActiveTurn({
6360
+ runtime: active.runtime,
6361
+ stopReason,
6362
+ runIds: [...active.runIds]
6363
+ });
6364
+ return;
6365
+ }
6366
+ if (sdkMessage?.type === "error") {
6367
+ this.completeActiveTurn({
6368
+ runtime: active.runtime,
6369
+ stopReason: sdkMessage.stopReason,
6370
+ runIds: [...active.runIds],
6371
+ success: false,
6372
+ detail: sdkMessage.errorDetail ?? sdkMessage.message,
6373
+ errorCode: sdkMessage.errorCode
6374
+ });
6375
+ }
6376
+ }
6377
+ transformStreamDelta(delta) {
6378
+ const messageType = typeof delta.message_type === "string" ? delta.message_type : undefined;
6379
+ const runId = typeof delta.run_id === "string" ? delta.run_id : undefined;
6380
+ const uuid = typeof delta.id === "string" ? delta.id : `${this.label}-${++this.messageCounter}`;
6381
+ if (messageType === "assistant_message") {
6382
+ const content = extractTextFromContent(delta.content);
6383
+ if (!content)
6384
+ return null;
6385
+ if (this.activeTurn)
6386
+ this.activeTurn.assistantText += content;
6387
+ return { type: "assistant", content, uuid, runId };
6388
+ }
6389
+ if (messageType === "reasoning_message") {
6390
+ const content = typeof delta.reasoning === "string" ? delta.reasoning : extractTextFromContent(delta.content);
6391
+ if (!content)
6392
+ return null;
6393
+ return { type: "reasoning", content, uuid, runId };
6394
+ }
6395
+ if (messageType === "tool_call_message" || messageType === "approval_request_message") {
6396
+ const toolCall = firstToolCall(delta);
6397
+ if (!toolCall)
6398
+ return null;
6399
+ const fn = toolCall.function && typeof toolCall.function === "object" ? toolCall.function : undefined;
6400
+ const toolCallId = (typeof toolCall.tool_call_id === "string" ? toolCall.tool_call_id : undefined) ?? (typeof toolCall.id === "string" ? toolCall.id : undefined);
6401
+ if (!toolCallId) {
6402
+ const detail = `Missing tool_call_id in ${messageType} (uuid=${uuid})`;
6403
+ return {
6404
+ type: "error",
6405
+ message: detail,
6406
+ errorCode: "protocol_error",
6407
+ stopReason: "protocol_error",
6408
+ runId,
6409
+ recoverable: false,
6410
+ errorDetail: detail
6411
+ };
6412
+ }
6413
+ const toolName = (typeof toolCall.name === "string" ? toolCall.name : undefined) ?? (typeof fn?.name === "string" ? fn.name : undefined) ?? "?";
6414
+ const { input, raw } = toolInputFromArguments(toolCall.arguments ?? fn?.arguments);
6415
+ return {
6416
+ type: "tool_call",
6417
+ toolCallId,
6418
+ toolName,
6419
+ toolInput: input,
6420
+ rawArguments: raw,
6421
+ uuid,
6422
+ runId
6423
+ };
6424
+ }
6425
+ if (messageType === "tool_return_message") {
6426
+ const toolReturn = firstToolReturn(delta) ?? delta;
6427
+ const toolCallId = (typeof delta.tool_call_id === "string" ? delta.tool_call_id : undefined) ?? (typeof toolReturn.tool_call_id === "string" ? toolReturn.tool_call_id : undefined);
6428
+ if (!toolCallId)
6429
+ return null;
6430
+ const content = extractTextFromContent(delta.tool_return ?? toolReturn.tool_return ?? toolReturn.content) ?? "";
6431
+ const status = typeof delta.status === "string" ? delta.status : toolReturn.status;
6432
+ return {
6433
+ type: "tool_result",
6434
+ toolCallId,
6435
+ content,
6436
+ isError: status === "error",
6437
+ uuid,
6438
+ runId
6439
+ };
6440
+ }
6441
+ if (messageType === "error_message" || messageType === "loop_error") {
6442
+ const detail = (typeof delta.detail === "string" ? delta.detail : undefined) ?? (typeof delta.message === "string" ? delta.message : undefined) ?? `${this.label} turn failed`;
6443
+ const stopReason = (typeof delta.stop_reason === "string" ? delta.stop_reason : undefined) ?? (typeof delta.error_type === "string" ? delta.error_type : undefined) ?? "error";
6444
+ const approvalConflict = isApprovalConflictSignal({
6445
+ detail,
6446
+ message: typeof delta.message === "string" ? delta.message : undefined,
6447
+ stopReason
6448
+ });
6449
+ return {
6450
+ type: "error",
6451
+ message: detail,
6452
+ errorCode: approvalConflict ? "approval_conflict" : toSdkErrorCode(stopReason),
6453
+ approvalConflict: approvalConflict || undefined,
6454
+ recoverable: approvalConflict ? true : false,
6455
+ errorDetail: detail,
6456
+ stopReason,
6457
+ runId
6458
+ };
6459
+ }
6460
+ if (messageType === "retry") {
6461
+ return {
6462
+ type: "retry",
6463
+ reason: typeof delta.reason === "string" ? delta.reason : "error",
6464
+ attempt: typeof delta.attempt === "number" ? delta.attempt : 0,
6465
+ maxAttempts: typeof delta.max_attempts === "number" ? delta.max_attempts : 0,
6466
+ delayMs: typeof delta.delay_ms === "number" ? delta.delay_ms : 0,
6467
+ runId
6468
+ };
6469
+ }
6470
+ if (messageType === "stop_reason" || messageType === "ping") {
6471
+ return null;
6472
+ }
6473
+ return {
6474
+ type: "stream_event",
6475
+ event: delta,
6476
+ uuid
6477
+ };
6478
+ }
6479
+ resultFromTurn(turn, tracker) {
6480
+ const stopReason = turn.stopReason ?? (turn.success === false ? "error" : undefined);
6481
+ const approvalConflict = isApprovalConflictSignal({
6482
+ detail: turn.detail,
6483
+ stopReason
6484
+ });
6485
+ const success = turn.success !== undefined ? turn.success && !approvalConflict && !FAILURE_STOP_REASONS.has(stopReason ?? "") : !approvalConflict && !FAILURE_STOP_REASONS.has(stopReason ?? "");
6486
+ const errorCode = approvalConflict ? "approval_conflict" : turn.errorCode ?? toSdkErrorCode(stopReason);
6487
+ return {
6488
+ type: "result",
6489
+ success,
6490
+ result: success ? tracker?.assistantText || undefined : undefined,
6491
+ error: success ? undefined : errorCode ?? stopReason ?? "error",
6492
+ errorCode: success ? undefined : errorCode ?? "error",
6493
+ approvalConflict: approvalConflict || undefined,
6494
+ recoverable: approvalConflict ? true : success ? undefined : false,
6495
+ errorDetail: success ? undefined : turn.detail,
6496
+ stopReason,
6497
+ durationMs: Date.now() - (tracker?.startedAt || this._activeTurnStartedAt),
6498
+ conversationId: turn.runtime.conversation_id,
6499
+ runIds: turn.runIds.length > 0 ? turn.runIds : undefined
6500
+ };
6501
+ }
6502
+ enqueue(message) {
6503
+ const resolver = this.streamResolvers.shift();
6504
+ if (resolver) {
6505
+ resolver(message);
6506
+ return;
6507
+ }
6508
+ this.streamQueue.push(message);
6509
+ }
6510
+ resolveAll(value) {
6511
+ for (const resolve of this.streamResolvers.splice(0)) {
6512
+ resolve(value);
6513
+ }
6514
+ }
6515
+ }
6516
+ // src/remote-client-session-core.ts
6517
+ class RemoteClientSessionCore {
6518
+ mode;
6519
+ controller = null;
6520
+ runtime = null;
6521
+ initialized = false;
6522
+ closed = false;
6523
+ _agentId = null;
6524
+ _sessionId = null;
6525
+ _conversationId = null;
6526
+ _model = "";
6527
+ _modelSettings = null;
6528
+ label;
6529
+ requestTimeoutMs;
6530
+ initializePromise = null;
6531
+ removeMessageHandler = null;
6532
+ turns;
6533
+ toolNames;
6534
+ deviceStatusListeners = new Set;
6535
+ deviceStatusRefreshCancels = new Set;
6536
+ constructor(mode, config) {
6537
+ this.mode = mode;
6538
+ this.label = config.label;
6539
+ this.requestTimeoutMs = config.requestTimeoutMs;
6540
+ this.turns = new RemoteTurnCoordinator({
6541
+ label: config.label,
6542
+ requestTimeoutMs: config.requestTimeoutMs,
6543
+ onDeviceStatus: (status) => this.emitDeviceStatus(status)
6544
+ });
6545
+ }
6546
+ async initialize() {
6547
+ if (this.closed) {
6548
+ throw new Error("Session is closed");
6549
+ }
6550
+ if (this.initializePromise) {
6551
+ return this.initializePromise;
6552
+ }
6553
+ if (this.initialized) {
6554
+ throw new Error("Session already initialized");
6555
+ }
6556
+ const attempt = this.performInitialize();
6557
+ const memo = attempt.catch((error) => {
6558
+ this.cleanupFailedInitialize();
6559
+ throw error;
6560
+ }).finally(() => {
6561
+ if (this.initializePromise === memo) {
6562
+ this.initializePromise = null;
6563
+ }
6564
+ });
6565
+ this.initializePromise = memo;
6566
+ return memo;
6567
+ }
6568
+ async performInitialize() {
6569
+ const init = await this.initializeRuntimeController();
6570
+ this.controller = init.controller;
6571
+ this.runtime = init.runtime;
6572
+ this._agentId = init.runtime.agent_id;
6573
+ this._conversationId = init.runtime.conversation_id;
6574
+ this._sessionId = `${init.runtime.agent_id}:${init.runtime.conversation_id}`;
6575
+ this._modelSettings = init.modelSettings ?? null;
6576
+ this._model = typeof init.model === "string" ? init.model : typeof this._modelSettings?.model === "string" ? this._modelSettings.model : "";
6577
+ this.toolNames = init.tools;
6578
+ this.removeMessageHandler = this.controller.onMessage((message) => {
6579
+ if (this.runtime)
6580
+ this.turns.handleProtocolMessage(message, this.runtime);
6581
+ });
6582
+ await this.afterRuntimeInitialized();
6583
+ await this.applyPostInitializeOptions();
6584
+ if (this.closed) {
6585
+ throw new Error("Session is closed");
6586
+ }
6587
+ this.initialized = true;
6588
+ const initMessage = {
6589
+ type: "init",
6590
+ agentId: init.runtime.agent_id,
6591
+ sessionId: this._sessionId,
6592
+ conversationId: init.runtime.conversation_id,
6593
+ model: this._model
6594
+ };
6595
+ if (this.toolNames !== undefined)
6596
+ initMessage.tools = this.toolNames;
6597
+ if (init.skillSources !== undefined) {
6598
+ initMessage.skillSources = init.skillSources;
6599
+ }
6600
+ return initMessage;
6601
+ }
6602
+ cleanupFailedInitialize() {
6603
+ this.removeMessageHandler?.();
6604
+ this.removeMessageHandler = null;
6605
+ this.controller?.close();
6606
+ this.controller = null;
6607
+ this.onCoreClose();
6608
+ this.runtime = null;
6609
+ this._agentId = null;
6610
+ this._conversationId = null;
6611
+ this._sessionId = null;
6612
+ this._modelSettings = null;
6613
+ this._model = "";
6614
+ this.toolNames = undefined;
6615
+ this.initialized = false;
6616
+ }
6617
+ async send(message) {
6618
+ if (!this.initialized) {
6619
+ await this.initialize();
6620
+ }
6621
+ if (!this.controller || !this.runtime) {
6622
+ throw new Error("Session is not initialized");
6623
+ }
6624
+ await this.beforeTurn();
6625
+ const turn = this.turns.trackSentTurn(this.runtime);
6626
+ try {
6627
+ this.controller.sendTurnMessage(this.runtime, message, {
6628
+ clientMessageId: turn.clientMessageId
6629
+ });
6630
+ } catch (error) {
6631
+ this.turns.removeTrackedTurn(turn);
6632
+ throw error;
6633
+ }
6634
+ }
6635
+ async runTurn(message, _options = {}) {
6636
+ if (this.turns.hasInFlightTurn()) {
6637
+ throw new Error(`A turn is already in flight for this ${this.label} session. Use send() and stream() to let the listener queue messages.`);
6638
+ }
6639
+ await this.send(message);
6640
+ for await (const msg of this.stream()) {
6641
+ if (msg.type === "result") {
6642
+ return msg;
6643
+ }
6644
+ }
6645
+ return {
6646
+ type: "result",
6647
+ success: false,
6648
+ error: "stream_closed",
6649
+ errorCode: "stream_closed",
6650
+ recoverable: false,
6651
+ errorDetail: "Stream ended before terminal result",
6652
+ durationMs: Date.now() - this.turns.activeTurnStartedAt,
6653
+ conversationId: this._conversationId
6654
+ };
6655
+ }
6656
+ async* stream() {
6657
+ while (true) {
6658
+ const msg = await this.turns.nextMessage();
6659
+ if (!msg)
6660
+ break;
6661
+ yield msg;
6662
+ if (msg.type === "result")
6663
+ break;
6664
+ }
6665
+ }
6666
+ async abort() {
6667
+ if (!this.initialized)
6668
+ return;
6669
+ if (!this.controller || !this.runtime)
6670
+ return;
6671
+ this.turns.markAbortRequested();
6672
+ await this.controller.abort(this.runtime);
6673
+ }
6674
+ async sendCommand(command, options) {
6675
+ if (!this.initialized) {
6676
+ await this.initialize();
6677
+ }
6678
+ if (!this.controller) {
6679
+ throw new Error("Session is not initialized");
6680
+ }
6681
+ if (!command || typeof command !== "object" || Array.isArray(command)) {
6682
+ throw new Error("Invalid command. Expected a protocol command object.");
6683
+ }
6684
+ if (typeof command.type !== "string" || command.type.length === 0) {
6685
+ throw new Error("Invalid command. Expected a non-empty type.");
6686
+ }
6687
+ if (!options || !options.responseType && !options.predicate && options.timeoutMs === undefined) {
6688
+ this.controller.send(command);
6689
+ return;
6690
+ }
6691
+ const { type, ...body } = command;
6692
+ const response = await this.controller.request(type, body, {
6693
+ ...options.timeoutMs !== undefined ? { timeoutMs: options.timeoutMs } : {},
6694
+ predicate: options.predicate ? (message) => options.predicate?.(message) === true : options.responseType ? (message) => message.type === options.responseType : undefined
6695
+ });
6696
+ return response;
6697
+ }
6698
+ async listModels() {
6699
+ if (!this.initialized) {
6700
+ await this.initialize();
6701
+ }
6702
+ if (!this.controller) {
6703
+ throw new Error("Session is not initialized");
6704
+ }
6705
+ return this.controller.listModels();
6706
+ }
6707
+ async updateModel(update) {
6708
+ if (!this.initialized) {
6709
+ await this.initialize();
6710
+ }
6711
+ if (!this.controller || !this.runtime) {
6712
+ throw new Error("Session is not initialized");
6713
+ }
6714
+ return this.applyModelUpdate(update);
6715
+ }
6716
+ async applyModelUpdate(update) {
6717
+ if (!this.controller || !this.runtime) {
6718
+ throw new Error("Session is not initialized");
6719
+ }
6720
+ const normalized = normalizeUpdateModelInput(update);
6721
+ const payload = await this.resolveUpdateModelPayload(normalized);
6722
+ const result = await this.controller.updateModel(this.runtime, payload);
6723
+ if (result.modelHandle !== undefined) {
6724
+ this._model = result.modelHandle;
6725
+ } else if (payload.model_handle !== undefined) {
6726
+ this._model = payload.model_handle;
6727
+ } else if (typeof result.modelSettings?.model === "string") {
6728
+ this._model = result.modelSettings.model;
6729
+ }
6341
6730
  if ("modelSettings" in result) {
6342
6731
  this._modelSettings = result.modelSettings ?? null;
6343
6732
  }
@@ -6456,561 +6845,211 @@ class RemoteClientSessionCore {
6456
6845
  });
6457
6846
  });
6458
6847
  }
6459
- async listMessages(options = {}) {
6460
- if (!this.initialized) {
6461
- await this.initialize();
6462
- }
6463
- if (!this.controller) {
6464
- throw new Error("Session is not initialized");
6465
- }
6466
- const conversationId = options.conversationId ?? this._conversationId;
6467
- if (!conversationId) {
6468
- throw new Error("No conversation id available for listMessages()");
6469
- }
6470
- return this.controller.listMessages(conversationId, options);
6471
- }
6472
- async bootstrapState(options = {}) {
6473
- if (!this.initialized) {
6474
- await this.initialize();
6475
- }
6476
- const page = await this.listMessages({
6477
- limit: options.limit,
6478
- order: options.order
6479
- });
6480
- const state = {
6481
- agentId: this._agentId ?? "",
6482
- conversationId: this._conversationId ?? "",
6483
- model: this._model,
6484
- messages: page.messages
6485
- };
6486
- if (this.toolNames !== undefined) {
6487
- state.tools = this.toolNames;
6488
- }
6489
- if (page.nextBefore !== undefined) {
6490
- state.nextBefore = page.nextBefore;
6491
- }
6492
- if (page.hasMore !== undefined) {
6493
- state.hasMore = page.hasMore;
6494
- }
6495
- return state;
6496
- }
6497
- close() {
6498
- if (this.closed)
6499
- return;
6500
- this.closed = true;
6501
- this.removeMessageHandler?.();
6502
- this.removeMessageHandler = null;
6503
- if (this.activeTurn?.timeout)
6504
- clearTimeout(this.activeTurn.timeout);
6505
- for (const turn of this.pendingTurns) {
6506
- if (turn.timeout)
6507
- clearTimeout(turn.timeout);
6508
- }
6509
- this.activeTurn = null;
6510
- this.pendingTurns.length = 0;
6511
- for (const cancel of [...this.deviceStatusRefreshCancels]) {
6512
- cancel(new Error(`Session closed while waiting for ${this.label} device status`));
6513
- }
6514
- this.deviceStatusRefreshCancels.clear();
6515
- this.deviceStatusListeners.clear();
6516
- this.controller?.close();
6517
- this.controller = null;
6518
- this.onCoreClose();
6519
- this.resolveAll(null);
6520
- }
6521
- get agentId() {
6522
- return this._agentId;
6523
- }
6524
- get sessionId() {
6525
- return this._sessionId;
6526
- }
6527
- get conversationId() {
6528
- return this._conversationId;
6529
- }
6530
- async[Symbol.asyncDispose]() {
6531
- this.close();
6532
- }
6533
- async changeDeviceState(updates) {
6534
- if (!this.initialized) {
6535
- await this.initialize();
6536
- }
6537
- if (!this.controller || !this.runtime) {
6538
- throw new Error("Session is not initialized");
6539
- }
6540
- const payload = {};
6541
- if (updates.cwd !== undefined)
6542
- payload.cwd = updates.cwd;
6543
- if (updates.permissionMode !== undefined) {
6544
- const mode = mapPermissionMode(updates.permissionMode);
6545
- if (mode !== undefined)
6546
- payload.mode = mode;
6547
- }
6548
- if (Object.keys(payload).length === 0) {
6549
- throw new Error("Invalid device state update. Expected cwd or permissionMode.");
6550
- }
6551
- this.controller.send({
6552
- type: "change_device_state",
6553
- runtime: this.runtime,
6554
- payload
6555
- });
6556
- }
6557
- async updateToolset(toolsetPreference) {
6558
- if (!this.initialized) {
6559
- await this.initialize();
6560
- }
6561
- if (!this.controller || !this.runtime) {
6562
- throw new Error("Session is not initialized");
6563
- }
6564
- const response = await this.controller.request("update_toolset", {
6565
- runtime: this.runtime,
6566
- toolset_preference: toolsetPreference
6567
- }, { predicate: (message) => message.type === "update_toolset_response" });
6568
- ensureSuccess(response, "Failed to update toolset");
6569
- }
6570
- async afterRuntimeInitialized() {}
6571
- async beforeTurn() {}
6572
- onCoreClose() {}
6573
- currentOptions() {
6574
- return this.mode.options;
6575
- }
6576
- shouldEnableMemfs(options) {
6577
- return false;
6578
- }
6579
- enableMemfsBody() {
6580
- if (!this.runtime)
6581
- return {};
6582
- return { agent_id: this.runtime.agent_id };
6583
- }
6584
- setModel(model) {
6585
- this._model = model;
6586
- }
6587
- trackSentTurn(runtime) {
6588
- const turn = {
6589
- id: ++this.nextTurnId,
6590
- runtime,
6591
- clientMessageId: `sdk-message-${Date.now()}-${++this.clientMessageCounter}`,
6592
- queuedAt: Date.now(),
6593
- startedAt: 0,
6594
- assistantText: "",
6595
- runIds: new Set,
6596
- observedTurnEvidence: false,
6597
- observedRequiresApprovalStop: false,
6598
- abortRequested: false,
6599
- timeout: null
6600
- };
6601
- if (this.activeTurn) {
6602
- this.pendingTurns.push(turn);
6603
- } else {
6604
- this.activateTurn(turn);
6605
- }
6606
- return turn;
6607
- }
6608
- activateTurn(turn) {
6609
- this.activeTurn = turn;
6610
- turn.startedAt = Date.now();
6611
- this.activeTurnStartedAt = turn.startedAt;
6612
- if (this.requestTimeoutMs !== undefined) {
6613
- turn.timeout = setTimeout(() => {
6614
- this.failTurn(turn, `Timed out waiting for ${this.label} turn`);
6615
- }, this.requestTimeoutMs);
6616
- turn.timeout.unref?.();
6617
- }
6618
- }
6619
- activateNextTurnFromProtocol() {
6620
- if (this.activeTurn)
6621
- return this.activeTurn;
6622
- const next = this.pendingTurns.shift();
6623
- if (!next)
6624
- return null;
6625
- this.activateTurn(next);
6626
- return next;
6627
- }
6628
- removeTrackedTurn(turn) {
6629
- if (turn.timeout)
6630
- clearTimeout(turn.timeout);
6631
- if (this.activeTurn === turn) {
6632
- this.activeTurn = null;
6633
- return;
6634
- }
6635
- const index = this.pendingTurns.indexOf(turn);
6636
- if (index !== -1)
6637
- this.pendingTurns.splice(index, 1);
6638
- }
6639
- failTurn(turn, detail) {
6640
- if (this.activeTurn !== turn)
6641
- return;
6642
- this.enqueue({
6643
- type: "error",
6644
- message: detail,
6645
- errorCode: "error",
6646
- stopReason: "error",
6647
- errorDetail: detail,
6648
- recoverable: false
6649
- });
6650
- this.completeActiveTurn({
6651
- runtime: turn.runtime,
6652
- stopReason: "error",
6653
- runIds: [...turn.runIds],
6654
- success: false,
6655
- detail,
6656
- errorCode: "error"
6657
- });
6658
- }
6659
- completeActiveTurn(turn) {
6660
- const active = this.activeTurn;
6661
- if (!active)
6662
- return;
6663
- if (active.timeout) {
6664
- clearTimeout(active.timeout);
6665
- active.timeout = null;
6666
- }
6667
- this.enqueue(this.resultFromTurn(turn, active));
6668
- this.activeTurn = null;
6669
- }
6670
- async resolveUpdateModelPayload(input) {
6671
- if (input.reasoningEffort === undefined) {
6672
- return modelPayloadWithoutReasoning(input);
6848
+ async listMessages(options = {}) {
6849
+ if (!this.initialized) {
6850
+ await this.initialize();
6673
6851
  }
6674
6852
  if (!this.controller) {
6675
6853
  throw new Error("Session is not initialized");
6676
6854
  }
6677
- const catalog = await this.controller.listModels();
6678
- const byId = new Map(catalog.entries.map((entry) => [entry.id, entry]));
6679
- const aliases = catalog.byokProviderAliases;
6680
- let baseEntry;
6681
- let explicitHandle;
6682
- let targetHandle;
6683
- if (input.modelId !== undefined) {
6684
- baseEntry = byId.get(input.modelId);
6685
- explicitHandle = input.modelHandle;
6686
- targetHandle = baseEntry?.handle ?? toBaseModelHandle(input.modelHandle, aliases);
6687
- } else if (input.modelHandle !== undefined) {
6688
- explicitHandle = input.modelHandle;
6689
- targetHandle = toBaseModelHandle(input.modelHandle, aliases);
6690
- } else if (input.model !== undefined) {
6691
- baseEntry = byId.get(input.model);
6692
- if (baseEntry) {
6693
- targetHandle = baseEntry.handle;
6694
- } else {
6695
- explicitHandle = input.model;
6696
- targetHandle = toBaseModelHandle(input.model, aliases);
6697
- }
6698
- } else {
6699
- explicitHandle = this._model || undefined;
6700
- targetHandle = toBaseModelHandle(this._model || undefined, aliases);
6855
+ const conversationId = options.conversationId ?? this._conversationId;
6856
+ if (!conversationId) {
6857
+ throw new Error("No conversation id available for listMessages()");
6701
6858
  }
6702
- if (!targetHandle) {
6703
- throw new Error("reasoningEffort requires a current model or explicit model/modelId/modelHandle.");
6859
+ return this.controller.listMessages(conversationId, options);
6860
+ }
6861
+ async bootstrapState(options = {}) {
6862
+ if (!this.initialized) {
6863
+ await this.initialize();
6704
6864
  }
6705
- const candidates = catalog.entries.filter((entry) => entry.handle === targetHandle || entry.handle === explicitHandle);
6706
- if (candidates.length === 0) {
6707
- throw new Error(`reasoningEffort requires a model from listModels(); no catalog entry found for ${targetHandle}.`);
6865
+ const page = await this.listMessages({
6866
+ limit: options.limit,
6867
+ order: options.order
6868
+ });
6869
+ const state = {
6870
+ agentId: this._agentId ?? "",
6871
+ conversationId: this._conversationId ?? "",
6872
+ model: this._model,
6873
+ messages: page.messages
6874
+ };
6875
+ if (this.toolNames !== undefined) {
6876
+ state.tools = this.toolNames;
6708
6877
  }
6709
- const contextWindow = getContextWindow(baseEntry?.updateArgs) ?? getContextWindow(this._modelSettings);
6710
- const scopedCandidates = sameContextCandidates(candidates, contextWindow);
6711
- const matchingEntry = scopedCandidates.find((entry) => getReasoningEffort(entry) === input.reasoningEffort) ?? candidates.find((entry) => getReasoningEffort(entry) === input.reasoningEffort);
6712
- if (!matchingEntry) {
6713
- throw new Error(`No ${input.reasoningEffort} reasoning tier found for model ${targetHandle}.`);
6878
+ if (page.nextBefore !== undefined) {
6879
+ state.nextBefore = page.nextBefore;
6714
6880
  }
6715
- const payload = { model_id: matchingEntry.id };
6716
- if (explicitHandle !== undefined) {
6717
- payload.model_handle = explicitHandle;
6881
+ if (page.hasMore !== undefined) {
6882
+ state.hasMore = page.hasMore;
6718
6883
  }
6719
- return payload;
6884
+ return state;
6720
6885
  }
6721
- async applyPostInitializeOptions() {
6722
- if (!this.controller || !this.runtime)
6723
- return;
6724
- const options = this.currentOptions();
6725
- if (this.shouldEnableMemfs(options)) {
6726
- const response = await this.controller.request("enable_memfs", this.enableMemfsBody(), {
6727
- predicate: (message) => message.type === "enable_memfs_response",
6728
- timeoutMs: 180000
6729
- });
6730
- ensureSuccess(response, "Failed to enable memfs");
6731
- }
6732
- const dreamingSettings = resolveDreamingSettings(options.dreaming);
6733
- if (dreamingSettings) {
6734
- const response = await this.controller.request("set_reflection_settings", {
6735
- runtime: this.runtime,
6736
- settings: dreamingSettings,
6737
- scope: "both"
6738
- }, { predicate: (message) => message.type === "set_reflection_settings_response" });
6739
- ensureSuccess(response, "Failed to update dreaming settings");
6740
- }
6741
- if (this.mode.kind !== "session")
6886
+ close() {
6887
+ if (this.closed)
6742
6888
  return;
6743
- if (this.mode.options.model !== undefined || this.mode.options.reasoningEffort !== undefined) {
6744
- await this.applyModelUpdate({
6745
- ...this.mode.options.model !== undefined ? { model: this.mode.options.model } : {},
6746
- ...this.mode.options.reasoningEffort !== undefined ? { reasoningEffort: this.mode.options.reasoningEffort } : {}
6747
- });
6889
+ this.closed = true;
6890
+ this.removeMessageHandler?.();
6891
+ this.removeMessageHandler = null;
6892
+ this.turns.close();
6893
+ for (const cancel of [...this.deviceStatusRefreshCancels]) {
6894
+ cancel(new Error(`Session closed while waiting for ${this.label} device status`));
6748
6895
  }
6896
+ this.deviceStatusRefreshCancels.clear();
6897
+ this.deviceStatusListeners.clear();
6898
+ this.controller?.close();
6899
+ this.controller = null;
6900
+ this.onCoreClose();
6749
6901
  }
6750
- handleProtocolMessage = (message) => {
6751
- if (!this.runtime || !sameRuntime2(message, this.runtime))
6752
- return;
6753
- const deviceStatus = deviceStatusRecord(message);
6754
- if (deviceStatus) {
6755
- const status = toSessionDeviceStatus(deviceStatus);
6756
- if (!status)
6757
- return;
6758
- for (const listener of [...this.deviceStatusListeners]) {
6759
- try {
6760
- listener(status);
6761
- } catch {}
6762
- }
6763
- return;
6764
- }
6765
- if (message.type === "update_queue") {
6766
- const sdkMessage2 = {
6767
- type: "queue_update",
6768
- queue: queueItems(message)
6769
- };
6770
- this.enqueue(sdkMessage2);
6771
- return;
6772
- }
6773
- if (message.type === "update_loop_status") {
6774
- this.handleLoopStatusMessage(message);
6775
- return;
6776
- }
6777
- const delta = streamDeltaRecord(message);
6778
- if (!delta)
6779
- return;
6780
- const active = this.activateNextTurnFromProtocol();
6781
- if (active) {
6782
- active.observedTurnEvidence = true;
6783
- const runId = streamDeltaRunId2(delta);
6784
- if (runId)
6785
- active.runIds.add(runId);
6786
- }
6787
- const sdkMessage = this.transformStreamDelta(delta);
6788
- if (sdkMessage) {
6789
- this.enqueue(sdkMessage);
6902
+ get agentId() {
6903
+ return this._agentId;
6904
+ }
6905
+ get sessionId() {
6906
+ return this._sessionId;
6907
+ }
6908
+ get conversationId() {
6909
+ return this._conversationId;
6910
+ }
6911
+ async[Symbol.asyncDispose]() {
6912
+ this.close();
6913
+ }
6914
+ async changeDeviceState(updates) {
6915
+ if (!this.initialized) {
6916
+ await this.initialize();
6790
6917
  }
6791
- this.handleTurnTerminalDelta(delta, sdkMessage);
6792
- };
6793
- handleLoopStatusMessage(message) {
6794
- const status = loopStatusValue(message);
6795
- if (!status)
6796
- return;
6797
- const activeRunIds = loopStatusRunIds(message);
6798
- const sdkMessage = {
6799
- type: "loop_status",
6800
- status,
6801
- activeRunIds
6802
- };
6803
- this.enqueue(sdkMessage);
6804
- const active = this.activeTurn;
6805
- if (!active)
6806
- return;
6807
- for (const runId of activeRunIds)
6808
- active.runIds.add(runId);
6809
- const hadTurnEvidence = active.observedTurnEvidence || active.observedRequiresApprovalStop;
6810
- if (!hadTurnEvidence)
6811
- return;
6812
- if (status === "WAITING_ON_APPROVAL") {
6813
- this.completeActiveTurn({
6814
- runtime: active.runtime,
6815
- stopReason: "requires_approval",
6816
- runIds: [...active.runIds]
6817
- });
6818
- return;
6918
+ if (!this.controller || !this.runtime) {
6919
+ throw new Error("Session is not initialized");
6819
6920
  }
6820
- if (status === "WAITING_ON_INPUT" && active.abortRequested) {
6821
- this.completeActiveTurn({
6822
- runtime: active.runtime,
6823
- stopReason: "interrupted",
6824
- runIds: [...active.runIds],
6825
- success: false,
6826
- detail: "Interrupted",
6827
- errorCode: "interrupted"
6828
- });
6829
- return;
6921
+ const payload = {};
6922
+ if (updates.cwd !== undefined)
6923
+ payload.cwd = updates.cwd;
6924
+ if (updates.permissionMode !== undefined) {
6925
+ const mode = mapPermissionMode(updates.permissionMode);
6926
+ if (mode !== undefined)
6927
+ payload.mode = mode;
6830
6928
  }
6831
- if (status === "WAITING_ON_INPUT" && active.observedTurnEvidence) {
6832
- this.completeActiveTurn({
6833
- runtime: active.runtime,
6834
- stopReason: null,
6835
- runIds: [...active.runIds]
6836
- });
6929
+ if (Object.keys(payload).length === 0) {
6930
+ throw new Error("Invalid device state update. Expected cwd or permissionMode.");
6837
6931
  }
6932
+ this.controller.send({
6933
+ type: "change_device_state",
6934
+ runtime: this.runtime,
6935
+ payload
6936
+ });
6838
6937
  }
6839
- handleTurnTerminalDelta(delta, sdkMessage) {
6840
- const active = this.activeTurn;
6841
- if (!active)
6842
- return;
6843
- const messageType = streamDeltaMessageType2(delta);
6844
- if (messageType === "stop_reason") {
6845
- const stopReason = streamDeltaStopReason2(delta) ?? null;
6846
- if (stopReason === "requires_approval") {
6847
- active.observedRequiresApprovalStop = true;
6848
- return;
6849
- }
6850
- this.completeActiveTurn({
6851
- runtime: active.runtime,
6852
- stopReason,
6853
- runIds: [...active.runIds]
6854
- });
6855
- return;
6938
+ async updateToolset(toolsetPreference) {
6939
+ if (!this.initialized) {
6940
+ await this.initialize();
6856
6941
  }
6857
- if (sdkMessage?.type === "error") {
6858
- this.completeActiveTurn({
6859
- runtime: active.runtime,
6860
- stopReason: sdkMessage.stopReason,
6861
- runIds: [...active.runIds],
6862
- success: false,
6863
- detail: sdkMessage.errorDetail ?? sdkMessage.message,
6864
- errorCode: sdkMessage.errorCode
6865
- });
6942
+ if (!this.controller || !this.runtime) {
6943
+ throw new Error("Session is not initialized");
6866
6944
  }
6945
+ const response = await this.controller.request("update_toolset", {
6946
+ runtime: this.runtime,
6947
+ toolset_preference: toolsetPreference
6948
+ }, { predicate: (message) => message.type === "update_toolset_response" });
6949
+ ensureSuccess(response, "Failed to update toolset");
6950
+ }
6951
+ async afterRuntimeInitialized() {}
6952
+ async beforeTurn() {}
6953
+ onCoreClose() {}
6954
+ currentOptions() {
6955
+ return this.mode.options;
6956
+ }
6957
+ shouldEnableMemfs(options) {
6958
+ return false;
6959
+ }
6960
+ enableMemfsBody() {
6961
+ if (!this.runtime)
6962
+ return {};
6963
+ return { agent_id: this.runtime.agent_id };
6867
6964
  }
6868
- transformStreamDelta(delta) {
6869
- const messageType = typeof delta.message_type === "string" ? delta.message_type : undefined;
6870
- const runId = typeof delta.run_id === "string" ? delta.run_id : undefined;
6871
- const uuid = typeof delta.id === "string" ? delta.id : `${this.label}-${++this.messageCounter}`;
6872
- if (messageType === "assistant_message") {
6873
- const content = extractTextFromContent(delta.content);
6874
- if (!content)
6875
- return null;
6876
- if (this.activeTurn)
6877
- this.activeTurn.assistantText += content;
6878
- return { type: "assistant", content, uuid, runId };
6965
+ setModel(model) {
6966
+ this._model = model;
6967
+ }
6968
+ async resolveUpdateModelPayload(input) {
6969
+ if (input.reasoningEffort === undefined) {
6970
+ return modelPayloadWithoutReasoning(input);
6879
6971
  }
6880
- if (messageType === "reasoning_message") {
6881
- const content = typeof delta.reasoning === "string" ? delta.reasoning : extractTextFromContent(delta.content);
6882
- if (!content)
6883
- return null;
6884
- return { type: "reasoning", content, uuid, runId };
6972
+ if (!this.controller) {
6973
+ throw new Error("Session is not initialized");
6885
6974
  }
6886
- if (messageType === "tool_call_message" || messageType === "approval_request_message") {
6887
- const toolCall = firstToolCall(delta);
6888
- if (!toolCall)
6889
- return null;
6890
- const fn = toolCall.function && typeof toolCall.function === "object" ? toolCall.function : undefined;
6891
- const toolCallId = (typeof toolCall.tool_call_id === "string" ? toolCall.tool_call_id : undefined) ?? (typeof toolCall.id === "string" ? toolCall.id : undefined);
6892
- if (!toolCallId) {
6893
- const detail = `Missing tool_call_id in ${messageType} (uuid=${uuid})`;
6894
- return {
6895
- type: "error",
6896
- message: detail,
6897
- errorCode: "protocol_error",
6898
- stopReason: "protocol_error",
6899
- runId,
6900
- recoverable: false,
6901
- errorDetail: detail
6902
- };
6975
+ const catalog = await this.controller.listModels();
6976
+ const byId = new Map(catalog.entries.map((entry) => [entry.id, entry]));
6977
+ const aliases = catalog.byokProviderAliases;
6978
+ let baseEntry;
6979
+ let explicitHandle;
6980
+ let targetHandle;
6981
+ if (input.modelId !== undefined) {
6982
+ baseEntry = byId.get(input.modelId);
6983
+ explicitHandle = input.modelHandle;
6984
+ targetHandle = baseEntry?.handle ?? toBaseModelHandle(input.modelHandle, aliases);
6985
+ } else if (input.modelHandle !== undefined) {
6986
+ explicitHandle = input.modelHandle;
6987
+ targetHandle = toBaseModelHandle(input.modelHandle, aliases);
6988
+ } else if (input.model !== undefined) {
6989
+ baseEntry = byId.get(input.model);
6990
+ if (baseEntry) {
6991
+ targetHandle = baseEntry.handle;
6992
+ } else {
6993
+ explicitHandle = input.model;
6994
+ targetHandle = toBaseModelHandle(input.model, aliases);
6903
6995
  }
6904
- const toolName = (typeof toolCall.name === "string" ? toolCall.name : undefined) ?? (typeof fn?.name === "string" ? fn.name : undefined) ?? "?";
6905
- const { input, raw } = toolInputFromArguments(toolCall.arguments ?? fn?.arguments);
6906
- return {
6907
- type: "tool_call",
6908
- toolCallId,
6909
- toolName,
6910
- toolInput: input,
6911
- rawArguments: raw,
6912
- uuid,
6913
- runId
6914
- };
6996
+ } else {
6997
+ explicitHandle = this._model || undefined;
6998
+ targetHandle = toBaseModelHandle(this._model || undefined, aliases);
6915
6999
  }
6916
- if (messageType === "tool_return_message") {
6917
- const toolReturn = firstToolReturn(delta) ?? delta;
6918
- const toolCallId = (typeof delta.tool_call_id === "string" ? delta.tool_call_id : undefined) ?? (typeof toolReturn.tool_call_id === "string" ? toolReturn.tool_call_id : undefined);
6919
- if (!toolCallId)
6920
- return null;
6921
- const content = extractTextFromContent(delta.tool_return ?? toolReturn.tool_return ?? toolReturn.content) ?? "";
6922
- const status = typeof delta.status === "string" ? delta.status : toolReturn.status;
6923
- return {
6924
- type: "tool_result",
6925
- toolCallId,
6926
- content,
6927
- isError: status === "error",
6928
- uuid,
6929
- runId
6930
- };
7000
+ if (!targetHandle) {
7001
+ throw new Error("reasoningEffort requires a current model or explicit model/modelId/modelHandle.");
6931
7002
  }
6932
- if (messageType === "error_message" || messageType === "loop_error") {
6933
- const detail = (typeof delta.detail === "string" ? delta.detail : undefined) ?? (typeof delta.message === "string" ? delta.message : undefined) ?? `${this.label} turn failed`;
6934
- const stopReason = (typeof delta.stop_reason === "string" ? delta.stop_reason : undefined) ?? (typeof delta.error_type === "string" ? delta.error_type : undefined) ?? "error";
6935
- const approvalConflict = isApprovalConflictSignal({
6936
- detail,
6937
- message: typeof delta.message === "string" ? delta.message : undefined,
6938
- stopReason
6939
- });
6940
- return {
6941
- type: "error",
6942
- message: detail,
6943
- errorCode: approvalConflict ? "approval_conflict" : toSdkErrorCode(stopReason),
6944
- approvalConflict: approvalConflict || undefined,
6945
- recoverable: approvalConflict ? true : false,
6946
- errorDetail: detail,
6947
- stopReason,
6948
- runId
6949
- };
7003
+ const candidates = catalog.entries.filter((entry) => entry.handle === targetHandle || entry.handle === explicitHandle);
7004
+ if (candidates.length === 0) {
7005
+ throw new Error(`reasoningEffort requires a model from listModels(); no catalog entry found for ${targetHandle}.`);
6950
7006
  }
6951
- if (messageType === "retry") {
6952
- return {
6953
- type: "retry",
6954
- reason: typeof delta.reason === "string" ? delta.reason : "error",
6955
- attempt: typeof delta.attempt === "number" ? delta.attempt : 0,
6956
- maxAttempts: typeof delta.max_attempts === "number" ? delta.max_attempts : 0,
6957
- delayMs: typeof delta.delay_ms === "number" ? delta.delay_ms : 0,
6958
- runId
6959
- };
7007
+ const contextWindow = getContextWindow(baseEntry?.updateArgs) ?? getContextWindow(this._modelSettings);
7008
+ const scopedCandidates = sameContextCandidates(candidates, contextWindow);
7009
+ const matchingEntry = scopedCandidates.find((entry) => getReasoningEffort(entry) === input.reasoningEffort) ?? candidates.find((entry) => getReasoningEffort(entry) === input.reasoningEffort);
7010
+ if (!matchingEntry) {
7011
+ throw new Error(`No ${input.reasoningEffort} reasoning tier found for model ${targetHandle}.`);
6960
7012
  }
6961
- if (messageType === "stop_reason" || messageType === "ping") {
6962
- return null;
7013
+ const payload = { model_id: matchingEntry.id };
7014
+ if (explicitHandle !== undefined) {
7015
+ payload.model_handle = explicitHandle;
6963
7016
  }
6964
- return {
6965
- type: "stream_event",
6966
- event: delta,
6967
- uuid
6968
- };
6969
- }
6970
- resultFromTurn(turn, tracker) {
6971
- const stopReason = turn.stopReason ?? (turn.success === false ? "error" : undefined);
6972
- const approvalConflict = isApprovalConflictSignal({
6973
- detail: turn.detail,
6974
- stopReason
6975
- });
6976
- const success = turn.success !== undefined ? turn.success && !approvalConflict && !FAILURE_STOP_REASONS.has(stopReason ?? "") : !approvalConflict && !FAILURE_STOP_REASONS.has(stopReason ?? "");
6977
- const errorCode = approvalConflict ? "approval_conflict" : turn.errorCode ?? toSdkErrorCode(stopReason);
6978
- return {
6979
- type: "result",
6980
- success,
6981
- result: success ? tracker?.assistantText || undefined : undefined,
6982
- error: success ? undefined : errorCode ?? stopReason ?? "error",
6983
- errorCode: success ? undefined : errorCode ?? "error",
6984
- approvalConflict: approvalConflict || undefined,
6985
- recoverable: approvalConflict ? true : success ? undefined : false,
6986
- errorDetail: success ? undefined : turn.detail,
6987
- stopReason,
6988
- durationMs: Date.now() - (tracker?.startedAt || this.activeTurnStartedAt),
6989
- conversationId: turn.runtime.conversation_id,
6990
- runIds: turn.runIds.length > 0 ? turn.runIds : undefined
6991
- };
7017
+ return payload;
6992
7018
  }
6993
- enqueue(message) {
6994
- const resolver = this.streamResolvers.shift();
6995
- if (resolver) {
6996
- resolver(message);
7019
+ async applyPostInitializeOptions() {
7020
+ if (!this.controller || !this.runtime)
6997
7021
  return;
7022
+ const options = this.currentOptions();
7023
+ if (this.shouldEnableMemfs(options)) {
7024
+ const response = await this.controller.request("enable_memfs", this.enableMemfsBody(), {
7025
+ predicate: (message) => message.type === "enable_memfs_response",
7026
+ timeoutMs: 180000
7027
+ });
7028
+ ensureSuccess(response, "Failed to enable memfs");
7029
+ }
7030
+ const dreamingSettings = resolveDreamingSettings(options.dreaming);
7031
+ if (dreamingSettings) {
7032
+ const response = await this.controller.request("set_reflection_settings", {
7033
+ runtime: this.runtime,
7034
+ settings: dreamingSettings,
7035
+ scope: "both"
7036
+ }, { predicate: (message) => message.type === "set_reflection_settings_response" });
7037
+ ensureSuccess(response, "Failed to update dreaming settings");
7038
+ }
7039
+ if (this.mode.kind !== "session")
7040
+ return;
7041
+ if (this.mode.options.model !== undefined || this.mode.options.reasoningEffort !== undefined) {
7042
+ await this.applyModelUpdate({
7043
+ ...this.mode.options.model !== undefined ? { model: this.mode.options.model } : {},
7044
+ ...this.mode.options.reasoningEffort !== undefined ? { reasoningEffort: this.mode.options.reasoningEffort } : {}
7045
+ });
6998
7046
  }
6999
- this.streamQueue.push(message);
7000
- }
7001
- nextMessage() {
7002
- const next = this.streamQueue.shift();
7003
- if (next)
7004
- return Promise.resolve(next);
7005
- if (this.closed)
7006
- return Promise.resolve(null);
7007
- return new Promise((resolve) => {
7008
- this.streamResolvers.push(resolve);
7009
- });
7010
7047
  }
7011
- resolveAll(value) {
7012
- for (const resolve of this.streamResolvers.splice(0)) {
7013
- resolve(value);
7048
+ emitDeviceStatus(status) {
7049
+ for (const listener of [...this.deviceStatusListeners]) {
7050
+ try {
7051
+ listener(status);
7052
+ } catch {}
7014
7053
  }
7015
7054
  }
7016
7055
  }
@@ -7911,13 +7950,58 @@ class RemoteEnvironmentClient {
7911
7950
  }
7912
7951
  }
7913
7952
 
7953
+ // src/cloud-sandbox.ts
7954
+ var MIN_TTL_MINUTES = 1;
7955
+ var MAX_TTL_MINUTES = 60;
7956
+ var MAX_GITHUB_REPOSITORIES = 10;
7957
+ var GITHUB_OWNER_PATTERN = /^[A-Za-z0-9-]+$/;
7958
+ var GITHUB_REPOSITORY_PATTERN = /^[A-Za-z0-9._-]+$/;
7959
+ function validatePositiveInteger(value, name) {
7960
+ if (value !== undefined && (!Number.isInteger(value) || value <= 0)) {
7961
+ throw new Error(`Invalid ${name}. Expected a positive integer.`);
7962
+ }
7963
+ }
7964
+ function validateCloudSandboxOptions(options, name) {
7965
+ if (options === undefined)
7966
+ return;
7967
+ if (options === null || typeof options !== "object" || Array.isArray(options)) {
7968
+ throw new Error(`Invalid ${name}. Expected an object.`);
7969
+ }
7970
+ if (options.ttlMinutes !== undefined && (!Number.isInteger(options.ttlMinutes) || options.ttlMinutes < MIN_TTL_MINUTES || options.ttlMinutes > MAX_TTL_MINUTES)) {
7971
+ throw new Error(`Invalid ${name}.ttlMinutes. Expected an integer between ${MIN_TTL_MINUTES} and ${MAX_TTL_MINUTES}.`);
7972
+ }
7973
+ validatePositiveInteger(options.readyTimeoutMs, `${name}.readyTimeoutMs`);
7974
+ validatePositiveInteger(options.readyPollIntervalMs, `${name}.readyPollIntervalMs`);
7975
+ validatePositiveInteger(options.refreshIntervalMs, `${name}.refreshIntervalMs`);
7976
+ if (options.githubRepositories !== undefined) {
7977
+ if (!Array.isArray(options.githubRepositories)) {
7978
+ throw new Error(`Invalid ${name}.githubRepositories. Expected an array.`);
7979
+ }
7980
+ if (options.githubRepositories.length > MAX_GITHUB_REPOSITORIES) {
7981
+ throw new Error(`Invalid ${name}.githubRepositories. Expected at most ${MAX_GITHUB_REPOSITORIES} repositories.`);
7982
+ }
7983
+ for (const [index, repository] of options.githubRepositories.entries()) {
7984
+ if (repository === null || typeof repository !== "object" || Array.isArray(repository)) {
7985
+ throw new Error(`Invalid ${name}.githubRepositories[${index}]. Expected an object.`);
7986
+ }
7987
+ if (typeof repository.owner !== "string" || !GITHUB_OWNER_PATTERN.test(repository.owner)) {
7988
+ throw new Error(`Invalid ${name}.githubRepositories[${index}].owner.`);
7989
+ }
7990
+ if (typeof repository.repo !== "string" || !GITHUB_REPOSITORY_PATTERN.test(repository.repo)) {
7991
+ throw new Error(`Invalid ${name}.githubRepositories[${index}].repo.`);
7992
+ }
7993
+ }
7994
+ }
7995
+ if (options.terminateOnClose !== undefined && typeof options.terminateOnClose !== "boolean") {
7996
+ throw new Error(`Invalid ${name}.terminateOnClose. Expected a boolean.`);
7997
+ }
7998
+ }
7999
+
7914
8000
  // src/cloud-session.ts
7915
8001
  var DEFAULT_CLOUD_API_BASE_URL3 = "https://api.letta.com";
7916
8002
  var DEFAULT_TURN_TIMEOUT_MS = 120000;
7917
8003
  var DEFAULT_PING_INTERVAL_MS = 30000;
7918
8004
  var DEFAULT_SANDBOX_TTL_MINUTES = 5;
7919
- var MIN_SANDBOX_TTL_MINUTES = 1;
7920
- var MAX_SANDBOX_TTL_MINUTES = 60;
7921
8005
  var DEFAULT_SANDBOX_READY_TIMEOUT_MS = 120000;
7922
8006
  var DEFAULT_SANDBOX_READY_POLL_INTERVAL_MS = 1000;
7923
8007
  var DEFAULT_REPOSITORY_ATTACH_TIMEOUT_MS = 1e4;
@@ -8028,34 +8112,13 @@ function assertOkResponse2(response, body, action, url) {
8028
8112
  throw new Error(parts.join(" — "));
8029
8113
  }
8030
8114
  }
8031
- function validatePositiveInteger(value, name) {
8115
+ function validatePositiveInteger2(value, name) {
8032
8116
  if (value !== undefined && (!Number.isInteger(value) || value <= 0)) {
8033
8117
  throw new Error(`Invalid ${name}. Expected a positive integer.`);
8034
8118
  }
8035
8119
  }
8036
- function validateIntegerRange(value, name, min, max) {
8037
- if (value === undefined)
8038
- return;
8039
- if (!Number.isInteger(value) || value < min || value > max) {
8040
- throw new Error(`Invalid ${name}. Expected an integer between ${min} and ${max}.`);
8041
- }
8042
- }
8043
- function validateCloudSandboxOptions(options, name) {
8044
- if (options === undefined)
8045
- return;
8046
- if (options === null || typeof options !== "object" || Array.isArray(options)) {
8047
- throw new Error(`Invalid ${name}. Expected an object.`);
8048
- }
8049
- validateIntegerRange(options.ttlMinutes, `${name}.ttlMinutes`, MIN_SANDBOX_TTL_MINUTES, MAX_SANDBOX_TTL_MINUTES);
8050
- validatePositiveInteger(options.readyTimeoutMs, `${name}.readyTimeoutMs`);
8051
- validatePositiveInteger(options.readyPollIntervalMs, `${name}.readyPollIntervalMs`);
8052
- validatePositiveInteger(options.refreshIntervalMs, `${name}.refreshIntervalMs`);
8053
- if (options.terminateOnClose !== undefined && typeof options.terminateOnClose !== "boolean") {
8054
- throw new Error(`Invalid ${name}.terminateOnClose. Expected a boolean.`);
8055
- }
8056
- }
8057
8120
  function validateCloudClientOptions(options) {
8058
- validatePositiveInteger(options.requestTimeoutMs, "requestTimeoutMs");
8121
+ validatePositiveInteger2(options.requestTimeoutMs, "requestTimeoutMs");
8059
8122
  validateCloudSandboxOptions(options.sandbox, "sandbox");
8060
8123
  if (options.environment !== undefined && options.sandbox !== undefined) {
8061
8124
  throw new Error("Letta Cloud sessions cannot specify both environment and sandbox options.");
@@ -8658,10 +8721,15 @@ class CloudEnvironmentSession extends RemoteClientSessionCore {
8658
8721
  async createManagedSandbox(agentId, conversationId) {
8659
8722
  const fetchImpl = getFetch3(this.cloudOptions.fetch);
8660
8723
  const baseUrl = normalizeCloudApiBaseUrl2(this.cloudOptions.apiBaseUrl);
8724
+ const sandboxOptions = this.resolvedSandboxOptions();
8725
+ const githubRepositories = sandboxOptions.githubRepositories;
8661
8726
  const response = await fetchImpl(`${baseUrl}/v1/agents/${encodeURIComponent(agentId)}/sandboxes`, {
8662
8727
  method: "POST",
8663
8728
  headers: cloudHeaders2(this.cloudOptions),
8664
- body: JSON.stringify(conversationId ? { conversationId } : {})
8729
+ body: JSON.stringify({
8730
+ ...conversationId ? { conversationId } : {},
8731
+ ...githubRepositories && githubRepositories.length > 0 ? { githubRepositories } : {}
8732
+ })
8665
8733
  });
8666
8734
  const body = await parseJsonResponse3(response);
8667
8735
  assertOkResponse2(response, body, "Cloud create managed sandbox", `${baseUrl}/v1/agents/${encodeURIComponent(agentId)}/sandboxes`);
@@ -8672,7 +8740,6 @@ class CloudEnvironmentSession extends RemoteClientSessionCore {
8672
8740
  if (responseConversationId !== null && responseConversationId !== conversationId) {
8673
8741
  throw new Error(`Cloud managed sandbox response conversation mismatch: expected ${conversationId ?? "none"}, got ${responseConversationId}.`);
8674
8742
  }
8675
- const sandboxOptions = this.resolvedSandboxOptions();
8676
8743
  const ttlMinutes = sandboxOptions.ttlMinutes ?? DEFAULT_SANDBOX_TTL_MINUTES;
8677
8744
  const readyTimeoutMs = sandboxOptions.readyTimeoutMs ?? DEFAULT_SANDBOX_READY_TIMEOUT_MS;
8678
8745
  const readyPollIntervalMs = sandboxOptions.readyPollIntervalMs ?? DEFAULT_SANDBOX_READY_POLL_INTERVAL_MS;
@@ -11206,4 +11273,4 @@ export {
11206
11273
  CloudManagedSandboxExpiredError
11207
11274
  };
11208
11275
 
11209
- //# debugId=98DBA625B202A81364756E2164756E21
11276
+ //# debugId=01C64A8CE3FD2BF964756E2164756E21