@jaypie/mcp 0.8.183 → 0.8.185
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/assets.js +3 -3
- package/package.json +1 -1
- package/release-notes/jaypie/1.2.119.md +9 -0
- package/release-notes/jaypie/1.2.120.md +9 -0
- package/release-notes/llm/1.3.60.md +26 -0
- package/release-notes/llm/1.3.61.md +28 -0
- package/release-notes/mcp/0.8.184.md +10 -0
- package/release-notes/mcp/0.8.185.md +10 -0
- package/release-notes/testkit/1.2.82.md +9 -0
- package/release-notes/testkit/1.2.83.md +9 -0
- package/skills/llm.md +109 -35
package/dist/assets.js
CHANGED
|
@@ -55,11 +55,11 @@ function getMcpAssetPaths() {
|
|
|
55
55
|
*/
|
|
56
56
|
function getMcpBuildInfo() {
|
|
57
57
|
return {
|
|
58
|
-
commit: "
|
|
58
|
+
commit: "a5a715a3"
|
|
59
59
|
,
|
|
60
|
-
version: "0.8.
|
|
60
|
+
version: "0.8.185"
|
|
61
61
|
,
|
|
62
|
-
versionString: "@jaypie/mcp@0.8.
|
|
62
|
+
versionString: "@jaypie/mcp@0.8.185#a5a715a3"
|
|
63
63
|
,
|
|
64
64
|
};
|
|
65
65
|
}
|
package/package.json
CHANGED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
---
|
|
2
|
+
version: 1.3.60
|
|
3
|
+
date: 2026-10-07
|
|
4
|
+
summary: effort accepts a per-model map, fallback entries take their own effort, and resolveEffort exports the native mapping
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Changes
|
|
8
|
+
|
|
9
|
+
### Per-model effort (issue #612)
|
|
10
|
+
|
|
11
|
+
A fallback chain mixes providers whose reasoning cost differs sharply at the same level, but `effort` was one value per call.
|
|
12
|
+
|
|
13
|
+
- `effort` accepts `LlmEffortMap`. Each attempt (primary, fallback, linger pass) resolves its own level: exact model id, then `MODEL` catalog key whose value is exactly the model, then provider (or the `gemini` alias), then `default`. No match leaves the provider default.
|
|
14
|
+
- Catalog keys match exact catalog values only, never name fragments, so `flash` cannot catch both Gemini Flash and GLM Flash.
|
|
15
|
+
- `LlmFallbackConfig.effort` sets a single level for one entry and replaces the call's value there.
|
|
16
|
+
- `LlmExchangeRequest.effort` records the level each attempt resolved.
|
|
17
|
+
|
|
18
|
+
### `resolveEffort`
|
|
19
|
+
|
|
20
|
+
- `resolveEffort({ model, effort, provider? })` returns `{ level, model, native, papered, provider }`, where `native` is the request fragment the adapter sends (e.g. `{ thinkingConfig: { thinkingLevel: "LOW" } }`). Undefined `native` means no level resolved or the model has no reasoning control.
|
|
21
|
+
- Adapters expose `resolveEffort` and build requests from it, so the export and the wire request share one mapping.
|
|
22
|
+
|
|
23
|
+
## Testing
|
|
24
|
+
|
|
25
|
+
- `resolveEffort.spec.ts` covers map precedence, catalog keys, the provider alias, and native fragments per provider.
|
|
26
|
+
- `OperateLoop` and `StreamLoop` specs cover map resolution and the exchange record; `Llm` specs cover per-entry effort on a fallback.
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
---
|
|
2
|
+
version: 1.3.61
|
|
3
|
+
date: 2026-10-07
|
|
4
|
+
summary: modelOptions sets provider options per model for every attempt in a chain; providerOptions and send are deprecated
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Changes
|
|
8
|
+
|
|
9
|
+
### `modelOptions` (issue #614)
|
|
10
|
+
|
|
11
|
+
`providerOptions` reached the primary only, so a fallback ran on defaults unless the caller rebuilt the chain with options on every entry.
|
|
12
|
+
|
|
13
|
+
- `modelOptions` (`LlmModelOptions`) on `operate` and `stream` keys provider options by exact model id, `MODEL` catalog key, provider (or the `gemini` alias), or `default`. Each attempt (primary, fallback, linger pass) resolves it against its own model.
|
|
14
|
+
- Every matching key merges, least to most specific: `default` → provider → catalog key → exact id. Objects merge deeply; arrays and scalars replace.
|
|
15
|
+
- First-class `effort`, `temperature`, and `format` still win over resolved options.
|
|
16
|
+
- When `modelOptions` is set, `providerOptions` (call and chain entry) is ignored.
|
|
17
|
+
- `LlmExchangeRequest.providerOptions` records the options each attempt sent.
|
|
18
|
+
- `resolveModelOptions({ model, modelOptions, provider? })` returns `{ keys, model, options, provider }`.
|
|
19
|
+
|
|
20
|
+
### Deprecations
|
|
21
|
+
|
|
22
|
+
- `providerOptions` on `LlmOperateOptions` and `LlmFallbackConfig` is deprecated and removed in 2.0. Use `modelOptions`.
|
|
23
|
+
- `Llm.send` (instance and static) is deprecated and receives no new features. Use `operate`.
|
|
24
|
+
|
|
25
|
+
## Testing
|
|
26
|
+
|
|
27
|
+
- `modelOptions.spec.ts` covers merge order, deep merge, array replacement, the provider alias, ignoring `providerOptions`, and the issue's example through the OpenAI and Google adapters.
|
|
28
|
+
- `OperateLoop` and `StreamLoop` specs cover resolution and the exchange record; `Llm` specs cover `modelOptions` reaching every fallback and the linger pass.
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
---
|
|
2
|
+
version: 0.8.184
|
|
3
|
+
date: 2026-10-07
|
|
4
|
+
summary: Release notes for @jaypie/llm 1.3.60, testkit 1.2.82, and jaypie 1.2.119; llm skill documents per-model effort and resolveEffort
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Changes
|
|
8
|
+
|
|
9
|
+
- **Release notes**: `@jaypie/llm` 1.3.60, `@jaypie/testkit` 1.2.82, and `jaypie` 1.2.119
|
|
10
|
+
- **`llm` skill**: per-model effort maps, `LlmFallbackConfig.effort`, and `resolveEffort`
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
---
|
|
2
|
+
version: 0.8.185
|
|
3
|
+
date: 2026-10-07
|
|
4
|
+
summary: Release notes for @jaypie/llm 1.3.61, testkit 1.2.83, and jaypie 1.2.120; llm skill documents modelOptions and the providerOptions and send deprecations
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Changes
|
|
8
|
+
|
|
9
|
+
- **Release notes**: `@jaypie/llm` 1.3.61, `@jaypie/testkit` 1.2.83, and `jaypie` 1.2.120
|
|
10
|
+
- **`llm` skill**: `modelOptions`, `resolveModelOptions`, and the deprecation of `providerOptions` and `send()`
|
package/skills/llm.md
CHANGED
|
@@ -138,9 +138,11 @@ Completions `length`, Anthropic `max_tokens`, and OpenAI `max_output_tokens`
|
|
|
138
138
|
all read `max_tokens`). The provider's own value rides
|
|
139
139
|
`exchange.response.stopReason`.
|
|
140
140
|
|
|
141
|
-
### send() - Simple Completions
|
|
141
|
+
### send() - Simple Completions (deprecated)
|
|
142
142
|
|
|
143
|
-
|
|
143
|
+
`send()` is deprecated and receives no new features (fallback, `effort`,
|
|
144
|
+
`modelOptions`, tools). Prefer `operate()`, with `format` for structured
|
|
145
|
+
output. For single-shot text completions:
|
|
144
146
|
|
|
145
147
|
```typescript
|
|
146
148
|
const response = await Llm.send("Explain REST APIs", {
|
|
@@ -859,23 +861,41 @@ An incomplete `content` is the raw partial text, a string even when `format` was
|
|
|
859
861
|
|
|
860
862
|
A `format` request answered with **no content** (zero output tokens, an empty candidate, a blocked prompt) settles incomplete with `error.detail` `Model returned no content: <stop reason>`, logged at `warn`, and `stopReason: "other"`. An adapter that supports the corrective turn tries it once first. A chain moves past an empty response like any cut-off, and an earlier partial is kept over a later empty one. When nothing but empty responses come back, `operate` throws `LlmIncompleteError` whatever `incomplete` says: there is no partial to return (issue #608).
|
|
861
863
|
|
|
862
|
-
###
|
|
864
|
+
### Model Options in a Chain
|
|
863
865
|
|
|
864
|
-
`
|
|
866
|
+
`modelOptions` sets provider-specific request fields per model. Every attempt (primary, each fallback, and the linger pass) resolves the map against its own model, so options shaped for one provider (OpenAI `reasoning`, Gemini `thinkingConfig`) reach every model they fit and no other. Keys match the way [effort maps](#per-model-effort) do: exact model id, `MODEL` catalog key, provider (or alias such as `gemini`), `default`.
|
|
867
|
+
|
|
868
|
+
Every matching key merges, least to most specific: `default` → provider → catalog key → exact id. Objects merge deeply; arrays and scalars replace. First-class fields (`effort`, `temperature`, `format`) still win.
|
|
865
869
|
|
|
866
870
|
```typescript
|
|
867
|
-
|
|
871
|
+
await llm.operate(input, {
|
|
872
|
+
model: LLM.MODEL.SOL,
|
|
868
873
|
fallback: [
|
|
869
|
-
{
|
|
870
|
-
|
|
871
|
-
model: LLM.MODEL.GEMINI_FLASH,
|
|
872
|
-
providerOptions: { thinkingConfig: { thinkingBudget: 1024 } },
|
|
873
|
-
},
|
|
874
|
+
{ provider: "google", model: LLM.MODEL.GEMINI_FLASH },
|
|
875
|
+
{ provider: "openai", model: "gpt-6-mini" },
|
|
874
876
|
],
|
|
875
|
-
|
|
877
|
+
effort: { gemini_flash: "low", default: "medium" },
|
|
878
|
+
modelOptions: {
|
|
879
|
+
openai: { reasoning: { summary: "detailed" } },
|
|
880
|
+
gemini_flash: { thinkingConfig: { includeThoughts: true } },
|
|
881
|
+
},
|
|
876
882
|
});
|
|
883
|
+
// gpt-6-sol, gpt-6-mini: reasoning { summary: "detailed", effort: "medium" }
|
|
884
|
+
// gemini-3.8-flash: thinkingConfig { includeThoughts: true, thinkingLevel: "LOW" }
|
|
877
885
|
```
|
|
878
886
|
|
|
887
|
+
The exchange records the merged options each attempt sent (`LlmExchangeRequest.providerOptions`). `resolveModelOptions` returns them for one model, with the keys that matched in merge order:
|
|
888
|
+
|
|
889
|
+
```typescript
|
|
890
|
+
import { resolveModelOptions } from "@jaypie/llm";
|
|
891
|
+
|
|
892
|
+
resolveModelOptions({ model: LLM.MODEL.SOL, modelOptions });
|
|
893
|
+
// → { keys: ["openai"], model: "gpt-6-sol", provider: "openai",
|
|
894
|
+
// options: { reasoning: { summary: "detailed" } } }
|
|
895
|
+
```
|
|
896
|
+
|
|
897
|
+
`providerOptions` is deprecated and removed in 2.0. Until then, per-call `providerOptions` reach the primary only (including its linger pass) and a fallback receives only the `providerOptions` on its own entry. When `modelOptions` is set, `providerOptions` (call and chain entry) is ignored.
|
|
898
|
+
|
|
879
899
|
### Attempt Timeout
|
|
880
900
|
|
|
881
901
|
`timeout` sets a per-attempt deadline in milliseconds. Without it, a provider that accepts the connection but never answers holds the chain until the runtime gives up (undici waits 300 s for response headers). A stalled attempt is aborted and throws `LlmTimeoutError` (a `LlmTransientError`, status 504, with `timeoutMs`):
|
|
@@ -1066,10 +1086,10 @@ budget runs out. Those errors carry `error.reason` (`LlmResponseErrorReason`)
|
|
|
1066
1086
|
because status alone cannot identify them: an exhausted turn budget is a 429,
|
|
1067
1087
|
exactly like a provider rate limit.
|
|
1068
1088
|
|
|
1069
|
-
| `reason` | Status | Meaning
|
|
1070
|
-
| ------------- | ------ |
|
|
1071
|
-
| `max_turns` | 429 | The model asked for another tool call after `turns` ran out. Nothing failed; the run did not converge.
|
|
1072
|
-
| `tool_errors` | 502 | Tool execution failed six times in a row and the loop stopped.
|
|
1089
|
+
| `reason` | Status | Meaning |
|
|
1090
|
+
| ------------- | ------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
1091
|
+
| `max_turns` | 429 | The model asked for another tool call after `turns` ran out. Nothing failed; the run did not converge. |
|
|
1092
|
+
| `tool_errors` | 502 | Tool execution failed six times in a row and the loop stopped. |
|
|
1073
1093
|
| `incomplete` | 502 | The provider cut the model off before it finished (an output token ceiling, a content filter). `content` holds the partial text; `error.detail` names the provider's reason and `stopReason` normalizes it. A fallback chain moves past it. With `format`, empty content settles here too and throws once the chain is spent. |
|
|
1074
1094
|
|
|
1075
1095
|
```typescript
|
|
@@ -1125,14 +1145,15 @@ describe("LLM Integration", () => {
|
|
|
1125
1145
|
interface LlmOperateOptions {
|
|
1126
1146
|
cache?: boolean | 0 | "5m" | "1h"; // Prompt caching (default on at 1h; false/0 disables)
|
|
1127
1147
|
data?: Record<string, any>; // Placeholder substitution data
|
|
1128
|
-
effort?: LlmEffort; //
|
|
1148
|
+
effort?: LlmEffort | LlmEffortMap; // Reasoning effort (lowest|low|medium|high|highest), or a per-model map
|
|
1129
1149
|
fallback?: LlmFallbackConfig[] | false; // Fallback provider chain
|
|
1130
1150
|
format?: NaturalSchema | JsonObject | ZodType; // Structured output schema (natural syntax preferred)
|
|
1131
1151
|
history?: LlmHistory; // Previous conversation
|
|
1132
1152
|
hooks?: LlmHooks; // Lifecycle callbacks
|
|
1133
1153
|
instructions?: string; // Additional instructions
|
|
1134
1154
|
model?: string; // Model override
|
|
1135
|
-
|
|
1155
|
+
modelOptions?: LlmModelOptions; // Provider-specific request fields per model, every attempt
|
|
1156
|
+
providerOptions?: JsonObject; // Deprecated: primary only; ignored when modelOptions is set
|
|
1136
1157
|
system?: string; // System prompt
|
|
1137
1158
|
temperature?: number; // Sampling temperature (0-2)
|
|
1138
1159
|
tools?: LlmTool[] | Toolkit; // Available tools
|
|
@@ -1144,6 +1165,9 @@ interface LlmFallbackConfig {
|
|
|
1144
1165
|
provider: string; // Provider name (e.g., "openai", "anthropic", "google")
|
|
1145
1166
|
model?: string; // Model to use (optional, uses provider default)
|
|
1146
1167
|
apiKey?: string; // API key (optional, uses environment variable)
|
|
1168
|
+
effort?: LlmEffort; // Effort for this entry only, replacing the call's effort
|
|
1169
|
+
providerOptions?: JsonObject; // Deprecated: this entry only; ignored when modelOptions is set
|
|
1170
|
+
timeout?: number | false; // Per-attempt deadline for this entry only
|
|
1147
1171
|
}
|
|
1148
1172
|
```
|
|
1149
1173
|
|
|
@@ -1220,9 +1244,62 @@ erroring):
|
|
|
1220
1244
|
tools natively — no emulation.
|
|
1221
1245
|
- **Bedrock** — not yet wired; `effort` is ignored.
|
|
1222
1246
|
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1247
|
+
### Per-model effort
|
|
1248
|
+
|
|
1249
|
+
Reasoning cost differs sharply between providers at the same level, so a
|
|
1250
|
+
fallback chain can set `effort` per model with a map. Each attempt (primary,
|
|
1251
|
+
every fallback, and the linger pass) resolves its own level, first match wins:
|
|
1252
|
+
|
|
1253
|
+
1. **Exact model id** (`"gpt-6.1-sol"`)
|
|
1254
|
+
2. **`MODEL` catalog key** whose value is exactly the serving model (`"sol"`
|
|
1255
|
+
for `MODEL.SOL`, `"gemini_flash"`, `"fireworks.glm"`); case-insensitive,
|
|
1256
|
+
any separator. Keys never match by name fragment: `"flash"` matches nothing.
|
|
1257
|
+
3. **Provider** (`"openai"`, `"anthropic"`, `"google"`, `"xai"`,
|
|
1258
|
+
`"openrouter"`, ...) or an alias (`"gemini"` → `google`)
|
|
1259
|
+
4. **`default`**
|
|
1260
|
+
5. No match leaves the provider default untouched
|
|
1261
|
+
|
|
1262
|
+
```typescript
|
|
1263
|
+
await llm.operate(input, {
|
|
1264
|
+
model: "gemini-3-flash",
|
|
1265
|
+
fallback: [
|
|
1266
|
+
{ provider: "openai", model: "gpt-6.1-sol" },
|
|
1267
|
+
{ provider: "anthropic", model: "claude-opus-5-5", effort: "highest" },
|
|
1268
|
+
],
|
|
1269
|
+
effort: { gemini: "low", "gpt-6.1-sol": "medium", default: "high" },
|
|
1270
|
+
});
|
|
1271
|
+
```
|
|
1272
|
+
|
|
1273
|
+
A single `LlmEffort` keeps its meaning everywhere. A fallback entry's own
|
|
1274
|
+
`effort` replaces the call's value (single or map) for that entry. The exchange
|
|
1275
|
+
records the level each attempt resolved (`LlmExchangeRequest.effort`).
|
|
1276
|
+
|
|
1277
|
+
### `resolveEffort`
|
|
1278
|
+
|
|
1279
|
+
`resolveEffort` returns the level a model resolves to and the request fragment
|
|
1280
|
+
its adapter would send (`native`), or no `native` when the model has no
|
|
1281
|
+
reasoning control:
|
|
1282
|
+
|
|
1283
|
+
```typescript
|
|
1284
|
+
import { resolveEffort } from "@jaypie/llm";
|
|
1285
|
+
|
|
1286
|
+
resolveEffort({ model: "gemini-3-flash", effort: "low" });
|
|
1287
|
+
// → { level: "low", model: "gemini-3-flash", provider: "google", papered: false,
|
|
1288
|
+
// native: { thinkingConfig: { thinkingLevel: "LOW" } } }
|
|
1289
|
+
|
|
1290
|
+
resolveEffort({ model: "claude-opus-5-5", effort: { anthropic: "high" } });
|
|
1291
|
+
// → { level: "high", ..., native: { output_config: { effort: "high" } } }
|
|
1292
|
+
```
|
|
1293
|
+
|
|
1294
|
+
Accepts an optional `provider` when the model id alone does not route (e.g. an
|
|
1295
|
+
OpenRouter path). Comparing `native` across levels shows which are distinct on
|
|
1296
|
+
a model: `lowest` and `low` on Claude both send `{ effort: "low" }`, so one of
|
|
1297
|
+
the two is redundant in an effort sweep.
|
|
1298
|
+
|
|
1299
|
+
First-class `effort` takes precedence over a raw `reasoning` in
|
|
1300
|
+
`modelOptions` (same convention as `temperature`). For control the neutral
|
|
1301
|
+
scale does not express (an exact token budget, OpenAI `none`), use
|
|
1302
|
+
`modelOptions` directly.
|
|
1226
1303
|
|
|
1227
1304
|
## Prompt Caching
|
|
1228
1305
|
|
|
@@ -1252,9 +1329,9 @@ tokens surface as `cacheRead`/`cacheWrite` on usage (with `cacheWriteTtl`
|
|
|
1252
1329
|
splitting writes by TTL on Anthropic and Bedrock), in the exchange envelope
|
|
1253
1330
|
`usageTotals`, and in the report tally.
|
|
1254
1331
|
|
|
1255
|
-
##
|
|
1332
|
+
## Model Options and Output Limits
|
|
1256
1333
|
|
|
1257
|
-
`
|
|
1334
|
+
`modelOptions` passes provider-specific request fields straight through to
|
|
1258
1335
|
the underlying API: Anthropic merges them into the Messages request body;
|
|
1259
1336
|
Google merges them into the generation config.
|
|
1260
1337
|
|
|
@@ -1269,19 +1346,16 @@ truncate:
|
|
|
1269
1346
|
- **Streaming** (`stream()`): the model maximum — e.g., 128,000 for current
|
|
1270
1347
|
Claude models (64,000 for Haiku), 65,536 for Gemini 2.5/3.x
|
|
1271
1348
|
|
|
1272
|
-
Override per
|
|
1349
|
+
Override per model with `modelOptions`:
|
|
1273
1350
|
|
|
1274
1351
|
```typescript
|
|
1275
|
-
// Anthropic: max_tokens
|
|
1276
1352
|
await Llm.operate(input, {
|
|
1277
1353
|
model: LLM.MODEL.SONNET,
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
// Google: maxOutputTokens
|
|
1282
|
-
|
|
1283
|
-
model: LLM.MODEL.GEMINI_PRO,
|
|
1284
|
-
providerOptions: { maxOutputTokens: 32000 },
|
|
1354
|
+
fallback: [{ provider: "google", model: LLM.MODEL.GEMINI_PRO }],
|
|
1355
|
+
modelOptions: {
|
|
1356
|
+
anthropic: { max_tokens: 32000 }, // Anthropic: max_tokens
|
|
1357
|
+
google: { maxOutputTokens: 32000 }, // Google: maxOutputTokens
|
|
1358
|
+
},
|
|
1285
1359
|
});
|
|
1286
1360
|
```
|
|
1287
1361
|
|
|
@@ -1290,13 +1364,13 @@ A chain that mixes them with Anthropic, Google, or Mistral therefore mixes
|
|
|
1290
1364
|
output budgets: a Gemini primary resolves to 16,384 non-streaming while an
|
|
1291
1365
|
OpenAI fallback sends no ceiling, so swapping the primary moves the effective
|
|
1292
1366
|
budget with nothing at the call site changing. Reasoning tokens count against
|
|
1293
|
-
the ceiling. Set `
|
|
1294
|
-
|
|
1367
|
+
the ceiling. Set `maxOutputTokens` (Google) or `max_tokens` (Anthropic,
|
|
1368
|
+
Mistral) in `modelOptions` to pin it per model.
|
|
1295
1369
|
Mistral is capped (32,768 streaming / 16,384 non-streaming) despite publishing
|
|
1296
1370
|
no low ceiling: a Mistral model can degenerate into restating its answer when
|
|
1297
1371
|
`format` and tools are combined, and an uncapped completion turns that into a
|
|
1298
|
-
multi-minute request. Override with `
|
|
1299
|
-
OpenRouter varies by routed model; pass `max_tokens` via `
|
|
1372
|
+
multi-minute request. Override with `modelOptions: { mistral: { max_tokens } }`.
|
|
1373
|
+
OpenRouter varies by routed model; pass `max_tokens` via `modelOptions`
|
|
1300
1374
|
when needed. A truncated response settles `status: "incomplete"` with
|
|
1301
1375
|
`stopReason: "max_tokens"` and moves a fallback chain to its next entry;
|
|
1302
1376
|
raise the limit or switch to `stream()`.
|