nolo-cli 0.83.0 → 0.84.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-LUNEV235.js → _executeModel-BPUR2QYH.js} +29 -28
- package/{action-YVYQEAAV.js → action-P4TNFGAD.js} +3 -3
- package/{addContentAction-O7R66HEX.js → addContentAction-MB2HHMDZ.js} +2 -2
- package/{addDialogAgentAction-74OA7KYP.js → addDialogAgentAction-S2NRBCWW.js} +2 -2
- package/{agentDeleteCommand-2YAHAZFJ.js → agentDeleteCommand-MNAA6MIG.js} +15 -14
- package/{agentEmailCommands-G6A7IRPQ.js → agentEmailCommands-SK34WJKU.js} +37 -36
- package/{agentListCommands-KMS675GZ.js → agentListCommands-I26MKI4T.js} +31 -19
- package/{agentMachineCommands-W2SMNSQ3.js → agentMachineCommands-M6QDR6P3.js} +15 -14
- package/{agentProviderCommands-GNPTL5XR.js → agentProviderCommands-X3UNW77C.js} +1 -1
- package/{agentRecordCommands-D7BRMFNI.js → agentRecordCommands-HTHLO2MM.js} +36 -35
- package/{agentRunCommand-VL6MMEUB.js → agentRunCommand-IAIRCMTH.js} +38 -36
- package/{agentRuntimeLocal-VXZSDIGT.js → agentRuntimeLocal-3WTYYIT2.js} +16 -11
- package/{agentSlice-5YJHUO47.js → agentSlice-TVP3HINW.js} +2 -2
- package/{appDeleteCommands-32MHLR4L.js → appDeleteCommands-SB5TNLKY.js} +16 -15
- package/{appDeployCommands-WCQOUSOB.js → appDeployCommands-2IPKZINV.js} +16 -15
- package/{appDeployStatusCommands-6QKB7DYN.js → appDeployStatusCommands-K63TFUID.js} +16 -15
- package/{appGetCommands-SFAPP5PB.js → appGetCommands-VU2SLNEH.js} +16 -15
- package/{appListCommands-EKUBDRUO.js → appListCommands-S3T4DJ36.js} +16 -15
- package/{authCommand-F4EFRRX6.js → authCommand-HGP2XTKC.js} +100 -8
- package/{builtinSkillRegistry-FUAVTRVZ.js → builtinSkillRegistry-Q2VVY3SC.js} +2 -2
- package/{chatQueueReduxAdapter-PQMRR2PK.js → chatQueueReduxAdapter-TWIYKVIZ.js} +9 -9
- package/{chunk-Z77CRGTW.js → chunk-3AMA42ZI.js} +1 -1
- package/{chunk-5FBTLSFG.js → chunk-3BGIKIPF.js} +317 -153
- package/{chunk-ORYWEJO4.js → chunk-3IUWIAHP.js} +3 -3
- package/{chunk-Q2XN3EOZ.js → chunk-3VUWPRFW.js} +17 -7
- package/{chunk-GEPUP7OO.js → chunk-3YIAR5UI.js} +1 -1
- package/{chunk-5H7KJX7J.js → chunk-4MK3I7Y4.js} +1 -1
- package/{chunk-6VFARHZW.js → chunk-52Q2IW2X.js} +783 -999
- package/{chunk-6Q33GUCC.js → chunk-5MEYHVIB.js} +1 -1
- package/{chunk-6YTOJY35.js → chunk-6D2JFXLY.js} +35 -0
- package/{chunk-FZGV4FGK.js → chunk-6GFOD3TK.js} +260 -140
- package/{chunk-HJUYAD4A.js → chunk-6Z7MY3V7.js} +1 -1
- package/{chunk-V4MJDUSR.js → chunk-AHAHBQMU.js} +1 -1
- package/{chunk-TOP2VXOR.js → chunk-BFDFRLLQ.js} +2 -2
- package/chunk-BMQ2MJUK.js +153 -0
- package/{chunk-RG6JBBX5.js → chunk-CWQINZEA.js} +119 -3
- package/{chunk-BTI7PJDX.js → chunk-DD6XE56O.js} +12 -65
- package/{chunk-ETI2NYVF.js → chunk-FKNWP6SG.js} +1 -1
- package/{chunk-SSDAAEC2.js → chunk-FP76KI2Y.js} +280 -40
- package/chunk-FV3JEYR3.js +870 -0
- package/{chunk-DHDMC6FO.js → chunk-GIVFXPWK.js} +2 -0
- package/chunk-GMZLP5DV.js +82 -0
- package/{chunk-UZGQNTVW.js → chunk-GNCCNNZD.js} +3 -1
- package/{chunk-AFUORTY4.js → chunk-GP5LKBUZ.js} +1 -1
- package/{chunk-ZCYXJSTU.js → chunk-H4AHY5BU.js} +4 -81
- package/{chunk-OEVAY4J6.js → chunk-HAFJ3NDE.js} +2 -2
- package/{chunk-IIVGDG4I.js → chunk-HCT7U36O.js} +3 -0
- package/{chunk-4OEFYTWL.js → chunk-HKNXJGEC.js} +1 -1
- package/{chunk-VLTIYV3X.js → chunk-HYJFRTLW.js} +1 -1
- package/{chunk-NA35QHCF.js → chunk-K36IXSCQ.js} +1 -1
- package/{chunk-DRGSDQBL.js → chunk-KAUSRTO6.js} +2 -2
- package/{chunk-GPCZ7UXG.js → chunk-LJ5VW2UJ.js} +1 -1
- package/{chunk-YFE4A4O7.js → chunk-LMREEBWT.js} +120 -37
- package/{chunk-JRQFUXY7.js → chunk-LVIFM7VW.js} +1 -1
- package/{chunk-RFCKMYDK.js → chunk-MZYBSTMH.js} +4 -4
- package/chunk-OCZKATRC.js +129 -0
- package/{chunk-DNCEALKX.js → chunk-P5EVSOPA.js} +2 -2
- package/{chunk-BP4XNZRM.js → chunk-PBA4UJBK.js} +1 -1
- package/{chunk-G2O6V3HJ.js → chunk-PMAIQX7A.js} +3 -3
- package/{chunk-AEOE4Z6Q.js → chunk-QSHEEA5N.js} +2 -2
- package/{chunk-KQ4ONNQD.js → chunk-QU7KDSZX.js} +1 -1
- package/{chunk-45C5ER5U.js → chunk-RPJUFEGR.js} +4 -4
- package/{chunk-X6DN5HBD.js → chunk-U4OKDZFH.js} +3 -3
- package/{chunk-4S5QUMJP.js → chunk-UDVH2P4A.js} +4 -4
- package/{chunk-UKZDAFYT.js → chunk-UEVXFHQB.js} +2 -2
- package/{chunk-H62HCIUP.js → chunk-VRTTFDBM.js} +2 -1
- package/{chunk-6IG4XSS6.js → chunk-WP5UXDA5.js} +71 -4
- package/{chunk-3DII57IT.js → chunk-XD2MJFUG.js} +1 -1
- package/{chunk-QVKRR2SS.js → chunk-XP3VVAPG.js} +878 -175
- package/{chunk-L5UXH3B2.js → chunk-Z2PV6O2T.js} +18 -2
- package/{chunk-53HEEOTT.js → chunk-Z5625XML.js} +1 -1
- package/{contentThunks-GJV22WVZ.js → contentThunks-JYWI7G7I.js} +10 -10
- package/{createAgentAutomationAction-6V25TZEO.js → createAgentAutomationAction-Z4SUJ54Y.js} +10 -10
- package/{createDialogAction-SX36BGSX.js → createDialogAction-RCHFLVJ2.js} +12 -12
- package/{createPageAction-IR4BGJSI.js → createPageAction-YK2253XQ.js} +11 -11
- package/{dbSlice-XVWBAGYN.js → dbSlice-A6C6H32X.js} +1 -1
- package/{dialogCommands-5J56DFWN.js → dialogCommands-X4UOZQWX.js} +16 -15
- package/{dialogSlice-UNX2FAPZ.js → dialogSlice-IVTWLCE2.js} +15 -9
- package/{docCreateCommands-KYI2DC2U.js → docCreateCommands-VD6TGHG4.js} +15 -14
- package/{docDeleteCommands-67REUSRY.js → docDeleteCommands-OT3R2G4W.js} +16 -15
- package/{docReadCommands-HOSVSBDJ.js → docReadCommands-2G7BIXSH.js} +15 -14
- package/{docStore-JWVG5NDO.js → docStore-UENKCCDX.js} +2 -2
- package/{docUpdateCommands-EMGCSMXY.js → docUpdateCommands-45MVJKZA.js} +15 -14
- package/{handleSendMessageAction-B75UOJKF.js → handleSendMessageAction-LM2J4HC3.js} +50 -58
- package/index.js +51 -51
- package/{machineCommands-GFPTOY6L.js → machineCommands-6N6MQIE6.js} +38 -37
- package/{machineWsRunDispatch-46PSZ3DJ.js → machineWsRunDispatch-7MFKVQCR.js} +35 -34
- package/{memberThunks-QGFLFVCI.js → memberThunks-P2ECUJ56.js} +2 -2
- package/package.json +1 -1
- package/pdf-U6KSUEZZ.js +26435 -0
- package/{providerPresetApply-FG6NZ57W.js → providerPresetApply-XI3WUPTI.js} +2 -2
- package/{providerRegistry-757OWH3O.js → providerRegistry-KEPWWGXD.js} +2 -2
- package/{readlineWorkspace-UFSWHFKD.js → readlineWorkspace-JWBON5CX.js} +184 -63
- package/{removeDialogAgentAction-IX3MN2ZO.js → removeDialogAgentAction-W66BJ7CF.js} +4 -4
- package/{runAgentClientLoop-25LJ4XGV.js → runAgentClientLoop-TA4SSPHE.js} +26 -26
- package/{setDialogExtraReferencesAction-X4HCPNZL.js → setDialogExtraReferencesAction-2ALKG3WA.js} +3 -3
- package/{setPrimaryDialogAgentAction-4GMIQLOD.js → setPrimaryDialogAgentAction-TQZB55F6.js} +4 -4
- package/{settingSlice-ZQZVUPKK.js → settingSlice-P4ZW7K5X.js} +2 -2
- package/{spaceCommands-NKJVJCQQ.js → spaceCommands-6NSAXB7D.js} +15 -14
- package/{streamAgentChatTurn-A46QFV4O.js → streamAgentChatTurn-X5ENGUIS.js} +94 -34
- package/{switchDialogAgentAction-N52LRPA3.js → switchDialogAgentAction-3KI72HHS.js} +2 -2
- package/{toolApiClient-QVJ6HDNN.js → toolApiClient-G3M73RTB.js} +2 -2
- package/{tools-TTDGRNY6.js → tools-XRQR7ZZR.js} +23 -23
- package/{tuiSummaryLlmCaller-WFRWERGK.js → tuiSummaryLlmCaller-UFGFOIIW.js} +5 -4
- package/{updateDialogTitleAction-QJPZGF52.js → updateDialogTitleAction-ESUUD3GT.js} +10 -10
- package/chunk-Q5FJJ6XI.js +0 -103
|
@@ -5,13 +5,16 @@ import {
|
|
|
5
5
|
finalizeResponsesToolCalls,
|
|
6
6
|
flushChatCompletionStream,
|
|
7
7
|
providerHttpFailure,
|
|
8
|
-
readSseFrames,
|
|
9
|
-
streamSseDataValues,
|
|
10
8
|
throwIfChatCompletionStreamFailed
|
|
11
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-H4AHY5BU.js";
|
|
12
10
|
import {
|
|
13
|
-
DEVIN_CONNECT_URL
|
|
14
|
-
|
|
11
|
+
DEVIN_CONNECT_URL,
|
|
12
|
+
parseSseDataLineJson,
|
|
13
|
+
parseSseDataLineObject
|
|
14
|
+
} from "./chunk-FV3JEYR3.js";
|
|
15
|
+
import {
|
|
16
|
+
readSseFrames
|
|
17
|
+
} from "./chunk-GMZLP5DV.js";
|
|
15
18
|
import {
|
|
16
19
|
clipToolText,
|
|
17
20
|
hasImageInRuntimeMessages,
|
|
@@ -20,7 +23,7 @@ import {
|
|
|
20
23
|
resolveHistoricalToolContentCap,
|
|
21
24
|
resolveToolOutputProfile,
|
|
22
25
|
stripImagePartsFromMessages
|
|
23
|
-
} from "./chunk-
|
|
26
|
+
} from "./chunk-4MK3I7Y4.js";
|
|
24
27
|
import {
|
|
25
28
|
downgradeUnparsableToolCalls,
|
|
26
29
|
hasParsableObjectArguments,
|
|
@@ -35,6 +38,7 @@ import {
|
|
|
35
38
|
finalizeAccumulatedToolCalls
|
|
36
39
|
} from "./chunk-N7J63Q6C.js";
|
|
37
40
|
import {
|
|
41
|
+
DELETE_SAFETY_RED_LINE,
|
|
38
42
|
TOOL_GUIDED_SECTION_ORDER,
|
|
39
43
|
buildIdentityBlock,
|
|
40
44
|
buildRuntimeGuidanceBlocks,
|
|
@@ -46,7 +50,7 @@ import {
|
|
|
46
50
|
requiresBareImageUrl,
|
|
47
51
|
resolveToolGuidedSections,
|
|
48
52
|
toBareImageUrlMessages
|
|
49
|
-
} from "./chunk-
|
|
53
|
+
} from "./chunk-Z2PV6O2T.js";
|
|
50
54
|
import {
|
|
51
55
|
convertMessagesToResponsesInput,
|
|
52
56
|
extractReasoningFromResponseOutput,
|
|
@@ -64,18 +68,14 @@ import {
|
|
|
64
68
|
applyToolSurfaceConstraints,
|
|
65
69
|
buildDialogReadEnvelope,
|
|
66
70
|
buildNoloWorkspaceCommandArgs,
|
|
71
|
+
buildNoloWorkspaceOpenAiTools,
|
|
67
72
|
createStreamingDialogReadProjector,
|
|
68
73
|
noloPositiveIntegerString,
|
|
69
74
|
noloStringArg,
|
|
70
75
|
parseNoloWorkspaceToolArguments,
|
|
71
76
|
readTextStreamUpToChars,
|
|
72
77
|
resolveNoloDialogInput
|
|
73
|
-
} from "./chunk-
|
|
74
|
-
import {
|
|
75
|
-
getAntigravityUserAgent,
|
|
76
|
-
readAntigravityProjectId,
|
|
77
|
-
resolveAntigravityCloudCodeBaseUrl
|
|
78
|
-
} from "./chunk-UZGQNTVW.js";
|
|
78
|
+
} from "./chunk-HCT7U36O.js";
|
|
79
79
|
import {
|
|
80
80
|
buildProviderAuthHeaders,
|
|
81
81
|
buildProviderExecutionPlan
|
|
@@ -93,7 +93,7 @@ import {
|
|
|
93
93
|
resolveEmptyAssistantFallbackMessage,
|
|
94
94
|
resolveEmptyAssistantOutcome,
|
|
95
95
|
resolveTruncatedReasoningTailLog
|
|
96
|
-
} from "./chunk-
|
|
96
|
+
} from "./chunk-HKNXJGEC.js";
|
|
97
97
|
import {
|
|
98
98
|
COMPACTION_SUMMARY_SCHEMA_VERSION,
|
|
99
99
|
COMPACTION_SUMMARY_SYSTEM_PROMPT,
|
|
@@ -112,7 +112,7 @@ import {
|
|
|
112
112
|
resolveCompressionTriggerRatio,
|
|
113
113
|
truncateToolOutputForContext,
|
|
114
114
|
withProviderCallTimingFields
|
|
115
|
-
} from "./chunk-
|
|
115
|
+
} from "./chunk-P5EVSOPA.js";
|
|
116
116
|
import {
|
|
117
117
|
estimateTokenCount
|
|
118
118
|
} from "./chunk-PSCNXBYA.js";
|
|
@@ -11900,6 +11900,7 @@ var toQueue = /* @__PURE__ */ dual(2, (self, options) => toQueueArray(self.chann
|
|
|
11900
11900
|
var runIntoQueue = /* @__PURE__ */ dual(2, (self, queue) => runIntoQueueArray(self.channel, queue));
|
|
11901
11901
|
|
|
11902
11902
|
// packages/agent-runtime/abortableKernel.ts
|
|
11903
|
+
var IDLE_WATCHDOG_SLICES = 20;
|
|
11903
11904
|
function runAbortableWithTimeout(args2) {
|
|
11904
11905
|
const taskEffect = Effect_exports.callback(
|
|
11905
11906
|
(resume) => {
|
|
@@ -11935,12 +11936,26 @@ function runAbortableWithTimeout(args2) {
|
|
|
11935
11936
|
raced = Effect_exports.raceFirst(taskEffect, abortEffect);
|
|
11936
11937
|
}
|
|
11937
11938
|
if (typeof args2.timeoutMs === "number") {
|
|
11938
|
-
const
|
|
11939
|
+
const outer = raced;
|
|
11939
11940
|
const timeoutMs = args2.timeoutMs;
|
|
11940
|
-
|
|
11941
|
-
|
|
11942
|
-
|
|
11941
|
+
const activityVersion = args2.activityVersion;
|
|
11942
|
+
const idleWatchdog = Effect_exports.gen(function* () {
|
|
11943
|
+
const sliceCount = activityVersion ? IDLE_WATCHDOG_SLICES : 1;
|
|
11944
|
+
const baseSliceMs = Math.max(1, Math.floor(timeoutMs / sliceCount));
|
|
11945
|
+
let idleMs = 0;
|
|
11946
|
+
for (; ; ) {
|
|
11947
|
+
const versionAtSliceStart = activityVersion?.();
|
|
11948
|
+
const sliceMs = Math.max(1, Math.min(timeoutMs - idleMs, baseSliceMs));
|
|
11949
|
+
yield* Effect_exports.sleep(Duration_exports.millis(sliceMs));
|
|
11950
|
+
idleMs += sliceMs;
|
|
11951
|
+
if (activityVersion && activityVersion() !== versionAtSliceStart) {
|
|
11952
|
+
idleMs = 0;
|
|
11953
|
+
continue;
|
|
11954
|
+
}
|
|
11955
|
+
if (idleMs >= timeoutMs) return { kind: "timeout" };
|
|
11956
|
+
}
|
|
11943
11957
|
});
|
|
11958
|
+
raced = Effect_exports.raceFirst(outer, idleWatchdog);
|
|
11944
11959
|
}
|
|
11945
11960
|
return args2.runtime ? args2.runtime.runPromise(raced) : Effect_exports.runPromise(raced);
|
|
11946
11961
|
}
|
|
@@ -12627,6 +12642,13 @@ function isColdResume(history, nowMs) {
|
|
|
12627
12642
|
}
|
|
12628
12643
|
async function maybeAutoCompactLocalHistory(args2) {
|
|
12629
12644
|
const { adapter, dialogId, history } = args2;
|
|
12645
|
+
const emitPhase = (phase) => {
|
|
12646
|
+
try {
|
|
12647
|
+
args2.onPhase?.(phase);
|
|
12648
|
+
} catch {
|
|
12649
|
+
}
|
|
12650
|
+
};
|
|
12651
|
+
emitPhase({ kind: "validating-context" });
|
|
12630
12652
|
const unchanged = (decision) => ({
|
|
12631
12653
|
history,
|
|
12632
12654
|
compressed: false,
|
|
@@ -12722,8 +12744,15 @@ async function maybeAutoCompactLocalHistory(args2) {
|
|
|
12722
12744
|
if (!plan.shouldCompress) {
|
|
12723
12745
|
return projectExisting();
|
|
12724
12746
|
}
|
|
12747
|
+
emitPhase({ kind: "compaction-start" });
|
|
12725
12748
|
try {
|
|
12749
|
+
if (args2.abortSignal?.aborted) {
|
|
12750
|
+
throw Object.assign(new Error("auto-compaction aborted"), { compactionReason: "aborted" });
|
|
12751
|
+
}
|
|
12726
12752
|
const provider = await args2.resolveProvider();
|
|
12753
|
+
if (args2.abortSignal?.aborted) {
|
|
12754
|
+
throw Object.assign(new Error("auto-compaction aborted"), { compactionReason: "aborted" });
|
|
12755
|
+
}
|
|
12727
12756
|
const msgsToCompress = plan.msgsToCompress;
|
|
12728
12757
|
const messagesText = formatMessagesForSummaryWithTruncation(msgsToCompress);
|
|
12729
12758
|
const fileOpsText = formatFileOperationsFromMessages(
|
|
@@ -12735,20 +12764,55 @@ async function maybeAutoCompactLocalHistory(args2) {
|
|
|
12735
12764
|
messagesText,
|
|
12736
12765
|
fileOpsText
|
|
12737
12766
|
});
|
|
12738
|
-
|
|
12739
|
-
|
|
12740
|
-
|
|
12741
|
-
|
|
12767
|
+
emitPhase({ kind: "waiting-provider" });
|
|
12768
|
+
const timeoutMs = typeof args2.timeoutMs === "number" && Number.isFinite(args2.timeoutMs) && args2.timeoutMs > 0 ? args2.timeoutMs : void 0;
|
|
12769
|
+
const requestController = new AbortController();
|
|
12770
|
+
let timeoutHandle;
|
|
12771
|
+
let abortListener;
|
|
12772
|
+
const request3 = provider.complete(
|
|
12773
|
+
[{ role: "system", content: COMPACTION_SUMMARY_SYSTEM_PROMPT }, { role: "user", content: promptContent }],
|
|
12774
|
+
{ signal: requestController.signal, ...timeoutMs ? { timeoutMs } : {} }
|
|
12775
|
+
).then(
|
|
12776
|
+
(value) => ({ kind: "done", value }),
|
|
12777
|
+
(error) => ({ kind: "provider-error", error })
|
|
12778
|
+
);
|
|
12779
|
+
const guards = [];
|
|
12780
|
+
if (timeoutMs) guards.push(new Promise((resolve5) => {
|
|
12781
|
+
timeoutHandle = setTimeout(() => {
|
|
12782
|
+
requestController.abort();
|
|
12783
|
+
resolve5({ kind: "timeout" });
|
|
12784
|
+
}, timeoutMs);
|
|
12785
|
+
}));
|
|
12786
|
+
if (args2.abortSignal) guards.push(new Promise((resolve5) => {
|
|
12787
|
+
abortListener = () => {
|
|
12788
|
+
requestController.abort(args2.abortSignal?.reason);
|
|
12789
|
+
resolve5({ kind: "aborted" });
|
|
12790
|
+
};
|
|
12791
|
+
args2.abortSignal?.addEventListener("abort", abortListener, { once: true });
|
|
12792
|
+
}));
|
|
12793
|
+
const outcome = guards.length ? await Promise.race([request3, ...guards]) : await request3;
|
|
12794
|
+
if (timeoutHandle) clearTimeout(timeoutHandle);
|
|
12795
|
+
if (abortListener) args2.abortSignal?.removeEventListener("abort", abortListener);
|
|
12796
|
+
if (outcome.kind !== "done") {
|
|
12797
|
+
const reason = outcome.kind === "timeout" ? "timeout" : outcome.kind === "aborted" ? "aborted" : "provider-error";
|
|
12798
|
+
const detail = outcome.kind === "provider-error" ? outcome.error instanceof Error ? outcome.error.message : String(outcome.error) : reason === "timeout" ? `auto-compaction timed out after ${timeoutMs}ms` : "auto-compaction aborted";
|
|
12799
|
+
throw Object.assign(new Error(detail), { compactionReason: reason });
|
|
12800
|
+
}
|
|
12801
|
+
const result4 = outcome.value;
|
|
12742
12802
|
const newSummary = typeof result4.content === "string" ? result4.content.trim() : "";
|
|
12743
12803
|
if (!newSummary) {
|
|
12744
12804
|
console.warn(
|
|
12745
12805
|
"[localLoop] auto-compaction produced empty summary; keeping prior projection"
|
|
12746
12806
|
);
|
|
12807
|
+
const failureReason = "provider-error";
|
|
12808
|
+
emitPhase({ kind: "compaction-failed", reason: failureReason });
|
|
12747
12809
|
return {
|
|
12748
12810
|
...projectExisting(),
|
|
12749
12811
|
failureMessage: "summary model returned empty content",
|
|
12812
|
+
failureReason,
|
|
12750
12813
|
decision: {
|
|
12751
12814
|
outcome: "failed",
|
|
12815
|
+
reason: failureReason,
|
|
12752
12816
|
detail: "summary model returned empty content"
|
|
12753
12817
|
}
|
|
12754
12818
|
};
|
|
@@ -12775,6 +12839,7 @@ async function maybeAutoCompactLocalHistory(args2) {
|
|
|
12775
12839
|
summaryUsage: result4.usage
|
|
12776
12840
|
});
|
|
12777
12841
|
console.log(formatCompactionMetricsLog(metrics));
|
|
12842
|
+
emitPhase({ kind: "compaction-end" });
|
|
12778
12843
|
return {
|
|
12779
12844
|
history: projectHistoryWithSummary({
|
|
12780
12845
|
history,
|
|
@@ -12802,10 +12867,13 @@ async function maybeAutoCompactLocalHistory(args2) {
|
|
|
12802
12867
|
} catch (error) {
|
|
12803
12868
|
console.warn("[localLoop] auto-compaction failed:", error);
|
|
12804
12869
|
const failureMessage = error instanceof Error && error.message ? error.message.slice(0, 200) : String(error).slice(0, 200);
|
|
12870
|
+
const failureReason = error instanceof Error && "compactionReason" in error ? error.compactionReason : "provider-error";
|
|
12871
|
+
emitPhase({ kind: "compaction-failed", reason: failureReason });
|
|
12805
12872
|
return {
|
|
12806
12873
|
...projectExisting(),
|
|
12807
12874
|
failureMessage,
|
|
12808
|
-
|
|
12875
|
+
failureReason,
|
|
12876
|
+
decision: { outcome: "failed", reason: failureReason, detail: failureMessage }
|
|
12809
12877
|
};
|
|
12810
12878
|
}
|
|
12811
12879
|
}
|
|
@@ -12862,6 +12930,8 @@ function emitLoopEvent(boundary, event, bridge) {
|
|
|
12862
12930
|
boundary.emit(bridge ? { event, bridge } : { event });
|
|
12863
12931
|
}
|
|
12864
12932
|
var LLM_REQUEST_TIMEOUT = "LLM_REQUEST_TIMEOUT";
|
|
12933
|
+
var DEFAULT_LLM_REQUEST_TIMEOUT_MS = 10 * 60 * 1e3;
|
|
12934
|
+
var DEFAULT_COMPACTION_TIMEOUT_MS = 60 * 1e3;
|
|
12865
12935
|
var LOCAL_TURN_ABORTED_CODE = "LOCAL_TURN_ABORTED";
|
|
12866
12936
|
function buildAbortedError() {
|
|
12867
12937
|
const error = new Error("local agent turn aborted by user");
|
|
@@ -12889,8 +12959,11 @@ async function runAbortableToolTask(input, task, pendingToolName) {
|
|
|
12889
12959
|
}
|
|
12890
12960
|
function resolveLlmRequestTimeoutMs(input) {
|
|
12891
12961
|
const raw = input.llmRequestTimeoutMs ?? input.timeoutMs;
|
|
12892
|
-
|
|
12893
|
-
|
|
12962
|
+
return typeof raw === "number" && Number.isFinite(raw) && raw > 0 ? raw : DEFAULT_LLM_REQUEST_TIMEOUT_MS;
|
|
12963
|
+
}
|
|
12964
|
+
function resolveCompactionTimeoutMs(input) {
|
|
12965
|
+
const raw = input.compactionTimeoutMs;
|
|
12966
|
+
return typeof raw === "number" && Number.isFinite(raw) && raw > 0 ? raw : DEFAULT_COMPACTION_TIMEOUT_MS;
|
|
12894
12967
|
}
|
|
12895
12968
|
async function runCompleteWithTimeout(args2) {
|
|
12896
12969
|
const { provider, messages, options, timeoutMs, round, input, boundary, context: context3, providerName, model } = args2;
|
|
@@ -12913,6 +12986,7 @@ async function runCompleteWithTimeout(args2) {
|
|
|
12913
12986
|
const outcome = await runAbortableWithTimeout({
|
|
12914
12987
|
task: complete,
|
|
12915
12988
|
timeoutMs: typeof timeoutMs === "number" ? timeoutMs : void 0,
|
|
12989
|
+
activityVersion: args2.activityVersion,
|
|
12916
12990
|
abortSignal: input.abortSignal,
|
|
12917
12991
|
runtime: input.effectRuntime
|
|
12918
12992
|
});
|
|
@@ -12923,7 +12997,7 @@ async function runCompleteWithTimeout(args2) {
|
|
|
12923
12997
|
}
|
|
12924
12998
|
if (outcome.kind === "timeout") {
|
|
12925
12999
|
const timeoutError = new Error(
|
|
12926
|
-
`LLM request timed out after ${timeoutMs}ms (round ${round})`
|
|
13000
|
+
`LLM request timed out after ${timeoutMs}ms without new output (idle window, round ${round})`
|
|
12927
13001
|
);
|
|
12928
13002
|
timeoutError.code = LLM_REQUEST_TIMEOUT;
|
|
12929
13003
|
throw timeoutError;
|
|
@@ -13604,6 +13678,9 @@ async function runLocalAgentTurn(input) {
|
|
|
13604
13678
|
input.contextBlockScopes
|
|
13605
13679
|
);
|
|
13606
13680
|
const mergedContextBlockScopes = [
|
|
13681
|
+
// 删除安全红线:系统层最高优先级约束,位于所有块之前(含身份信息块),
|
|
13682
|
+
// owner 要求常驻「根本提示词」的最顶部(2026-09-26 批量误删事故)。
|
|
13683
|
+
{ content: DELETE_SAFETY_RED_LINE, cacheScope: "session" },
|
|
13607
13684
|
{ content: identityBlock, cacheScope: "session" },
|
|
13608
13685
|
...guidanceScopes,
|
|
13609
13686
|
...callerScopes
|
|
@@ -13636,6 +13713,16 @@ async function runLocalAgentTurn(input) {
|
|
|
13636
13713
|
}
|
|
13637
13714
|
}
|
|
13638
13715
|
let compactionUsage;
|
|
13716
|
+
const emitCompactionPhase = (phase, scope3) => {
|
|
13717
|
+
const atMs = Date.now();
|
|
13718
|
+
if (phase.kind === "validating-context") emitLoopEvent(observationBoundary, { kind: "turn-phase", phase: "validating-context", atMs, compactionScope: scope3 });
|
|
13719
|
+
else if (phase.kind === "compaction-start") {
|
|
13720
|
+
emitLoopEvent(observationBoundary, { kind: "turn-phase", phase: "compacting", atMs, compactionScope: scope3 });
|
|
13721
|
+
emitLoopEvent(observationBoundary, { kind: "compaction-start", atMs, scope: scope3 });
|
|
13722
|
+
} else if (phase.kind === "waiting-provider") emitLoopEvent(observationBoundary, { kind: "turn-phase", phase: "waiting-provider", atMs, compactionScope: scope3 });
|
|
13723
|
+
else if (phase.kind === "compaction-end") emitLoopEvent(observationBoundary, { kind: "compaction-end", atMs, scope: scope3 });
|
|
13724
|
+
else emitLoopEvent(observationBoundary, { kind: "compaction-failed", atMs, scope: scope3, reason: phase.reason });
|
|
13725
|
+
};
|
|
13639
13726
|
const emitCompactionObservation = (compacted) => {
|
|
13640
13727
|
const decision = compacted.decision;
|
|
13641
13728
|
if (decision?.outcome === "skipped") {
|
|
@@ -13669,7 +13756,10 @@ async function runLocalAgentTurn(input) {
|
|
|
13669
13756
|
model: agentConfig.model,
|
|
13670
13757
|
resolveProvider: resolveProviderOnce,
|
|
13671
13758
|
contextWindow,
|
|
13672
|
-
realContextUsagePercent
|
|
13759
|
+
realContextUsagePercent,
|
|
13760
|
+
abortSignal: input.abortSignal,
|
|
13761
|
+
timeoutMs: resolveCompactionTimeoutMs(input),
|
|
13762
|
+
onPhase: (phase) => emitCompactionPhase(phase, "initial")
|
|
13673
13763
|
});
|
|
13674
13764
|
history = compacted.history;
|
|
13675
13765
|
compactionUsage = compacted.usage;
|
|
@@ -13775,7 +13865,10 @@ async function runLocalAgentTurn(input) {
|
|
|
13775
13865
|
model: agentConfig.model,
|
|
13776
13866
|
resolveProvider: resolveProviderOnce,
|
|
13777
13867
|
contextWindow,
|
|
13778
|
-
...ratio !== void 0 ? { realContextUsagePercent: ratio } : {}
|
|
13868
|
+
...ratio !== void 0 ? { realContextUsagePercent: ratio } : {},
|
|
13869
|
+
abortSignal: input.abortSignal,
|
|
13870
|
+
timeoutMs: resolveCompactionTimeoutMs(input),
|
|
13871
|
+
onPhase: (phase) => emitCompactionPhase(phase, "in-loop")
|
|
13779
13872
|
});
|
|
13780
13873
|
if (compacted.usage) {
|
|
13781
13874
|
compactionUsage = addOutOfBandUsage(compactionUsage, compacted.usage);
|
|
@@ -13845,11 +13938,12 @@ async function runLocalAgentTurn(input) {
|
|
|
13845
13938
|
const shouldPassToolEvents = Boolean(
|
|
13846
13939
|
input.onToolEvent || input.onObservationEvent || input.observationBoundary
|
|
13847
13940
|
);
|
|
13941
|
+
let llmStreamActivity = 0;
|
|
13848
13942
|
result4 = await runCompleteWithTimeout({
|
|
13849
13943
|
provider,
|
|
13850
13944
|
messages: requestMessages,
|
|
13851
13945
|
options: {
|
|
13852
|
-
|
|
13946
|
+
timeoutMs: resolveLlmRequestTimeoutMs(input),
|
|
13853
13947
|
// 用户取消信号穿进 provider options:providerStreamRetry 据此在
|
|
13854
13948
|
// 取消后跳过重试,provider 分支(如 antigravity/openai-compatible)
|
|
13855
13949
|
// 也可把 fetch 绑定到同一信号,实现真正的传输层取消。
|
|
@@ -13858,6 +13952,7 @@ async function runLocalAgentTurn(input) {
|
|
|
13858
13952
|
// 归到具体对话而不是 chat-proxy 兜底桶。新对话首轮 id 尚未分配。
|
|
13859
13953
|
...input.continueDialogId ? { dialogId: input.continueDialogId } : {},
|
|
13860
13954
|
...shouldStreamDeltas ? { onTextDelta: (chunk) => {
|
|
13955
|
+
llmStreamActivity += 1;
|
|
13861
13956
|
partialContent += chunk;
|
|
13862
13957
|
observationBoundary.emit({
|
|
13863
13958
|
kind: "text-delta",
|
|
@@ -13867,6 +13962,7 @@ async function runLocalAgentTurn(input) {
|
|
|
13867
13962
|
});
|
|
13868
13963
|
} } : {},
|
|
13869
13964
|
...shouldStreamReasoning ? { onReasoningDelta: (chunk) => {
|
|
13965
|
+
llmStreamActivity += 1;
|
|
13870
13966
|
observationBoundary.emit({
|
|
13871
13967
|
kind: "reasoning-delta",
|
|
13872
13968
|
chunk,
|
|
@@ -13875,6 +13971,7 @@ async function runLocalAgentTurn(input) {
|
|
|
13875
13971
|
});
|
|
13876
13972
|
} } : {},
|
|
13877
13973
|
...shouldPassToolEvents ? { onToolEvent: (event) => {
|
|
13974
|
+
llmStreamActivity += 1;
|
|
13878
13975
|
observationBoundary.emit({
|
|
13879
13976
|
kind: "tool-event",
|
|
13880
13977
|
event,
|
|
@@ -13885,6 +13982,7 @@ async function runLocalAgentTurn(input) {
|
|
|
13885
13982
|
...shouldPassToolEvents ? { toolEventRound: round } : {}
|
|
13886
13983
|
},
|
|
13887
13984
|
timeoutMs: resolveLlmRequestTimeoutMs(input),
|
|
13985
|
+
activityVersion: () => llmStreamActivity,
|
|
13888
13986
|
round,
|
|
13889
13987
|
input,
|
|
13890
13988
|
boundary: observationBoundary,
|
|
@@ -14366,23 +14464,6 @@ function kimiIdentityHeaders(url) {
|
|
|
14366
14464
|
return isKimiEndpoint(url) ? { "User-Agent": KIMI_CODE_USER_AGENT } : {};
|
|
14367
14465
|
}
|
|
14368
14466
|
|
|
14369
|
-
// packages/agent-runtime/sseDataLine.ts
|
|
14370
|
-
function parseSseDataLineJson(line) {
|
|
14371
|
-
const trimmed = line.trim();
|
|
14372
|
-
if (!trimmed.startsWith("data:")) return null;
|
|
14373
|
-
const payload = trimmed.slice(5).trim();
|
|
14374
|
-
if (!payload || payload === "[DONE]") return null;
|
|
14375
|
-
try {
|
|
14376
|
-
return JSON.parse(payload);
|
|
14377
|
-
} catch {
|
|
14378
|
-
return null;
|
|
14379
|
-
}
|
|
14380
|
-
}
|
|
14381
|
-
function parseSseDataLineObject(line) {
|
|
14382
|
-
const parsed = parseSseDataLineJson(line);
|
|
14383
|
-
return parsed && typeof parsed === "object" ? parsed : null;
|
|
14384
|
-
}
|
|
14385
|
-
|
|
14386
14467
|
// packages/integrations/openai/responsesRequestBody.ts
|
|
14387
14468
|
function buildResponsesRequestBody(body, model) {
|
|
14388
14469
|
const tools = Array.isArray(body.tools) ? toResponsesTools(body.tools) : void 0;
|
|
@@ -15652,132 +15733,6 @@ async function evaluateCapabilityPolicy(capability, normalizedInput, ctx) {
|
|
|
15652
15733
|
}
|
|
15653
15734
|
}
|
|
15654
15735
|
|
|
15655
|
-
// packages/agent-runtime/localToolPolicy.ts
|
|
15656
|
-
var NEVER_LOCAL_TOOLS = /* @__PURE__ */ new Set([
|
|
15657
|
-
"deleteSpaces",
|
|
15658
|
-
"updateAgent",
|
|
15659
|
-
"updateSelf",
|
|
15660
|
-
"createAgent"
|
|
15661
|
-
]);
|
|
15662
|
-
var DEFAULT_LOCAL_TOOLS = /* @__PURE__ */ new Set([
|
|
15663
|
-
"readFile",
|
|
15664
|
-
"writeFile",
|
|
15665
|
-
"editFile",
|
|
15666
|
-
"globFiles",
|
|
15667
|
-
"execShell",
|
|
15668
|
-
"launchProcess",
|
|
15669
|
-
"listProcesses",
|
|
15670
|
-
// ProcessTask follow-up tools. Same tier as listProcesses: they observe/stop
|
|
15671
|
-
// tasks the agent itself already spawned, so their blast radius is strictly
|
|
15672
|
-
// narrower than launchProcess (which is default-enabled). Model-facing
|
|
15673
|
-
// follow-ups are taskWait/taskStop only — lifecycle history (taskLogs) stays
|
|
15674
|
-
// runtime-internal.
|
|
15675
|
-
"taskWait",
|
|
15676
|
-
"taskStop",
|
|
15677
|
-
// Scheduling tools: forking/observing sub-agents is a declared capability
|
|
15678
|
-
// of capable agents, and the blast radius is strictly narrower than
|
|
15679
|
-
// execShell (already default-enabled). Requiring an env allowlist for these
|
|
15680
|
-
// while execShell is open by default inverted the risk model and forced every
|
|
15681
|
-
// new local user to hand-edit .env files before sub-agent tasks worked.
|
|
15682
|
-
"startAgentRun",
|
|
15683
|
-
"controlAgentRun"
|
|
15684
|
-
]);
|
|
15685
|
-
function parseToolAllowlist(value) {
|
|
15686
|
-
return (value ?? "").split(",").flatMap((item) => {
|
|
15687
|
-
const trimmed = item.trim();
|
|
15688
|
-
return trimmed ? [trimmed] : [];
|
|
15689
|
-
});
|
|
15690
|
-
}
|
|
15691
|
-
function normalizeLocalToolName(toolName) {
|
|
15692
|
-
return canonicalizeToolName(
|
|
15693
|
-
String(toolName ?? "").replace(/^functions\./, "").trim()
|
|
15694
|
-
);
|
|
15695
|
-
}
|
|
15696
|
-
function isRestrictedLocalToolMode(env) {
|
|
15697
|
-
return env.NOLO_LOCAL_TOOL_MODE === "restricted";
|
|
15698
|
-
}
|
|
15699
|
-
function resolveLocalToolPolicy(args2) {
|
|
15700
|
-
const toolName = normalizeLocalToolName(args2.toolName);
|
|
15701
|
-
const restrictedMode = isRestrictedLocalToolMode(args2.env);
|
|
15702
|
-
if (!toolName) {
|
|
15703
|
-
return {
|
|
15704
|
-
allowed: false,
|
|
15705
|
-
toolName,
|
|
15706
|
-
reason: "Tool name is required."
|
|
15707
|
-
};
|
|
15708
|
-
}
|
|
15709
|
-
if (NEVER_LOCAL_TOOLS.has(toolName)) {
|
|
15710
|
-
return {
|
|
15711
|
-
allowed: false,
|
|
15712
|
-
toolName,
|
|
15713
|
-
reason: `${toolName} is blocked by the local runtime safety policy.`
|
|
15714
|
-
};
|
|
15715
|
-
}
|
|
15716
|
-
const allowedByEnv = new Set(parseToolAllowlist(args2.env.NOLO_LOCAL_ALLOWED_TOOLS));
|
|
15717
|
-
const agentTools = new Set(
|
|
15718
|
-
(args2.agentToolNames ?? []).flatMap((item) => {
|
|
15719
|
-
const normalized = normalizeLocalToolName(item);
|
|
15720
|
-
return normalized ? [normalized] : [];
|
|
15721
|
-
})
|
|
15722
|
-
);
|
|
15723
|
-
if (!restrictedMode && agentTools.has(toolName)) {
|
|
15724
|
-
return { allowed: true, toolName };
|
|
15725
|
-
}
|
|
15726
|
-
if (DEFAULT_LOCAL_TOOLS.has(toolName) && agentTools.has(toolName)) {
|
|
15727
|
-
return { allowed: true, toolName };
|
|
15728
|
-
}
|
|
15729
|
-
if (allowedByEnv.has(toolName) && agentTools.has(toolName)) {
|
|
15730
|
-
return { allowed: true, toolName };
|
|
15731
|
-
}
|
|
15732
|
-
return {
|
|
15733
|
-
allowed: false,
|
|
15734
|
-
toolName,
|
|
15735
|
-
reason: `${toolName} is not enabled for local runtime runs. The agent must declare the tool in its manifest; in restricted mode (NOLO_LOCAL_TOOL_MODE=restricted) non-default tools also require adding to NOLO_LOCAL_ALLOWED_TOOLS (e.g. NOLO_LOCAL_ALLOWED_TOOLS=someCustomTool) and restarting the session so the env var loads.`
|
|
15736
|
-
};
|
|
15737
|
-
}
|
|
15738
|
-
async function executeLocalToolWithPolicy(args2) {
|
|
15739
|
-
if (args2.runToolNames !== void 0 && !args2.runToolNames.includes(normalizeLocalToolName(args2.call.name))) {
|
|
15740
|
-
throw new Error(`${args2.call.name} is outside the final run tool surface.`);
|
|
15741
|
-
}
|
|
15742
|
-
const decision = resolveLocalToolPolicy({
|
|
15743
|
-
env: args2.env,
|
|
15744
|
-
agentToolNames: args2.agentToolNames,
|
|
15745
|
-
toolName: args2.call.name
|
|
15746
|
-
});
|
|
15747
|
-
if (!decision.allowed) throw new Error(decision.reason);
|
|
15748
|
-
const executor = args2.executors?.[decision.toolName];
|
|
15749
|
-
if (!executor) {
|
|
15750
|
-
throw new Error(`${decision.toolName} is allowed by policy but no local executor is registered.`);
|
|
15751
|
-
}
|
|
15752
|
-
const opts = {
|
|
15753
|
-
...args2.abortSignal ? { abortSignal: args2.abortSignal } : {},
|
|
15754
|
-
...args2.detachMs !== void 0 ? { detachMs: args2.detachMs } : {},
|
|
15755
|
-
...args2.confirmed !== void 0 ? { confirmed: args2.confirmed } : {},
|
|
15756
|
-
...args2.enableDestructiveShellGuard !== void 0 ? { enableDestructiveShellGuard: args2.enableDestructiveShellGuard } : {},
|
|
15757
|
-
...args2.confirmDestructiveAction ? { confirmDestructiveAction: args2.confirmDestructiveAction } : {},
|
|
15758
|
-
...args2.blockDestructiveWithoutConfirmation !== void 0 ? { blockDestructiveWithoutConfirmation: args2.blockDestructiveWithoutConfirmation } : {}
|
|
15759
|
-
};
|
|
15760
|
-
if (decision.toolName === "execShell") {
|
|
15761
|
-
let parsedInput = args2.call.arguments;
|
|
15762
|
-
if (typeof parsedInput === "string") {
|
|
15763
|
-
try {
|
|
15764
|
-
parsedInput = JSON.parse(parsedInput);
|
|
15765
|
-
} catch {
|
|
15766
|
-
parsedInput = { command: parsedInput };
|
|
15767
|
-
}
|
|
15768
|
-
}
|
|
15769
|
-
await evaluateExecShellDestructiveGuard(parsedInput, opts);
|
|
15770
|
-
opts.confirmed = true;
|
|
15771
|
-
}
|
|
15772
|
-
return executor(
|
|
15773
|
-
{
|
|
15774
|
-
...args2.call,
|
|
15775
|
-
name: decision.toolName
|
|
15776
|
-
},
|
|
15777
|
-
opts
|
|
15778
|
-
);
|
|
15779
|
-
}
|
|
15780
|
-
|
|
15781
15736
|
// packages/agent-runtime/localWorkspaceTools.ts
|
|
15782
15737
|
import { existsSync as existsSync3 } from "node:fs";
|
|
15783
15738
|
import { createHash as createHash3 } from "node:crypto";
|
|
@@ -16576,29 +16531,6 @@ function getProcessRegistry() {
|
|
|
16576
16531
|
return registry;
|
|
16577
16532
|
}
|
|
16578
16533
|
|
|
16579
|
-
// packages/agent-runtime/processOwnership.ts
|
|
16580
|
-
var asNonEmptyString = (value) => {
|
|
16581
|
-
if (typeof value !== "string") return null;
|
|
16582
|
-
const trimmed = value.trim();
|
|
16583
|
-
return trimmed ? trimmed : null;
|
|
16584
|
-
};
|
|
16585
|
-
function readProcessOwner(runtimeContext) {
|
|
16586
|
-
if (!runtimeContext || typeof runtimeContext !== "object") return null;
|
|
16587
|
-
const dialogId = asNonEmptyString(runtimeContext.dialogId) ?? asNonEmptyString(runtimeContext.parentThreadId);
|
|
16588
|
-
if (!dialogId) return null;
|
|
16589
|
-
const turnId = asNonEmptyString(runtimeContext.turnId);
|
|
16590
|
-
const ownerId = asNonEmptyString(runtimeContext.ownerId);
|
|
16591
|
-
return {
|
|
16592
|
-
dialogId,
|
|
16593
|
-
...turnId ? { turnId } : {},
|
|
16594
|
-
...ownerId ? { ownerId } : {}
|
|
16595
|
-
};
|
|
16596
|
-
}
|
|
16597
|
-
|
|
16598
|
-
// packages/agent-runtime/workspaceShell.ts
|
|
16599
|
-
import { resolve as resolve3 } from "node:path";
|
|
16600
|
-
import { spawn as spawnChildProcess2 } from "node:child_process";
|
|
16601
|
-
|
|
16602
16534
|
// packages/agent-runtime/processTaskResult.ts
|
|
16603
16535
|
var PROCESS_RESULT_CAPSULE_TAIL_CHARS = 4e3;
|
|
16604
16536
|
var PROCESS_RESULT_CAPSULE_SPILL_THRESHOLD_CHARS = 2e4;
|
|
@@ -16618,11 +16550,17 @@ function buildProcessTaskResultCapsule(args2) {
|
|
|
16618
16550
|
const exitCode = args2.exitCode;
|
|
16619
16551
|
const captureError = args2.captureError?.trim() || void 0;
|
|
16620
16552
|
const durationMs = typeof args2.startedAt === "number" && Number.isFinite(args2.startedAt) ? Math.max(0, (args2.endedAt ?? Date.now()) - args2.startedAt) : void 0;
|
|
16621
|
-
const
|
|
16622
|
-
const
|
|
16553
|
+
const stdoutProvenance = args2.streamProvenance?.stdout;
|
|
16554
|
+
const stderrProvenance = args2.streamProvenance?.stderr;
|
|
16555
|
+
const ringEvicted = Boolean(stdoutProvenance?.evicted || stderrProvenance?.evicted);
|
|
16556
|
+
const stdoutTailSource = typeof args2.stdoutTail === "string" ? args2.stdoutTail : stdout;
|
|
16557
|
+
const stderrTailSource = typeof args2.stderrTail === "string" ? args2.stderrTail : stderr;
|
|
16558
|
+
const stdoutTail = tailText(stdoutTailSource, tailChars);
|
|
16559
|
+
const stderrTail = tailText(stderrTailSource, tailChars);
|
|
16623
16560
|
const inlineSize = stdout.length + stderr.length;
|
|
16624
16561
|
const inlineTruncated = stdoutTail.truncated || stderrTail.truncated;
|
|
16625
|
-
const
|
|
16562
|
+
const truncated = inlineTruncated || ringEvicted || Boolean(captureError);
|
|
16563
|
+
const shouldSpill = truncated || inlineSize > spillThresholdChars;
|
|
16626
16564
|
let spill;
|
|
16627
16565
|
if (shouldSpill) {
|
|
16628
16566
|
try {
|
|
@@ -16636,8 +16574,11 @@ function buildProcessTaskResultCapsule(args2) {
|
|
|
16636
16574
|
});
|
|
16637
16575
|
spill = {
|
|
16638
16576
|
displayPath: result4.displayPath,
|
|
16639
|
-
|
|
16640
|
-
|
|
16577
|
+
// Prefer the caller's live provenance counters: they count every
|
|
16578
|
+
// byte of the original stream, while the buffered content above may
|
|
16579
|
+
// be a capped prefix of it.
|
|
16580
|
+
totalChars: (stdoutProvenance?.totalChars ?? stdout.length) + (stderrProvenance?.totalChars ?? stderr.length),
|
|
16581
|
+
totalLines: (stdoutProvenance?.totalLines ?? countLines(stdout)) + (stderrProvenance?.totalLines ?? countLines(stderr))
|
|
16641
16582
|
};
|
|
16642
16583
|
} catch {
|
|
16643
16584
|
}
|
|
@@ -16648,12 +16589,33 @@ function buildProcessTaskResultCapsule(args2) {
|
|
|
16648
16589
|
exitCode,
|
|
16649
16590
|
...durationMs !== void 0 ? { durationMs } : {},
|
|
16650
16591
|
...captureError ? { captureError } : {},
|
|
16651
|
-
truncated
|
|
16592
|
+
truncated,
|
|
16652
16593
|
...spill ? { spill } : {}
|
|
16653
16594
|
};
|
|
16654
16595
|
}
|
|
16655
16596
|
|
|
16597
|
+
// packages/agent-runtime/processOwnership.ts
|
|
16598
|
+
var asNonEmptyString = (value) => {
|
|
16599
|
+
if (typeof value !== "string") return null;
|
|
16600
|
+
const trimmed = value.trim();
|
|
16601
|
+
return trimmed ? trimmed : null;
|
|
16602
|
+
};
|
|
16603
|
+
function readProcessOwner(runtimeContext) {
|
|
16604
|
+
if (!runtimeContext || typeof runtimeContext !== "object") return null;
|
|
16605
|
+
const dialogId = asNonEmptyString(runtimeContext.dialogId) ?? asNonEmptyString(runtimeContext.parentThreadId);
|
|
16606
|
+
if (!dialogId) return null;
|
|
16607
|
+
const turnId = asNonEmptyString(runtimeContext.turnId);
|
|
16608
|
+
const ownerId = asNonEmptyString(runtimeContext.ownerId);
|
|
16609
|
+
return {
|
|
16610
|
+
dialogId,
|
|
16611
|
+
...turnId ? { turnId } : {},
|
|
16612
|
+
...ownerId ? { ownerId } : {}
|
|
16613
|
+
};
|
|
16614
|
+
}
|
|
16615
|
+
|
|
16656
16616
|
// packages/agent-runtime/workspaceShell.ts
|
|
16617
|
+
import { resolve as resolve3 } from "node:path";
|
|
16618
|
+
import { spawn as spawnChildProcess2 } from "node:child_process";
|
|
16657
16619
|
var EXEC_SHELL_TIMEOUT_ENV = "NOLO_EXEC_SHELL_TIMEOUT_MS";
|
|
16658
16620
|
var EXEC_SHELL_DETACH_ENV = "NOLO_EXEC_SHELL_DETACH_MS";
|
|
16659
16621
|
var DEFAULT_EXEC_SHELL_DETACH_MS = 12e4;
|
|
@@ -17522,68 +17484,230 @@ function runTasks(args2) {
|
|
|
17522
17484
|
return { tasks, count: tasks.length };
|
|
17523
17485
|
}
|
|
17524
17486
|
|
|
17525
|
-
// packages/agent-runtime/
|
|
17526
|
-
|
|
17527
|
-
|
|
17528
|
-
|
|
17529
|
-
|
|
17530
|
-
|
|
17531
|
-
|
|
17532
|
-
|
|
17533
|
-
|
|
17534
|
-
|
|
17535
|
-
|
|
17536
|
-
|
|
17537
|
-
|
|
17538
|
-
|
|
17539
|
-
|
|
17540
|
-
type: "string",
|
|
17541
|
-
description: "Compatibility alias for command."
|
|
17542
|
-
}
|
|
17543
|
-
}
|
|
17487
|
+
// packages/agent-runtime/execShellCompletionWarnings.ts
|
|
17488
|
+
var BG_ESCAPE_WORD_PATTERN = /(?:^|[\s;|(&/\\])(nohup|disown|setsid|start-process)(?=$|[\s;|)&])/i;
|
|
17489
|
+
var SHELL_SPLIT_CHARS = /* @__PURE__ */ new Set([";", "|", "&", "(", ")", "<", ">", "\n", " ", " "]);
|
|
17490
|
+
function maskQuotedAndEscaped(command) {
|
|
17491
|
+
const out = Array.from(command);
|
|
17492
|
+
let quote = null;
|
|
17493
|
+
for (let i = 0; i < out.length; i += 1) {
|
|
17494
|
+
const ch = out[i];
|
|
17495
|
+
if (quote) {
|
|
17496
|
+
out[i] = " ";
|
|
17497
|
+
if (ch === "\\" && quote !== "'") {
|
|
17498
|
+
if (i + 1 < out.length) out[i + 1] = " ";
|
|
17499
|
+
i += 1;
|
|
17500
|
+
} else if (ch === quote) {
|
|
17501
|
+
quote = null;
|
|
17544
17502
|
}
|
|
17503
|
+
continue;
|
|
17545
17504
|
}
|
|
17546
|
-
|
|
17547
|
-
|
|
17548
|
-
|
|
17549
|
-
|
|
17550
|
-
|
|
17551
|
-
}
|
|
17552
|
-
if (typeof input === "string") {
|
|
17553
|
-
const trimmed = input.trim();
|
|
17554
|
-
if (!trimmed) {
|
|
17555
|
-
throw new Error("execShell requires a non-empty command.");
|
|
17505
|
+
if (ch === "\\") {
|
|
17506
|
+
out[i] = " ";
|
|
17507
|
+
if (i + 1 < out.length) out[i + 1] = " ";
|
|
17508
|
+
i += 1;
|
|
17509
|
+
continue;
|
|
17556
17510
|
}
|
|
17557
|
-
if (
|
|
17558
|
-
|
|
17559
|
-
|
|
17560
|
-
|
|
17561
|
-
|
|
17562
|
-
|
|
17563
|
-
|
|
17511
|
+
if (ch === "'" || ch === '"' || ch === "`") {
|
|
17512
|
+
quote = ch;
|
|
17513
|
+
out[i] = " ";
|
|
17514
|
+
continue;
|
|
17515
|
+
}
|
|
17516
|
+
if (ch === "#" && (i === 0 || /[\s;]/.test(out[i - 1] ?? " "))) {
|
|
17517
|
+
while (i < out.length && out[i] !== "\n") {
|
|
17518
|
+
out[i] = " ";
|
|
17519
|
+
i += 1;
|
|
17564
17520
|
}
|
|
17565
17521
|
}
|
|
17566
|
-
return { command: trimmed };
|
|
17567
17522
|
}
|
|
17568
|
-
|
|
17569
|
-
|
|
17570
|
-
|
|
17571
|
-
|
|
17572
|
-
|
|
17573
|
-
|
|
17574
|
-
|
|
17523
|
+
return out.join("");
|
|
17524
|
+
}
|
|
17525
|
+
function readRedirectTarget(original, start) {
|
|
17526
|
+
let i = start;
|
|
17527
|
+
while (i < original.length && /\s/.test(original[i] ?? "")) {
|
|
17528
|
+
i += 1;
|
|
17529
|
+
}
|
|
17530
|
+
if (i >= original.length) return void 0;
|
|
17531
|
+
let text = "";
|
|
17532
|
+
let j = i;
|
|
17533
|
+
while (j < original.length) {
|
|
17534
|
+
const o = original[j];
|
|
17535
|
+
if (o === "'" || o === '"' || o === "`") {
|
|
17536
|
+
const quote = o;
|
|
17537
|
+
j += 1;
|
|
17538
|
+
while (j < original.length && original[j] !== quote) {
|
|
17539
|
+
if (original[j] === "\\" && quote !== "'" && j + 1 < original.length) {
|
|
17540
|
+
text += original[j + 1];
|
|
17541
|
+
j += 2;
|
|
17542
|
+
continue;
|
|
17543
|
+
}
|
|
17544
|
+
text += original[j];
|
|
17545
|
+
j += 1;
|
|
17575
17546
|
}
|
|
17547
|
+
j += 1;
|
|
17548
|
+
continue;
|
|
17576
17549
|
}
|
|
17577
|
-
|
|
17550
|
+
if (/\s/.test(o) || SHELL_SPLIT_CHARS.has(o)) break;
|
|
17551
|
+
text += o;
|
|
17552
|
+
j += 1;
|
|
17553
|
+
}
|
|
17554
|
+
if (!text || text === "$") return void 0;
|
|
17555
|
+
return { text, end: j };
|
|
17556
|
+
}
|
|
17557
|
+
function isIgnoredRedirectTarget(target) {
|
|
17558
|
+
return target === "/dev/null";
|
|
17559
|
+
}
|
|
17560
|
+
function detectExecShellSynchronousWarnings(command, shell) {
|
|
17561
|
+
const masked = maskQuotedAndEscaped(command);
|
|
17562
|
+
const isPowerShell = shell?.resolvedShell === "powershell";
|
|
17563
|
+
const redirectTargets = [];
|
|
17564
|
+
let backgrounded = false;
|
|
17565
|
+
let i = 0;
|
|
17566
|
+
while (i < masked.length) {
|
|
17567
|
+
const ch = masked[i];
|
|
17568
|
+
if (ch === "&") {
|
|
17569
|
+
const next = masked[i + 1];
|
|
17570
|
+
if (next === "&") {
|
|
17571
|
+
i += 2;
|
|
17572
|
+
continue;
|
|
17573
|
+
}
|
|
17574
|
+
if (next === ">") {
|
|
17575
|
+
let j = i + 2;
|
|
17576
|
+
if (masked[j] === ">") j += 1;
|
|
17577
|
+
const target = readRedirectTarget(command, j);
|
|
17578
|
+
if (target && !isIgnoredRedirectTarget(target.text)) redirectTargets.push(target.text);
|
|
17579
|
+
i = target ? target.end : j;
|
|
17580
|
+
continue;
|
|
17581
|
+
}
|
|
17582
|
+
const prev = masked[i - 1];
|
|
17583
|
+
if (prev === ">" || prev === "<") {
|
|
17584
|
+
i += 1;
|
|
17585
|
+
continue;
|
|
17586
|
+
}
|
|
17587
|
+
if (isPowerShell) {
|
|
17588
|
+
i += 1;
|
|
17589
|
+
continue;
|
|
17590
|
+
}
|
|
17591
|
+
backgrounded = true;
|
|
17592
|
+
i += 1;
|
|
17593
|
+
continue;
|
|
17594
|
+
}
|
|
17595
|
+
if (ch === ">") {
|
|
17596
|
+
const prev = masked[i - 1];
|
|
17597
|
+
if (prev === ">" || prev === "&" || prev === "<") {
|
|
17598
|
+
i += 1;
|
|
17599
|
+
continue;
|
|
17600
|
+
}
|
|
17601
|
+
let j = i + 1;
|
|
17602
|
+
if (masked[j] === ">") j += 1;
|
|
17603
|
+
if (masked[j] === "&") {
|
|
17604
|
+
const ampTarget = readRedirectTarget(command, j + 1);
|
|
17605
|
+
const isFdDuplication = ampTarget !== void 0 && (/^\d+$/.test(ampTarget.text) || ampTarget.text === "-");
|
|
17606
|
+
if (ampTarget && !isFdDuplication && !isIgnoredRedirectTarget(ampTarget.text)) {
|
|
17607
|
+
redirectTargets.push(ampTarget.text);
|
|
17608
|
+
}
|
|
17609
|
+
i = ampTarget ? ampTarget.end : j + 1;
|
|
17610
|
+
continue;
|
|
17611
|
+
}
|
|
17612
|
+
const target = readRedirectTarget(command, j);
|
|
17613
|
+
if (target && !isIgnoredRedirectTarget(target.text)) redirectTargets.push(target.text);
|
|
17614
|
+
i = target ? target.end : j;
|
|
17615
|
+
continue;
|
|
17616
|
+
}
|
|
17617
|
+
if (ch === "<") {
|
|
17618
|
+
i += masked[i + 1] === "<" || masked[i + 1] === "&" ? 2 : 1;
|
|
17619
|
+
continue;
|
|
17620
|
+
}
|
|
17621
|
+
i += 1;
|
|
17622
|
+
}
|
|
17623
|
+
const wordMatch = BG_ESCAPE_WORD_PATTERN.exec(masked);
|
|
17624
|
+
if (wordMatch) backgrounded = true;
|
|
17625
|
+
const warnings = [];
|
|
17626
|
+
if (redirectTargets.length > 0) {
|
|
17627
|
+
const target = redirectTargets[0];
|
|
17628
|
+
warnings.push({
|
|
17629
|
+
kind: "output-redirect",
|
|
17630
|
+
redirectTarget: target,
|
|
17631
|
+
message: `[wake-safety] This execShell call completed synchronously; its output was redirected to ${target}. That file is NOT delivered by any completion notification \u2014 no tracked background task was created. If you need the result, read that file in this turn.`
|
|
17632
|
+
});
|
|
17633
|
+
}
|
|
17634
|
+
if (backgrounded) {
|
|
17635
|
+
warnings.push({
|
|
17636
|
+
kind: "shell-backgrounding",
|
|
17637
|
+
message: `[wake-safety] Detected shell-internal backgrounding (lone \`&\`, nohup/disown/setsid/Start-Process or similar). Descendant processes are NOT tracked as platform tasks and will not produce completion notifications; text such as \`LAUNCHED\` printed by the command is plain stdout, not a platform receipt.`
|
|
17638
|
+
});
|
|
17639
|
+
}
|
|
17640
|
+
return warnings;
|
|
17641
|
+
}
|
|
17642
|
+
|
|
17643
|
+
// packages/agent-runtime/capabilities/execShellCapability.ts
|
|
17644
|
+
function buildExecShellToolDefinition(toolName = "execShell") {
|
|
17645
|
+
return {
|
|
17646
|
+
type: "function",
|
|
17647
|
+
function: {
|
|
17648
|
+
name: toolName,
|
|
17649
|
+
description: `Execute a shell command from the workspace root. Prefer one compound command (e.g. 'git status && git diff --stat') to perform complete verification in one step instead of multiple small roundtrips. Do not cd into guessed paths; commands already run from the workspace root. Commands block until exit. Long-running commands (sleep over ${IMMEDIATE_DETACH_SLEEP_THRESHOLD_SECONDS}s, dev servers, watchers) automatically detach to background returning {detached: true, pid, label}; for persistent services, prefer launchProcess. On Windows the resolved shell may be Windows PowerShell 5.1 (metadata.shellKind="powershell5"): it does not support '&&'/'||' or $PSStyle \u2014 join commands with ';' or split into multiple calls. metadata.shellKind="pwsh" means PowerShell 7+ with full syntax. Read resolvedShell/shellKind from any execShell result before writing Windows-specific syntax. LIFECYCLE CONTRACT (misreading this contract silenced a real dialog for 10 hours): (1) A normal command waits synchronously for at most 120 seconds; if it ends inside that window the call IS finished \u2014 a result containing exitCode means the command has already completed, never "still running". (2) Only a result with metadata.detached === true AND a taskId represents a tracked background task that may trigger completion wake-up (terminal completion turn carrying a bounded result capsule); that handle may be waited on with taskWait and will produce a completion notification. (3) Text the command itself prints (LAUNCHED, STARTED, BACKGROUND, ...) is plain stdout with zero lifecycle meaning \u2014 never read it as a platform receipt. (4) Shell-level backgrounding (\`&\`, nohup, disown, setsid, self-daemonizing scripts, PowerShell Start-Process) is NOT tracked: those descendants produce no completion notification, and the outer shell finishing tells you nothing about them. Use background: true to turn a finite job into a tracked background task immediately. When a synchronous result's core output was redirected to a file, read that file in the SAME turn \u2014 never end the turn promising a later automatic report without a taskId.`,
|
|
17650
|
+
parameters: {
|
|
17651
|
+
type: "object",
|
|
17652
|
+
properties: {
|
|
17653
|
+
command: {
|
|
17654
|
+
type: "string",
|
|
17655
|
+
description: "Shell command to run (non-empty)."
|
|
17656
|
+
},
|
|
17657
|
+
cmd: {
|
|
17658
|
+
type: "string",
|
|
17659
|
+
description: "Compatibility alias for command."
|
|
17660
|
+
},
|
|
17661
|
+
background: {
|
|
17662
|
+
type: "boolean",
|
|
17663
|
+
description: "Immediately detach this command into a tracked background task (no 120s synchronous wait): returns {detached: true, taskId}, and on completion the platform resumes this conversation with a bounded result capsule (exitCode, duration, stdout/stderr tail). Default false. Use for finite jobs (tests, builds, batch) whose result you need later; NOT for dev servers/watchers \u2014 use launchProcess for those."
|
|
17664
|
+
}
|
|
17665
|
+
}
|
|
17666
|
+
}
|
|
17667
|
+
}
|
|
17668
|
+
};
|
|
17669
|
+
}
|
|
17670
|
+
function normalizeExecShellInput(input) {
|
|
17671
|
+
if (input === null || input === void 0) {
|
|
17672
|
+
throw new Error("execShell requires a non-empty command.");
|
|
17673
|
+
}
|
|
17674
|
+
if (typeof input === "string") {
|
|
17675
|
+
const trimmed = input.trim();
|
|
17676
|
+
if (!trimmed) {
|
|
17677
|
+
throw new Error("execShell requires a non-empty command.");
|
|
17678
|
+
}
|
|
17679
|
+
if (trimmed.startsWith("{") && trimmed.endsWith("}")) {
|
|
17680
|
+
try {
|
|
17681
|
+
const parsed = JSON.parse(trimmed);
|
|
17682
|
+
if (parsed && typeof parsed === "object") {
|
|
17683
|
+
return normalizeExecShellInput(parsed);
|
|
17684
|
+
}
|
|
17685
|
+
} catch {
|
|
17686
|
+
}
|
|
17687
|
+
}
|
|
17688
|
+
return { command: trimmed };
|
|
17689
|
+
}
|
|
17690
|
+
if (typeof input === "object") {
|
|
17691
|
+
const record = input;
|
|
17692
|
+
let rawCommand = resolveShellCommandArg(record);
|
|
17693
|
+
if (typeof rawCommand !== "string" || !rawCommand.trim()) {
|
|
17694
|
+
const fallback = record.command ?? record.cmd;
|
|
17695
|
+
if (typeof fallback === "string" && fallback.trim()) {
|
|
17696
|
+
rawCommand = fallback;
|
|
17697
|
+
}
|
|
17698
|
+
}
|
|
17699
|
+
const command = typeof rawCommand === "string" ? rawCommand.trim() : "";
|
|
17578
17700
|
if (!command) {
|
|
17579
17701
|
throw new Error("execShell requires a non-empty command.");
|
|
17580
17702
|
}
|
|
17581
17703
|
const activity = extractActivity(record);
|
|
17704
|
+
const background = record.background === true || typeof record.background === "string" && record.background.trim().toLowerCase() === "true";
|
|
17582
17705
|
return {
|
|
17583
17706
|
command,
|
|
17584
17707
|
...record.shell !== void 0 ? { shell: record.shell } : {},
|
|
17585
17708
|
...activity ? { activity } : {},
|
|
17586
|
-
...record.input !== void 0 ? { input: record.input } : {}
|
|
17709
|
+
...record.input !== void 0 ? { input: record.input } : {},
|
|
17710
|
+
...background ? { background: true } : {}
|
|
17587
17711
|
};
|
|
17588
17712
|
}
|
|
17589
17713
|
throw new Error("execShell requires a non-empty command.");
|
|
@@ -17621,6 +17745,7 @@ var execShellCapability = {
|
|
|
17621
17745
|
command,
|
|
17622
17746
|
shell: normalized.shell
|
|
17623
17747
|
});
|
|
17748
|
+
const background = normalized.background === true;
|
|
17624
17749
|
const result4 = await runWorkspaceCommand({
|
|
17625
17750
|
workspaceRoot,
|
|
17626
17751
|
command: shellPlan.argv,
|
|
@@ -17628,15 +17753,18 @@ var execShellCapability = {
|
|
|
17628
17753
|
outputLimit: ctx.commandOutputLimit,
|
|
17629
17754
|
commandPrefix: ctx.commandPrefix,
|
|
17630
17755
|
abortSignal: ctx.abortSignal,
|
|
17631
|
-
detachMs: isImmediateDetachShellCommand({ command }) ? 0 : ctx.detachMs,
|
|
17756
|
+
detachMs: background ? 0 : isImmediateDetachShellCommand({ command }) ? 0 : ctx.detachMs,
|
|
17632
17757
|
stdin: typeof normalized.input === "string" ? normalized.input : void 0,
|
|
17633
17758
|
// Ownership of the turn that invoked this command: an auto-detached
|
|
17634
17759
|
// command keeps its parent dialog so its terminal can resume that
|
|
17635
17760
|
// conversation (see processOwnership.ts). Absent ctx.owner = unowned.
|
|
17636
17761
|
owner: ctx.owner ?? null
|
|
17637
17762
|
});
|
|
17763
|
+
const warnings = result4.detached || result4.spawnFailed ? [] : detectExecShellSynchronousWarnings(command, {
|
|
17764
|
+
resolvedShell: shellPlan.resolvedShell
|
|
17765
|
+
});
|
|
17638
17766
|
return {
|
|
17639
|
-
content: result4.content,
|
|
17767
|
+
content: warnings.length > 0 ? [result4.content, ...warnings.map((warning) => warning.message)].join("\n\n") : result4.content,
|
|
17640
17768
|
metadata: {
|
|
17641
17769
|
command,
|
|
17642
17770
|
exitCode: result4.exitCode,
|
|
@@ -17651,8 +17779,21 @@ var execShellCapability = {
|
|
|
17651
17779
|
// Phase 0: stable taskId from the pre-registered Execution
|
|
17652
17780
|
// Envelope (additive; existing detached fields untouched).
|
|
17653
17781
|
taskId: result4.taskId,
|
|
17654
|
-
status: "running"
|
|
17655
|
-
|
|
17782
|
+
status: "running",
|
|
17783
|
+
// P0 machine-readable execution state: an explicit positive
|
|
17784
|
+
// signal instead of requiring the model to infer "not detached"
|
|
17785
|
+
// from absence. Mirrors the real lifecycle contract.
|
|
17786
|
+
executionState: "detached",
|
|
17787
|
+
trackedBackgroundTask: true,
|
|
17788
|
+
completionNotification: "terminal-resume"
|
|
17789
|
+
} : {
|
|
17790
|
+
// P0 machine-readable execution state: the command already
|
|
17791
|
+
// finished inside the synchronous window; no background task
|
|
17792
|
+
// exists, so no completion notification will ever arrive.
|
|
17793
|
+
executionState: "synchronous-complete",
|
|
17794
|
+
trackedBackgroundTask: false,
|
|
17795
|
+
completionNotification: "none"
|
|
17796
|
+
},
|
|
17656
17797
|
...normalized.activity ? { activity: normalized.activity } : {}
|
|
17657
17798
|
}
|
|
17658
17799
|
};
|
|
@@ -17868,7 +18009,7 @@ function buildLaunchProcessTool() {
|
|
|
17868
18009
|
type: "function",
|
|
17869
18010
|
function: {
|
|
17870
18011
|
name: "launchProcess",
|
|
17871
|
-
description: "Start a long-running background process (dev server, watcher, REPL) and return immediately with {pid, label, status}. Use listProcesses to inspect or stop it.",
|
|
18012
|
+
description: "Start a long-running ambient background process (dev server, watcher, REPL) and return immediately with {pid, label, taskId, status}. Real boundaries: this registers a tracked background task, but completion does NOT automatically start a new turn \u2014 the process is intentionally notice-only (an exited dev server must not silently burn a model turn). When it reaches a terminal state the bounded result (exitCode, duration, stdout/stderr tail) is recorded and surfaced as a notice injected only on your next real turn in the same conversation. Use listProcesses to inspect, taskWait to block for its terminal state, or taskStop to stop it. For a finite job (tests, builds, batch) whose result must resume the conversation automatically, use execShell with background: true instead.",
|
|
17872
18013
|
parameters: {
|
|
17873
18014
|
type: "object",
|
|
17874
18015
|
properties: {
|
|
@@ -19009,6 +19150,55 @@ async function execShellTool(args2) {
|
|
|
19009
19150
|
}
|
|
19010
19151
|
);
|
|
19011
19152
|
}
|
|
19153
|
+
var LAUNCH_PROCESS_STREAM_RING_CHARS = 65536;
|
|
19154
|
+
var LAUNCH_PROCESS_STREAM_CAPTURE_MAX_CHARS = 4e6;
|
|
19155
|
+
function createLaunchProcessStreamCapture() {
|
|
19156
|
+
let ring = "";
|
|
19157
|
+
let full = null;
|
|
19158
|
+
let capturedChars = 0;
|
|
19159
|
+
let totalChars = 0;
|
|
19160
|
+
let totalNewlines = 0;
|
|
19161
|
+
return {
|
|
19162
|
+
push(chunk) {
|
|
19163
|
+
const str = typeof chunk === "string" ? chunk : chunk.toString("utf8");
|
|
19164
|
+
if (!str) return;
|
|
19165
|
+
totalChars += str.length;
|
|
19166
|
+
for (let i = 0; i < str.length; i += 1) {
|
|
19167
|
+
if (str.charCodeAt(i) === 10) totalNewlines += 1;
|
|
19168
|
+
}
|
|
19169
|
+
const combined = ring + str;
|
|
19170
|
+
if (combined.length <= LAUNCH_PROCESS_STREAM_RING_CHARS) {
|
|
19171
|
+
ring = combined;
|
|
19172
|
+
return;
|
|
19173
|
+
}
|
|
19174
|
+
if (full === null) {
|
|
19175
|
+
full = [combined];
|
|
19176
|
+
capturedChars = combined.length;
|
|
19177
|
+
} else if (capturedChars < LAUNCH_PROCESS_STREAM_CAPTURE_MAX_CHARS) {
|
|
19178
|
+
const room = LAUNCH_PROCESS_STREAM_CAPTURE_MAX_CHARS - capturedChars;
|
|
19179
|
+
const slice = str.length <= room ? str : str.slice(0, room);
|
|
19180
|
+
full.push(slice);
|
|
19181
|
+
capturedChars += slice.length;
|
|
19182
|
+
}
|
|
19183
|
+
ring = combined.slice(-LAUNCH_PROCESS_STREAM_RING_CHARS);
|
|
19184
|
+
},
|
|
19185
|
+
text() {
|
|
19186
|
+
return full === null ? ring : full.join("");
|
|
19187
|
+
},
|
|
19188
|
+
tailText() {
|
|
19189
|
+
return ring;
|
|
19190
|
+
},
|
|
19191
|
+
evicted() {
|
|
19192
|
+
return full !== null;
|
|
19193
|
+
},
|
|
19194
|
+
totalChars() {
|
|
19195
|
+
return totalChars;
|
|
19196
|
+
},
|
|
19197
|
+
totalLines() {
|
|
19198
|
+
return totalChars > 0 ? totalNewlines + 1 : 0;
|
|
19199
|
+
}
|
|
19200
|
+
};
|
|
19201
|
+
}
|
|
19012
19202
|
async function launchProcessTool(args2) {
|
|
19013
19203
|
const parsed = parseWorkspaceToolArguments(args2.call.arguments);
|
|
19014
19204
|
const command = requireShellCommand(parsed, args2.call.name);
|
|
@@ -19036,6 +19226,14 @@ async function launchProcessTool(args2) {
|
|
|
19036
19226
|
stdio: ["ignore", "pipe", "pipe"],
|
|
19037
19227
|
detached
|
|
19038
19228
|
});
|
|
19229
|
+
const stdoutCapture = createLaunchProcessStreamCapture();
|
|
19230
|
+
const stderrCapture = createLaunchProcessStreamCapture();
|
|
19231
|
+
proc.stdout?.on("data", (chunk) => stdoutCapture.push(chunk));
|
|
19232
|
+
proc.stderr?.on("data", (chunk) => stderrCapture.push(chunk));
|
|
19233
|
+
proc.stdout?.on("error", () => {
|
|
19234
|
+
});
|
|
19235
|
+
proc.stderr?.on("error", () => {
|
|
19236
|
+
});
|
|
19039
19237
|
const pid = proc.pid;
|
|
19040
19238
|
if (typeof pid !== "number") {
|
|
19041
19239
|
return {
|
|
@@ -19076,7 +19274,38 @@ async function launchProcessTool(args2) {
|
|
|
19076
19274
|
process.removeListener("SIGTERM", cleanupChildOnHostSignal);
|
|
19077
19275
|
process.removeListener("SIGINT", cleanupChildOnHostSignal);
|
|
19078
19276
|
}
|
|
19079
|
-
|
|
19277
|
+
const exitCode = code ?? 1;
|
|
19278
|
+
let capsule;
|
|
19279
|
+
try {
|
|
19280
|
+
capsule = buildProcessTaskResultCapsule({
|
|
19281
|
+
// The full captured output (bounded prefix when the process was
|
|
19282
|
+
// extremely chatty): the module tails it for the inline capsule and
|
|
19283
|
+
// spills it for recovery. Provenance carries the live original-stream
|
|
19284
|
+
// counters so truncated/spill metadata never derives from the ring.
|
|
19285
|
+
stdout: stdoutCapture.text(),
|
|
19286
|
+
stderr: stderrCapture.text(),
|
|
19287
|
+
stdoutTail: stdoutCapture.tailText(),
|
|
19288
|
+
stderrTail: stderrCapture.tailText(),
|
|
19289
|
+
exitCode,
|
|
19290
|
+
// Duration measured from the registry envelope's startedAt (spawn).
|
|
19291
|
+
startedAt: envelope.startedAt,
|
|
19292
|
+
workspaceRoot: args2.workspaceRoot,
|
|
19293
|
+
streamProvenance: {
|
|
19294
|
+
stdout: {
|
|
19295
|
+
evicted: stdoutCapture.evicted(),
|
|
19296
|
+
totalChars: stdoutCapture.totalChars(),
|
|
19297
|
+
totalLines: stdoutCapture.totalLines()
|
|
19298
|
+
},
|
|
19299
|
+
stderr: {
|
|
19300
|
+
evicted: stderrCapture.evicted(),
|
|
19301
|
+
totalChars: stderrCapture.totalChars(),
|
|
19302
|
+
totalLines: stderrCapture.totalLines()
|
|
19303
|
+
}
|
|
19304
|
+
}
|
|
19305
|
+
});
|
|
19306
|
+
} catch {
|
|
19307
|
+
}
|
|
19308
|
+
registry2.markExited(pid, exitCode, capsule);
|
|
19080
19309
|
});
|
|
19081
19310
|
const activity = extractActivity(parsed);
|
|
19082
19311
|
const resultData = { pid, label, taskId: envelope.taskId, status: "running" };
|
|
@@ -19088,6 +19317,13 @@ async function launchProcessTool(args2) {
|
|
|
19088
19317
|
label,
|
|
19089
19318
|
status: "running",
|
|
19090
19319
|
taskId: envelope.taskId,
|
|
19320
|
+
// P0 machine-readable execution state (consistent with the real wake
|
|
19321
|
+
// contract): a real background task from birth, but ambient — its
|
|
19322
|
+
// terminal result rides the next real turn's notice, not an automatic
|
|
19323
|
+
// completion turn.
|
|
19324
|
+
executionState: "background",
|
|
19325
|
+
trackedBackgroundTask: true,
|
|
19326
|
+
completionNotification: "next-turn-notice",
|
|
19091
19327
|
processLaunch: resultData,
|
|
19092
19328
|
...activity ? { activity } : {}
|
|
19093
19329
|
}
|
|
@@ -19312,6 +19548,290 @@ function createLocalWorkspaceToolExecutors(args2) {
|
|
|
19312
19548
|
};
|
|
19313
19549
|
}
|
|
19314
19550
|
|
|
19551
|
+
// packages/agent-runtime/toolArgumentGate.ts
|
|
19552
|
+
var FIELD_ALIAS_GROUPS = [
|
|
19553
|
+
// localWorkspaceTools.ts:336 导出常量(readFile/writeFile/editFile/globFiles)
|
|
19554
|
+
PATH_FIELD_ALIASES,
|
|
19555
|
+
// localWorkspaceTools.ts:339-340 导出常量(editFile)
|
|
19556
|
+
OLD_TEXT_FIELD_ALIASES,
|
|
19557
|
+
NEW_TEXT_FIELD_ALIASES,
|
|
19558
|
+
// localWorkspaceTools.ts:733 `args.cmd || args.command`(launchProcess);
|
|
19559
|
+
// launchProcess 的 required ["command"] 见 localWorkspaceToolDefs.ts:283。
|
|
19560
|
+
// 注:execShell 的 schema 无 required(command 在 executor 层强制,
|
|
19561
|
+
// capabilities/execShellCapability.ts:42 声明 cmd 兼容字段),本组对它不产生拦截。
|
|
19562
|
+
["command", "cmd"],
|
|
19563
|
+
// localWorkspaceTools.ts:698-699 `args.pattern ?? args.glob`(globFiles)
|
|
19564
|
+
["pattern", "glob"],
|
|
19565
|
+
// noloWorkspaceTools.ts:492 `args.dialog ?? args.dialogId ?? args.id`(readDialog)
|
|
19566
|
+
["dialog", "dialogId", "id"],
|
|
19567
|
+
// noloWorkspaceTools.ts:545 `args.agent ?? args.agentKey ?? args.id`(readAgent)
|
|
19568
|
+
["agent", "agentKey", "id"],
|
|
19569
|
+
// noloWorkspaceTools.ts:552 `args.space ?? args.spaceId ?? args.id`(readSpace)
|
|
19570
|
+
["space", "spaceId", "id"],
|
|
19571
|
+
// noloWorkspaceTools.ts:561/567 `args.doc ?? args.docKey ?? args.pageKey ?? args.key`
|
|
19572
|
+
// (readDoc / readSkillDoc)
|
|
19573
|
+
["doc", "docKey", "pageKey", "key"],
|
|
19574
|
+
// noloWorkspaceTools.node.ts:238 `parsed.name ?? parsed.skillName ?? parsed.skill`(loadSkill)
|
|
19575
|
+
["name", "skillName", "skill"],
|
|
19576
|
+
// noloWorkspaceTools.ts:593 `args.table ?? args.tableId ?? args.metaKey`(queryTableRows)
|
|
19577
|
+
["table", "tableId", "metaKey"]
|
|
19578
|
+
];
|
|
19579
|
+
var TYPE_MATCHERS = {
|
|
19580
|
+
string: (value) => typeof value === "string",
|
|
19581
|
+
// 数字字符串视为可接受:executor 普遍 Number()/clamp 宽松处理,拦截会误报。
|
|
19582
|
+
number: (value) => typeof value === "number" || typeof value === "string" && value.trim() !== "" && Number.isFinite(Number(value)),
|
|
19583
|
+
integer: (value) => typeof value === "number" || typeof value === "string" && value.trim() !== "" && Number.isFinite(Number(value)),
|
|
19584
|
+
boolean: (value) => typeof value === "boolean" || value === "true" || value === "false",
|
|
19585
|
+
object: (value) => typeof value === "object" && value !== null && !Array.isArray(value),
|
|
19586
|
+
array: (value) => Array.isArray(value)
|
|
19587
|
+
};
|
|
19588
|
+
function describeValueType(value) {
|
|
19589
|
+
if (value === null) return "null";
|
|
19590
|
+
if (Array.isArray(value)) return "array";
|
|
19591
|
+
return typeof value;
|
|
19592
|
+
}
|
|
19593
|
+
function isAliasSatisfied(args2, field) {
|
|
19594
|
+
for (const group of FIELD_ALIAS_GROUPS) {
|
|
19595
|
+
if (!group.includes(field)) continue;
|
|
19596
|
+
if (group.some((alias) => args2[alias] !== void 0)) return true;
|
|
19597
|
+
}
|
|
19598
|
+
return false;
|
|
19599
|
+
}
|
|
19600
|
+
function readRequiredFields(parameters) {
|
|
19601
|
+
const required = parameters.required;
|
|
19602
|
+
if (!Array.isArray(required)) return [];
|
|
19603
|
+
return required.filter((field) => typeof field === "string");
|
|
19604
|
+
}
|
|
19605
|
+
function readProperties(parameters) {
|
|
19606
|
+
const properties = parameters.properties;
|
|
19607
|
+
if (!properties || typeof properties !== "object" || Array.isArray(properties)) {
|
|
19608
|
+
return {};
|
|
19609
|
+
}
|
|
19610
|
+
return properties;
|
|
19611
|
+
}
|
|
19612
|
+
function validateToolArguments(args2) {
|
|
19613
|
+
const { toolName, rawArguments, parameters } = args2;
|
|
19614
|
+
if (!parameters || typeof parameters !== "object" || Array.isArray(parameters)) {
|
|
19615
|
+
return { ok: true, args: {} };
|
|
19616
|
+
}
|
|
19617
|
+
const schema = parameters;
|
|
19618
|
+
const requiredFields = readRequiredFields(schema);
|
|
19619
|
+
const properties = readProperties(schema);
|
|
19620
|
+
if (requiredFields.length === 0 && Object.keys(properties).length === 0) {
|
|
19621
|
+
return { ok: true, args: {} };
|
|
19622
|
+
}
|
|
19623
|
+
const raw = typeof rawArguments === "string" ? rawArguments.trim() : "";
|
|
19624
|
+
let record = {};
|
|
19625
|
+
if (raw !== "") {
|
|
19626
|
+
let parsed;
|
|
19627
|
+
try {
|
|
19628
|
+
parsed = JSON.parse(raw);
|
|
19629
|
+
} catch {
|
|
19630
|
+
return { ok: true, args: {} };
|
|
19631
|
+
}
|
|
19632
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
19633
|
+
return { ok: true, args: {} };
|
|
19634
|
+
}
|
|
19635
|
+
record = parsed;
|
|
19636
|
+
}
|
|
19637
|
+
for (const field of requiredFields) {
|
|
19638
|
+
if (record[field] !== void 0) continue;
|
|
19639
|
+
if (isAliasSatisfied(record, field)) continue;
|
|
19640
|
+
return {
|
|
19641
|
+
ok: false,
|
|
19642
|
+
message: `${toolName} \u53C2\u6570\u6821\u9A8C\u5931\u8D25\uFF1A\u7F3A\u5C11\u5FC5\u586B\u53C2\u6570 "${field}"\u3002\u8BF7\u8865\u4E0A\u540E\u91CD\u65B0\u8C03\u7528 ${toolName}\u3002`
|
|
19643
|
+
};
|
|
19644
|
+
}
|
|
19645
|
+
for (const [field, spec] of Object.entries(properties)) {
|
|
19646
|
+
const value = record[field];
|
|
19647
|
+
if (value === void 0 || value === null) continue;
|
|
19648
|
+
if (!spec || typeof spec !== "object" || Array.isArray(spec)) continue;
|
|
19649
|
+
const declared = spec.type;
|
|
19650
|
+
if (typeof declared !== "string") continue;
|
|
19651
|
+
const matcher = TYPE_MATCHERS[declared];
|
|
19652
|
+
if (!matcher) continue;
|
|
19653
|
+
if (!matcher(value)) {
|
|
19654
|
+
return {
|
|
19655
|
+
ok: false,
|
|
19656
|
+
message: `${toolName} \u53C2\u6570\u6821\u9A8C\u5931\u8D25\uFF1A\u53C2\u6570 "${field}" \u5E94\u4E3A ${declared}\uFF0C\u5B9E\u9645\u6536\u5230 ${describeValueType(value)}\u3002\u8BF7\u4FEE\u6B63\u540E\u91CD\u65B0\u8C03\u7528 ${toolName}\u3002`
|
|
19657
|
+
};
|
|
19658
|
+
}
|
|
19659
|
+
}
|
|
19660
|
+
return { ok: true, args: record };
|
|
19661
|
+
}
|
|
19662
|
+
function buildToolParametersIndex(tools) {
|
|
19663
|
+
const index = /* @__PURE__ */ new Map();
|
|
19664
|
+
for (const tool of tools) {
|
|
19665
|
+
if (!tool || typeof tool !== "object") continue;
|
|
19666
|
+
const fn3 = tool.function;
|
|
19667
|
+
if (!fn3 || typeof fn3 !== "object") continue;
|
|
19668
|
+
const name = fn3.name;
|
|
19669
|
+
const parameters = fn3.parameters;
|
|
19670
|
+
if (typeof name === "string" && name && parameters !== void 0) {
|
|
19671
|
+
index.set(name, parameters);
|
|
19672
|
+
}
|
|
19673
|
+
}
|
|
19674
|
+
return index;
|
|
19675
|
+
}
|
|
19676
|
+
var cachedAgentRuntimeIndex = null;
|
|
19677
|
+
function getAgentRuntimeToolParametersIndex() {
|
|
19678
|
+
if (cachedAgentRuntimeIndex) return cachedAgentRuntimeIndex;
|
|
19679
|
+
const index = /* @__PURE__ */ new Map();
|
|
19680
|
+
try {
|
|
19681
|
+
const workspaceTools = buildLocalWorkspaceOpenAiTools({
|
|
19682
|
+
toolNames: [...WORKSPACE_TOOL_NAMES],
|
|
19683
|
+
exposeShellTools: true
|
|
19684
|
+
});
|
|
19685
|
+
for (const [name, parameters] of buildToolParametersIndex(workspaceTools)) {
|
|
19686
|
+
index.set(name, parameters);
|
|
19687
|
+
}
|
|
19688
|
+
const noloTools = buildNoloWorkspaceOpenAiTools({
|
|
19689
|
+
toolNames: [...NOLO_WORKSPACE_TOOL_NAMES]
|
|
19690
|
+
});
|
|
19691
|
+
for (const [name, parameters] of buildToolParametersIndex(noloTools)) {
|
|
19692
|
+
index.set(name, parameters);
|
|
19693
|
+
}
|
|
19694
|
+
} catch {
|
|
19695
|
+
}
|
|
19696
|
+
cachedAgentRuntimeIndex = index;
|
|
19697
|
+
return index;
|
|
19698
|
+
}
|
|
19699
|
+
|
|
19700
|
+
// packages/agent-runtime/localToolPolicy.ts
|
|
19701
|
+
var NEVER_LOCAL_TOOLS = /* @__PURE__ */ new Set([
|
|
19702
|
+
"deleteSpaces",
|
|
19703
|
+
"updateAgent",
|
|
19704
|
+
"updateSelf",
|
|
19705
|
+
"createAgent"
|
|
19706
|
+
]);
|
|
19707
|
+
var DEFAULT_LOCAL_TOOLS = /* @__PURE__ */ new Set([
|
|
19708
|
+
"readFile",
|
|
19709
|
+
"writeFile",
|
|
19710
|
+
"editFile",
|
|
19711
|
+
"globFiles",
|
|
19712
|
+
"execShell",
|
|
19713
|
+
"launchProcess",
|
|
19714
|
+
"listProcesses",
|
|
19715
|
+
// ProcessTask follow-up tools. Same tier as listProcesses: they observe/stop
|
|
19716
|
+
// tasks the agent itself already spawned, so their blast radius is strictly
|
|
19717
|
+
// narrower than launchProcess (which is default-enabled). Model-facing
|
|
19718
|
+
// follow-ups are taskWait/taskStop only — lifecycle history (taskLogs) stays
|
|
19719
|
+
// runtime-internal.
|
|
19720
|
+
"taskWait",
|
|
19721
|
+
"taskStop",
|
|
19722
|
+
// Scheduling tools: forking/observing sub-agents is a declared capability
|
|
19723
|
+
// of capable agents, and the blast radius is strictly narrower than
|
|
19724
|
+
// execShell (already default-enabled). Requiring an env allowlist for these
|
|
19725
|
+
// while execShell is open by default inverted the risk model and forced every
|
|
19726
|
+
// new local user to hand-edit .env files before sub-agent tasks worked.
|
|
19727
|
+
"startAgentRun",
|
|
19728
|
+
"controlAgentRun"
|
|
19729
|
+
]);
|
|
19730
|
+
function parseToolAllowlist(value) {
|
|
19731
|
+
return (value ?? "").split(",").flatMap((item) => {
|
|
19732
|
+
const trimmed = item.trim();
|
|
19733
|
+
return trimmed ? [trimmed] : [];
|
|
19734
|
+
});
|
|
19735
|
+
}
|
|
19736
|
+
function normalizeLocalToolName(toolName) {
|
|
19737
|
+
return canonicalizeToolName(
|
|
19738
|
+
String(toolName ?? "").replace(/^functions\./, "").trim()
|
|
19739
|
+
);
|
|
19740
|
+
}
|
|
19741
|
+
function isRestrictedLocalToolMode(env) {
|
|
19742
|
+
return env.NOLO_LOCAL_TOOL_MODE === "restricted";
|
|
19743
|
+
}
|
|
19744
|
+
function resolveLocalToolPolicy(args2) {
|
|
19745
|
+
const toolName = normalizeLocalToolName(args2.toolName);
|
|
19746
|
+
const restrictedMode = isRestrictedLocalToolMode(args2.env);
|
|
19747
|
+
if (!toolName) {
|
|
19748
|
+
return {
|
|
19749
|
+
allowed: false,
|
|
19750
|
+
toolName,
|
|
19751
|
+
reason: "Tool name is required."
|
|
19752
|
+
};
|
|
19753
|
+
}
|
|
19754
|
+
if (NEVER_LOCAL_TOOLS.has(toolName)) {
|
|
19755
|
+
return {
|
|
19756
|
+
allowed: false,
|
|
19757
|
+
toolName,
|
|
19758
|
+
reason: `${toolName} is blocked by the local runtime safety policy.`
|
|
19759
|
+
};
|
|
19760
|
+
}
|
|
19761
|
+
const allowedByEnv = new Set(parseToolAllowlist(args2.env.NOLO_LOCAL_ALLOWED_TOOLS));
|
|
19762
|
+
const agentTools = new Set(
|
|
19763
|
+
(args2.agentToolNames ?? []).flatMap((item) => {
|
|
19764
|
+
const normalized = normalizeLocalToolName(item);
|
|
19765
|
+
return normalized ? [normalized] : [];
|
|
19766
|
+
})
|
|
19767
|
+
);
|
|
19768
|
+
if (!restrictedMode && agentTools.has(toolName)) {
|
|
19769
|
+
return { allowed: true, toolName };
|
|
19770
|
+
}
|
|
19771
|
+
if (DEFAULT_LOCAL_TOOLS.has(toolName) && agentTools.has(toolName)) {
|
|
19772
|
+
return { allowed: true, toolName };
|
|
19773
|
+
}
|
|
19774
|
+
if (allowedByEnv.has(toolName) && agentTools.has(toolName)) {
|
|
19775
|
+
return { allowed: true, toolName };
|
|
19776
|
+
}
|
|
19777
|
+
return {
|
|
19778
|
+
allowed: false,
|
|
19779
|
+
toolName,
|
|
19780
|
+
reason: `${toolName} is not enabled for local runtime runs. The agent must declare the tool in its manifest; in restricted mode (NOLO_LOCAL_TOOL_MODE=restricted) non-default tools also require adding to NOLO_LOCAL_ALLOWED_TOOLS (e.g. NOLO_LOCAL_ALLOWED_TOOLS=someCustomTool) and restarting the session so the env var loads.`
|
|
19781
|
+
};
|
|
19782
|
+
}
|
|
19783
|
+
async function executeLocalToolWithPolicy(args2) {
|
|
19784
|
+
if (args2.runToolNames !== void 0 && !args2.runToolNames.includes(normalizeLocalToolName(args2.call.name))) {
|
|
19785
|
+
throw new Error(`${args2.call.name} is outside the final run tool surface.`);
|
|
19786
|
+
}
|
|
19787
|
+
const decision = resolveLocalToolPolicy({
|
|
19788
|
+
env: args2.env,
|
|
19789
|
+
agentToolNames: args2.agentToolNames,
|
|
19790
|
+
toolName: args2.call.name
|
|
19791
|
+
});
|
|
19792
|
+
if (!decision.allowed) throw new Error(decision.reason);
|
|
19793
|
+
const executor = args2.executors?.[decision.toolName];
|
|
19794
|
+
if (!executor) {
|
|
19795
|
+
throw new Error(`${decision.toolName} is allowed by policy but no local executor is registered.`);
|
|
19796
|
+
}
|
|
19797
|
+
const parametersSchema = args2.toolParametersIndex?.get(decision.toolName);
|
|
19798
|
+
if (parametersSchema !== void 0) {
|
|
19799
|
+
const gate = validateToolArguments({
|
|
19800
|
+
toolName: decision.toolName,
|
|
19801
|
+
rawArguments: args2.call.arguments,
|
|
19802
|
+
parameters: parametersSchema
|
|
19803
|
+
});
|
|
19804
|
+
if (!gate.ok) throw new Error(gate.message);
|
|
19805
|
+
}
|
|
19806
|
+
const opts = {
|
|
19807
|
+
...args2.abortSignal ? { abortSignal: args2.abortSignal } : {},
|
|
19808
|
+
...args2.detachMs !== void 0 ? { detachMs: args2.detachMs } : {},
|
|
19809
|
+
...args2.confirmed !== void 0 ? { confirmed: args2.confirmed } : {},
|
|
19810
|
+
...args2.enableDestructiveShellGuard !== void 0 ? { enableDestructiveShellGuard: args2.enableDestructiveShellGuard } : {},
|
|
19811
|
+
...args2.confirmDestructiveAction ? { confirmDestructiveAction: args2.confirmDestructiveAction } : {},
|
|
19812
|
+
...args2.blockDestructiveWithoutConfirmation !== void 0 ? { blockDestructiveWithoutConfirmation: args2.blockDestructiveWithoutConfirmation } : {}
|
|
19813
|
+
};
|
|
19814
|
+
if (decision.toolName === "execShell") {
|
|
19815
|
+
let parsedInput = args2.call.arguments;
|
|
19816
|
+
if (typeof parsedInput === "string") {
|
|
19817
|
+
try {
|
|
19818
|
+
parsedInput = JSON.parse(parsedInput);
|
|
19819
|
+
} catch {
|
|
19820
|
+
parsedInput = { command: parsedInput };
|
|
19821
|
+
}
|
|
19822
|
+
}
|
|
19823
|
+
await evaluateExecShellDestructiveGuard(parsedInput, opts);
|
|
19824
|
+
opts.confirmed = true;
|
|
19825
|
+
}
|
|
19826
|
+
return executor(
|
|
19827
|
+
{
|
|
19828
|
+
...args2.call,
|
|
19829
|
+
name: decision.toolName
|
|
19830
|
+
},
|
|
19831
|
+
opts
|
|
19832
|
+
);
|
|
19833
|
+
}
|
|
19834
|
+
|
|
19315
19835
|
// packages/cli/client/localDialogRecords.ts
|
|
19316
19836
|
var localDialogMessageRecordToRuntimeMessage = dialogMessageRecordToAgentRuntimeMessage;
|
|
19317
19837
|
function buildLocalDialogWritePlan(args2) {
|
|
@@ -19451,7 +19971,7 @@ function buildLoadSkillExecutor(args2) {
|
|
|
19451
19971
|
const { resolveSkillByName } = await import("./skillDiscovery-CYUCJMAG.js");
|
|
19452
19972
|
const resolved = resolveSkillByName(args2.cwd, name);
|
|
19453
19973
|
if (!resolved) {
|
|
19454
|
-
const { resolveBuiltinSkillByName } = await import("./builtinSkillRegistry-
|
|
19974
|
+
const { resolveBuiltinSkillByName } = await import("./builtinSkillRegistry-Q2VVY3SC.js");
|
|
19455
19975
|
const builtin = resolveBuiltinSkillByName(name);
|
|
19456
19976
|
if (builtin) {
|
|
19457
19977
|
return {
|
|
@@ -19509,737 +20029,8 @@ No skills were discovered in this workspace.`;
|
|
|
19509
20029
|
Available skills: ${available.join(", ")}`;
|
|
19510
20030
|
}
|
|
19511
20031
|
|
|
19512
|
-
// packages/core/chat/upstreamErrorBody.ts
|
|
19513
|
-
function parseUpstreamErrorBody(errorText, statusText) {
|
|
19514
|
-
if (errorText) {
|
|
19515
|
-
try {
|
|
19516
|
-
const parsed = JSON.parse(errorText);
|
|
19517
|
-
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
19518
|
-
const error = parsed.error;
|
|
19519
|
-
if (error && typeof error === "object" && !Array.isArray(error)) {
|
|
19520
|
-
return parsed;
|
|
19521
|
-
}
|
|
19522
|
-
}
|
|
19523
|
-
} catch {
|
|
19524
|
-
}
|
|
19525
|
-
}
|
|
19526
|
-
return { error: { message: errorText || statusText } };
|
|
19527
|
-
}
|
|
19528
|
-
|
|
19529
|
-
// packages/agent-runtime/antigravityCloudCodeProvider.ts
|
|
19530
|
-
import { randomUUID } from "node:crypto";
|
|
19531
|
-
|
|
19532
|
-
// packages/agent-runtime/antigravityWireModel.ts
|
|
19533
|
-
var WIRE_PROFILES = {
|
|
19534
|
-
// Antigravity discovery exposes 3.7 Flash as one tiered wire model.
|
|
19535
|
-
// The UI labels its effort variants (Low/Medium/High), but the literal
|
|
19536
|
-
// -medium/-high ids return 404 from streamGenerateContent.
|
|
19537
|
-
"gemini-3.7-flash-tiered": { modelEnum: "MODEL_PLACEHOLDER_M301", maxOutputTokens: 65536 },
|
|
19538
|
-
// Gemini 3.8 Flash 沿用 3.7 的 tiered 兼容策略:仓库内暂无 Antigravity discovery
|
|
19539
|
-
// 证据确认 3.8 的 wire modelEnum,禁止虚构,先只声明同档输出上限;enum 待
|
|
19540
|
-
// discovery 证据到位后补齐。
|
|
19541
|
-
"gemini-3.8-flash-tiered": { maxOutputTokens: 65536 },
|
|
19542
|
-
"gemini-3.6-flash-low": { maxOutputTokens: 65536 },
|
|
19543
|
-
"gemini-3.6-flash-medium": { maxOutputTokens: 65536 },
|
|
19544
|
-
"gemini-3.6-flash-high": { maxOutputTokens: 65536 },
|
|
19545
|
-
// 旧模型 wire 映射保留:存量自定义 agent 仍可能引用(注册表已下线不影响此处)。
|
|
19546
|
-
"gemini-3.5-flash-extra-low": { modelEnum: "MODEL_PLACEHOLDER_M187", maxOutputTokens: 65536 },
|
|
19547
|
-
"gemini-3.5-flash-low": { modelEnum: "MODEL_PLACEHOLDER_M20", maxOutputTokens: 65536 },
|
|
19548
|
-
"gemini-3-flash-agent": { modelEnum: "MODEL_PLACEHOLDER_M132", maxOutputTokens: 65536 },
|
|
19549
|
-
"gemini-3.1-pro-low": { modelEnum: "MODEL_PLACEHOLDER_M36", maxOutputTokens: 65535 },
|
|
19550
|
-
"gemini-pro-agent": { modelEnum: "MODEL_PLACEHOLDER_M16", maxOutputTokens: 65535 },
|
|
19551
|
-
"claude-sonnet-5": { maxOutputTokens: 64e3 },
|
|
19552
|
-
"claude-sonnet-4-6": { maxOutputTokens: 64e3 },
|
|
19553
|
-
"claude-opus-4-6-thinking": { maxOutputTokens: 64e3 },
|
|
19554
|
-
"gemini-2.5-flash": { maxOutputTokens: 65536 },
|
|
19555
|
-
"gemini-2.5-pro": { maxOutputTokens: 65536 }
|
|
19556
|
-
};
|
|
19557
|
-
function resolveAntigravityWireModel(logicalModelId) {
|
|
19558
|
-
const id = logicalModelId.trim();
|
|
19559
|
-
const lower = id.toLowerCase();
|
|
19560
|
-
if (lower === "gemini-3.5-flash") {
|
|
19561
|
-
const wireModelId = "gemini-3.5-flash-low";
|
|
19562
|
-
return { wireModelId, profile: WIRE_PROFILES[wireModelId] };
|
|
19563
|
-
}
|
|
19564
|
-
if (lower === "gemini-3.7-flash" || ["gemini-3.7-flash-low", "gemini-3.7-flash-medium", "gemini-3.7-flash-high"].includes(lower)) {
|
|
19565
|
-
const wireModelId = "gemini-3.7-flash-tiered";
|
|
19566
|
-
return { wireModelId, profile: WIRE_PROFILES[wireModelId] };
|
|
19567
|
-
}
|
|
19568
|
-
if (lower === "gemini-3.8-flash" || ["gemini-3.8-flash-low", "gemini-3.8-flash-medium", "gemini-3.8-flash-high"].includes(lower)) {
|
|
19569
|
-
const wireModelId = "gemini-3.8-flash-tiered";
|
|
19570
|
-
return { wireModelId, profile: WIRE_PROFILES[wireModelId] };
|
|
19571
|
-
}
|
|
19572
|
-
if (lower === "gemini-3.6-flash") {
|
|
19573
|
-
const wireModelId = "gemini-3.6-flash-low";
|
|
19574
|
-
return { wireModelId, profile: WIRE_PROFILES[wireModelId] };
|
|
19575
|
-
}
|
|
19576
|
-
if (lower === "gemini-3.1-pro" || lower === "gemini-3.1-pro-preview") {
|
|
19577
|
-
const wireModelId = "gemini-3.1-pro-low";
|
|
19578
|
-
return { wireModelId, profile: WIRE_PROFILES[wireModelId] };
|
|
19579
|
-
}
|
|
19580
|
-
if (WIRE_PROFILES[id]) {
|
|
19581
|
-
return { wireModelId: id, profile: WIRE_PROFILES[id] };
|
|
19582
|
-
}
|
|
19583
|
-
return { wireModelId: id };
|
|
19584
|
-
}
|
|
19585
|
-
|
|
19586
|
-
// packages/agent-runtime/geminiNativeShared.ts
|
|
19587
|
-
var SKIP_THOUGHT_SIGNATURE = "skip_thought_signature_validator";
|
|
19588
|
-
function resolveGeminiModelQuirks(modelId) {
|
|
19589
|
-
const lower = modelId.toLowerCase();
|
|
19590
|
-
const isGemini3 = lower.includes("gemini-3");
|
|
19591
|
-
const isStrictSignatureModel = lower.includes("gemini-3.5") || lower.includes("flash-preview");
|
|
19592
|
-
const isClaude = lower.includes("claude");
|
|
19593
|
-
return {
|
|
19594
|
-
requiresThoughtSignature: isGemini3,
|
|
19595
|
-
allowsThoughtSignatureSentinel: isGemini3 && !isStrictSignatureModel,
|
|
19596
|
-
isClaudeCrossModel: isClaude
|
|
19597
|
-
};
|
|
19598
|
-
}
|
|
19599
|
-
function isGemini3Model(modelId) {
|
|
19600
|
-
return resolveGeminiModelQuirks(modelId).requiresThoughtSignature;
|
|
19601
|
-
}
|
|
19602
|
-
function messageText(content) {
|
|
19603
|
-
if (typeof content === "string") return content;
|
|
19604
|
-
if (!Array.isArray(content)) return "";
|
|
19605
|
-
return content.filter(
|
|
19606
|
-
(part) => part?.type === "text"
|
|
19607
|
-
).map((part) => part.text).join("\n").trim();
|
|
19608
|
-
}
|
|
19609
|
-
function parseDataUrlToInlineData(url) {
|
|
19610
|
-
const match7 = /^data:([A-Za-z0-9.+-]+\/[A-Za-z0-9.+-]+);base64,([A-Za-z0-9+/=]*)$/.exec(
|
|
19611
|
-
url
|
|
19612
|
-
);
|
|
19613
|
-
if (!match7) return null;
|
|
19614
|
-
return { mimeType: match7[1], data: match7[2] };
|
|
19615
|
-
}
|
|
19616
|
-
function extractInlineDataParts(content) {
|
|
19617
|
-
if (!Array.isArray(content)) return [];
|
|
19618
|
-
const parts2 = [];
|
|
19619
|
-
for (const part of content) {
|
|
19620
|
-
if (!part || typeof part !== "object") continue;
|
|
19621
|
-
if (part.type !== "image_url") continue;
|
|
19622
|
-
const url = part.image_url?.url;
|
|
19623
|
-
if (typeof url !== "string" || !url.trim()) continue;
|
|
19624
|
-
const inline = parseDataUrlToInlineData(url);
|
|
19625
|
-
if (inline) parts2.push({ inlineData: inline });
|
|
19626
|
-
}
|
|
19627
|
-
return parts2;
|
|
19628
|
-
}
|
|
19629
|
-
function convertOpenAiMessagesToGemini(messages, options) {
|
|
19630
|
-
const contents = [];
|
|
19631
|
-
const systemTexts = [];
|
|
19632
|
-
let toolCallIndex = 0;
|
|
19633
|
-
let pendingFunctionCalls = [];
|
|
19634
|
-
const pushOrMergeContent = (role, parts2) => {
|
|
19635
|
-
if (parts2.length === 0) return;
|
|
19636
|
-
const last = contents[contents.length - 1];
|
|
19637
|
-
if (last && last.role === role) {
|
|
19638
|
-
last.parts.push(...parts2);
|
|
19639
|
-
} else {
|
|
19640
|
-
contents.push({ role, parts: parts2 });
|
|
19641
|
-
}
|
|
19642
|
-
};
|
|
19643
|
-
const flushPendingFunctionCalls = () => {
|
|
19644
|
-
if (pendingFunctionCalls.length === 0) return;
|
|
19645
|
-
const dummyResponses = pendingFunctionCalls.map(
|
|
19646
|
-
({ name, id }) => ({
|
|
19647
|
-
functionResponse: {
|
|
19648
|
-
name,
|
|
19649
|
-
response: { output: "{}" },
|
|
19650
|
-
...id ? { id } : {}
|
|
19651
|
-
}
|
|
19652
|
-
})
|
|
19653
|
-
);
|
|
19654
|
-
pendingFunctionCalls = [];
|
|
19655
|
-
pushOrMergeContent("user", dummyResponses);
|
|
19656
|
-
};
|
|
19657
|
-
for (const raw of messages) {
|
|
19658
|
-
if (!raw || typeof raw !== "object" || !("role" in raw)) continue;
|
|
19659
|
-
const role = String(raw.role);
|
|
19660
|
-
const content = "content" in raw ? raw.content : null;
|
|
19661
|
-
if (role === "system") {
|
|
19662
|
-
const text = messageText(
|
|
19663
|
-
content
|
|
19664
|
-
);
|
|
19665
|
-
if (text) systemTexts.push(text);
|
|
19666
|
-
continue;
|
|
19667
|
-
}
|
|
19668
|
-
if (role === "user") {
|
|
19669
|
-
flushPendingFunctionCalls();
|
|
19670
|
-
const text = messageText(
|
|
19671
|
-
content
|
|
19672
|
-
);
|
|
19673
|
-
const imageParts = extractInlineDataParts(
|
|
19674
|
-
content
|
|
19675
|
-
);
|
|
19676
|
-
if (!text && imageParts.length === 0) continue;
|
|
19677
|
-
const parts2 = [];
|
|
19678
|
-
if (text) parts2.push({ text });
|
|
19679
|
-
for (const img of imageParts) parts2.push(img);
|
|
19680
|
-
pushOrMergeContent("user", parts2);
|
|
19681
|
-
continue;
|
|
19682
|
-
}
|
|
19683
|
-
if (role === "assistant") {
|
|
19684
|
-
flushPendingFunctionCalls();
|
|
19685
|
-
const text = messageText(
|
|
19686
|
-
content
|
|
19687
|
-
);
|
|
19688
|
-
const toolCalls = "tool_calls" in raw && Array.isArray(raw.tool_calls) ? raw.tool_calls ?? [] : [];
|
|
19689
|
-
const parts2 = [];
|
|
19690
|
-
if (text) {
|
|
19691
|
-
parts2.push({ text });
|
|
19692
|
-
}
|
|
19693
|
-
for (const call of toolCalls) {
|
|
19694
|
-
const name = call?.function?.name?.trim();
|
|
19695
|
-
if (!name) continue;
|
|
19696
|
-
const id = call.id?.trim() || `${name}_${toolCallIndex++}`;
|
|
19697
|
-
pendingFunctionCalls.push({ name, id });
|
|
19698
|
-
const realSignature = typeof call.thought_signature === "string" && call.thought_signature ? call.thought_signature : void 0;
|
|
19699
|
-
const isFirstFunctionCallPart = !parts2.some(
|
|
19700
|
-
(p) => "functionCall" in p
|
|
19701
|
-
);
|
|
19702
|
-
const signature = realSignature ?? (options.attachSkipThoughtSignature && isFirstFunctionCallPart ? SKIP_THOUGHT_SIGNATURE : void 0);
|
|
19703
|
-
const part = {
|
|
19704
|
-
functionCall: {
|
|
19705
|
-
name,
|
|
19706
|
-
args: parseToolArgs(call.function?.arguments),
|
|
19707
|
-
...id ? { id } : {}
|
|
19708
|
-
},
|
|
19709
|
-
...signature ? { thoughtSignature: signature } : {}
|
|
19710
|
-
};
|
|
19711
|
-
parts2.push(part);
|
|
19712
|
-
}
|
|
19713
|
-
pushOrMergeContent("model", parts2);
|
|
19714
|
-
continue;
|
|
19715
|
-
}
|
|
19716
|
-
if (role === "tool") {
|
|
19717
|
-
const toolCallId = "tool_call_id" in raw && typeof raw.tool_call_id === "string" ? raw.tool_call_id : "";
|
|
19718
|
-
const rawName = "name" in raw && typeof raw.name === "string" ? raw.name.trim() : "";
|
|
19719
|
-
const pendingIndex = pendingFunctionCalls.findIndex(
|
|
19720
|
-
(p) => toolCallId ? p.id === toolCallId : rawName ? p.name === rawName : true
|
|
19721
|
-
);
|
|
19722
|
-
if (pendingIndex === -1) continue;
|
|
19723
|
-
const [{ name, id }] = pendingFunctionCalls.splice(pendingIndex, 1);
|
|
19724
|
-
const output = messageText(content) || "{}";
|
|
19725
|
-
pushOrMergeContent("user", [
|
|
19726
|
-
{
|
|
19727
|
-
functionResponse: {
|
|
19728
|
-
name,
|
|
19729
|
-
response: { output },
|
|
19730
|
-
// 保留 OpenAI tool_call_id:antigravity Cloud Code Assist 网关把
|
|
19731
|
-
// Gemini contents 转成 Claude messages 时需要 functionResponse →
|
|
19732
|
-
// tool_result 的 tool_use_id;缺 id 时网关报
|
|
19733
|
-
// "tool_result.tool_use_id: Field required"(HTTP 400)。
|
|
19734
|
-
...id ? { id } : {}
|
|
19735
|
-
}
|
|
19736
|
-
}
|
|
19737
|
-
]);
|
|
19738
|
-
}
|
|
19739
|
-
}
|
|
19740
|
-
flushPendingFunctionCalls();
|
|
19741
|
-
if (contents.length > 0 && contents[0]?.role === "model") {
|
|
19742
|
-
contents.unshift({
|
|
19743
|
-
role: "user",
|
|
19744
|
-
parts: [{ text: "Continue the conversation." }]
|
|
19745
|
-
});
|
|
19746
|
-
}
|
|
19747
|
-
return { contents, systemTexts };
|
|
19748
|
-
}
|
|
19749
|
-
function parseToolArgs(raw) {
|
|
19750
|
-
if (typeof raw === "string") {
|
|
19751
|
-
try {
|
|
19752
|
-
const parsed = JSON.parse(raw);
|
|
19753
|
-
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
19754
|
-
return parsed;
|
|
19755
|
-
}
|
|
19756
|
-
} catch {
|
|
19757
|
-
}
|
|
19758
|
-
}
|
|
19759
|
-
if (raw && typeof raw === "object" && !Array.isArray(raw)) {
|
|
19760
|
-
return raw;
|
|
19761
|
-
}
|
|
19762
|
-
return {};
|
|
19763
|
-
}
|
|
19764
|
-
function sanitizeGeminiSchemaNode(node, active) {
|
|
19765
|
-
const out = {};
|
|
19766
|
-
if (!node || typeof node !== "object" || Array.isArray(node)) {
|
|
19767
|
-
return { type: "string" };
|
|
19768
|
-
}
|
|
19769
|
-
if (active?.has(node)) {
|
|
19770
|
-
return { type: "object", description: "(circular schema reference)" };
|
|
19771
|
-
}
|
|
19772
|
-
const seen = active ?? /* @__PURE__ */ new WeakSet();
|
|
19773
|
-
seen.add(node);
|
|
19774
|
-
try {
|
|
19775
|
-
return sanitizeGeminiSchemaNodeInner(node, out, seen);
|
|
19776
|
-
} finally {
|
|
19777
|
-
seen.delete(node);
|
|
19778
|
-
}
|
|
19779
|
-
}
|
|
19780
|
-
function sanitizeGeminiSchemaNodeInner(src, out, seen) {
|
|
19781
|
-
if (Array.isArray(src.type)) {
|
|
19782
|
-
const firstNonNull = src.type.find((t) => t !== "null");
|
|
19783
|
-
if (typeof firstNonNull === "string") out.type = firstNonNull;
|
|
19784
|
-
out.nullable = true;
|
|
19785
|
-
} else if (typeof src.type === "string") {
|
|
19786
|
-
out.type = src.type;
|
|
19787
|
-
}
|
|
19788
|
-
if (typeof src.description === "string") out.description = src.description;
|
|
19789
|
-
if (typeof src.minimum === "number") out.minimum = src.minimum;
|
|
19790
|
-
if (typeof src.maximum === "number") out.maximum = src.maximum;
|
|
19791
|
-
if (Array.isArray(src.enum) && src.enum.length > 0) out.enum = src.enum;
|
|
19792
|
-
if (src.nullable === true) out.nullable = true;
|
|
19793
|
-
if ("const" in src && src.const !== void 0 && !out.enum) {
|
|
19794
|
-
out.enum = [src.const];
|
|
19795
|
-
}
|
|
19796
|
-
const variantBranches = [
|
|
19797
|
-
...Array.isArray(src.oneOf) ? src.oneOf : [],
|
|
19798
|
-
...Array.isArray(src.anyOf) ? src.anyOf : []
|
|
19799
|
-
];
|
|
19800
|
-
if (variantBranches.length > 0) {
|
|
19801
|
-
const mergedProperties = {};
|
|
19802
|
-
let requiredIntersection;
|
|
19803
|
-
for (const branch of variantBranches) {
|
|
19804
|
-
const sanitized = sanitizeGeminiSchemaNode(branch, seen);
|
|
19805
|
-
const branchProperties = sanitized.properties ?? {};
|
|
19806
|
-
for (const [key, value] of Object.entries(branchProperties)) {
|
|
19807
|
-
const previous = mergedProperties[key];
|
|
19808
|
-
const prevEnum = previous?.enum;
|
|
19809
|
-
const nextEnum = value?.enum;
|
|
19810
|
-
if (prevEnum && nextEnum) {
|
|
19811
|
-
mergedProperties[key] = {
|
|
19812
|
-
...value,
|
|
19813
|
-
enum: [.../* @__PURE__ */ new Set([...prevEnum, ...nextEnum])]
|
|
19814
|
-
};
|
|
19815
|
-
} else {
|
|
19816
|
-
mergedProperties[key] = value;
|
|
19817
|
-
}
|
|
19818
|
-
}
|
|
19819
|
-
const branchRequired = Array.isArray(sanitized.required) ? sanitized.required : [];
|
|
19820
|
-
requiredIntersection = requiredIntersection === void 0 ? [...branchRequired] : requiredIntersection.filter((r) => branchRequired.includes(r));
|
|
19821
|
-
}
|
|
19822
|
-
out.properties = {
|
|
19823
|
-
...out.properties ?? {},
|
|
19824
|
-
...mergedProperties
|
|
19825
|
-
};
|
|
19826
|
-
if (requiredIntersection !== void 0 && requiredIntersection.length > 0) {
|
|
19827
|
-
out.required = requiredIntersection;
|
|
19828
|
-
}
|
|
19829
|
-
if (typeof out.type !== "string") out.type = "object";
|
|
19830
|
-
}
|
|
19831
|
-
if (Array.isArray(src.allOf)) {
|
|
19832
|
-
for (const branch of src.allOf) {
|
|
19833
|
-
const sanitized = sanitizeGeminiSchemaNode(branch, seen);
|
|
19834
|
-
out.properties = {
|
|
19835
|
-
...out.properties ?? {},
|
|
19836
|
-
...sanitized.properties ?? {}
|
|
19837
|
-
};
|
|
19838
|
-
if (Array.isArray(sanitized.required)) {
|
|
19839
|
-
out.required = [
|
|
19840
|
-
.../* @__PURE__ */ new Set([
|
|
19841
|
-
...out.required ?? [],
|
|
19842
|
-
...sanitized.required ?? []
|
|
19843
|
-
])
|
|
19844
|
-
];
|
|
19845
|
-
}
|
|
19846
|
-
}
|
|
19847
|
-
if (typeof out.type !== "string") out.type = "object";
|
|
19848
|
-
}
|
|
19849
|
-
if (src.properties && typeof src.properties === "object") {
|
|
19850
|
-
const properties = {};
|
|
19851
|
-
for (const [key, value] of Object.entries(
|
|
19852
|
-
src.properties
|
|
19853
|
-
)) {
|
|
19854
|
-
properties[key] = sanitizeGeminiSchemaNode(value, seen);
|
|
19855
|
-
}
|
|
19856
|
-
out.properties = properties;
|
|
19857
|
-
if (typeof out.type !== "string") out.type = "object";
|
|
19858
|
-
}
|
|
19859
|
-
if (Array.isArray(src.required)) {
|
|
19860
|
-
const properties = out.properties ?? {};
|
|
19861
|
-
const required = [...new Set(src.required)].filter(
|
|
19862
|
-
(r) => typeof r === "string" && r in properties
|
|
19863
|
-
);
|
|
19864
|
-
if (required.length > 0) out.required = required;
|
|
19865
|
-
}
|
|
19866
|
-
if (src.items !== void 0) {
|
|
19867
|
-
out.items = sanitizeGeminiSchemaNode(src.items, seen);
|
|
19868
|
-
if (typeof out.type !== "string") out.type = "array";
|
|
19869
|
-
}
|
|
19870
|
-
if (typeof out.type !== "string") out.type = "object";
|
|
19871
|
-
return out;
|
|
19872
|
-
}
|
|
19873
|
-
function convertOpenAiToolsToGemini(tools) {
|
|
19874
|
-
if (!Array.isArray(tools) || tools.length === 0) return void 0;
|
|
19875
|
-
const declarations = [];
|
|
19876
|
-
for (const tool of tools) {
|
|
19877
|
-
if (!tool || typeof tool !== "object" || !("function" in tool)) continue;
|
|
19878
|
-
const fn3 = tool.function;
|
|
19879
|
-
const name = typeof fn3.name === "string" ? fn3.name : "";
|
|
19880
|
-
if (!name) continue;
|
|
19881
|
-
declarations.push({
|
|
19882
|
-
name,
|
|
19883
|
-
description: typeof fn3.description === "string" ? fn3.description : "",
|
|
19884
|
-
parameters: sanitizeGeminiSchemaNode(
|
|
19885
|
-
fn3.parameters ?? { type: "object", properties: {} }
|
|
19886
|
-
)
|
|
19887
|
-
});
|
|
19888
|
-
}
|
|
19889
|
-
if (declarations.length === 0) return void 0;
|
|
19890
|
-
return [{ functionDeclarations: declarations }];
|
|
19891
|
-
}
|
|
19892
|
-
function createGeminiAccumulatorState() {
|
|
19893
|
-
return {
|
|
19894
|
-
text: "",
|
|
19895
|
-
toolCalls: [],
|
|
19896
|
-
reasoning: "",
|
|
19897
|
-
events: []
|
|
19898
|
-
};
|
|
19899
|
-
}
|
|
19900
|
-
function applyGeminiChunk(chunk, state, options) {
|
|
19901
|
-
if (!chunk || typeof chunk !== "object") return;
|
|
19902
|
-
const response = "response" in chunk && chunk.response && typeof chunk.response === "object" ? chunk.response : chunk;
|
|
19903
|
-
if ("usageMetadata" in response && response.usageMetadata && typeof response.usageMetadata === "object") {
|
|
19904
|
-
const meta = response.usageMetadata;
|
|
19905
|
-
const prompt = typeof meta.promptTokenCount === "number" ? meta.promptTokenCount : 0;
|
|
19906
|
-
const candidates2 = typeof meta.candidatesTokenCount === "number" ? meta.candidatesTokenCount : 0;
|
|
19907
|
-
const total = typeof meta.totalTokenCount === "number" ? meta.totalTokenCount : prompt + candidates2;
|
|
19908
|
-
const cached3 = typeof meta.cachedContentTokenCount === "number" && Number.isFinite(meta.cachedContentTokenCount) ? (
|
|
19909
|
-
// cached ⊆ prompt;对畸形上游防御性钳位,避免 cache_read > input 破坏归一化与计费
|
|
19910
|
-
Math.min(Math.max(0, Math.floor(meta.cachedContentTokenCount)), prompt)
|
|
19911
|
-
) : 0;
|
|
19912
|
-
state.usage = {
|
|
19913
|
-
prompt_tokens: prompt,
|
|
19914
|
-
completion_tokens: candidates2,
|
|
19915
|
-
total_tokens: total,
|
|
19916
|
-
...cached3 > 0 ? { cache_read_input_tokens: cached3 } : {}
|
|
19917
|
-
};
|
|
19918
|
-
state.events.push({ kind: "usage", usage: state.usage });
|
|
19919
|
-
}
|
|
19920
|
-
const candidates = Array.isArray(response.candidates) ? response.candidates : [];
|
|
19921
|
-
for (const candidate of candidates) {
|
|
19922
|
-
if (!candidate || typeof candidate !== "object") continue;
|
|
19923
|
-
const candidateFinishReason = candidate.finishReason;
|
|
19924
|
-
if (typeof candidateFinishReason === "string" && candidateFinishReason.trim()) {
|
|
19925
|
-
state.finishReason = candidateFinishReason.trim();
|
|
19926
|
-
state.events.push({ kind: "finish", reason: state.finishReason });
|
|
19927
|
-
}
|
|
19928
|
-
const parts2 = Array.isArray(
|
|
19929
|
-
candidate.content?.parts
|
|
19930
|
-
) ? candidate.content.parts : [];
|
|
19931
|
-
for (const part of parts2) {
|
|
19932
|
-
if (!part || typeof part !== "object") continue;
|
|
19933
|
-
const partSignature = part.thoughtSignature;
|
|
19934
|
-
const isThought = Boolean(part.thought);
|
|
19935
|
-
if ("text" in part && typeof part.text === "string") {
|
|
19936
|
-
const piece = part.text;
|
|
19937
|
-
if (!isThought) {
|
|
19938
|
-
state.text += piece;
|
|
19939
|
-
if (piece) {
|
|
19940
|
-
state.events.push({ kind: "text", text: piece });
|
|
19941
|
-
if (options?.onTextDelta) options.onTextDelta(piece);
|
|
19942
|
-
}
|
|
19943
|
-
} else {
|
|
19944
|
-
state.reasoning += piece;
|
|
19945
|
-
if (piece) {
|
|
19946
|
-
state.events.push({ kind: "reasoning", text: piece });
|
|
19947
|
-
if (options?.onReasoningDelta) options.onReasoningDelta(piece);
|
|
19948
|
-
}
|
|
19949
|
-
}
|
|
19950
|
-
}
|
|
19951
|
-
if (isThought && typeof partSignature === "string" && partSignature) {
|
|
19952
|
-
state.pendingThoughtSignature = partSignature;
|
|
19953
|
-
}
|
|
19954
|
-
if ("functionCall" in part && part.functionCall) {
|
|
19955
|
-
const call = part.functionCall;
|
|
19956
|
-
const name = typeof call.name === "string" ? call.name : "tool";
|
|
19957
|
-
const id = typeof call.id === "string" ? call.id : `${name}_${state.toolCalls.length}`;
|
|
19958
|
-
const argsObj = call.args && typeof call.args === "object" ? call.args : {};
|
|
19959
|
-
const resolvedSignature = typeof partSignature === "string" && partSignature ? partSignature : state.pendingThoughtSignature;
|
|
19960
|
-
state.pendingThoughtSignature = void 0;
|
|
19961
|
-
const toolCall = {
|
|
19962
|
-
id,
|
|
19963
|
-
type: "function",
|
|
19964
|
-
function: { name, arguments: JSON.stringify(argsObj) },
|
|
19965
|
-
...typeof resolvedSignature === "string" && resolvedSignature ? { thought_signature: resolvedSignature } : {}
|
|
19966
|
-
};
|
|
19967
|
-
state.toolCalls.push(toolCall);
|
|
19968
|
-
state.events.push({ kind: "tool_call", toolCall });
|
|
19969
|
-
}
|
|
19970
|
-
}
|
|
19971
|
-
}
|
|
19972
|
-
}
|
|
19973
|
-
function accumulateGeminiChunks(chunks2, options) {
|
|
19974
|
-
const state = createGeminiAccumulatorState();
|
|
19975
|
-
for (const chunk of chunks2) {
|
|
19976
|
-
applyGeminiChunk(chunk, state, options);
|
|
19977
|
-
}
|
|
19978
|
-
return {
|
|
19979
|
-
text: state.text,
|
|
19980
|
-
toolCalls: state.toolCalls,
|
|
19981
|
-
usage: state.usage,
|
|
19982
|
-
finishReason: state.finishReason,
|
|
19983
|
-
reasoningContent: state.reasoning,
|
|
19984
|
-
events: state.events
|
|
19985
|
-
};
|
|
19986
|
-
}
|
|
19987
|
-
async function accumulateGeminiStream(stream, options) {
|
|
19988
|
-
const state = createGeminiAccumulatorState();
|
|
19989
|
-
for await (const chunk of stream) {
|
|
19990
|
-
applyGeminiChunk(chunk, state, options);
|
|
19991
|
-
}
|
|
19992
|
-
return {
|
|
19993
|
-
text: state.text,
|
|
19994
|
-
toolCalls: state.toolCalls,
|
|
19995
|
-
usage: state.usage,
|
|
19996
|
-
finishReason: state.finishReason,
|
|
19997
|
-
reasoningContent: state.reasoning,
|
|
19998
|
-
events: state.events
|
|
19999
|
-
};
|
|
20000
|
-
}
|
|
20001
|
-
function shouldUseGeminiNativeToolRoute(provider, model, tools, isImageModel) {
|
|
20002
|
-
return provider === "google" && !isImageModel(model) && isGemini3Model(model) && Array.isArray(tools) && tools.length > 0;
|
|
20003
|
-
}
|
|
20004
|
-
function buildGeminiGenerateContentRequest(args2) {
|
|
20005
|
-
const { contents, systemTexts } = convertOpenAiMessagesToGemini(
|
|
20006
|
-
args2.messages,
|
|
20007
|
-
{ attachSkipThoughtSignature: args2.attachSkipThoughtSignature }
|
|
20008
|
-
);
|
|
20009
|
-
const request3 = { contents };
|
|
20010
|
-
if (systemTexts.length > 0) {
|
|
20011
|
-
request3.systemInstruction = {
|
|
20012
|
-
role: "user",
|
|
20013
|
-
parts: systemTexts.map((text) => ({ text }))
|
|
20014
|
-
};
|
|
20015
|
-
}
|
|
20016
|
-
const toolsResult = convertOpenAiToolsToGemini(args2.tools);
|
|
20017
|
-
if (toolsResult) {
|
|
20018
|
-
request3.tools = toolsResult;
|
|
20019
|
-
request3.toolConfig = { functionCallingConfig: { mode: "VALIDATED" } };
|
|
20020
|
-
}
|
|
20021
|
-
const generationConfig = {};
|
|
20022
|
-
if (typeof args2.maxTokens === "number" && args2.maxTokens > 0) {
|
|
20023
|
-
generationConfig.maxOutputTokens = args2.maxTokens;
|
|
20024
|
-
}
|
|
20025
|
-
if (typeof args2.temperature === "number") {
|
|
20026
|
-
generationConfig.temperature = args2.temperature;
|
|
20027
|
-
}
|
|
20028
|
-
if (Object.keys(generationConfig).length > 0) {
|
|
20029
|
-
request3.generationConfig = generationConfig;
|
|
20030
|
-
}
|
|
20031
|
-
return request3;
|
|
20032
|
-
}
|
|
20033
|
-
|
|
20034
|
-
// packages/agent-runtime/antigravityCloudCodeProvider.ts
|
|
20035
|
-
var STREAM_PATH = "/v1internal:streamGenerateContent?alt=sse";
|
|
20036
|
-
function buildCloudCodeAssistPayload(args2) {
|
|
20037
|
-
const projectId = readAntigravityProjectId(args2.metadata);
|
|
20038
|
-
if (!projectId) {
|
|
20039
|
-
throw new Error(
|
|
20040
|
-
"Antigravity OAuth credential is missing metadata.projectId. Re-run `nolo auth antigravity`."
|
|
20041
|
-
);
|
|
20042
|
-
}
|
|
20043
|
-
const logicalModel = asOptionalTrimmedString(args2.openAiBody.model) ?? asOptionalTrimmedString(args2.agentConfig.model) ?? "gemini-3.1-pro";
|
|
20044
|
-
const { wireModelId: model, profile } = resolveAntigravityWireModel(logicalModel);
|
|
20045
|
-
const rawMessages = Array.isArray(args2.openAiBody.messages) ? args2.openAiBody.messages : [];
|
|
20046
|
-
const quirks = resolveGeminiModelQuirks(model);
|
|
20047
|
-
const isClaude = quirks.isClaudeCrossModel;
|
|
20048
|
-
const { contents, systemTexts } = convertOpenAiMessagesToGemini(rawMessages, {
|
|
20049
|
-
attachSkipThoughtSignature: quirks.allowsThoughtSignatureSentinel
|
|
20050
|
-
});
|
|
20051
|
-
if (contents.length === 0) {
|
|
20052
|
-
throw new Error("Antigravity Cloud Code Assist request has no user/model contents.");
|
|
20053
|
-
}
|
|
20054
|
-
const prompt = args2.agentConfig.prompt?.trim();
|
|
20055
|
-
if (prompt) systemTexts.unshift(prompt);
|
|
20056
|
-
const request3 = { contents };
|
|
20057
|
-
if (systemTexts.length > 0) {
|
|
20058
|
-
request3.systemInstruction = {
|
|
20059
|
-
role: "user",
|
|
20060
|
-
parts: systemTexts.map((text) => ({ text }))
|
|
20061
|
-
};
|
|
20062
|
-
}
|
|
20063
|
-
const tools = convertOpenAiToolsToGemini(
|
|
20064
|
-
Array.isArray(args2.openAiBody.tools) ? args2.openAiBody.tools : void 0
|
|
20065
|
-
);
|
|
20066
|
-
if (tools) {
|
|
20067
|
-
request3.tools = tools;
|
|
20068
|
-
request3.toolConfig = { functionCallingConfig: { mode: "VALIDATED" } };
|
|
20069
|
-
}
|
|
20070
|
-
const generationConfig = {};
|
|
20071
|
-
if (profile?.maxOutputTokens) {
|
|
20072
|
-
generationConfig.maxOutputTokens = profile.maxOutputTokens;
|
|
20073
|
-
} else if (typeof args2.agentConfig.max_tokens === "number" && args2.agentConfig.max_tokens > 0) {
|
|
20074
|
-
generationConfig.maxOutputTokens = args2.agentConfig.max_tokens;
|
|
20075
|
-
}
|
|
20076
|
-
if (typeof args2.agentConfig.temperature === "number") {
|
|
20077
|
-
generationConfig.temperature = args2.agentConfig.temperature;
|
|
20078
|
-
}
|
|
20079
|
-
if (Object.keys(generationConfig).length > 0) {
|
|
20080
|
-
request3.generationConfig = generationConfig;
|
|
20081
|
-
}
|
|
20082
|
-
const agentId = randomUUID();
|
|
20083
|
-
const trajectoryId = randomUUID();
|
|
20084
|
-
const step = 2;
|
|
20085
|
-
const requestId = `agent/${agentId}/${Date.now()}/${trajectoryId}/${step}`;
|
|
20086
|
-
const labels = {
|
|
20087
|
-
trajectory_id: trajectoryId,
|
|
20088
|
-
last_step_index: String(step - 1),
|
|
20089
|
-
used_claude: String(isClaude),
|
|
20090
|
-
used_claude_conservative: String(isClaude)
|
|
20091
|
-
};
|
|
20092
|
-
if (profile?.modelEnum) {
|
|
20093
|
-
labels.model_enum = profile.modelEnum;
|
|
20094
|
-
}
|
|
20095
|
-
request3.labels = labels;
|
|
20096
|
-
request3.sessionId = `-${Math.floor(Math.random() * 9e15)}`;
|
|
20097
|
-
return {
|
|
20098
|
-
url: `${resolveAntigravityCloudCodeBaseUrl(args2.agentConfig.customProviderUrl)}${STREAM_PATH}`,
|
|
20099
|
-
envelope: {
|
|
20100
|
-
project: projectId,
|
|
20101
|
-
model,
|
|
20102
|
-
request: request3,
|
|
20103
|
-
requestId,
|
|
20104
|
-
requestType: "agent",
|
|
20105
|
-
userAgent: "antigravity"
|
|
20106
|
-
}
|
|
20107
|
-
};
|
|
20108
|
-
}
|
|
20109
|
-
function resolveAntigravityFinishReason(upstream) {
|
|
20110
|
-
const normalized = (upstream ?? "").trim().toUpperCase();
|
|
20111
|
-
if (normalized === "MAX_TOKENS") return "length";
|
|
20112
|
-
if (normalized === "SAFETY" || normalized === "RECITATION" || normalized === "PROHIBITED_CONTENT" || normalized === "BLOCKLIST") {
|
|
20113
|
-
return "content_filter";
|
|
20114
|
-
}
|
|
20115
|
-
return "stop";
|
|
20116
|
-
}
|
|
20117
|
-
function normalizeAntigravityCompletion(decoded) {
|
|
20118
|
-
const { text, toolCalls, usage, finishReason, reasoningContent, events } = decoded;
|
|
20119
|
-
const normalizedFinishReason = (finishReason ?? "").trim().toUpperCase();
|
|
20120
|
-
if (!text && !reasoningContent && toolCalls.length === 0 && !finishReason && !usage) {
|
|
20121
|
-
const body = {
|
|
20122
|
-
error: {
|
|
20123
|
-
message: "antigravity upstream returned an empty stream (no content, finishReason or usage); channel degradation, not model emptiness"
|
|
20124
|
-
},
|
|
20125
|
-
provider_events: events
|
|
20126
|
-
};
|
|
20127
|
-
return {
|
|
20128
|
-
status: 502,
|
|
20129
|
-
text: "",
|
|
20130
|
-
toolCalls: [],
|
|
20131
|
-
providerEvents: events,
|
|
20132
|
-
body
|
|
20133
|
-
};
|
|
20134
|
-
}
|
|
20135
|
-
if (normalizedFinishReason === "MALFORMED_FUNCTION_CALL") {
|
|
20136
|
-
const message2 = "antigravity upstream returned MALFORMED_FUNCTION_CALL (model generated an invalid function call or tool arguments were rejected by upstream)";
|
|
20137
|
-
const providerFailure = {
|
|
20138
|
-
kind: "provider_failure",
|
|
20139
|
-
provider: "antigravity",
|
|
20140
|
-
code: "MALFORMED_FUNCTION_CALL",
|
|
20141
|
-
message: message2,
|
|
20142
|
-
providerReason: "MALFORMED_FUNCTION_CALL",
|
|
20143
|
-
retryable: false,
|
|
20144
|
-
status: 502
|
|
20145
|
-
};
|
|
20146
|
-
return {
|
|
20147
|
-
status: 502,
|
|
20148
|
-
text: "",
|
|
20149
|
-
toolCalls: [],
|
|
20150
|
-
finishReason,
|
|
20151
|
-
providerEvents: events,
|
|
20152
|
-
providerFailure,
|
|
20153
|
-
runtimeProviderFailure: {
|
|
20154
|
-
message: providerFailure.message,
|
|
20155
|
-
retryable: providerFailure.retryable
|
|
20156
|
-
},
|
|
20157
|
-
body: {
|
|
20158
|
-
error: {
|
|
20159
|
-
message: message2,
|
|
20160
|
-
code: "MALFORMED_FUNCTION_CALL",
|
|
20161
|
-
category: "malformed_function_call",
|
|
20162
|
-
providerReason: "MALFORMED_FUNCTION_CALL",
|
|
20163
|
-
retryable: false
|
|
20164
|
-
},
|
|
20165
|
-
provider_failure: providerFailure,
|
|
20166
|
-
provider_events: events
|
|
20167
|
-
}
|
|
20168
|
-
};
|
|
20169
|
-
}
|
|
20170
|
-
const message = {
|
|
20171
|
-
role: "assistant",
|
|
20172
|
-
content: text || null
|
|
20173
|
-
};
|
|
20174
|
-
if (toolCalls.length > 0) message.tool_calls = toolCalls;
|
|
20175
|
-
if (reasoningContent) message.reasoning_content = reasoningContent;
|
|
20176
|
-
return {
|
|
20177
|
-
status: 200,
|
|
20178
|
-
text,
|
|
20179
|
-
...reasoningContent ? { reasoningContent } : {},
|
|
20180
|
-
toolCalls,
|
|
20181
|
-
...usage ? { usage } : {},
|
|
20182
|
-
...finishReason ? { finishReason } : {},
|
|
20183
|
-
providerEvents: events,
|
|
20184
|
-
body: {
|
|
20185
|
-
choices: [{
|
|
20186
|
-
index: 0,
|
|
20187
|
-
message,
|
|
20188
|
-
finish_reason: toolCalls.length > 0 ? "tool_calls" : resolveAntigravityFinishReason(finishReason)
|
|
20189
|
-
}],
|
|
20190
|
-
...usage ? { usage } : {},
|
|
20191
|
-
provider_events: events
|
|
20192
|
-
}
|
|
20193
|
-
};
|
|
20194
|
-
}
|
|
20195
|
-
async function fetchAntigravityCloudCodeCompletion(args2) {
|
|
20196
|
-
const fetchImpl = args2.fetchImpl ?? fetch;
|
|
20197
|
-
const { url, envelope } = buildCloudCodeAssistPayload(args2);
|
|
20198
|
-
const response = await fetchImpl(url, {
|
|
20199
|
-
method: "POST",
|
|
20200
|
-
headers: {
|
|
20201
|
-
Authorization: `Bearer ${args2.accessToken}`,
|
|
20202
|
-
"Content-Type": "application/json",
|
|
20203
|
-
"User-Agent": getAntigravityUserAgent()
|
|
20204
|
-
},
|
|
20205
|
-
body: JSON.stringify(envelope),
|
|
20206
|
-
signal: args2.signal
|
|
20207
|
-
});
|
|
20208
|
-
if (!response.ok) {
|
|
20209
|
-
const errorText = await response.text();
|
|
20210
|
-
return {
|
|
20211
|
-
status: response.status,
|
|
20212
|
-
text: "",
|
|
20213
|
-
toolCalls: [],
|
|
20214
|
-
providerEvents: [],
|
|
20215
|
-
// 保留上游结构:Antigravity 的限流 body 同样携带结构化的重置信息,
|
|
20216
|
-
// 压成字符串会让冷却退化成 5 分钟默认值。
|
|
20217
|
-
body: parseUpstreamErrorBody(errorText, response.statusText)
|
|
20218
|
-
};
|
|
20219
|
-
}
|
|
20220
|
-
const chunkStream = streamSseDataValues(response, parseSseDataLineJson);
|
|
20221
|
-
const { text, toolCalls, usage, finishReason, reasoningContent, events } = await accumulateGeminiStream(chunkStream, {
|
|
20222
|
-
onTextDelta: args2.onTextDelta,
|
|
20223
|
-
onReasoningDelta: args2.onReasoningDelta
|
|
20224
|
-
});
|
|
20225
|
-
const normalized = normalizeAntigravityCompletion({
|
|
20226
|
-
text,
|
|
20227
|
-
toolCalls,
|
|
20228
|
-
usage,
|
|
20229
|
-
finishReason,
|
|
20230
|
-
reasoningContent,
|
|
20231
|
-
events
|
|
20232
|
-
});
|
|
20233
|
-
if (normalized.status !== 200 || !text && toolCalls.length === 0) {
|
|
20234
|
-
console.warn(
|
|
20235
|
-
`[antigravity] empty completion: finishReason=${JSON.stringify(finishReason)} reasoningLen=${reasoningContent?.length ?? 0} usage=${JSON.stringify(usage) ?? "none"} model=${String(envelope.model)} base=${new URL(url).host}`
|
|
20236
|
-
);
|
|
20237
|
-
}
|
|
20238
|
-
return normalized;
|
|
20239
|
-
}
|
|
20240
|
-
|
|
20241
20032
|
// packages/agent-runtime/devin/devinProvider.ts
|
|
20242
|
-
import { randomBytes, randomUUID
|
|
20033
|
+
import { randomBytes, randomUUID } from "node:crypto";
|
|
20243
20034
|
var CLIENT_NAME = "chisel";
|
|
20244
20035
|
var CLIENT_VERSION = "2026.8.18";
|
|
20245
20036
|
function writeVarint(fieldNum, value) {
|
|
@@ -20301,7 +20092,7 @@ function encodeDevinClientMetadata(token) {
|
|
|
20301
20092
|
function encodeDevinChatMessage(msg) {
|
|
20302
20093
|
const source = msg.role === "assistant" ? 2 : msg.role === "tool" ? 4 : 1;
|
|
20303
20094
|
return Buffer.concat([
|
|
20304
|
-
writeStringField(1,
|
|
20095
|
+
writeStringField(1, randomUUID()),
|
|
20305
20096
|
writeVarint(2, source),
|
|
20306
20097
|
writeStringField(3, msg.text),
|
|
20307
20098
|
...(msg.toolCalls ?? []).map(
|
|
@@ -20389,7 +20180,7 @@ ${item.text}`;
|
|
|
20389
20180
|
const chatMessageBuffers = coalesced.map((m) => encodeDevinChatMessage(m));
|
|
20390
20181
|
const completionConfig = buildCompletionConfig({ temperature });
|
|
20391
20182
|
const modelConfig = Buffer.concat([
|
|
20392
|
-
writeStringField(1,
|
|
20183
|
+
writeStringField(1, randomUUID()),
|
|
20393
20184
|
writeVarint(2, 1),
|
|
20394
20185
|
writeVarint(3, 4)
|
|
20395
20186
|
]);
|
|
@@ -20401,7 +20192,7 @@ ${item.text}`;
|
|
|
20401
20192
|
writeMessageField(8, completionConfig),
|
|
20402
20193
|
...tools.map((tool) => writeMessageField(10, encodeDevinToolDefinition(tool))),
|
|
20403
20194
|
writeMessageField(15, modelConfig),
|
|
20404
|
-
writeStringField(16,
|
|
20195
|
+
writeStringField(16, randomUUID()),
|
|
20405
20196
|
writeVarint(20, 1),
|
|
20406
20197
|
writeStringField(21, model)
|
|
20407
20198
|
]);
|
|
@@ -20775,8 +20566,6 @@ export {
|
|
|
20775
20566
|
LOCAL_AGENT_CONFIG_MISSING_CODE,
|
|
20776
20567
|
LOCAL_TURN_ABORTED_CODE,
|
|
20777
20568
|
runLocalAgentTurn,
|
|
20778
|
-
parseSseDataLineJson,
|
|
20779
|
-
parseSseDataLineObject,
|
|
20780
20569
|
codexStreamFailureStatus,
|
|
20781
20570
|
aggregateResponsesStream,
|
|
20782
20571
|
buildOpenAiCompatibleChatCompletionRequest,
|
|
@@ -20792,8 +20581,6 @@ export {
|
|
|
20792
20581
|
createHybridRecordStore,
|
|
20793
20582
|
isDestructiveShellCommand,
|
|
20794
20583
|
evaluateShellCommandPolicy,
|
|
20795
|
-
resolveLocalToolPolicy,
|
|
20796
|
-
executeLocalToolWithPolicy,
|
|
20797
20584
|
filterRetainedLedgerRecords,
|
|
20798
20585
|
isLineRangeCovered,
|
|
20799
20586
|
getProcessRegistry,
|
|
@@ -20804,17 +20591,14 @@ export {
|
|
|
20804
20591
|
internalSearchWorkspace,
|
|
20805
20592
|
internalListWorkspaceEntries,
|
|
20806
20593
|
createLocalWorkspaceToolExecutors,
|
|
20594
|
+
buildToolParametersIndex,
|
|
20595
|
+
getAgentRuntimeToolParametersIndex,
|
|
20596
|
+
resolveLocalToolPolicy,
|
|
20597
|
+
executeLocalToolWithPolicy,
|
|
20807
20598
|
localDialogMessageRecordToRuntimeMessage,
|
|
20808
20599
|
buildLocalDialogWritePlan,
|
|
20809
20600
|
buildNoloWorkspaceCliToolExecutors,
|
|
20810
20601
|
buildLoadSkillExecutor,
|
|
20811
|
-
parseUpstreamErrorBody,
|
|
20812
|
-
isGemini3Model,
|
|
20813
|
-
accumulateGeminiChunks,
|
|
20814
|
-
shouldUseGeminiNativeToolRoute,
|
|
20815
|
-
buildGeminiGenerateContentRequest,
|
|
20816
|
-
resolveAntigravityFinishReason,
|
|
20817
|
-
fetchAntigravityCloudCodeCompletion,
|
|
20818
20602
|
readDevinUpstreamFailure,
|
|
20819
20603
|
createDevinProvider
|
|
20820
20604
|
};
|