Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 41 additions & 10 deletions packages/agent-chat/src/ranch-shell/RanchChatShell.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -396,14 +396,31 @@ function shouldOfferStoreOpenRouterKey(
): boolean {
if (code === "insufficient_credits") return false;
if (code === "official_not_authorized" || code === "official_model_unsupported") {
return true;
return false;
}
const blob = `${code || ""} ${message || ""}`;
return /invalid[- ]api[- ]key|missing[- ]api[- ]key|no api key|openrouter.*(?:key|credit|quota)|api key not/i.test(
blob,
);
}

function requestedModelForSend(
selected: string | null,
listed: string | null,
official: boolean,
keyGeo: string | null | undefined,
): string | null {
if (
official &&
(keyGeo || "").trim() &&
selected &&
!officialShelfAllows(selected, keyGeo)
) {
return listed;
}
return selected;
}

function sendFailureCopy(
e: unknown,
t: RanchMessages,
Expand All @@ -419,11 +436,15 @@ function sendFailureCopy(
? t.billingUnavailable
: e.code === "unsupported_model"
? t.unsupportedModel
: offerStoreKey
? t.needOpenRouterKey
: e.code === "model_pricing_unavailable"
? t.modelPricingUnavailable
: e.message || t.sendFailed;
: e.code === "official_not_authorized"
? t.officialNotAuthorized
: e.code === "official_model_unsupported"
? t.officialModelUnsupported
: offerStoreKey
? t.needOpenRouterKey
: e.code === "model_pricing_unavailable"
? t.modelPricingUnavailable
: e.message || t.sendFailed;
return { text, offerStoreKey };
}

Expand Down Expand Up @@ -2742,7 +2763,12 @@ export function RanchChatShell(props: RanchChatShellProps) {
? opts.threadId
: (activeTopic?.id ?? composerTopic?.id ?? null);
await client.sendMessage(chatId, text, mentions, sendThreadId, {
requested_model: selectedModelId,
requested_model: requestedModelForSend(
selectedModelId,
composerModel?.listed_model_id ?? null,
Boolean(composerModel?.official_channel),
composerModel?.official_key_geo,
),
});
if (group && mentions) {
if (mentions.length === 1) {
Expand Down Expand Up @@ -2891,7 +2917,12 @@ export function RanchChatShell(props: RanchChatShellProps) {
text,
mentions,
activeTopic?.id ?? composerTopic?.id ?? null,
{ requested_model: selectedModelId },
{ requested_model: requestedModelForSend(
selectedModelId,
composerModel?.listed_model_id ?? null,
Boolean(composerModel?.official_channel),
composerModel?.official_key_geo,
) },
);
if (group && mentions) {
if (mentions.length === 1) {
Expand Down Expand Up @@ -3151,7 +3182,8 @@ export function RanchChatShell(props: RanchChatShellProps) {
catalogPending &&
stored &&
!listedChanged &&
officialV0SupportsModel(stored)
officialV0SupportsModel(stored) &&
officialShelfAllows(stored, row.official_key_geo)
) {
setSelectedModelId(stored);
} else {
Expand Down Expand Up @@ -4872,7 +4904,6 @@ export function RanchChatShell(props: RanchChatShellProps) {
const visible = filterComposerModels(options, composerMenuQuery);
const value =
options.find((id) => sameModelId(id, selectedModelId)) ||
(official && selectedModelId ? selectedModelId : "") ||
options.find((id) => sameModelId(id, listed)) ||
options[0] ||
"";
Expand Down
8 changes: 4 additions & 4 deletions packages/agent-chat/src/ranch-shell/i18n.ts
Original file line number Diff line number Diff line change
Expand Up @@ -588,12 +588,12 @@ const en: RanchMessages = {
billingUnavailable: "Billing check unavailable. Try again in a moment.",
unsupportedModel: "This agent does not support that model.",
officialNotAuthorized:
"Official hosted inference is not available. Use this agent’s own key, or write a Store OpenRouter key into its runtime.",
"This model is not on the official Host shelf. Pick one from the list.",
needOpenRouterKey:
"OpenRouter is BYO: the key lives on the agent, not on Interfaze. Host cannot see the key — we only read the heartbeat model. Put a key in its runtime, or buy Store credits for the owner to write one in.",
buyOpenRouterCredits: "Buy OpenRouter credits",
officialModelUnsupported:
"Official hosted inference is frozen and cannot run thinking/reasoning models. Use the agent’s key, or pick a chat model after writing a Store key.",
"Official hosted inference cannot run thinking/reasoning models. Pick a chat model from the list.",
modelPricingUnavailable: "No platform price for that model yet. Pick another or ask the owner to wait for Host pack coverage.",
pricingMismatch: (listed, observed) =>
`Listed ${listed} ≠ ran ${observed} (billed at listing price)`,
Expand Down Expand Up @@ -1180,12 +1180,12 @@ const zh: RanchMessages = {
billingUnavailable: "计费服务暂时不可用,请稍后再试。",
unsupportedModel: "该智能体不支持所选模型。",
officialNotAuthorized:
"官方代打未开放。请用这只 agent 自己的钥匙,或把 Store OpenRouter 钥匙写进 runtime。",
"这个型号不在官方货架上,请换一个列表里的模型。",
needOpenRouterKey:
"OpenRouter 是自备钥匙:钥匙在 agent 运行时里,Interfaze 不会代收。Host 看不见钥匙,只认心跳型号。请写进它的 OpenClaw / runtime,或去 Store 买额度让 Owner 写入。",
buyOpenRouterCredits: "去 Store 买 OpenRouter 额度",
officialModelUnsupported:
"官方代打已冻结,思考/推理模跑不了。请用 agent 自己的钥匙,或写入 Store 钥匙后再选对话模。",
"官方通道跑不了思考/推理模,请换一个列表里的对话模型。",
modelPricingUnavailable: "平台暂无该模型报价,请换一个;或等 Host 价包录入后再试。",
pricingMismatch: (listed, observed) =>
`挂牌 ${listed} ≠ 运行 ${observed}(按挂牌价结算)`,
Expand Down
Loading