llmist 1.6.1 → 1.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.
@@ -1089,7 +1089,7 @@ function applyLineLimit(lines, limit) {
1089
1089
  }
1090
1090
  return lines;
1091
1091
  }
1092
- function createGadgetOutputViewer(store) {
1092
+ function createGadgetOutputViewer(store, maxOutputChars = DEFAULT_MAX_OUTPUT_CHARS) {
1093
1093
  return createGadget({
1094
1094
  name: "GadgetOutputViewer",
1095
1095
  description: "View stored output from gadgets that returned too much data. Use patterns to filter lines (like grep) and limit to control output size. Patterns are applied first in order, then the limit is applied to the result.",
@@ -1154,19 +1154,43 @@ function createGadgetOutputViewer(store) {
1154
1154
  if (limit) {
1155
1155
  lines = applyLineLimit(lines, limit);
1156
1156
  }
1157
+ let output = lines.join("\n");
1157
1158
  const totalLines = stored.lineCount;
1158
1159
  const returnedLines = lines.length;
1159
1160
  if (returnedLines === 0) {
1160
1161
  return `No lines matched the filters. Original output had ${totalLines} lines.`;
1161
1162
  }
1162
- const header = returnedLines < totalLines ? `[Showing ${returnedLines} of ${totalLines} lines]
1163
- ` : `[Showing all ${totalLines} lines]
1163
+ let truncatedBySize = false;
1164
+ let linesIncluded = returnedLines;
1165
+ if (output.length > maxOutputChars) {
1166
+ truncatedBySize = true;
1167
+ let truncatedOutput = "";
1168
+ linesIncluded = 0;
1169
+ for (const line of lines) {
1170
+ if (truncatedOutput.length + line.length + 1 > maxOutputChars) break;
1171
+ truncatedOutput += line + "\n";
1172
+ linesIncluded++;
1173
+ }
1174
+ output = truncatedOutput;
1175
+ }
1176
+ let header;
1177
+ if (truncatedBySize) {
1178
+ const remainingLines = returnedLines - linesIncluded;
1179
+ header = `[Showing ${linesIncluded} of ${totalLines} lines (truncated due to size limit)]
1180
+ [... ${remainingLines.toLocaleString()} more lines. Use limit parameter to paginate, e.g., limit: "${linesIncluded + 1}-${linesIncluded + 200}"]
1164
1181
  `;
1165
- return header + lines.join("\n");
1182
+ } else if (returnedLines < totalLines) {
1183
+ header = `[Showing ${returnedLines} of ${totalLines} lines]
1184
+ `;
1185
+ } else {
1186
+ header = `[Showing all ${totalLines} lines]
1187
+ `;
1188
+ }
1189
+ return header + output;
1166
1190
  }
1167
1191
  });
1168
1192
  }
1169
- var patternSchema;
1193
+ var patternSchema, DEFAULT_MAX_OUTPUT_CHARS;
1170
1194
  var init_output_viewer = __esm({
1171
1195
  "src/gadgets/output-viewer.ts"() {
1172
1196
  "use strict";
@@ -1177,6 +1201,7 @@ var init_output_viewer = __esm({
1177
1201
  before: z3.number().int().min(0).default(0).describe("Context lines before each match (like grep -B)"),
1178
1202
  after: z3.number().int().min(0).default(0).describe("Context lines after each match (like grep -A)")
1179
1203
  });
1204
+ DEFAULT_MAX_OUTPUT_CHARS = 76800;
1180
1205
  }
1181
1206
  });
1182
1207
 
@@ -3382,7 +3407,10 @@ var init_agent = __esm({
3382
3407
  const contextWindow = limits?.contextWindow ?? FALLBACK_CONTEXT_WINDOW;
3383
3408
  this.outputLimitCharLimit = Math.floor(contextWindow * (limitPercent / 100) * CHARS_PER_TOKEN);
3384
3409
  if (this.outputLimitEnabled) {
3385
- this.registry.register("GadgetOutputViewer", createGadgetOutputViewer(this.outputStore));
3410
+ this.registry.register(
3411
+ "GadgetOutputViewer",
3412
+ createGadgetOutputViewer(this.outputStore, this.outputLimitCharLimit)
3413
+ );
3386
3414
  }
3387
3415
  this.hooks = this.mergeOutputLimiterHook(options.hooks);
3388
3416
  const baseBuilder = new LLMMessageBuilder(options.promptConfig);
@@ -3889,6 +3917,7 @@ var init_builder = __esm({
3889
3917
  gadgetOutputLimitPercent;
3890
3918
  compactionConfig;
3891
3919
  signal;
3920
+ trailingMessage;
3892
3921
  constructor(client) {
3893
3922
  this.client = client;
3894
3923
  }
@@ -4364,6 +4393,31 @@ var init_builder = __esm({
4364
4393
  this.signal = signal;
4365
4394
  return this;
4366
4395
  }
4396
+ /**
4397
+ * Add an ephemeral trailing message that appears at the end of each LLM request.
4398
+ *
4399
+ * The message is NOT persisted to conversation history - it only appears in the
4400
+ * current LLM call. This is useful for injecting context-specific instructions
4401
+ * or reminders without polluting the conversation history.
4402
+ *
4403
+ * @param message - Static string or function that generates the message
4404
+ * @returns This builder for chaining
4405
+ *
4406
+ * @example
4407
+ * ```typescript
4408
+ * // Static message
4409
+ * .withTrailingMessage("Always respond in JSON format.")
4410
+ *
4411
+ * // Dynamic message based on iteration
4412
+ * .withTrailingMessage((ctx) =>
4413
+ * `[Iteration ${ctx.iteration}/${ctx.maxIterations}] Stay focused on the task.`
4414
+ * )
4415
+ * ```
4416
+ */
4417
+ withTrailingMessage(message) {
4418
+ this.trailingMessage = message;
4419
+ return this;
4420
+ }
4367
4421
  /**
4368
4422
  * Add a synthetic gadget call to the conversation history.
4369
4423
  *
@@ -4405,6 +4459,36 @@ ${endPrefix}`
4405
4459
  });
4406
4460
  return this;
4407
4461
  }
4462
+ /**
4463
+ * Compose the final hooks, including trailing message if configured.
4464
+ */
4465
+ composeHooks() {
4466
+ if (!this.trailingMessage) {
4467
+ return this.hooks;
4468
+ }
4469
+ const trailingMsg = this.trailingMessage;
4470
+ const existingBeforeLLMCall = this.hooks?.controllers?.beforeLLMCall;
4471
+ const trailingMessageController = async (ctx) => {
4472
+ const result = existingBeforeLLMCall ? await existingBeforeLLMCall(ctx) : { action: "proceed" };
4473
+ if (result.action === "skip") {
4474
+ return result;
4475
+ }
4476
+ const messages = [...result.modifiedOptions?.messages || ctx.options.messages];
4477
+ const content = typeof trailingMsg === "function" ? trailingMsg({ iteration: ctx.iteration, maxIterations: ctx.maxIterations }) : trailingMsg;
4478
+ messages.push({ role: "user", content });
4479
+ return {
4480
+ action: "proceed",
4481
+ modifiedOptions: { ...result.modifiedOptions, messages }
4482
+ };
4483
+ };
4484
+ return {
4485
+ ...this.hooks,
4486
+ controllers: {
4487
+ ...this.hooks?.controllers,
4488
+ beforeLLMCall: trailingMessageController
4489
+ }
4490
+ };
4491
+ }
4408
4492
  /**
4409
4493
  * Format parameters as block format with JSON Pointer paths.
4410
4494
  */
@@ -4466,7 +4550,7 @@ ${endPrefix}`
4466
4550
  maxIterations: this.maxIterations,
4467
4551
  temperature: this.temperature,
4468
4552
  logger: this.logger,
4469
- hooks: this.hooks,
4553
+ hooks: this.composeHooks(),
4470
4554
  promptConfig: this.promptConfig,
4471
4555
  initialMessages: this.initialMessages,
4472
4556
  onHumanInputRequired: this.onHumanInputRequired,
@@ -4570,7 +4654,7 @@ ${endPrefix}`
4570
4654
  maxIterations: this.maxIterations,
4571
4655
  temperature: this.temperature,
4572
4656
  logger: this.logger,
4573
- hooks: this.hooks,
4657
+ hooks: this.composeHooks(),
4574
4658
  promptConfig: this.promptConfig,
4575
4659
  initialMessages: this.initialMessages,
4576
4660
  onHumanInputRequired: this.onHumanInputRequired,
@@ -8032,4 +8116,4 @@ export {
8032
8116
  MockPromptRecorder,
8033
8117
  waitFor
8034
8118
  };
8035
- //# sourceMappingURL=chunk-X5XQ6M5P.js.map
8119
+ //# sourceMappingURL=chunk-E52IO2NO.js.map