@letta-ai/letta-agent-sdk 0.8.72 → 0.8.74
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/README.md +69 -0
- package/dist/app-server-session.d.ts +28 -7
- package/dist/app-server-session.d.ts.map +1 -1
- package/dist/client-base.d.ts +17 -0
- package/dist/client-base.d.ts.map +1 -1
- package/dist/client-entry.d.ts +1 -0
- package/dist/client-entry.d.ts.map +1 -1
- package/dist/client-entry.js +480 -77
- package/dist/client-entry.js.map +15 -12
- package/dist/client.d.ts +9 -0
- package/dist/client.d.ts.map +1 -1
- package/dist/cloud-session.d.ts.map +1 -1
- package/dist/cloud-status-transport.d.ts.map +1 -1
- package/dist/external-tools.d.ts +11 -0
- package/dist/external-tools.d.ts.map +1 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +509 -103
- package/dist/index.js.map +17 -14
- package/dist/remote-client-session-core.d.ts.map +1 -1
- package/dist/remote-session-protocol.d.ts +3 -1
- package/dist/remote-session-protocol.d.ts.map +1 -1
- package/dist/remote-turn-coordinator.d.ts +14 -0
- package/dist/remote-turn-coordinator.d.ts.map +1 -1
- package/dist/runtime-tool-policy.d.ts +57 -0
- package/dist/runtime-tool-policy.d.ts.map +1 -0
- package/dist/structured-output-session.d.ts.map +1 -1
- package/dist/tool-registration.d.ts +67 -0
- package/dist/tool-registration.d.ts.map +1 -0
- package/dist/types.d.ts +30 -2
- package/dist/types.d.ts.map +1 -1
- package/package.json +3 -3
- package/src/app-server-session.ts +104 -60
- package/src/client-base.ts +57 -14
- package/src/client-entry.ts +1 -0
- package/src/client.ts +6 -2
- package/src/cloud-session.ts +12 -3
- package/src/cloud-status-transport.ts +4 -0
- package/src/external-tools.ts +69 -0
- package/src/index.ts +3 -0
- package/src/remote-client-session-core.ts +4 -4
- package/src/remote-session-protocol.ts +3 -0
- package/src/remote-turn-coordinator.ts +80 -15
- package/src/runtime-tool-policy.ts +114 -0
- package/src/structured-output-session.ts +2 -1
- package/src/tool-registration.ts +311 -0
- package/src/types.ts +39 -1
package/dist/client-entry.js
CHANGED
|
@@ -13128,7 +13128,7 @@ async function* streamStructuredTurns(config) {
|
|
|
13128
13128
|
return;
|
|
13129
13129
|
});
|
|
13130
13130
|
}
|
|
13131
|
-
if (msg.type !== "result") {
|
|
13131
|
+
if (msg.type !== "result" || msg.origin !== undefined) {
|
|
13132
13132
|
yield msg;
|
|
13133
13133
|
continue;
|
|
13134
13134
|
}
|
|
@@ -13245,9 +13245,115 @@ function expandMcpToolWildcards(allowedTools, mcpTools) {
|
|
|
13245
13245
|
return [...new Set(expanded)];
|
|
13246
13246
|
}
|
|
13247
13247
|
|
|
13248
|
+
// src/external-tools.ts
|
|
13249
|
+
function externalToolGroups(tools) {
|
|
13250
|
+
if (!tools || tools.length === 0)
|
|
13251
|
+
return;
|
|
13252
|
+
return [
|
|
13253
|
+
{
|
|
13254
|
+
tools: tools.map((tool) => ({
|
|
13255
|
+
name: tool.name,
|
|
13256
|
+
label: tool.label,
|
|
13257
|
+
description: tool.description,
|
|
13258
|
+
parameters: tool.parameters
|
|
13259
|
+
}))
|
|
13260
|
+
}
|
|
13261
|
+
];
|
|
13262
|
+
}
|
|
13263
|
+
var MAX_REMEMBERED_EXTERNAL_TOOL_CALLS = 200;
|
|
13264
|
+
function createExternalToolCallHandler(externalTools, fallbackRuntime) {
|
|
13265
|
+
const calls = new Map;
|
|
13266
|
+
const execute = async (request) => {
|
|
13267
|
+
const tool = externalTools.get(request.tool_name);
|
|
13268
|
+
if (!tool) {
|
|
13269
|
+
throw new Error(`Unknown external tool: ${request.tool_name}`);
|
|
13270
|
+
}
|
|
13271
|
+
const runtime = request.runtime ?? fallbackRuntime?.() ?? null;
|
|
13272
|
+
const context = runtime ? { toolCallId: request.tool_call_id, agentId: runtime.agent_id, conversationId: runtime.conversation_id } : undefined;
|
|
13273
|
+
const result = await tool.execute(request.tool_call_id, request.input, undefined, undefined, context);
|
|
13274
|
+
return {
|
|
13275
|
+
content: result.content.map((part) => ({
|
|
13276
|
+
type: part.type,
|
|
13277
|
+
...part.text !== undefined ? { text: part.text } : {},
|
|
13278
|
+
...part.data !== undefined ? { data: part.data } : {},
|
|
13279
|
+
...part.mimeType !== undefined ? { mimeType: part.mimeType } : {}
|
|
13280
|
+
})),
|
|
13281
|
+
...result.isError === true ? { is_error: true } : {}
|
|
13282
|
+
};
|
|
13283
|
+
};
|
|
13284
|
+
return (request) => {
|
|
13285
|
+
const requestId = request.request_id;
|
|
13286
|
+
if (typeof requestId !== "string" || requestId.length === 0) {
|
|
13287
|
+
return execute(request);
|
|
13288
|
+
}
|
|
13289
|
+
const existing = calls.get(requestId);
|
|
13290
|
+
if (existing)
|
|
13291
|
+
return existing;
|
|
13292
|
+
const call = execute(request);
|
|
13293
|
+
calls.set(requestId, call);
|
|
13294
|
+
while (calls.size > MAX_REMEMBERED_EXTERNAL_TOOL_CALLS) {
|
|
13295
|
+
const oldest = calls.keys().next().value;
|
|
13296
|
+
if (oldest === undefined)
|
|
13297
|
+
break;
|
|
13298
|
+
calls.delete(oldest);
|
|
13299
|
+
}
|
|
13300
|
+
return call;
|
|
13301
|
+
};
|
|
13302
|
+
}
|
|
13303
|
+
|
|
13304
|
+
// src/runtime-tool-policy.ts
|
|
13305
|
+
var RUNTIME_TOOL_POLICY_CAPABILITY = "runtime_tool_policy";
|
|
13306
|
+
var CAPABILITY_PROBE_TIMEOUT_MS = 5000;
|
|
13307
|
+
function clientToolsetPayload(toolset) {
|
|
13308
|
+
return {
|
|
13309
|
+
...toolset.base !== undefined ? { base: toolset.base } : {},
|
|
13310
|
+
...toolset.include !== undefined ? { include: [...new Set(toolset.include)] } : {}
|
|
13311
|
+
};
|
|
13312
|
+
}
|
|
13313
|
+
function runtimeToolPolicy(allowedTools, toolset) {
|
|
13314
|
+
return {
|
|
13315
|
+
...toolset !== undefined ? { toolset: clientToolsetPayload(toolset) } : {},
|
|
13316
|
+
...allowedTools !== undefined ? { allowlist: [...new Set(allowedTools)] } : {},
|
|
13317
|
+
exclude_interactive: true
|
|
13318
|
+
};
|
|
13319
|
+
}
|
|
13320
|
+
async function supportsRuntimeToolPolicy(client) {
|
|
13321
|
+
try {
|
|
13322
|
+
const info = await client.info({ timeoutMs: CAPABILITY_PROBE_TIMEOUT_MS });
|
|
13323
|
+
const capabilities = info.capabilities;
|
|
13324
|
+
return capabilities?.[RUNTIME_TOOL_POLICY_CAPABILITY] === true;
|
|
13325
|
+
} catch {
|
|
13326
|
+
return false;
|
|
13327
|
+
}
|
|
13328
|
+
}
|
|
13329
|
+
function mergeInheritedTools(inherited, own) {
|
|
13330
|
+
if (!inherited)
|
|
13331
|
+
return own;
|
|
13332
|
+
const tools = new Map(inherited.tools.map((tool) => [tool.name, tool]));
|
|
13333
|
+
for (const tool of own.tools)
|
|
13334
|
+
tools.set(tool.name, tool);
|
|
13335
|
+
const ownNames = new Set(own.tools.map((tool) => tool.name));
|
|
13336
|
+
const registered = inherited.allowedTools;
|
|
13337
|
+
const allowedTools = registered === undefined ? own.allowedTools : own.allowedTools === undefined ? [...new Set([...registered, ...ownNames])] : own.allowedTools.filter((name) => registered.includes(name) || ownNames.has(name));
|
|
13338
|
+
const toolset = own.toolset ?? inherited.toolset;
|
|
13339
|
+
return {
|
|
13340
|
+
tools: [...tools.values()],
|
|
13341
|
+
...allowedTools !== undefined ? { allowedTools } : {},
|
|
13342
|
+
...toolset !== undefined ? { toolset } : {}
|
|
13343
|
+
};
|
|
13344
|
+
}
|
|
13345
|
+
|
|
13248
13346
|
// src/remote-turn-coordinator.ts
|
|
13249
13347
|
var MAX_RECENTLY_SETTLED_RUN_IDS = 256;
|
|
13250
13348
|
var TRAILING_USAGE_GRACE_MS = 100;
|
|
13349
|
+
var TURN_ORIGINS = new Set([
|
|
13350
|
+
"task_notification",
|
|
13351
|
+
"cron",
|
|
13352
|
+
"subagent",
|
|
13353
|
+
"system",
|
|
13354
|
+
"channel",
|
|
13355
|
+
"user"
|
|
13356
|
+
]);
|
|
13251
13357
|
|
|
13252
13358
|
class RemoteTurnCoordinator {
|
|
13253
13359
|
label;
|
|
@@ -13259,6 +13365,8 @@ class RemoteTurnCoordinator {
|
|
|
13259
13365
|
activeTurn = null;
|
|
13260
13366
|
pendingTurns = [];
|
|
13261
13367
|
settledRunIds = new Set;
|
|
13368
|
+
queueOrigins = new Map;
|
|
13369
|
+
nextServerOrigin = "unknown";
|
|
13262
13370
|
nextTurnId = 0;
|
|
13263
13371
|
messageCounter = 0;
|
|
13264
13372
|
clientMessageCounter = 0;
|
|
@@ -13274,16 +13382,27 @@ class RemoteTurnCoordinator {
|
|
|
13274
13382
|
return this._activeTurnStartedAt;
|
|
13275
13383
|
}
|
|
13276
13384
|
hasInFlightTurn() {
|
|
13277
|
-
return this.activeTurn !== null || this.pendingTurns.length > 0;
|
|
13385
|
+
return this.activeTurn !== null && this.activeTurn.origin === undefined || this.pendingTurns.length > 0;
|
|
13278
13386
|
}
|
|
13279
13387
|
trackSentTurn(runtime, callerOtid, outputFormat) {
|
|
13280
13388
|
const otid = normalizeCallerOtid(callerOtid);
|
|
13281
|
-
const turn = {
|
|
13282
|
-
id: ++this.nextTurnId,
|
|
13283
|
-
runtime,
|
|
13389
|
+
const turn = this.newTracker(runtime, {
|
|
13284
13390
|
...otid !== undefined ? { otid } : {},
|
|
13285
13391
|
...outputFormat !== undefined ? { outputFormat } : {},
|
|
13286
|
-
clientMessageId: otid ?? `sdk-message-${Date.now()}-${++this.clientMessageCounter}
|
|
13392
|
+
clientMessageId: otid ?? `sdk-message-${Date.now()}-${++this.clientMessageCounter}`
|
|
13393
|
+
});
|
|
13394
|
+
if (this.activeTurn) {
|
|
13395
|
+
this.pendingTurns.push(turn);
|
|
13396
|
+
} else {
|
|
13397
|
+
this.activateTurn(turn);
|
|
13398
|
+
}
|
|
13399
|
+
return turn;
|
|
13400
|
+
}
|
|
13401
|
+
newTracker(runtime, identity) {
|
|
13402
|
+
return {
|
|
13403
|
+
id: ++this.nextTurnId,
|
|
13404
|
+
runtime,
|
|
13405
|
+
...identity,
|
|
13287
13406
|
queuedAt: Date.now(),
|
|
13288
13407
|
startedAt: 0,
|
|
13289
13408
|
assistantText: "",
|
|
@@ -13300,13 +13419,32 @@ class RemoteTurnCoordinator {
|
|
|
13300
13419
|
abortRequested: false,
|
|
13301
13420
|
timeout: null
|
|
13302
13421
|
};
|
|
13303
|
-
|
|
13304
|
-
|
|
13305
|
-
|
|
13306
|
-
|
|
13307
|
-
|
|
13422
|
+
}
|
|
13423
|
+
startServerTurn(runtime) {
|
|
13424
|
+
const turn = this.newTracker(runtime, { clientMessageId: "", origin: this.nextServerOrigin });
|
|
13425
|
+
this.nextServerOrigin = "unknown";
|
|
13426
|
+
this.activateTurn(turn);
|
|
13308
13427
|
return turn;
|
|
13309
13428
|
}
|
|
13429
|
+
observeQueueOrigins(message, queue) {
|
|
13430
|
+
for (const item of queue) {
|
|
13431
|
+
if (!item.clientMessageId)
|
|
13432
|
+
continue;
|
|
13433
|
+
this.queueOrigins.set(item.clientMessageId, TURN_ORIGINS.has(item.source) ? item.source : "unknown");
|
|
13434
|
+
if (this.queueOrigins.size > MAX_RECENTLY_SETTLED_RUN_IDS) {
|
|
13435
|
+
this.queueOrigins.delete(this.queueOrigins.keys().next().value);
|
|
13436
|
+
}
|
|
13437
|
+
}
|
|
13438
|
+
for (const removed of Array.isArray(message.removed) ? message.removed : []) {
|
|
13439
|
+
const { client_message_id: id, disposition, source } = removed;
|
|
13440
|
+
if (disposition !== "dequeued" || typeof id !== "string")
|
|
13441
|
+
continue;
|
|
13442
|
+
const own = [this.activeTurn, ...this.pendingTurns].some((turn) => turn?.clientMessageId === id);
|
|
13443
|
+
if (own)
|
|
13444
|
+
continue;
|
|
13445
|
+
this.nextServerOrigin = typeof source === "string" && TURN_ORIGINS.has(source) ? source : this.queueOrigins.get(id) ?? "unknown";
|
|
13446
|
+
}
|
|
13447
|
+
}
|
|
13310
13448
|
removeTrackedTurn(turn) {
|
|
13311
13449
|
if (turn.timeout)
|
|
13312
13450
|
clearTimeout(turn.timeout);
|
|
@@ -13320,6 +13458,12 @@ class RemoteTurnCoordinator {
|
|
|
13320
13458
|
if (index !== -1)
|
|
13321
13459
|
this.pendingTurns.splice(index, 1);
|
|
13322
13460
|
}
|
|
13461
|
+
failServerTurn(detail) {
|
|
13462
|
+
const active = this.activeTurn;
|
|
13463
|
+
if (active?.origin === undefined)
|
|
13464
|
+
return;
|
|
13465
|
+
this.failTurn(active, detail, { errorCode: "stream_closed", recoverable: true });
|
|
13466
|
+
}
|
|
13323
13467
|
markAbortRequested() {
|
|
13324
13468
|
if (this.activeTurn)
|
|
13325
13469
|
this.activeTurn.abortRequested = true;
|
|
@@ -13339,6 +13483,7 @@ class RemoteTurnCoordinator {
|
|
|
13339
13483
|
type: "queue_update",
|
|
13340
13484
|
queue: queueItems(message)
|
|
13341
13485
|
};
|
|
13486
|
+
this.observeQueueOrigins(message, sdkMessage2.queue);
|
|
13342
13487
|
this.enqueue(sdkMessage2);
|
|
13343
13488
|
return;
|
|
13344
13489
|
}
|
|
@@ -13381,9 +13526,9 @@ class RemoteTurnCoordinator {
|
|
|
13381
13526
|
if (!delta)
|
|
13382
13527
|
return;
|
|
13383
13528
|
const messageType = streamDeltaMessageType(delta);
|
|
13384
|
-
const active = messageType === "usage_statistics" || messageType === "stop_reason" ? this.activeTurn : this.activateNextTurnFromProtocol();
|
|
13385
13529
|
const runId = streamDeltaRunId(delta);
|
|
13386
13530
|
const isTurnEvidence = messageType === "assistant_message" || messageType === "reasoning_message" || messageType === "tool_call_message" || messageType === "approval_request_message" || messageType === "tool_return_message" || messageType === "error_message" || messageType === "loop_error" || runId !== undefined && (messageType === "usage_statistics" || messageType === "stop_reason");
|
|
13531
|
+
const active = messageType === "usage_statistics" || messageType === "stop_reason" ? this.activeTurn : this.activateNextTurnFromProtocol() ?? (isTurnEvidence && runId !== undefined ? this.startServerTurn(runtime) : null);
|
|
13387
13532
|
if (active && isTurnEvidence) {
|
|
13388
13533
|
active.observedTurnEvidence = true;
|
|
13389
13534
|
if (runId)
|
|
@@ -13841,7 +13986,8 @@ class RemoteTurnCoordinator {
|
|
|
13841
13986
|
stopReason,
|
|
13842
13987
|
durationMs: Date.now() - (tracker?.startedAt || this._activeTurnStartedAt),
|
|
13843
13988
|
conversationId: turn.runtime.conversation_id,
|
|
13844
|
-
runIds: turn.runIds.length > 0 ? turn.runIds : undefined
|
|
13989
|
+
runIds: turn.runIds.length > 0 ? turn.runIds : undefined,
|
|
13990
|
+
...tracker?.origin !== undefined ? { origin: tracker.origin } : {}
|
|
13845
13991
|
};
|
|
13846
13992
|
}
|
|
13847
13993
|
enqueue(message) {
|
|
@@ -14083,9 +14229,8 @@ class RemoteClientSessionCore {
|
|
|
14083
14229
|
}
|
|
14084
14230
|
await this.send(message);
|
|
14085
14231
|
for await (const msg of this.stream()) {
|
|
14086
|
-
if (msg.type === "result")
|
|
14232
|
+
if (msg.type === "result" && msg.origin === undefined)
|
|
14087
14233
|
return msg;
|
|
14088
|
-
}
|
|
14089
14234
|
}
|
|
14090
14235
|
return {
|
|
14091
14236
|
type: "result",
|
|
@@ -14121,7 +14266,7 @@ class RemoteClientSessionCore {
|
|
|
14121
14266
|
if (!msg)
|
|
14122
14267
|
break;
|
|
14123
14268
|
yield msg;
|
|
14124
|
-
if (msg.type === "result")
|
|
14269
|
+
if (msg.type === "result" && msg.origin === undefined)
|
|
14125
14270
|
break;
|
|
14126
14271
|
}
|
|
14127
14272
|
}
|
|
@@ -14431,6 +14576,7 @@ class RemoteClientSessionCore {
|
|
|
14431
14576
|
this.controller?.close();
|
|
14432
14577
|
this.controller = null;
|
|
14433
14578
|
const error = new Error(`${this.label} connection closed before send`);
|
|
14579
|
+
this.turns.failServerTurn(error.message);
|
|
14434
14580
|
for (const cancel of [...this.deviceStatusRefreshCancels])
|
|
14435
14581
|
cancel(error);
|
|
14436
14582
|
this.deviceStatusRefreshCancels.clear();
|
|
@@ -14571,38 +14717,6 @@ function agentToolNames(agent) {
|
|
|
14571
14717
|
return typeof name === "string" && name.length > 0 ? [name] : [];
|
|
14572
14718
|
});
|
|
14573
14719
|
}
|
|
14574
|
-
function externalToolGroups(tools) {
|
|
14575
|
-
if (!tools || tools.length === 0)
|
|
14576
|
-
return;
|
|
14577
|
-
return [
|
|
14578
|
-
{
|
|
14579
|
-
tools: tools.map((tool) => ({
|
|
14580
|
-
name: tool.name,
|
|
14581
|
-
label: tool.label,
|
|
14582
|
-
description: tool.description,
|
|
14583
|
-
parameters: tool.parameters
|
|
14584
|
-
}))
|
|
14585
|
-
}
|
|
14586
|
-
];
|
|
14587
|
-
}
|
|
14588
|
-
function createExternalToolCallHandler(externalTools) {
|
|
14589
|
-
return async (request) => {
|
|
14590
|
-
const tool = externalTools.get(request.tool_name);
|
|
14591
|
-
if (!tool) {
|
|
14592
|
-
throw new Error(`Unknown external tool: ${request.tool_name}`);
|
|
14593
|
-
}
|
|
14594
|
-
const result = await tool.execute(request.tool_call_id, request.input);
|
|
14595
|
-
return {
|
|
14596
|
-
content: result.content.map((part) => ({
|
|
14597
|
-
type: part.type,
|
|
14598
|
-
...part.text !== undefined ? { text: part.text } : {},
|
|
14599
|
-
...part.data !== undefined ? { data: part.data } : {},
|
|
14600
|
-
...part.mimeType !== undefined ? { mimeType: part.mimeType } : {}
|
|
14601
|
-
})),
|
|
14602
|
-
...result.isError === true ? { is_error: true } : {}
|
|
14603
|
-
};
|
|
14604
|
-
};
|
|
14605
|
-
}
|
|
14606
14720
|
async function resolveAppServerToolApproval(options, toolName, toolInput, context) {
|
|
14607
14721
|
if ("outputFormat" in options && options.outputFormat !== undefined && toolName === STRUCTURED_OUTPUT_TOOL) {
|
|
14608
14722
|
return { behavior: "allow", updatedInput: null, updatedPermissions: [] };
|
|
@@ -14779,11 +14893,26 @@ class AppServerRuntimeController {
|
|
|
14779
14893
|
options;
|
|
14780
14894
|
clientToolAllowlist;
|
|
14781
14895
|
clientToolset;
|
|
14782
|
-
|
|
14896
|
+
toolPolicyApplied;
|
|
14897
|
+
constructor(client, options, clientToolAllowlist, clientToolset, toolPolicyApplied = false) {
|
|
14783
14898
|
this.client = client;
|
|
14784
14899
|
this.options = options;
|
|
14785
14900
|
this.clientToolAllowlist = clientToolAllowlist;
|
|
14786
14901
|
this.clientToolset = clientToolset;
|
|
14902
|
+
this.toolPolicyApplied = toolPolicyApplied;
|
|
14903
|
+
}
|
|
14904
|
+
async updateToolSelection(runtime, selection) {
|
|
14905
|
+
this.clientToolAllowlist = selection.allowedTools;
|
|
14906
|
+
this.clientToolset = selection.toolset;
|
|
14907
|
+
const response = await this.client.runtimeExternalToolsUpdate({
|
|
14908
|
+
updates: [{
|
|
14909
|
+
runtimes: [runtime],
|
|
14910
|
+
external_tools: externalToolGroups(selection.tools) ?? [],
|
|
14911
|
+
...this.toolPolicyApplied ? { tool_policy: runtimeToolPolicy(selection.allowedTools, selection.toolset) } : {}
|
|
14912
|
+
}]
|
|
14913
|
+
});
|
|
14914
|
+
if (!response.success)
|
|
14915
|
+
throw new Error(response.error ?? "Failed to update session tools");
|
|
14787
14916
|
}
|
|
14788
14917
|
onMessage(handler) {
|
|
14789
14918
|
return this.client.onMessage((message, channel) => {
|
|
@@ -14805,14 +14934,11 @@ class AppServerRuntimeController {
|
|
|
14805
14934
|
}
|
|
14806
14935
|
]
|
|
14807
14936
|
};
|
|
14808
|
-
if (this.clientToolAllowlist !== undefined) {
|
|
14937
|
+
if (!this.toolPolicyApplied && this.clientToolAllowlist !== undefined) {
|
|
14809
14938
|
payload.client_tool_allowlist = [...new Set(this.clientToolAllowlist)];
|
|
14810
14939
|
}
|
|
14811
|
-
if (this.clientToolset !== undefined) {
|
|
14812
|
-
payload.client_toolset =
|
|
14813
|
-
...this.clientToolset.base !== undefined ? { base: this.clientToolset.base } : {},
|
|
14814
|
-
...this.clientToolset.include !== undefined ? { include: [...new Set(this.clientToolset.include)] } : {}
|
|
14815
|
-
};
|
|
14940
|
+
if (!this.toolPolicyApplied && this.clientToolset !== undefined) {
|
|
14941
|
+
payload.client_toolset = clientToolsetPayload(this.clientToolset);
|
|
14816
14942
|
}
|
|
14817
14943
|
if (options.outputFormat !== undefined) {
|
|
14818
14944
|
payload.response_format = {
|
|
@@ -14824,7 +14950,8 @@ class AppServerRuntimeController {
|
|
|
14824
14950
|
}
|
|
14825
14951
|
};
|
|
14826
14952
|
}
|
|
14827
|
-
|
|
14953
|
+
if (!this.toolPolicyApplied)
|
|
14954
|
+
payload.exclude_interactive_tools = true;
|
|
14828
14955
|
this.client.input({
|
|
14829
14956
|
runtime,
|
|
14830
14957
|
payload
|
|
@@ -14916,6 +15043,9 @@ class AppServerSession extends RemoteClientSessionCore {
|
|
|
14916
15043
|
mcpCleanup = Promise.resolve();
|
|
14917
15044
|
removeExternalToolHandler = null;
|
|
14918
15045
|
removeControlRequestHandler = null;
|
|
15046
|
+
inheritedTools = null;
|
|
15047
|
+
removeInheritedListener = null;
|
|
15048
|
+
ownSelection = null;
|
|
14919
15049
|
constructor(remoteOptions, mode) {
|
|
14920
15050
|
super(mode, {
|
|
14921
15051
|
label: "app-server",
|
|
@@ -14927,6 +15057,27 @@ class AppServerSession extends RemoteClientSessionCore {
|
|
|
14927
15057
|
this.externalTools.set(tool.name, tool);
|
|
14928
15058
|
}
|
|
14929
15059
|
}
|
|
15060
|
+
inheritTools(source) {
|
|
15061
|
+
this.inheritedTools = source;
|
|
15062
|
+
this.removeInheritedListener = source.onChange(() => {
|
|
15063
|
+
this.refreshInheritedTools().catch(() => {
|
|
15064
|
+
return;
|
|
15065
|
+
});
|
|
15066
|
+
});
|
|
15067
|
+
}
|
|
15068
|
+
applyToolSelection() {
|
|
15069
|
+
const selection = mergeInheritedTools(this.inheritedTools?.current() ?? null, this.ownSelection ?? { tools: [] });
|
|
15070
|
+
this.externalTools.clear();
|
|
15071
|
+
for (const tool of selection.tools)
|
|
15072
|
+
this.externalTools.set(tool.name, tool);
|
|
15073
|
+
return selection;
|
|
15074
|
+
}
|
|
15075
|
+
async refreshInheritedTools() {
|
|
15076
|
+
if (!this.ownSelection || !this.runtime || !(this.controller instanceof AppServerRuntimeController))
|
|
15077
|
+
return;
|
|
15078
|
+
const selection = this.applyToolSelection();
|
|
15079
|
+
await this.controller.updateToolSelection(this.runtime, selection);
|
|
15080
|
+
}
|
|
14930
15081
|
shouldEnableMemfs(options) {
|
|
14931
15082
|
if (this.mode.kind !== "create-agent")
|
|
14932
15083
|
return false;
|
|
@@ -14942,6 +15093,9 @@ class AppServerSession extends RemoteClientSessionCore {
|
|
|
14942
15093
|
...this.remoteOptions.requestTimeoutMs !== undefined ? { requestTimeoutMs: this.remoteOptions.requestTimeoutMs } : {}
|
|
14943
15094
|
}));
|
|
14944
15095
|
const options = this.currentOptions();
|
|
15096
|
+
this.externalTools.clear();
|
|
15097
|
+
for (const tool of this.mode.options.tools ?? [])
|
|
15098
|
+
this.externalTools.set(tool.name, tool);
|
|
14945
15099
|
this.mcpBridge = await connectMcpServers("mcpServers" in options ? options.mcpServers : undefined, {
|
|
14946
15100
|
cwd: options.cwd,
|
|
14947
15101
|
reservedToolNames: this.externalTools.keys()
|
|
@@ -14949,13 +15103,22 @@ class AppServerSession extends RemoteClientSessionCore {
|
|
|
14949
15103
|
for (const tool of this.mcpBridge.tools) {
|
|
14950
15104
|
this.externalTools.set(tool.name, tool);
|
|
14951
15105
|
}
|
|
15106
|
+
const mcpToolNames = this.mcpBridge.tools.map((tool) => tool.name);
|
|
15107
|
+
const ownToolset = "toolset" in options ? options.toolset : undefined;
|
|
15108
|
+
const ownAllowedTools = expandMcpToolWildcards(options.allowedTools, mcpToolNames);
|
|
15109
|
+
this.ownSelection = {
|
|
15110
|
+
tools: [...this.externalTools.values()],
|
|
15111
|
+
...ownAllowedTools !== undefined ? { allowedTools: ownAllowedTools } : {},
|
|
15112
|
+
...ownToolset !== undefined ? { toolset: ownToolset } : {}
|
|
15113
|
+
};
|
|
15114
|
+
const { allowedTools, toolset: clientToolset } = this.applyToolSelection();
|
|
14952
15115
|
this.removeControlRequestHandler = registerAppServerControlRequestHandler({
|
|
14953
15116
|
client,
|
|
14954
15117
|
getRuntime: () => this.runtime,
|
|
14955
15118
|
getOptions: () => this.currentOptions()
|
|
14956
15119
|
});
|
|
14957
|
-
if (this.externalTools.size > 0) {
|
|
14958
|
-
this.removeExternalToolHandler = client.onExternalToolCall(createExternalToolCallHandler(this.externalTools));
|
|
15120
|
+
if (this.externalTools.size > 0 || this.inheritedTools) {
|
|
15121
|
+
this.removeExternalToolHandler = client.onExternalToolCall(createExternalToolCallHandler(this.externalTools, () => this.runtime));
|
|
14959
15122
|
}
|
|
14960
15123
|
try {
|
|
14961
15124
|
await client.connect();
|
|
@@ -14966,19 +15129,17 @@ class AppServerSession extends RemoteClientSessionCore {
|
|
|
14966
15129
|
throw new Error(`Local query() requires a Letta Code app-server with local conversation support (connected version: ${info.letta_code_version}). Upgrade @letta-ai/letta-code.`);
|
|
14967
15130
|
}
|
|
14968
15131
|
}
|
|
14969
|
-
const response = await this.startRuntime(client);
|
|
15132
|
+
const response = await this.startRuntime(client, runtimeToolPolicy(allowedTools, clientToolset));
|
|
14970
15133
|
if (!response.success || !response.runtime) {
|
|
14971
15134
|
throw new Error(response.error ?? "Failed to start app-server runtime");
|
|
14972
15135
|
}
|
|
14973
15136
|
this.watchTransportDisconnect(client);
|
|
15137
|
+
const toolPolicyApplied = await supportsRuntimeToolPolicy(client);
|
|
14974
15138
|
const tools = agentToolNames(response.agent);
|
|
14975
15139
|
const skillSources = options.skillSources;
|
|
14976
|
-
const clientToolset = "toolset" in options ? options.toolset : undefined;
|
|
14977
|
-
const mcpToolNames = this.mcpBridge?.tools.map((tool) => tool.name) ?? [];
|
|
14978
|
-
const allowedTools = expandMcpToolWildcards(options.allowedTools, mcpToolNames);
|
|
14979
15140
|
const availableTools = tools === undefined && mcpToolNames.length === 0 ? undefined : [...tools ?? [], ...mcpToolNames];
|
|
14980
15141
|
return {
|
|
14981
|
-
controller: new AppServerRuntimeController(client, this.remoteOptions, allowedTools, clientToolset),
|
|
15142
|
+
controller: new AppServerRuntimeController(client, this.remoteOptions, allowedTools, clientToolset, toolPolicyApplied),
|
|
14982
15143
|
runtime: response.runtime,
|
|
14983
15144
|
model: typeof response.agent?.model === "string" ? response.agent.model : typeof response.conversation?.model === "string" ? response.conversation.model : "",
|
|
14984
15145
|
modelSettings: objectRecord(response.agent?.model_settings) ?? objectRecord(response.conversation?.model_settings) ?? null,
|
|
@@ -14996,6 +15157,10 @@ class AppServerSession extends RemoteClientSessionCore {
|
|
|
14996
15157
|
}
|
|
14997
15158
|
}
|
|
14998
15159
|
onCoreClose() {
|
|
15160
|
+
if (this.closed) {
|
|
15161
|
+
this.removeInheritedListener?.();
|
|
15162
|
+
this.removeInheritedListener = null;
|
|
15163
|
+
}
|
|
14999
15164
|
this.removeExternalToolHandler?.();
|
|
15000
15165
|
this.removeExternalToolHandler = null;
|
|
15001
15166
|
this.removeControlRequestHandler?.();
|
|
@@ -15026,11 +15191,11 @@ class AppServerSession extends RemoteClientSessionCore {
|
|
|
15026
15191
|
this.ownedConnection = connection;
|
|
15027
15192
|
return connection.url;
|
|
15028
15193
|
}
|
|
15029
|
-
async startRuntime(client) {
|
|
15030
|
-
const command = await this.buildRuntimeStartCommand(client);
|
|
15194
|
+
async startRuntime(client, toolPolicy) {
|
|
15195
|
+
const command = await this.buildRuntimeStartCommand(client, toolPolicy);
|
|
15031
15196
|
return client.runtimeStart(command);
|
|
15032
15197
|
}
|
|
15033
|
-
async buildRuntimeStartCommand(client) {
|
|
15198
|
+
async buildRuntimeStartCommand(client, toolPolicy) {
|
|
15034
15199
|
const options = this.mode.options;
|
|
15035
15200
|
const command = {
|
|
15036
15201
|
client_info: {
|
|
@@ -15061,6 +15226,7 @@ class AppServerSession extends RemoteClientSessionCore {
|
|
|
15061
15226
|
const groups = externalToolGroups([...this.externalTools.values()]);
|
|
15062
15227
|
if (groups)
|
|
15063
15228
|
command.external_tools = groups;
|
|
15229
|
+
command.tool_policy = toolPolicy;
|
|
15064
15230
|
if (this.mode.kind === "create-agent") {
|
|
15065
15231
|
command.create_agent = {
|
|
15066
15232
|
body: await createAgentBody(this.mode.options),
|
|
@@ -15543,6 +15709,9 @@ class CloudStatusTransport {
|
|
|
15543
15709
|
if (channel === "control" && message.type === "stream_delta") {
|
|
15544
15710
|
return false;
|
|
15545
15711
|
}
|
|
15712
|
+
if (channel === "stream" && message.type === "external_tool_call_request") {
|
|
15713
|
+
return false;
|
|
15714
|
+
}
|
|
15546
15715
|
if (this.isDuplicate(message))
|
|
15547
15716
|
return false;
|
|
15548
15717
|
this.trackEventSequence(message);
|
|
@@ -16039,7 +16208,7 @@ class CloudEnvironmentSession extends RemoteClientSessionCore {
|
|
|
16039
16208
|
getOptions: () => this.currentOptions()
|
|
16040
16209
|
});
|
|
16041
16210
|
if (this.externalTools.size > 0) {
|
|
16042
|
-
this.removeExternalToolHandler = client.onExternalToolCall(createExternalToolCallHandler(this.externalTools));
|
|
16211
|
+
this.removeExternalToolHandler = client.onExternalToolCall(createExternalToolCallHandler(this.externalTools, () => this.runtime));
|
|
16043
16212
|
}
|
|
16044
16213
|
}
|
|
16045
16214
|
cleanupTransportHandlers() {
|
|
@@ -16097,6 +16266,7 @@ class CloudEnvironmentSession extends RemoteClientSessionCore {
|
|
|
16097
16266
|
const groups = externalToolGroups([...this.externalTools.values()]);
|
|
16098
16267
|
if (groups)
|
|
16099
16268
|
command.external_tools = groups;
|
|
16269
|
+
command.tool_policy = runtimeToolPolicy(expandMcpToolWildcards(options.allowedTools, this.mcpBridge?.tools.map((tool) => tool.name) ?? []), "toolset" in options ? options.toolset : undefined);
|
|
16100
16270
|
return await client.runtimeStart(command);
|
|
16101
16271
|
}
|
|
16102
16272
|
async afterRuntimeInitialized() {
|
|
@@ -16662,6 +16832,221 @@ function createQuery(createSession, params) {
|
|
|
16662
16832
|
});
|
|
16663
16833
|
}
|
|
16664
16834
|
|
|
16835
|
+
// src/tool-registration.ts
|
|
16836
|
+
var RECONNECT_DELAYS_MS = [250, 1000, 5000, 15000];
|
|
16837
|
+
var runtimeKey = (runtime) => `${runtime.agent_id}:${runtime.conversation_id}`;
|
|
16838
|
+
|
|
16839
|
+
class ToolRegistry {
|
|
16840
|
+
options;
|
|
16841
|
+
connection = null;
|
|
16842
|
+
entries = new Set;
|
|
16843
|
+
listeners = new Set;
|
|
16844
|
+
reconnectAttempt = 0;
|
|
16845
|
+
reconnectTimer = null;
|
|
16846
|
+
closed = false;
|
|
16847
|
+
constructor(options) {
|
|
16848
|
+
this.options = options;
|
|
16849
|
+
}
|
|
16850
|
+
async register(options) {
|
|
16851
|
+
if (this.closed)
|
|
16852
|
+
throw new Error("LettaAgentClient is closed");
|
|
16853
|
+
const entry = { options, runtimes: [], call: createExternalToolCallHandler(new Map) };
|
|
16854
|
+
await this.apply(entry, options);
|
|
16855
|
+
const registry = this;
|
|
16856
|
+
return {
|
|
16857
|
+
get conversations() {
|
|
16858
|
+
return [...entry.options.conversations];
|
|
16859
|
+
},
|
|
16860
|
+
update: async (next) => {
|
|
16861
|
+
if (!registry.entries.has(entry))
|
|
16862
|
+
throw new Error("This tool registration is closed.");
|
|
16863
|
+
await registry.apply(entry, { ...entry.options, ...next });
|
|
16864
|
+
},
|
|
16865
|
+
close: () => registry.remove(entry),
|
|
16866
|
+
[Symbol.asyncDispose]: () => registry.remove(entry)
|
|
16867
|
+
};
|
|
16868
|
+
}
|
|
16869
|
+
close() {
|
|
16870
|
+
this.closed = true;
|
|
16871
|
+
this.entries.clear();
|
|
16872
|
+
this.disconnect();
|
|
16873
|
+
this.notify();
|
|
16874
|
+
}
|
|
16875
|
+
inheritFor(id, own) {
|
|
16876
|
+
const covering = this.covering(id);
|
|
16877
|
+
if (!covering)
|
|
16878
|
+
return null;
|
|
16879
|
+
const registered = new Set(covering.options.tools.map((tool) => tool.name));
|
|
16880
|
+
const clash = own.tools?.find((tool) => registered.has(tool.name));
|
|
16881
|
+
if (clash) {
|
|
16882
|
+
throw new Error(`Tool ${clash.name} is already registered for ${id} with registerTools(); don't pass it to the session again.`);
|
|
16883
|
+
}
|
|
16884
|
+
if (own.toolset !== undefined && covering.options.toolset !== undefined && JSON.stringify(own.toolset) !== JSON.stringify(covering.options.toolset)) {
|
|
16885
|
+
throw new Error(`${id} already has a toolset from registerTools(); narrow it with the session's allowedTools instead.`);
|
|
16886
|
+
}
|
|
16887
|
+
return {
|
|
16888
|
+
current: () => this.covering(id)?.options ?? null,
|
|
16889
|
+
onChange: (listener) => {
|
|
16890
|
+
this.listeners.add(listener);
|
|
16891
|
+
return () => this.listeners.delete(listener);
|
|
16892
|
+
}
|
|
16893
|
+
};
|
|
16894
|
+
}
|
|
16895
|
+
covering(id) {
|
|
16896
|
+
return [...this.entries].find((entry) => entry.options.conversations.includes(id) || entry.runtimes.some((runtime) => runtime.conversation_id === id || runtime.conversation_id === "default" && runtime.agent_id === id));
|
|
16897
|
+
}
|
|
16898
|
+
notify() {
|
|
16899
|
+
for (const listener of [...this.listeners])
|
|
16900
|
+
listener();
|
|
16901
|
+
}
|
|
16902
|
+
async apply(entry, options) {
|
|
16903
|
+
if (!Array.isArray(options.conversations) || options.conversations.length === 0) {
|
|
16904
|
+
throw new Error("registerTools() requires at least one conversation.");
|
|
16905
|
+
}
|
|
16906
|
+
if (!Array.isArray(options.tools))
|
|
16907
|
+
throw new Error("registerTools() requires a tools array.");
|
|
16908
|
+
const connection = await this.connect();
|
|
16909
|
+
if (!connection.toolPolicy && (options.allowedTools || options.toolset)) {
|
|
16910
|
+
throw new Error("registerTools() allowedTools and toolset require a Letta Code app server that supports runtime tool policies. Upgrade @letta-ai/letta-code.");
|
|
16911
|
+
}
|
|
16912
|
+
const runtimes = await Promise.all(options.conversations.map((id) => resolveRuntime(connection.client, id)));
|
|
16913
|
+
const taken = new Set([...this.entries].filter((other) => other !== entry).flatMap((other) => other.runtimes.map(runtimeKey)));
|
|
16914
|
+
const overlap = options.conversations.find((_, index) => taken.has(runtimeKey(runtimes[index])));
|
|
16915
|
+
if (overlap)
|
|
16916
|
+
throw new Error(`Tools are already registered for ${overlap}.`);
|
|
16917
|
+
const keys = new Set(runtimes.map(runtimeKey));
|
|
16918
|
+
const dropped = entry.runtimes.filter((runtime) => !keys.has(runtimeKey(runtime)));
|
|
16919
|
+
const previous = { ...entry };
|
|
16920
|
+
const isNew = !this.entries.has(entry);
|
|
16921
|
+
entry.options = options;
|
|
16922
|
+
entry.runtimes = runtimes;
|
|
16923
|
+
entry.call = createExternalToolCallHandler(new Map(options.tools.map((tool) => [tool.name, tool])));
|
|
16924
|
+
this.entries.add(entry);
|
|
16925
|
+
try {
|
|
16926
|
+
await publish(connection.client, [
|
|
16927
|
+
group(runtimes, options, connection.toolPolicy),
|
|
16928
|
+
...dropped.length > 0 ? [{ runtimes: dropped, external_tools: [] }] : []
|
|
16929
|
+
]);
|
|
16930
|
+
} catch (error) {
|
|
16931
|
+
Object.assign(entry, previous);
|
|
16932
|
+
if (isNew)
|
|
16933
|
+
this.entries.delete(entry);
|
|
16934
|
+
throw error;
|
|
16935
|
+
}
|
|
16936
|
+
this.notify();
|
|
16937
|
+
}
|
|
16938
|
+
async remove(entry) {
|
|
16939
|
+
if (!this.entries.delete(entry))
|
|
16940
|
+
return;
|
|
16941
|
+
this.notify();
|
|
16942
|
+
if (this.entries.size === 0) {
|
|
16943
|
+
this.disconnect();
|
|
16944
|
+
return;
|
|
16945
|
+
}
|
|
16946
|
+
const connection = await this.connect();
|
|
16947
|
+
await publish(connection.client, [{ runtimes: entry.runtimes, external_tools: [] }]);
|
|
16948
|
+
}
|
|
16949
|
+
connect() {
|
|
16950
|
+
this.connection ??= this.open().catch((error) => {
|
|
16951
|
+
this.connection = null;
|
|
16952
|
+
throw error;
|
|
16953
|
+
});
|
|
16954
|
+
return this.connection;
|
|
16955
|
+
}
|
|
16956
|
+
async open() {
|
|
16957
|
+
const owned = this.options.url ? null : await this.options.connect?.();
|
|
16958
|
+
const url = this.options.url ?? owned?.url;
|
|
16959
|
+
if (!url)
|
|
16960
|
+
throw new Error("registerTools() requires an app-server url.");
|
|
16961
|
+
const client = applyUniqueRequestIds(createAppServerClient({
|
|
16962
|
+
url,
|
|
16963
|
+
...this.options.authToken !== undefined ? { authToken: this.options.authToken } : {},
|
|
16964
|
+
...this.options.WebSocket ? { WebSocket: this.options.WebSocket } : {},
|
|
16965
|
+
...this.options.requestTimeoutMs !== undefined ? { requestTimeoutMs: this.options.requestTimeoutMs } : {}
|
|
16966
|
+
}));
|
|
16967
|
+
client.onExternalToolCall(async (request) => {
|
|
16968
|
+
const runtime = request.runtime;
|
|
16969
|
+
const entry = runtime && [...this.entries].find((candidate) => candidate.runtimes.some((r) => runtimeKey(r) === runtimeKey(runtime)));
|
|
16970
|
+
if (!entry)
|
|
16971
|
+
throw new Error(`No tools registered for conversation ${runtime?.conversation_id}`);
|
|
16972
|
+
return entry.call(request);
|
|
16973
|
+
});
|
|
16974
|
+
try {
|
|
16975
|
+
await client.connect();
|
|
16976
|
+
} catch (error) {
|
|
16977
|
+
client.close();
|
|
16978
|
+
owned?.close();
|
|
16979
|
+
throw error;
|
|
16980
|
+
}
|
|
16981
|
+
client.onDisconnect(() => this.onDisconnect(client));
|
|
16982
|
+
return { client, owned: owned ?? null, toolPolicy: await supportsRuntimeToolPolicy(client) };
|
|
16983
|
+
}
|
|
16984
|
+
disconnect() {
|
|
16985
|
+
if (this.reconnectTimer)
|
|
16986
|
+
clearTimeout(this.reconnectTimer);
|
|
16987
|
+
this.reconnectTimer = null;
|
|
16988
|
+
const connection = this.connection;
|
|
16989
|
+
this.connection = null;
|
|
16990
|
+
connection?.then(({ client, owned }) => {
|
|
16991
|
+
client.close();
|
|
16992
|
+
owned?.close();
|
|
16993
|
+
}, () => {
|
|
16994
|
+
return;
|
|
16995
|
+
});
|
|
16996
|
+
}
|
|
16997
|
+
onDisconnect(client) {
|
|
16998
|
+
this.connection?.then((current) => {
|
|
16999
|
+
if (current.client !== client)
|
|
17000
|
+
return;
|
|
17001
|
+
current.owned?.close();
|
|
17002
|
+
this.connection = null;
|
|
17003
|
+
this.scheduleReconnect();
|
|
17004
|
+
}, () => {
|
|
17005
|
+
return;
|
|
17006
|
+
});
|
|
17007
|
+
}
|
|
17008
|
+
scheduleReconnect() {
|
|
17009
|
+
if (this.closed || this.entries.size === 0 || this.reconnectTimer)
|
|
17010
|
+
return;
|
|
17011
|
+
const delay = RECONNECT_DELAYS_MS[Math.min(this.reconnectAttempt, RECONNECT_DELAYS_MS.length - 1)];
|
|
17012
|
+
this.reconnectAttempt += 1;
|
|
17013
|
+
this.reconnectTimer = setTimeout(() => {
|
|
17014
|
+
this.reconnectTimer = null;
|
|
17015
|
+
this.republish().catch(() => this.scheduleReconnect());
|
|
17016
|
+
}, delay);
|
|
17017
|
+
this.reconnectTimer.unref?.();
|
|
17018
|
+
}
|
|
17019
|
+
async republish() {
|
|
17020
|
+
const connection = await this.connect();
|
|
17021
|
+
await publish(connection.client, [...this.entries].map((entry) => group(entry.runtimes, entry.options, connection.toolPolicy)));
|
|
17022
|
+
this.reconnectAttempt = 0;
|
|
17023
|
+
}
|
|
17024
|
+
}
|
|
17025
|
+
function group(runtimes, options, toolPolicy) {
|
|
17026
|
+
return {
|
|
17027
|
+
runtimes,
|
|
17028
|
+
external_tools: externalToolGroups(options.tools) ?? [],
|
|
17029
|
+
...toolPolicy ? { tool_policy: runtimeToolPolicy(options.allowedTools, options.toolset) } : {}
|
|
17030
|
+
};
|
|
17031
|
+
}
|
|
17032
|
+
async function publish(client, updates) {
|
|
17033
|
+
const response = await client.runtimeExternalToolsUpdate({ updates });
|
|
17034
|
+
if (!response.success)
|
|
17035
|
+
throw new Error(response.error ?? "Failed to register tools");
|
|
17036
|
+
}
|
|
17037
|
+
async function resolveRuntime(client, id) {
|
|
17038
|
+
if (!id.startsWith("conv-") && !id.startsWith("local-conv-")) {
|
|
17039
|
+
return { agent_id: id, conversation_id: "default" };
|
|
17040
|
+
}
|
|
17041
|
+
const response = await client.request({ type: "conversation_retrieve", request_id: client.nextRequestId("conversation_retrieve"), conversation_id: id }, {
|
|
17042
|
+
predicate: (message) => message.type === "conversation_retrieve_response"
|
|
17043
|
+
});
|
|
17044
|
+
if (!response.success || !response.conversation) {
|
|
17045
|
+
throw new Error(response.error ?? `Failed to retrieve conversation ${id}`);
|
|
17046
|
+
}
|
|
17047
|
+
return { agent_id: response.conversation.agent_id ?? null, conversation_id: id };
|
|
17048
|
+
}
|
|
17049
|
+
|
|
16665
17050
|
// src/validation.ts
|
|
16666
17051
|
var VALID_SKILL_SOURCES = [
|
|
16667
17052
|
"bundled",
|
|
@@ -16938,6 +17323,7 @@ class LettaAgentClientBase {
|
|
|
16938
17323
|
agentRepositoriesClient = null;
|
|
16939
17324
|
cloudClient = null;
|
|
16940
17325
|
managementTransport = null;
|
|
17326
|
+
toolRegistry = null;
|
|
16941
17327
|
closed = false;
|
|
16942
17328
|
closePromise = null;
|
|
16943
17329
|
constructor(options = {}) {
|
|
@@ -17056,20 +17442,21 @@ class LettaAgentClientBase {
|
|
|
17056
17442
|
const sessionOptions = stripCloudExecutionOptions(options);
|
|
17057
17443
|
validateCreateSessionOptions(sessionOptions);
|
|
17058
17444
|
this.assertSessionBackend("resumeSession", options);
|
|
17445
|
+
const inherited = this.backend === "cloud" ? null : this.toolRegistry?.inheritFor(id, sessionOptions) ?? null;
|
|
17059
17446
|
if (this.backend === "remote") {
|
|
17060
|
-
|
|
17061
|
-
|
|
17062
|
-
|
|
17063
|
-
|
|
17064
|
-
|
|
17065
|
-
});
|
|
17066
|
-
}
|
|
17067
|
-
return new AppServerSession(this.appServerSessionOptions(), {
|
|
17447
|
+
const session2 = looksLikeConversationId(id) ? new AppServerSession(this.appServerSessionOptions(), {
|
|
17448
|
+
kind: "session",
|
|
17449
|
+
conversationId: id,
|
|
17450
|
+
options
|
|
17451
|
+
}) : new AppServerSession(this.appServerSessionOptions(), {
|
|
17068
17452
|
kind: "session",
|
|
17069
17453
|
agentId: id,
|
|
17070
17454
|
defaultConversation: true,
|
|
17071
17455
|
options
|
|
17072
17456
|
});
|
|
17457
|
+
if (inherited)
|
|
17458
|
+
session2.inheritTools(inherited);
|
|
17459
|
+
return session2;
|
|
17073
17460
|
}
|
|
17074
17461
|
if (this.backend === "cloud") {
|
|
17075
17462
|
if (looksLikeConversationId(id)) {
|
|
@@ -17086,7 +17473,10 @@ class LettaAgentClientBase {
|
|
|
17086
17473
|
options
|
|
17087
17474
|
}, this.getCloudClient());
|
|
17088
17475
|
}
|
|
17089
|
-
|
|
17476
|
+
const session = this.resumeLocalSession(id, options);
|
|
17477
|
+
if (inherited && session instanceof AppServerSession)
|
|
17478
|
+
session.inheritTools(inherited);
|
|
17479
|
+
return session;
|
|
17090
17480
|
}
|
|
17091
17481
|
async prompt(message, agentId, options = {}) {
|
|
17092
17482
|
this.assertOpen();
|
|
@@ -17294,10 +17684,23 @@ class LettaAgentClientBase {
|
|
|
17294
17684
|
}
|
|
17295
17685
|
return this.managementTransport;
|
|
17296
17686
|
}
|
|
17687
|
+
registerTools(options) {
|
|
17688
|
+
this.assertOpen();
|
|
17689
|
+
if (this.backend === "cloud") {
|
|
17690
|
+
return Promise.reject(new Error('registerTools() requires backend: "local" or "remote". Cloud sessions register tools through the tools session option.'));
|
|
17691
|
+
}
|
|
17692
|
+
this.toolRegistry ??= new ToolRegistry(this.backend === "remote" ? this.remoteOptions() : this.localAppServerConnection());
|
|
17693
|
+
return this.toolRegistry.register(options);
|
|
17694
|
+
}
|
|
17695
|
+
localAppServerConnection() {
|
|
17696
|
+
throw this.localBackendUnavailableError();
|
|
17697
|
+
}
|
|
17297
17698
|
close() {
|
|
17298
17699
|
if (this.closePromise)
|
|
17299
17700
|
return this.closePromise;
|
|
17300
17701
|
this.closed = true;
|
|
17702
|
+
this.toolRegistry?.close();
|
|
17703
|
+
this.toolRegistry = null;
|
|
17301
17704
|
const transport = this.managementTransport;
|
|
17302
17705
|
this.managementTransport = null;
|
|
17303
17706
|
const close = transport?.close() ?? Promise.resolve();
|
|
@@ -17842,4 +18245,4 @@ export {
|
|
|
17842
18245
|
CloudManagedSandboxExpiredError
|
|
17843
18246
|
};
|
|
17844
18247
|
|
|
17845
|
-
//# debugId=
|
|
18248
|
+
//# debugId=6BF8FBE2B45A41B264756E2164756E21
|