llmist 1.3.1 → 1.5.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
@@ -857,38 +857,83 @@ function formatParamsAsBlock(params, prefix = "", argPrefix = GADGET_ARG_PREFIX)
857
857
  }
858
858
  return lines.join("\n");
859
859
  }
860
- function formatSchemaAsPlainText(schema, indent = "") {
860
+ function formatParamLine(key, propObj, isRequired, indent = "") {
861
+ const type = propObj.type;
862
+ const description = propObj.description;
863
+ const enumValues = propObj.enum;
864
+ let line = `${indent}- ${key}`;
865
+ if (type === "array") {
866
+ const items = propObj.items;
867
+ const itemType = items?.type || "any";
868
+ line += ` (array of ${itemType})`;
869
+ } else if (type === "object" && propObj.properties) {
870
+ line += " (object)";
871
+ } else {
872
+ line += ` (${type})`;
873
+ }
874
+ if (isRequired && indent !== "") {
875
+ line += " [required]";
876
+ }
877
+ if (description) {
878
+ line += `: ${description}`;
879
+ }
880
+ if (enumValues) {
881
+ line += ` - one of: ${enumValues.map((v) => `"${v}"`).join(", ")}`;
882
+ }
883
+ return line;
884
+ }
885
+ function formatSchemaAsPlainText(schema, indent = "", atRoot = true) {
861
886
  const lines = [];
862
887
  const properties = schema.properties || {};
863
888
  const required = schema.required || [];
864
- for (const [key, prop] of Object.entries(properties)) {
865
- const propObj = prop;
866
- const type = propObj.type;
867
- const description = propObj.description;
868
- const isRequired = required.includes(key);
869
- const enumValues = propObj.enum;
870
- let line = `${indent}- ${key}`;
871
- if (type === "array") {
872
- const items = propObj.items;
873
- const itemType = items?.type || "any";
874
- line += ` (array of ${itemType})`;
875
- } else if (type === "object" && propObj.properties) {
876
- line += " (object)";
877
- } else {
878
- line += ` (${type})`;
889
+ if (atRoot && indent === "") {
890
+ const requiredProps = [];
891
+ const optionalProps = [];
892
+ for (const [key, prop] of Object.entries(properties)) {
893
+ if (required.includes(key)) {
894
+ requiredProps.push([key, prop]);
895
+ } else {
896
+ optionalProps.push([key, prop]);
897
+ }
879
898
  }
880
- if (isRequired) {
881
- line += " [required]";
899
+ const reqCount = requiredProps.length;
900
+ const optCount = optionalProps.length;
901
+ if (reqCount > 0 || optCount > 0) {
902
+ const parts = [];
903
+ if (reqCount > 0) parts.push(`${reqCount} required`);
904
+ if (optCount > 0) parts.push(`${optCount} optional`);
905
+ lines.push(parts.join(", "));
906
+ lines.push("");
882
907
  }
883
- if (description) {
884
- line += `: ${description}`;
908
+ if (reqCount > 0) {
909
+ lines.push("REQUIRED Parameters:");
910
+ for (const [key, prop] of requiredProps) {
911
+ lines.push(formatParamLine(key, prop, true, ""));
912
+ const propObj = prop;
913
+ if (propObj.type === "object" && propObj.properties) {
914
+ lines.push(formatSchemaAsPlainText(propObj, " ", false));
915
+ }
916
+ }
885
917
  }
886
- if (enumValues) {
887
- line += ` - one of: ${enumValues.map((v) => `"${v}"`).join(", ")}`;
918
+ if (optCount > 0) {
919
+ if (reqCount > 0) lines.push("");
920
+ lines.push("OPTIONAL Parameters:");
921
+ for (const [key, prop] of optionalProps) {
922
+ lines.push(formatParamLine(key, prop, false, ""));
923
+ const propObj = prop;
924
+ if (propObj.type === "object" && propObj.properties) {
925
+ lines.push(formatSchemaAsPlainText(propObj, " ", false));
926
+ }
927
+ }
888
928
  }
889
- lines.push(line);
890
- if (type === "object" && propObj.properties) {
891
- lines.push(formatSchemaAsPlainText(propObj, indent + " "));
929
+ return lines.join("\n");
930
+ }
931
+ for (const [key, prop] of Object.entries(properties)) {
932
+ const isRequired = required.includes(key);
933
+ lines.push(formatParamLine(key, prop, isRequired, indent));
934
+ const propObj = prop;
935
+ if (propObj.type === "object" && propObj.properties) {
936
+ lines.push(formatSchemaAsPlainText(propObj, indent + " ", false));
892
937
  }
893
938
  }
894
939
  return lines.join("\n");
@@ -939,10 +984,11 @@ var init_gadget = __esm({
939
984
  * Generate instruction text for the LLM.
940
985
  * Combines name, description, and parameter schema into a formatted instruction.
941
986
  *
942
- * @param argPrefix - Optional custom argument prefix for block format examples
987
+ * @param optionsOrArgPrefix - Optional custom prefixes for examples, or just argPrefix string for backwards compatibility
943
988
  * @returns Formatted instruction string
944
989
  */
945
- getInstruction(argPrefix) {
990
+ getInstruction(optionsOrArgPrefix) {
991
+ const options = typeof optionsOrArgPrefix === "string" ? { argPrefix: optionsOrArgPrefix } : optionsOrArgPrefix;
946
992
  const parts = [];
947
993
  parts.push(this.description);
948
994
  if (this.parameterSchema) {
@@ -956,18 +1002,25 @@ var init_gadget = __esm({
956
1002
  }
957
1003
  if (this.examples && this.examples.length > 0) {
958
1004
  parts.push("\n\nExamples:");
959
- const effectiveArgPrefix = argPrefix ?? GADGET_ARG_PREFIX;
1005
+ const effectiveArgPrefix = options?.argPrefix ?? GADGET_ARG_PREFIX;
1006
+ const effectiveStartPrefix = options?.startPrefix ?? GADGET_START_PREFIX;
1007
+ const effectiveEndPrefix = options?.endPrefix ?? GADGET_END_PREFIX;
1008
+ const gadgetName = this.name || this.constructor.name;
960
1009
  this.examples.forEach((example, index) => {
961
1010
  if (index > 0) {
962
1011
  parts.push("");
1012
+ parts.push("---");
1013
+ parts.push("");
963
1014
  }
964
1015
  if (example.comment) {
965
1016
  parts.push(`# ${example.comment}`);
966
1017
  }
967
- parts.push("Input:");
1018
+ parts.push(`${effectiveStartPrefix}${gadgetName}`);
968
1019
  parts.push(formatParamsAsBlock(example.params, "", effectiveArgPrefix));
1020
+ parts.push(effectiveEndPrefix);
969
1021
  if (example.output !== void 0) {
970
- parts.push("Output:");
1022
+ parts.push("");
1023
+ parts.push("Expected Output:");
971
1024
  parts.push(example.output);
972
1025
  }
973
1026
  });
@@ -3307,6 +3360,8 @@ var init_agent = __esm({
3307
3360
  outputLimitCharLimit;
3308
3361
  // Context compaction
3309
3362
  compactionManager;
3363
+ // Cancellation
3364
+ signal;
3310
3365
  /**
3311
3366
  * Creates a new Agent instance.
3312
3367
  * @internal This constructor is private. Use LLMist.createAgent() or AgentBuilder instead.
@@ -3374,6 +3429,7 @@ var init_agent = __esm({
3374
3429
  options.compactionConfig
3375
3430
  );
3376
3431
  }
3432
+ this.signal = options.signal;
3377
3433
  }
3378
3434
  /**
3379
3435
  * Get the gadget registry for this agent.
@@ -3491,7 +3547,8 @@ var init_agent = __esm({
3491
3547
  model: this.model,
3492
3548
  messages: this.conversation.getMessages(),
3493
3549
  temperature: this.temperature,
3494
- maxTokens: this.defaultMaxTokens
3550
+ maxTokens: this.defaultMaxTokens,
3551
+ signal: this.signal
3495
3552
  };
3496
3553
  await this.safeObserve(async () => {
3497
3554
  if (this.hooks.observers?.onLLMCallStart) {
@@ -4109,7 +4166,7 @@ var init_base_provider = __esm({
4109
4166
  async *stream(options, descriptor, spec) {
4110
4167
  const preparedMessages = this.prepareMessages(options.messages);
4111
4168
  const payload = this.buildRequestPayload(options, descriptor, spec, preparedMessages);
4112
- const rawStream = await this.executeStreamRequest(payload);
4169
+ const rawStream = await this.executeStreamRequest(payload, options.signal);
4113
4170
  yield* this.wrapStream(rawStream);
4114
4171
  }
4115
4172
  /**
@@ -4227,9 +4284,9 @@ var init_anthropic = __esm({
4227
4284
  };
4228
4285
  return payload;
4229
4286
  }
4230
- async executeStreamRequest(payload) {
4287
+ async executeStreamRequest(payload, signal) {
4231
4288
  const client = this.client;
4232
- const stream2 = await client.messages.create(payload);
4289
+ const stream2 = await client.messages.create(payload, signal ? { signal } : void 0);
4233
4290
  return stream2;
4234
4291
  }
4235
4292
  async *wrapStream(iterable) {
@@ -4561,9 +4618,15 @@ var init_gemini = __esm({
4561
4618
  config
4562
4619
  };
4563
4620
  }
4564
- async executeStreamRequest(payload) {
4621
+ async executeStreamRequest(payload, signal) {
4565
4622
  const client = this.client;
4566
- const streamResponse = await client.models.generateContentStream(payload);
4623
+ const streamResponse = await client.models.generateContentStream({
4624
+ ...payload,
4625
+ config: {
4626
+ ...payload.config,
4627
+ ...signal ? { abortSignal: signal } : {}
4628
+ }
4629
+ });
4567
4630
  return streamResponse;
4568
4631
  }
4569
4632
  /**
@@ -5152,9 +5215,9 @@ var init_openai = __esm({
5152
5215
  ...shouldIncludeTemperature ? { temperature } : {}
5153
5216
  };
5154
5217
  }
5155
- async executeStreamRequest(payload) {
5218
+ async executeStreamRequest(payload, signal) {
5156
5219
  const client = this.client;
5157
- const stream2 = await client.chat.completions.create(payload);
5220
+ const stream2 = await client.chat.completions.create(payload, signal ? { signal } : void 0);
5158
5221
  return stream2;
5159
5222
  }
5160
5223
  async *wrapStream(iterable) {
@@ -5817,6 +5880,7 @@ var init_builder = __esm({
5817
5880
  gadgetOutputLimit;
5818
5881
  gadgetOutputLimitPercent;
5819
5882
  compactionConfig;
5883
+ signal;
5820
5884
  constructor(client) {
5821
5885
  this.client = client;
5822
5886
  }
@@ -6263,6 +6327,35 @@ var init_builder = __esm({
6263
6327
  this.compactionConfig = { enabled: false };
6264
6328
  return this;
6265
6329
  }
6330
+ /**
6331
+ * Set an abort signal for cancelling requests mid-flight.
6332
+ *
6333
+ * When the signal is aborted, the current LLM request will be cancelled
6334
+ * and the agent loop will exit gracefully.
6335
+ *
6336
+ * @param signal - AbortSignal from an AbortController
6337
+ * @returns This builder for chaining
6338
+ *
6339
+ * @example
6340
+ * ```typescript
6341
+ * const controller = new AbortController();
6342
+ *
6343
+ * // Cancel after 30 seconds
6344
+ * setTimeout(() => controller.abort(), 30000);
6345
+ *
6346
+ * const agent = LLMist.createAgent()
6347
+ * .withModel("sonnet")
6348
+ * .withSignal(controller.signal)
6349
+ * .ask("Write a long story");
6350
+ *
6351
+ * // Or cancel on user action
6352
+ * document.getElementById("cancel").onclick = () => controller.abort();
6353
+ * ```
6354
+ */
6355
+ withSignal(signal) {
6356
+ this.signal = signal;
6357
+ return this;
6358
+ }
6266
6359
  /**
6267
6360
  * Add a synthetic gadget call to the conversation history.
6268
6361
  *
@@ -6379,7 +6472,8 @@ ${endPrefix}`
6379
6472
  defaultGadgetTimeoutMs: this.defaultGadgetTimeoutMs,
6380
6473
  gadgetOutputLimit: this.gadgetOutputLimit,
6381
6474
  gadgetOutputLimitPercent: this.gadgetOutputLimitPercent,
6382
- compactionConfig: this.compactionConfig
6475
+ compactionConfig: this.compactionConfig,
6476
+ signal: this.signal
6383
6477
  };
6384
6478
  return new Agent(AGENT_INTERNAL_KEY, options);
6385
6479
  }
@@ -6482,7 +6576,8 @@ ${endPrefix}`
6482
6576
  defaultGadgetTimeoutMs: this.defaultGadgetTimeoutMs,
6483
6577
  gadgetOutputLimit: this.gadgetOutputLimit,
6484
6578
  gadgetOutputLimitPercent: this.gadgetOutputLimitPercent,
6485
- compactionConfig: this.compactionConfig
6579
+ compactionConfig: this.compactionConfig,
6580
+ signal: this.signal
6486
6581
  };
6487
6582
  return new Agent(AGENT_INTERNAL_KEY, options);
6488
6583
  }