@tangle-network/sdk-provider-cli-base 0.13.17 → 0.13.19
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/dist/adapters/amp/index.d.mts +250 -0
- package/dist/adapters/amp/index.mjs +233 -0
- package/dist/adapters/factory-droids/index.d.mts +200 -0
- package/dist/adapters/factory-droids/index.mjs +356 -0
- package/dist/adapters/grok/index.d.mts +27 -0
- package/dist/adapters/grok/index.mjs +56 -0
- package/dist/adapters/hermes/index.d.mts +148 -0
- package/dist/adapters/hermes/index.mjs +244 -0
- package/dist/adapters/nanoclaw/index.d.mts +50 -0
- package/dist/adapters/nanoclaw/index.mjs +116 -0
- package/dist/adapters/openclaw/index.d.mts +68 -0
- package/dist/adapters/openclaw/index.mjs +240 -0
- package/dist/adapters/prime/index.d.mts +126 -0
- package/dist/adapters/prime/index.mjs +446 -0
- package/dist/conformance/index.d.mts +1 -1
- package/dist/index-BpO3fvbf.d.mts +1254 -0
- package/dist/index.d.mts +3 -1254
- package/dist/index.mjs +1 -4585
- package/dist/{prompt-input-BHn_1z69.d.mts → prompt-input-CD7okX8T.d.mts} +1 -1
- package/dist/src-Fn8Pu1xq.mjs +4586 -0
- package/package.json +38 -9
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
import { G as isLocalMcpConfig, H as CliProviderAdapterBase, I as plaintextResponseParser, K as localMcpArgv, Tt as sessionObservedEvents, V as recordCliTokenUsage, it as partitionImageAttachments, ot as prependPromptSection, q as localMcpEnv } from "../../src-Fn8Pu1xq.mjs";
|
|
2
|
+
import { resolveTangleRouterDefaults } from "@tangle-network/agent-interface";
|
|
3
|
+
import { lchown, mkdir, writeFile } from "node:fs/promises";
|
|
4
|
+
import { dirname, join } from "node:path";
|
|
5
|
+
import { DatabaseSync } from "node:sqlite";
|
|
6
|
+
//#region src/adapters/hermes/adapter.ts
|
|
7
|
+
/** Hermes provider name to the env var that holds its API key. */
|
|
8
|
+
const PROVIDER_API_KEY_ENV = {
|
|
9
|
+
auto: "OPENROUTER_API_KEY",
|
|
10
|
+
openrouter: "OPENROUTER_API_KEY",
|
|
11
|
+
anthropic: "ANTHROPIC_API_KEY",
|
|
12
|
+
"openai-codex": "OPENAI_API_KEY",
|
|
13
|
+
nous: "NOUS_API_KEY",
|
|
14
|
+
custom: "OPENAI_API_KEY"
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* Maps a hermes inference provider to the env var hermes consults for the
|
|
18
|
+
* provider base URL. Used to point hermes at tangle-router or a self-hosted
|
|
19
|
+
* OpenAI-compatible endpoint without writing config files at runtime.
|
|
20
|
+
*/
|
|
21
|
+
const PROVIDER_BASE_URL_ENV = {
|
|
22
|
+
auto: null,
|
|
23
|
+
openrouter: "OPENROUTER_BASE_URL",
|
|
24
|
+
anthropic: "ANTHROPIC_BASE_URL",
|
|
25
|
+
"openai-codex": "OPENAI_BASE_URL",
|
|
26
|
+
nous: null,
|
|
27
|
+
custom: "OPENAI_BASE_URL"
|
|
28
|
+
};
|
|
29
|
+
var HermesProviderAdapter = class extends CliProviderAdapterBase {
|
|
30
|
+
provider = "hermes";
|
|
31
|
+
profileHarness = "hermes";
|
|
32
|
+
activeSessionId;
|
|
33
|
+
defaultCliPath = "hermes";
|
|
34
|
+
isBenignNonZeroExit({ exitCode, stderr, state }) {
|
|
35
|
+
if (exitCode === null || exitCode === 0) return false;
|
|
36
|
+
if (state.textBuffer.trim().length > 0) return true;
|
|
37
|
+
return /session_id:\s*\S/.test(stderr);
|
|
38
|
+
}
|
|
39
|
+
buildMcpAddArgs(name, config) {
|
|
40
|
+
const args = [
|
|
41
|
+
"mcp",
|
|
42
|
+
"add",
|
|
43
|
+
name
|
|
44
|
+
];
|
|
45
|
+
if (!isLocalMcpConfig(config)) return [
|
|
46
|
+
...args,
|
|
47
|
+
"--url",
|
|
48
|
+
config.url
|
|
49
|
+
];
|
|
50
|
+
const [command, ...commandArgs] = localMcpArgv(config);
|
|
51
|
+
args.push("--command", command);
|
|
52
|
+
if (commandArgs.length > 0) args.push("--args", ...commandArgs);
|
|
53
|
+
const environment = localMcpEnv(config);
|
|
54
|
+
if (environment && Object.keys(environment).length > 0) args.push("--env", ...Object.entries(environment).map(([key, value]) => `${key}=${value}`));
|
|
55
|
+
return args;
|
|
56
|
+
}
|
|
57
|
+
/** The contract store, or a workspace fallback when no runtime home is set. */
|
|
58
|
+
resolveHermesHome() {
|
|
59
|
+
const runtimeHome = this.config.runtimeHome?.trim();
|
|
60
|
+
if (runtimeHome) return join(runtimeHome, ".hermes");
|
|
61
|
+
if (!this.activeSessionId) throw new Error("Hermes native session id is required before resolving HERMES_HOME");
|
|
62
|
+
return join(process.env.AGENT_WORKSPACE_ROOT?.trim() || this.storagePath, ".hermes", "sessions", this.activeSessionId);
|
|
63
|
+
}
|
|
64
|
+
async preparePromptInput(parts, workspaceRoot, sessionId) {
|
|
65
|
+
if (!/^[A-Za-z0-9][A-Za-z0-9_-]{0,127}$/.test(sessionId)) throw new Error("Hermes native session id is not a safe directory name");
|
|
66
|
+
if (this.activeSessionId && this.activeSessionId !== sessionId) throw new Error("Hermes backend cannot serve two native sessions");
|
|
67
|
+
this.activeSessionId = sessionId;
|
|
68
|
+
const home = this.resolveHermesHome();
|
|
69
|
+
const created = await mkdir(home, { recursive: true });
|
|
70
|
+
await writeFile(join(home, "config.yaml"), "agent:\n auto_recovery_cycles: 0\n", { flag: "wx" }).catch(() => void 0);
|
|
71
|
+
const owner = this.subprocessIdentity();
|
|
72
|
+
if (owner) {
|
|
73
|
+
const sessions = dirname(home);
|
|
74
|
+
const top = created !== void 0 && sessions.startsWith(`${created}/`) ? created : sessions;
|
|
75
|
+
for (let dir = home;; dir = dirname(dir)) {
|
|
76
|
+
await lchown(dir, owner.uid, owner.gid);
|
|
77
|
+
if (dir === top) break;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
return super.preparePromptInput(parts, workspaceRoot, sessionId, { inlineImageBudgetBytes: 0 });
|
|
81
|
+
}
|
|
82
|
+
nativeAttachmentKinds() {
|
|
83
|
+
return ["image"];
|
|
84
|
+
}
|
|
85
|
+
buildExecArgs(params) {
|
|
86
|
+
const args = ["chat", "--quiet"];
|
|
87
|
+
const gatewayDefaults = resolveTangleRouterDefaults();
|
|
88
|
+
const configuredProvider = params.config.inferenceProvider;
|
|
89
|
+
const defaultThroughGateway = !configuredProvider || configuredProvider === "openrouter" || configuredProvider === "custom" || configuredProvider === "openai-codex";
|
|
90
|
+
const model = params.model ?? params.config.model ?? (defaultThroughGateway ? gatewayDefaults.model : void 0);
|
|
91
|
+
if (model) {
|
|
92
|
+
args.push("--model", model);
|
|
93
|
+
const provider = configuredProvider ?? "openrouter";
|
|
94
|
+
if (provider) args.push("--provider", provider);
|
|
95
|
+
}
|
|
96
|
+
if (params.config.toolsets?.length) args.push("--toolsets", params.config.toolsets.join(","));
|
|
97
|
+
if (params.sessionId) {
|
|
98
|
+
this.releaseTurnLease(params.sessionId);
|
|
99
|
+
args.push("--resume", params.sessionId);
|
|
100
|
+
}
|
|
101
|
+
if (params.config.bypassPermissions !== false) args.push("--yolo");
|
|
102
|
+
if (params.config.extraFlags?.length) args.push(...params.config.extraFlags);
|
|
103
|
+
const { native: nativeImages, message: messageWithStrandedMarkers } = partitionImageAttachments({
|
|
104
|
+
message: params.message,
|
|
105
|
+
attachments: params.attachments,
|
|
106
|
+
qualifies: (attachment) => attachment.path !== void 0,
|
|
107
|
+
maxNative: 1
|
|
108
|
+
});
|
|
109
|
+
const nativePath = nativeImages[0]?.path;
|
|
110
|
+
const fullMessage = prependPromptSection(params.systemPrompt, messageWithStrandedMarkers);
|
|
111
|
+
if (nativePath) args.push("--image", nativePath);
|
|
112
|
+
args.push("-q", fullMessage);
|
|
113
|
+
return {
|
|
114
|
+
command: this.getCliPath(),
|
|
115
|
+
args,
|
|
116
|
+
useStdin: false
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
releaseTurnLease(sessionId) {
|
|
120
|
+
const home = this.config.runtimeHome?.trim();
|
|
121
|
+
if (!home) return;
|
|
122
|
+
try {
|
|
123
|
+
const db = new DatabaseSync(join(home, ".hermes", "state.db"), { timeout: 2e3 });
|
|
124
|
+
try {
|
|
125
|
+
db.prepare("DELETE FROM session_turn_leases WHERE conversation_id = ?").run(sessionId);
|
|
126
|
+
} finally {
|
|
127
|
+
db.close();
|
|
128
|
+
}
|
|
129
|
+
} catch {
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
buildExecEnv(config) {
|
|
134
|
+
const env = this.agentEnvironmentValues();
|
|
135
|
+
env.HERMES_HOME = this.resolveHermesHome();
|
|
136
|
+
const authMode = config.authMode ?? (config.apiKey ? "api-key" : "oauth");
|
|
137
|
+
const gatewayDefaults = resolveTangleRouterDefaults();
|
|
138
|
+
const configuredProvider = config.inferenceProvider;
|
|
139
|
+
const provider = configuredProvider ?? "openrouter";
|
|
140
|
+
const defaultThroughGateway = !configuredProvider || configuredProvider === "openrouter" || configuredProvider === "custom" || configuredProvider === "openai-codex";
|
|
141
|
+
if (authMode === "api-key" && config.apiKey) {
|
|
142
|
+
const keyEnv = PROVIDER_API_KEY_ENV[provider];
|
|
143
|
+
if (keyEnv) env[keyEnv] = config.apiKey;
|
|
144
|
+
}
|
|
145
|
+
const baseUrl = config.baseUrl || (defaultThroughGateway ? gatewayDefaults.baseUrl : void 0);
|
|
146
|
+
if (baseUrl) {
|
|
147
|
+
const urlEnv = PROVIDER_BASE_URL_ENV[provider];
|
|
148
|
+
if (urlEnv) env[urlEnv] = baseUrl;
|
|
149
|
+
}
|
|
150
|
+
const model = config.model ?? (defaultThroughGateway ? gatewayDefaults.model : void 0);
|
|
151
|
+
if (model) env.HERMES_INFERENCE_MODEL = model;
|
|
152
|
+
return env;
|
|
153
|
+
}
|
|
154
|
+
async afterCliProcessExit(params) {
|
|
155
|
+
const hermesSessionId = parseHermesSessionId(params.stderr);
|
|
156
|
+
if (!hermesSessionId) return;
|
|
157
|
+
for (const event of sessionObservedEvents(params.state, "hermes", hermesSessionId)) params.onEvent?.(event);
|
|
158
|
+
if (!params.exit.success) return;
|
|
159
|
+
const exported = await this.runCli({
|
|
160
|
+
command: this.getCliPath(),
|
|
161
|
+
args: [
|
|
162
|
+
"sessions",
|
|
163
|
+
"export",
|
|
164
|
+
"--session-id",
|
|
165
|
+
hermesSessionId,
|
|
166
|
+
"-"
|
|
167
|
+
],
|
|
168
|
+
cwd: params.workspaceRoot,
|
|
169
|
+
env: params.env,
|
|
170
|
+
timeoutMs: 15e3
|
|
171
|
+
});
|
|
172
|
+
if (!exported.exit.success) {
|
|
173
|
+
this.logger.warn("hermes: session export failed after run", {
|
|
174
|
+
sessionId: hermesSessionId,
|
|
175
|
+
exitCode: exported.exit.code,
|
|
176
|
+
stderr: exported.stderr.slice(0, 500)
|
|
177
|
+
});
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
let session;
|
|
181
|
+
try {
|
|
182
|
+
session = parseHermesExport(exported.stdout ?? "");
|
|
183
|
+
} catch (error) {
|
|
184
|
+
this.logger.warn("hermes: session export returned invalid JSON", {
|
|
185
|
+
sessionId: hermesSessionId,
|
|
186
|
+
error: error instanceof Error ? error.message : String(error)
|
|
187
|
+
});
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
if (!session) {
|
|
191
|
+
this.logger.warn("hermes: session export did not return JSON", { sessionId: hermesSessionId });
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
recordCliTokenUsage(params.state, {
|
|
195
|
+
usage: {
|
|
196
|
+
input_tokens: session.input_tokens,
|
|
197
|
+
output_tokens: session.output_tokens,
|
|
198
|
+
cache_read_input_tokens: session.cache_read_tokens,
|
|
199
|
+
cache_creation_input_tokens: session.cache_write_tokens
|
|
200
|
+
},
|
|
201
|
+
cost_usd: session.actual_cost_usd ?? session.estimated_cost_usd
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
createEventParser(state, onEvent) {
|
|
205
|
+
return plaintextResponseParser(state, onEvent, {
|
|
206
|
+
classify: (line) => line.startsWith("API call failed") || line.startsWith("Error:") || line.startsWith("hermes:") ? {
|
|
207
|
+
type: "error",
|
|
208
|
+
message: line
|
|
209
|
+
} : {
|
|
210
|
+
type: "text",
|
|
211
|
+
line
|
|
212
|
+
},
|
|
213
|
+
map: (event, response) => {
|
|
214
|
+
switch (event.type) {
|
|
215
|
+
case "text":
|
|
216
|
+
response.text(event.line);
|
|
217
|
+
return [];
|
|
218
|
+
case "error":
|
|
219
|
+
response.error(event.message);
|
|
220
|
+
return [{
|
|
221
|
+
type: "warning",
|
|
222
|
+
code: "HERMES_ERROR",
|
|
223
|
+
message: event.message
|
|
224
|
+
}];
|
|
225
|
+
case "complete": return [];
|
|
226
|
+
}
|
|
227
|
+
},
|
|
228
|
+
emptyFailureDetail: "hermes errored without producing a response body"
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
};
|
|
232
|
+
function parseHermesSessionId(stderr) {
|
|
233
|
+
return /(?:^|\n)\s*session_id:\s*([^\s]+)/i.exec(stderr)?.[1];
|
|
234
|
+
}
|
|
235
|
+
function parseHermesExport(stdout) {
|
|
236
|
+
const line = stdout.split(/\r?\n/).map((entry) => entry.trim()).find(Boolean);
|
|
237
|
+
if (!line) return void 0;
|
|
238
|
+
const parsed = JSON.parse(line);
|
|
239
|
+
return typeof parsed === "object" && parsed !== null ? parsed : void 0;
|
|
240
|
+
}
|
|
241
|
+
//#endregion
|
|
242
|
+
export { HermesProviderAdapter };
|
|
243
|
+
|
|
244
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { Mt as CliExecArgs, Pt as CliProviderConfig, Rt as ExecutionState, ht as CliProviderAdapterBase, n as HarnessId } 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/nanoclaw/types.d.ts
|
|
6
|
+
type NanoclawAuthMode = "api-key" | "oauth";
|
|
7
|
+
interface NanoclawConfig extends CliProviderConfig {
|
|
8
|
+
projectRoot?: string;
|
|
9
|
+
apiKey?: string;
|
|
10
|
+
authMode?: NanoclawAuthMode;
|
|
11
|
+
baseUrl?: string;
|
|
12
|
+
}
|
|
13
|
+
interface NanoclawTextEvent {
|
|
14
|
+
type: "text";
|
|
15
|
+
line: string;
|
|
16
|
+
}
|
|
17
|
+
interface NanoclawErrorEvent {
|
|
18
|
+
type: "error";
|
|
19
|
+
message: string;
|
|
20
|
+
}
|
|
21
|
+
interface NanoclawUsageEvent {
|
|
22
|
+
type: "usage";
|
|
23
|
+
usage: Record<string, unknown>;
|
|
24
|
+
raw: string;
|
|
25
|
+
}
|
|
26
|
+
interface NanoclawSessionEvent {
|
|
27
|
+
type: "session";
|
|
28
|
+
id: string;
|
|
29
|
+
}
|
|
30
|
+
type NanoclawEvent = NanoclawTextEvent | NanoclawErrorEvent | NanoclawUsageEvent | NanoclawSessionEvent;
|
|
31
|
+
//#endregion
|
|
32
|
+
//#region src/adapters/nanoclaw/adapter.d.ts
|
|
33
|
+
declare class NanoclawProviderAdapter extends CliProviderAdapterBase<NanoclawConfig, NanoclawEvent> {
|
|
34
|
+
readonly provider = "nanoclaw";
|
|
35
|
+
protected readonly profileHarness: HarnessId;
|
|
36
|
+
protected readonly defaultCliPath = "tsx";
|
|
37
|
+
protected buildExecArgs(params: {
|
|
38
|
+
message: string;
|
|
39
|
+
config: NanoclawConfig;
|
|
40
|
+
model?: string;
|
|
41
|
+
sessionId?: string;
|
|
42
|
+
workspaceRoot: string;
|
|
43
|
+
systemPrompt?: string;
|
|
44
|
+
}): CliExecArgs;
|
|
45
|
+
protected buildExecEnv(config: NanoclawConfig): Record<string, string | undefined>;
|
|
46
|
+
protected createEventParser(state: ExecutionState, onEvent?: (event: StreamEvent) => void): StreamParserConfig<NanoclawEvent>;
|
|
47
|
+
}
|
|
48
|
+
//#endregion
|
|
49
|
+
export { type NanoclawConfig, type NanoclawEvent, NanoclawProviderAdapter };
|
|
50
|
+
//# sourceMappingURL=index.d.mts.map
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { H as CliProviderAdapterBase, I as plaintextResponseParser, Tt as sessionObservedEvents, V as recordCliTokenUsage, ot as prependPromptSection, z as parseCliUsageLine } from "../../src-Fn8Pu1xq.mjs";
|
|
2
|
+
import { normalizeOpenAiCompatibleBaseUrl, resolveTangleRouterDefaults } from "@tangle-network/agent-interface";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
//#region src/adapters/nanoclaw/adapter.ts
|
|
5
|
+
var NanoclawProviderAdapter = class extends CliProviderAdapterBase {
|
|
6
|
+
provider = "nanoclaw";
|
|
7
|
+
profileHarness = "nanoclaw";
|
|
8
|
+
defaultCliPath = "tsx";
|
|
9
|
+
buildExecArgs(params) {
|
|
10
|
+
const projectRoot = params.config.projectRoot ?? process.env.NANOCLAW_PROJECT_ROOT ?? params.workspaceRoot;
|
|
11
|
+
const fullMessage = prependPromptSection(params.systemPrompt, params.message);
|
|
12
|
+
return {
|
|
13
|
+
command: join(projectRoot, "node_modules", ".bin", "tsx"),
|
|
14
|
+
args: [
|
|
15
|
+
join(projectRoot, "scripts", "chat.ts"),
|
|
16
|
+
"nanoclaw-chat",
|
|
17
|
+
params.sessionId ?? "-",
|
|
18
|
+
fullMessage
|
|
19
|
+
],
|
|
20
|
+
cwd: projectRoot,
|
|
21
|
+
useStdin: false
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
buildExecEnv(config) {
|
|
25
|
+
const env = this.agentEnvironmentValues();
|
|
26
|
+
if (config.projectRoot) env.NANOCLAW_PROJECT_ROOT = config.projectRoot;
|
|
27
|
+
env.NANOCLAW_NATIVE_CREDENTIALS ??= "true";
|
|
28
|
+
env.COREPACK_ENABLE_DOWNLOAD_PROMPT = "0";
|
|
29
|
+
const modelKey = config.apiKey ?? env.OPENCODE_MODEL_API_KEY;
|
|
30
|
+
const authMode = config.authMode ?? (modelKey ? "api-key" : "oauth");
|
|
31
|
+
if (authMode === "api-key" && modelKey) {
|
|
32
|
+
env.OPENCODE_MODEL_API_KEY = modelKey;
|
|
33
|
+
env.OPENAI_API_KEY = modelKey;
|
|
34
|
+
env.OPENROUTER_API_KEY = modelKey;
|
|
35
|
+
env.ANTHROPIC_AUTH_TOKEN = modelKey;
|
|
36
|
+
} else if (authMode !== "api-key") {
|
|
37
|
+
env.OPENCODE_MODEL_API_KEY = void 0;
|
|
38
|
+
env.OPENAI_API_KEY = void 0;
|
|
39
|
+
env.OPENROUTER_API_KEY = void 0;
|
|
40
|
+
env.ANTHROPIC_AUTH_TOKEN = void 0;
|
|
41
|
+
}
|
|
42
|
+
const gatewayDefaults = resolveTangleRouterDefaults(env);
|
|
43
|
+
const openAiBaseUrl = config.baseUrl ? normalizeOpenAiCompatibleBaseUrl(config.baseUrl) : gatewayDefaults.baseUrl;
|
|
44
|
+
env.OPENAI_BASE_URL ??= openAiBaseUrl;
|
|
45
|
+
env.OPENROUTER_BASE_URL ??= openAiBaseUrl;
|
|
46
|
+
env.ANTHROPIC_BASE_URL ??= resolveAnthropicBaseUrl(config.baseUrl ?? gatewayDefaults.rootUrl);
|
|
47
|
+
const model = config.model ?? gatewayDefaults.model;
|
|
48
|
+
if (model) env.TANGLE_ROUTER_MODEL = model;
|
|
49
|
+
return env;
|
|
50
|
+
}
|
|
51
|
+
createEventParser(state, onEvent) {
|
|
52
|
+
return plaintextResponseParser(state, onEvent, {
|
|
53
|
+
classify: classifyNanoclawLine,
|
|
54
|
+
map: (event, response) => {
|
|
55
|
+
switch (event.type) {
|
|
56
|
+
case "text":
|
|
57
|
+
response.text(event.line);
|
|
58
|
+
return [];
|
|
59
|
+
case "session":
|
|
60
|
+
if (state.sessionId === event.id) return [];
|
|
61
|
+
return sessionObservedEvents(state, "nanoclaw", event.id);
|
|
62
|
+
case "error":
|
|
63
|
+
response.error(event.message);
|
|
64
|
+
return [{
|
|
65
|
+
type: "warning",
|
|
66
|
+
code: "NANOCLAW_ERROR",
|
|
67
|
+
message: event.message
|
|
68
|
+
}];
|
|
69
|
+
case "usage":
|
|
70
|
+
recordCliTokenUsage(state, event.usage);
|
|
71
|
+
return [];
|
|
72
|
+
}
|
|
73
|
+
},
|
|
74
|
+
emptyFailureDetail: "nanoclaw exited without producing a response body"
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
function classifyNanoclawLine(line) {
|
|
79
|
+
if (line.length === 0) return null;
|
|
80
|
+
if (line.startsWith("nanoclaw-session:")) {
|
|
81
|
+
const id = line.slice(17).trim();
|
|
82
|
+
return id ? {
|
|
83
|
+
type: "session",
|
|
84
|
+
id
|
|
85
|
+
} : null;
|
|
86
|
+
}
|
|
87
|
+
if (line.startsWith("usage:")) {
|
|
88
|
+
try {
|
|
89
|
+
const usage = parseCliUsageLine(line);
|
|
90
|
+
if (usage) return {
|
|
91
|
+
type: "usage",
|
|
92
|
+
usage,
|
|
93
|
+
raw: line
|
|
94
|
+
};
|
|
95
|
+
} catch {}
|
|
96
|
+
return {
|
|
97
|
+
type: "error",
|
|
98
|
+
message: `Unparseable NanoClaw usage line: ${line}`
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
if (line.startsWith("NanoClaw daemon not reachable") || line.startsWith("CLI socket error:") || line.startsWith("timeout:")) return {
|
|
102
|
+
type: "error",
|
|
103
|
+
message: line
|
|
104
|
+
};
|
|
105
|
+
return {
|
|
106
|
+
type: "text",
|
|
107
|
+
line
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
function resolveAnthropicBaseUrl(baseUrl) {
|
|
111
|
+
return baseUrl.replace(/\/+$/, "").replace(/\/v\d+[^/]*$/, "");
|
|
112
|
+
}
|
|
113
|
+
//#endregion
|
|
114
|
+
export { NanoclawProviderAdapter };
|
|
115
|
+
|
|
116
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { Mt as CliExecArgs, Pt as CliProviderConfig, Rt as ExecutionState, ht as CliProviderAdapterBase, n as HarnessId, o as WorkspacePlanApplication } from "../../index-BpO3fvbf.mjs";
|
|
2
|
+
import { StreamParserConfig } from "@tangle-network/sdk-cli-runner";
|
|
3
|
+
import { CliAuthFile, ProviderConfig, StreamEvent } from "@tangle-network/agent-interface";
|
|
4
|
+
|
|
5
|
+
//#region src/adapters/openclaw/adapter.d.ts
|
|
6
|
+
/**
|
|
7
|
+
* OpenClaw configuration. `authMode` "config-only" means openclaw uses the
|
|
8
|
+
* config already in $HOME (a workspace restored from a snapshot); otherwise
|
|
9
|
+
* the adapter synthesizes a router-backed `~/.openclaw/openclaw.json` unless
|
|
10
|
+
* `authFiles` already carries one.
|
|
11
|
+
*/
|
|
12
|
+
interface OpenclawConfig extends CliProviderConfig {
|
|
13
|
+
authMode?: "auth-files" | "config-only";
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* OpenClaw's embedded agent: `openclaw agent --local --json --agent main
|
|
17
|
+
* --session-id <id> -m "<prompt>"`, configured by `~/.openclaw/openclaw.json`.
|
|
18
|
+
* It does not stream: `--json` prints one envelope when the turn ends, and
|
|
19
|
+
* that envelope is the only place it reports usage and its session id.
|
|
20
|
+
*/
|
|
21
|
+
declare class OpenclawProviderAdapter extends CliProviderAdapterBase<OpenclawConfig, never> {
|
|
22
|
+
readonly provider = "openclaw";
|
|
23
|
+
protected readonly profileHarness: HarnessId;
|
|
24
|
+
protected readonly defaultCliPath = "openclaw";
|
|
25
|
+
/**
|
|
26
|
+
* Managed `~/.openclaw/openclaw.json` synthesized during initialize() and
|
|
27
|
+
* materialized to disk by the sidecar via getManagedAuthFiles(). Empty when
|
|
28
|
+
* the caller manages openclaw config itself.
|
|
29
|
+
*/
|
|
30
|
+
private managedAuthFiles;
|
|
31
|
+
/**
|
|
32
|
+
* Openclaw reads NO credentials from env — it loads them from
|
|
33
|
+
* `~/.openclaw/openclaw.json`. A managed sandbox provisions none, so without
|
|
34
|
+
* a synthesized config openclaw falls back to its bundled `claude-cli`
|
|
35
|
+
* backend (which needs a Claude login) and the session never starts. Always
|
|
36
|
+
* synthesize a router-backed config so `openclaw agent --local` authenticates
|
|
37
|
+
* against the Tangle router, unless the caller manages config itself
|
|
38
|
+
* (authMode "config-only") or already supplied an `openclaw.json`.
|
|
39
|
+
*/
|
|
40
|
+
protected afterInitialize(_config: ProviderConfig): Promise<void>;
|
|
41
|
+
getManagedAuthFiles(): CliAuthFile[];
|
|
42
|
+
private computeManagedAuthFiles;
|
|
43
|
+
protected buildExecArgs(params: {
|
|
44
|
+
message: string;
|
|
45
|
+
config: OpenclawConfig;
|
|
46
|
+
model?: string;
|
|
47
|
+
sessionId?: string;
|
|
48
|
+
mintedSessionId?: string;
|
|
49
|
+
workspaceRoot: string;
|
|
50
|
+
systemPrompt?: string;
|
|
51
|
+
}): CliExecArgs;
|
|
52
|
+
protected buildExecEnv(config: OpenclawConfig): Record<string, string | undefined>;
|
|
53
|
+
/**
|
|
54
|
+
* openclaw's file and exec tools resolve against its agent workspace
|
|
55
|
+
* (`~/.openclaw/workspace` by default), not the process cwd, so a turn that
|
|
56
|
+
* did not pin it edited a directory the caller never sees.
|
|
57
|
+
*/
|
|
58
|
+
protected buildTurnEnvironment(executionConfig: OpenclawConfig, profilePlan: WorkspacePlanApplication | undefined, workspaceRoot: string, correlationHeaders: Readonly<Record<string, string>> | undefined): Record<string, string | undefined>;
|
|
59
|
+
protected createEventParser(state: ExecutionState, onEvent?: (event: StreamEvent) => void): StreamParserConfig<never>;
|
|
60
|
+
/**
|
|
61
|
+
* Parse the buffered stdout as openclaw's JSON envelope and synthesize the
|
|
62
|
+
* canonical message.part.updated + status:completed events.
|
|
63
|
+
*/
|
|
64
|
+
private flushEnvelope;
|
|
65
|
+
}
|
|
66
|
+
//#endregion
|
|
67
|
+
export { OpenclawProviderAdapter };
|
|
68
|
+
//# sourceMappingURL=index.d.mts.map
|