@llm4ts/runner 2.42.0 → 2.43.0

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.
@@ -0,0 +1,56 @@
1
+ import * as Effect from "effect/Effect";
2
+ import type * as Scope from "effect/Scope";
3
+ import { InvalidRequestError, ProviderError } from "@llm4ts/core/Errors";
4
+ import type { ProcessExecutorShape } from "@llm4ts/core/ProcessExecutor";
5
+ import type { TemporaryFilesShape } from "@llm4ts/core/TemporaryFiles";
6
+ import { type ModelReply, type OpenAiUsage } from "@llm4ts/core/providers/GeminiModelBridge";
7
+ /**
8
+ * The bridge's model route (ADR 0037): `/v1/chat/completions` in OpenAI's
9
+ * shape, for pi's `"api": "openai-completions"` custom provider. Each
10
+ * request is one `gemini` call with Gemini CLI's own agent switched off —
11
+ * pi's system prompt in place of Gemini's (`GEMINI_SYSTEM_MD`), every tool
12
+ * denied by an admin policy, sub-agents off in the system settings — so
13
+ * Gemini answers as a plain model and pi runs its own tools. Only Gemini
14
+ * CLI talks to Google, under its own login; this module never reads or
15
+ * forwards a credential.
16
+ */
17
+ export interface GeminiModelCallConfig {
18
+ readonly executor: ProcessExecutorShape;
19
+ readonly temporaryFiles: TemporaryFilesShape;
20
+ /** Where `gemini` runs: an empty directory, so no project GEMINI.md is read. */
21
+ readonly cwd: string;
22
+ /** The Gemini model, overriding the one pi's request names (`LLM4TS_GEMINI_MODEL`). */
23
+ readonly model?: string;
24
+ readonly envVars?: Readonly<Record<string, string>>;
25
+ }
26
+ export interface GeminiModelBridgeConfig extends GeminiModelCallConfig {
27
+ readonly port: number;
28
+ /**
29
+ * `.toml` files in Gemini CLI's standard system policy directory: with
30
+ * any, the CLI ignores `--admin-policy`, so the tools would stay in view.
31
+ * Default: what is on this machine (`systemAdminPolicies`).
32
+ */
33
+ readonly systemPolicies?: ReadonlyArray<string>;
34
+ }
35
+ export interface RunningGeminiModelBridge {
36
+ readonly port: number;
37
+ readonly baseUrl: string;
38
+ }
39
+ /** The standard directories Gemini CLI reads system (admin) policies from. */
40
+ export declare const systemPolicyDirectories: ReadonlyArray<string>;
41
+ /** The admin policy files on this machine that would make Gemini CLI ignore `--admin-policy`. */
42
+ export declare const systemAdminPolicies: () => ReadonlyArray<string>;
43
+ export declare const systemPolicyProblem: (policies: ReadonlyArray<string>) => string;
44
+ export interface ChatCompletionOutcome {
45
+ readonly model: string;
46
+ readonly reply: ModelReply;
47
+ readonly usage: OpenAiUsage;
48
+ }
49
+ /**
50
+ * One chat completion: a `gemini` call, and a second one only when the
51
+ * first reply holds a tool call that cannot be used — the model then sees
52
+ * its reply and why. A second bad reply goes back to pi as text.
53
+ */
54
+ export declare const handleChatCompletion: (config: GeminiModelCallConfig, body: import("effect/Schema").Json) => Effect.Effect<ChatCompletionOutcome, ProviderError | import("@llm4ts/core/Errors").UsageLimitError | import("@llm4ts/core/Errors").AuthenticationError | InvalidRequestError | import("@llm4ts/core/Errors").ParseError | import("@llm4ts/core/Errors").ToolError | import("@llm4ts/core/Errors").ConfigError | import("@llm4ts/core/Errors").RateLimitError | import("@llm4ts/core/Errors").TimeoutError | import("@llm4ts/core/Errors").TurnLimitError, never>;
55
+ export declare const runGeminiModelBridge: (config: GeminiModelBridgeConfig) => Effect.Effect<RunningGeminiModelBridge, ProviderError | import("@llm4ts/core/Errors").UsageLimitError | import("@llm4ts/core/Errors").AuthenticationError | InvalidRequestError | import("@llm4ts/core/Errors").ParseError | import("@llm4ts/core/Errors").ToolError | import("@llm4ts/core/Errors").ConfigError | import("@llm4ts/core/Errors").RateLimitError | import("@llm4ts/core/Errors").TimeoutError | import("@llm4ts/core/Errors").TurnLimitError, Scope.Scope>;
56
+ //# sourceMappingURL=NodeGeminiModelBridge.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NodeGeminiModelBridge.d.ts","sourceRoot":"","sources":["../src/NodeGeminiModelBridge.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AACvC,OAAO,KAAK,KAAK,KAAK,MAAM,cAAc,CAAA;AAE1C,OAAO,EAAE,mBAAmB,EAAE,aAAa,EAAiB,MAAM,qBAAqB,CAAA;AACvF,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,8BAA8B,CAAA;AACxE,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAA;AAGtE,OAAO,EAYL,KAAK,UAAU,EACf,KAAK,WAAW,EACjB,MAAM,0CAA0C,CAAA;AAUjD;;;;;;;;;GASG;AAEH,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,QAAQ,EAAE,oBAAoB,CAAA;IACvC,QAAQ,CAAC,cAAc,EAAE,mBAAmB,CAAA;IAC5C,gFAAgF;IAChF,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;IACpB,uFAAuF;IACvF,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,OAAO,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAA;CACpD;AAED,MAAM,WAAW,uBAAwB,SAAQ,qBAAqB;IACpE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB;;;;OAIG;IACH,QAAQ,CAAC,cAAc,CAAC,EAAE,aAAa,CAAC,MAAM,CAAC,CAAA;CAChD;AAED,MAAM,WAAW,wBAAwB;IACvC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;CACzB;AAED,8EAA8E;AAC9E,eAAO,MAAM,uBAAuB,EAAE,aAAa,CAAC,MAAM,CAIzD,CAAA;AAED,iGAAiG;AACjG,eAAO,MAAM,mBAAmB,QAAO,aAAa,CAAC,MAAM,CAWvD,CAAA;AAEJ,eAAO,MAAM,mBAAmB,GAAI,UAAU,aAAa,CAAC,MAAM,CAAC,KAAG,MAMzD,CAAA;AA2Gb,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAA;IAC1B,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAA;CAC5B;AAED;;;;GAIG;AACH,eAAO,MAAM,oBAAoB,ygBAoChC,CAAA;AA0BD,eAAO,MAAM,oBAAoB,gfAuEhC,CAAA"}
@@ -0,0 +1,206 @@
1
+ import { existsSync, readdirSync } from "node:fs";
2
+ import { join } from "node:path";
3
+ import * as Effect from "effect/Effect";
4
+ import * as Stream from "effect/Stream";
5
+ import { InvalidRequestError, ProviderError } from "@llm4ts/core/Errors";
6
+ import { parseGeminiCliStreamEvent } from "@llm4ts/core/providers/GeminiCliProvider";
7
+ import { chatRequestFrom, completionChunks, completionJson, correctionTranscript, denyAllToolsPolicyToml, modelModeSettingsJson, openAiUsage, parseModelReply, systemFileFor, transcriptFor } from "@llm4ts/core/providers/GeminiModelBridge";
8
+ import { acquireServer, errorStatus, parseJsonBody, readBody, requestPath, writeJson } from "./NodeGeminiAcpBridge.js";
9
+ /** The standard directories Gemini CLI reads system (admin) policies from. */
10
+ export const systemPolicyDirectories = [
11
+ "/etc/gemini-cli/policies",
12
+ "/Library/Application Support/GeminiCli/policies",
13
+ "C:\\ProgramData\\gemini-cli\\policies"
14
+ ];
15
+ /** The admin policy files on this machine that would make Gemini CLI ignore `--admin-policy`. */
16
+ export const systemAdminPolicies = () => systemPolicyDirectories.flatMap((directory) => {
17
+ try {
18
+ return existsSync(directory)
19
+ ? readdirSync(directory)
20
+ .filter((file) => file.endsWith(".toml"))
21
+ .map((file) => join(directory, file))
22
+ : [];
23
+ }
24
+ catch {
25
+ return [];
26
+ }
27
+ });
28
+ export const systemPolicyProblem = (policies) => [
29
+ `Gemini CLI has system admin policies (${policies.join(", ")}), so it ignores the`,
30
+ "--admin-policy the model bridge relies on to take every tool out of the model's view.",
31
+ "The bridge will not run Gemini with its tools still in reach (ADR 0037); use",
32
+ "LLM4TS_GEMINI_BRIDGE_MODE=acp, or ask the administrator to allow this policy."
33
+ ].join(" ");
34
+ /** One `gemini` call over `transcript`, its system file and lock-down written for the call. */
35
+ const geminiTurn = (config, model, system, transcript) => Effect.scoped(Effect.gen(function* () {
36
+ const systemFile = yield* config.temporaryFiles.write("gemini-system-", ".md", system);
37
+ const settings = yield* config.temporaryFiles.write("gemini-settings-", ".json", modelModeSettingsJson);
38
+ const policy = yield* config.temporaryFiles.write("gemini-deny-all-", ".toml", denyAllToolsPolicyToml);
39
+ const events = yield* Stream.runCollect(config.executor
40
+ .runStreamingWithStdin([
41
+ "gemini",
42
+ // Bound to its flag, so it can never read as a flag of its own.
43
+ `--model=${model}`,
44
+ "--output-format",
45
+ "stream-json",
46
+ "-e",
47
+ "none",
48
+ "--admin-policy",
49
+ policy
50
+ ], config.cwd, {
51
+ ...config.envVars,
52
+ GEMINI_CLI_TRUST_WORKSPACE: "true",
53
+ GEMINI_SYSTEM_MD: systemFile,
54
+ GEMINI_CLI_SYSTEM_SETTINGS_PATH: settings
55
+ }, transcript)
56
+ .pipe(Stream.map(parseGeminiCliStreamEvent)));
57
+ let text = "";
58
+ let tokens;
59
+ for (const event of events) {
60
+ switch (event._tag) {
61
+ case "Message":
62
+ if (event.role === "assistant" && event.content !== undefined) {
63
+ text += event.content;
64
+ }
65
+ break;
66
+ case "Error":
67
+ return yield* ProviderError.make({
68
+ message: `gemini: ${event.message ?? "error"}`
69
+ });
70
+ case "Result":
71
+ if (event.status === "error") {
72
+ return yield* ProviderError.make({
73
+ message: `gemini: ${event.errorMessage ?? "the call failed"}`
74
+ });
75
+ }
76
+ tokens =
77
+ event.stats === undefined
78
+ ? undefined
79
+ : {
80
+ ...(event.stats.inputTokens === undefined
81
+ ? {}
82
+ : { inputTokens: event.stats.inputTokens }),
83
+ ...(event.stats.outputTokens === undefined
84
+ ? {}
85
+ : { outputTokens: event.stats.outputTokens }),
86
+ ...(event.stats.cached === undefined ? {} : { cached: event.stats.cached })
87
+ };
88
+ break;
89
+ default:
90
+ break;
91
+ }
92
+ }
93
+ return { text, tokens };
94
+ }));
95
+ const addTokens = (left, right) => ({
96
+ inputTokens: (left?.inputTokens ?? 0) + (right?.inputTokens ?? 0),
97
+ outputTokens: (left?.outputTokens ?? 0) + (right?.outputTokens ?? 0),
98
+ cached: (left?.cached ?? 0) + (right?.cached ?? 0)
99
+ });
100
+ /** The largest request the bridge reads: a long conversation, not an unbounded upload. */
101
+ const maxRequestBytes = 32 * 1024 * 1024;
102
+ /** What a Gemini model id looks like: `gemini-3.8-flash`, `gemini-2.5-pro-001`. */
103
+ const modelName = /^[A-Za-z0-9][A-Za-z0-9._:-]*$/u;
104
+ /**
105
+ * One chat completion: a `gemini` call, and a second one only when the
106
+ * first reply holds a tool call that cannot be used — the model then sees
107
+ * its reply and why. A second bad reply goes back to pi as text.
108
+ */
109
+ export const handleChatCompletion = Effect.fn("@llm4ts/runner/NodeGeminiModelBridge.handle")(function* (config, body) {
110
+ const request = chatRequestFrom(body);
111
+ if (request._tag === "Invalid") {
112
+ return yield* InvalidRequestError.make({ message: request.reason });
113
+ }
114
+ const model = config.model ?? request.model;
115
+ // The model reaches Gemini CLI's arguments: a name only, never a flag.
116
+ if (!modelName.test(model)) {
117
+ return yield* InvalidRequestError.make({
118
+ message: `"${model}" is not a model name (letters, digits, . _ : -, starting with a letter or digit)`
119
+ });
120
+ }
121
+ const system = systemFileFor(request);
122
+ const transcript = transcriptFor(request.messages);
123
+ const toolNames = request.tools.map((tool) => tool.name);
124
+ const first = yield* geminiTurn(config, model, system, transcript);
125
+ const reply = parseModelReply(first.text, toolNames);
126
+ if (reply._tag !== "Malformed") {
127
+ return { model, reply, usage: openAiUsage(first.tokens) };
128
+ }
129
+ const second = yield* geminiTurn(config, model, system, correctionTranscript(transcript, first.text, reply.error));
130
+ return {
131
+ model,
132
+ reply: parseModelReply(second.text, toolNames),
133
+ usage: openAiUsage(addTokens(first.tokens, second.tokens))
134
+ };
135
+ });
136
+ let completions = 0;
137
+ const nextIds = () => {
138
+ completions += 1;
139
+ return { id: `chatcmpl-llm4ts-${completions}`, callId: `call_llm4ts_${completions}` };
140
+ };
141
+ const writeChunks = (response, chunks) => {
142
+ response.writeHead(200, {
143
+ "Content-Type": "text/event-stream",
144
+ "Cache-Control": "no-cache",
145
+ Connection: "keep-alive"
146
+ });
147
+ for (const chunk of chunks) {
148
+ response.write(`data: ${JSON.stringify(chunk)}\n\n`);
149
+ }
150
+ response.write("data: [DONE]\n\n");
151
+ response.end();
152
+ };
153
+ const streamWanted = (body) => {
154
+ const request = chatRequestFrom(body);
155
+ return request._tag === "Request" && request.stream;
156
+ };
157
+ export const runGeminiModelBridge = Effect.fn("@llm4ts/runner/NodeGeminiModelBridge.run")(function* (config) {
158
+ const policies = config.systemPolicies ?? systemAdminPolicies();
159
+ if (policies.length > 0) {
160
+ return yield* ProviderError.make({ message: systemPolicyProblem(policies) });
161
+ }
162
+ const listener = (request, response) => {
163
+ if (request.method !== "POST" || requestPath(request.url) !== "/v1/chat/completions") {
164
+ writeJson(response, 404, { error: { message: "not found" } });
165
+ return;
166
+ }
167
+ // pi posts JSON from Node, with no Origin. A browser page posting to
168
+ // this loopback port (a cross-site form needs no preflight as
169
+ // text/plain) is refused before anything runs.
170
+ const contentType = request.headers["content-type"] ?? "";
171
+ // A DNS name rebound to 127.0.0.1 still sends its own Host.
172
+ const host = (request.headers.host ?? "").replace(/:\d+$/u, "");
173
+ if (request.headers.origin !== undefined ||
174
+ !contentType.includes("application/json") ||
175
+ !["127.0.0.1", "localhost", "[::1]"].includes(host)) {
176
+ writeJson(response, 403, {
177
+ error: { message: "the bridge answers JSON requests from local tools only" }
178
+ });
179
+ return;
180
+ }
181
+ const handled = Effect.gen(function* () {
182
+ const body = yield* parseJsonBody(yield* readBody(request, maxRequestBytes));
183
+ const outcome = yield* handleChatCompletion(config, body);
184
+ const { id, callId } = nextIds();
185
+ const created = Math.floor(Date.now() / 1000);
186
+ if (streamWanted(body)) {
187
+ return yield* Effect.sync(() => writeChunks(response, completionChunks(id, outcome.model, outcome.reply, outcome.usage, created, callId)));
188
+ }
189
+ return yield* Effect.sync(() => writeJson(response, 200, completionJson(id, outcome.model, outcome.reply, outcome.usage, created, callId)));
190
+ }).pipe(Effect.catch((error) => Effect.sync(() => {
191
+ if (!response.headersSent) {
192
+ writeJson(response, errorStatus(error), { error: { message: error.message } });
193
+ }
194
+ })));
195
+ Effect.runPromise(handled).catch((defect) => {
196
+ if (!response.headersSent) {
197
+ writeJson(response, 500, { error: { message: String(defect) } });
198
+ }
199
+ });
200
+ };
201
+ const server = yield* acquireServer(config.port, listener);
202
+ const address = server.address();
203
+ const port = address !== null && typeof address !== "string" ? address.port : config.port;
204
+ return { port, baseUrl: `http://127.0.0.1:${port}` };
205
+ });
206
+ //# sourceMappingURL=NodeGeminiModelBridge.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NodeGeminiModelBridge.js","sourceRoot":"","sources":["../src/NodeGeminiModelBridge.ts"],"names":[],"mappings":"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"}
@@ -5,6 +5,19 @@ export declare const defaultGeminiBridgePort = "8731";
5
5
  */
