opencode-google-auth 0.0.1 → 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +3 -6
- package/src/lib/logger.ts +2 -2
- package/src/lib/runtime.ts +4 -4
- package/src/main.ts +3 -3
- package/src/models.json +12 -55
- package/src/{lib/services → services}/config.test.ts +1 -1
- package/src/{lib/services → services}/config.ts +1 -1
- package/src/{lib/services → services}/oauth.ts +1 -1
- package/src/{lib/services → services}/session.ts +1 -1
- package/src/transform/request.test.ts +2 -2
- package/src/transform/request.ts +2 -2
- package/dist/main.mjs +0 -716
- package/dist/main.mjs.map +0 -1
- /package/src/{lib/services → services}/opencode.ts +0 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "opencode-google-auth",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.2",
|
|
4
4
|
"description": "_description_",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"opencode-google-auth"
|
|
@@ -16,23 +16,21 @@
|
|
|
16
16
|
"email": "erickchristian48@gmail.com"
|
|
17
17
|
},
|
|
18
18
|
"type": "module",
|
|
19
|
+
"main": "./src/main.ts",
|
|
19
20
|
"exports": {
|
|
20
21
|
".": {
|
|
21
|
-
"default": "./
|
|
22
|
+
"default": "./src/main.ts"
|
|
22
23
|
}
|
|
23
24
|
},
|
|
24
25
|
"files": [
|
|
25
|
-
"dist",
|
|
26
26
|
"src"
|
|
27
27
|
],
|
|
28
28
|
"scripts": {
|
|
29
29
|
"prebuild": "bun ./scripts/fetch-models.ts",
|
|
30
|
-
"build": "tsdown",
|
|
31
30
|
"predeploy": "bun run build",
|
|
32
31
|
"deploy": "bun ./scripts/deploy.ts",
|
|
33
32
|
"format": "prettier --write .",
|
|
34
33
|
"lint": "oxlint",
|
|
35
|
-
"prepack": "bun run build",
|
|
36
34
|
"release": "bumpp && npm publish",
|
|
37
35
|
"typecheck": "tsgo"
|
|
38
36
|
},
|
|
@@ -56,7 +54,6 @@
|
|
|
56
54
|
"oxlint": "^1.39.0",
|
|
57
55
|
"oxlint-tsgolint": "^0.11.0",
|
|
58
56
|
"prettier": "^3.7.4",
|
|
59
|
-
"tsdown": "^0.19.0",
|
|
60
57
|
"typescript": "^5.9.3",
|
|
61
58
|
"yargs": "^18.0.0"
|
|
62
59
|
},
|
package/src/lib/logger.ts
CHANGED
|
@@ -2,8 +2,8 @@ import { PlatformLogger } from "@effect/platform"
|
|
|
2
2
|
import { Effect, Inspectable, Logger, LogLevel, pipe } from "effect"
|
|
3
3
|
import path from "node:path"
|
|
4
4
|
import type { OpenCodeLogLevel } from "../types"
|
|
5
|
-
import { ProviderConfig } from "
|
|
6
|
-
import { OpenCodeContext } from "
|
|
5
|
+
import { ProviderConfig } from "../services/config"
|
|
6
|
+
import { OpenCodeContext } from "../services/opencode"
|
|
7
7
|
|
|
8
8
|
const makeOpenCodeLogger = Effect.gen(function* () {
|
|
9
9
|
const openCode = yield* OpenCodeContext
|
package/src/lib/runtime.ts
CHANGED
|
@@ -3,10 +3,10 @@ import { BunFileSystem } from "@effect/platform-bun"
|
|
|
3
3
|
import type { PluginInput } from "@opencode-ai/plugin"
|
|
4
4
|
import { Layer, Logger, ManagedRuntime, pipe } from "effect"
|
|
5
5
|
import { combinedLogger } from "./logger"
|
|
6
|
-
import { ProviderConfig, type ProviderConfigShape } from "
|
|
7
|
-
import { OAuth } from "
|
|
8
|
-
import { OpenCodeContext } from "
|
|
9
|
-
import { Session } from "
|
|
6
|
+
import { ProviderConfig, type ProviderConfigShape } from "../services/config"
|
|
7
|
+
import { OAuth } from "../services/oauth"
|
|
8
|
+
import { OpenCodeContext } from "../services/opencode"
|
|
9
|
+
import { Session } from "../services/session"
|
|
10
10
|
|
|
11
11
|
export const makeRuntime = ({
|
|
12
12
|
providerConfig,
|
package/src/main.ts
CHANGED
|
@@ -10,9 +10,9 @@ import {
|
|
|
10
10
|
antigravityConfig,
|
|
11
11
|
geminiCliConfig,
|
|
12
12
|
ProviderConfig,
|
|
13
|
-
} from "./
|
|
14
|
-
import { OAuth } from "./
|
|
15
|
-
import { Session } from "./
|
|
13
|
+
} from "./services/config"
|
|
14
|
+
import { OAuth } from "./services/oauth"
|
|
15
|
+
import { Session } from "./services/session"
|
|
16
16
|
import { transformRequest } from "./transform/request"
|
|
17
17
|
import { transformNonStreamingResponse } from "./transform/response"
|
|
18
18
|
import { transformStreamingResponse } from "./transform/stream"
|
package/src/models.json
CHANGED
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"id": "google",
|
|
3
|
-
"env": [
|
|
4
|
-
"GOOGLE_GENERATIVE_AI_API_KEY",
|
|
5
|
-
"GEMINI_API_KEY"
|
|
6
|
-
],
|
|
3
|
+
"env": ["GOOGLE_GENERATIVE_AI_API_KEY", "GEMINI_API_KEY"],
|
|
7
4
|
"npm": "@ai-sdk/google",
|
|
8
5
|
"name": "Google",
|
|
9
6
|
"doc": "https://ai.google.dev/gemini-api/docs/pricing",
|
|
@@ -21,16 +18,8 @@
|
|
|
21
18
|
"release_date": "2025-12-17",
|
|
22
19
|
"last_updated": "2025-12-17",
|
|
23
20
|
"modalities": {
|
|
24
|
-
"input": [
|
|
25
|
-
|
|
26
|
-
"image",
|
|
27
|
-
"video",
|
|
28
|
-
"audio",
|
|
29
|
-
"pdf"
|
|
30
|
-
],
|
|
31
|
-
"output": [
|
|
32
|
-
"text"
|
|
33
|
-
]
|
|
21
|
+
"input": ["text", "image", "video", "audio", "pdf"],
|
|
22
|
+
"output": ["text"]
|
|
34
23
|
},
|
|
35
24
|
"open_weights": false,
|
|
36
25
|
"cost": {
|
|
@@ -61,16 +50,8 @@
|
|
|
61
50
|
"release_date": "2025-11-18",
|
|
62
51
|
"last_updated": "2025-11-18",
|
|
63
52
|
"modalities": {
|
|
64
|
-
"input": [
|
|
65
|
-
|
|
66
|
-
"image",
|
|
67
|
-
"video",
|
|
68
|
-
"audio",
|
|
69
|
-
"pdf"
|
|
70
|
-
],
|
|
71
|
-
"output": [
|
|
72
|
-
"text"
|
|
73
|
-
]
|
|
53
|
+
"input": ["text", "image", "video", "audio", "pdf"],
|
|
54
|
+
"output": ["text"]
|
|
74
55
|
},
|
|
75
56
|
"open_weights": false,
|
|
76
57
|
"cost": {
|
|
@@ -101,16 +82,8 @@
|
|
|
101
82
|
"release_date": "2025-03-20",
|
|
102
83
|
"last_updated": "2025-06-05",
|
|
103
84
|
"modalities": {
|
|
104
|
-
"input": [
|
|
105
|
-
|
|
106
|
-
"image",
|
|
107
|
-
"audio",
|
|
108
|
-
"video",
|
|
109
|
-
"pdf"
|
|
110
|
-
],
|
|
111
|
-
"output": [
|
|
112
|
-
"text"
|
|
113
|
-
]
|
|
85
|
+
"input": ["text", "image", "audio", "video", "pdf"],
|
|
86
|
+
"output": ["text"]
|
|
114
87
|
},
|
|
115
88
|
"open_weights": false,
|
|
116
89
|
"cost": {
|
|
@@ -137,16 +110,8 @@
|
|
|
137
110
|
"release_date": "2025-06-17",
|
|
138
111
|
"last_updated": "2025-06-17",
|
|
139
112
|
"modalities": {
|
|
140
|
-
"input": [
|
|
141
|
-
|
|
142
|
-
"image",
|
|
143
|
-
"audio",
|
|
144
|
-
"video",
|
|
145
|
-
"pdf"
|
|
146
|
-
],
|
|
147
|
-
"output": [
|
|
148
|
-
"text"
|
|
149
|
-
]
|
|
113
|
+
"input": ["text", "image", "audio", "video", "pdf"],
|
|
114
|
+
"output": ["text"]
|
|
150
115
|
},
|
|
151
116
|
"open_weights": false,
|
|
152
117
|
"cost": {
|
|
@@ -172,16 +137,8 @@
|
|
|
172
137
|
"release_date": "2025-03-20",
|
|
173
138
|
"last_updated": "2025-06-05",
|
|
174
139
|
"modalities": {
|
|
175
|
-
"input": [
|
|
176
|
-
|
|
177
|
-
"image",
|
|
178
|
-
"audio",
|
|
179
|
-
"video",
|
|
180
|
-
"pdf"
|
|
181
|
-
],
|
|
182
|
-
"output": [
|
|
183
|
-
"text"
|
|
184
|
-
]
|
|
140
|
+
"input": ["text", "image", "audio", "video", "pdf"],
|
|
141
|
+
"output": ["text"]
|
|
185
142
|
},
|
|
186
143
|
"open_weights": false,
|
|
187
144
|
"cost": {
|
|
@@ -195,4 +152,4 @@
|
|
|
195
152
|
}
|
|
196
153
|
}
|
|
197
154
|
}
|
|
198
|
-
}
|
|
155
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { describe, expect, it } from "bun:test"
|
|
2
|
-
import { transformRequest } from "
|
|
2
|
+
import { transformRequest } from "../transform/request"
|
|
3
3
|
import { antigravityConfig, ProviderConfig } from "./config"
|
|
4
4
|
import { Session } from "./session"
|
|
5
5
|
import { Effect, Layer, pipe } from "effect"
|
|
@@ -14,7 +14,7 @@ import {
|
|
|
14
14
|
import { BunHttpServer } from "@effect/platform-bun"
|
|
15
15
|
import { Data, Deferred, Effect, Fiber, Schema } from "effect"
|
|
16
16
|
import { OAuth2Client } from "google-auth-library"
|
|
17
|
-
import type { BunServeOptions } from "
|
|
17
|
+
import type { BunServeOptions } from "../types"
|
|
18
18
|
import { ProviderConfig } from "./config"
|
|
19
19
|
|
|
20
20
|
export class OAuthError extends Data.TaggedError("OAuthError")<{
|
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
} from "@effect/platform"
|
|
6
6
|
import { Data, Effect, pipe, Ref, Schema } from "effect"
|
|
7
7
|
import { OAuth2Client } from "google-auth-library"
|
|
8
|
-
import type { Credentials } from "
|
|
8
|
+
import type { Credentials } from "../types"
|
|
9
9
|
import { CODE_ASSIST_VERSION, ProviderConfig } from "./config"
|
|
10
10
|
import { OpenCodeContext } from "./opencode"
|
|
11
11
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { describe, expect, it } from "bun:test"
|
|
2
2
|
import { transformRequest } from "./request"
|
|
3
|
-
import { geminiCliConfig, ProviderConfig } from "../
|
|
4
|
-
import { Session } from "../
|
|
3
|
+
import { geminiCliConfig, ProviderConfig } from "../services/config"
|
|
4
|
+
import { Session } from "../services/session"
|
|
5
5
|
import { Effect, Layer, pipe } from "effect"
|
|
6
6
|
|
|
7
7
|
describe("transformRequest", () => {
|
package/src/transform/request.ts
CHANGED
|
@@ -4,8 +4,8 @@ import {
|
|
|
4
4
|
CODE_ASSIST_VERSION,
|
|
5
5
|
ProviderConfig,
|
|
6
6
|
type RequestContext,
|
|
7
|
-
} from "../
|
|
8
|
-
import { Session } from "../
|
|
7
|
+
} from "../services/config"
|
|
8
|
+
import { Session } from "../services/session"
|
|
9
9
|
|
|
10
10
|
const STREAM_ACTION = "streamGenerateContent"
|
|
11
11
|
const PATH_PATTERN = regex("/models/(?<model>[^:]+):(?<action>\\w+)")
|
package/dist/main.mjs
DELETED
|
@@ -1,716 +0,0 @@
|
|
|
1
|
-
import { FetchHttpClient, HttpClient, HttpClientRequest, HttpClientResponse, HttpRouter, HttpServer, HttpServerRequest, HttpServerResponse, PlatformLogger } from "@effect/platform";
|
|
2
|
-
import { Context, Data, Deferred, Effect, Fiber, Inspectable, Layer, LogLevel, Logger, ManagedRuntime, Ref, Schema, Stream, pipe } from "effect";
|
|
3
|
-
import { BunFileSystem, BunHttpServer } from "@effect/platform-bun";
|
|
4
|
-
import path from "node:path";
|
|
5
|
-
import { OAuth2Client } from "google-auth-library";
|
|
6
|
-
import { regex } from "arkregex";
|
|
7
|
-
import { Retry, encoder, makeChannel } from "@effect/experimental/Sse";
|
|
8
|
-
|
|
9
|
-
//#region src/lib/services/config.ts
|
|
10
|
-
var ProviderConfig = class extends Context.Tag("ProviderConfig")() {};
|
|
11
|
-
const CODE_ASSIST_VERSION = "v1internal";
|
|
12
|
-
const GEMINI_CLI_MODELS = [
|
|
13
|
-
"gemini-2.5-pro",
|
|
14
|
-
"gemini-2.5-flash",
|
|
15
|
-
"gemini-2.5-flash-lite",
|
|
16
|
-
"gemini-3-pro-preview",
|
|
17
|
-
"gemini-3-flash-preview"
|
|
18
|
-
];
|
|
19
|
-
const geminiCliConfig = () => ({
|
|
20
|
-
SERVICE_NAME: "gemini-cli",
|
|
21
|
-
DISPLAY_NAME: "Gemini CLI",
|
|
22
|
-
CLIENT_ID: "681255809395-oo8ft2oprdrnp9e3aqf6av3hmdib135j.apps.googleusercontent.com",
|
|
23
|
-
CLIENT_SECRET: "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",
|
|
24
|
-
SCOPES: [
|
|
25
|
-
"https://www.googleapis.com/auth/cloud-platform",
|
|
26
|
-
"https://www.googleapis.com/auth/userinfo.email",
|
|
27
|
-
"https://www.googleapis.com/auth/userinfo.profile"
|
|
28
|
-
],
|
|
29
|
-
ENDPOINTS: ["https://cloudcode-pa.googleapis.com"],
|
|
30
|
-
HEADERS: {
|
|
31
|
-
"User-Agent": "google-api-nodejs-client/9.15.1",
|
|
32
|
-
"X-Goog-Api-Client": "gl-node/22.17.0",
|
|
33
|
-
"Client-Metadata": "ideType=IDE_UNSPECIFIED,platform=PLATFORM_UNSPECIFIED,pluginType=GEMINI"
|
|
34
|
-
},
|
|
35
|
-
getConfig: (modelsDev) => {
|
|
36
|
-
const provider = modelsDev.google;
|
|
37
|
-
const filteredModels = pipe(provider.models, (models) => Object.entries(models), (entries) => entries.filter(([key]) => GEMINI_CLI_MODELS.includes(key)), (filtered) => Object.fromEntries(filtered));
|
|
38
|
-
return {
|
|
39
|
-
...provider,
|
|
40
|
-
id: geminiCliConfig().SERVICE_NAME,
|
|
41
|
-
name: geminiCliConfig().DISPLAY_NAME,
|
|
42
|
-
api: geminiCliConfig().ENDPOINTS.at(0),
|
|
43
|
-
models: filteredModels
|
|
44
|
-
};
|
|
45
|
-
}
|
|
46
|
-
});
|
|
47
|
-
const antigravityConfig = () => ({
|
|
48
|
-
SERVICE_NAME: "antigravity",
|
|
49
|
-
DISPLAY_NAME: "Antigravity",
|
|
50
|
-
CLIENT_ID: "1071006060591-tmhssin2h21lcre235vtolojh4g403ep.apps.googleusercontent.com",
|
|
51
|
-
CLIENT_SECRET: "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",
|
|
52
|
-
SCOPES: [
|
|
53
|
-
"https://www.googleapis.com/auth/cloud-platform",
|
|
54
|
-
"https://www.googleapis.com/auth/userinfo.email",
|
|
55
|
-
"https://www.googleapis.com/auth/userinfo.profile",
|
|
56
|
-
"https://www.googleapis.com/auth/cclog",
|
|
57
|
-
"https://www.googleapis.com/auth/experimentsandconfigs"
|
|
58
|
-
],
|
|
59
|
-
ENDPOINTS: [
|
|
60
|
-
"https://daily-cloudcode-pa.sandbox.googleapis.com",
|
|
61
|
-
"https://autopush-cloudcode-pa.sandbox.googleapis.com",
|
|
62
|
-
"https://cloudcode-pa.googleapis.com"
|
|
63
|
-
],
|
|
64
|
-
HEADERS: {
|
|
65
|
-
"User-Agent": "antigravity/1.11.5 windows/amd64",
|
|
66
|
-
"X-Goog-Api-Client": "google-cloud-sdk vscode_cloudshelleditor/0.1",
|
|
67
|
-
"Client-Metadata": "{\"ideType\":\"IDE_UNSPECIFIED\",\"platform\":\"PLATFORM_UNSPECIFIED\",\"pluginType\":\"GEMINI\"}"
|
|
68
|
-
},
|
|
69
|
-
getConfig: (modelsDev) => {
|
|
70
|
-
const googleProvider = modelsDev.google;
|
|
71
|
-
const googleVertextProvider = modelsDev["google-vertex-anthropic"];
|
|
72
|
-
const geminiFlash = googleProvider.models["gemini-3-flash-preview"];
|
|
73
|
-
const geminiPro = googleProvider.models["gemini-3-pro-preview"];
|
|
74
|
-
const claudeSonnet = googleVertextProvider.models["claude-sonnet-4-5@20250929"];
|
|
75
|
-
const claudeOpus = googleVertextProvider.models["claude-opus-4-5@20251101"];
|
|
76
|
-
const models = {
|
|
77
|
-
"gemini-3-flash": {
|
|
78
|
-
...geminiFlash,
|
|
79
|
-
id: "gemini-3-flash"
|
|
80
|
-
},
|
|
81
|
-
"gemini-3-pro-low": {
|
|
82
|
-
...geminiPro,
|
|
83
|
-
id: "gemini-3-pro-low",
|
|
84
|
-
name: "Gemini 3 Pro (Low)",
|
|
85
|
-
temperature: false,
|
|
86
|
-
options: { thinkingConfig: { thinkingLevel: "low" } }
|
|
87
|
-
},
|
|
88
|
-
"gemini-3-pro-high": {
|
|
89
|
-
...geminiPro,
|
|
90
|
-
id: "gemini-3-pro-high",
|
|
91
|
-
name: "Gemini 3 Pro (High)",
|
|
92
|
-
temperature: false,
|
|
93
|
-
options: { thinkingConfig: { thinkingLevel: "high" } }
|
|
94
|
-
},
|
|
95
|
-
"claude-sonnet-4-5": {
|
|
96
|
-
...claudeSonnet,
|
|
97
|
-
id: "claude-sonnet-4-5",
|
|
98
|
-
reasoning: false,
|
|
99
|
-
options: { thinkingConfig: { includeThoughts: false } }
|
|
100
|
-
},
|
|
101
|
-
"claude-sonnet-4-5-thinking": {
|
|
102
|
-
...claudeSonnet,
|
|
103
|
-
id: "claude-sonnet-4-5-thinking",
|
|
104
|
-
name: "Claude Sonnet 4.5 (Reasoning)"
|
|
105
|
-
},
|
|
106
|
-
"claude-opus-4-5-thinking": {
|
|
107
|
-
...claudeOpus,
|
|
108
|
-
id: "claude-opus-4-5-thinking",
|
|
109
|
-
name: "Claude Opus 4.5 (Reasoning)"
|
|
110
|
-
}
|
|
111
|
-
};
|
|
112
|
-
return {
|
|
113
|
-
...googleProvider,
|
|
114
|
-
id: antigravityConfig().SERVICE_NAME,
|
|
115
|
-
name: antigravityConfig().DISPLAY_NAME,
|
|
116
|
-
api: antigravityConfig().ENDPOINTS.at(2),
|
|
117
|
-
models
|
|
118
|
-
};
|
|
119
|
-
},
|
|
120
|
-
transformRequest: Effect.fn(function* (context) {
|
|
121
|
-
yield* Effect.log("Transforming request for: ", antigravityConfig().SERVICE_NAME);
|
|
122
|
-
const { body, headers, url } = context;
|
|
123
|
-
const innerRequest = body.request;
|
|
124
|
-
let sessionId;
|
|
125
|
-
if (innerRequest.labels && typeof innerRequest.labels === "object" && "sessionId" in innerRequest.labels) {
|
|
126
|
-
const labels = innerRequest.labels;
|
|
127
|
-
sessionId = labels.sessionId;
|
|
128
|
-
delete labels.sessionId;
|
|
129
|
-
if (Object.keys(labels).length === 0) delete innerRequest.labels;
|
|
130
|
-
}
|
|
131
|
-
const isClaude = body.model.toLowerCase().includes("claude");
|
|
132
|
-
const isThinking = body.model.toLowerCase().includes("thinking");
|
|
133
|
-
if (isClaude && body.request && typeof body.request === "object") {
|
|
134
|
-
const generationConfig = body.request.generationConfig;
|
|
135
|
-
innerRequest.toolConfig = { functionCallingConfig: { mode: "VALIDATED" } };
|
|
136
|
-
if (!isThinking && generationConfig?.thinkingConfig) delete generationConfig.thinkingConfig;
|
|
137
|
-
if (isThinking && generationConfig?.thinkingConfig) {
|
|
138
|
-
const thinkingConfig = generationConfig.thinkingConfig;
|
|
139
|
-
if (thinkingConfig.includeThoughts !== void 0) {
|
|
140
|
-
thinkingConfig.include_thoughts = thinkingConfig.includeThoughts;
|
|
141
|
-
delete thinkingConfig.includeThoughts;
|
|
142
|
-
}
|
|
143
|
-
if (thinkingConfig.thinkingBudget !== void 0) {
|
|
144
|
-
thinkingConfig.thinking_budget = thinkingConfig.thinkingBudget;
|
|
145
|
-
delete thinkingConfig.thinkingBudget;
|
|
146
|
-
}
|
|
147
|
-
if (thinkingConfig.thinking_budget === void 0) thinkingConfig.thinking_budget = 32768;
|
|
148
|
-
}
|
|
149
|
-
if (isThinking) headers.set("anthropic-beta", "interleaved-thinking-2025-05-14");
|
|
150
|
-
}
|
|
151
|
-
if (sessionId) {
|
|
152
|
-
const hashedSession = yield* Effect.promise(() => hash(sessionId));
|
|
153
|
-
innerRequest.sessionId = [
|
|
154
|
-
`-${crypto.randomUUID()}`,
|
|
155
|
-
body.model,
|
|
156
|
-
body.project,
|
|
157
|
-
`seed-${hashedSession}`
|
|
158
|
-
].join(":");
|
|
159
|
-
}
|
|
160
|
-
if (innerRequest.tools && Array.isArray(innerRequest.tools)) {
|
|
161
|
-
const tools = innerRequest.tools;
|
|
162
|
-
for (const tool of tools) if (tool.functionDeclarations && Array.isArray(tool.functionDeclarations)) {
|
|
163
|
-
const functionDeclarations = tool.functionDeclarations;
|
|
164
|
-
for (let i = 0; i < functionDeclarations.length; i++) {
|
|
165
|
-
const declaration = functionDeclarations[i];
|
|
166
|
-
if (declaration && declaration.name === "todoread") functionDeclarations[i] = {
|
|
167
|
-
...functionDeclarations[i],
|
|
168
|
-
parameters: {
|
|
169
|
-
type: "object",
|
|
170
|
-
properties: { _placeholder: {
|
|
171
|
-
type: "boolean",
|
|
172
|
-
description: "Placeholder. Always pass true."
|
|
173
|
-
} },
|
|
174
|
-
required: ["_placeholder"],
|
|
175
|
-
additionalProperties: false
|
|
176
|
-
}
|
|
177
|
-
};
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
if (innerRequest.systemInstruction && typeof innerRequest.systemInstruction === "object") {
|
|
182
|
-
const systemInstruction = innerRequest.systemInstruction;
|
|
183
|
-
systemInstruction.role = "user";
|
|
184
|
-
}
|
|
185
|
-
return {
|
|
186
|
-
headers,
|
|
187
|
-
url,
|
|
188
|
-
body: {
|
|
189
|
-
...body,
|
|
190
|
-
requestType: "agent",
|
|
191
|
-
userAgent: "antigravity",
|
|
192
|
-
requestId: `agent-${crypto.randomUUID()}`
|
|
193
|
-
}
|
|
194
|
-
};
|
|
195
|
-
})
|
|
196
|
-
});
|
|
197
|
-
async function hash(str) {
|
|
198
|
-
const data = new TextEncoder().encode(str);
|
|
199
|
-
const hashBuffer = await crypto.subtle.digest("SHA-256", data);
|
|
200
|
-
return Array.from(new Uint8Array(hashBuffer)).map((b) => b.toString(16).padStart(2, "0")).join("").slice(0, 16);
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
//#endregion
|
|
204
|
-
//#region src/lib/services/opencode.ts
|
|
205
|
-
var OpenCodeContext = class extends Context.Tag("OpenCodeContext")() {};
|
|
206
|
-
|
|
207
|
-
//#endregion
|
|
208
|
-
//#region src/lib/logger.ts
|
|
209
|
-
const makeOpenCodeLogger = Effect.gen(function* () {
|
|
210
|
-
const openCode = yield* OpenCodeContext;
|
|
211
|
-
const config = yield* ProviderConfig;
|
|
212
|
-
return Logger.make((log) => {
|
|
213
|
-
let level = "debug";
|
|
214
|
-
if (LogLevel.greaterThanEqual(log.logLevel, LogLevel.Error)) level = "error";
|
|
215
|
-
else if (LogLevel.greaterThanEqual(log.logLevel, LogLevel.Warning)) level = "warn";
|
|
216
|
-
else if (LogLevel.greaterThanEqual(log.logLevel, LogLevel.Info)) level = "info";
|
|
217
|
-
const message = Inspectable.toStringUnknown(log.message);
|
|
218
|
-
openCode.client.app.log({ body: {
|
|
219
|
-
level,
|
|
220
|
-
message,
|
|
221
|
-
service: config.SERVICE_NAME
|
|
222
|
-
} });
|
|
223
|
-
});
|
|
224
|
-
});
|
|
225
|
-
const combinedLogger = Effect.gen(function* () {
|
|
226
|
-
const openCodeLogger = yield* makeOpenCodeLogger;
|
|
227
|
-
const fileLogger = yield* pipe(Logger.jsonLogger, PlatformLogger.toFile(path.join(import.meta.dir, "plugin.log")));
|
|
228
|
-
return Logger.zip(openCodeLogger, fileLogger);
|
|
229
|
-
});
|
|
230
|
-
|
|
231
|
-
//#endregion
|
|
232
|
-
//#region src/lib/services/oauth.ts
|
|
233
|
-
/**
|
|
234
|
-
* OAuth service
|
|
235
|
-
*
|
|
236
|
-
* Handles initial OAuth authentication flow only.
|
|
237
|
-
* Token refresh is handled by the Session service.
|
|
238
|
-
*/
|
|
239
|
-
var OAuthError = class extends Data.TaggedError("OAuthError") {};
|
|
240
|
-
const SuccessParamsSchema = Schema.Struct({
|
|
241
|
-
code: Schema.String,
|
|
242
|
-
state: Schema.String
|
|
243
|
-
});
|
|
244
|
-
const FailureParamsSchema = Schema.Struct({
|
|
245
|
-
error: Schema.String,
|
|
246
|
-
error_description: Schema.optional(Schema.String),
|
|
247
|
-
state: Schema.optional(Schema.String)
|
|
248
|
-
});
|
|
249
|
-
const isFailureParams = Schema.is(FailureParamsSchema);
|
|
250
|
-
const ParamsSchema = Schema.Union(SuccessParamsSchema, FailureParamsSchema);
|
|
251
|
-
var OAuth = class extends Effect.Service()("OAuth", { effect: Effect.gen(function* () {
|
|
252
|
-
const config = yield* ProviderConfig;
|
|
253
|
-
const client = new OAuth2Client({
|
|
254
|
-
clientId: config.CLIENT_ID,
|
|
255
|
-
clientSecret: config.CLIENT_SECRET
|
|
256
|
-
});
|
|
257
|
-
const ServerLive = BunHttpServer.layerServer({ port: 0 });
|
|
258
|
-
return { authenticate: Effect.gen(function* () {
|
|
259
|
-
yield* HttpServer.logAddress;
|
|
260
|
-
const deferredParams = yield* Deferred.make();
|
|
261
|
-
const redirectUri = yield* HttpServer.addressFormattedWith((address) => Effect.succeed(`${address}/oauth2callback`));
|
|
262
|
-
const state = crypto.randomUUID();
|
|
263
|
-
const authUrl = client.generateAuthUrl({
|
|
264
|
-
state,
|
|
265
|
-
redirect_uri: redirectUri,
|
|
266
|
-
access_type: "offline",
|
|
267
|
-
scope: config.SCOPES,
|
|
268
|
-
prompt: "consent"
|
|
269
|
-
});
|
|
270
|
-
yield* Effect.log(`OAuth2 authorization URL: ${authUrl}`);
|
|
271
|
-
const serverFiber = yield* HttpRouter.empty.pipe(HttpRouter.get("/oauth2callback", Effect.gen(function* () {
|
|
272
|
-
const params = yield* HttpServerRequest.schemaSearchParams(ParamsSchema);
|
|
273
|
-
if (isFailureParams(params)) yield* Deferred.fail(deferredParams, new OAuthError({
|
|
274
|
-
reason: "callback",
|
|
275
|
-
message: `${params.error} - ${params.error_description ?? "No additional details provided"}`
|
|
276
|
-
}));
|
|
277
|
-
else yield* Deferred.succeed(deferredParams, params);
|
|
278
|
-
return yield* HttpServerResponse.text("You may now close this tab.");
|
|
279
|
-
}).pipe(Effect.tapError(Effect.logError))), HttpServer.serveEffect(), Effect.fork);
|
|
280
|
-
yield* Effect.log("Started OAuth2 callback server");
|
|
281
|
-
const search = yield* Deferred.await(deferredParams);
|
|
282
|
-
yield* Effect.log("Received OAuth2 callback with params", search);
|
|
283
|
-
yield* Fiber.interrupt(serverFiber);
|
|
284
|
-
if (state !== search.state) return yield* new OAuthError({
|
|
285
|
-
reason: "state_mismatch",
|
|
286
|
-
message: "Invalid state parameter. Possible CSRF attack."
|
|
287
|
-
});
|
|
288
|
-
return (yield* Effect.tryPromise({
|
|
289
|
-
try: () => client.getToken({
|
|
290
|
-
code: search.code,
|
|
291
|
-
redirect_uri: redirectUri
|
|
292
|
-
}),
|
|
293
|
-
catch: (cause) => new OAuthError({
|
|
294
|
-
reason: "token_exchange",
|
|
295
|
-
message: "Failed to exchange authorization code for tokens",
|
|
296
|
-
cause
|
|
297
|
-
})
|
|
298
|
-
})).tokens;
|
|
299
|
-
}).pipe(Effect.provide(ServerLive), Effect.scoped) };
|
|
300
|
-
}) }) {};
|
|
301
|
-
|
|
302
|
-
//#endregion
|
|
303
|
-
//#region src/lib/services/session.ts
|
|
304
|
-
var SessionError = class extends Data.TaggedError("SessionError") {};
|
|
305
|
-
var TokenExpiredError = class extends Data.TaggedError("TokenExpiredError") {};
|
|
306
|
-
const CodeAssistTier = Schema.Struct({
|
|
307
|
-
id: Schema.String,
|
|
308
|
-
name: Schema.String,
|
|
309
|
-
description: Schema.String,
|
|
310
|
-
userDefinedCloudaicompanionProject: Schema.Boolean,
|
|
311
|
-
isDefault: Schema.optional(Schema.Boolean)
|
|
312
|
-
});
|
|
313
|
-
const LoadCodeAssistResponse = Schema.Struct({
|
|
314
|
-
currentTier: CodeAssistTier,
|
|
315
|
-
allowedTiers: Schema.Array(CodeAssistTier),
|
|
316
|
-
cloudaicompanionProject: Schema.String,
|
|
317
|
-
gcpManaged: Schema.Boolean,
|
|
318
|
-
manageSubscriptionUri: Schema.String
|
|
319
|
-
});
|
|
320
|
-
var Session = class extends Effect.Service()("Session", { effect: Effect.gen(function* () {
|
|
321
|
-
const config = yield* ProviderConfig;
|
|
322
|
-
const openCode = yield* OpenCodeContext;
|
|
323
|
-
const httpClient = yield* HttpClient.HttpClient;
|
|
324
|
-
const credentialsRef = yield* Ref.make(null);
|
|
325
|
-
const projectRef = yield* Ref.make(null);
|
|
326
|
-
const endpoint = config.ENDPOINTS.at(0);
|
|
327
|
-
const oauthClient = new OAuth2Client({
|
|
328
|
-
clientId: config.CLIENT_ID,
|
|
329
|
-
clientSecret: config.CLIENT_SECRET
|
|
330
|
-
});
|
|
331
|
-
const getCredentials = Effect.gen(function* () {
|
|
332
|
-
const current = yield* Ref.get(credentialsRef);
|
|
333
|
-
if (!current) return yield* new SessionError({
|
|
334
|
-
reason: "no_tokens",
|
|
335
|
-
message: "No credentials set"
|
|
336
|
-
});
|
|
337
|
-
return current;
|
|
338
|
-
});
|
|
339
|
-
const refreshTokens = Effect.gen(function* () {
|
|
340
|
-
const credentials = yield* getCredentials;
|
|
341
|
-
oauthClient.setCredentials(credentials);
|
|
342
|
-
const newCredentials = (yield* Effect.tryPromise({
|
|
343
|
-
try: () => oauthClient.refreshAccessToken(),
|
|
344
|
-
catch: (cause) => new SessionError({
|
|
345
|
-
reason: "token_refresh",
|
|
346
|
-
message: "Failed to refresh access token",
|
|
347
|
-
cause
|
|
348
|
-
})
|
|
349
|
-
})).credentials;
|
|
350
|
-
yield* Ref.set(credentialsRef, newCredentials);
|
|
351
|
-
const accessToken = newCredentials.access_token;
|
|
352
|
-
const refreshToken = newCredentials.refresh_token;
|
|
353
|
-
const expiryDate = newCredentials.expiry_date;
|
|
354
|
-
if (accessToken && refreshToken && expiryDate) yield* Effect.promise(() => openCode.client.auth.set({
|
|
355
|
-
path: { id: config.SERVICE_NAME },
|
|
356
|
-
body: {
|
|
357
|
-
type: "oauth",
|
|
358
|
-
access: accessToken,
|
|
359
|
-
refresh: refreshToken,
|
|
360
|
-
expires: expiryDate
|
|
361
|
-
}
|
|
362
|
-
}));
|
|
363
|
-
return newCredentials;
|
|
364
|
-
});
|
|
365
|
-
const fetchAttempt = Effect.gen(function* () {
|
|
366
|
-
const credentials = yield* getCredentials;
|
|
367
|
-
const request = yield* HttpClientRequest.post(`${endpoint}/${CODE_ASSIST_VERSION}:loadCodeAssist`).pipe(HttpClientRequest.bearerToken(credentials.access_token), HttpClientRequest.bodyJson({ metadata: {
|
|
368
|
-
ideType: "IDE_UNSPECIFIED",
|
|
369
|
-
platform: "PLATFORM_UNSPECIFIED",
|
|
370
|
-
pluginType: "GEMINI"
|
|
371
|
-
} }));
|
|
372
|
-
return yield* pipe(httpClient.execute(request), Effect.andThen(HttpClientResponse.matchStatus({
|
|
373
|
-
"2xx": (res) => HttpClientResponse.schemaBodyJson(LoadCodeAssistResponse)(res),
|
|
374
|
-
401: () => new TokenExpiredError({ message: "Token expired" }),
|
|
375
|
-
orElse: (response) => new SessionError({
|
|
376
|
-
reason: "project_fetch",
|
|
377
|
-
message: `HTTP error: ${response.status}`
|
|
378
|
-
})
|
|
379
|
-
})));
|
|
380
|
-
});
|
|
381
|
-
const fetchProject = fetchAttempt.pipe(Effect.catchTag("TokenExpiredError", () => pipe(Effect.log("Token expired, refreshing..."), Effect.flatMap(() => refreshTokens), Effect.flatMap(() => fetchAttempt))), Effect.catchAll((error) => {
|
|
382
|
-
if (error instanceof SessionError) return Effect.fail(error);
|
|
383
|
-
return Effect.fail(new SessionError({
|
|
384
|
-
reason: "project_fetch",
|
|
385
|
-
message: "Failed to fetch project",
|
|
386
|
-
cause: error
|
|
387
|
-
}));
|
|
388
|
-
}));
|
|
389
|
-
const ensureProject = Effect.gen(function* () {
|
|
390
|
-
const cached = yield* Ref.get(projectRef);
|
|
391
|
-
if (cached !== null) return cached;
|
|
392
|
-
const project = yield* fetchProject;
|
|
393
|
-
yield* Ref.set(projectRef, project);
|
|
394
|
-
return project;
|
|
395
|
-
});
|
|
396
|
-
return {
|
|
397
|
-
setCredentials: (credentials) => Ref.set(credentialsRef, credentials),
|
|
398
|
-
getAccessToken: Effect.gen(function* () {
|
|
399
|
-
const currentCreds = yield* Ref.get(credentialsRef);
|
|
400
|
-
if (!currentCreds?.access_token) return yield* new SessionError({
|
|
401
|
-
reason: "no_tokens",
|
|
402
|
-
message: "No access token available"
|
|
403
|
-
});
|
|
404
|
-
const isExpired = (currentCreds.expiry_date ?? 0) < Date.now() + 300 * 1e3;
|
|
405
|
-
let accessToken = currentCreds.access_token;
|
|
406
|
-
if (isExpired) {
|
|
407
|
-
yield* Effect.log("Access token expired, refreshing...");
|
|
408
|
-
const refreshed = yield* refreshTokens;
|
|
409
|
-
if (!refreshed.access_token) return yield* new SessionError({
|
|
410
|
-
reason: "token_refresh",
|
|
411
|
-
message: "Refresh did not return access token"
|
|
412
|
-
});
|
|
413
|
-
accessToken = refreshed.access_token;
|
|
414
|
-
}
|
|
415
|
-
yield* ensureProject;
|
|
416
|
-
return accessToken;
|
|
417
|
-
}),
|
|
418
|
-
ensureProject
|
|
419
|
-
};
|
|
420
|
-
}) }) {};
|
|
421
|
-
|
|
422
|
-
//#endregion
|
|
423
|
-
//#region src/lib/runtime.ts
|
|
424
|
-
const makeRuntime = ({ providerConfig, openCodeCtx }) => {
|
|
425
|
-
const LoggerLive = Logger.replaceScoped(Logger.defaultLogger, combinedLogger);
|
|
426
|
-
const ProviderConfigLive = Layer.succeed(ProviderConfig, providerConfig);
|
|
427
|
-
const OpenCodeLive = Layer.succeed(OpenCodeContext, openCodeCtx);
|
|
428
|
-
const MainLive = pipe(Layer.empty, Layer.provide(LoggerLive), Layer.provide(BunFileSystem.layer), Layer.merge(OAuth.Default), Layer.merge(Session.Default), Layer.provideMerge(OpenCodeLive), Layer.provideMerge(FetchHttpClient.layer), Layer.provideMerge(ProviderConfigLive));
|
|
429
|
-
return ManagedRuntime.make(MainLive);
|
|
430
|
-
};
|
|
431
|
-
|
|
432
|
-
//#endregion
|
|
433
|
-
//#region src/transform/request.ts
|
|
434
|
-
const STREAM_ACTION = "streamGenerateContent";
|
|
435
|
-
const PATH_PATTERN = regex("/models/(?<model>[^:]+):(?<action>\\w+)");
|
|
436
|
-
const transformRequest = Effect.fn("transformRequest")(function* (input, init, endpoint) {
|
|
437
|
-
const config = yield* ProviderConfig;
|
|
438
|
-
const session = yield* Session;
|
|
439
|
-
const accessToken = yield* session.getAccessToken;
|
|
440
|
-
const projectId = (yield* session.ensureProject).cloudaicompanionProject;
|
|
441
|
-
const url = new URL(input instanceof Request ? input.url : input);
|
|
442
|
-
const endpointUrl = new URL(endpoint);
|
|
443
|
-
url.protocol = endpointUrl.protocol;
|
|
444
|
-
url.host = endpointUrl.host;
|
|
445
|
-
const match = PATH_PATTERN.exec(url.pathname);
|
|
446
|
-
if (!match) return {
|
|
447
|
-
input: url.toString(),
|
|
448
|
-
init: init ?? {},
|
|
449
|
-
streaming: false
|
|
450
|
-
};
|
|
451
|
-
const { model, action } = match.groups;
|
|
452
|
-
const streaming = action === STREAM_ACTION;
|
|
453
|
-
url.pathname = `/${CODE_ASSIST_VERSION}:${action}`;
|
|
454
|
-
if (streaming) url.searchParams.set("alt", "sse");
|
|
455
|
-
const headers = new Headers(init?.headers);
|
|
456
|
-
headers.delete("x-api-key");
|
|
457
|
-
headers.set("x-opencode-tools-debug", "1");
|
|
458
|
-
headers.set("Authorization", `Bearer ${accessToken}`);
|
|
459
|
-
for (const [key, value] of Object.entries(config.HEADERS)) headers.set(key, value);
|
|
460
|
-
if (streaming) headers.set("Accept", "text/event-stream");
|
|
461
|
-
const isJson = typeof init?.body === "string";
|
|
462
|
-
const parsedBody = yield* pipe(Effect.try(() => isJson ? JSON.parse(init.body) : null), Effect.orElseSucceed(() => null));
|
|
463
|
-
const wrappedBody = {
|
|
464
|
-
project: projectId,
|
|
465
|
-
model,
|
|
466
|
-
request: parsedBody ?? {}
|
|
467
|
-
};
|
|
468
|
-
const { body: transformedBody, headers: finalHeaders, url: finalUrl } = config.transformRequest ? yield* config.transformRequest({
|
|
469
|
-
body: wrappedBody,
|
|
470
|
-
headers,
|
|
471
|
-
url
|
|
472
|
-
}) : {
|
|
473
|
-
body: wrappedBody,
|
|
474
|
-
headers,
|
|
475
|
-
url
|
|
476
|
-
};
|
|
477
|
-
const finalBody = isJson && parsedBody ? JSON.stringify(transformedBody) : init?.body;
|
|
478
|
-
return {
|
|
479
|
-
input: finalUrl.toString(),
|
|
480
|
-
init: {
|
|
481
|
-
...init,
|
|
482
|
-
headers: finalHeaders,
|
|
483
|
-
body: finalBody
|
|
484
|
-
},
|
|
485
|
-
streaming
|
|
486
|
-
};
|
|
487
|
-
});
|
|
488
|
-
|
|
489
|
-
//#endregion
|
|
490
|
-
//#region src/transform/response.ts
|
|
491
|
-
const transformNonStreamingResponse = async (response) => {
|
|
492
|
-
if (!response.headers.get("content-type")?.includes("application/json")) return response;
|
|
493
|
-
try {
|
|
494
|
-
const parsed = await response.clone().json();
|
|
495
|
-
if (parsed.response !== void 0) {
|
|
496
|
-
const { response: responseData, ...rest } = parsed;
|
|
497
|
-
return new Response(JSON.stringify({
|
|
498
|
-
...rest,
|
|
499
|
-
...responseData
|
|
500
|
-
}), {
|
|
501
|
-
status: response.status,
|
|
502
|
-
statusText: response.statusText,
|
|
503
|
-
headers: response.headers
|
|
504
|
-
});
|
|
505
|
-
}
|
|
506
|
-
} catch {}
|
|
507
|
-
return response;
|
|
508
|
-
};
|
|
509
|
-
|
|
510
|
-
//#endregion
|
|
511
|
-
//#region src/transform/stream.ts
|
|
512
|
-
const parseAndMerge = (event) => {
|
|
513
|
-
if (!event.data) return encoder.write(event);
|
|
514
|
-
try {
|
|
515
|
-
const parsed = JSON.parse(event.data);
|
|
516
|
-
if (parsed.response) {
|
|
517
|
-
const { response, ...rest } = parsed;
|
|
518
|
-
return encoder.write({
|
|
519
|
-
...event,
|
|
520
|
-
data: JSON.stringify({
|
|
521
|
-
...rest,
|
|
522
|
-
...response
|
|
523
|
-
})
|
|
524
|
-
});
|
|
525
|
-
}
|
|
526
|
-
return encoder.write(event);
|
|
527
|
-
} catch {
|
|
528
|
-
return encoder.write(event);
|
|
529
|
-
}
|
|
530
|
-
};
|
|
531
|
-
const parseSSE = (body) => pipe(Stream.fromReadableStream(() => body, (error) => error), Stream.decodeText, Stream.pipeThroughChannel(makeChannel()), Stream.map((event) => Retry.is(event) ? encoder.write(event) : parseAndMerge(event)), Stream.encodeText);
|
|
532
|
-
const transformStreamingResponse = (response) => {
|
|
533
|
-
if (!response.body) return response;
|
|
534
|
-
const transformed = parseSSE(response.body);
|
|
535
|
-
const readable = Stream.toReadableStream(transformed);
|
|
536
|
-
return new Response(readable, {
|
|
537
|
-
status: response.status,
|
|
538
|
-
statusText: response.statusText,
|
|
539
|
-
headers: response.headers
|
|
540
|
-
});
|
|
541
|
-
};
|
|
542
|
-
|
|
543
|
-
//#endregion
|
|
544
|
-
//#region src/main.ts
|
|
545
|
-
const fetchModelsDev = Effect.gen(function* () {
|
|
546
|
-
return yield* (yield* (yield* HttpClient.HttpClient).get("https://models.dev/api.json")).json;
|
|
547
|
-
});
|
|
548
|
-
const customFetch = Effect.fn(function* (input, init) {
|
|
549
|
-
const config = yield* ProviderConfig;
|
|
550
|
-
let lastResponse = null;
|
|
551
|
-
for (const endpoint of config.ENDPOINTS) {
|
|
552
|
-
const result = yield* transformRequest(input, init, endpoint);
|
|
553
|
-
const { request, ...loggedBody } = JSON.parse(result.init.body);
|
|
554
|
-
const generationConfig = request.generationConfig;
|
|
555
|
-
yield* Effect.log("Transformed request (Omitting request except generationConfig) :", result.streaming, result.input, {
|
|
556
|
-
...loggedBody,
|
|
557
|
-
request: { generationConfig }
|
|
558
|
-
});
|
|
559
|
-
const response = yield* Effect.promise(() => fetch(result.input, result.init));
|
|
560
|
-
if (response.status === 429 || response.status === 403) {
|
|
561
|
-
yield* Effect.log(`${response.status} on ${endpoint}, trying next...`);
|
|
562
|
-
lastResponse = response;
|
|
563
|
-
continue;
|
|
564
|
-
}
|
|
565
|
-
if (!response.ok) {
|
|
566
|
-
const cloned = response.clone();
|
|
567
|
-
const clonedJson = yield* Effect.promise(() => cloned.json());
|
|
568
|
-
yield* Effect.log("Received response:", cloned.status, clonedJson, cloned.headers);
|
|
569
|
-
}
|
|
570
|
-
return result.streaming ? transformStreamingResponse(response) : yield* Effect.promise(() => transformNonStreamingResponse(response));
|
|
571
|
-
}
|
|
572
|
-
yield* Effect.logWarning("All endpoints rate limited (429)");
|
|
573
|
-
return lastResponse;
|
|
574
|
-
}, Effect.tapDefect(Effect.logError));
|
|
575
|
-
const geminiCli = async (context) => {
|
|
576
|
-
const runtime = makeRuntime({
|
|
577
|
-
openCodeCtx: context,
|
|
578
|
-
providerConfig: geminiCliConfig()
|
|
579
|
-
});
|
|
580
|
-
const config = await runtime.runPromise(Effect.gen(function* () {
|
|
581
|
-
const providerConfig = yield* ProviderConfig;
|
|
582
|
-
const modelsDev = yield* fetchModelsDev;
|
|
583
|
-
return providerConfig.getConfig(modelsDev);
|
|
584
|
-
}));
|
|
585
|
-
return {
|
|
586
|
-
config: async (cfg) => {
|
|
587
|
-
cfg.provider ??= {};
|
|
588
|
-
cfg.provider[config.id] = config;
|
|
589
|
-
},
|
|
590
|
-
auth: {
|
|
591
|
-
provider: config.id,
|
|
592
|
-
loader: async (getAuth) => {
|
|
593
|
-
const auth = await getAuth();
|
|
594
|
-
if (auth.type !== "oauth") return {};
|
|
595
|
-
const credentials = {
|
|
596
|
-
access_token: auth.access,
|
|
597
|
-
refresh_token: auth.refresh,
|
|
598
|
-
expiry_date: auth.expires
|
|
599
|
-
};
|
|
600
|
-
await runtime.runPromise(Effect.gen(function* () {
|
|
601
|
-
yield* (yield* Session).setCredentials(credentials);
|
|
602
|
-
}));
|
|
603
|
-
return {
|
|
604
|
-
apiKey: "",
|
|
605
|
-
fetch: (async (input, init) => {
|
|
606
|
-
return await runtime.runPromise(customFetch(input, init));
|
|
607
|
-
})
|
|
608
|
-
};
|
|
609
|
-
},
|
|
610
|
-
methods: [{
|
|
611
|
-
type: "oauth",
|
|
612
|
-
label: "OAuth with Google",
|
|
613
|
-
authorize: async () => {
|
|
614
|
-
const result = await runtime.runPromise(Effect.gen(function* () {
|
|
615
|
-
return yield* (yield* OAuth).authenticate;
|
|
616
|
-
}));
|
|
617
|
-
return {
|
|
618
|
-
url: "",
|
|
619
|
-
method: "auto",
|
|
620
|
-
instructions: "You are now authenticated!",
|
|
621
|
-
callback: async () => {
|
|
622
|
-
const accessToken = result.access_token;
|
|
623
|
-
const refreshToken = result.refresh_token;
|
|
624
|
-
const expiryDate = result.expiry_date;
|
|
625
|
-
if (!accessToken || !refreshToken || !expiryDate) return { type: "failed" };
|
|
626
|
-
return {
|
|
627
|
-
type: "success",
|
|
628
|
-
provider: config.id,
|
|
629
|
-
access: accessToken,
|
|
630
|
-
refresh: refreshToken,
|
|
631
|
-
expires: expiryDate
|
|
632
|
-
};
|
|
633
|
-
}
|
|
634
|
-
};
|
|
635
|
-
}
|
|
636
|
-
}]
|
|
637
|
-
}
|
|
638
|
-
};
|
|
639
|
-
};
|
|
640
|
-
const antigravity = async (context) => {
|
|
641
|
-
const runtime = makeRuntime({
|
|
642
|
-
openCodeCtx: context,
|
|
643
|
-
providerConfig: antigravityConfig()
|
|
644
|
-
});
|
|
645
|
-
const config = await runtime.runPromise(Effect.gen(function* () {
|
|
646
|
-
const providerConfig = yield* ProviderConfig;
|
|
647
|
-
const modelsDev = yield* fetchModelsDev;
|
|
648
|
-
return providerConfig.getConfig(modelsDev);
|
|
649
|
-
}));
|
|
650
|
-
return {
|
|
651
|
-
config: async (cfg) => {
|
|
652
|
-
cfg.provider ??= {};
|
|
653
|
-
cfg.provider[config.id] = config;
|
|
654
|
-
},
|
|
655
|
-
auth: {
|
|
656
|
-
provider: config.id,
|
|
657
|
-
loader: async (getAuth) => {
|
|
658
|
-
const auth = await getAuth();
|
|
659
|
-
if (auth.type !== "oauth") return {};
|
|
660
|
-
const credentials = {
|
|
661
|
-
access_token: auth.access,
|
|
662
|
-
refresh_token: auth.refresh,
|
|
663
|
-
expiry_date: auth.expires
|
|
664
|
-
};
|
|
665
|
-
await runtime.runPromise(Effect.gen(function* () {
|
|
666
|
-
yield* (yield* Session).setCredentials(credentials);
|
|
667
|
-
}));
|
|
668
|
-
return {
|
|
669
|
-
apiKey: "",
|
|
670
|
-
fetch: (async (input, init) => {
|
|
671
|
-
return await runtime.runPromise(customFetch(input, init));
|
|
672
|
-
})
|
|
673
|
-
};
|
|
674
|
-
},
|
|
675
|
-
methods: [{
|
|
676
|
-
type: "oauth",
|
|
677
|
-
label: "OAuth with Google",
|
|
678
|
-
authorize: async () => {
|
|
679
|
-
const result = await runtime.runPromise(Effect.gen(function* () {
|
|
680
|
-
return yield* (yield* OAuth).authenticate;
|
|
681
|
-
}));
|
|
682
|
-
return {
|
|
683
|
-
url: "",
|
|
684
|
-
method: "auto",
|
|
685
|
-
instructions: "You are now authenticated!",
|
|
686
|
-
callback: async () => {
|
|
687
|
-
const accessToken = result.access_token;
|
|
688
|
-
const refreshToken = result.refresh_token;
|
|
689
|
-
const expiryDate = result.expiry_date;
|
|
690
|
-
if (!accessToken || !refreshToken || !expiryDate) return { type: "failed" };
|
|
691
|
-
return {
|
|
692
|
-
type: "success",
|
|
693
|
-
provider: config.id,
|
|
694
|
-
access: accessToken,
|
|
695
|
-
refresh: refreshToken,
|
|
696
|
-
expires: expiryDate
|
|
697
|
-
};
|
|
698
|
-
}
|
|
699
|
-
};
|
|
700
|
-
}
|
|
701
|
-
}]
|
|
702
|
-
},
|
|
703
|
-
"chat.params": async (input, output) => {
|
|
704
|
-
await runtime.runPromise(Effect.log("chat.params event before:", input.model, output.options));
|
|
705
|
-
if (input.model.providerID === config.id) output.options = {
|
|
706
|
-
...output.options,
|
|
707
|
-
labels: { sessionId: input.sessionID }
|
|
708
|
-
};
|
|
709
|
-
await runtime.runPromise(Effect.log("chat.params event after:", input.model, output.options));
|
|
710
|
-
}
|
|
711
|
-
};
|
|
712
|
-
};
|
|
713
|
-
|
|
714
|
-
//#endregion
|
|
715
|
-
export { antigravity, geminiCli };
|
|
716
|
-
//# sourceMappingURL=main.mjs.map
|
package/dist/main.mjs.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"main.mjs","names":[],"sources":["../src/lib/services/config.ts","../src/lib/services/opencode.ts","../src/lib/logger.ts","../src/lib/services/oauth.ts","../src/lib/services/session.ts","../src/lib/runtime.ts","../src/transform/request.ts","../src/transform/response.ts","../src/transform/stream.ts","../src/main.ts"],"sourcesContent":["import type { GoogleGenerativeAIProviderOptions } from \"@ai-sdk/google\"\nimport { Context, Effect, pipe } from \"effect\"\nimport type {\n ModelsDev,\n OpenCodeModel,\n OpenCodeProvider,\n Provider,\n} from \"../../types\"\n\nexport interface WrappedBody {\n readonly project: string\n readonly request: unknown\n readonly model: string\n}\n\nexport interface RequestContext {\n readonly body: WrappedBody\n readonly headers: Headers\n readonly url: URL\n}\n\nexport interface ProviderConfigShape {\n readonly SERVICE_NAME: string\n readonly DISPLAY_NAME: string\n readonly ENDPOINTS: readonly string[]\n readonly HEADERS: Readonly<Record<string, string>>\n readonly SCOPES: readonly string[]\n readonly CLIENT_ID: string\n readonly CLIENT_SECRET: string\n readonly getConfig: (modelsDev: ModelsDev) => OpenCodeProvider\n readonly transformRequest?: (context: RequestContext) => Effect.Effect<{\n body: Record<string, unknown>\n headers: Headers\n url: URL\n }>\n}\n\nexport class ProviderConfig extends Context.Tag(\"ProviderConfig\")<\n ProviderConfig,\n ProviderConfigShape\n>() {}\n\nexport const CODE_ASSIST_VERSION = \"v1internal\"\n\nexport const CLIENT_METADATA = {\n ideType: \"IDE_UNSPECIFIED\",\n platform: \"PLATFORM_UNSPECIFIED\",\n pluginType: \"GEMINI\",\n} as const\n\nexport const GEMINI_CLI_MODELS = [\n \"gemini-2.5-pro\",\n \"gemini-2.5-flash\",\n \"gemini-2.5-flash-lite\",\n \"gemini-3-pro-preview\",\n \"gemini-3-flash-preview\",\n] as const\n\nexport const ANTIGRAVITY_MODELS = [\n \"gemini-3-flash\",\n \"gemini-3-pro-low\",\n \"gemini-3-pro-high\",\n \"claude-sonnet-4-5\",\n \"claude-sonnet-4-5-thinking\",\n \"claude-opus-4-5-thinking\",\n] as const\n\nexport const geminiCliConfig = (): ProviderConfigShape => ({\n SERVICE_NAME: \"gemini-cli\",\n DISPLAY_NAME: \"Gemini CLI\",\n CLIENT_ID:\n \"681255809395-oo8ft2oprdrnp9e3aqf6av3hmdib135j.apps.googleusercontent.com\",\n CLIENT_SECRET: \"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\",\n SCOPES: [\n \"https://www.googleapis.com/auth/cloud-platform\",\n \"https://www.googleapis.com/auth/userinfo.email\",\n \"https://www.googleapis.com/auth/userinfo.profile\",\n ],\n ENDPOINTS: [\"https://cloudcode-pa.googleapis.com\"],\n HEADERS: {\n \"User-Agent\": \"google-api-nodejs-client/9.15.1\",\n \"X-Goog-Api-Client\": \"gl-node/22.17.0\",\n \"Client-Metadata\":\n \"ideType=IDE_UNSPECIFIED,platform=PLATFORM_UNSPECIFIED,pluginType=GEMINI\",\n },\n getConfig: (modelsDev) => {\n const provider = modelsDev.google as Provider\n const filteredModels = pipe(\n provider.models,\n (models) => Object.entries(models),\n (entries) =>\n entries.filter(([key]) =>\n (GEMINI_CLI_MODELS as readonly string[]).includes(key),\n ),\n (filtered) => Object.fromEntries(filtered),\n )\n\n return {\n ...provider,\n id: geminiCliConfig().SERVICE_NAME,\n name: geminiCliConfig().DISPLAY_NAME,\n api: geminiCliConfig().ENDPOINTS.at(0) as string,\n models: filteredModels as Record<string, OpenCodeModel>,\n }\n },\n})\n\nexport const antigravityConfig = (): ProviderConfigShape => ({\n SERVICE_NAME: \"antigravity\",\n DISPLAY_NAME: \"Antigravity\",\n CLIENT_ID:\n \"1071006060591-tmhssin2h21lcre235vtolojh4g403ep.apps.googleusercontent.com\",\n CLIENT_SECRET: \"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\",\n SCOPES: [\n \"https://www.googleapis.com/auth/cloud-platform\",\n \"https://www.googleapis.com/auth/userinfo.email\",\n \"https://www.googleapis.com/auth/userinfo.profile\",\n \"https://www.googleapis.com/auth/cclog\",\n \"https://www.googleapis.com/auth/experimentsandconfigs\",\n ],\n ENDPOINTS: [\n \"https://daily-cloudcode-pa.sandbox.googleapis.com\",\n \"https://autopush-cloudcode-pa.sandbox.googleapis.com\",\n \"https://cloudcode-pa.googleapis.com\",\n ],\n HEADERS: {\n \"User-Agent\": \"antigravity/1.11.5 windows/amd64\",\n \"X-Goog-Api-Client\": \"google-cloud-sdk vscode_cloudshelleditor/0.1\",\n \"Client-Metadata\":\n '{\"ideType\":\"IDE_UNSPECIFIED\",\"platform\":\"PLATFORM_UNSPECIFIED\",\"pluginType\":\"GEMINI\"}',\n },\n getConfig: (modelsDev) => {\n const googleProvider = modelsDev.google as Provider\n const googleVertextProvider = modelsDev[\n \"google-vertex-anthropic\"\n ] as Provider\n\n const geminiFlash = googleProvider.models[\n \"gemini-3-flash-preview\"\n ] as OpenCodeModel\n const geminiPro = googleProvider.models[\n \"gemini-3-pro-preview\"\n ] as OpenCodeModel\n const claudeSonnet = googleVertextProvider.models[\n \"claude-sonnet-4-5@20250929\"\n ] as OpenCodeModel\n const claudeOpus = googleVertextProvider.models[\n \"claude-opus-4-5@20251101\"\n ] as OpenCodeModel\n\n const models: Record<string, OpenCodeModel> = {\n \"gemini-3-flash\": {\n ...geminiFlash,\n id: \"gemini-3-flash\",\n },\n \"gemini-3-pro-low\": {\n ...geminiPro,\n id: \"gemini-3-pro-low\",\n name: \"Gemini 3 Pro (Low)\",\n temperature: false,\n options: {\n thinkingConfig: {\n thinkingLevel: \"low\",\n },\n } satisfies GoogleGenerativeAIProviderOptions,\n },\n \"gemini-3-pro-high\": {\n ...geminiPro,\n id: \"gemini-3-pro-high\",\n name: \"Gemini 3 Pro (High)\",\n temperature: false,\n options: {\n thinkingConfig: {\n thinkingLevel: \"high\",\n },\n } satisfies GoogleGenerativeAIProviderOptions,\n },\n \"claude-sonnet-4-5\": {\n ...claudeSonnet,\n id: \"claude-sonnet-4-5\",\n reasoning: false,\n options: {\n thinkingConfig: {\n includeThoughts: false,\n },\n } satisfies GoogleGenerativeAIProviderOptions,\n },\n \"claude-sonnet-4-5-thinking\": {\n ...claudeSonnet,\n id: \"claude-sonnet-4-5-thinking\",\n name: \"Claude Sonnet 4.5 (Reasoning)\",\n },\n \"claude-opus-4-5-thinking\": {\n ...claudeOpus,\n id: \"claude-opus-4-5-thinking\",\n name: \"Claude Opus 4.5 (Reasoning)\",\n },\n }\n\n return {\n ...googleProvider,\n id: antigravityConfig().SERVICE_NAME,\n name: antigravityConfig().DISPLAY_NAME,\n api: antigravityConfig().ENDPOINTS.at(2) as string,\n models,\n }\n },\n transformRequest: Effect.fn(function* (context) {\n yield* Effect.log(\n \"Transforming request for: \",\n antigravityConfig().SERVICE_NAME,\n )\n\n const { body, headers, url } = context\n const innerRequest = body.request as Record<string, unknown>\n\n let sessionId: string | undefined\n if (\n innerRequest.labels\n && typeof innerRequest.labels === \"object\"\n && \"sessionId\" in innerRequest.labels\n ) {\n const labels = innerRequest.labels as Record<string, unknown>\n sessionId = labels.sessionId as string\n delete labels.sessionId\n if (Object.keys(labels).length === 0) {\n delete innerRequest.labels\n }\n }\n\n // Handle thinkingConfig for Claude models\n const isClaude = body.model.toLowerCase().includes(\"claude\")\n const isThinking = body.model.toLowerCase().includes(\"thinking\")\n\n if (isClaude && body.request && typeof body.request === \"object\") {\n const request = body.request as Record<string, unknown>\n const generationConfig = request.generationConfig as\n | Record<string, unknown>\n | undefined\n\n innerRequest.toolConfig = {\n functionCallingConfig: {\n mode: \"VALIDATED\",\n },\n }\n\n // For non-thinking Claude, remove thinkingConfig entirely\n if (!isThinking && generationConfig?.thinkingConfig) {\n delete generationConfig.thinkingConfig\n }\n\n // For thinking Claude, convert camelCase to snake_case and add default budget\n if (isThinking && generationConfig?.thinkingConfig) {\n const thinkingConfig = generationConfig.thinkingConfig as Record<\n string,\n unknown\n >\n\n if (thinkingConfig.includeThoughts !== undefined) {\n thinkingConfig.include_thoughts = thinkingConfig.includeThoughts\n delete thinkingConfig.includeThoughts\n }\n\n if (thinkingConfig.thinkingBudget !== undefined) {\n thinkingConfig.thinking_budget = thinkingConfig.thinkingBudget\n delete thinkingConfig.thinkingBudget\n }\n\n // Add default thinking_budget if not present (required for Claude thinking)\n if (thinkingConfig.thinking_budget === undefined) {\n thinkingConfig.thinking_budget = 32768 // Default to high tier\n }\n }\n\n if (isThinking) {\n headers.set(\"anthropic-beta\", \"interleaved-thinking-2025-05-14\")\n }\n }\n\n if (sessionId) {\n const hashedSession = yield* Effect.promise(() => hash(sessionId))\n\n const finalSessionId = [\n `-${crypto.randomUUID()}`,\n body.model,\n body.project,\n `seed-${hashedSession}`,\n ].join(\":\")\n\n innerRequest.sessionId = finalSessionId\n }\n\n if (innerRequest.tools && Array.isArray(innerRequest.tools)) {\n const tools = innerRequest.tools as Array<Record<string, unknown>>\n for (const tool of tools) {\n if (\n tool.functionDeclarations\n && Array.isArray(tool.functionDeclarations)\n ) {\n const functionDeclarations = tool.functionDeclarations as Array<\n Record<string, unknown>\n >\n for (let i = 0; i < functionDeclarations.length; i++) {\n const declaration = functionDeclarations[i]\n if (declaration && declaration.name === \"todoread\") {\n functionDeclarations[i] = {\n ...functionDeclarations[i],\n parameters: {\n type: \"object\",\n properties: {\n _placeholder: {\n type: \"boolean\",\n description: \"Placeholder. Always pass true.\",\n },\n },\n required: [\"_placeholder\"],\n additionalProperties: false,\n },\n }\n }\n }\n }\n }\n }\n\n // if (\n // innerRequest.systemInstruction\n // && typeof innerRequest.systemInstruction === \"object\"\n // ) {\n // const systemInstruction = innerRequest.systemInstruction as Record<\n // string,\n // unknown\n // >\n\n // if (systemInstruction.parts && Array.isArray(systemInstruction.parts)) {\n // let parts = systemInstruction.parts as Array<{ text: string }>\n\n // parts.unshift({\n // text: \"You are Antigravity, a powerful agentic AI coding assistant designed by the Google DeepMind team working on Advanced Agentic Coding.\",\n // })\n // }\n // }\n\n if (\n innerRequest.systemInstruction\n && typeof innerRequest.systemInstruction === \"object\"\n ) {\n const systemInstruction = innerRequest.systemInstruction as Record<\n string,\n unknown\n >\n\n systemInstruction.role = \"user\"\n }\n\n return {\n headers,\n url,\n body: {\n ...body,\n requestType: \"agent\",\n userAgent: \"antigravity\",\n requestId: `agent-${crypto.randomUUID()}`,\n },\n }\n }),\n})\n\nasync function hash(str: string) {\n const encoder = new TextEncoder()\n const data = encoder.encode(str)\n\n const hashBuffer = await crypto.subtle.digest(\"SHA-256\", data)\n const hashArray = Array.from(new Uint8Array(hashBuffer))\n const hashHex = hashArray.map((b) => b.toString(16).padStart(2, \"0\")).join(\"\")\n\n return hashHex.slice(0, 16)\n}\n","import type { PluginInput } from \"@opencode-ai/plugin\"\nimport { Context } from \"effect\"\n\nexport class OpenCodeContext extends Context.Tag(\"OpenCodeContext\")<\n OpenCodeContext,\n PluginInput\n>() {}\n","import { PlatformLogger } from \"@effect/platform\"\nimport { Effect, Inspectable, Logger, LogLevel, pipe } from \"effect\"\nimport path from \"node:path\"\nimport type { OpenCodeLogLevel } from \"../types\"\nimport { ProviderConfig } from \"./services/config\"\nimport { OpenCodeContext } from \"./services/opencode\"\n\nconst makeOpenCodeLogger = Effect.gen(function* () {\n const openCode = yield* OpenCodeContext\n const config = yield* ProviderConfig\n\n return Logger.make((log) => {\n let level: OpenCodeLogLevel = \"debug\"\n\n if (LogLevel.greaterThanEqual(log.logLevel, LogLevel.Error)) {\n level = \"error\"\n } else if (LogLevel.greaterThanEqual(log.logLevel, LogLevel.Warning)) {\n level = \"warn\"\n } else if (LogLevel.greaterThanEqual(log.logLevel, LogLevel.Info)) {\n level = \"info\"\n }\n\n const message = Inspectable.toStringUnknown(log.message)\n\n void openCode.client.app.log({\n body: {\n level,\n message,\n service: config.SERVICE_NAME,\n },\n })\n })\n})\n\nexport const combinedLogger = Effect.gen(function* () {\n const openCodeLogger = yield* makeOpenCodeLogger\n const fileLogger = yield* pipe(\n Logger.jsonLogger,\n PlatformLogger.toFile(path.join(import.meta.dir, \"plugin.log\")),\n )\n\n return Logger.zip(openCodeLogger, fileLogger)\n})\n","/**\n * OAuth service\n *\n * Handles initial OAuth authentication flow only.\n * Token refresh is handled by the Session service.\n */\n\nimport {\n HttpRouter,\n HttpServer,\n HttpServerRequest,\n HttpServerResponse,\n} from \"@effect/platform\"\nimport { BunHttpServer } from \"@effect/platform-bun\"\nimport { Data, Deferred, Effect, Fiber, Schema } from \"effect\"\nimport { OAuth2Client } from \"google-auth-library\"\nimport type { BunServeOptions } from \"../../types\"\nimport { ProviderConfig } from \"./config\"\n\nexport class OAuthError extends Data.TaggedError(\"OAuthError\")<{\n readonly reason: \"browser\" | \"callback\" | \"state_mismatch\" | \"token_exchange\"\n readonly message: string\n readonly cause?: unknown\n}> {}\n\nconst SuccessParamsSchema = Schema.Struct({\n code: Schema.String,\n state: Schema.String,\n})\n\nconst FailureParamsSchema = Schema.Struct({\n error: Schema.String,\n error_description: Schema.optional(Schema.String),\n state: Schema.optional(Schema.String),\n})\n\nconst isFailureParams = Schema.is(FailureParamsSchema)\n\nconst ParamsSchema = Schema.Union(SuccessParamsSchema, FailureParamsSchema)\n\nclass OAuth extends Effect.Service<OAuth>()(\"OAuth\", {\n effect: Effect.gen(function* () {\n const config = yield* ProviderConfig\n\n const client = new OAuth2Client({\n clientId: config.CLIENT_ID,\n clientSecret: config.CLIENT_SECRET,\n })\n const serverOptions: BunServeOptions = { port: 0 }\n const ServerLive = BunHttpServer.layerServer(serverOptions)\n\n const authenticate = Effect.gen(function* () {\n yield* HttpServer.logAddress\n\n const deferredParams = yield* Deferred.make<\n typeof SuccessParamsSchema.Type,\n OAuthError\n >()\n\n const redirectUri = yield* HttpServer.addressFormattedWith((address) =>\n Effect.succeed(`${address}/oauth2callback`),\n )\n const state = crypto.randomUUID()\n\n const authUrl = client.generateAuthUrl({\n state,\n redirect_uri: redirectUri,\n access_type: \"offline\",\n scope: config.SCOPES as unknown as string[],\n prompt: \"consent\",\n })\n yield* Effect.log(`OAuth2 authorization URL: ${authUrl}`)\n\n const serverFiber = yield* HttpRouter.empty.pipe(\n HttpRouter.get(\n \"/oauth2callback\",\n Effect.gen(function* () {\n const params =\n yield* HttpServerRequest.schemaSearchParams(ParamsSchema)\n\n if (isFailureParams(params)) {\n yield* Deferred.fail(\n deferredParams,\n new OAuthError({\n reason: \"callback\",\n message: `${params.error} - ${params.error_description ?? \"No additional details provided\"}`,\n }),\n )\n } else {\n yield* Deferred.succeed(deferredParams, params)\n }\n\n return yield* HttpServerResponse.text(\"You may now close this tab.\")\n }).pipe(Effect.tapError(Effect.logError)),\n ),\n HttpServer.serveEffect(),\n Effect.fork,\n )\n\n yield* Effect.log(\"Started OAuth2 callback server\")\n\n const search = yield* Deferred.await(deferredParams)\n yield* Effect.log(\"Received OAuth2 callback with params\", search)\n\n yield* Fiber.interrupt(serverFiber)\n\n if (state !== search.state) {\n return yield* new OAuthError({\n reason: \"state_mismatch\",\n message: \"Invalid state parameter. Possible CSRF attack.\",\n })\n }\n\n const result = yield* Effect.tryPromise({\n try: () =>\n client.getToken({\n code: search.code,\n redirect_uri: redirectUri,\n }),\n catch: (cause) =>\n new OAuthError({\n reason: \"token_exchange\",\n message: \"Failed to exchange authorization code for tokens\",\n cause,\n }),\n })\n\n return result.tokens\n }).pipe(Effect.provide(ServerLive), Effect.scoped)\n\n return { authenticate }\n }),\n}) {}\n\nexport { OAuth }\n","import {\n HttpClient,\n HttpClientRequest,\n HttpClientResponse,\n} from \"@effect/platform\"\nimport { Data, Effect, pipe, Ref, Schema } from \"effect\"\nimport { OAuth2Client } from \"google-auth-library\"\nimport type { Credentials } from \"../../types\"\nimport { CODE_ASSIST_VERSION, ProviderConfig } from \"./config\"\nimport { OpenCodeContext } from \"./opencode\"\n\nexport class SessionError extends Data.TaggedError(\"SessionError\")<{\n readonly reason:\n | \"project_fetch\"\n | \"token_refresh\"\n | \"no_tokens\"\n | \"unauthorized\"\n readonly message: string\n readonly cause?: unknown\n}> {}\n\nexport class TokenExpiredError extends Data.TaggedError(\"TokenExpiredError\")<{\n readonly message?: string\n}> {}\n\nconst CodeAssistTier = Schema.Struct({\n id: Schema.String,\n name: Schema.String,\n description: Schema.String,\n userDefinedCloudaicompanionProject: Schema.Boolean,\n isDefault: Schema.optional(Schema.Boolean),\n})\n\nconst LoadCodeAssistResponse = Schema.Struct({\n currentTier: CodeAssistTier,\n allowedTiers: Schema.Array(CodeAssistTier),\n cloudaicompanionProject: Schema.String,\n gcpManaged: Schema.Boolean,\n manageSubscriptionUri: Schema.String,\n})\n\nexport type LoadCodeAssistResponse = typeof LoadCodeAssistResponse.Type\n\nexport class Session extends Effect.Service<Session>()(\"Session\", {\n effect: Effect.gen(function* () {\n const config = yield* ProviderConfig\n const openCode = yield* OpenCodeContext\n const httpClient = yield* HttpClient.HttpClient\n\n const credentialsRef = yield* Ref.make<Credentials | null>(null)\n const projectRef = yield* Ref.make<LoadCodeAssistResponse | null>(null)\n\n const endpoint = config.ENDPOINTS.at(0) as string\n const oauthClient = new OAuth2Client({\n clientId: config.CLIENT_ID,\n clientSecret: config.CLIENT_SECRET,\n })\n\n const getCredentials = Effect.gen(function* () {\n const current = yield* Ref.get(credentialsRef)\n if (!current) {\n return yield* new SessionError({\n reason: \"no_tokens\",\n message: \"No credentials set\",\n })\n }\n\n return current\n })\n\n const refreshTokens = Effect.gen(function* () {\n const credentials = yield* getCredentials\n oauthClient.setCredentials(credentials)\n\n const result = yield* Effect.tryPromise({\n try: () => oauthClient.refreshAccessToken(),\n catch: (cause) =>\n new SessionError({\n reason: \"token_refresh\",\n message: \"Failed to refresh access token\",\n cause,\n }),\n })\n\n const newCredentials = result.credentials\n yield* Ref.set(credentialsRef, newCredentials as Credentials)\n\n const accessToken = newCredentials.access_token\n const refreshToken = newCredentials.refresh_token\n const expiryDate = newCredentials.expiry_date\n\n if (accessToken && refreshToken && expiryDate) {\n yield* Effect.promise(() =>\n openCode.client.auth.set({\n path: { id: config.SERVICE_NAME },\n body: {\n type: \"oauth\",\n access: accessToken,\n refresh: refreshToken,\n expires: expiryDate,\n },\n }),\n )\n }\n\n return newCredentials\n })\n\n const fetchAttempt = Effect.gen(function* () {\n const credentials = yield* getCredentials\n\n const request = yield* HttpClientRequest.post(\n `${endpoint}/${CODE_ASSIST_VERSION}:loadCodeAssist`,\n ).pipe(\n HttpClientRequest.bearerToken(credentials.access_token),\n HttpClientRequest.bodyJson({\n metadata: {\n ideType: \"IDE_UNSPECIFIED\",\n platform: \"PLATFORM_UNSPECIFIED\",\n pluginType: \"GEMINI\",\n },\n }),\n )\n\n return yield* pipe(\n httpClient.execute(request),\n Effect.andThen(\n HttpClientResponse.matchStatus({\n \"2xx\": (res) =>\n HttpClientResponse.schemaBodyJson(LoadCodeAssistResponse)(res),\n 401: () => new TokenExpiredError({ message: \"Token expired\" }),\n orElse: (response) =>\n new SessionError({\n reason: \"project_fetch\",\n message: `HTTP error: ${response.status}`,\n }),\n }),\n ),\n )\n })\n\n const fetchProject = fetchAttempt.pipe(\n Effect.catchTag(\"TokenExpiredError\", () =>\n pipe(\n Effect.log(\"Token expired, refreshing...\"),\n Effect.flatMap(() => refreshTokens),\n Effect.flatMap(() => fetchAttempt),\n ),\n ),\n Effect.catchAll((error) => {\n if (error instanceof SessionError) {\n return Effect.fail(error)\n }\n return Effect.fail(\n new SessionError({\n reason: \"project_fetch\",\n message: \"Failed to fetch project\",\n cause: error,\n }),\n )\n }),\n )\n\n const ensureProject = Effect.gen(function* () {\n const cached = yield* Ref.get(projectRef)\n if (cached !== null) {\n return cached\n }\n const project = yield* fetchProject\n yield* Ref.set(projectRef, project)\n return project\n })\n\n const getAccessToken = Effect.gen(function* () {\n const currentCreds = yield* Ref.get(credentialsRef)\n\n if (!currentCreds?.access_token) {\n return yield* new SessionError({\n reason: \"no_tokens\",\n message: \"No access token available\",\n })\n }\n\n const buffer = 5 * 60 * 1000\n const isExpired = (currentCreds.expiry_date ?? 0) < Date.now() + buffer\n\n let accessToken = currentCreds.access_token\n\n if (isExpired) {\n yield* Effect.log(\"Access token expired, refreshing...\")\n const refreshed = yield* refreshTokens\n if (!refreshed.access_token) {\n return yield* new SessionError({\n reason: \"token_refresh\",\n message: \"Refresh did not return access token\",\n })\n }\n accessToken = refreshed.access_token\n }\n\n yield* ensureProject\n return accessToken\n })\n\n return {\n setCredentials: (credentials: Credentials) =>\n Ref.set(credentialsRef, credentials),\n getAccessToken,\n ensureProject,\n }\n }),\n}) {}\n","import { FetchHttpClient } from \"@effect/platform\"\nimport { BunFileSystem } from \"@effect/platform-bun\"\nimport type { PluginInput } from \"@opencode-ai/plugin\"\nimport { Layer, Logger, ManagedRuntime, pipe } from \"effect\"\nimport { combinedLogger } from \"./logger\"\nimport { ProviderConfig, type ProviderConfigShape } from \"./services/config\"\nimport { OAuth } from \"./services/oauth\"\nimport { OpenCodeContext } from \"./services/opencode\"\nimport { Session } from \"./services/session\"\n\nexport const makeRuntime = ({\n providerConfig,\n openCodeCtx,\n}: {\n providerConfig: ProviderConfigShape\n openCodeCtx: PluginInput\n}) => {\n const LoggerLive = Logger.replaceScoped(Logger.defaultLogger, combinedLogger)\n const ProviderConfigLive = Layer.succeed(ProviderConfig, providerConfig)\n const OpenCodeLive = Layer.succeed(OpenCodeContext, openCodeCtx)\n\n const MainLive = pipe(\n Layer.empty,\n Layer.provide(LoggerLive),\n Layer.provide(BunFileSystem.layer),\n Layer.merge(OAuth.Default),\n Layer.merge(Session.Default),\n Layer.provideMerge(OpenCodeLive),\n Layer.provideMerge(FetchHttpClient.layer),\n Layer.provideMerge(ProviderConfigLive),\n )\n\n return ManagedRuntime.make(MainLive)\n}\n","import { regex } from \"arkregex\"\nimport { Effect, pipe } from \"effect\"\nimport {\n CODE_ASSIST_VERSION,\n ProviderConfig,\n type RequestContext,\n} from \"../lib/services/config\"\nimport { Session } from \"../lib/services/session\"\n\nconst STREAM_ACTION = \"streamGenerateContent\"\nconst PATH_PATTERN = regex(\"/models/(?<model>[^:]+):(?<action>\\\\w+)\")\n\nexport const transformRequest = Effect.fn(\"transformRequest\")(function* (\n input: Parameters<typeof fetch>[0],\n init: Parameters<typeof fetch>[1],\n endpoint: string,\n) {\n const config = yield* ProviderConfig\n const session = yield* Session\n const accessToken = yield* session.getAccessToken\n const project = yield* session.ensureProject\n const projectId = project.cloudaicompanionProject\n\n const url = new URL(input instanceof Request ? input.url : input)\n\n // Rewrite the URL to use the specified endpoint\n const endpointUrl = new URL(endpoint)\n url.protocol = endpointUrl.protocol\n url.host = endpointUrl.host\n\n const match = PATH_PATTERN.exec(url.pathname)\n if (!match) {\n return {\n input: url.toString(),\n init: init ?? {},\n streaming: false,\n }\n }\n\n const { model, action } = match.groups\n const streaming = action === STREAM_ACTION\n\n // Transform URL to internal endpoint\n url.pathname = `/${CODE_ASSIST_VERSION}:${action}`\n if (streaming) {\n url.searchParams.set(\"alt\", \"sse\")\n }\n\n // Transform headers\n const headers = new Headers(init?.headers)\n headers.delete(\"x-api-key\")\n // headers.delete(\"x-goog-api-key\")\n headers.set(\"x-opencode-tools-debug\", \"1\")\n headers.set(\"Authorization\", `Bearer ${accessToken}`)\n\n for (const [key, value] of Object.entries(config.HEADERS)) {\n headers.set(key, value)\n }\n\n if (streaming) {\n headers.set(\"Accept\", \"text/event-stream\")\n }\n\n // Wrap and transform request\n const isJson = typeof init?.body === \"string\"\n const parsedBody = yield* pipe(\n Effect.try(() => (isJson ? JSON.parse(init.body as string) : null)),\n Effect.orElseSucceed(() => null),\n )\n\n const wrappedBody = {\n project: projectId,\n model,\n request: parsedBody ?? {},\n }\n\n const {\n body: transformedBody,\n headers: finalHeaders,\n url: finalUrl,\n } =\n config.transformRequest ?\n yield* config.transformRequest({\n body: wrappedBody,\n headers,\n url,\n } satisfies RequestContext)\n : { body: wrappedBody, headers, url }\n\n const finalBody =\n isJson && parsedBody ? JSON.stringify(transformedBody) : init?.body\n\n return {\n input: finalUrl.toString(),\n init: {\n ...init,\n headers: finalHeaders,\n body: finalBody,\n },\n streaming,\n }\n})\n","export const transformNonStreamingResponse = async (\n response: Response,\n): Promise<Response> => {\n const contentType = response.headers.get(\"content-type\")\n\n if (!contentType?.includes(\"application/json\")) {\n return response\n }\n\n try {\n const cloned = response.clone()\n const parsed = (await cloned.json()) as { response?: unknown }\n\n if (parsed.response !== undefined) {\n const { response: responseData, ...rest } = parsed\n return new Response(JSON.stringify({ ...rest, ...responseData }), {\n status: response.status,\n statusText: response.statusText,\n headers: response.headers,\n })\n }\n } catch {\n // Return original if parse fails\n }\n\n return response\n}\n","import {\n encoder,\n type Event,\n makeChannel,\n Retry,\n} from \"@effect/experimental/Sse\"\nimport { pipe, Stream } from \"effect\"\n\nconst parseAndMerge = (event: Event): string => {\n if (!event.data) {\n return encoder.write(event)\n }\n\n try {\n const parsed = JSON.parse(event.data) as {\n response?: Record<string, unknown>\n }\n if (parsed.response) {\n const { response, ...rest } = parsed\n return encoder.write({\n ...event,\n data: JSON.stringify({ ...rest, ...response }),\n })\n }\n\n return encoder.write(event)\n } catch {\n return encoder.write(event)\n }\n}\n\nconst parseSSE = (body: ReadableStream<Uint8Array>) =>\n pipe(\n Stream.fromReadableStream(\n () => body,\n (error) => error,\n ),\n Stream.decodeText,\n Stream.pipeThroughChannel(makeChannel()),\n Stream.map((event) =>\n Retry.is(event) ? encoder.write(event) : parseAndMerge(event),\n ),\n Stream.encodeText,\n )\n\nexport const transformStreamingResponse = (response: Response) => {\n if (!response.body) {\n return response\n }\n\n const transformed = parseSSE(response.body)\n const readable = Stream.toReadableStream(\n transformed as Stream.Stream<Uint8Array, never, never>,\n )\n\n return new Response(readable, {\n status: response.status,\n statusText: response.statusText,\n headers: response.headers,\n })\n}\n","import type {\n GoogleGenerativeAIProviderOptions,\n GoogleGenerativeAIProviderSettings,\n} from \"@ai-sdk/google\"\nimport { HttpClient } from \"@effect/platform\"\nimport type { Plugin } from \"@opencode-ai/plugin\"\nimport { Effect } from \"effect\"\nimport { makeRuntime } from \"./lib/runtime\"\nimport {\n antigravityConfig,\n geminiCliConfig,\n ProviderConfig,\n} from \"./lib/services/config\"\nimport { OAuth } from \"./lib/services/oauth\"\nimport { Session } from \"./lib/services/session\"\nimport { transformRequest } from \"./transform/request\"\nimport { transformNonStreamingResponse } from \"./transform/response\"\nimport { transformStreamingResponse } from \"./transform/stream\"\nimport type { Credentials, ModelsDev } from \"./types\"\n\nconst fetchModelsDev = Effect.gen(function* () {\n const client = yield* HttpClient.HttpClient\n const response = yield* client.get(\"https://models.dev/api.json\")\n return (yield* response.json) as ModelsDev\n})\n\nconst customFetch = Effect.fn(function* (\n input: Parameters<typeof fetch>[0],\n init: Parameters<typeof fetch>[1],\n) {\n const config = yield* ProviderConfig\n\n let lastResponse: Response | null = null\n\n for (const endpoint of config.ENDPOINTS) {\n const result = yield* transformRequest(input, init, endpoint)\n\n const { request, ...loggedBody } = JSON.parse(result.init.body as string)\n const generationConfig = request.generationConfig\n\n yield* Effect.log(\n \"Transformed request (Omitting request except generationConfig) :\",\n result.streaming,\n result.input,\n { ...loggedBody, request: { generationConfig } },\n )\n\n const response = yield* Effect.promise(() =>\n fetch(result.input, result.init),\n )\n\n // On 429 or 403, try next endpoint\n if (response.status === 429 || response.status === 403) {\n yield* Effect.log(`${response.status} on ${endpoint}, trying next...`)\n lastResponse = response\n continue\n }\n\n if (!response.ok) {\n const cloned = response.clone()\n const clonedJson = yield* Effect.promise(() => cloned.json())\n\n yield* Effect.log(\n \"Received response:\",\n cloned.status,\n clonedJson,\n cloned.headers,\n )\n }\n\n return result.streaming ?\n transformStreamingResponse(response)\n : yield* Effect.promise(() => transformNonStreamingResponse(response))\n }\n\n // All endpoints exhausted with 429\n yield* Effect.logWarning(\"All endpoints rate limited (429)\")\n return lastResponse as Response\n}, Effect.tapDefect(Effect.logError))\n\nexport const geminiCli: Plugin = async (context) => {\n const runtime = makeRuntime({\n openCodeCtx: context,\n providerConfig: geminiCliConfig(),\n })\n\n const config = await runtime.runPromise(\n Effect.gen(function* () {\n const providerConfig = yield* ProviderConfig\n const modelsDev = yield* fetchModelsDev\n\n return providerConfig.getConfig(modelsDev)\n }),\n )\n\n return {\n config: async (cfg) => {\n cfg.provider ??= {}\n cfg.provider[config.id as string] = config\n },\n auth: {\n provider: config.id as string,\n loader: async (getAuth) => {\n const auth = await getAuth()\n if (auth.type !== \"oauth\") return {}\n\n const credentials: Credentials = {\n access_token: auth.access,\n refresh_token: auth.refresh,\n expiry_date: auth.expires,\n }\n\n await runtime.runPromise(\n Effect.gen(function* () {\n const session = yield* Session\n yield* session.setCredentials(credentials)\n }),\n )\n\n return {\n apiKey: \"\",\n fetch: (async (input, init) => {\n const response = await runtime.runPromise(customFetch(input, init))\n return response\n }) as typeof fetch,\n } satisfies GoogleGenerativeAIProviderSettings\n },\n methods: [\n {\n type: \"oauth\",\n label: \"OAuth with Google\",\n authorize: async () => {\n const result = await runtime.runPromise(\n Effect.gen(function* () {\n const oauth = yield* OAuth\n return yield* oauth.authenticate\n }),\n )\n\n return {\n url: \"\",\n method: \"auto\",\n instructions: \"You are now authenticated!\",\n callback: async () => {\n const accessToken = result.access_token\n const refreshToken = result.refresh_token\n const expiryDate = result.expiry_date\n\n if (!accessToken || !refreshToken || !expiryDate) {\n return { type: \"failed\" }\n }\n\n return {\n type: \"success\",\n provider: config.id as string,\n access: accessToken,\n refresh: refreshToken,\n expires: expiryDate,\n }\n },\n }\n },\n },\n ],\n },\n }\n}\n\nexport const antigravity: Plugin = async (context) => {\n const runtime = makeRuntime({\n openCodeCtx: context,\n providerConfig: antigravityConfig(),\n })\n\n const config = await runtime.runPromise(\n Effect.gen(function* () {\n const providerConfig = yield* ProviderConfig\n const modelsDev = yield* fetchModelsDev\n\n return providerConfig.getConfig(modelsDev)\n }),\n )\n\n return {\n config: async (cfg) => {\n cfg.provider ??= {}\n cfg.provider[config.id as string] = config\n },\n auth: {\n provider: config.id as string,\n loader: async (getAuth) => {\n const auth = await getAuth()\n if (auth.type !== \"oauth\") return {}\n\n const credentials: Credentials = {\n access_token: auth.access,\n refresh_token: auth.refresh,\n expiry_date: auth.expires,\n }\n\n await runtime.runPromise(\n Effect.gen(function* () {\n const session = yield* Session\n yield* session.setCredentials(credentials)\n }),\n )\n\n return {\n apiKey: \"\",\n fetch: (async (input, init) => {\n const response = await runtime.runPromise(customFetch(input, init))\n return response\n }) as typeof fetch,\n } satisfies GoogleGenerativeAIProviderSettings\n },\n methods: [\n {\n type: \"oauth\",\n label: \"OAuth with Google\",\n authorize: async () => {\n const result = await runtime.runPromise(\n Effect.gen(function* () {\n const oauth = yield* OAuth\n return yield* oauth.authenticate\n }),\n )\n\n return {\n url: \"\",\n method: \"auto\",\n instructions: \"You are now authenticated!\",\n callback: async () => {\n const accessToken = result.access_token\n const refreshToken = result.refresh_token\n const expiryDate = result.expiry_date\n\n if (!accessToken || !refreshToken || !expiryDate) {\n return { type: \"failed\" }\n }\n\n return {\n type: \"success\",\n provider: config.id as string,\n access: accessToken,\n refresh: refreshToken,\n expires: expiryDate,\n }\n },\n }\n },\n },\n ],\n },\n \"chat.params\": async (input, output) => {\n await runtime.runPromise(\n Effect.log(\"chat.params event before:\", input.model, output.options),\n )\n\n if (input.model.providerID === config.id) {\n output.options = {\n ...output.options,\n labels: {\n sessionId: input.sessionID,\n },\n } satisfies GoogleGenerativeAIProviderOptions\n }\n\n await runtime.runPromise(\n Effect.log(\"chat.params event after:\", input.model, output.options),\n )\n },\n }\n}\n"],"mappings":"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"}
|
|
File without changes
|