@tangle-network/sdk-provider-cli-base 0.13.16 → 0.13.18

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,356 @@
1
+ import { At as toolStartEvents, Dt as textDeltaEvents, Et as streamPartBase, F as jsonEventParser, G as isLocalMcpConfig, H as CliProviderAdapterBase, J as enabledInteractionKinds, K as localMcpArgv, Tt as sessionObservedEvents, V as recordCliTokenUsage, et as withTurnInteractions, k as McpInteractionSupport, kt as toolResultEvents, q as localMcpEnv, wt as reasoningEvents } from "../../src-Fn8Pu1xq.mjs";
2
+ import { createHash, randomUUID } from "node:crypto";
3
+ import { InteractionKind } from "@tangle-network/agent-interface";
4
+ import { mkdir, readFile, writeFile } from "node:fs/promises";
5
+ import { join } from "node:path";
6
+ import { renameSync, rmSync, writeFileSync } from "node:fs";
7
+ //#region src/adapters/factory-droids/event-mapper.ts
8
+ /**
9
+ * Type guard for Factory Droids events.
10
+ */
11
+ function isFactoryDroidsEvent(value) {
12
+ if (typeof value !== "object" || value === null) return false;
13
+ return typeof value.type === "string";
14
+ }
15
+ function mapToolResultEvent(event, state) {
16
+ return toolResultEvents(state, {
17
+ id: event.tool_use_id,
18
+ content: event.content,
19
+ isError: Boolean(event.is_error)
20
+ });
21
+ }
22
+ /**
23
+ * Maps a Factory Droids system event to StreamEvents.
24
+ */
25
+ function mapSystemEvent(event) {
26
+ return [{
27
+ type: "status",
28
+ status: "processing",
29
+ detail: event.content
30
+ }];
31
+ }
32
+ /**
33
+ * Maps a Factory Droids error event to a failed terminal status carrying
34
+ * droid's own message. droid exits 0 after an error event, so a warning left
35
+ * the turn as "completed without user-visible output" and lost the cause.
36
+ */
37
+ function mapErrorEvent(event) {
38
+ return [{
39
+ type: "status",
40
+ status: "failed",
41
+ detail: event.message ?? event.content ?? `Factory Droids error ${event.code ?? "FACTORY_DROIDS_ERROR"}`
42
+ }];
43
+ }
44
+ /**
45
+ * Maps a Factory Droids result event to StreamEvents.
46
+ */
47
+ function mapResultEvent(event, state) {
48
+ recordCliTokenUsage(state, event);
49
+ return [{
50
+ type: "status",
51
+ status: "completed"
52
+ }];
53
+ }
54
+ /**
55
+ * droid ≥0.159 `message` event — assistant text accumulates into the buffer
56
+ * exactly like the older `assistant` event (each event is a full turn, so turns
57
+ * are newline-joined); the `user` echo of our own prompt is ignored.
58
+ */
59
+ function mapMessageEvent(event, state) {
60
+ if (event.role !== "assistant" || !event.text) return [];
61
+ const previousLength = state.textBuffer.length;
62
+ state.textBuffer += previousLength > 0 ? `\n${event.text}` : event.text;
63
+ state.textPartId ??= randomUUID();
64
+ const textPart = {
65
+ ...streamPartBase(state, state.textPartId),
66
+ type: "text",
67
+ text: state.textBuffer
68
+ };
69
+ const events = [];
70
+ if (previousLength === 0) events.push({
71
+ type: "model-processing",
72
+ phase: "generating"
73
+ });
74
+ events.push({
75
+ type: "message.part.updated",
76
+ part: textPart
77
+ });
78
+ return events;
79
+ }
80
+ /** droid ≥0.159 `tool_call` event — same role as the older `tool_use`. */
81
+ function mapToolCallEvent(event, state) {
82
+ return toolStartEvents(state, {
83
+ id: event.toolId ?? event.id ?? randomUUID(),
84
+ name: event.toolName,
85
+ input: event.parameters ?? {}
86
+ });
87
+ }
88
+ /** droid ≥0.159 terminal `completion` event — same role as the older `result`. */
89
+ function mapCompletionEvent(event, state) {
90
+ const events = [];
91
+ if (state.textBuffer.length === 0 && event.finalText) {
92
+ state.textBuffer = event.finalText;
93
+ state.textPartId ??= randomUUID();
94
+ events.push({
95
+ type: "message.part.updated",
96
+ part: {
97
+ ...streamPartBase(state, state.textPartId),
98
+ type: "text",
99
+ text: state.textBuffer
100
+ }
101
+ });
102
+ }
103
+ return [...events, ...mapResultEvent({
104
+ type: "result",
105
+ text: event.finalText ?? "",
106
+ session_id: event.session_id,
107
+ usage: event.usage
108
+ }, state)];
109
+ }
110
+ /**
111
+ * Maps a Factory Droids event to StreamEvent(s).
112
+ *
113
+ * Uses message.part.updated as the primary event type for all content updates,
114
+ * matching the OpenCode provider's event format.
115
+ *
116
+ * @param event - The Factory Droids event
117
+ * @param state - The execution state (mutated by this function)
118
+ * @returns Array of StreamEvents
119
+ */
120
+ function mapFactoryDroidsEvent(event, state) {
121
+ return [...observeSession(event, state), ...mapEvent(event, state)];
122
+ }
123
+ /**
124
+ * droid names its session on every stream event, from the first `system`
125
+ * init on. Report it at the first event, not at the final result, so a turn
126
+ * killed mid-run still names the session file it was writing.
127
+ */
128
+ function observeSession(event, state) {
129
+ const sessionId = event.session_id;
130
+ if (typeof sessionId !== "string" || !sessionId) return [];
131
+ if (state.sessionId === sessionId) return [];
132
+ return sessionObservedEvents(state, "factory-droids", sessionId);
133
+ }
134
+ function mapEvent(event, state) {
135
+ switch (event.type) {
136
+ case "assistant": return textDeltaEvents(state, event.content);
137
+ case "thinking": return reasoningEvents(state, event.content, { signalPhase: true });
138
+ case "tool_use": return toolStartEvents(state, event);
139
+ case "tool_result": return mapToolResultEvent(event, state);
140
+ case "system": return mapSystemEvent(event);
141
+ case "error": return mapErrorEvent(event);
142
+ case "result": return mapResultEvent(event, state);
143
+ case "message": return mapMessageEvent(event, state);
144
+ case "tool_call": return mapToolCallEvent(event, state);
145
+ case "completion": return mapCompletionEvent(event, state);
146
+ default: return [{
147
+ type: "raw",
148
+ backend: "factory-droids",
149
+ event
150
+ }];
151
+ }
152
+ }
153
+ //#endregion
154
+ //#region src/adapters/factory-droids/adapter.ts
155
+ const DEFAULT_MODEL = "claude-opus-4-5-20251101";
156
+ /**
157
+ * A caller-owned OpenAI-compatible endpoint (`baseUrl` + `apiKey`) runs as a
158
+ * droid custom model. droid reads it from a runtime settings file passed with
159
+ * `--settings`; the file names the key by this env var, which droid expands,
160
+ * so the key never lands on disk. Factory's own account is not used. The
161
+ * custom model's id is `custom:<model>`, the id droid records in its session.
162
+ */
163
+ const ENDPOINT_API_KEY_ENV = "TANGLE_DROID_ENDPOINT_API_KEY";
164
+ const ENDPOINT_SETTINGS_PREFIX = ".tangle-droid-endpoint-";
165
+ /** Name of the interaction MCP server registered into `.factory/mcp.json`. */
166
+ const DROID_INTERACTION_MCP_NAME = "tangle-interaction";
167
+ /**
168
+ * Factory Droids provider adapter.
169
+ *
170
+ * Implements the SdkProviderAdapter interface for the Factory Droids CLI tool.
171
+ * Extends CliProviderAdapterBase with Factory Droids-specific event parsing and CLI arguments.
172
+ */
173
+ var FactoryDroidsProviderAdapter = class extends CliProviderAdapterBase {
174
+ provider = "factory-droids";
175
+ defaultCliPath = "droid";
176
+ /**
177
+ * Shared interaction round-trip for questions. droid auto-discovers
178
+ * MCP tools, so the agent calls `ask_user` itself; permission
179
+ * stays governed by droid's own `--auto` / `--skip-permissions-unsafe`.
180
+ */
181
+ activeInteractions;
182
+ configuredInteractionKinds(interactions = this.config.interactions) {
183
+ return enabledInteractionKinds(interactions, ["question"]).map(() => InteractionKind.Question);
184
+ }
185
+ getCapabilities() {
186
+ const interactions = this.configuredInteractionKinds();
187
+ return {
188
+ ...super.getCapabilities(),
189
+ ...interactions.length > 0 ? { interactions } : {}
190
+ };
191
+ }
192
+ /**
193
+ * Host a per-execution interaction MCP server when `interactions` is on and
194
+ * register it into the SAME `$HOME/.factory/mcp.json` that `droid exec` reads
195
+ * (HOME resolved exactly as the base adapter's exec env resolves it, so the
196
+ * write lands where droid looks). The entry is removed and every pending
197
+ * interaction failed-closed in `finally` when the turn unwinds.
198
+ */
199
+ async execute(input, services, onEvent) {
200
+ const turnConfig = withTurnInteractions(this.config, input);
201
+ const kinds = this.configuredInteractionKinds(turnConfig.interactions);
202
+ if (kinds.length === 0) return super.execute(input, services, onEvent);
203
+ const sessionId = input.sessionId ?? input.interactionBinding?.sessionId ?? randomUUID();
204
+ const workspaceRoot = input.workspaceRoot ?? this.storagePath;
205
+ const home = this.applyWritableHomeDefaults(this.buildExecEnv(this.config), workspaceRoot).HOME ?? workspaceRoot;
206
+ const interactions = new McpInteractionSupport(DROID_INTERACTION_MCP_NAME, kinds);
207
+ this.activeInteractions = interactions;
208
+ const server = await interactions.start(sessionId, this.interactionExecutionBinding(input, sessionId), onEvent);
209
+ await upsertDroidMcpEntry(home, DROID_INTERACTION_MCP_NAME, {
210
+ type: "http",
211
+ url: server.url,
212
+ headers: { Authorization: `Bearer ${server.token}` }
213
+ });
214
+ try {
215
+ return await super.execute(input, services, onEvent);
216
+ } finally {
217
+ await removeDroidMcpEntry(home, DROID_INTERACTION_MCP_NAME).catch(() => {});
218
+ this.activeInteractions = void 0;
219
+ await interactions.stop(sessionId);
220
+ }
221
+ }
222
+ async respondToInteraction(response) {
223
+ this.activeInteractions?.respond(response);
224
+ }
225
+ /**
226
+ * Initialize the adapter with API key validation.
227
+ * Factory Droids requires an API key to function.
228
+ */
229
+ async afterInitialize(config) {
230
+ if (!(config.model?.apiKey ?? this.config.apiKey ?? process.env.FACTORY_API_KEY)) throw new Error("API key is required for Factory Droids. Set FACTORY_API_KEY environment variable or provide apiKey in config.");
231
+ }
232
+ buildExecArgs(params) {
233
+ const args = ["exec"];
234
+ const model = params.model ?? params.config.model ?? DEFAULT_MODEL;
235
+ const baseUrl = params.config.baseUrl?.trim();
236
+ if (baseUrl) {
237
+ const home = this.config.runtimeHome?.trim() || params.workspaceRoot;
238
+ args.push("--settings", writeEndpointSettings(home, {
239
+ model,
240
+ baseUrl
241
+ }), "--model", `custom:${model}`);
242
+ } else args.push("--model", model);
243
+ if (params.config.bypassPermissions !== false) args.push("--skip-permissions-unsafe");
244
+ else if (params.config.autonomyLevel) args.push("--auto", params.config.autonomyLevel);
245
+ args.push("--output-format", "stream-json");
246
+ args.push("--cwd", params.workspaceRoot);
247
+ if (params.systemPrompt) args.push("--append-system-prompt", params.systemPrompt);
248
+ if (params.config.extraFlags) args.push(...params.config.extraFlags);
249
+ if (params.sessionId) args.push("--session-id", params.sessionId);
250
+ args.push(params.message);
251
+ return {
252
+ command: this.getCliPath(),
253
+ args,
254
+ useStdin: false
255
+ };
256
+ }
257
+ buildExecEnv(config) {
258
+ const env = this.agentEnvironmentValues();
259
+ if (config.baseUrl?.trim()) {
260
+ if (!config.apiKey) throw new Error("Factory Droids on a caller endpoint (baseUrl) needs that endpoint's apiKey.");
261
+ env[ENDPOINT_API_KEY_ENV] = config.apiKey;
262
+ delete env.FACTORY_API_KEY;
263
+ return env;
264
+ }
265
+ const apiKey = config.apiKey ?? process.env.FACTORY_API_KEY;
266
+ if (apiKey) env.FACTORY_API_KEY = apiKey;
267
+ return env;
268
+ }
269
+ createEventParser(state, onEvent) {
270
+ return jsonEventParser(this.logger, onEvent, {
271
+ label: "Factory Droids",
272
+ accept: isFactoryDroidsEvent,
273
+ map: (event) => mapFactoryDroidsEvent(event, state)
274
+ });
275
+ }
276
+ buildMcpAddArgs(name, config) {
277
+ const args = [
278
+ "mcp",
279
+ "add",
280
+ name
281
+ ];
282
+ if (isLocalMcpConfig(config)) {
283
+ args.push("--type", "stdio", ...localMcpArgv(config));
284
+ for (const [key, value] of Object.entries(localMcpEnv(config) ?? {})) args.push("--env", `${key}=${value}`);
285
+ } else {
286
+ args.push("--type", "http", config.url);
287
+ for (const [key, value] of Object.entries(config.headers ?? {})) args.push("--header", `${key}: ${value}`);
288
+ }
289
+ return args;
290
+ }
291
+ };
292
+ /**
293
+ * Read–merge–write a single HTTP server into `<home>/.factory/mcp.json`. droid
294
+ * reads this file at `droid exec` startup; the shape is the standard
295
+ * `{ mcpServers: { <name>: { type, url, headers } } }` (verified against
296
+ * `droid mcp add --type http`). Merges into any existing config so a tenant's
297
+ * own servers survive; overwrites our own entry idempotently across turns.
298
+ */
299
+ async function upsertDroidMcpEntry(home, name, entry) {
300
+ const dir = join(home, ".factory");
301
+ const file = join(dir, "mcp.json");
302
+ await mkdir(dir, { recursive: true });
303
+ const doc = await readMcpDoc(file);
304
+ doc.mcpServers[name] = entry;
305
+ await writeFile(file, `${JSON.stringify(doc, null, 2)}\n`, "utf8");
306
+ }
307
+ /** Remove our entry from `<home>/.factory/mcp.json` (best-effort teardown). */
308
+ async function removeDroidMcpEntry(home, name) {
309
+ const file = join(home, ".factory", "mcp.json");
310
+ const doc = await readMcpDoc(file);
311
+ if (!(name in doc.mcpServers)) return;
312
+ delete doc.mcpServers[name];
313
+ await writeFile(file, `${JSON.stringify(doc, null, 2)}\n`, "utf8");
314
+ }
315
+ async function readMcpDoc(file) {
316
+ try {
317
+ const parsed = JSON.parse(await readFile(file, "utf8"));
318
+ const servers = parsed?.mcpServers;
319
+ return {
320
+ ...parsed,
321
+ mcpServers: servers && typeof servers === "object" ? servers : {}
322
+ };
323
+ } catch {
324
+ return { mcpServers: {} };
325
+ }
326
+ }
327
+ /**
328
+ * Write the runtime settings that declare the caller's endpoint as droid's
329
+ * custom model, and return the file's path. The key stays an env reference.
330
+ */
331
+ function writeEndpointSettings(home, endpoint) {
332
+ const path = join(home, `${ENDPOINT_SETTINGS_PREFIX}${createHash("sha256").update(`${endpoint.baseUrl}\n${endpoint.model}`).digest("hex").slice(0, 16)}.settings.json`);
333
+ const candidate = join(home, `.${randomUUID()}.droid-settings`);
334
+ try {
335
+ writeFileSync(candidate, `${JSON.stringify({ customModels: [{
336
+ id: `custom:${endpoint.model}`,
337
+ displayName: "tangle-endpoint",
338
+ model: endpoint.model,
339
+ baseUrl: endpoint.baseUrl,
340
+ apiKey: `\${${ENDPOINT_API_KEY_ENV}}`,
341
+ provider: "generic-chat-completion-api"
342
+ }] }, null, 2)}\n`, {
343
+ mode: 420,
344
+ flag: "wx"
345
+ });
346
+ renameSync(candidate, path);
347
+ } catch (error) {
348
+ rmSync(candidate, { force: true });
349
+ throw error;
350
+ }
351
+ return path;
352
+ }
353
+ //#endregion
354
+ export { FactoryDroidsProviderAdapter, isFactoryDroidsEvent, mapFactoryDroidsEvent };
355
+
356
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1,27 @@
1
+ import { Mt as CliExecArgs, Pt as CliProviderConfig, Rt as ExecutionState, ht as CliProviderAdapterBase } from "../../index-BpO3fvbf.mjs";
2
+ import { StreamParserConfig } from "@tangle-network/sdk-cli-runner";
3
+ import { StreamEvent } from "@tangle-network/agent-interface";
4
+
5
+ //#region src/adapters/grok/adapter.d.ts
6
+ type GrokLine = {
7
+ type: "text";
8
+ line: string;
9
+ };
10
+ declare class GrokProviderAdapter extends CliProviderAdapterBase<CliProviderConfig, GrokLine> {
11
+ readonly provider = "grok";
12
+ protected readonly defaultCliPath = "grok";
13
+ protected buildExecArgs(params: {
14
+ message: string;
15
+ config: CliProviderConfig;
16
+ model?: string;
17
+ sessionId?: string;
18
+ workspaceRoot: string;
19
+ systemPrompt?: string;
20
+ }): CliExecArgs;
21
+ /** The host agent environment, with the turn's key and endpoint over it. */
22
+ protected buildExecEnv(config: CliProviderConfig): Record<string, string | undefined>;
23
+ protected createEventParser(state: ExecutionState, onEvent?: (event: StreamEvent) => void): StreamParserConfig<GrokLine>;
24
+ }
25
+ //#endregion
26
+ export { GrokProviderAdapter };
27
+ //# sourceMappingURL=index.d.mts.map
@@ -0,0 +1,56 @@
1
+ import { H as CliProviderAdapterBase, I as plaintextResponseParser, Tt as sessionObservedEvents, ot as prependPromptSection } from "../../src-Fn8Pu1xq.mjs";
2
+ //#region src/adapters/grok/adapter.ts
3
+ const DECLARE_MODEL = "d=$HOME/.grok; [ -z \"$GROK_HOME\" ] || d=$GROK_HOME; t=\"[model.\\\"$1\\\"]\"; mkdir -p \"$d\" && { grep -qxF \"$t\" \"$d/managed_config.toml\" 2>/dev/null || printf '%s\\nmodel = \"%s\"\\n' \"$t\" \"$1\" >> \"$d/managed_config.toml\"; }; shift; exec \"$@\"";
4
+ var GrokProviderAdapter = class extends CliProviderAdapterBase {
5
+ provider = "grok";
6
+ defaultCliPath = "grok";
7
+ buildExecArgs(params) {
8
+ const args = [
9
+ "--always-approve",
10
+ "--output-format",
11
+ "streaming-json"
12
+ ];
13
+ const model = params.model ?? params.config.model ?? "";
14
+ if (model) args.push("-m", model);
15
+ if (params.sessionId) args.push("-r", params.sessionId);
16
+ args.push("-p", prependPromptSection(params.systemPrompt, params.message));
17
+ if (!params.config.baseUrl?.trim() || !/^[\w.:@+/-]+$/.test(model)) return {
18
+ command: this.getCliPath(),
19
+ args,
20
+ useStdin: false
21
+ };
22
+ args.unshift("-c", DECLARE_MODEL, "grok", model, this.getCliPath());
23
+ return {
24
+ command: "/bin/sh",
25
+ args,
26
+ useStdin: false
27
+ };
28
+ }
29
+ /** The host agent environment, with the turn's key and endpoint over it. */
30
+ buildExecEnv(config) {
31
+ const env = this.agentEnvironmentValues();
32
+ if (config.apiKey) env.XAI_API_KEY = config.apiKey;
33
+ const baseUrl = config.baseUrl?.trim();
34
+ if (baseUrl) env.GROK_MODELS_BASE_URL = baseUrl;
35
+ return env;
36
+ }
37
+ createEventParser(state, onEvent) {
38
+ return plaintextResponseParser(state, onEvent, {
39
+ classify: (line) => line.length === 0 ? null : {
40
+ type: "text",
41
+ line
42
+ },
43
+ map: (event, response) => {
44
+ response.text(event.line);
45
+ const id = /"sessionId"\s*:\s*"([^"]+)"/.exec(event.line)?.[1];
46
+ if (!id || state.sessionId === id) return [];
47
+ return sessionObservedEvents(state, "grok", id);
48
+ },
49
+ emptyFailureDetail: "grok exited without producing a response body"
50
+ });
51
+ }
52
+ };
53
+ //#endregion
54
+ export { GrokProviderAdapter };
55
+
56
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1,148 @@
1
+ import { Mt as CliExecArgs, Pt as CliProviderConfig, Rt as ExecutionState, ht as CliProviderAdapterBase, n as HarnessId } from "../../index-BpO3fvbf.mjs";
2
+ import { i as PreparedAttachment } from "../../prompt-input-CD7okX8T.mjs";
3
+ import { StreamParserConfig } from "@tangle-network/sdk-cli-runner";
4
+ import { InputPart, McpConfig, StreamEvent } from "@tangle-network/agent-interface";
5
+ import { MessagePart } from "@tangle-network/sdk-session-persistence";
6
+
7
+ //#region src/adapters/hermes/types.d.ts
8
+ /**
9
+ * Authentication mode for hermes.
10
+ *
11
+ * - "api-key": Use the provider-specific key env (OPENROUTER_API_KEY,
12
+ * ANTHROPIC_API_KEY, …) from `apiKey` or env. The adapter sets the env var
13
+ * for the provider chosen by `inferenceProvider`.
14
+ * - "oauth": Use Nous Portal OAuth tokens previously stored via `hermes login`
15
+ * (or `hermes auth add ... --type oauth`). The CLI reads them from
16
+ * `$HERMES_HOME/.env` or its credential store.
17
+ */
18
+ type HermesAuthMode = "api-key" | "oauth";
19
+ /**
20
+ * Inference provider hermes will route the model call through. Subset of the
21
+ * providers hermes supports natively (`hermes --provider …`). The list here is
22
+ * intentionally narrow to the providers we plumb env vars for in the adapter;
23
+ * hermes accepts a wider set for end-user CLI use.
24
+ */
25
+ type HermesInferenceProvider = "auto" | "openrouter" | "anthropic" | "openai-codex" | "nous" | "custom";
26
+ /**
27
+ * Hermes-specific configuration.
28
+ */
29
+ interface HermesConfig extends CliProviderConfig {
30
+ /** Path to the hermes CLI executable. Default: "hermes" (resolved on PATH). */
31
+ cliPath?: string;
32
+ /** Model to use (e.g. "anthropic/claude-sonnet-4"). Forwarded as `--model`. */
33
+ model?: string;
34
+ /**
35
+ * Inference provider for the model call. Forwarded as `--provider`.
36
+ */
37
+ inferenceProvider?: HermesInferenceProvider;
38
+ /**
39
+ * Authentication mode. Defaults to "api-key" when an apiKey is present;
40
+ * otherwise "oauth" (which assumes the CLI's credential store is populated).
41
+ */
42
+ authMode?: HermesAuthMode;
43
+ /**
44
+ * Optional auth files to materialize under `$HOME` before invoking the CLI.
45
+ * Hermes reads its API keys from `$HERMES_HOME/.env` and OAuth tokens from
46
+ * `$HERMES_HOME/credentials/*` — both targets work via the standard authFile
47
+ * materialization pipeline (see apps/sidecar/src/backends/cli-auth.ts).
48
+ */
49
+ authFiles?: Array<{
50
+ path: string;
51
+ content: string;
52
+ mode?: number;
53
+ }>;
54
+ /**
55
+ * API key. When present, written to the env var matching `inferenceProvider`
56
+ * (`OPENROUTER_API_KEY` for openrouter, `ANTHROPIC_API_KEY` for anthropic,
57
+ * etc). Used only when `authMode === "api-key"`.
58
+ */
59
+ apiKey?: string;
60
+ /**
61
+ * Base URL for the inference provider. Forwarded as a provider-specific env
62
+ * var (`OPENROUTER_BASE_URL` for openrouter, etc) so hermes routes through
63
+ * a custom endpoint like `https://router.tangle.tools/v1`.
64
+ */
65
+ baseUrl?: string;
66
+ /** Comma-separated toolsets to enable via `--toolsets`. */
67
+ toolsets?: string[];
68
+ /**
69
+ * Extra flags appended before the terminal `-q <prompt>` pair.
70
+ */
71
+ extraFlags?: string[];
72
+ }
73
+ /**
74
+ * Emitted for every stdout line — accumulated into the response text. Quiet
75
+ * mode prints only the final content block, so the entire stream is body text.
76
+ */
77
+ interface HermesTextEvent {
78
+ type: "text";
79
+ line: string;
80
+ }
81
+ /**
82
+ * Emitted when stdout closes; carries the full accumulated response so the
83
+ * adapter can synthesize a final `message.part.updated` and `result` event.
84
+ */
85
+ interface HermesCompleteEvent {
86
+ type: "complete";
87
+ text: string;
88
+ }
89
+ /**
90
+ * Emitted when hermes exits non-zero or prints a recognizable error pattern.
91
+ * `message` is the raw line so callers can surface the upstream message verbatim.
92
+ */
93
+ interface HermesErrorEvent {
94
+ type: "error";
95
+ message: string;
96
+ }
97
+ type HermesEvent = HermesTextEvent | HermesCompleteEvent | HermesErrorEvent;
98
+ //#endregion
99
+ //#region src/adapters/hermes/adapter.d.ts
100
+ declare class HermesProviderAdapter extends CliProviderAdapterBase<HermesConfig, HermesEvent> {
101
+ readonly provider = "hermes";
102
+ protected readonly profileHarness: HarnessId;
103
+ private activeSessionId?;
104
+ protected readonly defaultCliPath = "hermes";
105
+ protected isBenignNonZeroExit({
106
+ exitCode,
107
+ stderr,
108
+ state
109
+ }: {
110
+ exitCode: number | null;
111
+ stderr: string;
112
+ state: ExecutionState;
113
+ }): boolean;
114
+ protected buildMcpAddArgs(name: string, config: McpConfig): string[];
115
+ /** The contract store, or a workspace fallback when no runtime home is set. */
116
+ private resolveHermesHome;
117
+ protected preparePromptInput(parts: InputPart[], workspaceRoot: string, sessionId: string): Promise<{
118
+ promptText: string;
119
+ persistedParts: MessagePart[];
120
+ attachments: PreparedAttachment[];
121
+ }>;
122
+ protected nativeAttachmentKinds(): ReadonlyArray<"image" | "file">;
123
+ protected buildExecArgs(params: {
124
+ message: string;
125
+ config: HermesConfig;
126
+ model?: string;
127
+ sessionId?: string;
128
+ workspaceRoot: string;
129
+ systemPrompt?: string;
130
+ attachments?: PreparedAttachment[];
131
+ }): CliExecArgs;
132
+ private releaseTurnLease;
133
+ protected buildExecEnv(config: HermesConfig): Record<string, string | undefined>;
134
+ protected afterCliProcessExit(params: {
135
+ state: ExecutionState;
136
+ stderr: string;
137
+ exit: {
138
+ success: boolean;
139
+ };
140
+ workspaceRoot: string;
141
+ env: Record<string, string | undefined>;
142
+ onEvent?: (event: StreamEvent) => void;
143
+ }): Promise<void>;
144
+ protected createEventParser(state: ExecutionState, onEvent?: (event: StreamEvent) => void): StreamParserConfig<HermesEvent>;
145
+ }
146
+ //#endregion
147
+ export { type HermesAuthMode, type HermesCompleteEvent, type HermesConfig, type HermesErrorEvent, type HermesEvent, type HermesInferenceProvider, HermesProviderAdapter, type HermesTextEvent };
148
+ //# sourceMappingURL=index.d.mts.map