nolo-cli 0.97.0-alpha.1 → 0.97.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/{_executeModel-JIG7MRXQ.js → _executeModel-DYHTQJZC.js} +68 -63
- package/{action-YVYQEAAV.js → action-GI44T4DR.js} +10 -10
- package/{addContentAction-O7R66HEX.js → addContentAction-B2DRF7P6.js} +9 -9
- package/{addDialogAgentAction-74OA7KYP.js → addDialogAgentAction-T3I7IXPK.js} +15 -17
- package/{agentDeleteCommand-THAZ5GQS.js → agentDeleteCommand-LLNNP3AM.js} +47 -43
- package/{agentEmailCommands-A7T7AJA4.js → agentEmailCommands-EO3H2LDW.js} +90 -82
- package/agentListCommands-J3MWAZWO.js +741 -0
- package/{agentMachineCommands-DM4N5PK3.js → agentMachineCommands-V65VOQNK.js} +42 -38
- package/{agentProviderCommands-GNPTL5XR.js → agentProviderCommands-EMZCM6VA.js} +1 -1
- package/{agentPullCommand-O5MPVJ5E.js → agentPullCommand-HF4A42D4.js} +1 -1
- package/agentRecordCommands-VY35OMX3.js +136 -0
- package/{agentRunCommand-JVSTGVG2.js → agentRunCommand-CSEX4QIH.js} +90 -80
- package/{agentRunControl-WCTKX5VL.js → agentRunControl-5T64LM2M.js} +2 -2
- package/{agentRuntimeLocal-73CVIWBB.js → agentRuntimeLocal-AY6YNUAL.js} +44 -36
- package/{agentSlice-6X4JL2E3.js → agentSlice-FOZUXW7X.js} +11 -11
- package/{appDeleteCommands-S7CK4OYL.js → appDeleteCommands-QTTL3QF3.js} +42 -38
- package/{appDeployCommands-U6TMS5GO.js → appDeployCommands-43LJECGV.js} +42 -38
- package/{appDeployStatusCommands-DTNQJ3LJ.js → appDeployStatusCommands-L5BKOLYW.js} +42 -38
- package/{appGetCommands-3SHZEQD5.js → appGetCommands-HOFZKOPC.js} +42 -38
- package/{appListCommands-E2ZMIUB6.js → appListCommands-I7C3SJCE.js} +42 -38
- package/{authCommand-F4EFRRX6.js → authCommand-2YPMMIJN.js} +117 -23
- package/{authCommands-RGOGCPP6.js → authCommands-FFDS4FVX.js} +7 -5
- package/{builtinSkillRegistry-FUAVTRVZ.js → builtinSkillRegistry-CALVIJTX.js} +6 -5
- package/{chatQueueReduxAdapter-LAQEZQKE.js → chatQueueReduxAdapter-NMEZRYC2.js} +30 -29
- package/{chromeCommands-FZYAU75D.js → chromeCommands-K27J4OVZ.js} +124 -28
- package/{chromeOpsCommands-62P2Q2YB.js → chromeOpsCommands-IXRLN57H.js} +4 -3
- package/{chunk-6OZ36FXI.js → chunk-27ONFIEY.js} +22 -4
- package/{chunk-JEDZAO7L.js → chunk-2SYTUTLI.js} +257 -37
- package/{chunk-YQTQQX2H.js → chunk-2UV22D2F.js} +1 -1
- package/{chunk-R2B3MIZA.js → chunk-3BFMH6GE.js} +6 -7
- package/{chunk-OIVSQH2O.js → chunk-3BXNTXYI.js} +299 -5
- package/{chunk-QIAVMDHY.js → chunk-3LX6YE3P.js} +4 -4
- package/{chunk-EYAQT56M.js → chunk-4DPP773Q.js} +2 -2
- package/chunk-4LCOCOR5.js +50 -0
- package/{chunk-2GRGFCF6.js → chunk-4VJAC32I.js} +2 -1
- package/{chunk-MC4XLIJ7.js → chunk-523DITKR.js} +1 -1
- package/{chunk-E4MARS3Q.js → chunk-5GVBDNTO.js} +1 -1
- package/chunk-5J3PYNUP.js +255 -0
- package/chunk-5MMAK75Q.js +15 -0
- package/{chunk-JPGCXHNM.js → chunk-5OA5HMTL.js} +1 -1
- package/{chunk-42V6BK2E.js → chunk-62IL3KQV.js} +4 -34
- package/{chunk-6YTOJY35.js → chunk-6D2JFXLY.js} +35 -0
- package/{chunk-3BMYXEUW.js → chunk-6O4IK4V2.js} +1 -1
- package/{chunk-IIVGDG4I.js → chunk-6PHKBY2Q.js} +10 -4
- package/{chunk-WADCY6G6.js → chunk-6ZWMH6TJ.js} +111 -41
- package/{chunk-ABQYVJBJ.js → chunk-7CHC4W22.js} +1 -1
- package/{chunk-GQBOR3G6.js → chunk-7KVZ5LDQ.js} +2 -2
- package/{chunk-ZWUOR654.js → chunk-7WCQEMPB.js} +971 -1093
- package/{chunk-BLJWCTRL.js → chunk-AOPCEXTB.js} +1 -1
- package/{chunk-LXF6XQDT.js → chunk-AQ3I6DZE.js} +865 -207
- package/{chunk-Q554LLSI.js → chunk-AUDNYVRC.js} +1 -1
- package/{chunk-RG6JBBX5.js → chunk-AWF3WO5R.js} +166 -13
- package/{chunk-GPCZ7UXG.js → chunk-AZRHIN5B.js} +1 -1
- package/chunk-BMQ2MJUK.js +153 -0
- package/{chunk-HWIZU4OL.js → chunk-C3VLSD4K.js} +236 -36
- package/{chunk-3IIEFNGY.js → chunk-C53ZG23R.js} +2 -2
- package/chunk-CHOZJMJS.js +78 -0
- package/{chunk-HJUYAD4A.js → chunk-CPUFH46E.js} +8 -8
- package/{chunk-LS2ZANRJ.js → chunk-CTUQJVQM.js} +1 -1
- package/{chunk-BP4XNZRM.js → chunk-CU3QB4HW.js} +3 -3
- package/{chunk-ACTMNVHM.js → chunk-CYSYR67N.js} +1 -1
- package/{chunk-KQ4ONNQD.js → chunk-DAWDCRIG.js} +82 -8
- package/{chunk-VLTIYV3X.js → chunk-DCLMZ5TX.js} +4 -4
- package/{chunk-UKZDAFYT.js → chunk-DSSTTEKI.js} +6 -10
- package/{chunk-LZIWMYX4.js → chunk-EKS2APRJ.js} +21 -5
- package/{chunk-HVURBGF3.js → chunk-ESRMFY7G.js} +2 -2
- package/{chunk-TRV2MIDW.js → chunk-EXAJ6DCR.js} +1 -0
- package/chunk-FD5K6MPI.js +7808 -0
- package/chunk-GMZLP5DV.js +82 -0
- package/{chunk-FDTR4QJ6.js → chunk-H6A6X4EK.js} +32 -1
- package/{chunk-DVINR3PL.js → chunk-HDLLCBRF.js} +1 -1
- package/{chunk-JCIHVIVG.js → chunk-HKTIX4ZE.js} +23 -76
- package/{chunk-ONXOABJR.js → chunk-HNGRBWYF.js} +3 -0
- package/{chunk-H62HCIUP.js → chunk-HYZIYH2H.js} +11 -10
- package/{chunk-3VNWWVKB.js → chunk-I3QNET24.js} +30 -17
- package/{chunk-WV42OMV7.js → chunk-IAESIMK7.js} +4 -4
- package/{chunk-6FVRQBRR.js → chunk-JJ7P5CIY.js} +56 -34
- package/{chunk-3WD6RUUJ.js → chunk-JZ5II5UV.js} +15 -20
- package/{chunk-JRQFUXY7.js → chunk-KCDUTE5V.js} +96 -19
- package/{chunk-Y5HW6GM2.js → chunk-KHVJXNRY.js} +100 -100
- package/{chunk-7S4YWN7P.js → chunk-MX574M24.js} +1 -1
- package/{chunk-FZGV4FGK.js → chunk-NUHHBEJC.js} +378 -187
- package/{chunk-53HEEOTT.js → chunk-O26PCYLS.js} +80 -13
- package/{chunk-3DII57IT.js → chunk-O2OWEFII.js} +1 -1
- package/{chunk-TDRTS7QW.js → chunk-O6JPWEEK.js} +77 -17
- package/chunk-OCZKATRC.js +129 -0
- package/{chunk-6D6VBVEW.js → chunk-OTEMQQZI.js} +80 -14
- package/{chunk-7OLPQSMQ.js → chunk-OYOWA3CP.js} +24 -5
- package/chunk-P6GMCCAT.js +870 -0
- package/{chunk-ESWUWEFS.js → chunk-PQTSOHBT.js} +13 -13
- package/{chunk-WGR3J4Q6.js → chunk-Q4GP72HX.js} +9 -3
- package/{chunk-DHDMC6FO.js → chunk-QKUMVP3O.js} +11 -6
- package/{chunk-TZJJ77KQ.js → chunk-RMAWULCS.js} +498 -480
- package/{chunk-V4MJDUSR.js → chunk-RSEEDUMS.js} +2 -2
- package/{chunk-UZGQNTVW.js → chunk-S5XGT6GB.js} +5 -3
- package/{chunk-76WEAXJB.js → chunk-SACTCJAC.js} +18 -15
- package/{chunk-AFUORTY4.js → chunk-SONWNI3L.js} +21 -21
- package/{chunk-BYMV6QZG.js → chunk-TNIX77YM.js} +4 -0
- package/{chunk-OF7AQZUG.js → chunk-TU5NE4U3.js} +9 -84
- package/chunk-TY3TIUJK.js +89 -0
- package/chunk-UEGYKNHO.js +13349 -0
- package/chunk-UNYJU5L6.js +780 -0
- package/{chunk-J4MOO56S.js → chunk-UQNS32WZ.js} +10 -2
- package/chunk-VIWDGTDA.js +8 -0
- package/chunk-VJVNU77E.js +83 -0
- package/{chunk-54ADB4W7.js → chunk-VYN7O3OY.js} +1 -1
- package/{chunk-JAXOVNM4.js → chunk-WILHZY7K.js} +45 -45
- package/{chunk-UKWGR5SS.js → chunk-WIWM4FE3.js} +187 -398
- package/{chunk-O6OSWFZQ.js → chunk-XUWRURDF.js} +6 -0
- package/{chunk-Q67DOFOO.js → chunk-Y3PMXGLH.js} +2 -0
- package/{chunk-SNPMM7H3.js → chunk-Y6AZRODX.js} +13 -13
- package/{chunk-SQQVLHMH.js → chunk-YJKDTJ2X.js} +7 -7
- package/{chunk-SH43IESU.js → chunk-YUNJN43V.js} +44 -9
- package/{chunk-TOP2VXOR.js → chunk-Z4CSIXYP.js} +2 -2
- package/{chunk-2F7RJC6L.js → chunk-ZOVKKMF6.js} +1 -1
- package/chunk-ZRAU6T47.js +56 -0
- package/{chunk-Z77CRGTW.js → chunk-ZYWQNCBN.js} +1 -1
- package/commandRegistry-MRPLKSWP.js +833 -0
- package/{contentThunks-ATLWNC2D.js → contentThunks-TD5YOAQM.js} +32 -30
- package/{cooldownCommands-REAWYVTY.js → cooldownCommands-ZLEPIB4A.js} +2 -2
- package/{createAgentAutomationAction-QYYWTVUR.js → createAgentAutomationAction-XUG62ANM.js} +32 -30
- package/{createDialogAction-7I5VGWCR.js → createDialogAction-L3CMZKNL.js} +36 -33
- package/{createPageAction-WNURYCWU.js → createPageAction-WJ3MX6JS.js} +38 -36
- package/{chunk-YVIV7WT4.js → cursorProvider-YGGNMVWX.js} +2496 -9890
- package/{dbSlice-XVWBAGYN.js → dbSlice-DQ32LYTJ.js} +8 -8
- package/{deleteFile-YG6QMJLU.js → deleteFile-NX6QHCWZ.js} +3 -3
- package/{dialogCommands-RILHDRQ5.js → dialogCommands-VM3I4HBW.js} +45 -41
- package/{dialogSlice-W5BYELVR.js → dialogSlice-DSHG3YUE.js} +36 -29
- package/{dist-VODFSGNG.js → dist-NJC2W7I4.js} +61 -54
- package/{docCreateCommands-GSTPU7SG.js → docCreateCommands-TYUJPCOP.js} +44 -40
- package/{docDeleteCommands-2FC3LSUT.js → docDeleteCommands-5XEG2LXO.js} +44 -40
- package/{docReadCommands-27POBA34.js → docReadCommands-M6RO6QHV.js} +43 -39
- package/{docStore-7LAHBFP2.js → docStore-RYOGMPEF.js} +11 -10
- package/{docUpdateCommands-U4II6VCO.js → docUpdateCommands-DKOFTZRX.js} +44 -40
- package/{fetchMessages-EIU7UFFK.js → fetchMessages-67MEFPZR.js} +2 -2
- package/{getPricing-LUSEABA6.js → getPricing-NMMFT3YI.js} +3 -3
- package/{handleSendMessageAction-SKMJMVRU.js → handleSendMessageAction-XH742B27.js} +91 -83
- package/index.js +87 -884
- package/{localDialogRead-BTFJ4V2I.js → localDialogRead-EBRS242U.js} +2 -2
- package/{localRuntimeAuthority-6IR6BBXE.js → localRuntimeAuthority-5W6IJRAD.js} +6 -6
- package/{localRuntimeDb-SYQGUF4U.js → localRuntimeDb-3LRMNLCM.js} +1 -1
- package/{machineCommands-S2RNYKVJ.js → machineCommands-BKYVMMEG.js} +85 -77
- package/{machineWsRunDispatch-JC44LBLP.js → machineWsRunDispatch-QOBSQQ72.js} +82 -74
- package/{memberThunks-QGFLFVCI.js → memberThunks-5ZXPR63F.js} +9 -9
- package/{models-T3SG6MJ5.js → models-ZPU5EDF4.js} +2 -2
- package/oauthTokenStore-ITEB663N.js +23 -0
- package/package.json +1 -1
- package/pdf-U6KSUEZZ.js +26435 -0
- package/processSpawn-SOAV3FEV.js +11 -0
- package/profileConfig-ZGOFORWV.js +43 -0
- package/{providerPresetApply-FG6NZ57W.js → providerPresetApply-76AVU3HD.js} +7 -7
- package/{providerRegistry-757OWH3O.js → providerRegistry-Z62NC45X.js} +11 -7
- package/{read-COE3ZYR6.js → read-EPTJRAEF.js} +5 -5
- package/{readDocTool-5USN4A6V.js → readDocTool-W4NDXNEX.js} +5 -3
- package/{readlineWorkspace-VZSBXUH4.js → readlineWorkspace-7P7IORIT.js} +2450 -2022
- package/{removeDialogAgentAction-IX3MN2ZO.js → removeDialogAgentAction-BVAWQKXE.js} +17 -19
- package/{runAgentClientLoop-ZYENU7GH.js → runAgentClientLoop-7WXN6I7L.js} +62 -58
- package/{runtimeDoctorCommands-X6WDBEQX.js → runtimeDoctorCommands-3USD722U.js} +3 -3
- package/runtimeModeArgs-2Y7BALTO.js +31 -0
- package/{setDialogExtraReferencesAction-X4HCPNZL.js → setDialogExtraReferencesAction-LYY45IAD.js} +12 -11
- package/{setPrimaryDialogAgentAction-4GMIQLOD.js → setPrimaryDialogAgentAction-73IL7DLU.js} +18 -20
- package/{settingSlice-ZQZVUPKK.js → settingSlice-Q6EKL7EQ.js} +9 -9
- package/{skillDiscovery-CYUCJMAG.js → skillDiscovery-ZBU76COE.js} +3 -3
- package/{spaceCommands-QB3NNEMN.js → spaceCommands-QFP4ZXKG.js} +44 -40
- package/{streamAgentChatTurn-43GPPQSN.js → streamAgentChatTurn-B4PXPJJS.js} +184 -91
- package/{switchDialogAgentAction-N52LRPA3.js → switchDialogAgentAction-UUXDSQ6X.js} +15 -17
- package/{tableCommands-O6NWHFKV.js → tableCommands-G7RV3RU3.js} +4 -4
- package/{toolApiClient-QVJ6HDNN.js → toolApiClient-INIQCPGY.js} +3 -3
- package/{tools-SX6Y4STZ.js → tools-QFS2L7BU.js} +55 -51
- package/{tuiSummaryLlmCaller-T2SHYMDZ.js → tuiSummaryLlmCaller-74NRRLVW.js} +18 -16
- package/{updateCommands-2M74UL7P.js → updateCommands-4EHDLF5J.js} +3 -3
- package/{updateDialogTitleAction-VAKA4ZNY.js → updateDialogTitleAction-HTDYCNNZ.js} +81 -43
- package/agentListCommands-BRZFEJQM.js +0 -406
- package/agentRecordCommands-TTAEMNHB.js +0 -128
- package/chunk-K4YGZD3P.js +0 -18881
- package/chunk-M76ECQRD.js +0 -13658
- package/chunk-Q5FJJ6XI.js +0 -103
- package/chunk-S7Z2HMCN.js +0 -25
- package/{chunk-VMFTFOWF.js → chunk-3AH7LNUB.js} +7 -7
- package/{chunk-X7HHHIOZ.js → chunk-Y6ROFCZO.js} +0 -0
- package/{db-WK5MDZVN.js → db-VQSAOWAO.js} +1 -1
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
import {
|
|
2
|
+
DEVIN_CONNECT_URL,
|
|
3
|
+
parseSseDataLineJson,
|
|
4
|
+
parseSseDataLineObject
|
|
5
|
+
} from "./chunk-P6GMCCAT.js";
|
|
1
6
|
import {
|
|
2
7
|
applyChatCompletionDelta,
|
|
3
8
|
applyResponsesToolEvent,
|
|
@@ -5,13 +10,15 @@ import {
|
|
|
5
10
|
finalizeResponsesToolCalls,
|
|
6
11
|
flushChatCompletionStream,
|
|
7
12
|
providerHttpFailure,
|
|
8
|
-
readSseFrames,
|
|
9
|
-
streamSseDataValues,
|
|
10
13
|
throwIfChatCompletionStreamFailed
|
|
11
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-TU5NE4U3.js";
|
|
12
15
|
import {
|
|
13
|
-
|
|
14
|
-
} from "./chunk-
|
|
16
|
+
readSseFrames
|
|
17
|
+
} from "./chunk-GMZLP5DV.js";
|
|
18
|
+
import {
|
|
19
|
+
evaluateFileWritePolicy,
|
|
20
|
+
summarizeToolArguments
|
|
21
|
+
} from "./chunk-CHOZJMJS.js";
|
|
15
22
|
import {
|
|
16
23
|
clipToolText,
|
|
17
24
|
hasImageInRuntimeMessages,
|
|
@@ -20,13 +27,16 @@ import {
|
|
|
20
27
|
resolveHistoricalToolContentCap,
|
|
21
28
|
resolveToolOutputProfile,
|
|
22
29
|
stripImagePartsFromMessages
|
|
23
|
-
} from "./chunk-
|
|
30
|
+
} from "./chunk-C53ZG23R.js";
|
|
24
31
|
import {
|
|
25
32
|
downgradeUnparsableToolCalls,
|
|
26
33
|
hasParsableObjectArguments,
|
|
27
34
|
repairTruncatedToolArguments,
|
|
28
35
|
sanitizeForOutbound
|
|
29
36
|
} from "./chunk-CQ3WA2NE.js";
|
|
37
|
+
import {
|
|
38
|
+
buildDialogFallbackTitleFromUserInput
|
|
39
|
+
} from "./chunk-2MBTWINN.js";
|
|
30
40
|
import {
|
|
31
41
|
createThinkParserState,
|
|
32
42
|
createToolCallAccumulator,
|
|
@@ -35,6 +45,7 @@ import {
|
|
|
35
45
|
finalizeAccumulatedToolCalls
|
|
36
46
|
} from "./chunk-N7J63Q6C.js";
|
|
37
47
|
import {
|
|
48
|
+
DELETE_SAFETY_RED_LINE,
|
|
38
49
|
TOOL_GUIDED_SECTION_ORDER,
|
|
39
50
|
buildIdentityBlock,
|
|
40
51
|
buildRuntimeGuidanceBlocks,
|
|
@@ -46,7 +57,7 @@ import {
|
|
|
46
57
|
requiresBareImageUrl,
|
|
47
58
|
resolveToolGuidedSections,
|
|
48
59
|
toBareImageUrlMessages
|
|
49
|
-
} from "./chunk-
|
|
60
|
+
} from "./chunk-EKS2APRJ.js";
|
|
50
61
|
import {
|
|
51
62
|
convertMessagesToResponsesInput,
|
|
52
63
|
extractReasoningFromResponseOutput,
|
|
@@ -64,25 +75,18 @@ import {
|
|
|
64
75
|
applyToolSurfaceConstraints,
|
|
65
76
|
buildDialogReadEnvelope,
|
|
66
77
|
buildNoloWorkspaceCommandArgs,
|
|
78
|
+
buildNoloWorkspaceOpenAiTools,
|
|
67
79
|
createStreamingDialogReadProjector,
|
|
68
80
|
noloPositiveIntegerString,
|
|
69
81
|
noloStringArg,
|
|
70
82
|
parseNoloWorkspaceToolArguments,
|
|
71
83
|
readTextStreamUpToChars,
|
|
72
84
|
resolveNoloDialogInput
|
|
73
|
-
} from "./chunk-
|
|
74
|
-
import {
|
|
75
|
-
getAntigravityUserAgent,
|
|
76
|
-
readAntigravityProjectId,
|
|
77
|
-
resolveAntigravityCloudCodeBaseUrl
|
|
78
|
-
} from "./chunk-UZGQNTVW.js";
|
|
85
|
+
} from "./chunk-6PHKBY2Q.js";
|
|
79
86
|
import {
|
|
80
87
|
buildProviderAuthHeaders,
|
|
81
88
|
buildProviderExecutionPlan
|
|
82
|
-
} from "./chunk-
|
|
83
|
-
import {
|
|
84
|
-
buildDialogFallbackTitleFromUserInput
|
|
85
|
-
} from "./chunk-2MBTWINN.js";
|
|
89
|
+
} from "./chunk-27ONFIEY.js";
|
|
86
90
|
import {
|
|
87
91
|
EMPTY_ASSISTANT_REPAIR_PROMPT,
|
|
88
92
|
getModelContextWindow,
|
|
@@ -93,13 +97,12 @@ import {
|
|
|
93
97
|
resolveEmptyAssistantFallbackMessage,
|
|
94
98
|
resolveEmptyAssistantOutcome,
|
|
95
99
|
resolveTruncatedReasoningTailLog
|
|
96
|
-
} from "./chunk-
|
|
100
|
+
} from "./chunk-WILHZY7K.js";
|
|
97
101
|
import {
|
|
98
102
|
COMPACTION_SUMMARY_SCHEMA_VERSION,
|
|
99
103
|
COMPACTION_SUMMARY_SYSTEM_PROMPT,
|
|
100
104
|
buildCompactionMetricsFromPlan,
|
|
101
105
|
buildCompactionUserContent,
|
|
102
|
-
clipCompactText,
|
|
103
106
|
createProviderCallTimingTracker,
|
|
104
107
|
finalizeProviderCallTiming,
|
|
105
108
|
formatCompactionMetricsLog,
|
|
@@ -112,26 +115,29 @@ import {
|
|
|
112
115
|
resolveCompressionTriggerRatio,
|
|
113
116
|
truncateToolOutputForContext,
|
|
114
117
|
withProviderCallTimingFields
|
|
115
|
-
} from "./chunk-
|
|
118
|
+
} from "./chunk-6ZWMH6TJ.js";
|
|
119
|
+
import {
|
|
120
|
+
clipCompactText
|
|
121
|
+
} from "./chunk-5MMAK75Q.js";
|
|
116
122
|
import {
|
|
117
123
|
estimateTokenCount
|
|
118
124
|
} from "./chunk-PSCNXBYA.js";
|
|
119
|
-
import {
|
|
120
|
-
resolveNoloStateDir
|
|
121
|
-
} from "./chunk-ONXOABJR.js";
|
|
122
125
|
import {
|
|
123
126
|
toErrorMessage
|
|
124
127
|
} from "./chunk-HNMXYYJR.js";
|
|
128
|
+
import {
|
|
129
|
+
resolveNoloStateDir
|
|
130
|
+
} from "./chunk-HNGRBWYF.js";
|
|
125
131
|
import {
|
|
126
132
|
buildDialogSummaryLayer
|
|
127
|
-
} from "./chunk-
|
|
133
|
+
} from "./chunk-HDLLCBRF.js";
|
|
128
134
|
import {
|
|
129
135
|
buildUserResponseLanguageContext
|
|
130
|
-
} from "./chunk-
|
|
136
|
+
} from "./chunk-4VJAC32I.js";
|
|
131
137
|
import {
|
|
132
138
|
canonicalizeToolName,
|
|
133
139
|
canonicalizeToolNames
|
|
134
|
-
} from "./chunk-
|
|
140
|
+
} from "./chunk-XUWRURDF.js";
|
|
135
141
|
import {
|
|
136
142
|
asRecordOrEmpty
|
|
137
143
|
} from "./chunk-KX6YBIHG.js";
|
|
@@ -139,7 +145,7 @@ import {
|
|
|
139
145
|
asTrimmedNonEmptyStringArray,
|
|
140
146
|
dialogMessageKey,
|
|
141
147
|
dialogMessageRange
|
|
142
|
-
} from "./chunk-
|
|
148
|
+
} from "./chunk-3AH7LNUB.js";
|
|
143
149
|
import {
|
|
144
150
|
asOptionalFiniteNumber
|
|
145
151
|
} from "./chunk-WWC7I6TA.js";
|
|
@@ -11900,6 +11906,7 @@ var toQueue = /* @__PURE__ */ dual(2, (self, options) => toQueueArray(self.chann
|
|
|
11900
11906
|
var runIntoQueue = /* @__PURE__ */ dual(2, (self, queue) => runIntoQueueArray(self.channel, queue));
|
|
11901
11907
|
|
|
11902
11908
|
// packages/agent-runtime/abortableKernel.ts
|
|
11909
|
+
var IDLE_WATCHDOG_SLICES = 20;
|
|
11903
11910
|
function runAbortableWithTimeout(args2) {
|
|
11904
11911
|
const taskEffect = Effect_exports.callback(
|
|
11905
11912
|
(resume) => {
|
|
@@ -11935,12 +11942,26 @@ function runAbortableWithTimeout(args2) {
|
|
|
11935
11942
|
raced = Effect_exports.raceFirst(taskEffect, abortEffect);
|
|
11936
11943
|
}
|
|
11937
11944
|
if (typeof args2.timeoutMs === "number") {
|
|
11938
|
-
const
|
|
11945
|
+
const outer = raced;
|
|
11939
11946
|
const timeoutMs = args2.timeoutMs;
|
|
11940
|
-
|
|
11941
|
-
|
|
11942
|
-
|
|
11947
|
+
const activityVersion = args2.activityVersion;
|
|
11948
|
+
const idleWatchdog = Effect_exports.gen(function* () {
|
|
11949
|
+
const sliceCount = activityVersion ? IDLE_WATCHDOG_SLICES : 1;
|
|
11950
|
+
const baseSliceMs = Math.max(1, Math.floor(timeoutMs / sliceCount));
|
|
11951
|
+
let idleMs = 0;
|
|
11952
|
+
for (; ; ) {
|
|
11953
|
+
const versionAtSliceStart = activityVersion?.();
|
|
11954
|
+
const sliceMs = Math.max(1, Math.min(timeoutMs - idleMs, baseSliceMs));
|
|
11955
|
+
yield* Effect_exports.sleep(Duration_exports.millis(sliceMs));
|
|
11956
|
+
idleMs += sliceMs;
|
|
11957
|
+
if (activityVersion && activityVersion() !== versionAtSliceStart) {
|
|
11958
|
+
idleMs = 0;
|
|
11959
|
+
continue;
|
|
11960
|
+
}
|
|
11961
|
+
if (idleMs >= timeoutMs) return { kind: "timeout" };
|
|
11962
|
+
}
|
|
11943
11963
|
});
|
|
11964
|
+
raced = Effect_exports.raceFirst(outer, idleWatchdog);
|
|
11944
11965
|
}
|
|
11945
11966
|
return args2.runtime ? args2.runtime.runPromise(raced) : Effect_exports.runPromise(raced);
|
|
11946
11967
|
}
|
|
@@ -12039,26 +12060,6 @@ function createLocalLoopObservationBoundary(initialCallbacks) {
|
|
|
12039
12060
|
};
|
|
12040
12061
|
}
|
|
12041
12062
|
|
|
12042
|
-
// packages/agent-runtime/fileWritePolicy.ts
|
|
12043
|
-
function evaluateFileWritePolicy(args2) {
|
|
12044
|
-
if (args2.sessionApproved) return { permissionDecision: "allow" };
|
|
12045
|
-
return {
|
|
12046
|
-
permissionDecision: "ask",
|
|
12047
|
-
permissionRequest: {
|
|
12048
|
-
id: "permission-file-write-session",
|
|
12049
|
-
tool: args2.tool,
|
|
12050
|
-
action: "file_write",
|
|
12051
|
-
title: "\u786E\u8BA4\u5199\u5165\u6587\u4EF6",
|
|
12052
|
-
body: `\u672C\u4F1A\u8BDD\u9996\u6B21\u5199\u5165\u6587\u4EF6\uFF1A${args2.path}\u3002\u6279\u51C6\u540E\u672C\u4F1A\u8BDD\u540E\u7EED\u5199\u5165\u4E0D\u518D\u9010\u6B21\u786E\u8BA4\u3002`,
|
|
12053
|
-
command: args2.path,
|
|
12054
|
-
suggestedRule: {
|
|
12055
|
-
scope: "session",
|
|
12056
|
-
pattern: { capability: "file_write", target: "session" }
|
|
12057
|
-
}
|
|
12058
|
-
}
|
|
12059
|
-
};
|
|
12060
|
-
}
|
|
12061
|
-
|
|
12062
12063
|
// packages/agent-runtime/toolCallPairing.ts
|
|
12063
12064
|
function readToolCallId(message) {
|
|
12064
12065
|
if (typeof message.tool_call_id === "string" && message.tool_call_id) {
|
|
@@ -12160,50 +12161,6 @@ function sanitizeToolCallPairing(messages) {
|
|
|
12160
12161
|
return output;
|
|
12161
12162
|
}
|
|
12162
12163
|
|
|
12163
|
-
// packages/agent-runtime/parseToolArguments.ts
|
|
12164
|
-
function parseToolArgumentsJson(raw) {
|
|
12165
|
-
if (!raw?.trim()) return {};
|
|
12166
|
-
try {
|
|
12167
|
-
return asRecordOrEmpty(JSON.parse(raw));
|
|
12168
|
-
} catch {
|
|
12169
|
-
return {};
|
|
12170
|
-
}
|
|
12171
|
-
}
|
|
12172
|
-
|
|
12173
|
-
// packages/agent-runtime/summarizeToolArguments.ts
|
|
12174
|
-
function clip(value, max4 = 240) {
|
|
12175
|
-
return clipCompactText(value, max4);
|
|
12176
|
-
}
|
|
12177
|
-
function summarizeToolArguments(toolName, rawArgs) {
|
|
12178
|
-
const args2 = parseToolArgumentsJson(rawArgs);
|
|
12179
|
-
const pick = (...keys3) => {
|
|
12180
|
-
for (const key of keys3) {
|
|
12181
|
-
const value = asOptionalTrimmedString(args2[key]);
|
|
12182
|
-
if (value) return value;
|
|
12183
|
-
}
|
|
12184
|
-
return "";
|
|
12185
|
-
};
|
|
12186
|
-
const command = pick("command", "cmd", "runCommand", "executeCommand", "bash");
|
|
12187
|
-
if (command) return clip(command);
|
|
12188
|
-
const query = pick("query", "pattern", "search", "q");
|
|
12189
|
-
if (query) return clip(query);
|
|
12190
|
-
const filePath = pick("filePath", "file_path", "path", "filename", "file");
|
|
12191
|
-
if (filePath) return clip(filePath);
|
|
12192
|
-
const keys2 = Object.keys(args2);
|
|
12193
|
-
if (keys2.length === 0) return "";
|
|
12194
|
-
return clip(
|
|
12195
|
-
keys2.slice(0, 6).map((key) => {
|
|
12196
|
-
const value = args2[key];
|
|
12197
|
-
if (typeof value === "string") return `${key}=${clip(value, 80)}`;
|
|
12198
|
-
if (typeof value === "number" || typeof value === "boolean") {
|
|
12199
|
-
return `${key}=${String(value)}`;
|
|
12200
|
-
}
|
|
12201
|
-
if (Array.isArray(value)) return `${key}[${value.length}]`;
|
|
12202
|
-
return `${key}=${value === null ? "null" : typeof value}`;
|
|
12203
|
-
}).join(" ")
|
|
12204
|
-
);
|
|
12205
|
-
}
|
|
12206
|
-
|
|
12207
12164
|
// packages/agent-runtime/progressGuard.ts
|
|
12208
12165
|
var DEFAULT_MAX_CONSECUTIVE_IDENTICAL_ROUNDS = 5;
|
|
12209
12166
|
var DEFAULT_MAX_CONSECUTIVE_STAGNANT_TOOL_ROUNDS = 8;
|
|
@@ -12627,20 +12584,40 @@ function isColdResume(history, nowMs) {
|
|
|
12627
12584
|
}
|
|
12628
12585
|
async function maybeAutoCompactLocalHistory(args2) {
|
|
12629
12586
|
const { adapter, dialogId, history } = args2;
|
|
12630
|
-
const
|
|
12587
|
+
const emitPhase = (phase) => {
|
|
12588
|
+
try {
|
|
12589
|
+
args2.onPhase?.(phase);
|
|
12590
|
+
} catch {
|
|
12591
|
+
}
|
|
12592
|
+
};
|
|
12593
|
+
emitPhase({ kind: "validating-context" });
|
|
12594
|
+
const unchanged = (decision) => ({
|
|
12631
12595
|
history,
|
|
12632
12596
|
compressed: false,
|
|
12633
|
-
summaryGenerated: false
|
|
12597
|
+
summaryGenerated: false,
|
|
12598
|
+
decision
|
|
12634
12599
|
});
|
|
12635
|
-
if (!dialogId
|
|
12636
|
-
return unchanged();
|
|
12600
|
+
if (!dialogId) {
|
|
12601
|
+
return unchanged({ outcome: "skipped", skipReason: "no-dialog-id" });
|
|
12602
|
+
}
|
|
12603
|
+
if (history.length === 0) {
|
|
12604
|
+
return unchanged({ outcome: "skipped", skipReason: "empty-history" });
|
|
12605
|
+
}
|
|
12606
|
+
if (typeof adapter.loadDialogSummary !== "function" || typeof adapter.saveDialogSummary !== "function") {
|
|
12607
|
+
return unchanged({
|
|
12608
|
+
outcome: "skipped",
|
|
12609
|
+
skipReason: "adapter-missing-summary-methods"
|
|
12610
|
+
});
|
|
12637
12611
|
}
|
|
12638
12612
|
let stored = null;
|
|
12639
12613
|
try {
|
|
12640
12614
|
stored = await adapter.loadDialogSummary(dialogId);
|
|
12641
12615
|
} catch (error) {
|
|
12642
12616
|
console.warn("[localLoop] loadDialogSummary failed:", error);
|
|
12643
|
-
return unchanged(
|
|
12617
|
+
return unchanged({
|
|
12618
|
+
outcome: "skipped",
|
|
12619
|
+
skipReason: "load-summary-failed"
|
|
12620
|
+
});
|
|
12644
12621
|
}
|
|
12645
12622
|
const bridged = toPlanCompressionMessages(history);
|
|
12646
12623
|
const validation = validateStoredSummary({ history, stored: stored ?? {} });
|
|
@@ -12676,7 +12653,21 @@ async function maybeAutoCompactLocalHistory(args2) {
|
|
|
12676
12653
|
...args2.realContextUsagePercent !== void 0 ? { realContextUsagePercent: args2.realContextUsagePercent } : {}
|
|
12677
12654
|
});
|
|
12678
12655
|
const projectExisting = () => {
|
|
12679
|
-
|
|
12656
|
+
const diag = plan.diagnostics;
|
|
12657
|
+
const diagSnapshot = diag ? {
|
|
12658
|
+
estimatedTokens: diag.totalUsed,
|
|
12659
|
+
historyBudget: diag.historyBudget,
|
|
12660
|
+
triggerRatio: diag.triggerRatio,
|
|
12661
|
+
...diag.realUsageRatio !== void 0 ? { realUsageRatio: diag.realUsageRatio } : {}
|
|
12662
|
+
} : {};
|
|
12663
|
+
const skippedDecision = {
|
|
12664
|
+
outcome: "skipped",
|
|
12665
|
+
skipReason: diag?.emptyReason === "no-pending" ? "no-pending" : diag?.emptyReason === "below-min-compress-count" ? "below-min-compress-count" : "below-trigger",
|
|
12666
|
+
...diagSnapshot,
|
|
12667
|
+
...diag ? { pendingMsgCount: diag.pendingMsgCount } : {},
|
|
12668
|
+
...diag?.compressCount !== void 0 ? { compressCount: diag.compressCount } : {}
|
|
12669
|
+
};
|
|
12670
|
+
if (!existingSummary.trim()) return unchanged(skippedDecision);
|
|
12680
12671
|
return {
|
|
12681
12672
|
history: projectHistoryWithSummary({
|
|
12682
12673
|
history,
|
|
@@ -12684,14 +12675,26 @@ async function maybeAutoCompactLocalHistory(args2) {
|
|
|
12684
12675
|
summarizedBeforeId
|
|
12685
12676
|
}),
|
|
12686
12677
|
compressed: true,
|
|
12687
|
-
summaryGenerated: false
|
|
12678
|
+
summaryGenerated: false,
|
|
12679
|
+
decision: {
|
|
12680
|
+
outcome: "compressed",
|
|
12681
|
+
trigger: "existing-summary",
|
|
12682
|
+
...diagSnapshot
|
|
12683
|
+
}
|
|
12688
12684
|
};
|
|
12689
12685
|
};
|
|
12690
12686
|
if (!plan.shouldCompress) {
|
|
12691
12687
|
return projectExisting();
|
|
12692
12688
|
}
|
|
12689
|
+
emitPhase({ kind: "compaction-start" });
|
|
12693
12690
|
try {
|
|
12691
|
+
if (args2.abortSignal?.aborted) {
|
|
12692
|
+
throw Object.assign(new Error("auto-compaction aborted"), { compactionReason: "aborted" });
|
|
12693
|
+
}
|
|
12694
12694
|
const provider = await args2.resolveProvider();
|
|
12695
|
+
if (args2.abortSignal?.aborted) {
|
|
12696
|
+
throw Object.assign(new Error("auto-compaction aborted"), { compactionReason: "aborted" });
|
|
12697
|
+
}
|
|
12695
12698
|
const msgsToCompress = plan.msgsToCompress;
|
|
12696
12699
|
const messagesText = formatMessagesForSummaryWithTruncation(msgsToCompress);
|
|
12697
12700
|
const fileOpsText = formatFileOperationsFromMessages(
|
|
@@ -12703,18 +12706,57 @@ async function maybeAutoCompactLocalHistory(args2) {
|
|
|
12703
12706
|
messagesText,
|
|
12704
12707
|
fileOpsText
|
|
12705
12708
|
});
|
|
12706
|
-
|
|
12707
|
-
|
|
12708
|
-
|
|
12709
|
-
|
|
12709
|
+
emitPhase({ kind: "waiting-provider" });
|
|
12710
|
+
const timeoutMs = typeof args2.timeoutMs === "number" && Number.isFinite(args2.timeoutMs) && args2.timeoutMs > 0 ? args2.timeoutMs : void 0;
|
|
12711
|
+
const requestController = new AbortController();
|
|
12712
|
+
let timeoutHandle;
|
|
12713
|
+
let abortListener;
|
|
12714
|
+
const request3 = provider.complete(
|
|
12715
|
+
[{ role: "system", content: COMPACTION_SUMMARY_SYSTEM_PROMPT }, { role: "user", content: promptContent }],
|
|
12716
|
+
{ signal: requestController.signal, ...timeoutMs ? { timeoutMs } : {} }
|
|
12717
|
+
).then(
|
|
12718
|
+
(value) => ({ kind: "done", value }),
|
|
12719
|
+
(error) => ({ kind: "provider-error", error })
|
|
12720
|
+
);
|
|
12721
|
+
const guards = [];
|
|
12722
|
+
if (timeoutMs) guards.push(new Promise((resolve5) => {
|
|
12723
|
+
timeoutHandle = setTimeout(() => {
|
|
12724
|
+
requestController.abort();
|
|
12725
|
+
resolve5({ kind: "timeout" });
|
|
12726
|
+
}, timeoutMs);
|
|
12727
|
+
}));
|
|
12728
|
+
if (args2.abortSignal) guards.push(new Promise((resolve5) => {
|
|
12729
|
+
abortListener = () => {
|
|
12730
|
+
requestController.abort(args2.abortSignal?.reason);
|
|
12731
|
+
resolve5({ kind: "aborted" });
|
|
12732
|
+
};
|
|
12733
|
+
args2.abortSignal?.addEventListener("abort", abortListener, { once: true });
|
|
12734
|
+
}));
|
|
12735
|
+
const outcome = guards.length ? await Promise.race([request3, ...guards]) : await request3;
|
|
12736
|
+
if (timeoutHandle) clearTimeout(timeoutHandle);
|
|
12737
|
+
if (abortListener) args2.abortSignal?.removeEventListener("abort", abortListener);
|
|
12738
|
+
if (outcome.kind !== "done") {
|
|
12739
|
+
const reason = outcome.kind === "timeout" ? "timeout" : outcome.kind === "aborted" ? "aborted" : "provider-error";
|
|
12740
|
+
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";
|
|
12741
|
+
throw Object.assign(new Error(detail), { compactionReason: reason });
|
|
12742
|
+
}
|
|
12743
|
+
const result4 = outcome.value;
|
|
12710
12744
|
const newSummary = typeof result4.content === "string" ? result4.content.trim() : "";
|
|
12711
12745
|
if (!newSummary) {
|
|
12712
12746
|
console.warn(
|
|
12713
12747
|
"[localLoop] auto-compaction produced empty summary; keeping prior projection"
|
|
12714
12748
|
);
|
|
12749
|
+
const failureReason = "provider-error";
|
|
12750
|
+
emitPhase({ kind: "compaction-failed", reason: failureReason });
|
|
12715
12751
|
return {
|
|
12716
12752
|
...projectExisting(),
|
|
12717
|
-
failureMessage: "summary model returned empty content"
|
|
12753
|
+
failureMessage: "summary model returned empty content",
|
|
12754
|
+
failureReason,
|
|
12755
|
+
decision: {
|
|
12756
|
+
outcome: "failed",
|
|
12757
|
+
reason: failureReason,
|
|
12758
|
+
detail: "summary model returned empty content"
|
|
12759
|
+
}
|
|
12718
12760
|
};
|
|
12719
12761
|
}
|
|
12720
12762
|
await adapter.saveDialogSummary({
|
|
@@ -12739,6 +12781,7 @@ async function maybeAutoCompactLocalHistory(args2) {
|
|
|
12739
12781
|
summaryUsage: result4.usage
|
|
12740
12782
|
});
|
|
12741
12783
|
console.log(formatCompactionMetricsLog(metrics));
|
|
12784
|
+
emitPhase({ kind: "compaction-end" });
|
|
12742
12785
|
return {
|
|
12743
12786
|
history: projectHistoryWithSummary({
|
|
12744
12787
|
history,
|
|
@@ -12751,12 +12794,29 @@ async function maybeAutoCompactLocalHistory(args2) {
|
|
|
12751
12794
|
beforeTokens: metrics.previousSummaryTokens + metrics.compressedTokens,
|
|
12752
12795
|
afterTokens: metrics.newSummaryTokens + metrics.retainedTokens,
|
|
12753
12796
|
...result4.usage ? { usage: result4.usage } : {},
|
|
12754
|
-
metrics
|
|
12797
|
+
metrics,
|
|
12798
|
+
decision: {
|
|
12799
|
+
outcome: "compressed",
|
|
12800
|
+
trigger: invalidSummary ? "invalid-summary" : coldResume ? "cold-resume" : plan.diagnostics?.triggeredByRealUsage ? "real-usage" : "estimate",
|
|
12801
|
+
...plan.diagnostics ? {
|
|
12802
|
+
estimatedTokens: plan.diagnostics.totalUsed,
|
|
12803
|
+
historyBudget: plan.diagnostics.historyBudget,
|
|
12804
|
+
triggerRatio: plan.diagnostics.triggerRatio,
|
|
12805
|
+
...plan.diagnostics.realUsageRatio !== void 0 ? { realUsageRatio: plan.diagnostics.realUsageRatio } : {}
|
|
12806
|
+
} : {}
|
|
12807
|
+
}
|
|
12755
12808
|
};
|
|
12756
12809
|
} catch (error) {
|
|
12757
12810
|
console.warn("[localLoop] auto-compaction failed:", error);
|
|
12758
12811
|
const failureMessage = error instanceof Error && error.message ? error.message.slice(0, 200) : String(error).slice(0, 200);
|
|
12759
|
-
|
|
12812
|
+
const failureReason = error instanceof Error && "compactionReason" in error ? error.compactionReason : "provider-error";
|
|
12813
|
+
emitPhase({ kind: "compaction-failed", reason: failureReason });
|
|
12814
|
+
return {
|
|
12815
|
+
...projectExisting(),
|
|
12816
|
+
failureMessage,
|
|
12817
|
+
failureReason,
|
|
12818
|
+
decision: { outcome: "failed", reason: failureReason, detail: failureMessage }
|
|
12819
|
+
};
|
|
12760
12820
|
}
|
|
12761
12821
|
}
|
|
12762
12822
|
|
|
@@ -12812,6 +12872,8 @@ function emitLoopEvent(boundary, event, bridge) {
|
|
|
12812
12872
|
boundary.emit(bridge ? { event, bridge } : { event });
|
|
12813
12873
|
}
|
|
12814
12874
|
var LLM_REQUEST_TIMEOUT = "LLM_REQUEST_TIMEOUT";
|
|
12875
|
+
var DEFAULT_LLM_REQUEST_TIMEOUT_MS = 10 * 60 * 1e3;
|
|
12876
|
+
var DEFAULT_COMPACTION_TIMEOUT_MS = 60 * 1e3;
|
|
12815
12877
|
var LOCAL_TURN_ABORTED_CODE = "LOCAL_TURN_ABORTED";
|
|
12816
12878
|
function buildAbortedError() {
|
|
12817
12879
|
const error = new Error("local agent turn aborted by user");
|
|
@@ -12839,8 +12901,11 @@ async function runAbortableToolTask(input, task, pendingToolName) {
|
|
|
12839
12901
|
}
|
|
12840
12902
|
function resolveLlmRequestTimeoutMs(input) {
|
|
12841
12903
|
const raw = input.llmRequestTimeoutMs ?? input.timeoutMs;
|
|
12842
|
-
|
|
12843
|
-
|
|
12904
|
+
return typeof raw === "number" && Number.isFinite(raw) && raw > 0 ? raw : DEFAULT_LLM_REQUEST_TIMEOUT_MS;
|
|
12905
|
+
}
|
|
12906
|
+
function resolveCompactionTimeoutMs(input) {
|
|
12907
|
+
const raw = input.compactionTimeoutMs;
|
|
12908
|
+
return typeof raw === "number" && Number.isFinite(raw) && raw > 0 ? raw : DEFAULT_COMPACTION_TIMEOUT_MS;
|
|
12844
12909
|
}
|
|
12845
12910
|
async function runCompleteWithTimeout(args2) {
|
|
12846
12911
|
const { provider, messages, options, timeoutMs, round, input, boundary, context: context3, providerName, model } = args2;
|
|
@@ -12863,6 +12928,7 @@ async function runCompleteWithTimeout(args2) {
|
|
|
12863
12928
|
const outcome = await runAbortableWithTimeout({
|
|
12864
12929
|
task: complete,
|
|
12865
12930
|
timeoutMs: typeof timeoutMs === "number" ? timeoutMs : void 0,
|
|
12931
|
+
activityVersion: args2.activityVersion,
|
|
12866
12932
|
abortSignal: input.abortSignal,
|
|
12867
12933
|
runtime: input.effectRuntime
|
|
12868
12934
|
});
|
|
@@ -12873,7 +12939,7 @@ async function runCompleteWithTimeout(args2) {
|
|
|
12873
12939
|
}
|
|
12874
12940
|
if (outcome.kind === "timeout") {
|
|
12875
12941
|
const timeoutError = new Error(
|
|
12876
|
-
`LLM request timed out after ${timeoutMs}ms (round ${round})`
|
|
12942
|
+
`LLM request timed out after ${timeoutMs}ms without new output (idle window, round ${round})`
|
|
12877
12943
|
);
|
|
12878
12944
|
timeoutError.code = LLM_REQUEST_TIMEOUT;
|
|
12879
12945
|
throw timeoutError;
|
|
@@ -12917,16 +12983,16 @@ async function runCompleteWithTimeout(args2) {
|
|
|
12917
12983
|
});
|
|
12918
12984
|
}
|
|
12919
12985
|
}
|
|
12920
|
-
function
|
|
12986
|
+
function clip(value, max4 = 240) {
|
|
12921
12987
|
return clipCompactText(value, max4);
|
|
12922
12988
|
}
|
|
12923
12989
|
function projectSafeToolObservationMetadata(metadata) {
|
|
12924
12990
|
if (!metadata || typeof metadata !== "object") return void 0;
|
|
12925
12991
|
const safe = {};
|
|
12926
12992
|
if (typeof metadata.exitCode === "number") safe.exitCode = metadata.exitCode;
|
|
12927
|
-
if (typeof metadata.actionGate === "string") safe.actionGate =
|
|
12928
|
-
if (typeof metadata.command === "string") safe.command =
|
|
12929
|
-
if (typeof metadata.path === "string") safe.path =
|
|
12993
|
+
if (typeof metadata.actionGate === "string") safe.actionGate = clip(metadata.actionGate, 240);
|
|
12994
|
+
if (typeof metadata.command === "string") safe.command = clip(metadata.command, 240);
|
|
12995
|
+
if (typeof metadata.path === "string") safe.path = clip(metadata.path, 240);
|
|
12930
12996
|
if (typeof metadata.truncated === "boolean") safe.truncated = metadata.truncated;
|
|
12931
12997
|
if (typeof metadata.byteCount === "number") safe.byteCount = metadata.byteCount;
|
|
12932
12998
|
if (typeof metadata.lineCount === "number") safe.lineCount = metadata.lineCount;
|
|
@@ -12942,7 +13008,7 @@ function summarizeToolResult(content, metadata) {
|
|
|
12942
13008
|
const lines = trimmed.split(/\r?\n/).length;
|
|
12943
13009
|
parts2.push(`${lines} line${lines === 1 ? "" : "s"}`);
|
|
12944
13010
|
parts2.push(`${trimmed.length} chars`);
|
|
12945
|
-
const tail =
|
|
13011
|
+
const tail = clip(trimmed.slice(-160), 160);
|
|
12946
13012
|
if (tail) parts2.push(`tail="${tail}"`);
|
|
12947
13013
|
} else {
|
|
12948
13014
|
parts2.push("empty");
|
|
@@ -13554,6 +13620,9 @@ async function runLocalAgentTurn(input) {
|
|
|
13554
13620
|
input.contextBlockScopes
|
|
13555
13621
|
);
|
|
13556
13622
|
const mergedContextBlockScopes = [
|
|
13623
|
+
// 删除安全红线:系统层最高优先级约束,位于所有块之前(含身份信息块),
|
|
13624
|
+
// owner 要求常驻「根本提示词」的最顶部(2026-09-26 批量误删事故)。
|
|
13625
|
+
{ content: DELETE_SAFETY_RED_LINE, cacheScope: "session" },
|
|
13557
13626
|
{ content: identityBlock, cacheScope: "session" },
|
|
13558
13627
|
...guidanceScopes,
|
|
13559
13628
|
...callerScopes
|
|
@@ -13586,20 +13655,40 @@ async function runLocalAgentTurn(input) {
|
|
|
13586
13655
|
}
|
|
13587
13656
|
}
|
|
13588
13657
|
let compactionUsage;
|
|
13658
|
+
const emitCompactionPhase = (phase, scope3) => {
|
|
13659
|
+
const atMs = Date.now();
|
|
13660
|
+
if (phase.kind === "validating-context") emitLoopEvent(observationBoundary, { kind: "turn-phase", phase: "validating-context", atMs, compactionScope: scope3 });
|
|
13661
|
+
else if (phase.kind === "compaction-start") {
|
|
13662
|
+
emitLoopEvent(observationBoundary, { kind: "turn-phase", phase: "compacting", atMs, compactionScope: scope3 });
|
|
13663
|
+
emitLoopEvent(observationBoundary, { kind: "compaction-start", atMs, scope: scope3 });
|
|
13664
|
+
} else if (phase.kind === "waiting-provider") emitLoopEvent(observationBoundary, { kind: "turn-phase", phase: "waiting-provider", atMs, compactionScope: scope3 });
|
|
13665
|
+
else if (phase.kind === "compaction-end") emitLoopEvent(observationBoundary, { kind: "compaction-end", atMs, scope: scope3 });
|
|
13666
|
+
else emitLoopEvent(observationBoundary, { kind: "compaction-failed", atMs, scope: scope3, reason: phase.reason });
|
|
13667
|
+
};
|
|
13589
13668
|
const emitCompactionObservation = (compacted) => {
|
|
13590
|
-
|
|
13591
|
-
|
|
13592
|
-
|
|
13593
|
-
|
|
13594
|
-
|
|
13595
|
-
summaryGenerated: compacted.summaryGenerated,
|
|
13596
|
-
compressed: compacted.compressed,
|
|
13597
|
-
...compacted.failureMessage ? { failed: true, detail: compacted.failureMessage } : {},
|
|
13598
|
-
...compacted.beforeTokens !== void 0 ? { beforeTokens: compacted.beforeTokens } : {},
|
|
13599
|
-
...compacted.afterTokens !== void 0 ? { afterTokens: compacted.afterTokens } : {},
|
|
13600
|
-
...compacted.savedTokens !== void 0 ? { savedTokens: compacted.savedTokens } : {}
|
|
13601
|
-
});
|
|
13669
|
+
const decision = compacted.decision;
|
|
13670
|
+
if (decision?.outcome === "skipped") {
|
|
13671
|
+
const isProtectionGap = decision.skipReason === "adapter-missing-summary-methods" || decision.skipReason === "load-summary-failed";
|
|
13672
|
+
const approachingBudget = decision.skipReason === "below-trigger" && typeof decision.estimatedTokens === "number" && typeof decision.historyBudget === "number" && decision.historyBudget > 0 && decision.estimatedTokens >= decision.historyBudget * 0.5;
|
|
13673
|
+
if (!isProtectionGap && !approachingBudget) return;
|
|
13602
13674
|
}
|
|
13675
|
+
emitLoopEvent(observationBoundary, {
|
|
13676
|
+
kind: "compaction",
|
|
13677
|
+
atMs: Date.now(),
|
|
13678
|
+
...compacted.reason ? { reason: compacted.reason } : {},
|
|
13679
|
+
summaryGenerated: compacted.summaryGenerated,
|
|
13680
|
+
compressed: compacted.compressed,
|
|
13681
|
+
...compacted.failureMessage ? { failed: true, detail: compacted.failureMessage } : {},
|
|
13682
|
+
...decision?.outcome === "skipped" ? { skipped: true, skipReason: decision.skipReason } : {},
|
|
13683
|
+
...decision && "trigger" in decision && decision.trigger ? { trigger: decision.trigger } : {},
|
|
13684
|
+
...decision && "estimatedTokens" in decision && decision.estimatedTokens !== void 0 ? { estimatedTokens: decision.estimatedTokens } : {},
|
|
13685
|
+
...decision && "historyBudget" in decision && decision.historyBudget !== void 0 ? { historyBudget: decision.historyBudget } : {},
|
|
13686
|
+
...decision && "realUsageRatio" in decision && decision.realUsageRatio !== void 0 ? { realUsageRatio: decision.realUsageRatio } : {},
|
|
13687
|
+
...decision && "triggerRatio" in decision && decision.triggerRatio !== void 0 ? { triggerRatio: decision.triggerRatio } : {},
|
|
13688
|
+
...compacted.beforeTokens !== void 0 ? { beforeTokens: compacted.beforeTokens } : {},
|
|
13689
|
+
...compacted.afterTokens !== void 0 ? { afterTokens: compacted.afterTokens } : {},
|
|
13690
|
+
...compacted.savedTokens !== void 0 ? { savedTokens: compacted.savedTokens } : {}
|
|
13691
|
+
});
|
|
13603
13692
|
};
|
|
13604
13693
|
try {
|
|
13605
13694
|
const compacted = await maybeAutoCompactLocalHistory({
|
|
@@ -13609,7 +13698,10 @@ async function runLocalAgentTurn(input) {
|
|
|
13609
13698
|
model: agentConfig.model,
|
|
13610
13699
|
resolveProvider: resolveProviderOnce,
|
|
13611
13700
|
contextWindow,
|
|
13612
|
-
realContextUsagePercent
|
|
13701
|
+
realContextUsagePercent,
|
|
13702
|
+
abortSignal: input.abortSignal,
|
|
13703
|
+
timeoutMs: resolveCompactionTimeoutMs(input),
|
|
13704
|
+
onPhase: (phase) => emitCompactionPhase(phase, "initial")
|
|
13613
13705
|
});
|
|
13614
13706
|
history = compacted.history;
|
|
13615
13707
|
compactionUsage = compacted.usage;
|
|
@@ -13680,17 +13772,26 @@ async function runLocalAgentTurn(input) {
|
|
|
13680
13772
|
let skipFinalAppend = false;
|
|
13681
13773
|
let partialContent = "";
|
|
13682
13774
|
const progressGuard = createLocalLoopProgressGuard(input.progressGuardConfig);
|
|
13775
|
+
let ephemeralSummary = null;
|
|
13776
|
+
const ephemeralDialogId = `ephemeral-${crypto.randomUUID()}`;
|
|
13777
|
+
const compactionAdapter = input.continueDialogId ? input.adapter : {
|
|
13778
|
+
...input.adapter,
|
|
13779
|
+
loadDialogSummary: async () => ephemeralSummary,
|
|
13780
|
+
saveDialogSummary: async (summaryInput) => {
|
|
13781
|
+
ephemeralSummary = summaryInput;
|
|
13782
|
+
}
|
|
13783
|
+
};
|
|
13784
|
+
const compactionDialogId = input.continueDialogId ?? ephemeralDialogId;
|
|
13683
13785
|
const maybeCompactInLoop = async () => {
|
|
13684
|
-
|
|
13685
|
-
|
|
13686
|
-
|
|
13687
|
-
|
|
13688
|
-
|
|
13689
|
-
if (ratio < compressionTriggerRatio) return;
|
|
13786
|
+
const inputTokens = contextUsage ? normalizeUsage(contextUsage).input_tokens : 0;
|
|
13787
|
+
const ratio = inputTokens > 0 ? Math.min(1, inputTokens / contextWindow) : void 0;
|
|
13788
|
+
if (ratio !== void 0 && ratio < compressionTriggerRatio * 0.85) {
|
|
13789
|
+
return;
|
|
13790
|
+
}
|
|
13690
13791
|
try {
|
|
13691
13792
|
const compacted = await maybeAutoCompactLocalHistory({
|
|
13692
|
-
adapter:
|
|
13693
|
-
dialogId:
|
|
13793
|
+
adapter: compactionAdapter,
|
|
13794
|
+
dialogId: compactionDialogId,
|
|
13694
13795
|
// canonical 坐标:store 全量历史 + 本轮消息的「持久化形态」
|
|
13695
13796
|
// (applyPersistedTurnInput 会把首条 user 消息换成 paste 展开形态)。
|
|
13696
13797
|
// 锚点与 sourceHash 都必须按持久化形态计算——否则下轮从 store
|
|
@@ -13706,7 +13807,10 @@ async function runLocalAgentTurn(input) {
|
|
|
13706
13807
|
model: agentConfig.model,
|
|
13707
13808
|
resolveProvider: resolveProviderOnce,
|
|
13708
13809
|
contextWindow,
|
|
13709
|
-
realContextUsagePercent: ratio
|
|
13810
|
+
...ratio !== void 0 ? { realContextUsagePercent: ratio } : {},
|
|
13811
|
+
abortSignal: input.abortSignal,
|
|
13812
|
+
timeoutMs: resolveCompactionTimeoutMs(input),
|
|
13813
|
+
onPhase: (phase) => emitCompactionPhase(phase, "in-loop")
|
|
13710
13814
|
});
|
|
13711
13815
|
if (compacted.usage) {
|
|
13712
13816
|
compactionUsage = addOutOfBandUsage(compactionUsage, compacted.usage);
|
|
@@ -13776,11 +13880,12 @@ async function runLocalAgentTurn(input) {
|
|
|
13776
13880
|
const shouldPassToolEvents = Boolean(
|
|
13777
13881
|
input.onToolEvent || input.onObservationEvent || input.observationBoundary
|
|
13778
13882
|
);
|
|
13883
|
+
let llmStreamActivity = 0;
|
|
13779
13884
|
result4 = await runCompleteWithTimeout({
|
|
13780
13885
|
provider,
|
|
13781
13886
|
messages: requestMessages,
|
|
13782
13887
|
options: {
|
|
13783
|
-
|
|
13888
|
+
timeoutMs: resolveLlmRequestTimeoutMs(input),
|
|
13784
13889
|
// 用户取消信号穿进 provider options:providerStreamRetry 据此在
|
|
13785
13890
|
// 取消后跳过重试,provider 分支(如 antigravity/openai-compatible)
|
|
13786
13891
|
// 也可把 fetch 绑定到同一信号,实现真正的传输层取消。
|
|
@@ -13789,6 +13894,7 @@ async function runLocalAgentTurn(input) {
|
|
|
13789
13894
|
// 归到具体对话而不是 chat-proxy 兜底桶。新对话首轮 id 尚未分配。
|
|
13790
13895
|
...input.continueDialogId ? { dialogId: input.continueDialogId } : {},
|
|
13791
13896
|
...shouldStreamDeltas ? { onTextDelta: (chunk) => {
|
|
13897
|
+
llmStreamActivity += 1;
|
|
13792
13898
|
partialContent += chunk;
|
|
13793
13899
|
observationBoundary.emit({
|
|
13794
13900
|
kind: "text-delta",
|
|
@@ -13798,6 +13904,7 @@ async function runLocalAgentTurn(input) {
|
|
|
13798
13904
|
});
|
|
13799
13905
|
} } : {},
|
|
13800
13906
|
...shouldStreamReasoning ? { onReasoningDelta: (chunk) => {
|
|
13907
|
+
llmStreamActivity += 1;
|
|
13801
13908
|
observationBoundary.emit({
|
|
13802
13909
|
kind: "reasoning-delta",
|
|
13803
13910
|
chunk,
|
|
@@ -13806,6 +13913,7 @@ async function runLocalAgentTurn(input) {
|
|
|
13806
13913
|
});
|
|
13807
13914
|
} } : {},
|
|
13808
13915
|
...shouldPassToolEvents ? { onToolEvent: (event) => {
|
|
13916
|
+
llmStreamActivity += 1;
|
|
13809
13917
|
observationBoundary.emit({
|
|
13810
13918
|
kind: "tool-event",
|
|
13811
13919
|
event,
|
|
@@ -13816,6 +13924,7 @@ async function runLocalAgentTurn(input) {
|
|
|
13816
13924
|
...shouldPassToolEvents ? { toolEventRound: round } : {}
|
|
13817
13925
|
},
|
|
13818
13926
|
timeoutMs: resolveLlmRequestTimeoutMs(input),
|
|
13927
|
+
activityVersion: () => llmStreamActivity,
|
|
13819
13928
|
round,
|
|
13820
13929
|
input,
|
|
13821
13930
|
boundary: observationBoundary,
|
|
@@ -14287,33 +14396,6 @@ ${reasoningTailLog}
|
|
|
14287
14396
|
}
|
|
14288
14397
|
}
|
|
14289
14398
|
|
|
14290
|
-
// packages/agent-runtime/kimiUserAgent.ts
|
|
14291
|
-
var KIMI_CODE_CLI_VERSION = "0.29.2";
|
|
14292
|
-
var KIMI_CODE_USER_AGENT = `kimi-code-cli/${KIMI_CODE_CLI_VERSION} (nolo)`;
|
|
14293
|
-
function isKimiEndpoint(url) {
|
|
14294
|
-
return url.includes("api.kimi.com");
|
|
14295
|
-
}
|
|
14296
|
-
function kimiIdentityHeaders(url) {
|
|
14297
|
-
return isKimiEndpoint(url) ? { "User-Agent": KIMI_CODE_USER_AGENT } : {};
|
|
14298
|
-
}
|
|
14299
|
-
|
|
14300
|
-
// packages/agent-runtime/sseDataLine.ts
|
|
14301
|
-
function parseSseDataLineJson(line) {
|
|
14302
|
-
const trimmed = line.trim();
|
|
14303
|
-
if (!trimmed.startsWith("data:")) return null;
|
|
14304
|
-
const payload = trimmed.slice(5).trim();
|
|
14305
|
-
if (!payload || payload === "[DONE]") return null;
|
|
14306
|
-
try {
|
|
14307
|
-
return JSON.parse(payload);
|
|
14308
|
-
} catch {
|
|
14309
|
-
return null;
|
|
14310
|
-
}
|
|
14311
|
-
}
|
|
14312
|
-
function parseSseDataLineObject(line) {
|
|
14313
|
-
const parsed = parseSseDataLineJson(line);
|
|
14314
|
-
return parsed && typeof parsed === "object" ? parsed : null;
|
|
14315
|
-
}
|
|
14316
|
-
|
|
14317
14399
|
// packages/integrations/openai/responsesRequestBody.ts
|
|
14318
14400
|
function buildResponsesRequestBody(body, model) {
|
|
14319
14401
|
const tools = Array.isArray(body.tools) ? toResponsesTools(body.tools) : void 0;
|
|
@@ -14536,9 +14618,9 @@ function buildOpenAiCompatibleChatCompletionRequest(args2) {
|
|
|
14536
14618
|
...buildProviderAuthHeaders({
|
|
14537
14619
|
endpoint,
|
|
14538
14620
|
apiKey: args2.providerConfig.apiKey,
|
|
14539
|
-
apiKeyHeader: args2.providerConfig.apiKeyHeader
|
|
14540
|
-
|
|
14541
|
-
|
|
14621
|
+
apiKeyHeader: args2.providerConfig.apiKeyHeader,
|
|
14622
|
+
sessionId: args2.sessionId
|
|
14623
|
+
})
|
|
14542
14624
|
};
|
|
14543
14625
|
return {
|
|
14544
14626
|
url: endpoint,
|
|
@@ -14641,7 +14723,8 @@ async function executeOpenAiCompatibleChatCompletion(args2) {
|
|
|
14641
14723
|
providerConfig: apiKey2 === args2.providerConfig.apiKey ? args2.providerConfig : { ...args2.providerConfig, apiKey: apiKey2 },
|
|
14642
14724
|
messages: args2.messages,
|
|
14643
14725
|
tools: args2.tools,
|
|
14644
|
-
stream: args2.stream
|
|
14726
|
+
stream: args2.stream,
|
|
14727
|
+
sessionId: args2.sessionId
|
|
14645
14728
|
});
|
|
14646
14729
|
return args2.fetchImpl(request3.url, {
|
|
14647
14730
|
...request3.init,
|
|
@@ -15583,132 +15666,6 @@ async function evaluateCapabilityPolicy(capability, normalizedInput, ctx) {
|
|
|
15583
15666
|
}
|
|
15584
15667
|
}
|
|
15585
15668
|
|
|
15586
|
-
// packages/agent-runtime/localToolPolicy.ts
|
|
15587
|
-
var NEVER_LOCAL_TOOLS = /* @__PURE__ */ new Set([
|
|
15588
|
-
"deleteSpaces",
|
|
15589
|
-
"updateAgent",
|
|
15590
|
-
"updateSelf",
|
|
15591
|
-
"createAgent"
|
|
15592
|
-
]);
|
|
15593
|
-
var DEFAULT_LOCAL_TOOLS = /* @__PURE__ */ new Set([
|
|
15594
|
-
"readFile",
|
|
15595
|
-
"writeFile",
|
|
15596
|
-
"editFile",
|
|
15597
|
-
"globFiles",
|
|
15598
|
-
"execShell",
|
|
15599
|
-
"launchProcess",
|
|
15600
|
-
"listProcesses",
|
|
15601
|
-
// ProcessTask follow-up tools. Same tier as listProcesses: they observe/stop
|
|
15602
|
-
// tasks the agent itself already spawned, so their blast radius is strictly
|
|
15603
|
-
// narrower than launchProcess (which is default-enabled). Model-facing
|
|
15604
|
-
// follow-ups are taskWait/taskStop only — lifecycle history (taskLogs) stays
|
|
15605
|
-
// runtime-internal.
|
|
15606
|
-
"taskWait",
|
|
15607
|
-
"taskStop",
|
|
15608
|
-
// Scheduling tools: forking/observing sub-agents is a declared capability
|
|
15609
|
-
// of capable agents, and the blast radius is strictly narrower than
|
|
15610
|
-
// execShell (already default-enabled). Requiring an env allowlist for these
|
|
15611
|
-
// while execShell is open by default inverted the risk model and forced every
|
|
15612
|
-
// new local user to hand-edit .env files before sub-agent tasks worked.
|
|
15613
|
-
"startAgentRun",
|
|
15614
|
-
"controlAgentRun"
|
|
15615
|
-
]);
|
|
15616
|
-
function parseToolAllowlist(value) {
|
|
15617
|
-
return (value ?? "").split(",").flatMap((item) => {
|
|
15618
|
-
const trimmed = item.trim();
|
|
15619
|
-
return trimmed ? [trimmed] : [];
|
|
15620
|
-
});
|
|
15621
|
-
}
|
|
15622
|
-
function normalizeLocalToolName(toolName) {
|
|
15623
|
-
return canonicalizeToolName(
|
|
15624
|
-
String(toolName ?? "").replace(/^functions\./, "").trim()
|
|
15625
|
-
);
|
|
15626
|
-
}
|
|
15627
|
-
function isRestrictedLocalToolMode(env) {
|
|
15628
|
-
return env.NOLO_LOCAL_TOOL_MODE === "restricted";
|
|
15629
|
-
}
|
|
15630
|
-
function resolveLocalToolPolicy(args2) {
|
|
15631
|
-
const toolName = normalizeLocalToolName(args2.toolName);
|
|
15632
|
-
const restrictedMode = isRestrictedLocalToolMode(args2.env);
|
|
15633
|
-
if (!toolName) {
|
|
15634
|
-
return {
|
|
15635
|
-
allowed: false,
|
|
15636
|
-
toolName,
|
|
15637
|
-
reason: "Tool name is required."
|
|
15638
|
-
};
|
|
15639
|
-
}
|
|
15640
|
-
if (NEVER_LOCAL_TOOLS.has(toolName)) {
|
|
15641
|
-
return {
|
|
15642
|
-
allowed: false,
|
|
15643
|
-
toolName,
|
|
15644
|
-
reason: `${toolName} is blocked by the local runtime safety policy.`
|
|
15645
|
-
};
|
|
15646
|
-
}
|
|
15647
|
-
const allowedByEnv = new Set(parseToolAllowlist(args2.env.NOLO_LOCAL_ALLOWED_TOOLS));
|
|
15648
|
-
const agentTools = new Set(
|
|
15649
|
-
(args2.agentToolNames ?? []).flatMap((item) => {
|
|
15650
|
-
const normalized = normalizeLocalToolName(item);
|
|
15651
|
-
return normalized ? [normalized] : [];
|
|
15652
|
-
})
|
|
15653
|
-
);
|
|
15654
|
-
if (!restrictedMode && agentTools.has(toolName)) {
|
|
15655
|
-
return { allowed: true, toolName };
|
|
15656
|
-
}
|
|
15657
|
-
if (DEFAULT_LOCAL_TOOLS.has(toolName) && agentTools.has(toolName)) {
|
|
15658
|
-
return { allowed: true, toolName };
|
|
15659
|
-
}
|
|
15660
|
-
if (allowedByEnv.has(toolName) && agentTools.has(toolName)) {
|
|
15661
|
-
return { allowed: true, toolName };
|
|
15662
|
-
}
|
|
15663
|
-
return {
|
|
15664
|
-
allowed: false,
|
|
15665
|
-
toolName,
|
|
15666
|
-
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.`
|
|
15667
|
-
};
|
|
15668
|
-
}
|
|
15669
|
-
async function executeLocalToolWithPolicy(args2) {
|
|
15670
|
-
if (args2.runToolNames !== void 0 && !args2.runToolNames.includes(normalizeLocalToolName(args2.call.name))) {
|
|
15671
|
-
throw new Error(`${args2.call.name} is outside the final run tool surface.`);
|
|
15672
|
-
}
|
|
15673
|
-
const decision = resolveLocalToolPolicy({
|
|
15674
|
-
env: args2.env,
|
|
15675
|
-
agentToolNames: args2.agentToolNames,
|
|
15676
|
-
toolName: args2.call.name
|
|
15677
|
-
});
|
|
15678
|
-
if (!decision.allowed) throw new Error(decision.reason);
|
|
15679
|
-
const executor = args2.executors?.[decision.toolName];
|
|
15680
|
-
if (!executor) {
|
|
15681
|
-
throw new Error(`${decision.toolName} is allowed by policy but no local executor is registered.`);
|
|
15682
|
-
}
|
|
15683
|
-
const opts = {
|
|
15684
|
-
...args2.abortSignal ? { abortSignal: args2.abortSignal } : {},
|
|
15685
|
-
...args2.detachMs !== void 0 ? { detachMs: args2.detachMs } : {},
|
|
15686
|
-
...args2.confirmed !== void 0 ? { confirmed: args2.confirmed } : {},
|
|
15687
|
-
...args2.enableDestructiveShellGuard !== void 0 ? { enableDestructiveShellGuard: args2.enableDestructiveShellGuard } : {},
|
|
15688
|
-
...args2.confirmDestructiveAction ? { confirmDestructiveAction: args2.confirmDestructiveAction } : {},
|
|
15689
|
-
...args2.blockDestructiveWithoutConfirmation !== void 0 ? { blockDestructiveWithoutConfirmation: args2.blockDestructiveWithoutConfirmation } : {}
|
|
15690
|
-
};
|
|
15691
|
-
if (decision.toolName === "execShell") {
|
|
15692
|
-
let parsedInput = args2.call.arguments;
|
|
15693
|
-
if (typeof parsedInput === "string") {
|
|
15694
|
-
try {
|
|
15695
|
-
parsedInput = JSON.parse(parsedInput);
|
|
15696
|
-
} catch {
|
|
15697
|
-
parsedInput = { command: parsedInput };
|
|
15698
|
-
}
|
|
15699
|
-
}
|
|
15700
|
-
await evaluateExecShellDestructiveGuard(parsedInput, opts);
|
|
15701
|
-
opts.confirmed = true;
|
|
15702
|
-
}
|
|
15703
|
-
return executor(
|
|
15704
|
-
{
|
|
15705
|
-
...args2.call,
|
|
15706
|
-
name: decision.toolName
|
|
15707
|
-
},
|
|
15708
|
-
opts
|
|
15709
|
-
);
|
|
15710
|
-
}
|
|
15711
|
-
|
|
15712
15669
|
// packages/agent-runtime/localWorkspaceTools.ts
|
|
15713
15670
|
import { existsSync as existsSync3 } from "node:fs";
|
|
15714
15671
|
import { createHash as createHash3 } from "node:crypto";
|
|
@@ -16507,29 +16464,6 @@ function getProcessRegistry() {
|
|
|
16507
16464
|
return registry;
|
|
16508
16465
|
}
|
|
16509
16466
|
|
|
16510
|
-
// packages/agent-runtime/processOwnership.ts
|
|
16511
|
-
var asNonEmptyString = (value) => {
|
|
16512
|
-
if (typeof value !== "string") return null;
|
|
16513
|
-
const trimmed = value.trim();
|
|
16514
|
-
return trimmed ? trimmed : null;
|
|
16515
|
-
};
|
|
16516
|
-
function readProcessOwner(runtimeContext) {
|
|
16517
|
-
if (!runtimeContext || typeof runtimeContext !== "object") return null;
|
|
16518
|
-
const dialogId = asNonEmptyString(runtimeContext.dialogId) ?? asNonEmptyString(runtimeContext.parentThreadId);
|
|
16519
|
-
if (!dialogId) return null;
|
|
16520
|
-
const turnId = asNonEmptyString(runtimeContext.turnId);
|
|
16521
|
-
const ownerId = asNonEmptyString(runtimeContext.ownerId);
|
|
16522
|
-
return {
|
|
16523
|
-
dialogId,
|
|
16524
|
-
...turnId ? { turnId } : {},
|
|
16525
|
-
...ownerId ? { ownerId } : {}
|
|
16526
|
-
};
|
|
16527
|
-
}
|
|
16528
|
-
|
|
16529
|
-
// packages/agent-runtime/workspaceShell.ts
|
|
16530
|
-
import { resolve as resolve3 } from "node:path";
|
|
16531
|
-
import { spawn as spawnChildProcess2 } from "node:child_process";
|
|
16532
|
-
|
|
16533
16467
|
// packages/agent-runtime/processTaskResult.ts
|
|
16534
16468
|
var PROCESS_RESULT_CAPSULE_TAIL_CHARS = 4e3;
|
|
16535
16469
|
var PROCESS_RESULT_CAPSULE_SPILL_THRESHOLD_CHARS = 2e4;
|
|
@@ -16549,11 +16483,17 @@ function buildProcessTaskResultCapsule(args2) {
|
|
|
16549
16483
|
const exitCode = args2.exitCode;
|
|
16550
16484
|
const captureError = args2.captureError?.trim() || void 0;
|
|
16551
16485
|
const durationMs = typeof args2.startedAt === "number" && Number.isFinite(args2.startedAt) ? Math.max(0, (args2.endedAt ?? Date.now()) - args2.startedAt) : void 0;
|
|
16552
|
-
const
|
|
16553
|
-
const
|
|
16486
|
+
const stdoutProvenance = args2.streamProvenance?.stdout;
|
|
16487
|
+
const stderrProvenance = args2.streamProvenance?.stderr;
|
|
16488
|
+
const ringEvicted = Boolean(stdoutProvenance?.evicted || stderrProvenance?.evicted);
|
|
16489
|
+
const stdoutTailSource = typeof args2.stdoutTail === "string" ? args2.stdoutTail : stdout;
|
|
16490
|
+
const stderrTailSource = typeof args2.stderrTail === "string" ? args2.stderrTail : stderr;
|
|
16491
|
+
const stdoutTail = tailText(stdoutTailSource, tailChars);
|
|
16492
|
+
const stderrTail = tailText(stderrTailSource, tailChars);
|
|
16554
16493
|
const inlineSize = stdout.length + stderr.length;
|
|
16555
16494
|
const inlineTruncated = stdoutTail.truncated || stderrTail.truncated;
|
|
16556
|
-
const
|
|
16495
|
+
const truncated = inlineTruncated || ringEvicted || Boolean(captureError);
|
|
16496
|
+
const shouldSpill = truncated || inlineSize > spillThresholdChars;
|
|
16557
16497
|
let spill;
|
|
16558
16498
|
if (shouldSpill) {
|
|
16559
16499
|
try {
|
|
@@ -16567,8 +16507,11 @@ function buildProcessTaskResultCapsule(args2) {
|
|
|
16567
16507
|
});
|
|
16568
16508
|
spill = {
|
|
16569
16509
|
displayPath: result4.displayPath,
|
|
16570
|
-
|
|
16571
|
-
|
|
16510
|
+
// Prefer the caller's live provenance counters: they count every
|
|
16511
|
+
// byte of the original stream, while the buffered content above may
|
|
16512
|
+
// be a capped prefix of it.
|
|
16513
|
+
totalChars: (stdoutProvenance?.totalChars ?? stdout.length) + (stderrProvenance?.totalChars ?? stderr.length),
|
|
16514
|
+
totalLines: (stdoutProvenance?.totalLines ?? countLines(stdout)) + (stderrProvenance?.totalLines ?? countLines(stderr))
|
|
16572
16515
|
};
|
|
16573
16516
|
} catch {
|
|
16574
16517
|
}
|
|
@@ -16579,12 +16522,33 @@ function buildProcessTaskResultCapsule(args2) {
|
|
|
16579
16522
|
exitCode,
|
|
16580
16523
|
...durationMs !== void 0 ? { durationMs } : {},
|
|
16581
16524
|
...captureError ? { captureError } : {},
|
|
16582
|
-
truncated
|
|
16525
|
+
truncated,
|
|
16583
16526
|
...spill ? { spill } : {}
|
|
16584
16527
|
};
|
|
16585
16528
|
}
|
|
16586
16529
|
|
|
16530
|
+
// packages/agent-runtime/processOwnership.ts
|
|
16531
|
+
var asNonEmptyString = (value) => {
|
|
16532
|
+
if (typeof value !== "string") return null;
|
|
16533
|
+
const trimmed = value.trim();
|
|
16534
|
+
return trimmed ? trimmed : null;
|
|
16535
|
+
};
|
|
16536
|
+
function readProcessOwner(runtimeContext) {
|
|
16537
|
+
if (!runtimeContext || typeof runtimeContext !== "object") return null;
|
|
16538
|
+
const dialogId = asNonEmptyString(runtimeContext.dialogId) ?? asNonEmptyString(runtimeContext.parentThreadId);
|
|
16539
|
+
if (!dialogId) return null;
|
|
16540
|
+
const turnId = asNonEmptyString(runtimeContext.turnId);
|
|
16541
|
+
const ownerId = asNonEmptyString(runtimeContext.ownerId);
|
|
16542
|
+
return {
|
|
16543
|
+
dialogId,
|
|
16544
|
+
...turnId ? { turnId } : {},
|
|
16545
|
+
...ownerId ? { ownerId } : {}
|
|
16546
|
+
};
|
|
16547
|
+
}
|
|
16548
|
+
|
|
16587
16549
|
// packages/agent-runtime/workspaceShell.ts
|
|
16550
|
+
import { resolve as resolve3 } from "node:path";
|
|
16551
|
+
import { spawn as spawnChildProcess2 } from "node:child_process";
|
|
16588
16552
|
var EXEC_SHELL_TIMEOUT_ENV = "NOLO_EXEC_SHELL_TIMEOUT_MS";
|
|
16589
16553
|
var EXEC_SHELL_DETACH_ENV = "NOLO_EXEC_SHELL_DETACH_MS";
|
|
16590
16554
|
var DEFAULT_EXEC_SHELL_DETACH_MS = 12e4;
|
|
@@ -17453,13 +17417,169 @@ function runTasks(args2) {
|
|
|
17453
17417
|
return { tasks, count: tasks.length };
|
|
17454
17418
|
}
|
|
17455
17419
|
|
|
17456
|
-
// packages/agent-runtime/
|
|
17457
|
-
|
|
17458
|
-
|
|
17420
|
+
// packages/agent-runtime/execShellCompletionWarnings.ts
|
|
17421
|
+
var BG_ESCAPE_WORD_PATTERN = /(?:^|[\s;|(&/\\])(nohup|disown|setsid|start-process)(?=$|[\s;|)&])/i;
|
|
17422
|
+
var SHELL_SPLIT_CHARS = /* @__PURE__ */ new Set([";", "|", "&", "(", ")", "<", ">", "\n", " ", " "]);
|
|
17423
|
+
function maskQuotedAndEscaped(command) {
|
|
17424
|
+
const out = Array.from(command);
|
|
17425
|
+
let quote = null;
|
|
17426
|
+
for (let i = 0; i < out.length; i += 1) {
|
|
17427
|
+
const ch = out[i];
|
|
17428
|
+
if (quote) {
|
|
17429
|
+
out[i] = " ";
|
|
17430
|
+
if (ch === "\\" && quote !== "'") {
|
|
17431
|
+
if (i + 1 < out.length) out[i + 1] = " ";
|
|
17432
|
+
i += 1;
|
|
17433
|
+
} else if (ch === quote) {
|
|
17434
|
+
quote = null;
|
|
17435
|
+
}
|
|
17436
|
+
continue;
|
|
17437
|
+
}
|
|
17438
|
+
if (ch === "\\") {
|
|
17439
|
+
out[i] = " ";
|
|
17440
|
+
if (i + 1 < out.length) out[i + 1] = " ";
|
|
17441
|
+
i += 1;
|
|
17442
|
+
continue;
|
|
17443
|
+
}
|
|
17444
|
+
if (ch === "'" || ch === '"' || ch === "`") {
|
|
17445
|
+
quote = ch;
|
|
17446
|
+
out[i] = " ";
|
|
17447
|
+
continue;
|
|
17448
|
+
}
|
|
17449
|
+
if (ch === "#" && (i === 0 || /[\s;]/.test(out[i - 1] ?? " "))) {
|
|
17450
|
+
while (i < out.length && out[i] !== "\n") {
|
|
17451
|
+
out[i] = " ";
|
|
17452
|
+
i += 1;
|
|
17453
|
+
}
|
|
17454
|
+
}
|
|
17455
|
+
}
|
|
17456
|
+
return out.join("");
|
|
17457
|
+
}
|
|
17458
|
+
function readRedirectTarget(original, start) {
|
|
17459
|
+
let i = start;
|
|
17460
|
+
while (i < original.length && /\s/.test(original[i] ?? "")) {
|
|
17461
|
+
i += 1;
|
|
17462
|
+
}
|
|
17463
|
+
if (i >= original.length) return void 0;
|
|
17464
|
+
let text = "";
|
|
17465
|
+
let j = i;
|
|
17466
|
+
while (j < original.length) {
|
|
17467
|
+
const o = original[j];
|
|
17468
|
+
if (o === "'" || o === '"' || o === "`") {
|
|
17469
|
+
const quote = o;
|
|
17470
|
+
j += 1;
|
|
17471
|
+
while (j < original.length && original[j] !== quote) {
|
|
17472
|
+
if (original[j] === "\\" && quote !== "'" && j + 1 < original.length) {
|
|
17473
|
+
text += original[j + 1];
|
|
17474
|
+
j += 2;
|
|
17475
|
+
continue;
|
|
17476
|
+
}
|
|
17477
|
+
text += original[j];
|
|
17478
|
+
j += 1;
|
|
17479
|
+
}
|
|
17480
|
+
j += 1;
|
|
17481
|
+
continue;
|
|
17482
|
+
}
|
|
17483
|
+
if (/\s/.test(o) || SHELL_SPLIT_CHARS.has(o)) break;
|
|
17484
|
+
text += o;
|
|
17485
|
+
j += 1;
|
|
17486
|
+
}
|
|
17487
|
+
if (!text || text === "$") return void 0;
|
|
17488
|
+
return { text, end: j };
|
|
17489
|
+
}
|
|
17490
|
+
function isIgnoredRedirectTarget(target) {
|
|
17491
|
+
return target === "/dev/null";
|
|
17492
|
+
}
|
|
17493
|
+
function detectExecShellSynchronousWarnings(command, shell) {
|
|
17494
|
+
const masked = maskQuotedAndEscaped(command);
|
|
17495
|
+
const isPowerShell = shell?.resolvedShell === "powershell";
|
|
17496
|
+
const redirectTargets = [];
|
|
17497
|
+
let backgrounded = false;
|
|
17498
|
+
let i = 0;
|
|
17499
|
+
while (i < masked.length) {
|
|
17500
|
+
const ch = masked[i];
|
|
17501
|
+
if (ch === "&") {
|
|
17502
|
+
const next = masked[i + 1];
|
|
17503
|
+
if (next === "&") {
|
|
17504
|
+
i += 2;
|
|
17505
|
+
continue;
|
|
17506
|
+
}
|
|
17507
|
+
if (next === ">") {
|
|
17508
|
+
let j = i + 2;
|
|
17509
|
+
if (masked[j] === ">") j += 1;
|
|
17510
|
+
const target = readRedirectTarget(command, j);
|
|
17511
|
+
if (target && !isIgnoredRedirectTarget(target.text)) redirectTargets.push(target.text);
|
|
17512
|
+
i = target ? target.end : j;
|
|
17513
|
+
continue;
|
|
17514
|
+
}
|
|
17515
|
+
const prev = masked[i - 1];
|
|
17516
|
+
if (prev === ">" || prev === "<") {
|
|
17517
|
+
i += 1;
|
|
17518
|
+
continue;
|
|
17519
|
+
}
|
|
17520
|
+
if (isPowerShell) {
|
|
17521
|
+
i += 1;
|
|
17522
|
+
continue;
|
|
17523
|
+
}
|
|
17524
|
+
backgrounded = true;
|
|
17525
|
+
i += 1;
|
|
17526
|
+
continue;
|
|
17527
|
+
}
|
|
17528
|
+
if (ch === ">") {
|
|
17529
|
+
const prev = masked[i - 1];
|
|
17530
|
+
if (prev === ">" || prev === "&" || prev === "<") {
|
|
17531
|
+
i += 1;
|
|
17532
|
+
continue;
|
|
17533
|
+
}
|
|
17534
|
+
let j = i + 1;
|
|
17535
|
+
if (masked[j] === ">") j += 1;
|
|
17536
|
+
if (masked[j] === "&") {
|
|
17537
|
+
const ampTarget = readRedirectTarget(command, j + 1);
|
|
17538
|
+
const isFdDuplication = ampTarget !== void 0 && (/^\d+$/.test(ampTarget.text) || ampTarget.text === "-");
|
|
17539
|
+
if (ampTarget && !isFdDuplication && !isIgnoredRedirectTarget(ampTarget.text)) {
|
|
17540
|
+
redirectTargets.push(ampTarget.text);
|
|
17541
|
+
}
|
|
17542
|
+
i = ampTarget ? ampTarget.end : j + 1;
|
|
17543
|
+
continue;
|
|
17544
|
+
}
|
|
17545
|
+
const target = readRedirectTarget(command, j);
|
|
17546
|
+
if (target && !isIgnoredRedirectTarget(target.text)) redirectTargets.push(target.text);
|
|
17547
|
+
i = target ? target.end : j;
|
|
17548
|
+
continue;
|
|
17549
|
+
}
|
|
17550
|
+
if (ch === "<") {
|
|
17551
|
+
i += masked[i + 1] === "<" || masked[i + 1] === "&" ? 2 : 1;
|
|
17552
|
+
continue;
|
|
17553
|
+
}
|
|
17554
|
+
i += 1;
|
|
17555
|
+
}
|
|
17556
|
+
const wordMatch = BG_ESCAPE_WORD_PATTERN.exec(masked);
|
|
17557
|
+
if (wordMatch) backgrounded = true;
|
|
17558
|
+
const warnings = [];
|
|
17559
|
+
if (redirectTargets.length > 0) {
|
|
17560
|
+
const target = redirectTargets[0];
|
|
17561
|
+
warnings.push({
|
|
17562
|
+
kind: "output-redirect",
|
|
17563
|
+
redirectTarget: target,
|
|
17564
|
+
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.`
|
|
17565
|
+
});
|
|
17566
|
+
}
|
|
17567
|
+
if (backgrounded) {
|
|
17568
|
+
warnings.push({
|
|
17569
|
+
kind: "shell-backgrounding",
|
|
17570
|
+
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.`
|
|
17571
|
+
});
|
|
17572
|
+
}
|
|
17573
|
+
return warnings;
|
|
17574
|
+
}
|
|
17575
|
+
|
|
17576
|
+
// packages/agent-runtime/capabilities/execShellCapability.ts
|
|
17577
|
+
function buildExecShellToolDefinition(toolName = "execShell") {
|
|
17578
|
+
return {
|
|
17459
17579
|
type: "function",
|
|
17460
17580
|
function: {
|
|
17461
17581
|
name: toolName,
|
|
17462
|
-
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.`,
|
|
17582
|
+
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.`,
|
|
17463
17583
|
parameters: {
|
|
17464
17584
|
type: "object",
|
|
17465
17585
|
properties: {
|
|
@@ -17470,6 +17590,10 @@ function buildExecShellToolDefinition(toolName = "execShell") {
|
|
|
17470
17590
|
cmd: {
|
|
17471
17591
|
type: "string",
|
|
17472
17592
|
description: "Compatibility alias for command."
|
|
17593
|
+
},
|
|
17594
|
+
background: {
|
|
17595
|
+
type: "boolean",
|
|
17596
|
+
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."
|
|
17473
17597
|
}
|
|
17474
17598
|
}
|
|
17475
17599
|
}
|
|
@@ -17510,11 +17634,13 @@ function normalizeExecShellInput(input) {
|
|
|
17510
17634
|
throw new Error("execShell requires a non-empty command.");
|
|
17511
17635
|
}
|
|
17512
17636
|
const activity = extractActivity(record);
|
|
17637
|
+
const background = record.background === true || typeof record.background === "string" && record.background.trim().toLowerCase() === "true";
|
|
17513
17638
|
return {
|
|
17514
17639
|
command,
|
|
17515
17640
|
...record.shell !== void 0 ? { shell: record.shell } : {},
|
|
17516
17641
|
...activity ? { activity } : {},
|
|
17517
|
-
...record.input !== void 0 ? { input: record.input } : {}
|
|
17642
|
+
...record.input !== void 0 ? { input: record.input } : {},
|
|
17643
|
+
...background ? { background: true } : {}
|
|
17518
17644
|
};
|
|
17519
17645
|
}
|
|
17520
17646
|
throw new Error("execShell requires a non-empty command.");
|
|
@@ -17552,6 +17678,7 @@ var execShellCapability = {
|
|
|
17552
17678
|
command,
|
|
17553
17679
|
shell: normalized.shell
|
|
17554
17680
|
});
|
|
17681
|
+
const background = normalized.background === true;
|
|
17555
17682
|
const result4 = await runWorkspaceCommand({
|
|
17556
17683
|
workspaceRoot,
|
|
17557
17684
|
command: shellPlan.argv,
|
|
@@ -17559,15 +17686,18 @@ var execShellCapability = {
|
|
|
17559
17686
|
outputLimit: ctx.commandOutputLimit,
|
|
17560
17687
|
commandPrefix: ctx.commandPrefix,
|
|
17561
17688
|
abortSignal: ctx.abortSignal,
|
|
17562
|
-
detachMs: isImmediateDetachShellCommand({ command }) ? 0 : ctx.detachMs,
|
|
17689
|
+
detachMs: background ? 0 : isImmediateDetachShellCommand({ command }) ? 0 : ctx.detachMs,
|
|
17563
17690
|
stdin: typeof normalized.input === "string" ? normalized.input : void 0,
|
|
17564
17691
|
// Ownership of the turn that invoked this command: an auto-detached
|
|
17565
17692
|
// command keeps its parent dialog so its terminal can resume that
|
|
17566
17693
|
// conversation (see processOwnership.ts). Absent ctx.owner = unowned.
|
|
17567
17694
|
owner: ctx.owner ?? null
|
|
17568
17695
|
});
|
|
17696
|
+
const warnings = result4.detached || result4.spawnFailed ? [] : detectExecShellSynchronousWarnings(command, {
|
|
17697
|
+
resolvedShell: shellPlan.resolvedShell
|
|
17698
|
+
});
|
|
17569
17699
|
return {
|
|
17570
|
-
content: result4.content,
|
|
17700
|
+
content: warnings.length > 0 ? [result4.content, ...warnings.map((warning) => warning.message)].join("\n\n") : result4.content,
|
|
17571
17701
|
metadata: {
|
|
17572
17702
|
command,
|
|
17573
17703
|
exitCode: result4.exitCode,
|
|
@@ -17582,8 +17712,21 @@ var execShellCapability = {
|
|
|
17582
17712
|
// Phase 0: stable taskId from the pre-registered Execution
|
|
17583
17713
|
// Envelope (additive; existing detached fields untouched).
|
|
17584
17714
|
taskId: result4.taskId,
|
|
17585
|
-
status: "running"
|
|
17586
|
-
|
|
17715
|
+
status: "running",
|
|
17716
|
+
// P0 machine-readable execution state: an explicit positive
|
|
17717
|
+
// signal instead of requiring the model to infer "not detached"
|
|
17718
|
+
// from absence. Mirrors the real lifecycle contract.
|
|
17719
|
+
executionState: "detached",
|
|
17720
|
+
trackedBackgroundTask: true,
|
|
17721
|
+
completionNotification: "terminal-resume"
|
|
17722
|
+
} : {
|
|
17723
|
+
// P0 machine-readable execution state: the command already
|
|
17724
|
+
// finished inside the synchronous window; no background task
|
|
17725
|
+
// exists, so no completion notification will ever arrive.
|
|
17726
|
+
executionState: "synchronous-complete",
|
|
17727
|
+
trackedBackgroundTask: false,
|
|
17728
|
+
completionNotification: "none"
|
|
17729
|
+
},
|
|
17587
17730
|
...normalized.activity ? { activity: normalized.activity } : {}
|
|
17588
17731
|
}
|
|
17589
17732
|
};
|
|
@@ -17799,7 +17942,7 @@ function buildLaunchProcessTool() {
|
|
|
17799
17942
|
type: "function",
|
|
17800
17943
|
function: {
|
|
17801
17944
|
name: "launchProcess",
|
|
17802
|
-
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.",
|
|
17945
|
+
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.",
|
|
17803
17946
|
parameters: {
|
|
17804
17947
|
type: "object",
|
|
17805
17948
|
properties: {
|
|
@@ -18585,6 +18728,87 @@ async function writeFileTool(args2) {
|
|
|
18585
18728
|
}
|
|
18586
18729
|
};
|
|
18587
18730
|
}
|
|
18731
|
+
function extractSnippetWords(text) {
|
|
18732
|
+
const tokens = [];
|
|
18733
|
+
const latinWords = text.match(/[A-Za-z0-9_]{2,}/g);
|
|
18734
|
+
if (latinWords) {
|
|
18735
|
+
for (const w of latinWords) tokens.push(w.toLowerCase());
|
|
18736
|
+
}
|
|
18737
|
+
const cjkChars = text.match(new RegExp("\\p{Script=Han}", "gu"));
|
|
18738
|
+
if (cjkChars) {
|
|
18739
|
+
for (let i = 0; i < cjkChars.length - 1; i++) {
|
|
18740
|
+
tokens.push(cjkChars[i] + cjkChars[i + 1]);
|
|
18741
|
+
}
|
|
18742
|
+
if (cjkChars.length === 1) tokens.push(cjkChars[0]);
|
|
18743
|
+
}
|
|
18744
|
+
return tokens;
|
|
18745
|
+
}
|
|
18746
|
+
function calculateEditLineSimilarity(a, b) {
|
|
18747
|
+
if (a === b) return 1;
|
|
18748
|
+
if (!a || !b) return 0;
|
|
18749
|
+
if (a.includes(b) || b.includes(a)) return 0.8;
|
|
18750
|
+
const wordsA = extractSnippetWords(a);
|
|
18751
|
+
const wordsB = extractSnippetWords(b);
|
|
18752
|
+
if (wordsA.length === 0 || wordsB.length === 0) return 0;
|
|
18753
|
+
const setB = new Set(wordsB);
|
|
18754
|
+
let matches = 0;
|
|
18755
|
+
for (const w of wordsA) {
|
|
18756
|
+
if (setB.has(w)) matches++;
|
|
18757
|
+
}
|
|
18758
|
+
return 2 * matches / (wordsA.length + wordsB.length);
|
|
18759
|
+
}
|
|
18760
|
+
function findClosestEditSnippet(content, oldText) {
|
|
18761
|
+
const contentLines = content.split(/\r?\n/);
|
|
18762
|
+
const oldLinesRaw = oldText.split(/\r?\n/);
|
|
18763
|
+
const oldTrimmedLines = oldLinesRaw.map((l) => l.trim()).filter(Boolean);
|
|
18764
|
+
if (contentLines.length === 0 || oldTrimmedLines.length === 0) return null;
|
|
18765
|
+
if (oldTrimmedLines.length > 0 && contentLines.length >= oldTrimmedLines.length) {
|
|
18766
|
+
for (let i = 0; i <= contentLines.length - oldTrimmedLines.length; i++) {
|
|
18767
|
+
let allMatch = true;
|
|
18768
|
+
for (let j = 0; j < oldTrimmedLines.length; j++) {
|
|
18769
|
+
if (contentLines[i + j].trim() !== oldTrimmedLines[j]) {
|
|
18770
|
+
allMatch = false;
|
|
18771
|
+
break;
|
|
18772
|
+
}
|
|
18773
|
+
}
|
|
18774
|
+
if (allMatch) {
|
|
18775
|
+
const startLine2 = i + 1;
|
|
18776
|
+
const endLine2 = i + oldTrimmedLines.length;
|
|
18777
|
+
const snippetLines2 = [];
|
|
18778
|
+
for (let k = i; k < i + oldTrimmedLines.length; k++) {
|
|
18779
|
+
snippetLines2.push(`> ${k + 1}: ${contentLines[k]}`);
|
|
18780
|
+
}
|
|
18781
|
+
return `Exact match found with different indentation/whitespace (lines ${startLine2}-${endLine2}):
|
|
18782
|
+
${snippetLines2.join("\n")}`;
|
|
18783
|
+
}
|
|
18784
|
+
}
|
|
18785
|
+
}
|
|
18786
|
+
const candidateTargetLines = oldTrimmedLines.filter((l) => l.length >= 4);
|
|
18787
|
+
const targetLine = candidateTargetLines[0] || oldTrimmedLines[0];
|
|
18788
|
+
if (!targetLine || targetLine.length < 3) return null;
|
|
18789
|
+
let bestIndex = -1;
|
|
18790
|
+
let bestScore = 0;
|
|
18791
|
+
for (let i = 0; i < contentLines.length; i++) {
|
|
18792
|
+
const line = contentLines[i].trim();
|
|
18793
|
+
if (!line || line.length < 3) continue;
|
|
18794
|
+
const score = calculateEditLineSimilarity(line, targetLine);
|
|
18795
|
+
if (score > bestScore && score >= 0.45) {
|
|
18796
|
+
bestScore = score;
|
|
18797
|
+
bestIndex = i;
|
|
18798
|
+
if (score === 1) break;
|
|
18799
|
+
}
|
|
18800
|
+
}
|
|
18801
|
+
if (bestIndex === -1) return null;
|
|
18802
|
+
const startLine = Math.max(0, bestIndex - 2);
|
|
18803
|
+
const endLine = Math.min(contentLines.length - 1, bestIndex + 2);
|
|
18804
|
+
const snippetLines = [];
|
|
18805
|
+
for (let i = startLine; i <= endLine; i++) {
|
|
18806
|
+
const prefix = i === bestIndex ? "> " : " ";
|
|
18807
|
+
snippetLines.push(`${prefix}${i + 1}: ${contentLines[i]}`);
|
|
18808
|
+
}
|
|
18809
|
+
return `Closest match near line ${bestIndex + 1}:
|
|
18810
|
+
${snippetLines.join("\n")}`;
|
|
18811
|
+
}
|
|
18588
18812
|
async function editFileTool(args2) {
|
|
18589
18813
|
const parsed = parseWorkspaceToolArguments(args2.call.arguments);
|
|
18590
18814
|
const requestedPath = requireWorkspaceToolPath(parsed);
|
|
@@ -18603,8 +18827,11 @@ async function editFileTool(args2) {
|
|
|
18603
18827
|
newText
|
|
18604
18828
|
});
|
|
18605
18829
|
if (replacementCount !== expectedReplacements) {
|
|
18830
|
+
const hint = replacementCount === 0 ? findClosestEditSnippet(content, oldText) : null;
|
|
18606
18831
|
throw new Error(
|
|
18607
|
-
`editFile expected ${expectedReplacements} ${pluralizeReplacement(expectedReplacements)} but found ${replacementCount} in ${requestedPath} (matched after EOL normalization; verify the exact text).`
|
|
18832
|
+
`editFile expected ${expectedReplacements} ${pluralizeReplacement(expectedReplacements)} but found ${replacementCount} in ${requestedPath} (matched after EOL normalization; verify the exact text).` + (hint ? `
|
|
18833
|
+
|
|
18834
|
+
${hint}` : "")
|
|
18608
18835
|
);
|
|
18609
18836
|
}
|
|
18610
18837
|
await writeFile(absolutePath, nextContent, "utf8");
|
|
@@ -18940,6 +19167,55 @@ async function execShellTool(args2) {
|
|
|
18940
19167
|
}
|
|
18941
19168
|
);
|
|
18942
19169
|
}
|
|
19170
|
+
var LAUNCH_PROCESS_STREAM_RING_CHARS = 65536;
|
|
19171
|
+
var LAUNCH_PROCESS_STREAM_CAPTURE_MAX_CHARS = 4e6;
|
|
19172
|
+
function createLaunchProcessStreamCapture() {
|
|
19173
|
+
let ring = "";
|
|
19174
|
+
let full = null;
|
|
19175
|
+
let capturedChars = 0;
|
|
19176
|
+
let totalChars = 0;
|
|
19177
|
+
let totalNewlines = 0;
|
|
19178
|
+
return {
|
|
19179
|
+
push(chunk) {
|
|
19180
|
+
const str = typeof chunk === "string" ? chunk : chunk.toString("utf8");
|
|
19181
|
+
if (!str) return;
|
|
19182
|
+
totalChars += str.length;
|
|
19183
|
+
for (let i = 0; i < str.length; i += 1) {
|
|
19184
|
+
if (str.charCodeAt(i) === 10) totalNewlines += 1;
|
|
19185
|
+
}
|
|
19186
|
+
const combined = ring + str;
|
|
19187
|
+
if (combined.length <= LAUNCH_PROCESS_STREAM_RING_CHARS) {
|
|
19188
|
+
ring = combined;
|
|
19189
|
+
return;
|
|
19190
|
+
}
|
|
19191
|
+
if (full === null) {
|
|
19192
|
+
full = [combined];
|
|
19193
|
+
capturedChars = combined.length;
|
|
19194
|
+
} else if (capturedChars < LAUNCH_PROCESS_STREAM_CAPTURE_MAX_CHARS) {
|
|
19195
|
+
const room = LAUNCH_PROCESS_STREAM_CAPTURE_MAX_CHARS - capturedChars;
|
|
19196
|
+
const slice = str.length <= room ? str : str.slice(0, room);
|
|
19197
|
+
full.push(slice);
|
|
19198
|
+
capturedChars += slice.length;
|
|
19199
|
+
}
|
|
19200
|
+
ring = combined.slice(-LAUNCH_PROCESS_STREAM_RING_CHARS);
|
|
19201
|
+
},
|
|
19202
|
+
text() {
|
|
19203
|
+
return full === null ? ring : full.join("");
|
|
19204
|
+
},
|
|
19205
|
+
tailText() {
|
|
19206
|
+
return ring;
|
|
19207
|
+
},
|
|
19208
|
+
evicted() {
|
|
19209
|
+
return full !== null;
|
|
19210
|
+
},
|
|
19211
|
+
totalChars() {
|
|
19212
|
+
return totalChars;
|
|
19213
|
+
},
|
|
19214
|
+
totalLines() {
|
|
19215
|
+
return totalChars > 0 ? totalNewlines + 1 : 0;
|
|
19216
|
+
}
|
|
19217
|
+
};
|
|
19218
|
+
}
|
|
18943
19219
|
async function launchProcessTool(args2) {
|
|
18944
19220
|
const parsed = parseWorkspaceToolArguments(args2.call.arguments);
|
|
18945
19221
|
const command = requireShellCommand(parsed, args2.call.name);
|
|
@@ -18967,6 +19243,14 @@ async function launchProcessTool(args2) {
|
|
|
18967
19243
|
stdio: ["ignore", "pipe", "pipe"],
|
|
18968
19244
|
detached
|
|
18969
19245
|
});
|
|
19246
|
+
const stdoutCapture = createLaunchProcessStreamCapture();
|
|
19247
|
+
const stderrCapture = createLaunchProcessStreamCapture();
|
|
19248
|
+
proc.stdout?.on("data", (chunk) => stdoutCapture.push(chunk));
|
|
19249
|
+
proc.stderr?.on("data", (chunk) => stderrCapture.push(chunk));
|
|
19250
|
+
proc.stdout?.on("error", () => {
|
|
19251
|
+
});
|
|
19252
|
+
proc.stderr?.on("error", () => {
|
|
19253
|
+
});
|
|
18970
19254
|
const pid = proc.pid;
|
|
18971
19255
|
if (typeof pid !== "number") {
|
|
18972
19256
|
return {
|
|
@@ -19007,7 +19291,38 @@ async function launchProcessTool(args2) {
|
|
|
19007
19291
|
process.removeListener("SIGTERM", cleanupChildOnHostSignal);
|
|
19008
19292
|
process.removeListener("SIGINT", cleanupChildOnHostSignal);
|
|
19009
19293
|
}
|
|
19010
|
-
|
|
19294
|
+
const exitCode = code ?? 1;
|
|
19295
|
+
let capsule;
|
|
19296
|
+
try {
|
|
19297
|
+
capsule = buildProcessTaskResultCapsule({
|
|
19298
|
+
// The full captured output (bounded prefix when the process was
|
|
19299
|
+
// extremely chatty): the module tails it for the inline capsule and
|
|
19300
|
+
// spills it for recovery. Provenance carries the live original-stream
|
|
19301
|
+
// counters so truncated/spill metadata never derives from the ring.
|
|
19302
|
+
stdout: stdoutCapture.text(),
|
|
19303
|
+
stderr: stderrCapture.text(),
|
|
19304
|
+
stdoutTail: stdoutCapture.tailText(),
|
|
19305
|
+
stderrTail: stderrCapture.tailText(),
|
|
19306
|
+
exitCode,
|
|
19307
|
+
// Duration measured from the registry envelope's startedAt (spawn).
|
|
19308
|
+
startedAt: envelope.startedAt,
|
|
19309
|
+
workspaceRoot: args2.workspaceRoot,
|
|
19310
|
+
streamProvenance: {
|
|
19311
|
+
stdout: {
|
|
19312
|
+
evicted: stdoutCapture.evicted(),
|
|
19313
|
+
totalChars: stdoutCapture.totalChars(),
|
|
19314
|
+
totalLines: stdoutCapture.totalLines()
|
|
19315
|
+
},
|
|
19316
|
+
stderr: {
|
|
19317
|
+
evicted: stderrCapture.evicted(),
|
|
19318
|
+
totalChars: stderrCapture.totalChars(),
|
|
19319
|
+
totalLines: stderrCapture.totalLines()
|
|
19320
|
+
}
|
|
19321
|
+
}
|
|
19322
|
+
});
|
|
19323
|
+
} catch {
|
|
19324
|
+
}
|
|
19325
|
+
registry2.markExited(pid, exitCode, capsule);
|
|
19011
19326
|
});
|
|
19012
19327
|
const activity = extractActivity(parsed);
|
|
19013
19328
|
const resultData = { pid, label, taskId: envelope.taskId, status: "running" };
|
|
@@ -19019,6 +19334,13 @@ async function launchProcessTool(args2) {
|
|
|
19019
19334
|
label,
|
|
19020
19335
|
status: "running",
|
|
19021
19336
|
taskId: envelope.taskId,
|
|
19337
|
+
// P0 machine-readable execution state (consistent with the real wake
|
|
19338
|
+
// contract): a real background task from birth, but ambient — its
|
|
19339
|
+
// terminal result rides the next real turn's notice, not an automatic
|
|
19340
|
+
// completion turn.
|
|
19341
|
+
executionState: "background",
|
|
19342
|
+
trackedBackgroundTask: true,
|
|
19343
|
+
completionNotification: "next-turn-notice",
|
|
19022
19344
|
processLaunch: resultData,
|
|
19023
19345
|
...activity ? { activity } : {}
|
|
19024
19346
|
}
|
|
@@ -19121,7 +19443,7 @@ async function tasksTool(_args) {
|
|
|
19121
19443
|
}
|
|
19122
19444
|
async function openDesktopPreviewTool(args2) {
|
|
19123
19445
|
const parsed = parseWorkspaceToolArguments(args2.call.arguments);
|
|
19124
|
-
const url =
|
|
19446
|
+
const url = asTrimmedString(parsed.url);
|
|
19125
19447
|
if (!url) {
|
|
19126
19448
|
return {
|
|
19127
19449
|
content: JSON.stringify({ error: "openDesktopPreview requires a non-empty url." }),
|
|
@@ -19243,6 +19565,292 @@ function createLocalWorkspaceToolExecutors(args2) {
|
|
|
19243
19565
|
};
|
|
19244
19566
|
}
|
|
19245
19567
|
|
|
19568
|
+
// packages/agent-runtime/toolArgumentGate.ts
|
|
19569
|
+
var FIELD_ALIAS_GROUPS = [
|
|
19570
|
+
// localWorkspaceTools.ts:336 导出常量(readFile/writeFile/editFile/globFiles)
|
|
19571
|
+
PATH_FIELD_ALIASES,
|
|
19572
|
+
// localWorkspaceTools.ts:339-340 导出常量(editFile)
|
|
19573
|
+
OLD_TEXT_FIELD_ALIASES,
|
|
19574
|
+
NEW_TEXT_FIELD_ALIASES,
|
|
19575
|
+
// localWorkspaceTools.ts:733 `args.cmd || args.command`(launchProcess);
|
|
19576
|
+
// launchProcess 的 required ["command"] 见 localWorkspaceToolDefs.ts:283。
|
|
19577
|
+
// 注:execShell 的 schema 无 required(command 在 executor 层强制,
|
|
19578
|
+
// capabilities/execShellCapability.ts:42 声明 cmd 兼容字段),本组对它不产生拦截。
|
|
19579
|
+
["command", "cmd"],
|
|
19580
|
+
// localWorkspaceTools.ts:698-699 `args.pattern ?? args.glob`(globFiles)
|
|
19581
|
+
["pattern", "glob"],
|
|
19582
|
+
// noloWorkspaceTools.ts:492 `args.dialog ?? args.dialogId ?? args.id`(readDialog)
|
|
19583
|
+
["dialog", "dialogId", "id"],
|
|
19584
|
+
// noloWorkspaceTools.ts:545 `args.agent ?? args.agentKey ?? args.id`(readAgent)
|
|
19585
|
+
["agent", "agentKey", "id"],
|
|
19586
|
+
// noloWorkspaceTools.ts:552 `args.space ?? args.spaceId ?? args.id`(readSpace)
|
|
19587
|
+
["space", "spaceId", "id"],
|
|
19588
|
+
// noloWorkspaceTools.ts:561/567 `args.doc ?? args.docKey ?? args.pageKey ?? args.key`
|
|
19589
|
+
// (readDoc / readSkillDoc)
|
|
19590
|
+
["doc", "docKey", "pageKey", "key"],
|
|
19591
|
+
// noloWorkspaceTools.node.ts:238 `parsed.name ?? parsed.skillName ?? parsed.skill`(loadSkill)
|
|
19592
|
+
["name", "skillName", "skill"],
|
|
19593
|
+
// noloWorkspaceTools.ts:593 `args.table ?? args.tableId ?? args.metaKey`(queryTableRows)
|
|
19594
|
+
["table", "tableId", "metaKey"]
|
|
19595
|
+
];
|
|
19596
|
+
var TYPE_MATCHERS = {
|
|
19597
|
+
string: (value) => typeof value === "string",
|
|
19598
|
+
// 数字字符串视为可接受:executor 普遍 Number()/clamp 宽松处理,拦截会误报。
|
|
19599
|
+
number: (value) => typeof value === "number" || typeof value === "string" && value.trim() !== "" && Number.isFinite(Number(value)),
|
|
19600
|
+
integer: (value) => typeof value === "number" || typeof value === "string" && value.trim() !== "" && Number.isFinite(Number(value)),
|
|
19601
|
+
boolean: (value) => typeof value === "boolean" || value === "true" || value === "false",
|
|
19602
|
+
object: (value) => typeof value === "object" && value !== null && !Array.isArray(value),
|
|
19603
|
+
array: (value) => Array.isArray(value)
|
|
19604
|
+
};
|
|
19605
|
+
function describeValueType(value) {
|
|
19606
|
+
if (value === null) return "null";
|
|
19607
|
+
if (Array.isArray(value)) return "array";
|
|
19608
|
+
return typeof value;
|
|
19609
|
+
}
|
|
19610
|
+
function isAliasSatisfied(args2, field) {
|
|
19611
|
+
for (const group of FIELD_ALIAS_GROUPS) {
|
|
19612
|
+
if (!group.includes(field)) continue;
|
|
19613
|
+
if (group.some((alias) => args2[alias] !== void 0)) return true;
|
|
19614
|
+
}
|
|
19615
|
+
return false;
|
|
19616
|
+
}
|
|
19617
|
+
function readRequiredFields(parameters) {
|
|
19618
|
+
const required = parameters.required;
|
|
19619
|
+
if (!Array.isArray(required)) return [];
|
|
19620
|
+
return required.filter((field) => typeof field === "string");
|
|
19621
|
+
}
|
|
19622
|
+
function readProperties(parameters) {
|
|
19623
|
+
const properties = parameters.properties;
|
|
19624
|
+
if (!properties || typeof properties !== "object" || Array.isArray(properties)) {
|
|
19625
|
+
return {};
|
|
19626
|
+
}
|
|
19627
|
+
return properties;
|
|
19628
|
+
}
|
|
19629
|
+
function validateToolArguments(args2) {
|
|
19630
|
+
const { toolName, rawArguments, parameters } = args2;
|
|
19631
|
+
if (!parameters || typeof parameters !== "object" || Array.isArray(parameters)) {
|
|
19632
|
+
return { ok: true, args: {} };
|
|
19633
|
+
}
|
|
19634
|
+
const schema = parameters;
|
|
19635
|
+
const requiredFields = readRequiredFields(schema);
|
|
19636
|
+
const properties = readProperties(schema);
|
|
19637
|
+
if (requiredFields.length === 0 && Object.keys(properties).length === 0) {
|
|
19638
|
+
return { ok: true, args: {} };
|
|
19639
|
+
}
|
|
19640
|
+
const raw = typeof rawArguments === "string" ? rawArguments.trim() : "";
|
|
19641
|
+
let record = {};
|
|
19642
|
+
if (raw !== "") {
|
|
19643
|
+
let parsed;
|
|
19644
|
+
try {
|
|
19645
|
+
parsed = JSON.parse(raw);
|
|
19646
|
+
} catch {
|
|
19647
|
+
return { ok: true, args: {} };
|
|
19648
|
+
}
|
|
19649
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
19650
|
+
return { ok: true, args: {} };
|
|
19651
|
+
}
|
|
19652
|
+
record = parsed;
|
|
19653
|
+
}
|
|
19654
|
+
for (const field of requiredFields) {
|
|
19655
|
+
if (record[field] !== void 0) continue;
|
|
19656
|
+
if (isAliasSatisfied(record, field)) continue;
|
|
19657
|
+
return {
|
|
19658
|
+
ok: false,
|
|
19659
|
+
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`
|
|
19660
|
+
};
|
|
19661
|
+
}
|
|
19662
|
+
for (const [field, spec] of Object.entries(properties)) {
|
|
19663
|
+
const value = record[field];
|
|
19664
|
+
if (value === void 0 || value === null) continue;
|
|
19665
|
+
if (!spec || typeof spec !== "object" || Array.isArray(spec)) continue;
|
|
19666
|
+
const declared = spec.type;
|
|
19667
|
+
if (typeof declared !== "string") continue;
|
|
19668
|
+
const matcher = TYPE_MATCHERS[declared];
|
|
19669
|
+
if (!matcher) continue;
|
|
19670
|
+
if (!matcher(value)) {
|
|
19671
|
+
return {
|
|
19672
|
+
ok: false,
|
|
19673
|
+
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`
|
|
19674
|
+
};
|
|
19675
|
+
}
|
|
19676
|
+
}
|
|
19677
|
+
return { ok: true, args: record };
|
|
19678
|
+
}
|
|
19679
|
+
function buildToolParametersIndex(tools) {
|
|
19680
|
+
const index = /* @__PURE__ */ new Map();
|
|
19681
|
+
for (const tool of tools) {
|
|
19682
|
+
if (!tool || typeof tool !== "object") continue;
|
|
19683
|
+
const fn3 = tool.function;
|
|
19684
|
+
if (!fn3 || typeof fn3 !== "object") continue;
|
|
19685
|
+
const name = fn3.name;
|
|
19686
|
+
const parameters = fn3.parameters;
|
|
19687
|
+
if (typeof name === "string" && name && parameters !== void 0) {
|
|
19688
|
+
index.set(name, parameters);
|
|
19689
|
+
}
|
|
19690
|
+
}
|
|
19691
|
+
return index;
|
|
19692
|
+
}
|
|
19693
|
+
var cachedAgentRuntimeIndex = null;
|
|
19694
|
+
function getAgentRuntimeToolParametersIndex() {
|
|
19695
|
+
if (cachedAgentRuntimeIndex) return cachedAgentRuntimeIndex;
|
|
19696
|
+
const index = /* @__PURE__ */ new Map();
|
|
19697
|
+
try {
|
|
19698
|
+
const workspaceTools = buildLocalWorkspaceOpenAiTools({
|
|
19699
|
+
toolNames: [...WORKSPACE_TOOL_NAMES],
|
|
19700
|
+
exposeShellTools: true
|
|
19701
|
+
});
|
|
19702
|
+
for (const [name, parameters] of buildToolParametersIndex(workspaceTools)) {
|
|
19703
|
+
index.set(name, parameters);
|
|
19704
|
+
}
|
|
19705
|
+
const noloTools = buildNoloWorkspaceOpenAiTools({
|
|
19706
|
+
toolNames: [...NOLO_WORKSPACE_TOOL_NAMES]
|
|
19707
|
+
});
|
|
19708
|
+
for (const [name, parameters] of buildToolParametersIndex(noloTools)) {
|
|
19709
|
+
index.set(name, parameters);
|
|
19710
|
+
}
|
|
19711
|
+
} catch {
|
|
19712
|
+
}
|
|
19713
|
+
cachedAgentRuntimeIndex = index;
|
|
19714
|
+
return index;
|
|
19715
|
+
}
|
|
19716
|
+
|
|
19717
|
+
// packages/agent-runtime/localToolPolicy.ts
|
|
19718
|
+
var NEVER_LOCAL_TOOLS = /* @__PURE__ */ new Set([
|
|
19719
|
+
"deleteSpaces",
|
|
19720
|
+
"updateAgent",
|
|
19721
|
+
"updateSelf",
|
|
19722
|
+
"createAgent"
|
|
19723
|
+
]);
|
|
19724
|
+
var DEFAULT_LOCAL_TOOLS = /* @__PURE__ */ new Set([
|
|
19725
|
+
"readFile",
|
|
19726
|
+
"writeFile",
|
|
19727
|
+
"editFile",
|
|
19728
|
+
"globFiles",
|
|
19729
|
+
"execShell",
|
|
19730
|
+
"launchProcess",
|
|
19731
|
+
"listProcesses",
|
|
19732
|
+
// ProcessTask follow-up tools. Same tier as listProcesses: they observe/stop
|
|
19733
|
+
// tasks the agent itself already spawned, so their blast radius is strictly
|
|
19734
|
+
// narrower than launchProcess (which is default-enabled). Model-facing
|
|
19735
|
+
// follow-ups are taskWait/taskStop only — lifecycle history (taskLogs) stays
|
|
19736
|
+
// runtime-internal.
|
|
19737
|
+
"taskWait",
|
|
19738
|
+
"taskStop",
|
|
19739
|
+
// Scheduling tools: forking/observing sub-agents is a declared capability
|
|
19740
|
+
// of capable agents, and the blast radius is strictly narrower than
|
|
19741
|
+
// execShell (already default-enabled). Requiring an env allowlist for these
|
|
19742
|
+
// while execShell is open by default inverted the risk model and forced every
|
|
19743
|
+
// new local user to hand-edit .env files before sub-agent tasks worked.
|
|
19744
|
+
"startAgentRun",
|
|
19745
|
+
"controlAgentRun"
|
|
19746
|
+
]);
|
|
19747
|
+
function parseToolAllowlist(value) {
|
|
19748
|
+
return (value ?? "").split(",").flatMap((item) => {
|
|
19749
|
+
const trimmed = item.trim();
|
|
19750
|
+
return trimmed ? [trimmed] : [];
|
|
19751
|
+
});
|
|
19752
|
+
}
|
|
19753
|
+
function normalizeLocalToolName(toolName) {
|
|
19754
|
+
return canonicalizeToolName(
|
|
19755
|
+
String(toolName ?? "").replace(/^functions\./, "").trim()
|
|
19756
|
+
);
|
|
19757
|
+
}
|
|
19758
|
+
function isRestrictedLocalToolMode(env) {
|
|
19759
|
+
return env.NOLO_LOCAL_TOOL_MODE === "restricted";
|
|
19760
|
+
}
|
|
19761
|
+
function resolveLocalToolPolicy(args2) {
|
|
19762
|
+
const toolName = normalizeLocalToolName(args2.toolName);
|
|
19763
|
+
const restrictedMode = isRestrictedLocalToolMode(args2.env);
|
|
19764
|
+
if (!toolName) {
|
|
19765
|
+
return {
|
|
19766
|
+
allowed: false,
|
|
19767
|
+
toolName,
|
|
19768
|
+
reason: "Tool name is required."
|
|
19769
|
+
};
|
|
19770
|
+
}
|
|
19771
|
+
if (NEVER_LOCAL_TOOLS.has(toolName)) {
|
|
19772
|
+
return {
|
|
19773
|
+
allowed: false,
|
|
19774
|
+
toolName,
|
|
19775
|
+
reason: `${toolName} is blocked by the local runtime safety policy.`
|
|
19776
|
+
};
|
|
19777
|
+
}
|
|
19778
|
+
const allowedByEnv = new Set(
|
|
19779
|
+
parseToolAllowlist(args2.env.NOLO_LOCAL_ALLOWED_TOOLS).map(normalizeLocalToolName)
|
|
19780
|
+
);
|
|
19781
|
+
const agentTools = new Set(
|
|
19782
|
+
(args2.agentToolNames ?? []).flatMap((item) => {
|
|
19783
|
+
const normalized = normalizeLocalToolName(item);
|
|
19784
|
+
return normalized ? [normalized] : [];
|
|
19785
|
+
})
|
|
19786
|
+
);
|
|
19787
|
+
if (!restrictedMode && agentTools.has(toolName)) {
|
|
19788
|
+
return { allowed: true, toolName };
|
|
19789
|
+
}
|
|
19790
|
+
if (DEFAULT_LOCAL_TOOLS.has(toolName) && agentTools.has(toolName)) {
|
|
19791
|
+
return { allowed: true, toolName };
|
|
19792
|
+
}
|
|
19793
|
+
if (allowedByEnv.has(toolName) && agentTools.has(toolName)) {
|
|
19794
|
+
return { allowed: true, toolName };
|
|
19795
|
+
}
|
|
19796
|
+
return {
|
|
19797
|
+
allowed: false,
|
|
19798
|
+
toolName,
|
|
19799
|
+
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.`
|
|
19800
|
+
};
|
|
19801
|
+
}
|
|
19802
|
+
async function executeLocalToolWithPolicy(args2) {
|
|
19803
|
+
if (args2.runToolNames !== void 0 && !args2.runToolNames.map(normalizeLocalToolName).includes(normalizeLocalToolName(args2.call.name))) {
|
|
19804
|
+
throw new Error(`${args2.call.name} is outside the final run tool surface.`);
|
|
19805
|
+
}
|
|
19806
|
+
const decision = resolveLocalToolPolicy({
|
|
19807
|
+
env: args2.env,
|
|
19808
|
+
agentToolNames: args2.agentToolNames,
|
|
19809
|
+
toolName: args2.call.name
|
|
19810
|
+
});
|
|
19811
|
+
if (!decision.allowed) throw new Error(decision.reason);
|
|
19812
|
+
const executor = args2.executors?.[decision.toolName];
|
|
19813
|
+
if (!executor) {
|
|
19814
|
+
throw new Error(`${decision.toolName} is allowed by policy but no local executor is registered.`);
|
|
19815
|
+
}
|
|
19816
|
+
const parametersSchema = args2.toolParametersIndex?.get(decision.toolName);
|
|
19817
|
+
if (parametersSchema !== void 0) {
|
|
19818
|
+
const gate = validateToolArguments({
|
|
19819
|
+
toolName: decision.toolName,
|
|
19820
|
+
rawArguments: args2.call.arguments,
|
|
19821
|
+
parameters: parametersSchema
|
|
19822
|
+
});
|
|
19823
|
+
if (!gate.ok) throw new Error(gate.message);
|
|
19824
|
+
}
|
|
19825
|
+
const opts = {
|
|
19826
|
+
...args2.abortSignal ? { abortSignal: args2.abortSignal } : {},
|
|
19827
|
+
...args2.detachMs !== void 0 ? { detachMs: args2.detachMs } : {},
|
|
19828
|
+
...args2.confirmed !== void 0 ? { confirmed: args2.confirmed } : {},
|
|
19829
|
+
...args2.enableDestructiveShellGuard !== void 0 ? { enableDestructiveShellGuard: args2.enableDestructiveShellGuard } : {},
|
|
19830
|
+
...args2.confirmDestructiveAction ? { confirmDestructiveAction: args2.confirmDestructiveAction } : {},
|
|
19831
|
+
...args2.blockDestructiveWithoutConfirmation !== void 0 ? { blockDestructiveWithoutConfirmation: args2.blockDestructiveWithoutConfirmation } : {}
|
|
19832
|
+
};
|
|
19833
|
+
if (decision.toolName === "execShell") {
|
|
19834
|
+
let parsedInput = args2.call.arguments;
|
|
19835
|
+
if (typeof parsedInput === "string") {
|
|
19836
|
+
try {
|
|
19837
|
+
parsedInput = JSON.parse(parsedInput);
|
|
19838
|
+
} catch {
|
|
19839
|
+
parsedInput = { command: parsedInput };
|
|
19840
|
+
}
|
|
19841
|
+
}
|
|
19842
|
+
await evaluateExecShellDestructiveGuard(parsedInput, opts);
|
|
19843
|
+
opts.confirmed = true;
|
|
19844
|
+
}
|
|
19845
|
+
return executor(
|
|
19846
|
+
{
|
|
19847
|
+
...args2.call,
|
|
19848
|
+
name: decision.toolName
|
|
19849
|
+
},
|
|
19850
|
+
opts
|
|
19851
|
+
);
|
|
19852
|
+
}
|
|
19853
|
+
|
|
19246
19854
|
// packages/cli/client/localDialogRecords.ts
|
|
19247
19855
|
var localDialogMessageRecordToRuntimeMessage = dialogMessageRecordToAgentRuntimeMessage;
|
|
19248
19856
|
function buildLocalDialogWritePlan(args2) {
|
|
@@ -19379,10 +19987,10 @@ function buildLoadSkillExecutor(args2) {
|
|
|
19379
19987
|
metadata: { loadSkill: true, resolved: false }
|
|
19380
19988
|
};
|
|
19381
19989
|
}
|
|
19382
|
-
const { resolveSkillByName } = await import("./skillDiscovery-
|
|
19990
|
+
const { resolveSkillByName } = await import("./skillDiscovery-ZBU76COE.js");
|
|
19383
19991
|
const resolved = resolveSkillByName(args2.cwd, name);
|
|
19384
19992
|
if (!resolved) {
|
|
19385
|
-
const { resolveBuiltinSkillByName } = await import("./builtinSkillRegistry-
|
|
19993
|
+
const { resolveBuiltinSkillByName } = await import("./builtinSkillRegistry-CALVIJTX.js");
|
|
19386
19994
|
const builtin = resolveBuiltinSkillByName(name);
|
|
19387
19995
|
if (builtin) {
|
|
19388
19996
|
return {
|
|
@@ -19425,7 +20033,7 @@ ${body}`,
|
|
|
19425
20033
|
};
|
|
19426
20034
|
}
|
|
19427
20035
|
async function formatUnknownSkillMessage(cwd, requestedName) {
|
|
19428
|
-
const { discoverSkills } = await import("./skillDiscovery-
|
|
20036
|
+
const { discoverSkills } = await import("./skillDiscovery-ZBU76COE.js");
|
|
19429
20037
|
let available = [];
|
|
19430
20038
|
try {
|
|
19431
20039
|
available = discoverSkills(cwd).map((s) => s.name);
|
|
@@ -19440,739 +20048,10 @@ No skills were discovered in this workspace.`;
|
|
|
19440
20048
|
Available skills: ${available.join(", ")}`;
|
|
19441
20049
|
}
|
|
19442
20050
|
|
|
19443
|
-
// packages/core/chat/upstreamErrorBody.ts
|
|
19444
|
-
function parseUpstreamErrorBody(errorText, statusText) {
|
|
19445
|
-
if (errorText) {
|
|
19446
|
-
try {
|
|
19447
|
-
const parsed = JSON.parse(errorText);
|
|
19448
|
-
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
19449
|
-
const error = parsed.error;
|
|
19450
|
-
if (error && typeof error === "object" && !Array.isArray(error)) {
|
|
19451
|
-
return parsed;
|
|
19452
|
-
}
|
|
19453
|
-
}
|
|
19454
|
-
} catch {
|
|
19455
|
-
}
|
|
19456
|
-
}
|
|
19457
|
-
return { error: { message: errorText || statusText } };
|
|
19458
|
-
}
|
|
19459
|
-
|
|
19460
|
-
// packages/agent-runtime/antigravityCloudCodeProvider.ts
|
|
19461
|
-
import { randomUUID } from "node:crypto";
|
|
19462
|
-
|
|
19463
|
-
// packages/agent-runtime/antigravityWireModel.ts
|
|
19464
|
-
var WIRE_PROFILES = {
|
|
19465
|
-
// Antigravity discovery exposes 3.7 Flash as one tiered wire model.
|
|
19466
|
-
// The UI labels its effort variants (Low/Medium/High), but the literal
|
|
19467
|
-
// -medium/-high ids return 404 from streamGenerateContent.
|
|
19468
|
-
"gemini-3.7-flash-tiered": { modelEnum: "MODEL_PLACEHOLDER_M301", maxOutputTokens: 65536 },
|
|
19469
|
-
// Gemini 3.8 Flash 沿用 3.7 的 tiered 兼容策略:仓库内暂无 Antigravity discovery
|
|
19470
|
-
// 证据确认 3.8 的 wire modelEnum,禁止虚构,先只声明同档输出上限;enum 待
|
|
19471
|
-
// discovery 证据到位后补齐。
|
|
19472
|
-
"gemini-3.8-flash-tiered": { maxOutputTokens: 65536 },
|
|
19473
|
-
"gemini-3.6-flash-low": { maxOutputTokens: 65536 },
|
|
19474
|
-
"gemini-3.6-flash-medium": { maxOutputTokens: 65536 },
|
|
19475
|
-
"gemini-3.6-flash-high": { maxOutputTokens: 65536 },
|
|
19476
|
-
// 旧模型 wire 映射保留:存量自定义 agent 仍可能引用(注册表已下线不影响此处)。
|
|
19477
|
-
"gemini-3.5-flash-extra-low": { modelEnum: "MODEL_PLACEHOLDER_M187", maxOutputTokens: 65536 },
|
|
19478
|
-
"gemini-3.5-flash-low": { modelEnum: "MODEL_PLACEHOLDER_M20", maxOutputTokens: 65536 },
|
|
19479
|
-
"gemini-3-flash-agent": { modelEnum: "MODEL_PLACEHOLDER_M132", maxOutputTokens: 65536 },
|
|
19480
|
-
"gemini-3.1-pro-low": { modelEnum: "MODEL_PLACEHOLDER_M36", maxOutputTokens: 65535 },
|
|
19481
|
-
"gemini-pro-agent": { modelEnum: "MODEL_PLACEHOLDER_M16", maxOutputTokens: 65535 },
|
|
19482
|
-
"claude-sonnet-5": { maxOutputTokens: 64e3 },
|
|
19483
|
-
"claude-sonnet-4-6": { maxOutputTokens: 64e3 },
|
|
19484
|
-
"claude-opus-4-6-thinking": { maxOutputTokens: 64e3 },
|
|
19485
|
-
"gemini-2.5-flash": { maxOutputTokens: 65536 },
|
|
19486
|
-
"gemini-2.5-pro": { maxOutputTokens: 65536 }
|
|
19487
|
-
};
|
|
19488
|
-
function resolveAntigravityWireModel(logicalModelId) {
|
|
19489
|
-
const id = logicalModelId.trim();
|
|
19490
|
-
const lower = id.toLowerCase();
|
|
19491
|
-
if (lower === "gemini-3.5-flash") {
|
|
19492
|
-
const wireModelId = "gemini-3.5-flash-low";
|
|
19493
|
-
return { wireModelId, profile: WIRE_PROFILES[wireModelId] };
|
|
19494
|
-
}
|
|
19495
|
-
if (lower === "gemini-3.7-flash" || ["gemini-3.7-flash-low", "gemini-3.7-flash-medium", "gemini-3.7-flash-high"].includes(lower)) {
|
|
19496
|
-
const wireModelId = "gemini-3.7-flash-tiered";
|
|
19497
|
-
return { wireModelId, profile: WIRE_PROFILES[wireModelId] };
|
|
19498
|
-
}
|
|
19499
|
-
if (lower === "gemini-3.8-flash" || ["gemini-3.8-flash-low", "gemini-3.8-flash-medium", "gemini-3.8-flash-high"].includes(lower)) {
|
|
19500
|
-
const wireModelId = "gemini-3.8-flash-tiered";
|
|
19501
|
-
return { wireModelId, profile: WIRE_PROFILES[wireModelId] };
|
|
19502
|
-
}
|
|
19503
|
-
if (lower === "gemini-3.6-flash") {
|
|
19504
|
-
const wireModelId = "gemini-3.6-flash-low";
|
|
19505
|
-
return { wireModelId, profile: WIRE_PROFILES[wireModelId] };
|
|
19506
|
-
}
|
|
19507
|
-
if (lower === "gemini-3.1-pro" || lower === "gemini-3.1-pro-preview") {
|
|
19508
|
-
const wireModelId = "gemini-3.1-pro-low";
|
|
19509
|
-
return { wireModelId, profile: WIRE_PROFILES[wireModelId] };
|
|
19510
|
-
}
|
|
19511
|
-
if (WIRE_PROFILES[id]) {
|
|
19512
|
-
return { wireModelId: id, profile: WIRE_PROFILES[id] };
|
|
19513
|
-
}
|
|
19514
|
-
return { wireModelId: id };
|
|
19515
|
-
}
|
|
19516
|
-
|
|
19517
|
-
// packages/agent-runtime/geminiNativeShared.ts
|
|
19518
|
-
var SKIP_THOUGHT_SIGNATURE = "skip_thought_signature_validator";
|
|
19519
|
-
function resolveGeminiModelQuirks(modelId) {
|
|
19520
|
-
const lower = modelId.toLowerCase();
|
|
19521
|
-
const isGemini3 = lower.includes("gemini-3");
|
|
19522
|
-
const isStrictSignatureModel = lower.includes("gemini-3.5") || lower.includes("flash-preview");
|
|
19523
|
-
const isClaude = lower.includes("claude");
|
|
19524
|
-
return {
|
|
19525
|
-
requiresThoughtSignature: isGemini3,
|
|
19526
|
-
allowsThoughtSignatureSentinel: isGemini3 && !isStrictSignatureModel,
|
|
19527
|
-
isClaudeCrossModel: isClaude
|
|
19528
|
-
};
|
|
19529
|
-
}
|
|
19530
|
-
function isGemini3Model(modelId) {
|
|
19531
|
-
return resolveGeminiModelQuirks(modelId).requiresThoughtSignature;
|
|
19532
|
-
}
|
|
19533
|
-
function messageText(content) {
|
|
19534
|
-
if (typeof content === "string") return content;
|
|
19535
|
-
if (!Array.isArray(content)) return "";
|
|
19536
|
-
return content.filter(
|
|
19537
|
-
(part) => part?.type === "text"
|
|
19538
|
-
).map((part) => part.text).join("\n").trim();
|
|
19539
|
-
}
|
|
19540
|
-
function parseDataUrlToInlineData(url) {
|
|
19541
|
-
const match7 = /^data:([A-Za-z0-9.+-]+\/[A-Za-z0-9.+-]+);base64,([A-Za-z0-9+/=]*)$/.exec(
|
|
19542
|
-
url
|
|
19543
|
-
);
|
|
19544
|
-
if (!match7) return null;
|
|
19545
|
-
return { mimeType: match7[1], data: match7[2] };
|
|
19546
|
-
}
|
|
19547
|
-
function extractInlineDataParts(content) {
|
|
19548
|
-
if (!Array.isArray(content)) return [];
|
|
19549
|
-
const parts2 = [];
|
|
19550
|
-
for (const part of content) {
|
|
19551
|
-
if (!part || typeof part !== "object") continue;
|
|
19552
|
-
if (part.type !== "image_url") continue;
|
|
19553
|
-
const url = part.image_url?.url;
|
|
19554
|
-
if (typeof url !== "string" || !url.trim()) continue;
|
|
19555
|
-
const inline = parseDataUrlToInlineData(url);
|
|
19556
|
-
if (inline) parts2.push({ inlineData: inline });
|
|
19557
|
-
}
|
|
19558
|
-
return parts2;
|
|
19559
|
-
}
|
|
19560
|
-
function convertOpenAiMessagesToGemini(messages, options) {
|
|
19561
|
-
const contents = [];
|
|
19562
|
-
const systemTexts = [];
|
|
19563
|
-
let toolCallIndex = 0;
|
|
19564
|
-
let pendingFunctionCalls = [];
|
|
19565
|
-
const pushOrMergeContent = (role, parts2) => {
|
|
19566
|
-
if (parts2.length === 0) return;
|
|
19567
|
-
const last = contents[contents.length - 1];
|
|
19568
|
-
if (last && last.role === role) {
|
|
19569
|
-
last.parts.push(...parts2);
|
|
19570
|
-
} else {
|
|
19571
|
-
contents.push({ role, parts: parts2 });
|
|
19572
|
-
}
|
|
19573
|
-
};
|
|
19574
|
-
const flushPendingFunctionCalls = () => {
|
|
19575
|
-
if (pendingFunctionCalls.length === 0) return;
|
|
19576
|
-
const dummyResponses = pendingFunctionCalls.map(
|
|
19577
|
-
({ name, id }) => ({
|
|
19578
|
-
functionResponse: {
|
|
19579
|
-
name,
|
|
19580
|
-
response: { output: "{}" },
|
|
19581
|
-
...id ? { id } : {}
|
|
19582
|
-
}
|
|
19583
|
-
})
|
|
19584
|
-
);
|
|
19585
|
-
pendingFunctionCalls = [];
|
|
19586
|
-
pushOrMergeContent("user", dummyResponses);
|
|
19587
|
-
};
|
|
19588
|
-
for (const raw of messages) {
|
|
19589
|
-
if (!raw || typeof raw !== "object" || !("role" in raw)) continue;
|
|
19590
|
-
const role = String(raw.role);
|
|
19591
|
-
const content = "content" in raw ? raw.content : null;
|
|
19592
|
-
if (role === "system") {
|
|
19593
|
-
const text = messageText(
|
|
19594
|
-
content
|
|
19595
|
-
);
|
|
19596
|
-
if (text) systemTexts.push(text);
|
|
19597
|
-
continue;
|
|
19598
|
-
}
|
|
19599
|
-
if (role === "user") {
|
|
19600
|
-
flushPendingFunctionCalls();
|
|
19601
|
-
const text = messageText(
|
|
19602
|
-
content
|
|
19603
|
-
);
|
|
19604
|
-
const imageParts = extractInlineDataParts(
|
|
19605
|
-
content
|
|
19606
|
-
);
|
|
19607
|
-
if (!text && imageParts.length === 0) continue;
|
|
19608
|
-
const parts2 = [];
|
|
19609
|
-
if (text) parts2.push({ text });
|
|
19610
|
-
for (const img of imageParts) parts2.push(img);
|
|
19611
|
-
pushOrMergeContent("user", parts2);
|
|
19612
|
-
continue;
|
|
19613
|
-
}
|
|
19614
|
-
if (role === "assistant") {
|
|
19615
|
-
flushPendingFunctionCalls();
|
|
19616
|
-
const text = messageText(
|
|
19617
|
-
content
|
|
19618
|
-
);
|
|
19619
|
-
const toolCalls = "tool_calls" in raw && Array.isArray(raw.tool_calls) ? raw.tool_calls ?? [] : [];
|
|
19620
|
-
const parts2 = [];
|
|
19621
|
-
if (text) {
|
|
19622
|
-
parts2.push({ text });
|
|
19623
|
-
}
|
|
19624
|
-
for (const call of toolCalls) {
|
|
19625
|
-
const name = call?.function?.name?.trim();
|
|
19626
|
-
if (!name) continue;
|
|
19627
|
-
const id = call.id?.trim() || `${name}_${toolCallIndex++}`;
|
|
19628
|
-
pendingFunctionCalls.push({ name, id });
|
|
19629
|
-
const realSignature = typeof call.thought_signature === "string" && call.thought_signature ? call.thought_signature : void 0;
|
|
19630
|
-
const isFirstFunctionCallPart = !parts2.some(
|
|
19631
|
-
(p) => "functionCall" in p
|
|
19632
|
-
);
|
|
19633
|
-
const signature = realSignature ?? (options.attachSkipThoughtSignature && isFirstFunctionCallPart ? SKIP_THOUGHT_SIGNATURE : void 0);
|
|
19634
|
-
const part = {
|
|
19635
|
-
functionCall: {
|
|
19636
|
-
name,
|
|
19637
|
-
args: parseToolArgs(call.function?.arguments),
|
|
19638
|
-
...id ? { id } : {}
|
|
19639
|
-
},
|
|
19640
|
-
...signature ? { thoughtSignature: signature } : {}
|
|
19641
|
-
};
|
|
19642
|
-
parts2.push(part);
|
|
19643
|
-
}
|
|
19644
|
-
pushOrMergeContent("model", parts2);
|
|
19645
|
-
continue;
|
|
19646
|
-
}
|
|
19647
|
-
if (role === "tool") {
|
|
19648
|
-
const toolCallId = "tool_call_id" in raw && typeof raw.tool_call_id === "string" ? raw.tool_call_id : "";
|
|
19649
|
-
const rawName = "name" in raw && typeof raw.name === "string" ? raw.name.trim() : "";
|
|
19650
|
-
const pendingIndex = pendingFunctionCalls.findIndex(
|
|
19651
|
-
(p) => toolCallId ? p.id === toolCallId : rawName ? p.name === rawName : true
|
|
19652
|
-
);
|
|
19653
|
-
if (pendingIndex === -1) continue;
|
|
19654
|
-
const [{ name, id }] = pendingFunctionCalls.splice(pendingIndex, 1);
|
|
19655
|
-
const output = messageText(content) || "{}";
|
|
19656
|
-
pushOrMergeContent("user", [
|
|
19657
|
-
{
|
|
19658
|
-
functionResponse: {
|
|
19659
|
-
name,
|
|
19660
|
-
response: { output },
|
|
19661
|
-
// 保留 OpenAI tool_call_id:antigravity Cloud Code Assist 网关把
|
|
19662
|
-
// Gemini contents 转成 Claude messages 时需要 functionResponse →
|
|
19663
|
-
// tool_result 的 tool_use_id;缺 id 时网关报
|
|
19664
|
-
// "tool_result.tool_use_id: Field required"(HTTP 400)。
|
|
19665
|
-
...id ? { id } : {}
|
|
19666
|
-
}
|
|
19667
|
-
}
|
|
19668
|
-
]);
|
|
19669
|
-
}
|
|
19670
|
-
}
|
|
19671
|
-
flushPendingFunctionCalls();
|
|
19672
|
-
if (contents.length > 0 && contents[0]?.role === "model") {
|
|
19673
|
-
contents.unshift({
|
|
19674
|
-
role: "user",
|
|
19675
|
-
parts: [{ text: "Continue the conversation." }]
|
|
19676
|
-
});
|
|
19677
|
-
}
|
|
19678
|
-
return { contents, systemTexts };
|
|
19679
|
-
}
|
|
19680
|
-
function parseToolArgs(raw) {
|
|
19681
|
-
if (typeof raw === "string") {
|
|
19682
|
-
try {
|
|
19683
|
-
const parsed = JSON.parse(raw);
|
|
19684
|
-
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
19685
|
-
return parsed;
|
|
19686
|
-
}
|
|
19687
|
-
} catch {
|
|
19688
|
-
}
|
|
19689
|
-
}
|
|
19690
|
-
if (raw && typeof raw === "object" && !Array.isArray(raw)) {
|
|
19691
|
-
return raw;
|
|
19692
|
-
}
|
|
19693
|
-
return {};
|
|
19694
|
-
}
|
|
19695
|
-
function sanitizeGeminiSchemaNode(node, active) {
|
|
19696
|
-
const out = {};
|
|
19697
|
-
if (!node || typeof node !== "object" || Array.isArray(node)) {
|
|
19698
|
-
return { type: "string" };
|
|
19699
|
-
}
|
|
19700
|
-
if (active?.has(node)) {
|
|
19701
|
-
return { type: "object", description: "(circular schema reference)" };
|
|
19702
|
-
}
|
|
19703
|
-
const seen = active ?? /* @__PURE__ */ new WeakSet();
|
|
19704
|
-
seen.add(node);
|
|
19705
|
-
try {
|
|
19706
|
-
return sanitizeGeminiSchemaNodeInner(node, out, seen);
|
|
19707
|
-
} finally {
|
|
19708
|
-
seen.delete(node);
|
|
19709
|
-
}
|
|
19710
|
-
}
|
|
19711
|
-
function sanitizeGeminiSchemaNodeInner(src, out, seen) {
|
|
19712
|
-
if (Array.isArray(src.type)) {
|
|
19713
|
-
const firstNonNull = src.type.find((t) => t !== "null");
|
|
19714
|
-
if (typeof firstNonNull === "string") out.type = firstNonNull;
|
|
19715
|
-
out.nullable = true;
|
|
19716
|
-
} else if (typeof src.type === "string") {
|
|
19717
|
-
out.type = src.type;
|
|
19718
|
-
}
|
|
19719
|
-
if (typeof src.description === "string") out.description = src.description;
|
|
19720
|
-
if (typeof src.minimum === "number") out.minimum = src.minimum;
|
|
19721
|
-
if (typeof src.maximum === "number") out.maximum = src.maximum;
|
|
19722
|
-
if (Array.isArray(src.enum) && src.enum.length > 0) out.enum = src.enum;
|
|
19723
|
-
if (src.nullable === true) out.nullable = true;
|
|
19724
|
-
if ("const" in src && src.const !== void 0 && !out.enum) {
|
|
19725
|
-
out.enum = [src.const];
|
|
19726
|
-
}
|
|
19727
|
-
const variantBranches = [
|
|
19728
|
-
...Array.isArray(src.oneOf) ? src.oneOf : [],
|
|
19729
|
-
...Array.isArray(src.anyOf) ? src.anyOf : []
|
|
19730
|
-
];
|
|
19731
|
-
if (variantBranches.length > 0) {
|
|
19732
|
-
const mergedProperties = {};
|
|
19733
|
-
let requiredIntersection;
|
|
19734
|
-
for (const branch of variantBranches) {
|
|
19735
|
-
const sanitized = sanitizeGeminiSchemaNode(branch, seen);
|
|
19736
|
-
const branchProperties = sanitized.properties ?? {};
|
|
19737
|
-
for (const [key, value] of Object.entries(branchProperties)) {
|
|
19738
|
-
const previous = mergedProperties[key];
|
|
19739
|
-
const prevEnum = previous?.enum;
|
|
19740
|
-
const nextEnum = value?.enum;
|
|
19741
|
-
if (prevEnum && nextEnum) {
|
|
19742
|
-
mergedProperties[key] = {
|
|
19743
|
-
...value,
|
|
19744
|
-
enum: [.../* @__PURE__ */ new Set([...prevEnum, ...nextEnum])]
|
|
19745
|
-
};
|
|
19746
|
-
} else {
|
|
19747
|
-
mergedProperties[key] = value;
|
|
19748
|
-
}
|
|
19749
|
-
}
|
|
19750
|
-
const branchRequired = Array.isArray(sanitized.required) ? sanitized.required : [];
|
|
19751
|
-
requiredIntersection = requiredIntersection === void 0 ? [...branchRequired] : requiredIntersection.filter((r) => branchRequired.includes(r));
|
|
19752
|
-
}
|
|
19753
|
-
out.properties = {
|
|
19754
|
-
...out.properties ?? {},
|
|
19755
|
-
...mergedProperties
|
|
19756
|
-
};
|
|
19757
|
-
if (requiredIntersection !== void 0 && requiredIntersection.length > 0) {
|
|
19758
|
-
out.required = requiredIntersection;
|
|
19759
|
-
}
|
|
19760
|
-
if (typeof out.type !== "string") out.type = "object";
|
|
19761
|
-
}
|
|
19762
|
-
if (Array.isArray(src.allOf)) {
|
|
19763
|
-
for (const branch of src.allOf) {
|
|
19764
|
-
const sanitized = sanitizeGeminiSchemaNode(branch, seen);
|
|
19765
|
-
out.properties = {
|
|
19766
|
-
...out.properties ?? {},
|
|
19767
|
-
...sanitized.properties ?? {}
|
|
19768
|
-
};
|
|
19769
|
-
if (Array.isArray(sanitized.required)) {
|
|
19770
|
-
out.required = [
|
|
19771
|
-
.../* @__PURE__ */ new Set([
|
|
19772
|
-
...out.required ?? [],
|
|
19773
|
-
...sanitized.required ?? []
|
|
19774
|
-
])
|
|
19775
|
-
];
|
|
19776
|
-
}
|
|
19777
|
-
}
|
|
19778
|
-
if (typeof out.type !== "string") out.type = "object";
|
|
19779
|
-
}
|
|
19780
|
-
if (src.properties && typeof src.properties === "object") {
|
|
19781
|
-
const properties = {};
|
|
19782
|
-
for (const [key, value] of Object.entries(
|
|
19783
|
-
src.properties
|
|
19784
|
-
)) {
|
|
19785
|
-
properties[key] = sanitizeGeminiSchemaNode(value, seen);
|
|
19786
|
-
}
|
|
19787
|
-
out.properties = properties;
|
|
19788
|
-
if (typeof out.type !== "string") out.type = "object";
|
|
19789
|
-
}
|
|
19790
|
-
if (Array.isArray(src.required)) {
|
|
19791
|
-
const properties = out.properties ?? {};
|
|
19792
|
-
const required = [...new Set(src.required)].filter(
|
|
19793
|
-
(r) => typeof r === "string" && r in properties
|
|
19794
|
-
);
|
|
19795
|
-
if (required.length > 0) out.required = required;
|
|
19796
|
-
}
|
|
19797
|
-
if (src.items !== void 0) {
|
|
19798
|
-
out.items = sanitizeGeminiSchemaNode(src.items, seen);
|
|
19799
|
-
if (typeof out.type !== "string") out.type = "array";
|
|
19800
|
-
}
|
|
19801
|
-
if (typeof out.type !== "string") out.type = "object";
|
|
19802
|
-
return out;
|
|
19803
|
-
}
|
|
19804
|
-
function convertOpenAiToolsToGemini(tools) {
|
|
19805
|
-
if (!Array.isArray(tools) || tools.length === 0) return void 0;
|
|
19806
|
-
const declarations = [];
|
|
19807
|
-
for (const tool of tools) {
|
|
19808
|
-
if (!tool || typeof tool !== "object" || !("function" in tool)) continue;
|
|
19809
|
-
const fn3 = tool.function;
|
|
19810
|
-
const name = typeof fn3.name === "string" ? fn3.name : "";
|
|
19811
|
-
if (!name) continue;
|
|
19812
|
-
declarations.push({
|
|
19813
|
-
name,
|
|
19814
|
-
description: typeof fn3.description === "string" ? fn3.description : "",
|
|
19815
|
-
parameters: sanitizeGeminiSchemaNode(
|
|
19816
|
-
fn3.parameters ?? { type: "object", properties: {} }
|
|
19817
|
-
)
|
|
19818
|
-
});
|
|
19819
|
-
}
|
|
19820
|
-
if (declarations.length === 0) return void 0;
|
|
19821
|
-
return [{ functionDeclarations: declarations }];
|
|
19822
|
-
}
|
|
19823
|
-
function createGeminiAccumulatorState() {
|
|
19824
|
-
return {
|
|
19825
|
-
text: "",
|
|
19826
|
-
toolCalls: [],
|
|
19827
|
-
reasoning: "",
|
|
19828
|
-
events: []
|
|
19829
|
-
};
|
|
19830
|
-
}
|
|
19831
|
-
function applyGeminiChunk(chunk, state, options) {
|
|
19832
|
-
if (!chunk || typeof chunk !== "object") return;
|
|
19833
|
-
const response = "response" in chunk && chunk.response && typeof chunk.response === "object" ? chunk.response : chunk;
|
|
19834
|
-
if ("usageMetadata" in response && response.usageMetadata && typeof response.usageMetadata === "object") {
|
|
19835
|
-
const meta = response.usageMetadata;
|
|
19836
|
-
const prompt = typeof meta.promptTokenCount === "number" ? meta.promptTokenCount : 0;
|
|
19837
|
-
const candidates2 = typeof meta.candidatesTokenCount === "number" ? meta.candidatesTokenCount : 0;
|
|
19838
|
-
const total = typeof meta.totalTokenCount === "number" ? meta.totalTokenCount : prompt + candidates2;
|
|
19839
|
-
const cached3 = typeof meta.cachedContentTokenCount === "number" && Number.isFinite(meta.cachedContentTokenCount) ? (
|
|
19840
|
-
// cached ⊆ prompt;对畸形上游防御性钳位,避免 cache_read > input 破坏归一化与计费
|
|
19841
|
-
Math.min(Math.max(0, Math.floor(meta.cachedContentTokenCount)), prompt)
|
|
19842
|
-
) : 0;
|
|
19843
|
-
state.usage = {
|
|
19844
|
-
prompt_tokens: prompt,
|
|
19845
|
-
completion_tokens: candidates2,
|
|
19846
|
-
total_tokens: total,
|
|
19847
|
-
...cached3 > 0 ? { cache_read_input_tokens: cached3 } : {}
|
|
19848
|
-
};
|
|
19849
|
-
state.events.push({ kind: "usage", usage: state.usage });
|
|
19850
|
-
}
|
|
19851
|
-
const candidates = Array.isArray(response.candidates) ? response.candidates : [];
|
|
19852
|
-
for (const candidate of candidates) {
|
|
19853
|
-
if (!candidate || typeof candidate !== "object") continue;
|
|
19854
|
-
const candidateFinishReason = candidate.finishReason;
|
|
19855
|
-
if (typeof candidateFinishReason === "string" && candidateFinishReason.trim()) {
|
|
19856
|
-
state.finishReason = candidateFinishReason.trim();
|
|
19857
|
-
state.events.push({ kind: "finish", reason: state.finishReason });
|
|
19858
|
-
}
|
|
19859
|
-
const parts2 = Array.isArray(
|
|
19860
|
-
candidate.content?.parts
|
|
19861
|
-
) ? candidate.content.parts : [];
|
|
19862
|
-
for (const part of parts2) {
|
|
19863
|
-
if (!part || typeof part !== "object") continue;
|
|
19864
|
-
const partSignature = part.thoughtSignature;
|
|
19865
|
-
const isThought = Boolean(part.thought);
|
|
19866
|
-
if ("text" in part && typeof part.text === "string") {
|
|
19867
|
-
const piece = part.text;
|
|
19868
|
-
if (!isThought) {
|
|
19869
|
-
state.text += piece;
|
|
19870
|
-
if (piece) {
|
|
19871
|
-
state.events.push({ kind: "text", text: piece });
|
|
19872
|
-
if (options?.onTextDelta) options.onTextDelta(piece);
|
|
19873
|
-
}
|
|
19874
|
-
} else {
|
|
19875
|
-
state.reasoning += piece;
|
|
19876
|
-
if (piece) {
|
|
19877
|
-
state.events.push({ kind: "reasoning", text: piece });
|
|
19878
|
-
if (options?.onReasoningDelta) options.onReasoningDelta(piece);
|
|
19879
|
-
}
|
|
19880
|
-
}
|
|
19881
|
-
}
|
|
19882
|
-
if (isThought && typeof partSignature === "string" && partSignature) {
|
|
19883
|
-
state.pendingThoughtSignature = partSignature;
|
|
19884
|
-
}
|
|
19885
|
-
if ("functionCall" in part && part.functionCall) {
|
|
19886
|
-
const call = part.functionCall;
|
|
19887
|
-
const name = typeof call.name === "string" ? call.name : "tool";
|
|
19888
|
-
const id = typeof call.id === "string" ? call.id : `${name}_${state.toolCalls.length}`;
|
|
19889
|
-
const argsObj = call.args && typeof call.args === "object" ? call.args : {};
|
|
19890
|
-
const resolvedSignature = typeof partSignature === "string" && partSignature ? partSignature : state.pendingThoughtSignature;
|
|
19891
|
-
state.pendingThoughtSignature = void 0;
|
|
19892
|
-
const toolCall = {
|
|
19893
|
-
id,
|
|
19894
|
-
type: "function",
|
|
19895
|
-
function: { name, arguments: JSON.stringify(argsObj) },
|
|
19896
|
-
...typeof resolvedSignature === "string" && resolvedSignature ? { thought_signature: resolvedSignature } : {}
|
|
19897
|
-
};
|
|
19898
|
-
state.toolCalls.push(toolCall);
|
|
19899
|
-
state.events.push({ kind: "tool_call", toolCall });
|
|
19900
|
-
}
|
|
19901
|
-
}
|
|
19902
|
-
}
|
|
19903
|
-
}
|
|
19904
|
-
function accumulateGeminiChunks(chunks2, options) {
|
|
19905
|
-
const state = createGeminiAccumulatorState();
|
|
19906
|
-
for (const chunk of chunks2) {
|
|
19907
|
-
applyGeminiChunk(chunk, state, options);
|
|
19908
|
-
}
|
|
19909
|
-
return {
|
|
19910
|
-
text: state.text,
|
|
19911
|
-
toolCalls: state.toolCalls,
|
|
19912
|
-
usage: state.usage,
|
|
19913
|
-
finishReason: state.finishReason,
|
|
19914
|
-
reasoningContent: state.reasoning,
|
|
19915
|
-
events: state.events
|
|
19916
|
-
};
|
|
19917
|
-
}
|
|
19918
|
-
async function accumulateGeminiStream(stream, options) {
|
|
19919
|
-
const state = createGeminiAccumulatorState();
|
|
19920
|
-
for await (const chunk of stream) {
|
|
19921
|
-
applyGeminiChunk(chunk, state, options);
|
|
19922
|
-
}
|
|
19923
|
-
return {
|
|
19924
|
-
text: state.text,
|
|
19925
|
-
toolCalls: state.toolCalls,
|
|
19926
|
-
usage: state.usage,
|
|
19927
|
-
finishReason: state.finishReason,
|
|
19928
|
-
reasoningContent: state.reasoning,
|
|
19929
|
-
events: state.events
|
|
19930
|
-
};
|
|
19931
|
-
}
|
|
19932
|
-
function shouldUseGeminiNativeToolRoute(provider, model, tools, isImageModel) {
|
|
19933
|
-
return provider === "google" && !isImageModel(model) && isGemini3Model(model) && Array.isArray(tools) && tools.length > 0;
|
|
19934
|
-
}
|
|
19935
|
-
function buildGeminiGenerateContentRequest(args2) {
|
|
19936
|
-
const { contents, systemTexts } = convertOpenAiMessagesToGemini(
|
|
19937
|
-
args2.messages,
|
|
19938
|
-
{ attachSkipThoughtSignature: args2.attachSkipThoughtSignature }
|
|
19939
|
-
);
|
|
19940
|
-
const request3 = { contents };
|
|
19941
|
-
if (systemTexts.length > 0) {
|
|
19942
|
-
request3.systemInstruction = {
|
|
19943
|
-
role: "user",
|
|
19944
|
-
parts: systemTexts.map((text) => ({ text }))
|
|
19945
|
-
};
|
|
19946
|
-
}
|
|
19947
|
-
const toolsResult = convertOpenAiToolsToGemini(args2.tools);
|
|
19948
|
-
if (toolsResult) {
|
|
19949
|
-
request3.tools = toolsResult;
|
|
19950
|
-
request3.toolConfig = { functionCallingConfig: { mode: "VALIDATED" } };
|
|
19951
|
-
}
|
|
19952
|
-
const generationConfig = {};
|
|
19953
|
-
if (typeof args2.maxTokens === "number" && args2.maxTokens > 0) {
|
|
19954
|
-
generationConfig.maxOutputTokens = args2.maxTokens;
|
|
19955
|
-
}
|
|
19956
|
-
if (typeof args2.temperature === "number") {
|
|
19957
|
-
generationConfig.temperature = args2.temperature;
|
|
19958
|
-
}
|
|
19959
|
-
if (Object.keys(generationConfig).length > 0) {
|
|
19960
|
-
request3.generationConfig = generationConfig;
|
|
19961
|
-
}
|
|
19962
|
-
return request3;
|
|
19963
|
-
}
|
|
19964
|
-
|
|
19965
|
-
// packages/agent-runtime/antigravityCloudCodeProvider.ts
|
|
19966
|
-
var STREAM_PATH = "/v1internal:streamGenerateContent?alt=sse";
|
|
19967
|
-
function buildCloudCodeAssistPayload(args2) {
|
|
19968
|
-
const projectId = readAntigravityProjectId(args2.metadata);
|
|
19969
|
-
if (!projectId) {
|
|
19970
|
-
throw new Error(
|
|
19971
|
-
"Antigravity OAuth credential is missing metadata.projectId. Re-run `nolo auth antigravity`."
|
|
19972
|
-
);
|
|
19973
|
-
}
|
|
19974
|
-
const logicalModel = asOptionalTrimmedString(args2.openAiBody.model) ?? asOptionalTrimmedString(args2.agentConfig.model) ?? "gemini-3.1-pro";
|
|
19975
|
-
const { wireModelId: model, profile } = resolveAntigravityWireModel(logicalModel);
|
|
19976
|
-
const rawMessages = Array.isArray(args2.openAiBody.messages) ? args2.openAiBody.messages : [];
|
|
19977
|
-
const quirks = resolveGeminiModelQuirks(model);
|
|
19978
|
-
const isClaude = quirks.isClaudeCrossModel;
|
|
19979
|
-
const { contents, systemTexts } = convertOpenAiMessagesToGemini(rawMessages, {
|
|
19980
|
-
attachSkipThoughtSignature: quirks.allowsThoughtSignatureSentinel
|
|
19981
|
-
});
|
|
19982
|
-
if (contents.length === 0) {
|
|
19983
|
-
throw new Error("Antigravity Cloud Code Assist request has no user/model contents.");
|
|
19984
|
-
}
|
|
19985
|
-
const prompt = args2.agentConfig.prompt?.trim();
|
|
19986
|
-
if (prompt) systemTexts.unshift(prompt);
|
|
19987
|
-
const request3 = { contents };
|
|
19988
|
-
if (systemTexts.length > 0) {
|
|
19989
|
-
request3.systemInstruction = {
|
|
19990
|
-
role: "user",
|
|
19991
|
-
parts: systemTexts.map((text) => ({ text }))
|
|
19992
|
-
};
|
|
19993
|
-
}
|
|
19994
|
-
const tools = convertOpenAiToolsToGemini(
|
|
19995
|
-
Array.isArray(args2.openAiBody.tools) ? args2.openAiBody.tools : void 0
|
|
19996
|
-
);
|
|
19997
|
-
if (tools) {
|
|
19998
|
-
request3.tools = tools;
|
|
19999
|
-
request3.toolConfig = { functionCallingConfig: { mode: "VALIDATED" } };
|
|
20000
|
-
}
|
|
20001
|
-
const generationConfig = {};
|
|
20002
|
-
if (profile?.maxOutputTokens) {
|
|
20003
|
-
generationConfig.maxOutputTokens = profile.maxOutputTokens;
|
|
20004
|
-
} else if (typeof args2.agentConfig.max_tokens === "number" && args2.agentConfig.max_tokens > 0) {
|
|
20005
|
-
generationConfig.maxOutputTokens = args2.agentConfig.max_tokens;
|
|
20006
|
-
}
|
|
20007
|
-
if (typeof args2.agentConfig.temperature === "number") {
|
|
20008
|
-
generationConfig.temperature = args2.agentConfig.temperature;
|
|
20009
|
-
}
|
|
20010
|
-
if (Object.keys(generationConfig).length > 0) {
|
|
20011
|
-
request3.generationConfig = generationConfig;
|
|
20012
|
-
}
|
|
20013
|
-
const agentId = randomUUID();
|
|
20014
|
-
const trajectoryId = randomUUID();
|
|
20015
|
-
const step = 2;
|
|
20016
|
-
const requestId = `agent/${agentId}/${Date.now()}/${trajectoryId}/${step}`;
|
|
20017
|
-
const labels = {
|
|
20018
|
-
trajectory_id: trajectoryId,
|
|
20019
|
-
last_step_index: String(step - 1),
|
|
20020
|
-
used_claude: String(isClaude),
|
|
20021
|
-
used_claude_conservative: String(isClaude)
|
|
20022
|
-
};
|
|
20023
|
-
if (profile?.modelEnum) {
|
|
20024
|
-
labels.model_enum = profile.modelEnum;
|
|
20025
|
-
}
|
|
20026
|
-
request3.labels = labels;
|
|
20027
|
-
request3.sessionId = `-${Math.floor(Math.random() * 9e15)}`;
|
|
20028
|
-
return {
|
|
20029
|
-
url: `${resolveAntigravityCloudCodeBaseUrl(args2.agentConfig.customProviderUrl)}${STREAM_PATH}`,
|
|
20030
|
-
envelope: {
|
|
20031
|
-
project: projectId,
|
|
20032
|
-
model,
|
|
20033
|
-
request: request3,
|
|
20034
|
-
requestId,
|
|
20035
|
-
requestType: "agent",
|
|
20036
|
-
userAgent: "antigravity"
|
|
20037
|
-
}
|
|
20038
|
-
};
|
|
20039
|
-
}
|
|
20040
|
-
function resolveAntigravityFinishReason(upstream) {
|
|
20041
|
-
const normalized = (upstream ?? "").trim().toUpperCase();
|
|
20042
|
-
if (normalized === "MAX_TOKENS") return "length";
|
|
20043
|
-
if (normalized === "SAFETY" || normalized === "RECITATION" || normalized === "PROHIBITED_CONTENT" || normalized === "BLOCKLIST") {
|
|
20044
|
-
return "content_filter";
|
|
20045
|
-
}
|
|
20046
|
-
return "stop";
|
|
20047
|
-
}
|
|
20048
|
-
function normalizeAntigravityCompletion(decoded) {
|
|
20049
|
-
const { text, toolCalls, usage, finishReason, reasoningContent, events } = decoded;
|
|
20050
|
-
const normalizedFinishReason = (finishReason ?? "").trim().toUpperCase();
|
|
20051
|
-
if (!text && !reasoningContent && toolCalls.length === 0 && !finishReason && !usage) {
|
|
20052
|
-
const body = {
|
|
20053
|
-
error: {
|
|
20054
|
-
message: "antigravity upstream returned an empty stream (no content, finishReason or usage); channel degradation, not model emptiness"
|
|
20055
|
-
},
|
|
20056
|
-
provider_events: events
|
|
20057
|
-
};
|
|
20058
|
-
return {
|
|
20059
|
-
status: 502,
|
|
20060
|
-
text: "",
|
|
20061
|
-
toolCalls: [],
|
|
20062
|
-
providerEvents: events,
|
|
20063
|
-
body
|
|
20064
|
-
};
|
|
20065
|
-
}
|
|
20066
|
-
if (normalizedFinishReason === "MALFORMED_FUNCTION_CALL") {
|
|
20067
|
-
const message2 = "antigravity upstream returned MALFORMED_FUNCTION_CALL (model generated an invalid function call or tool arguments were rejected by upstream)";
|
|
20068
|
-
const providerFailure = {
|
|
20069
|
-
kind: "provider_failure",
|
|
20070
|
-
provider: "antigravity",
|
|
20071
|
-
code: "MALFORMED_FUNCTION_CALL",
|
|
20072
|
-
message: message2,
|
|
20073
|
-
providerReason: "MALFORMED_FUNCTION_CALL",
|
|
20074
|
-
retryable: false,
|
|
20075
|
-
status: 502
|
|
20076
|
-
};
|
|
20077
|
-
return {
|
|
20078
|
-
status: 502,
|
|
20079
|
-
text: "",
|
|
20080
|
-
toolCalls: [],
|
|
20081
|
-
finishReason,
|
|
20082
|
-
providerEvents: events,
|
|
20083
|
-
providerFailure,
|
|
20084
|
-
runtimeProviderFailure: {
|
|
20085
|
-
message: providerFailure.message,
|
|
20086
|
-
retryable: providerFailure.retryable
|
|
20087
|
-
},
|
|
20088
|
-
body: {
|
|
20089
|
-
error: {
|
|
20090
|
-
message: message2,
|
|
20091
|
-
code: "MALFORMED_FUNCTION_CALL",
|
|
20092
|
-
category: "malformed_function_call",
|
|
20093
|
-
providerReason: "MALFORMED_FUNCTION_CALL",
|
|
20094
|
-
retryable: false
|
|
20095
|
-
},
|
|
20096
|
-
provider_failure: providerFailure,
|
|
20097
|
-
provider_events: events
|
|
20098
|
-
}
|
|
20099
|
-
};
|
|
20100
|
-
}
|
|
20101
|
-
const message = {
|
|
20102
|
-
role: "assistant",
|
|
20103
|
-
content: text || null
|
|
20104
|
-
};
|
|
20105
|
-
if (toolCalls.length > 0) message.tool_calls = toolCalls;
|
|
20106
|
-
if (reasoningContent) message.reasoning_content = reasoningContent;
|
|
20107
|
-
return {
|
|
20108
|
-
status: 200,
|
|
20109
|
-
text,
|
|
20110
|
-
...reasoningContent ? { reasoningContent } : {},
|
|
20111
|
-
toolCalls,
|
|
20112
|
-
...usage ? { usage } : {},
|
|
20113
|
-
...finishReason ? { finishReason } : {},
|
|
20114
|
-
providerEvents: events,
|
|
20115
|
-
body: {
|
|
20116
|
-
choices: [{
|
|
20117
|
-
index: 0,
|
|
20118
|
-
message,
|
|
20119
|
-
finish_reason: toolCalls.length > 0 ? "tool_calls" : resolveAntigravityFinishReason(finishReason)
|
|
20120
|
-
}],
|
|
20121
|
-
...usage ? { usage } : {},
|
|
20122
|
-
provider_events: events
|
|
20123
|
-
}
|
|
20124
|
-
};
|
|
20125
|
-
}
|
|
20126
|
-
async function fetchAntigravityCloudCodeCompletion(args2) {
|
|
20127
|
-
const fetchImpl = args2.fetchImpl ?? fetch;
|
|
20128
|
-
const { url, envelope } = buildCloudCodeAssistPayload(args2);
|
|
20129
|
-
const response = await fetchImpl(url, {
|
|
20130
|
-
method: "POST",
|
|
20131
|
-
headers: {
|
|
20132
|
-
Authorization: `Bearer ${args2.accessToken}`,
|
|
20133
|
-
"Content-Type": "application/json",
|
|
20134
|
-
"User-Agent": getAntigravityUserAgent()
|
|
20135
|
-
},
|
|
20136
|
-
body: JSON.stringify(envelope),
|
|
20137
|
-
signal: args2.signal
|
|
20138
|
-
});
|
|
20139
|
-
if (!response.ok) {
|
|
20140
|
-
const errorText = await response.text();
|
|
20141
|
-
return {
|
|
20142
|
-
status: response.status,
|
|
20143
|
-
text: "",
|
|
20144
|
-
toolCalls: [],
|
|
20145
|
-
providerEvents: [],
|
|
20146
|
-
// 保留上游结构:Antigravity 的限流 body 同样携带结构化的重置信息,
|
|
20147
|
-
// 压成字符串会让冷却退化成 5 分钟默认值。
|
|
20148
|
-
body: parseUpstreamErrorBody(errorText, response.statusText)
|
|
20149
|
-
};
|
|
20150
|
-
}
|
|
20151
|
-
const chunkStream = streamSseDataValues(response, parseSseDataLineJson);
|
|
20152
|
-
const { text, toolCalls, usage, finishReason, reasoningContent, events } = await accumulateGeminiStream(chunkStream, {
|
|
20153
|
-
onTextDelta: args2.onTextDelta,
|
|
20154
|
-
onReasoningDelta: args2.onReasoningDelta
|
|
20155
|
-
});
|
|
20156
|
-
const normalized = normalizeAntigravityCompletion({
|
|
20157
|
-
text,
|
|
20158
|
-
toolCalls,
|
|
20159
|
-
usage,
|
|
20160
|
-
finishReason,
|
|
20161
|
-
reasoningContent,
|
|
20162
|
-
events
|
|
20163
|
-
});
|
|
20164
|
-
if (normalized.status !== 200 || !text && toolCalls.length === 0) {
|
|
20165
|
-
console.warn(
|
|
20166
|
-
`[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}`
|
|
20167
|
-
);
|
|
20168
|
-
}
|
|
20169
|
-
return normalized;
|
|
20170
|
-
}
|
|
20171
|
-
|
|
20172
20051
|
// packages/agent-runtime/devin/devinProvider.ts
|
|
20173
|
-
import { randomBytes, randomUUID
|
|
20052
|
+
import { randomBytes, randomUUID } from "node:crypto";
|
|
20174
20053
|
var CLIENT_NAME = "chisel";
|
|
20175
|
-
var CLIENT_VERSION = "
|
|
20054
|
+
var CLIENT_VERSION = "3000.11.3";
|
|
20176
20055
|
function writeVarint(fieldNum, value) {
|
|
20177
20056
|
const tag = fieldNum << 3 | 0;
|
|
20178
20057
|
const bytes = [];
|
|
@@ -20232,7 +20111,7 @@ function encodeDevinClientMetadata(token) {
|
|
|
20232
20111
|
function encodeDevinChatMessage(msg) {
|
|
20233
20112
|
const source = msg.role === "assistant" ? 2 : msg.role === "tool" ? 4 : 1;
|
|
20234
20113
|
return Buffer.concat([
|
|
20235
|
-
writeStringField(1,
|
|
20114
|
+
writeStringField(1, randomUUID()),
|
|
20236
20115
|
writeVarint(2, source),
|
|
20237
20116
|
writeStringField(3, msg.text),
|
|
20238
20117
|
...(msg.toolCalls ?? []).map(
|
|
@@ -20320,7 +20199,7 @@ ${item.text}`;
|
|
|
20320
20199
|
const chatMessageBuffers = coalesced.map((m) => encodeDevinChatMessage(m));
|
|
20321
20200
|
const completionConfig = buildCompletionConfig({ temperature });
|
|
20322
20201
|
const modelConfig = Buffer.concat([
|
|
20323
|
-
writeStringField(1,
|
|
20202
|
+
writeStringField(1, randomUUID()),
|
|
20324
20203
|
writeVarint(2, 1),
|
|
20325
20204
|
writeVarint(3, 4)
|
|
20326
20205
|
]);
|
|
@@ -20332,7 +20211,7 @@ ${item.text}`;
|
|
|
20332
20211
|
writeMessageField(8, completionConfig),
|
|
20333
20212
|
...tools.map((tool) => writeMessageField(10, encodeDevinToolDefinition(tool))),
|
|
20334
20213
|
writeMessageField(15, modelConfig),
|
|
20335
|
-
writeStringField(16,
|
|
20214
|
+
writeStringField(16, randomUUID()),
|
|
20336
20215
|
writeVarint(20, 1),
|
|
20337
20216
|
writeStringField(21, model)
|
|
20338
20217
|
]);
|
|
@@ -20547,6 +20426,11 @@ function decodeDevinResponsePayload(payload) {
|
|
|
20547
20426
|
}
|
|
20548
20427
|
return { content, reasoning, finishReason, events, usage };
|
|
20549
20428
|
}
|
|
20429
|
+
function isMeaningfulDevinEvent(event) {
|
|
20430
|
+
if (event.type === "reasoning" || event.type === "content") return event.text.length > 0;
|
|
20431
|
+
if (event.type === "tool-call-start") return !!event.name;
|
|
20432
|
+
return event.argsDelta.length > 0;
|
|
20433
|
+
}
|
|
20550
20434
|
function createDevinProvider(options) {
|
|
20551
20435
|
const { token, model = "swe-2-max", fetchImpl = fetch, tools = [], temperature } = options;
|
|
20552
20436
|
return {
|
|
@@ -20561,6 +20445,7 @@ function createDevinProvider(options) {
|
|
|
20561
20445
|
temperature
|
|
20562
20446
|
});
|
|
20563
20447
|
const frame = buildDevinConnectFrame(requestPayload);
|
|
20448
|
+
const timingTracker = createProviderCallTimingTracker();
|
|
20564
20449
|
const response = await fetchImpl(DEVIN_CONNECT_URL, {
|
|
20565
20450
|
method: "POST",
|
|
20566
20451
|
headers: {
|
|
@@ -20618,6 +20503,7 @@ function createDevinProvider(options) {
|
|
|
20618
20503
|
reasoning += delta.reasoning;
|
|
20619
20504
|
if (delta.finishReason) finishReason = delta.finishReason;
|
|
20620
20505
|
for (const event of delta.events) {
|
|
20506
|
+
if (isMeaningfulDevinEvent(event)) observeMeaningfulProviderResponse(timingTracker);
|
|
20621
20507
|
if (event.type === "reasoning") {
|
|
20622
20508
|
opts?.onReasoningDelta?.(event.text);
|
|
20623
20509
|
} else if (event.type === "content") {
|
|
@@ -20666,13 +20552,14 @@ function createDevinProvider(options) {
|
|
|
20666
20552
|
if (!text && !reasoning && toolCalls.length === 0) {
|
|
20667
20553
|
throw new Error("Devin Connect upstream completed without content or tool calls");
|
|
20668
20554
|
}
|
|
20669
|
-
const
|
|
20555
|
+
const timing = finalizeProviderCallTiming(timingTracker);
|
|
20556
|
+
const usage = frameUsage ? withProviderCallTimingFields({
|
|
20670
20557
|
prompt_tokens: frameUsage.prompt + frameUsage.cacheRead,
|
|
20671
20558
|
completion_tokens: frameUsage.completion ?? 0,
|
|
20672
20559
|
total_tokens: frameUsage.prompt + frameUsage.cacheRead + (frameUsage.completion ?? 0) + frameUsage.cacheWrite,
|
|
20673
20560
|
...frameUsage.cacheRead > 0 ? { prompt_tokens_details: { cached_tokens: frameUsage.cacheRead } } : {},
|
|
20674
20561
|
...frameUsage.cacheWrite > 0 ? { cache_creation_input_tokens: frameUsage.cacheWrite } : {}
|
|
20675
|
-
} : void 0;
|
|
20562
|
+
}, timing) : void 0;
|
|
20676
20563
|
return {
|
|
20677
20564
|
content: text,
|
|
20678
20565
|
model: selectedModel,
|
|
@@ -20694,20 +20581,16 @@ function createDevinProvider(options) {
|
|
|
20694
20581
|
}
|
|
20695
20582
|
|
|
20696
20583
|
export {
|
|
20584
|
+
readCommandActionGatePayload,
|
|
20585
|
+
readActionGate,
|
|
20697
20586
|
Option_exports,
|
|
20698
20587
|
Duration_exports,
|
|
20699
20588
|
Exit_exports,
|
|
20700
20589
|
Effect_exports,
|
|
20701
|
-
readCommandActionGatePayload,
|
|
20702
|
-
readActionGate,
|
|
20703
|
-
evaluateFileWritePolicy,
|
|
20704
|
-
summarizeToolArguments,
|
|
20705
20590
|
formatToolOverflowMarker,
|
|
20706
20591
|
LOCAL_AGENT_CONFIG_MISSING_CODE,
|
|
20707
20592
|
LOCAL_TURN_ABORTED_CODE,
|
|
20708
20593
|
runLocalAgentTurn,
|
|
20709
|
-
parseSseDataLineJson,
|
|
20710
|
-
parseSseDataLineObject,
|
|
20711
20594
|
codexStreamFailureStatus,
|
|
20712
20595
|
aggregateResponsesStream,
|
|
20713
20596
|
buildOpenAiCompatibleChatCompletionRequest,
|
|
@@ -20723,8 +20606,6 @@ export {
|
|
|
20723
20606
|
createHybridRecordStore,
|
|
20724
20607
|
isDestructiveShellCommand,
|
|
20725
20608
|
evaluateShellCommandPolicy,
|
|
20726
|
-
resolveLocalToolPolicy,
|
|
20727
|
-
executeLocalToolWithPolicy,
|
|
20728
20609
|
filterRetainedLedgerRecords,
|
|
20729
20610
|
isLineRangeCovered,
|
|
20730
20611
|
getProcessRegistry,
|
|
@@ -20735,17 +20616,14 @@ export {
|
|
|
20735
20616
|
internalSearchWorkspace,
|
|
20736
20617
|
internalListWorkspaceEntries,
|
|
20737
20618
|
createLocalWorkspaceToolExecutors,
|
|
20619
|
+
buildToolParametersIndex,
|
|
20620
|
+
getAgentRuntimeToolParametersIndex,
|
|
20621
|
+
resolveLocalToolPolicy,
|
|
20622
|
+
executeLocalToolWithPolicy,
|
|
20738
20623
|
localDialogMessageRecordToRuntimeMessage,
|
|
20739
20624
|
buildLocalDialogWritePlan,
|
|
20740
20625
|
buildNoloWorkspaceCliToolExecutors,
|
|
20741
20626
|
buildLoadSkillExecutor,
|
|
20742
|
-
parseUpstreamErrorBody,
|
|
20743
|
-
isGemini3Model,
|
|
20744
|
-
accumulateGeminiChunks,
|
|
20745
|
-
shouldUseGeminiNativeToolRoute,
|
|
20746
|
-
buildGeminiGenerateContentRequest,
|
|
20747
|
-
resolveAntigravityFinishReason,
|
|
20748
|
-
fetchAntigravityCloudCodeCompletion,
|
|
20749
20627
|
readDevinUpstreamFailure,
|
|
20750
20628
|
createDevinProvider
|
|
20751
20629
|
};
|