llmist 0.1.3 → 0.1.5
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/README.md +67 -12
- package/dist/{chunk-TP7HE3MN.js → chunk-J3NCIWMY.js} +34 -36
- package/dist/chunk-J3NCIWMY.js.map +1 -0
- package/dist/{chunk-JEBGLCDW.js → chunk-MO5ONHPZ.js} +2 -2
- package/dist/{chunk-DCW33WV7.js → chunk-PVHHXDCV.js} +2 -2
- package/dist/cli.cjs +161 -92
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +130 -59
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +368 -75
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +376 -50
- package/dist/index.d.ts +376 -50
- package/dist/index.js +338 -43
- package/dist/index.js.map +1 -1
- package/dist/{mock-stream-D4erlo7B.d.cts → mock-stream-C2sBQlvc.d.cts} +1 -2
- package/dist/{mock-stream-D4erlo7B.d.ts → mock-stream-C2sBQlvc.d.ts} +1 -2
- package/dist/testing/index.cjs +33 -35
- 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 +2 -2
- package/dist/chunk-TP7HE3MN.js.map +0 -1
- /package/dist/{chunk-JEBGLCDW.js.map → chunk-MO5ONHPZ.js.map} +0 -0
- /package/dist/{chunk-DCW33WV7.js.map → chunk-PVHHXDCV.js.map} +0 -0
package/README.md
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
# llmist
|
|
2
2
|
|
|
3
3
|
[](https://github.com/zbigniewsobiecki/llmist/actions/workflows/ci.yml)
|
|
4
|
-
[](https://codecov.io/gh/zbigniewsobiecki/llmist)
|
|
5
|
+
[](https://www.npmjs.com/package/llmist)
|
|
6
6
|
[](https://opensource.org/licenses/MIT)
|
|
7
7
|
|
|
8
8
|
> **Universal TypeScript LLM client with streaming-first tool execution and simple, extensible agent framework**
|
|
9
9
|
|
|
10
|
+
> **⚠️ EARLY WORK IN PROGRESS** - This library is under active development. APIs may change without notice. Use in production at your own risk.
|
|
11
|
+
|
|
10
12
|
llmist is an asynchonous, streaming-first, provider-agnostic LLM client that makes it easy to build AI agents with **any model**—no structured outputs or native tool calling required. Switch between OpenAI, Anthropic, and Gemini without changing your code, plug into any part of the Agent workflow, have tools (Gadgets) triggered while still streaming.
|
|
11
13
|
|
|
12
14
|
---
|
|
@@ -19,7 +21,6 @@ llmist is an asynchonous, streaming-first, provider-agnostic LLM client that mak
|
|
|
19
21
|
- **🪝 Powerful Hooks** - Monitor, customize, and control every step of execution
|
|
20
22
|
- **🎨 Beautiful API** - Fluent builder pattern with model shortcuts and presets
|
|
21
23
|
- **🧪 Testing-Friendly** - Built-in mocking system for zero-cost testing
|
|
22
|
-
- **🤖 Soon-to-be Production-Ready** - Timeouts, error recovery, human-in-the-loop, structured logging
|
|
23
24
|
|
|
24
25
|
---
|
|
25
26
|
|
|
@@ -152,31 +153,85 @@ const calculator = createGadget({
|
|
|
152
153
|
|
|
153
154
|
### 🪝 Lifecycle Hooks
|
|
154
155
|
|
|
156
|
+
Monitor, transform, and control agent execution with ready-to-use presets or custom hooks:
|
|
157
|
+
|
|
158
|
+
**Quick start with presets:**
|
|
159
|
+
|
|
160
|
+
```typescript
|
|
161
|
+
import { LLMist, HookPresets } from 'llmist';
|
|
162
|
+
|
|
163
|
+
// Full monitoring suite (recommended for development)
|
|
164
|
+
await LLMist.createAgent()
|
|
165
|
+
.withHooks(HookPresets.monitoring())
|
|
166
|
+
.ask('Your prompt');
|
|
167
|
+
// Output: Logs + timing + token tracking + error logging
|
|
168
|
+
|
|
169
|
+
// Combine specific presets for focused monitoring
|
|
170
|
+
await LLMist.createAgent()
|
|
171
|
+
.withHooks(HookPresets.merge(
|
|
172
|
+
HookPresets.timing(),
|
|
173
|
+
HookPresets.tokenTracking()
|
|
174
|
+
))
|
|
175
|
+
.ask('Your prompt');
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
**Available presets:**
|
|
179
|
+
- `logging()` / `logging({ verbose: true })` - Event logging with optional details
|
|
180
|
+
- `timing()` - Execution time measurements
|
|
181
|
+
- `tokenTracking()` - Cumulative token usage and cost tracking
|
|
182
|
+
- `errorLogging()` - Detailed error information
|
|
183
|
+
- `silent()` - No output (for testing)
|
|
184
|
+
- `monitoring()` - All-in-one preset combining logging, timing, tokens, and errors
|
|
185
|
+
- `merge()` - Combine multiple presets or add custom hooks
|
|
186
|
+
|
|
187
|
+
**Production vs Development patterns:**
|
|
188
|
+
|
|
155
189
|
```typescript
|
|
156
|
-
|
|
190
|
+
// Environment-based configuration
|
|
191
|
+
const isDev = process.env.NODE_ENV === 'development';
|
|
192
|
+
const hooks = isDev
|
|
193
|
+
? HookPresets.monitoring({ verbose: true }) // Full visibility in dev
|
|
194
|
+
: HookPresets.merge(
|
|
195
|
+
HookPresets.errorLogging(), // Only errors in prod
|
|
196
|
+
HookPresets.tokenTracking() // Track costs
|
|
197
|
+
);
|
|
157
198
|
|
|
158
|
-
// Use presets for instant monitoring
|
|
159
199
|
await LLMist.createAgent()
|
|
160
|
-
.withHooks(
|
|
200
|
+
.withHooks(hooks)
|
|
161
201
|
.ask('Your prompt');
|
|
202
|
+
```
|
|
162
203
|
|
|
163
|
-
|
|
164
|
-
.withHooks(HookPresets.merge(
|
|
165
|
-
HookPresets.timing(),
|
|
166
|
-
HookPresets.tokenTracking()
|
|
167
|
-
))
|
|
204
|
+
**Custom hooks for advanced control:**
|
|
168
205
|
|
|
169
|
-
|
|
206
|
+
```typescript
|
|
207
|
+
// Observers: read-only monitoring
|
|
170
208
|
.withHooks({
|
|
171
209
|
observers: {
|
|
172
210
|
onLLMCallComplete: async (ctx) => {
|
|
173
211
|
console.log(`Used ${ctx.usage?.totalTokens} tokens`);
|
|
212
|
+
await sendMetricsToDataDog(ctx);
|
|
174
213
|
},
|
|
175
214
|
},
|
|
215
|
+
})
|
|
216
|
+
|
|
217
|
+
// Interceptors: transform data in flight
|
|
218
|
+
.withHooks({
|
|
176
219
|
interceptors: {
|
|
177
220
|
interceptTextChunk: (chunk) => chunk.toUpperCase(),
|
|
178
221
|
},
|
|
179
222
|
})
|
|
223
|
+
|
|
224
|
+
// Controllers: control execution flow
|
|
225
|
+
.withHooks({
|
|
226
|
+
controllers: {
|
|
227
|
+
beforeLLMCall: async (ctx) => {
|
|
228
|
+
if (shouldCache(ctx)) {
|
|
229
|
+
return { action: 'skip', syntheticResponse: cachedResponse };
|
|
230
|
+
}
|
|
231
|
+
return { action: 'proceed' };
|
|
232
|
+
},
|
|
233
|
+
},
|
|
234
|
+
})
|
|
180
235
|
```
|
|
181
236
|
|
|
182
237
|
📖 **[Hooks Guide](./docs/HOOKS.md)** | **[Examples](./examples/03-hooks.ts)**
|
|
@@ -424,14 +424,15 @@ var init_messages = __esm({
|
|
|
424
424
|
context
|
|
425
425
|
);
|
|
426
426
|
parts.push(mainInstruction);
|
|
427
|
-
parts.push(this.
|
|
427
|
+
parts.push(this.buildGadgetsSection(gadgets, parameterFormat));
|
|
428
428
|
parts.push(this.buildUsageSection(parameterFormat, context));
|
|
429
429
|
this.messages.push({ role: "system", content: parts.join("") });
|
|
430
430
|
return this;
|
|
431
431
|
}
|
|
432
|
-
|
|
432
|
+
buildGadgetsSection(gadgets, parameterFormat) {
|
|
433
433
|
const parts = [];
|
|
434
|
-
parts.push("
|
|
434
|
+
parts.push("\n\nAVAILABLE GADGETS");
|
|
435
|
+
parts.push("\n=================\n");
|
|
435
436
|
for (const gadget of gadgets) {
|
|
436
437
|
const gadgetName = gadget.name ?? gadget.constructor.name;
|
|
437
438
|
const instruction = gadget.getInstruction(parameterFormat);
|
|
@@ -439,18 +440,17 @@ var init_messages = __esm({
|
|
|
439
440
|
const schemaIndex = instruction.indexOf(schemaMarker);
|
|
440
441
|
const description = (schemaIndex !== -1 ? instruction.substring(0, schemaIndex) : instruction).trim();
|
|
441
442
|
const schema = schemaIndex !== -1 ? instruction.substring(schemaIndex + schemaMarker.length).trim() : "";
|
|
442
|
-
parts.push("\n <gadget>");
|
|
443
443
|
parts.push(`
|
|
444
|
-
|
|
444
|
+
GADGET: ${gadgetName}`);
|
|
445
445
|
parts.push(`
|
|
446
|
-
|
|
446
|
+
${description}`);
|
|
447
447
|
if (schema) {
|
|
448
448
|
parts.push(`
|
|
449
|
-
|
|
450
|
-
${
|
|
451
|
-
|
|
449
|
+
|
|
450
|
+
PARAMETERS (${parameterFormat.toUpperCase()}):
|
|
451
|
+
${schema}`);
|
|
452
452
|
}
|
|
453
|
-
parts.push("\n
|
|
453
|
+
parts.push("\n\n---");
|
|
454
454
|
}
|
|
455
455
|
return parts.join("");
|
|
456
456
|
}
|
|
@@ -465,26 +465,26 @@ ${schema}
|
|
|
465
465
|
DEFAULT_PROMPTS.formatDescriptionJson,
|
|
466
466
|
context
|
|
467
467
|
);
|
|
468
|
-
parts.push("
|
|
468
|
+
parts.push("\n\nHOW TO INVOKE GADGETS");
|
|
469
|
+
parts.push("\n=====================\n");
|
|
469
470
|
const criticalUsage = resolvePromptTemplate(
|
|
470
471
|
this.promptConfig.criticalUsage,
|
|
471
472
|
DEFAULT_PROMPTS.criticalUsage,
|
|
472
473
|
context
|
|
473
474
|
);
|
|
474
475
|
parts.push(`
|
|
475
|
-
|
|
476
|
-
|
|
476
|
+
CRITICAL: ${criticalUsage}
|
|
477
|
+
`);
|
|
478
|
+
parts.push("\nFORMAT:");
|
|
477
479
|
parts.push(`
|
|
478
|
-
|
|
480
|
+
1. Start marker: ${this.startPrefix}gadget_name`);
|
|
479
481
|
parts.push(`
|
|
480
|
-
|
|
482
|
+
2. ${formatDescription}`);
|
|
481
483
|
parts.push(`
|
|
482
|
-
|
|
483
|
-
parts.push("\n </format>");
|
|
484
|
+
3. End marker: ${this.endPrefix}`);
|
|
484
485
|
parts.push(this.buildExamplesSection(parameterFormat, context));
|
|
485
486
|
parts.push(this.buildRulesSection(context));
|
|
486
|
-
parts.push("\n
|
|
487
|
-
parts.push("\n</GADGETS>\n\n");
|
|
487
|
+
parts.push("\n");
|
|
488
488
|
return parts.join("");
|
|
489
489
|
}
|
|
490
490
|
buildExamplesSection(parameterFormat, context) {
|
|
@@ -492,7 +492,6 @@ ${schema}
|
|
|
492
492
|
return this.promptConfig.customExamples(context);
|
|
493
493
|
}
|
|
494
494
|
const parts = [];
|
|
495
|
-
parts.push("\n <examples>");
|
|
496
495
|
const singleExample = parameterFormat === "yaml" ? `${this.startPrefix}translate
|
|
497
496
|
from: English
|
|
498
497
|
to: Polish
|
|
@@ -501,9 +500,10 @@ ${this.endPrefix}` : `${this.startPrefix}translate
|
|
|
501
500
|
{"from": "English", "to": "Polish", "content": "Paris is the capital of France."}
|
|
502
501
|
${this.endPrefix}`;
|
|
503
502
|
parts.push(`
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
503
|
+
|
|
504
|
+
EXAMPLE (Single Gadget):
|
|
505
|
+
|
|
506
|
+
${singleExample}`);
|
|
507
507
|
const multipleExample = parameterFormat === "yaml" ? `${this.startPrefix}translate
|
|
508
508
|
from: English
|
|
509
509
|
to: Polish
|
|
@@ -520,21 +520,20 @@ ${this.startPrefix}analyze
|
|
|
520
520
|
{"type": "economic_analysis", "matter": "Polish Economy", "question": "Polish arms exports 2025."}
|
|
521
521
|
${this.endPrefix}`;
|
|
522
522
|
parts.push(`
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
523
|
+
|
|
524
|
+
EXAMPLE (Multiple Gadgets):
|
|
525
|
+
|
|
526
|
+
${multipleExample}`);
|
|
527
527
|
return parts.join("");
|
|
528
528
|
}
|
|
529
529
|
buildRulesSection(context) {
|
|
530
530
|
const parts = [];
|
|
531
|
-
parts.push("\n
|
|
531
|
+
parts.push("\n\nRULES:");
|
|
532
532
|
const rules = resolveRulesTemplate(this.promptConfig.rules, context);
|
|
533
533
|
for (const rule of rules) {
|
|
534
534
|
parts.push(`
|
|
535
|
-
|
|
535
|
+
- ${rule}`);
|
|
536
536
|
}
|
|
537
|
-
parts.push("\n </rules>");
|
|
538
537
|
return parts.join("");
|
|
539
538
|
}
|
|
540
539
|
addUser(content, metadata) {
|
|
@@ -1009,18 +1008,18 @@ var init_executor = __esm({
|
|
|
1009
1008
|
|
|
1010
1009
|
// src/gadgets/parser.ts
|
|
1011
1010
|
import * as yaml from "js-yaml";
|
|
1012
|
-
var StreamParser;
|
|
1011
|
+
var globalInvocationCounter, StreamParser;
|
|
1013
1012
|
var init_parser = __esm({
|
|
1014
1013
|
"src/gadgets/parser.ts"() {
|
|
1015
1014
|
"use strict";
|
|
1016
1015
|
init_constants();
|
|
1016
|
+
globalInvocationCounter = 0;
|
|
1017
1017
|
StreamParser = class {
|
|
1018
1018
|
buffer = "";
|
|
1019
1019
|
lastReportedTextLength = 0;
|
|
1020
1020
|
startPrefix;
|
|
1021
1021
|
endPrefix;
|
|
1022
1022
|
parameterFormat;
|
|
1023
|
-
invocationCounter = 0;
|
|
1024
1023
|
constructor(options = {}) {
|
|
1025
1024
|
this.startPrefix = options.startPrefix ?? GADGET_START_PREFIX;
|
|
1026
1025
|
this.endPrefix = options.endPrefix ?? GADGET_END_PREFIX;
|
|
@@ -1087,7 +1086,7 @@ var init_parser = __esm({
|
|
|
1087
1086
|
invocationId = parts[1];
|
|
1088
1087
|
} else {
|
|
1089
1088
|
actualGadgetName = gadgetName;
|
|
1090
|
-
invocationId = `
|
|
1089
|
+
invocationId = `gadget_${++globalInvocationCounter}`;
|
|
1091
1090
|
}
|
|
1092
1091
|
const contentStartIndex = metadataEndIndex + 1;
|
|
1093
1092
|
let partEndIndex;
|
|
@@ -1144,11 +1143,10 @@ var init_parser = __esm({
|
|
|
1144
1143
|
yield { type: "text", content: remainingText };
|
|
1145
1144
|
}
|
|
1146
1145
|
}
|
|
1147
|
-
// Reset parser state
|
|
1146
|
+
// Reset parser state (note: global invocation counter is NOT reset to ensure unique IDs)
|
|
1148
1147
|
reset() {
|
|
1149
1148
|
this.buffer = "";
|
|
1150
1149
|
this.lastReportedTextLength = 0;
|
|
1151
|
-
this.invocationCounter = 0;
|
|
1152
1150
|
}
|
|
1153
1151
|
};
|
|
1154
1152
|
}
|
|
@@ -4447,4 +4445,4 @@ export {
|
|
|
4447
4445
|
init_builder,
|
|
4448
4446
|
BaseGadget
|
|
4449
4447
|
};
|
|
4450
|
-
//# sourceMappingURL=chunk-
|
|
4448
|
+
//# sourceMappingURL=chunk-J3NCIWMY.js.map
|