@agent-native/core 0.119.4 → 0.119.5
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/corpus/README.md +1 -1
- package/corpus/core/CHANGELOG.md +8 -0
- package/corpus/core/package.json +1 -1
- package/corpus/core/src/agent/engine/index.ts +2 -0
- package/corpus/core/src/agent/engine/registry.ts +95 -2
- package/corpus/core/src/scripts/agent-engines/list-agent-engines.ts +8 -0
- package/corpus/core/src/scripts/agent-engines/manage-agent-engine.ts +5 -1
- package/corpus/core/src/scripts/agent-engines/set-agent-engine.ts +9 -1
- package/corpus/templates/slides/actions/patch-deck.ts +2 -1
- package/corpus/templates/slides/changelog/2026-07-23-opening-or-refining-a-deck-no-longer-crashes-with-a-blank-er.md +6 -0
- package/corpus/templates/slides/shared/aspect-ratios.ts +4 -1
- package/corpus/templates/tasks/.oxfmtrc.json +8 -0
- package/corpus/templates/tasks/AGENTS.md +34 -41
- package/corpus/templates/tasks/README.md +13 -6
- package/corpus/templates/tasks/actions/bulk-delete-inbox-items.ts +10 -8
- package/corpus/templates/tasks/actions/bulk-delete-tasks.ts +10 -8
- package/corpus/templates/tasks/actions/bulk-mark-inbox-items-ready.ts +1 -1
- package/corpus/templates/tasks/actions/bulk-update-tasks.ts +12 -10
- package/corpus/templates/tasks/actions/create-inbox-item.ts +7 -4
- package/corpus/templates/tasks/actions/create-task.ts +2 -1
- package/corpus/templates/tasks/actions/delete-inbox-item.ts +6 -4
- package/corpus/templates/tasks/actions/delete-task.ts +1 -1
- package/corpus/templates/tasks/actions/list-inbox-items.ts +4 -2
- package/corpus/templates/tasks/actions/list-visible-task-fields.ts +3 -1
- package/corpus/templates/tasks/actions/mark-inbox-item-ready.ts +6 -4
- package/corpus/templates/tasks/actions/navigate.ts +16 -14
- package/corpus/templates/tasks/actions/reorder-inbox-items.ts +9 -7
- package/corpus/templates/tasks/actions/update-inbox-item.ts +6 -4
- package/corpus/templates/tasks/actions/update-task.ts +12 -9
- package/corpus/templates/tasks/actions/update-visible-task-fields.ts +10 -8
- package/corpus/templates/tasks/actions/view-screen.ts +1 -1
- package/corpus/templates/tasks/app/components/tasks/fields/TaskFieldsSidebar.tsx +15 -0
- package/corpus/templates/tasks/changelog/2026-07-23-task-detail-extensions.md +6 -0
- package/corpus/templates/tasks/drizzle.config.ts +3 -0
- package/corpus/templates/tasks/package.json +4 -1
- package/corpus/templates/tasks/server/db/schema.ts +0 -10
- package/corpus/templates/tasks/server/db/test-tasks-table.ts +0 -5
- package/corpus/templates/tasks/server/plugins/agent-chat.ts +1 -1
- package/corpus/templates/tasks/server/plugins/db.ts +43 -10
- package/corpus/templates/tasks/server/user-config/store.ts +42 -81
- package/corpus/templates/tasks/tsconfig.json +1 -2
- package/corpus/templates/tasks/vitest.config.ts +10 -1
- package/dist/agent/engine/index.d.ts +1 -1
- package/dist/agent/engine/index.d.ts.map +1 -1
- package/dist/agent/engine/index.js +1 -1
- package/dist/agent/engine/index.js.map +1 -1
- package/dist/agent/engine/registry.d.ts +32 -1
- package/dist/agent/engine/registry.d.ts.map +1 -1
- package/dist/agent/engine/registry.js +75 -3
- package/dist/agent/engine/registry.js.map +1 -1
- package/dist/collab/routes.d.ts +1 -1
- package/dist/collab/struct-routes.d.ts +1 -1
- package/dist/notifications/routes.d.ts +1 -1
- package/dist/observability/routes.d.ts +1 -1
- package/dist/scripts/agent-engines/list-agent-engines.d.ts.map +1 -1
- package/dist/scripts/agent-engines/list-agent-engines.js +8 -2
- package/dist/scripts/agent-engines/list-agent-engines.js.map +1 -1
- package/dist/scripts/agent-engines/manage-agent-engine.d.ts.map +1 -1
- package/dist/scripts/agent-engines/manage-agent-engine.js +5 -2
- package/dist/scripts/agent-engines/manage-agent-engine.js.map +1 -1
- package/dist/scripts/agent-engines/set-agent-engine.d.ts.map +1 -1
- package/dist/scripts/agent-engines/set-agent-engine.js +9 -2
- package/dist/scripts/agent-engines/set-agent-engine.js.map +1 -1
- package/dist/server/agent-engine-api-key-route.d.ts +1 -1
- package/package.json +1 -1
- package/src/agent/engine/index.ts +2 -0
- package/src/agent/engine/registry.ts +95 -2
- package/src/scripts/agent-engines/list-agent-engines.ts +8 -0
- package/src/scripts/agent-engines/manage-agent-engine.ts +5 -1
- package/src/scripts/agent-engines/set-agent-engine.ts +9 -1
- package/corpus/templates/tasks/.prettierrc +0 -5
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"set-agent-engine.js","sourceRoot":"","sources":["../../../src/scripts/agent-engines/set-agent-engine.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EACL,gBAAgB,EAChB,mBAAmB,EACnB,6BAA6B,EAC7B,8BAA8B,EAC9B,uBAAuB,EACvB,sBAAsB,GACvB,MAAM,6BAA6B,CAAC;AAErC,OAAO,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAErD,MAAM,CAAC,MAAM,IAAI,GAAe;IAC9B,WAAW,EACT,oKAAoK;IACtK,UAAU,EAAE;QACV,IAAI,EAAE,QAAQ;QACd,UAAU,EAAE;YACV,MAAM,EAAE;gBACN,IAAI,EAAE,QAAQ;gBACd,WAAW,EACT,kIAAkI;aACrI;YACD,KAAK,EAAE;gBACL,IAAI,EAAE,QAAQ;gBACd,WAAW,EACT,8HAA8H;aACjI;SACF;QACD,QAAQ,EAAE,CAAC,QAAQ,CAAC;KACrB;CACF,CAAC;AAEF,MAAM,CAAC,KAAK,UAAU,GAAG,CAAC,IAA4B;IACpD,sBAAsB,EAAE,CAAC;IAEzB,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE,GAAG,IAAI,CAAC;IAE3C,IAAI,CAAC,UAAU;QAAE,OAAO,6BAA6B,CAAC;IAEtD,MAAM,KAAK,GAAG,mBAAmB,CAAC,UAAU,CAAC,CAAC;IAC9C,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,MAAM,SAAS,GAAG,gBAAgB,EAAE;aACjC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;aAClB,IAAI,CAAC,IAAI,CAAC,CAAC;QACd,OAAO,kBAAkB,UAAU,mCAAmC,SAAS,EAAE,CAAC;IACpF,CAAC;IAED,IAAI,CAAC,6BAA6B,CAAC,KAAK,CAAC,EAAE,CAAC;QAC1C,OAAO,kBAAkB,UAAU,kFAAkF,KAAK,CAAC,cAAc,EAAE,CAAC;IAC9I,CAAC;IAED,MAAM,cAAc,GAAG,KAAK,IAAI,KAAK,CAAC,YAAY,CAAC;IACnD,MAAM,aAAa,GAAG,uBAAuB,CAAC,KAAK,EAAE,cAAc,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"set-agent-engine.js","sourceRoot":"","sources":["../../../src/scripts/agent-engines/set-agent-engine.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EACL,gBAAgB,EAChB,mBAAmB,EACnB,6BAA6B,EAC7B,8BAA8B,EAC9B,uBAAuB,EACvB,kCAAkC,EAClC,sBAAsB,GACvB,MAAM,6BAA6B,CAAC;AAErC,OAAO,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAErD,MAAM,CAAC,MAAM,IAAI,GAAe;IAC9B,WAAW,EACT,oKAAoK;IACtK,UAAU,EAAE;QACV,IAAI,EAAE,QAAQ;QACd,UAAU,EAAE;YACV,MAAM,EAAE;gBACN,IAAI,EAAE,QAAQ;gBACd,WAAW,EACT,kIAAkI;aACrI;YACD,KAAK,EAAE;gBACL,IAAI,EAAE,QAAQ;gBACd,WAAW,EACT,8HAA8H;aACjI;SACF;QACD,QAAQ,EAAE,CAAC,QAAQ,CAAC;KACrB;CACF,CAAC;AAEF,MAAM,CAAC,KAAK,UAAU,GAAG,CAAC,IAA4B;IACpD,sBAAsB,EAAE,CAAC;IAEzB,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE,GAAG,IAAI,CAAC;IAE3C,IAAI,CAAC,UAAU;QAAE,OAAO,6BAA6B,CAAC;IAEtD,MAAM,KAAK,GAAG,mBAAmB,CAAC,UAAU,CAAC,CAAC;IAC9C,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,MAAM,SAAS,GAAG,gBAAgB,EAAE;aACjC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;aAClB,IAAI,CAAC,IAAI,CAAC,CAAC;QACd,OAAO,kBAAkB,UAAU,mCAAmC,SAAS,EAAE,CAAC;IACpF,CAAC;IAED,IAAI,CAAC,6BAA6B,CAAC,KAAK,CAAC,EAAE,CAAC;QAC1C,OAAO,kBAAkB,UAAU,kFAAkF,KAAK,CAAC,cAAc,EAAE,CAAC;IAC9I,CAAC;IAED,MAAM,cAAc,GAAG,KAAK,IAAI,KAAK,CAAC,YAAY,CAAC;IACnD,yEAAyE;IACzE,8EAA8E;IAC9E,8EAA8E;IAC9E,0BAA0B;IAC1B,MAAM,oBAAoB,GAAG,MAAM,kCAAkC,CAAC,KAAK,CAAC,CAAC;IAC7E,MAAM,aAAa,GAAG,uBAAuB,CAAC,KAAK,EAAE,cAAc,EAAE;QACnE,oBAAoB;KACrB,CAAC,CAAC;IAEH,MAAM,MAAM,GAAG,MAAM,8BAA8B,CACjD,EAAE,MAAM,EAAE,UAAU,EAAE,EACtB,KAAK,CACN,CAAC;IACF,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,MAAM,cAAc,GAAG,KAAK,CAAC,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACxD,OAAO,oBAAoB,UAAU,mFAAmF,cAAc,iDAAiD,CAAC;IAC1L,CAAC;IAED,MAAM,UAAU,CAAC,cAAc,EAAE;QAC/B,MAAM,EAAE,UAAU;QAClB,KAAK,EAAE,aAAa;KACrB,CAAC,CAAC;IAEH,MAAM,cAAc,GAClB,aAAa,KAAK,cAAc;QAC9B,CAAC,CAAC,EAAE;QACJ,CAAC,CAAC,qBAAqB,cAAc,iCAAiC,aAAa,sBAAsB,CAAC;IAE9G,OAAO,IAAI,CAAC,SAAS,CAAC;QACpB,EAAE,EAAE,IAAI;QACR,MAAM,EAAE,UAAU;QAClB,KAAK,EAAE,aAAa;QACpB,OAAO,EAAE,uBAAuB,KAAK,CAAC,KAAK,eAAe,aAAa,2CAA2C,cAAc,EAAE;KACnI,CAAC,CAAC;AACL,CAAC","sourcesContent":["/**\n * set-agent-engine — validates and writes agent engine selection to settings.\n */\n\nimport {\n listAgentEngines,\n getAgentEngineEntry,\n isAgentEnginePackageInstalled,\n isStoredEngineUsableForRequest,\n normalizeModelForEngine,\n resolveEnginePreservesCustomModels,\n registerBuiltinEngines,\n} from \"../../agent/engine/index.js\";\nimport type { ActionTool } from \"../../agent/types.js\";\nimport { putSetting } from \"../../settings/index.js\";\n\nexport const tool: ActionTool = {\n description:\n 'Set the active AI agent engine and model. Changes take effect on the next conversation. Use manage-agent-engine with action=\"list\" first to see available options.',\n parameters: {\n type: \"object\",\n properties: {\n engine: {\n type: \"string\",\n description:\n 'Engine name (e.g. \"anthropic\", \"ai-sdk:openai\", \"ai-sdk:google\"). Use manage-agent-engine with action=\"list\" to see all options.',\n },\n model: {\n type: \"string\",\n description:\n \"Model ID to use with this engine (e.g. 'gpt-5.6-sol', 'claude-sonnet-5'). Defaults to the engine's default model if omitted.\",\n },\n },\n required: [\"engine\"],\n },\n};\n\nexport async function run(args: Record<string, string>): Promise<string> {\n registerBuiltinEngines();\n\n const { engine: engineName, model } = args;\n\n if (!engineName) return \"Error: --engine is required\";\n\n const entry = getAgentEngineEntry(engineName);\n if (!entry) {\n const available = listAgentEngines()\n .map((e) => e.name)\n .join(\", \");\n return `Error: Engine \"${engineName}\" not found. Available engines: ${available}`;\n }\n\n if (!isAgentEnginePackageInstalled(entry)) {\n return `Error: Engine \"${engineName}\" requires optional packages that are not installed in this app. Run: pnpm add ${entry.installPackage}`;\n }\n\n const requestedModel = model ?? entry.defaultModel;\n // A static registry entry can't carry the runtime `preserveCustomModels`\n // flag, so resolve the OpenAI-compatible-endpoint capability here and pass it\n // through — otherwise a gateway model (e.g. an Ollama id) is rewritten to the\n // engine default on save.\n const preserveCustomModels = await resolveEnginePreservesCustomModels(entry);\n const resolvedModel = normalizeModelForEngine(entry, requestedModel, {\n preserveCustomModels,\n });\n\n const usable = await isStoredEngineUsableForRequest(\n { engine: engineName },\n entry,\n );\n if (!usable) {\n const missingEnvVars = entry.requiredEnvVars.join(\", \");\n return `Warning: Engine \"${engineName}\" requires the following credentials which are not configured for this request: ${missingEnvVars}. The engine will fail at runtime without them.`;\n }\n\n await putSetting(\"agent-engine\", {\n engine: engineName,\n model: resolvedModel,\n });\n\n const normalizedNote =\n resolvedModel === requestedModel\n ? \"\"\n : ` Requested model \"${requestedModel}\" is no longer supported, so \"${resolvedModel}\" was saved instead.`;\n\n return JSON.stringify({\n ok: true,\n engine: engineName,\n model: resolvedModel,\n message: `Agent engine set to ${entry.label} with model ${resolvedModel}. Takes effect on the next conversation.${normalizedNote}`,\n });\n}\n"]}
|
|
@@ -27,11 +27,11 @@ export declare function resolveAgentEngineApiKeyWriteTarget(event: H3Event, scop
|
|
|
27
27
|
export declare function createAgentEngineApiKeyHandler(): import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
|
|
28
28
|
error: any;
|
|
29
29
|
} | {
|
|
30
|
+
error?: undefined;
|
|
30
31
|
ok: boolean;
|
|
31
32
|
key: string;
|
|
32
33
|
baseUrlKey?: string;
|
|
33
34
|
scope: AgentEngineApiKeyScope;
|
|
34
|
-
error?: undefined;
|
|
35
35
|
}>>;
|
|
36
36
|
export {};
|
|
37
37
|
//# sourceMappingURL=agent-engine-api-key-route.d.ts.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agent-native/core",
|
|
3
|
-
"version": "0.119.
|
|
3
|
+
"version": "0.119.5",
|
|
4
4
|
"description": "Framework for agent-native application development — where AI agents and UI share SQL state, actions, and context",
|
|
5
5
|
"homepage": "https://github.com/BuilderIO/agent-native#readme",
|
|
6
6
|
"bugs": {
|
|
@@ -25,6 +25,8 @@ export {
|
|
|
25
25
|
getConfiguredEngineNameForRequest,
|
|
26
26
|
getStoredModelForEngine,
|
|
27
27
|
normalizeModelForEngine,
|
|
28
|
+
resolveEnginePreservesCustomModels,
|
|
29
|
+
type NormalizeModelOptions,
|
|
28
30
|
detectEngineFromEnv,
|
|
29
31
|
detectEngineFromEnvForRequest,
|
|
30
32
|
detectEngineFromUserSecrets,
|
|
@@ -96,6 +96,42 @@ function packageNameFromInstallSpecifier(specifier: string): string | null {
|
|
|
96
96
|
return versionIndex === -1 ? trimmed : trimmed.slice(0, versionIndex);
|
|
97
97
|
}
|
|
98
98
|
|
|
99
|
+
/**
|
|
100
|
+
* True only when there is positive evidence this module is executing from a
|
|
101
|
+
* bundled serverless function where optional dependencies were inlined into the
|
|
102
|
+
* bundle and are therefore NOT resolvable via `require.resolve` — even though
|
|
103
|
+
* the dynamic `import()` the engine uses to load them still works.
|
|
104
|
+
*
|
|
105
|
+
* Deliberately narrow. The Nitro Vercel/Netlify presets (which agent-native's
|
|
106
|
+
* own `deploy` command emits) inline optional peers and always set these env
|
|
107
|
+
* markers, so they are a reliable signal. Other serverless runtimes — a
|
|
108
|
+
* container on Cloud Run / Google Cloud Functions (`K_SERVICE` /
|
|
109
|
+
* `FUNCTION_TARGET`), or a plain AWS Lambda — commonly ship a real
|
|
110
|
+
* `node_modules` where `require.resolve` is authoritative; there a resolve miss
|
|
111
|
+
* means the package is genuinely absent and must NOT be masked. Those runtimes
|
|
112
|
+
* are still covered *when the code is actually bundled*, via the module-path
|
|
113
|
+
* check below, which stays false for a normal `node_modules` layout.
|
|
114
|
+
*/
|
|
115
|
+
function isBundledServerlessRuntime(): boolean {
|
|
116
|
+
const env = process.env;
|
|
117
|
+
// Nitro's Vercel/Netlify presets inline optional peers into the function
|
|
118
|
+
// bundle; these platforms always set these markers.
|
|
119
|
+
if (env.VERCEL || env.NETLIFY) return true;
|
|
120
|
+
// Otherwise require direct evidence that this module is running from inside a
|
|
121
|
+
// bundle output directory (Vercel's `/var/task`, Nitro's `.output/server`,
|
|
122
|
+
// inlined `_libs`). This is the real signal that `require.resolve` cannot be
|
|
123
|
+
// trusted; it stays false for normal `node_modules` layouts (dev, tests, and
|
|
124
|
+
// container/Lambda/Cloud Run deploys that ship their dependencies), so a
|
|
125
|
+
// genuine "package not installed" miss still surfaces there.
|
|
126
|
+
try {
|
|
127
|
+
return /[\\/](?:_libs|\.vercel|\.netlify|\.output)[\\/]|\/var\/task\//.test(
|
|
128
|
+
import.meta.url ?? "",
|
|
129
|
+
);
|
|
130
|
+
} catch {
|
|
131
|
+
return false;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
99
135
|
function canResolvePackage(packageName: string): boolean {
|
|
100
136
|
const cached = _packageAvailabilityCache.get(packageName);
|
|
101
137
|
if (cached !== undefined) return cached;
|
|
@@ -104,7 +140,15 @@ function canResolvePackage(packageName: string): boolean {
|
|
|
104
140
|
require.resolve(packageName);
|
|
105
141
|
available = true;
|
|
106
142
|
} catch {
|
|
107
|
-
|
|
143
|
+
// Bundled serverless runtimes (e.g. Nitro on Vercel/Netlify) inline optional
|
|
144
|
+
// provider packages into the function bundle, so require.resolve cannot find
|
|
145
|
+
// them even though the dynamic `import()` the engine actually uses to load
|
|
146
|
+
// them works. Treat them as available there and let the engine's own import
|
|
147
|
+
// be the real gate — it already fails with a clear "pnpm add …" message when
|
|
148
|
+
// the package is genuinely missing. Without this, every engine-usability
|
|
149
|
+
// gate rejects the AI-SDK engines at runtime and the agent silently falls
|
|
150
|
+
// back to the native Anthropic engine.
|
|
151
|
+
available = isBundledServerlessRuntime();
|
|
108
152
|
}
|
|
109
153
|
_packageAvailabilityCache.set(packageName, available);
|
|
110
154
|
return available;
|
|
@@ -179,17 +223,41 @@ function findLatestSupportedVersionMatch(
|
|
|
179
223
|
return best?.model;
|
|
180
224
|
}
|
|
181
225
|
|
|
226
|
+
export interface NormalizeModelOptions {
|
|
227
|
+
/**
|
|
228
|
+
* Force unrecognized (custom) model IDs to be kept verbatim, as if
|
|
229
|
+
* `engine.preserveCustomModels` were set on a live engine instance.
|
|
230
|
+
*
|
|
231
|
+
* The settings actions call `normalizeModelForEngine` with a static registry
|
|
232
|
+
* ENTRY, which never carries the runtime `preserveCustomModels` flag — that
|
|
233
|
+
* is only set on the engine INSTANCE created with an OpenAI-compatible
|
|
234
|
+
* `baseUrl`. They resolve the capability with
|
|
235
|
+
* {@link resolveEnginePreservesCustomModels} and pass it here so a gateway
|
|
236
|
+
* model (e.g. an Ollama `gemma4`) is not rewritten to the OpenAI default on
|
|
237
|
+
* save/read. First-party OpenAI (no gateway) leaves this unset, so an unknown
|
|
238
|
+
* or invalid model still normalizes to a supported one.
|
|
239
|
+
*/
|
|
240
|
+
preserveCustomModels?: boolean;
|
|
241
|
+
}
|
|
242
|
+
|
|
182
243
|
export function normalizeModelForEngine(
|
|
183
244
|
engine: Pick<
|
|
184
245
|
AgentEngine,
|
|
185
246
|
"name" | "defaultModel" | "supportedModels" | "preserveCustomModels"
|
|
186
247
|
>,
|
|
187
248
|
model: string | null | undefined,
|
|
249
|
+
options: NormalizeModelOptions = {},
|
|
188
250
|
): string {
|
|
189
251
|
const candidate = typeof model === "string" ? model.trim() : "";
|
|
190
252
|
if (!candidate) return engine.defaultModel;
|
|
191
253
|
|
|
192
|
-
|
|
254
|
+
// Preserve custom IDs verbatim BEFORE any catalog/version matching, so a
|
|
255
|
+
// version-shaped gateway model that happens to share a family with a
|
|
256
|
+
// built-in model (e.g. `gpt-5.4` on an OpenAI-compatible endpoint) is not
|
|
257
|
+
// rewritten to a catalog entry.
|
|
258
|
+
if (engine.preserveCustomModels || options.preserveCustomModels) {
|
|
259
|
+
return candidate;
|
|
260
|
+
}
|
|
193
261
|
|
|
194
262
|
if (engine.supportedModels.length === 0) return candidate;
|
|
195
263
|
|
|
@@ -203,6 +271,31 @@ export function normalizeModelForEngine(
|
|
|
203
271
|
);
|
|
204
272
|
}
|
|
205
273
|
|
|
274
|
+
/**
|
|
275
|
+
* Whether models saved or read for this engine ENTRY should be preserved
|
|
276
|
+
* verbatim instead of normalized against the built-in catalog.
|
|
277
|
+
*
|
|
278
|
+
* `normalizeModelForEngine` honors a live engine's `preserveCustomModels`, but
|
|
279
|
+
* that flag is only set on an AI SDK engine INSTANCE when the OpenAI provider
|
|
280
|
+
* is pointed at an OpenAI-compatible gateway (a custom base URL — e.g. Ollama
|
|
281
|
+
* Cloud or LiteLLM), whose model IDs are not in the built-in OpenAI catalog.
|
|
282
|
+
* The static registry entry the settings actions pass to
|
|
283
|
+
* `normalizeModelForEngine` cannot carry that runtime flag, so this async
|
|
284
|
+
* helper reproduces the same decision — `ai-sdk:openai` AND a resolved base URL
|
|
285
|
+
* — from the request's stored/deploy config. First-party OpenAI (no gateway)
|
|
286
|
+
* returns false so an unknown/invalid model still normalizes to a supported one.
|
|
287
|
+
*/
|
|
288
|
+
export async function resolveEnginePreservesCustomModels(
|
|
289
|
+
entry: Pick<AgentEngineEntry, "name">,
|
|
290
|
+
): Promise<boolean> {
|
|
291
|
+
if (entry.name !== "ai-sdk:openai") return false;
|
|
292
|
+
try {
|
|
293
|
+
return Boolean(await resolveOpenAiBaseUrl());
|
|
294
|
+
} catch {
|
|
295
|
+
return false;
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
|
|
206
299
|
function assertAgentEnginePackageInstalled(entry: AgentEngineEntry): void {
|
|
207
300
|
if (isAgentEnginePackageInstalled(entry)) return;
|
|
208
301
|
const installHint = entry.installPackage
|
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
isAgentEnginePackageInstalled,
|
|
14
14
|
isStoredEngineUsableForRequest,
|
|
15
15
|
normalizeModelForEngine,
|
|
16
|
+
resolveEnginePreservesCustomModels,
|
|
16
17
|
} from "../../agent/engine/index.js";
|
|
17
18
|
import type { ActionTool } from "../../agent/types.js";
|
|
18
19
|
import { getSetting } from "../../settings/index.js";
|
|
@@ -82,11 +83,18 @@ export async function run(args: Record<string, string> = {}): Promise<string> {
|
|
|
82
83
|
? current?.model
|
|
83
84
|
: undefined;
|
|
84
85
|
const currentEngineName = currentEntry?.name ?? "anthropic";
|
|
86
|
+
// Resolve the OpenAI-compatible-endpoint capability so a custom gateway model
|
|
87
|
+
// is reported as-is instead of being normalized to the engine default — the
|
|
88
|
+
// read-side counterpart of the same fix in set-/manage-agent-engine.
|
|
89
|
+
const preserveCustomModels = currentEntry
|
|
90
|
+
? await resolveEnginePreservesCustomModels(currentEntry)
|
|
91
|
+
: false;
|
|
85
92
|
const currentModel =
|
|
86
93
|
currentEntry && !envUnavailable
|
|
87
94
|
? normalizeModelForEngine(
|
|
88
95
|
currentEntry,
|
|
89
96
|
currentModelCandidate ?? currentEntry.defaultModel,
|
|
97
|
+
{ preserveCustomModels },
|
|
90
98
|
)
|
|
91
99
|
: (currentModelCandidate ?? DEFAULT_MODEL);
|
|
92
100
|
const result = {
|
|
@@ -16,6 +16,7 @@ import {
|
|
|
16
16
|
getAgentEngineEntry,
|
|
17
17
|
isAgentEnginePackageInstalled,
|
|
18
18
|
normalizeModelForEngine,
|
|
19
|
+
resolveEnginePreservesCustomModels,
|
|
19
20
|
registerBuiltinEngines,
|
|
20
21
|
} from "../../agent/engine/index.js";
|
|
21
22
|
import type { ActionTool } from "../../agent/types.js";
|
|
@@ -113,7 +114,10 @@ async function runSetAppDefault(args: Record<string, string>): Promise<string> {
|
|
|
113
114
|
if (!isAgentEnginePackageInstalled(entry)) {
|
|
114
115
|
return `Error: Engine "${engine}" requires optional packages that are not installed in this app. Run: pnpm add ${entry.installPackage}`;
|
|
115
116
|
}
|
|
116
|
-
const
|
|
117
|
+
const preserveCustomModels = await resolveEnginePreservesCustomModels(entry);
|
|
118
|
+
const normalizedModel = normalizeModelForEngine(entry, model, {
|
|
119
|
+
preserveCustomModels,
|
|
120
|
+
});
|
|
117
121
|
|
|
118
122
|
const ctx = currentContext();
|
|
119
123
|
const canUpdate = await canUpdateAgentAppModelDefaultSettings(
|
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
isAgentEnginePackageInstalled,
|
|
9
9
|
isStoredEngineUsableForRequest,
|
|
10
10
|
normalizeModelForEngine,
|
|
11
|
+
resolveEnginePreservesCustomModels,
|
|
11
12
|
registerBuiltinEngines,
|
|
12
13
|
} from "../../agent/engine/index.js";
|
|
13
14
|
import type { ActionTool } from "../../agent/types.js";
|
|
@@ -54,7 +55,14 @@ export async function run(args: Record<string, string>): Promise<string> {
|
|
|
54
55
|
}
|
|
55
56
|
|
|
56
57
|
const requestedModel = model ?? entry.defaultModel;
|
|
57
|
-
|
|
58
|
+
// A static registry entry can't carry the runtime `preserveCustomModels`
|
|
59
|
+
// flag, so resolve the OpenAI-compatible-endpoint capability here and pass it
|
|
60
|
+
// through — otherwise a gateway model (e.g. an Ollama id) is rewritten to the
|
|
61
|
+
// engine default on save.
|
|
62
|
+
const preserveCustomModels = await resolveEnginePreservesCustomModels(entry);
|
|
63
|
+
const resolvedModel = normalizeModelForEngine(entry, requestedModel, {
|
|
64
|
+
preserveCustomModels,
|
|
65
|
+
});
|
|
58
66
|
|
|
59
67
|
const usable = await isStoredEngineUsableForRequest(
|
|
60
68
|
{ engine: engineName },
|