nolo-cli 0.8.0 → 0.9.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/_executeModel-UD44KGZ4.js +203 -0
- package/action-ZJWE3Y5S.js +28 -0
- package/addContentAction-TVDBNJM5.js +26 -0
- package/addDialogAgentAction-EKH774VT.js +68 -0
- package/agentDeleteCommand-TCPEFJTF.js +327 -0
- package/agentEmailCommands-CZ3UILZ4.js +626 -0
- package/agentListCommands-SJKO2FFB.js +223 -0
- package/agentMachineCommands-PSNABISZ.js +425 -0
- package/agentPullCommand-O2MTUAFR.js +122 -0
- package/agentRecordCommands-MH2JKFHS.js +94 -0
- package/agentRunCommand-4KH6MIZR.js +110 -0
- package/agentRunControl-K4VKNEHF.js +57 -0
- package/agentRuntimeLocal-SKHJUWSS.js +104 -0
- package/agentSlice-3WXXN4VK.js +42 -0
- package/authCommand-PXFX6JDT.js +581 -0
- package/authCommands-356AYWEK.js +35 -0
- package/chunk-2EISRLRC.js +238 -0
- package/chunk-2FTTDCD4.js +675 -0
- package/chunk-2K2ECKSG.js +222 -0
- package/chunk-2PUGVR6E.js +19 -0
- package/chunk-3ASDTTEI.js +1774 -0
- package/chunk-3EUW3WEO.js +8 -0
- package/chunk-3LY4F7SV.js +9293 -0
- package/chunk-3TZDXYSF.js +71 -0
- package/chunk-3WYQEUBI.js +34 -0
- package/chunk-4CQLVGRV.js +50 -0
- package/chunk-4IJYA27C.js +342 -0
- package/chunk-4K2KKCSD.js +577 -0
- package/chunk-4SN6J65J.js +38 -0
- package/chunk-4VNS5WPM.js +42 -0
- package/chunk-4ZDM73SD.js +34 -0
- package/chunk-5CS33IBL.js +301 -0
- package/chunk-5KLGBAAR.js +386 -0
- package/chunk-5MIDPSSK.js +206 -0
- package/chunk-5MMAK75Q.js +15 -0
- package/chunk-5PJ3VWCS.js +360 -0
- package/chunk-63SLEOLK.js +175 -0
- package/chunk-63W5N6P3.js +150 -0
- package/chunk-6GANEXVO.js +231 -0
- package/chunk-6HYVJV7B.js +102 -0
- package/chunk-6WD3OOJS.js +20 -0
- package/chunk-7OOXPE3N.js +628 -0
- package/chunk-7QRKCBOP.js +1078 -0
- package/chunk-ATNTHIZI.js +13 -0
- package/chunk-AUQ747NZ.js +902 -0
- package/chunk-AVMKZHBC.js +85 -0
- package/chunk-AZPCASRE.js +36 -0
- package/chunk-BBYVOSU2.js +792 -0
- package/chunk-C3RUNRHT.js +51 -0
- package/chunk-CF2WZF4N.js +134 -0
- package/chunk-CF7PE763.js +10 -0
- package/chunk-CKOJQDKR.js +198 -0
- package/chunk-COMXDWNM.js +807 -0
- package/chunk-CPB2YM4D.js +171 -0
- package/chunk-CWMSB67P.js +34 -0
- package/chunk-DCOA4QSN.js +105 -0
- package/chunk-DFFIZ25G.js +30 -0
- package/chunk-DWLEOOGR.js +8 -0
- package/chunk-DZ3XJVET.js +231 -0
- package/chunk-EHLHSX7R.js +1433 -0
- package/chunk-ELRRLDWI.js +478 -0
- package/chunk-EXTIQUCI.js +482 -0
- package/chunk-EYEEHCU4.js +3066 -0
- package/chunk-G3SUCT4W.js +8 -0
- package/chunk-G43KEVSC.js +1447 -0
- package/chunk-GAKEBQD6.js +30 -0
- package/chunk-GBRG75BQ.js +86 -0
- package/chunk-GG4AJPSR.js +191 -0
- package/chunk-H33743XH.js +25 -0
- package/chunk-HNMXYYJR.js +12 -0
- package/chunk-I42VC5KR.js +15 -0
- package/chunk-IDZTNRP2.js +85 -0
- package/chunk-ISNCLGUZ.js +146 -0
- package/chunk-IWX4UW2E.js +548 -0
- package/chunk-JBTJAPUF.js +35 -0
- package/chunk-JEXVIMYZ.js +55 -0
- package/chunk-JRKKFRAV.js +537 -0
- package/chunk-JZPBVBIY.js +94 -0
- package/chunk-KKY4B2Q2.js +21 -0
- package/chunk-KOCA5FCS.js +4750 -0
- package/chunk-KQHGZWSV.js +63 -0
- package/chunk-KTVVPRJS.js +138 -0
- package/chunk-KUG52IAP.js +8 -0
- package/chunk-KX6YBIHG.js +8 -0
- package/chunk-LARL2V6G.js +9017 -0
- package/chunk-LCBAMY2M.js +60 -0
- package/chunk-LM6IYQ3F.js +16 -0
- package/chunk-M76ECQRD.js +13658 -0
- package/chunk-MGOJ5R6J.js +113 -0
- package/chunk-MKMWT7SA.js +27196 -0
- package/chunk-MRC4Q34M.js +188 -0
- package/chunk-OLZBQWZU.js +6 -0
- package/chunk-OPZYGHUC.js +89 -0
- package/chunk-OWOHNGCN.js +50 -0
- package/chunk-PAKN26FP.js +239 -0
- package/chunk-PCWC3JTN.js +91 -0
- package/chunk-PG5PNA7Y.js +939 -0
- package/chunk-Q2YZULBH.js +104 -0
- package/chunk-QSJ3HFEF.js +8 -0
- package/chunk-QYXLLLGL.js +4519 -0
- package/chunk-ROWQEJRP.js +139 -0
- package/chunk-S7Z2HMCN.js +25 -0
- package/chunk-SBR32ZZS.js +1901 -0
- package/chunk-SH2CFQOH.js +3391 -0
- package/chunk-SL35K7AH.js +226 -0
- package/chunk-TILFE6LV.js +381 -0
- package/chunk-TSS3XJY4.js +2052 -0
- package/chunk-U4TRT5V4.js +246 -0
- package/chunk-U6VC4MU4.js +8 -0
- package/chunk-UAD2WT54.js +64 -0
- package/chunk-UUJDGGAK.js +421 -0
- package/chunk-VF4K2QE6.js +21 -0
- package/chunk-VHBWHNVT.js +59 -0
- package/chunk-VIDPVFP3.js +20 -0
- package/chunk-VP4WJWKW.js +8882 -0
- package/chunk-W4NVOSFF.js +37 -0
- package/chunk-WKM6FH35.js +190 -0
- package/chunk-WWC7I6TA.js +8 -0
- package/chunk-X7W4TNB4.js +1550 -0
- package/chunk-XE635NI4.js +1948 -0
- package/chunk-XKIMRZO2.js +221 -0
- package/chunk-XS466O7S.js +933 -0
- package/chunk-Y5GCAMGP.js +9 -0
- package/chunk-YBWOP46I.js +3272 -0
- package/chunk-YPRZSPF3.js +148 -0
- package/chunk-YYUCRDOK.js +69 -0
- package/chunk-Z4NR32XR.js +50 -0
- package/chunk-ZIG5LJ7X.js +24765 -0
- package/chunk-ZNFJWEN4.js +56 -0
- package/chunk-ZQ2UM4KG.js +2878 -0
- package/cliExecutor-DNE7TCC4.js +36 -0
- package/clipboardy-BVE3LVEH.js +12001 -0
- package/createAgentAutomationAction-63OIP6X5.js +866 -0
- package/createDialogAction-ZLYZDYBB.js +54 -0
- package/createPageAction-AL5FSDCK.js +171 -0
- package/db-HCJ5PRB5.js +271 -0
- package/dbSlice-PR44QPXY.js +60 -0
- package/deleteFile-4SKGPHOZ.js +41 -0
- package/dialogCommands-F6YI5742.js +63 -0
- package/dialogSlice-JSBNZRLR.js +148 -0
- package/docCreateCommands-4CTO7ERT.js +219 -0
- package/docDeleteCommands-VBWERDRG.js +180 -0
- package/docReadCommands-KNP4MFYB.js +133 -0
- package/docStore-ADP5VYY4.js +98 -0
- package/docUpdateCommands-4BCBJQHA.js +317 -0
- package/fetchMessages-U6ZHN56A.js +17 -0
- package/getPricing-3E6UNPKL.js +30 -0
- package/handleSendMessageAction-IJDQ6ARA.js +185 -0
- package/index.js +188 -112943
- package/lib-FYYBQIXS.js +19839 -0
- package/localDialogRead-Z5UTAJPU.js +26 -0
- package/localFirstLog-DHNOY2NA.js +19 -0
- package/localRuntimeAuthority-TEGCOWX4.js +471 -0
- package/localRuntimeDb-LGDF6FQP.js +12 -0
- package/machineCommands-EA3M4XTN.js +779 -0
- package/machineInfo-M6KB6HZN.js +10 -0
- package/machineWsRunDispatch-NAPKE5ZA.js +110 -0
- package/memoryCommands-O4MIPIWQ.js +476 -0
- package/models-4OPOOLFS.js +9 -0
- package/offlineMarxistsAgentCommand-BCPJITJL.js +242 -0
- package/package.json +3 -25
- package/read-RIJCIVKX.js +17 -0
- package/readDocTool-GZD2N3LO.js +16 -0
- package/readlineWorkspace-KMWT4T4S.js +5509 -0
- package/removeDialogAgentAction-GJQJNDW6.js +73 -0
- package/runAgentClientLoop-U5Q6NDTJ.js +291 -0
- package/runtimeDoctorCommands-LRHLPDRC.js +289 -0
- package/setDialogExtraReferencesAction-M7OQG54N.js +60 -0
- package/setPrimaryDialogAgentAction-46UNFJDL.js +80 -0
- package/settingSlice-FVUUH4JA.js +199 -0
- package/skillSummaryMarker-42HKSXYY.js +9 -0
- package/slateToRenderMarkdown-Y5IYN73U.js +7 -0
- package/slateUtils-2M7MUTWX.js +19 -0
- package/spaceCommands-E2CFRPZJ.js +454 -0
- package/spaceSlice-L3R6IMXE.js +147 -0
- package/streamAgentChatTurn-UBDAOQWE.js +4528 -0
- package/tableCommands-GOFP7QKA.js +1286 -0
- package/toolApiClient-QI3YBNWB.js +26 -0
- package/tools-TMJXZTCA.js +85 -0
- package/tuiSummaryLlmCaller-RV3THLZF.js +78 -0
- package/understanding-GQKNDDWM.js +271 -0
- package/updateCommands-VOSPKXFF.js +31 -0
- package/updateDialogTitleAction-ZTWRDXI2.js +188 -0
|
@@ -0,0 +1,1078 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createCliLocalRuntimeAdapter,
|
|
3
|
+
summarizeEndpoint
|
|
4
|
+
} from "./chunk-LARL2V6G.js";
|
|
5
|
+
import {
|
|
6
|
+
clipMultilineText
|
|
7
|
+
} from "./chunk-MKMWT7SA.js";
|
|
8
|
+
import {
|
|
9
|
+
readPipeText,
|
|
10
|
+
spawnProcess
|
|
11
|
+
} from "./chunk-IDZTNRP2.js";
|
|
12
|
+
import {
|
|
13
|
+
parseUserIdFromAuthToken
|
|
14
|
+
} from "./chunk-ISNCLGUZ.js";
|
|
15
|
+
import {
|
|
16
|
+
DEFAULT_NOLO_SERVER_URL
|
|
17
|
+
} from "./chunk-OLZBQWZU.js";
|
|
18
|
+
import {
|
|
19
|
+
runLocalAgentTurn
|
|
20
|
+
} from "./chunk-XS466O7S.js";
|
|
21
|
+
import {
|
|
22
|
+
resolveLocalRuntimeEnvFromPolicy
|
|
23
|
+
} from "./chunk-5CS33IBL.js";
|
|
24
|
+
import {
|
|
25
|
+
toErrorMessage
|
|
26
|
+
} from "./chunk-HNMXYYJR.js";
|
|
27
|
+
import {
|
|
28
|
+
asRecordOrEmpty
|
|
29
|
+
} from "./chunk-KX6YBIHG.js";
|
|
30
|
+
import {
|
|
31
|
+
asTrimmedNonEmptyStringArray
|
|
32
|
+
} from "./chunk-I42VC5KR.js";
|
|
33
|
+
import {
|
|
34
|
+
asTrimmedString
|
|
35
|
+
} from "./chunk-3EUW3WEO.js";
|
|
36
|
+
import {
|
|
37
|
+
asOptionalPositiveFiniteNumber
|
|
38
|
+
} from "./chunk-U6VC4MU4.js";
|
|
39
|
+
import {
|
|
40
|
+
asOptionalTrimmedString
|
|
41
|
+
} from "./chunk-G3SUCT4W.js";
|
|
42
|
+
import {
|
|
43
|
+
isRecord
|
|
44
|
+
} from "./chunk-KUG52IAP.js";
|
|
45
|
+
|
|
46
|
+
// packages/ai/agent/machineRunPermissions.ts
|
|
47
|
+
var DEFAULT_POLICY = {
|
|
48
|
+
mode: "read_only",
|
|
49
|
+
allowFilesystemRead: true,
|
|
50
|
+
allowFilesystemWrite: false,
|
|
51
|
+
allowShell: false,
|
|
52
|
+
writableRoots: []
|
|
53
|
+
};
|
|
54
|
+
var WRITE_DENIED = "Machine permission denied: this bound machine agent is read-only for filesystem writes. Enable machine write permission for this agent before asking it to modify files.";
|
|
55
|
+
var SHELL_DENIED = "Machine permission denied: this bound machine agent cannot run arbitrary shell commands. Enable machine shell permission for this agent before asking it to execute commands.";
|
|
56
|
+
function normalizeWritableRoots(value) {
|
|
57
|
+
return asTrimmedNonEmptyStringArray(value);
|
|
58
|
+
}
|
|
59
|
+
function resolveMachineRunPermissionPolicy(agentConfig) {
|
|
60
|
+
const runtimeBinding = asRecordOrEmpty(agentConfig?.runtimeBinding);
|
|
61
|
+
const raw = asRecordOrEmpty(
|
|
62
|
+
agentConfig?.machinePermissions ?? runtimeBinding.permissions ?? runtimeBinding.machinePermissions
|
|
63
|
+
);
|
|
64
|
+
const mode = raw.mode === "full_access" || raw.allowFilesystemWrite === true || raw.allowShell === true ? "full_access" : "read_only";
|
|
65
|
+
if (mode === "full_access") {
|
|
66
|
+
return {
|
|
67
|
+
mode,
|
|
68
|
+
allowFilesystemRead: raw.allowFilesystemRead !== false,
|
|
69
|
+
allowFilesystemWrite: true,
|
|
70
|
+
allowShell: raw.allowShell !== false,
|
|
71
|
+
writableRoots: normalizeWritableRoots(raw.writableRoots)
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
return {
|
|
75
|
+
...DEFAULT_POLICY,
|
|
76
|
+
allowFilesystemRead: raw.allowFilesystemRead !== false
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
var WRITE_INTENT_RE = /\b(write|overwrite|edit|modify|delete|remove|rename|move|create|save|patch|apply patch|mkdir|touch|rm|rmdir|del|erase|copy-item|move-item|remove-item|set-content|add-content|new-item)\b|(\u5199\u5165|\u5199\u6587\u4EF6|\u5220\u9664|\u79FB\u9664|\u91CD\u547D\u540D|\u79FB\u52A8|\u521B\u5EFA|\u65B0\u5EFA|\u4FDD\u5B58|\u4FEE\u6539|\u7F16\u8F91|\u6253\u8865\u4E01|\u5E94\u7528\u8865\u4E01)/i;
|
|
80
|
+
var SHELL_INTENT_RE = /\b(run|execute|exec)\s+(?:a\s+)?(?:shell|command|terminal|powershell|pwsh|bash|zsh|cmd\.exe|npm|bun|node|python|git|curl|wget|ssh|scp|chmod|chown|sudo|tests?|test suite)\b|\b(open|start)\s+(?:a\s+)?(?:shell|terminal)\b|\b(powershell|pwsh|bash|zsh|cmd\.exe|ssh|sudo)\b|(\u8FD0\u884C\u547D\u4EE4|\u6267\u884C\u547D\u4EE4|\u547D\u4EE4\u884C|\u7EC8\u7AEF|\u63A7\u5236\u53F0)/i;
|
|
81
|
+
var NEGATION_RE = /\b(do not|don't|dont|never|no need to|without|非目标|不要|不需要|禁止|无需)\b|[\u4E0D\u975E]/i;
|
|
82
|
+
function stripNegatedPolicySentences(task) {
|
|
83
|
+
return task.split(/([\n.;!?。;!?])/).reduce((segments, part, index, parts) => {
|
|
84
|
+
if (index % 2 === 1) return segments;
|
|
85
|
+
const separator = parts[index + 1] ?? "";
|
|
86
|
+
const segment = `${part}${separator}`;
|
|
87
|
+
const mentionsRestrictedAction = WRITE_INTENT_RE.test(segment) || SHELL_INTENT_RE.test(segment);
|
|
88
|
+
if (mentionsRestrictedAction && NEGATION_RE.test(segment)) return segments;
|
|
89
|
+
segments.push(segment);
|
|
90
|
+
return segments;
|
|
91
|
+
}, []).join("");
|
|
92
|
+
}
|
|
93
|
+
function assertMachineRunAllowed(userInput, policy) {
|
|
94
|
+
const task = stripNegatedPolicySentences(String(userInput || ""));
|
|
95
|
+
if (!policy.allowFilesystemWrite && WRITE_INTENT_RE.test(task)) {
|
|
96
|
+
throw new Error(WRITE_DENIED);
|
|
97
|
+
}
|
|
98
|
+
if (!policy.allowShell && SHELL_INTENT_RE.test(task)) {
|
|
99
|
+
throw new Error(SHELL_DENIED);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
function buildMachinePermissionPromptBlock(policy) {
|
|
103
|
+
return [
|
|
104
|
+
"--- Machine permission policy ---",
|
|
105
|
+
`Mode: ${policy.mode}`,
|
|
106
|
+
`Filesystem reads are ${policy.allowFilesystemRead ? "allowed" : "not allowed"}.`,
|
|
107
|
+
`File writes are ${policy.allowFilesystemWrite ? "allowed" : "not allowed"}.`,
|
|
108
|
+
`Arbitrary shell commands are ${policy.allowShell ? "allowed" : "not allowed"}.`,
|
|
109
|
+
policy.writableRoots.length ? `Writable roots: ${policy.writableRoots.join(", ")}` : "Writable roots: none.",
|
|
110
|
+
"If the user asks for an operation outside this policy, refuse instead of attempting it."
|
|
111
|
+
].join("\n");
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// packages/cli/connectorRunArtifact.ts
|
|
115
|
+
import { existsSync } from "node:fs";
|
|
116
|
+
import { resolve } from "node:path";
|
|
117
|
+
var MAX_PATCH_PREVIEW_CHARS = 24e3;
|
|
118
|
+
function normalizePath(value) {
|
|
119
|
+
return resolve(value.trim());
|
|
120
|
+
}
|
|
121
|
+
function resolveConnectorRunCwd(args) {
|
|
122
|
+
const explicit = args.env?.NOLO_CONNECTOR_WORKDIR || args.env?.NOLO_AGENT_WORKDIR || "";
|
|
123
|
+
const candidate = explicit || args.policy.writableRoots[0] || args.fallbackCwd || process.cwd();
|
|
124
|
+
const cwd = normalizePath(candidate);
|
|
125
|
+
if (!existsSync(cwd)) {
|
|
126
|
+
throw new Error(`Connector run cwd does not exist: ${cwd}`);
|
|
127
|
+
}
|
|
128
|
+
return cwd;
|
|
129
|
+
}
|
|
130
|
+
async function runGit(args, cwd, options = {}) {
|
|
131
|
+
const proc = spawnProcess({
|
|
132
|
+
cmd: ["git", ...args],
|
|
133
|
+
cwd,
|
|
134
|
+
stdout: "pipe",
|
|
135
|
+
stderr: "pipe",
|
|
136
|
+
stdin: "ignore"
|
|
137
|
+
});
|
|
138
|
+
const [stdout, exitCode] = await Promise.all([
|
|
139
|
+
readPipeText(proc.stdout),
|
|
140
|
+
proc.exited
|
|
141
|
+
]);
|
|
142
|
+
if (exitCode !== 0) return null;
|
|
143
|
+
return options.trim === false ? stdout.replace(/\r?\n$/, "") : stdout.trim();
|
|
144
|
+
}
|
|
145
|
+
function parseStatusChangedFiles(statusShort) {
|
|
146
|
+
if (!statusShort) return [];
|
|
147
|
+
return [...new Set(statusShort.split(/\r?\n/).map((line) => {
|
|
148
|
+
const porcelainMatch = line.match(/^.{2} (.+)$/);
|
|
149
|
+
if (porcelainMatch?.[1]) return porcelainMatch[1].trim();
|
|
150
|
+
const trimmedMatch = line.match(/^[MADRCU?!]{1,2}\s+(.+)$/);
|
|
151
|
+
return trimmedMatch?.[1]?.trim() ?? "";
|
|
152
|
+
}).map((line) => line.includes(" -> ") ? line.split(" -> ").at(-1) ?? line : line).filter(Boolean))];
|
|
153
|
+
}
|
|
154
|
+
async function readConnectorGitHead(cwd) {
|
|
155
|
+
return runGit(["rev-parse", "HEAD"], cwd);
|
|
156
|
+
}
|
|
157
|
+
async function collectConnectorRunArtifact(args) {
|
|
158
|
+
const collectedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
159
|
+
try {
|
|
160
|
+
const [headSha, statusShort, diffStat, patchText] = await Promise.all([
|
|
161
|
+
readConnectorGitHead(args.cwd),
|
|
162
|
+
runGit(["status", "--short"], args.cwd, { trim: false }),
|
|
163
|
+
runGit(["diff", "--stat"], args.cwd),
|
|
164
|
+
runGit(["diff", "--no-color", "--unified=3"], args.cwd)
|
|
165
|
+
]);
|
|
166
|
+
const patchPreview = patchText ? clipMultilineText(patchText, MAX_PATCH_PREVIEW_CHARS) || void 0 : void 0;
|
|
167
|
+
return {
|
|
168
|
+
cwd: args.cwd,
|
|
169
|
+
exitStatus: args.exitStatus,
|
|
170
|
+
collectedAt,
|
|
171
|
+
baseSha: args.baseSha ?? null,
|
|
172
|
+
headSha,
|
|
173
|
+
changedFiles: parseStatusChangedFiles(statusShort),
|
|
174
|
+
...statusShort ? { statusShort } : {},
|
|
175
|
+
...diffStat ? { diffStat } : {},
|
|
176
|
+
...patchPreview ? { patchPreview } : {},
|
|
177
|
+
...args.error ? { error: args.error } : {}
|
|
178
|
+
};
|
|
179
|
+
} catch (error) {
|
|
180
|
+
return {
|
|
181
|
+
cwd: args.cwd,
|
|
182
|
+
exitStatus: args.exitStatus,
|
|
183
|
+
collectedAt,
|
|
184
|
+
baseSha: args.baseSha ?? null,
|
|
185
|
+
...args.error ? { error: args.error } : {},
|
|
186
|
+
artifactError: toErrorMessage(error)
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// packages/cli/machineWsPromptMaterialization.ts
|
|
192
|
+
import { createHash } from "node:crypto";
|
|
193
|
+
import { mkdirSync, writeFileSync } from "node:fs";
|
|
194
|
+
import { join } from "node:path";
|
|
195
|
+
var CLOUD_PROMPT_PAGE_READ_COMMAND = "bun packages/cli/index.ts doc read";
|
|
196
|
+
function byteLength(value) {
|
|
197
|
+
return Buffer.byteLength(value, "utf8");
|
|
198
|
+
}
|
|
199
|
+
function shortHash(value) {
|
|
200
|
+
return createHash("sha256").update(value).digest("hex").slice(0, 12);
|
|
201
|
+
}
|
|
202
|
+
function resolvePromptInlineMaxBytes(env) {
|
|
203
|
+
const raw = Number(env.NOLO_CONNECTOR_PROMPT_INLINE_MAX_BYTES);
|
|
204
|
+
return Number.isFinite(raw) && raw >= 1024 ? raw : 32e3;
|
|
205
|
+
}
|
|
206
|
+
function materializeLargeConnectorPrompt(args) {
|
|
207
|
+
const promptBytes = byteLength(args.prompt);
|
|
208
|
+
const promptHash = shortHash(args.prompt);
|
|
209
|
+
const maxInlineBytes = resolvePromptInlineMaxBytes(args.env);
|
|
210
|
+
if (promptBytes <= maxInlineBytes) {
|
|
211
|
+
return {
|
|
212
|
+
prompt: args.prompt,
|
|
213
|
+
promptBytes,
|
|
214
|
+
promptHash,
|
|
215
|
+
promptRef: null
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
const promptDir = join(args.cwd, ".nolo", "agent-prompts");
|
|
219
|
+
mkdirSync(promptDir, { recursive: true });
|
|
220
|
+
const promptRef = join(promptDir, `${args.requestId}-${promptHash}.md`);
|
|
221
|
+
writeFileSync(promptRef, args.prompt, "utf8");
|
|
222
|
+
return {
|
|
223
|
+
prompt: [
|
|
224
|
+
"A large Nolo runtime prompt has been materialized outside this command argument.",
|
|
225
|
+
...args.runtimePromptPage?.dbKey ? [
|
|
226
|
+
"Cloud prompt page is the shared audit/context source.",
|
|
227
|
+
`Cloud prompt page: ${args.runtimePromptPage.dbKey}`,
|
|
228
|
+
`Read cloud page: ${CLOUD_PROMPT_PAGE_READ_COMMAND} ${JSON.stringify(args.runtimePromptPage.dbKey)}`,
|
|
229
|
+
...args.runtimePromptPage.promptHash ? [`Cloud prompt sha256 prefix: ${args.runtimePromptPage.promptHash}`] : [],
|
|
230
|
+
""
|
|
231
|
+
] : [],
|
|
232
|
+
"Local prompt file is the execution-machine fallback and should match the cloud page content at run start.",
|
|
233
|
+
`Prompt file: ${promptRef}`,
|
|
234
|
+
`Prompt bytes: ${promptBytes}`,
|
|
235
|
+
`Prompt sha256 prefix: ${promptHash}`,
|
|
236
|
+
"",
|
|
237
|
+
"Prefer the cloud prompt page for shared context when readable; use the local prompt file as fallback.",
|
|
238
|
+
"Local repository edits, diffs, test output, and commits are still authoritative for local execution facts.",
|
|
239
|
+
"If neither source is readable, stop and report PROMPT_REF_UNREADABLE with both references."
|
|
240
|
+
].join("\n"),
|
|
241
|
+
promptBytes,
|
|
242
|
+
promptHash,
|
|
243
|
+
promptRef
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
function readRuntimePromptPageMeta(parsed) {
|
|
247
|
+
const page = parsed?.payload?.meta?.runtimePromptPage;
|
|
248
|
+
if (!page || typeof page !== "object") return null;
|
|
249
|
+
return {
|
|
250
|
+
dbKey: typeof page.dbKey === "string" ? page.dbKey : void 0,
|
|
251
|
+
promptHash: typeof page.promptHash === "string" ? page.promptHash : void 0,
|
|
252
|
+
contentBytes: typeof page.contentBytes === "number" ? page.contentBytes : void 0
|
|
253
|
+
};
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
// packages/cli/machineWsRunDispatchPurity.ts
|
|
257
|
+
function logConnectorRun(message, fields = {}) {
|
|
258
|
+
console.error(`[nolo-connector] ${message} ${JSON.stringify(fields)}`);
|
|
259
|
+
}
|
|
260
|
+
function summarizeRuntimePolicyForLogs(policy) {
|
|
261
|
+
return {
|
|
262
|
+
hasPolicy: Boolean(policy),
|
|
263
|
+
runtimeTools: policy?.runtimeTools ?? [],
|
|
264
|
+
agentTools: policy?.agentTools ?? [],
|
|
265
|
+
workspaceMode: policy?.workspace?.mode ?? null,
|
|
266
|
+
workspaceCwd: policy?.workspace?.cwd ?? null,
|
|
267
|
+
shellEnabled: policy?.shell?.enabled ?? null
|
|
268
|
+
};
|
|
269
|
+
}
|
|
270
|
+
function summarizeAgentConfigForLogs(agentConfig) {
|
|
271
|
+
const config = asRecordOrEmpty(agentConfig);
|
|
272
|
+
const runtimeBinding = asRecordOrEmpty(config.runtimeBinding);
|
|
273
|
+
return {
|
|
274
|
+
apiSource: readField(config, "apiSource") ?? null,
|
|
275
|
+
provider: readField(config, "provider") ?? null,
|
|
276
|
+
cliProvider: readField(config, "cliProvider") ?? null,
|
|
277
|
+
model: readField(config, "model") ?? null,
|
|
278
|
+
customProviderEndpoint: summarizeEndpoint(readField(config, "customProviderUrl")) ?? null,
|
|
279
|
+
useServerProxy: readField(config, "useServerProxy") ?? null,
|
|
280
|
+
skipLocalRuntimeEnsure: readField(config, "skipLocalRuntimeEnsure") ?? null,
|
|
281
|
+
hasApiKey: isNonEmptyString(readField(config, "apiKey")),
|
|
282
|
+
apiKeyHeader: readField(config, "apiKeyHeader") ?? null,
|
|
283
|
+
hasApiKeyFromAgentKey: (() => {
|
|
284
|
+
const value = readField(config, "apiKeyFromAgentKey");
|
|
285
|
+
return typeof value === "string" && value.length > 0;
|
|
286
|
+
})(),
|
|
287
|
+
runtimeBindingKind: readField(runtimeBinding, "kind") ?? null,
|
|
288
|
+
runtimeMachineId: readField(runtimeBinding, "machineId") ?? null,
|
|
289
|
+
connectorSurface: readField(runtimeBinding, "connectorSurface") ?? readField(runtimeBinding, "surface") ?? null
|
|
290
|
+
};
|
|
291
|
+
}
|
|
292
|
+
function readField(record, key) {
|
|
293
|
+
if (!isRecord(record)) return void 0;
|
|
294
|
+
return record[key];
|
|
295
|
+
}
|
|
296
|
+
function runtimePolicyFromConnectorPayload(parsed) {
|
|
297
|
+
const obj = asRecordOrEmpty(parsed);
|
|
298
|
+
const payload = asRecordOrEmpty(obj.payload);
|
|
299
|
+
const meta = asRecordOrEmpty(payload.meta);
|
|
300
|
+
const fromMeta = readField(meta, "runtimeToolPolicySnapshot");
|
|
301
|
+
const agentConfig = asRecordOrEmpty(payload.agentConfig);
|
|
302
|
+
const fromAgent = readField(agentConfig, "runtimeToolPolicy");
|
|
303
|
+
const policy = isRecord(fromMeta) ? fromMeta : isRecord(fromAgent) ? fromAgent : null;
|
|
304
|
+
return policy ? policy : void 0;
|
|
305
|
+
}
|
|
306
|
+
function requestsLocalWorkspaceRuntime(policy) {
|
|
307
|
+
return Boolean(
|
|
308
|
+
Array.isArray(policy?.runtimeTools) && policy.runtimeTools.length > 0
|
|
309
|
+
);
|
|
310
|
+
}
|
|
311
|
+
function isMachineBoundLocalCustomProvider(agentConfig) {
|
|
312
|
+
const config = asRecordOrEmpty(agentConfig);
|
|
313
|
+
const runtimeBinding = asRecordOrEmpty(config.runtimeBinding);
|
|
314
|
+
const machineIdRaw = readField(runtimeBinding, "machineId");
|
|
315
|
+
const machineId = asTrimmedString(machineIdRaw);
|
|
316
|
+
const providerUrlRaw = readField(config, "customProviderUrl");
|
|
317
|
+
const providerUrl = asTrimmedString(providerUrlRaw);
|
|
318
|
+
if (!machineId || !providerUrl) return false;
|
|
319
|
+
try {
|
|
320
|
+
const hostname = new URL(providerUrl).hostname.toLowerCase();
|
|
321
|
+
return hostname === "127.0.0.1" || hostname === "localhost" || hostname === "::1";
|
|
322
|
+
} catch {
|
|
323
|
+
return false;
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
function hasExplicitMachinePermissions(agentConfig) {
|
|
327
|
+
const config = asRecordOrEmpty(agentConfig);
|
|
328
|
+
const runtimeBinding = asRecordOrEmpty(config.runtimeBinding);
|
|
329
|
+
return Boolean(
|
|
330
|
+
isRecord(readField(config, "machinePermissions")) || isRecord(readField(runtimeBinding, "permissions")) || isRecord(readField(runtimeBinding, "machinePermissions")) || isRecord(readField(readField(config, "boundRuntimeMachine"), "permissions"))
|
|
331
|
+
);
|
|
332
|
+
}
|
|
333
|
+
function runtimeWorkspacePermissionPolicy(runtimePolicy, runtimeEnv, cwd) {
|
|
334
|
+
if (!requestsLocalWorkspaceRuntime(runtimePolicy)) return null;
|
|
335
|
+
return {
|
|
336
|
+
mode: "full_access",
|
|
337
|
+
allowFilesystemRead: true,
|
|
338
|
+
allowFilesystemWrite: true,
|
|
339
|
+
allowShell: Array.isArray(runtimePolicy?.runtimeTools) && runtimePolicy.runtimeTools.includes("execShell"),
|
|
340
|
+
writableRoots: [cwd]
|
|
341
|
+
};
|
|
342
|
+
}
|
|
343
|
+
function scopePermissionPolicyToRuntimeWorkspace(policy, runtimePolicy, cwd) {
|
|
344
|
+
if (!requestsLocalWorkspaceRuntime(runtimePolicy)) return policy;
|
|
345
|
+
return {
|
|
346
|
+
...policy,
|
|
347
|
+
writableRoots: policy.allowFilesystemWrite ? [cwd] : []
|
|
348
|
+
};
|
|
349
|
+
}
|
|
350
|
+
function isNonEmptyString(value) {
|
|
351
|
+
return typeof value === "string" && value.length > 0;
|
|
352
|
+
}
|
|
353
|
+
function readToolName(item) {
|
|
354
|
+
if (typeof item === "string") return item;
|
|
355
|
+
if (!isRecord(item)) return "";
|
|
356
|
+
const direct = readField(item, "name");
|
|
357
|
+
if (isNonEmptyString(direct)) return direct;
|
|
358
|
+
const functionField = readField(item, "function");
|
|
359
|
+
if (isRecord(functionField)) {
|
|
360
|
+
const inner = readField(functionField, "name");
|
|
361
|
+
if (isNonEmptyString(inner)) return inner;
|
|
362
|
+
}
|
|
363
|
+
return "";
|
|
364
|
+
}
|
|
365
|
+
function mergeToolNames(...values) {
|
|
366
|
+
const names = [];
|
|
367
|
+
for (const value of values) {
|
|
368
|
+
if (!Array.isArray(value)) continue;
|
|
369
|
+
for (const item of value) {
|
|
370
|
+
const name = readToolName(item);
|
|
371
|
+
if (name && !names.includes(name)) names.push(name);
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
return names;
|
|
375
|
+
}
|
|
376
|
+
function localRuntimeEnvFromPolicy(runtimeEnv, policy) {
|
|
377
|
+
return resolveLocalRuntimeEnvFromPolicy(runtimeEnv, policy);
|
|
378
|
+
}
|
|
379
|
+
function forwardedUserAuthToken(parsed) {
|
|
380
|
+
const obj = asRecordOrEmpty(parsed);
|
|
381
|
+
const payload = asRecordOrEmpty(obj.payload);
|
|
382
|
+
const meta = asRecordOrEmpty(payload.meta);
|
|
383
|
+
const value = readField(meta, "userAuthToken");
|
|
384
|
+
return asTrimmedString(value);
|
|
385
|
+
}
|
|
386
|
+
function withForwardedUserAuthToken(runtimeEnv, parsed) {
|
|
387
|
+
const userAuthToken = forwardedUserAuthToken(parsed);
|
|
388
|
+
return userAuthToken ? { ...runtimeEnv, AUTH_TOKEN: userAuthToken } : runtimeEnv;
|
|
389
|
+
}
|
|
390
|
+
function runtimeWorkspaceRootFromTrace(trace) {
|
|
391
|
+
if (!Array.isArray(trace)) return void 0;
|
|
392
|
+
for (const message of trace) {
|
|
393
|
+
if (!isRecord(message)) continue;
|
|
394
|
+
const metadataValue = readField(message, "tool_result_metadata");
|
|
395
|
+
const metadata = isRecord(metadataValue) ? metadataValue : null;
|
|
396
|
+
const rootRaw = metadata ? readField(metadata, "workspaceRoot") : void 0;
|
|
397
|
+
const workspaceRoot = asTrimmedString(rootRaw);
|
|
398
|
+
if (workspaceRoot) return workspaceRoot;
|
|
399
|
+
}
|
|
400
|
+
return void 0;
|
|
401
|
+
}
|
|
402
|
+
function buildArtifactProgress(args) {
|
|
403
|
+
if (!isRecord(args.artifacts)) return null;
|
|
404
|
+
const changedFilesRaw = readField(args.artifacts, "changedFiles");
|
|
405
|
+
const changedFiles = Array.isArray(changedFilesRaw) ? changedFilesRaw : [];
|
|
406
|
+
const statusShortRaw = readField(args.artifacts, "statusShort");
|
|
407
|
+
const statusShort = asTrimmedString(statusShortRaw);
|
|
408
|
+
if (changedFiles.length === 0 && !statusShort) return null;
|
|
409
|
+
const runtimeToolsRaw = args.runtimePolicy?.runtimeTools;
|
|
410
|
+
const runtimeTools = Array.isArray(runtimeToolsRaw) ? runtimeToolsRaw : [];
|
|
411
|
+
const shellTool = runtimeTools.includes("execShell") ? "execShell" : "workspaceArtifact";
|
|
412
|
+
return {
|
|
413
|
+
eventType: "tool-result",
|
|
414
|
+
toolCallCount: 1,
|
|
415
|
+
toolResultCount: 1,
|
|
416
|
+
lastToolNames: [shellTool],
|
|
417
|
+
workspaceRoot: args.workspaceRoot,
|
|
418
|
+
...args.workspaceKind ? { workspaceKind: args.workspaceKind } : {},
|
|
419
|
+
message: statusShort || `${changedFiles.length} changed file(s)`,
|
|
420
|
+
updatedAt: Date.now()
|
|
421
|
+
};
|
|
422
|
+
}
|
|
423
|
+
async function defaultRunConnectorLocalRuntimeAgent(args) {
|
|
424
|
+
const obj = asRecordOrEmpty(args.parsed);
|
|
425
|
+
const payload = asRecordOrEmpty(obj.payload);
|
|
426
|
+
const agentKeyRaw = readField(payload, "agentKey");
|
|
427
|
+
const agentKey = typeof agentKeyRaw === "string" ? agentKeyRaw : "";
|
|
428
|
+
const agentConfigRaw = readField(payload, "agentConfig");
|
|
429
|
+
const payloadAgentConfig = asRecordOrEmpty(agentConfigRaw);
|
|
430
|
+
const policy = runtimePolicyFromConnectorPayload(args.parsed);
|
|
431
|
+
const toolNames = mergeToolNames(
|
|
432
|
+
readField(payloadAgentConfig, "toolNames"),
|
|
433
|
+
readField(payloadAgentConfig, "tools"),
|
|
434
|
+
policy?.agentTools,
|
|
435
|
+
policy?.runtimeTools
|
|
436
|
+
);
|
|
437
|
+
const apiSourceRaw = readField(payloadAgentConfig, "apiSource");
|
|
438
|
+
const providerRaw = readField(payloadAgentConfig, "provider");
|
|
439
|
+
const agentRecord = {
|
|
440
|
+
...payloadAgentConfig,
|
|
441
|
+
dbKey: agentKey,
|
|
442
|
+
id: agentKey,
|
|
443
|
+
key: agentKey,
|
|
444
|
+
apiSource: typeof apiSourceRaw === "string" ? apiSourceRaw : "platform",
|
|
445
|
+
provider: typeof providerRaw === "string" ? providerRaw : typeof apiSourceRaw === "string" ? apiSourceRaw : "openai",
|
|
446
|
+
toolNames,
|
|
447
|
+
...policy ? { runtimeToolPolicy: policy } : {}
|
|
448
|
+
};
|
|
449
|
+
const store = /* @__PURE__ */ new Map([
|
|
450
|
+
[agentKey, agentRecord],
|
|
451
|
+
[`agent-${args.runtimeEnv.NOLO_USER_ID || "local"}-${agentKey}`, agentRecord],
|
|
452
|
+
[`agent-${args.runtimeEnv.NOLO_LOCAL_USER_ID || args.runtimeEnv.NOLO_USER_ID || "local"}-${agentKey}`, agentRecord]
|
|
453
|
+
]);
|
|
454
|
+
const env = localRuntimeEnvFromPolicy(
|
|
455
|
+
withForwardedUserAuthToken(args.runtimeEnv, args.parsed),
|
|
456
|
+
policy
|
|
457
|
+
);
|
|
458
|
+
logConnectorRun("agent.run.local-runtime.env", {
|
|
459
|
+
requestId: readField(obj, "requestId"),
|
|
460
|
+
agentKey,
|
|
461
|
+
cwd: args.cwd,
|
|
462
|
+
...summarizeRuntimePolicyForLogs(policy)
|
|
463
|
+
});
|
|
464
|
+
const adapter = createCliLocalRuntimeAdapter({
|
|
465
|
+
env,
|
|
466
|
+
cwd: args.cwd,
|
|
467
|
+
fetchImpl: args.fetchImpl ?? fetch,
|
|
468
|
+
store: {
|
|
469
|
+
read: async (key) => store.get(key) ?? null,
|
|
470
|
+
write: async (key, value) => {
|
|
471
|
+
store.set(key, value);
|
|
472
|
+
return value;
|
|
473
|
+
},
|
|
474
|
+
batch: async (ops) => {
|
|
475
|
+
for (const op of ops) {
|
|
476
|
+
if (op.type === "put") store.set(op.key, op.value);
|
|
477
|
+
}
|
|
478
|
+
},
|
|
479
|
+
iterator: async function* (options) {
|
|
480
|
+
const keys = [...store.keys()].sort();
|
|
481
|
+
for (const key of keys) {
|
|
482
|
+
if (key < options.gte) continue;
|
|
483
|
+
if (options.lte && key > options.lte) continue;
|
|
484
|
+
if (options.lt && key >= options.lt) continue;
|
|
485
|
+
yield [key, store.get(key)];
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
});
|
|
490
|
+
let toolCallCount = 0;
|
|
491
|
+
let toolResultCount = 0;
|
|
492
|
+
const lastToolNames = [];
|
|
493
|
+
let runtimeWorkspaceRoot;
|
|
494
|
+
let runtimeWorkspaceKind;
|
|
495
|
+
const noteToolName = (toolName) => {
|
|
496
|
+
if (!toolName) return;
|
|
497
|
+
const existingIndex = lastToolNames.indexOf(toolName);
|
|
498
|
+
if (existingIndex >= 0) lastToolNames.splice(existingIndex, 1);
|
|
499
|
+
lastToolNames.push(toolName);
|
|
500
|
+
while (lastToolNames.length > 8) lastToolNames.shift();
|
|
501
|
+
};
|
|
502
|
+
const userInputRaw = readField(payload, "userInput");
|
|
503
|
+
const continueDialogIdRaw = readField(payload, "continueDialogId");
|
|
504
|
+
const result = await runLocalAgentTurn({
|
|
505
|
+
adapter,
|
|
506
|
+
agentRef: agentKey,
|
|
507
|
+
input: typeof userInputRaw === "string" ? userInputRaw : "",
|
|
508
|
+
continueDialogId: typeof continueDialogIdRaw === "string" ? continueDialogIdRaw : void 0,
|
|
509
|
+
...args.abortSignal ? { abortSignal: args.abortSignal } : {},
|
|
510
|
+
onToolEvent: (event) => {
|
|
511
|
+
if (event.type === "tool-call") toolCallCount += 1;
|
|
512
|
+
if (event.type === "tool-result") toolResultCount += 1;
|
|
513
|
+
noteToolName(event.toolName);
|
|
514
|
+
const metadata = asRecordOrEmpty(event.metadata);
|
|
515
|
+
const rootRaw = asOptionalTrimmedString(readField(metadata, "workspaceRoot"));
|
|
516
|
+
if (rootRaw) runtimeWorkspaceRoot = rootRaw;
|
|
517
|
+
const kindRaw = asOptionalTrimmedString(readField(metadata, "workspaceKind"));
|
|
518
|
+
if (kindRaw) runtimeWorkspaceKind = kindRaw;
|
|
519
|
+
args.onProgress?.({
|
|
520
|
+
eventType: event.type,
|
|
521
|
+
toolCallCount,
|
|
522
|
+
toolResultCount,
|
|
523
|
+
lastToolNames: [...lastToolNames],
|
|
524
|
+
...runtimeWorkspaceRoot ? { workspaceRoot: runtimeWorkspaceRoot } : {},
|
|
525
|
+
...runtimeWorkspaceKind ? { workspaceKind: runtimeWorkspaceKind } : {},
|
|
526
|
+
...event.message ? { message: event.message } : {},
|
|
527
|
+
updatedAt: Date.now()
|
|
528
|
+
});
|
|
529
|
+
}
|
|
530
|
+
});
|
|
531
|
+
return {
|
|
532
|
+
...result,
|
|
533
|
+
runtimeWorkspaceRoot: runtimeWorkspaceRootFromTrace(result.trace) ?? runtimeWorkspaceRoot
|
|
534
|
+
};
|
|
535
|
+
}
|
|
536
|
+
function normalizeConnectorRunTimeoutMs(value) {
|
|
537
|
+
const finite = asOptionalPositiveFiniteNumber(value);
|
|
538
|
+
if (finite === void 0) return void 0;
|
|
539
|
+
return Math.floor(finite);
|
|
540
|
+
}
|
|
541
|
+
function isConnectorUserInput(value) {
|
|
542
|
+
return Array.isArray(value);
|
|
543
|
+
}
|
|
544
|
+
function readConnectorTextPart(part) {
|
|
545
|
+
if (!isRecord(part)) return null;
|
|
546
|
+
const text = readField(part, "text");
|
|
547
|
+
if (readField(part, "type") === "text" && isNonEmptyString(text)) {
|
|
548
|
+
return text;
|
|
549
|
+
}
|
|
550
|
+
return null;
|
|
551
|
+
}
|
|
552
|
+
function readConnectorImageUrlPart(part) {
|
|
553
|
+
if (!isRecord(part)) return null;
|
|
554
|
+
if (readField(part, "type") !== "image_url") return null;
|
|
555
|
+
const imageUrlValue = readField(part, "image_url");
|
|
556
|
+
if (!isRecord(imageUrlValue)) return null;
|
|
557
|
+
const url = readField(imageUrlValue, "url");
|
|
558
|
+
if (typeof url !== "string" || !url.trim()) return null;
|
|
559
|
+
return url.trim();
|
|
560
|
+
}
|
|
561
|
+
function extractMultimodalUserInput(userInput) {
|
|
562
|
+
if (typeof userInput === "string") {
|
|
563
|
+
return { text: userInput, imageUrls: [] };
|
|
564
|
+
}
|
|
565
|
+
if (!isConnectorUserInput(userInput)) {
|
|
566
|
+
return { text: String(userInput ?? ""), imageUrls: [] };
|
|
567
|
+
}
|
|
568
|
+
const textParts = [];
|
|
569
|
+
const imageUrls = [];
|
|
570
|
+
for (const part of userInput) {
|
|
571
|
+
const text = readConnectorTextPart(part);
|
|
572
|
+
if (text !== null) {
|
|
573
|
+
textParts.push(text);
|
|
574
|
+
continue;
|
|
575
|
+
}
|
|
576
|
+
const url = readConnectorImageUrlPart(part);
|
|
577
|
+
if (url !== null) imageUrls.push(url);
|
|
578
|
+
}
|
|
579
|
+
return { text: textParts.join("\n"), imageUrls };
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
// packages/cli/chatgptWebImageLocalJob.ts
|
|
583
|
+
import {
|
|
584
|
+
mkdirSync as mkdirSync2,
|
|
585
|
+
readFileSync,
|
|
586
|
+
statSync,
|
|
587
|
+
unlinkSync,
|
|
588
|
+
writeFileSync as writeFileSync2
|
|
589
|
+
} from "node:fs";
|
|
590
|
+
import { homedir } from "node:os";
|
|
591
|
+
import { basename, dirname, join as join2 } from "node:path";
|
|
592
|
+
var CHATGPT_WEB_IMAGE_LOCAL_JOB = "chatgptWebImageGenerate";
|
|
593
|
+
function readChatgptWebImageLocalJobMeta(payload) {
|
|
594
|
+
if (!isRecord(payload)) return null;
|
|
595
|
+
const meta = isRecord(payload.meta) ? payload.meta : null;
|
|
596
|
+
if (!meta || meta.localJob !== CHATGPT_WEB_IMAGE_LOCAL_JOB) return null;
|
|
597
|
+
const prompt = asTrimmedString(meta.prompt);
|
|
598
|
+
const userAuthToken = asTrimmedString(meta.userAuthToken);
|
|
599
|
+
const serverBase = asTrimmedString(meta.serverBase);
|
|
600
|
+
return {
|
|
601
|
+
prompt,
|
|
602
|
+
...userAuthToken ? { userAuthToken } : {},
|
|
603
|
+
...serverBase ? { serverBase } : {}
|
|
604
|
+
};
|
|
605
|
+
}
|
|
606
|
+
function defaultLockPath(home) {
|
|
607
|
+
return join2(home, ".nolo", "chatgpt-web-image.lock");
|
|
608
|
+
}
|
|
609
|
+
function defaultOutDir(home) {
|
|
610
|
+
return join2(home, "nolo-image-lab", "out");
|
|
611
|
+
}
|
|
612
|
+
function acquireChatgptWebImageLock(lockPath) {
|
|
613
|
+
mkdirSync2(dirname(lockPath), { recursive: true });
|
|
614
|
+
try {
|
|
615
|
+
writeFileSync2(lockPath, `${process.pid}
|
|
616
|
+
${Date.now()}
|
|
617
|
+
`, { flag: "wx" });
|
|
618
|
+
} catch (error) {
|
|
619
|
+
const code = error && typeof error === "object" && "code" in error ? error.code : void 0;
|
|
620
|
+
if (code === "EEXIST") {
|
|
621
|
+
throw new Error("ChatGPT \u7F51\u9875\u751F\u56FE\u4EFB\u52A1\u6B63\u5728\u8FDB\u884C\u4E2D\uFF0C\u8BF7\u7A0D\u540E\u518D\u8BD5\uFF08\u9501\u6587\u4EF6\u5360\u7528\uFF09");
|
|
622
|
+
}
|
|
623
|
+
throw error;
|
|
624
|
+
}
|
|
625
|
+
return () => {
|
|
626
|
+
try {
|
|
627
|
+
unlinkSync(lockPath);
|
|
628
|
+
} catch {
|
|
629
|
+
}
|
|
630
|
+
};
|
|
631
|
+
}
|
|
632
|
+
async function runOracleGenerateImage(args) {
|
|
633
|
+
const proc = args.spawn({
|
|
634
|
+
cmd: [
|
|
635
|
+
"npx",
|
|
636
|
+
"-y",
|
|
637
|
+
"@steipete/oracle",
|
|
638
|
+
"--engine",
|
|
639
|
+
"browser",
|
|
640
|
+
"--browser-manual-login",
|
|
641
|
+
"--browser-model-strategy",
|
|
642
|
+
"current",
|
|
643
|
+
"--generate-image",
|
|
644
|
+
args.outPath,
|
|
645
|
+
"-p",
|
|
646
|
+
args.prompt,
|
|
647
|
+
"--browser-timeout",
|
|
648
|
+
"15m",
|
|
649
|
+
"--browser-input-timeout",
|
|
650
|
+
"180s"
|
|
651
|
+
],
|
|
652
|
+
stdout: "pipe",
|
|
653
|
+
stderr: "pipe"
|
|
654
|
+
});
|
|
655
|
+
const [exitCode, stdout, stderr] = await Promise.all([
|
|
656
|
+
proc.exited,
|
|
657
|
+
readPipeText(proc.stdout),
|
|
658
|
+
readPipeText(proc.stderr)
|
|
659
|
+
]);
|
|
660
|
+
if (exitCode !== 0) {
|
|
661
|
+
const detail = (stderr || stdout || "").trim().slice(0, 800);
|
|
662
|
+
throw new Error(
|
|
663
|
+
detail ? `ChatGPT \u7F51\u9875\u751F\u56FE\u5931\u8D25\uFF08oracle exit ${exitCode}\uFF09\uFF1A${detail}` : `ChatGPT \u7F51\u9875\u751F\u56FE\u5931\u8D25\uFF08oracle exit ${exitCode}\uFF09`
|
|
664
|
+
);
|
|
665
|
+
}
|
|
666
|
+
}
|
|
667
|
+
function assertOutputImage(outPath) {
|
|
668
|
+
let st;
|
|
669
|
+
try {
|
|
670
|
+
st = statSync(outPath);
|
|
671
|
+
} catch {
|
|
672
|
+
throw new Error(`ChatGPT \u7F51\u9875\u751F\u56FE\u672A\u4EA7\u51FA\u6587\u4EF6\uFF1A${outPath}`);
|
|
673
|
+
}
|
|
674
|
+
if (!st.isFile() || st.size <= 0) {
|
|
675
|
+
throw new Error(`ChatGPT \u7F51\u9875\u751F\u56FE\u6587\u4EF6\u65E0\u6548\u6216\u4E3A\u7A7A\uFF1A${outPath}`);
|
|
676
|
+
}
|
|
677
|
+
}
|
|
678
|
+
async function uploadPngToNoloFs(args) {
|
|
679
|
+
const bytes = readFileSync(args.outPath);
|
|
680
|
+
const form = new FormData();
|
|
681
|
+
const fileName = basename(args.outPath) || "chatgpt-web.png";
|
|
682
|
+
form.append(
|
|
683
|
+
"file",
|
|
684
|
+
new Blob([bytes], { type: "image/png" }),
|
|
685
|
+
fileName
|
|
686
|
+
);
|
|
687
|
+
form.append(
|
|
688
|
+
"metadata",
|
|
689
|
+
JSON.stringify({
|
|
690
|
+
type: "file",
|
|
691
|
+
fileCategory: "image",
|
|
692
|
+
ownerType: "user",
|
|
693
|
+
userId: args.userId,
|
|
694
|
+
source: "chatgpt-web-image",
|
|
695
|
+
model: "chatgpt-web",
|
|
696
|
+
prompt: args.prompt,
|
|
697
|
+
tags: ["ai-generated", "chatgpt-web", "image"]
|
|
698
|
+
})
|
|
699
|
+
);
|
|
700
|
+
form.append("userId", args.userId);
|
|
701
|
+
form.append("ownerType", "user");
|
|
702
|
+
form.append("ownerId", args.userId);
|
|
703
|
+
const base = args.serverBase.replace(/\/+$/, "") || DEFAULT_NOLO_SERVER_URL;
|
|
704
|
+
const url = `${base}/api/v1/db/upload`;
|
|
705
|
+
const headers = {};
|
|
706
|
+
if (args.userAuthToken) {
|
|
707
|
+
headers.Authorization = `Bearer ${args.userAuthToken}`;
|
|
708
|
+
}
|
|
709
|
+
const response = await args.fetchImpl(url, {
|
|
710
|
+
method: "POST",
|
|
711
|
+
headers,
|
|
712
|
+
body: form
|
|
713
|
+
});
|
|
714
|
+
const body = await response.json().catch(() => ({}));
|
|
715
|
+
if (!response.ok) {
|
|
716
|
+
const errField = body.error;
|
|
717
|
+
const message = typeof errField === "string" && errField || isRecord(errField) && typeof errField.message === "string" && errField.message || typeof body.details === "string" && body.details || `HTTP ${response.status}`;
|
|
718
|
+
throw new Error(`\u4E0A\u4F20\u751F\u56FE\u7ED3\u679C\u5230 Nolo FS \u5931\u8D25\uFF1A${message}`);
|
|
719
|
+
}
|
|
720
|
+
const fileId = asTrimmedString(body.fileId);
|
|
721
|
+
if (!fileId) {
|
|
722
|
+
throw new Error("\u4E0A\u4F20\u751F\u56FE\u7ED3\u679C\u6210\u529F\u4F46\u54CD\u5E94\u7F3A\u5C11 fileId");
|
|
723
|
+
}
|
|
724
|
+
const metadata = asRecordOrEmpty(body.metadata);
|
|
725
|
+
return { fileId, metadata };
|
|
726
|
+
}
|
|
727
|
+
async function runChatgptWebImageLocalJob(input, deps = {}) {
|
|
728
|
+
const prompt = asTrimmedString(input.prompt);
|
|
729
|
+
if (!prompt) {
|
|
730
|
+
throw new Error("\u7F3A\u5C11\u751F\u56FE prompt\uFF08payload.meta.prompt \u5FC5\u586B\uFF09");
|
|
731
|
+
}
|
|
732
|
+
const home = (deps.homedir ?? homedir)();
|
|
733
|
+
const lockPath = deps.lockPath ?? defaultLockPath(home);
|
|
734
|
+
const outDir = deps.outDir ?? defaultOutDir(home);
|
|
735
|
+
const release = acquireChatgptWebImageLock(lockPath);
|
|
736
|
+
try {
|
|
737
|
+
mkdirSync2(outDir, { recursive: true });
|
|
738
|
+
const stamp = (deps.now ?? Date.now)();
|
|
739
|
+
const outPath = join2(outDir, `chatgpt-web-${stamp}.png`);
|
|
740
|
+
await runOracleGenerateImage({
|
|
741
|
+
prompt,
|
|
742
|
+
outPath,
|
|
743
|
+
spawn: deps.spawn ?? spawnProcess
|
|
744
|
+
});
|
|
745
|
+
assertOutputImage(outPath);
|
|
746
|
+
const userAuthToken = input.userAuthToken?.trim() || "";
|
|
747
|
+
const userId = parseUserIdFromAuthToken(userAuthToken) || "default";
|
|
748
|
+
const serverBase = (input.serverBase?.trim() || DEFAULT_NOLO_SERVER_URL).replace(/\/+$/, "");
|
|
749
|
+
const uploaded = await uploadPngToNoloFs({
|
|
750
|
+
outPath,
|
|
751
|
+
prompt,
|
|
752
|
+
userAuthToken,
|
|
753
|
+
serverBase,
|
|
754
|
+
userId,
|
|
755
|
+
fetchImpl: deps.fetchImpl ?? fetch
|
|
756
|
+
});
|
|
757
|
+
const rawData = {
|
|
758
|
+
text: `\u5DF2\u751F\u6210 1 \u5F20\u56FE\u7247\u3002`,
|
|
759
|
+
imageCount: 1,
|
|
760
|
+
files: [
|
|
761
|
+
{
|
|
762
|
+
fileId: uploaded.fileId,
|
|
763
|
+
metadata: {
|
|
764
|
+
...uploaded.metadata,
|
|
765
|
+
prompt,
|
|
766
|
+
model: "chatgpt-web"
|
|
767
|
+
}
|
|
768
|
+
}
|
|
769
|
+
]
|
|
770
|
+
};
|
|
771
|
+
return {
|
|
772
|
+
rawData,
|
|
773
|
+
outPath,
|
|
774
|
+
fileId: uploaded.fileId
|
|
775
|
+
};
|
|
776
|
+
} finally {
|
|
777
|
+
release();
|
|
778
|
+
}
|
|
779
|
+
}
|
|
780
|
+
|
|
781
|
+
// packages/cli/machineWsRunDispatch.ts
|
|
782
|
+
var activeRunAbortControllers = /* @__PURE__ */ new Map();
|
|
783
|
+
async function handleConnectorRunMessage(message, send, executeCli, runtimeEnv, fetchImpl, deps = {}) {
|
|
784
|
+
let parsed;
|
|
785
|
+
try {
|
|
786
|
+
parsed = JSON.parse(message);
|
|
787
|
+
} catch {
|
|
788
|
+
return;
|
|
789
|
+
}
|
|
790
|
+
if (!isRecord(parsed) || typeof parsed.requestId !== "string") return;
|
|
791
|
+
const requestId = parsed.requestId;
|
|
792
|
+
if (parsed.type === "agent.run.cancel") {
|
|
793
|
+
const controller = activeRunAbortControllers.get(requestId);
|
|
794
|
+
if (controller) {
|
|
795
|
+
controller.abort(new Error("agent.run.cancel received from server"));
|
|
796
|
+
}
|
|
797
|
+
return;
|
|
798
|
+
}
|
|
799
|
+
if (parsed.type !== "agent.run") return;
|
|
800
|
+
const payload = asRecordOrEmpty(parsed.payload);
|
|
801
|
+
const agentConfig = asRecordOrEmpty(payload.agentConfig);
|
|
802
|
+
const runAbortController = new AbortController();
|
|
803
|
+
activeRunAbortControllers.set(requestId, runAbortController);
|
|
804
|
+
const sendProgress = (progress) => {
|
|
805
|
+
send(JSON.stringify({
|
|
806
|
+
type: "agent.run.progress",
|
|
807
|
+
requestId,
|
|
808
|
+
progress
|
|
809
|
+
}));
|
|
810
|
+
};
|
|
811
|
+
const resolveConnectorRunCwd2 = deps.resolveConnectorRunCwd ?? resolveConnectorRunCwd;
|
|
812
|
+
const resolveMachineRunPermissionPolicy2 = deps.resolveMachineRunPermissionPolicy ?? resolveMachineRunPermissionPolicy;
|
|
813
|
+
const assertMachineRunAllowed2 = deps.assertMachineRunAllowed ?? assertMachineRunAllowed;
|
|
814
|
+
const readConnectorGitHead2 = deps.readConnectorGitHead ?? readConnectorGitHead;
|
|
815
|
+
const collectConnectorRunArtifact2 = deps.collectConnectorRunArtifact ?? collectConnectorRunArtifact;
|
|
816
|
+
const materializeLargeConnectorPrompt2 = deps.materializeLargeConnectorPrompt ?? materializeLargeConnectorPrompt;
|
|
817
|
+
const readRuntimePromptPageMeta2 = deps.readRuntimePromptPageMeta ?? readRuntimePromptPageMeta;
|
|
818
|
+
const runConnectorLocalRuntimeAgent = deps.runConnectorLocalRuntimeAgent ?? defaultRunConnectorLocalRuntimeAgent;
|
|
819
|
+
const runChatgptWebImageLocalJob2 = deps.runChatgptWebImageLocalJob ?? runChatgptWebImageLocalJob;
|
|
820
|
+
try {
|
|
821
|
+
const chatgptWebImageJob = readChatgptWebImageLocalJobMeta(payload);
|
|
822
|
+
if (chatgptWebImageJob) {
|
|
823
|
+
logConnectorRun("agent.run.local-job.start", {
|
|
824
|
+
requestId,
|
|
825
|
+
localJob: "chatgptWebImageGenerate",
|
|
826
|
+
agentKey: readField2(payload, "agentKey"),
|
|
827
|
+
promptBytes: Buffer.byteLength(chatgptWebImageJob.prompt || "", "utf8")
|
|
828
|
+
});
|
|
829
|
+
const userAuthToken = chatgptWebImageJob.userAuthToken || forwardedUserAuthToken(parsed) || "";
|
|
830
|
+
const jobResult = await runChatgptWebImageLocalJob2({
|
|
831
|
+
prompt: chatgptWebImageJob.prompt,
|
|
832
|
+
userAuthToken,
|
|
833
|
+
serverBase: chatgptWebImageJob.serverBase
|
|
834
|
+
});
|
|
835
|
+
const galleryRawData = jobResult.rawData;
|
|
836
|
+
send(JSON.stringify({
|
|
837
|
+
type: "agent.run.result",
|
|
838
|
+
requestId,
|
|
839
|
+
result: {
|
|
840
|
+
content: JSON.stringify(galleryRawData),
|
|
841
|
+
model: "chatgpt-web",
|
|
842
|
+
artifacts: {
|
|
843
|
+
localJob: "chatgptWebImageGenerate",
|
|
844
|
+
...jobResult.outPath ? { outPath: jobResult.outPath } : {},
|
|
845
|
+
...jobResult.fileId ? { fileId: jobResult.fileId } : {},
|
|
846
|
+
imageCount: galleryRawData.imageCount
|
|
847
|
+
}
|
|
848
|
+
}
|
|
849
|
+
}));
|
|
850
|
+
return;
|
|
851
|
+
}
|
|
852
|
+
const machinePermissionPolicy = resolveMachineRunPermissionPolicy2(agentConfig);
|
|
853
|
+
const runtimePolicy = runtimePolicyFromConnectorPayload(parsed);
|
|
854
|
+
const extractedInput = extractMultimodalUserInput(payload.userInput);
|
|
855
|
+
const userInput = extractedInput.text;
|
|
856
|
+
const connectorImageUrls = extractedInput.imageUrls;
|
|
857
|
+
const timeout = normalizeConnectorRunTimeoutMs(payload.timeoutMs);
|
|
858
|
+
let cwd = resolveConnectorRunCwd2({ env: runtimeEnv, policy: machinePermissionPolicy });
|
|
859
|
+
let runContent = "";
|
|
860
|
+
let runModel = (() => {
|
|
861
|
+
const value = readField2(agentConfig, "model");
|
|
862
|
+
return typeof value === "string" ? value : void 0;
|
|
863
|
+
})();
|
|
864
|
+
let runTrace = [];
|
|
865
|
+
let artifactCwd = cwd;
|
|
866
|
+
let baseSha = null;
|
|
867
|
+
if (agentConfig.apiSource === "cli") {
|
|
868
|
+
if (!deps.buildConnectorCliPrompt) {
|
|
869
|
+
throw new Error("buildConnectorCliPrompt is required for CLI connector runs.");
|
|
870
|
+
}
|
|
871
|
+
const runtimePermissionPolicy = !hasExplicitMachinePermissions(agentConfig) ? runtimeWorkspacePermissionPolicy(runtimePolicy, runtimeEnv, cwd) : null;
|
|
872
|
+
const effectivePermissionPolicy = scopePermissionPolicyToRuntimeWorkspace(
|
|
873
|
+
runtimePermissionPolicy ?? machinePermissionPolicy,
|
|
874
|
+
runtimePolicy,
|
|
875
|
+
cwd
|
|
876
|
+
);
|
|
877
|
+
assertMachineRunAllowed2(userInput, effectivePermissionPolicy);
|
|
878
|
+
baseSha = await readConnectorGitHead2(artifactCwd);
|
|
879
|
+
const providerRaw = readField2(agentConfig, "cliProvider");
|
|
880
|
+
const fallbackProvider = readField2(agentConfig, "provider");
|
|
881
|
+
const provider = asOptionalTrimmedString(providerRaw) ?? asOptionalTrimmedString(fallbackProvider) ?? "copilot";
|
|
882
|
+
const finalProvider = provider.trim() || "copilot";
|
|
883
|
+
const payloadAgentKey = readField2(payload, "agentKey");
|
|
884
|
+
const payloadRuntimeContext = readField2(payload, "runtimeContext");
|
|
885
|
+
const builtPrompt = deps.buildConnectorCliPrompt(agentConfig, userInput, {
|
|
886
|
+
agentKey: typeof payloadAgentKey === "string" ? payloadAgentKey : "",
|
|
887
|
+
runtimeContext: payloadRuntimeContext
|
|
888
|
+
}, effectivePermissionPolicy);
|
|
889
|
+
const materializedPrompt = materializeLargeConnectorPrompt2({
|
|
890
|
+
prompt: builtPrompt,
|
|
891
|
+
cwd,
|
|
892
|
+
env: runtimeEnv,
|
|
893
|
+
requestId,
|
|
894
|
+
runtimePromptPage: readRuntimePromptPageMeta2(parsed)
|
|
895
|
+
});
|
|
896
|
+
const runtimePromptPage = readRuntimePromptPageMeta2(parsed);
|
|
897
|
+
const startAt = Date.now();
|
|
898
|
+
const progressBase = {
|
|
899
|
+
provider: finalProvider,
|
|
900
|
+
requestId,
|
|
901
|
+
promptBytes: materializedPrompt.promptBytes,
|
|
902
|
+
promptHash: materializedPrompt.promptHash,
|
|
903
|
+
...materializedPrompt.promptRef ? { promptRef: materializedPrompt.promptRef } : {},
|
|
904
|
+
...runtimePromptPage?.dbKey ? { promptPageKey: runtimePromptPage.dbKey } : {},
|
|
905
|
+
...runtimePromptPage?.promptHash ? { promptPageHash: runtimePromptPage.promptHash } : {},
|
|
906
|
+
workspaceRoot: artifactCwd,
|
|
907
|
+
workspaceKind: "current"
|
|
908
|
+
};
|
|
909
|
+
logConnectorRun("agent.run.cli.start", {
|
|
910
|
+
requestId,
|
|
911
|
+
agentKey: payloadAgentKey,
|
|
912
|
+
provider: finalProvider,
|
|
913
|
+
cwd,
|
|
914
|
+
artifactCwd,
|
|
915
|
+
timeout,
|
|
916
|
+
promptBytes: materializedPrompt.promptBytes,
|
|
917
|
+
promptHash: materializedPrompt.promptHash,
|
|
918
|
+
promptRef: materializedPrompt.promptRef,
|
|
919
|
+
promptPageKey: runtimePromptPage?.dbKey
|
|
920
|
+
});
|
|
921
|
+
sendProgress({
|
|
922
|
+
...progressBase,
|
|
923
|
+
message: "cli-started",
|
|
924
|
+
updatedAt: startAt
|
|
925
|
+
});
|
|
926
|
+
const heartbeat = setInterval(() => {
|
|
927
|
+
sendProgress({
|
|
928
|
+
...progressBase,
|
|
929
|
+
message: "cli-running",
|
|
930
|
+
updatedAt: Date.now()
|
|
931
|
+
});
|
|
932
|
+
}, 15e3);
|
|
933
|
+
const effectiveRuntimeEnv = withForwardedUserAuthToken(runtimeEnv, parsed);
|
|
934
|
+
const reasoningEffortRaw = readField2(agentConfig, "reasoning_effort");
|
|
935
|
+
const reasoningEffortFallback = readField2(agentConfig, "reasoningEffort");
|
|
936
|
+
const reasoningEffort = typeof reasoningEffortRaw === "string" && reasoningEffortRaw || typeof reasoningEffortFallback === "string" && reasoningEffortFallback || void 0;
|
|
937
|
+
const modelValue = readField2(agentConfig, "model");
|
|
938
|
+
const result2 = await executeCli(finalProvider, materializedPrompt.prompt, {
|
|
939
|
+
model: typeof modelValue === "string" ? modelValue : void 0,
|
|
940
|
+
timeout,
|
|
941
|
+
cwd,
|
|
942
|
+
yolo: true,
|
|
943
|
+
...reasoningEffort ? { reasoningEffort } : {},
|
|
944
|
+
env: {
|
|
945
|
+
NOLO_SERVER: effectiveRuntimeEnv.NOLO_SERVER || effectiveRuntimeEnv.NOLO_SERVER_URL || effectiveRuntimeEnv.BASE_URL,
|
|
946
|
+
NOLO_SERVER_URL: effectiveRuntimeEnv.NOLO_SERVER_URL || effectiveRuntimeEnv.NOLO_SERVER || effectiveRuntimeEnv.BASE_URL,
|
|
947
|
+
BASE_URL: effectiveRuntimeEnv.BASE_URL || effectiveRuntimeEnv.NOLO_SERVER || effectiveRuntimeEnv.NOLO_SERVER_URL,
|
|
948
|
+
AUTH_TOKEN: effectiveRuntimeEnv.AUTH_TOKEN || effectiveRuntimeEnv.AUTH || effectiveRuntimeEnv.NOLO_MACHINE_API_KEY,
|
|
949
|
+
NOLO_MACHINE_API_KEY: effectiveRuntimeEnv.NOLO_MACHINE_API_KEY || effectiveRuntimeEnv.AUTH_TOKEN || effectiveRuntimeEnv.AUTH
|
|
950
|
+
},
|
|
951
|
+
...connectorImageUrls.length > 0 ? { imageInputs: connectorImageUrls.map((url) => ({ source: url })) } : {}
|
|
952
|
+
}).finally(() => clearInterval(heartbeat));
|
|
953
|
+
logConnectorRun("agent.run.cli.result", {
|
|
954
|
+
requestId,
|
|
955
|
+
provider: finalProvider,
|
|
956
|
+
elapsed: result2.elapsed,
|
|
957
|
+
outputBytes: byteLengthLocal(result2.raw ?? result2.text ?? "")
|
|
958
|
+
});
|
|
959
|
+
runContent = result2.text;
|
|
960
|
+
const explicitModel = readField2(agentConfig, "model");
|
|
961
|
+
runModel = asOptionalTrimmedString(explicitModel) ?? finalProvider;
|
|
962
|
+
runTrace = [{ role: "assistant", content: result2.text }];
|
|
963
|
+
const artifacts2 = await collectConnectorRunArtifact2({
|
|
964
|
+
cwd: artifactCwd,
|
|
965
|
+
baseSha,
|
|
966
|
+
exitStatus: "completed"
|
|
967
|
+
});
|
|
968
|
+
const artifactProgress2 = buildArtifactProgress({
|
|
969
|
+
artifacts: artifacts2,
|
|
970
|
+
runtimePolicy,
|
|
971
|
+
workspaceRoot: artifactCwd,
|
|
972
|
+
workspaceKind: "current"
|
|
973
|
+
});
|
|
974
|
+
if (artifactProgress2) sendProgress(artifactProgress2);
|
|
975
|
+
send(JSON.stringify({
|
|
976
|
+
type: "agent.run.result",
|
|
977
|
+
requestId,
|
|
978
|
+
result: {
|
|
979
|
+
content: runContent,
|
|
980
|
+
model: runModel,
|
|
981
|
+
trace: runTrace,
|
|
982
|
+
artifacts: artifacts2
|
|
983
|
+
}
|
|
984
|
+
}));
|
|
985
|
+
return;
|
|
986
|
+
}
|
|
987
|
+
if (!requestsLocalWorkspaceRuntime(runtimePolicy) && !isMachineBoundLocalCustomProvider(agentConfig)) {
|
|
988
|
+
throw new Error("Connector can only execute non-CLI agents when runtimeToolPolicySnapshot requests a local workspace runtime.");
|
|
989
|
+
}
|
|
990
|
+
logConnectorRun("agent.run.local-runtime.start", {
|
|
991
|
+
requestId,
|
|
992
|
+
agentKey: readField2(payload, "agentKey"),
|
|
993
|
+
cwd,
|
|
994
|
+
timeout,
|
|
995
|
+
machineBoundLocalCustomProvider: isMachineBoundLocalCustomProvider(agentConfig),
|
|
996
|
+
runtimePolicy: Boolean(runtimePolicy),
|
|
997
|
+
...summarizeAgentConfigForLogs(agentConfig)
|
|
998
|
+
});
|
|
999
|
+
baseSha = await readConnectorGitHead2(cwd);
|
|
1000
|
+
const result = await runConnectorLocalRuntimeAgent({
|
|
1001
|
+
parsed,
|
|
1002
|
+
runtimeEnv: withForwardedUserAuthToken(runtimeEnv, parsed),
|
|
1003
|
+
cwd,
|
|
1004
|
+
fetchImpl,
|
|
1005
|
+
onProgress: sendProgress,
|
|
1006
|
+
abortSignal: runAbortController.signal
|
|
1007
|
+
});
|
|
1008
|
+
runContent = result.content;
|
|
1009
|
+
runModel = result.model;
|
|
1010
|
+
runTrace = result.trace ?? [];
|
|
1011
|
+
artifactCwd = result.runtimeWorkspaceRoot ?? cwd;
|
|
1012
|
+
const artifacts = await collectConnectorRunArtifact2({
|
|
1013
|
+
cwd: artifactCwd,
|
|
1014
|
+
baseSha,
|
|
1015
|
+
exitStatus: "completed"
|
|
1016
|
+
});
|
|
1017
|
+
const artifactProgress = buildArtifactProgress({
|
|
1018
|
+
artifacts,
|
|
1019
|
+
runtimePolicy,
|
|
1020
|
+
workspaceRoot: artifactCwd,
|
|
1021
|
+
workspaceKind: "current"
|
|
1022
|
+
});
|
|
1023
|
+
if (artifactProgress) sendProgress(artifactProgress);
|
|
1024
|
+
send(JSON.stringify({
|
|
1025
|
+
type: "agent.run.result",
|
|
1026
|
+
requestId,
|
|
1027
|
+
result: {
|
|
1028
|
+
content: runContent,
|
|
1029
|
+
model: runModel,
|
|
1030
|
+
trace: runTrace,
|
|
1031
|
+
artifacts
|
|
1032
|
+
}
|
|
1033
|
+
}));
|
|
1034
|
+
} catch (error) {
|
|
1035
|
+
logConnectorRun("agent.run.error", {
|
|
1036
|
+
requestId,
|
|
1037
|
+
agentKey: readField2(payload, "agentKey"),
|
|
1038
|
+
...summarizeAgentConfigForLogs(agentConfig),
|
|
1039
|
+
errorName: error instanceof Error ? error.name : null,
|
|
1040
|
+
error: toErrorMessage(error)
|
|
1041
|
+
});
|
|
1042
|
+
const cancelled = runAbortController.signal.aborted;
|
|
1043
|
+
send(JSON.stringify({
|
|
1044
|
+
type: "agent.run.result",
|
|
1045
|
+
requestId,
|
|
1046
|
+
error: toErrorMessage(error),
|
|
1047
|
+
...cancelled ? { cancelled: true } : {}
|
|
1048
|
+
}));
|
|
1049
|
+
} finally {
|
|
1050
|
+
if (activeRunAbortControllers.get(requestId) === runAbortController) {
|
|
1051
|
+
activeRunAbortControllers.delete(requestId);
|
|
1052
|
+
}
|
|
1053
|
+
}
|
|
1054
|
+
}
|
|
1055
|
+
function byteLengthLocal(value) {
|
|
1056
|
+
return Buffer.byteLength(value, "utf8");
|
|
1057
|
+
}
|
|
1058
|
+
function readField2(record, key) {
|
|
1059
|
+
if (!isRecord(record)) return void 0;
|
|
1060
|
+
return record[key];
|
|
1061
|
+
}
|
|
1062
|
+
|
|
1063
|
+
export {
|
|
1064
|
+
resolveMachineRunPermissionPolicy,
|
|
1065
|
+
buildMachinePermissionPromptBlock,
|
|
1066
|
+
summarizeAgentConfigForLogs,
|
|
1067
|
+
runtimePolicyFromConnectorPayload,
|
|
1068
|
+
requestsLocalWorkspaceRuntime,
|
|
1069
|
+
isMachineBoundLocalCustomProvider,
|
|
1070
|
+
hasExplicitMachinePermissions,
|
|
1071
|
+
runtimeWorkspacePermissionPolicy,
|
|
1072
|
+
scopePermissionPolicyToRuntimeWorkspace,
|
|
1073
|
+
localRuntimeEnvFromPolicy,
|
|
1074
|
+
buildArtifactProgress,
|
|
1075
|
+
defaultRunConnectorLocalRuntimeAgent,
|
|
1076
|
+
extractMultimodalUserInput,
|
|
1077
|
+
handleConnectorRunMessage
|
|
1078
|
+
};
|