Compare commits
No commits in common. "4ad92799e154d15f755ddf90f4d438d2592e94c1" and "b1d12d2f3771c50f848f9edcf86b56bf2168573f" have entirely different histories.
4ad92799e1
...
b1d12d2f37
12 changed files with 14 additions and 156 deletions
|
|
@ -144,23 +144,6 @@ export function asStringArray(value: unknown): string[] {
|
||||||
return Array.isArray(value) ? value.filter((item): item is string => typeof item === "string") : [];
|
return Array.isArray(value) ? value.filter((item): item is string => typeof item === "string") : [];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Resolve an adapter billing type with an optional user-configured override.
|
|
||||||
*
|
|
||||||
* When `billingMode` is `"subscription"` or `"metered"`, the override takes
|
|
||||||
* precedence over the auto-detected value. Any other value (including the
|
|
||||||
* default `"auto"` or empty string) falls through to `autoDetected`.
|
|
||||||
*/
|
|
||||||
export function applyBillingModeOverride(
|
|
||||||
autoDetected: "api" | "subscription",
|
|
||||||
billingMode: string,
|
|
||||||
): "api" | "subscription" {
|
|
||||||
const normalized = billingMode.trim().toLowerCase();
|
|
||||||
if (normalized === "subscription") return "subscription";
|
|
||||||
if (normalized === "metered" || normalized === "api") return "api";
|
|
||||||
return autoDetected;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function parseJson(value: string): Record<string, unknown> | null {
|
export function parseJson(value: string): Record<string, unknown> | null {
|
||||||
try {
|
try {
|
||||||
return JSON.parse(value) as Record<string, unknown>;
|
return JSON.parse(value) as Record<string, unknown>;
|
||||||
|
|
|
||||||
|
|
@ -344,7 +344,6 @@ export interface CreateConfigValues {
|
||||||
workspaceBranchTemplate?: string;
|
workspaceBranchTemplate?: string;
|
||||||
worktreeParentDir?: string;
|
worktreeParentDir?: string;
|
||||||
runtimeServicesJson?: string;
|
runtimeServicesJson?: string;
|
||||||
billingMode?: string;
|
|
||||||
maxTurnsPerRun: number;
|
maxTurnsPerRun: number;
|
||||||
heartbeatEnabled: boolean;
|
heartbeatEnabled: boolean;
|
||||||
intervalSec: number;
|
intervalSec: number;
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,6 @@ import {
|
||||||
ensurePathInEnv,
|
ensurePathInEnv,
|
||||||
renderTemplate,
|
renderTemplate,
|
||||||
runChildProcess,
|
runChildProcess,
|
||||||
applyBillingModeOverride,
|
|
||||||
} from "@paperclipai/adapter-utils/server-utils";
|
} from "@paperclipai/adapter-utils/server-utils";
|
||||||
import {
|
import {
|
||||||
parseClaudeStreamJson,
|
parseClaudeStreamJson,
|
||||||
|
|
@ -98,10 +97,9 @@ function hasNonEmptyEnvValue(env: Record<string, string>, key: string): boolean
|
||||||
return typeof raw === "string" && raw.trim().length > 0;
|
return typeof raw === "string" && raw.trim().length > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
function resolveClaudeBillingType(env: Record<string, string>, billingMode: string): "api" | "subscription" {
|
function resolveClaudeBillingType(env: Record<string, string>): "api" | "subscription" {
|
||||||
// Claude uses API-key auth when ANTHROPIC_API_KEY is present; otherwise rely on local login/session auth.
|
// Claude uses API-key auth when ANTHROPIC_API_KEY is present; otherwise rely on local login/session auth.
|
||||||
const autoDetected = hasNonEmptyEnvValue(env, "ANTHROPIC_API_KEY") ? "api" : "subscription";
|
return hasNonEmptyEnvValue(env, "ANTHROPIC_API_KEY") ? "api" : "subscription";
|
||||||
return applyBillingModeOverride(autoDetected, billingMode);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function buildClaudeRuntimeConfig(input: ClaudeExecutionInput): Promise<ClaudeRuntimeConfig> {
|
async function buildClaudeRuntimeConfig(input: ClaudeExecutionInput): Promise<ClaudeRuntimeConfig> {
|
||||||
|
|
@ -340,7 +338,7 @@ export async function execute(ctx: AdapterExecutionContext): Promise<AdapterExec
|
||||||
(entry): entry is [string, string] => typeof entry[1] === "string",
|
(entry): entry is [string, string] => typeof entry[1] === "string",
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
const billingType = resolveClaudeBillingType(effectiveEnv, asString(config.billingMode, "auto"));
|
const billingType = resolveClaudeBillingType(effectiveEnv);
|
||||||
const skillsDir = await buildSkillsDir(config);
|
const skillsDir = await buildSkillsDir(config);
|
||||||
|
|
||||||
// When instructionsFilePath is configured, create a combined temp file that
|
// When instructionsFilePath is configured, create a combined temp file that
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,6 @@ import {
|
||||||
renderTemplate,
|
renderTemplate,
|
||||||
joinPromptSections,
|
joinPromptSections,
|
||||||
runChildProcess,
|
runChildProcess,
|
||||||
applyBillingModeOverride,
|
|
||||||
} from "@paperclipai/adapter-utils/server-utils";
|
} from "@paperclipai/adapter-utils/server-utils";
|
||||||
import { parseCodexJsonl, isCodexUnknownSessionError } from "./parse.js";
|
import { parseCodexJsonl, isCodexUnknownSessionError } from "./parse.js";
|
||||||
import { pathExists, prepareManagedCodexHome, resolveManagedCodexHomeDir } from "./codex-home.js";
|
import { pathExists, prepareManagedCodexHome, resolveManagedCodexHomeDir } from "./codex-home.js";
|
||||||
|
|
@ -58,10 +57,9 @@ function hasNonEmptyEnvValue(env: Record<string, string>, key: string): boolean
|
||||||
return typeof raw === "string" && raw.trim().length > 0;
|
return typeof raw === "string" && raw.trim().length > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
function resolveCodexBillingType(env: Record<string, string>, billingMode: string): "api" | "subscription" {
|
function resolveCodexBillingType(env: Record<string, string>): "api" | "subscription" {
|
||||||
// Codex uses API-key auth when OPENAI_API_KEY is present; otherwise rely on local login/session auth.
|
// Codex uses API-key auth when OPENAI_API_KEY is present; otherwise rely on local login/session auth.
|
||||||
const autoDetected = hasNonEmptyEnvValue(env, "OPENAI_API_KEY") ? "api" : "subscription";
|
return hasNonEmptyEnvValue(env, "OPENAI_API_KEY") ? "api" : "subscription";
|
||||||
return applyBillingModeOverride(autoDetected, billingMode);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function resolveCodexBiller(env: Record<string, string>, billingType: "api" | "subscription"): string {
|
function resolveCodexBiller(env: Record<string, string>, billingType: "api" | "subscription"): string {
|
||||||
|
|
@ -380,7 +378,7 @@ export async function execute(ctx: AdapterExecutionContext): Promise<AdapterExec
|
||||||
(entry): entry is [string, string] => typeof entry[1] === "string",
|
(entry): entry is [string, string] => typeof entry[1] === "string",
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
const billingType = resolveCodexBillingType(effectiveEnv, asString(config.billingMode, "auto"));
|
const billingType = resolveCodexBillingType(effectiveEnv);
|
||||||
const runtimeEnv = ensurePathInEnv(effectiveEnv);
|
const runtimeEnv = ensurePathInEnv(effectiveEnv);
|
||||||
await ensureCommandResolvable(command, cwd, runtimeEnv);
|
await ensureCommandResolvable(command, cwd, runtimeEnv);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,6 @@ import {
|
||||||
renderTemplate,
|
renderTemplate,
|
||||||
joinPromptSections,
|
joinPromptSections,
|
||||||
runChildProcess,
|
runChildProcess,
|
||||||
applyBillingModeOverride,
|
|
||||||
} from "@paperclipai/adapter-utils/server-utils";
|
} from "@paperclipai/adapter-utils/server-utils";
|
||||||
import { DEFAULT_CURSOR_LOCAL_MODEL } from "../index.js";
|
import { DEFAULT_CURSOR_LOCAL_MODEL } from "../index.js";
|
||||||
import { parseCursorJsonl, isCursorUnknownSessionError } from "./parse.js";
|
import { parseCursorJsonl, isCursorUnknownSessionError } from "./parse.js";
|
||||||
|
|
@ -43,11 +42,10 @@ function hasNonEmptyEnvValue(env: Record<string, string>, key: string): boolean
|
||||||
return typeof raw === "string" && raw.trim().length > 0;
|
return typeof raw === "string" && raw.trim().length > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
function resolveCursorBillingType(env: Record<string, string>, billingMode: string): "api" | "subscription" {
|
function resolveCursorBillingType(env: Record<string, string>): "api" | "subscription" {
|
||||||
const autoDetected = hasNonEmptyEnvValue(env, "CURSOR_API_KEY") || hasNonEmptyEnvValue(env, "OPENAI_API_KEY")
|
return hasNonEmptyEnvValue(env, "CURSOR_API_KEY") || hasNonEmptyEnvValue(env, "OPENAI_API_KEY")
|
||||||
? "api"
|
? "api"
|
||||||
: "subscription";
|
: "subscription";
|
||||||
return applyBillingModeOverride(autoDetected, billingMode);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function resolveCursorBiller(
|
function resolveCursorBiller(
|
||||||
|
|
@ -270,7 +268,7 @@ export async function execute(ctx: AdapterExecutionContext): Promise<AdapterExec
|
||||||
(entry): entry is [string, string] => typeof entry[1] === "string",
|
(entry): entry is [string, string] => typeof entry[1] === "string",
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
const billingType = resolveCursorBillingType(effectiveEnv, asString(config.billingMode, "auto"));
|
const billingType = resolveCursorBillingType(effectiveEnv);
|
||||||
const runtimeEnv = ensurePathInEnv(effectiveEnv);
|
const runtimeEnv = ensurePathInEnv(effectiveEnv);
|
||||||
await ensureCommandResolvable(command, cwd, runtimeEnv);
|
await ensureCommandResolvable(command, cwd, runtimeEnv);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,6 @@ import {
|
||||||
redactEnvForLogs,
|
redactEnvForLogs,
|
||||||
renderTemplate,
|
renderTemplate,
|
||||||
runChildProcess,
|
runChildProcess,
|
||||||
applyBillingModeOverride,
|
|
||||||
} from "@paperclipai/adapter-utils/server-utils";
|
} from "@paperclipai/adapter-utils/server-utils";
|
||||||
import { DEFAULT_GEMINI_LOCAL_MODEL } from "../index.js";
|
import { DEFAULT_GEMINI_LOCAL_MODEL } from "../index.js";
|
||||||
import {
|
import {
|
||||||
|
|
@ -41,11 +40,10 @@ function hasNonEmptyEnvValue(env: Record<string, string>, key: string): boolean
|
||||||
return typeof raw === "string" && raw.trim().length > 0;
|
return typeof raw === "string" && raw.trim().length > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
function resolveGeminiBillingType(env: Record<string, string>, billingMode: string): "api" | "subscription" {
|
function resolveGeminiBillingType(env: Record<string, string>): "api" | "subscription" {
|
||||||
const autoDetected = hasNonEmptyEnvValue(env, "GEMINI_API_KEY") || hasNonEmptyEnvValue(env, "GOOGLE_API_KEY")
|
return hasNonEmptyEnvValue(env, "GEMINI_API_KEY") || hasNonEmptyEnvValue(env, "GOOGLE_API_KEY")
|
||||||
? "api"
|
? "api"
|
||||||
: "subscription";
|
: "subscription";
|
||||||
return applyBillingModeOverride(autoDetected, billingMode);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderPaperclipEnvNote(env: Record<string, string>): string {
|
function renderPaperclipEnvNote(env: Record<string, string>): string {
|
||||||
|
|
@ -219,7 +217,7 @@ export async function execute(ctx: AdapterExecutionContext): Promise<AdapterExec
|
||||||
(entry): entry is [string, string] => typeof entry[1] === "string",
|
(entry): entry is [string, string] => typeof entry[1] === "string",
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
const billingType = resolveGeminiBillingType(effectiveEnv, asString(config.billingMode, "auto"));
|
const billingType = resolveGeminiBillingType(effectiveEnv);
|
||||||
const runtimeEnv = ensurePathInEnv(effectiveEnv);
|
const runtimeEnv = ensurePathInEnv(effectiveEnv);
|
||||||
await ensureCommandResolvable(command, cwd, runtimeEnv);
|
await ensureCommandResolvable(command, cwd, runtimeEnv);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,6 @@ import {
|
||||||
runChildProcess,
|
runChildProcess,
|
||||||
readPaperclipRuntimeSkillEntries,
|
readPaperclipRuntimeSkillEntries,
|
||||||
resolvePaperclipDesiredSkillNames,
|
resolvePaperclipDesiredSkillNames,
|
||||||
applyBillingModeOverride,
|
|
||||||
} from "@paperclipai/adapter-utils/server-utils";
|
} from "@paperclipai/adapter-utils/server-utils";
|
||||||
import { isOpenCodeUnknownSessionError, parseOpenCodeJsonl } from "./parse.js";
|
import { isOpenCodeUnknownSessionError, parseOpenCodeJsonl } from "./parse.js";
|
||||||
import { ensureOpenCodeModelConfiguredAndAvailable } from "./models.js";
|
import { ensureOpenCodeModelConfiguredAndAvailable } from "./models.js";
|
||||||
|
|
@ -372,10 +371,7 @@ export async function execute(ctx: AdapterExecutionContext): Promise<AdapterExec
|
||||||
provider: parseModelProvider(modelId),
|
provider: parseModelProvider(modelId),
|
||||||
biller: resolveOpenCodeBiller(runtimeEnv, parseModelProvider(modelId)),
|
biller: resolveOpenCodeBiller(runtimeEnv, parseModelProvider(modelId)),
|
||||||
model: modelId,
|
model: modelId,
|
||||||
billingType: (() => {
|
billingType: "unknown",
|
||||||
const mode = asString(config.billingMode, "auto").trim().toLowerCase();
|
|
||||||
return mode === "auto" || mode === "" ? "unknown" : applyBillingModeOverride("api", mode);
|
|
||||||
})(),
|
|
||||||
costUsd: attempt.parsed.costUsd,
|
costUsd: attempt.parsed.costUsd,
|
||||||
resultJson: {
|
resultJson: {
|
||||||
stdout: attempt.proc.stdout,
|
stdout: attempt.proc.stdout,
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,6 @@ import {
|
||||||
removeMaintainerOnlySkillSymlinks,
|
removeMaintainerOnlySkillSymlinks,
|
||||||
renderTemplate,
|
renderTemplate,
|
||||||
runChildProcess,
|
runChildProcess,
|
||||||
applyBillingModeOverride,
|
|
||||||
} from "@paperclipai/adapter-utils/server-utils";
|
} from "@paperclipai/adapter-utils/server-utils";
|
||||||
import { isPiUnknownSessionError, parsePiJsonl } from "./parse.js";
|
import { isPiUnknownSessionError, parsePiJsonl } from "./parse.js";
|
||||||
import { ensurePiModelConfiguredAndAvailable } from "./models.js";
|
import { ensurePiModelConfiguredAndAvailable } from "./models.js";
|
||||||
|
|
@ -461,10 +460,7 @@ export async function execute(ctx: AdapterExecutionContext): Promise<AdapterExec
|
||||||
provider: provider,
|
provider: provider,
|
||||||
biller: resolvePiBiller(runtimeEnv, provider),
|
biller: resolvePiBiller(runtimeEnv, provider),
|
||||||
model: model,
|
model: model,
|
||||||
billingType: (() => {
|
billingType: "unknown",
|
||||||
const mode = asString(config.billingMode, "auto").trim().toLowerCase();
|
|
||||||
return mode === "auto" || mode === "" ? "unknown" : applyBillingModeOverride("api", mode);
|
|
||||||
})(),
|
|
||||||
costUsd: attempt.parsed.usage.costUsd,
|
costUsd: attempt.parsed.usage.costUsd,
|
||||||
resultJson: {
|
resultJson: {
|
||||||
stdout: attempt.proc.stdout,
|
stdout: attempt.proc.stdout,
|
||||||
|
|
|
||||||
|
|
@ -1,68 +0,0 @@
|
||||||
import { describe, expect, it } from "vitest";
|
|
||||||
import { applyBillingModeOverride } from "@paperclipai/adapter-utils/server-utils";
|
|
||||||
|
|
||||||
describe("applyBillingModeOverride", () => {
|
|
||||||
it("returns auto-detected value when billingMode is 'auto'", () => {
|
|
||||||
expect(applyBillingModeOverride("api", "auto")).toBe("api");
|
|
||||||
expect(applyBillingModeOverride("subscription", "auto")).toBe("subscription");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("returns auto-detected value when billingMode is empty", () => {
|
|
||||||
expect(applyBillingModeOverride("api", "")).toBe("api");
|
|
||||||
expect(applyBillingModeOverride("subscription", "")).toBe("subscription");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("overrides to subscription when billingMode is 'subscription'", () => {
|
|
||||||
expect(applyBillingModeOverride("api", "subscription")).toBe("subscription");
|
|
||||||
expect(applyBillingModeOverride("subscription", "subscription")).toBe("subscription");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("overrides to api when billingMode is 'metered'", () => {
|
|
||||||
expect(applyBillingModeOverride("subscription", "metered")).toBe("api");
|
|
||||||
expect(applyBillingModeOverride("api", "metered")).toBe("api");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("overrides to api when billingMode is 'api'", () => {
|
|
||||||
expect(applyBillingModeOverride("subscription", "api")).toBe("api");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("normalizes whitespace and casing", () => {
|
|
||||||
expect(applyBillingModeOverride("api", " Subscription ")).toBe("subscription");
|
|
||||||
expect(applyBillingModeOverride("subscription", " METERED ")).toBe("api");
|
|
||||||
expect(applyBillingModeOverride("api", " AUTO ")).toBe("api");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("falls through for unrecognized values", () => {
|
|
||||||
expect(applyBillingModeOverride("api", "something_else")).toBe("api");
|
|
||||||
expect(applyBillingModeOverride("subscription", "credits")).toBe("subscription");
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("pi/opencode billing mode pattern (unknown-default adapters)", () => {
|
|
||||||
// Mirrors the inline pattern used in pi-local and opencode-local where
|
|
||||||
// the default billing type is "unknown" (no auto-detection available).
|
|
||||||
function resolveUnknownDefault(billingMode: string): string {
|
|
||||||
const mode = billingMode.trim().toLowerCase();
|
|
||||||
return mode === "auto" || mode === "" ? "unknown" : applyBillingModeOverride("api", mode);
|
|
||||||
}
|
|
||||||
|
|
||||||
it("returns 'unknown' when billingMode is 'auto' (default)", () => {
|
|
||||||
expect(resolveUnknownDefault("auto")).toBe("unknown");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("returns 'unknown' when billingMode is empty", () => {
|
|
||||||
expect(resolveUnknownDefault("")).toBe("unknown");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("returns 'subscription' when billingMode is 'subscription'", () => {
|
|
||||||
expect(resolveUnknownDefault("subscription")).toBe("subscription");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("returns 'api' when billingMode is 'metered'", () => {
|
|
||||||
expect(resolveUnknownDefault("metered")).toBe("api");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("returns 'api' when billingMode is 'api'", () => {
|
|
||||||
expect(resolveUnknownDefault("api")).toBe("api");
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
@ -1,36 +0,0 @@
|
||||||
import type { AdapterConfigFieldsProps } from "./types";
|
|
||||||
import { Field, help } from "../components/agent-config-primitives";
|
|
||||||
|
|
||||||
const selectClass =
|
|
||||||
"w-full rounded-md border border-border px-2.5 py-1.5 bg-transparent outline-none text-sm font-mono";
|
|
||||||
|
|
||||||
export function BillingModeField({
|
|
||||||
isCreate,
|
|
||||||
values,
|
|
||||||
set,
|
|
||||||
config,
|
|
||||||
eff,
|
|
||||||
mark,
|
|
||||||
}: Pick<AdapterConfigFieldsProps, "isCreate" | "values" | "set" | "config" | "eff" | "mark">) {
|
|
||||||
const value = isCreate
|
|
||||||
? String(values?.billingMode ?? "auto")
|
|
||||||
: eff("adapterConfig", "billingMode", String(config.billingMode ?? "auto"));
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Field label="Billing mode" hint={help.billingMode}>
|
|
||||||
<select
|
|
||||||
value={value}
|
|
||||||
onChange={(e) =>
|
|
||||||
isCreate
|
|
||||||
? set?.({ billingMode: e.target.value })
|
|
||||||
: mark("adapterConfig", "billingMode", e.target.value === "auto" ? undefined : e.target.value)
|
|
||||||
}
|
|
||||||
className={selectClass}
|
|
||||||
>
|
|
||||||
<option value="auto">Auto (detect from API keys)</option>
|
|
||||||
<option value="subscription">Subscription (non-billable)</option>
|
|
||||||
<option value="metered">Metered API (billable)</option>
|
|
||||||
</select>
|
|
||||||
</Field>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
@ -41,7 +41,6 @@ import {
|
||||||
import { defaultCreateValues } from "./agent-config-defaults";
|
import { defaultCreateValues } from "./agent-config-defaults";
|
||||||
import { getUIAdapter } from "../adapters";
|
import { getUIAdapter } from "../adapters";
|
||||||
import { ClaudeLocalAdvancedFields } from "../adapters/claude-local/config-fields";
|
import { ClaudeLocalAdvancedFields } from "../adapters/claude-local/config-fields";
|
||||||
import { BillingModeField } from "../adapters/billing-mode-field";
|
|
||||||
import { MarkdownEditor } from "./MarkdownEditor";
|
import { MarkdownEditor } from "./MarkdownEditor";
|
||||||
import { ChoosePathButton } from "./PathInstructionsModal";
|
import { ChoosePathButton } from "./PathInstructionsModal";
|
||||||
import { OpenCodeLogoIcon } from "./OpenCodeLogoIcon";
|
import { OpenCodeLogoIcon } from "./OpenCodeLogoIcon";
|
||||||
|
|
@ -774,8 +773,6 @@ export function AgentConfigForm(props: AgentConfigFormProps) {
|
||||||
<ClaudeLocalAdvancedFields {...adapterFieldProps} />
|
<ClaudeLocalAdvancedFields {...adapterFieldProps} />
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{isLocal && <BillingModeField {...adapterFieldProps} />}
|
|
||||||
|
|
||||||
<Field label="Extra args (comma-separated)" hint={help.extraArgs}>
|
<Field label="Extra args (comma-separated)" hint={help.extraArgs}>
|
||||||
<DraftInput
|
<DraftInput
|
||||||
value={
|
value={
|
||||||
|
|
|
||||||
|
|
@ -55,7 +55,6 @@ export const help: Record<string, string> = {
|
||||||
cooldownSec: "Minimum seconds between consecutive heartbeat runs.",
|
cooldownSec: "Minimum seconds between consecutive heartbeat runs.",
|
||||||
maxConcurrentRuns: "Maximum number of heartbeat runs that can execute simultaneously for this agent.",
|
maxConcurrentRuns: "Maximum number of heartbeat runs that can execute simultaneously for this agent.",
|
||||||
budgetMonthlyCents: "Monthly spending limit in cents. 0 means no limit.",
|
budgetMonthlyCents: "Monthly spending limit in cents. 0 means no limit.",
|
||||||
billingMode: "Controls how runs are billed. Auto detects from API keys. Set to Subscription if you're on a plan (e.g. Claude Max, GPT Plus) so runs don't count toward spend.",
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const adapterLabels: Record<string, string> = {
|
export const adapterLabels: Record<string, string> = {
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue