llmist 1.7.0 → 2.0.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.
@@ -315,6 +315,271 @@ interface ResolvedCompactionConfig {
315
315
  onCompaction?: (event: CompactionEvent) => void;
316
316
  }
317
317
 
318
+ /**
319
+ * Model Registry
320
+ *
321
+ * Centralized registry for querying LLM model specifications,
322
+ * validating configurations, and estimating costs.
323
+ *
324
+ * Model data is provided by ProviderAdapter implementations and
325
+ * automatically populated when providers are registered.
326
+ */
327
+
328
+ declare class ModelRegistry {
329
+ private modelSpecs;
330
+ private providerMap;
331
+ /**
332
+ * Register a provider and collect its model specifications
333
+ */
334
+ registerProvider(provider: ProviderAdapter): void;
335
+ /**
336
+ * Register a custom model specification at runtime
337
+ *
338
+ * Use this to add models that aren't in the built-in catalog, such as:
339
+ * - Fine-tuned models with custom pricing
340
+ * - New models not yet supported by llmist
341
+ * - Custom deployments with different configurations
342
+ *
343
+ * @param spec - Complete model specification
344
+ * @throws {Error} If spec is missing required fields
345
+ *
346
+ * @example
347
+ * ```ts
348
+ * client.modelRegistry.registerModel({
349
+ * provider: "openai",
350
+ * modelId: "ft:gpt-4o-2024-08-06:my-org:custom:abc123",
351
+ * displayName: "My Fine-tuned GPT-4o",
352
+ * contextWindow: 128_000,
353
+ * maxOutputTokens: 16_384,
354
+ * pricing: { input: 7.5, output: 30.0 },
355
+ * knowledgeCutoff: "2024-08",
356
+ * features: { streaming: true, functionCalling: true, vision: true }
357
+ * });
358
+ * ```
359
+ */
360
+ registerModel(spec: ModelSpec): void;
361
+ /**
362
+ * Register multiple custom model specifications at once
363
+ *
364
+ * @param specs - Array of complete model specifications
365
+ *
366
+ * @example
367
+ * ```ts
368
+ * client.modelRegistry.registerModels([
369
+ * { provider: "openai", modelId: "gpt-5", ... },
370
+ * { provider: "openai", modelId: "gpt-5-mini", ... }
371
+ * ]);
372
+ * ```
373
+ */
374
+ registerModels(specs: ModelSpec[]): void;
375
+ /**
376
+ * Get model specification by model ID
377
+ * @param modelId - Full model identifier (e.g., 'gpt-5', 'claude-sonnet-4-5-20250929')
378
+ * @returns ModelSpec if found, undefined otherwise
379
+ */
380
+ getModelSpec(modelId: string): ModelSpec | undefined;
381
+ /**
382
+ * List all models, optionally filtered by provider
383
+ * @param providerId - Optional provider ID to filter by (e.g., 'openai', 'anthropic')
384
+ * @returns Array of ModelSpec objects
385
+ */
386
+ listModels(providerId?: string): ModelSpec[];
387
+ /**
388
+ * Get context window and output limits for a model
389
+ * @param modelId - Full model identifier
390
+ * @returns ModelLimits if model found, undefined otherwise
391
+ */
392
+ getModelLimits(modelId: string): ModelLimits | undefined;
393
+ /**
394
+ * Estimate API cost for a given model and token usage
395
+ * @param modelId - Full model identifier
396
+ * @param inputTokens - Number of input tokens (total, including cached and cache creation)
397
+ * @param outputTokens - Number of output tokens
398
+ * @param cachedInputTokens - Number of cached input tokens (subset of inputTokens)
399
+ * @param cacheCreationInputTokens - Number of cache creation tokens (subset of inputTokens, Anthropic only)
400
+ * @returns CostEstimate if model found, undefined otherwise
401
+ */
402
+ estimateCost(modelId: string, inputTokens: number, outputTokens: number, cachedInputTokens?: number, cacheCreationInputTokens?: number): CostEstimate | undefined;
403
+ /**
404
+ * Validate that requested token count fits within model limits
405
+ * @param modelId - Full model identifier
406
+ * @param requestedTokens - Total tokens requested (input + output)
407
+ * @returns true if valid, false if model not found or exceeds limits
408
+ */
409
+ validateModelConfig(modelId: string, requestedTokens: number): boolean;
410
+ /**
411
+ * Check if a model supports a specific feature
412
+ * @param modelId - Full model identifier
413
+ * @param feature - Feature to check ('streaming', 'functionCalling', 'vision', etc.)
414
+ * @returns true if model supports feature, false otherwise
415
+ */
416
+ supportsFeature(modelId: string, feature: keyof ModelSpec["features"]): boolean;
417
+ /**
418
+ * Get all models that support a specific feature
419
+ * @param feature - Feature to filter by
420
+ * @param providerId - Optional provider ID to filter by
421
+ * @returns Array of ModelSpec objects that support the feature
422
+ */
423
+ getModelsByFeature(feature: keyof ModelSpec["features"], providerId?: string): ModelSpec[];
424
+ /**
425
+ * Get the most cost-effective model for a given provider and token budget
426
+ * @param inputTokens - Expected input tokens
427
+ * @param outputTokens - Expected output tokens
428
+ * @param providerId - Optional provider ID to filter by
429
+ * @returns ModelSpec with lowest total cost, or undefined if no models found
430
+ */
431
+ getCheapestModel(inputTokens: number, outputTokens: number, providerId?: string): ModelSpec | undefined;
432
+ }
433
+
434
+ interface LLMGenerationOptions {
435
+ model: string;
436
+ messages: LLMMessage[];
437
+ maxTokens?: number;
438
+ temperature?: number;
439
+ topP?: number;
440
+ stopSequences?: string[];
441
+ responseFormat?: "text";
442
+ metadata?: Record<string, unknown>;
443
+ extra?: Record<string, unknown>;
444
+ /**
445
+ * Optional abort signal for cancelling the request mid-flight.
446
+ *
447
+ * When the signal is aborted, the provider will attempt to cancel
448
+ * the underlying HTTP request and the stream will terminate with
449
+ * an abort error. Use `isAbortError()` from `@/core/errors` to
450
+ * detect cancellation in error handling.
451
+ *
452
+ * @example
453
+ * ```typescript
454
+ * const controller = new AbortController();
455
+ *
456
+ * const stream = client.stream({
457
+ * model: "claude-3-5-sonnet-20241022",
458
+ * messages: [{ role: "user", content: "Tell me a long story" }],
459
+ * signal: controller.signal,
460
+ * });
461
+ *
462
+ * // Cancel after 5 seconds
463
+ * setTimeout(() => controller.abort(), 5000);
464
+ *
465
+ * try {
466
+ * for await (const chunk of stream) {
467
+ * process.stdout.write(chunk.text);
468
+ * }
469
+ * } catch (error) {
470
+ * if (isAbortError(error)) {
471
+ * console.log("\nRequest was cancelled");
472
+ * } else {
473
+ * throw error;
474
+ * }
475
+ * }
476
+ * ```
477
+ */
478
+ signal?: AbortSignal;
479
+ }
480
+ interface TokenUsage {
481
+ inputTokens: number;
482
+ outputTokens: number;
483
+ totalTokens: number;
484
+ /** Number of input tokens served from cache (subset of inputTokens) */
485
+ cachedInputTokens?: number;
486
+ /** Number of input tokens written to cache (subset of inputTokens, Anthropic only) */
487
+ cacheCreationInputTokens?: number;
488
+ }
489
+ interface LLMStreamChunk {
490
+ text: string;
491
+ /**
492
+ * Indicates that the provider has finished producing output and includes the reason if available.
493
+ */
494
+ finishReason?: string | null;
495
+ /**
496
+ * Token usage information, typically available in the final chunk when the stream completes.
497
+ */
498
+ usage?: TokenUsage;
499
+ /**
500
+ * Provider specific payload emitted at the same time as the text chunk. This is useful for debugging and tests.
501
+ */
502
+ rawEvent?: unknown;
503
+ }
504
+ interface LLMStream extends AsyncIterable<LLMStreamChunk> {
505
+ }
506
+ type ProviderIdentifier = string;
507
+ interface ModelDescriptor {
508
+ provider: string;
509
+ name: string;
510
+ }
511
+ declare class ModelIdentifierParser {
512
+ private readonly defaultProvider;
513
+ constructor(defaultProvider?: string);
514
+ parse(identifier: string): ModelDescriptor;
515
+ }
516
+
517
+ /**
518
+ * Quick execution methods for simple use cases.
519
+ *
520
+ * These methods provide convenient shortcuts for common operations
521
+ * without requiring full agent setup.
522
+ *
523
+ * @example
524
+ * ```typescript
525
+ * // Quick completion
526
+ * const answer = await llmist.complete("What is 2+2?");
527
+ *
528
+ * // Quick streaming
529
+ * for await (const chunk of llmist.stream("Tell me a story")) {
530
+ * process.stdout.write(chunk);
531
+ * }
532
+ * ```
533
+ */
534
+
535
+ /**
536
+ * Options for quick execution methods.
537
+ */
538
+ interface QuickOptions {
539
+ /** Model to use (supports aliases like "gpt4", "sonnet", "flash") */
540
+ model?: string;
541
+ /** Temperature (0-1) */
542
+ temperature?: number;
543
+ /** System prompt */
544
+ systemPrompt?: string;
545
+ /** Max tokens to generate */
546
+ maxTokens?: number;
547
+ }
548
+ /**
549
+ * Quick completion - returns final text response.
550
+ *
551
+ * @param client - LLMist client instance
552
+ * @param prompt - User prompt
553
+ * @param options - Optional configuration
554
+ * @returns Complete text response
555
+ *
556
+ * @example
557
+ * ```typescript
558
+ * const client = new LLMist();
559
+ * const answer = await complete(client, "What is 2+2?");
560
+ * console.log(answer); // "4" or "2+2 equals 4"
561
+ * ```
562
+ */
563
+ declare function complete(client: LLMist, prompt: string, options?: QuickOptions): Promise<string>;
564
+ /**
565
+ * Quick streaming - returns async generator of text chunks.
566
+ *
567
+ * @param client - LLMist client instance
568
+ * @param prompt - User prompt
569
+ * @param options - Optional configuration
570
+ * @returns Async generator yielding text chunks
571
+ *
572
+ * @example
573
+ * ```typescript
574
+ * const client = new LLMist();
575
+ *
576
+ * for await (const chunk of stream(client, "Tell me a story")) {
577
+ * process.stdout.write(chunk);
578
+ * }
579
+ * ```
580
+ */
581
+ declare function stream(client: LLMist, prompt: string, options?: QuickOptions): AsyncGenerator<string>;
582
+
318
583
  /**
319
584
  * Example of gadget usage to help LLMs understand proper invocation.
320
585
  *
@@ -350,7 +615,34 @@ interface GadgetExecutionResult {
350
615
  error?: string;
351
616
  executionTimeMs: number;
352
617
  breaksLoop?: boolean;
618
+ /** Cost of gadget execution in USD. Defaults to 0 if not provided by gadget. */
619
+ cost?: number;
353
620
  }
