Skip to content

feat(platform): support provider-qualified model refs#1583

Merged
larryro merged 6 commits into
mainfrom
feat/provider-qualified-model-refs
Apr 20, 2026
Merged

feat(platform): support provider-qualified model refs#1583
larryro merged 6 commits into
mainfrom
feat/provider-qualified-model-refs

Conversation

@larryro
Copy link
Copy Markdown
Collaborator

@larryro larryro commented Apr 20, 2026

Summary

  • Add <provider>:<model-id> prefix syntax for supportedModels so agents can pin routing when the same id is defined in multiple provider files.
  • Plain (unqualified) entries still work — they resolve to the first provider that defines the id, and the save path emits a warning when an unqualified entry matches more than one provider.
  • New shared model-ref util (parse / format / strip / validate) with unit tests, wired into the agent Zod schema and the UI model selectors.
  • Example agent configs updated to use openrouter: prefixes for the shipped seed agents; docs/platform/admin/providers.md gains a "Pinning an entry to a specific provider" section.

Test plan

  • npm run lint --workspace=@tale/platform
  • npx tsc --noEmit from services/platform/
  • Run model-ref unit tests and existing save_agent_validation tests
  • Manual: load an agent config with a duplicated model id across providers and confirm the save warning fires; switch the entry to a <provider>: form and confirm the warning clears
  • Manual: verify the model selector dropdown still renders the seeded chat-agent models after the openrouter: prefix migration

Summary by CodeRabbit

Release Notes

  • New Features

    • Added support for provider-scoped model identifiers in agent configurations, allowing disambiguation when the same model exists across multiple providers.
    • Enhanced model selector UI to display provider information and context when selecting models.
  • Documentation

    • Added guidance on pinning model entries to specific providers using the new qualifier format.
  • Improvements

    • Enhanced validation messaging for agent configuration errors.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 20, 2026

📝 Walkthrough

Walkthrough

This PR introduces support for provider-qualified model references throughout the platform (e.g., openrouter:anthropic/claude-opus-4.6). It adds documentation on disambiguation using the <provider>: prefix format, updates all example agent configurations to use qualified openrouter: prefixes, and implements utilities for parsing/validating/formatting model references. The backend model resolution logic now handles both qualified and unqualified references, with warnings issued for multi-provider ambiguities. UI components are extended to display provider information alongside model names. New validation rules and error codes (UNKNOWN_PROVIDER, UNKNOWN_MODEL, VALIDATION_ERROR) are introduced for model resolution. The changes maintain backward compatibility with unqualified model IDs while supporting explicit provider qualification.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 8.33% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title 'feat(platform): support provider-qualified model refs' directly and clearly describes the main feature addition across the changeset—enabling provider-qualified model references (e.g., 'openrouter:/') throughout the platform.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/provider-qualified-model-refs

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 8

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
examples/agents/web-assistant.json (1)

1-16: ⚠️ Potential issue | 🟡 Minor

Fix formatting to pass pipeline check.

