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.
@@ -829,38 +829,83 @@ function formatParamsAsBlock(params, prefix = "", argPrefix = GADGET_ARG_PREFIX)
829
829
  }
830
830
  return lines.join("\n");
831
831
  }
832
- function formatSchemaAsPlainText(schema, indent = "") {
832
+ function formatParamLine(key, propObj, isRequired, indent = "") {
833
+ const type = propObj.type;
834
+ const description = propObj.description;
835
+ const enumValues = propObj.enum;
836
+ let line = `${indent}- ${key}`;
837
+ if (type === "array") {
838
+ const items = propObj.items;
839
+ const itemType = items?.type || "any";
840
+ line += ` (array of ${itemType})`;
841
+ } else if (type === "object" && propObj.properties) {
842
+ line += " (object)";
843
+ } else {
844
+ line += ` (${type})`;
845
+ }
846
+ if (isRequired && indent !== "") {
847
+ line += " [required]";
848
+ }
849
+ if (description) {
850
+ line += `: ${description}`;
851
+ }
852
+ if (enumValues) {
853
+ line += ` - one of: ${enumValues.map((v) => `"${v}"`).join(", ")}`;
854
+ }
855
+ return line;
856
+ }
857
+ function formatSchemaAsPlainText(schema, indent = "", atRoot = true) {
833
858
  const lines = [];
834
859
  const properties = schema.properties || {};
835
860
  const required = schema.required || [];
836
- for (const [key, prop] of Object.entries(properties)) {
837
- const propObj = prop;
838
- const type = propObj.type;
839
- const description = propObj.description;
840
- const isRequired = required.includes(key);
841
- const enumValues = propObj.enum;
842
- let line = `${indent}- ${key}`;
843
- if (type === "array") {
844
- const items = propObj.items;
845
- const itemType = items?.type || "any";
846
- line += ` (array of ${itemType})`;
847
- } else if (type === "object" && propObj.properties) {
848
- line += " (object)";
849
- } else {
850
- line += ` (${type})`;
861
+ if (atRoot && indent === "") {
862
+ const requiredProps = [];
863
+ const optionalProps = [];
864
+ for (const [key, prop] of Object.entries(properties)) {
865
+ if (required.includes(key)) {
866
+ requiredProps.push([key, prop]);
867
+ } else {
868
+ optionalProps.push([key, prop]);
869
+ }
851
870
  }
852
- if (isRequired) {
853
- line += " [required]";
871
+ const reqCount = requiredProps.length;
872
+ const optCount = optionalProps.length;
873
+ if (reqCount > 0 || optCount > 0) {
874
+ const parts = [];
875
+ if (reqCount > 0) parts.push(`${reqCount} required`);
876
+ if (optCount > 0) parts.push(`${optCount} optional`);
877
+ lines.push(parts.join(", "));
878
+ lines.push("");
854
879
  }
855
- if (description) {
856
- line += `: ${description}`;
880
+ if (reqCount > 0) {
881
+ lines.push("REQUIRED Parameters:");
882
+ for (const [key, prop] of requiredProps) {
883
+ lines.push(formatParamLine(key, prop, true, ""));
884
+ const propObj = prop;
885
+ if (propObj.type === "object" && propObj.properties) {
886
+ lines.push(formatSchemaAsPlainText(propObj, " ", false));
887
+ }
888
+ }
857
889
  }
858
- if (enumValues) {
859
- line += ` - one of: ${enumValues.map((v) => `"${v}"`).join(", ")}`;
890
+ if (optCount > 0) {
891
+ if (reqCount > 0) lines.push("");
892
+ lines.push("OPTIONAL Parameters:");
893
+ for (const [key, prop] of optionalProps) {
894
+ lines.push(formatParamLine(key, prop, false, ""));
895
+ const propObj = prop;
896
+ if (propObj.type === "object" && propObj.properties) {
897
+ lines.push(formatSchemaAsPlainText(propObj, " ", false));
898
+ }
899
+ }
860
900
  }
861
- lines.push(line);
862
- if (type === "object" && propObj.properties) {
863
- lines.push(formatSchemaAsPlainText(propObj, indent + " "));
901
+ return lines.join("\n");
902
+ }
903
+ for (const [key, prop] of Object.entries(properties)) {
904
+ const isRequired = required.includes(key);
905
+ lines.push(formatParamLine(key, prop, isRequired, indent));
906
+ const propObj = prop;
907
+ if (propObj.type === "object" && propObj.properties) {
908
+ lines.push(formatSchemaAsPlainText(propObj, indent + " ", false));
864
909
  }
865
910
  }
866
911
  return lines.join("\n");
@@ -911,10 +956,11 @@ var init_gadget = __esm({
911
956
  * Generate instruction text for the LLM.
912
957
  * Combines name, description, and parameter schema into a formatted instruction.
913
958
  *
914
- * @param argPrefix - Optional custom argument prefix for block format examples
959
+ * @param optionsOrArgPrefix - Optional custom prefixes for examples, or just argPrefix string for backwards compatibility
915
960
  * @returns Formatted instruction string
916
961
  */
917
- getInstruction(argPrefix) {
962
+ getInstruction(optionsOrArgPrefix) {
963
+ const options = typeof optionsOrArgPrefix === "string" ? { argPrefix: optionsOrArgPrefix } : optionsOrArgPrefix;
918
964
  const parts = [];
919
965
  parts.push(this.description);
920
966
  if (this.parameterSchema) {
@@ -928,18 +974,25 @@ var init_gadget = __esm({
928
974
  }
929
975
  if (this.examples && this.examples.length > 0) {
930
976
  parts.push("\n\nExamples:");
931
- const effectiveArgPrefix = argPrefix ?? GADGET_ARG_PREFIX;
977
+ const effectiveArgPrefix = options?.argPrefix ?? GADGET_ARG_PREFIX;
978
+ const effectiveStartPrefix = options?.startPrefix ?? GADGET_START_PREFIX;
979
+ const effectiveEndPrefix = options?.endPrefix ?? GADGET_END_PREFIX;
980
+ const gadgetName = this.name || this.constructor.name;
932
981
  this.examples.forEach((example, index) => {
933
982
  if (index > 0) {
934
983
  parts.push("");
984
+ parts.push("---");
985
+ parts.push("");
935
986
  }
936
987
  if (example.comment) {
937
988
  parts.push(`# ${example.comment}`);
938
989
  }
939
- parts.push("Input:");
990
+ parts.push(`${effectiveStartPrefix}${gadgetName}`);
940
991
  parts.push(formatParamsAsBlock(example.params, "", effectiveArgPrefix));
992
+ parts.push(effectiveEndPrefix);
941
993
  if (example.output !== void 0) {
942
- parts.push("Output:");
994
+ parts.push("");
995
+ parts.push("Expected Output:");
943
996
  parts.push(example.output);
944
997
  }
945
998
  });
@@ -3249,6 +3302,8 @@ var init_agent = __esm({
3249
3302
  outputLimitCharLimit;
3250
3303
  // Context compaction
3251
3304
  compactionManager;
3305
+ // Cancellation
3306
+ signal;
3252
3307
  /**
3253
3308
  * Creates a new Agent instance.
3254
3309
  * @internal This constructor is private. Use LLMist.createAgent() or AgentBuilder instead.
@@ -3316,6 +3371,7 @@ var init_agent = __esm({
3316
3371
  options.compactionConfig
3317
3372
  );
3318
3373
  }
3374
+ this.signal = options.signal;
3319
3375
  }
3320
3376
  /**
3321
3377
  * Get the gadget registry for this agent.
@@ -3433,7 +3489,8 @@ var init_agent = __esm({
3433
3489
  model: this.model,
3434
3490
  messages: this.conversation.getMessages(),
3435
3491
  temperature: this.temperature,
3436
- maxTokens: this.defaultMaxTokens
3492
+ maxTokens: this.defaultMaxTokens,
3493
+ signal: this.signal
3437
3494
  };
3438
3495
  await this.safeObserve(async () => {
3439
3496
  if (this.hooks.observers?.onLLMCallStart) {
@@ -3786,6 +3843,7 @@ var init_builder = __esm({
3786
3843
  gadgetOutputLimit;
3787
3844
  gadgetOutputLimitPercent;
3788
3845
  compactionConfig;
3846
+ signal;
3789
3847
  constructor(client) {
3790
3848
  this.client = client;
3791
3849
  }
@@ -4232,6 +4290,35 @@ var init_builder = __esm({
4232
4290
  this.compactionConfig = { enabled: false };
4233
4291
  return this;
4234
4292
  }
4293
+ /**
4294
+ * Set an abort signal for cancelling requests mid-flight.
4295
+ *
4296
+ * When the signal is aborted, the current LLM request will be cancelled
4297
+ * and the agent loop will exit gracefully.
4298
+ *
4299
+ * @param signal - AbortSignal from an AbortController
4300
+ * @returns This builder for chaining
4301
+ *
4302
+ * @example
4303
+ * ```typescript
4304
+ * const controller = new AbortController();
4305
+ *
4306
+ * // Cancel after 30 seconds
4307
+ * setTimeout(() => controller.abort(), 30000);
4308
+ *
4309
+ * const agent = LLMist.createAgent()
4310
+ * .withModel("sonnet")
4311
+ * .withSignal(controller.signal)
4312
+ * .ask("Write a long story");
4313
+ *
4314
+ * // Or cancel on user action
4315
+ * document.getElementById("cancel").onclick = () => controller.abort();
4316
+ * ```
4317
+ */
4318
+ withSignal(signal) {
4319
+ this.signal = signal;
4320
+ return this;
4321
+ }
4235
4322
  /**
4236
4323
  * Add a synthetic gadget call to the conversation history.
4237
4324
  *
@@ -4348,7 +4435,8 @@ ${endPrefix}`
4348
4435
  defaultGadgetTimeoutMs: this.defaultGadgetTimeoutMs,
4349
4436
  gadgetOutputLimit: this.gadgetOutputLimit,
4350
4437
  gadgetOutputLimitPercent: this.gadgetOutputLimitPercent,
4351
- compactionConfig: this.compactionConfig
4438
+ compactionConfig: this.compactionConfig,
4439
+ signal: this.signal
4352
4440
  };
4353
4441
  return new Agent(AGENT_INTERNAL_KEY, options);
4354
4442
  }
@@ -4451,7 +4539,8 @@ ${endPrefix}`
4451
4539
  defaultGadgetTimeoutMs: this.defaultGadgetTimeoutMs,
4452
4540
  gadgetOutputLimit: this.gadgetOutputLimit,
4453
4541
  gadgetOutputLimitPercent: this.gadgetOutputLimitPercent,
4454
- compactionConfig: this.compactionConfig
4542
+ compactionConfig: this.compactionConfig,
4543
+ signal: this.signal
4455
4544
  };
4456
4545
  return new Agent(AGENT_INTERNAL_KEY, options);
4457
4546
  }
@@ -4758,7 +4847,7 @@ var init_base_provider = __esm({
4758
4847
  async *stream(options, descriptor, spec) {
4759
4848
  const preparedMessages = this.prepareMessages(options.messages);
4760
4849
  const payload = this.buildRequestPayload(options, descriptor, spec, preparedMessages);
4761
- const rawStream = await this.executeStreamRequest(payload);
4850
+ const rawStream = await this.executeStreamRequest(payload, options.signal);
4762
4851
  yield* this.wrapStream(rawStream);
4763
4852
  }
4764
4853
  /**
@@ -4876,9 +4965,9 @@ var init_anthropic = __esm({
4876
4965
  };
4877
4966
  return payload;
4878
4967
  }
4879
- async executeStreamRequest(payload) {
4968
+ async executeStreamRequest(payload, signal) {
4880
4969
  const client = this.client;
4881
- const stream2 = await client.messages.create(payload);
4970
+ const stream2 = await client.messages.create(payload, signal ? { signal } : void 0);
4882
4971
  return stream2;
4883
4972
  }
4884
4973
  async *wrapStream(iterable) {
@@ -5210,9 +5299,15 @@ var init_gemini = __esm({
5210
5299
  config
5211
5300
  };
5212
5301
  }
5213
- async executeStreamRequest(payload) {
5302
+ async executeStreamRequest(payload, signal) {
5214
5303
  const client = this.client;
5215
- const streamResponse = await client.models.generateContentStream(payload);
5304
+ const streamResponse = await client.models.generateContentStream({
5305
+ ...payload,
5306
+ config: {
5307
+ ...payload.config,
5308
+ ...signal ? { abortSignal: signal } : {}
5309
+ }
5310
+ });
5216
5311
  return streamResponse;
5217
5312
  }
5218
5313
  /**
@@ -5801,9 +5896,9 @@ var init_openai = __esm({
5801
5896
  ...shouldIncludeTemperature ? { temperature } : {}
5802
5897
  };
5803
5898
  }
5804
- async executeStreamRequest(payload) {
5899
+ async executeStreamRequest(payload, signal) {
5805
5900
  const client = this.client;
5806
- const stream2 = await client.chat.completions.create(payload);
5901
+ const stream2 = await client.chat.completions.create(payload, signal ? { signal } : void 0);
5807
5902
  return stream2;
5808
5903
  }
5809
5904
  async *wrapStream(iterable) {