diff --git a/apps/mobile/src/features/threads/ThreadSettingsRows.shared.tsx b/apps/mobile/src/features/threads/ThreadSettingsRows.shared.tsx
index 40841697892a9..350f916070030 100644
--- a/apps/mobile/src/features/threads/ThreadSettingsRows.shared.tsx
+++ b/apps/mobile/src/features/threads/ThreadSettingsRows.shared.tsx
@@ -80,6 +80,11 @@ export function ModelRowContent(
Legacy
) : null}
+ {props.option.isGateway ? (
+
+ LiteLLM
+
+ ) : null}
{props.option.isHidden ? (
Hidden
) : null}
diff --git a/apps/mobile/src/lib/modelOptions.ts b/apps/mobile/src/lib/modelOptions.ts
index 7771c738042d3..616411c9a6a48 100644
--- a/apps/mobile/src/lib/modelOptions.ts
+++ b/apps/mobile/src/lib/modelOptions.ts
@@ -40,6 +40,8 @@ export type ModelOption = {
};
readonly isDefault: boolean;
readonly isLegacy: boolean;
+ /** Served by a LiteLLM gateway rather than the harness's own catalog. */
+ readonly isGateway?: boolean;
readonly isUnavailable?: boolean;
readonly isHidden?: boolean;
readonly canHide?: boolean;
@@ -381,6 +383,7 @@ export function buildModelOptions(
canHide: !model.isCustom,
isDefault: model.isDefault === true,
isLegacy: model.isLegacy === true,
+ ...(model.gateway ? { isGateway: true } : {}),
...(updateRequired ? { providerUpdateRequired: updateRequired } : {}),
capabilities: model.capabilities,
selection: normalizeSelectionOptions(
@@ -444,6 +447,7 @@ export function buildModelOptions(
providerBadge: providerBadgeFor(fallbackModelSelection.instanceId),
isDefault: false,
isLegacy: model?.isLegacy === true,
+ ...(model?.gateway ? { isGateway: true } : {}),
...(isModelSelectionUnavailable(config, fallbackModelSelection, projectId) ||
(provider !== undefined && !isProviderEnabledForProject(config, provider, projectId)) ||
provider?.updateRequiredModels?.some((gated) => gated.slug === fallbackModelSelection.model)
diff --git a/apps/server/src/orchestration-v2/ProviderAuthRetry.ts b/apps/server/src/orchestration-v2/ProviderAuthRetry.ts
index 47e6cfa5bb92e..90acf1655fb08 100644
--- a/apps/server/src/orchestration-v2/ProviderAuthRetry.ts
+++ b/apps/server/src/orchestration-v2/ProviderAuthRetry.ts
@@ -17,7 +17,7 @@ import * as ThreadManagementService from "./ThreadManagementService.ts";
const RETRY_MESSAGE_PREFIX = "message:auth-retry:";
const AUTH_REJECTION_CODES = new Set(["api_error_401", "api_error_403"]);
-// Codex, OpenCode and Pi only pass the gateway's text through. LiteLLM answers an
+// Codex and OpenCode only pass the gateway's text through. LiteLLM answers an
// expired or revoked key with "Authentication Error, ..." and HTTP 401.
// A bare 401 or "unauthorized" is too common in tool output to count.
const AUTH_REJECTION_TEXT =
diff --git a/apps/server/src/provider/builtInDrivers.ts b/apps/server/src/provider/builtInDrivers.ts
index 3ee0c42cce206..348189922a6e0 100644
--- a/apps/server/src/provider/builtInDrivers.ts
+++ b/apps/server/src/provider/builtInDrivers.ts
@@ -21,7 +21,7 @@ import {
type LiteLLMLauncherEnv,
} from "@t3tools/provider-core/server/litellm";
-import { LITELLM_CLAUDE, LITELLM_CODEX, LITELLM_OPENCODE, LITELLM_PI } from "./liteLLMLaunchers.ts";
+import { LITELLM_CLAUDE, LITELLM_CODEX, LITELLM_OPENCODE } from "./liteLLMLaunchers.ts";
export type BuiltInDriversEnv =
| AcpRegistryDriverEnv
@@ -46,7 +46,7 @@ export const BUILT_IN_DRIVERS: ReadonlyArray = {
gatewayModelSlug: claudeGatewayModelSlug,
};
+const OPENCODE_GATEWAY_PREFIX = "litellm/";
+
export const LITELLM_OPENCODE: LiteLLMLauncherSpec = {
harness: "opencode",
configure: (config, launch) =>
config.serverUrl
? Effect.fail("Clear Server URL: LiteLLM can only route an OpenCode server T3 starts.")
: Effect.succeed({ ...config, binaryPath: launch.binaryPath }),
-};
-
-export const LITELLM_PI: LiteLLMLauncherSpec = {
- harness: "pi",
- configure: (config, launch) => Effect.succeed({ ...config, binaryPath: launch.binaryPath }),
- homeEnvironment: (homeDir) => ({ PI_CODING_AGENT_DIR: homeDir }),
+ // `lite opencode` adds the gateway as the `litellm` provider; other providers stay direct.
+ listedModelGatewayId: (slug) =>
+ slug.startsWith(OPENCODE_GATEWAY_PREFIX)
+ ? slug.slice(OPENCODE_GATEWAY_PREFIX.length)
+ : undefined,
};
diff --git a/apps/web/src/components/chat/ModelListRow.tsx b/apps/web/src/components/chat/ModelListRow.tsx
index 69da770f1f84b..4c584f20d3b70 100644
--- a/apps/web/src/components/chat/ModelListRow.tsx
+++ b/apps/web/src/components/chat/ModelListRow.tsx
@@ -29,6 +29,8 @@ export const ModelListRow = memo(function ModelListRow(props: {
/** Marks this instance apart from another of the same provider. */
showInstanceBadge: boolean;
showNewBadge?: boolean;
+ /** Served by a LiteLLM gateway rather than the harness's own catalog. */
+ showGatewayBadge?: boolean;
unavailable?: boolean;
jumpLabel?: string | null;
disabledReason?: string | null;
@@ -93,6 +95,11 @@ export const ModelListRow = memo(function ModelListRow(props: {
New
) : null}
+ {props.showGatewayBadge ? (
+
+ LiteLLM
+
+ ) : null}
{props.unavailable ? (
Unavailable
diff --git a/apps/web/src/components/chat/ModelPickerContent.tsx b/apps/web/src/components/chat/ModelPickerContent.tsx
index f040df764cda9..294c6dda725ea 100644
--- a/apps/web/src/components/chat/ModelPickerContent.tsx
+++ b/apps/web/src/components/chat/ModelPickerContent.tsx
@@ -79,6 +79,7 @@ type ModelPickerItem = {
acpRegistryIconUrl?: string | undefined;
continuationGroupKey?: string | undefined;
isLegacy?: boolean | undefined;
+ gateway?: "litellm" | undefined;
isUnavailable?: boolean | undefined;
};
@@ -567,6 +568,7 @@ export const ModelPickerContent = memo(function ModelPickerContent(props: {
...(model.subProvider ? { subProvider: model.subProvider } : {}),
...(model.badge ? { badge: model.badge } : {}),
...(model.isLegacy ? { isLegacy: true } : {}),
+ ...(model.gateway ? { gateway: model.gateway } : {}),
...(model.isUnavailable ? { isUnavailable: true } : {}),
instanceId,
driverKind: entry.driverKind,
@@ -1056,6 +1058,7 @@ export const ModelPickerContent = memo(function ModelPickerContent(props: {
favoriteStarOnHover={selectedInstanceId === "favorites" && !isSearching}
showInstanceBadge={badgedInstanceIds.has(model.instanceId)}
showNewBadge={model.badge === "new"}
+ showGatewayBadge={model.gateway === "litellm"}
unavailable={model.isUnavailable === true}
jumpLabel={modelJumpLabelByKey.get(modelKey) ?? null}
disabledReason={disabledReason}
diff --git a/apps/web/src/components/chat/providerIconUtils.ts b/apps/web/src/components/chat/providerIconUtils.ts
index 565dc25c05f1d..31e325b389642 100644
--- a/apps/web/src/components/chat/providerIconUtils.ts
+++ b/apps/web/src/components/chat/providerIconUtils.ts
@@ -10,6 +10,7 @@ export type ModelEsque = {
isDefault?: boolean | undefined;
badge?: "new" | undefined;
isLegacy?: boolean | undefined;
+ gateway?: "litellm" | undefined;
isUnavailable?: boolean | undefined;
};
diff --git a/apps/web/src/components/settings/AddProviderInstanceDialog.logic.ts b/apps/web/src/components/settings/AddProviderInstanceDialog.logic.ts
index 2324e31c848b3..ad5264562d246 100644
--- a/apps/web/src/components/settings/AddProviderInstanceDialog.logic.ts
+++ b/apps/web/src/components/settings/AddProviderInstanceDialog.logic.ts
@@ -27,7 +27,6 @@ export const LITELLM_LAUNCHER_DRIVERS: ReadonlySet = new Set([
"claudeAgent",
"codex",
"opencode",
- "pi",
]);
/** The suggested label follows the launcher until the user types their own. */
diff --git a/apps/web/src/components/settings/ProviderInstanceCard.tsx b/apps/web/src/components/settings/ProviderInstanceCard.tsx
index ab5be4f15fc2e..0f4990eba7554 100644
--- a/apps/web/src/components/settings/ProviderInstanceCard.tsx
+++ b/apps/web/src/components/settings/ProviderInstanceCard.tsx
@@ -1287,7 +1287,7 @@ export function ProviderInstanceCard({
}
/>
- {LITELLM_LAUNCHER_DRIVERS.has(instance.driver) ? (
+ {LITELLM_LAUNCHER_DRIVERS.has(instance.driver) || instance.launcher === "litellm" ? (
diff --git a/apps/web/src/components/settings/ProviderModelsSection.tsx b/apps/web/src/components/settings/ProviderModelsSection.tsx
index 3e39d6ccfc12b..6e576ba44abd8 100644
--- a/apps/web/src/components/settings/ProviderModelsSection.tsx
+++ b/apps/web/src/components/settings/ProviderModelsSection.tsx
@@ -532,6 +532,9 @@ function ProviderModelRow({
{model.isCustom ? (
custom
) : null}
+ {model.gateway === "litellm" ? (
+ LiteLLM
+ ) : null}
{capLabels.length > 0 ? (
diff --git a/apps/web/src/modelSelection.ts b/apps/web/src/modelSelection.ts
index 96de6feb60ff7..3644c044a82b0 100644
--- a/apps/web/src/modelSelection.ts
+++ b/apps/web/src/modelSelection.ts
@@ -70,6 +70,7 @@ export interface AppModelOption {
isCustom: boolean;
isDefault?: boolean;
isLegacy?: boolean;
+ gateway?: "litellm";
isUnavailable?: boolean;
}
@@ -80,7 +81,7 @@ const LITELLM_REQUEST_TAG_DRIVERS: ReadonlySet = new Set([
"opencode",
]);
-/** LiteLLM tags reach the gateway through Claude, Codex and OpenCode; Pi has no tag channel. */
+/** LiteLLM tags reach the gateway through Claude, Codex and OpenCode. */
export function supportsLiteLLMRequestTags(
settings: Pick,
instanceId: ProviderInstanceId,
@@ -150,6 +151,7 @@ function toAppModelOption(
if (model.badge) option.badge = model.badge;
if (model.isDefault) option.isDefault = true;
if (model.isLegacy) option.isLegacy = true;
+ if (model.gateway) option.gateway = model.gateway;
return option;
}
diff --git a/docs/user/providers-litellm.md b/docs/user/providers-litellm.md
index d8c6cb8fc9fd1..5d83395dcfb37 100644
--- a/docs/user/providers-litellm.md
+++ b/docs/user/providers-litellm.md
@@ -1,6 +1,6 @@
# LiteLLM
-T3 Code can run Claude, Codex, OpenCode, and Pi through a [LiteLLM](https://docs.litellm.ai)
+T3 Code can run Claude, Codex, and OpenCode through a [LiteLLM](https://docs.litellm.ai)
gateway with the LiteLLM CLI (`lite`). Each harness keeps working as usual, but it signs in
with your gateway's SSO and uses the gateway's models. This lets you, for example, use a
GPT model on the Claude harness.
@@ -17,7 +17,7 @@ GPT model on the Claude harness.
2. Set `LITELLM_PROXY_URL` to your gateway URL in your shell profile, for example
`export LITELLM_PROXY_URL=https://litellm.example.com`. The desktop app reads it from your
login shell. You can also set it in a provider instance's **Environment variables**.
-3. In **Settings > Providers**, choose **Add provider**, pick Claude, Codex, OpenCode, or Pi,
+3. In **Settings > Providers**, choose **Add provider**, pick Claude, Codex, or OpenCode,
and turn on **Launch through LiteLLM**. The suggested label is, for example,
**LiteLLM Claude**, and that is the name the model picker shows. To route an existing
provider instead, such as the built-in Codex or Claude, open it and turn on
@@ -42,8 +42,12 @@ full URL and paste it in T3 Code when it asks.
## Models
- **LiteLLM Claude** lists every model the gateway offers.
-- **LiteLLM Codex**, **LiteLLM OpenCode**, and **LiteLLM Pi** list the models that `lite`
- syncs into those harnesses.
+- **LiteLLM Codex** and **LiteLLM OpenCode** list the models that `lite` syncs into those
+ harnesses.
+
+In the model picker and in **Settings > Providers**, a **LiteLLM** label marks each model the
+gateway serves. A model without the label comes from the harness's own list. LiteLLM OpenCode
+sends those models to their usual provider, not to the gateway.
T3 Code checks the gateway's model list at most once a minute, and **Refresh** in
**Settings > Providers** checks it now. If the gateway removes the model a thread uses, the
@@ -71,13 +75,11 @@ commit messages, and other text generation do not carry tags.
- Threads that a thread starts, such as delegated tasks, forks, and threads an agent creates,
copy its tags. A scheduled task keeps the tags you set on it.
-LiteLLM Pi does not send request tags yet.
-
## Limits
-- LiteLLM Codex and LiteLLM Pi use their own config directory, so they do not read your
- usual Codex or Pi config, skills, or extensions. A Codex provider you switch to LiteLLM
- might not resume threads it started before the switch.
+- LiteLLM Codex uses its own config directory, so it does not read your usual Codex config or
+ skills. A Codex provider you switch to LiteLLM might not resume threads it started before
+ the switch.
- When the selected text generation model is not on the gateway, commit messages, titles,
and branch names use the first gateway model.
- LiteLLM Codex does not accept `-c` or `--config` in **Launch arguments**, because Codex
diff --git a/packages/contracts/src/server.ts b/packages/contracts/src/server.ts
index e027930c116ba..2b2c3c853521d 100644
--- a/packages/contracts/src/server.ts
+++ b/packages/contracts/src/server.ts
@@ -83,6 +83,8 @@ export const ServerProviderModel = Schema.Struct({
isCustom: Schema.Boolean,
isDefault: Schema.optional(Schema.Boolean),
isLegacy: Schema.optional(Schema.Boolean),
+ /** Set when a LiteLLM gateway serves the model, as opposed to the harness's own catalog. */
+ gateway: Schema.optional(Schema.Literal("litellm")),
capabilities: Schema.NullOr(ModelCapabilities),
});
export type ServerProviderModel = typeof ServerProviderModel.Type;
diff --git a/packages/provider-core/src/server/litellm.test.ts b/packages/provider-core/src/server/litellm.test.ts
index 6a33e3bf99928..e56f03abfba17 100644
--- a/packages/provider-core/src/server/litellm.test.ts
+++ b/packages/provider-core/src/server/litellm.test.ts
@@ -35,6 +35,7 @@ import {
liteLLMSignedOutMessage,
parseLiteLLMModelIds,
type LiteLLMHarness,
+ type LiteLLMStatus,
withLiteLLMLauncher,
} from "./litellm.ts";
import type {
@@ -92,13 +93,13 @@ describe("applyLiteLLMStatus", () => {
(id) => id.replace(/^bedrock\//, ""),
);
assert.deepEqual(
- result.models.map((model) => [model.slug, model.name, model.isCustom]),
+ result.models.map((model) => [model.slug, model.name, model.isCustom, model.gateway]),
[
- ["gpt-5", "gpt-5", false],
- ["claude-sonnet-4-5", "Claude Sonnet 4.5", false],
- ["bedrock/sonnet-4.5", "bedrock/sonnet-4.5", false],
- ["claude sonnet 4.5", "claude sonnet 4.5", false],
- ["my-alias", "My alias", true],
+ ["gpt-5", "gpt-5", false, "litellm"],
+ ["claude-sonnet-4-5", "Claude Sonnet 4.5", false, "litellm"],
+ ["bedrock/sonnet-4.5", "bedrock/sonnet-4.5", false, "litellm"],
+ ["claude sonnet 4.5", "claude sonnet 4.5", false, "litellm"],
+ ["my-alias", "My alias", true, undefined],
],
);
assert.strictEqual(result.models[0]?.capabilities, capabilities);
@@ -106,6 +107,30 @@ describe("applyLiteLLMStatus", () => {
assert.strictEqual(result.models[3]?.capabilities, sonnetCapabilities);
});
+ it("marks only the harness-listed models the gateway serves", () => {
+ const listed = (slug: string) => ({ slug, name: slug, isCustom: false, capabilities: null });
+ const harnessSnapshot = snapshot({
+ models: [listed("litellm/gpt-5"), listed("openai/gpt-5"), listed("litellm/retired")],
+ });
+ const gatewayId = (slug: string) =>
+ slug.startsWith("litellm/") ? slug.slice("litellm/".length) : undefined;
+ const marks = (status: LiteLLMStatus) =>
+ applyLiteLLMStatus(harnessSnapshot, status, undefined, undefined, gatewayId).models.map(
+ (model) => [model.slug, model.gateway],
+ );
+ assert.deepEqual(marks({ auth: { status: "authenticated" }, models: ["gpt-5"] }), [
+ ["litellm/gpt-5", "litellm"],
+ ["openai/gpt-5", undefined],
+ ["litellm/retired", undefined],
+ ]);
+ // Without the gateway's list, no model can claim to be served by it.
+ assert.deepEqual(marks({ auth: { status: "unauthenticated", message: "Signed out." } }), [
+ ["litellm/gpt-5", undefined],
+ ["openai/gpt-5", undefined],
+ ["litellm/retired", undefined],
+ ]);
+ });
+
it("reports the gateway sign-in instead of the harness's own account", () => {
const signedOut = applyLiteLLMStatus(
snapshot(),
@@ -326,7 +351,6 @@ const createLiteLLMInstance = (
harness: options.harness ?? "claude",
configure: (config, launch) =>
Effect.succeed({ ...config, binaryPath: launch.binaryPath, homePath: launch.homeDir }),
- homeEnvironment: (homeDir) => ({ FAKE_HOME: homeDir }),
gatewayModelCapabilities: capabilities,
servesModel: (model, requested) => model.slug === `my-${requested}`,
});
@@ -387,10 +411,6 @@ describe.skipIf(windowsHost)("withLiteLLMLauncher", () => {
shim,
NodePath.join(fixture.dir, "state", "litellm", instanceId, "bin", "claude"),
);
- assert.deepEqual(
- input.environment.find((variable) => variable.name === "FAKE_HOME")?.value,
- input.config.homePath,
- );
const run = (args: ReadonlyArray) =>
spawnAndCollect(shim, ChildProcess.make(shim, [...args], { env: fixture.environment }));
@@ -603,8 +623,6 @@ describe.skipIf(windowsHost)("withLiteLLMLauncher", () => {
"tool:company,project:billing",
]);
assert.deepEqual(yield* tagsWith({ mode: "off", custom: "" }), ["", "project:billing"]);
- const pi = yield* createLiteLLMInstance(fixture, [], { harness: "pi" });
- assert.isUndefined(pi.orchestrationAdapter.launchTags);
}).pipe(Effect.scoped, Effect.provide(testServices)),
);
diff --git a/packages/provider-core/src/server/litellm.ts b/packages/provider-core/src/server/litellm.ts
index fd9a673ffa6fb..47b4da4820a0f 100644
--- a/packages/provider-core/src/server/litellm.ts
+++ b/packages/provider-core/src/server/litellm.ts
@@ -1,5 +1,5 @@
/**
- * Runs an existing harness (Claude, Codex, Pi, OpenCode) through the LiteLLM CLI
+ * Runs an existing harness (Claude, Codex, OpenCode) through the LiteLLM CLI
* (`lite `), which signs in with SSO, routes the harness at the gateway
* and syncs the gateway's models into the harness. T3 keeps no LiteLLM secrets:
* `lite` owns the key, its refresh, and the gateway URL (`LITELLM_PROXY_URL`).
@@ -45,9 +45,8 @@ import * as ProviderHost from "./ProviderHost.ts";
import type { ManagedServerProvider } from "./snapshot.ts";
import { spawnAndCollect } from "./snapshotProbe.ts";
-export type LiteLLMHarness = "claude" | "codex" | "pi" | "opencode";
+export type LiteLLMHarness = "claude" | "codex" | "opencode";
-/** `lite pi` first shipped in 1.102.0; `--pkce` login in 1.99.0. */
const MINIMUM_LITELLM_CLI_VERSION = "1.102.0";
const INSTALL_HINT = "Install the LiteLLM CLI with `uv tool install 'litellm[cli]'`.";
const STATUS_TTL_MS = 60_000;
@@ -129,8 +128,6 @@ const requestTagShimLines = (harness: LiteLLMHarness): ReadonlyArray =>
return [
`if ${TAGS_SET} && [ -z "\${OPENCODE_CONFIG-}" ]; then export OPENCODE_CONFIG="$(dirname "$0")/${OPENCODE_TAGS_CONFIG}"; fi`,
];
- case "pi":
- return [];
}
};
@@ -225,6 +222,21 @@ const mergeGatewayModels = (
return [...gateway, ...current.filter((model) => model.isCustom && !listed.has(model.slug))];
};
+const markGatewayModels = (
+ models: ReadonlyArray,
+ gatewayIds: ReadonlyArray | undefined,
+ listedModelGatewayId: (slug: string) => string | undefined,
+): ReadonlyArray => {
+ if (gatewayIds === undefined) return models;
+ const served = new Set(gatewayIds);
+ return models.map((model) => {
+ const gatewayId = listedModelGatewayId(model.slug);
+ return gatewayId !== undefined && served.has(gatewayId)
+ ? { ...model, gateway: "litellm" as const }
+ : model;
+ });
+};
+
/**
* `gatewayModelCapabilities` is `undefined` for harnesses that list the models
* `lite` syncs into them; otherwise the gateway's list replaces the catalog.
@@ -234,23 +246,23 @@ export const applyLiteLLMStatus = (
status: LiteLLMStatus,
gatewayModelCapabilities: ModelCapabilities | null | undefined,
gatewayModelSlug: (gatewayId: string) => string = (gatewayId) => gatewayId,
+ listedModelGatewayId: (slug: string) => string | undefined = (slug) => slug,
): ServerProvider => {
const authenticated = status.auth.status === "authenticated";
const ownsCatalog = gatewayModelCapabilities !== undefined;
+ const models = ownsCatalog
+ ? mergeGatewayModels(
+ snapshot.models,
+ status.models ?? [],
+ gatewayModelCapabilities,
+ gatewayModelSlug,
+ )
+ : snapshot.models;
const base: ServerProvider = {
...snapshot,
setup: { ...snapshot.setup, canAuthenticate: true, canInstall: false },
auth: { status: authenticated ? "authenticated" : "unauthenticated", label: "LiteLLM SSO" },
- ...(ownsCatalog
- ? {
- models: mergeGatewayModels(
- snapshot.models,
- status.models ?? [],
- gatewayModelCapabilities,
- gatewayModelSlug,
- ),
- }
- : {}),
+ models: markGatewayModels(models, status.models, listedModelGatewayId),
};
if (status.auth.status !== "authenticated" || !snapshot.enabled)
return status.auth.status === "authenticated" || !snapshot.enabled
@@ -318,12 +330,12 @@ export interface LiteLLMLauncherSpec {
readonly environment: NodeJS.ProcessEnv;
},
) => Effect.Effect;
- /** Environment that places the harness home; user values win. */
- readonly homeEnvironment?: (homeDir: string) => Record;
/** Set when T3 owns the model catalog (Claude); other harnesses list what `lite` syncs. */
readonly gatewayModelCapabilities?: ModelCapabilities | null;
/** Maps a gateway model ID to a catalog slug or alias so it keeps catalog capabilities. */
readonly gatewayModelSlug?: (gatewayId: string) => string;
+ /** The gateway model ID behind a listed slug, if any; absent means the slug is the ID. */
+ readonly listedModelGatewayId?: (slug: string) => string | undefined;
/** Aliases the harness resolves to a listed model; exact slugs always count. */
readonly servesModel?: (model: ServerProviderModel, requested: string) => boolean;
}
@@ -527,14 +539,7 @@ export const withLiteLLMLauncher = (
);
}).pipe(Effect.mapError((cause) => fail("Could not write the LiteLLM launcher.", cause)));
- const userEnvironment = new Set(input.environment.map((variable) => variable.name));
- const environment = [
- ...input.environment,
- ...Object.entries(spec.homeEnvironment?.(homeDir) ?? {})
- .filter(([name]) => !userEnvironment.has(name))
- .map(([name, value]) => ({ name, value, sensitive: false })),
- ];
- const processEnv = yield* mergeProviderInstanceEnvironment(environment);
+ const processEnv = yield* mergeProviderInstanceEnvironment(input.environment);
const config = yield* spec
.configure(input.config, { binaryPath, homeDir, environment: processEnv })
.pipe(Effect.mapError((detail) => fail(detail)));
@@ -661,10 +666,16 @@ export const withLiteLLMLauncher = (
};
});
- const instance = yield* driver.create({ ...input, config, environment, launchGeneration });
+ const instance = yield* driver.create({ ...input, config, launchGeneration });
yield* Deferred.succeed(innerSnapshot, instance.snapshot);
const snapshot = wrapSnapshot(instance.snapshot, status, freshStatus, (current, liteStatus) =>
- applyLiteLLMStatus(current, liteStatus, spec.gatewayModelCapabilities, spec.gatewayModelSlug),
+ applyLiteLLMStatus(
+ current,
+ liteStatus,
+ spec.gatewayModelCapabilities,
+ spec.gatewayModelSlug,
+ spec.listedModelGatewayId,
+ ),
);
const auth = yield* makeLiteLLMAuth({
instanceId: input.instanceId,
@@ -687,16 +698,12 @@ export const withLiteLLMLauncher = (
orchestrationAdapter: {
...adapter,
launchGeneration,
- ...(spec.harness === "pi"
- ? {}
- : {
- launchTags: (policy) =>
- withRequestTags(policy).pipe(
- Effect.map(
- ({ launchEnvironment }) => launchEnvironment?.[LITELLM_REQUEST_TAGS_ENV] ?? "",
- ),
- ),
- }),
+ launchTags: (policy) =>
+ withRequestTags(policy).pipe(
+ Effect.map(
+ ({ launchEnvironment }) => launchEnvironment?.[LITELLM_REQUEST_TAGS_ENV] ?? "",
+ ),
+ ),
// New threads get their own session, so a new thread never inherits an old
// key or model list. Threads already on a shared session keep sharing it.
getCapabilities: () => adapter.getCapabilities().pipe(Effect.map(perThreadSessions)),