6
6
  export declare const defaultReadPiModelsJson: () => string | undefined;
7
7
  export declare const geminiBridgePort: (environment: Readonly<Record<string, string | undefined>>) => string;
8
+ /**
9
+ * Which route the bridge serves (ADR 0037): `acp` (ADR 0016's Anthropic
10
+ * Messages over a Gemini ACP session, the default) or `model` (OpenAI chat
11
+ * completions over one locked-down `gemini` call per request).
12
+ */
13
+ export type GeminiBridgeMode = {
14
+ readonly _tag: "Mode";
15
+ readonly mode: "acp" | "model";
16
+ } | {
17
+ readonly _tag: "Unknown";
18
+ readonly value: string;
19
+ };
20
+ export declare const geminiBridgeMode: (environment: Readonly<Record<string, string | undefined>>) => GeminiBridgeMode;
8
21
  /**
9
22
  * One value pi accepts for `--model`: `<provider>/<model>`, where the
10
23
  * provider is a key under `providers` in `~/.pi/agent/models.json` and the
@@ -1 +1 @@
1
- {"version":3,"file":"PiModels.d.ts","sourceRoot":"","sources":["../src/PiModels.ts"],"names":[],"mappings":"AAeA,eAAO,MAAM,uBAAuB,SAAS,CAAA;AAE7C;;;GAGG;AACH,eAAO,MAAM,uBAAuB,QAAO,MAAM,GAAG,SAMnD,CAAA;AAED,eAAO,MAAM,gBAAgB,GAC3B,aAAa,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC,KACxD,MAG0B,CAAA;AAE7B;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;IACpB,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAA;IACzB,QAAQ,CAAC,cAAc,EAAE,OAAO,CAAA;CACjC;AAED;;;;;GAKG;AACH,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAC,UAAU,CAAC,CAAA;IACxC,QAAQ,CAAC,QAAQ,EAAE,aAAa,CAAC,MAAM,CAAC,CAAA;CACzC;AA2BD;;;;;GAKG;AACH,eAAO,MAAM,cAAc,GAAI,YAAY,MAAM,GAAG,SAAS,EAAE,MAAM,MAAM,KAAG,cA8C7E,CAAA;AAED,8DAA8D;AAC9D,eAAO,MAAM,WAAW,GACtB,YAAY,MAAM,GAAG,SAAS,EAC9B,MAAM,MAAM,KACX,aAAa,CAAC,UAAU,CAA0C,CAAA;AAErE,wEAAwE;AACxE,eAAO,MAAM,eAAe,GAC1B,YAAY,MAAM,GAAG,SAAS,EAC9B,MAAM,MAAM,KACX,aAAa,CAAC,MAAM,CAGO,CAAA;AAE9B;;;;GAIG;AACH,MAAM,MAAM,qBAAqB,GAC7B;IAAE,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GACrD;IAAE,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC;IAAC,QAAQ,CAAC,UAAU,EAAE,aAAa,CAAC,MAAM,CAAC,CAAA;CAAE,GAC1E;IAAE,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAC;IAAC,QAAQ,CAAC,QAAQ,EAAE,aAAa,CAAC,MAAM,CAAC,CAAA;CAAE,CAAA;AAE9E,eAAO,MAAM,kBAAkB,GAC7B,YAAY,MAAM,GAAG,SAAS,EAC9B,MAAM,MAAM,EACZ,YAAY,MAAM,GAAG,SAAS,KAC7B,qBAoBF,CAAA;AAED,6EAA6E;AAC7E,eAAO,MAAM,kBAAkB,GAC7B,YAAY,qBAAqB,EACjC,MAAM,MAAM,KACX,MAAM,GAAG,SAqBX,CAAA"}
1
+ {"version":3,"file":"PiModels.d.ts","sourceRoot":"","sources":["../src/PiModels.ts"],"names":[],"mappings":"AAeA,eAAO,MAAM,uBAAuB,SAAS,CAAA;AAE7C;;;GAGG;AACH,eAAO,MAAM,uBAAuB,QAAO,MAAM,GAAG,SAMnD,CAAA;AAED,eAAO,MAAM,gBAAgB,GAC3B,aAAa,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC,KACxD,MAG0B,CAAA;AAE7B;;;;GAIG;AACH,MAAM,MAAM,gBAAgB,GACxB;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,KAAK,GAAG,OAAO,CAAA;CAAE,GACzD;IAAE,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAA;AAExD,eAAO,MAAM,gBAAgB,GAC3B,aAAa,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC,KACxD,gBAOF,CAAA;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;IACpB,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAA;IACzB,QAAQ,CAAC,cAAc,EAAE,OAAO,CAAA;CACjC;AAED;;;;;GAKG;AACH,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAC,UAAU,CAAC,CAAA;IACxC,QAAQ,CAAC,QAAQ,EAAE,aAAa,CAAC,MAAM,CAAC,CAAA;CACzC;AA2BD;;;;;GAKG;AACH,eAAO,MAAM,cAAc,GAAI,YAAY,MAAM,GAAG,SAAS,EAAE,MAAM,MAAM,KAAG,cA8C7E,CAAA;AAED,8DAA8D;AAC9D,eAAO,MAAM,WAAW,GACtB,YAAY,MAAM,GAAG,SAAS,EAC9B,MAAM,MAAM,KACX,aAAa,CAAC,UAAU,CAA0C,CAAA;AAErE,wEAAwE;AACxE,eAAO,MAAM,eAAe,GAC1B,YAAY,MAAM,GAAG,SAAS,EAC9B,MAAM,MAAM,KACX,aAAa,CAAC,MAAM,CAGO,CAAA;AAE9B;;;;GAIG;AACH,MAAM,MAAM,qBAAqB,GAC7B;IAAE,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GACrD;IAAE,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC;IAAC,QAAQ,CAAC,UAAU,EAAE,aAAa,CAAC,MAAM,CAAC,CAAA;CAAE,GAC1E;IAAE,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAC;IAAC,QAAQ,CAAC,QAAQ,EAAE,aAAa,CAAC,MAAM,CAAC,CAAA;CAAE,CAAA;AAE9E,eAAO,MAAM,kBAAkB,GAC7B,YAAY,MAAM,GAAG,SAAS,EAC9B,MAAM,MAAM,EACZ,YAAY,MAAM,GAAG,SAAS,KAC7B,qBAoBF,CAAA;AAED,6EAA6E;AAC7E,eAAO,MAAM,kBAAkB,GAC7B,YAAY,qBAAqB,EACjC,MAAM,MAAM,KACX,MAAM,GAAG,SAqBX,CAAA"}
package/dist/PiModels.js CHANGED
@@ -25,6 +25,14 @@ export const defaultReadPiModelsJson = () => {
25
25
  export const geminiBridgePort = (environment) => isSet(environment.LLM4TS_GEMINI_BRIDGE_PORT)
26
26
  ? environment.LLM4TS_GEMINI_BRIDGE_PORT.trim()
27
27
  : defaultGeminiBridgePort;
28
+ export const geminiBridgeMode = (environment) => {
29
+ const value = (environment.LLM4TS_GEMINI_BRIDGE_MODE ?? "").trim().toLowerCase();
30
+ return value === "" || value === "acp"
31
+ ? { _tag: "Mode", mode: "acp" }
32
+ : value === "model"
33
+ ? { _tag: "Mode", mode: "model" }
34
+ : { _tag: "Unknown", value };
35
+ };
28
36
  const isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
29
37
  /** Annotated rather than asserted, matching `NodeGeminiAcpBridge.parseJson`. */
