-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmodel-adapter.ts
More file actions
76 lines (66 loc) · 2.47 KB
/
Copy pathmodel-adapter.ts
File metadata and controls
76 lines (66 loc) · 2.47 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
// Provider-agnostic LLM adapter interface.
//
// The orchestrator talks to LLMs exclusively through this interface so a provider
// (Gemini, OpenAI, …) can be swapped without touching agent logic, prompts, or the
// quality-gate loop. Each adapter is responsible only for the raw generate call and
// (optionally) provider-specific context caching; telemetry is recorded at the
// orchestrator boundary, keeping adapters pure.
export type ModelProvider = "gemini" | "openai";
export interface GenerateOptions {
systemInstruction: string;
userPrompt: string;
maxOutputTokens?: number;
temperature?: number;
topP?: number;
// Provider-specific cached-content handle (e.g. a Gemini context cache name).
// Ignored by providers that do not support caching.
cachedContentName?: string | null;
}
export interface LlmUsage {
promptTokens: number;
completionTokens: number;
// Tokens served from the provider cache (billed cheaper / not at all). 0 when no cache hit.
cachedTokens: number;
}
export interface LlmResult {
// null signals a failed call after the adapter's own retries are exhausted.
text: string | null;
usage: LlmUsage;
}
export interface CacheOptions {
systemInstruction: string;
resumeJson: unknown;
}
export interface ModelAdapter {
readonly provider: ModelProvider;
readonly model: string;
readonly supportsContextCache: boolean;
generateContent(opts: GenerateOptions): Promise<LlmResult>;
// Returns a provider cache handle, or null when caching is unsupported or creation failed.
getOrCreateCache?(opts: CacheOptions): Promise<string | null>;
}
export const ZERO_USAGE: LlmUsage = {
promptTokens: 0,
completionTokens: 0,
cachedTokens: 0,
};
/**
* Builds the adapter for a provider. Adapters are dynamically imported so the unused
* provider SDK is never loaded (e.g. a Gemini-only run never imports the OpenAI SDK),
* and so a missing optional dependency cannot break the default path.
*
* Provider resolution: explicit arg → MODEL_PROVIDER env → "gemini".
*/
export async function getModelAdapter(
provider?: ModelProvider,
apiKey?: string
): Promise<ModelAdapter> {
const resolved =
provider ?? (process.env.MODEL_PROVIDER as ModelProvider | undefined) ?? "gemini";
if (resolved === "openai") {
const { OpenAIAdapter } = await import("./adapters/openai-adapter.js");
return new OpenAIAdapter(apiKey);
}
const { GeminiAdapter } = await import("./adapters/gemini-adapter.js");
return new GeminiAdapter(apiKey);
}