@exellix/ai-tasks 8.2.5 → 8.4.0
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 +28 -0
- package/README.md +17 -13
- package/RUNTASK_REQUEST.md +3 -3
- package/dist/aiSkillsUpstreamExports.d.ts +1 -1
- package/dist/aiSkillsUpstreamExports.d.ts.map +1 -1
- package/dist/aiSkillsUpstreamExports.js +1 -1
- package/dist/aiSkillsUpstreamExports.js.map +1 -1
- package/dist/analysis/analyzeRunTaskRequest.d.ts +2 -2
- package/dist/analysis/analyzeRunTaskRequest.d.ts.map +1 -1
- package/dist/analysis/analyzeRunTaskRequest.js +11 -4
- package/dist/analysis/analyzeRunTaskRequest.js.map +1 -1
- package/dist/builders/task-request-builder.d.ts +9 -12
- package/dist/builders/task-request-builder.d.ts.map +1 -1
- package/dist/builders/task-request-builder.js +22 -15
- package/dist/builders/task-request-builder.js.map +1 -1
- package/dist/compile/compileTaskConfiguration.d.ts.map +1 -1
- package/dist/compile/compileTaskConfiguration.js +4 -3
- package/dist/compile/compileTaskConfiguration.js.map +1 -1
- package/dist/core/task-sdk.d.ts.map +1 -1
- package/dist/core/task-sdk.js +10 -11
- package/dist/core/task-sdk.js.map +1 -1
- package/dist/errors/modelConfigRequiredError.d.ts +9 -0
- package/dist/errors/modelConfigRequiredError.d.ts.map +1 -0
- package/dist/errors/modelConfigRequiredError.js +20 -0
- package/dist/errors/modelConfigRequiredError.js.map +1 -0
- package/dist/errors/runTaskExecutionError.d.ts +2 -1
- package/dist/errors/runTaskExecutionError.d.ts.map +1 -1
- package/dist/errors/runTaskExecutionError.js +1 -1
- package/dist/errors/runTaskExecutionError.js.map +1 -1
- package/dist/index.d.ts +4 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -3
- package/dist/index.js.map +1 -1
- package/dist/internal/resolveLlmCallForXynthesis.d.ts +17 -40
- package/dist/internal/resolveLlmCallForXynthesis.d.ts.map +1 -1
- package/dist/internal/resolveLlmCallForXynthesis.js +15 -55
- package/dist/internal/resolveLlmCallForXynthesis.js.map +1 -1
- package/dist/internal/runPostStepLlmCall.d.ts +3 -17
- package/dist/internal/runPostStepLlmCall.d.ts.map +1 -1
- package/dist/internal/runPostStepLlmCall.js +31 -30
- package/dist/internal/runPostStepLlmCall.js.map +1 -1
- package/dist/invocation/defaultAiProfilesResolveOptions.d.ts +27 -0
- package/dist/invocation/defaultAiProfilesResolveOptions.d.ts.map +1 -0
- package/dist/invocation/defaultAiProfilesResolveOptions.js +43 -0
- package/dist/invocation/defaultAiProfilesResolveOptions.js.map +1 -0
- package/dist/invocation/resolveProfileInvocationRouting.d.ts +5 -3
- package/dist/invocation/resolveProfileInvocationRouting.d.ts.map +1 -1
- package/dist/invocation/resolveProfileInvocationRouting.js +30 -19
- package/dist/invocation/resolveProfileInvocationRouting.js.map +1 -1
- package/dist/logxer/packageLogxers.d.ts +0 -1
- package/dist/logxer/packageLogxers.d.ts.map +1 -1
- package/dist/observability/classifyRunTaskFailure.js +2 -2
- package/dist/observability/classifyRunTaskFailure.js.map +1 -1
- package/dist/observability/logLlmProviderInvocation.d.ts +1 -2
- package/dist/observability/logLlmProviderInvocation.d.ts.map +1 -1
- package/dist/observability/logLlmProviderInvocation.js +3 -3
- package/dist/observability/logLlmProviderInvocation.js.map +1 -1
- package/dist/packaged-tasks-client.js +1 -1
- package/dist/packaged-tasks-client.js.map +1 -1
- package/dist/post-steps/audit/runAudit.d.ts.map +1 -1
- package/dist/post-steps/audit/runAudit.js +6 -16
- package/dist/post-steps/audit/runAudit.js.map +1 -1
- package/dist/post-steps/polish/runPolish.d.ts +2 -0
- package/dist/post-steps/polish/runPolish.d.ts.map +1 -1
- package/dist/post-steps/polish/runPolish.js +5 -9
- package/dist/post-steps/polish/runPolish.js.map +1 -1
- package/dist/post-steps/resolvePostStepConfig.d.ts +4 -35
- package/dist/post-steps/resolvePostStepConfig.d.ts.map +1 -1
- package/dist/post-steps/resolvePostStepConfig.js +9 -36
- package/dist/post-steps/resolvePostStepConfig.js.map +1 -1
- package/dist/strategies/direct-execution-strategy.d.ts.map +1 -1
- package/dist/strategies/direct-execution-strategy.js +6 -3
- package/dist/strategies/direct-execution-strategy.js.map +1 -1
- package/dist/synthesis/runStructuredSynthesisRobust.d.ts +0 -1
- package/dist/synthesis/runStructuredSynthesisRobust.d.ts.map +1 -1
- package/dist/synthesis/runStructuredSynthesisRobust.js +20 -58
- package/dist/synthesis/runStructuredSynthesisRobust.js.map +1 -1
- package/dist/types/index.d.ts +1 -1
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/llmCall.d.ts +18 -47
- package/dist/types/llmCall.d.ts.map +1 -1
- package/dist/types/llmCall.js +1 -10
- package/dist/types/llmCall.js.map +1 -1
- package/dist/types/model-config.d.ts +22 -9
- package/dist/types/model-config.d.ts.map +1 -1
- package/dist/types/model-config.js +62 -13
- package/dist/types/model-config.js.map +1 -1
- package/dist/types/task-types.d.ts +16 -12
- package/dist/types/task-types.d.ts.map +1 -1
- package/dist/types/task-types.js.map +1 -1
- package/dist/utilities/runUtility.d.ts.map +1 -1
- package/dist/utilities/runUtility.js +8 -11
- package/dist/utilities/runUtility.js.map +1 -1
- package/dist/utils/aiProfileModelFormat.d.ts.map +1 -1
- package/dist/utils/aiProfileModelFormat.js +8 -65
- package/dist/utils/aiProfileModelFormat.js.map +1 -1
- package/dist/utils/resolveAiProfileModel.d.ts +5 -2
- package/dist/utils/resolveAiProfileModel.d.ts.map +1 -1
- package/dist/utils/resolveAiProfileModel.js +3 -1
- package/dist/utils/resolveAiProfileModel.js.map +1 -1
- package/dist/utils/resolveRunTaskModelReferences.d.ts +1 -1
- package/dist/utils/resolveRunTaskModelReferences.d.ts.map +1 -1
- package/dist/utils/resolveRunTaskModelReferences.js +8 -3
- package/dist/utils/resolveRunTaskModelReferences.js.map +1 -1
- package/dist/utils/routeModelConfigSlots.d.ts +1 -1
- package/dist/utils/routeModelConfigSlots.d.ts.map +1 -1
- package/dist/utils/routeModelConfigSlots.js +1 -1
- package/dist/utils/routeModelConfigSlots.js.map +1 -1
- package/dist/validation/helpers.d.ts +5 -2
- package/dist/validation/helpers.d.ts.map +1 -1
- package/dist/validation/helpers.js +65 -22
- package/dist/validation/helpers.js.map +1 -1
- package/dist/validation/types.d.ts +1 -1
- package/dist/validation/types.d.ts.map +1 -1
- package/dist/validation/validateRunTaskConfig.d.ts.map +1 -1
- package/dist/validation/validateRunTaskConfig.js +2 -1
- package/dist/validation/validateRunTaskConfig.js.map +1 -1
- package/documenations/upstream-feature-requests/README.md +21 -0
- package/documenations/upstream-feature-requests/ai-skills-orchestrator-invoke-contract-5.9.md +151 -0
- package/documenations/upstream-feature-requests/ai-tasks-wrap-up-after-upstream.md +126 -0
- 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/documenations/upstream-feature-requests/xynthesis-orchestrator-invoke-contract-4.2.md +175 -0
- package/package.json +6 -5
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# Upstream feature requests (from `@exellix/ai-tasks`)
|
|
2
|
+
|
|
3
|
+
Fix reports filed for sibling packages. Hand these to the package owners; after they ship, complete the ai-tasks wrap-up.
|
|
4
|
+
|
|
5
|
+
## Invoke contract (8.4+) — **current priority**
|
|
6
|
+
|
|
7
|
+
| Package | Document | Status |
|
|
8
|
+
|---------|----------|--------|
|
|
9
|
+
| `@exellix/ai-skills` ≥ 5.9 | [ai-skills-orchestrator-invoke-contract-5.9.md](./ai-skills-orchestrator-invoke-contract-5.9.md) | **open** — `reasoningEffort` on request |
|
|
10
|
+
| `@exellix/xynthesis` ≥ 4.2 | [xynthesis-orchestrator-invoke-contract-4.2.md](./xynthesis-orchestrator-invoke-contract-4.2.md) | **open** — `reasoningEffort`, temperature/topP audit, docs |
|
|
11
|
+
| `@exellix/ai-tasks` | [ai-tasks-wrap-up-after-upstream.md](./ai-tasks-wrap-up-after-upstream.md) | **blocked** on above |
|
|
12
|
+
|
|
13
|
+
## Older / parallel tracks
|
|
14
|
+
|
|
15
|
+
| Package | Document |
|
|
16
|
+
|---------|----------|
|
|
17
|
+
| `@exellix/ai-skills` | [ai-skills-llm-observability.md](./ai-skills-llm-observability.md) |
|
|
18
|
+
| `@exellix/xynthesis` | [xynthesis-llm-observability.md](./xynthesis-llm-observability.md) |
|
|
19
|
+
| `@x12i/logxer` | [logxer-failure-classification-and-causal-diagnostics.md](./logxer-failure-classification-and-causal-diagnostics.md) |
|
|
20
|
+
| `@x12i/funcx` | [funcx-openrouter-model-id-pass-through.md](./funcx-openrouter-model-id-pass-through.md) |
|
|
21
|
+
| `@exellix/xynthesis` | [xynthesis-openrouter-wire-model-double-prefix-bug.md](./xynthesis-openrouter-wire-model-double-prefix-bug.md) |
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
# `@exellix/ai-skills` — orchestrator invoke contract fixes (≥ 5.9)
|
|
2
|
+
|
|
3
|
+
Status: **open** — blocks clean `@exellix/ai-tasks` 8.4+ integration
|
|
4
|
+
Owner: `@exellix/ai-skills`
|
|
5
|
+
Filed by: `@exellix/ai-tasks`
|
|
6
|
+
Consumer: `@exellix/ai-tasks` 8.4.0, graph-engine 7.x (`RunTaskRequest.modelConfig` triplet)
|
|
7
|
+
Pinned in ai-tasks today: `@exellix/ai-skills@5.9.11`
|
|
8
|
+
|
|
9
|
+
Related (older, partially superseded): [`ai-skills-llm-observability.md`](./ai-skills-llm-observability.md)
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## Summary
|
|
14
|
+
|
|
15
|
+
**MAIN** skill invocation should follow the same contract as xynthesis 4.2+:
|
|
16
|
+
|
|
17
|
+
| Orchestrator sends | Package owns internally |
|
|
18
|
+
|--------------------|-------------------------|
|
|
19
|
+
| Wire **model** (`model` / `modelId`) | — |
|
|
20
|
+
| **temperature**, **topP**, other sampling knobs | — |
|
|
21
|
+
| **reasoningEffort** (for Optimixer / provider) | — |
|
|
22
|
+
| — | **max completion tokens** (Optimixer + Catalox catalog) |
|
|
23
|
+
|
|
24
|
+
ai-skills **5.9.11 already enforces the right side** (`ModelConfig.maxTokens?: never`, Optimixer merge before invoke). The remaining gap is the **left side**: the public request must **ask for `reasoningEffort`**, not only read it from Catalox.
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## Already correct in 5.9.11 (no change needed)
|
|
29
|
+
|
|
30
|
+
### 1. Caller must not set completion token caps on `ModelConfig`
|
|
31
|
+
|
|
32
|
+
- `ModelConfig.maxTokens` is typed `never` and validated/rejected at invoke.
|
|
33
|
+
- `mergeOptimixerPredictionIntoModelConfig` / `skills-optimixer` set the effective cap.
|
|
34
|
+
- Trace echo uses `maxTokensRequested` on `SkillDiagnosticsTrace`, not `invokeRequest.modelConfig.maxTokens`.
|
|
35
|
+
|
|
36
|
+
**Acceptance (already met):** Hosts that pass `modelConfig: { model, temperature, topP }` without `maxTokens` succeed; hosts that pass `maxTokens` get a clear rejection or strip + anomaly log.
|
|
37
|
+
|
|
38
|
+
### 2. Catalox catalog carries Optimixer metadata
|
|
39
|
+
|
|
40
|
+
- `SkillOptimixerCatalogSpec` includes mandatory `reasoningEffort`, `outputIntent`, etc. (`skill-optimixer-catalog.ts`).
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
## Required fixes
|
|
45
|
+
|
|
46
|
+
### 1. Accept `reasoningEffort` on `RunSkillRequest` (or explicit `ModelConfig` extension)
|
|
47
|
+
|
|
48
|
+
#### Today
|
|
49
|
+
|
|
50
|
+
- `reasoningEffort` exists only on the **Catalox `ai-skills` catalog row** (`SkillOptimixerCatalogSpec.reasoningEffort`).
|
|
51
|
+
- `RunSkillRequest` / `ModelConfig` expose `model`, `temperature`, `topP`, … but **no `reasoningEffort`**.
|
|
52
|
+
- `@exellix/ai-tasks` has nothing to forward from graph-engine / `llmCall` even when the operator configures it per task.
|
|
53
|
+
|
|
54
|
+
#### Why it hurts
|
|
55
|
+
|
|
56
|
+
Orchestrators (graph-engine, ai-tasks) are the **source of truth** for per-node tuning. Catalog defaults are not enough when one skill key is reused with different reasoning depth per graph node. xynthesis 4.2 already threads `reasoningEffort` into Optimixer predict input internally; ai-skills should expose the same knob on the **host-facing** API.
|
|
57
|
+
|
|
58
|
+
#### Asked behavior
|
|
59
|
+
|
|
60
|
+
Add optional:
|
|
61
|
+
|
|
62
|
+
```typescript
|
|
63
|
+
import type { OptimixerReasoningEffort } from "@x12i/optimixer";
|
|
64
|
+
|
|
65
|
+
// Option A — on ModelConfig (preferred for parity with temperature/topP):
|
|
66
|
+
interface ModelConfig {
|
|
67
|
+
// ...existing fields...
|
|
68
|
+
reasoningEffort?: OptimixerReasoningEffort;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Option B — top-level on RunSkillRequest:
|
|
72
|
+
interface RunSkillRequest {
|
|
73
|
+
reasoningEffort?: OptimixerReasoningEffort;
|
|
74
|
+
}
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
**Resolution order** (document and implement consistently):
|
|
78
|
+
|
|
79
|
+
1. Request override (`modelConfig.reasoningEffort` or `RunSkillRequest.reasoningEffort`)
|
|
80
|
+
2. Catalox `SkillOptimixerCatalogSpec.reasoningEffort`
|
|
81
|
+
3. Package default (e.g. `"not-applicable"`)
|
|
82
|
+
|
|
83
|
+
Forward the resolved value into `buildAiMaxTokensPredictionInput` / Optimixer predict (same as xynthesis `resolveEffectiveMaxTokens`).
|
|
84
|
+
|
|
85
|
+
#### Acceptance
|
|
86
|
+
|
|
87
|
+
- `runSkill({ modelConfig: { model: "…", reasoningEffort: "high" } })` uses `"high"` in Optimixer predict even when catalog says `"medium"`.
|
|
88
|
+
- Trace / `invokeRequest` echo includes effective `reasoningEffort` (or Optimixer diagnostics slice).
|
|
89
|
+
- Omitting the field keeps today’s catalog-only behavior unchanged.
|
|
90
|
+
|
|
91
|
+
---
|
|
92
|
+
|
|
93
|
+
### 2. Document the orchestrator ↔ MAIN invoke contract (README / BREAKING)
|
|
94
|
+
|
|
95
|
+
Add a short **“Host responsibilities”** section:
|
|
96
|
+
|
|
97
|
+
- **Send:** concrete or resolved wire `model`, optional `temperature`, `topP`, `reasoningEffort`, `timeoutMs`.
|
|
98
|
+
- **Do not send:** `maxTokens`, `max_completion_tokens`, `max_output_tokens` on `modelConfig` (rejected).
|
|
99
|
+
- **Token budget:** owned by Optimixer from catalog + prompts; echo `usage.maxTokensRequested` / `metadata.maxTokensRequested` after invoke.
|
|
100
|
+
|
|
101
|
+
Point `@exellix/ai-tasks` integrators to this section instead of legacy `modelConfig.maxTokens` docs.
|
|
102
|
+
|
|
103
|
+
---
|
|
104
|
+
|
|
105
|
+
### 3. Update §2 in `ai-skills-llm-observability.md` (stale)
|
|
106
|
+
|
|
107
|
+
The open item **“`outputExpectation` passthrough + xynthesis-style auto-sizer on RunSkillRequest”** assumed hosts still set `modelConfig.maxTokens`. With 5.9 Optimixer, revise to:
|
|
108
|
+
|
|
109
|
+
- **Optional:** `outputExpectation` on `RunSkillRequest` to steer Optimixer output intent (parity with xynthesis), **not** to supply a literal token count.
|
|
110
|
+
- **Not asked:** restoring caller `modelConfig.maxTokens`.
|
|
111
|
+
|
|
112
|
+
(Can be a separate FR or folded into §1 if output intent is also catalog-only today.)
|
|
113
|
+
|
|
114
|
+
---
|
|
115
|
+
|
|
116
|
+
## Integration note (5.9.12 — ai-tasks)
|
|
117
|
+
|
|
118
|
+
### `analyzeSkillRequest` root export removed
|
|
119
|
+
|
|
120
|
+
- **Today:** `analyzeSkillRequest(catalox, …)` exists in `dist/analysis/` but is **not** re-exported from `@exellix/ai-skills` package root. Use **`ExellixSkillsClient.analyzeSkillRequest`** (or export the function again from `index.js` for Catalox-only callers).
|
|
121
|
+
- **ai-tasks:** `analyzeRunTaskRequest` uses a short-lived `ExellixSkillsClient` until root export returns.
|
|
122
|
+
|
|
123
|
+
### `testContentRegistryConnection` renamed
|
|
124
|
+
|
|
125
|
+
- Use **`ExellixSkillsClient.testCatalogConnection()`** (Catalox reachability; replaces gateway content-registry check).
|
|
126
|
+
|
|
127
|
+
---
|
|
128
|
+
|
|
129
|
+
## Optional (lower priority)
|
|
130
|
+
|
|
131
|
+
### 4. `SkillExecutionError` in default mode
|
|
132
|
+
|
|
133
|
+
Still valuable; see [`ai-skills-llm-observability.md` §1](./ai-skills-llm-observability.md). Independent of token / reasoning contract.
|
|
134
|
+
|
|
135
|
+
---
|
|
136
|
+
|
|
137
|
+
## Verification checklist (for ai-skills PR)
|
|
138
|
+
|
|
139
|
+
- [ ] TypeScript: `ModelConfig` / `RunSkillRequest` exposes `reasoningEffort`.
|
|
140
|
+
- [ ] Unit test: request override beats catalog default in Optimixer predict input.
|
|
141
|
+
- [ ] Unit test: `modelConfig.maxTokens` still rejected.
|
|
142
|
+
- [ ] README/BREAKING: host must not send max token caps on `modelConfig`.
|
|
143
|
+
|
|
144
|
+
---
|
|
145
|
+
|
|
146
|
+
## After this ships — ai-tasks follow-up
|
|
147
|
+
|
|
148
|
+
See [`ai-tasks-wrap-up-after-upstream.md`](./ai-tasks-wrap-up-after-upstream.md):
|
|
149
|
+
|
|
150
|
+
- Add `reasoningEffort` to `LlmCallConfig` / tuning passthrough → `buildAiSkillsModelConfigForMain`.
|
|
151
|
+
- Stop forwarding any `maxTokens` / `maxTokensCap` to `runSkill`.
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
# `@exellix/ai-tasks` — wrap-up after upstream invoke-contract fixes
|
|
2
|
+
|
|
3
|
+
Status: **blocked** on upstream PRs until both packages ship items in:
|
|
4
|
+
|
|
5
|
+
- [`ai-skills-orchestrator-invoke-contract-5.9.md`](./ai-skills-orchestrator-invoke-contract-5.9.md)
|
|
6
|
+
- [`xynthesis-orchestrator-invoke-contract-4.2.md`](./xynthesis-orchestrator-invoke-contract-4.2.md)
|
|
7
|
+
|
|
8
|
+
Owner: `@exellix/ai-tasks`
|
|
9
|
+
Target release: **8.4.x** (or **8.5.0** if breaking `llmCall` surface)
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## Contract (locked with product)
|
|
14
|
+
|
|
15
|
+
**ai-tasks sends to lower layers:**
|
|
16
|
+
|
|
17
|
+
- Model ids via `RunTaskModelConfig` triplet (`preActionModel`, `skillModel`, `postActionModel`) + optional `llmCall.model` overrides.
|
|
18
|
+
- `temperature`, `topP`, **`reasoningEffort`** (once upstream exposes it).
|
|
19
|
+
- **`outputExpectation`** on xynthesis-backed hops only (sizing intent — **not** a token count).
|
|
20
|
+
|
|
21
|
+
**ai-tasks does not send:**
|
|
22
|
+
|
|
23
|
+
- `maxTokens` / `maxTokensCap` on `modelConfig`, `runSkill`, `executeXynthesisAction`, or direct gateway repair (unless product later revives an explicit ceiling knob with a new name).
|
|
24
|
+
|
|
25
|
+
**Lower layers own:**
|
|
26
|
+
|
|
27
|
+
- MAIN caps → `@exellix/ai-skills` Optimixer + Catalox skill catalog.
|
|
28
|
+
- PRE/POST/scoping/utility caps → `@exellix/xynthesis` `resolveEffectiveMaxTokens` inside `executeXynthesisAction`.
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
## Already done in ai-tasks (this branch)
|
|
33
|
+
|
|
34
|
+
- [x] `RunTaskRequest.modelConfig` typed as `RunTaskModelConfig` (not ai-skills `ModelConfig` with `maxTokens`).
|
|
35
|
+
- [x] Removed `maxTokens` from `RunTaskModelConfig`; strip legacy key at ai-skills boundary.
|
|
36
|
+
- [x] Stopped mapping `llmCall.maxTokensCap` → `modelConfig.maxTokens` in `buildAiSkillsModelConfigForMain`.
|
|
37
|
+
- [x] Trace repair: `mapGatewayInvokeToTrace` uses `maxTokensRequested` only (not `modelConfig.maxTokens`).
|
|
38
|
+
- [x] README / BREAKING-CHANGES partial updates for modelConfig + MAIN Optimixer.
|
|
39
|
+
|
|
40
|
+
---
|
|
41
|
+
|
|
42
|
+
## TODO after upstream ships
|
|
43
|
+
|
|
44
|
+
### 1. Remove broken / duplicate token budgeting
|
|
45
|
+
|
|
46
|
+
| File / area | Change |
|
|
47
|
+
|-------------|--------|
|
|
48
|
+
| `src/internal/resolveLlmCallForXynthesis.ts` | Remove `resolveMaxTokens` import; either delete token resolution or reduce to **outputExpectation-only** helper (rename e.g. `resolveLlmOutputExpectationForXynthesis`). |
|
|
49
|
+
| `src/internal/runPostStepLlmCall.ts` | Drop `maxTokens` / `resolveLlmCallForXynthesis` pre-resolution; pass **`outputExpectation`** (required). |
|
|
50
|
+
| `src/synthesis/runStructuredSynthesisRobust.ts` | Repair path: stop `resolveMaxTokens`; do not push `maxTokens` into raw AIGateway `config` unless gateway documents a non-Optimixer escape hatch. |
|
|
51
|
+
| `src/index.ts` | Stop re-exporting `resolveMaxTokens`; export `resolveEffectiveMaxTokens` only if graph-engine needs it (prefer not). |
|
|
52
|
+
| `src/utilities/runUtility.ts` | Remove `maxTokens` forward to xynthesis finalize. |
|
|
53
|
+
| `src/post-steps/resolvePostStepConfig.ts` | Remove env `*_MAX_TOKENS_CAP` wiring if contract is zero host caps (or keep env as deprecated no-op one release). |
|
|
54
|
+
|
|
55
|
+
### 2. Add `reasoningEffort` to ai-tasks surface
|
|
56
|
+
|
|
57
|
+
| File | Change |
|
|
58
|
+
|------|--------|
|
|
59
|
+
| `src/types/llmCall.ts` | `reasoningEffort?: OptimixerReasoningEffort` (re-export type from `@x12i/optimixer` or xynthesis). |
|
|
60
|
+
| `src/types/model-config.ts` | Optional tuning field; passthrough in `modelConfigTuningPassthrough` (not stripped). |
|
|
61
|
+
| `src/types/task-types.ts` | Document on `llmCall` and post-step configs. |
|
|
62
|
+
| `buildAiSkillsModelConfigForMain` | Forward to ai-skills `modelConfig` when upstream §1 ships. |
|
|
63
|
+
| `runPostStepLlmCall` / `task-sdk` synthesis | Forward to `executeXynthesisAction` / structured params. |
|
|
64
|
+
| `src/validation/helpers.ts` | Optional enum validation if finite set. |
|
|
65
|
+
| `src/builders/task-request-builder.ts` | Document in `withLlmCall` JSDoc. |
|
|
66
|
+
|
|
67
|
+
### 3. Fix xynthesis call sites (no new upstream needed except §1–2)
|
|
68
|
+
|
|
69
|
+
| Call site | Pass |
|
|
70
|
+
|-----------|------|
|
|
71
|
+
| `runPostStepLlmCall` → `executeXynthesisAction` | `outputExpectation`, `temperature`, `topP`, `sidekickAction` / `activixActionType`, `reasoningEffort` (when exists) |
|
|
72
|
+
| PRE structured / markdown synthesis (`task-sdk`) | Same via gateway / `runStructuredSynthesisGatewayCall` params |
|
|
73
|
+
| AI scoping | `outputExpectation` (already defaulted in `runScopingCall`) |
|
|
74
|
+
|
|
75
|
+
### 4. Remove / deprecate `maxTokensCap` on `LlmCallConfig`
|
|
76
|
+
|
|
77
|
+
- **Breaking:** remove `maxTokensCap` from `LlmCallConfig`, `RunUtilityRequest.exec`, post-step env fallbacks, validation, README.
|
|
78
|
+
- **Or soft:** mark deprecated in 8.4.1, ignore at runtime, remove in 8.5.0.
|
|
79
|
+
|
|
80
|
+
Confirm with graph-engine before hard removal.
|
|
81
|
+
|
|
82
|
+
### 5. Tests & docs
|
|
83
|
+
|
|
84
|
+
- [ ] `npm run build` + `tsc -p tsconfig.test.json` green (no `resolveMaxTokens` import).
|
|
85
|
+
- [ ] `npm run test` green (mocks via `setSynthesisInvoker` unchanged).
|
|
86
|
+
- [ ] Update [`README.md`](../../README.md) token-budget section (remove `llmCall.maxTokensCap` → `modelConfig.maxTokens` overlay story).
|
|
87
|
+
- [ ] Update [`ai-skills-llm-observability.md`](./ai-skills-llm-observability.md) §2 (stale maxTokens wording).
|
|
88
|
+
- [ ] Update [`xynthesis-llm-observability.md`](./xynthesis-llm-observability.md) superseded sections.
|
|
89
|
+
- [ ] Link all three contract docs from [`BREAKING-CHANGES.md`](../../BREAKING-CHANGES.md) 8.4 section.
|
|
90
|
+
|
|
91
|
+
---
|
|
92
|
+
|
|
93
|
+
## Dependency order
|
|
94
|
+
|
|
95
|
+
```mermaid
|
|
96
|
+
flowchart LR
|
|
97
|
+
A[ai-skills: reasoningEffort on RunSkillRequest]
|
|
98
|
+
B[xynthesis: reasoningEffort on ExecuteXynthesisActionRequest]
|
|
99
|
+
C[xynthesis: verify temperature topP all paths]
|
|
100
|
+
D[ai-tasks: remove maxTokens forwarding]
|
|
101
|
+
E[ai-tasks: wire reasoningEffort + outputExpectation]
|
|
102
|
+
A --> E
|
|
103
|
+
B --> E
|
|
104
|
+
C --> E
|
|
105
|
+
D --> E
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
Recommended sequence:
|
|
109
|
+
|
|
110
|
+
1. Merge **xynthesis** + **ai-skills** contract PRs (can be parallel).
|
|
111
|
+
2. Bump `package.json` minimums in ai-tasks.
|
|
112
|
+
3. Execute **this wrap-up** checklist in one ai-tasks PR.
|
|
113
|
+
4. Release note in **8.4.x** or **8.5.0** with graph-engine migration (drop `maxTokensCap` on task payloads if removed).
|
|
114
|
+
|
|
115
|
+
---
|
|
116
|
+
|
|
117
|
+
## Quick smoke test after wrap-up
|
|
118
|
+
|
|
119
|
+
```bash
|
|
120
|
+
npm run build
|
|
121
|
+
npm run test
|
|
122
|
+
# Optional live:
|
|
123
|
+
# npm run test:e2e:synthesis
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
Expect: no import of `resolveMaxTokens` from `@exellix/xynthesis/ai-actions`; live POST/PRE calls succeed with `outputExpectation` only (no `maxTokens` on request).
|
|
@@ -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)
|