name usage reference contract across server

This commit is contained in:
Mohamed Boudra
2026-09-26 20:52:57 +02:00
parent 03ad69e445
commit 0612bf9348
7 changed files with 23 additions and 21 deletions
@@ -660,6 +660,11 @@ export interface AgentPermissionResult {
followUpPrompt?: AgentPromptInput;
}
export interface UsageReference {
source: string;
input: JsonValue;
}
export interface AgentSession {
readonly provider: AgentProvider;
readonly id: string | null;
@@ -669,7 +674,7 @@ export interface AgentSession {
* replay them at their original timestamps; restored sessions omit old rows. */
readonly initialTimeline?: ImportedTimelineEntry[];
/** Resolved at fetch time because model and credentials may change during a session. */
getUsageReference?(): Promise<{ source: string; input: JsonValue } | null>;
getUsageReference?(): Promise<UsageReference | null>;
run(prompt: AgentPromptInput, options?: AgentRunOptions): Promise<AgentRunResult>;
startTurn(prompt: AgentPromptInput, options?: AgentRunOptions): Promise<{ turnId: string }>;
steerActiveTurn?(prompt: AgentPromptInput, options: SteerActiveTurnOptions): Promise<SteerResult>;
@@ -51,6 +51,7 @@ import type {
ProviderRefreshContext,
SteerActiveTurnOptions,
SteerResult,
UsageReference,
} from "./agent-sdk-types.js";
import {
isDefaultAgentCreateConfigUnattended,
@@ -567,7 +568,7 @@ class ProviderRuntimeSession {
return this.capabilities;
}
async getUsageReference(): Promise<{ source: string; input: JsonValue } | null> {
async getUsageReference(): Promise<UsageReference | null> {
if (!this.capabilities.includes("session.usage_reference")) return null;
const event = await this.runtime.complete({
type: "session.usage_reference",
@@ -1087,7 +1088,7 @@ class PluginAgentSession implements AgentSession {
return agentCapabilities(this.bridge.negotiatedCapabilities);
}
getUsageReference(): Promise<{ source: string; input: JsonValue } | null> {
getUsageReference(): Promise<UsageReference | null> {
return this.bridge.getUsageReference();
}
@@ -58,6 +58,7 @@ import {
type SteerResult,
type ToolCallDetail,
type ToolCallTimelineItem,
type UsageReference,
} from "../agent-sdk-types.js";
import { importSessionFromPersistence } from "../provider-session-import.js";
import {
@@ -3390,7 +3391,7 @@ async function readOpenCodeUsageAuth(
function resolveOpenCodeUsageReference(
model: string,
auth: Record<string, unknown> | null,
): { source: string; input: import("@getpaseo/protocol/agent-types").JsonValue } | null {
): UsageReference | null {
if (!auth) return null;
if (model.startsWith("openai/")) {
const entry = auth.openai;
@@ -3607,10 +3608,7 @@ class OpenCodeAgentSession implements AgentSession {
};
}
async getUsageReference(): Promise<{
source: string;
input: import("@getpaseo/protocol/agent-types").JsonValue;
} | null> {
async getUsageReference(): Promise<UsageReference | null> {
const model = this.config.model;
if (!model?.startsWith("openai/") && !model?.startsWith("opencode-go/")) return null;
const auth = await readOpenCodeUsageAuth(this.usageEnv);
+3 -8
View File
@@ -28,6 +28,7 @@ import type { PluginProviderMetadata } from "./plugin-process-protocol.js";
import { readPluginProviderIcon } from "./provider-icon.js";
import { UsageSourceRegistry } from "./usage-sources/index.js";
import type { PluginUsageSourceMetadata } from "./plugin-process-protocol.js";
import type { UsageReference } from "../agent/agent-sdk-types.js";
const BUILTIN_PROVIDER_ID_SET: ReadonlySet<string> = new Set(BUILTIN_PROVIDER_IDS);
@@ -142,17 +143,11 @@ export class PluginService {
return [...this.providers.values()].sort((left, right) => left.id.localeCompare(right.id));
}
listUsageReports(options?: {
forceRefresh?: boolean;
references?: Array<{ source: string; input: unknown }>;
}) {
listUsageReports(options?: { forceRefresh?: boolean; references?: UsageReference[] }) {
return this.usageSources.listReports(options);
}
fetchUsageReference(
reference: { source: string; input: unknown },
options?: { forceRefresh?: boolean },
) {
fetchUsageReference(reference: UsageReference, options?: { forceRefresh?: boolean }) {
return this.usageSources.fetchReference(reference, options);
}
@@ -1,6 +1,7 @@
import { fileURLToPath } from "node:url";
import { expect, test } from "vitest";
import { ACPAgentSession } from "../agent/providers/acp-agent.js";
import type { UsageReference } from "../agent/agent-sdk-types.js";
import { ClaudeAgentClient } from "../agent/providers/claude/agent.js";
import { CodexAppServerAgentSession } from "../agent/providers/codex-app-server-agent.js";
import { createTestLogger } from "../../test-utils/test-logger.js";
@@ -49,7 +50,7 @@ test("agent.get_usage_report resolves source IDs from default built-in and ACP s
);
const providers = ["claude", "codex", "copilot", "cursor", "kimi", "generic-acp"] as const;
const logger = createTestLogger();
const references = new Map<string, { source: string; input: Record<string, string> } | null>();
const references = new Map<string, UsageReference | null>();
const claude = await new ClaudeAgentClient({
logger,
resolveBinary: async () => "/test/claude/bin",
@@ -4,6 +4,7 @@ import {
type UsageReportEntry,
type ProviderUsage,
} from "@getpaseo/protocol/messages";
import type { UsageReference } from "../../agent/agent-sdk-types.js";
export interface UsageSource {
id: string;
@@ -37,7 +38,7 @@ export class UsageSourceRegistry {
async listReports(
options: {
forceRefresh?: boolean;
references?: Array<{ source: string; input: unknown }>;
references?: UsageReference[];
} = {},
): Promise<UsageReportEntry[]> {
const discovered = await Promise.all(
@@ -67,7 +68,7 @@ export class UsageSourceRegistry {
}
fetchReference(
reference: { source: string; input: unknown },
reference: UsageReference,
options: { forceRefresh?: boolean } = {},
): Promise<UsageReportEntry | null> {
return this.sources.has(reference.source)
+3 -2
View File
@@ -134,6 +134,7 @@ import {
type AgentPermissionResponse,
type AgentRunOptions,
type AgentSessionConfig,
type UsageReference,
} from "./agent/agent-sdk-types.js";
import type { StoredAgentRecord } from "./agent/agent-storage.js";
import type { AgentStorage } from "./agent/agent-storage.js";
@@ -511,10 +512,10 @@ export interface SessionOptions {
invokePluginRpc(pluginId: string, method: string, input: unknown): Promise<unknown>;
listUsageReports(options?: {
forceRefresh?: boolean;
references?: Array<{ source: string; input: unknown }>;
references?: UsageReference[];
}): Promise<UsageReportEntry[]>;
fetchUsageReference(
reference: { source: string; input: unknown },
reference: UsageReference,
options?: { forceRefresh?: boolean },
): Promise<UsageReportEntry | null>;
listLegacyUsage(): Promise<{ fetchedAt: string; providers: ProviderUsage[] }>;