@letta-ai/letta-agent-sdk 0.8.79 → 0.8.80

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.
@@ -1,4 +1,4 @@
1
- import type { AppServerExternalToolCallHandler } from "@letta-ai/letta-code/app-server-client";
1
+ import type { AppServerClient, AppServerExternalToolCallHandler } from "@letta-ai/letta-code/app-server-client";
2
2
  import type { RuntimeScope } from "./remote-session-protocol.js";
3
3
  import type { AnyAgentTool } from "./types.js";
4
4
  /** The `external_tools` groups that advertise client tools to the runtime. */
@@ -7,5 +7,9 @@ export declare function externalToolGroups(tools: AnyAgentTool[] | undefined): A
7
7
  * Run a runtime's external tool call against the client tools by name.
8
8
  * `fallbackRuntime` covers listeners that send calls without a `runtime`.
9
9
  */
10
- export declare function createExternalToolCallHandler(externalTools: Map<string, AnyAgentTool>, fallbackRuntime?: () => RuntimeScope | null): AppServerExternalToolCallHandler;
10
+ export declare function createExternalToolCallHandler(externalTools: Map<string, AnyAgentTool>, fallbackRuntime?: () => RuntimeScope | null): CancellableToolCallHandler;
11
+ type CancellableToolCallHandler = (request: Parameters<AppServerExternalToolCallHandler>[0], signal?: AbortSignal) => ReturnType<AppServerExternalToolCallHandler>;
12
+ /** Own response arbitration so cancellation and completion cannot both reply. */
13
+ export declare function registerExternalToolCallHandler(client: AppServerClient, handler: CancellableToolCallHandler): () => void;
14
+ export {};
11
15
  //# sourceMappingURL=external-tools.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"external-tools.d.ts","sourceRoot":"","sources":["../src/external-tools.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gCAAgC,EAAE,MAAM,wCAAwC,CAAC;AAC/F,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AACjE,OAAO,KAAK,EAAwB,YAAY,EAAE,MAAM,YAAY,CAAC;AAErE,8EAA8E;AAC9E,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,YAAY,EAAE,GAAG,SAAS,GAAG,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GAAG,SAAS,CAYhH;AAID;;;GAGG;AACH,wBAAgB,6BAA6B,CAC3C,aAAa,EAAE,GAAG,CAAC,MAAM,EAAE,YAAY,CAAC,EACxC,eAAe,CAAC,EAAE,MAAM,YAAY,GAAG,IAAI,GAC1C,gCAAgC,CAwClC"}
1
+ {"version":3,"file":"external-tools.d.ts","sourceRoot":"","sources":["../src/external-tools.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,gCAAgC,EAAE,MAAM,wCAAwC,CAAC;AAChH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AACjE,OAAO,KAAK,EAAwB,YAAY,EAAE,MAAM,YAAY,CAAC;AAErE,8EAA8E;AAC9E,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,YAAY,EAAE,GAAG,SAAS,GAAG,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GAAG,SAAS,CAahH;AAID;;;GAGG;AACH,wBAAgB,6BAA6B,CAC3C,aAAa,EAAE,GAAG,CAAC,MAAM,EAAE,YAAY,CAAC,EACxC,eAAe,CAAC,EAAE,MAAM,YAAY,GAAG,IAAI,GAC1C,0BAA0B,CAwC5B;AAED,KAAK,0BAA0B,GAAG,CAChC,OAAO,EAAE,UAAU,CAAC,gCAAgC,CAAC,CAAC,CAAC,CAAC,EACxD,MAAM,CAAC,EAAE,WAAW,KACjB,UAAU,CAAC,gCAAgC,CAAC,CAAC;AAElD,iFAAiF;AACjF,wBAAgB,+BAA+B,CAC7C,MAAM,EAAE,eAAe,EACvB,OAAO,EAAE,0BAA0B,GAClC,MAAM,IAAI,CAuCZ"}
package/dist/index.js CHANGED
@@ -9536,18 +9536,39 @@ function onceSocketEvent(socket, type, listener) {
9536
9536
  });
9537
9537
  return detach;
9538
9538
  }
