llmist 17.5.0 → 17.6.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/dist/index.cjs CHANGED
@@ -1414,7 +1414,7 @@ Produces: { "items": ["first", "second"] }`);
1414
1414
  * @param mediaIds - Optional IDs for the media outputs
1415
1415
  * @param storedMedia - Optional stored media info including file paths
1416
1416
  */
1417
- addGadgetCallResult(gadget, parameters, result, invocationId, media, mediaIds, storedMedia) {
1417
+ addGadgetCallResult(gadget, parameters, result, invocationId, media, mediaIds, storedMedia, metadata) {
1418
1418
  const paramStr = this.formatBlockParameters(parameters, "");
1419
1419
  this.messages.push({
1420
1420
  role: "assistant",
@@ -1438,11 +1438,12 @@ ${idRefs}`;
1438
1438
  parts.push(audioFromBase64(item.data, item.mimeType));
1439
1439
  }
1440
1440
  }
1441
- this.messages.push({ role: "user", content: parts });
1441
+ this.messages.push({ role: "user", content: parts, metadata });
1442
1442
  } else {
1443
1443
  this.messages.push({
1444
1444
  role: "user",
1445
- content: `Result (${invocationId}): ${result}`
1445
+ content: `Result (${invocationId}): ${result}`,
1446
+ metadata
1446
1447
  });
1447
1448
  }
1448
1449
  return this;
