@letta-ai/letta-agent-sdk 0.6.3 → 0.7.0
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/AGENTS.md +42 -0
- package/README.md +64 -0
- package/dist/app-server-session.d.ts.map +1 -1
- package/dist/client-entry.d.ts +2 -0
- package/dist/client-entry.d.ts.map +1 -1
- package/dist/client-entry.js +496 -23
- package/dist/client-entry.js.map +13 -12
- package/dist/cloud-session.d.ts.map +1 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +497 -24
- package/dist/index.js.map +14 -13
- package/dist/remote-client-session-core.d.ts +2 -2
- package/dist/remote-client-session-core.d.ts.map +1 -1
- package/dist/remote-session-protocol.d.ts +11 -0
- package/dist/remote-session-protocol.d.ts.map +1 -1
- package/dist/remote-turn-coordinator.d.ts +6 -1
- package/dist/remote-turn-coordinator.d.ts.map +1 -1
- package/dist/transcript-accumulator.d.ts +133 -0
- package/dist/transcript-accumulator.d.ts.map +1 -0
- package/dist/types.d.ts +29 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/validation.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/app-server-session.ts +9 -0
- package/src/client-entry.ts +14 -0
- package/src/cloud-session.ts +1 -0
- package/src/index.ts +15 -0
- package/src/remote-client-session-core.ts +15 -10
- package/src/remote-session-protocol.ts +24 -0
- package/src/remote-turn-coordinator.ts +11 -2
- package/src/transcript-accumulator.ts +823 -0
- package/src/types.ts +31 -1
- package/src/validation.ts +16 -0
package/dist/client-entry.js
CHANGED
|
@@ -3073,7 +3073,7 @@ function isAppServerInfoResponseMessage(message) {
|
|
|
3073
3073
|
return false;
|
|
3074
3074
|
}
|
|
3075
3075
|
const capabilityRecord = capabilities;
|
|
3076
|
-
return candidate.type === "app_server_info_response" && typeof candidate.request_id === "string" && candidate.request_id.length > 0 && candidate.success === true && (candidate.backend === "local" || candidate.backend === "api") && typeof candidate.letta_code_version === "string" && typeof candidate.protocol_version === "number" && Number.isInteger(candidate.protocol_version) && typeof capabilityRecord.agent_management === "boolean" && typeof capabilityRecord.conversation_management === "boolean" && typeof capabilityRecord.memory_management === "boolean" && typeof capabilityRecord.runtime_start === "boolean" && typeof capabilityRecord.split_channels === "boolean";
|
|
3076
|
+
return candidate.type === "app_server_info_response" && typeof candidate.request_id === "string" && candidate.request_id.length > 0 && candidate.success === true && (candidate.backend === "local" || candidate.backend === "api") && typeof candidate.letta_code_version === "string" && typeof candidate.protocol_version === "number" && Number.isInteger(candidate.protocol_version) && typeof capabilityRecord.agent_management === "boolean" && typeof capabilityRecord.conversation_management === "boolean" && typeof capabilityRecord.memory_management === "boolean" && typeof capabilityRecord.runtime_start === "boolean" && (capabilityRecord.runtime_external_tools_update === undefined || typeof capabilityRecord.runtime_external_tools_update === "boolean") && typeof capabilityRecord.split_channels === "boolean";
|
|
3077
3077
|
}
|
|
3078
3078
|
var DEFAULT_REQUEST_TIMEOUT_MS = 30000;
|
|
3079
3079
|
var WEBSOCKET_OPEN_STATE = 1;
|
|
@@ -3316,6 +3316,16 @@ class AppServerClient {
|
|
|
3316
3316
|
predicate: (message) => message.type === "runtime_start_response"
|
|
3317
3317
|
});
|
|
3318
3318
|
}
|
|
3319
|
+
runtimeExternalToolsUpdate(command, options = {}) {
|
|
3320
|
+
return this.request({
|
|
3321
|
+
type: "runtime_external_tools_update",
|
|
3322
|
+
request_id: command.request_id ?? this.nextRequestId("runtime-external-tools"),
|
|
3323
|
+
...command
|
|
3324
|
+
}, {
|
|
3325
|
+
...options,
|
|
3326
|
+
predicate: (message) => message.type === "runtime_external_tools_update_response"
|
|
3327
|
+
});
|
|
3328
|
+
}
|
|
3319
3329
|
sync(command, options = {}) {
|
|
3320
3330
|
return this.request({
|
|
3321
3331
|
type: "sync",
|
|
@@ -3836,12 +3846,7 @@ You **MUST** be proactive in creating crons when work extends beyond the current
|
|
|
3836
3846
|
|
|
3837
3847
|
**Cost**: Self-invocation is critical, but expensive. Default to the longest interval that still serves the user. Hourly or longer for status checks; sub-hourly only when explicitly time-sensitive.
|
|
3838
3848
|
|
|
3839
|
-
|
|
3840
|
-
- One-shot follow-up: \`letta cron add --name <short-name> --description <description> --prompt <future-message> --at "in 30m"\`
|
|
3841
|
-
- Recurring monitoring/heartbeat: \`letta cron add --name <short-name> --description <description> --prompt <future-message> --every "2h"\` or \`--cron "0 9 * * *"\`
|
|
3842
|
-
Always include \`--name\`, \`--description\`, and \`--prompt\`. \`$AGENT_ID\` is automatically injected into the shell environment, and \`letta cron\` uses it by default, so you do not need to specify which agent to invoke unless overriding the current agent intentionally.
|
|
3843
|
-
|
|
3844
|
-
Where crons run: for cloud agents, schedules default to durable Cloud schedules that fire from the cloud and execute in your cloud sandbox — they survive local shutdown, so this is the right default. If the scheduled work must run on a specific computer (e.g. it needs that computer's filesystem or local services), add \`--computer <deviceId>\` (from \`letta environments list\`) to keep the durable Cloud schedule but execute on that computer, with sandbox fallback if it is offline. Use \`--runner local\` only when that fallback is unacceptable; local schedules only fire while a Letta session is running on that computer.
|
|
3849
|
+
The mechanics — flags, where schedules run and execute, timezone handling — live in the scheduling-tasks skill. Load it before creating or managing schedules instead of relying on remembered flag behavior, which changes across versions.
|
|
3845
3850
|
|
|
3846
3851
|
# Harness Architecture
|
|
3847
3852
|
|
|
@@ -4018,12 +4023,7 @@ You **MUST** be proactive in creating crons when work extends beyond the current
|
|
|
4018
4023
|
|
|
4019
4024
|
**Cost**: Self-invocation is critical, but expensive. Default to the longest interval that still serves the user. Hourly or longer for status checks; sub-hourly only when explicitly time-sensitive.
|
|
4020
4025
|
|
|
4021
|
-
|
|
4022
|
-
- One-shot follow-up: \`letta cron add --name <short-name> --description <description> --prompt <future-message> --at "in 30m"\`
|
|
4023
|
-
- Recurring monitoring/heartbeat: \`letta cron add --name <short-name> --description <description> --prompt <future-message> --every "2h"\` or \`--cron "0 9 * * *"\`
|
|
4024
|
-
Always include \`--name\`, \`--description\`, and \`--prompt\`. \`$AGENT_ID\` is automatically injected into the shell environment, and \`letta cron\` uses it by default, so you do not need to specify which agent to invoke unless overriding the current agent intentionally.
|
|
4025
|
-
|
|
4026
|
-
Where crons run: for cloud agents, schedules default to durable Cloud schedules that fire from the cloud and execute in your cloud sandbox — they survive local shutdown, so this is the right default. If the scheduled work must run on a specific computer (e.g. it needs that computer's filesystem or local services), add \`--computer <deviceId>\` (from \`letta environments list\`) to keep the durable Cloud schedule but execute on that computer, with sandbox fallback if it is offline. Use \`--runner local\` only when that fallback is unacceptable; local schedules only fire while a Letta session is running on that computer.
|
|
4026
|
+
The mechanics — flags, where schedules run and execute, timezone handling — live in the scheduling-tasks skill. Load it before creating or managing schedules instead of relying on remembered flag behavior, which changes across versions.
|
|
4027
4027
|
|
|
4028
4028
|
# Harness Architecture
|
|
4029
4029
|
|
|
@@ -9050,6 +9050,20 @@ function toSessionDeviceStatus(status) {
|
|
|
9050
9050
|
function normalizeSendMessage(message) {
|
|
9051
9051
|
return message;
|
|
9052
9052
|
}
|
|
9053
|
+
function normalizeCallerOtid(otid) {
|
|
9054
|
+
if (otid === undefined)
|
|
9055
|
+
return;
|
|
9056
|
+
if (typeof otid !== "string" || otid.trim() === "") {
|
|
9057
|
+
throw new Error("send() otid must be a non-empty string");
|
|
9058
|
+
}
|
|
9059
|
+
return otid;
|
|
9060
|
+
}
|
|
9061
|
+
function turnSendOptions(turn) {
|
|
9062
|
+
return {
|
|
9063
|
+
clientMessageId: turn.clientMessageId,
|
|
9064
|
+
...turn.otid !== undefined ? { otid: turn.otid } : {}
|
|
9065
|
+
};
|
|
9066
|
+
}
|
|
9053
9067
|
|
|
9054
9068
|
// src/remote-turn-coordinator.ts
|
|
9055
9069
|
class RemoteTurnCoordinator {
|
|
@@ -9078,11 +9092,13 @@ class RemoteTurnCoordinator {
|
|
|
9078
9092
|
hasInFlightTurn() {
|
|
9079
9093
|
return this.activeTurn !== null || this.pendingTurns.length > 0;
|
|
9080
9094
|
}
|
|
9081
|
-
trackSentTurn(runtime) {
|
|
9095
|
+
trackSentTurn(runtime, callerOtid) {
|
|
9096
|
+
const otid = normalizeCallerOtid(callerOtid);
|
|
9082
9097
|
const turn = {
|
|
9083
9098
|
id: ++this.nextTurnId,
|
|
9084
9099
|
runtime,
|
|
9085
|
-
|
|
9100
|
+
...otid !== undefined ? { otid } : {},
|
|
9101
|
+
clientMessageId: otid ?? `sdk-message-${Date.now()}-${++this.clientMessageCounter}`,
|
|
9086
9102
|
queuedAt: Date.now(),
|
|
9087
9103
|
startedAt: 0,
|
|
9088
9104
|
assistantText: "",
|
|
@@ -9584,7 +9600,7 @@ class RemoteClientSessionCore {
|
|
|
9584
9600
|
this.toolNames = undefined;
|
|
9585
9601
|
this.initialized = false;
|
|
9586
9602
|
}
|
|
9587
|
-
async send(message) {
|
|
9603
|
+
async send(message, options) {
|
|
9588
9604
|
if (this.closed)
|
|
9589
9605
|
throw new Error("Session is closed");
|
|
9590
9606
|
if (!this.initialized) {
|
|
@@ -9600,11 +9616,9 @@ class RemoteClientSessionCore {
|
|
|
9600
9616
|
if (!controller || !runtime) {
|
|
9601
9617
|
throw new Error("Session transport disconnected before the turn was sent");
|
|
9602
9618
|
}
|
|
9603
|
-
const turn = this.turns.trackSentTurn(runtime);
|
|
9619
|
+
const turn = this.turns.trackSentTurn(runtime, options?.otid);
|
|
9604
9620
|
try {
|
|
9605
|
-
controller.sendTurnMessage(runtime, message,
|
|
9606
|
-
clientMessageId: turn.clientMessageId
|
|
9607
|
-
});
|
|
9621
|
+
controller.sendTurnMessage(runtime, message, turnSendOptions(turn));
|
|
9608
9622
|
} catch (error) {
|
|
9609
9623
|
this.turns.removeTrackedTurn(turn);
|
|
9610
9624
|
throw error;
|
|
@@ -9683,6 +9697,9 @@ class RemoteClientSessionCore {
|
|
|
9683
9697
|
return this.controller.listModels();
|
|
9684
9698
|
}
|
|
9685
9699
|
async updateModel(update) {
|
|
9700
|
+
if (this.mode.kind === "session" && this.mode.options.stateless === true) {
|
|
9701
|
+
throw new Error("updateModel() is unavailable in a stateless session because it changes persisted agent configuration.");
|
|
9702
|
+
}
|
|
9686
9703
|
if (!this.initialized) {
|
|
9687
9704
|
await this.initialize();
|
|
9688
9705
|
}
|
|
@@ -10083,7 +10100,8 @@ class RemoteClientSessionCore {
|
|
|
10083
10100
|
ensureSuccess(response, "Failed to enable memfs");
|
|
10084
10101
|
}
|
|
10085
10102
|
const dreamingSettings = resolveDreamingSettings(options.dreaming);
|
|
10086
|
-
|
|
10103
|
+
const isStatelessSession = this.mode.kind === "session" && this.mode.options.stateless === true;
|
|
10104
|
+
if (dreamingSettings && !isStatelessSession) {
|
|
10087
10105
|
const response = await this.controller.request("set_reflection_settings", {
|
|
10088
10106
|
runtime: this.runtime,
|
|
10089
10107
|
settings: dreamingSettings,
|
|
@@ -10349,7 +10367,8 @@ class AppServerRuntimeController {
|
|
|
10349
10367
|
{
|
|
10350
10368
|
role: "user",
|
|
10351
10369
|
content: normalizeSendMessage(message),
|
|
10352
|
-
client_message_id: options.clientMessageId
|
|
10370
|
+
client_message_id: options.clientMessageId,
|
|
10371
|
+
...options.otid !== undefined ? { otid: options.otid } : {}
|
|
10353
10372
|
}
|
|
10354
10373
|
]
|
|
10355
10374
|
};
|
|
@@ -10576,6 +10595,9 @@ class AppServerSession extends RemoteClientSessionCore {
|
|
|
10576
10595
|
command.mode = mode;
|
|
10577
10596
|
if (options.cwd !== undefined)
|
|
10578
10597
|
command.cwd = options.cwd;
|
|
10598
|
+
if (this.mode.kind === "session" && this.mode.options.stateless === true) {
|
|
10599
|
+
command.stateless = true;
|
|
10600
|
+
}
|
|
10579
10601
|
if (options.skillSources !== undefined) {
|
|
10580
10602
|
command.skill_sources = [...new Set(options.skillSources)];
|
|
10581
10603
|
}
|
|
@@ -11433,6 +11455,8 @@ class CloudEnvironmentSession extends RemoteClientSessionCore {
|
|
|
11433
11455
|
command.mode = mode;
|
|
11434
11456
|
if (options.cwd !== undefined)
|
|
11435
11457
|
command.cwd = options.cwd;
|
|
11458
|
+
if (this.cloudMode.options.stateless === true)
|
|
11459
|
+
command.stateless = true;
|
|
11436
11460
|
if (options.skillSources !== undefined) {
|
|
11437
11461
|
command.skill_sources = [...new Set(options.skillSources)];
|
|
11438
11462
|
}
|
|
@@ -12037,6 +12061,20 @@ function validateMcpServers(servers) {
|
|
|
12037
12061
|
}
|
|
12038
12062
|
}
|
|
12039
12063
|
function validateCreateSessionOptions(options) {
|
|
12064
|
+
if (options.stateless !== undefined && typeof options.stateless !== "boolean") {
|
|
12065
|
+
throw new Error("Invalid stateless. Expected a boolean.");
|
|
12066
|
+
}
|
|
12067
|
+
if (options.stateless) {
|
|
12068
|
+
const persistedOption = [
|
|
12069
|
+
["model", options.model],
|
|
12070
|
+
["reasoningEffort", options.reasoningEffort],
|
|
12071
|
+
["dreaming", options.dreaming],
|
|
12072
|
+
["resources", options.resources]
|
|
12073
|
+
].find(([, value]) => value !== undefined);
|
|
12074
|
+
if (persistedOption) {
|
|
12075
|
+
throw new Error(`stateless sessions cannot set ${persistedOption[0]} because it changes persisted agent configuration.`);
|
|
12076
|
+
}
|
|
12077
|
+
}
|
|
12040
12078
|
validateClientToolset(options.toolset);
|
|
12041
12079
|
validateSkillSources(options.skillSources);
|
|
12042
12080
|
validateMcpServers(options.mcpServers);
|
|
@@ -12465,6 +12503,440 @@ function extractStreamTextDelta(event) {
|
|
|
12465
12503
|
}
|
|
12466
12504
|
return null;
|
|
12467
12505
|
}
|
|
12506
|
+
// src/transcript-accumulator.ts
|
|
12507
|
+
var SEP = ":";
|
|
12508
|
+
var MAX_TRACKED_RUNS = 64;
|
|
12509
|
+
var ANONYMOUS_RUN = "";
|
|
12510
|
+
function familyOtidAlias(kind, otid) {
|
|
12511
|
+
return `${kind}${SEP}otid${SEP}${otid}`;
|
|
12512
|
+
}
|
|
12513
|
+
function familyUuidAlias(kind, uuid) {
|
|
12514
|
+
return `${kind}${SEP}uuid${SEP}${uuid}`;
|
|
12515
|
+
}
|
|
12516
|
+
function toolRowKey(toolCallId) {
|
|
12517
|
+
return `tool_call${SEP}id${SEP}${toolCallId}`;
|
|
12518
|
+
}
|
|
12519
|
+
function asRecord(value) {
|
|
12520
|
+
return value && typeof value === "object" && !Array.isArray(value) ? value : undefined;
|
|
12521
|
+
}
|
|
12522
|
+
function readString(record, field) {
|
|
12523
|
+
const value = record[field];
|
|
12524
|
+
return typeof value === "string" && value.length > 0 ? value : undefined;
|
|
12525
|
+
}
|
|
12526
|
+
function readNumber(record, field) {
|
|
12527
|
+
const value = record[field];
|
|
12528
|
+
return typeof value === "number" && Number.isFinite(value) ? value : undefined;
|
|
12529
|
+
}
|
|
12530
|
+
function parseJsonObject(raw) {
|
|
12531
|
+
const trimmed = raw.trim();
|
|
12532
|
+
if (trimmed.length === 0)
|
|
12533
|
+
return;
|
|
12534
|
+
try {
|
|
12535
|
+
return asRecord(JSON.parse(trimmed));
|
|
12536
|
+
} catch {
|
|
12537
|
+
return;
|
|
12538
|
+
}
|
|
12539
|
+
}
|
|
12540
|
+
function isRawArgumentsWrapper(input, rawArguments) {
|
|
12541
|
+
if (!input)
|
|
12542
|
+
return false;
|
|
12543
|
+
const keys = Object.keys(input);
|
|
12544
|
+
if (keys.length !== 1 || keys[0] !== "raw")
|
|
12545
|
+
return false;
|
|
12546
|
+
const wrapped = input.raw;
|
|
12547
|
+
if (typeof wrapped !== "string")
|
|
12548
|
+
return false;
|
|
12549
|
+
return rawArguments === undefined || wrapped === rawArguments;
|
|
12550
|
+
}
|
|
12551
|
+
function toolStatus(row) {
|
|
12552
|
+
if (row.result)
|
|
12553
|
+
return "complete";
|
|
12554
|
+
return row.argumentsComplete ? "ready" : "streaming";
|
|
12555
|
+
}
|
|
12556
|
+
function mergeToolArguments(previous, merge) {
|
|
12557
|
+
let { rawArguments, toolInput, argumentsComplete } = previous;
|
|
12558
|
+
const fragment = merge.rawArguments;
|
|
12559
|
+
const wrapped = isRawArgumentsWrapper(merge.toolInput, fragment);
|
|
12560
|
+
if (fragment !== undefined && fragment.length > 0) {
|
|
12561
|
+
const whole = parseJsonObject(fragment);
|
|
12562
|
+
if (whole) {
|
|
12563
|
+
return { rawArguments: fragment, toolInput: whole, argumentsComplete: true };
|
|
12564
|
+
}
|
|
12565
|
+
if (argumentsComplete) {
|
|
12566
|
+
return previous;
|
|
12567
|
+
}
|
|
12568
|
+
if (merge.mode === "whole") {
|
|
12569
|
+
return { rawArguments: rawArguments ?? fragment, toolInput, argumentsComplete };
|
|
12570
|
+
}
|
|
12571
|
+
rawArguments = (rawArguments ?? "") + fragment;
|
|
12572
|
+
const parsed = parseJsonObject(rawArguments);
|
|
12573
|
+
if (parsed) {
|
|
12574
|
+
return { rawArguments, toolInput: parsed, argumentsComplete: true };
|
|
12575
|
+
}
|
|
12576
|
+
return { rawArguments, toolInput, argumentsComplete: false };
|
|
12577
|
+
}
|
|
12578
|
+
if (!wrapped && merge.toolInput) {
|
|
12579
|
+
const keys = Object.keys(merge.toolInput);
|
|
12580
|
+
if (keys.length > 0) {
|
|
12581
|
+
return { rawArguments, toolInput: merge.toolInput, argumentsComplete: true };
|
|
12582
|
+
}
|
|
12583
|
+
if (rawArguments === undefined) {
|
|
12584
|
+
return { rawArguments, toolInput, argumentsComplete: true };
|
|
12585
|
+
}
|
|
12586
|
+
}
|
|
12587
|
+
return previous;
|
|
12588
|
+
}
|
|
12589
|
+
|
|
12590
|
+
class TranscriptAccumulatorImpl {
|
|
12591
|
+
byKey = new Map;
|
|
12592
|
+
aliasByOtid = new Map;
|
|
12593
|
+
aliasByUuid = new Map;
|
|
12594
|
+
seqThresholds = new Map;
|
|
12595
|
+
snapshot = null;
|
|
12596
|
+
anonymousCounter = 0;
|
|
12597
|
+
apply(message) {
|
|
12598
|
+
switch (message.type) {
|
|
12599
|
+
case "assistant":
|
|
12600
|
+
case "reasoning":
|
|
12601
|
+
this.applyText({
|
|
12602
|
+
kind: message.type,
|
|
12603
|
+
text: message.content,
|
|
12604
|
+
uuid: message.uuid,
|
|
12605
|
+
otid: typeof message.otid === "string" ? message.otid : undefined,
|
|
12606
|
+
runId: message.runId,
|
|
12607
|
+
seqId: message.seqId
|
|
12608
|
+
});
|
|
12609
|
+
break;
|
|
12610
|
+
case "tool_call":
|
|
12611
|
+
this.mergeToolCall({
|
|
12612
|
+
toolCallId: message.toolCallId,
|
|
12613
|
+
toolName: message.toolName,
|
|
12614
|
+
toolInput: message.toolInput,
|
|
12615
|
+
rawArguments: message.rawArguments,
|
|
12616
|
+
uuid: message.uuid,
|
|
12617
|
+
runId: message.runId,
|
|
12618
|
+
mode: "fragment"
|
|
12619
|
+
});
|
|
12620
|
+
break;
|
|
12621
|
+
case "tool_result":
|
|
12622
|
+
this.mergeToolResult({
|
|
12623
|
+
toolCallId: message.toolCallId,
|
|
12624
|
+
content: message.content,
|
|
12625
|
+
isError: message.isError,
|
|
12626
|
+
uuid: message.uuid,
|
|
12627
|
+
runId: message.runId
|
|
12628
|
+
});
|
|
12629
|
+
break;
|
|
12630
|
+
case "stream_event":
|
|
12631
|
+
this.applyStreamEvent(message);
|
|
12632
|
+
break;
|
|
12633
|
+
default:
|
|
12634
|
+
break;
|
|
12635
|
+
}
|
|
12636
|
+
return this.rows();
|
|
12637
|
+
}
|
|
12638
|
+
rebase(page, options) {
|
|
12639
|
+
const messages = normalizeHistoryPage(page, options?.order);
|
|
12640
|
+
if (messages.length === 0)
|
|
12641
|
+
return this.rows();
|
|
12642
|
+
const historyKeys = [];
|
|
12643
|
+
const seen = new Set;
|
|
12644
|
+
for (const message of messages) {
|
|
12645
|
+
const key = this.applyHistoryMessage(message);
|
|
12646
|
+
if (!key || seen.has(key))
|
|
12647
|
+
continue;
|
|
12648
|
+
seen.add(key);
|
|
12649
|
+
historyKeys.push(key);
|
|
12650
|
+
}
|
|
12651
|
+
this.reorder(historyKeys);
|
|
12652
|
+
return this.rows();
|
|
12653
|
+
}
|
|
12654
|
+
rows() {
|
|
12655
|
+
if (!this.snapshot) {
|
|
12656
|
+
this.snapshot = Array.from(this.byKey.values());
|
|
12657
|
+
}
|
|
12658
|
+
return this.snapshot;
|
|
12659
|
+
}
|
|
12660
|
+
reset() {
|
|
12661
|
+
this.byKey.clear();
|
|
12662
|
+
this.aliasByOtid.clear();
|
|
12663
|
+
this.aliasByUuid.clear();
|
|
12664
|
+
this.seqThresholds.clear();
|
|
12665
|
+
this.anonymousCounter = 0;
|
|
12666
|
+
this.snapshot = null;
|
|
12667
|
+
}
|
|
12668
|
+
isReplay(runId, seqId) {
|
|
12669
|
+
if (seqId === undefined)
|
|
12670
|
+
return false;
|
|
12671
|
+
const bucket = runId ?? ANONYMOUS_RUN;
|
|
12672
|
+
const threshold = this.seqThresholds.get(bucket);
|
|
12673
|
+
if (threshold !== undefined && seqId <= threshold)
|
|
12674
|
+
return true;
|
|
12675
|
+
this.rememberSeq(bucket, seqId);
|
|
12676
|
+
return false;
|
|
12677
|
+
}
|
|
12678
|
+
rememberSeq(bucket, seqId) {
|
|
12679
|
+
const threshold = this.seqThresholds.get(bucket);
|
|
12680
|
+
if (threshold !== undefined && threshold >= seqId)
|
|
12681
|
+
return;
|
|
12682
|
+
this.seqThresholds.set(bucket, seqId);
|
|
12683
|
+
while (this.seqThresholds.size > MAX_TRACKED_RUNS) {
|
|
12684
|
+
const oldest = this.seqThresholds.keys().next();
|
|
12685
|
+
if (oldest.done)
|
|
12686
|
+
break;
|
|
12687
|
+
this.seqThresholds.delete(oldest.value);
|
|
12688
|
+
}
|
|
12689
|
+
}
|
|
12690
|
+
applyText(slice) {
|
|
12691
|
+
if (this.isReplay(slice.runId, slice.seqId))
|
|
12692
|
+
return;
|
|
12693
|
+
this.writeText(slice, "append");
|
|
12694
|
+
}
|
|
12695
|
+
writeText(slice, write) {
|
|
12696
|
+
const key = this.resolveTextKey(slice.kind, slice.uuid, slice.otid);
|
|
12697
|
+
const existing = this.byKey.get(key);
|
|
12698
|
+
const previous = existing && existing.kind === slice.kind ? existing : undefined;
|
|
12699
|
+
this.setRow(key, {
|
|
12700
|
+
kind: slice.kind,
|
|
12701
|
+
key,
|
|
12702
|
+
text: write === "append" ? (previous?.text ?? "") + slice.text : slice.text,
|
|
12703
|
+
uuid: previous?.uuid ?? slice.uuid,
|
|
12704
|
+
otid: slice.otid ?? previous?.otid,
|
|
12705
|
+
runId: slice.runId ?? previous?.runId,
|
|
12706
|
+
seqId: maxDefined(slice.seqId, previous?.seqId)
|
|
12707
|
+
});
|
|
12708
|
+
return key;
|
|
12709
|
+
}
|
|
12710
|
+
resolveTextKey(kind, uuid, otid) {
|
|
12711
|
+
const otidAlias = otid ? familyOtidAlias(kind, otid) : undefined;
|
|
12712
|
+
const uuidAlias = uuid ? familyUuidAlias(kind, uuid) : undefined;
|
|
12713
|
+
const fromOtid = otidAlias ? this.aliasByOtid.get(otidAlias) : undefined;
|
|
12714
|
+
const fromUuid = uuidAlias ? this.aliasByUuid.get(uuidAlias) : undefined;
|
|
12715
|
+
let key = fromOtid ?? fromUuid;
|
|
12716
|
+
if (key && !fromOtid && otid) {
|
|
12717
|
+
const existing = this.byKey.get(key);
|
|
12718
|
+
if (existing && existing.otid !== undefined && existing.otid !== otid) {
|
|
12719
|
+
key = undefined;
|
|
12720
|
+
}
|
|
12721
|
+
}
|
|
12722
|
+
if (!key) {
|
|
12723
|
+
key = otidAlias ?? uuidAlias ?? `${kind}${SEP}auto${SEP}${++this.anonymousCounter}`;
|
|
12724
|
+
}
|
|
12725
|
+
if (otidAlias)
|
|
12726
|
+
this.aliasByOtid.set(otidAlias, key);
|
|
12727
|
+
if (uuidAlias)
|
|
12728
|
+
this.aliasByUuid.set(uuidAlias, key);
|
|
12729
|
+
return key;
|
|
12730
|
+
}
|
|
12731
|
+
mergeToolCall(merge) {
|
|
12732
|
+
const key = toolRowKey(merge.toolCallId);
|
|
12733
|
+
const existing = this.byKey.get(key);
|
|
12734
|
+
const previous = existing && existing.kind === "tool_call" ? existing : undefined;
|
|
12735
|
+
const args = mergeToolArguments({
|
|
12736
|
+
rawArguments: previous?.rawArguments,
|
|
12737
|
+
toolInput: previous?.toolInput ?? {},
|
|
12738
|
+
argumentsComplete: previous?.argumentsComplete ?? false
|
|
12739
|
+
}, merge);
|
|
12740
|
+
const toolName = merge.toolName && merge.toolName !== "?" ? merge.toolName : previous?.toolName ?? merge.toolName ?? "?";
|
|
12741
|
+
const next = {
|
|
12742
|
+
kind: "tool_call",
|
|
12743
|
+
key,
|
|
12744
|
+
toolCallId: merge.toolCallId,
|
|
12745
|
+
toolName,
|
|
12746
|
+
toolInput: args.toolInput,
|
|
12747
|
+
...args.rawArguments !== undefined ? { rawArguments: args.rawArguments } : {},
|
|
12748
|
+
argumentsComplete: args.argumentsComplete,
|
|
12749
|
+
...previous?.result ? { result: previous.result } : {},
|
|
12750
|
+
status: "streaming",
|
|
12751
|
+
uuid: previous?.uuid ?? merge.uuid,
|
|
12752
|
+
runId: merge.runId ?? previous?.runId,
|
|
12753
|
+
seqId: maxDefined(merge.seqId, previous?.seqId)
|
|
12754
|
+
};
|
|
12755
|
+
next.status = toolStatus(next);
|
|
12756
|
+
this.setRow(key, next);
|
|
12757
|
+
return key;
|
|
12758
|
+
}
|
|
12759
|
+
mergeToolResult(merge) {
|
|
12760
|
+
const key = toolRowKey(merge.toolCallId);
|
|
12761
|
+
const existing = this.byKey.get(key);
|
|
12762
|
+
const previous = existing && existing.kind === "tool_call" ? existing : undefined;
|
|
12763
|
+
this.setRow(key, {
|
|
12764
|
+
kind: "tool_call",
|
|
12765
|
+
key,
|
|
12766
|
+
toolCallId: merge.toolCallId,
|
|
12767
|
+
toolName: previous?.toolName ?? "?",
|
|
12768
|
+
toolInput: previous?.toolInput ?? {},
|
|
12769
|
+
...previous?.rawArguments !== undefined ? { rawArguments: previous.rawArguments } : {},
|
|
12770
|
+
argumentsComplete: previous?.argumentsComplete ?? false,
|
|
12771
|
+
result: {
|
|
12772
|
+
content: merge.content,
|
|
12773
|
+
isError: merge.isError,
|
|
12774
|
+
...merge.uuid ? { uuid: merge.uuid } : {}
|
|
12775
|
+
},
|
|
12776
|
+
status: "complete",
|
|
12777
|
+
uuid: previous?.uuid,
|
|
12778
|
+
runId: merge.runId ?? previous?.runId,
|
|
12779
|
+
seqId: maxDefined(merge.seqId, previous?.seqId)
|
|
12780
|
+
});
|
|
12781
|
+
return key;
|
|
12782
|
+
}
|
|
12783
|
+
applyStreamEvent(message) {
|
|
12784
|
+
const delta = extractStreamTextDelta(message.event);
|
|
12785
|
+
if (!delta)
|
|
12786
|
+
return;
|
|
12787
|
+
const payload = asRecord(message.event);
|
|
12788
|
+
const otid = payload ? readString(payload, "otid") : undefined;
|
|
12789
|
+
const payloadId = payload ? readString(payload, "id") : undefined;
|
|
12790
|
+
const identified = otid !== undefined || payloadId !== undefined;
|
|
12791
|
+
this.applyText({
|
|
12792
|
+
kind: delta.kind,
|
|
12793
|
+
text: delta.text,
|
|
12794
|
+
uuid: identified ? payloadId : `${delta.kind}${SEP}live`,
|
|
12795
|
+
otid,
|
|
12796
|
+
runId: payload ? readString(payload, "run_id") : undefined,
|
|
12797
|
+
seqId: payload ? readNumber(payload, "seq_id") : undefined
|
|
12798
|
+
});
|
|
12799
|
+
}
|
|
12800
|
+
applyHistoryMessage(message) {
|
|
12801
|
+
const record = asRecord(message);
|
|
12802
|
+
if (!record)
|
|
12803
|
+
return;
|
|
12804
|
+
const messageType = readString(record, "message_type");
|
|
12805
|
+
if (!messageType)
|
|
12806
|
+
return;
|
|
12807
|
+
const uuid = readString(record, "id");
|
|
12808
|
+
const otid = readString(record, "otid");
|
|
12809
|
+
const runId = readString(record, "run_id");
|
|
12810
|
+
const seqId = readNumber(record, "seq_id");
|
|
12811
|
+
if (seqId !== undefined) {
|
|
12812
|
+
this.rememberSeq(runId ?? ANONYMOUS_RUN, seqId);
|
|
12813
|
+
}
|
|
12814
|
+
switch (messageType) {
|
|
12815
|
+
case "user_message":
|
|
12816
|
+
case "assistant_message": {
|
|
12817
|
+
const text = extractTextFromContent(record.content);
|
|
12818
|
+
if (text === null)
|
|
12819
|
+
return;
|
|
12820
|
+
return this.writeText({
|
|
12821
|
+
kind: messageType === "user_message" ? "user" : "assistant",
|
|
12822
|
+
text,
|
|
12823
|
+
uuid,
|
|
12824
|
+
otid,
|
|
12825
|
+
runId,
|
|
12826
|
+
seqId
|
|
12827
|
+
}, "replace");
|
|
12828
|
+
}
|
|
12829
|
+
case "reasoning_message": {
|
|
12830
|
+
const text = typeof record.reasoning === "string" ? record.reasoning : extractTextFromContent(record.content);
|
|
12831
|
+
if (text === null || text === undefined)
|
|
12832
|
+
return;
|
|
12833
|
+
return this.writeText({ kind: "reasoning", text, uuid, otid, runId, seqId }, "replace");
|
|
12834
|
+
}
|
|
12835
|
+
case "tool_call_message":
|
|
12836
|
+
case "approval_request_message": {
|
|
12837
|
+
const toolCall = firstToolCall(record);
|
|
12838
|
+
if (!toolCall)
|
|
12839
|
+
return;
|
|
12840
|
+
const fn = asRecord(toolCall.function);
|
|
12841
|
+
const toolCallId = (typeof toolCall.tool_call_id === "string" ? toolCall.tool_call_id : undefined) ?? (typeof toolCall.id === "string" ? toolCall.id : undefined);
|
|
12842
|
+
if (!toolCallId)
|
|
12843
|
+
return;
|
|
12844
|
+
const args = toolCall.arguments ?? fn?.arguments;
|
|
12845
|
+
return this.mergeToolCall({
|
|
12846
|
+
toolCallId,
|
|
12847
|
+
toolName: (typeof toolCall.name === "string" ? toolCall.name : undefined) ?? (typeof fn?.name === "string" ? fn.name : undefined),
|
|
12848
|
+
toolInput: asRecord(args),
|
|
12849
|
+
rawArguments: typeof args === "string" ? args : undefined,
|
|
12850
|
+
uuid,
|
|
12851
|
+
runId,
|
|
12852
|
+
seqId,
|
|
12853
|
+
mode: "whole"
|
|
12854
|
+
});
|
|
12855
|
+
}
|
|
12856
|
+
case "tool_return_message": {
|
|
12857
|
+
const toolReturn = firstToolReturn(record) ?? record;
|
|
12858
|
+
const toolCallId = readString(record, "tool_call_id") ?? (typeof toolReturn.tool_call_id === "string" ? toolReturn.tool_call_id : undefined);
|
|
12859
|
+
if (!toolCallId)
|
|
12860
|
+
return;
|
|
12861
|
+
const content = extractTextFromContent(record.tool_return ?? toolReturn.tool_return ?? toolReturn.content) ?? "";
|
|
12862
|
+
const status = readString(record, "status") ?? (typeof toolReturn.status === "string" ? toolReturn.status : undefined);
|
|
12863
|
+
return this.mergeToolResult({
|
|
12864
|
+
toolCallId,
|
|
12865
|
+
content,
|
|
12866
|
+
isError: status === "error",
|
|
12867
|
+
uuid,
|
|
12868
|
+
runId,
|
|
12869
|
+
seqId
|
|
12870
|
+
});
|
|
12871
|
+
}
|
|
12872
|
+
default:
|
|
12873
|
+
return;
|
|
12874
|
+
}
|
|
12875
|
+
}
|
|
12876
|
+
setRow(key, row) {
|
|
12877
|
+
this.byKey.set(key, row);
|
|
12878
|
+
this.snapshot = null;
|
|
12879
|
+
}
|
|
12880
|
+
reorder(historyKeys) {
|
|
12881
|
+
if (historyKeys.length === 0)
|
|
12882
|
+
return;
|
|
12883
|
+
const historySet = new Set(historyKeys);
|
|
12884
|
+
const reordered = new Map;
|
|
12885
|
+
for (const key of historyKeys) {
|
|
12886
|
+
const row = this.byKey.get(key);
|
|
12887
|
+
if (row)
|
|
12888
|
+
reordered.set(key, row);
|
|
12889
|
+
}
|
|
12890
|
+
for (const [key, row] of this.byKey) {
|
|
12891
|
+
if (historySet.has(key))
|
|
12892
|
+
continue;
|
|
12893
|
+
reordered.set(key, row);
|
|
12894
|
+
}
|
|
12895
|
+
this.byKey = reordered;
|
|
12896
|
+
this.snapshot = null;
|
|
12897
|
+
}
|
|
12898
|
+
}
|
|
12899
|
+
function maxDefined(next, previous) {
|
|
12900
|
+
if (next === undefined)
|
|
12901
|
+
return previous;
|
|
12902
|
+
if (previous === undefined)
|
|
12903
|
+
return next;
|
|
12904
|
+
return Math.max(next, previous);
|
|
12905
|
+
}
|
|
12906
|
+
function normalizeHistoryPage(page, order) {
|
|
12907
|
+
const messages = Array.isArray(page) ? page : page.messages ?? [];
|
|
12908
|
+
if (messages.length < 2)
|
|
12909
|
+
return messages;
|
|
12910
|
+
const descending = order ? order === "desc" : detectDescending(messages);
|
|
12911
|
+
return descending ? [...messages].reverse() : messages;
|
|
12912
|
+
}
|
|
12913
|
+
function detectDescending(messages) {
|
|
12914
|
+
const seqIds = [];
|
|
12915
|
+
const dates = [];
|
|
12916
|
+
for (const message of messages) {
|
|
12917
|
+
const record = asRecord(message);
|
|
12918
|
+
if (!record)
|
|
12919
|
+
continue;
|
|
12920
|
+
const seqId = readNumber(record, "seq_id");
|
|
12921
|
+
if (seqId !== undefined)
|
|
12922
|
+
seqIds.push(seqId);
|
|
12923
|
+
const date = readString(record, "date");
|
|
12924
|
+
if (!date)
|
|
12925
|
+
continue;
|
|
12926
|
+
const parsed = Date.parse(date);
|
|
12927
|
+
if (!Number.isNaN(parsed))
|
|
12928
|
+
dates.push(parsed);
|
|
12929
|
+
}
|
|
12930
|
+
const ordered = seqIds.length >= 2 ? seqIds : dates;
|
|
12931
|
+
if (ordered.length < 2)
|
|
12932
|
+
return false;
|
|
12933
|
+
const first = ordered[0];
|
|
12934
|
+
const last = ordered[ordered.length - 1];
|
|
12935
|
+
return last < first;
|
|
12936
|
+
}
|
|
12937
|
+
function createTranscriptAccumulator() {
|
|
12938
|
+
return new TranscriptAccumulatorImpl;
|
|
12939
|
+
}
|
|
12468
12940
|
// src/websocket.ts
|
|
12469
12941
|
function createReactNativeWebSocketConstructor(WebSocket) {
|
|
12470
12942
|
class ReactNativeWebSocketAdapter {
|
|
@@ -12486,10 +12958,11 @@ class LettaAgentClient extends LettaAgentClientBase {
|
|
|
12486
12958
|
}
|
|
12487
12959
|
export {
|
|
12488
12960
|
extractStreamTextDelta,
|
|
12961
|
+
createTranscriptAccumulator,
|
|
12489
12962
|
createReactNativeWebSocketConstructor,
|
|
12490
12963
|
RepositoriesClient,
|
|
12491
12964
|
LettaAgentClient,
|
|
12492
12965
|
CloudManagedSandboxExpiredError
|
|
12493
12966
|
};
|
|
12494
12967
|
|
|
12495
|
-
//# debugId=
|
|
12968
|
+
//# debugId=EF77573F8BD0F2C464756E2164756E21
|