@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/index.js
CHANGED
|
@@ -13183,7 +13183,7 @@ async function* streamStructuredTurns(config) {
|
|
|
13183
13183
|
return;
|
|
13184
13184
|
});
|
|
13185
13185
|
}
|
|
13186
|
-
if (msg.type !== "result") {
|
|
13186
|
+
if (msg.type !== "result" || msg.origin !== undefined) {
|
|
13187
13187
|
yield msg;
|
|
13188
13188
|
continue;
|
|
13189
13189
|
}
|
|
@@ -13303,9 +13303,115 @@ function expandMcpToolWildcards(allowedTools, mcpTools) {
|
|
|
13303
13303
|
return [...new Set(expanded)];
|
|
13304
13304
|
}
|
|
13305
13305
|
|
|
13306
|
+
// src/external-tools.ts
|
|
13307
|
+
function externalToolGroups(tools) {
|
|
13308
|
+
if (!tools || tools.length === 0)
|
|
13309
|
+
return;
|
|
13310
|
+
return [
|
|
13311
|
+
{
|
|
13312
|
+
tools: tools.map((tool) => ({
|
|
13313
|
+
name: tool.name,
|
|
13314
|
+
label: tool.label,
|
|
13315
|
+
description: tool.description,
|
|
13316
|
+
parameters: tool.parameters
|
|
13317
|
+
}))
|
|
13318
|
+
}
|
|
13319
|
+
];
|
|
13320
|
+
}
|
|
13321
|
+
var MAX_REMEMBERED_EXTERNAL_TOOL_CALLS = 200;
|
|
13322
|
+
function createExternalToolCallHandler(externalTools, fallbackRuntime) {
|
|
13323
|
+
const calls = new Map;
|
|
13324
|
+
const execute = async (request) => {
|
|
13325
|
+
const tool = externalTools.get(request.tool_name);
|
|
13326
|
+
if (!tool) {
|
|
13327
|
+
throw new Error(`Unknown external tool: ${request.tool_name}`);
|
|
13328
|
+
}
|
|
13329
|
+
const runtime = request.runtime ?? fallbackRuntime?.() ?? null;
|
|
13330
|
+
const context = runtime ? { toolCallId: request.tool_call_id, agentId: runtime.agent_id, conversationId: runtime.conversation_id } : undefined;
|
|
13331
|
+
const result = await tool.execute(request.tool_call_id, request.input, undefined, undefined, context);
|
|
13332
|
+
return {
|
|
13333
|
+
content: result.content.map((part) => ({
|
|
13334
|
+
type: part.type,
|
|
13335
|
+
...part.text !== undefined ? { text: part.text } : {},
|
|
13336
|
+
...part.data !== undefined ? { data: part.data } : {},
|
|
13337
|
+
...part.mimeType !== undefined ? { mimeType: part.mimeType } : {}
|
|
13338
|
+
})),
|
|
13339
|
+
...result.isError === true ? { is_error: true } : {}
|
|
13340
|
+
};
|
|
13341
|
+
};
|
|
13342
|
+
return (request) => {
|
|
13343
|
+
const requestId = request.request_id;
|
|
13344
|
+
if (typeof requestId !== "string" || requestId.length === 0) {
|
|
13345
|
+
return execute(request);
|
|
13346
|
+
}
|
|
13347
|
+
const existing = calls.get(requestId);
|
|
13348
|
+
if (existing)
|
|
13349
|
+
return existing;
|
|
13350
|
+
const call = execute(request);
|
|
13351
|
+
calls.set(requestId, call);
|
|
13352
|
+
while (calls.size > MAX_REMEMBERED_EXTERNAL_TOOL_CALLS) {
|
|
13353
|
+
const oldest = calls.keys().next().value;
|
|
13354
|
+
if (oldest === undefined)
|
|
13355
|
+
break;
|
|
13356
|
+
calls.delete(oldest);
|
|
13357
|
+
}
|
|
13358
|
+
return call;
|
|
13359
|
+
};
|
|
13360
|
+
}
|
|
13361
|
+
|
|
13362
|
+
// src/runtime-tool-policy.ts
|
|
13363
|
+
var RUNTIME_TOOL_POLICY_CAPABILITY = "runtime_tool_policy";
|
|
13364
|
+
var CAPABILITY_PROBE_TIMEOUT_MS = 5000;
|
|
13365
|
+
function clientToolsetPayload(toolset) {
|
|
13366
|
+
return {
|
|
13367
|
+
...toolset.base !== undefined ? { base: toolset.base } : {},
|
|
13368
|
+
...toolset.include !== undefined ? { include: [...new Set(toolset.include)] } : {}
|
|
13369
|
+
};
|
|
13370
|
+
}
|
|
13371
|
+
function runtimeToolPolicy(allowedTools, toolset) {
|
|
13372
|
+
return {
|
|
13373
|
+
...toolset !== undefined ? { toolset: clientToolsetPayload(toolset) } : {},
|
|
13374
|
+
...allowedTools !== undefined ? { allowlist: [...new Set(allowedTools)] } : {},
|
|
13375
|
+
exclude_interactive: true
|
|
13376
|
+
};
|
|
13377
|
+
}
|
|
13378
|
+
async function supportsRuntimeToolPolicy(client) {
|
|
13379
|
+
try {
|
|
13380
|
+
const info = await client.info({ timeoutMs: CAPABILITY_PROBE_TIMEOUT_MS });
|
|
13381
|
+
const capabilities = info.capabilities;
|
|
13382
|
+
return capabilities?.[RUNTIME_TOOL_POLICY_CAPABILITY] === true;
|
|
13383
|
+
} catch {
|
|
13384
|
+
return false;
|
|
13385
|
+
}
|
|
13386
|
+
}
|
|
13387
|
+
function mergeInheritedTools(inherited, own) {
|
|
13388
|
+
if (!inherited)
|
|
13389
|
+
return own;
|
|
13390
|
+
const tools = new Map(inherited.tools.map((tool) => [tool.name, tool]));
|
|
13391
|
+
for (const tool of own.tools)
|
|
13392
|
+
tools.set(tool.name, tool);
|
|
13393
|
+
const ownNames = new Set(own.tools.map((tool) => tool.name));
|
|
13394
|
+
const registered = inherited.allowedTools;
|
|
13395
|
+
const allowedTools = registered === undefined ? own.allowedTools : own.allowedTools === undefined ? [...new Set([...registered, ...ownNames])] : own.allowedTools.filter((name) => registered.includes(name) || ownNames.has(name));
|
|
13396
|
+
const toolset = own.toolset ?? inherited.toolset;
|
|
13397
|
+
return {
|
|
13398
|
+
tools: [...tools.values()],
|
|
13399
|
+
...allowedTools !== undefined ? { allowedTools } : {},
|
|
13400
|
+
...toolset !== undefined ? { toolset } : {}
|
|
13401
|
+
};
|
|
13402
|
+
}
|
|
13403
|
+
|
|
13306
13404
|
// src/remote-turn-coordinator.ts
|
|
13307
13405
|
var MAX_RECENTLY_SETTLED_RUN_IDS = 256;
|
|
13308
13406
|
var TRAILING_USAGE_GRACE_MS = 100;
|
|
13407
|
+
var TURN_ORIGINS = new Set([
|
|
13408
|
+
"task_notification",
|
|
13409
|
+
"cron",
|
|
13410
|
+
"subagent",
|
|
13411
|
+
"system",
|
|
13412
|
+
"channel",
|
|
13413
|
+
"user"
|
|
13414
|
+
]);
|
|
13309
13415
|
|
|
13310
13416
|
class RemoteTurnCoordinator {
|
|
13311
13417
|
label;
|
|
@@ -13317,6 +13423,8 @@ class RemoteTurnCoordinator {
|
|
|
13317
13423
|
activeTurn = null;
|
|
13318
13424
|
pendingTurns = [];
|
|
13319
13425
|
settledRunIds = new Set;
|
|
13426
|
+
queueOrigins = new Map;
|
|
13427
|
+
nextServerOrigin = "unknown";
|
|
13320
13428
|
nextTurnId = 0;
|
|
13321
13429
|
messageCounter = 0;
|
|
13322
13430
|
clientMessageCounter = 0;
|
|
@@ -13332,16 +13440,27 @@ class RemoteTurnCoordinator {
|
|
|
13332
13440
|
return this._activeTurnStartedAt;
|
|
13333
13441
|
}
|
|
13334
13442
|
hasInFlightTurn() {
|
|
13335
|
-
return this.activeTurn !== null || this.pendingTurns.length > 0;
|
|
13443
|
+
return this.activeTurn !== null && this.activeTurn.origin === undefined || this.pendingTurns.length > 0;
|
|
13336
13444
|
}
|
|
13337
13445
|
trackSentTurn(runtime, callerOtid, outputFormat) {
|
|
13338
13446
|
const otid = normalizeCallerOtid(callerOtid);
|
|
13339
|
-
const turn = {
|
|
13340
|
-
id: ++this.nextTurnId,
|
|
13341
|
-
runtime,
|
|
13447
|
+
const turn = this.newTracker(runtime, {
|
|
13342
13448
|
...otid !== undefined ? { otid } : {},
|
|
13343
13449
|
...outputFormat !== undefined ? { outputFormat } : {},
|
|
13344
|
-
clientMessageId: otid ?? `sdk-message-${Date.now()}-${++this.clientMessageCounter}
|
|
13450
|
+
clientMessageId: otid ?? `sdk-message-${Date.now()}-${++this.clientMessageCounter}`
|
|
13451
|
+
});
|
|
13452
|
+
if (this.activeTurn) {
|
|
13453
|
+
this.pendingTurns.push(turn);
|
|
13454
|
+
} else {
|
|
13455
|
+
this.activateTurn(turn);
|
|
13456
|
+
}
|
|
13457
|
+
return turn;
|
|
13458
|
+
}
|
|
13459
|
+
newTracker(runtime, identity) {
|
|
13460
|
+
return {
|
|
13461
|
+
id: ++this.nextTurnId,
|
|
13462
|
+
runtime,
|
|
13463
|
+
...identity,
|
|
13345
13464
|
queuedAt: Date.now(),
|
|
13346
13465
|
startedAt: 0,
|
|
13347
13466
|
assistantText: "",
|
|
@@ -13358,13 +13477,32 @@ class RemoteTurnCoordinator {
|
|
|
13358
13477
|
abortRequested: false,
|
|
13359
13478
|
timeout: null
|
|
13360
13479
|
};
|
|
13361
|
-
|
|
13362
|
-
|
|
13363
|
-
|
|
13364
|
-
|
|
13365
|
-
|
|
13480
|
+
}
|
|
13481
|
+
startServerTurn(runtime) {
|
|
13482
|
+
const turn = this.newTracker(runtime, { clientMessageId: "", origin: this.nextServerOrigin });
|
|
13483
|
+
this.nextServerOrigin = "unknown";
|
|
13484
|
+
this.activateTurn(turn);
|
|
13366
13485
|
return turn;
|
|
13367
13486
|
}
|
|
13487
|
+
observeQueueOrigins(message, queue) {
|
|
13488
|
+
for (const item of queue) {
|
|
13489
|
+
if (!item.clientMessageId)
|
|
13490
|
+
continue;
|
|
13491
|
+
this.queueOrigins.set(item.clientMessageId, TURN_ORIGINS.has(item.source) ? item.source : "unknown");
|
|
13492
|
+
if (this.queueOrigins.size > MAX_RECENTLY_SETTLED_RUN_IDS) {
|
|
13493
|
+
this.queueOrigins.delete(this.queueOrigins.keys().next().value);
|
|
13494
|
+
}
|
|
13495
|
+
}
|
|
13496
|
+
for (const removed of Array.isArray(message.removed) ? message.removed : []) {
|
|
13497
|
+
const { client_message_id: id, disposition, source } = removed;
|
|
13498
|
+
if (disposition !== "dequeued" || typeof id !== "string")
|
|
13499
|
+
continue;
|
|
13500
|
+
const own = [this.activeTurn, ...this.pendingTurns].some((turn) => turn?.clientMessageId === id);
|
|
13501
|
+
if (own)
|
|
13502
|
+
continue;
|
|
13503
|
+
this.nextServerOrigin = typeof source === "string" && TURN_ORIGINS.has(source) ? source : this.queueOrigins.get(id) ?? "unknown";
|
|
13504
|
+
}
|
|
13505
|
+
}
|
|
13368
13506
|
removeTrackedTurn(turn) {
|
|
13369
13507
|
if (turn.timeout)
|
|
13370
13508
|
clearTimeout(turn.timeout);
|
|
@@ -13378,6 +13516,12 @@ class RemoteTurnCoordinator {
|
|
|
13378
13516
|
if (index !== -1)
|
|
13379
13517
|
this.pendingTurns.splice(index, 1);
|
|
13380
13518
|
}
|
|
13519
|
+
failServerTurn(detail) {
|
|
13520
|
+
const active = this.activeTurn;
|
|
13521
|
+
if (active?.origin === undefined)
|
|
13522
|
+
return;
|
|
13523
|
+
this.failTurn(active, detail, { errorCode: "stream_closed", recoverable: true });
|
|
13524
|
+
}
|
|
13381
13525
|
markAbortRequested() {
|
|
13382
13526
|
if (this.activeTurn)
|
|
13383
13527
|
this.activeTurn.abortRequested = true;
|
|
@@ -13397,6 +13541,7 @@ class RemoteTurnCoordinator {
|
|
|
13397
13541
|
type: "queue_update",
|
|
13398
13542
|
queue: queueItems(message)
|
|
13399
13543
|
};
|
|
13544
|
+
this.observeQueueOrigins(message, sdkMessage2.queue);
|
|
13400
13545
|
this.enqueue(sdkMessage2);
|
|
13401
13546
|
return;
|
|
13402
13547
|
}
|
|
@@ -13439,9 +13584,9 @@ class RemoteTurnCoordinator {
|
|
|
13439
13584
|
if (!delta)
|
|
13440
13585
|
return;
|
|
13441
13586
|
const messageType = streamDeltaMessageType(delta);
|
|
13442
|
-
const active = messageType === "usage_statistics" || messageType === "stop_reason" ? this.activeTurn : this.activateNextTurnFromProtocol();
|
|
13443
13587
|
const runId = streamDeltaRunId(delta);
|
|
13444
13588
|
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");
|
|
13589
|
+
const active = messageType === "usage_statistics" || messageType === "stop_reason" ? this.activeTurn : this.activateNextTurnFromProtocol() ?? (isTurnEvidence && runId !== undefined ? this.startServerTurn(runtime) : null);
|
|
13445
13590
|
if (active && isTurnEvidence) {
|
|
13446
13591
|
active.observedTurnEvidence = true;
|
|
13447
13592
|
if (runId)
|
|
@@ -13899,7 +14044,8 @@ class RemoteTurnCoordinator {
|
|
|
13899
14044
|
stopReason,
|
|
13900
14045
|
durationMs: Date.now() - (tracker?.startedAt || this._activeTurnStartedAt),
|
|
13901
14046
|
conversationId: turn.runtime.conversation_id,
|
|
13902
|
-
runIds: turn.runIds.length > 0 ? turn.runIds : undefined
|
|
14047
|
+
runIds: turn.runIds.length > 0 ? turn.runIds : undefined,
|
|
14048
|
+
...tracker?.origin !== undefined ? { origin: tracker.origin } : {}
|
|
13903
14049
|
};
|
|
13904
14050
|
}
|
|
13905
14051
|
enqueue(message) {
|
|
@@ -14141,9 +14287,8 @@ class RemoteClientSessionCore {
|
|
|
14141
14287
|
}
|
|
14142
14288
|
await this.send(message);
|
|
14143
14289
|
for await (const msg of this.stream()) {
|
|
14144
|
-
if (msg.type === "result")
|
|
14290
|
+
if (msg.type === "result" && msg.origin === undefined)
|
|
14145
14291
|
return msg;
|
|
14146
|
-
}
|
|
14147
14292
|
}
|
|
14148
14293
|
return {
|
|
14149
14294
|
type: "result",
|
|
@@ -14179,7 +14324,7 @@ class RemoteClientSessionCore {
|
|
|
14179
14324
|
if (!msg)
|
|
14180
14325
|
break;
|
|
14181
14326
|
yield msg;
|
|
14182
|
-
if (msg.type === "result")
|
|
14327
|
+
if (msg.type === "result" && msg.origin === undefined)
|
|
14183
14328
|
break;
|
|
14184
14329
|
}
|
|
14185
14330
|
}
|
|
@@ -14489,6 +14634,7 @@ class RemoteClientSessionCore {
|
|
|
14489
14634
|
this.controller?.close();
|
|
14490
14635
|
this.controller = null;
|
|
14491
14636
|
const error = new Error(`${this.label} connection closed before send`);
|
|
14637
|
+
this.turns.failServerTurn(error.message);
|
|
14492
14638
|
for (const cancel of [...this.deviceStatusRefreshCancels])
|
|
14493
14639
|
cancel(error);
|
|
14494
14640
|
this.deviceStatusRefreshCancels.clear();
|
|
@@ -14629,38 +14775,6 @@ function agentToolNames(agent) {
|
|
|
14629
14775
|
return typeof name === "string" && name.length > 0 ? [name] : [];
|
|
14630
14776
|
});
|
|
14631
14777
|
}
|
|
14632
|
-
function externalToolGroups(tools) {
|
|
14633
|
-
if (!tools || tools.length === 0)
|
|
14634
|
-
return;
|
|
14635
|
-
return [
|
|
14636
|
-
{
|
|
14637
|
-
tools: tools.map((tool) => ({
|
|
14638
|
-
name: tool.name,
|
|
14639
|
-
label: tool.label,
|
|
14640
|
-
description: tool.description,
|
|
14641
|
-
parameters: tool.parameters
|
|
14642
|
-
}))
|
|
14643
|
-
}
|
|
14644
|
-
];
|
|
14645
|
-
}
|
|
14646
|
-
function createExternalToolCallHandler(externalTools) {
|
|
14647
|
-
return async (request) => {
|
|
14648
|
-
const tool = externalTools.get(request.tool_name);
|
|
14649
|
-
if (!tool) {
|
|
14650
|
-
throw new Error(`Unknown external tool: ${request.tool_name}`);
|
|
14651
|
-
}
|
|
14652
|
-
const result = await tool.execute(request.tool_call_id, request.input);
|
|
14653
|
-
return {
|
|
14654
|
-
content: result.content.map((part) => ({
|
|
14655
|
-
type: part.type,
|
|
14656
|
-
...part.text !== undefined ? { text: part.text } : {},
|
|
14657
|
-
...part.data !== undefined ? { data: part.data } : {},
|
|
14658
|
-
...part.mimeType !== undefined ? { mimeType: part.mimeType } : {}
|
|
14659
|
-
})),
|
|
14660
|
-
...result.isError === true ? { is_error: true } : {}
|
|
14661
|
-
};
|
|
14662
|
-
};
|
|
14663
|
-
}
|
|
14664
14778
|
async function resolveAppServerToolApproval(options, toolName, toolInput, context) {
|
|
14665
14779
|
if ("outputFormat" in options && options.outputFormat !== undefined && toolName === STRUCTURED_OUTPUT_TOOL) {
|
|
14666
14780
|
return { behavior: "allow", updatedInput: null, updatedPermissions: [] };
|
|
@@ -14837,11 +14951,26 @@ class AppServerRuntimeController {
|
|
|
14837
14951
|
options;
|
|
14838
14952
|
clientToolAllowlist;
|
|
14839
14953
|
clientToolset;
|
|
14840
|
-
|
|
14954
|
+
toolPolicyApplied;
|
|
14955
|
+
constructor(client, options, clientToolAllowlist, clientToolset, toolPolicyApplied = false) {
|
|
14841
14956
|
this.client = client;
|
|
14842
14957
|
this.options = options;
|
|
14843
14958
|
this.clientToolAllowlist = clientToolAllowlist;
|
|
14844
14959
|
this.clientToolset = clientToolset;
|
|
14960
|
+
this.toolPolicyApplied = toolPolicyApplied;
|
|
14961
|
+
}
|
|
14962
|
+
async updateToolSelection(runtime, selection) {
|
|
14963
|
+
this.clientToolAllowlist = selection.allowedTools;
|
|
14964
|
+
this.clientToolset = selection.toolset;
|
|
14965
|
+
const response = await this.client.runtimeExternalToolsUpdate({
|
|
14966
|
+
updates: [{
|
|
14967
|
+
runtimes: [runtime],
|
|
14968
|
+
external_tools: externalToolGroups(selection.tools) ?? [],
|
|
14969
|
+
...this.toolPolicyApplied ? { tool_policy: runtimeToolPolicy(selection.allowedTools, selection.toolset) } : {}
|
|
14970
|
+
}]
|
|
14971
|
+
});
|
|
14972
|
+
if (!response.success)
|
|
14973
|
+
throw new Error(response.error ?? "Failed to update session tools");
|
|
14845
14974
|
}
|
|
14846
14975
|
onMessage(handler) {
|
|
14847
14976
|
return this.client.onMessage((message, channel) => {
|
|
@@ -14863,14 +14992,11 @@ class AppServerRuntimeController {
|
|
|
14863
14992
|
}
|
|
14864
14993
|
]
|
|
14865
14994
|
};
|
|
14866
|
-
if (this.clientToolAllowlist !== undefined) {
|
|
14995
|
+
if (!this.toolPolicyApplied && this.clientToolAllowlist !== undefined) {
|
|
14867
14996
|
payload.client_tool_allowlist = [...new Set(this.clientToolAllowlist)];
|
|
14868
14997
|
}
|
|
14869
|
-
if (this.clientToolset !== undefined) {
|
|
14870
|
-
payload.client_toolset =
|
|
14871
|
-
...this.clientToolset.base !== undefined ? { base: this.clientToolset.base } : {},
|
|
14872
|
-
...this.clientToolset.include !== undefined ? { include: [...new Set(this.clientToolset.include)] } : {}
|
|
14873
|
-
};
|
|
14998
|
+
if (!this.toolPolicyApplied && this.clientToolset !== undefined) {
|
|
14999
|
+
payload.client_toolset = clientToolsetPayload(this.clientToolset);
|
|
14874
15000
|
}
|
|
14875
15001
|
if (options.outputFormat !== undefined) {
|
|
14876
15002
|
payload.response_format = {
|
|
@@ -14882,7 +15008,8 @@ class AppServerRuntimeController {
|
|
|
14882
15008
|
}
|
|
14883
15009
|
};
|
|
14884
15010
|
}
|
|
14885
|
-
|
|
15011
|
+
if (!this.toolPolicyApplied)
|
|
15012
|
+
payload.exclude_interactive_tools = true;
|
|
14886
15013
|
this.client.input({
|
|
14887
15014
|
runtime,
|
|
14888
15015
|
payload
|
|
@@ -14974,6 +15101,9 @@ class AppServerSession extends RemoteClientSessionCore {
|
|
|
14974
15101
|
mcpCleanup = Promise.resolve();
|
|
14975
15102
|
removeExternalToolHandler = null;
|
|
14976
15103
|
removeControlRequestHandler = null;
|
|
15104
|
+
inheritedTools = null;
|
|
15105
|
+
removeInheritedListener = null;
|
|
15106
|
+
ownSelection = null;
|
|
14977
15107
|
constructor(remoteOptions, mode) {
|
|
14978
15108
|
super(mode, {
|
|
14979
15109
|
label: "app-server",
|
|
@@ -14985,6 +15115,27 @@ class AppServerSession extends RemoteClientSessionCore {
|
|
|
14985
15115
|
this.externalTools.set(tool.name, tool);
|
|
14986
15116
|
}
|
|
14987
15117
|
}
|
|
15118
|
+
inheritTools(source) {
|
|
15119
|
+
this.inheritedTools = source;
|
|
15120
|
+
this.removeInheritedListener = source.onChange(() => {
|
|
15121
|
+
this.refreshInheritedTools().catch(() => {
|
|
15122
|
+
return;
|
|
15123
|
+
});
|
|
15124
|
+
});
|
|
15125
|
+
}
|
|
15126
|
+
applyToolSelection() {
|
|
15127
|
+
const selection = mergeInheritedTools(this.inheritedTools?.current() ?? null, this.ownSelection ?? { tools: [] });
|
|
15128
|
+
this.externalTools.clear();
|
|
15129
|
+
for (const tool of selection.tools)
|
|
15130
|
+
this.externalTools.set(tool.name, tool);
|
|
15131
|
+
return selection;
|
|
15132
|
+
}
|
|
15133
|
+
async refreshInheritedTools() {
|
|
15134
|
+
if (!this.ownSelection || !this.runtime || !(this.controller instanceof AppServerRuntimeController))
|
|
15135
|
+
return;
|
|
15136
|
+
const selection = this.applyToolSelection();
|
|
15137
|
+
await this.controller.updateToolSelection(this.runtime, selection);
|
|
15138
|
+
}
|
|
14988
15139
|
shouldEnableMemfs(options) {
|
|
14989
15140
|
if (this.mode.kind !== "create-agent")
|
|
14990
15141
|
return false;
|
|
@@ -15000,6 +15151,9 @@ class AppServerSession extends RemoteClientSessionCore {
|
|
|
15000
15151
|
...this.remoteOptions.requestTimeoutMs !== undefined ? { requestTimeoutMs: this.remoteOptions.requestTimeoutMs } : {}
|
|
15001
15152
|
}));
|
|
15002
15153
|
const options = this.currentOptions();
|
|
15154
|
+
this.externalTools.clear();
|
|
15155
|
+
for (const tool of this.mode.options.tools ?? [])
|
|
15156
|
+
this.externalTools.set(tool.name, tool);
|
|
15003
15157
|
this.mcpBridge = await connectMcpServers("mcpServers" in options ? options.mcpServers : undefined, {
|
|
15004
15158
|
cwd: options.cwd,
|
|
15005
15159
|
reservedToolNames: this.externalTools.keys()
|
|
@@ -15007,13 +15161,22 @@ class AppServerSession extends RemoteClientSessionCore {
|
|
|
15007
15161
|
for (const tool of this.mcpBridge.tools) {
|
|
15008
15162
|
this.externalTools.set(tool.name, tool);
|
|
15009
15163
|
}
|
|
15164
|
+
const mcpToolNames = this.mcpBridge.tools.map((tool) => tool.name);
|
|
15165
|
+
const ownToolset = "toolset" in options ? options.toolset : undefined;
|
|
15166
|
+
const ownAllowedTools = expandMcpToolWildcards(options.allowedTools, mcpToolNames);
|
|
15167
|
+
this.ownSelection = {
|
|
15168
|
+
tools: [...this.externalTools.values()],
|
|
15169
|
+
...ownAllowedTools !== undefined ? { allowedTools: ownAllowedTools } : {},
|
|
15170
|
+
...ownToolset !== undefined ? { toolset: ownToolset } : {}
|
|
15171
|
+
};
|
|
15172
|
+
const { allowedTools, toolset: clientToolset } = this.applyToolSelection();
|
|
15010
15173
|
this.removeControlRequestHandler = registerAppServerControlRequestHandler({
|
|
15011
15174
|
client,
|
|
15012
15175
|
getRuntime: () => this.runtime,
|
|
15013
15176
|
getOptions: () => this.currentOptions()
|
|
15014
15177
|
});
|
|
15015
|
-
if (this.externalTools.size > 0) {
|
|
15016
|
-
this.removeExternalToolHandler = client.onExternalToolCall(createExternalToolCallHandler(this.externalTools));
|
|
15178
|
+
if (this.externalTools.size > 0 || this.inheritedTools) {
|
|
15179
|
+
this.removeExternalToolHandler = client.onExternalToolCall(createExternalToolCallHandler(this.externalTools, () => this.runtime));
|
|
15017
15180
|
}
|
|
15018
15181
|
try {
|
|
15019
15182
|
await client.connect();
|
|
@@ -15024,19 +15187,17 @@ class AppServerSession extends RemoteClientSessionCore {
|
|
|
15024
15187
|
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.`);
|
|
15025
15188
|
}
|
|
15026
15189
|
}
|
|
15027
|
-
const response = await this.startRuntime(client);
|
|
15190
|
+
const response = await this.startRuntime(client, runtimeToolPolicy(allowedTools, clientToolset));
|
|
15028
15191
|
if (!response.success || !response.runtime) {
|
|
15029
15192
|
throw new Error(response.error ?? "Failed to start app-server runtime");
|
|
15030
15193
|
}
|
|
15031
15194
|
this.watchTransportDisconnect(client);
|
|
15195
|
+
const toolPolicyApplied = await supportsRuntimeToolPolicy(client);
|
|
15032
15196
|
const tools = agentToolNames(response.agent);
|
|
15033
15197
|
const skillSources = options.skillSources;
|
|
15034
|
-
const clientToolset = "toolset" in options ? options.toolset : undefined;
|
|
15035
|
-
const mcpToolNames = this.mcpBridge?.tools.map((tool) => tool.name) ?? [];
|
|
15036
|
-
const allowedTools = expandMcpToolWildcards(options.allowedTools, mcpToolNames);
|
|
15037
15198
|
const availableTools = tools === undefined && mcpToolNames.length === 0 ? undefined : [...tools ?? [], ...mcpToolNames];
|
|
15038
15199
|
return {
|
|
15039
|
-
controller: new AppServerRuntimeController(client, this.remoteOptions, allowedTools, clientToolset),
|
|
15200
|
+
controller: new AppServerRuntimeController(client, this.remoteOptions, allowedTools, clientToolset, toolPolicyApplied),
|
|
15040
15201
|
runtime: response.runtime,
|
|
15041
15202
|
model: typeof response.agent?.model === "string" ? response.agent.model : typeof response.conversation?.model === "string" ? response.conversation.model : "",
|
|
15042
15203
|
modelSettings: objectRecord(response.agent?.model_settings) ?? objectRecord(response.conversation?.model_settings) ?? null,
|
|
@@ -15054,6 +15215,10 @@ class AppServerSession extends RemoteClientSessionCore {
|
|
|
15054
15215
|
}
|
|
15055
15216
|
}
|
|
15056
15217
|
onCoreClose() {
|
|
15218
|
+
if (this.closed) {
|
|
15219
|
+
this.removeInheritedListener?.();
|
|
15220
|
+
this.removeInheritedListener = null;
|
|
15221
|
+
}
|
|
15057
15222
|
this.removeExternalToolHandler?.();
|
|
15058
15223
|
this.removeExternalToolHandler = null;
|
|
15059
15224
|
this.removeControlRequestHandler?.();
|
|
@@ -15084,11 +15249,11 @@ class AppServerSession extends RemoteClientSessionCore {
|
|
|
15084
15249
|
this.ownedConnection = connection;
|
|
15085
15250
|
return connection.url;
|
|
15086
15251
|
}
|
|
15087
|
-
async startRuntime(client) {
|
|
15088
|
-
const command = await this.buildRuntimeStartCommand(client);
|
|
15252
|
+
async startRuntime(client, toolPolicy) {
|
|
15253
|
+
const command = await this.buildRuntimeStartCommand(client, toolPolicy);
|
|
15089
15254
|
return client.runtimeStart(command);
|
|
15090
15255
|
}
|
|
15091
|
-
async buildRuntimeStartCommand(client) {
|
|
15256
|
+
async buildRuntimeStartCommand(client, toolPolicy) {
|
|
15092
15257
|
const options = this.mode.options;
|
|
15093
15258
|
const command = {
|
|
15094
15259
|
client_info: {
|
|
@@ -15119,6 +15284,7 @@ class AppServerSession extends RemoteClientSessionCore {
|
|
|
15119
15284
|
const groups = externalToolGroups([...this.externalTools.values()]);
|
|
15120
15285
|
if (groups)
|
|
15121
15286
|
command.external_tools = groups;
|
|
15287
|
+
command.tool_policy = toolPolicy;
|
|
15122
15288
|
if (this.mode.kind === "create-agent") {
|
|
15123
15289
|
command.create_agent = {
|
|
15124
15290
|
body: await createAgentBody(this.mode.options),
|
|
@@ -15601,6 +15767,9 @@ class CloudStatusTransport {
|
|
|
15601
15767
|
if (channel === "control" && message.type === "stream_delta") {
|
|
15602
15768
|
return false;
|
|
15603
15769
|
}
|
|
15770
|
+
if (channel === "stream" && message.type === "external_tool_call_request") {
|
|
15771
|
+
return false;
|
|
15772
|
+
}
|
|
15604
15773
|
if (this.isDuplicate(message))
|
|
15605
15774
|
return false;
|
|
15606
15775
|
this.trackEventSequence(message);
|
|
@@ -16097,7 +16266,7 @@ class CloudEnvironmentSession extends RemoteClientSessionCore {
|
|
|
16097
16266
|
getOptions: () => this.currentOptions()
|
|
16098
16267
|
});
|
|
16099
16268
|
if (this.externalTools.size > 0) {
|
|
16100
|
-
this.removeExternalToolHandler = client.onExternalToolCall(createExternalToolCallHandler(this.externalTools));
|
|
16269
|
+
this.removeExternalToolHandler = client.onExternalToolCall(createExternalToolCallHandler(this.externalTools, () => this.runtime));
|
|
16101
16270
|
}
|
|
16102
16271
|
}
|
|
16103
16272
|
cleanupTransportHandlers() {
|
|
@@ -16155,6 +16324,7 @@ class CloudEnvironmentSession extends RemoteClientSessionCore {
|
|
|
16155
16324
|
const groups = externalToolGroups([...this.externalTools.values()]);
|
|
16156
16325
|
if (groups)
|
|
16157
16326
|
command.external_tools = groups;
|
|
16327
|
+
command.tool_policy = runtimeToolPolicy(expandMcpToolWildcards(options.allowedTools, this.mcpBridge?.tools.map((tool) => tool.name) ?? []), "toolset" in options ? options.toolset : undefined);
|
|
16158
16328
|
return await client.runtimeStart(command);
|
|
16159
16329
|
}
|
|
16160
16330
|
async afterRuntimeInitialized() {
|
|
@@ -16720,6 +16890,221 @@ function createQuery(createSession, params) {
|
|
|
16720
16890
|
});
|
|
16721
16891
|
}
|
|
16722
16892
|
|
|
16893
|
+
// src/tool-registration.ts
|
|
16894
|
+
var RECONNECT_DELAYS_MS = [250, 1000, 5000, 15000];
|
|
16895
|
+
var runtimeKey = (runtime) => `${runtime.agent_id}:${runtime.conversation_id}`;
|
|
16896
|
+
|
|
16897
|
+
class ToolRegistry {
|
|
16898
|
+
options;
|
|
16899
|
+
connection = null;
|
|
16900
|
+
entries = new Set;
|
|
16901
|
+
listeners = new Set;
|
|
16902
|
+
reconnectAttempt = 0;
|
|
16903
|
+
reconnectTimer = null;
|
|
16904
|
+
closed = false;
|
|
16905
|
+
constructor(options) {
|
|
16906
|
+
this.options = options;
|
|
16907
|
+
}
|
|
16908
|
+
async register(options) {
|
|
16909
|
+
if (this.closed)
|
|
16910
|
+
throw new Error("LettaAgentClient is closed");
|
|
16911
|
+
const entry = { options, runtimes: [], call: createExternalToolCallHandler(new Map) };
|
|
16912
|
+
await this.apply(entry, options);
|
|
16913
|
+
const registry = this;
|
|
16914
|
+
return {
|
|
16915
|
+
get conversations() {
|
|
16916
|
+
return [...entry.options.conversations];
|
|
16917
|
+
},
|
|
16918
|
+
update: async (next) => {
|
|
16919
|
+
if (!registry.entries.has(entry))
|
|
16920
|
+
throw new Error("This tool registration is closed.");
|
|
16921
|
+
await registry.apply(entry, { ...entry.options, ...next });
|
|
16922
|
+
},
|
|
16923
|
+
close: () => registry.remove(entry),
|
|
16924
|
+
[Symbol.asyncDispose]: () => registry.remove(entry)
|
|
16925
|
+
};
|
|
16926
|
+
}
|
|
16927
|
+
close() {
|
|
16928
|
+
this.closed = true;
|
|
16929
|
+
this.entries.clear();
|
|
16930
|
+
this.disconnect();
|
|
16931
|
+
this.notify();
|
|
16932
|
+
}
|
|
16933
|
+
inheritFor(id, own) {
|
|
16934
|
+
const covering = this.covering(id);
|
|
16935
|
+
if (!covering)
|
|
16936
|
+
return null;
|
|
16937
|
+
const registered = new Set(covering.options.tools.map((tool) => tool.name));
|
|
16938
|
+
const clash = own.tools?.find((tool) => registered.has(tool.name));
|
|
16939
|
+
if (clash) {
|
|
16940
|
+
throw new Error(`Tool ${clash.name} is already registered for ${id} with registerTools(); don't pass it to the session again.`);
|
|
16941
|
+
}
|
|
16942
|
+
if (own.toolset !== undefined && covering.options.toolset !== undefined && JSON.stringify(own.toolset) !== JSON.stringify(covering.options.toolset)) {
|
|
16943
|
+
throw new Error(`${id} already has a toolset from registerTools(); narrow it with the session's allowedTools instead.`);
|
|
16944
|
+
}
|
|
16945
|
+
return {
|
|
16946
|
+
current: () => this.covering(id)?.options ?? null,
|
|
16947
|
+
onChange: (listener) => {
|
|
16948
|
+
this.listeners.add(listener);
|
|
16949
|
+
return () => this.listeners.delete(listener);
|
|
16950
|
+
}
|
|
16951
|
+
};
|
|
16952
|
+
}
|
|
16953
|
+
covering(id) {
|
|
16954
|
+
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));
|
|
16955
|
+
}
|
|
16956
|
+
notify() {
|
|
16957
|
+
for (const listener of [...this.listeners])
|
|
16958
|
+
listener();
|
|
16959
|
+
}
|
|
16960
|
+
async apply(entry, options) {
|
|
16961
|
+
if (!Array.isArray(options.conversations) || options.conversations.length === 0) {
|
|
16962
|
+
throw new Error("registerTools() requires at least one conversation.");
|
|
16963
|
+
}
|
|
16964
|
+
if (!Array.isArray(options.tools))
|
|
16965
|
+
throw new Error("registerTools() requires a tools array.");
|
|
16966
|
+
const connection = await this.connect();
|
|
16967
|
+
if (!connection.toolPolicy && (options.allowedTools || options.toolset)) {
|
|
16968
|
+
throw new Error("registerTools() allowedTools and toolset require a Letta Code app server that supports runtime tool policies. Upgrade @letta-ai/letta-code.");
|
|
16969
|
+
}
|
|
16970
|
+
const runtimes = await Promise.all(options.conversations.map((id) => resolveRuntime(connection.client, id)));
|
|
16971
|
+
const taken = new Set([...this.entries].filter((other) => other !== entry).flatMap((other) => other.runtimes.map(runtimeKey)));
|
|
16972
|
+
const overlap = options.conversations.find((_, index) => taken.has(runtimeKey(runtimes[index])));
|
|
16973
|
+
if (overlap)
|
|
16974
|
+
throw new Error(`Tools are already registered for ${overlap}.`);
|
|
16975
|
+
const keys = new Set(runtimes.map(runtimeKey));
|
|
16976
|
+
const dropped = entry.runtimes.filter((runtime) => !keys.has(runtimeKey(runtime)));
|
|
16977
|
+
const previous = { ...entry };
|
|
16978
|
+
const isNew = !this.entries.has(entry);
|
|
16979
|
+
entry.options = options;
|
|
16980
|
+
entry.runtimes = runtimes;
|
|
16981
|
+
entry.call = createExternalToolCallHandler(new Map(options.tools.map((tool) => [tool.name, tool])));
|
|
16982
|
+
this.entries.add(entry);
|
|
16983
|
+
try {
|
|
16984
|
+
await publish(connection.client, [
|
|
16985
|
+
group(runtimes, options, connection.toolPolicy),
|
|
16986
|
+
...dropped.length > 0 ? [{ runtimes: dropped, external_tools: [] }] : []
|
|
16987
|
+
]);
|
|
16988
|
+
} catch (error) {
|
|
16989
|
+
Object.assign(entry, previous);
|
|
16990
|
+
if (isNew)
|
|
16991
|
+
this.entries.delete(entry);
|
|
16992
|
+
throw error;
|
|
16993
|
+
}
|
|
16994
|
+
this.notify();
|
|
16995
|
+
}
|
|
16996
|
+
async remove(entry) {
|
|
16997
|
+
if (!this.entries.delete(entry))
|
|
16998
|
+
return;
|
|
16999
|
+
this.notify();
|
|
17000
|
+
if (this.entries.size === 0) {
|
|
17001
|
+
this.disconnect();
|
|
17002
|
+
return;
|
|
17003
|
+
}
|
|
17004
|
+
const connection = await this.connect();
|
|
17005
|
+
await publish(connection.client, [{ runtimes: entry.runtimes, external_tools: [] }]);
|
|
17006
|
+
}
|
|
17007
|
+
connect() {
|
|
17008
|
+
this.connection ??= this.open().catch((error) => {
|
|
17009
|
+
this.connection = null;
|
|
17010
|
+
throw error;
|
|
17011
|
+
});
|
|
17012
|
+
return this.connection;
|
|
17013
|
+
}
|
|
17014
|
+
async open() {
|
|
17015
|
+
const owned = this.options.url ? null : await this.options.connect?.();
|
|
17016
|
+
const url = this.options.url ?? owned?.url;
|
|
17017
|
+
if (!url)
|
|
17018
|
+
throw new Error("registerTools() requires an app-server url.");
|
|
17019
|
+
const client = applyUniqueRequestIds(createAppServerClient({
|
|
17020
|
+
url,
|
|
17021
|
+
...this.options.authToken !== undefined ? { authToken: this.options.authToken } : {},
|
|
17022
|
+
...this.options.WebSocket ? { WebSocket: this.options.WebSocket } : {},
|
|
17023
|
+
...this.options.requestTimeoutMs !== undefined ? { requestTimeoutMs: this.options.requestTimeoutMs } : {}
|
|
17024
|
+
}));
|
|
17025
|
+
client.onExternalToolCall(async (request) => {
|
|
17026
|
+
const runtime = request.runtime;
|
|
17027
|
+
const entry = runtime && [...this.entries].find((candidate) => candidate.runtimes.some((r) => runtimeKey(r) === runtimeKey(runtime)));
|
|
17028
|
+
if (!entry)
|
|
17029
|
+
throw new Error(`No tools registered for conversation ${runtime?.conversation_id}`);
|
|
17030
|
+
return entry.call(request);
|
|
17031
|
+
});
|
|
17032
|
+
try {
|
|
17033
|
+
await client.connect();
|
|
17034
|
+
} catch (error) {
|
|
17035
|
+
client.close();
|
|
17036
|
+
owned?.close();
|
|
17037
|
+
throw error;
|
|
17038
|
+
}
|
|
17039
|
+
client.onDisconnect(() => this.onDisconnect(client));
|
|
17040
|
+
return { client, owned: owned ?? null, toolPolicy: await supportsRuntimeToolPolicy(client) };
|
|
17041
|
+
}
|
|
17042
|
+
disconnect() {
|
|
17043
|
+
if (this.reconnectTimer)
|
|
17044
|
+
clearTimeout(this.reconnectTimer);
|
|
17045
|
+
this.reconnectTimer = null;
|
|
17046
|
+
const connection = this.connection;
|
|
17047
|
+
this.connection = null;
|
|
17048
|
+
connection?.then(({ client, owned }) => {
|
|
17049
|
+
client.close();
|
|
17050
|
+
owned?.close();
|
|
17051
|
+
}, () => {
|
|
17052
|
+
return;
|
|
17053
|
+
});
|
|
17054
|
+
}
|
|
17055
|
+
onDisconnect(client) {
|
|
17056
|
+
this.connection?.then((current) => {
|
|
17057
|
+
if (current.client !== client)
|
|
17058
|
+
return;
|
|
17059
|
+
current.owned?.close();
|
|
17060
|
+
this.connection = null;
|
|
17061
|
+
this.scheduleReconnect();
|
|
17062
|
+
}, () => {
|
|
17063
|
+
return;
|
|
17064
|
+
});
|
|
17065
|
+
}
|
|
17066
|
+
scheduleReconnect() {
|
|
17067
|
+
if (this.closed || this.entries.size === 0 || this.reconnectTimer)
|
|
17068
|
+
return;
|
|
17069
|
+
const delay = RECONNECT_DELAYS_MS[Math.min(this.reconnectAttempt, RECONNECT_DELAYS_MS.length - 1)];
|
|
17070
|
+
this.reconnectAttempt += 1;
|
|
17071
|
+
this.reconnectTimer = setTimeout(() => {
|
|
17072
|
+
this.reconnectTimer = null;
|
|
17073
|
+
this.republish().catch(() => this.scheduleReconnect());
|
|
17074
|
+
}, delay);
|
|
17075
|
+
this.reconnectTimer.unref?.();
|
|
17076
|
+
}
|
|
17077
|
+
async republish() {
|
|
17078
|
+
const connection = await this.connect();
|
|
17079
|
+
await publish(connection.client, [...this.entries].map((entry) => group(entry.runtimes, entry.options, connection.toolPolicy)));
|
|
17080
|
+
this.reconnectAttempt = 0;
|
|
17081
|
+
}
|
|
17082
|
+
}
|
|
17083
|
+
function group(runtimes, options, toolPolicy) {
|
|
17084
|
+
return {
|
|
17085
|
+
runtimes,
|
|
17086
|
+
external_tools: externalToolGroups(options.tools) ?? [],
|
|
17087
|
+
...toolPolicy ? { tool_policy: runtimeToolPolicy(options.allowedTools, options.toolset) } : {}
|
|
17088
|
+
};
|
|
17089
|
+
}
|
|
17090
|
+
async function publish(client, updates) {
|
|
17091
|
+
const response = await client.runtimeExternalToolsUpdate({ updates });
|
|
17092
|
+
if (!response.success)
|
|
17093
|
+
throw new Error(response.error ?? "Failed to register tools");
|
|
17094
|
+
}
|
|
17095
|
+
async function resolveRuntime(client, id) {
|
|
17096
|
+
if (!id.startsWith("conv-") && !id.startsWith("local-conv-")) {
|
|
17097
|
+
return { agent_id: id, conversation_id: "default" };
|
|
17098
|
+
}
|
|
17099
|
+
const response = await client.request({ type: "conversation_retrieve", request_id: client.nextRequestId("conversation_retrieve"), conversation_id: id }, {
|
|
17100
|
+
predicate: (message) => message.type === "conversation_retrieve_response"
|
|
17101
|
+
});
|
|
17102
|
+
if (!response.success || !response.conversation) {
|
|
17103
|
+
throw new Error(response.error ?? `Failed to retrieve conversation ${id}`);
|
|
17104
|
+
}
|
|
17105
|
+
return { agent_id: response.conversation.agent_id ?? null, conversation_id: id };
|
|
17106
|
+
}
|
|
17107
|
+
|
|
16723
17108
|
// src/validation.ts
|
|
16724
17109
|
var VALID_SKILL_SOURCES = [
|
|
16725
17110
|
"bundled",
|
|
@@ -16996,6 +17381,7 @@ class LettaAgentClientBase {
|
|
|
16996
17381
|
agentRepositoriesClient = null;
|
|
16997
17382
|
cloudClient = null;
|
|
16998
17383
|
managementTransport = null;
|
|
17384
|
+
toolRegistry = null;
|
|
16999
17385
|
closed = false;
|
|
17000
17386
|
closePromise = null;
|
|
17001
17387
|
constructor(options = {}) {
|
|
@@ -17114,20 +17500,21 @@ class LettaAgentClientBase {
|
|
|
17114
17500
|
const sessionOptions = stripCloudExecutionOptions(options);
|
|
17115
17501
|
validateCreateSessionOptions(sessionOptions);
|
|
17116
17502
|
this.assertSessionBackend("resumeSession", options);
|
|
17503
|
+
const inherited = this.backend === "cloud" ? null : this.toolRegistry?.inheritFor(id, sessionOptions) ?? null;
|
|
17117
17504
|
if (this.backend === "remote") {
|
|
17118
|
-
|
|
17119
|
-
|
|
17120
|
-
|
|
17121
|
-
|
|
17122
|
-
|
|
17123
|
-
});
|
|
17124
|
-
}
|
|
17125
|
-
return new AppServerSession(this.appServerSessionOptions(), {
|
|
17505
|
+
const session2 = looksLikeConversationId(id) ? new AppServerSession(this.appServerSessionOptions(), {
|
|
17506
|
+
kind: "session",
|
|
17507
|
+
conversationId: id,
|
|
17508
|
+
options
|
|
17509
|
+
}) : new AppServerSession(this.appServerSessionOptions(), {
|
|
17126
17510
|
kind: "session",
|
|
17127
17511
|
agentId: id,
|
|
17128
17512
|
defaultConversation: true,
|
|
17129
17513
|
options
|
|
17130
17514
|
});
|
|
17515
|
+
if (inherited)
|
|
17516
|
+
session2.inheritTools(inherited);
|
|
17517
|
+
return session2;
|
|
17131
17518
|
}
|
|
17132
17519
|
if (this.backend === "cloud") {
|
|
17133
17520
|
if (looksLikeConversationId(id)) {
|
|
@@ -17144,7 +17531,10 @@ class LettaAgentClientBase {
|
|
|
17144
17531
|
options
|
|
17145
17532
|
}, this.getCloudClient());
|
|
17146
17533
|
}
|
|
17147
|
-
|
|
17534
|
+
const session = this.resumeLocalSession(id, options);
|
|
17535
|
+
if (inherited && session instanceof AppServerSession)
|
|
17536
|
+
session.inheritTools(inherited);
|
|
17537
|
+
return session;
|
|
17148
17538
|
}
|
|
17149
17539
|
async prompt(message, agentId, options = {}) {
|
|
17150
17540
|
this.assertOpen();
|
|
@@ -17352,10 +17742,23 @@ class LettaAgentClientBase {
|
|
|
17352
17742
|
}
|
|
17353
17743
|
return this.managementTransport;
|
|
17354
17744
|
}
|
|
17745
|
+
registerTools(options) {
|
|
17746
|
+
this.assertOpen();
|
|
17747
|
+
if (this.backend === "cloud") {
|
|
17748
|
+
return Promise.reject(new Error('registerTools() requires backend: "local" or "remote". Cloud sessions register tools through the tools session option.'));
|
|
17749
|
+
}
|
|
17750
|
+
this.toolRegistry ??= new ToolRegistry(this.backend === "remote" ? this.remoteOptions() : this.localAppServerConnection());
|
|
17751
|
+
return this.toolRegistry.register(options);
|
|
17752
|
+
}
|
|
17753
|
+
localAppServerConnection() {
|
|
17754
|
+
throw this.localBackendUnavailableError();
|
|
17755
|
+
}
|
|
17355
17756
|
close() {
|
|
17356
17757
|
if (this.closePromise)
|
|
17357
17758
|
return this.closePromise;
|
|
17358
17759
|
this.closed = true;
|
|
17760
|
+
this.toolRegistry?.close();
|
|
17761
|
+
this.toolRegistry = null;
|
|
17359
17762
|
const transport = this.managementTransport;
|
|
17360
17763
|
this.managementTransport = null;
|
|
17361
17764
|
const close = transport?.close() ?? Promise.resolve();
|
|
@@ -18142,15 +18545,18 @@ class LettaAgentClient extends LettaAgentClientBase {
|
|
|
18142
18545
|
return { loadSkillDirectory, pushSkillSupportFiles };
|
|
18143
18546
|
}
|
|
18144
18547
|
createLocalManagementTransport() {
|
|
18548
|
+
return new AppServerManagementTransport(this.localAppServerConnection());
|
|
18549
|
+
}
|
|
18550
|
+
localAppServerConnection() {
|
|
18145
18551
|
const localOptions = this.options.appServer;
|
|
18146
18552
|
const sharedServer = this.sharedLocalServer();
|
|
18147
|
-
return
|
|
18553
|
+
return {
|
|
18148
18554
|
...localOptions?.url !== undefined ? { url: localOptions.url } : {
|
|
18149
18555
|
connect: () => sharedServer.connect()
|
|
18150
18556
|
},
|
|
18151
18557
|
...localOptions?.WebSocket !== undefined ? { WebSocket: localOptions.WebSocket } : {},
|
|
18152
18558
|
...localOptions?.requestTimeoutMs !== undefined ? { requestTimeoutMs: localOptions.requestTimeoutMs } : {}
|
|
18153
|
-
}
|
|
18559
|
+
};
|
|
18154
18560
|
}
|
|
18155
18561
|
async createLocalAgent(options) {
|
|
18156
18562
|
const localOptions = this.options;
|
|
@@ -19647,12 +20053,12 @@ var require_applicability2 = __commonJS2((exports) => {
|
|
|
19647
20053
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
19648
20054
|
exports.shouldUseRule = exports.shouldUseGroup = exports.schemaHasRulesForType = undefined;
|
|
19649
20055
|
function schemaHasRulesForType({ schema, self }, type) {
|
|
19650
|
-
const
|
|
19651
|
-
return
|
|
20056
|
+
const group2 = self.RULES.types[type];
|
|
20057
|
+
return group2 && group2 !== true && shouldUseGroup(schema, group2);
|
|
19652
20058
|
}
|
|
19653
20059
|
exports.schemaHasRulesForType = schemaHasRulesForType;
|
|
19654
|
-
function shouldUseGroup(schema,
|
|
19655
|
-
return
|
|
20060
|
+
function shouldUseGroup(schema, group2) {
|
|
20061
|
+
return group2.rules.some((rule) => shouldUseRule(schema, rule));
|
|
19656
20062
|
}
|
|
19657
20063
|
exports.shouldUseGroup = shouldUseGroup;
|
|
19658
20064
|
function shouldUseRule(schema, rule) {
|
|
@@ -20644,36 +21050,36 @@ var require_validate2 = __commonJS2((exports) => {
|
|
|
20644
21050
|
if (!opts.jtd)
|
|
20645
21051
|
checkStrictTypes(it, types);
|
|
20646
21052
|
gen.block(() => {
|
|
20647
|
-
for (const
|
|
20648
|
-
groupKeywords(
|
|
21053
|
+
for (const group2 of RULES.rules)
|
|
21054
|
+
groupKeywords(group2);
|
|
20649
21055
|
groupKeywords(RULES.post);
|
|
20650
21056
|
});
|
|
20651
|
-
function groupKeywords(
|
|
20652
|
-
if (!(0, applicability_1.shouldUseGroup)(schema,
|
|
21057
|
+
function groupKeywords(group2) {
|
|
21058
|
+
if (!(0, applicability_1.shouldUseGroup)(schema, group2))
|
|
20653
21059
|
return;
|
|
20654
|
-
if (
|
|
20655
|
-
gen.if((0, dataType_2.checkDataType)(
|
|
20656
|
-
iterateKeywords(it,
|
|
20657
|
-
if (types.length === 1 && types[0] ===
|
|
21060
|
+
if (group2.type) {
|
|
21061
|
+
gen.if((0, dataType_2.checkDataType)(group2.type, data, opts.strictNumbers));
|
|
21062
|
+
iterateKeywords(it, group2);
|
|
21063
|
+
if (types.length === 1 && types[0] === group2.type && typeErrors) {
|
|
20658
21064
|
gen.else();
|
|
20659
21065
|
(0, dataType_2.reportTypeError)(it);
|
|
20660
21066
|
}
|
|
20661
21067
|
gen.endIf();
|
|
20662
21068
|
} else {
|
|
20663
|
-
iterateKeywords(it,
|
|
21069
|
+
iterateKeywords(it, group2);
|
|
20664
21070
|
}
|
|
20665
21071
|
if (!allErrors)
|
|
20666
21072
|
gen.if((0, codegen_1._)`${names_1.default.errors} === ${errsCount || 0}`);
|
|
20667
21073
|
}
|
|
20668
21074
|
}
|
|
20669
|
-
function iterateKeywords(it,
|
|
21075
|
+
function iterateKeywords(it, group2) {
|
|
20670
21076
|
const { gen, schema, opts: { useDefaults } } = it;
|
|
20671
21077
|
if (useDefaults)
|
|
20672
|
-
(0, defaults_1.assignDefaults)(it,
|
|
21078
|
+
(0, defaults_1.assignDefaults)(it, group2.type);
|
|
20673
21079
|
gen.block(() => {
|
|
20674
|
-
for (const rule of
|
|
21080
|
+
for (const rule of group2.rules) {
|
|
20675
21081
|
if ((0, applicability_1.shouldUseRule)(schema, rule)) {
|
|
20676
|
-
keywordCode(it, rule.keyword, rule.definition,
|
|
21082
|
+
keywordCode(it, rule.keyword, rule.definition, group2.type);
|
|
20677
21083
|
}
|
|
20678
21084
|
}
|
|
20679
21085
|
});
|
|
@@ -22358,10 +22764,10 @@ var require_core3 = __commonJS2((exports) => {
|
|
|
22358
22764
|
const { RULES } = this;
|
|
22359
22765
|
delete RULES.keywords[keyword];
|
|
22360
22766
|
delete RULES.all[keyword];
|
|
22361
|
-
for (const
|
|
22362
|
-
const i =
|
|
22767
|
+
for (const group2 of RULES.rules) {
|
|
22768
|
+
const i = group2.rules.findIndex((rule) => rule.keyword === keyword);
|
|
22363
22769
|
if (i >= 0)
|
|
22364
|
-
|
|
22770
|
+
group2.rules.splice(i, 1);
|
|
22365
22771
|
}
|
|
22366
22772
|
return this;
|
|
22367
22773
|
}
|
|
@@ -29615,16 +30021,16 @@ var safeDecode = /* @__PURE__ */ _safeDecode(ZodRealError);
|
|
|
29615
30021
|
var safeEncodeAsync = /* @__PURE__ */ _safeEncodeAsync(ZodRealError);
|
|
29616
30022
|
var safeDecodeAsync = /* @__PURE__ */ _safeDecodeAsync(ZodRealError);
|
|
29617
30023
|
var _installedGroups = /* @__PURE__ */ new WeakMap;
|
|
29618
|
-
function _installLazyMethods(inst,
|
|
30024
|
+
function _installLazyMethods(inst, group2, methods) {
|
|
29619
30025
|
const proto = Object.getPrototypeOf(inst);
|
|
29620
30026
|
let installed = _installedGroups.get(proto);
|
|
29621
30027
|
if (!installed) {
|
|
29622
30028
|
installed = new Set;
|
|
29623
30029
|
_installedGroups.set(proto, installed);
|
|
29624
30030
|
}
|
|
29625
|
-
if (installed.has(
|
|
30031
|
+
if (installed.has(group2))
|
|
29626
30032
|
return;
|
|
29627
|
-
installed.add(
|
|
30033
|
+
installed.add(group2);
|
|
29628
30034
|
for (const key in methods) {
|
|
29629
30035
|
const fn = methods[key];
|
|
29630
30036
|
Object.defineProperty(proto, key, {
|
|
@@ -35002,7 +35408,7 @@ class StreamableHTTPClientTransport {
|
|
|
35002
35408
|
}
|
|
35003
35409
|
var DEFAULT_CLIENT_INFO = {
|
|
35004
35410
|
name: "letta-code",
|
|
35005
|
-
version: "0.34.
|
|
35411
|
+
version: "0.34.44"
|
|
35006
35412
|
};
|
|
35007
35413
|
async function connectMcpServer(config2, options = {}) {
|
|
35008
35414
|
let client = new Client(options.clientInfo ?? DEFAULT_CLIENT_INFO);
|
|
@@ -36030,4 +36436,4 @@ export {
|
|
|
36030
36436
|
CloudManagedSandboxExpiredError
|
|
36031
36437
|
};
|
|
36032
36438
|
|
|
36033
|
-
//# debugId=
|
|
36439
|
+
//# debugId=6E9CA934B8E5A10D64756E2164756E21
|