@owlmeans/llm 0.1.14
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 +193 -0
- package/agent-meta/instructions/llm.instructions.md +66 -0
- package/agent-meta/manifest.json +23 -0
- package/agent-meta/skills/llm/SKILL.md +121 -0
- package/build/consts.d.ts +67 -0
- package/build/consts.d.ts.map +1 -0
- package/build/consts.js +76 -0
- package/build/consts.js.map +1 -0
- package/build/errors.d.ts +33 -0
- package/build/errors.d.ts.map +1 -0
- package/build/errors.js +52 -0
- package/build/errors.js.map +1 -0
- package/build/execution/index.d.ts +4 -0
- package/build/execution/index.d.ts.map +1 -0
- package/build/execution/index.js +3 -0
- package/build/execution/index.js.map +1 -0
- package/build/execution/service.d.ts +21 -0
- package/build/execution/service.d.ts.map +1 -0
- package/build/execution/service.js +129 -0
- package/build/execution/service.js.map +1 -0
- package/build/execution/types.d.ts +119 -0
- package/build/execution/types.d.ts.map +1 -0
- package/build/execution/types.js +2 -0
- package/build/execution/types.js.map +1 -0
- package/build/execution/utils.d.ts +28 -0
- package/build/execution/utils.d.ts.map +1 -0
- package/build/execution/utils.js +60 -0
- package/build/execution/utils.js.map +1 -0
- package/build/helpers/index.d.ts +5 -0
- package/build/helpers/index.d.ts.map +1 -0
- package/build/helpers/index.js +5 -0
- package/build/helpers/index.js.map +1 -0
- package/build/helpers/json.d.ts +24 -0
- package/build/helpers/json.d.ts.map +1 -0
- package/build/helpers/json.js +119 -0
- package/build/helpers/json.js.map +1 -0
- package/build/helpers/messages.d.ts +10 -0
- package/build/helpers/messages.d.ts.map +1 -0
- package/build/helpers/messages.js +9 -0
- package/build/helpers/messages.js.map +1 -0
- package/build/helpers/retry.d.ts +18 -0
- package/build/helpers/retry.d.ts.map +1 -0
- package/build/helpers/retry.js +57 -0
- package/build/helpers/retry.js.map +1 -0
- package/build/helpers/spectate.d.ts +8 -0
- package/build/helpers/spectate.d.ts.map +1 -0
- package/build/helpers/spectate.js +54 -0
- package/build/helpers/spectate.js.map +1 -0
- package/build/index.d.ts +13 -0
- package/build/index.d.ts.map +1 -0
- package/build/index.js +11 -0
- package/build/index.js.map +1 -0
- package/build/model.d.ts +12 -0
- package/build/model.d.ts.map +1 -0
- package/build/model.js +297 -0
- package/build/model.js.map +1 -0
- package/build/plugins/anthropic.d.ts +4 -0
- package/build/plugins/anthropic.d.ts.map +1 -0
- package/build/plugins/anthropic.js +86 -0
- package/build/plugins/anthropic.js.map +1 -0
- package/build/plugins/compatible.d.ts +18 -0
- package/build/plugins/compatible.d.ts.map +1 -0
- package/build/plugins/compatible.js +54 -0
- package/build/plugins/compatible.js.map +1 -0
- package/build/plugins/export.d.ts +6 -0
- package/build/plugins/export.d.ts.map +1 -0
- package/build/plugins/export.js +5 -0
- package/build/plugins/export.js.map +1 -0
- package/build/plugins/index.d.ts +18 -0
- package/build/plugins/index.d.ts.map +1 -0
- package/build/plugins/index.js +42 -0
- package/build/plugins/index.js.map +1 -0
- package/build/plugins/openai.d.ts +28 -0
- package/build/plugins/openai.d.ts.map +1 -0
- package/build/plugins/openai.js +89 -0
- package/build/plugins/openai.js.map +1 -0
- package/build/plugins/types.d.ts +80 -0
- package/build/plugins/types.d.ts.map +1 -0
- package/build/plugins/types.js +2 -0
- package/build/plugins/types.js.map +1 -0
- package/build/plugins/utils.d.ts +27 -0
- package/build/plugins/utils.d.ts.map +1 -0
- package/build/plugins/utils.js +33 -0
- package/build/plugins/utils.js.map +1 -0
- package/build/service.d.ts +24 -0
- package/build/service.d.ts.map +1 -0
- package/build/service.js +95 -0
- package/build/service.js.map +1 -0
- package/build/types.d.ts +190 -0
- package/build/types.d.ts.map +1 -0
- package/build/types.js +2 -0
- package/build/types.js.map +1 -0
- package/build/utils/config.d.ts +13 -0
- package/build/utils/config.d.ts.map +1 -0
- package/build/utils/config.js +15 -0
- package/build/utils/config.js.map +1 -0
- package/build/utils/null-report.d.ts +36 -0
- package/build/utils/null-report.d.ts.map +1 -0
- package/build/utils/null-report.js +84 -0
- package/build/utils/null-report.js.map +1 -0
- package/build/utils/prompt.d.ts +15 -0
- package/build/utils/prompt.d.ts.map +1 -0
- package/build/utils/prompt.js +45 -0
- package/build/utils/prompt.js.map +1 -0
- package/build/utils/schema.d.ts +20 -0
- package/build/utils/schema.d.ts.map +1 -0
- package/build/utils/schema.js +28 -0
- package/build/utils/schema.js.map +1 -0
- package/build/utils/stream.d.ts +22 -0
- package/build/utils/stream.d.ts.map +1 -0
- package/build/utils/stream.js +54 -0
- package/build/utils/stream.js.map +1 -0
- package/package.json +65 -0
- package/src/consts.ts +89 -0
- package/src/errors.ts +65 -0
- package/src/execution/index.ts +4 -0
- package/src/execution/service.ts +185 -0
- package/src/execution/types.ts +139 -0
- package/src/execution/utils.ts +79 -0
- package/src/helpers/index.ts +5 -0
- package/src/helpers/json.ts +117 -0
- package/src/helpers/messages.ts +12 -0
- package/src/helpers/retry.ts +59 -0
- package/src/helpers/spectate.ts +67 -0
- package/src/index.ts +13 -0
- package/src/model.ts +379 -0
- package/src/plugins/anthropic.ts +97 -0
- package/src/plugins/compatible.ts +62 -0
- package/src/plugins/export.ts +6 -0
- package/src/plugins/index.ts +53 -0
- package/src/plugins/openai.ts +108 -0
- package/src/plugins/types.ts +92 -0
- package/src/plugins/utils.ts +38 -0
- package/src/service.ts +125 -0
- package/src/types.ts +214 -0
- package/src/utils/config.ts +19 -0
- package/src/utils/null-report.ts +126 -0
- package/src/utils/prompt.ts +46 -0
- package/src/utils/schema.ts +35 -0
- package/src/utils/stream.ts +58 -0
- package/tests/context.ts +110 -0
- package/tests/execution.spec.ts +200 -0
- package/tests/helpers.spec.ts +192 -0
- package/tests/internals.spec.ts +141 -0
- package/tests/model.spec.ts +116 -0
- package/tests/plugins.spec.ts +227 -0
- package/tsconfig.json +19 -0
package/README.md
ADDED
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
# @owlmeans/llm
|
|
2
|
+
|
|
3
|
+
LLM inference runtime for OwlMeans applications: a resilient four-method model over any
|
|
4
|
+
LangChain chat model, a provider-plugin layer, a model factory service, and an execution
|
|
5
|
+
abstraction that resolves models from an inheritable policy.
|
|
6
|
+
|
|
7
|
+
## Overview
|
|
8
|
+
|
|
9
|
+
- **Model** — `ask` / `talk` / `invoke` / `request` with streaming under an idle deadline,
|
|
10
|
+
retry with an escalating output budget, schema validation and coercion, observability
|
|
11
|
+
and full diagnostics when a call returns nothing usable
|
|
12
|
+
- **Plugins** — everything provider-specific (client construction, retry refinement,
|
|
13
|
+
structured-output mode, `tool_choice` spelling, prompt caching, fatal-error rules) lives
|
|
14
|
+
in a replaceable `LlmPlugin`; Anthropic, OpenAI and OpenAI-compatible ship built in
|
|
15
|
+
- **Service** — `LlmService` builds and memoizes models from a config list, with preset
|
|
16
|
+
inheritance and a stronger `fallback` model attached for retry escalation
|
|
17
|
+
- **Execution** — frozen, three-level (`Project` → `Task` → `Helper`) execution objects
|
|
18
|
+
carrying a `ModelPolicy`, plus snapshot / restore / checkpoint for resumable workflows
|
|
19
|
+
|
|
20
|
+
## Installation
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
bun add @owlmeans/llm @owlmeans/llm-common
|
|
24
|
+
bun add @langchain/core @langchain/openai @langchain/anthropic # peer dependencies
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
The `@langchain/*` packages are **peer dependencies** on purpose: model instances cross the
|
|
28
|
+
package boundary, and two copies of a class with protected members are nominally distinct
|
|
29
|
+
types. Your app must provide exactly one copy.
|
|
30
|
+
|
|
31
|
+
## Usage
|
|
32
|
+
|
|
33
|
+
### Resolve a model and talk to it
|
|
34
|
+
|
|
35
|
+
```typescript
|
|
36
|
+
import { makeLlmService, makeLlmModel } from '@owlmeans/llm'
|
|
37
|
+
import { ModelProvider } from '@owlmeans/llm-common'
|
|
38
|
+
|
|
39
|
+
const llm = makeLlmService({
|
|
40
|
+
models: () => [{
|
|
41
|
+
alias: 'analyst',
|
|
42
|
+
provider: ModelProvider.Compatible,
|
|
43
|
+
model: 'z-ai/glm-5.1',
|
|
44
|
+
secret: process.env.OPENROUTER_SECRET!,
|
|
45
|
+
baseUrl: 'https://openrouter.ai/api/v1',
|
|
46
|
+
maxTokens: 8192,
|
|
47
|
+
maxTokensCap: 32000,
|
|
48
|
+
reasoning: { max_tokens: 1024 },
|
|
49
|
+
}],
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
const model = makeLlmModel(
|
|
53
|
+
{ model: llm.getModel('analyst'), purpose: { type: 'analysis' } },
|
|
54
|
+
spectator, // any { log, captureNull? } sink
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
const text = await model.ask('Summarise this changelog', { action: 'summarise' })
|
|
58
|
+
const spec = await model.invoke('Describe the app', SpecSchema, { action: 'spec' })
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### Drive it through an execution
|
|
62
|
+
|
|
63
|
+
An execution carries the policy, so a caller never picks a model by name:
|
|
64
|
+
|
|
65
|
+
```typescript
|
|
66
|
+
import { appendExecutionService, appendLlmService, DEFAULT_EFFORT } from '@owlmeans/llm'
|
|
67
|
+
import { ExecutionEffort } from '@owlmeans/llm-common'
|
|
68
|
+
|
|
69
|
+
appendLlmService(context, { models: () => configs })
|
|
70
|
+
appendExecutionService(context)
|
|
71
|
+
|
|
72
|
+
const root = context.executions().root({
|
|
73
|
+
models: () => context.llm(),
|
|
74
|
+
policy: { effort: DEFAULT_EFFORT },
|
|
75
|
+
purpose: { type: 'ingest' },
|
|
76
|
+
})
|
|
77
|
+
|
|
78
|
+
// Refine downward — each step returns a NEW frozen object.
|
|
79
|
+
const task = context.executions().forTask(root, { phase: 'draft' })
|
|
80
|
+
const helper = context.executions().forHelper(task, { role: 'analyst', dedication: 'summary' })
|
|
81
|
+
// A hard sub-step runs on a stronger tier without touching the branch it came from:
|
|
82
|
+
const harder = context.executions().escalate(task, { effort: ExecutionEffort.High })
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
Resolution precedence in `executions().model(exec, role, override)`:
|
|
86
|
+
**roleOverride → modelOverride → effort tier → `LlmService.getModel`**.
|
|
87
|
+
|
|
88
|
+
### Persist and resume
|
|
89
|
+
|
|
90
|
+
```typescript
|
|
91
|
+
context.executions().use({
|
|
92
|
+
onCheckpoint: async (state, _exec, key) => queue.put(key!, JSON.stringify(state)),
|
|
93
|
+
onRestore: async key => JSON.parse(await queue.get(key)),
|
|
94
|
+
})
|
|
95
|
+
|
|
96
|
+
await context.executions().checkpoint(task, jobId) // JSON-safe, no collaborators
|
|
97
|
+
const resumed = context.executions().restore(state, { models: () => context.llm() })
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### Add a provider
|
|
101
|
+
|
|
102
|
+
```typescript
|
|
103
|
+
import { openAiFamily, registerLlmPlugin } from '@owlmeans/llm'
|
|
104
|
+
import { StructuredMode } from '@owlmeans/llm-common'
|
|
105
|
+
|
|
106
|
+
registerLlmPlugin({
|
|
107
|
+
...openAiFamily, // shares owns/refine/toolChoice/responseFormat
|
|
108
|
+
type: 'my-gateway',
|
|
109
|
+
structuredMode: config => config.structuredOutput === true ? StructuredMode.Native : StructuredMode.Tool,
|
|
110
|
+
build: ({ config, secret, callbacks }) => new ChatOpenAI({ /* … */ }),
|
|
111
|
+
})
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
Registration order matters for instance-based lookup (a refined model that lost its config
|
|
115
|
+
metadata): the first plugin whose `owns` matches wins, so the conservative member of a
|
|
116
|
+
client family must be registered first.
|
|
117
|
+
|
|
118
|
+
## API
|
|
119
|
+
|
|
120
|
+
### Model
|
|
121
|
+
|
|
122
|
+
| Method | Returns | Use for |
|
|
123
|
+
|--------|---------|---------|
|
|
124
|
+
| `ask(input, options)` | `string` | Plain text. |
|
|
125
|
+
| `talk(input, options)` | `AIMessage` | The raw message (tool calls, metadata). |
|
|
126
|
+
| `invoke(input, schema, options)` | `T` | A schema-validated object. |
|
|
127
|
+
| `request(input, schema, options)` | `AIMessage` | A message whose `content` is the validated JSON. |
|
|
128
|
+
|
|
129
|
+
Shared options: `action` (run name + spectator label), `ref` (out-of-band result +
|
|
130
|
+
spectator entry), `filter` (reject a result and force a retry), `useCache` / `cacheMax`
|
|
131
|
+
(prompt caching where the provider supports it), `temperature` (`invoke` only).
|
|
132
|
+
|
|
133
|
+
### Resilience built into every call
|
|
134
|
+
|
|
135
|
+
| Problem | What the package does |
|
|
136
|
+
|---------|-----------------------|
|
|
137
|
+
| Provider accepts the request and never streams | Idle (per-token) deadline aborts and retries — `ModelConfig.streamTimeout` |
|
|
138
|
+
| Duplicate final SSE chunk corrupts tool-call arguments | Stream breaks at the first non-empty `finish_reason` |
|
|
139
|
+
| Reasoning eats the whole output budget | Retry doubles `maxTokens` toward `maxTokensCap` **and** shrinks an absolute reasoning cap |
|
|
140
|
+
| A weak cheap model keeps failing | Escalates to `ModelConfig.fallback` after `FALLBACK_AFTER_ATTEMPTS`, within one plugin family |
|
|
141
|
+
| Model stringifies arrays / over-wraps scalars | `coerceToSchema` reconciles the answer with the schema before validation |
|
|
142
|
+
| Model ignores the tool and answers in prose | `parseJsonContent` salvages JSON from fences and surrounding text |
|
|
143
|
+
| Nothing usable came back | `NullCapture` — request, response, token accounting and finish reason, to the spectator |
|
|
144
|
+
| An error no retry can fix | `registerFatalError` / `LlmPlugin.isFatal` abort the loop immediately |
|
|
145
|
+
|
|
146
|
+
### Helpers (usable alongside a model)
|
|
147
|
+
|
|
148
|
+
`withRetry` · `registerFatalError` · `spectate` · `normalizeInput` · `parseJsonContent` ·
|
|
149
|
+
`coerceToSchema`. Also exported from `@owlmeans/llm/helpers`.
|
|
150
|
+
|
|
151
|
+
Everything under `src/utils/` is library-private and deliberately not exported.
|
|
152
|
+
|
|
153
|
+
### Plugins
|
|
154
|
+
|
|
155
|
+
Exported from `@owlmeans/llm/plugins` as well as the root: `plugins` (the registry),
|
|
156
|
+
`registerLlmPlugin`, `resolvePlugin`, `pluginOf`, `pluginFor`, `anthropicPlugin`,
|
|
157
|
+
`openAiPlugin`, `compatiblePlugin`, `openAiFamily`.
|
|
158
|
+
|
|
159
|
+
## Tests
|
|
160
|
+
|
|
161
|
+
```bash
|
|
162
|
+
bun test ./tests
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
Offline specs always run. The live specs in `tests/model.spec.ts` are gated: set
|
|
166
|
+
`OPENROUTER_SECRET` (and optionally `OPENROUTER_URL`) and/or `ANTHROPIC_SECRET` in the repo
|
|
167
|
+
root `.env`. With none set they self-skip with a printed reason — never a failure.
|
|
168
|
+
|
|
169
|
+
## Depends On
|
|
170
|
+
|
|
171
|
+
- `@owlmeans/llm-common` — serializable contracts
|
|
172
|
+
- `@owlmeans/context` — service registration
|
|
173
|
+
- `@owlmeans/error` — `ResilientError` family
|
|
174
|
+
- `@owlmeans/basic-ids` — diagnostic ids
|
|
175
|
+
- `ajv` — schema validation
|
|
176
|
+
- peer `@langchain/core`, `@langchain/openai`, `@langchain/anthropic`
|
|
177
|
+
|
|
178
|
+
<!-- owlmeans:agent-guidance:start -->
|
|
179
|
+
## Agent guidance
|
|
180
|
+
|
|
181
|
+
This package ships embedded Claude Code skills and GitHub Copilot instructions under
|
|
182
|
+
`agent-meta/`. After installing your `@owlmeans/*` packages, run the OwlMeans
|
|
183
|
+
agent-skills installer to place them into your project's native locations
|
|
184
|
+
(`.claude/skills/` and `.github/instructions/`):
|
|
185
|
+
|
|
186
|
+
```sh
|
|
187
|
+
npx @owlmeans/agent-skills
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
The embedded files are version-matched to this package release. Do not edit them
|
|
191
|
+
directly — they are regenerated on each publish. To contribute guidance edits,
|
|
192
|
+
open a PR against the source monorepo.
|
|
193
|
+
<!-- owlmeans:agent-guidance:end -->
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: "How to use @owlmeans/llm — the LLM inference runtime: four-method model, provider plugins, model factory service, and the policy-driven execution abstraction."
|
|
3
|
+
applyTo: "**/*.ts, **/*.tsx"
|
|
4
|
+
---
|
|
5
|
+
<!-- AUTO-GENERATED — do not edit. Regenerate via sync-agent-meta. -->
|
|
6
|
+
|
|
7
|
+
# @owlmeans/llm
|
|
8
|
+
|
|
9
|
+
**Layer:** Core
|
|
10
|
+
**Install:** `"@owlmeans/llm": "^0.1.14"` in `dependencies` (plus the `@langchain/*` peers)
|
|
11
|
+
|
|
12
|
+
The inference runtime. Everything provider-specific is a **plugin**; the model owns only the
|
|
13
|
+
provider-independent parts. Serializable contracts live in `@owlmeans/llm-common`.
|
|
14
|
+
|
|
15
|
+
## Key Exports
|
|
16
|
+
|
|
17
|
+
| Export | Description |
|
|
18
|
+
|--------|-------------|
|
|
19
|
+
| `makeLlmModel(options, spectator)` | `ask` / `talk` / `invoke` / `request`. |
|
|
20
|
+
| `makeLlmService` · `appendLlmService` · `llmServiceApi` | Model factory/registry; `llmServiceApi` composes into your own service. |
|
|
21
|
+
| `makeExecutionService` · `appendExecutionService` · `executionServiceApi` | Frozen 3-level executions, policy resolution, snapshot/restore/checkpoint. |
|
|
22
|
+
| `plugins`, `registerLlmPlugin`, `resolvePlugin`, `pluginOf`, `pluginFor` | Provider-plugin registry (`@owlmeans/llm/plugins`). |
|
|
23
|
+
| `anthropicPlugin`, `openAiPlugin`, `compatiblePlugin`, `openAiFamily` | Built-ins; spread `openAiFamily` into a new OpenAI-compatible plugin. |
|
|
24
|
+
| `withRetry`, `registerFatalError`, `spectate`, `normalizeInput`, `parseJsonContent`, `coerceToSchema` | Helpers (`@owlmeans/llm/helpers`). |
|
|
25
|
+
| `LlmModelError` (retryable), `LlmMissconfiguredError`, `LlmPluginError`, `LlmRetryExceededError` | `ResilientError` family. |
|
|
26
|
+
|
|
27
|
+
## Rules
|
|
28
|
+
|
|
29
|
+
- `src/helpers/` is what consumers may use; `src/utils/` is library-private and never
|
|
30
|
+
exported. Place a new function on the right side rather than exporting a util for a test.
|
|
31
|
+
- Never branch on the provider (`instanceof ChatAnthropic`, `provider === …`) in the model or
|
|
32
|
+
the service — put it on the `LlmPlugin` (`build` / `owns` / `family` / `refine` /
|
|
33
|
+
`structuredMode` / `toolChoice` / `responseFormat` / `patchCache` / `isFatal`).
|
|
34
|
+
- Plugin registration order is load-bearing: `pluginFor` returns the first `owns` match, and
|
|
35
|
+
`compatible` precedes `openai` so an unlabelled `ChatOpenAI` gets the conservative
|
|
36
|
+
tool-calling behaviour.
|
|
37
|
+
- `@langchain/*` are **peer** dependencies — model instances cross the package boundary and
|
|
38
|
+
two installed copies are nominally distinct types. Pin one copy in the consumer.
|
|
39
|
+
- Extend the execution generically: your own `ExecutionShape`, your collaborator fields in
|
|
40
|
+
`collaboratorKeys`. Do not narrow inherited method signatures (contravariance error).
|
|
41
|
+
|
|
42
|
+
## Usage
|
|
43
|
+
|
|
44
|
+
```typescript
|
|
45
|
+
import { makeLlmModel, makeLlmService } from '@owlmeans/llm'
|
|
46
|
+
|
|
47
|
+
const llm = makeLlmService({ models: () => configs })
|
|
48
|
+
const model = makeLlmModel(
|
|
49
|
+
{ model: llm.getModel('analyst'), purpose: { type: 'analysis' } }, spectator
|
|
50
|
+
)
|
|
51
|
+
const spec = await model.invoke('Describe the app', SpecSchema, { action: 'spec' })
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Execution resolution precedence: **roleOverride → modelOverride → effort tier →
|
|
55
|
+
`LlmService.getModel`**.
|
|
56
|
+
|
|
57
|
+
## Already handled — do not reimplement
|
|
58
|
+
|
|
59
|
+
Idle stream deadline · duplicate-final-chunk dedup · output-budget escalation ·
|
|
60
|
+
reasoning-cap shrink · same-family fallback model · schema coercion · JSON salvage from
|
|
61
|
+
prose · `NullCapture` diagnostics · fatal-error short-circuit.
|
|
62
|
+
|
|
63
|
+
## Depends On
|
|
64
|
+
|
|
65
|
+
- `@owlmeans/llm-common`, `@owlmeans/context`, `@owlmeans/error`, `@owlmeans/basic-ids`, `ajv`
|
|
66
|
+
- peer `@langchain/core`, `@langchain/openai`, `@langchain/anthropic`
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 1,
|
|
3
|
+
"package": "@owlmeans/llm",
|
|
4
|
+
"version": "0.1.14",
|
|
5
|
+
"generatedAt": "2026-08-05T16:56:53.378Z",
|
|
6
|
+
"canonicalRepo": "https://github.com/owlmeans/common",
|
|
7
|
+
"entries": [
|
|
8
|
+
{
|
|
9
|
+
"kind": "skill",
|
|
10
|
+
"name": "llm",
|
|
11
|
+
"category": "package-specific",
|
|
12
|
+
"file": "skills/llm/SKILL.md",
|
|
13
|
+
"canonicalPath": ".claude/skills/llm/SKILL.md"
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
"kind": "instruction",
|
|
17
|
+
"name": "llm",
|
|
18
|
+
"category": "package-specific",
|
|
19
|
+
"file": "instructions/llm.instructions.md",
|
|
20
|
+
"canonicalPath": ".github/instructions/llm.instructions.md"
|
|
21
|
+
}
|
|
22
|
+
]
|
|
23
|
+
}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: llm
|
|
3
|
+
description: How to use @owlmeans/llm — the LLM inference runtime (four-method model, provider plugins, model factory service, policy-driven execution abstraction). Auto-invoked when importing the model, an LlmPlugin, the LlmService, or the execution service.
|
|
4
|
+
user-invocable: false
|
|
5
|
+
---
|
|
6
|
+
<!-- AUTO-GENERATED — do not edit. Regenerate via sync-agent-meta. -->
|
|
7
|
+
|
|
8
|
+
# @owlmeans/llm
|
|
9
|
+
|
|
10
|
+
**Layer:** Core
|
|
11
|
+
**Install:** `"@owlmeans/llm": "^0.1.14"` in `dependencies` (plus the `@langchain/*` peers)
|
|
12
|
+
|
|
13
|
+
The inference runtime. Everything provider-specific is a **plugin**; the model itself only
|
|
14
|
+
owns the provider-independent parts (streaming discipline, retries, validation,
|
|
15
|
+
observability). Serializable contracts live in `@owlmeans/llm-common`.
|
|
16
|
+
|
|
17
|
+
## Key Exports
|
|
18
|
+
|
|
19
|
+
| Export | Description |
|
|
20
|
+
|--------|-------------|
|
|
21
|
+
| `makeLlmModel(options, spectator)` | The four-method model: `ask` / `talk` / `invoke` / `request`. |
|
|
22
|
+
| `makeLlmService(options, alias?)` · `appendLlmService(ctx, options, alias?)` | Model factory/registry — resolves a `ModelConfig` by alias, memoized per alias+override. |
|
|
23
|
+
| `llmServiceApi(options, self)` | The factory half WITHOUT `createService`, to compose into your own service (role accessors, domain helpers). |
|
|
24
|
+
| `makeExecutionService(alias?, options?)` · `appendExecutionService(ctx, alias?, options?)` | Frozen 3-level executions + policy resolution + snapshot/restore/checkpoint. |
|
|
25
|
+
| `executionServiceApi(options, self)` | The execution half without `createService`, for the same composition pattern. |
|
|
26
|
+
| `plugins`, `registerLlmPlugin`, `resolvePlugin`, `pluginOf`, `pluginFor` | The provider-plugin registry. Also at `@owlmeans/llm/plugins`. |
|
|
27
|
+
| `anthropicPlugin`, `openAiPlugin`, `compatiblePlugin`, `openAiFamily` | Built-in providers; `openAiFamily` is the shared OpenAI-client behaviour to spread into a new plugin. |
|
|
28
|
+
| `withRetry`, `registerFatalError`, `spectate`, `normalizeInput`, `parseJsonContent`, `coerceToSchema` | Helpers usable alongside a model. Also at `@owlmeans/llm/helpers`. |
|
|
29
|
+
| `LlmError`, `LlmModelError`, `LlmMissconfiguredError`, `LlmPluginError`, `LlmRetryExceededError` | `ResilientError` family. `LlmModelError` is the RETRYABLE one. |
|
|
30
|
+
| `DEFAULT_MODEL_RETRIES`, `MODEL_STREAM_TIMEOUT_MS`, `FALLBACK_AFTER_ATTEMPTS`, `DEFAULT_EFFORT`, `EFFORT_TABLE`, `LLM_SERVICE`, `EXECUTION_SERVICE` | Tuning + aliases. |
|
|
31
|
+
|
|
32
|
+
## helpers/ vs utils/ — the rule this package follows
|
|
33
|
+
|
|
34
|
+
- `src/helpers/` — functions a **consumer** may use alongside a model. Exported.
|
|
35
|
+
- `src/utils/` — used only inside the library. **Never exported**; a spec that needs one
|
|
36
|
+
imports it from `../src/utils/…`.
|
|
37
|
+
|
|
38
|
+
Adding a function? Decide which side it belongs to first, then place it. Do not export a
|
|
39
|
+
`utils/` symbol "because a test needs it".
|
|
40
|
+
|
|
41
|
+
## Provider differences are plugins, never `if`s
|
|
42
|
+
|
|
43
|
+
`LlmPlugin` is the single seam. If you find yourself writing `instanceof ChatAnthropic` or
|
|
44
|
+
`config.provider === …` in `model.ts` or `service.ts`, it belongs on the plugin instead:
|
|
45
|
+
|
|
46
|
+
| Plugin member | Replaces |
|
|
47
|
+
|---|---|
|
|
48
|
+
| `build` | the provider switch in the model factory |
|
|
49
|
+
| `owns` / `family` | `instanceof` checks; `family` gates cross-provider fallback |
|
|
50
|
+
| `refine` | the per-provider retry rebuild (budget doubling, reasoning shrink) |
|
|
51
|
+
| `structuredMode` | native `response_format` vs the forced-tool-call hack |
|
|
52
|
+
| `toolChoice` / `responseFormat` | the provider-specific call shapes |
|
|
53
|
+
| `patchCache` | prompt-cache markers |
|
|
54
|
+
| `isFatal` | "this error can never be retried" |
|
|
55
|
+
|
|
56
|
+
**Registration order is load-bearing.** Instance-based lookup (`pluginFor`) returns the
|
|
57
|
+
FIRST plugin whose `owns` matches. `compatible` is registered before `openai` because both
|
|
58
|
+
build a `ChatOpenAI`, and assuming the tool-calling hack for an unlabelled model is safe
|
|
59
|
+
everywhere while assuming native JSON-schema support is not.
|
|
60
|
+
|
|
61
|
+
## Execution: policy in, model out
|
|
62
|
+
|
|
63
|
+
```
|
|
64
|
+
ProjectExecution ← root: policy + purpose + models resolver
|
|
65
|
+
└─ TaskExecution ← + resumable state (phase/cursor/completed/data)
|
|
66
|
+
└─ HelperExecution ← + a RESOLVED model + temperatureFactory, bound to a role
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Every method returns a NEW `Object.freeze`d object. Resolution precedence in
|
|
70
|
+
`model(exec, role, override)`: **roleOverride → modelOverride → effort tier →
|
|
71
|
+
`LlmService.getModel`**. `escalate(exec, { effort })` raises the tier once and cascades to
|
|
72
|
+
everything derived from it.
|
|
73
|
+
|
|
74
|
+
Extending it for a domain: declare your own `Execution`/input types, list your collaborator
|
|
75
|
+
fields in `ExecutionServiceOptions.collaboratorKeys` so they stay out of snapshots, and
|
|
76
|
+
instantiate the service generic with your own `ExecutionShape` — **do not narrow the
|
|
77
|
+
inherited method signatures**, which would be a contravariance error.
|
|
78
|
+
|
|
79
|
+
`snapshot` excludes `state` itself; without that, every `derive`/`escalate`/`withPurpose`
|
|
80
|
+
on a task would nest another copy of the previous state.
|
|
81
|
+
|
|
82
|
+
## Peer-dependency rule (langchain identity)
|
|
83
|
+
|
|
84
|
+
`@langchain/core`, `@langchain/openai` and `@langchain/anthropic` are **peer** dependencies:
|
|
85
|
+
model instances cross the package boundary, and two installed copies of a class with
|
|
86
|
+
protected members are nominally distinct types. In a linked-workspace checkout the consumer
|
|
87
|
+
must pin them to a single copy — see the `bun-linked-workspaces` skill.
|
|
88
|
+
|
|
89
|
+
## Usage
|
|
90
|
+
|
|
91
|
+
```typescript
|
|
92
|
+
import { makeLlmModel, makeLlmService } from '@owlmeans/llm'
|
|
93
|
+
import { ModelProvider } from '@owlmeans/llm-common'
|
|
94
|
+
|
|
95
|
+
const llm = makeLlmService({ models: () => configs })
|
|
96
|
+
const model = makeLlmModel(
|
|
97
|
+
{ model: llm.getModel('analyst'), purpose: { type: 'analysis' } }, spectator
|
|
98
|
+
)
|
|
99
|
+
const spec = await model.invoke('Describe the app', SpecSchema, { action: 'spec' })
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
## Resilience already handled — do not reimplement
|
|
103
|
+
|
|
104
|
+
Idle stream deadline · duplicate-final-chunk dedup · output-budget escalation · reasoning-cap
|
|
105
|
+
shrink · same-family fallback model · schema coercion · JSON salvage from prose · `NullCapture`
|
|
106
|
+
diagnostics · fatal-error short-circuit. Details: package `README.md`.
|
|
107
|
+
|
|
108
|
+
## Tests
|
|
109
|
+
|
|
110
|
+
`bun test ./tests` in the package. Offline specs always run; `tests/model.spec.ts` is gated
|
|
111
|
+
on `OPENROUTER_SECRET` / `ANTHROPIC_SECRET` in the repo-root `.env` and self-skips otherwise.
|
|
112
|
+
|
|
113
|
+
## Depends On
|
|
114
|
+
|
|
115
|
+
- `@owlmeans/llm-common` · `@owlmeans/context` · `@owlmeans/error` · `@owlmeans/basic-ids` · `ajv`
|
|
116
|
+
- peer `@langchain/core`, `@langchain/openai`, `@langchain/anthropic`
|
|
117
|
+
|
|
118
|
+
## Related
|
|
119
|
+
|
|
120
|
+
- [[llm-common]] — the serializable contracts
|
|
121
|
+
- [[context]] — service registration · [[error]] — the `ResilientError` family
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { ExecutionEffort } from '@owlmeans/llm-common';
|
|
2
|
+
import type { ModelConfigPatch } from '@owlmeans/llm-common';
|
|
3
|
+
/** Context-service alias for the {@link LlmService} (model factory / registry). */
|
|
4
|
+
export declare const LLM_SERVICE = "owlmeans-llm-service";
|
|
5
|
+
/** Context-service alias for the {@link ExecutionService}. */
|
|
6
|
+
export declare const EXECUTION_SERVICE = "owlmeans-llm-execution-service";
|
|
7
|
+
/** Default number of attempts a single model call makes before giving up. */
|
|
8
|
+
export declare const DEFAULT_MODEL_RETRIES = 8;
|
|
9
|
+
/**
|
|
10
|
+
* Idle (inactivity) deadline in ms for a streamed response: abort the stream when no
|
|
11
|
+
* new token has arrived within this window. NOT a total cap — the timer is re-armed on
|
|
12
|
+
* every chunk, so long but actively-streaming generations are never aborted. Guards
|
|
13
|
+
* against a provider that accepts the request and then never streams anything (observed
|
|
14
|
+
* with throughput-sorted OpenRouter routing), which would otherwise block forever —
|
|
15
|
+
* `maxRetries` never helps there because the request never errors, it just hangs.
|
|
16
|
+
* Overridable per model via `ModelConfig.streamTimeout`.
|
|
17
|
+
*/
|
|
18
|
+
export declare const MODEL_STREAM_TIMEOUT_MS: number;
|
|
19
|
+
/**
|
|
20
|
+
* Number of failed attempts after which the retry escalator switches from a role's
|
|
21
|
+
* cheap primary model to its configured `fallback` (stronger) model. With
|
|
22
|
+
* {@link DEFAULT_MODEL_RETRIES} = 8 the primary runs attempts 0..2 and the fallback
|
|
23
|
+
* runs attempts 3..7.
|
|
24
|
+
*/
|
|
25
|
+
export declare const FALLBACK_AFTER_ATTEMPTS = 3;
|
|
26
|
+
/**
|
|
27
|
+
* Output-token ceiling used by the retry escalator when a model config declares no
|
|
28
|
+
* `maxTokensCap`. Deliberately high (192K) — it exceeds many real per-request output
|
|
29
|
+
* limits, which is why a precise cap belongs in the preset: without it a retry can
|
|
30
|
+
* issue a 400 "max_tokens exceeds the model's per-request limit".
|
|
31
|
+
*/
|
|
32
|
+
export declare const DEFAULT_MAX_OUTPUT_CAP: number;
|
|
33
|
+
/** Provider hard limit on prompt-cache breakpoints (Anthropic). */
|
|
34
|
+
export declare const MAX_CACHE_BREAKPOINTS = 4;
|
|
35
|
+
/**
|
|
36
|
+
* Appended to the prompt of `invoke`/`request` when no message already mentions JSON.
|
|
37
|
+
* Some providers refuse or ignore JSON modes unless the word appears in the prompt;
|
|
38
|
+
* the length guidance keeps a verbose model from padding the object past the output
|
|
39
|
+
* limit and truncating it.
|
|
40
|
+
*/
|
|
41
|
+
export declare const JSON_INSTRUCTION: string;
|
|
42
|
+
/**
|
|
43
|
+
* Qwen3-family soft switch that suppresses hidden reasoning. Injected when
|
|
44
|
+
* `ModelConfig.disableThinking` is set; without it those models routinely spend the
|
|
45
|
+
* whole output budget on thinking and return empty content with `finish_reason="length"`.
|
|
46
|
+
*/
|
|
47
|
+
export declare const NO_THINK_DIRECTIVE = "/no_think";
|
|
48
|
+
/** Tool name used for structured output when a schema carries no usable title/name. */
|
|
49
|
+
export declare const DEFAULT_TOOL_NAME = "extract";
|
|
50
|
+
/** Default effort tier when a policy does not specify one. */
|
|
51
|
+
export declare const DEFAULT_EFFORT = ExecutionEffort.Standard;
|
|
52
|
+
/**
|
|
53
|
+
* Effort tier → JSON-safe model config bump merged into `LlmService.getModel` overrides.
|
|
54
|
+
* Pure data: an explicit `modelOverride` always wins over this table, and a `roleOverride`
|
|
55
|
+
* is applied before it.
|
|
56
|
+
*/
|
|
57
|
+
export declare const EFFORT_TABLE: Record<ExecutionEffort, ModelConfigPatch>;
|
|
58
|
+
/**
|
|
59
|
+
* Execution fields that are collaborators, not state: never copied into a snapshot.
|
|
60
|
+
* A consumer adds its own (e.g. a file-access helper) through
|
|
61
|
+
* `ExecutionServiceOptions.collaboratorKeys`.
|
|
62
|
+
*
|
|
63
|
+
* `state` is in the list because a `TaskExecution` carries its own composed state —
|
|
64
|
+
* without excluding it every `derive`/`escalate`/`withPurpose` would nest another copy.
|
|
65
|
+
*/
|
|
66
|
+
export declare const COLLABORATOR_KEYS: string[];
|
|
67
|
+
//# sourceMappingURL=consts.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"consts.d.ts","sourceRoot":"","sources":["../src/consts.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAA;AACtD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAA;AAE5D,mFAAmF;AACnF,eAAO,MAAM,WAAW,yBAAyB,CAAA;AAEjD,8DAA8D;AAC9D,eAAO,MAAM,iBAAiB,mCAAmC,CAAA;AAEjE,6EAA6E;AAC7E,eAAO,MAAM,qBAAqB,IAAI,CAAA;AAEtC;;;;;;;;GAQG;AACH,eAAO,MAAM,uBAAuB,QAAgB,CAAA;AAEpD;;;;;GAKG;AACH,eAAO,MAAM,uBAAuB,IAAI,CAAA;AAExC;;;;;GAKG;AACH,eAAO,MAAM,sBAAsB,QAAY,CAAA;AAE/C,mEAAmE;AACnE,eAAO,MAAM,qBAAqB,IAAI,CAAA;AAEtC;;;;;GAKG;AACH,eAAO,MAAM,gBAAgB,QAGkD,CAAA;AAE/E;;;;GAIG;AACH,eAAO,MAAM,kBAAkB,cAAc,CAAA;AAE7C,uFAAuF;AACvF,eAAO,MAAM,iBAAiB,YAAY,CAAA;AAE1C,8DAA8D;AAC9D,eAAO,MAAM,cAAc,2BAA2B,CAAA;AAEtD;;;;GAIG;AACH,eAAO,MAAM,YAAY,EAAE,MAAM,CAAC,eAAe,EAAE,gBAAgB,CAKlE,CAAA;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,iBAAiB,EAAE,MAAM,EAErC,CAAA"}
|
package/build/consts.js
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { ExecutionEffort } from '@owlmeans/llm-common';
|
|
2
|
+
/** Context-service alias for the {@link LlmService} (model factory / registry). */
|
|
3
|
+
export const LLM_SERVICE = 'owlmeans-llm-service';
|
|
4
|
+
/** Context-service alias for the {@link ExecutionService}. */
|
|
5
|
+
export const EXECUTION_SERVICE = 'owlmeans-llm-execution-service';
|
|
6
|
+
/** Default number of attempts a single model call makes before giving up. */
|
|
7
|
+
export const DEFAULT_MODEL_RETRIES = 8;
|
|
8
|
+
/**
|
|
9
|
+
* Idle (inactivity) deadline in ms for a streamed response: abort the stream when no
|
|
10
|
+
* new token has arrived within this window. NOT a total cap — the timer is re-armed on
|
|
11
|
+
* every chunk, so long but actively-streaming generations are never aborted. Guards
|
|
12
|
+
* against a provider that accepts the request and then never streams anything (observed
|
|
13
|
+
* with throughput-sorted OpenRouter routing), which would otherwise block forever —
|
|
14
|
+
* `maxRetries` never helps there because the request never errors, it just hangs.
|
|
15
|
+
* Overridable per model via `ModelConfig.streamTimeout`.
|
|
16
|
+
*/
|
|
17
|
+
export const MODEL_STREAM_TIMEOUT_MS = 5 * 60 * 1000;
|
|
18
|
+
/**
|
|
19
|
+
* Number of failed attempts after which the retry escalator switches from a role's
|
|
20
|
+
* cheap primary model to its configured `fallback` (stronger) model. With
|
|
21
|
+
* {@link DEFAULT_MODEL_RETRIES} = 8 the primary runs attempts 0..2 and the fallback
|
|
22
|
+
* runs attempts 3..7.
|
|
23
|
+
*/
|
|
24
|
+
export const FALLBACK_AFTER_ATTEMPTS = 3;
|
|
25
|
+
/**
|
|
26
|
+
* Output-token ceiling used by the retry escalator when a model config declares no
|
|
27
|
+
* `maxTokensCap`. Deliberately high (192K) — it exceeds many real per-request output
|
|
28
|
+
* limits, which is why a precise cap belongs in the preset: without it a retry can
|
|
29
|
+
* issue a 400 "max_tokens exceeds the model's per-request limit".
|
|
30
|
+
*/
|
|
31
|
+
export const DEFAULT_MAX_OUTPUT_CAP = 3 * 64000;
|
|
32
|
+
/** Provider hard limit on prompt-cache breakpoints (Anthropic). */
|
|
33
|
+
export const MAX_CACHE_BREAKPOINTS = 4;
|
|
34
|
+
/**
|
|
35
|
+
* Appended to the prompt of `invoke`/`request` when no message already mentions JSON.
|
|
36
|
+
* Some providers refuse or ignore JSON modes unless the word appears in the prompt;
|
|
37
|
+
* the length guidance keeps a verbose model from padding the object past the output
|
|
38
|
+
* limit and truncating it.
|
|
39
|
+
*/
|
|
40
|
+
export const JSON_INSTRUCTION = 'Respond with a single complete and valid JSON object only. '
|
|
41
|
+
+ 'Do not wrap it in markdown fences, and do not add any commentary, reasoning, or explanation outside the JSON. '
|
|
42
|
+
+ 'Keep string values focused — do not pad them with restated requirements or numbered summaries, '
|
|
43
|
+
+ 'so the whole object stays within the output limit and is never truncated.';
|
|
44
|
+
/**
|
|
45
|
+
* Qwen3-family soft switch that suppresses hidden reasoning. Injected when
|
|
46
|
+
* `ModelConfig.disableThinking` is set; without it those models routinely spend the
|
|
47
|
+
* whole output budget on thinking and return empty content with `finish_reason="length"`.
|
|
48
|
+
*/
|
|
49
|
+
export const NO_THINK_DIRECTIVE = '/no_think';
|
|
50
|
+
/** Tool name used for structured output when a schema carries no usable title/name. */
|
|
51
|
+
export const DEFAULT_TOOL_NAME = 'extract';
|
|
52
|
+
/** Default effort tier when a policy does not specify one. */
|
|
53
|
+
export const DEFAULT_EFFORT = ExecutionEffort.Standard;
|
|
54
|
+
/**
|
|
55
|
+
* Effort tier → JSON-safe model config bump merged into `LlmService.getModel` overrides.
|
|
56
|
+
* Pure data: an explicit `modelOverride` always wins over this table, and a `roleOverride`
|
|
57
|
+
* is applied before it.
|
|
58
|
+
*/
|
|
59
|
+
export const EFFORT_TABLE = {
|
|
60
|
+
[ExecutionEffort.Economy]: { maxTokensCap: 16000 },
|
|
61
|
+
[ExecutionEffort.Standard]: {},
|
|
62
|
+
[ExecutionEffort.High]: { maxTokens: 16000, maxTokensCap: 32000 },
|
|
63
|
+
[ExecutionEffort.Max]: { maxTokens: 32000, maxTokensCap: 64000 },
|
|
64
|
+
};
|
|
65
|
+
/**
|
|
66
|
+
* Execution fields that are collaborators, not state: never copied into a snapshot.
|
|
67
|
+
* A consumer adds its own (e.g. a file-access helper) through
|
|
68
|
+
* `ExecutionServiceOptions.collaboratorKeys`.
|
|
69
|
+
*
|
|
70
|
+
* `state` is in the list because a `TaskExecution` carries its own composed state —
|
|
71
|
+
* without excluding it every `derive`/`escalate`/`withPurpose` would nest another copy.
|
|
72
|
+
*/
|
|
73
|
+
export const COLLABORATOR_KEYS = [
|
|
74
|
+
'state', 'models', 'model', 'temperatureFactory', 'outputErrors',
|
|
75
|
+
];
|
|
76
|
+
//# sourceMappingURL=consts.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"consts.js","sourceRoot":"","sources":["../src/consts.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAA;AAGtD,mFAAmF;AACnF,MAAM,CAAC,MAAM,WAAW,GAAG,sBAAsB,CAAA;AAEjD,8DAA8D;AAC9D,MAAM,CAAC,MAAM,iBAAiB,GAAG,gCAAgC,CAAA;AAEjE,6EAA6E;AAC7E,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,CAAA;AAEtC;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAAG,CAAC,GAAG,EAAE,GAAG,IAAI,CAAA;AAEpD;;;;;GAKG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAAG,CAAC,CAAA;AAExC;;;;;GAKG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC,GAAG,KAAK,CAAA;AAE/C,mEAAmE;AACnE,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,CAAA;AAEtC;;;;;GAKG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,6DAA6D;MACzF,gHAAgH;MAChH,iGAAiG;MACjG,2EAA2E,CAAA;AAE/E;;;;GAIG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG,WAAW,CAAA;AAE7C,uFAAuF;AACvF,MAAM,CAAC,MAAM,iBAAiB,GAAG,SAAS,CAAA;AAE1C,8DAA8D;AAC9D,MAAM,CAAC,MAAM,cAAc,GAAG,eAAe,CAAC,QAAQ,CAAA;AAEtD;;;;GAIG;AACH,MAAM,CAAC,MAAM,YAAY,GAA8C;IACrE,CAAC,eAAe,CAAC,OAAO,CAAC,EAAE,EAAE,YAAY,EAAE,KAAK,EAAE;IAClD,CAAC,eAAe,CAAC,QAAQ,CAAC,EAAE,EAAE;IAC9B,CAAC,eAAe,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,KAAK,EAAE,YAAY,EAAE,KAAK,EAAE;IACjE,CAAC,eAAe,CAAC,GAAG,CAAC,EAAE,EAAE,SAAS,EAAE,KAAK,EAAE,YAAY,EAAE,KAAK,EAAE;CACjE,CAAA;AAED;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAa;IACzC,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,oBAAoB,EAAE,cAAc;CACjE,CAAA"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { ResilientError } from '@owlmeans/error';
|
|
2
|
+
export declare class LlmError extends ResilientError {
|
|
3
|
+
static typeName: string;
|
|
4
|
+
constructor(message?: string);
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* A model call produced something unusable (null/empty content, failed validation,
|
|
8
|
+
* a rejected filter, a stalled stream). **Retryable** — `withRetry` swallows it and
|
|
9
|
+
* escalates to the next attempt.
|
|
10
|
+
*/
|
|
11
|
+
export declare class LlmModelError extends LlmError {
|
|
12
|
+
static typeName: string;
|
|
13
|
+
retry: number;
|
|
14
|
+
constructor(message?: string);
|
|
15
|
+
}
|
|
16
|
+
/** A model alias has no config, or its config names no provider/secret/plugin. */
|
|
17
|
+
export declare class LlmMissconfiguredError extends LlmError {
|
|
18
|
+
static typeName: string;
|
|
19
|
+
constructor(message?: string);
|
|
20
|
+
}
|
|
21
|
+
/** No provider plugin is registered for the requested type / model instance. */
|
|
22
|
+
export declare class LlmPluginError extends LlmError {
|
|
23
|
+
static readonly NO_PLUGIN = "no-plugin";
|
|
24
|
+
static typeName: string;
|
|
25
|
+
constructor(message?: string);
|
|
26
|
+
}
|
|
27
|
+
/** Every attempt failed. `cause` carries the last error, `attempt` the last index. */
|
|
28
|
+
export declare class LlmRetryExceededError extends LlmError {
|
|
29
|
+
static typeName: string;
|
|
30
|
+
attempt: number;
|
|
31
|
+
constructor(message?: string);
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAA;AAEhD,qBAAa,QAAS,SAAQ,cAAc;IAC1C,OAAuB,QAAQ,SAAkC;gBAErD,OAAO,GAAE,MAAgB;CAGtC;AAED;;;;GAIG;AACH,qBAAa,aAAc,SAAQ,QAAQ;IACzC,OAAuB,QAAQ,SAA8B;IAEtD,KAAK,EAAE,MAAM,CAAI;gBAEZ,OAAO,GAAE,MAAgB;CAItC;AAED,kFAAkF;AAClF,qBAAa,sBAAuB,SAAQ,QAAQ;IAClD,OAAuB,QAAQ,SAAuC;gBAE1D,OAAO,GAAE,MAAgB;CAItC;AAED,gFAAgF;AAChF,qBAAa,cAAe,SAAQ,QAAQ;IAC1C,gBAAuB,SAAS,eAAc;IAE9C,OAAuB,QAAQ,SAA+B;gBAElD,OAAO,GAAE,MAAgB;CAItC;AAED,sFAAsF;AACtF,qBAAa,qBAAsB,SAAQ,QAAQ;IACjD,OAAuB,QAAQ,SAAsC;IAE9D,OAAO,EAAE,MAAM,CAAI;gBAEd,OAAO,GAAE,MAAgB;CAItC"}
|
package/build/errors.js
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { ResilientError } from '@owlmeans/error';
|
|
2
|
+
export class LlmError extends ResilientError {
|
|
3
|
+
static typeName = `Llm${ResilientError.typeName}`;
|
|
4
|
+
constructor(message = 'error') {
|
|
5
|
+
super(LlmError.typeName, `llm:${message}`);
|
|
6
|
+
}
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* A model call produced something unusable (null/empty content, failed validation,
|
|
10
|
+
* a rejected filter, a stalled stream). **Retryable** — `withRetry` swallows it and
|
|
11
|
+
* escalates to the next attempt.
|
|
12
|
+
*/
|
|
13
|
+
export class LlmModelError extends LlmError {
|
|
14
|
+
static typeName = `Model${LlmError.typeName}`;
|
|
15
|
+
retry = 0;
|
|
16
|
+
constructor(message = 'error') {
|
|
17
|
+
super(`model:${message}`);
|
|
18
|
+
this.type = LlmModelError.typeName;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
/** A model alias has no config, or its config names no provider/secret/plugin. */
|
|
22
|
+
export class LlmMissconfiguredError extends LlmError {
|
|
23
|
+
static typeName = `Missconfigured${LlmError.typeName}`;
|
|
24
|
+
constructor(message = 'error') {
|
|
25
|
+
super(`missconfigured:${message}`);
|
|
26
|
+
this.type = LlmMissconfiguredError.typeName;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
/** No provider plugin is registered for the requested type / model instance. */
|
|
30
|
+
export class LlmPluginError extends LlmError {
|
|
31
|
+
static NO_PLUGIN = 'no-plugin';
|
|
32
|
+
static typeName = `Plugin${LlmError.typeName}`;
|
|
33
|
+
constructor(message = 'error') {
|
|
34
|
+
super(`plugin:${message}`);
|
|
35
|
+
this.type = LlmPluginError.typeName;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
/** Every attempt failed. `cause` carries the last error, `attempt` the last index. */
|
|
39
|
+
export class LlmRetryExceededError extends LlmError {
|
|
40
|
+
static typeName = `RetryExceeded${LlmError.typeName}`;
|
|
41
|
+
attempt = 0;
|
|
42
|
+
constructor(message = 'error') {
|
|
43
|
+
super(`retry-exceeded:${message}`);
|
|
44
|
+
this.type = LlmRetryExceededError.typeName;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
ResilientError.registerErrorClass(LlmError);
|
|
48
|
+
ResilientError.registerErrorClass(LlmModelError);
|
|
49
|
+
ResilientError.registerErrorClass(LlmMissconfiguredError);
|
|
50
|
+
ResilientError.registerErrorClass(LlmPluginError);
|
|
51
|
+
ResilientError.registerErrorClass(LlmRetryExceededError);
|
|
52
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAA;AAEhD,MAAM,OAAO,QAAS,SAAQ,cAAc;IACnC,MAAM,CAAU,QAAQ,GAAG,MAAM,cAAc,CAAC,QAAQ,EAAE,CAAA;IAEjE,YAAY,UAAkB,OAAO;QACnC,KAAK,CAAC,QAAQ,CAAC,QAAQ,EAAE,OAAO,OAAO,EAAE,CAAC,CAAA;IAC5C,CAAC;;AAGH;;;;GAIG;AACH,MAAM,OAAO,aAAc,SAAQ,QAAQ;IAClC,MAAM,CAAU,QAAQ,GAAG,QAAQ,QAAQ,CAAC,QAAQ,EAAE,CAAA;IAEtD,KAAK,GAAW,CAAC,CAAA;IAExB,YAAY,UAAkB,OAAO;QACnC,KAAK,CAAC,SAAS,OAAO,EAAE,CAAC,CAAA;QACzB,IAAI,CAAC,IAAI,GAAG,aAAa,CAAC,QAAQ,CAAA;IACpC,CAAC;;AAGH,kFAAkF;AAClF,MAAM,OAAO,sBAAuB,SAAQ,QAAQ;IAC3C,MAAM,CAAU,QAAQ,GAAG,iBAAiB,QAAQ,CAAC,QAAQ,EAAE,CAAA;IAEtE,YAAY,UAAkB,OAAO;QACnC,KAAK,CAAC,kBAAkB,OAAO,EAAE,CAAC,CAAA;QAClC,IAAI,CAAC,IAAI,GAAG,sBAAsB,CAAC,QAAQ,CAAA;IAC7C,CAAC;;AAGH,gFAAgF;AAChF,MAAM,OAAO,cAAe,SAAQ,QAAQ;IACnC,MAAM,CAAU,SAAS,GAAG,WAAW,CAAA;IAEvC,MAAM,CAAU,QAAQ,GAAG,SAAS,QAAQ,CAAC,QAAQ,EAAE,CAAA;IAE9D,YAAY,UAAkB,OAAO;QACnC,KAAK,CAAC,UAAU,OAAO,EAAE,CAAC,CAAA;QAC1B,IAAI,CAAC,IAAI,GAAG,cAAc,CAAC,QAAQ,CAAA;IACrC,CAAC;;AAGH,sFAAsF;AACtF,MAAM,OAAO,qBAAsB,SAAQ,QAAQ;IAC1C,MAAM,CAAU,QAAQ,GAAG,gBAAgB,QAAQ,CAAC,QAAQ,EAAE,CAAA;IAE9D,OAAO,GAAW,CAAC,CAAA;IAE1B,YAAY,UAAkB,OAAO;QACnC,KAAK,CAAC,kBAAkB,OAAO,EAAE,CAAC,CAAA;QAClC,IAAI,CAAC,IAAI,GAAG,qBAAqB,CAAC,QAAQ,CAAA;IAC5C,CAAC;;AAGH,cAAc,CAAC,kBAAkB,CAAC,QAAQ,CAAC,CAAA;AAC3C,cAAc,CAAC,kBAAkB,CAAC,aAAa,CAAC,CAAA;AAChD,cAAc,CAAC,kBAAkB,CAAC,sBAAsB,CAAC,CAAA;AACzD,cAAc,CAAC,kBAAkB,CAAC,cAAc,CAAC,CAAA;AACjD,cAAc,CAAC,kBAAkB,CAAC,qBAAqB,CAAC,CAAA"}
|