File size: 3,637 Bytes
d0eb8b9
 
 
 
 
 
 
 
 
 
142c9c4
 
 
 
 
759fe9e
 
 
 
 
 
 
 
 
d0eb8b9
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
53d3b3b
 
d0eb8b9
 
 
 
 
 
759fe9e
 
 
 
 
 
 
 
 
 
 
 
 
 
d0eb8b9
 
 
 
 
 
 
 
 
ab2754a
 
 
 
 
 
 
 
 
 
142c9c4
 
 
 
 
ab2754a
 
 
142c9c4
ab2754a
 
 
 
d0eb8b9
 
ab2754a
d0eb8b9
 
 
 
 
 
 
 
 
 
fadda70
d0eb8b9
 
 
 
 
 
 
 
8b777a2
 
 
 
 
 
 
 
 
 
 
 
 
d0eb8b9
 
 
 
 
 
 
 
 
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
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
/**
 * Google Gemini API types for generateContent / streamGenerateContent compatibility
 */
import { z } from "zod";

// --- Request ---

const GeminiPartSchema = z.object({
  text: z.string().optional(),
  thought: z.boolean().optional(),
  // Inline image data
  inlineData: z.object({
    mimeType: z.string(),
    data: z.string(),
  }).optional(),
  // Function calling fields (accepted for compatibility, not forwarded to Codex)
  functionCall: z.object({
    name: z.string(),
    args: z.record(z.unknown()).optional(),
  }).optional(),
  functionResponse: z.object({
    name: z.string(),
    response: z.record(z.unknown()).optional(),
  }).optional(),
});

const GeminiContentSchema = z.object({
  role: z.enum(["user", "model"]).optional(),
  parts: z.array(GeminiPartSchema).min(1),
});

const GeminiThinkingConfigSchema = z.object({
  thinkingBudget: z.number().optional(),
});

const GeminiGenerationConfigSchema = z.object({
  temperature: z.number().optional(),
  topP: z.number().optional(),
  topK: z.number().optional(),
  maxOutputTokens: z.number().optional(),
  stopSequences: z.array(z.string()).optional(),
  thinkingConfig: GeminiThinkingConfigSchema.optional(),
  responseMimeType: z.string().optional(),
  responseSchema: z.record(z.unknown()).optional(),
});

export const GeminiGenerateContentRequestSchema = z.object({
  contents: z.array(GeminiContentSchema).min(1),
  systemInstruction: GeminiContentSchema.optional(),
  generationConfig: GeminiGenerationConfigSchema.optional(),
  // Tool-related fields (accepted for compatibility, not forwarded to Codex)
  tools: z.array(z.object({
    functionDeclarations: z.array(z.object({
      name: z.string(),
      description: z.string().optional(),
      parameters: z.record(z.unknown()).optional(),
    })).optional(),
  }).passthrough()).optional(),
  toolConfig: z.object({
    functionCallingConfig: z.object({
      mode: z.enum(["AUTO", "NONE", "ANY"]).optional(),
      allowedFunctionNames: z.array(z.string()).optional(),
    }).optional(),
  }).optional(),
});

export type GeminiGenerateContentRequest = z.infer<
  typeof GeminiGenerateContentRequestSchema
>;
export type GeminiContent = z.infer<typeof GeminiContentSchema>;

// --- Response ---

export interface GeminiFunctionCall {
  name: string;
  args?: Record<string, unknown>;
}

export interface GeminiFunctionResponse {
  name: string;
  response?: Record<string, unknown>;
}

export interface GeminiInlineData {
  mimeType: string;
  data: string;
}

export interface GeminiPart {
  text?: string;
  thought?: boolean;
  inlineData?: GeminiInlineData;
  functionCall?: GeminiFunctionCall;
  functionResponse?: GeminiFunctionResponse;
}

export interface GeminiCandidate {
  content: {
    parts: GeminiPart[];
    role: "model";
  };
  finishReason?: "STOP" | "MAX_TOKENS" | "SAFETY" | "OTHER";
  index: number;
}

export interface GeminiUsageMetadata {
  promptTokenCount: number;
  candidatesTokenCount: number;
  totalTokenCount: number;
  cachedContentTokenCount?: number;
}

export interface GeminiGenerateContentResponse {
  candidates: GeminiCandidate[];
  usageMetadata?: GeminiUsageMetadata;
  modelVersion?: string;
}

// --- Status map (shared by error-handler and gemini route) ---

export const GEMINI_STATUS_MAP: Record<number, string> = {
  400: "INVALID_ARGUMENT",
  401: "UNAUTHENTICATED",
  403: "PERMISSION_DENIED",
  404: "NOT_FOUND",
  429: "RESOURCE_EXHAUSTED",
  500: "INTERNAL",
  502: "INTERNAL",
  503: "UNAVAILABLE",
};

// --- Error ---

export interface GeminiErrorResponse {
  error: {
    code: number;
    message: string;
    status: string;
  };
}