@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.
@@ -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
- Creating crons:
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
- Creating crons:
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
- clientMessageId: `sdk-message-${Date.now()}-${++this.clientMessageCounter}`,
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
- if (dreamingSettings) {
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=6E490415C5923C8964756E2164756E21
12968
+ //# debugId=EF77573F8BD0F2C464756E2164756E21