llmist 0.3.1 → 0.4.1
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/{chunk-VRTKJK2X.js → chunk-A4GRCCXF.js} +2 -2
- package/dist/{chunk-VYBRYR2S.js → chunk-LQE7TKKW.js} +43 -38
- package/dist/chunk-LQE7TKKW.js.map +1 -0
- package/dist/{chunk-I55AV3WV.js → chunk-QVDGTUQN.js} +2 -2
- package/dist/cli.cjs +186 -148
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +146 -113
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +225 -37
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +227 -6
- package/dist/index.d.ts +227 -6
- package/dist/index.js +186 -3
- package/dist/index.js.map +1 -1
- package/dist/{mock-stream-C2sBQlvc.d.cts → mock-stream-C0vOqI3L.d.cts} +1 -1
- package/dist/{mock-stream-C2sBQlvc.d.ts → mock-stream-C0vOqI3L.d.ts} +1 -1
- package/dist/testing/index.cjs +42 -37
- package/dist/testing/index.cjs.map +1 -1
- package/dist/testing/index.d.cts +2 -2
- package/dist/testing/index.d.ts +2 -2
- package/dist/testing/index.js +2 -2
- package/package.json +1 -1
- package/dist/chunk-VYBRYR2S.js.map +0 -1
- /package/dist/{chunk-VRTKJK2X.js.map → chunk-A4GRCCXF.js.map} +0 -0
- /package/dist/{chunk-I55AV3WV.js.map → chunk-QVDGTUQN.js.map} +0 -0
package/dist/index.cjs
CHANGED
|
@@ -2791,10 +2791,11 @@ var init_gemini = __esm({
|
|
|
2791
2791
|
return GEMINI_MODELS;
|
|
2792
2792
|
}
|
|
2793
2793
|
buildRequestPayload(options, descriptor, _spec, messages) {
|
|
2794
|
-
const
|
|
2794
|
+
const contents = this.convertMessagesToContents(messages);
|
|
2795
2795
|
const generationConfig = this.buildGenerationConfig(options);
|
|
2796
2796
|
const config = {
|
|
2797
|
-
|
|
2797
|
+
// Note: systemInstruction removed - it doesn't work with countTokens()
|
|
2798
|
+
// System messages are now included in contents as user+model exchanges
|
|
2798
2799
|
...generationConfig ? { ...generationConfig } : {},
|
|
2799
2800
|
// Explicitly disable function calling to prevent UNEXPECTED_TOOL_CALL errors
|
|
2800
2801
|
toolConfig: {
|
|
@@ -2815,31 +2816,37 @@ var init_gemini = __esm({
|
|
|
2815
2816
|
const streamResponse = await client.models.generateContentStream(payload);
|
|
2816
2817
|
return streamResponse;
|
|
2817
2818
|
}
|
|
2818
|
-
|
|
2819
|
-
|
|
2820
|
-
|
|
2821
|
-
|
|
2822
|
-
|
|
2823
|
-
|
|
2824
|
-
|
|
2825
|
-
|
|
2826
|
-
|
|
2827
|
-
|
|
2828
|
-
|
|
2819
|
+
/**
|
|
2820
|
+
* Convert LLM messages to Gemini contents format.
|
|
2821
|
+
*
|
|
2822
|
+
* For Gemini, we convert system messages to user+model exchanges instead of
|
|
2823
|
+
* using systemInstruction, because:
|
|
2824
|
+
* 1. systemInstruction doesn't work with countTokens() API
|
|
2825
|
+
* 2. This approach gives perfect token counting accuracy (0% error)
|
|
2826
|
+
* 3. The model receives and follows system instructions identically
|
|
2827
|
+
*
|
|
2828
|
+
* System message: "You are a helpful assistant"
|
|
2829
|
+
* Becomes:
|
|
2830
|
+
* - User: "You are a helpful assistant"
|
|
2831
|
+
* - Model: "Understood."
|
|
2832
|
+
*/
|
|
2833
|
+
convertMessagesToContents(messages) {
|
|
2834
|
+
const expandedMessages = [];
|
|
2835
|
+
for (const message of messages) {
|
|
2836
|
+
if (message.role === "system") {
|
|
2837
|
+
expandedMessages.push({
|
|
2838
|
+
role: "user",
|
|
2839
|
+
content: message.content
|
|
2840
|
+
});
|
|
2841
|
+
expandedMessages.push({
|
|
2842
|
+
role: "assistant",
|
|
2843
|
+
content: "Understood."
|
|
2844
|
+
});
|
|
2845
|
+
} else {
|
|
2846
|
+
expandedMessages.push(message);
|
|
2847
|
+
}
|
|
2829
2848
|
}
|
|
2830
|
-
|
|
2831
|
-
const nonSystemMessages = [
|
|
2832
|
-
...messages.slice(0, firstSystemIndex),
|
|
2833
|
-
...messages.slice(systemBlockEnd)
|
|
2834
|
-
];
|
|
2835
|
-
const systemInstruction = {
|
|
2836
|
-
role: "system",
|
|
2837
|
-
parts: systemMessages.map((message) => ({ text: message.content }))
|
|
2838
|
-
};
|
|
2839
|
-
return {
|
|
2840
|
-
systemInstruction,
|
|
2841
|
-
contents: this.mergeConsecutiveMessages(nonSystemMessages)
|
|
2842
|
-
};
|
|
2849
|
+
return this.mergeConsecutiveMessages(expandedMessages);
|
|
2843
2850
|
}
|
|
2844
2851
|
mergeConsecutiveMessages(messages) {
|
|
2845
2852
|
if (messages.length === 0) {
|
|
@@ -2928,8 +2935,8 @@ var init_gemini = __esm({
|
|
|
2928
2935
|
*
|
|
2929
2936
|
* This method provides accurate token estimation for Gemini models by:
|
|
2930
2937
|
* - Using the SDK's countTokens() method
|
|
2931
|
-
* -
|
|
2932
|
-
* -
|
|
2938
|
+
* - Converting system messages to user+model exchanges (same as in generation)
|
|
2939
|
+
* - This gives perfect token counting accuracy (0% error vs actual usage)
|
|
2933
2940
|
*
|
|
2934
2941
|
* @param messages - The messages to count tokens for
|
|
2935
2942
|
* @param descriptor - Model descriptor containing the model name
|
|
@@ -2948,16 +2955,14 @@ var init_gemini = __esm({
|
|
|
2948
2955
|
*/
|
|
2949
2956
|
async countTokens(messages, descriptor, _spec) {
|
|
2950
2957
|
const client = this.client;
|
|
2951
|
-
const
|
|
2952
|
-
const request = {
|
|
2953
|
-
model: descriptor.name,
|
|
2954
|
-
contents: this.convertContentsForNewSDK(contents)
|
|
2955
|
-
};
|
|
2956
|
-
if (systemInstruction) {
|
|
2957
|
-
request.systemInstruction = systemInstruction.parts.map((p) => p.text).join("\n");
|
|
2958
|
-
}
|
|
2958
|
+
const contents = this.convertMessagesToContents(messages);
|
|
2959
2959
|
try {
|
|
2960
|
-
const response = await client.models.countTokens(
|
|
2960
|
+
const response = await client.models.countTokens({
|
|
2961
|
+
model: descriptor.name,
|
|
2962
|
+
contents: this.convertContentsForNewSDK(contents)
|
|
2963
|
+
// Note: systemInstruction not used - it's not supported by countTokens()
|
|
2964
|
+
// and would cause a 2100% token counting error
|
|
2965
|
+
});
|
|
2961
2966
|
return response.totalTokens ?? 0;
|
|
2962
2967
|
} catch (error) {
|
|
2963
2968
|
console.warn(
|
|
@@ -4604,6 +4609,189 @@ var HookPresets = class _HookPresets {
|
|
|
4604
4609
|
}
|
|
4605
4610
|
};
|
|
4606
4611
|
}
|
|
4612
|
+
/**
|
|
4613
|
+
* Tracks comprehensive progress metrics including iterations, tokens, cost, and timing.
|
|
4614
|
+
*
|
|
4615
|
+
* **This preset showcases llmist's core capabilities by demonstrating:**
|
|
4616
|
+
* - Observer pattern for non-intrusive monitoring
|
|
4617
|
+
* - Integration with ModelRegistry for cost estimation
|
|
4618
|
+
* - Callback-based architecture for flexible UI updates
|
|
4619
|
+
* - Provider-agnostic token and cost tracking
|
|
4620
|
+
*
|
|
4621
|
+
* Unlike `tokenTracking()` which only logs to console, this preset provides
|
|
4622
|
+
* structured data through callbacks, making it perfect for building custom UIs,
|
|
4623
|
+
* dashboards, or progress indicators (like the llmist CLI).
|
|
4624
|
+
*
|
|
4625
|
+
* **Output (when logProgress: true):**
|
|
4626
|
+
* - Iteration number and call count
|
|
4627
|
+
* - Cumulative token usage (input + output)
|
|
4628
|
+
* - Cumulative cost in USD (requires modelRegistry)
|
|
4629
|
+
* - Elapsed time in seconds
|
|
4630
|
+
*
|
|
4631
|
+
* **Use cases:**
|
|
4632
|
+
* - Building CLI progress indicators with live updates
|
|
4633
|
+
* - Creating web dashboards with real-time metrics
|
|
4634
|
+
* - Budget monitoring and cost alerts
|
|
4635
|
+
* - Performance tracking and optimization
|
|
4636
|
+
* - Custom logging to external systems (Datadog, CloudWatch, etc.)
|
|
4637
|
+
*
|
|
4638
|
+
* **Performance:** Minimal overhead. Uses Date.now() for timing and optional
|
|
4639
|
+
* ModelRegistry.estimateCost() which is O(1) lookup. Callback invocation is
|
|
4640
|
+
* synchronous and fast.
|
|
4641
|
+
*
|
|
4642
|
+
* @param options - Progress tracking options
|
|
4643
|
+
* @param options.modelRegistry - ModelRegistry for cost estimation (optional)
|
|
4644
|
+
* @param options.onProgress - Callback invoked after each LLM call (optional)
|
|
4645
|
+
* @param options.logProgress - Log progress to console (default: false)
|
|
4646
|
+
* @returns Hook configuration with progress tracking observers
|
|
4647
|
+
*
|
|
4648
|
+
* @example
|
|
4649
|
+
* ```typescript
|
|
4650
|
+
* // Basic usage with callback (RECOMMENDED - used by llmist CLI)
|
|
4651
|
+
* import { LLMist, HookPresets } from 'llmist';
|
|
4652
|
+
*
|
|
4653
|
+
* const client = LLMist.create();
|
|
4654
|
+
*
|
|
4655
|
+
* await client.agent()
|
|
4656
|
+
* .withHooks(HookPresets.progressTracking({
|
|
4657
|
+
* modelRegistry: client.modelRegistry,
|
|
4658
|
+
* onProgress: (stats) => {
|
|
4659
|
+
* // Update your UI with stats
|
|
4660
|
+
* console.log(`#${stats.currentIteration} | ${stats.totalTokens} tokens | $${stats.totalCost.toFixed(4)}`);
|
|
4661
|
+
* }
|
|
4662
|
+
* }))
|
|
4663
|
+
* .withGadgets(Calculator)
|
|
4664
|
+
* .ask("Calculate 15 * 23");
|
|
4665
|
+
* // Output: #1 | 245 tokens | $0.0012
|
|
4666
|
+
* ```
|
|
4667
|
+
*
|
|
4668
|
+
* @example
|
|
4669
|
+
* ```typescript
|
|
4670
|
+
* // Console logging mode (quick debugging)
|
|
4671
|
+
* await client.agent()
|
|
4672
|
+
* .withHooks(HookPresets.progressTracking({
|
|
4673
|
+
* modelRegistry: client.modelRegistry,
|
|
4674
|
+
* logProgress: true // Simple console output
|
|
4675
|
+
* }))
|
|
4676
|
+
* .ask("Your prompt");
|
|
4677
|
+
* // Output: 📊 Progress: Iteration #1 | 245 tokens | $0.0012 | 1.2s
|
|
4678
|
+
* ```
|
|
4679
|
+
*
|
|
4680
|
+
* @example
|
|
4681
|
+
* ```typescript
|
|
4682
|
+
* // Budget monitoring with alerts
|
|
4683
|
+
* const BUDGET_USD = 0.10;
|
|
4684
|
+
*
|
|
4685
|
+
* await client.agent()
|
|
4686
|
+
* .withHooks(HookPresets.progressTracking({
|
|
4687
|
+
* modelRegistry: client.modelRegistry,
|
|
4688
|
+
* onProgress: (stats) => {
|
|
4689
|
+
* if (stats.totalCost > BUDGET_USD) {
|
|
4690
|
+
* throw new Error(`Budget exceeded: $${stats.totalCost.toFixed(4)}`);
|
|
4691
|
+
* }
|
|
4692
|
+
* }
|
|
4693
|
+
* }))
|
|
4694
|
+
* .ask("Long running task...");
|
|
4695
|
+
* ```
|
|
4696
|
+
*
|
|
4697
|
+
* @example
|
|
4698
|
+
* ```typescript
|
|
4699
|
+
* // Web dashboard integration
|
|
4700
|
+
* let progressBar: HTMLElement;
|
|
4701
|
+
*
|
|
4702
|
+
* await client.agent()
|
|
4703
|
+
* .withHooks(HookPresets.progressTracking({
|
|
4704
|
+
* modelRegistry: client.modelRegistry,
|
|
4705
|
+
* onProgress: (stats) => {
|
|
4706
|
+
* // Update web UI in real-time
|
|
4707
|
+
* progressBar.textContent = `Iteration ${stats.currentIteration}`;
|
|
4708
|
+
* progressBar.dataset.cost = stats.totalCost.toFixed(4);
|
|
4709
|
+
* progressBar.dataset.tokens = stats.totalTokens.toString();
|
|
4710
|
+
* }
|
|
4711
|
+
* }))
|
|
4712
|
+
* .ask("Your prompt");
|
|
4713
|
+
* ```
|
|
4714
|
+
*
|
|
4715
|
+
* @example
|
|
4716
|
+
* ```typescript
|
|
4717
|
+
* // External logging (Datadog, CloudWatch, etc.)
|
|
4718
|
+
* await client.agent()
|
|
4719
|
+
* .withHooks(HookPresets.progressTracking({
|
|
4720
|
+
* modelRegistry: client.modelRegistry,
|
|
4721
|
+
* onProgress: async (stats) => {
|
|
4722
|
+
* await metrics.gauge('llm.iteration', stats.currentIteration);
|
|
4723
|
+
* await metrics.gauge('llm.cost', stats.totalCost);
|
|
4724
|
+
* await metrics.gauge('llm.tokens', stats.totalTokens);
|
|
4725
|
+
* }
|
|
4726
|
+
* }))
|
|
4727
|
+
* .ask("Your prompt");
|
|
4728
|
+
* ```
|
|
4729
|
+
*
|
|
4730
|
+
* @see {@link https://github.com/zbigniewsobiecki/llmist/blob/main/docs/HOOKS.md#hookpresetsprogresstrackingoptions | Full documentation}
|
|
4731
|
+
* @see {@link ProgressTrackingOptions} for detailed options
|
|
4732
|
+
* @see {@link ProgressStats} for the callback data structure
|
|
4733
|
+
*/
|
|
4734
|
+
static progressTracking(options) {
|
|
4735
|
+
const { modelRegistry, onProgress, logProgress = false } = options ?? {};
|
|
4736
|
+
let totalCalls = 0;
|
|
4737
|
+
let currentIteration = 0;
|
|
4738
|
+
let totalInputTokens = 0;
|
|
4739
|
+
let totalOutputTokens = 0;
|
|
4740
|
+
let totalCost = 0;
|
|
4741
|
+
const startTime = Date.now();
|
|
4742
|
+
return {
|
|
4743
|
+
observers: {
|
|
4744
|
+
// Track iteration on each LLM call start
|
|
4745
|
+
onLLMCallStart: async (ctx) => {
|
|
4746
|
+
currentIteration++;
|
|
4747
|
+
},
|
|
4748
|
+
// Accumulate metrics and report progress on each LLM call completion
|
|
4749
|
+
onLLMCallComplete: async (ctx) => {
|
|
4750
|
+
totalCalls++;
|
|
4751
|
+
if (ctx.usage) {
|
|
4752
|
+
totalInputTokens += ctx.usage.inputTokens;
|
|
4753
|
+
totalOutputTokens += ctx.usage.outputTokens;
|
|
4754
|
+
if (modelRegistry) {
|
|
4755
|
+
try {
|
|
4756
|
+
const modelName = ctx.options.model.includes(":") ? ctx.options.model.split(":")[1] : ctx.options.model;
|
|
4757
|
+
const costEstimate = modelRegistry.estimateCost(
|
|
4758
|
+
modelName,
|
|
4759
|
+
ctx.usage.inputTokens,
|
|
4760
|
+
ctx.usage.outputTokens
|
|
4761
|
+
);
|
|
4762
|
+
if (costEstimate) {
|
|
4763
|
+
totalCost += costEstimate.totalCost;
|
|
4764
|
+
}
|
|
4765
|
+
} catch (error) {
|
|
4766
|
+
if (logProgress) {
|
|
4767
|
+
console.warn(`\u26A0\uFE0F Cost estimation failed:`, error);
|
|
4768
|
+
}
|
|
4769
|
+
}
|
|
4770
|
+
}
|
|
4771
|
+
}
|
|
4772
|
+
const stats = {
|
|
4773
|
+
currentIteration,
|
|
4774
|
+
totalCalls,
|
|
4775
|
+
totalInputTokens,
|
|
4776
|
+
totalOutputTokens,
|
|
4777
|
+
totalTokens: totalInputTokens + totalOutputTokens,
|
|
4778
|
+
totalCost,
|
|
4779
|
+
elapsedSeconds: Number(((Date.now() - startTime) / 1e3).toFixed(1))
|
|
4780
|
+
};
|
|
4781
|
+
if (onProgress) {
|
|
4782
|
+
onProgress(stats);
|
|
4783
|
+
}
|
|
4784
|
+
if (logProgress) {
|
|
4785
|
+
const formattedTokens = stats.totalTokens >= 1e3 ? `${(stats.totalTokens / 1e3).toFixed(1)}k` : `${stats.totalTokens}`;
|
|
4786
|
+
const formattedCost = stats.totalCost > 0 ? `$${stats.totalCost.toFixed(4)}` : "$0";
|
|
4787
|
+
console.log(
|
|
4788
|
+
`\u{1F4CA} Progress: Iteration #${stats.currentIteration} | ${formattedTokens} tokens | ${formattedCost} | ${stats.elapsedSeconds}s`
|
|
4789
|
+
);
|
|
4790
|
+
}
|
|
4791
|
+
}
|
|
4792
|
+
}
|
|
4793
|
+
};
|
|
4794
|
+
}
|
|
4607
4795
|
/**
|
|
4608
4796
|
* Logs detailed error information for debugging and troubleshooting.
|
|
4609
4797
|
*
|