30
38
  const parseJson = (raw) => {
@@ -1 +1 @@
1
- {"version":3,"file":"PiModels.js","sourceRoot":"","sources":["../src/PiModels.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"PiModels.js","sourceRoot":"","sources":["../src/PiModels.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@llm4ts/runner",
3
- "version": "2.42.0",
3
+ "version": "2.43.0",
4
4
  "description": "Node runner, CLI, terminal, and MCP composition for llm4ts",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -28,6 +28,7 @@
28
28
  "./Kits": "./dist/Kits.js",
29
29
  "./McpStdio": "./dist/McpStdio.js",
30
30
  "./NodeGeminiAcpBridge": "./dist/NodeGeminiAcpBridge.js",
31
+ "./NodeGeminiModelBridge": "./dist/NodeGeminiModelBridge.js",
31
32
  "./NodeHttpClient": "./dist/NodeHttpClient.js",
32
33
  "./NodeGeminiCliExecutor": "./dist/NodeGeminiCliExecutor.js",
33
34
  "./NodePlainFileStore": "./dist/NodePlainFileStore.js",
@@ -70,8 +71,8 @@
70
71
  "typescript"
71
72
  ],
72
73
  "dependencies": {
73
- "@llm4ts/core": "2.42.0",
74
- "@llm4ts/flow": "2.42.0"
74
+ "@llm4ts/core": "2.43.0",
75
+ "@llm4ts/flow": "2.43.0"
75
76
  },
76
77
  "peerDependencies": {
77
78
  "effect": "4.0.0"
package/src/Doctor.ts CHANGED
@@ -9,8 +9,10 @@ import { nodeProcessExecutor } from "./NodeProcessExecutor.ts"
9
9
  import {
10
10
  defaultReadPiModelsJson as readPiModels,
11
11
  geminiBridgePort as bridgePort,
12
- piModelsConfig as parsePiModels
12
+ piModelsConfig as parsePiModels,
13
+ geminiBridgeMode
13
14
  } from "./PiModels.ts"
15
+ import { systemAdminPolicies, systemPolicyProblem } from "./NodeGeminiModelBridge.ts"
14
16
  import { otelConfig, otelDoctorLine, probeOtelEndpoint, type OtelConfig } from "./Otel.ts"
15
17
 
16
18
  const credentialKeys = [
@@ -210,6 +212,50 @@ export const geminiBridgePrerequisites = (
210
212
  }
211
213
  }
212
214
 
215
+ /** Gemini CLI's own words on third-party access (0.62.0, `docs/resources/tos-privacy.md`). */
216
+ export const geminiTermsClause =
217
+ "Directly accessing the services powering Gemini CLI (for example, the Gemini Code Assist " +
218
+ "service) using third-party software, tools, or services (for example, using OpenClaw with " +
219
+ "Gemini CLI OAuth) is a violation of applicable terms and policies. Such actions may be " +
220
+ "grounds for suspension or termination of your account."
221
+
222
+ /**
223
+ * The model mode of the bridge (ADR 0037): whether a system admin policy
224
+ * would keep Gemini's tools in view, how pi's provider must be shaped, and
225
+ * the terms clause the customer confirms against. `undefined` unless the
226
+ * bridge runs in model mode.
227
+ */
228
+ export const geminiModelModePrerequisites = (
229
+ environment: Readonly<Record<string, string | undefined>>,
230
+ systemPolicies: ReadonlyArray<string>
231
+ ): PrerequisiteReport | undefined => {
232
+ const mode = geminiBridgeMode(environment)
233
+ if (!truthy(environment.LLM4TS_GEMINI_BRIDGE) || mode._tag !== "Mode" || mode.mode !== "model") {
234
+ return undefined
235
+ }
236
+ const detail = [
237
+ 'pi\'s bridge provider in ~/.pi/agent/models.json needs "api": "openai-completions"',
238
+ "(the route is /v1/chat/completions); only Gemini CLI talks to Google, under its own",
239
+ "login, and llm4ts never reads or forwards its credentials. Gemini CLI's terms say:",
240
+ ` "${geminiTermsClause}"`,
241
+ "Using Gemini CLI as a model for pi stays close to that clause: confirm with Google",
242
+ "before relying on it."
243
+ ]
244
+ return systemPolicies.length > 0
245
+ ? {
246
+ satisfied: false,
247
+ summary: `system admin policies make Gemini CLI ignore the bridge's: ${systemPolicies.join(", ")}`,
248
+ hint: systemPolicyProblem(systemPolicies),
249
+ detail
250
+ }
251
+ : {
252
+ satisfied: true,
253
+ summary:
254
+ "model mode: Gemini CLI answers as a plain model, its prompt replaced and every tool denied",
255
+ detail
256
+ }
257
+ }
258
+
213
259
  export const makeDoctorProgram = (
214
260
  registry: ConnectorRegistryShape = nodeFlowRunnerDependencies().registry,
215
261
  environment: Readonly<Record<string, string | undefined>> = process.env,
@@ -223,7 +269,9 @@ export const makeDoctorProgram = (
223
269
  environment
224
270
  ),
225
271
  /** Whether the OTLP endpoint answers (ADR 0026); the network probe by default. */
226
- probeOtel: (config: OtelConfig) => Effect.Effect<boolean | undefined> = probeOtelEndpoint
272
+ probeOtel: (config: OtelConfig) => Effect.Effect<boolean | undefined> = probeOtelEndpoint,
273
+ /** Gemini CLI's system admin policy files (ADR 0037); this machine's by default. */
274
+ systemPolicies: () => ReadonlyArray<string> = systemAdminPolicies
227
275
  ): Effect.Effect<string> => {
228
276
  const otel = otelConfig(environment)
229
277
  return Effect.map(
@@ -266,6 +314,7 @@ export const makeDoctorProgram = (
266
314
  id.value === ConnectorIds.GeminiCli.value || id.value === ConnectorIds.GeminiApi.value
267
315
  )
268
316
  const bridge = geminiBridgePrerequisites(environment, readPiModelsJson())
317
+ const modelMode = geminiModelModePrerequisites(environment, systemPolicies())
269
318
  if (geminiRelevant || bridge !== undefined) {
270
319
  lines.push("")
271
320
  lines.push("prerequisites:")
@@ -284,6 +333,9 @@ export const makeDoctorProgram = (
284
333
  if (bridge !== undefined) {
285
334
  pushReport("pi-gemini-bridge", bridge)
286
335
  }
336
+ if (modelMode !== undefined) {
337
+ pushReport("pi-gemini-bridge model mode", modelMode)
338
+ }
287
339
  }
288
340
 
289
341
  lines.push("")
package/src/FlowRunner.ts CHANGED
@@ -1,3 +1,5 @@
1
+ import { mkdtempSync, rmSync } from "node:fs"
2
+ import { tmpdir } from "node:os"
1
3
  import { join } from "node:path"
2
4
  import * as Cause from "effect/Cause"
3
5
  import * as Clock from "effect/Clock"
@@ -25,11 +27,13 @@ import { ConnectorIds } from "@llm4ts/core/Models"
25
27
  import { ProviderError } from "@llm4ts/core/Errors"
26
28
  import { makeCostTracker, type CostTracker } from "@llm4ts/flow/CostTracker"
27
29
  import { runGeminiAcpBridge } from "./NodeGeminiAcpBridge.ts"
30
+ import { runGeminiModelBridge } from "./NodeGeminiModelBridge.ts"
28
31
  import {
29
32
  bridgeModelProblem,
30
33
  defaultReadPiModelsJson,
31
34
  geminiBridgePort,
32
- resolveBridgeModel
35
+ resolveBridgeModel,
36
+ geminiBridgeMode
33
37
  } from "./PiModels.ts"
34
38
  import {
35
39
  appendCostRecord,
@@ -128,6 +132,8 @@ export interface FlowRunnerDependencies {
128
132
  readonly files: PlainFileStoreShape
129
133
  /** pi's own model config (ADR 0016), injectable so a test never reads $HOME. */
130
134
  readonly readPiModelsJson?: () => string | undefined
135
+ /** Files the Gemini model bridge writes per call (ADR 0037); temporary files on disk by default. */
136
+ readonly temporaryFiles?: TemporaryFilesShape
131
137
  /** For the hosted TypeSafe judgment backend; defaults to the Node client. */
132
138
  readonly http?: HttpClientShape
133
139
  /** Where `--transcript` writes, given its directory; files on disk by default. */
@@ -280,14 +286,38 @@ const geminiBridgeSeats = Effect.fn("@llm4ts/runner/FlowRunner.geminiBridgeSeats
280
286
  }
281
287
  const model = resolution.model
282
288
 
283
- yield* runGeminiAcpBridge({
284
- port: Number(port),
285
- cwd: options.workDir,
286
- executor: dependencies.process,
287
- ...(environment.LLM4TS_GEMINI_MODEL === undefined
288
- ? {}
289
- : { model: environment.LLM4TS_GEMINI_MODEL })
290
- }).pipe(Effect.mapError(FlowLlmError.from))
289
+ const mode = geminiBridgeMode(environment)
290
+ if (mode._tag === "Unknown") {
291
+ return yield* FlowLlmError.from(
292
+ ProviderError.make({
293
+ message: `LLM4TS_GEMINI_BRIDGE_MODE is "${mode.value}"; use acp (the default) or model`
294
+ })
295
+ )
296
+ }
297
+ const geminiModel =
298
+ environment.LLM4TS_GEMINI_MODEL === undefined ? {} : { model: environment.LLM4TS_GEMINI_MODEL }
299
+ if (mode.mode === "model") {
300
+ // ADR 0037: one locked-down `gemini` call per request, in an empty
301
+ // directory so no project GEMINI.md reaches the model.
302
+ const scratch = yield* Effect.acquireRelease(
303
+ Effect.sync(() => mkdtempSync(join(tmpdir(), "llm4ts-gemini-model-"))),
304
+ (directory) => Effect.sync(() => rmSync(directory, { recursive: true, force: true }))
305
+ )
306
+ yield* runGeminiModelBridge({
307
+ port: Number(port),
308
+ cwd: scratch,
309
+ executor: dependencies.process,
310
+ temporaryFiles: dependencies.temporaryFiles ?? nodeTemporaryFiles,
311
+ ...geminiModel
312
+ }).pipe(Effect.mapError(FlowLlmError.from))
313
+ } else {
314
+ yield* runGeminiAcpBridge({
315
+ port: Number(port),
316
+ cwd: options.workDir,
317
+ executor: dependencies.process,
318
+ ...geminiModel
319
+ }).pipe(Effect.mapError(FlowLlmError.from))
320
+ }
291
321
 
292
322
  return (config: ConnectorConfig): ConnectorConfig =>
293
323
  isPiSeat(config) && config.model === undefined
@@ -400,10 +400,23 @@ export const handleMessagesRequest = Effect.fn(
400
400
  return anthropicResponse(requestModel(body), outcome)
401
401
  })
402
402
 
403
- const readBody = (request: IncomingMessage): Effect.Effect<string, ProviderError> =>
403
+ /** Shared with the model route (`NodeGeminiModelBridge.ts`, ADR 0037). */
404
+ export const readBody = (
405
+ request: IncomingMessage,
406
+ maxBytes: number = Number.POSITIVE_INFINITY
407
+ ): Effect.Effect<string, ProviderError> =>
404
408
  Effect.callback((resume) => {
405
409
  const chunks: Array<Buffer> = []
406
- request.on("data", (chunk: Buffer) => chunks.push(chunk))
410
+ let size = 0
411
+ request.on("data", (chunk: Buffer) => {
412
+ size += chunk.length
413
+ if (size > maxBytes) {
414
+ request.destroy()
415
+ resume(Effect.fail(ProviderError.make({ message: `request body over ${maxBytes} bytes` })))
416
+ return
417
+ }
418
+ chunks.push(chunk)
419
+ })
407
420
  request.on("end", () => resume(Effect.succeed(Buffer.concat(chunks).toString("utf8"))))
408
421
  request.on("error", (error) =>
409
422
  resume(ProviderError.make({ message: "failed to read request body", cause: error }))
@@ -412,7 +425,8 @@ const readBody = (request: IncomingMessage): Effect.Effect<string, ProviderError
412
425
 
413
426
  const parseJson = (raw: string): JsonValue => JSON.parse(raw)
414
427
 
415
- const parseJsonBody = (raw: string): Effect.Effect<JsonValue, InvalidRequestError> =>
428
+ /** Shared with the model route (`NodeGeminiModelBridge.ts`, ADR 0037). */
429
+ export const parseJsonBody = (raw: string): Effect.Effect<JsonValue, InvalidRequestError> =>
416
430
  Effect.try({
417
431
  try: () => parseJson(raw),
418
432
  catch: () => InvalidRequestError.make({ message: "request body is not valid JSON" })
@@ -459,13 +473,15 @@ const respondStreaming = (
459
473
  })
460
474
  )
461
475
 
462
- const writeJson = (response: ServerResponse, status: number, body: JsonValue): void => {
476
+ /** Shared with the model route (`NodeGeminiModelBridge.ts`, ADR 0037). */
477
+ export const writeJson = (response: ServerResponse, status: number, body: JsonValue): void => {
463
478
  const text = JSON.stringify(body)
464
479
  response.writeHead(status, { "Content-Type": "application/json" })
465
480
  response.end(text)
466
481
  }
467
482
 
468
- const errorStatus = (error: LlmError | InvalidRequestError): number =>
483
+ /** Shared with the model route (`NodeGeminiModelBridge.ts`, ADR 0037). */
484
+ export const errorStatus = (error: LlmError | InvalidRequestError): number =>
469
485
  error._tag === "InvalidRequestError" ? 400 : error._tag === "AuthenticationError" ? 401 : 502
470
486
 
471
487
  export interface GeminiAcpBridgeConfig {
@@ -489,7 +505,8 @@ const bindError = (port: number, cause: unknown): ProviderError =>
489
505
  cause
490
506
  })
491
507
 
492
- const acquireServer = (
508
+ /** Shared with the model route (`NodeGeminiModelBridge.ts`, ADR 0037). */
509
+ export const acquireServer = (
493
510
  port: number,
494
511
  listener: (request: IncomingMessage, response: ServerResponse) => void
495
512
  ): Effect.Effect<Server, ProviderError, Scope.Scope> =>