@jaypie/mcp 0.8.184 → 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 CHANGED
@@ -55,11 +55,11 @@ function getMcpAssetPaths() {
55
55
  */
56
56
  function getMcpBuildInfo() {
57
57
  return {
58
- commit: "9aa68f12"
58
+ commit: "a5a715a3"
59
59
  ,
60
- version: "0.8.184"
60
+ version: "0.8.185"
61
61
  ,
62
- versionString: "@jaypie/mcp@0.8.184#9aa68f12"
62
+ versionString: "@jaypie/mcp@0.8.185#a5a715a3"
63
63
  ,
64
64
  };
65
65
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jaypie/mcp",
3
- "version": "0.8.184",
3
+ "version": "0.8.185",
4
4
  "description": "Jaypie MCP",
5
5
  "repository": {
6
6
  "type": "git",
@@ -0,0 +1,9 @@
1
+ ---
2
+ version: 1.2.120
3
+ date: 2026-10-07
4
+ summary: Pulls @jaypie/llm 1.3.61
5
+ ---
6
+
7
+ ## Changes
8
+
9
+ - **`@jaypie/llm` 1.3.61**: `modelOptions` sets provider options per model for every attempt in a chain; `providerOptions` and `send` are deprecated.
@@ -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.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()`
@@ -0,0 +1,9 @@
1
+ ---
2
+ version: 1.2.83
3
+ date: 2026-10-07
4
+ summary: Passes through resolveModelOptions from @jaypie/llm
5
+ ---
6
+
7
+ ## Changes
8
+
9
+ - `resolveModelOptions` in the `@jaypie/llm` mock, passed through to the real implementation.
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
- For single-shot text completions:
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
- ### Provider Options in a Chain
864
+ ### Model Options in a Chain
863
865
 
864
- `providerOptions` belongs to the model it was written for. Per-call `providerOptions` reach the primary only (including its linger pass); a fallback receives only the `providerOptions` on its own entry, or none. Options shaped for one provider (OpenAI `reasoning`, Gemini `thinkingConfig`) would otherwise break every other provider in the chain. Prefer first-class `effort` and `temperature`, which translate per provider.
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
- const response = await llm.operate(input, {
871
+ await llm.operate(input, {
872
+ model: LLM.MODEL.SOL,
868
873
  fallback: [
869
- {
870
- provider: "google",
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
- providerOptions: { reasoning: { summary: "detailed" } }, // primary only
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
@@ -1132,7 +1152,8 @@ interface LlmOperateOptions {
1132
1152
  hooks?: LlmHooks; // Lifecycle callbacks
1133
1153
  instructions?: string; // Additional instructions
1134
1154
  model?: string; // Model override
1135
- providerOptions?: JsonObject; // Provider-specific request fields (passthrough)
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
@@ -1145,7 +1166,7 @@ interface LlmFallbackConfig {
1145
1166
  model?: string; // Model to use (optional, uses provider default)
1146
1167
  apiKey?: string; // API key (optional, uses environment variable)
1147
1168
  effort?: LlmEffort; // Effort for this entry only, replacing the call's effort
1148
- providerOptions?: JsonObject; // Provider-specific options for this entry only
1169
+ providerOptions?: JsonObject; // Deprecated: this entry only; ignored when modelOptions is set
1149
1170
  timeout?: number | false; // Per-attempt deadline for this entry only
1150
1171
  }
1151
1172
  ```
@@ -1275,9 +1296,10 @@ OpenRouter path). Comparing `native` across levels shows which are distinct on
1275
1296
  a model: `lowest` and `low` on Claude both send `{ effort: "low" }`, so one of
1276
1297
  the two is redundant in an effort sweep.
1277
1298
 
1278
- First-class `effort` takes precedence over a raw `providerOptions.reasoning`
1279
- (same convention as `temperature`). For control the neutral scale doesn't
1280
- express (an exact token budget, OpenAI `none`), use `providerOptions` directly.
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.
1281
1303
 
1282
1304
  ## Prompt Caching
1283
1305
 
@@ -1307,9 +1329,9 @@ tokens surface as `cacheRead`/`cacheWrite` on usage (with `cacheWriteTtl`
1307
1329
  splitting writes by TTL on Anthropic and Bedrock), in the exchange envelope
1308
1330
  `usageTotals`, and in the report tally.
1309
1331
 
1310
- ## Provider Options and Output Limits
1332
+ ## Model Options and Output Limits
1311
1333
 
1312
- `providerOptions` passes provider-specific request fields straight through to
1334
+ `modelOptions` passes provider-specific request fields straight through to
1313
1335
  the underlying API: Anthropic merges them into the Messages request body;
1314
1336
  Google merges them into the generation config.
1315
1337
 
@@ -1324,19 +1346,16 @@ truncate:
1324
1346
  - **Streaming** (`stream()`): the model maximum — e.g., 128,000 for current
1325
1347
  Claude models (64,000 for Haiku), 65,536 for Gemini 2.5/3.x
1326
1348
 
1327
- Override per call with `providerOptions`:
1349
+ Override per model with `modelOptions`:
1328
1350
 
1329
1351
  ```typescript
1330
- // Anthropic: max_tokens
1331
1352
  await Llm.operate(input, {
1332
1353
  model: LLM.MODEL.SONNET,
1333
- providerOptions: { max_tokens: 32000 },
1334
- });
1335
-
1336
- // Google: maxOutputTokens
1337
- await Llm.operate(input, {
1338
- model: LLM.MODEL.GEMINI_PRO,
1339
- 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
+ },
1340
1359
  });
1341
1360
  ```
1342
1361
 
@@ -1345,13 +1364,13 @@ A chain that mixes them with Anthropic, Google, or Mistral therefore mixes
1345
1364
  output budgets: a Gemini primary resolves to 16,384 non-streaming while an
1346
1365
  OpenAI fallback sends no ceiling, so swapping the primary moves the effective
1347
1366
  budget with nothing at the call site changing. Reasoning tokens count against
1348
- the ceiling. Set `providerOptions.maxOutputTokens` (Google) or `max_tokens`
1349
- (Anthropic, Mistral) on the call or chain entry to pin it.
1367
+ the ceiling. Set `maxOutputTokens` (Google) or `max_tokens` (Anthropic,
1368
+ Mistral) in `modelOptions` to pin it per model.
1350
1369
  Mistral is capped (32,768 streaming / 16,384 non-streaming) despite publishing
1351
1370
  no low ceiling: a Mistral model can degenerate into restating its answer when
1352
1371
  `format` and tools are combined, and an uncapped completion turns that into a
1353
- multi-minute request. Override with `providerOptions: { max_tokens }`.
1354
- OpenRouter varies by routed model; pass `max_tokens` via `providerOptions`
1372
+ multi-minute request. Override with `modelOptions: { mistral: { max_tokens } }`.
1373
+ OpenRouter varies by routed model; pass `max_tokens` via `modelOptions`
1355
1374
  when needed. A truncated response settles `status: "incomplete"` with
1356
1375
  `stopReason: "max_tokens"` and moves a fallback chain to its next entry;
1357
1376
  raise the limit or switch to `stream()`.