@exellix/ai-tasks 8.2.4 → 8.2.9
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/CHANGELOG.md +2 -0
- package/dist/invocation/resolveProfileInvocationRouting.d.ts +1 -1
- package/dist/invocation/resolveProfileInvocationRouting.d.ts.map +1 -1
- package/dist/invocation/resolveProfileInvocationRouting.js +15 -14
- package/dist/invocation/resolveProfileInvocationRouting.js.map +1 -1
- package/documenations/upstream-feature-requests/funcx-openrouter-model-id-pass-through.md +105 -0
- package/documenations/upstream-feature-requests/xynthesis-openrouter-wire-model-double-prefix-bug.md +191 -0
- package/package.json +6 -5
package/CHANGELOG.md
CHANGED
|
@@ -8,6 +8,8 @@ The published **npm version** always matches **`version`** in [`package.json`](p
|
|
|
8
8
|
|
|
9
9
|
### Changed
|
|
10
10
|
|
|
11
|
+
- **`@x12i/ai-profiles` ≥1.8.0:** Direct dependency bumped from **^1.7.2**; **`npm` override** pins transitive `@x12i/ai-profiles` to this package's direct version (required fix in **1.8.0** for profile alias resolution). Live coverage: `npm run test:live` → `test/e2e/ai-profiles-live.test.ts` (registry `auto` + real xynthesis alias call).
|
|
12
|
+
- **`@exellix/xynthesis` ^4.1.8:** Fixes OpenRouter **400 invalid model ID** on PRE/POST hops (wire id was `openrouter/<slug>` instead of bare OR API slug). ai-tasks invocation routing aligned (skill gateway shape vs xynthesis Funcx slug). Requires **≥4.1.8** — do not use **4.1.7** for alias-based xynthesis calls with OpenRouter.
|
|
11
13
|
- **`@x12i/logxer` ^4.4.2:** Package diagnostics use **`createLogxer`** with diagnostic catalog (`.metadata/log-diagnostics.json`), **`warnCode`** / **`DebugLogAbstract`**, **`fieldEvidence`**, **`runWithLogContext`** during **`runTask()`**, and in-process **`getAiTasksJobLogs`** for debug UIs. Override pins transitive logxer to **4.4.2** (no nested **4.4.0** from `@x12i/optimixer`).
|
|
12
14
|
|
|
13
15
|
## [8.1.1] - 2026-05-28
|
|
@@ -20,7 +20,7 @@ export type ResolvedProfileInvocation = {
|
|
|
20
20
|
directModelId?: string;
|
|
21
21
|
resolvedProfile?: ResolvedAIProfile;
|
|
22
22
|
};
|
|
23
|
-
/** Match `@exellix/xynthesis` `
|
|
23
|
+
/** Match `@exellix/xynthesis` `xynthesisWireModelIdFromResolved` — bare OpenRouter API slug for Funcx. */
|
|
24
24
|
export declare function formatXynthesisWireModelId(provider: string, modelId: string): string;
|
|
25
25
|
/**
|
|
26
26
|
* Shared profile-slot → routed provider/model resolver used by `resolveModelReference` and
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resolveProfileInvocationRouting.d.ts","sourceRoot":"","sources":["../../src/invocation/resolveProfileInvocationRouting.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAUhG,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAEpD,eAAO,MAAM,2BAA2B,oBAAoB,CAAC;AAE7D,MAAM,MAAM,mBAAmB,GAAG,OAAO,GAAG,WAAW,CAAC;AAExD,MAAM,MAAM,sCAAsC,GAAG;IACnD,SAAS,EAAE,mBAAmB,CAAC;IAC/B,oGAAoG;IACpG,sBAAsB,EAAE,OAAO,CAAC;IAChC,MAAM,CAAC,EAAE,kBAAkB,CAAC;CAC7B,CAAC;AAEF,MAAM,MAAM,yBAAyB,GAAG;IACtC,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,iBAAiB,CAAC;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,eAAe,CAAC;IAC7B,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,eAAe,CAAC,EAAE,iBAAiB,CAAC;CACrC,CAAC;AAEF,
|
|
1
|
+
{"version":3,"file":"resolveProfileInvocationRouting.d.ts","sourceRoot":"","sources":["../../src/invocation/resolveProfileInvocationRouting.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAUhG,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAEpD,eAAO,MAAM,2BAA2B,oBAAoB,CAAC;AAE7D,MAAM,MAAM,mBAAmB,GAAG,OAAO,GAAG,WAAW,CAAC;AAExD,MAAM,MAAM,sCAAsC,GAAG;IACnD,SAAS,EAAE,mBAAmB,CAAC;IAC/B,oGAAoG;IACpG,sBAAsB,EAAE,OAAO,CAAC;IAChC,MAAM,CAAC,EAAE,kBAAkB,CAAC;CAC7B,CAAC;AAEF,MAAM,MAAM,yBAAyB,GAAG;IACtC,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,iBAAiB,CAAC;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,eAAe,CAAC;IAC7B,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,eAAe,CAAC,EAAE,iBAAiB,CAAC;CACrC,CAAC;AAEF,0GAA0G;AAC1G,wBAAgB,0BAA0B,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAMpF;AAsDD;;;;GAIG;AACH,wBAAsB,+BAA+B,CACnD,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,sCAAsC,GAC9C,OAAO,CAAC,yBAAyB,CAAC,CA4EpC"}
|
|
@@ -5,7 +5,7 @@ import { isConcreteModelId } from "../utils/concreteModelId.js";
|
|
|
5
5
|
import { formatEngineLabel } from "./formatEngineLabel.js";
|
|
6
6
|
import { parseProfileSlot } from "./parseProfileSlot.js";
|
|
7
7
|
export const INVOCATION_RESOLVER_VERSION = "ai-tasks/8.1.16";
|
|
8
|
-
/** Match `@exellix/xynthesis` `
|
|
8
|
+
/** Match `@exellix/xynthesis` `xynthesisWireModelIdFromResolved` — bare OpenRouter API slug for Funcx. */
|
|
9
9
|
export function formatXynthesisWireModelId(provider, modelId) {
|
|
10
10
|
const p = provider.trim();
|
|
11
11
|
const m = modelId.trim();
|
|
@@ -28,16 +28,19 @@ function directModelIdFromInvocation(resolved) {
|
|
|
28
28
|
return formatResolvedProfileModelId(resolved.provider, resolved.modelId);
|
|
29
29
|
}
|
|
30
30
|
function openrouterModelIdFromInvocation(resolved) {
|
|
31
|
-
const or = resolved.invocation?.openrouter;
|
|
32
|
-
if (or
|
|
33
|
-
return or
|
|
34
|
-
}
|
|
31
|
+
const or = resolved.invocation?.openrouter?.modelId?.trim();
|
|
32
|
+
if (or)
|
|
33
|
+
return or;
|
|
35
34
|
if (resolved.routing === "openrouter") {
|
|
35
|
+
const m = resolved.modelId.trim();
|
|
36
|
+
if (m.includes("/"))
|
|
37
|
+
return m;
|
|
36
38
|
return formatResolvedProfileModelId(resolved.provider, resolved.modelId);
|
|
37
39
|
}
|
|
38
40
|
return undefined;
|
|
39
41
|
}
|
|
40
|
-
|
|
42
|
+
/** ai-skills MAIN gateway shape: `openrouter/<vendor>/<model>`. */
|
|
43
|
+
function skillOpenRouterGatewayModelId(resolved) {
|
|
41
44
|
const or = openrouterModelIdFromInvocation(resolved);
|
|
42
45
|
if (!or)
|
|
43
46
|
return undefined;
|
|
@@ -45,18 +48,16 @@ function openrouterWireModelId(resolved) {
|
|
|
45
48
|
}
|
|
46
49
|
function skillWireModelIdFromResolved(resolved) {
|
|
47
50
|
if (resolved.routing === "openrouter") {
|
|
48
|
-
const
|
|
49
|
-
if (
|
|
50
|
-
return
|
|
51
|
+
const gateway = skillOpenRouterGatewayModelId(resolved);
|
|
52
|
+
if (gateway)
|
|
53
|
+
return gateway;
|
|
51
54
|
}
|
|
52
55
|
return formatResolvedProfileModelId(resolved.provider, resolved.modelId);
|
|
53
56
|
}
|
|
54
57
|
function xynthesisWireModelIdFromResolved(resolved) {
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
return orWire;
|
|
59
|
-
}
|
|
58
|
+
const orApi = openrouterModelIdFromInvocation(resolved);
|
|
59
|
+
if (orApi)
|
|
60
|
+
return orApi;
|
|
60
61
|
return formatXynthesisWireModelId(resolved.provider, resolved.modelId);
|
|
61
62
|
}
|
|
62
63
|
function profileWarnings(resolved) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resolveProfileInvocationRouting.js","sourceRoot":"","sources":["../../src/invocation/resolveProfileInvocationRouting.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAEtE,OAAO,EAAE,sBAAsB,EAAE,MAAM,qCAAqC,CAAC;AAC7E,OAAO,EACL,4BAA4B,EAC5B,sBAAsB,EACtB,4BAA4B,GAC7B,MAAM,kCAAkC,CAAC;AAC1C,OAAO,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AAChE,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAGzD,MAAM,CAAC,MAAM,2BAA2B,GAAG,iBAAiB,CAAC;AAwB7D,
|
|
1
|
+
{"version":3,"file":"resolveProfileInvocationRouting.js","sourceRoot":"","sources":["../../src/invocation/resolveProfileInvocationRouting.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
# `@x12i/funcx` — OpenRouter `model` pass-through (no defect; optional hardening)
|
|
2
|
+
|
|
3
|
+
Status: **informational — not a funcx bug; xynthesis fix in 4.1.8 verified**
|
|
4
|
+
Filed by: `@exellix/ai-tasks` (8.2.x)
|
|
5
|
+
Context: investigation of OpenRouter **400 invalid model ID** on xynthesis PRE/POST hops (resolved upstream)
|
|
6
|
+
Primary report: [`xynthesis-openrouter-wire-model-double-prefix-bug.md`](./xynthesis-openrouter-wire-model-double-prefix-bug.md)
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## Summary
|
|
11
|
+
|
|
12
|
+
During live E2E (`test/e2e/ai-profiles-live.test.ts`), OpenRouter rejected:
|
|
13
|
+
|
|
14
|
+
```text
|
|
15
|
+
openrouter/google/gemini-2.5-flash-lite is not a valid model ID
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Tracing the call stack shows **funcx sends exactly the `model` string it receives** from `@exellix/xynthesis` **`FuncxInvoker.askFuncx`** — no transformation, strip, or re-prefix inside funcx.
|
|
19
|
+
|
|
20
|
+
**Fix belongs in xynthesis** (`wireModelId` formatting). **Do not** add a funcx workaround that strips `openrouter/` unless funcx explicitly documents that callers may send gateway-shaped ids (that would hide upstream bugs).
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## Call chain (verified)
|
|
25
|
+
|
|
26
|
+
| Layer | Responsibility |
|
|
27
|
+
|-------|----------------|
|
|
28
|
+
| ai-tasks | Passes ai-profiles **alias** on `llmCall.model` / `executeXynthesisAction({ model: "cheap" })` |
|
|
29
|
+
| xynthesis | `resolveXynthesisModel` → **`wireModelId`** (bug: double `openrouter/` prefix) |
|
|
30
|
+
| xynthesis `FuncxInvoker` | `client.ask(userPrompt, { model: resolved.wireModelId, … })` |
|
|
31
|
+
| funcx | Forwards `model` to `https://openrouter.ai/api/v1/chat/completions` |
|
|
32
|
+
| OpenRouter | Expects slug like `google/gemini-2.5-flash-lite` |
|
|
33
|
+
|
|
34
|
+
Funcx activity log (from live run) shows the invalid model in the **request body** — same value xynthesis supplied:
|
|
35
|
+
|
|
36
|
+
```json
|
|
37
|
+
{
|
|
38
|
+
"url": "https://openrouter.ai/api/v1/chat/completions",
|
|
39
|
+
"body": {
|
|
40
|
+
"model": "openrouter/google/gemini-2.5-flash-lite"
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
---
|
|
46
|
+
|
|
47
|
+
## Why this is not a funcx defect
|
|
48
|
+
|
|
49
|
+
1. **Contract:** Funcx OpenRouter backend accepts a **provider model slug** for the REST API. It is not funcx’s job to guess whether the caller meant gateway notation vs API notation.
|
|
50
|
+
|
|
51
|
+
2. **Correct upstream already exists:** `@x12i/ai-profiles` **≥ 1.8.0** exposes the correct slug on **`ResolvedAIProfile.invocation.openrouter.modelId`**. Xynthesis should use that for Funcx, not re-wrap with `openrouter/`.
|
|
52
|
+
|
|
53
|
+
3. **Silent correction in funcx would be harmful:** Stripping `openrouter/` inside funcx could mask bugs in other callers and make debugging harder.
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
|
|
57
|
+
## Optional enhancements (funcx — low priority, not required for this incident)
|
|
58
|
+
|
|
59
|
+
If funcx wants better operator experience **without** changing wire behavior:
|
|
60
|
+
|
|
61
|
+
### O1 — Document OpenRouter `model` field
|
|
62
|
+
|
|
63
|
+
In README / `Client.ask` JSDoc, state explicitly:
|
|
64
|
+
|
|
65
|
+
- OpenRouter backend: **`model`** must be the **OpenRouter API model id** (e.g. `google/gemini-2.5-flash-lite`, `anthropic/claude-sonnet-4.5`).
|
|
66
|
+
- **Not** the ai-skills gateway form `openrouter/<vendor>/<model>`.
|
|
67
|
+
|
|
68
|
+
### O2 — Fail fast on obvious gateway-shaped ids (optional)
|
|
69
|
+
|
|
70
|
+
When `backend === "openrouter"` and `model.startsWith("openrouter/")`, throw a **clear, named error** before HTTP:
|
|
71
|
+
|
|
72
|
+
```text
|
|
73
|
+
Funcx OpenRouter backend: model must be a bare OpenRouter slug (got gateway-shaped "openrouter/…").
|
|
74
|
+
Resolve via @x12i/ai-profiles invocation.openrouter.modelId or fix upstream wire formatting.
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
**Pros:** Surfaces misconfiguration immediately; points to xynthesis/ai-skills boundary.
|
|
78
|
+
**Cons:** Breaking if any caller intentionally relied on funcx to accept gateway ids (none known).
|
|
79
|
+
|
|
80
|
+
### O3 — Include requested model in `AI_ACTIVITY_FAILED` diagnostics
|
|
81
|
+
|
|
82
|
+
Already partially present in activity logs. Ensure **`request.body.model`** is always in structured diagnostics for 400 responses (helps cross-package RCA).
|
|
83
|
+
|
|
84
|
+
---
|
|
85
|
+
|
|
86
|
+
## Paste-ready GitHub issue (funcx repo) — **optional, enhancement only**
|
|
87
|
+
|
|
88
|
+
**Title:** Document OpenRouter `ask({ model })` must use bare API slug; optional guard against `openrouter/` prefix
|
|
89
|
+
|
|
90
|
+
**Type:** Documentation (+ optional DX guard)
|
|
91
|
+
|
|
92
|
+
**Body:** Summarize O1–O2 above. Link xynthesis fix as primary resolution.
|
|
93
|
+
|
|
94
|
+
**Acceptance criteria:**
|
|
95
|
+
|
|
96
|
+
- [ ] README documents valid OpenRouter model id format.
|
|
97
|
+
- [ ] (Optional) Named error when `model.startsWith("openrouter/")` on OpenRouter backend.
|
|
98
|
+
- [ ] No automatic rewrite/strip of model ids (avoid masking upstream bugs).
|
|
99
|
+
|
|
100
|
+
---
|
|
101
|
+
|
|
102
|
+
## Related
|
|
103
|
+
|
|
104
|
+
- [`xynthesis-openrouter-wire-model-double-prefix-bug.md`](./xynthesis-openrouter-wire-model-double-prefix-bug.md) — **fix here first**
|
|
105
|
+
- [`funcx-upstream-github-issues-draft.md`](../funcx-upstream-github-issues-draft.md) — other funcx tracking
|
package/documenations/upstream-feature-requests/xynthesis-openrouter-wire-model-double-prefix-bug.md
ADDED
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
# `@exellix/xynthesis` — OpenRouter wire model double-prefix (400 invalid model ID)
|
|
2
|
+
|
|
3
|
+
Status: **fixed in `@exellix/xynthesis` ≥ 4.1.8**
|
|
4
|
+
Filed by: `@exellix/ai-tasks` (8.2.x)
|
|
5
|
+
Reproduced with: `@x12i/ai-profiles` **≥ 1.8.0**, `@exellix/xynthesis` **4.1.7** (broken), **4.1.8+** (fixed), `@x12i/funcx` **4.3.0**
|
|
6
|
+
Live test: `test/e2e/ai-profiles-live.test.ts` → `npm run test:live`
|
|
7
|
+
Verified: **2026-05-31** — all 8 live ai-profiles tests pass on **xynthesis 4.1.8** (wire id `google/gemini-2.5-flash-lite`, real POST-step LLM OK).
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## Summary
|
|
12
|
+
|
|
13
|
+
When **`PREFER_OPENROUTER`** routing is active, xynthesis PRE/POST hops resolve an ai-profiles alias (e.g. `cheap`) and pass a **wire model id** to **`FuncxInvoker`** → **`client.ask({ model })`**. That wire id is incorrectly formatted as **`openrouter/<openrouter-api-slug>`** instead of the **bare OpenRouter API slug** returned by ai-profiles.
|
|
14
|
+
|
|
15
|
+
OpenRouter responds **400**:
|
|
16
|
+
|
|
17
|
+
```json
|
|
18
|
+
{
|
|
19
|
+
"error": {
|
|
20
|
+
"message": "openrouter/google/gemini-2.5-flash-lite is not a valid model ID",
|
|
21
|
+
"code": 400
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Valid slug for that profile choice: **`google/gemini-2.5-flash-lite`**.
|
|
27
|
+
|
|
28
|
+
**Not an ai-profiles bug.** **Not an ai-tasks bug** (ai-tasks passes aliases; xynthesis resolves at invoke time). **Not a funcx bug** (funcx forwards the model string it receives).
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
## Impact
|
|
33
|
+
|
|
34
|
+
| Path | Symptom |
|
|
35
|
+
|------|---------|
|
|
36
|
+
| `executeXynthesisAction` with alias `model` (`cheap`, `balanced`, …) + OpenRouter key | **400** from OpenRouter; POST audit/polish/scoping/PRE synthesis fails |
|
|
37
|
+
| `@exellix/ai-tasks` `runPostStepLlmCall` | Same — all xynthesis-backed post steps |
|
|
38
|
+
| MAIN skill via `@exellix/ai-skills` | **Unaffected** — ai-skills expects gateway shape `openrouter/<vendor>/<model>` |
|
|
39
|
+
|
|
40
|
+
---
|
|
41
|
+
|
|
42
|
+
## Reproduction
|
|
43
|
+
|
|
44
|
+
### Minimal (ai-tasks live test)
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
# Requires OPENROUTER_API_KEY (or OPEN_ROUTER_KEY) and network
|
|
48
|
+
cd ai-tasks
|
|
49
|
+
npm run test:live
|
|
50
|
+
# Fails: diagnostic + real LLM tests until xynthesis is fixed
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Or:
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
RUN_LIVE_AI_E2E=1 node --test dist-test/test/e2e/ai-profiles-live.test.js
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### Resolution chain (alias `cheap`, OpenRouter routing)
|
|
60
|
+
|
|
61
|
+
| Step | Component | Value |
|
|
62
|
+
|------|-----------|-------|
|
|
63
|
+
| 1 | `@x12i/ai-profiles` `resolveAIProfile("cheap")` → `invocation.openrouter.modelId` | `google/gemini-2.5-flash-lite` ✓ |
|
|
64
|
+
| 2 | `@exellix/xynthesis` `resolveXynthesisModel("cheap").wireModelId` | `openrouter/google/gemini-2.5-flash-lite` ✗ |
|
|
65
|
+
| 3 | `@x12i/funcx` HTTP body `model` | `openrouter/google/gemini-2.5-flash-lite` (pass-through) |
|
|
66
|
+
| 4 | OpenRouter API | **400 invalid model ID** |
|
|
67
|
+
|
|
68
|
+
Observed Funcx request body (from live run):
|
|
69
|
+
|
|
70
|
+
```json
|
|
71
|
+
{
|
|
72
|
+
"model": "openrouter/google/gemini-2.5-flash-lite",
|
|
73
|
+
"messages": [ … ]
|
|
74
|
+
}
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
---
|
|
78
|
+
|
|
79
|
+
## Root cause (xynthesis `@exellix/xynthesis` **4.1.7**)
|
|
80
|
+
|
|
81
|
+
**File:** `src/resolveAiProfileModel.ts`
|
|
82
|
+
|
|
83
|
+
1. `openrouterModelIdFromInvocation()` correctly reads ai-profiles **`invocation.openrouter.modelId`** (bare slug when it contains `/`).
|
|
84
|
+
|
|
85
|
+
2. **`openrouterWireModelId()`** then **always prepends** `openrouter/`:
|
|
86
|
+
|
|
87
|
+
```ts
|
|
88
|
+
function openrouterWireModelId(resolved: ResolvedAIProfile): string | undefined {
|
|
89
|
+
const or = openrouterModelIdFromInvocation(resolved);
|
|
90
|
+
if (!or) return undefined;
|
|
91
|
+
return or.startsWith("openrouter/") ? or : `openrouter/${or}`; // ← bug
|
|
92
|
+
}
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
3. **`xynthesisWireModelIdFromResolved()`** uses that helper for OpenRouter-routed profiles:
|
|
96
|
+
|
|
97
|
+
```ts
|
|
98
|
+
export function xynthesisWireModelIdFromResolved(resolved: ResolvedAIProfile): string {
|
|
99
|
+
if (resolved.routing === "openrouter") {
|
|
100
|
+
const orWire = openrouterWireModelId(resolved);
|
|
101
|
+
if (orWire) return orWire;
|
|
102
|
+
}
|
|
103
|
+
return toOpenRouterModelId(resolved.provider, resolved.modelId);
|
|
104
|
+
}
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
4. **`FuncxInvoker.askFuncx`** passes `wireModelId` directly to OpenRouter:
|
|
108
|
+
|
|
109
|
+
```ts
|
|
110
|
+
return client.ask(opts.userPrompt, {
|
|
111
|
+
model: resolved.wireModelId, // must be bare OR slug, not openrouter/…
|
|
112
|
+
…
|
|
113
|
+
});
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
### Why two wire shapes exist
|
|
117
|
+
|
|
118
|
+
| Consumer | Expected model shape | Example |
|
|
119
|
+
|----------|---------------------|---------|
|
|
120
|
+
| **ai-skills MAIN** (gateway) | `openrouter/<vendor>/<model>` | `openrouter/anthropic/claude-sonnet-4.5` |
|
|
121
|
+
| **Funcx OpenRouter backend** (REST API) | bare OpenRouter slug | `google/gemini-2.5-flash-lite` |
|
|
122
|
+
|
|
123
|
+
Xynthesis conflates the **gateway** prefix rule with the **OpenRouter API** slug rule on the Funcx path.
|
|
124
|
+
|
|
125
|
+
---
|
|
126
|
+
|
|
127
|
+
## Recommended fix (xynthesis)
|
|
128
|
+
|
|
129
|
+
**In `xynthesisWireModelIdFromResolved` (Funcx / PRE/POST path):**
|
|
130
|
+
|
|
131
|
+
- Use **`resolved.invocation.openrouter.modelId`** as-is when present.
|
|
132
|
+
- Fallback: when `resolved.routing === "openrouter"` and `resolved.modelId` already contains `/`, return **`resolved.modelId`** (not `openrouter/${modelId}`).
|
|
133
|
+
- Only use `toOpenRouterModelId(provider, modelId)` for **vendor-direct** routing.
|
|
134
|
+
|
|
135
|
+
**Do not** prepend `openrouter/` on the Funcx invoke path.
|
|
136
|
+
|
|
137
|
+
**Remove or restrict** `openrouterWireModelId()` so it is not used for xynthesis wire ids (it may remain useful only if a future gateway-shaped export is needed elsewhere).
|
|
138
|
+
|
|
139
|
+
### Tests to add (xynthesis)
|
|
140
|
+
|
|
141
|
+
In `test/resolveAiProfileModel.unit.ts` (or new file):
|
|
142
|
+
|
|
143
|
+
```ts
|
|
144
|
+
const cheapOr = await resolveXynthesisModel("cheap", {
|
|
145
|
+
source: "bundled",
|
|
146
|
+
preferOpenRouter: true,
|
|
147
|
+
openrouterApiKeyPresent: true,
|
|
148
|
+
});
|
|
149
|
+
assert.equal(cheapOr?.routing, "openrouter");
|
|
150
|
+
assert.ok(cheapOr?.wireModelId.includes("/"));
|
|
151
|
+
assert.ok(!cheapOr!.wireModelId.startsWith("openrouter/"));
|
|
152
|
+
assert.equal(
|
|
153
|
+
cheapOr?.wireModelId,
|
|
154
|
+
cheapOr?.profile.invocation?.openrouter?.modelId
|
|
155
|
+
);
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
Optional integration test: mock Funcx `client.ask` and assert `model` is bare slug.
|
|
159
|
+
|
|
160
|
+
---
|
|
161
|
+
|
|
162
|
+
## ai-tasks alignment (diagnostics only)
|
|
163
|
+
|
|
164
|
+
`@exellix/ai-tasks` **`resolveProfileInvocationRouting`** mirrored the same double-prefix for **`phaseKind: "xynthesis"`** in observability logs (`LLM_PROVIDER_INVOCATION`). That affects **diagnostics only** — the HTTP payload is built inside xynthesis. ai-tasks should align xynthesis-phase diagnostics with the fixed wire shape once xynthesis ships.
|
|
165
|
+
|
|
166
|
+
Skill phase (`phaseKind: "skill"`) should **keep** `openrouter/` gateway prefix for ai-skills MAIN.
|
|
167
|
+
|
|
168
|
+
---
|
|
169
|
+
|
|
170
|
+
## Paste-ready GitHub issue (xynthesis repo)
|
|
171
|
+
|
|
172
|
+
**Title:** `resolveXynthesisModel`: Funcx OpenRouter wire id must use bare API slug, not `openrouter/` prefix
|
|
173
|
+
|
|
174
|
+
**Labels:** `bug`, `openrouter`, `ai-profiles`
|
|
175
|
+
|
|
176
|
+
**Body:** Use the Summary, Reproduction, and Recommended fix sections above.
|
|
177
|
+
|
|
178
|
+
**Acceptance criteria:**
|
|
179
|
+
|
|
180
|
+
- [ ] `resolveXynthesisModel("cheap", { preferOpenRouter: true })` → `wireModelId` equals ai-profiles `invocation.openrouter.modelId` (no `openrouter/` prefix).
|
|
181
|
+
- [ ] Live OpenRouter call with alias `cheap` succeeds (200, non-empty completion).
|
|
182
|
+
- [ ] Vendor-direct routing (`preferOpenRouter: false`) unchanged.
|
|
183
|
+
- [ ] Changelog entry; semver patch or minor per release policy.
|
|
184
|
+
|
|
185
|
+
---
|
|
186
|
+
|
|
187
|
+
## Related
|
|
188
|
+
|
|
189
|
+
- [`.docs/prefer-openrouter-routing-policy.md`](../../.docs/prefer-openrouter-routing-policy.md)
|
|
190
|
+
- [`funcx-openrouter-model-id-pass-through.md`](./funcx-openrouter-model-id-pass-through.md) — funcx is pass-through; no fix required there
|
|
191
|
+
- [`xynthesis-upstream-fixes-checklist.md`](../xynthesis-upstream-fixes-checklist.md)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@exellix/ai-tasks",
|
|
3
|
-
"version": "8.2.
|
|
3
|
+
"version": "8.2.9",
|
|
4
4
|
"description": "Task orchestration for the Exellix stack: runTask() with local handlers or LLM-backed execution, task-scoped memory/context enrichment, and executor dispatch via @exellix/ai-skills. ERC-compliant.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -60,12 +60,13 @@
|
|
|
60
60
|
},
|
|
61
61
|
"overrides": {
|
|
62
62
|
"@x12i/activix": "$@x12i/activix",
|
|
63
|
+
"@x12i/ai-profiles": "$@x12i/ai-profiles",
|
|
63
64
|
"@x12i/catalox": "$@x12i/catalox",
|
|
64
65
|
"@x12i/funcx": "$@x12i/funcx",
|
|
65
66
|
"@x12i/logxer": "$@x12i/logxer"
|
|
66
67
|
},
|
|
67
68
|
"dependencies": {
|
|
68
|
-
"@exellix/ai-skills": "^5.9.
|
|
69
|
+
"@exellix/ai-skills": "^5.9.8",
|
|
69
70
|
"@exellix/memorix-narrix-adapter": "^2.0.0",
|
|
70
71
|
"@exellix/narrix-adapter-chat": "^2.0.0",
|
|
71
72
|
"@exellix/narrix-adapter-docs": "^2.0.0",
|
|
@@ -77,13 +78,13 @@
|
|
|
77
78
|
"@exellix/narrix-ingest": "^2.0.0",
|
|
78
79
|
"@exellix/narrix-runner": "^2.0.0",
|
|
79
80
|
"@exellix/narrix-web-scoper": "^2.0.0",
|
|
80
|
-
"@exellix/xynthesis": "^4.1.
|
|
81
|
+
"@exellix/xynthesis": "^4.1.8",
|
|
81
82
|
"@x12i/activix": "^8.5.0",
|
|
82
|
-
"@x12i/ai-profiles": "^1.
|
|
83
|
+
"@x12i/ai-profiles": "^1.8.0",
|
|
83
84
|
"@x12i/catalox": "^5.1.3",
|
|
84
85
|
"@x12i/env": "^4.0.1",
|
|
85
86
|
"@x12i/execution-memory-manager": "^1.2.0",
|
|
86
|
-
"@x12i/funcx": "^4.
|
|
87
|
+
"@x12i/funcx": "^4.3.0",
|
|
87
88
|
"@x12i/logxer": "^4.6.0",
|
|
88
89
|
"@x12i/rendrix": "^4.3.0",
|
|
89
90
|
"@x12i/search-adapter": "^1.5.1",
|