@@ -2674,11 +2675,19 @@ var init_sliding_window = __esm({
2674
2675
  }
2675
2676
  const turnsToKeep = turns.slice(-preserveCount);
2676
2677
  const turnsRemoved = turns.length - preserveCount;
2678
+ const keptMessageRefs = new Set(turnsToKeep.flatMap((turn) => turn.messages));
2679
+ const stickyToPreserve = messages.filter(
2680
+ (msg) => msg.metadata?.sticky === true && !keptMessageRefs.has(msg)
2681
+ );
2677
2682
  const truncationMarker = {
2678
2683
  role: "user",
2679
2684
  content: TRUNCATION_MARKER_TEMPLATE.replace("{count}", turnsRemoved.toString())
2680
2685
  };
2681
- const compactedMessages = [truncationMarker, ...flattenTurns(turnsToKeep)];
2686
+ const compactedMessages = [
2687
+ truncationMarker,
2688
+ ...stickyToPreserve,
2689
+ ...flattenTurns(turnsToKeep)
2690
+ ];
2682
2691
  const tokensAfter = Math.ceil(
2683
2692
  compactedMessages.reduce((sum, msg) => sum + (msg.content?.length ?? 0), 0) / 4
2684
2693
  );
@@ -2722,7 +2731,14 @@ var init_summarization = __esm({
2722
2731
  }
2723
2732
  const turnsToSummarize = turns.slice(0, -preserveCount);
2724
2733
  const turnsToKeep = turns.slice(-preserveCount);
2725
- const conversationToSummarize = this.formatTurnsForSummary(flattenTurns(turnsToSummarize));
2734
+ const keptMessageRefs = new Set(turnsToKeep.flatMap((turn) => turn.messages));
2735
+ const stickyToPreserve = messages.filter(
2736
+ (msg) => msg.metadata?.sticky === true && !keptMessageRefs.has(msg)
2737
+ );
2738
+ const turnsToSummarizeMessages = flattenTurns(turnsToSummarize).filter(
2739
+ (msg) => msg.metadata?.sticky !== true
2740
+ );
2741
+ const conversationToSummarize = this.formatTurnsForSummary(turnsToSummarizeMessages);
2726
2742
  const summary = await this.generateSummary(conversationToSummarize, config, context);
2727
2743
  const summaryMessage = {
2728
2744
  role: "user",
@@ -2730,7 +2746,11 @@ var init_summarization = __esm({
2730
2746
  ${summary}
2731
2747
  [End of summary - conversation continues below]`
2732
2748
  };
2733
- const compactedMessages = [summaryMessage, ...flattenTurns(turnsToKeep)];
2749
+ const compactedMessages = [
2750
+ summaryMessage,
2751
+ ...stickyToPreserve,
2752
+ ...flattenTurns(turnsToKeep)
2753
+ ];
2734
2754
  const tokensAfter = Math.ceil(
2735
2755
  compactedMessages.reduce((sum, msg) => sum + (msg.content?.length ?? 0), 0) / 4
2736
2756
  );
@@ -3051,7 +3071,7 @@ var init_conversation_manager = __esm({
3051
3071
  addAssistantMessage(content) {
3052
3072
  this.historyBuilder.addAssistant(content);
3053
3073
  }
3054
- addGadgetCallResult(gadgetName, parameters, result, invocationId, media, mediaIds, storedMedia) {
3074
+ addGadgetCallResult(gadgetName, parameters, result, invocationId, media, mediaIds, storedMedia, metadata) {
3055
3075
  this.historyBuilder.addGadgetCallResult(
3056
3076
  gadgetName,
3057
3077
  parameters,
@@ -3059,7 +3079,8 @@ var init_conversation_manager = __esm({
3059
3079
  invocationId,
3060
3080
  media,
3061
3081
  mediaIds,
3062
- storedMedia
3082
+ storedMedia,
3083
+ metadata
3063
3084
  );
3064
3085
  }
3065
3086
  getMessages() {
@@ -3191,6 +3212,7 @@ var init_conversation_updater = __esm({
3191
3212
  for (const output of gadgetResults) {
3192
3213
  if (output.type === "gadget_result") {
3193
3214
  const gadgetResult = output.result;
3215
+ const metadata = gadgetResult.stickyResult === true && gadgetResult.error === void 0 ? { sticky: true } : void 0;
3194
3216
  this.conversation.addGadgetCallResult(
3195
3217
  gadgetResult.gadgetName,
3196
3218
  gadgetResult.parameters,
@@ -3198,7 +3220,8 @@ var init_conversation_updater = __esm({
3198
3220
  gadgetResult.invocationId,
3199
3221
  gadgetResult.media,
3200
3222
  gadgetResult.mediaIds,
3201
- gadgetResult.storedMedia
3223
+ gadgetResult.storedMedia,
3224
+ metadata
3202
3225
  );
3203
3226
  }
3204
3227
  }
@@ -4460,6 +4483,22 @@ var init_gadget = __esm({
4460
4483
  * This is a safety floor: external config cannot weaken it.
4461
4484
  */
4462
4485
  exclusive;
4486
+ /**
4487
+ * If true, results produced by this gadget are marked sticky on the
4488
+ * conversation (`message.metadata.sticky === true`). Compaction strategies
4489
+ * preserve sticky messages past the truncation point, so the agent retains
4490
+ * the gadget's output for the rest of the conversation rather than having
4491
+ * it dropped on the next compaction pass.
4492
+ *
4493
+ * Use for gadgets whose output is *reference material* the agent will keep
4494
+ * consulting — `LoadSkill` is the canonical example: a multi-KB skill body
4495
+ * the agent needs to remember across iterations. Don't use for routine
4496
+ * gadget outputs (file reads, computation results) — those should churn
4497
+ * normally with the conversation.
4498
+ *
4499
+ * Has no effect on agents that don't enable compaction.
4500
+ */
4501
+ stickyResult;
4463
4502
  /**
4464
4503
  * Throws an AbortException if the execution has been aborted.
4465
4504
  *
@@ -4656,6 +4695,7 @@ function createGadget(config) {
4656
4695
  timeoutMs = config.timeoutMs;
4657
4696
  examples = config.examples;
4658
4697
  maxConcurrent = config.maxConcurrent;
4698
+ stickyResult = config.stickyResult;
4659
4699
  execute(params, ctx) {
4660
4700
  return config.execute(params, ctx);
4661
4701
  }
@@ -5204,7 +5244,6 @@ var init_retry_orchestrator = __esm({
5204
5244
  for await (const event of processor.process(stream2)) {
5205
5245
  if (event.type === "stream_complete") {
5206
5246
  streamMetadata = event;
5207
- continue;
5208
5247
  }
5209
5248
  if (event.type === "llm_response_end") {
5210
5249
  this.tree.endLLMResponse(llmNodeId, {
@@ -5494,6 +5533,12 @@ function createLoadSkillGadget(registry) {
5494
5533
  skill: import_zod2.z.enum(skillNames).describe("Name of the skill to load"),
5495
5534
  arguments: import_zod2.z.string().optional().describe("Arguments for the skill (e.g., a filename, issue number, or search query)")
5496
5535
  }),
5536
+ // LoadSkill exists specifically so the agent can keep a skill body in
5537
+ // context for the rest of the task — marking its results sticky lets the
5538
+ // compaction layer preserve them past truncation. Without this the agent
5539
+ // gets the skill body once, compaction drops it, and the next iteration
5540
+ // falls back to stale training knowledge of whatever the skill covered.
5541
+ stickyResult: true,
5497
5542
  execute: async ({ skill: skillName, arguments: args }) => {
5498
5543
  const skill = registry.get(skillName);
5499
5544
  if (!skill) {
@@ -14876,7 +14921,13 @@ var init_executor = __esm({
14876
14921
  cost: totalCost,
14877
14922
  media,
14878
14923
  mediaIds,
14879
- storedMedia
14924
+ storedMedia,
14925
+ // Copy the gadget's sticky flag into the result envelope so the
14926
+ // conversation-updater can mark the persisted message sticky for
14927
+ // the compaction layer. Only set on success — errors and other
14928
+ // unsuccessful exits skip this so failed loads don't pin themselves
14929
+ // in context.
14930
+ stickyResult: gadget.stickyResult
14880
14931
  };
14881
14932
  } catch (error) {
14882
14933
  const isTaskCompletionSignal = error instanceof Error && error.name === "TaskCompletionSignal";