coding-agents-sdk 0.0.1 → 0.2.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.
- package/README.md +242 -0
- package/dist/Agent-D8WkUilj.mjs +262 -0
- package/dist/SdkAgent-B47mJiIE.mjs +38 -0
- package/dist/adapters/claude-code-cli/index.d.mts +2 -0
- package/dist/adapters/claude-code-cli/index.mjs +490 -0
- package/dist/adapters/claude-code-sdk/index.d.mts +2 -0
- package/dist/adapters/claude-code-sdk/index.mjs +483 -0
- package/dist/adapters/codex-cli/index.d.mts +2 -0
- package/dist/adapters/codex-cli/index.mjs +626 -0
- package/dist/adapters/codex-sdk/index.d.mts +2 -0
- package/dist/adapters/codex-sdk/index.mjs +286 -0
- package/dist/adapters/gemini-cli/index.d.mts +2 -0
- package/dist/adapters/gemini-cli/index.mjs +292 -0
- package/dist/classify-error-pL6jeu4T.mjs +456 -0
- package/dist/container/index.d.mts +2 -0
- package/dist/container/index.mjs +24 -0
- package/dist/container-2UmPZ0CI.mjs +22 -0
- package/dist/container-CHxKIonn.mjs +440 -0
- package/dist/container-D2Z0ITDJ.mjs +22 -0
- package/dist/diff-De8d3MVb.mjs +333 -0
- package/dist/errors-BAmHDQu8.mjs +45 -0
- package/dist/events-nxuRbYIu.d.mts +239 -0
- package/dist/index-B3YqrgIp.d.mts +45 -0
- package/dist/index-ByAOGMUM.d.mts +224 -0
- package/dist/index-C3ZxLAd0.d.mts +315 -0
- package/dist/index-CFpNOmdA.d.mts +145 -0
- package/dist/index-dRVpEAr8.d.mts +39 -0
- package/dist/index-nzo1sBiK.d.mts +110 -0
- package/dist/index.d.mts +16 -0
- package/dist/index.mjs +61 -0
- package/dist/oci-DMZZQZ47.mjs +438 -0
- package/dist/schemas/index.d.mts +2 -0
- package/dist/schemas/index.mjs +2 -0
- package/dist/schemas-DwD4pwJB.mjs +96 -0
- package/dist/spawner-Bw9UBEGX.mjs +54 -0
- package/dist/structured-output-BHtr_zpz.mjs +19 -0
- package/dist/types-Cb_EXIEe.d.mts +177 -0
- package/dist/types-aNMD8h3x.mjs +19 -0
- package/dist/util-B4RQZkKr.mjs +77 -0
- package/package.json +86 -9
- package/index.js +0 -7
|
@@ -0,0 +1,286 @@
|
|
|
1
|
+
import { r as parseJsonResponseText } from "../../util-B4RQZkKr.mjs";
|
|
2
|
+
import { a as buildBaseProcessEnv, l as toTextPart, o as createAgentEvent, r as applyMappedEventBatch } from "../../classify-error-pL6jeu4T.mjs";
|
|
3
|
+
import { t as SdkAgent } from "../../SdkAgent-B47mJiIE.mjs";
|
|
4
|
+
import { Codex } from "@openai/codex-sdk";
|
|
5
|
+
//#region src/adapters/codex-sdk/events/mappers.ts
|
|
6
|
+
const toStats = (usage) => ({
|
|
7
|
+
turns: 1,
|
|
8
|
+
costUsd: 0,
|
|
9
|
+
inputTokens: usage.input_tokens,
|
|
10
|
+
cacheReadInputTokens: usage.cached_input_tokens,
|
|
11
|
+
outputTokens: usage.output_tokens,
|
|
12
|
+
totalTokens: usage.input_tokens + usage.cached_input_tokens + usage.output_tokens
|
|
13
|
+
});
|
|
14
|
+
const getCommandToolRecord = (item) => ({
|
|
15
|
+
toolCallId: item.id,
|
|
16
|
+
toolName: "Bash",
|
|
17
|
+
input: { command: item.command }
|
|
18
|
+
});
|
|
19
|
+
const getMcpToolRecord = (item) => ({
|
|
20
|
+
toolCallId: item.id,
|
|
21
|
+
toolName: item.tool,
|
|
22
|
+
input: {
|
|
23
|
+
server: item.server,
|
|
24
|
+
arguments: item.arguments
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
const getWebSearchToolRecord = (item) => ({
|
|
28
|
+
toolCallId: item.id,
|
|
29
|
+
toolName: "WebSearch",
|
|
30
|
+
input: { query: item.query }
|
|
31
|
+
});
|
|
32
|
+
const mapToolCallStart = (toolRecord, context, options) => ({
|
|
33
|
+
events: [createAgentEvent(context.runId, "tool-call", {
|
|
34
|
+
sessionId: context.sessionId,
|
|
35
|
+
model: options.model ?? null,
|
|
36
|
+
toolCallId: toolRecord.toolCallId,
|
|
37
|
+
toolName: toolRecord.toolName,
|
|
38
|
+
input: toolRecord.input
|
|
39
|
+
})],
|
|
40
|
+
toolCalls: [{
|
|
41
|
+
toolCallId: toolRecord.toolCallId,
|
|
42
|
+
toolName: toolRecord.toolName,
|
|
43
|
+
input: toolRecord.input
|
|
44
|
+
}]
|
|
45
|
+
});
|
|
46
|
+
const mapToolResultCompletion = (toolRecord, output, errorState, context, options) => {
|
|
47
|
+
const priorToolCall = context.toolCalls.get(toolRecord.toolCallId);
|
|
48
|
+
const resolvedTool = priorToolCall ?? toolRecord;
|
|
49
|
+
const events = [];
|
|
50
|
+
const toolCalls = [];
|
|
51
|
+
if (!priorToolCall) {
|
|
52
|
+
events.push(createAgentEvent(context.runId, "tool-call", {
|
|
53
|
+
sessionId: context.sessionId,
|
|
54
|
+
model: options.model ?? null,
|
|
55
|
+
toolCallId: toolRecord.toolCallId,
|
|
56
|
+
toolName: toolRecord.toolName,
|
|
57
|
+
input: toolRecord.input
|
|
58
|
+
}));
|
|
59
|
+
toolCalls.push({
|
|
60
|
+
toolCallId: toolRecord.toolCallId,
|
|
61
|
+
toolName: toolRecord.toolName,
|
|
62
|
+
input: toolRecord.input
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
events.push(createAgentEvent(context.runId, "tool-result", {
|
|
66
|
+
sessionId: context.sessionId,
|
|
67
|
+
toolCallId: toolRecord.toolCallId,
|
|
68
|
+
toolName: resolvedTool.toolName,
|
|
69
|
+
input: resolvedTool.input,
|
|
70
|
+
output,
|
|
71
|
+
isError: errorState.isError || void 0,
|
|
72
|
+
error: errorState.error
|
|
73
|
+
}));
|
|
74
|
+
return {
|
|
75
|
+
events,
|
|
76
|
+
toolCalls: toolCalls.length > 0 ? toolCalls : void 0
|
|
77
|
+
};
|
|
78
|
+
};
|
|
79
|
+
const getCommandErrorState = (item) => {
|
|
80
|
+
const isError = item.status === "failed" || item.exit_code !== void 0 && item.exit_code !== 0;
|
|
81
|
+
return {
|
|
82
|
+
isError,
|
|
83
|
+
error: isError ? `Command exited with code ${item.exit_code ?? 1}.` : void 0
|
|
84
|
+
};
|
|
85
|
+
};
|
|
86
|
+
const getMcpOutput = (item) => item.result?.structured_content ?? item.result?.content ?? item.error?.message ?? "";
|
|
87
|
+
const getMcpErrorState = (item) => ({
|
|
88
|
+
isError: item.status === "failed" || item.error !== void 0,
|
|
89
|
+
error: item.error?.message
|
|
90
|
+
});
|
|
91
|
+
const mapErrorItem = (item, context) => ({
|
|
92
|
+
events: [createAgentEvent(context.runId, "stderr", {
|
|
93
|
+
sessionId: context.sessionId,
|
|
94
|
+
text: item.message
|
|
95
|
+
})],
|
|
96
|
+
state: { error: {
|
|
97
|
+
kind: "provider",
|
|
98
|
+
message: item.message
|
|
99
|
+
} }
|
|
100
|
+
});
|
|
101
|
+
const mapItemStartedEvent = (event, context, options) => {
|
|
102
|
+
switch (event.item.type) {
|
|
103
|
+
case "command_execution": return mapToolCallStart(getCommandToolRecord(event.item), context, options);
|
|
104
|
+
case "mcp_tool_call": return mapToolCallStart(getMcpToolRecord(event.item), context, options);
|
|
105
|
+
case "web_search": return mapToolCallStart(getWebSearchToolRecord(event.item), context, options);
|
|
106
|
+
default: return { events: [] };
|
|
107
|
+
}
|
|
108
|
+
};
|
|
109
|
+
const mapItemCompletedEvent = (event, context, options) => {
|
|
110
|
+
switch (event.item.type) {
|
|
111
|
+
case "agent_message": return {
|
|
112
|
+
events: [createAgentEvent(context.runId, "message", {
|
|
113
|
+
sessionId: context.sessionId,
|
|
114
|
+
model: options.model ?? null,
|
|
115
|
+
role: "assistant",
|
|
116
|
+
content: [toTextPart(event.item.text)],
|
|
117
|
+
text: event.item.text
|
|
118
|
+
})],
|
|
119
|
+
state: { output: { text: event.item.text } }
|
|
120
|
+
};
|
|
121
|
+
case "reasoning": return { events: [createAgentEvent(context.runId, "reasoning", {
|
|
122
|
+
sessionId: context.sessionId,
|
|
123
|
+
model: options.model ?? null,
|
|
124
|
+
content: [toTextPart(event.item.text)],
|
|
125
|
+
text: event.item.text
|
|
126
|
+
})] };
|
|
127
|
+
case "command_execution": return mapToolResultCompletion(getCommandToolRecord(event.item), event.item.aggregated_output, getCommandErrorState(event.item), context, options);
|
|
128
|
+
case "mcp_tool_call": return mapToolResultCompletion(getMcpToolRecord(event.item), getMcpOutput(event.item), getMcpErrorState(event.item), context, options);
|
|
129
|
+
case "web_search": return mapToolResultCompletion(getWebSearchToolRecord(event.item), "", { isError: false }, context, options);
|
|
130
|
+
case "error": return mapErrorItem(event.item, context);
|
|
131
|
+
default: return { events: [] };
|
|
132
|
+
}
|
|
133
|
+
};
|
|
134
|
+
const mapCodexSdkEvent = (event, context, options = {}) => {
|
|
135
|
+
switch (event.type) {
|
|
136
|
+
case "thread.started": return {
|
|
137
|
+
events: [],
|
|
138
|
+
sessionId: event.thread_id
|
|
139
|
+
};
|
|
140
|
+
case "turn.started": return { events: [] };
|
|
141
|
+
case "turn.completed": return {
|
|
142
|
+
events: [],
|
|
143
|
+
state: {
|
|
144
|
+
stats: toStats(event.usage),
|
|
145
|
+
status: "completed",
|
|
146
|
+
error: void 0
|
|
147
|
+
}
|
|
148
|
+
};
|
|
149
|
+
case "turn.failed": return {
|
|
150
|
+
events: [],
|
|
151
|
+
state: {
|
|
152
|
+
status: "failed",
|
|
153
|
+
error: {
|
|
154
|
+
kind: "provider",
|
|
155
|
+
message: event.error.message
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
};
|
|
159
|
+
case "item.started": return mapItemStartedEvent(event, context, options);
|
|
160
|
+
case "item.updated": return { events: [] };
|
|
161
|
+
case "item.completed": return mapItemCompletedEvent(event, context, options);
|
|
162
|
+
case "error": return {
|
|
163
|
+
events: [],
|
|
164
|
+
state: {
|
|
165
|
+
status: "failed",
|
|
166
|
+
error: {
|
|
167
|
+
kind: "provider",
|
|
168
|
+
message: event.message
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
};
|
|
172
|
+
default: return { events: [] };
|
|
173
|
+
}
|
|
174
|
+
};
|
|
175
|
+
//#endregion
|
|
176
|
+
//#region src/adapters/codex-sdk/adapter.ts
|
|
177
|
+
const CODEX_SDK_CAPABILITIES = {
|
|
178
|
+
structuredOutput: true,
|
|
179
|
+
sessionResume: true,
|
|
180
|
+
imageInput: true,
|
|
181
|
+
mcp: true,
|
|
182
|
+
eventStreaming: true
|
|
183
|
+
};
|
|
184
|
+
const toCodexInput = (input) => {
|
|
185
|
+
return input.length === 1 && input[0]?.type === "text" ? input[0].text : input.map((part) => part.type === "text" ? {
|
|
186
|
+
type: "text",
|
|
187
|
+
text: part.text
|
|
188
|
+
} : {
|
|
189
|
+
type: "local_image",
|
|
190
|
+
path: part.path
|
|
191
|
+
});
|
|
192
|
+
};
|
|
193
|
+
const buildTurnOptions = (run, signal) => ({
|
|
194
|
+
outputSchema: run.normalizedRequest.schema.kind === "none" ? void 0 : run.normalizedRequest.schema.jsonSchema,
|
|
195
|
+
signal
|
|
196
|
+
});
|
|
197
|
+
var CodexSdkAgentImpl = class extends SdkAgent {
|
|
198
|
+
type = "codex-sdk";
|
|
199
|
+
defaults;
|
|
200
|
+
runDefaults;
|
|
201
|
+
command;
|
|
202
|
+
codex;
|
|
203
|
+
resolvedEnv;
|
|
204
|
+
constructor(options = {}) {
|
|
205
|
+
super({
|
|
206
|
+
type: "codex-sdk",
|
|
207
|
+
capabilities: CODEX_SDK_CAPABILITIES,
|
|
208
|
+
sessionId: options.sessionId,
|
|
209
|
+
onEvent: options.onEvent
|
|
210
|
+
});
|
|
211
|
+
this.command = options.command;
|
|
212
|
+
this.defaults = {
|
|
213
|
+
cwd: options.cwd,
|
|
214
|
+
model: options.model
|
|
215
|
+
};
|
|
216
|
+
this.runDefaults = {
|
|
217
|
+
permissionMode: options.permissionMode,
|
|
218
|
+
sandboxMode: options.sandboxMode,
|
|
219
|
+
skipGitRepoCheck: options.skipGitRepoCheck,
|
|
220
|
+
modelReasoningEffort: options.modelReasoningEffort,
|
|
221
|
+
networkAccessEnabled: options.networkAccessEnabled,
|
|
222
|
+
webSearchMode: options.webSearchMode,
|
|
223
|
+
webSearchEnabled: options.webSearchEnabled,
|
|
224
|
+
additionalDirectories: options.additionalDirectories ? [...options.additionalDirectories] : void 0
|
|
225
|
+
};
|
|
226
|
+
const env = buildBaseProcessEnv({ propagateEnv: options.propagateEnv });
|
|
227
|
+
if (options.env) Object.assign(env, options.env);
|
|
228
|
+
this.resolvedEnv = env;
|
|
229
|
+
this.codex = options.codex ?? new Codex({
|
|
230
|
+
codexPathOverride: this.command,
|
|
231
|
+
baseUrl: options.baseUrl,
|
|
232
|
+
apiKey: options.apiKey,
|
|
233
|
+
config: options.config,
|
|
234
|
+
env
|
|
235
|
+
});
|
|
236
|
+
}
|
|
237
|
+
getResolvedEnvForTesting() {
|
|
238
|
+
return this.resolvedEnv;
|
|
239
|
+
}
|
|
240
|
+
get runRequestDefaults() {
|
|
241
|
+
return this.defaults;
|
|
242
|
+
}
|
|
243
|
+
async executeSdkRun(run, request, abortController) {
|
|
244
|
+
const threadOptions = this.buildThreadOptions(request, run);
|
|
245
|
+
const thread = run.requestedSessionId ? this.codex.resumeThread(run.requestedSessionId, threadOptions) : this.codex.startThread(threadOptions);
|
|
246
|
+
if (!run.sessionId && thread.id) {
|
|
247
|
+
run.sessionId = thread.id;
|
|
248
|
+
this.setSessionId(thread.id);
|
|
249
|
+
}
|
|
250
|
+
if (run.stopReason) return;
|
|
251
|
+
const streamed = await thread.runStreamed(toCodexInput(run.normalizedRequest.input), buildTurnOptions(run, abortController.signal));
|
|
252
|
+
for await (const event of streamed.events) {
|
|
253
|
+
const batch = mapCodexSdkEvent(event, {
|
|
254
|
+
runId: run.runId,
|
|
255
|
+
requestedSessionId: run.requestedSessionId,
|
|
256
|
+
sessionId: run.sessionId,
|
|
257
|
+
schemaRequested: run.normalizedRequest.schema.kind !== "none",
|
|
258
|
+
toolCalls: run.toolCalls
|
|
259
|
+
}, { model: run.normalizedRequest.model });
|
|
260
|
+
this.applyBatch(run, batch);
|
|
261
|
+
}
|
|
262
|
+
if (run.normalizedRequest.schema.kind !== "none" && run.output.value === void 0 && run.error === void 0 && run.status !== "failed" && run.output.text) try {
|
|
263
|
+
applyMappedEventBatch(run, {
|
|
264
|
+
events: [],
|
|
265
|
+
state: { output: { value: parseJsonResponseText(run.output.text) } }
|
|
266
|
+
});
|
|
267
|
+
} catch {}
|
|
268
|
+
}
|
|
269
|
+
buildThreadOptions(request, run) {
|
|
270
|
+
return {
|
|
271
|
+
model: run.normalizedRequest.model,
|
|
272
|
+
workingDirectory: run.normalizedRequest.cwd,
|
|
273
|
+
approvalPolicy: request.permissionMode ?? this.runDefaults.permissionMode,
|
|
274
|
+
sandboxMode: request.sandboxMode ?? this.runDefaults.sandboxMode,
|
|
275
|
+
skipGitRepoCheck: request.skipGitRepoCheck ?? this.runDefaults.skipGitRepoCheck,
|
|
276
|
+
modelReasoningEffort: request.modelReasoningEffort ?? this.runDefaults.modelReasoningEffort,
|
|
277
|
+
networkAccessEnabled: request.networkAccessEnabled ?? this.runDefaults.networkAccessEnabled,
|
|
278
|
+
webSearchMode: request.webSearchMode ?? this.runDefaults.webSearchMode,
|
|
279
|
+
webSearchEnabled: request.webSearchEnabled ?? this.runDefaults.webSearchEnabled,
|
|
280
|
+
additionalDirectories: request.additionalDirectories ?? this.runDefaults.additionalDirectories
|
|
281
|
+
};
|
|
282
|
+
}
|
|
283
|
+
};
|
|
284
|
+
const createCodexSdkAgent = (options) => new CodexSdkAgentImpl(options);
|
|
285
|
+
//#endregion
|
|
286
|
+
export { createCodexSdkAgent };
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import { a as GeminiCliRunOptions, i as GeminiCliPermissionMode, n as GeminiCliAgent, o as GeminiEvent, r as GeminiCliAgentOptions, t as createGeminiCliAgent } from "../../index-dRVpEAr8.mjs";
|
|
2
|
+
export { GeminiCliAgent, GeminiCliAgentOptions, GeminiCliPermissionMode, GeminiCliRunOptions, GeminiEvent, createGeminiCliAgent };
|
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
import { a as toArray, n as isRecord } from "../../util-B4RQZkKr.mjs";
|
|
2
|
+
import { c as getInputText, l as toTextPart, o as createAgentEvent, s as createEventParser } from "../../classify-error-pL6jeu4T.mjs";
|
|
3
|
+
import { t as Agent } from "../../Agent-D8WkUilj.mjs";
|
|
4
|
+
import { z } from "zod/v4";
|
|
5
|
+
//#region src/adapters/gemini-cli/events/mappers.ts
|
|
6
|
+
const asString = (value) => typeof value === "string" ? value : void 0;
|
|
7
|
+
const asNumber = (value) => typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
8
|
+
const extractText = (value) => {
|
|
9
|
+
if (typeof value === "string") return value;
|
|
10
|
+
if (Array.isArray(value)) return value.map(extractText).join("");
|
|
11
|
+
if (isRecord(value)) {
|
|
12
|
+
const text = asString(value.text);
|
|
13
|
+
if (text) return text;
|
|
14
|
+
const parts = value.parts ?? value.content;
|
|
15
|
+
if (Array.isArray(parts)) return parts.map(extractText).join("");
|
|
16
|
+
}
|
|
17
|
+
return "";
|
|
18
|
+
};
|
|
19
|
+
const stringifyValue = (value) => {
|
|
20
|
+
if (typeof value === "string") return value;
|
|
21
|
+
if (value === null || value === void 0) return "";
|
|
22
|
+
try {
|
|
23
|
+
return JSON.stringify(value);
|
|
24
|
+
} catch {
|
|
25
|
+
return String(value);
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
const nextId = () => crypto.randomUUID();
|
|
29
|
+
const getGeminiSessionId = (event) => {
|
|
30
|
+
const raw = event;
|
|
31
|
+
const sessionId = asString(raw.session_id) ?? asString(raw.sessionId);
|
|
32
|
+
if (sessionId) return sessionId;
|
|
33
|
+
if (isRecord(raw.message)) return asString(raw.message.session_id) ?? asString(raw.message.sessionId);
|
|
34
|
+
};
|
|
35
|
+
const mapInitEvent = (_raw, context) => {
|
|
36
|
+
const text = "[init]";
|
|
37
|
+
return { events: [createAgentEvent(context.runId, "message", {
|
|
38
|
+
sessionId: context.sessionId,
|
|
39
|
+
model: null,
|
|
40
|
+
role: "system",
|
|
41
|
+
content: [toTextPart(text)],
|
|
42
|
+
text
|
|
43
|
+
})] };
|
|
44
|
+
};
|
|
45
|
+
const mapMessageEvent = (raw, context, options) => {
|
|
46
|
+
const payload = isRecord(raw.message) ? raw.message : raw;
|
|
47
|
+
const role = asString(payload.role) ?? asString(raw.role) ?? "assistant";
|
|
48
|
+
const model = asString(payload.model) ?? asString(raw.model) ?? options.model ?? null;
|
|
49
|
+
const text = extractText(payload.content ?? payload.parts ?? payload.text ?? raw.content ?? raw.text);
|
|
50
|
+
if (!text?.trim()) return { events: [] };
|
|
51
|
+
if (role === "assistant") return { events: [createAgentEvent(context.runId, "message", {
|
|
52
|
+
sessionId: context.sessionId,
|
|
53
|
+
model,
|
|
54
|
+
role: "assistant",
|
|
55
|
+
content: [toTextPart(text)],
|
|
56
|
+
text
|
|
57
|
+
})] };
|
|
58
|
+
return { events: [createAgentEvent(context.runId, "message", {
|
|
59
|
+
sessionId: context.sessionId,
|
|
60
|
+
model: null,
|
|
61
|
+
role: "user",
|
|
62
|
+
content: [toTextPart(text)],
|
|
63
|
+
text
|
|
64
|
+
})] };
|
|
65
|
+
};
|
|
66
|
+
const mapThoughtEvent = (raw, context, options) => {
|
|
67
|
+
const text = asString(raw.thought) ?? asString(raw.text) ?? asString(raw.content) ?? "";
|
|
68
|
+
if (!text.trim()) return { events: [] };
|
|
69
|
+
return { events: [createAgentEvent(context.runId, "reasoning", {
|
|
70
|
+
sessionId: context.sessionId,
|
|
71
|
+
model: options.model ?? null,
|
|
72
|
+
content: [toTextPart(text)],
|
|
73
|
+
text
|
|
74
|
+
})] };
|
|
75
|
+
};
|
|
76
|
+
const mapToolUseEvent = (raw, context, options) => {
|
|
77
|
+
const toolCallId = asString(raw.tool_id) ?? asString(raw.id) ?? nextId();
|
|
78
|
+
const toolName = asString(raw.tool_name) ?? asString(raw.name) ?? "tool";
|
|
79
|
+
const input = (isRecord(raw.parameters) ? raw.parameters : void 0) ?? (isRecord(raw.args) ? raw.args : void 0) ?? (isRecord(raw.input) ? raw.input : void 0) ?? {};
|
|
80
|
+
return {
|
|
81
|
+
events: [createAgentEvent(context.runId, "tool-call", {
|
|
82
|
+
sessionId: context.sessionId,
|
|
83
|
+
model: options.model ?? null,
|
|
84
|
+
toolCallId,
|
|
85
|
+
toolName,
|
|
86
|
+
input
|
|
87
|
+
})],
|
|
88
|
+
toolCalls: [{
|
|
89
|
+
toolCallId,
|
|
90
|
+
toolName,
|
|
91
|
+
input
|
|
92
|
+
}]
|
|
93
|
+
};
|
|
94
|
+
};
|
|
95
|
+
const mapToolResultEvent = (raw, context) => {
|
|
96
|
+
const toolCallId = asString(raw.tool_id) ?? asString(raw.tool_use_id) ?? asString(raw.id) ?? nextId();
|
|
97
|
+
const status = asString(raw.status);
|
|
98
|
+
const isError = status ? status !== "success" : Boolean(raw.error);
|
|
99
|
+
const output = raw.output ?? raw.result ?? raw.content ?? raw.message ?? (typeof raw.error === "string" ? raw.error : void 0);
|
|
100
|
+
const outputStr = stringifyValue(output);
|
|
101
|
+
const tool = context.toolCalls.get(toolCallId);
|
|
102
|
+
return { events: [createAgentEvent(context.runId, "tool-result", {
|
|
103
|
+
sessionId: context.sessionId,
|
|
104
|
+
toolCallId,
|
|
105
|
+
toolName: tool?.toolName,
|
|
106
|
+
input: tool?.input,
|
|
107
|
+
output: outputStr,
|
|
108
|
+
isError: isError || void 0,
|
|
109
|
+
error: isError ? stringifyValue(raw.error ?? output) : void 0
|
|
110
|
+
})] };
|
|
111
|
+
};
|
|
112
|
+
const extractUsage = (raw) => {
|
|
113
|
+
const tokenCount = (isRecord(raw.token_count) ? raw.token_count : void 0) ?? (isRecord(raw.tokenCount) ? raw.tokenCount : void 0) ?? (isRecord(raw.usage) ? raw.usage : void 0) ?? (isRecord(raw.usage_metadata) ? raw.usage_metadata : void 0) ?? (isRecord(raw.usageMetadata) ? raw.usageMetadata : void 0) ?? (isRecord(raw.stats) ? raw.stats : void 0);
|
|
114
|
+
if (!tokenCount) return void 0;
|
|
115
|
+
const inputTokens = asNumber(tokenCount.prompt_tokens) ?? asNumber(tokenCount.promptTokens) ?? asNumber(tokenCount.input_tokens) ?? asNumber(tokenCount.inputTokens) ?? asNumber(tokenCount.prompt_token_count);
|
|
116
|
+
const outputTokens = asNumber(tokenCount.completion_tokens) ?? asNumber(tokenCount.output_tokens) ?? asNumber(tokenCount.outputTokens) ?? asNumber(tokenCount.candidates_token_count) ?? asNumber(tokenCount.completion_token_count);
|
|
117
|
+
if (inputTokens === void 0 && outputTokens === void 0) return void 0;
|
|
118
|
+
return {
|
|
119
|
+
inputTokens: inputTokens ?? 0,
|
|
120
|
+
outputTokens: outputTokens ?? 0
|
|
121
|
+
};
|
|
122
|
+
};
|
|
123
|
+
const mapResultEvent = (raw, context) => {
|
|
124
|
+
const status = asString(raw.status) ?? asString(raw.subtype) ?? "success";
|
|
125
|
+
const isError = status !== "success" || Boolean(raw.error) || raw.is_error === true;
|
|
126
|
+
const resultValue = raw.result ?? raw.output ?? raw.text ?? raw.content;
|
|
127
|
+
const durationMs = asNumber(raw.duration_ms) ?? asNumber(raw.durationMs) ?? (isRecord(raw.stats) ? asNumber(raw.stats.total_time_ms) : void 0) ?? 0;
|
|
128
|
+
const usage = extractUsage(raw);
|
|
129
|
+
const totalTokens = usage ? usage.inputTokens + usage.outputTokens : void 0;
|
|
130
|
+
const state = { stats: {
|
|
131
|
+
durationMs,
|
|
132
|
+
apiDurationMs: durationMs,
|
|
133
|
+
turns: asNumber(raw.num_turns) ?? 1,
|
|
134
|
+
costUsd: asNumber(raw.total_cost_usd) ?? 0,
|
|
135
|
+
inputTokens: usage?.inputTokens,
|
|
136
|
+
outputTokens: usage?.outputTokens,
|
|
137
|
+
totalTokens
|
|
138
|
+
} };
|
|
139
|
+
if (typeof resultValue === "string") state.output = { text: resultValue };
|
|
140
|
+
if (raw.structured_output !== void 0) state.output = {
|
|
141
|
+
...state.output,
|
|
142
|
+
value: raw.structured_output
|
|
143
|
+
};
|
|
144
|
+
else if (context.schemaRequested && resultValue !== void 0) state.output = {
|
|
145
|
+
...state.output,
|
|
146
|
+
value: resultValue
|
|
147
|
+
};
|
|
148
|
+
if (isError) {
|
|
149
|
+
state.status = "failed";
|
|
150
|
+
state.error = {
|
|
151
|
+
kind: "provider",
|
|
152
|
+
message: asString(raw.error) ?? (typeof resultValue === "string" && resultValue.trim() ? resultValue : stringifyValue(raw.error ?? resultValue ?? status))
|
|
153
|
+
};
|
|
154
|
+
} else state.status = "completed";
|
|
155
|
+
return {
|
|
156
|
+
events: [],
|
|
157
|
+
state
|
|
158
|
+
};
|
|
159
|
+
};
|
|
160
|
+
const mapErrorEvent = (raw, context) => {
|
|
161
|
+
const message = asString(raw.message) ?? (raw.error === void 0 ? void 0 : stringifyValue(raw.error)) ?? (raw.details === void 0 ? void 0 : stringifyValue(raw.details)) ?? "Gemini emitted an error event.";
|
|
162
|
+
return { events: [createAgentEvent(context.runId, "stderr", {
|
|
163
|
+
sessionId: context.sessionId,
|
|
164
|
+
text: message
|
|
165
|
+
})] };
|
|
166
|
+
};
|
|
167
|
+
const mapGeminiEvent = (event, context, options = {}) => {
|
|
168
|
+
const raw = event;
|
|
169
|
+
switch (event.type) {
|
|
170
|
+
case "init": return mapInitEvent(raw, context);
|
|
171
|
+
case "message": return mapMessageEvent(raw, context, options);
|
|
172
|
+
case "thought": return mapThoughtEvent(raw, context, options);
|
|
173
|
+
case "tool_use": return mapToolUseEvent(raw, context, options);
|
|
174
|
+
case "tool_result": return mapToolResultEvent(raw, context);
|
|
175
|
+
case "result": return mapResultEvent(raw, context);
|
|
176
|
+
case "error": return mapErrorEvent(raw, context);
|
|
177
|
+
default: return { events: [] };
|
|
178
|
+
}
|
|
179
|
+
};
|
|
180
|
+
//#endregion
|
|
181
|
+
//#region src/adapters/gemini-cli/events/parser.ts
|
|
182
|
+
const parseGeminiEvent = createEventParser(z.object({ type: z.string() }).passthrough());
|
|
183
|
+
//#endregion
|
|
184
|
+
//#region src/adapters/gemini-cli/adapter.ts
|
|
185
|
+
const GEMINI_CLI_CAPABILITIES = {
|
|
186
|
+
structuredOutput: false,
|
|
187
|
+
sessionResume: true,
|
|
188
|
+
imageInput: false,
|
|
189
|
+
mcp: true,
|
|
190
|
+
eventStreaming: true
|
|
191
|
+
};
|
|
192
|
+
var GeminiCliAgentImpl = class extends Agent {
|
|
193
|
+
type = "gemini-cli";
|
|
194
|
+
creationOptions;
|
|
195
|
+
runDefaults;
|
|
196
|
+
runModels = /* @__PURE__ */ new Map();
|
|
197
|
+
runTextBuffers = /* @__PURE__ */ new Map();
|
|
198
|
+
constructor(options = {}) {
|
|
199
|
+
super({
|
|
200
|
+
type: "gemini-cli",
|
|
201
|
+
capabilities: GEMINI_CLI_CAPABILITIES,
|
|
202
|
+
defaults: {
|
|
203
|
+
cwd: options.cwd,
|
|
204
|
+
env: options.env,
|
|
205
|
+
command: toArray(options.command ?? "gemini"),
|
|
206
|
+
sessionId: options.sessionId,
|
|
207
|
+
model: options.model,
|
|
208
|
+
systemPrompt: options.systemPrompt
|
|
209
|
+
},
|
|
210
|
+
spawner: options.spawner,
|
|
211
|
+
container: options.container,
|
|
212
|
+
logPath: options.logPath,
|
|
213
|
+
onEvent: options.onEvent
|
|
214
|
+
});
|
|
215
|
+
this.creationOptions = options;
|
|
216
|
+
this.runDefaults = {
|
|
217
|
+
allowedTools: options.allowedTools ? [...options.allowedTools] : void 0,
|
|
218
|
+
disallowedTools: options.disallowedTools ? [...options.disallowedTools] : void 0,
|
|
219
|
+
permissionMode: options.permissionMode,
|
|
220
|
+
extraArgs: options.extraArgs ? [...options.extraArgs] : void 0
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
buildArgs(request, run) {
|
|
224
|
+
const args = ["--output-format", "stream-json"];
|
|
225
|
+
const inputText = getInputText(request.input);
|
|
226
|
+
const allowedTools = request.allowedTools ?? this.runDefaults.allowedTools;
|
|
227
|
+
const disallowedTools = request.disallowedTools ?? this.runDefaults.disallowedTools;
|
|
228
|
+
const permissionMode = request.permissionMode ?? this.runDefaults.permissionMode;
|
|
229
|
+
const extraArgs = request.extraArgs ?? this.runDefaults.extraArgs;
|
|
230
|
+
this.runModels.set(run.runId, request.model);
|
|
231
|
+
if (request.model) args.push("--model", request.model);
|
|
232
|
+
if (request.systemPrompt) args.push("--system-prompt", request.systemPrompt);
|
|
233
|
+
if (permissionMode === "full") args.push("--approval-mode", "yolo");
|
|
234
|
+
if (allowedTools && allowedTools.length > 0) {
|
|
235
|
+
const disallowed = new Set((disallowedTools ?? []).map((t) => t.toLowerCase()));
|
|
236
|
+
const filtered = allowedTools.filter((t) => !disallowed.has(t.toLowerCase()));
|
|
237
|
+
for (const tool of filtered) args.push("--allowed-tools", tool);
|
|
238
|
+
}
|
|
239
|
+
if (run.requestedSessionId) args.push("--resume", run.requestedSessionId);
|
|
240
|
+
if (extraArgs && extraArgs.length > 0) args.push(...extraArgs);
|
|
241
|
+
if (inputText.trim().startsWith("-")) args.push("--prompt", inputText);
|
|
242
|
+
else args.push(inputText);
|
|
243
|
+
return args;
|
|
244
|
+
}
|
|
245
|
+
buildEnv(_request, _run) {
|
|
246
|
+
return this.buildDefaultEnv(this.creationOptions.propagateEnv);
|
|
247
|
+
}
|
|
248
|
+
mapRawEvent(raw, context) {
|
|
249
|
+
this.appendRawLog(raw);
|
|
250
|
+
const parsed = parseGeminiEvent(raw);
|
|
251
|
+
if (!parsed) {
|
|
252
|
+
this.onParseError(JSON.stringify(raw).slice(0, 200), /* @__PURE__ */ new Error("schema validation failed"));
|
|
253
|
+
return { events: [] };
|
|
254
|
+
}
|
|
255
|
+
const sessionId = getGeminiSessionId(parsed) ?? context.sessionId;
|
|
256
|
+
const batch = mapGeminiEvent(parsed, {
|
|
257
|
+
...context,
|
|
258
|
+
sessionId
|
|
259
|
+
}, { model: this.runModels.get(context.runId) });
|
|
260
|
+
if (sessionId && batch.sessionId === void 0) batch.sessionId = sessionId;
|
|
261
|
+
let assistantText;
|
|
262
|
+
for (const event of batch.events) {
|
|
263
|
+
if (event.type !== "message" || event.role !== "assistant" || !event.text) continue;
|
|
264
|
+
const nextText = `${this.runTextBuffers.get(context.runId) ?? ""}${event.text}`;
|
|
265
|
+
this.runTextBuffers.set(context.runId, nextText);
|
|
266
|
+
assistantText = nextText;
|
|
267
|
+
}
|
|
268
|
+
if (parsed.type === "result" && batch.state?.output?.text !== void 0) this.runTextBuffers.set(context.runId, batch.state.output.text);
|
|
269
|
+
else if (assistantText !== void 0) batch.state = {
|
|
270
|
+
...batch.state,
|
|
271
|
+
output: {
|
|
272
|
+
...batch.state?.output,
|
|
273
|
+
text: assistantText
|
|
274
|
+
}
|
|
275
|
+
};
|
|
276
|
+
return batch;
|
|
277
|
+
}
|
|
278
|
+
async onRunFinished(run) {
|
|
279
|
+
await super.onRunFinished(run);
|
|
280
|
+
this.runModels.delete(run.runId);
|
|
281
|
+
this.runTextBuffers.delete(run.runId);
|
|
282
|
+
}
|
|
283
|
+
};
|
|
284
|
+
const createGeminiCliAgent = (options) => {
|
|
285
|
+
if (!options?.container) return new GeminiCliAgentImpl(options);
|
|
286
|
+
return new GeminiCliAgentImpl({
|
|
287
|
+
...options,
|
|
288
|
+
spawner: options.container.spawner
|
|
289
|
+
});
|
|
290
|
+
};
|
|
291
|
+
//#endregion
|
|
292
|
+
export { createGeminiCliAgent };
|