621
+ /**
622
+ * Result returned by gadget execute() method.
623
+ * Can be a simple string or an object with result and optional cost.
624
+ *
625
+ * @example
626
+ * ```typescript
627
+ * // Simple string return (free gadget)
628
+ * execute: () => "result"
629
+ *
630
+ * // Object return with cost
631
+ * execute: () => ({ result: "data", cost: 0.001 })
632
+ * ```
633
+ */
634
+ interface GadgetExecuteResult {
635
+ /** The execution result as a string */
636
+ result: string;
637
+ /** Optional cost in USD (e.g., 0.001 for $0.001) */
638
+ cost?: number;
639
+ }
640
+ /**
641
+ * Union type for backwards-compatible execute() return type.
642
+ * Gadgets can return either a string (legacy, cost = 0) or
643
+ * an object with result and optional cost.
644
+ */
645
+ type GadgetExecuteReturn = string | GadgetExecuteResult;
354
646
  interface ParsedGadgetCall {
355
647
  gadgetName: string;
356
648
  invocationId: string;
@@ -433,6 +725,174 @@ type TextOnlyAction = {
433
725
  name: string;
434
726
  parameters: Record<string, unknown>;
435
727
  };
728
+ /**
729
+ * LLMist client interface for use within gadgets.
730
+ *
731
+ * Provides LLM completion methods that automatically report costs
732
+ * via the execution context. All LLM calls made through this client
733
+ * will have their costs tracked and included in the gadget's total cost.
734
+ *
735
+ * @example
736
+ * ```typescript
737
+ * execute: async ({ text }, ctx) => {
738
+ * // LLM costs are automatically reported
739
+ * const summary = await ctx.llmist.complete('Summarize: ' + text, {
740
+ * model: 'haiku',
741
+ * });
742
+ * return summary;
743
+ * }
744
+ * ```
745
+ */
746
+ interface CostReportingLLMist {
747
+ /**
748
+ * Quick completion - returns final text response.
749
+ * Costs are automatically reported to the execution context.
750
+ */
751
+ complete(prompt: string, options?: QuickOptions): Promise<string>;
752
+ /**
753
+ * Quick streaming - returns async generator of text chunks.
754
+ * Costs are automatically reported when the stream completes.
755
+ */
756
+ streamText(prompt: string, options?: QuickOptions): AsyncGenerator<string>;
757
+ /**
758
+ * Low-level stream access for full control.
759
+ * Costs are automatically reported based on usage metadata in chunks.
760
+ */
761
+ stream(options: LLMGenerationOptions): LLMStream;
762
+ /**
763
+ * Access to model registry for cost estimation.
764
+ */
765
+ readonly modelRegistry: ModelRegistry;
766
+ }
767
+ /**
768
+ * Execution context provided to gadgets during execution.
769
+ *
770
+ * Contains utilities for cost reporting and LLM access.
771
+ * This parameter is optional for backwards compatibility -
772
+ * existing gadgets without the context parameter continue to work.
773
+ *
774
+ * @example
775
+ * ```typescript
776
+ * // Using reportCost() for manual cost reporting
777
+ * const apiGadget = createGadget({
778
+ * description: 'Calls external API',
779
+ * schema: z.object({ query: z.string() }),
780
+ * execute: async ({ query }, ctx) => {
781
+ * const result = await callExternalAPI(query);
782
+ * ctx.reportCost(0.001); // Report $0.001 cost
783
+ * return result;
784
+ * },
785
+ * });
786
+ *
787
+ * // Using ctx.llmist for automatic LLM cost tracking
788
+ * const summarizer = createGadget({
789
+ * description: 'Summarizes text using LLM',
790
+ * schema: z.object({ text: z.string() }),
791
+ * execute: async ({ text }, ctx) => {
792
+ * // LLM costs are automatically reported!
793
+ * return ctx.llmist.complete('Summarize: ' + text);
794
+ * },
795
+ * });
796
+ * ```
797
+ */
798
+ interface ExecutionContext {
799
+ /**
800
+ * Report a cost incurred during gadget execution.
801
+ *
802
+ * Costs are accumulated and added to the gadget's total cost.
803
+ * Can be called multiple times during execution.
804
+ * This is summed with any cost returned from the execute() method
805
+ * and any costs from ctx.llmist calls.
806
+ *
807
+ * @param amount - Cost in USD (e.g., 0.001 for $0.001)
808
+ *
809
+ * @example
810
+ * ```typescript
811
+ * execute: async (params, ctx) => {
812
+ * await callExternalAPI(params.query);
813
+ * ctx.reportCost(0.001); // $0.001 per API call
814
+ *
815
+ * await callAnotherAPI(params.data);
816
+ * ctx.reportCost(0.002); // Can be called multiple times
817
+ *
818
+ * return 'done';
819
+ * // Total cost: $0.003
820
+ * }
821
+ * ```
822
+ */
823
+ reportCost(amount: number): void;
824
+ /**
825
+ * Pre-configured LLMist client that automatically reports LLM costs
826
+ * as gadget costs via the reportCost() callback.
827
+ *
828
+ * All LLM calls made through this client will have their costs
829
+ * automatically tracked and included in the gadget's total cost.
830
+ *
831
+ * This property is optional - it will be `undefined` if:
832
+ * - The gadget is executed via CLI `gadget run` command
833
+ * - The gadget is tested directly without agent context
834
+ * - No LLMist client was provided to the executor
835
+ *
836
+ * Always check for availability before use: `ctx.llmist?.complete(...)`
837
+ *
838
+ * @example
839
+ * ```typescript
840
+ * execute: async ({ text }, ctx) => {
841
+ * // Check if llmist is available
842
+ * if (!ctx.llmist) {
843
+ * return 'LLM not available in this context';
844
+ * }
845
+ *
846
+ * // LLM costs are automatically reported
847
+ * const summary = await ctx.llmist.complete('Summarize: ' + text, {
848
+ * model: 'haiku',
849
+ * });
850
+ *
851
+ * // Additional manual costs can still be reported
852
+ * ctx.reportCost(0.0001); // Processing overhead
853
+ *
854
+ * return summary;
855
+ * }
856
+ * ```
857
+ */
858
+ llmist?: CostReportingLLMist;
859
+ /**
860
+ * Abort signal for cancellation support.
861
+ *
862
+ * When a gadget times out, this signal is aborted before the TimeoutException
863
+ * is thrown. Gadgets can use this to clean up resources (close browsers,
864
+ * cancel HTTP requests, etc.) when execution is cancelled.
865
+ *
866
+ * The signal is always provided (never undefined) to simplify gadget code.
867
+ *
868
+ * @example
869
+ * ```typescript
870
+ * // Check for abort at key checkpoints
871
+ * execute: async (params, ctx) => {
872
+ * if (ctx.signal.aborted) return 'Aborted';
873
+ *
874
+ * await doExpensiveWork();
875
+ *
876
+ * if (ctx.signal.aborted) return 'Aborted';
877
+ * return result;
878
+ * }
879
+ *
880
+ * // Register cleanup handlers
881
+ * execute: async (params, ctx) => {
882
+ * const browser = await chromium.launch();
883
+ * ctx.signal.addEventListener('abort', () => browser.close(), { once: true });
884
+ * // ... use browser
885
+ * }
886
+ *
887
+ * // Pass to fetch for automatic cancellation
888
+ * execute: async ({ url }, ctx) => {
889
+ * const response = await fetch(url, { signal: ctx.signal });
890
+ * return await response.text();
891
+ * }
892
+ * ```
893
+ */
894
+ signal: AbortSignal;
895
+ }
436
896
 
437
897
  /**
438
898
  * Internal base class for gadgets. Most users should use the `Gadget` class
@@ -477,9 +937,67 @@ declare abstract class BaseGadget {
477
937
  * Can be synchronous or asynchronous.
478
938
  *
479
939
  * @param params - Parameters passed from the LLM
480
- * @returns Result as a string
940
+ * @param ctx - Optional execution context for cost reporting and LLM access
941
+ * @returns Result as a string, or an object with result and optional cost
942
+ *
943
+ * @example
944
+ * ```typescript
945
+ * // Simple string return (free gadget)
946
+ * execute(params) {
947
+ * return "result";
948
+ * }
949
+ *
950
+ * // Object return with cost tracking
951
+ * execute(params) {
952
+ * return { result: "data", cost: 0.001 };
953
+ * }
954
+ *
955
+ * // Using context for callback-based cost reporting
956
+ * execute(params, ctx) {
957
+ * ctx.reportCost(0.001);
958
+ * return "result";
959
+ * }
960
+ *
961
+ * // Using wrapped LLMist for automatic cost tracking
962
+ * async execute(params, ctx) {
963
+ * const summary = await ctx.llmist.complete('Summarize: ' + params.text);
964
+ * return summary;
965
+ * }
966
+ * ```
967
+ */
968
+ abstract execute(params: Record<string, unknown>, ctx?: ExecutionContext): GadgetExecuteReturn | Promise<GadgetExecuteReturn>;
969
+ /**
970
+ * Throws an AbortError if the execution has been aborted.
971
+ *
972
+ * Call this at key checkpoints in long-running gadgets to allow early exit
973
+ * when the gadget has been cancelled (e.g., due to timeout). This enables
974
+ * resource cleanup and prevents unnecessary work after cancellation.
975
+ *
976
+ * @param ctx - The execution context containing the abort signal
977
+ * @throws AbortError if ctx.signal.aborted is true
978
+ *
979
+ * @example
980
+ * ```typescript
981
+ * class DataProcessor extends Gadget({
982
+ * description: 'Processes data in multiple steps',
983
+ * schema: z.object({ items: z.array(z.string()) }),
984
+ * }) {
985
+ * async execute(params: this['params'], ctx?: ExecutionContext): Promise<string> {
986
+ * const results: string[] = [];
987
+ *
988
+ * for (const item of params.items) {
989
+ * // Check before each expensive operation
990
+ * this.throwIfAborted(ctx);
991
+ *
992
+ * results.push(await this.processItem(item));
993
+ * }
994
+ *
995
+ * return results.join(', ');
996
+ * }
997
+ * }
998
+ * ```
481
999
  */
482
- abstract execute(params: Record<string, unknown>): string | Promise<string>;
1000
+ throwIfAborted(ctx?: ExecutionContext): void;
483
1001
  /**
484
1002
  * Auto-generated instruction text for the LLM.
485
1003
  * Combines name, description, and parameter schema into a formatted instruction.
@@ -613,146 +1131,63 @@ declare const DEFAULT_PROMPTS: Required<Omit<PromptConfig, "rules" | "customExam
613
1131
  rules: (context: PromptContext) => string[];
614
1132
  customExamples: null;
615
1133
  }>;
616
- /**
617
- * Resolve a prompt template to a string using the given context.
618
- */
619
- declare function resolvePromptTemplate(template: PromptTemplate | undefined, defaultValue: PromptTemplate, context: PromptContext): string;
620
- /**
621
- * Resolve rules template to an array of strings.
622
- */
623
- declare function resolveRulesTemplate(rules: PromptConfig["rules"] | undefined, context: PromptContext): string[];
624
- /**
625
- * Resolve a hint template to a string using the given context.
626
- * Supports both function templates and string templates with placeholders.
627
- *
628
- * @param template - The hint template to resolve
629
- * @param defaultValue - Default value if template is undefined
630
- * @param context - Context for rendering the template
631
- * @returns The resolved hint string
632
- */
633
- declare function resolveHintTemplate(template: HintTemplate | undefined, defaultValue: string, context: HintContext): string;
634
-
635
- type LLMRole = "system" | "user" | "assistant";
636
- interface LLMMessage {
637
- role: LLMRole;
638
- content: string;
639
- name?: string;
640
- metadata?: Record<string, unknown>;
641
- }
642
- declare class LLMMessageBuilder {
643
- private readonly messages;
644
- private startPrefix;
645
- private endPrefix;
646
- private argPrefix;
647
- private promptConfig;
648
- constructor(promptConfig?: PromptConfig);
649
- /**
650
- * Set custom prefixes for gadget markers.
651
- * Used to configure history builder to match system prompt markers.
652
- */
653
- withPrefixes(startPrefix: string, endPrefix: string, argPrefix?: string): this;
654
- addSystem(content: string, metadata?: Record<string, unknown>): this;
655
- addGadgets(gadgets: BaseGadget[], options?: {
656
- startPrefix?: string;
657
- endPrefix?: string;
658
- argPrefix?: string;
659
- }): this;
660
- private buildGadgetsSection;
661
- private buildUsageSection;
662
- private buildExamplesSection;
663
- private buildRulesSection;
664
- addUser(content: string, metadata?: Record<string, unknown>): this;
665
- addAssistant(content: string, metadata?: Record<string, unknown>): this;
666
- addGadgetCall(gadget: string, parameters: Record<string, unknown>, result: string): this;
667
- /**
668
- * Format parameters as Block format with JSON Pointer paths.
669
- * Uses the configured argPrefix for consistency with system prompt.
670
- */
671
- private formatBlockParameters;
672
- build(): LLMMessage[];
673
- }
674
-
675
- interface LLMGenerationOptions {
676
- model: string;
677
- messages: LLMMessage[];
678
- maxTokens?: number;
679
- temperature?: number;
680
- topP?: number;
681
- stopSequences?: string[];
682
- responseFormat?: "text";
683
- metadata?: Record<string, unknown>;
684
- extra?: Record<string, unknown>;
685
- /**
686
- * Optional abort signal for cancelling the request mid-flight.
687
- *
688
- * When the signal is aborted, the provider will attempt to cancel
689
- * the underlying HTTP request and the stream will terminate with
690
- * an abort error. Use `isAbortError()` from `@/core/errors` to
691
- * detect cancellation in error handling.
692
- *
693
- * @example
694
- * ```typescript
695
- * const controller = new AbortController();
696
- *
697
- * const stream = client.stream({
698
- * model: "claude-3-5-sonnet-20241022",
699
- * messages: [{ role: "user", content: "Tell me a long story" }],
700
- * signal: controller.signal,
701
- * });
702
- *
703
- * // Cancel after 5 seconds
704
- * setTimeout(() => controller.abort(), 5000);
705
- *
706
- * try {
707
- * for await (const chunk of stream) {
708
- * process.stdout.write(chunk.text);
709
- * }
710
- * } catch (error) {
711
- * if (isAbortError(error)) {
712
- * console.log("\nRequest was cancelled");
713
- * } else {
714
- * throw error;
715
- * }
716
- * }
717
- * ```
718
- */
719
- signal?: AbortSignal;
720
- }
721
- interface TokenUsage {
722
- inputTokens: number;
723
- outputTokens: number;
724
- totalTokens: number;
725
- /** Number of input tokens served from cache (subset of inputTokens) */
726
- cachedInputTokens?: number;
727
- /** Number of input tokens written to cache (subset of inputTokens, Anthropic only) */
728
- cacheCreationInputTokens?: number;
1134
+ /**
1135
+ * Resolve a prompt template to a string using the given context.
1136
+ */
1137
+ declare function resolvePromptTemplate(template: PromptTemplate | undefined, defaultValue: PromptTemplate, context: PromptContext): string;
1138
+ /**
1139
+ * Resolve rules template to an array of strings.
1140
+ */
1141
+ declare function resolveRulesTemplate(rules: PromptConfig["rules"] | undefined, context: PromptContext): string[];
1142
+ /**
1143
+ * Resolve a hint template to a string using the given context.
1144
+ * Supports both function templates and string templates with placeholders.
1145
+ *
1146
+ * @param template - The hint template to resolve
1147
+ * @param defaultValue - Default value if template is undefined
1148
+ * @param context - Context for rendering the template
1149
+ * @returns The resolved hint string
1150
+ */
1151
+ declare function resolveHintTemplate(template: HintTemplate | undefined, defaultValue: string, context: HintContext): string;
1152
+
1153
+ type LLMRole = "system" | "user" | "assistant";
1154
+ interface LLMMessage {
1155
+ role: LLMRole;
1156
+ content: string;
1157
+ name?: string;
1158
+ metadata?: Record<string, unknown>;
729
1159
  }
730
- interface LLMStreamChunk {
731
- text: string;
732
- /**
733
- * Indicates that the provider has finished producing output and includes the reason if available.
734
- */
735
- finishReason?: string | null;
1160
+ declare class LLMMessageBuilder {
1161
+ private readonly messages;
1162
+ private startPrefix;
1163
+ private endPrefix;
1164
+ private argPrefix;
1165
+ private promptConfig;
1166
+ constructor(promptConfig?: PromptConfig);
736
1167
  /**
737
- * Token usage information, typically available in the final chunk when the stream completes.
1168
+ * Set custom prefixes for gadget markers.
1169
+ * Used to configure history builder to match system prompt markers.
738
1170
  */
739
- usage?: TokenUsage;
1171
+ withPrefixes(startPrefix: string, endPrefix: string, argPrefix?: string): this;
1172
+ addSystem(content: string, metadata?: Record<string, unknown>): this;
1173
+ addGadgets(gadgets: BaseGadget[], options?: {
1174
+ startPrefix?: string;
1175
+ endPrefix?: string;
1176
+ argPrefix?: string;
1177
+ }): this;
1178
+ private buildGadgetsSection;
1179
+ private buildUsageSection;
1180
+ private buildExamplesSection;
1181
+ private buildRulesSection;
1182
+ addUser(content: string, metadata?: Record<string, unknown>): this;
1183
+ addAssistant(content: string, metadata?: Record<string, unknown>): this;
1184
+ addGadgetCall(gadget: string, parameters: Record<string, unknown>, result: string): this;
740
1185
  /**
741
- * Provider specific payload emitted at the same time as the text chunk. This is useful for debugging and tests.
1186
+ * Format parameters as Block format with JSON Pointer paths.
1187
+ * Uses the configured argPrefix for consistency with system prompt.
742
1188
  */
743
- rawEvent?: unknown;
744
- }
745
- interface LLMStream extends AsyncIterable<LLMStreamChunk> {
746
- }
747
- type ProviderIdentifier = string;
748
- interface ModelDescriptor {
749
- provider: string;
750
- name: string;
751
- }
752
- declare class ModelIdentifierParser {
753
- private readonly defaultProvider;
754
- constructor(defaultProvider?: string);
755
- parse(identifier: string): ModelDescriptor;
1189
+ private formatBlockParameters;
1190
+ build(): LLMMessage[];
756
1191
  }
757
1192
 
758
1193
  interface ProviderAdapter {
@@ -789,188 +1224,6 @@ interface ProviderAdapter {
789
1224
  countTokens?(messages: LLMMessage[], descriptor: ModelDescriptor, spec?: ModelSpec): Promise<number>;
790
1225
  }
791
1226
 
792
- /**
793
- * Model Registry
794
- *
795
- * Centralized registry for querying LLM model specifications,
796
- * validating configurations, and estimating costs.
797
- *
798
- * Model data is provided by ProviderAdapter implementations and
799
- * automatically populated when providers are registered.
800
- */
801
-
802
- declare class ModelRegistry {
803
- private modelSpecs;
804
- private providerMap;
805
- /**
806
- * Register a provider and collect its model specifications
807
- */
808
- registerProvider(provider: ProviderAdapter): void;
809
- /**
810
- * Register a custom model specification at runtime
811
- *
812
- * Use this to add models that aren't in the built-in catalog, such as:
813
- * - Fine-tuned models with custom pricing
814
- * - New models not yet supported by llmist
815
- * - Custom deployments with different configurations
816
- *
817
- * @param spec - Complete model specification
818
- * @throws {Error} If spec is missing required fields
819
- *
820
- * @example
821
- * ```ts
822
- * client.modelRegistry.registerModel({
823
- * provider: "openai",
824
- * modelId: "ft:gpt-4o-2024-08-06:my-org:custom:abc123",
825
- * displayName: "My Fine-tuned GPT-4o",
826
- * contextWindow: 128_000,
827
- * maxOutputTokens: 16_384,
828
- * pricing: { input: 7.5, output: 30.0 },
829
- * knowledgeCutoff: "2024-08",
830
- * features: { streaming: true, functionCalling: true, vision: true }
831
- * });
832
- * ```
833
- */
834
- registerModel(spec: ModelSpec): void;
835
- /**
836
- * Register multiple custom model specifications at once
837
- *
838
- * @param specs - Array of complete model specifications
839
- *
840
- * @example
841
- * ```ts
842
- * client.modelRegistry.registerModels([
843
- * { provider: "openai", modelId: "gpt-5", ... },
844
- * { provider: "openai", modelId: "gpt-5-mini", ... }
845
- * ]);
846
- * ```
847
- */
848
- registerModels(specs: ModelSpec[]): void;
849
- /**
850
- * Get model specification by model ID
851
- * @param modelId - Full model identifier (e.g., 'gpt-5', 'claude-sonnet-4-5-20250929')
852
- * @returns ModelSpec if found, undefined otherwise
853
- */
854
- getModelSpec(modelId: string): ModelSpec | undefined;
855
- /**
856
- * List all models, optionally filtered by provider
857
- * @param providerId - Optional provider ID to filter by (e.g., 'openai', 'anthropic')
858
- * @returns Array of ModelSpec objects
859
- */
860
- listModels(providerId?: string): ModelSpec[];
861
- /**
862
- * Get context window and output limits for a model
863
- * @param modelId - Full model identifier
864
- * @returns ModelLimits if model found, undefined otherwise
865
- */
866
- getModelLimits(modelId: string): ModelLimits | undefined;
867
- /**
868
- * Estimate API cost for a given model and token usage
869
- * @param modelId - Full model identifier
870
- * @param inputTokens - Number of input tokens (total, including cached and cache creation)
871
- * @param outputTokens - Number of output tokens
872
- * @param cachedInputTokens - Number of cached input tokens (subset of inputTokens)
873
- * @param cacheCreationInputTokens - Number of cache creation tokens (subset of inputTokens, Anthropic only)
874
- * @returns CostEstimate if model found, undefined otherwise
875
- */
876
- estimateCost(modelId: string, inputTokens: number, outputTokens: number, cachedInputTokens?: number, cacheCreationInputTokens?: number): CostEstimate | undefined;
877
- /**
878
- * Validate that requested token count fits within model limits
879
- * @param modelId - Full model identifier
880
- * @param requestedTokens - Total tokens requested (input + output)
881
- * @returns true if valid, false if model not found or exceeds limits
882
- */
883
- validateModelConfig(modelId: string, requestedTokens: number): boolean;
884
- /**
885
- * Check if a model supports a specific feature
886
- * @param modelId - Full model identifier
887
- * @param feature - Feature to check ('streaming', 'functionCalling', 'vision', etc.)
888
- * @returns true if model supports feature, false otherwise
889
- */
890
- supportsFeature(modelId: string, feature: keyof ModelSpec["features"]): boolean;
891
- /**
892
- * Get all models that support a specific feature
893
- * @param feature - Feature to filter by
894
- * @param providerId - Optional provider ID to filter by
895
- * @returns Array of ModelSpec objects that support the feature
896
- */
897
- getModelsByFeature(feature: keyof ModelSpec["features"], providerId?: string): ModelSpec[];
898
- /**
899
- * Get the most cost-effective model for a given provider and token budget
900
- * @param inputTokens - Expected input tokens
901
- * @param outputTokens - Expected output tokens
902
- * @param providerId - Optional provider ID to filter by
903
- * @returns ModelSpec with lowest total cost, or undefined if no models found
904
- */
905
- getCheapestModel(inputTokens: number, outputTokens: number, providerId?: string): ModelSpec | undefined;
906
- }
907
-
908
- /**
909
- * Quick execution methods for simple use cases.
910
- *
911
- * These methods provide convenient shortcuts for common operations
912
- * without requiring full agent setup.
913
- *
914
- * @example
915
- * ```typescript
916
- * // Quick completion
917
- * const answer = await llmist.complete("What is 2+2?");
918
- *
919
- * // Quick streaming
920
- * for await (const chunk of llmist.stream("Tell me a story")) {
921
- * process.stdout.write(chunk);
922
- * }
923
- * ```
924
- */
925
-
926
- /**
927
- * Options for quick execution methods.
928
- */
929
- interface QuickOptions {
930
- /** Model to use (supports aliases like "gpt4", "sonnet", "flash") */
931
- model?: string;
932
- /** Temperature (0-1) */
933
- temperature?: number;
934
- /** System prompt */
935
- systemPrompt?: string;
936
- /** Max tokens to generate */
937
- maxTokens?: number;
938
- }
939
- /**
940
- * Quick completion - returns final text response.
941
- *
942
- * @param client - LLMist client instance
943
- * @param prompt - User prompt
944
- * @param options - Optional configuration
945
- * @returns Complete text response
946
- *
947
- * @example
948
- * ```typescript
949
- * const client = new LLMist();
950
- * const answer = await complete(client, "What is 2+2?");
951
- * console.log(answer); // "4" or "2+2 equals 4"
952
- * ```
953
- */
954
- declare function complete(client: LLMist, prompt: string, options?: QuickOptions): Promise<string>;
955
- /**
956
- * Quick streaming - returns async generator of text chunks.
957
- *
958
- * @param client - LLMist client instance
959
- * @param prompt - User prompt
960
- * @param options - Optional configuration
961
- * @returns Async generator yielding text chunks
962
- *
963
- * @example
964
- * ```typescript
965
- * const client = new LLMist();
966
- *
967
- * for await (const chunk of stream(client, "Tell me a story")) {
968
- * process.stdout.write(chunk);
969
- * }
970
- * ```
971
- */
972
- declare function stream(client: LLMist, prompt: string, options?: QuickOptions): AsyncGenerator<string>;
973
-
974
1227
  interface LLMistOptions {
975
1228
  /**
976
1229
  * Provider adapters to register manually.
@@ -1508,6 +1761,8 @@ interface ObserveGadgetCompleteContext {
1508
1761
  error?: string;
1509
1762
  executionTimeMs: number;
1510
1763
  breaksLoop?: boolean;
1764
+ /** Cost of gadget execution in USD. 0 if gadget didn't report cost. */
1765
+ cost?: number;
1511
1766
  logger: Logger<ILogObj>;
1512
1767
  }
1513
1768
  /**
@@ -3264,4 +3519,4 @@ declare function createTextMockStream(text: string, options?: {
3264
3519
  usage?: MockResponse["usage"];
3265
3520
  }): LLMStream;
3266
3521
 
3267
- export { type AfterLLMErrorAction as $, type AgentHooks as A, BaseGadget as B, type CompactionStrategy as C, type ModelDescriptor as D, type ModelSpec as E, type LLMGenerationOptions as F, GadgetRegistry as G, type HintTemplate as H, type IConversationManager as I, type HistoryMessage as J, type TrailingMessage as K, type LLMStream as L, MockProviderAdapter as M, type TrailingMessageContext as N, AgentBuilder as O, type ParsedGadgetCall as P, type EventHandlers as Q, type ResolvedCompactionConfig as R, type StreamEvent as S, type TokenUsage as T, collectEvents as U, collectText as V, runWithHandlers as W, type AfterGadgetExecutionAction as X, type AfterGadgetExecutionControllerContext as Y, type AfterLLMCallAction as Z, type AfterLLMCallControllerContext as _, type LLMStreamChunk as a, type AgentOptions as a0, type BeforeGadgetExecutionAction as a1, type BeforeLLMCallAction as a2, type ChunkInterceptorContext as a3, type Controllers as a4, type GadgetExecutionControllerContext as a5, type GadgetParameterInterceptorContext as a6, type GadgetResultInterceptorContext as a7, type Interceptors as a8, type LLMCallControllerContext as a9, DEFAULT_HINTS as aA, DEFAULT_PROMPTS as aB, resolveHintTemplate as aC, resolvePromptTemplate as aD, resolveRulesTemplate as aE, type QuickOptions as aF, complete as aG, stream as aH, type GadgetClass as aI, type GadgetOrClass as aJ, type TextOnlyAction as aK, type TextOnlyContext as aL, type TextOnlyCustomHandler as aM, type TextOnlyGadgetConfig as aN, type TextOnlyHandler as aO, type TextOnlyStrategy as aP, type LLMErrorControllerContext as aa, type MessageInterceptorContext as ab, type ObserveChunkContext as ac, type ObserveGadgetCompleteContext as ad, type ObserveGadgetStartContext as ae, type ObserveLLMCallContext as af, type ObserveLLMCompleteContext as ag, type ObserveLLMErrorContext as ah, type Observers as ai, type MessageTurn as aj, type ObserveCompactionContext as ak, DEFAULT_COMPACTION_CONFIG as al, DEFAULT_SUMMARIZATION_PROMPT as am, type LLMistOptions as an, type LLMRole as ao, LLMMessageBuilder as ap, type CostEstimate as aq, type ModelFeatures as ar, type ModelLimits as as, type ModelPricing as at, type ProviderIdentifier as au, ModelIdentifierParser as av, type HintContext as aw, type PromptConfig as ax, type PromptContext as ay, type PromptTemplate as az, type LLMMessage as b, createMockAdapter as c, MockBuilder as d, createMockClient as e, MockManager as f, getMockManager as g, createMockStream as h, createTextMockStream as i, type MockMatcher as j, type MockMatcherContext as k, type MockOptions as l, mockLLM as m, type MockRegistration as n, type MockResponse as o, type MockStats as p, ModelRegistry as q, type CompactionContext as r, type CompactionResult as s, LLMist as t, type CompactionConfig as u, type CompactionEvent as v, type CompactionStats as w, type GadgetExample as x, type GadgetExecutionResult as y, type ProviderAdapter as z };
3522
+ export { type AfterLLMCallAction as $, type AgentHooks as A, BaseGadget as B, type CompactionStrategy as C, type ProviderAdapter as D, type ExecutionContext as E, type ModelDescriptor as F, GadgetRegistry as G, type HintTemplate as H, type IConversationManager as I, type ModelSpec as J, type LLMGenerationOptions as K, type LLMStream as L, MockProviderAdapter as M, type HistoryMessage as N, type TrailingMessage as O, type ParsedGadgetCall as P, type TrailingMessageContext as Q, type ResolvedCompactionConfig as R, type StreamEvent as S, type TokenUsage as T, AgentBuilder as U, type EventHandlers as V, collectEvents as W, collectText as X, runWithHandlers as Y, type AfterGadgetExecutionAction as Z, type AfterGadgetExecutionControllerContext as _, type LLMStreamChunk as a, type AfterLLMCallControllerContext as a0, type AfterLLMErrorAction as a1, type AgentOptions as a2, type BeforeGadgetExecutionAction as a3, type BeforeLLMCallAction as a4, type ChunkInterceptorContext as a5, type Controllers as a6, type GadgetExecutionControllerContext as a7, type GadgetParameterInterceptorContext as a8, type GadgetResultInterceptorContext as a9, type PromptContext as aA, type PromptTemplate as aB, DEFAULT_HINTS as aC, DEFAULT_PROMPTS as aD, resolveHintTemplate as aE, resolvePromptTemplate as aF, resolveRulesTemplate as aG, type QuickOptions as aH, complete as aI, stream as aJ, type GadgetClass as aK, type GadgetOrClass as aL, type CostReportingLLMist as aM, type GadgetExecuteResult as aN, type TextOnlyAction as aO, type TextOnlyContext as aP, type TextOnlyCustomHandler as aQ, type TextOnlyGadgetConfig as aR, type TextOnlyHandler as aS, type TextOnlyStrategy as aT, type Interceptors as aa, type LLMCallControllerContext as ab, type LLMErrorControllerContext as ac, type MessageInterceptorContext as ad, type ObserveChunkContext as ae, type ObserveGadgetCompleteContext as af, type ObserveGadgetStartContext as ag, type ObserveLLMCallContext as ah, type ObserveLLMCompleteContext as ai, type ObserveLLMErrorContext as aj, type Observers as ak, type MessageTurn as al, type ObserveCompactionContext as am, DEFAULT_COMPACTION_CONFIG as an, DEFAULT_SUMMARIZATION_PROMPT as ao, type LLMistOptions as ap, type LLMRole as aq, LLMMessageBuilder as ar, type CostEstimate as as, type ModelFeatures as at, type ModelLimits as au, type ModelPricing as av, type ProviderIdentifier as aw, ModelIdentifierParser as ax, type HintContext as ay, type PromptConfig as az, type LLMMessage as b, createMockAdapter as c, MockBuilder as d, createMockClient as e, MockManager as f, getMockManager as g, createMockStream as h, createTextMockStream as i, type MockMatcher as j, type MockMatcherContext as k, type MockOptions as l, mockLLM as m, type MockRegistration as n, type MockResponse as o, type MockStats as p, ModelRegistry as q, LLMist as r, type CompactionContext as s, type CompactionResult as t, type CompactionConfig as u, type CompactionEvent as v, type CompactionStats as w, type GadgetExecuteReturn as x, type GadgetExample as y, type GadgetExecutionResult as z };