The pipeline reports a formatting failure from oxfmt. Run the formatter to fix the file before merging.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@examples/agents/web-assistant.json` around lines 1 - 16, The JSON file
"examples/agents/web-assistant.json" failed the oxfmt pipeline check due to
formatting; run the project's formatter (oxfmt) on this file and commit the
formatted output so keys like "displayName", "systemInstructions", "toolNames"
and others are correctly indented and escaped, ensuring valid JSON (no trailing
commas or unescaped newlines) and preserving the exact string content
(especially the multi-line systemInstructions) before pushing the fix.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@examples/agents/crm-assistant.json`:
- Around line 5-12: The JSON in examples/agents/crm-assistant.json is not
formatted to the repo's formatter (oxfmt), causing CI to fail; run the formatter
(e.g., oxfmt or your project's format script) to reformat this file and commit
the updated JSON so oxfmt --check passes; focus on formatting the array/object
entries like "toolNames" and "supportedModels" and ensure the committed changes
include only the formatting updates.

In `@examples/agents/image-creator.json`:
- Around line 5-11: The JSON formatting for the object containing the
"integrationBindings" and "supportedModels" keys is not normalized and fails
oxfmt --check; run the repository formatter (oxfmt) against this JSON, update
the file with the normalized output, and commit the formatted JSON so CI passes
(ensure the JSON follows the project's formatter rules and removes any
trailing/extra whitespace or comma issues).

In `@services/platform/app/features/agents/hooks/use-agents-table-config.tsx`:
- Around line 56-58: The Badge rendering can crash when
stripModelRefQualifier(model) throws on malformed refs; update the rendering in
use-agents-table-config.tsx to call stripModelRefQualifier safely by first
validating or try/catching the result and falling back to the original model
string (e.g., use a safeNormalize variable = safe result || model) before
passing into <Badge> so malformed values like ":x" or "x:" do not break row
render; target the return that currently uses stripModelRefQualifier(model) and
ensure a safe fallback is used.

In
`@services/platform/app/features/chat/components/arena/arena-model-selector.tsx`:
- Around line 83-87: The current getDisplayName collapses provider-qualified
refs by stripping qualifiers before lookup; instead, look up modelInfoMap using
the full ref first (use ref directly), fall back to the stripped plain id only
if the full ref is not present, and when constructing the short name use
getModelShortName(ref) (not the stripped plain) so provider qualifiers remain
part of the label; apply the same change to the other lookup at lines referenced
(the similar logic around the other label generation) so qualified model refs
remain disambiguated.

In `@services/platform/convex/agents/config.ts`:
- Around line 79-85: The code matches on stripped ids using
stripModelRefQualifier(modelId) against supportedModels but then sets
config.model = modelId, which can drop provider pinning; change the assignment
to use the actual matched supportedModels entry (the matched "ref" from the
supportedModels.some/iteration) so config.model is set to the provider-qualified
ref instead of the raw modelId, and keep config.fallbackModels = undefined as
before; locate the logic around stripModelRefQualifier, supportedModels,
config.model and replace the modelId assignment with the matched supported ref.

In `@services/platform/convex/agents/unified_chat.ts`:
- Around line 183-190: The call to stripModelRefQualifier(args.modelId) can
throw and prevent rollbackGenerating() from running; wrap the model-ref parsing
in a try/catch (or validate before calling) inside the same control flow that
runs the access check so any parse error will still call
rollbackGenerating(authUserId, threadId or relevant IDs) before
rethrowing/returning an error. Specifically, guard the stripModelRefQualifier
invocation used when calling
internal.governance.internal_queries.checkModelAccessInternal and ensure
rollbackGenerating (the function used later to clear the thread generating
state) is invoked in the catch/finally path so malformed model refs cannot leave
a thread stuck in generating state.

In `@services/platform/convex/providers/file_actions.ts`:
- Around line 369-411: The ambiguity warning in the resolveModelData logic (the
console.warn inside the firstMatch branch that uses firstMatch,
secondaryMatchProviders, and args.providerName) should be returned to callers
rather than only logged; modify the function that returns the model info to
include an optional warnings?: string[] field and, when
secondaryMatchProviders.length > 0 and args.providerName is falsy, push the
existing ambiguity message into that warnings array (instead of only
console.warn), then update callers such as resolveLanguageModelById to accept
and propagate the warnings (just like saveAgent's warnings?: string[]) so
downstream code can surface the warning to users or logs.

In `@services/platform/lib/shared/utils/model-ref.ts`:
- Around line 1-4: The exported interface ParsedModelRef is declared but unused
externally; remove the export to make it internal (or alternatively use it in
callers) so the symbol is no longer an unused export. Concretely, in the
ParsedModelRef declaration remove the "export" modifier (making it "interface
ParsedModelRef { ... }") or replace usages by importing/consuming ParsedModelRef
in the modules that need it; ensure any references to ParsedModelRef in this
module still compile after the change.

---

Outside diff comments:
In `@examples/agents/web-assistant.json`:
- Around line 1-16: The JSON file "examples/agents/web-assistant.json" failed
the oxfmt pipeline check due to formatting; run the project's formatter (oxfmt)
on this file and commit the formatted output so keys like "displayName",
"systemInstructions", "toolNames" and others are correctly indented and escaped,
ensuring valid JSON (no trailing commas or unescaped newlines) and preserving
the exact string content (especially the multi-line systemInstructions) before
pushing the fix.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: b472f995-3581-4614-9480-5f149f3d6f0d

📥 Commits

Reviewing files that changed from the base of the PR and between 05a49dd and faffa04.

📒 Files selected for processing (27)
  • docs/platform/admin/providers.md
  • examples/agents/chat-agent.json
  • examples/agents/crm-assistant.json
  • examples/agents/file-assistant.json
  • examples/agents/image-creator.json
  • examples/agents/integration-assistant.json
  • examples/agents/researcher.json
  • examples/agents/web-assistant.json
  • examples/agents/workflow-assistant.json
  • services/platform/app/components/ui/forms/model-selector.tsx
  • services/platform/app/features/agents/components/agent-create-dialog.tsx
  • services/platform/app/features/agents/hooks/use-agents-table-config.tsx
  • services/platform/app/features/chat/components/arena/arena-model-selector.tsx
  • services/platform/app/features/chat/components/model-selector.tsx
  • services/platform/app/features/chat/context/chat-layout-context.tsx
  • services/platform/app/routes/dashboard/$id/agents/$agentId/instructions.tsx
  • services/platform/convex/agents/__tests__/save_agent_validation.test.ts
  • services/platform/convex/agents/config.ts
  • services/platform/convex/agents/file_actions.ts
  • services/platform/convex/agents/unified_chat.ts
  • services/platform/convex/lib/agent_chat/internal_actions.ts
  • services/platform/convex/providers/file_actions.ts
  • services/platform/lib/shared/schemas/agents.ts
  • services/platform/lib/shared/utils/__tests__/model-ref.test.ts
  • services/platform/lib/shared/utils/model-ref.ts
  • services/platform/messages/de.json
  • services/platform/messages/en.json

Comment thread examples/agents/crm-assistant.json Outdated
Comment on lines +5 to +12
"toolNames": [
"customer_read",
"product_read"
],
"supportedModels": [
"openrouter:anthropic/claude-opus-4.6",
"openrouter:openai/gpt-5.2"
],
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Formatting check is failing in CI and needs a formatter pass.

oxfmt --check is currently red for this PR. Please run the formatter and commit the resulting JSON formatting changes so lint passes.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@examples/agents/crm-assistant.json` around lines 5 - 12, The JSON in
examples/agents/crm-assistant.json is not formatted to the repo's formatter
(oxfmt), causing CI to fail; run the formatter (e.g., oxfmt or your project's
format script) to reformat this file and commit the updated JSON so oxfmt
--check passes; focus on formatting the array/object entries like "toolNames"
and "supportedModels" and ensure the committed changes include only the
formatting updates.

Comment thread examples/agents/image-creator.json Outdated
Comment on lines +5 to +11
"integrationBindings": [
"ai-image"
],
"supportedModels": [
"openrouter:moonshotai/kimi-k2.5",
"openrouter:anthropic/claude-sonnet-4.6"
],
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Formatting is currently blocking this PR.

oxfmt --check is failing for this file in CI. Please run the formatter and commit the normalized JSON output.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@examples/agents/image-creator.json` around lines 5 - 11, The JSON formatting
for the object containing the "integrationBindings" and "supportedModels" keys
is not normalized and fails oxfmt --check; run the repository formatter (oxfmt)
against this JSON, update the file with the normalized output, and commit the
formatted JSON so CI passes (ensure the JSON follows the project's formatter
rules and removes any trailing/extra whitespace or comma issues).

Comment on lines +56 to +58
return (
<Badge variant="outline">{stripModelRefQualifier(model)}</Badge>
);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Guard model ref normalization to avoid render crashes on bad data.

Line 57 can throw for malformed refs (:x, x:), which would break the row render. Add a safe fallback to the raw model string.

🛡️ Safe fallback patch
         cell: ({ row }) => {
           const model = row.original.supportedModels?.[0];
           if (!model) return null;
-          return (
-            <Badge variant="outline">{stripModelRefQualifier(model)}</Badge>
-          );
+          let label = model;
+          try {
+            label = stripModelRefQualifier(model);
+          } catch {
+            // keep raw model label if malformed
+          }
+          return <Badge variant="outline">{label}</Badge>;
         },
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@services/platform/app/features/agents/hooks/use-agents-table-config.tsx`
around lines 56 - 58, The Badge rendering can crash when
stripModelRefQualifier(model) throws on malformed refs; update the rendering in
use-agents-table-config.tsx to call stripModelRefQualifier safely by first
validating or try/catching the result and falling back to the original model
string (e.g., use a safeNormalize variable = safe result || model) before
passing into <Badge> so malformed values like ":x" or "x:" do not break row
render; target the return that currently uses stripModelRefQualifier(model) and
ensure a safe fallback is used.

Comment on lines 83 to +87
const getDisplayName = useCallback(
(modelId: string) =>
modelInfoMap.get(modelId)?.displayName ?? getModelShortName(modelId),
(ref: string) => {
const plain = stripModelRefQualifier(ref);
return modelInfoMap.get(plain)?.displayName ?? getModelShortName(plain);
},
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Do not collapse provider-qualified options to identical display labels.

At Line 85 and Line 113, stripping qualifiers for label lookup can make two provider-qualified refs appear as the same option when they share a plain modelId. That breaks disambiguation in arena selection.

🔧 Proposed fix
-import { stripModelRefQualifier } from '@/lib/shared/utils/model-ref';
+import {
+  parseModelRef,
+  stripModelRefQualifier,
+} from '@/lib/shared/utils/model-ref';

 const getDisplayName = useCallback(
   (ref: string) => {
-    const plain = stripModelRefQualifier(ref);
-    return modelInfoMap.get(plain)?.displayName ?? getModelShortName(plain);
+    const { providerName, modelId } = parseModelRef(ref);
+    const base =
+      modelInfoMap.get(modelId)?.displayName ?? getModelShortName(modelId);
+    return providerName ? `${base} (${providerName})` : base;
   },
   [modelInfoMap],
 );

Also applies to: 111-114

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@services/platform/app/features/chat/components/arena/arena-model-selector.tsx`
around lines 83 - 87, The current getDisplayName collapses provider-qualified
refs by stripping qualifiers before lookup; instead, look up modelInfoMap using
the full ref first (use ref directly), fall back to the stripped plain id only
if the full ref is not present, and when constructing the short name use
getModelShortName(ref) (not the stripped plain) so provider qualifiers remain
part of the label; apply the same change to the other lookup at lines referenced
(the similar logic around the other label generation) so qualified model refs
remain disambiguated.

Comment on lines +79 to 85
const target = stripModelRefQualifier(modelId);
const matched = supportedModels.some(
(ref) => stripModelRefQualifier(ref) === target,
);
if (matched) {
config.model = modelId;
config.fallbackModels = undefined;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Preserve provider pinning by assigning the matched supported ref, not raw input.

Current logic matches on stripped ids but sets config.model = modelId. If caller sends an unqualified or different-qualified ref with the same plain id, provider pinning can be lost.

🔧 Proposed fix
 export function applyModelOverride(
   config: SerializableAgentConfig,
   modelId: string,
   supportedModels: string[],
 ): boolean {
   const target = stripModelRefQualifier(modelId);
-  const matched = supportedModels.some(
-    (ref) => stripModelRefQualifier(ref) === target,
-  );
-  if (matched) {
-    config.model = modelId;
+  const exactMatch = supportedModels.find((ref) => ref === modelId);
+  const normalizedMatch = supportedModels.find(
+    (ref) => stripModelRefQualifier(ref) === target,
+  );
+  const matchedRef = exactMatch ?? normalizedMatch;
+
+  if (matchedRef) {
+    config.model = matchedRef;
     config.fallbackModels = undefined;
     return true;
   }
   return false;
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@services/platform/convex/agents/config.ts` around lines 79 - 85, The code
matches on stripped ids using stripModelRefQualifier(modelId) against
supportedModels but then sets config.model = modelId, which can drop provider
pinning; change the assignment to use the actual matched supportedModels entry
(the matched "ref" from the supportedModels.some/iteration) so config.model is
set to the provider-qualified ref instead of the raw modelId, and keep
config.fallbackModels = undefined as before; locate the logic around
stripModelRefQualifier, supportedModels, config.model and replace the modelId
assignment with the matched supported ref.

Comment on lines 183 to 190
if (args.modelId) {
const accessCheck = await ctx.runQuery(
internal.governance.internal_queries.checkModelAccessInternal,
{
organizationId: args.organizationId,
userId: authUserId,
modelId: args.modelId,
modelId: stripModelRefQualifier(args.modelId),
},
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Guard model-ref parsing so failures still clear generation status.

At Line 189, stripModelRefQualifier(args.modelId) can throw on malformed refs. In that failure path, rollbackGenerating() is skipped, so the thread may remain stuck in generating state.

🔧 Proposed fix
 if (args.modelId) {
+  let normalizedModelId: string;
+  try {
+    normalizedModelId = stripModelRefQualifier(args.modelId);
+  } catch {
+    await rollbackGenerating();
+    throw new Error('Invalid model reference.');
+  }
+
   const accessCheck = await ctx.runQuery(
     internal.governance.internal_queries.checkModelAccessInternal,
     {
       organizationId: args.organizationId,
       userId: authUserId,
-      modelId: stripModelRefQualifier(args.modelId),
+      modelId: normalizedModelId,
     },
   );

As per coding guidelines: "Validate and sanitize all user input at system boundaries".

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (args.modelId) {
const accessCheck = await ctx.runQuery(
internal.governance.internal_queries.checkModelAccessInternal,
{
organizationId: args.organizationId,
userId: authUserId,
modelId: args.modelId,
modelId: stripModelRefQualifier(args.modelId),
},
if (args.modelId) {
let normalizedModelId: string;
try {
normalizedModelId = stripModelRefQualifier(args.modelId);
} catch {
await rollbackGenerating();
throw new Error('Invalid model reference.');
}
const accessCheck = await ctx.runQuery(
internal.governance.internal_queries.checkModelAccessInternal,
{
organizationId: args.organizationId,
userId: authUserId,
modelId: normalizedModelId,
},
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@services/platform/convex/agents/unified_chat.ts` around lines 183 - 190, The
call to stripModelRefQualifier(args.modelId) can throw and prevent
rollbackGenerating() from running; wrap the model-ref parsing in a try/catch (or
validate before calling) inside the same control flow that runs the access check
so any parse error will still call rollbackGenerating(authUserId, threadId or
relevant IDs) before rethrowing/returning an error. Specifically, guard the
stripModelRefQualifier invocation used when calling
internal.governance.internal_queries.checkModelAccessInternal and ensure
rollbackGenerating (the function used later to clear the thread generating
state) is invoked in the catch/finally path so malformed model refs cannot leave
a thread stuck in generating state.

Comment on lines +369 to +411
let firstMatch:
| {
provider: (typeof candidates)[number];
definition: (typeof candidates)[number]['config']['models'][number];
}
| undefined;
const secondaryMatchProviders: string[] = [];
for (const provider of candidates) {
const definition = provider.config.models.find(
(m) => m.id === args.modelId,
);
if (definition) {
return {
providerName: provider.name,
baseUrl: definition.baseUrl ?? provider.config.baseUrl,
apiKey:
provider.secrets.modelKeys?.[definition.id] ??
provider.secrets.apiKey,
modelId: args.modelId,
maxOutputTokens: definition.maxOutputTokens,
supportsStructuredOutputs:
definition.supportsStructuredOutputs ??
provider.config.supportsStructuredOutputs ??
false,
inputCentsPerMillion: definition.cost?.inputCentsPerMillion,
outputCentsPerMillion: definition.cost?.outputCentsPerMillion,
};
if (!definition) continue;
if (!firstMatch) {
firstMatch = { provider, definition };
} else {
secondaryMatchProviders.push(provider.name);
}
}

if (firstMatch) {
if (!args.providerName && secondaryMatchProviders.length > 0) {
console.warn(
`[resolveModelData] Unqualified model "${args.modelId}" matches multiple providers ` +
`(pinned: ${firstMatch.provider.name}; also in: ${secondaryMatchProviders.join(', ')}). ` +
`Qualify as "${firstMatch.provider.name}:${args.modelId}" to pin explicitly.`,
);
}
const { provider, definition } = firstMatch;
return {
providerName: provider.name,
baseUrl: definition.baseUrl ?? provider.config.baseUrl,
apiKey:
provider.secrets.modelKeys?.[definition.id] ??
provider.secrets.apiKey,
modelId: args.modelId,
maxOutputTokens: definition.maxOutputTokens,
supportsStructuredOutputs:
definition.supportsStructuredOutputs ??
provider.config.supportsStructuredOutputs ??
false,
inputCentsPerMillion: definition.cost?.inputCentsPerMillion,
outputCentsPerMillion: definition.cost?.outputCentsPerMillion,
};
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Consider surfacing the ambiguity warning to callers.

The console.warn for unqualified models matching multiple providers is only visible server-side. Based on the relevant code snippet from resolve_model.ts (lines 220-234), resolveLanguageModelById invokes this action and silently uses the returned modelData without any awareness that the model might not be the user's intended choice.

Consider returning the warning as part of the response (similar to how saveAgent returns warnings?: string[]) so downstream callers can surface it to users or logs with more context.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@services/platform/convex/providers/file_actions.ts` around lines 369 - 411,
The ambiguity warning in the resolveModelData logic (the console.warn inside the
firstMatch branch that uses firstMatch, secondaryMatchProviders, and
args.providerName) should be returned to callers rather than only logged; modify
the function that returns the model info to include an optional warnings?:
string[] field and, when secondaryMatchProviders.length > 0 and
args.providerName is falsy, push the existing ambiguity message into that
warnings array (instead of only console.warn), then update callers such as
resolveLanguageModelById to accept and propagate the warnings (just like
saveAgent's warnings?: string[]) so downstream code can surface the warning to
users or logs.

Comment on lines +1 to +4
export interface ParsedModelRef {
providerName?: string;
modelId: string;
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Remove or consume ParsedModelRef export to unblock CI.

knip is failing because ParsedModelRef is exported but unused outside this module (Line 1). Make it internal (or use it in consumers) so lint passes.

🔧 Minimal fix
-export interface ParsedModelRef {
+interface ParsedModelRef {
   providerName?: string;
   modelId: string;
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export interface ParsedModelRef {
providerName?: string;
modelId: string;
}
interface ParsedModelRef {
providerName?: string;
modelId: string;
}
🧰 Tools
🪛 GitHub Actions: Lint

[error] 1-1: Knip reported unused exported type: ParsedModelRef (interface) at services/platform/lib/shared/utils/model-ref.ts:1:18

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@services/platform/lib/shared/utils/model-ref.ts` around lines 1 - 4, The
exported interface ParsedModelRef is declared but unused externally; remove the
export to make it internal (or alternatively use it in callers) so the symbol is
no longer an unused export. Concretely, in the ParsedModelRef declaration remove
the "export" modifier (making it "interface ParsedModelRef { ... }") or replace
usages by importing/consuming ParsedModelRef in the modules that need it; ensure
any references to ParsedModelRef in this module still compile after the change.

larryro added 5 commits April 20, 2026 13:18
Add "<provider>:<model-id>" prefix syntax for supportedModels so entries
can pin routing when the same id is defined in multiple provider files.
Plain entries still resolve to the first matching provider, with a
save-time warning when more than one match exists.
…xport

- Run oxfmt on the three rebased agent JSONs (crm, image-creator, web)
  so format:check passes.
- Make ParsedModelRef internal — it's only used inside model-ref.ts, so
  exporting it triggers knip's unused-exports check.
…ucture

- Platform Dockerfile: add COPY lines for docs/, packages/tale_knowledge,
  packages/tale_shared, packages/tale_telemetry package.json files in
  both workspace-deps and pruner stages so bun install can resolve the
  workspaces the docs PR #1579 added to root package.json.
- docs/package.json: route mintlify through bunx so CI and image builds
  don't require a global install for broken-link checks.
- knip.config.ts: ignore uvx (used by tale_* python packages) alongside
  the existing uv entry.
…r ruff findings

- .dockerignore: add !docs/package.json exception so the Docker build can
  COPY the workspace manifest the root package.json now references.
- tale_knowledge: resolve the pre-existing ruff findings the docs PR
  left unfixed — zip(strict=True), B904 raise ... from err, SIM110 any(),
  drop unused imports/unpacked vars — so turbo lint goes green after the
  mintlify script is unblocked.
Pre-existing ruff errors surfaced after the docs lint step stopped
short-circuiting turbo. Fixes:
- tale_telemetry: replace en-dash with hyphen in comment (RUF003).
- tale_shared/config/base.py: split provider imports so isort is happy.
- tale_shared/db/retry.py: move AsyncIterator import to collections.abc.
- tale_shared/errors/__init__.py: sort __all__.
- tale_shared/logging/__init__.py: add __all__ so re-exports are explicit.
- tale_shared/logging/setup.py: wrap the loguru format string across
  lines so it fits the 120 col limit.
@larryro larryro force-pushed the feat/provider-qualified-model-refs branch from dfadd23 to 73932b9 Compare April 20, 2026 05:19
Turbo's lint / format:check tasks depend on each workspace's setup task.
@tale/rag#setup runs `uv sync --extra dev`, so the lint and format jobs
need uv on PATH. The prior `install-python: 'false'` override, added
during the CI right-size pass, skipped the uv install and made both
jobs exit 127 before any real check ran.

Drop the override for these two jobs so the default (Python + uv) kicks
back in. Other jobs in lint.yml and elsewhere keep `install-python: false`
because their turbo tasks don't chain through setup.
@larryro larryro merged commit 6700004 into main Apr 20, 2026
15 checks passed
@larryro larryro deleted the feat/provider-qualified-model-refs branch April 20, 2026 05:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant