Merge public-gh/master into paperclip-company-import-export

This commit is contained in:
Dotta
2026-03-16 17:02:39 -05:00
125 changed files with 38085 additions and 683 deletions

View File

@@ -0,0 +1,28 @@
import { describe, expect, it } from "vitest";
import { inferOpenAiCompatibleBiller } from "./billing.js";
describe("inferOpenAiCompatibleBiller", () => {
it("returns openrouter when OPENROUTER_API_KEY is present", () => {
expect(
inferOpenAiCompatibleBiller({ OPENROUTER_API_KEY: "sk-or-123" } as NodeJS.ProcessEnv, "openai"),
).toBe("openrouter");
});
it("returns openrouter when OPENAI_BASE_URL points at OpenRouter", () => {
expect(
inferOpenAiCompatibleBiller(
{ OPENAI_BASE_URL: "https://openrouter.ai/api/v1" } as NodeJS.ProcessEnv,
"openai",
),
).toBe("openrouter");
});
it("returns fallback when no OpenRouter markers are present", () => {
expect(
inferOpenAiCompatibleBiller(
{ OPENAI_BASE_URL: "https://api.openai.com/v1" } as NodeJS.ProcessEnv,
"openai",
),
).toBe("openai");
});
});

View File

@@ -0,0 +1,20 @@
function readEnv(env: NodeJS.ProcessEnv, key: string): string | null {
const value = env[key];
return typeof value === "string" && value.trim().length > 0 ? value.trim() : null;
}
export function inferOpenAiCompatibleBiller(
env: NodeJS.ProcessEnv,
fallback: string | null = "openai",
): string | null {
const explicitOpenRouterKey = readEnv(env, "OPENROUTER_API_KEY");
if (explicitOpenRouterKey) return "openrouter";
const baseUrl =
readEnv(env, "OPENAI_BASE_URL") ??
readEnv(env, "OPENAI_API_BASE") ??
readEnv(env, "OPENAI_API_BASE_URL");
if (baseUrl && /openrouter\.ai/i.test(baseUrl)) return "openrouter";
return fallback;
}

View File

@@ -22,6 +22,8 @@ export type {
HireApprovedPayload,
HireApprovedHookResult,
ServerAdapterModule,
QuotaWindow,
ProviderQuotaResult,
TranscriptEntry,
StdoutLineParser,
CLIAdapterModule,
@@ -33,3 +35,4 @@ export {
redactHomePathUserSegmentsInValue,
redactTranscriptEntryPaths,
} from "./log-redaction.js";
export { inferOpenAiCompatibleBiller } from "./billing.js";

View File

@@ -30,7 +30,15 @@ export interface UsageSummary {
cachedInputTokens?: number;
}
export type AdapterBillingType = "api" | "subscription" | "unknown";
export type AdapterBillingType =
| "api"
| "subscription"
| "metered_api"
| "subscription_included"
| "subscription_overage"
| "credits"
| "fixed"
| "unknown";
export interface AdapterRuntimeServiceReport {
id?: string | null;
@@ -68,6 +76,7 @@ export interface AdapterExecutionResult {
sessionParams?: Record<string, unknown> | null;
sessionDisplayId?: string | null;
provider?: string | null;
biller?: string | null;
model?: string | null;
billingType?: AdapterBillingType | null;
costUsd?: number | null;
@@ -209,6 +218,37 @@ export interface HireApprovedHookResult {
detail?: Record<string, unknown>;
}
// ---------------------------------------------------------------------------
// Quota window types — used by adapters that can report provider quota/rate-limit state
// ---------------------------------------------------------------------------
/** a single rate-limit or usage window returned by a provider quota API */
export interface QuotaWindow {
/** human label, e.g. "5h", "7d", "Sonnet 7d", "Credits" */
label: string;
/** percent of the window already consumed (0-100), null when not reported */
usedPercent: number | null;
/** iso timestamp when this window resets, null when not reported */
resetsAt: string | null;
/** free-form value label for credit-style windows, e.g. "$4.20 remaining" */
valueLabel: string | null;
/** optional supporting text, e.g. reset details or provider-specific notes */
detail?: string | null;
}
/** result for one provider from getQuotaWindows() */
export interface ProviderQuotaResult {
/** provider slug, e.g. "anthropic", "openai" */
provider: string;
/** source label when the provider reports where the quota data came from */
source?: string | null;
/** true when the fetch succeeded and windows is populated */
ok: boolean;
/** error message when ok is false */
error?: string;
windows: QuotaWindow[];
}
export interface ServerAdapterModule {
type: string;
execute(ctx: AdapterExecutionContext): Promise<AdapterExecutionResult>;
@@ -228,6 +268,12 @@ export interface ServerAdapterModule {
payload: HireApprovedPayload,
adapterConfig: Record<string, unknown>,
) => Promise<HireApprovedHookResult>;
/**
* Optional: fetch live provider quota/rate-limit windows for this adapter.
* Returns a ProviderQuotaResult so the server can aggregate across adapters
* without knowing provider-specific credential paths or API shapes.
*/
getQuotaWindows?: () => Promise<ProviderQuotaResult>;
}
// ---------------------------------------------------------------------------