9539
- function waitForSocketOpen(socket) {
9539
+ function waitForSocketOpen(socket, timeoutMs) {
9540
9540
  if (socket.readyState === WEBSOCKET_OPEN_STATE) {
9541
9541
  return Promise.resolve();
9542
9542
  }
9543
- return new Promise((resolve, reject) => {
9543
+ return new Promise((resolvePromise, rejectPromise) => {
9544
+ let settled = false;
9545
+ const resolve = () => {
9546
+ if (settled)
9547
+ return;
9548
+ settled = true;
9549
+ resolvePromise();
9550
+ };
9551
+ const reject = (error) => {
9552
+ if (settled)
9553
+ return;
9554
+ settled = true;
9555
+ rejectPromise(error);
9556
+ };
9544
9557
  let detachOpen = () => {};
9545
9558
  let detachError = () => {};
9559
+ let detachClose = () => {};
9546
9560
  let detachResponse = () => {};
9547
9561
  let detachBody = () => {};
9562
+ let upgradeRejected = false;
9563
+ const timer = timeoutMs > 0 ? setTimeout(() => {
9564
+ cleanup();
9565
+ reject(new Error(`App-server WebSocket failed to open: timed out after ${timeoutMs}ms`));
9566
+ }, timeoutMs) : undefined;
9548
9567
  const cleanup = () => {
9568
+ clearTimeout(timer);
9549
9569
  detachOpen();
9550
9570
  detachError();
9571
+ detachClose();
9551
9572
  detachResponse();
9552
9573
  detachBody();
9553
9574
  };
@@ -9559,6 +9580,7 @@ function waitForSocketOpen(socket) {
9559
9580
  const onResponse = (_request, response) => {
9560
9581
  if (!response)
9561
9582
  return;
9583
+ upgradeRejected = true;
9562
9584
  const request = _request;
9563
9585
  let body = Buffer.alloc(0);
9564
9586
  let finished = false;
@@ -9600,6 +9622,12 @@ function waitForSocketOpen(socket) {
9600
9622
  cleanup();
9601
9623
  reject(new Error(`App-server WebSocket failed to open: ${String(event)}`));
9602
9624
  });
9625
+ detachClose = onceSocketEvent(socket, "close", () => {
9626
+ if (upgradeRejected)
9627
+ return;
9628
+ cleanup();
9629
+ reject(new Error("App-server WebSocket failed to open: closed before opening"));
9630
+ });
9603
9631
  });
9604
9632
  }
9605
9633
  function rawEventData(event) {
@@ -9667,7 +9695,7 @@ class AppServerClient {
9667
9695
  });
9668
9696
  }
9669
9697
  async connect() {
9670
- await waitForSocketOpen(this.socket);
9698
+ await waitForSocketOpen(this.socket, this.requestTimeoutMs);
9671
9699
  return this;
9672
9700
  }
9673
9701
  close() {
@@ -13294,6 +13322,7 @@ function externalToolGroups(tools) {
13294
13322
  return;
13295
13323
  return [
13296
13324
  {
13325
+ capabilities: { external_tool_call_cancel: true },
13297
13326
  tools: tools.map((tool) => ({
13298
13327
  name: tool.name,
13299
13328
  label: tool.label,
@@ -13306,14 +13335,14 @@ function externalToolGroups(tools) {
13306
13335
  var MAX_REMEMBERED_EXTERNAL_TOOL_CALLS = 200;
13307
13336
  function createExternalToolCallHandler(externalTools, fallbackRuntime) {
13308
13337
  const calls = new Map;
13309
- const execute = async (request) => {
13338
+ const execute = async (request, signal) => {
13310
13339
  const tool = externalTools.get(request.tool_name);
13311
13340
  if (!tool) {
13312
13341
  throw new Error(`Unknown external tool: ${request.tool_name}`);
13313
13342
  }
13314
13343
  const runtime = request.runtime ?? fallbackRuntime?.() ?? null;
13315
13344
  const context = runtime ? { toolCallId: request.tool_call_id, agentId: runtime.agent_id, conversationId: runtime.conversation_id } : undefined;
13316
- const result = await tool.execute(request.tool_call_id, request.input, undefined, undefined, context);
13345
+ const result = await tool.execute(request.tool_call_id, request.input, signal, undefined, context);
13317
13346
  return {
13318
13347
  content: result.content.map((part) => ({
13319
13348
  type: part.type,
@@ -13324,15 +13353,15 @@ function createExternalToolCallHandler(externalTools, fallbackRuntime) {
13324
13353
  ...result.isError === true ? { is_error: true } : {}
13325
13354
  };
13326
13355
  };
13327
- return (request) => {
13356
+ return (request, signal) => {
13328
13357
  const requestId = request.request_id;
13329
13358
  if (typeof requestId !== "string" || requestId.length === 0) {
13330
- return execute(request);
13359
+ return execute(request, signal);
13331
13360
  }
13332
13361
  const existing = calls.get(requestId);
13333
13362
  if (existing)
13334
13363
  return existing;
13335
- const call = execute(request);
13364
+ const call = execute(request, signal);
13336
13365
  calls.set(requestId, call);
13337
13366
  while (calls.size > MAX_REMEMBERED_EXTERNAL_TOOL_CALLS) {
13338
13367
  const oldest = calls.keys().next().value;
@@ -13343,6 +13372,49 @@ function createExternalToolCallHandler(externalTools, fallbackRuntime) {
13343
13372
  return call;
13344
13373
  };
13345
13374
  }
13375
+ function registerExternalToolCallHandler(client, handler) {
13376
+ const pending = new Map;
13377
+ const completed = new Set;
13378
+ const remove = client.onMessage((raw, channel) => {
13379
+ if (channel !== "control")
13380
+ return;
13381
+ const message = raw;
13382
+ const requestId = message.request_id;
13383
+ if (typeof requestId !== "string")
13384
+ return;
13385
+ if (message.type === "external_tool_call_cancel") {
13386
+ const call = pending.get(requestId);
13387
+ if (!call)
13388
+ return;
13389
+ call.finish({ error: "cancelled" });
13390
+ call.controller.abort(message.reason);
13391
+ return;
13392
+ }
13393
+ if (message.type !== "external_tool_call_request" || pending.has(requestId) || completed.has(requestId))
13394
+ return;
13395
+ const controller = new AbortController;
13396
+ const finish = (response) => {
13397
+ if (!pending.delete(requestId))
13398
+ return;
13399
+ completed.add(requestId);
13400
+ if (completed.size > MAX_REMEMBERED_EXTERNAL_TOOL_CALLS)
13401
+ completed.delete(completed.values().next().value);
13402
+ client.send({ type: "external_tool_call_response", request_id: requestId, ...response });
13403
+ };
13404
+ pending.set(requestId, { controller, finish });
13405
+ try {
13406
+ Promise.resolve(handler(raw, controller.signal)).then((result) => finish({ result }), (error) => finish({ error: error instanceof Error ? error.message : String(error) }));
13407
+ } catch (error) {
13408
+ finish({ error: error instanceof Error ? error.message : String(error) });
13409
+ }
13410
+ });
13411
+ return () => {
13412
+ remove();
13413
+ for (const call of pending.values())
13414
+ call.controller.abort();
13415
+ pending.clear();
13416
+ };
13417
+ }
13346
13418
 
13347
13419
  // src/runtime-tool-policy.ts
13348
13420
  var RUNTIME_TOOL_POLICY_CAPABILITY = "runtime_tool_policy";
@@ -15167,7 +15239,7 @@ class AppServerSession extends RemoteClientSessionCore {
15167
15239
  getOptions: () => this.currentOptions()
15168
15240
  });
15169
15241
  if (this.externalTools.size > 0 || this.inheritedTools) {
15170
- this.removeExternalToolHandler = client.onExternalToolCall(createExternalToolCallHandler(this.externalTools, () => this.runtime));
15242
+ this.removeExternalToolHandler = registerExternalToolCallHandler(client, createExternalToolCallHandler(this.externalTools, () => this.runtime));
15171
15243
  }
15172
15244
  try {
15173
15245
  await client.connect();
@@ -16272,7 +16344,7 @@ class CloudEnvironmentSession extends RemoteClientSessionCore {
16272
16344
  getOptions: () => this.currentOptions()
16273
16345
  });
16274
16346
  if (this.externalTools.size > 0) {
16275
- this.removeExternalToolHandler = client.onExternalToolCall(createExternalToolCallHandler(this.externalTools, () => this.runtime));
16347
+ this.removeExternalToolHandler = registerExternalToolCallHandler(client, createExternalToolCallHandler(this.externalTools, () => this.runtime));
16276
16348
  }
16277
16349
  }
16278
16350
  cleanupTransportHandlers() {
@@ -17030,12 +17102,12 @@ class ToolRegistry {
17030
17102
  ...this.options.WebSocket ? { WebSocket: this.options.WebSocket } : {},
17031
17103
  ...this.options.requestTimeoutMs !== undefined ? { requestTimeoutMs: this.options.requestTimeoutMs } : {}
17032
17104
  }));
17033
- client.onExternalToolCall(async (request) => {
17105
+ registerExternalToolCallHandler(client, async (request, signal) => {
17034
17106
  const runtime = request.runtime;
17035
17107
  const entry = runtime && [...this.entries].find((candidate) => candidate.runtimes.some((r) => runtimeKey(r) === runtimeKey(runtime)));
17036
17108
  if (!entry)
17037
17109
  throw new Error(`No tools registered for conversation ${runtime?.conversation_id}`);
17038
- return entry.call(request);
17110
+ return entry.call(request, signal);
17039
17111
  });
17040
17112
  try {
17041
17113
  await client.connect();
@@ -35463,7 +35535,7 @@ class StreamableHTTPClientTransport {
35463
35535
  }
35464
35536
  var DEFAULT_CLIENT_INFO = {
35465
35537
  name: "letta-code",
35466
- version: "0.34.49"
35538
+ version: "0.34.50"
35467
35539
  };
35468
35540
  async function connectMcpServer(config2, options = {}) {
35469
35541
  let client = new Client(options.clientInfo ?? DEFAULT_CLIENT_INFO);
@@ -36491,4 +36563,4 @@ export {
36491
36563
  CloudManagedSandboxExpiredError
36492
36564
  };
36493
36565
 
36494
- //# debugId=AFB0BEDEFE911CAD64756E2164756E21
36566
+ //# debugId=FF481D2B70CB9B5D64756E2164756E21