nolo-cli 0.91.0-alpha.1 → 0.91.1
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-U5V7LOJX.js → _executeModel-H35GQ2XO.js} +61 -60
- package/{action-EXQVY3UO.js → action-3ZOODRBC.js} +11 -11
- package/{addContentAction-6IXQSRD2.js → addContentAction-IJHG2ZV7.js} +9 -9
- package/{addDialogAgentAction-FZOB4BYM.js → addDialogAgentAction-IGFS2UBX.js} +11 -11
- package/{agentDeleteCommand-4MIJFQQB.js → agentDeleteCommand-XOFMXMHW.js} +43 -42
- package/{agentEmailCommands-JUXT36BY.js → agentEmailCommands-H2SEP6ZQ.js} +82 -78
- package/{agentGrantCommands-YW6PQAQ2.js → agentGrantCommands-M3XFO6EN.js} +2 -2
- package/{agentListCommands-MUVKMMZ5.js → agentListCommands-RYGH6NUL.js} +72 -80
- package/{agentMachineCommands-56FTZLYV.js → agentMachineCommands-XELOBZIP.js} +37 -36
- package/{agentProviderCommands-TOMVKJOV.js → agentProviderCommands-JCRK6ST2.js} +1 -1
- package/{agentPullCommand-GLOOXJ2E.js → agentPullCommand-HF4A42D4.js} +3 -3
- package/agentRecordCommands-43HAXAZO.js +130 -0
- package/{agentRunCommand-UMUEVIY2.js → agentRunCommand-GIPN6DBO.js} +80 -75
- package/{agentRunControl-XLGD3UZ5.js → agentRunControl-AVJR4JW4.js} +2 -2
- package/{agentRuntimeLocal-NH6GSGAJ.js → agentRuntimeLocal-SDOSSCLU.js} +38 -33
- package/{agentSlice-YZK6KG73.js → agentSlice-B2DLZMAC.js} +11 -11
- package/{appDeleteCommands-U45KXYX7.js → appDeleteCommands-7OR5MAOR.js} +37 -36
- package/{appDeployCommands-LWQIQCFX.js → appDeployCommands-5GNI723H.js} +37 -36
- package/{appDeployStatusCommands-LZO33PGD.js → appDeployStatusCommands-WL2NG3SG.js} +37 -36
- package/{appGetCommands-OJSO6BCF.js → appGetCommands-7BVKQS44.js} +37 -36
- package/{appListCommands-NE56V7DI.js → appListCommands-5VXFJOBU.js} +37 -36
- package/{authCommand-U5LA6H4Y.js → authCommand-N4Q6463J.js} +115 -23
- package/{authCommands-RGOGCPP6.js → authCommands-GBIFZWD3.js} +5 -5
- package/{builtinSkillRegistry-4NB7PCOF.js → builtinSkillRegistry-JPY2DKRF.js} +7 -7
- package/{chatQueueReduxAdapter-FRMSYX7N.js → chatQueueReduxAdapter-3KDRKXTT.js} +29 -29
- package/{chromeCommands-VOIRNJBL.js → chromeCommands-NKU3OWKH.js} +36 -11
- package/{chromeOpsCommands-M7DPCX2T.js → chromeOpsCommands-OQDJGD4Y.js} +31 -1
- package/{chunk-R2YY6MWV.js → chunk-232453C2.js} +994 -1036
- package/{chunk-HWZAXNO7.js → chunk-25GAGMRK.js} +6 -83
- package/{chunk-DM4UNXPK.js → chunk-3IYMTWYZ.js} +22 -22
- package/{chunk-NTW5GWDM.js → chunk-3VNWWVKB.js} +2 -0
- package/{chunk-X2ZTVRXP.js → chunk-46CRK7XP.js} +7 -7
- package/{chunk-WKEUHK57.js → chunk-55VQ4OPL.js} +4 -4
- package/{chunk-JPGCXHNM.js → chunk-5OA5HMTL.js} +1 -1
- package/{chunk-DWUCB2A3.js → chunk-62IL3KQV.js} +4 -34
- package/{chunk-4JBZUECA.js → chunk-64TIEZHF.js} +1 -1
- package/{chunk-6YTOJY35.js → chunk-6D2JFXLY.js} +35 -0
- package/{chunk-3BMYXEUW.js → chunk-6O4IK4V2.js} +1 -1
- package/{chunk-UBNV6CS6.js → chunk-6PELJ3DS.js} +533 -236
- package/{chunk-7IBK6MYW.js → chunk-7EMJBGCA.js} +966 -218
- package/{chunk-YPYMGGPJ.js → chunk-7YMUSSHQ.js} +93 -93
- package/chunk-ACTMNVHM.js +93 -0
- package/{chunk-Q554LLSI.js → chunk-AUDNYVRC.js} +1 -1
- package/{chunk-UKWGR5SS.js → chunk-AUXHZ2M5.js} +186 -397
- package/{chunk-377KM42Z.js → chunk-B4PW6UAI.js} +61 -34
- package/{chunk-XLGHBHGP.js → chunk-B7ANJQWZ.js} +2 -2
- package/{chunk-COM7GG76.js → chunk-BAAKVSMZ.js} +4 -4
- package/{chunk-QMASIHYZ.js → chunk-BFCXG6AJ.js} +16 -16
- package/{chunk-KR3YI36B.js → chunk-BJUDYFV5.js} +10 -2
- package/chunk-BMQ2MJUK.js +153 -0
- package/{chunk-XGJAR4T5.js → chunk-BNGW5ASC.js} +65 -4
- package/{chunk-VOOTT7HA.js → chunk-BTSYHR7J.js} +4 -4
- package/{chunk-LS2ZANRJ.js → chunk-CTUQJVQM.js} +1 -1
- package/{chunk-JEDZAO7L.js → chunk-D2W6WRHT.js} +13 -8
- package/{chunk-U47DH2WO.js → chunk-D76D3RTR.js} +2 -2
- package/{chunk-HQCSU3DI.js → chunk-DCLMZ5TX.js} +4 -4
- package/{chunk-OOLWKQSM.js → chunk-EFZKILX6.js} +4 -4
- package/{chunk-WP6BC7OF.js → chunk-EHO5EGU4.js} +23 -76
- package/{chunk-HVURBGF3.js → chunk-ESRMFY7G.js} +2 -2
- package/{chunk-ABQYVJBJ.js → chunk-ETZWFV6M.js} +1 -1
- package/{chunk-TRV2MIDW.js → chunk-EXAJ6DCR.js} +1 -0
- package/{chunk-BF2K6MRF.js → chunk-F64B2W3R.js} +110 -34
- package/{chunk-S3UI4IUJ.js → chunk-G4EMOUX3.js} +886 -154
- package/{chunk-B4S7MR5S.js → chunk-GJUKGFHG.js} +74 -16
- package/{chunk-LSSBA2TN.js → chunk-GMVELWJG.js} +3 -3
- package/chunk-GMZLP5DV.js +82 -0
- package/{chunk-CJCJF5XB.js → chunk-H6A6X4EK.js} +36 -3
- package/{chunk-DSX6K7C2.js → chunk-HBTA2SGQ.js} +97 -21
- package/{chunk-ONXOABJR.js → chunk-HNGRBWYF.js} +3 -0
- package/{chunk-W2E6HIIK.js → chunk-HNRASX3X.js} +8 -8
- package/{chunk-CPH3W5A7.js → chunk-I3TQJXQ7.js} +94 -3
- package/{chunk-E3VQ6S3A.js → chunk-IS5VEM2G.js} +140 -15
- package/{chunk-NKIH4Q7W.js → chunk-ISHYYQJC.js} +5 -3
- package/{chunk-RLEWGSM5.js → chunk-K7M4I3PF.js} +30 -7
- package/{chunk-OH7H6LPC.js → chunk-KQOD3G2X.js} +165 -15
- package/{chunk-YOXYA2GU.js → chunk-LNPYTNMG.js} +10 -5
- package/{chunk-GRDSMV4V.js → chunk-LS2MI3B4.js} +45 -45
- package/{chunk-GII32WZW.js → chunk-M2EJHDJP.js} +3 -0
- package/{chunk-7S4YWN7P.js → chunk-MX574M24.js} +1 -1
- package/{chunk-RZYQMSQA.js → chunk-N3XA2O6O.js} +1 -1
- package/{chunk-SASGLNUD.js → chunk-NILSKYOE.js} +3 -3
- package/chunk-OCZKATRC.js +129 -0
- package/{chunk-MBEEYLGL.js → chunk-OOSVFT6S.js} +2 -2
- package/{chunk-QCZX4FTW.js → chunk-OY5IJI2N.js} +194 -21
- package/{chunk-SUERPXJZ.js → chunk-PAYUVQ6P.js} +7517 -1091
- package/{chunk-JTYPAMGP.js → chunk-Q67DOFOO.js} +59 -4
- package/{chunk-F3UTRUDO.js → chunk-QALRKMHF.js} +11 -10
- package/{chunk-546FPOW3.js → chunk-QDSINZM3.js} +1 -1
- package/{chunk-TMAZ3VHN.js → chunk-QJLEMM2V.js} +1 -1
- package/{chunk-IIKPWSPX.js → chunk-R4SQ3LGW.js} +1 -1
- package/{chunk-E2NP7ZQU.js → chunk-RZ6CQZB2.js} +34 -20
- package/{chunk-SAFZABH7.js → chunk-SV5IJK6K.js} +1 -1
- package/{chunk-AQDH76OK.js → chunk-T5V7HA3K.js} +1 -1
- package/{chunk-BYMV6QZG.js → chunk-TNIX77YM.js} +4 -0
- package/chunk-UNYJU5L6.js +780 -0
- package/{chunk-QFMFJZLO.js → chunk-V7E4PXQD.js} +1 -1
- package/{chunk-G5X57NDE.js → chunk-VBSVA6CB.js} +2 -2
- package/{chunk-3XMOAYRC.js → chunk-VETFWL5K.js} +1 -1
- package/chunk-VJVNU77E.js +83 -0
- package/{chunk-6D6VBVEW.js → chunk-VPFEPRME.js} +9 -9
- package/{chunk-HGRDL36J.js → chunk-W2P25VGS.js} +25 -6
- package/{chunk-XAQAF25W.js → chunk-WC6A2Q7S.js} +5 -3
- package/{chunk-WON762L4.js → chunk-WT2IAJAJ.js} +4 -4
- package/chunk-X6YIXGPT.js +870 -0
- package/{chunk-ZKMYGRO7.js → chunk-YMPTI7RZ.js} +9 -9
- package/{chunk-BKP7CFUD.js → chunk-YRIFJ6XQ.js} +13 -13
- package/{chunk-FZGV4FGK.js → chunk-YRRASA5Q.js} +268 -143
- package/{chunk-UDEFS2PV.js → chunk-Z5W7UMQV.js} +2 -2
- package/{chunk-ZHUTWJ3N.js → chunk-ZGJLSHER.js} +2 -2
- package/{chunk-4CAPEGHN.js → chunk-ZI2MEZMT.js} +304 -136
- package/{chunk-2F7RJC6L.js → chunk-ZOVKKMF6.js} +1 -1
- package/commandRegistry-BP5JLW24.js +822 -0
- package/{contentThunks-TC3AENBY.js → contentThunks-2HYFUXUM.js} +29 -29
- package/{cooldownCommands-BSCH2W7P.js → cooldownCommands-ZLEPIB4A.js} +2 -2
- package/{createAgentAutomationAction-67EOD3WK.js → createAgentAutomationAction-DCKUSJH7.js} +29 -29
- package/{createDialogAction-4OCQC5MW.js → createDialogAction-NRIAEH2A.js} +32 -32
- package/{createPageAction-JLGVP57B.js → createPageAction-AUJHHXGG.js} +35 -35
- package/{dbSlice-RDGCE5MU.js → dbSlice-HFPIJT5P.js} +8 -8
- package/{deleteFile-YG6QMJLU.js → deleteFile-UEAD5A5Z.js} +3 -3
- package/{dialogCommands-JHSDKCR5.js → dialogCommands-UJRGCRN6.js} +42 -39
- package/{dialogSlice-I2DK32ZT.js → dialogSlice-AHU4XXIW.js} +35 -29
- package/{dist-VODFSGNG.js → dist-NJC2W7I4.js} +61 -54
- package/{docCreateCommands-QUL6VWK2.js → docCreateCommands-ZOV3ZBLW.js} +39 -38
- package/{docDeleteCommands-DMQ2MU6I.js → docDeleteCommands-G4KAXJYQ.js} +39 -38
- package/{docReadCommands-FVHENBU6.js → docReadCommands-B2MM3JIT.js} +38 -37
- package/{docStore-OLC6MD7B.js → docStore-SITH63V3.js} +9 -9
- package/{docUpdateCommands-VA6V5C6L.js → docUpdateCommands-2QNF5CYN.js} +39 -38
- package/{fetchMessages-EIU7UFFK.js → fetchMessages-67MEFPZR.js} +2 -2
- package/{getPricing-YYXTEPBP.js → getPricing-OX7B4R6B.js} +3 -3
- package/{handleSendMessageAction-GRDIRXAK.js → handleSendMessageAction-7ZMJMWLC.js} +72 -80
- package/index.js +74 -877
- 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-IJJ66MYU.js → machineCommands-YCTD5KOL.js} +75 -71
- package/{machineWsRunDispatch-PP2ZBS6D.js → machineWsRunDispatch-JFMD4ZAW.js} +73 -69
- package/{memberThunks-WQGQWYYT.js → memberThunks-SKFZ37VS.js} +9 -9
- package/{models-UN7YGMPM.js → models-T3SG6MJ5.js} +2 -2
- package/oauthTokenStore-ITEB663N.js +23 -0
- package/{offlineMarxistsAgentCommand-JEWCIAWM.js → offlineMarxistsAgentCommand-HGXZV4XJ.js} +1 -1
- 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-NO73BG45.js → providerPresetApply-2QTBYN36.js} +7 -7
- package/{providerRegistry-OVY4VKNN.js → providerRegistry-SVXE4G4T.js} +7 -7
- package/{read-S4WC2OUK.js → read-IEJLLUXY.js} +5 -5
- package/{readDocTool-PQNM63KV.js → readDocTool-4SPYCP2Y.js} +5 -3
- package/{readlineWorkspace-ASJECDJD.js → readlineWorkspace-M3PLTBLD.js} +2396 -2018
- package/{removeDialogAgentAction-YJZ6XJV6.js → removeDialogAgentAction-LILXTOQY.js} +14 -14
- package/{runAgentClientLoop-KIOQSDRC.js → runAgentClientLoop-QMCXBOBH.js} +55 -55
- package/{runtimeDoctorCommands-X6WDBEQX.js → runtimeDoctorCommands-3USD722U.js} +3 -3
- package/runtimeModeArgs-2Y7BALTO.js +31 -0
- package/{setDialogExtraReferencesAction-E6A3WL4E.js → setDialogExtraReferencesAction-LVNHLNT5.js} +10 -10
- package/{setPrimaryDialogAgentAction-WBLIVICQ.js → setPrimaryDialogAgentAction-DCKO5NTW.js} +14 -14
- package/{settingSlice-JR6S7TRD.js → settingSlice-CNE75ISY.js} +10 -10
- package/{spaceCommands-WDUNCAK5.js → spaceCommands-3U6OHM6O.js} +39 -38
- package/{streamAgentChatTurn-EGQDPMAO.js → streamAgentChatTurn-JPMJQSEE.js} +144 -84
- package/{switchDialogAgentAction-DTR36ZY2.js → switchDialogAgentAction-JSYUQ5CG.js} +11 -11
- package/{tableCommands-O6NWHFKV.js → tableCommands-G7RV3RU3.js} +4 -4
- package/{toolApiClient-7PSIFQPJ.js → toolApiClient-INIQCPGY.js} +3 -3
- package/{tools-AOVE5LKM.js → tools-XQ5GIH6P.js} +49 -49
- package/{tuiSummaryLlmCaller-XRQCSNYQ.js → tuiSummaryLlmCaller-L63PDJUD.js} +16 -15
- package/{updateCommands-2M74UL7P.js → updateCommands-ECWKIWLQ.js} +3 -3
- package/{updateDialogTitleAction-T66TXHIR.js → updateDialogTitleAction-EGAZMLUB.js} +32 -32
- package/agentRecordCommands-FST3KAKG.js +0 -126
- package/chunk-4QKBQHPQ.js +0 -79
- 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-X6YIXGPT.js";
|
|
1
6
|
import {
|
|
2
7
|
applyChatCompletionDelta,
|
|
3
8
|
applyResponsesToolEvent,
|
|
@@ -5,13 +10,11 @@ import {
|
|
|
5
10
|
finalizeResponsesToolCalls,
|
|
6
11
|
flushChatCompletionStream,
|
|
7
12
|
providerHttpFailure,
|
|
8
|
-
readSseFrames,
|
|
9
|
-
streamSseDataValues,
|
|
10
13
|
throwIfChatCompletionStreamFailed
|
|
11
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-25GAGMRK.js";
|
|
12
15
|
import {
|
|
13
|
-
|
|
14
|
-
} from "./chunk-
|
|
16
|
+
readSseFrames
|
|
17
|
+
} from "./chunk-GMZLP5DV.js";
|
|
15
18
|
import {
|
|
16
19
|
clipToolText,
|
|
17
20
|
hasImageInRuntimeMessages,
|
|
@@ -20,13 +23,16 @@ import {
|
|
|
20
23
|
resolveHistoricalToolContentCap,
|
|
21
24
|
resolveToolOutputProfile,
|
|
22
25
|
stripImagePartsFromMessages
|
|
23
|
-
} from "./chunk-
|
|
26
|
+
} from "./chunk-VBSVA6CB.js";
|
|
24
27
|
import {
|
|
25
28
|
downgradeUnparsableToolCalls,
|
|
26
29
|
hasParsableObjectArguments,
|
|
27
30
|
repairTruncatedToolArguments,
|
|
28
31
|
sanitizeForOutbound
|
|
29
32
|
} from "./chunk-CQ3WA2NE.js";
|
|
33
|
+
import {
|
|
34
|
+
buildDialogFallbackTitleFromUserInput
|
|
35
|
+
} from "./chunk-2MBTWINN.js";
|
|
30
36
|
import {
|
|
31
37
|
createThinkParserState,
|
|
32
38
|
createToolCallAccumulator,
|
|
@@ -35,16 +41,19 @@ import {
|
|
|
35
41
|
finalizeAccumulatedToolCalls
|
|
36
42
|
} from "./chunk-N7J63Q6C.js";
|
|
37
43
|
import {
|
|
44
|
+
DELETE_SAFETY_RED_LINE,
|
|
38
45
|
TOOL_GUIDED_SECTION_ORDER,
|
|
39
46
|
buildIdentityBlock,
|
|
40
47
|
buildRuntimeGuidanceBlocks,
|
|
48
|
+
detectDispatchIntent,
|
|
49
|
+
detectDispatchIntentFromMessages,
|
|
41
50
|
estimateContextTokens,
|
|
42
51
|
hashStablePrefixContent,
|
|
43
52
|
normalizeChatCompletionsBodyForProvider,
|
|
44
53
|
requiresBareImageUrl,
|
|
45
54
|
resolveToolGuidedSections,
|
|
46
55
|
toBareImageUrlMessages
|
|
47
|
-
} from "./chunk-
|
|
56
|
+
} from "./chunk-HBTA2SGQ.js";
|
|
48
57
|
import {
|
|
49
58
|
convertMessagesToResponsesInput,
|
|
50
59
|
extractReasoningFromResponseOutput,
|
|
@@ -62,25 +71,18 @@ import {
|
|
|
62
71
|
applyToolSurfaceConstraints,
|
|
63
72
|
buildDialogReadEnvelope,
|
|
64
73
|
buildNoloWorkspaceCommandArgs,
|
|
74
|
+
buildNoloWorkspaceOpenAiTools,
|
|
65
75
|
createStreamingDialogReadProjector,
|
|
66
76
|
noloPositiveIntegerString,
|
|
67
77
|
noloStringArg,
|
|
68
78
|
parseNoloWorkspaceToolArguments,
|
|
69
79
|
readTextStreamUpToChars,
|
|
70
80
|
resolveNoloDialogInput
|
|
71
|
-
} from "./chunk-
|
|
72
|
-
import {
|
|
73
|
-
getAntigravityUserAgent,
|
|
74
|
-
readAntigravityProjectId,
|
|
75
|
-
resolveAntigravityCloudCodeBaseUrl
|
|
76
|
-
} from "./chunk-NKIH4Q7W.js";
|
|
81
|
+
} from "./chunk-LNPYTNMG.js";
|
|
77
82
|
import {
|
|
78
83
|
buildProviderAuthHeaders,
|
|
79
84
|
buildProviderExecutionPlan
|
|
80
|
-
} from "./chunk-
|
|
81
|
-
import {
|
|
82
|
-
buildDialogFallbackTitleFromUserInput
|
|
83
|
-
} from "./chunk-2MBTWINN.js";
|
|
85
|
+
} from "./chunk-OOSVFT6S.js";
|
|
84
86
|
import {
|
|
85
87
|
EMPTY_ASSISTANT_REPAIR_PROMPT,
|
|
86
88
|
getModelContextWindow,
|
|
@@ -91,7 +93,7 @@ import {
|
|
|
91
93
|
resolveEmptyAssistantFallbackMessage,
|
|
92
94
|
resolveEmptyAssistantOutcome,
|
|
93
95
|
resolveTruncatedReasoningTailLog
|
|
94
|
-
} from "./chunk-
|
|
96
|
+
} from "./chunk-LS2MI3B4.js";
|
|
95
97
|
import {
|
|
96
98
|
COMPACTION_SUMMARY_SCHEMA_VERSION,
|
|
97
99
|
COMPACTION_SUMMARY_SYSTEM_PROMPT,
|
|
@@ -110,16 +112,16 @@ import {
|
|
|
110
112
|
resolveCompressionTriggerRatio,
|
|
111
113
|
truncateToolOutputForContext,
|
|
112
114
|
withProviderCallTimingFields
|
|
113
|
-
} from "./chunk-
|
|
115
|
+
} from "./chunk-F64B2W3R.js";
|
|
114
116
|
import {
|
|
115
117
|
estimateTokenCount
|
|
116
118
|
} from "./chunk-PSCNXBYA.js";
|
|
117
|
-
import {
|
|
118
|
-
resolveNoloStateDir
|
|
119
|
-
} from "./chunk-ONXOABJR.js";
|
|
120
119
|
import {
|
|
121
120
|
toErrorMessage
|
|
122
121
|
} from "./chunk-HNMXYYJR.js";
|
|
122
|
+
import {
|
|
123
|
+
resolveNoloStateDir
|
|
124
|
+
} from "./chunk-HNGRBWYF.js";
|
|
123
125
|
import {
|
|
124
126
|
buildDialogSummaryLayer
|
|
125
127
|
} from "./chunk-DVINR3PL.js";
|
|
@@ -137,7 +139,7 @@ import {
|
|
|
137
139
|
asTrimmedNonEmptyStringArray,
|
|
138
140
|
dialogMessageKey,
|
|
139
141
|
dialogMessageRange
|
|
140
|
-
} from "./chunk-
|
|
142
|
+
} from "./chunk-3AH7LNUB.js";
|
|
141
143
|
import {
|
|
142
144
|
asOptionalFiniteNumber
|
|
143
145
|
} from "./chunk-WWC7I6TA.js";
|
|
@@ -11898,6 +11900,7 @@ var toQueue = /* @__PURE__ */ dual(2, (self, options) => toQueueArray(self.chann
|
|
|
11898
11900
|
var runIntoQueue = /* @__PURE__ */ dual(2, (self, queue) => runIntoQueueArray(self.channel, queue));
|
|
11899
11901
|
|
|
11900
11902
|
// packages/agent-runtime/abortableKernel.ts
|
|
11903
|
+
var IDLE_WATCHDOG_SLICES = 20;
|
|
11901
11904
|
function runAbortableWithTimeout(args2) {
|
|
11902
11905
|
const taskEffect = Effect_exports.callback(
|
|
11903
11906
|
(resume) => {
|
|
@@ -11933,12 +11936,26 @@ function runAbortableWithTimeout(args2) {
|
|
|
11933
11936
|
raced = Effect_exports.raceFirst(taskEffect, abortEffect);
|
|
11934
11937
|
}
|
|
11935
11938
|
if (typeof args2.timeoutMs === "number") {
|
|
11936
|
-
const
|
|
11939
|
+
const outer = raced;
|
|
11937
11940
|
const timeoutMs = args2.timeoutMs;
|
|
11938
|
-
|
|
11939
|
-
|
|
11940
|
-
|
|
11941
|
+
const activityVersion = args2.activityVersion;
|
|
11942
|
+
const idleWatchdog = Effect_exports.gen(function* () {
|
|
11943
|
+
const sliceCount = activityVersion ? IDLE_WATCHDOG_SLICES : 1;
|
|
11944
|
+
const baseSliceMs = Math.max(1, Math.floor(timeoutMs / sliceCount));
|
|
11945
|
+
let idleMs = 0;
|
|
11946
|
+
for (; ; ) {
|
|
11947
|
+
const versionAtSliceStart = activityVersion?.();
|
|
11948
|
+
const sliceMs = Math.max(1, Math.min(timeoutMs - idleMs, baseSliceMs));
|
|
11949
|
+
yield* Effect_exports.sleep(Duration_exports.millis(sliceMs));
|
|
11950
|
+
idleMs += sliceMs;
|
|
11951
|
+
if (activityVersion && activityVersion() !== versionAtSliceStart) {
|
|
11952
|
+
idleMs = 0;
|
|
11953
|
+
continue;
|
|
11954
|
+
}
|
|
11955
|
+
if (idleMs >= timeoutMs) return { kind: "timeout" };
|
|
11956
|
+
}
|
|
11941
11957
|
});
|
|
11958
|
+
raced = Effect_exports.raceFirst(outer, idleWatchdog);
|
|
11942
11959
|
}
|
|
11943
11960
|
return args2.runtime ? args2.runtime.runPromise(raced) : Effect_exports.runPromise(raced);
|
|
11944
11961
|
}
|
|
@@ -12625,20 +12642,40 @@ function isColdResume(history, nowMs) {
|
|
|
12625
12642
|
}
|
|
12626
12643
|
async function maybeAutoCompactLocalHistory(args2) {
|
|
12627
12644
|
const { adapter, dialogId, history } = args2;
|
|
12628
|
-
const
|
|
12645
|
+
const emitPhase = (phase) => {
|
|
12646
|
+
try {
|
|
12647
|
+
args2.onPhase?.(phase);
|
|
12648
|
+
} catch {
|
|
12649
|
+
}
|
|
12650
|
+
};
|
|
12651
|
+
emitPhase({ kind: "validating-context" });
|
|
12652
|
+
const unchanged = (decision) => ({
|
|
12629
12653
|
history,
|
|
12630
12654
|
compressed: false,
|
|
12631
|
-
summaryGenerated: false
|
|
12655
|
+
summaryGenerated: false,
|
|
12656
|
+
decision
|
|
12632
12657
|
});
|
|
12633
|
-
if (!dialogId
|
|
12634
|
-
return unchanged();
|
|
12658
|
+
if (!dialogId) {
|
|
12659
|
+
return unchanged({ outcome: "skipped", skipReason: "no-dialog-id" });
|
|
12660
|
+
}
|
|
12661
|
+
if (history.length === 0) {
|
|
12662
|
+
return unchanged({ outcome: "skipped", skipReason: "empty-history" });
|
|
12663
|
+
}
|
|
12664
|
+
if (typeof adapter.loadDialogSummary !== "function" || typeof adapter.saveDialogSummary !== "function") {
|
|
12665
|
+
return unchanged({
|
|
12666
|
+
outcome: "skipped",
|
|
12667
|
+
skipReason: "adapter-missing-summary-methods"
|
|
12668
|
+
});
|
|
12635
12669
|
}
|
|
12636
12670
|
let stored = null;
|
|
12637
12671
|
try {
|
|
12638
12672
|
stored = await adapter.loadDialogSummary(dialogId);
|
|
12639
12673
|
} catch (error) {
|
|
12640
12674
|
console.warn("[localLoop] loadDialogSummary failed:", error);
|
|
12641
|
-
return unchanged(
|
|
12675
|
+
return unchanged({
|
|
12676
|
+
outcome: "skipped",
|
|
12677
|
+
skipReason: "load-summary-failed"
|
|
12678
|
+
});
|
|
12642
12679
|
}
|
|
12643
12680
|
const bridged = toPlanCompressionMessages(history);
|
|
12644
12681
|
const validation = validateStoredSummary({ history, stored: stored ?? {} });
|
|
@@ -12674,7 +12711,21 @@ async function maybeAutoCompactLocalHistory(args2) {
|
|
|
12674
12711
|
...args2.realContextUsagePercent !== void 0 ? { realContextUsagePercent: args2.realContextUsagePercent } : {}
|
|
12675
12712
|
});
|
|
12676
12713
|
const projectExisting = () => {
|
|
12677
|
-
|
|
12714
|
+
const diag = plan.diagnostics;
|
|
12715
|
+
const diagSnapshot = diag ? {
|
|
12716
|
+
estimatedTokens: diag.totalUsed,
|
|
12717
|
+
historyBudget: diag.historyBudget,
|
|
12718
|
+
triggerRatio: diag.triggerRatio,
|
|
12719
|
+
...diag.realUsageRatio !== void 0 ? { realUsageRatio: diag.realUsageRatio } : {}
|
|
12720
|
+
} : {};
|
|
12721
|
+
const skippedDecision = {
|
|
12722
|
+
outcome: "skipped",
|
|
12723
|
+
skipReason: diag?.emptyReason === "no-pending" ? "no-pending" : diag?.emptyReason === "below-min-compress-count" ? "below-min-compress-count" : "below-trigger",
|
|
12724
|
+
...diagSnapshot,
|
|
12725
|
+
...diag ? { pendingMsgCount: diag.pendingMsgCount } : {},
|
|
12726
|
+
...diag?.compressCount !== void 0 ? { compressCount: diag.compressCount } : {}
|
|
12727
|
+
};
|
|
12728
|
+
if (!existingSummary.trim()) return unchanged(skippedDecision);
|
|
12678
12729
|
return {
|
|
12679
12730
|
history: projectHistoryWithSummary({
|
|
12680
12731
|
history,
|
|
@@ -12682,14 +12733,26 @@ async function maybeAutoCompactLocalHistory(args2) {
|
|
|
12682
12733
|
summarizedBeforeId
|
|
12683
12734
|
}),
|
|
12684
12735
|
compressed: true,
|
|
12685
|
-
summaryGenerated: false
|
|
12736
|
+
summaryGenerated: false,
|
|
12737
|
+
decision: {
|
|
12738
|
+
outcome: "compressed",
|
|
12739
|
+
trigger: "existing-summary",
|
|
12740
|
+
...diagSnapshot
|
|
12741
|
+
}
|
|
12686
12742
|
};
|
|
12687
12743
|
};
|
|
12688
12744
|
if (!plan.shouldCompress) {
|
|
12689
12745
|
return projectExisting();
|
|
12690
12746
|
}
|
|
12747
|
+
emitPhase({ kind: "compaction-start" });
|
|
12691
12748
|
try {
|
|
12749
|
+
if (args2.abortSignal?.aborted) {
|
|
12750
|
+
throw Object.assign(new Error("auto-compaction aborted"), { compactionReason: "aborted" });
|
|
12751
|
+
}
|
|
12692
12752
|
const provider = await args2.resolveProvider();
|
|
12753
|
+
if (args2.abortSignal?.aborted) {
|
|
12754
|
+
throw Object.assign(new Error("auto-compaction aborted"), { compactionReason: "aborted" });
|
|
12755
|
+
}
|
|
12693
12756
|
const msgsToCompress = plan.msgsToCompress;
|
|
12694
12757
|
const messagesText = formatMessagesForSummaryWithTruncation(msgsToCompress);
|
|
12695
12758
|
const fileOpsText = formatFileOperationsFromMessages(
|
|
@@ -12701,18 +12764,57 @@ async function maybeAutoCompactLocalHistory(args2) {
|
|
|
12701
12764
|
messagesText,
|
|
12702
12765
|
fileOpsText
|
|
12703
12766
|
});
|
|
12704
|
-
|
|
12705
|
-
|
|
12706
|
-
|
|
12707
|
-
|
|
12767
|
+
emitPhase({ kind: "waiting-provider" });
|
|
12768
|
+
const timeoutMs = typeof args2.timeoutMs === "number" && Number.isFinite(args2.timeoutMs) && args2.timeoutMs > 0 ? args2.timeoutMs : void 0;
|
|
12769
|
+
const requestController = new AbortController();
|
|
12770
|
+
let timeoutHandle;
|
|
12771
|
+
let abortListener;
|
|
12772
|
+
const request3 = provider.complete(
|
|
12773
|
+
[{ role: "system", content: COMPACTION_SUMMARY_SYSTEM_PROMPT }, { role: "user", content: promptContent }],
|
|
12774
|
+
{ signal: requestController.signal, ...timeoutMs ? { timeoutMs } : {} }
|
|
12775
|
+
).then(
|
|
12776
|
+
(value) => ({ kind: "done", value }),
|
|
12777
|
+
(error) => ({ kind: "provider-error", error })
|
|
12778
|
+
);
|
|
12779
|
+
const guards = [];
|
|
12780
|
+
if (timeoutMs) guards.push(new Promise((resolve5) => {
|
|
12781
|
+
timeoutHandle = setTimeout(() => {
|
|
12782
|
+
requestController.abort();
|
|
12783
|
+
resolve5({ kind: "timeout" });
|
|
12784
|
+
}, timeoutMs);
|
|
12785
|
+
}));
|
|
12786
|
+
if (args2.abortSignal) guards.push(new Promise((resolve5) => {
|
|
12787
|
+
abortListener = () => {
|
|
12788
|
+
requestController.abort(args2.abortSignal?.reason);
|
|
12789
|
+
resolve5({ kind: "aborted" });
|
|
12790
|
+
};
|
|
12791
|
+
args2.abortSignal?.addEventListener("abort", abortListener, { once: true });
|
|
12792
|
+
}));
|
|
12793
|
+
const outcome = guards.length ? await Promise.race([request3, ...guards]) : await request3;
|
|
12794
|
+
if (timeoutHandle) clearTimeout(timeoutHandle);
|
|
12795
|
+
if (abortListener) args2.abortSignal?.removeEventListener("abort", abortListener);
|
|
12796
|
+
if (outcome.kind !== "done") {
|
|
12797
|
+
const reason = outcome.kind === "timeout" ? "timeout" : outcome.kind === "aborted" ? "aborted" : "provider-error";
|
|
12798
|
+
const detail = outcome.kind === "provider-error" ? outcome.error instanceof Error ? outcome.error.message : String(outcome.error) : reason === "timeout" ? `auto-compaction timed out after ${timeoutMs}ms` : "auto-compaction aborted";
|
|
12799
|
+
throw Object.assign(new Error(detail), { compactionReason: reason });
|
|
12800
|
+
}
|
|
12801
|
+
const result4 = outcome.value;
|
|
12708
12802
|
const newSummary = typeof result4.content === "string" ? result4.content.trim() : "";
|
|
12709
12803
|
if (!newSummary) {
|
|
12710
12804
|
console.warn(
|
|
12711
12805
|
"[localLoop] auto-compaction produced empty summary; keeping prior projection"
|
|
12712
12806
|
);
|
|
12807
|
+
const failureReason = "provider-error";
|
|
12808
|
+
emitPhase({ kind: "compaction-failed", reason: failureReason });
|
|
12713
12809
|
return {
|
|
12714
12810
|
...projectExisting(),
|
|
12715
|
-
failureMessage: "summary model returned empty content"
|
|
12811
|
+
failureMessage: "summary model returned empty content",
|
|
12812
|
+
failureReason,
|
|
12813
|
+
decision: {
|
|
12814
|
+
outcome: "failed",
|
|
12815
|
+
reason: failureReason,
|
|
12816
|
+
detail: "summary model returned empty content"
|
|
12817
|
+
}
|
|
12716
12818
|
};
|
|
12717
12819
|
}
|
|
12718
12820
|
await adapter.saveDialogSummary({
|
|
@@ -12737,6 +12839,7 @@ async function maybeAutoCompactLocalHistory(args2) {
|
|
|
12737
12839
|
summaryUsage: result4.usage
|
|
12738
12840
|
});
|
|
12739
12841
|
console.log(formatCompactionMetricsLog(metrics));
|
|
12842
|
+
emitPhase({ kind: "compaction-end" });
|
|
12740
12843
|
return {
|
|
12741
12844
|
history: projectHistoryWithSummary({
|
|
12742
12845
|
history,
|
|
@@ -12749,12 +12852,29 @@ async function maybeAutoCompactLocalHistory(args2) {
|
|
|
12749
12852
|
beforeTokens: metrics.previousSummaryTokens + metrics.compressedTokens,
|
|
12750
12853
|
afterTokens: metrics.newSummaryTokens + metrics.retainedTokens,
|
|
12751
12854
|
...result4.usage ? { usage: result4.usage } : {},
|
|
12752
|
-
metrics
|
|
12855
|
+
metrics,
|
|
12856
|
+
decision: {
|
|
12857
|
+
outcome: "compressed",
|
|
12858
|
+
trigger: invalidSummary ? "invalid-summary" : coldResume ? "cold-resume" : plan.diagnostics?.triggeredByRealUsage ? "real-usage" : "estimate",
|
|
12859
|
+
...plan.diagnostics ? {
|
|
12860
|
+
estimatedTokens: plan.diagnostics.totalUsed,
|
|
12861
|
+
historyBudget: plan.diagnostics.historyBudget,
|
|
12862
|
+
triggerRatio: plan.diagnostics.triggerRatio,
|
|
12863
|
+
...plan.diagnostics.realUsageRatio !== void 0 ? { realUsageRatio: plan.diagnostics.realUsageRatio } : {}
|
|
12864
|
+
} : {}
|
|
12865
|
+
}
|
|
12753
12866
|
};
|
|
12754
12867
|
} catch (error) {
|
|
12755
12868
|
console.warn("[localLoop] auto-compaction failed:", error);
|
|
12756
12869
|
const failureMessage = error instanceof Error && error.message ? error.message.slice(0, 200) : String(error).slice(0, 200);
|
|
12757
|
-
|
|
12870
|
+
const failureReason = error instanceof Error && "compactionReason" in error ? error.compactionReason : "provider-error";
|
|
12871
|
+
emitPhase({ kind: "compaction-failed", reason: failureReason });
|
|
12872
|
+
return {
|
|
12873
|
+
...projectExisting(),
|
|
12874
|
+
failureMessage,
|
|
12875
|
+
failureReason,
|
|
12876
|
+
decision: { outcome: "failed", reason: failureReason, detail: failureMessage }
|
|
12877
|
+
};
|
|
12758
12878
|
}
|
|
12759
12879
|
}
|
|
12760
12880
|
|
|
@@ -12810,6 +12930,8 @@ function emitLoopEvent(boundary, event, bridge) {
|
|
|
12810
12930
|
boundary.emit(bridge ? { event, bridge } : { event });
|
|
12811
12931
|
}
|
|
12812
12932
|
var LLM_REQUEST_TIMEOUT = "LLM_REQUEST_TIMEOUT";
|
|
12933
|
+
var DEFAULT_LLM_REQUEST_TIMEOUT_MS = 10 * 60 * 1e3;
|
|
12934
|
+
var DEFAULT_COMPACTION_TIMEOUT_MS = 60 * 1e3;
|
|
12813
12935
|
var LOCAL_TURN_ABORTED_CODE = "LOCAL_TURN_ABORTED";
|
|
12814
12936
|
function buildAbortedError() {
|
|
12815
12937
|
const error = new Error("local agent turn aborted by user");
|
|
@@ -12837,8 +12959,11 @@ async function runAbortableToolTask(input, task, pendingToolName) {
|
|
|
12837
12959
|
}
|
|
12838
12960
|
function resolveLlmRequestTimeoutMs(input) {
|
|
12839
12961
|
const raw = input.llmRequestTimeoutMs ?? input.timeoutMs;
|
|
12840
|
-
|
|
12841
|
-
|
|
12962
|
+
return typeof raw === "number" && Number.isFinite(raw) && raw > 0 ? raw : DEFAULT_LLM_REQUEST_TIMEOUT_MS;
|
|
12963
|
+
}
|
|
12964
|
+
function resolveCompactionTimeoutMs(input) {
|
|
12965
|
+
const raw = input.compactionTimeoutMs;
|
|
12966
|
+
return typeof raw === "number" && Number.isFinite(raw) && raw > 0 ? raw : DEFAULT_COMPACTION_TIMEOUT_MS;
|
|
12842
12967
|
}
|
|
12843
12968
|
async function runCompleteWithTimeout(args2) {
|
|
12844
12969
|
const { provider, messages, options, timeoutMs, round, input, boundary, context: context3, providerName, model } = args2;
|
|
@@ -12861,6 +12986,7 @@ async function runCompleteWithTimeout(args2) {
|
|
|
12861
12986
|
const outcome = await runAbortableWithTimeout({
|
|
12862
12987
|
task: complete,
|
|
12863
12988
|
timeoutMs: typeof timeoutMs === "number" ? timeoutMs : void 0,
|
|
12989
|
+
activityVersion: args2.activityVersion,
|
|
12864
12990
|
abortSignal: input.abortSignal,
|
|
12865
12991
|
runtime: input.effectRuntime
|
|
12866
12992
|
});
|
|
@@ -12871,7 +12997,7 @@ async function runCompleteWithTimeout(args2) {
|
|
|
12871
12997
|
}
|
|
12872
12998
|
if (outcome.kind === "timeout") {
|
|
12873
12999
|
const timeoutError = new Error(
|
|
12874
|
-
`LLM request timed out after ${timeoutMs}ms (round ${round})`
|
|
13000
|
+
`LLM request timed out after ${timeoutMs}ms without new output (idle window, round ${round})`
|
|
12875
13001
|
);
|
|
12876
13002
|
timeoutError.code = LLM_REQUEST_TIMEOUT;
|
|
12877
13003
|
throw timeoutError;
|
|
@@ -13529,7 +13655,14 @@ async function runLocalAgentTurn(input) {
|
|
|
13529
13655
|
agentConfig.exposedToolNames ?? agentConfig.toolNames ?? []
|
|
13530
13656
|
);
|
|
13531
13657
|
const guidanceBlocks = buildRuntimeGuidanceBlocks(agentTools);
|
|
13532
|
-
const toolGuidedSections = resolveToolGuidedSections(agentTools
|
|
13658
|
+
const toolGuidedSections = resolveToolGuidedSections(agentTools, {
|
|
13659
|
+
// 单调锁定:历史里任一 user 消息命中派发关键词、或已出现过
|
|
13660
|
+
// startAgentRun/controlAgentRun 的 tool_calls,后续每轮都保持 true,
|
|
13661
|
+
// 防止 session-scope 的 agentCollaboration 段逐轮翻转击穿前缀缓存。
|
|
13662
|
+
dispatchIntent: detectDispatchIntentFromMessages(history) || detectDispatchIntent(
|
|
13663
|
+
typeof input.input === "string" ? input.input : void 0
|
|
13664
|
+
)
|
|
13665
|
+
});
|
|
13533
13666
|
const guidanceScopes = [
|
|
13534
13667
|
...input.userLanguage?.trim() ? [buildUserResponseLanguageContext({ language: input.userLanguage })] : [],
|
|
13535
13668
|
guidanceBlocks.startupProtocol,
|
|
@@ -13545,6 +13678,9 @@ async function runLocalAgentTurn(input) {
|
|
|
13545
13678
|
input.contextBlockScopes
|
|
13546
13679
|
);
|
|
13547
13680
|
const mergedContextBlockScopes = [
|
|
13681
|
+
// 删除安全红线:系统层最高优先级约束,位于所有块之前(含身份信息块),
|
|
13682
|
+
// owner 要求常驻「根本提示词」的最顶部(2026-09-26 批量误删事故)。
|
|
13683
|
+
{ content: DELETE_SAFETY_RED_LINE, cacheScope: "session" },
|
|
13548
13684
|
{ content: identityBlock, cacheScope: "session" },
|
|
13549
13685
|
...guidanceScopes,
|
|
13550
13686
|
...callerScopes
|
|
@@ -13577,20 +13713,40 @@ async function runLocalAgentTurn(input) {
|
|
|
13577
13713
|
}
|
|
13578
13714
|
}
|
|
13579
13715
|
let compactionUsage;
|
|
13716
|
+
const emitCompactionPhase = (phase, scope3) => {
|
|
13717
|
+
const atMs = Date.now();
|
|
13718
|
+
if (phase.kind === "validating-context") emitLoopEvent(observationBoundary, { kind: "turn-phase", phase: "validating-context", atMs, compactionScope: scope3 });
|
|
13719
|
+
else if (phase.kind === "compaction-start") {
|
|
13720
|
+
emitLoopEvent(observationBoundary, { kind: "turn-phase", phase: "compacting", atMs, compactionScope: scope3 });
|
|
13721
|
+
emitLoopEvent(observationBoundary, { kind: "compaction-start", atMs, scope: scope3 });
|
|
13722
|
+
} else if (phase.kind === "waiting-provider") emitLoopEvent(observationBoundary, { kind: "turn-phase", phase: "waiting-provider", atMs, compactionScope: scope3 });
|
|
13723
|
+
else if (phase.kind === "compaction-end") emitLoopEvent(observationBoundary, { kind: "compaction-end", atMs, scope: scope3 });
|
|
13724
|
+
else emitLoopEvent(observationBoundary, { kind: "compaction-failed", atMs, scope: scope3, reason: phase.reason });
|
|
13725
|
+
};
|
|
13580
13726
|
const emitCompactionObservation = (compacted) => {
|
|
13581
|
-
|
|
13582
|
-
|
|
13583
|
-
|
|
13584
|
-
|
|
13585
|
-
|
|
13586
|
-
summaryGenerated: compacted.summaryGenerated,
|
|
13587
|
-
compressed: compacted.compressed,
|
|
13588
|
-
...compacted.failureMessage ? { failed: true, detail: compacted.failureMessage } : {},
|
|
13589
|
-
...compacted.beforeTokens !== void 0 ? { beforeTokens: compacted.beforeTokens } : {},
|
|
13590
|
-
...compacted.afterTokens !== void 0 ? { afterTokens: compacted.afterTokens } : {},
|
|
13591
|
-
...compacted.savedTokens !== void 0 ? { savedTokens: compacted.savedTokens } : {}
|
|
13592
|
-
});
|
|
13727
|
+
const decision = compacted.decision;
|
|
13728
|
+
if (decision?.outcome === "skipped") {
|
|
13729
|
+
const isProtectionGap = decision.skipReason === "adapter-missing-summary-methods" || decision.skipReason === "load-summary-failed";
|
|
13730
|
+
const approachingBudget = decision.skipReason === "below-trigger" && typeof decision.estimatedTokens === "number" && typeof decision.historyBudget === "number" && decision.historyBudget > 0 && decision.estimatedTokens >= decision.historyBudget * 0.5;
|
|
13731
|
+
if (!isProtectionGap && !approachingBudget) return;
|
|
13593
13732
|
}
|
|
13733
|
+
emitLoopEvent(observationBoundary, {
|
|
13734
|
+
kind: "compaction",
|
|
13735
|
+
atMs: Date.now(),
|
|
13736
|
+
...compacted.reason ? { reason: compacted.reason } : {},
|
|
13737
|
+
summaryGenerated: compacted.summaryGenerated,
|
|
13738
|
+
compressed: compacted.compressed,
|
|
13739
|
+
...compacted.failureMessage ? { failed: true, detail: compacted.failureMessage } : {},
|
|
13740
|
+
...decision?.outcome === "skipped" ? { skipped: true, skipReason: decision.skipReason } : {},
|
|
13741
|
+
...decision && "trigger" in decision && decision.trigger ? { trigger: decision.trigger } : {},
|
|
13742
|
+
...decision && "estimatedTokens" in decision && decision.estimatedTokens !== void 0 ? { estimatedTokens: decision.estimatedTokens } : {},
|
|
13743
|
+
...decision && "historyBudget" in decision && decision.historyBudget !== void 0 ? { historyBudget: decision.historyBudget } : {},
|
|
13744
|
+
...decision && "realUsageRatio" in decision && decision.realUsageRatio !== void 0 ? { realUsageRatio: decision.realUsageRatio } : {},
|
|
13745
|
+
...decision && "triggerRatio" in decision && decision.triggerRatio !== void 0 ? { triggerRatio: decision.triggerRatio } : {},
|
|
13746
|
+
...compacted.beforeTokens !== void 0 ? { beforeTokens: compacted.beforeTokens } : {},
|
|
13747
|
+
...compacted.afterTokens !== void 0 ? { afterTokens: compacted.afterTokens } : {},
|
|
13748
|
+
...compacted.savedTokens !== void 0 ? { savedTokens: compacted.savedTokens } : {}
|
|
13749
|
+
});
|
|
13594
13750
|
};
|
|
13595
13751
|
try {
|
|
13596
13752
|
const compacted = await maybeAutoCompactLocalHistory({
|
|
@@ -13600,7 +13756,10 @@ async function runLocalAgentTurn(input) {
|
|
|
13600
13756
|
model: agentConfig.model,
|
|
13601
13757
|
resolveProvider: resolveProviderOnce,
|
|
13602
13758
|
contextWindow,
|
|
13603
|
-
realContextUsagePercent
|
|
13759
|
+
realContextUsagePercent,
|
|
13760
|
+
abortSignal: input.abortSignal,
|
|
13761
|
+
timeoutMs: resolveCompactionTimeoutMs(input),
|
|
13762
|
+
onPhase: (phase) => emitCompactionPhase(phase, "initial")
|
|
13604
13763
|
});
|
|
13605
13764
|
history = compacted.history;
|
|
13606
13765
|
compactionUsage = compacted.usage;
|
|
@@ -13671,17 +13830,26 @@ async function runLocalAgentTurn(input) {
|
|
|
13671
13830
|
let skipFinalAppend = false;
|
|
13672
13831
|
let partialContent = "";
|
|
13673
13832
|
const progressGuard = createLocalLoopProgressGuard(input.progressGuardConfig);
|
|
13833
|
+
let ephemeralSummary = null;
|
|
13834
|
+
const ephemeralDialogId = `ephemeral-${crypto.randomUUID()}`;
|
|
13835
|
+
const compactionAdapter = input.continueDialogId ? input.adapter : {
|
|
13836
|
+
...input.adapter,
|
|
13837
|
+
loadDialogSummary: async () => ephemeralSummary,
|
|
13838
|
+
saveDialogSummary: async (summaryInput) => {
|
|
13839
|
+
ephemeralSummary = summaryInput;
|
|
13840
|
+
}
|
|
13841
|
+
};
|
|
13842
|
+
const compactionDialogId = input.continueDialogId ?? ephemeralDialogId;
|
|
13674
13843
|
const maybeCompactInLoop = async () => {
|
|
13675
|
-
|
|
13676
|
-
|
|
13677
|
-
|
|
13678
|
-
|
|
13679
|
-
|
|
13680
|
-
if (ratio < compressionTriggerRatio) return;
|
|
13844
|
+
const inputTokens = contextUsage ? normalizeUsage(contextUsage).input_tokens : 0;
|
|
13845
|
+
const ratio = inputTokens > 0 ? Math.min(1, inputTokens / contextWindow) : void 0;
|
|
13846
|
+
if (ratio !== void 0 && ratio < compressionTriggerRatio * 0.85) {
|
|
13847
|
+
return;
|
|
13848
|
+
}
|
|
13681
13849
|
try {
|
|
13682
13850
|
const compacted = await maybeAutoCompactLocalHistory({
|
|
13683
|
-
adapter:
|
|
13684
|
-
dialogId:
|
|
13851
|
+
adapter: compactionAdapter,
|
|
13852
|
+
dialogId: compactionDialogId,
|
|
13685
13853
|
// canonical 坐标:store 全量历史 + 本轮消息的「持久化形态」
|
|
13686
13854
|
// (applyPersistedTurnInput 会把首条 user 消息换成 paste 展开形态)。
|
|
13687
13855
|
// 锚点与 sourceHash 都必须按持久化形态计算——否则下轮从 store
|
|
@@ -13697,7 +13865,10 @@ async function runLocalAgentTurn(input) {
|
|
|
13697
13865
|
model: agentConfig.model,
|
|
13698
13866
|
resolveProvider: resolveProviderOnce,
|
|
13699
13867
|
contextWindow,
|
|
13700
|
-
realContextUsagePercent: ratio
|
|
13868
|
+
...ratio !== void 0 ? { realContextUsagePercent: ratio } : {},
|
|
13869
|
+
abortSignal: input.abortSignal,
|
|
13870
|
+
timeoutMs: resolveCompactionTimeoutMs(input),
|
|
13871
|
+
onPhase: (phase) => emitCompactionPhase(phase, "in-loop")
|
|
13701
13872
|
});
|
|
13702
13873
|
if (compacted.usage) {
|
|
13703
13874
|
compactionUsage = addOutOfBandUsage(compactionUsage, compacted.usage);
|
|
@@ -13767,11 +13938,12 @@ async function runLocalAgentTurn(input) {
|
|
|
13767
13938
|
const shouldPassToolEvents = Boolean(
|
|
13768
13939
|
input.onToolEvent || input.onObservationEvent || input.observationBoundary
|
|
13769
13940
|
);
|
|
13941
|
+
let llmStreamActivity = 0;
|
|
13770
13942
|
result4 = await runCompleteWithTimeout({
|
|
13771
13943
|
provider,
|
|
13772
13944
|
messages: requestMessages,
|
|
13773
13945
|
options: {
|
|
13774
|
-
|
|
13946
|
+
timeoutMs: resolveLlmRequestTimeoutMs(input),
|
|
13775
13947
|
// 用户取消信号穿进 provider options:providerStreamRetry 据此在
|
|
13776
13948
|
// 取消后跳过重试,provider 分支(如 antigravity/openai-compatible)
|
|
13777
13949
|
// 也可把 fetch 绑定到同一信号,实现真正的传输层取消。
|
|
@@ -13780,6 +13952,7 @@ async function runLocalAgentTurn(input) {
|
|
|
13780
13952
|
// 归到具体对话而不是 chat-proxy 兜底桶。新对话首轮 id 尚未分配。
|
|
13781
13953
|
...input.continueDialogId ? { dialogId: input.continueDialogId } : {},
|
|
13782
13954
|
...shouldStreamDeltas ? { onTextDelta: (chunk) => {
|
|
13955
|
+
llmStreamActivity += 1;
|
|
13783
13956
|
partialContent += chunk;
|
|
13784
13957
|
observationBoundary.emit({
|
|
13785
13958
|
kind: "text-delta",
|
|
@@ -13789,6 +13962,7 @@ async function runLocalAgentTurn(input) {
|
|
|
13789
13962
|
});
|
|
13790
13963
|
} } : {},
|
|
13791
13964
|
...shouldStreamReasoning ? { onReasoningDelta: (chunk) => {
|
|
13965
|
+
llmStreamActivity += 1;
|
|
13792
13966
|
observationBoundary.emit({
|
|
13793
13967
|
kind: "reasoning-delta",
|
|
13794
13968
|
chunk,
|
|
@@ -13797,6 +13971,7 @@ async function runLocalAgentTurn(input) {
|
|
|
13797
13971
|
});
|
|
13798
13972
|
} } : {},
|
|
13799
13973
|
...shouldPassToolEvents ? { onToolEvent: (event) => {
|
|
13974
|
+
llmStreamActivity += 1;
|
|
13800
13975
|
observationBoundary.emit({
|
|
13801
13976
|
kind: "tool-event",
|
|
13802
13977
|
event,
|
|
@@ -13807,6 +13982,7 @@ async function runLocalAgentTurn(input) {
|
|
|
13807
13982
|
...shouldPassToolEvents ? { toolEventRound: round } : {}
|
|
13808
13983
|
},
|
|
13809
13984
|
timeoutMs: resolveLlmRequestTimeoutMs(input),
|
|
13985
|
+
activityVersion: () => llmStreamActivity,
|
|
13810
13986
|
round,
|
|
13811
13987
|
input,
|
|
13812
13988
|
boundary: observationBoundary,
|
|
@@ -14278,33 +14454,6 @@ ${reasoningTailLog}
|
|
|
14278
14454
|
}
|
|
14279
14455
|
}
|
|
14280
14456
|
|
|
14281
|
-
// packages/agent-runtime/kimiUserAgent.ts
|
|
14282
|
-
var KIMI_CODE_CLI_VERSION = "0.29.2";
|
|
14283
|
-
var KIMI_CODE_USER_AGENT = `kimi-code-cli/${KIMI_CODE_CLI_VERSION} (nolo)`;
|
|
14284
|
-
function isKimiEndpoint(url) {
|
|
14285
|
-
return url.includes("api.kimi.com");
|
|
14286
|
-
}
|
|
14287
|
-
function kimiIdentityHeaders(url) {
|
|
14288
|
-
return isKimiEndpoint(url) ? { "User-Agent": KIMI_CODE_USER_AGENT } : {};
|
|
14289
|
-
}
|
|
14290
|
-
|
|
14291
|
-
// packages/agent-runtime/sseDataLine.ts
|
|
14292
|
-
function parseSseDataLineJson(line) {
|
|
14293
|
-
const trimmed = line.trim();
|
|
14294
|
-
if (!trimmed.startsWith("data:")) return null;
|
|
14295
|
-
const payload = trimmed.slice(5).trim();
|
|
14296
|
-
if (!payload || payload === "[DONE]") return null;
|
|
14297
|
-
try {
|
|
14298
|
-
return JSON.parse(payload);
|
|
14299
|
-
} catch {
|
|
14300
|
-
return null;
|
|
14301
|
-
}
|
|
14302
|
-
}
|
|
14303
|
-
function parseSseDataLineObject(line) {
|
|
14304
|
-
const parsed = parseSseDataLineJson(line);
|
|
14305
|
-
return parsed && typeof parsed === "object" ? parsed : null;
|
|
14306
|
-
}
|
|
14307
|
-
|
|
14308
14457
|
// packages/integrations/openai/responsesRequestBody.ts
|
|
14309
14458
|
function buildResponsesRequestBody(body, model) {
|
|
14310
14459
|
const tools = Array.isArray(body.tools) ? toResponsesTools(body.tools) : void 0;
|
|
@@ -14528,8 +14677,7 @@ function buildOpenAiCompatibleChatCompletionRequest(args2) {
|
|
|
14528
14677
|
endpoint,
|
|
14529
14678
|
apiKey: args2.providerConfig.apiKey,
|
|
14530
14679
|
apiKeyHeader: args2.providerConfig.apiKeyHeader
|
|
14531
|
-
})
|
|
14532
|
-
...kimiIdentityHeaders(endpoint)
|
|
14680
|
+
})
|
|
14533
14681
|
};
|
|
14534
14682
|
return {
|
|
14535
14683
|
url: endpoint,
|
|
@@ -15574,132 +15722,6 @@ async function evaluateCapabilityPolicy(capability, normalizedInput, ctx) {
|
|
|
15574
15722
|
}
|
|
15575
15723
|
}
|
|
15576
15724
|
|
|
15577
|
-
// packages/agent-runtime/localToolPolicy.ts
|
|
15578
|
-
var NEVER_LOCAL_TOOLS = /* @__PURE__ */ new Set([
|
|
15579
|
-
"deleteSpaces",
|
|
15580
|
-
"updateAgent",
|
|
15581
|
-
"updateSelf",
|
|
15582
|
-
"createAgent"
|
|
15583
|
-
]);
|
|
15584
|
-
var DEFAULT_LOCAL_TOOLS = /* @__PURE__ */ new Set([
|
|
15585
|
-
"readFile",
|
|
15586
|
-
"writeFile",
|
|
15587
|
-
"editFile",
|
|
15588
|
-
"globFiles",
|
|
15589
|
-
"execShell",
|
|
15590
|
-
"launchProcess",
|
|
15591
|
-
"listProcesses",
|
|
15592
|
-
// ProcessTask follow-up tools. Same tier as listProcesses: they observe/stop
|
|
15593
|
-
// tasks the agent itself already spawned, so their blast radius is strictly
|
|
15594
|
-
// narrower than launchProcess (which is default-enabled). Model-facing
|
|
15595
|
-
// follow-ups are taskWait/taskStop only — lifecycle history (taskLogs) stays
|
|
15596
|
-
// runtime-internal.
|
|
15597
|
-
"taskWait",
|
|
15598
|
-
"taskStop",
|
|
15599
|
-
// Scheduling tools: forking/observing sub-agents is a declared capability
|
|
15600
|
-
// of capable agents, and the blast radius is strictly narrower than
|
|
15601
|
-
// execShell (already default-enabled). Requiring an env allowlist for these
|
|
15602
|
-
// while execShell is open by default inverted the risk model and forced every
|
|
15603
|
-
// new local user to hand-edit .env files before sub-agent tasks worked.
|
|
15604
|
-
"startAgentRun",
|
|
15605
|
-
"controlAgentRun"
|
|
15606
|
-
]);
|
|
15607
|
-
function parseToolAllowlist(value) {
|
|
15608
|
-
return (value ?? "").split(",").flatMap((item) => {
|
|
15609
|
-
const trimmed = item.trim();
|
|
15610
|
-
return trimmed ? [trimmed] : [];
|
|
15611
|
-
});
|
|
15612
|
-
}
|
|
15613
|
-
function normalizeLocalToolName(toolName) {
|
|
15614
|
-
return canonicalizeToolName(
|
|
15615
|
-
String(toolName ?? "").replace(/^functions\./, "").trim()
|
|
15616
|
-
);
|
|
15617
|
-
}
|
|
15618
|
-
function isRestrictedLocalToolMode(env) {
|
|
15619
|
-
return env.NOLO_LOCAL_TOOL_MODE === "restricted";
|
|
15620
|
-
}
|
|
15621
|
-
function resolveLocalToolPolicy(args2) {
|
|
15622
|
-
const toolName = normalizeLocalToolName(args2.toolName);
|
|
15623
|
-
const restrictedMode = isRestrictedLocalToolMode(args2.env);
|
|
15624
|
-
if (!toolName) {
|
|
15625
|
-
return {
|
|
15626
|
-
allowed: false,
|
|
15627
|
-
toolName,
|
|
15628
|
-
reason: "Tool name is required."
|
|
15629
|
-
};
|
|
15630
|
-
}
|
|
15631
|
-
if (NEVER_LOCAL_TOOLS.has(toolName)) {
|
|
15632
|
-
return {
|
|
15633
|
-
allowed: false,
|
|
15634
|
-
toolName,
|
|
15635
|
-
reason: `${toolName} is blocked by the local runtime safety policy.`
|
|
15636
|
-
};
|
|
15637
|
-
}
|
|
15638
|
-
const allowedByEnv = new Set(parseToolAllowlist(args2.env.NOLO_LOCAL_ALLOWED_TOOLS));
|
|
15639
|
-
const agentTools = new Set(
|
|
15640
|
-
(args2.agentToolNames ?? []).flatMap((item) => {
|
|
15641
|
-
const normalized = normalizeLocalToolName(item);
|
|
15642
|
-
return normalized ? [normalized] : [];
|
|
15643
|
-
})
|
|
15644
|
-
);
|
|
15645
|
-
if (!restrictedMode && agentTools.has(toolName)) {
|
|
15646
|
-
return { allowed: true, toolName };
|
|
15647
|
-
}
|
|
15648
|
-
if (DEFAULT_LOCAL_TOOLS.has(toolName) && agentTools.has(toolName)) {
|
|
15649
|
-
return { allowed: true, toolName };
|
|
15650
|
-
}
|
|
15651
|
-
if (allowedByEnv.has(toolName) && agentTools.has(toolName)) {
|
|
15652
|
-
return { allowed: true, toolName };
|
|
15653
|
-
}
|
|
15654
|
-
return {
|
|
15655
|
-
allowed: false,
|
|
15656
|
-
toolName,
|
|
15657
|
-
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.`
|
|
15658
|
-
};
|
|
15659
|
-
}
|
|
15660
|
-
async function executeLocalToolWithPolicy(args2) {
|
|
15661
|
-
if (args2.runToolNames !== void 0 && !args2.runToolNames.includes(normalizeLocalToolName(args2.call.name))) {
|
|
15662
|
-
throw new Error(`${args2.call.name} is outside the final run tool surface.`);
|
|
15663
|
-
}
|
|
15664
|
-
const decision = resolveLocalToolPolicy({
|
|
15665
|
-
env: args2.env,
|
|
15666
|
-
agentToolNames: args2.agentToolNames,
|
|
15667
|
-
toolName: args2.call.name
|
|
15668
|
-
});
|
|
15669
|
-
if (!decision.allowed) throw new Error(decision.reason);
|
|
15670
|
-
const executor = args2.executors?.[decision.toolName];
|
|
15671
|
-
if (!executor) {
|
|
15672
|
-
throw new Error(`${decision.toolName} is allowed by policy but no local executor is registered.`);
|
|
15673
|
-
}
|
|
15674
|
-
const opts = {
|
|
15675
|
-
...args2.abortSignal ? { abortSignal: args2.abortSignal } : {},
|
|
15676
|
-
...args2.detachMs !== void 0 ? { detachMs: args2.detachMs } : {},
|
|
15677
|
-
...args2.confirmed !== void 0 ? { confirmed: args2.confirmed } : {},
|
|
15678
|
-
...args2.enableDestructiveShellGuard !== void 0 ? { enableDestructiveShellGuard: args2.enableDestructiveShellGuard } : {},
|
|
15679
|
-
...args2.confirmDestructiveAction ? { confirmDestructiveAction: args2.confirmDestructiveAction } : {},
|
|
15680
|
-
...args2.blockDestructiveWithoutConfirmation !== void 0 ? { blockDestructiveWithoutConfirmation: args2.blockDestructiveWithoutConfirmation } : {}
|
|
15681
|
-
};
|
|
15682
|
-
if (decision.toolName === "execShell") {
|
|
15683
|
-
let parsedInput = args2.call.arguments;
|
|
15684
|
-
if (typeof parsedInput === "string") {
|
|
15685
|
-
try {
|
|
15686
|
-
parsedInput = JSON.parse(parsedInput);
|
|
15687
|
-
} catch {
|
|
15688
|
-
parsedInput = { command: parsedInput };
|
|
15689
|
-
}
|
|
15690
|
-
}
|
|
15691
|
-
await evaluateExecShellDestructiveGuard(parsedInput, opts);
|
|
15692
|
-
opts.confirmed = true;
|
|
15693
|
-
}
|
|
15694
|
-
return executor(
|
|
15695
|
-
{
|
|
15696
|
-
...args2.call,
|
|
15697
|
-
name: decision.toolName
|
|
15698
|
-
},
|
|
15699
|
-
opts
|
|
15700
|
-
);
|
|
15701
|
-
}
|
|
15702
|
-
|
|
15703
15725
|
// packages/agent-runtime/localWorkspaceTools.ts
|
|
15704
15726
|
import { existsSync as existsSync3 } from "node:fs";
|
|
15705
15727
|
import { createHash as createHash3 } from "node:crypto";
|
|
@@ -16498,29 +16520,6 @@ function getProcessRegistry() {
|
|
|
16498
16520
|
return registry;
|
|
16499
16521
|
}
|
|
16500
16522
|
|
|
16501
|
-
// packages/agent-runtime/processOwnership.ts
|
|
16502
|
-
var asNonEmptyString = (value) => {
|
|
16503
|
-
if (typeof value !== "string") return null;
|
|
16504
|
-
const trimmed = value.trim();
|
|
16505
|
-
return trimmed ? trimmed : null;
|
|
16506
|
-
};
|
|
16507
|
-
function readProcessOwner(runtimeContext) {
|
|
16508
|
-
if (!runtimeContext || typeof runtimeContext !== "object") return null;
|
|
16509
|
-
const dialogId = asNonEmptyString(runtimeContext.dialogId) ?? asNonEmptyString(runtimeContext.parentThreadId);
|
|
16510
|
-
if (!dialogId) return null;
|
|
16511
|
-
const turnId = asNonEmptyString(runtimeContext.turnId);
|
|
16512
|
-
const ownerId = asNonEmptyString(runtimeContext.ownerId);
|
|
16513
|
-
return {
|
|
16514
|
-
dialogId,
|
|
16515
|
-
...turnId ? { turnId } : {},
|
|
16516
|
-
...ownerId ? { ownerId } : {}
|
|
16517
|
-
};
|
|
16518
|
-
}
|
|
16519
|
-
|
|
16520
|
-
// packages/agent-runtime/workspaceShell.ts
|
|
16521
|
-
import { resolve as resolve3 } from "node:path";
|
|
16522
|
-
import { spawn as spawnChildProcess2 } from "node:child_process";
|
|
16523
|
-
|
|
16524
16523
|
// packages/agent-runtime/processTaskResult.ts
|
|
16525
16524
|
var PROCESS_RESULT_CAPSULE_TAIL_CHARS = 4e3;
|
|
16526
16525
|
var PROCESS_RESULT_CAPSULE_SPILL_THRESHOLD_CHARS = 2e4;
|
|
@@ -16540,11 +16539,17 @@ function buildProcessTaskResultCapsule(args2) {
|
|
|
16540
16539
|
const exitCode = args2.exitCode;
|
|
16541
16540
|
const captureError = args2.captureError?.trim() || void 0;
|
|
16542
16541
|
const durationMs = typeof args2.startedAt === "number" && Number.isFinite(args2.startedAt) ? Math.max(0, (args2.endedAt ?? Date.now()) - args2.startedAt) : void 0;
|
|
16543
|
-
const
|
|
16544
|
-
const
|
|
16542
|
+
const stdoutProvenance = args2.streamProvenance?.stdout;
|
|
16543
|
+
const stderrProvenance = args2.streamProvenance?.stderr;
|
|
16544
|
+
const ringEvicted = Boolean(stdoutProvenance?.evicted || stderrProvenance?.evicted);
|
|
16545
|
+
const stdoutTailSource = typeof args2.stdoutTail === "string" ? args2.stdoutTail : stdout;
|
|
16546
|
+
const stderrTailSource = typeof args2.stderrTail === "string" ? args2.stderrTail : stderr;
|
|
16547
|
+
const stdoutTail = tailText(stdoutTailSource, tailChars);
|
|
16548
|
+
const stderrTail = tailText(stderrTailSource, tailChars);
|
|
16545
16549
|
const inlineSize = stdout.length + stderr.length;
|
|
16546
16550
|
const inlineTruncated = stdoutTail.truncated || stderrTail.truncated;
|
|
16547
|
-
const
|
|
16551
|
+
const truncated = inlineTruncated || ringEvicted || Boolean(captureError);
|
|
16552
|
+
const shouldSpill = truncated || inlineSize > spillThresholdChars;
|
|
16548
16553
|
let spill;
|
|
16549
16554
|
if (shouldSpill) {
|
|
16550
16555
|
try {
|
|
@@ -16558,8 +16563,11 @@ function buildProcessTaskResultCapsule(args2) {
|
|
|
16558
16563
|
});
|
|
16559
16564
|
spill = {
|
|
16560
16565
|
displayPath: result4.displayPath,
|
|
16561
|
-
|
|
16562
|
-
|
|
16566
|
+
// Prefer the caller's live provenance counters: they count every
|
|
16567
|
+
// byte of the original stream, while the buffered content above may
|
|
16568
|
+
// be a capped prefix of it.
|
|
16569
|
+
totalChars: (stdoutProvenance?.totalChars ?? stdout.length) + (stderrProvenance?.totalChars ?? stderr.length),
|
|
16570
|
+
totalLines: (stdoutProvenance?.totalLines ?? countLines(stdout)) + (stderrProvenance?.totalLines ?? countLines(stderr))
|
|
16563
16571
|
};
|
|
16564
16572
|
} catch {
|
|
16565
16573
|
}
|
|
@@ -16570,12 +16578,33 @@ function buildProcessTaskResultCapsule(args2) {
|
|
|
16570
16578
|
exitCode,
|
|
16571
16579
|
...durationMs !== void 0 ? { durationMs } : {},
|
|
16572
16580
|
...captureError ? { captureError } : {},
|
|
16573
|
-
truncated
|
|
16581
|
+
truncated,
|
|
16574
16582
|
...spill ? { spill } : {}
|
|
16575
16583
|
};
|
|
16576
16584
|
}
|
|
16577
16585
|
|
|
16586
|
+
// packages/agent-runtime/processOwnership.ts
|
|
16587
|
+
var asNonEmptyString = (value) => {
|
|
16588
|
+
if (typeof value !== "string") return null;
|
|
16589
|
+
const trimmed = value.trim();
|
|
16590
|
+
return trimmed ? trimmed : null;
|
|
16591
|
+
};
|
|
16592
|
+
function readProcessOwner(runtimeContext) {
|
|
16593
|
+
if (!runtimeContext || typeof runtimeContext !== "object") return null;
|
|
16594
|
+
const dialogId = asNonEmptyString(runtimeContext.dialogId) ?? asNonEmptyString(runtimeContext.parentThreadId);
|
|
16595
|
+
if (!dialogId) return null;
|
|
16596
|
+
const turnId = asNonEmptyString(runtimeContext.turnId);
|
|
16597
|
+
const ownerId = asNonEmptyString(runtimeContext.ownerId);
|
|
16598
|
+
return {
|
|
16599
|
+
dialogId,
|
|
16600
|
+
...turnId ? { turnId } : {},
|
|
16601
|
+
...ownerId ? { ownerId } : {}
|
|
16602
|
+
};
|
|
16603
|
+
}
|
|
16604
|
+
|
|
16578
16605
|
// packages/agent-runtime/workspaceShell.ts
|
|
16606
|
+
import { resolve as resolve3 } from "node:path";
|
|
16607
|
+
import { spawn as spawnChildProcess2 } from "node:child_process";
|
|
16579
16608
|
var EXEC_SHELL_TIMEOUT_ENV = "NOLO_EXEC_SHELL_TIMEOUT_MS";
|
|
16580
16609
|
var EXEC_SHELL_DETACH_ENV = "NOLO_EXEC_SHELL_DETACH_MS";
|
|
16581
16610
|
var DEFAULT_EXEC_SHELL_DETACH_MS = 12e4;
|
|
@@ -17444,32 +17473,192 @@ function runTasks(args2) {
|
|
|
17444
17473
|
return { tasks, count: tasks.length };
|
|
17445
17474
|
}
|
|
17446
17475
|
|
|
17447
|
-
// packages/agent-runtime/
|
|
17448
|
-
|
|
17449
|
-
|
|
17450
|
-
|
|
17451
|
-
|
|
17452
|
-
|
|
17453
|
-
|
|
17454
|
-
|
|
17455
|
-
|
|
17456
|
-
|
|
17457
|
-
|
|
17458
|
-
|
|
17459
|
-
|
|
17460
|
-
|
|
17461
|
-
|
|
17462
|
-
type: "string",
|
|
17463
|
-
description: "Compatibility alias for command."
|
|
17464
|
-
}
|
|
17465
|
-
}
|
|
17476
|
+
// packages/agent-runtime/execShellCompletionWarnings.ts
|
|
17477
|
+
var BG_ESCAPE_WORD_PATTERN = /(?:^|[\s;|(&/\\])(nohup|disown|setsid|start-process)(?=$|[\s;|)&])/i;
|
|
17478
|
+
var SHELL_SPLIT_CHARS = /* @__PURE__ */ new Set([";", "|", "&", "(", ")", "<", ">", "\n", " ", " "]);
|
|
17479
|
+
function maskQuotedAndEscaped(command) {
|
|
17480
|
+
const out = Array.from(command);
|
|
17481
|
+
let quote = null;
|
|
17482
|
+
for (let i = 0; i < out.length; i += 1) {
|
|
17483
|
+
const ch = out[i];
|
|
17484
|
+
if (quote) {
|
|
17485
|
+
out[i] = " ";
|
|
17486
|
+
if (ch === "\\" && quote !== "'") {
|
|
17487
|
+
if (i + 1 < out.length) out[i + 1] = " ";
|
|
17488
|
+
i += 1;
|
|
17489
|
+
} else if (ch === quote) {
|
|
17490
|
+
quote = null;
|
|
17466
17491
|
}
|
|
17492
|
+
continue;
|
|
17467
17493
|
}
|
|
17468
|
-
|
|
17469
|
-
|
|
17470
|
-
|
|
17471
|
-
|
|
17472
|
-
|
|
17494
|
+
if (ch === "\\") {
|
|
17495
|
+
out[i] = " ";
|
|
17496
|
+
if (i + 1 < out.length) out[i + 1] = " ";
|
|
17497
|
+
i += 1;
|
|
17498
|
+
continue;
|
|
17499
|
+
}
|
|
17500
|
+
if (ch === "'" || ch === '"' || ch === "`") {
|
|
17501
|
+
quote = ch;
|
|
17502
|
+
out[i] = " ";
|
|
17503
|
+
continue;
|
|
17504
|
+
}
|
|
17505
|
+
if (ch === "#" && (i === 0 || /[\s;]/.test(out[i - 1] ?? " "))) {
|
|
17506
|
+
while (i < out.length && out[i] !== "\n") {
|
|
17507
|
+
out[i] = " ";
|
|
17508
|
+
i += 1;
|
|
17509
|
+
}
|
|
17510
|
+
}
|
|
17511
|
+
}
|
|
17512
|
+
return out.join("");
|
|
17513
|
+
}
|
|
17514
|
+
function readRedirectTarget(original, start) {
|
|
17515
|
+
let i = start;
|
|
17516
|
+
while (i < original.length && /\s/.test(original[i] ?? "")) {
|
|
17517
|
+
i += 1;
|
|
17518
|
+
}
|
|
17519
|
+
if (i >= original.length) return void 0;
|
|
17520
|
+
let text = "";
|
|
17521
|
+
let j = i;
|
|
17522
|
+
while (j < original.length) {
|
|
17523
|
+
const o = original[j];
|
|
17524
|
+
if (o === "'" || o === '"' || o === "`") {
|
|
17525
|
+
const quote = o;
|
|
17526
|
+
j += 1;
|
|
17527
|
+
while (j < original.length && original[j] !== quote) {
|
|
17528
|
+
if (original[j] === "\\" && quote !== "'" && j + 1 < original.length) {
|
|
17529
|
+
text += original[j + 1];
|
|
17530
|
+
j += 2;
|
|
17531
|
+
continue;
|
|
17532
|
+
}
|
|
17533
|
+
text += original[j];
|
|
17534
|
+
j += 1;
|
|
17535
|
+
}
|
|
17536
|
+
j += 1;
|
|
17537
|
+
continue;
|
|
17538
|
+
}
|
|
17539
|
+
if (/\s/.test(o) || SHELL_SPLIT_CHARS.has(o)) break;
|
|
17540
|
+
text += o;
|
|
17541
|
+
j += 1;
|
|
17542
|
+
}
|
|
17543
|
+
if (!text || text === "$") return void 0;
|
|
17544
|
+
return { text, end: j };
|
|
17545
|
+
}
|
|
17546
|
+
function isIgnoredRedirectTarget(target) {
|
|
17547
|
+
return target === "/dev/null";
|
|
17548
|
+
}
|
|
17549
|
+
function detectExecShellSynchronousWarnings(command, shell) {
|
|
17550
|
+
const masked = maskQuotedAndEscaped(command);
|
|
17551
|
+
const isPowerShell = shell?.resolvedShell === "powershell";
|
|
17552
|
+
const redirectTargets = [];
|
|
17553
|
+
let backgrounded = false;
|
|
17554
|
+
let i = 0;
|
|
17555
|
+
while (i < masked.length) {
|
|
17556
|
+
const ch = masked[i];
|
|
17557
|
+
if (ch === "&") {
|
|
17558
|
+
const next = masked[i + 1];
|
|
17559
|
+
if (next === "&") {
|
|
17560
|
+
i += 2;
|
|
17561
|
+
continue;
|
|
17562
|
+
}
|
|
17563
|
+
if (next === ">") {
|
|
17564
|
+
let j = i + 2;
|
|
17565
|
+
if (masked[j] === ">") j += 1;
|
|
17566
|
+
const target = readRedirectTarget(command, j);
|
|
17567
|
+
if (target && !isIgnoredRedirectTarget(target.text)) redirectTargets.push(target.text);
|
|
17568
|
+
i = target ? target.end : j;
|
|
17569
|
+
continue;
|
|
17570
|
+
}
|
|
17571
|
+
const prev = masked[i - 1];
|
|
17572
|
+
if (prev === ">" || prev === "<") {
|
|
17573
|
+
i += 1;
|
|
17574
|
+
continue;
|
|
17575
|
+
}
|
|
17576
|
+
if (isPowerShell) {
|
|
17577
|
+
i += 1;
|
|
17578
|
+
continue;
|
|
17579
|
+
}
|
|
17580
|
+
backgrounded = true;
|
|
17581
|
+
i += 1;
|
|
17582
|
+
continue;
|
|
17583
|
+
}
|
|
17584
|
+
if (ch === ">") {
|
|
17585
|
+
const prev = masked[i - 1];
|
|
17586
|
+
if (prev === ">" || prev === "&" || prev === "<") {
|
|
17587
|
+
i += 1;
|
|
17588
|
+
continue;
|
|
17589
|
+
}
|
|
17590
|
+
let j = i + 1;
|
|
17591
|
+
if (masked[j] === ">") j += 1;
|
|
17592
|
+
if (masked[j] === "&") {
|
|
17593
|
+
const ampTarget = readRedirectTarget(command, j + 1);
|
|
17594
|
+
const isFdDuplication = ampTarget !== void 0 && (/^\d+$/.test(ampTarget.text) || ampTarget.text === "-");
|
|
17595
|
+
if (ampTarget && !isFdDuplication && !isIgnoredRedirectTarget(ampTarget.text)) {
|
|
17596
|
+
redirectTargets.push(ampTarget.text);
|
|
17597
|
+
}
|
|
17598
|
+
i = ampTarget ? ampTarget.end : j + 1;
|
|
17599
|
+
continue;
|
|
17600
|
+
}
|
|
17601
|
+
const target = readRedirectTarget(command, j);
|
|
17602
|
+
if (target && !isIgnoredRedirectTarget(target.text)) redirectTargets.push(target.text);
|
|
17603
|
+
i = target ? target.end : j;
|
|
17604
|
+
continue;
|
|
17605
|
+
}
|
|
17606
|
+
if (ch === "<") {
|
|
17607
|
+
i += masked[i + 1] === "<" || masked[i + 1] === "&" ? 2 : 1;
|
|
17608
|
+
continue;
|
|
17609
|
+
}
|
|
17610
|
+
i += 1;
|
|
17611
|
+
}
|
|
17612
|
+
const wordMatch = BG_ESCAPE_WORD_PATTERN.exec(masked);
|
|
17613
|
+
if (wordMatch) backgrounded = true;
|
|
17614
|
+
const warnings = [];
|
|
17615
|
+
if (redirectTargets.length > 0) {
|
|
17616
|
+
const target = redirectTargets[0];
|
|
17617
|
+
warnings.push({
|
|
17618
|
+
kind: "output-redirect",
|
|
17619
|
+
redirectTarget: target,
|
|
17620
|
+
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.`
|
|
17621
|
+
});
|
|
17622
|
+
}
|
|
17623
|
+
if (backgrounded) {
|
|
17624
|
+
warnings.push({
|
|
17625
|
+
kind: "shell-backgrounding",
|
|
17626
|
+
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.`
|
|
17627
|
+
});
|
|
17628
|
+
}
|
|
17629
|
+
return warnings;
|
|
17630
|
+
}
|
|
17631
|
+
|
|
17632
|
+
// packages/agent-runtime/capabilities/execShellCapability.ts
|
|
17633
|
+
function buildExecShellToolDefinition(toolName = "execShell") {
|
|
17634
|
+
return {
|
|
17635
|
+
type: "function",
|
|
17636
|
+
function: {
|
|
17637
|
+
name: toolName,
|
|
17638
|
+
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.`,
|
|
17639
|
+
parameters: {
|
|
17640
|
+
type: "object",
|
|
17641
|
+
properties: {
|
|
17642
|
+
command: {
|
|
17643
|
+
type: "string",
|
|
17644
|
+
description: "Shell command to run (non-empty)."
|
|
17645
|
+
},
|
|
17646
|
+
cmd: {
|
|
17647
|
+
type: "string",
|
|
17648
|
+
description: "Compatibility alias for command."
|
|
17649
|
+
},
|
|
17650
|
+
background: {
|
|
17651
|
+
type: "boolean",
|
|
17652
|
+
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."
|
|
17653
|
+
}
|
|
17654
|
+
}
|
|
17655
|
+
}
|
|
17656
|
+
}
|
|
17657
|
+
};
|
|
17658
|
+
}
|
|
17659
|
+
function normalizeExecShellInput(input) {
|
|
17660
|
+
if (input === null || input === void 0) {
|
|
17661
|
+
throw new Error("execShell requires a non-empty command.");
|
|
17473
17662
|
}
|
|
17474
17663
|
if (typeof input === "string") {
|
|
17475
17664
|
const trimmed = input.trim();
|
|
@@ -17501,11 +17690,13 @@ function normalizeExecShellInput(input) {
|
|
|
17501
17690
|
throw new Error("execShell requires a non-empty command.");
|
|
17502
17691
|
}
|
|
17503
17692
|
const activity = extractActivity(record);
|
|
17693
|
+
const background = record.background === true || typeof record.background === "string" && record.background.trim().toLowerCase() === "true";
|
|
17504
17694
|
return {
|
|
17505
17695
|
command,
|
|
17506
17696
|
...record.shell !== void 0 ? { shell: record.shell } : {},
|
|
17507
17697
|
...activity ? { activity } : {},
|
|
17508
|
-
...record.input !== void 0 ? { input: record.input } : {}
|
|
17698
|
+
...record.input !== void 0 ? { input: record.input } : {},
|
|
17699
|
+
...background ? { background: true } : {}
|
|
17509
17700
|
};
|
|
17510
17701
|
}
|
|
17511
17702
|
throw new Error("execShell requires a non-empty command.");
|
|
@@ -17543,6 +17734,7 @@ var execShellCapability = {
|
|
|
17543
17734
|
command,
|
|
17544
17735
|
shell: normalized.shell
|
|
17545
17736
|
});
|
|
17737
|
+
const background = normalized.background === true;
|
|
17546
17738
|
const result4 = await runWorkspaceCommand({
|
|
17547
17739
|
workspaceRoot,
|
|
17548
17740
|
command: shellPlan.argv,
|
|
@@ -17550,15 +17742,18 @@ var execShellCapability = {
|
|
|
17550
17742
|
outputLimit: ctx.commandOutputLimit,
|
|
17551
17743
|
commandPrefix: ctx.commandPrefix,
|
|
17552
17744
|
abortSignal: ctx.abortSignal,
|
|
17553
|
-
detachMs: isImmediateDetachShellCommand({ command }) ? 0 : ctx.detachMs,
|
|
17745
|
+
detachMs: background ? 0 : isImmediateDetachShellCommand({ command }) ? 0 : ctx.detachMs,
|
|
17554
17746
|
stdin: typeof normalized.input === "string" ? normalized.input : void 0,
|
|
17555
17747
|
// Ownership of the turn that invoked this command: an auto-detached
|
|
17556
17748
|
// command keeps its parent dialog so its terminal can resume that
|
|
17557
17749
|
// conversation (see processOwnership.ts). Absent ctx.owner = unowned.
|
|
17558
17750
|
owner: ctx.owner ?? null
|
|
17559
17751
|
});
|
|
17752
|
+
const warnings = result4.detached || result4.spawnFailed ? [] : detectExecShellSynchronousWarnings(command, {
|
|
17753
|
+
resolvedShell: shellPlan.resolvedShell
|
|
17754
|
+
});
|
|
17560
17755
|
return {
|
|
17561
|
-
content: result4.content,
|
|
17756
|
+
content: warnings.length > 0 ? [result4.content, ...warnings.map((warning) => warning.message)].join("\n\n") : result4.content,
|
|
17562
17757
|
metadata: {
|
|
17563
17758
|
command,
|
|
17564
17759
|
exitCode: result4.exitCode,
|
|
@@ -17573,8 +17768,21 @@ var execShellCapability = {
|
|
|
17573
17768
|
// Phase 0: stable taskId from the pre-registered Execution
|
|
17574
17769
|
// Envelope (additive; existing detached fields untouched).
|
|
17575
17770
|
taskId: result4.taskId,
|
|
17576
|
-
status: "running"
|
|
17577
|
-
|
|
17771
|
+
status: "running",
|
|
17772
|
+
// P0 machine-readable execution state: an explicit positive
|
|
17773
|
+
// signal instead of requiring the model to infer "not detached"
|
|
17774
|
+
// from absence. Mirrors the real lifecycle contract.
|
|
17775
|
+
executionState: "detached",
|
|
17776
|
+
trackedBackgroundTask: true,
|
|
17777
|
+
completionNotification: "terminal-resume"
|
|
17778
|
+
} : {
|
|
17779
|
+
// P0 machine-readable execution state: the command already
|
|
17780
|
+
// finished inside the synchronous window; no background task
|
|
17781
|
+
// exists, so no completion notification will ever arrive.
|
|
17782
|
+
executionState: "synchronous-complete",
|
|
17783
|
+
trackedBackgroundTask: false,
|
|
17784
|
+
completionNotification: "none"
|
|
17785
|
+
},
|
|
17578
17786
|
...normalized.activity ? { activity: normalized.activity } : {}
|
|
17579
17787
|
}
|
|
17580
17788
|
};
|
|
@@ -17790,7 +17998,7 @@ function buildLaunchProcessTool() {
|
|
|
17790
17998
|
type: "function",
|
|
17791
17999
|
function: {
|
|
17792
18000
|
name: "launchProcess",
|
|
17793
|
-
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.",
|
|
18001
|
+
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.",
|
|
17794
18002
|
parameters: {
|
|
17795
18003
|
type: "object",
|
|
17796
18004
|
properties: {
|
|
@@ -18576,6 +18784,87 @@ async function writeFileTool(args2) {
|
|
|
18576
18784
|
}
|
|
18577
18785
|
};
|
|
18578
18786
|
}
|
|
18787
|
+
function extractSnippetWords(text) {
|
|
18788
|
+
const tokens = [];
|
|
18789
|
+
const latinWords = text.match(/[A-Za-z0-9_]{2,}/g);
|
|
18790
|
+
if (latinWords) {
|
|
18791
|
+
for (const w of latinWords) tokens.push(w.toLowerCase());
|
|
18792
|
+
}
|
|
18793
|
+
const cjkChars = text.match(new RegExp("\\p{Script=Han}", "gu"));
|
|
18794
|
+
if (cjkChars) {
|
|
18795
|
+
for (let i = 0; i < cjkChars.length - 1; i++) {
|
|
18796
|
+
tokens.push(cjkChars[i] + cjkChars[i + 1]);
|
|
18797
|
+
}
|
|
18798
|
+
if (cjkChars.length === 1) tokens.push(cjkChars[0]);
|
|
18799
|
+
}
|
|
18800
|
+
return tokens;
|
|
18801
|
+
}
|
|
18802
|
+
function calculateEditLineSimilarity(a, b) {
|
|
18803
|
+
if (a === b) return 1;
|
|
18804
|
+
if (!a || !b) return 0;
|
|
18805
|
+
if (a.includes(b) || b.includes(a)) return 0.8;
|
|
18806
|
+
const wordsA = extractSnippetWords(a);
|
|
18807
|
+
const wordsB = extractSnippetWords(b);
|
|
18808
|
+
if (wordsA.length === 0 || wordsB.length === 0) return 0;
|
|
18809
|
+
const setB = new Set(wordsB);
|
|
18810
|
+
let matches = 0;
|
|
18811
|
+
for (const w of wordsA) {
|
|
18812
|
+
if (setB.has(w)) matches++;
|
|
18813
|
+
}
|
|
18814
|
+
return 2 * matches / (wordsA.length + wordsB.length);
|
|
18815
|
+
}
|
|
18816
|
+
function findClosestEditSnippet(content, oldText) {
|
|
18817
|
+
const contentLines = content.split(/\r?\n/);
|
|
18818
|
+
const oldLinesRaw = oldText.split(/\r?\n/);
|
|
18819
|
+
const oldTrimmedLines = oldLinesRaw.map((l) => l.trim()).filter(Boolean);
|
|
18820
|
+
if (contentLines.length === 0 || oldTrimmedLines.length === 0) return null;
|
|
18821
|
+
if (oldTrimmedLines.length > 0 && contentLines.length >= oldTrimmedLines.length) {
|
|
18822
|
+
for (let i = 0; i <= contentLines.length - oldTrimmedLines.length; i++) {
|
|
18823
|
+
let allMatch = true;
|
|
18824
|
+
for (let j = 0; j < oldTrimmedLines.length; j++) {
|
|
18825
|
+
if (contentLines[i + j].trim() !== oldTrimmedLines[j]) {
|
|
18826
|
+
allMatch = false;
|
|
18827
|
+
break;
|
|
18828
|
+
}
|
|
18829
|
+
}
|
|
18830
|
+
if (allMatch) {
|
|
18831
|
+
const startLine2 = i + 1;
|
|
18832
|
+
const endLine2 = i + oldTrimmedLines.length;
|
|
18833
|
+
const snippetLines2 = [];
|
|
18834
|
+
for (let k = i; k < i + oldTrimmedLines.length; k++) {
|
|
18835
|
+
snippetLines2.push(`> ${k + 1}: ${contentLines[k]}`);
|
|
18836
|
+
}
|
|
18837
|
+
return `Exact match found with different indentation/whitespace (lines ${startLine2}-${endLine2}):
|
|
18838
|
+
${snippetLines2.join("\n")}`;
|
|
18839
|
+
}
|
|
18840
|
+
}
|
|
18841
|
+
}
|
|
18842
|
+
const candidateTargetLines = oldTrimmedLines.filter((l) => l.length >= 4);
|
|
18843
|
+
const targetLine = candidateTargetLines[0] || oldTrimmedLines[0];
|
|
18844
|
+
if (!targetLine || targetLine.length < 3) return null;
|
|
18845
|
+
let bestIndex = -1;
|
|
18846
|
+
let bestScore = 0;
|
|
18847
|
+
for (let i = 0; i < contentLines.length; i++) {
|
|
18848
|
+
const line = contentLines[i].trim();
|
|
18849
|
+
if (!line || line.length < 3) continue;
|
|
18850
|
+
const score = calculateEditLineSimilarity(line, targetLine);
|
|
18851
|
+
if (score > bestScore && score >= 0.45) {
|
|
18852
|
+
bestScore = score;
|
|
18853
|
+
bestIndex = i;
|
|
18854
|
+
if (score === 1) break;
|
|
18855
|
+
}
|
|
18856
|
+
}
|
|
18857
|
+
if (bestIndex === -1) return null;
|
|
18858
|
+
const startLine = Math.max(0, bestIndex - 2);
|
|
18859
|
+
const endLine = Math.min(contentLines.length - 1, bestIndex + 2);
|
|
18860
|
+
const snippetLines = [];
|
|
18861
|
+
for (let i = startLine; i <= endLine; i++) {
|
|
18862
|
+
const prefix = i === bestIndex ? "> " : " ";
|
|
18863
|
+
snippetLines.push(`${prefix}${i + 1}: ${contentLines[i]}`);
|
|
18864
|
+
}
|
|
18865
|
+
return `Closest match near line ${bestIndex + 1}:
|
|
18866
|
+
${snippetLines.join("\n")}`;
|
|
18867
|
+
}
|
|
18579
18868
|
async function editFileTool(args2) {
|
|
18580
18869
|
const parsed = parseWorkspaceToolArguments(args2.call.arguments);
|
|
18581
18870
|
const requestedPath = requireWorkspaceToolPath(parsed);
|
|
@@ -18594,8 +18883,11 @@ async function editFileTool(args2) {
|
|
|
18594
18883
|
newText
|
|
18595
18884
|
});
|
|
18596
18885
|
if (replacementCount !== expectedReplacements) {
|
|
18886
|
+
const hint = replacementCount === 0 ? findClosestEditSnippet(content, oldText) : null;
|
|
18597
18887
|
throw new Error(
|
|
18598
|
-
`editFile expected ${expectedReplacements} ${pluralizeReplacement(expectedReplacements)} but found ${replacementCount} in ${requestedPath} (matched after EOL normalization; verify the exact text).`
|
|
18888
|
+
`editFile expected ${expectedReplacements} ${pluralizeReplacement(expectedReplacements)} but found ${replacementCount} in ${requestedPath} (matched after EOL normalization; verify the exact text).` + (hint ? `
|
|
18889
|
+
|
|
18890
|
+
${hint}` : "")
|
|
18599
18891
|
);
|
|
18600
18892
|
}
|
|
18601
18893
|
await writeFile(absolutePath, nextContent, "utf8");
|
|
@@ -18931,6 +19223,55 @@ async function execShellTool(args2) {
|
|
|
18931
19223
|
}
|
|
18932
19224
|
);
|
|
18933
19225
|
}
|
|
19226
|
+
var LAUNCH_PROCESS_STREAM_RING_CHARS = 65536;
|
|
19227
|
+
var LAUNCH_PROCESS_STREAM_CAPTURE_MAX_CHARS = 4e6;
|
|
19228
|
+
function createLaunchProcessStreamCapture() {
|
|
19229
|
+
let ring = "";
|
|
19230
|
+
let full = null;
|
|
19231
|
+
let capturedChars = 0;
|
|
19232
|
+
let totalChars = 0;
|
|
19233
|
+
let totalNewlines = 0;
|
|
19234
|
+
return {
|
|
19235
|
+
push(chunk) {
|
|
19236
|
+
const str = typeof chunk === "string" ? chunk : chunk.toString("utf8");
|
|
19237
|
+
if (!str) return;
|
|
19238
|
+
totalChars += str.length;
|
|
19239
|
+
for (let i = 0; i < str.length; i += 1) {
|
|
19240
|
+
if (str.charCodeAt(i) === 10) totalNewlines += 1;
|
|
19241
|
+
}
|
|
19242
|
+
const combined = ring + str;
|
|
19243
|
+
if (combined.length <= LAUNCH_PROCESS_STREAM_RING_CHARS) {
|
|
19244
|
+
ring = combined;
|
|
19245
|
+
return;
|
|
19246
|
+
}
|
|
19247
|
+
if (full === null) {
|
|
19248
|
+
full = [combined];
|
|
19249
|
+
capturedChars = combined.length;
|
|
19250
|
+
} else if (capturedChars < LAUNCH_PROCESS_STREAM_CAPTURE_MAX_CHARS) {
|
|
19251
|
+
const room = LAUNCH_PROCESS_STREAM_CAPTURE_MAX_CHARS - capturedChars;
|
|
19252
|
+
const slice = str.length <= room ? str : str.slice(0, room);
|
|
19253
|
+
full.push(slice);
|
|
19254
|
+
capturedChars += slice.length;
|
|
19255
|
+
}
|
|
19256
|
+
ring = combined.slice(-LAUNCH_PROCESS_STREAM_RING_CHARS);
|
|
19257
|
+
},
|
|
19258
|
+
text() {
|
|
19259
|
+
return full === null ? ring : full.join("");
|
|
19260
|
+
},
|
|
19261
|
+
tailText() {
|
|
19262
|
+
return ring;
|
|
19263
|
+
},
|
|
19264
|
+
evicted() {
|
|
19265
|
+
return full !== null;
|
|
19266
|
+
},
|
|
19267
|
+
totalChars() {
|
|
19268
|
+
return totalChars;
|
|
19269
|
+
},
|
|
19270
|
+
totalLines() {
|
|
19271
|
+
return totalChars > 0 ? totalNewlines + 1 : 0;
|
|
19272
|
+
}
|
|
19273
|
+
};
|
|
19274
|
+
}
|
|
18934
19275
|
async function launchProcessTool(args2) {
|
|
18935
19276
|
const parsed = parseWorkspaceToolArguments(args2.call.arguments);
|
|
18936
19277
|
const command = requireShellCommand(parsed, args2.call.name);
|
|
@@ -18958,6 +19299,14 @@ async function launchProcessTool(args2) {
|
|
|
18958
19299
|
stdio: ["ignore", "pipe", "pipe"],
|
|
18959
19300
|
detached
|
|
18960
19301
|
});
|
|
19302
|
+
const stdoutCapture = createLaunchProcessStreamCapture();
|
|
19303
|
+
const stderrCapture = createLaunchProcessStreamCapture();
|
|
19304
|
+
proc.stdout?.on("data", (chunk) => stdoutCapture.push(chunk));
|
|
19305
|
+
proc.stderr?.on("data", (chunk) => stderrCapture.push(chunk));
|
|
19306
|
+
proc.stdout?.on("error", () => {
|
|
19307
|
+
});
|
|
19308
|
+
proc.stderr?.on("error", () => {
|
|
19309
|
+
});
|
|
18961
19310
|
const pid = proc.pid;
|
|
18962
19311
|
if (typeof pid !== "number") {
|
|
18963
19312
|
return {
|
|
@@ -18998,7 +19347,38 @@ async function launchProcessTool(args2) {
|
|
|
18998
19347
|
process.removeListener("SIGTERM", cleanupChildOnHostSignal);
|
|
18999
19348
|
process.removeListener("SIGINT", cleanupChildOnHostSignal);
|
|
19000
19349
|
}
|
|
19001
|
-
|
|
19350
|
+
const exitCode = code ?? 1;
|
|
19351
|
+
let capsule;
|
|
19352
|
+
try {
|
|
19353
|
+
capsule = buildProcessTaskResultCapsule({
|
|
19354
|
+
// The full captured output (bounded prefix when the process was
|
|
19355
|
+
// extremely chatty): the module tails it for the inline capsule and
|
|
19356
|
+
// spills it for recovery. Provenance carries the live original-stream
|
|
19357
|
+
// counters so truncated/spill metadata never derives from the ring.
|
|
19358
|
+
stdout: stdoutCapture.text(),
|
|
19359
|
+
stderr: stderrCapture.text(),
|
|
19360
|
+
stdoutTail: stdoutCapture.tailText(),
|
|
19361
|
+
stderrTail: stderrCapture.tailText(),
|
|
19362
|
+
exitCode,
|
|
19363
|
+
// Duration measured from the registry envelope's startedAt (spawn).
|
|
19364
|
+
startedAt: envelope.startedAt,
|
|
19365
|
+
workspaceRoot: args2.workspaceRoot,
|
|
19366
|
+
streamProvenance: {
|
|
19367
|
+
stdout: {
|
|
19368
|
+
evicted: stdoutCapture.evicted(),
|
|
19369
|
+
totalChars: stdoutCapture.totalChars(),
|
|
19370
|
+
totalLines: stdoutCapture.totalLines()
|
|
19371
|
+
},
|
|
19372
|
+
stderr: {
|
|
19373
|
+
evicted: stderrCapture.evicted(),
|
|
19374
|
+
totalChars: stderrCapture.totalChars(),
|
|
19375
|
+
totalLines: stderrCapture.totalLines()
|
|
19376
|
+
}
|
|
19377
|
+
}
|
|
19378
|
+
});
|
|
19379
|
+
} catch {
|
|
19380
|
+
}
|
|
19381
|
+
registry2.markExited(pid, exitCode, capsule);
|
|
19002
19382
|
});
|
|
19003
19383
|
const activity = extractActivity(parsed);
|
|
19004
19384
|
const resultData = { pid, label, taskId: envelope.taskId, status: "running" };
|
|
@@ -19010,6 +19390,13 @@ async function launchProcessTool(args2) {
|
|
|
19010
19390
|
label,
|
|
19011
19391
|
status: "running",
|
|
19012
19392
|
taskId: envelope.taskId,
|
|
19393
|
+
// P0 machine-readable execution state (consistent with the real wake
|
|
19394
|
+
// contract): a real background task from birth, but ambient — its
|
|
19395
|
+
// terminal result rides the next real turn's notice, not an automatic
|
|
19396
|
+
// completion turn.
|
|
19397
|
+
executionState: "background",
|
|
19398
|
+
trackedBackgroundTask: true,
|
|
19399
|
+
completionNotification: "next-turn-notice",
|
|
19013
19400
|
processLaunch: resultData,
|
|
19014
19401
|
...activity ? { activity } : {}
|
|
19015
19402
|
}
|
|
@@ -19112,7 +19499,7 @@ async function tasksTool(_args) {
|
|
|
19112
19499
|
}
|
|
19113
19500
|
async function openDesktopPreviewTool(args2) {
|
|
19114
19501
|
const parsed = parseWorkspaceToolArguments(args2.call.arguments);
|
|
19115
|
-
const url =
|
|
19502
|
+
const url = asTrimmedString(parsed.url);
|
|
19116
19503
|
if (!url) {
|
|
19117
19504
|
return {
|
|
19118
19505
|
content: JSON.stringify({ error: "openDesktopPreview requires a non-empty url." }),
|
|
@@ -19234,6 +19621,290 @@ function createLocalWorkspaceToolExecutors(args2) {
|
|
|
19234
19621
|
};
|
|
19235
19622
|
}
|
|
19236
19623
|
|
|
19624
|
+
// packages/agent-runtime/toolArgumentGate.ts
|
|
19625
|
+
var FIELD_ALIAS_GROUPS = [
|
|
19626
|
+
// localWorkspaceTools.ts:336 导出常量(readFile/writeFile/editFile/globFiles)
|
|
19627
|
+
PATH_FIELD_ALIASES,
|
|
19628
|
+
// localWorkspaceTools.ts:339-340 导出常量(editFile)
|
|
19629
|
+
OLD_TEXT_FIELD_ALIASES,
|
|
19630
|
+
NEW_TEXT_FIELD_ALIASES,
|
|
19631
|
+
// localWorkspaceTools.ts:733 `args.cmd || args.command`(launchProcess);
|
|
19632
|
+
// launchProcess 的 required ["command"] 见 localWorkspaceToolDefs.ts:283。
|
|
19633
|
+
// 注:execShell 的 schema 无 required(command 在 executor 层强制,
|
|
19634
|
+
// capabilities/execShellCapability.ts:42 声明 cmd 兼容字段),本组对它不产生拦截。
|
|
19635
|
+
["command", "cmd"],
|
|
19636
|
+
// localWorkspaceTools.ts:698-699 `args.pattern ?? args.glob`(globFiles)
|
|
19637
|
+
["pattern", "glob"],
|
|
19638
|
+
// noloWorkspaceTools.ts:492 `args.dialog ?? args.dialogId ?? args.id`(readDialog)
|
|
19639
|
+
["dialog", "dialogId", "id"],
|
|
19640
|
+
// noloWorkspaceTools.ts:545 `args.agent ?? args.agentKey ?? args.id`(readAgent)
|
|
19641
|
+
["agent", "agentKey", "id"],
|
|
19642
|
+
// noloWorkspaceTools.ts:552 `args.space ?? args.spaceId ?? args.id`(readSpace)
|
|
19643
|
+
["space", "spaceId", "id"],
|
|
19644
|
+
// noloWorkspaceTools.ts:561/567 `args.doc ?? args.docKey ?? args.pageKey ?? args.key`
|
|
19645
|
+
// (readDoc / readSkillDoc)
|
|
19646
|
+
["doc", "docKey", "pageKey", "key"],
|
|
19647
|
+
// noloWorkspaceTools.node.ts:238 `parsed.name ?? parsed.skillName ?? parsed.skill`(loadSkill)
|
|
19648
|
+
["name", "skillName", "skill"],
|
|
19649
|
+
// noloWorkspaceTools.ts:593 `args.table ?? args.tableId ?? args.metaKey`(queryTableRows)
|
|
19650
|
+
["table", "tableId", "metaKey"]
|
|
19651
|
+
];
|
|
19652
|
+
var TYPE_MATCHERS = {
|
|
19653
|
+
string: (value) => typeof value === "string",
|
|
19654
|
+
// 数字字符串视为可接受:executor 普遍 Number()/clamp 宽松处理,拦截会误报。
|
|
19655
|
+
number: (value) => typeof value === "number" || typeof value === "string" && value.trim() !== "" && Number.isFinite(Number(value)),
|
|
19656
|
+
integer: (value) => typeof value === "number" || typeof value === "string" && value.trim() !== "" && Number.isFinite(Number(value)),
|
|
19657
|
+
boolean: (value) => typeof value === "boolean" || value === "true" || value === "false",
|
|
19658
|
+
object: (value) => typeof value === "object" && value !== null && !Array.isArray(value),
|
|
19659
|
+
array: (value) => Array.isArray(value)
|
|
19660
|
+
};
|
|
19661
|
+
function describeValueType(value) {
|
|
19662
|
+
if (value === null) return "null";
|
|
19663
|
+
if (Array.isArray(value)) return "array";
|
|
19664
|
+
return typeof value;
|
|
19665
|
+
}
|
|
19666
|
+
function isAliasSatisfied(args2, field) {
|
|
19667
|
+
for (const group of FIELD_ALIAS_GROUPS) {
|
|
19668
|
+
if (!group.includes(field)) continue;
|
|
19669
|
+
if (group.some((alias) => args2[alias] !== void 0)) return true;
|
|
19670
|
+
}
|
|
19671
|
+
return false;
|
|
19672
|
+
}
|
|
19673
|
+
function readRequiredFields(parameters) {
|
|
19674
|
+
const required = parameters.required;
|
|
19675
|
+
if (!Array.isArray(required)) return [];
|
|
19676
|
+
return required.filter((field) => typeof field === "string");
|
|
19677
|
+
}
|
|
19678
|
+
function readProperties(parameters) {
|
|
19679
|
+
const properties = parameters.properties;
|
|
19680
|
+
if (!properties || typeof properties !== "object" || Array.isArray(properties)) {
|
|
19681
|
+
return {};
|
|
19682
|
+
}
|
|
19683
|
+
return properties;
|
|
19684
|
+
}
|
|
19685
|
+
function validateToolArguments(args2) {
|
|
19686
|
+
const { toolName, rawArguments, parameters } = args2;
|
|
19687
|
+
if (!parameters || typeof parameters !== "object" || Array.isArray(parameters)) {
|
|
19688
|
+
return { ok: true, args: {} };
|
|
19689
|
+
}
|
|
19690
|
+
const schema = parameters;
|
|
19691
|
+
const requiredFields = readRequiredFields(schema);
|
|
19692
|
+
const properties = readProperties(schema);
|
|
19693
|
+
if (requiredFields.length === 0 && Object.keys(properties).length === 0) {
|
|
19694
|
+
return { ok: true, args: {} };
|
|
19695
|
+
}
|
|
19696
|
+
const raw = typeof rawArguments === "string" ? rawArguments.trim() : "";
|
|
19697
|
+
let record = {};
|
|
19698
|
+
if (raw !== "") {
|
|
19699
|
+
let parsed;
|
|
19700
|
+
try {
|
|
19701
|
+
parsed = JSON.parse(raw);
|
|
19702
|
+
} catch {
|
|
19703
|
+
return { ok: true, args: {} };
|
|
19704
|
+
}
|
|
19705
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
19706
|
+
return { ok: true, args: {} };
|
|
19707
|
+
}
|
|
19708
|
+
record = parsed;
|
|
19709
|
+
}
|
|
19710
|
+
for (const field of requiredFields) {
|
|
19711
|
+
if (record[field] !== void 0) continue;
|
|
19712
|
+
if (isAliasSatisfied(record, field)) continue;
|
|
19713
|
+
return {
|
|
19714
|
+
ok: false,
|
|
19715
|
+
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`
|
|
19716
|
+
};
|
|
19717
|
+
}
|
|
19718
|
+
for (const [field, spec] of Object.entries(properties)) {
|
|
19719
|
+
const value = record[field];
|
|
19720
|
+
if (value === void 0 || value === null) continue;
|
|
19721
|
+
if (!spec || typeof spec !== "object" || Array.isArray(spec)) continue;
|
|
19722
|
+
const declared = spec.type;
|
|
19723
|
+
if (typeof declared !== "string") continue;
|
|
19724
|
+
const matcher = TYPE_MATCHERS[declared];
|
|
19725
|
+
if (!matcher) continue;
|
|
19726
|
+
if (!matcher(value)) {
|
|
19727
|
+
return {
|
|
19728
|
+
ok: false,
|
|
19729
|
+
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`
|
|
19730
|
+
};
|
|
19731
|
+
}
|
|
19732
|
+
}
|
|
19733
|
+
return { ok: true, args: record };
|
|
19734
|
+
}
|
|
19735
|
+
function buildToolParametersIndex(tools) {
|
|
19736
|
+
const index = /* @__PURE__ */ new Map();
|
|
19737
|
+
for (const tool of tools) {
|
|
19738
|
+
if (!tool || typeof tool !== "object") continue;
|
|
19739
|
+
const fn3 = tool.function;
|
|
19740
|
+
if (!fn3 || typeof fn3 !== "object") continue;
|
|
19741
|
+
const name = fn3.name;
|
|
19742
|
+
const parameters = fn3.parameters;
|
|
19743
|
+
if (typeof name === "string" && name && parameters !== void 0) {
|
|
19744
|
+
index.set(name, parameters);
|
|
19745
|
+
}
|
|
19746
|
+
}
|
|
19747
|
+
return index;
|
|
19748
|
+
}
|
|
19749
|
+
var cachedAgentRuntimeIndex = null;
|
|
19750
|
+
function getAgentRuntimeToolParametersIndex() {
|
|
19751
|
+
if (cachedAgentRuntimeIndex) return cachedAgentRuntimeIndex;
|
|
19752
|
+
const index = /* @__PURE__ */ new Map();
|
|
19753
|
+
try {
|
|
19754
|
+
const workspaceTools = buildLocalWorkspaceOpenAiTools({
|
|
19755
|
+
toolNames: [...WORKSPACE_TOOL_NAMES],
|
|
19756
|
+
exposeShellTools: true
|
|
19757
|
+
});
|
|
19758
|
+
for (const [name, parameters] of buildToolParametersIndex(workspaceTools)) {
|
|
19759
|
+
index.set(name, parameters);
|
|
19760
|
+
}
|
|
19761
|
+
const noloTools = buildNoloWorkspaceOpenAiTools({
|
|
19762
|
+
toolNames: [...NOLO_WORKSPACE_TOOL_NAMES]
|
|
19763
|
+
});
|
|
19764
|
+
for (const [name, parameters] of buildToolParametersIndex(noloTools)) {
|
|
19765
|
+
index.set(name, parameters);
|
|
19766
|
+
}
|
|
19767
|
+
} catch {
|
|
19768
|
+
}
|
|
19769
|
+
cachedAgentRuntimeIndex = index;
|
|
19770
|
+
return index;
|
|
19771
|
+
}
|
|
19772
|
+
|
|
19773
|
+
// packages/agent-runtime/localToolPolicy.ts
|
|
19774
|
+
var NEVER_LOCAL_TOOLS = /* @__PURE__ */ new Set([
|
|
19775
|
+
"deleteSpaces",
|
|
19776
|
+
"updateAgent",
|
|
19777
|
+
"updateSelf",
|
|
19778
|
+
"createAgent"
|
|
19779
|
+
]);
|
|
19780
|
+
var DEFAULT_LOCAL_TOOLS = /* @__PURE__ */ new Set([
|
|
19781
|
+
"readFile",
|
|
19782
|
+
"writeFile",
|
|
19783
|
+
"editFile",
|
|
19784
|
+
"globFiles",
|
|
19785
|
+
"execShell",
|
|
19786
|
+
"launchProcess",
|
|
19787
|
+
"listProcesses",
|
|
19788
|
+
// ProcessTask follow-up tools. Same tier as listProcesses: they observe/stop
|
|
19789
|
+
// tasks the agent itself already spawned, so their blast radius is strictly
|
|
19790
|
+
// narrower than launchProcess (which is default-enabled). Model-facing
|
|
19791
|
+
// follow-ups are taskWait/taskStop only — lifecycle history (taskLogs) stays
|
|
19792
|
+
// runtime-internal.
|
|
19793
|
+
"taskWait",
|
|
19794
|
+
"taskStop",
|
|
19795
|
+
// Scheduling tools: forking/observing sub-agents is a declared capability
|
|
19796
|
+
// of capable agents, and the blast radius is strictly narrower than
|
|
19797
|
+
// execShell (already default-enabled). Requiring an env allowlist for these
|
|
19798
|
+
// while execShell is open by default inverted the risk model and forced every
|
|
19799
|
+
// new local user to hand-edit .env files before sub-agent tasks worked.
|
|
19800
|
+
"startAgentRun",
|
|
19801
|
+
"controlAgentRun"
|
|
19802
|
+
]);
|
|
19803
|
+
function parseToolAllowlist(value) {
|
|
19804
|
+
return (value ?? "").split(",").flatMap((item) => {
|
|
19805
|
+
const trimmed = item.trim();
|
|
19806
|
+
return trimmed ? [trimmed] : [];
|
|
19807
|
+
});
|
|
19808
|
+
}
|
|
19809
|
+
function normalizeLocalToolName(toolName) {
|
|
19810
|
+
return canonicalizeToolName(
|
|
19811
|
+
String(toolName ?? "").replace(/^functions\./, "").trim()
|
|
19812
|
+
);
|
|
19813
|
+
}
|
|
19814
|
+
function isRestrictedLocalToolMode(env) {
|
|
19815
|
+
return env.NOLO_LOCAL_TOOL_MODE === "restricted";
|
|
19816
|
+
}
|
|
19817
|
+
function resolveLocalToolPolicy(args2) {
|
|
19818
|
+
const toolName = normalizeLocalToolName(args2.toolName);
|
|
19819
|
+
const restrictedMode = isRestrictedLocalToolMode(args2.env);
|
|
19820
|
+
if (!toolName) {
|
|
19821
|
+
return {
|
|
19822
|
+
allowed: false,
|
|
19823
|
+
toolName,
|
|
19824
|
+
reason: "Tool name is required."
|
|
19825
|
+
};
|
|
19826
|
+
}
|
|
19827
|
+
if (NEVER_LOCAL_TOOLS.has(toolName)) {
|
|
19828
|
+
return {
|
|
19829
|
+
allowed: false,
|
|
19830
|
+
toolName,
|
|
19831
|
+
reason: `${toolName} is blocked by the local runtime safety policy.`
|
|
19832
|
+
};
|
|
19833
|
+
}
|
|
19834
|
+
const allowedByEnv = new Set(parseToolAllowlist(args2.env.NOLO_LOCAL_ALLOWED_TOOLS));
|
|
19835
|
+
const agentTools = new Set(
|
|
19836
|
+
(args2.agentToolNames ?? []).flatMap((item) => {
|
|
19837
|
+
const normalized = normalizeLocalToolName(item);
|
|
19838
|
+
return normalized ? [normalized] : [];
|
|
19839
|
+
})
|
|
19840
|
+
);
|
|
19841
|
+
if (!restrictedMode && agentTools.has(toolName)) {
|
|
19842
|
+
return { allowed: true, toolName };
|
|
19843
|
+
}
|
|
19844
|
+
if (DEFAULT_LOCAL_TOOLS.has(toolName) && agentTools.has(toolName)) {
|
|
19845
|
+
return { allowed: true, toolName };
|
|
19846
|
+
}
|
|
19847
|
+
if (allowedByEnv.has(toolName) && agentTools.has(toolName)) {
|
|
19848
|
+
return { allowed: true, toolName };
|
|
19849
|
+
}
|
|
19850
|
+
return {
|
|
19851
|
+
allowed: false,
|
|
19852
|
+
toolName,
|
|
19853
|
+
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.`
|
|
19854
|
+
};
|
|
19855
|
+
}
|
|
19856
|
+
async function executeLocalToolWithPolicy(args2) {
|
|
19857
|
+
if (args2.runToolNames !== void 0 && !args2.runToolNames.includes(normalizeLocalToolName(args2.call.name))) {
|
|
19858
|
+
throw new Error(`${args2.call.name} is outside the final run tool surface.`);
|
|
19859
|
+
}
|
|
19860
|
+
const decision = resolveLocalToolPolicy({
|
|
19861
|
+
env: args2.env,
|
|
19862
|
+
agentToolNames: args2.agentToolNames,
|
|
19863
|
+
toolName: args2.call.name
|
|
19864
|
+
});
|
|
19865
|
+
if (!decision.allowed) throw new Error(decision.reason);
|
|
19866
|
+
const executor = args2.executors?.[decision.toolName];
|
|
19867
|
+
if (!executor) {
|
|
19868
|
+
throw new Error(`${decision.toolName} is allowed by policy but no local executor is registered.`);
|
|
19869
|
+
}
|
|
19870
|
+
const parametersSchema = args2.toolParametersIndex?.get(decision.toolName);
|
|
19871
|
+
if (parametersSchema !== void 0) {
|
|
19872
|
+
const gate = validateToolArguments({
|
|
19873
|
+
toolName: decision.toolName,
|
|
19874
|
+
rawArguments: args2.call.arguments,
|
|
19875
|
+
parameters: parametersSchema
|
|
19876
|
+
});
|
|
19877
|
+
if (!gate.ok) throw new Error(gate.message);
|
|
19878
|
+
}
|
|
19879
|
+
const opts = {
|
|
19880
|
+
...args2.abortSignal ? { abortSignal: args2.abortSignal } : {},
|
|
19881
|
+
...args2.detachMs !== void 0 ? { detachMs: args2.detachMs } : {},
|
|
19882
|
+
...args2.confirmed !== void 0 ? { confirmed: args2.confirmed } : {},
|
|
19883
|
+
...args2.enableDestructiveShellGuard !== void 0 ? { enableDestructiveShellGuard: args2.enableDestructiveShellGuard } : {},
|
|
19884
|
+
...args2.confirmDestructiveAction ? { confirmDestructiveAction: args2.confirmDestructiveAction } : {},
|
|
19885
|
+
...args2.blockDestructiveWithoutConfirmation !== void 0 ? { blockDestructiveWithoutConfirmation: args2.blockDestructiveWithoutConfirmation } : {}
|
|
19886
|
+
};
|
|
19887
|
+
if (decision.toolName === "execShell") {
|
|
19888
|
+
let parsedInput = args2.call.arguments;
|
|
19889
|
+
if (typeof parsedInput === "string") {
|
|
19890
|
+
try {
|
|
19891
|
+
parsedInput = JSON.parse(parsedInput);
|
|
19892
|
+
} catch {
|
|
19893
|
+
parsedInput = { command: parsedInput };
|
|
19894
|
+
}
|
|
19895
|
+
}
|
|
19896
|
+
await evaluateExecShellDestructiveGuard(parsedInput, opts);
|
|
19897
|
+
opts.confirmed = true;
|
|
19898
|
+
}
|
|
19899
|
+
return executor(
|
|
19900
|
+
{
|
|
19901
|
+
...args2.call,
|
|
19902
|
+
name: decision.toolName
|
|
19903
|
+
},
|
|
19904
|
+
opts
|
|
19905
|
+
);
|
|
19906
|
+
}
|
|
19907
|
+
|
|
19237
19908
|
// packages/cli/client/localDialogRecords.ts
|
|
19238
19909
|
var localDialogMessageRecordToRuntimeMessage = dialogMessageRecordToAgentRuntimeMessage;
|
|
19239
19910
|
function buildLocalDialogWritePlan(args2) {
|
|
@@ -19373,7 +20044,7 @@ function buildLoadSkillExecutor(args2) {
|
|
|
19373
20044
|
const { resolveSkillByName } = await import("./skillDiscovery-CYUCJMAG.js");
|
|
19374
20045
|
const resolved = resolveSkillByName(args2.cwd, name);
|
|
19375
20046
|
if (!resolved) {
|
|
19376
|
-
const { resolveBuiltinSkillByName } = await import("./builtinSkillRegistry-
|
|
20047
|
+
const { resolveBuiltinSkillByName } = await import("./builtinSkillRegistry-JPY2DKRF.js");
|
|
19377
20048
|
const builtin = resolveBuiltinSkillByName(name);
|
|
19378
20049
|
if (builtin) {
|
|
19379
20050
|
return {
|
|
@@ -19431,739 +20102,10 @@ No skills were discovered in this workspace.`;
|
|
|
19431
20102
|
Available skills: ${available.join(", ")}`;
|
|
19432
20103
|
}
|
|
19433
20104
|
|
|
19434
|
-
// packages/core/chat/upstreamErrorBody.ts
|
|
19435
|
-
function parseUpstreamErrorBody(errorText, statusText) {
|
|
19436
|
-
if (errorText) {
|
|
19437
|
-
try {
|
|
19438
|
-
const parsed = JSON.parse(errorText);
|
|
19439
|
-
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
19440
|
-
const error = parsed.error;
|
|
19441
|
-
if (error && typeof error === "object" && !Array.isArray(error)) {
|
|
19442
|
-
return parsed;
|
|
19443
|
-
}
|
|
19444
|
-
}
|
|
19445
|
-
} catch {
|
|
19446
|
-
}
|
|
19447
|
-
}
|
|
19448
|
-
return { error: { message: errorText || statusText } };
|
|
19449
|
-
}
|
|
19450
|
-
|
|
19451
|
-
// packages/agent-runtime/antigravityCloudCodeProvider.ts
|
|
19452
|
-
import { randomUUID } from "node:crypto";
|
|
19453
|
-
|
|
19454
|
-
// packages/agent-runtime/antigravityWireModel.ts
|
|
19455
|
-
var WIRE_PROFILES = {
|
|
19456
|
-
// Antigravity discovery exposes 3.7 Flash as one tiered wire model.
|
|
19457
|
-
// The UI labels its effort variants (Low/Medium/High), but the literal
|
|
19458
|
-
// -medium/-high ids return 404 from streamGenerateContent.
|
|
19459
|
-
"gemini-3.7-flash-tiered": { modelEnum: "MODEL_PLACEHOLDER_M301", maxOutputTokens: 65536 },
|
|
19460
|
-
// Gemini 3.8 Flash 沿用 3.7 的 tiered 兼容策略:仓库内暂无 Antigravity discovery
|
|
19461
|
-
// 证据确认 3.8 的 wire modelEnum,禁止虚构,先只声明同档输出上限;enum 待
|
|
19462
|
-
// discovery 证据到位后补齐。
|
|
19463
|
-
"gemini-3.8-flash-tiered": { maxOutputTokens: 65536 },
|
|
19464
|
-
"gemini-3.6-flash-low": { maxOutputTokens: 65536 },
|
|
19465
|
-
"gemini-3.6-flash-medium": { maxOutputTokens: 65536 },
|
|
19466
|
-
"gemini-3.6-flash-high": { maxOutputTokens: 65536 },
|
|
19467
|
-
// 旧模型 wire 映射保留:存量自定义 agent 仍可能引用(注册表已下线不影响此处)。
|
|
19468
|
-
"gemini-3.5-flash-extra-low": { modelEnum: "MODEL_PLACEHOLDER_M187", maxOutputTokens: 65536 },
|
|
19469
|
-
"gemini-3.5-flash-low": { modelEnum: "MODEL_PLACEHOLDER_M20", maxOutputTokens: 65536 },
|
|
19470
|
-
"gemini-3-flash-agent": { modelEnum: "MODEL_PLACEHOLDER_M132", maxOutputTokens: 65536 },
|
|
19471
|
-
"gemini-3.1-pro-low": { modelEnum: "MODEL_PLACEHOLDER_M36", maxOutputTokens: 65535 },
|
|
19472
|
-
"gemini-pro-agent": { modelEnum: "MODEL_PLACEHOLDER_M16", maxOutputTokens: 65535 },
|
|
19473
|
-
"claude-sonnet-5": { maxOutputTokens: 64e3 },
|
|
19474
|
-
"claude-sonnet-4-6": { maxOutputTokens: 64e3 },
|
|
19475
|
-
"claude-opus-4-6-thinking": { maxOutputTokens: 64e3 },
|
|
19476
|
-
"gemini-2.5-flash": { maxOutputTokens: 65536 },
|
|
19477
|
-
"gemini-2.5-pro": { maxOutputTokens: 65536 }
|
|
19478
|
-
};
|
|
19479
|
-
function resolveAntigravityWireModel(logicalModelId) {
|
|
19480
|
-
const id = logicalModelId.trim();
|
|
19481
|
-
const lower = id.toLowerCase();
|
|
19482
|
-
if (lower === "gemini-3.5-flash") {
|
|
19483
|
-
const wireModelId = "gemini-3.5-flash-low";
|
|
19484
|
-
return { wireModelId, profile: WIRE_PROFILES[wireModelId] };
|
|
19485
|
-
}
|
|
19486
|
-
if (lower === "gemini-3.7-flash" || ["gemini-3.7-flash-low", "gemini-3.7-flash-medium", "gemini-3.7-flash-high"].includes(lower)) {
|
|
19487
|
-
const wireModelId = "gemini-3.7-flash-tiered";
|
|
19488
|
-
return { wireModelId, profile: WIRE_PROFILES[wireModelId] };
|
|
19489
|
-
}
|
|
19490
|
-
if (lower === "gemini-3.8-flash" || ["gemini-3.8-flash-low", "gemini-3.8-flash-medium", "gemini-3.8-flash-high"].includes(lower)) {
|
|
19491
|
-
const wireModelId = "gemini-3.8-flash-tiered";
|
|
19492
|
-
return { wireModelId, profile: WIRE_PROFILES[wireModelId] };
|
|
19493
|
-
}
|
|
19494
|
-
if (lower === "gemini-3.6-flash") {
|
|
19495
|
-
const wireModelId = "gemini-3.6-flash-low";
|
|
19496
|
-
return { wireModelId, profile: WIRE_PROFILES[wireModelId] };
|
|
19497
|
-
}
|
|
19498
|
-
if (lower === "gemini-3.1-pro" || lower === "gemini-3.1-pro-preview") {
|
|
19499
|
-
const wireModelId = "gemini-3.1-pro-low";
|
|
19500
|
-
return { wireModelId, profile: WIRE_PROFILES[wireModelId] };
|
|
19501
|
-
}
|
|
19502
|
-
if (WIRE_PROFILES[id]) {
|
|
19503
|
-
return { wireModelId: id, profile: WIRE_PROFILES[id] };
|
|
19504
|
-
}
|
|
19505
|
-
return { wireModelId: id };
|
|
19506
|
-
}
|
|
19507
|
-
|
|
19508
|
-
// packages/agent-runtime/geminiNativeShared.ts
|
|
19509
|
-
var SKIP_THOUGHT_SIGNATURE = "skip_thought_signature_validator";
|
|
19510
|
-
function resolveGeminiModelQuirks(modelId) {
|
|
19511
|
-
const lower = modelId.toLowerCase();
|
|
19512
|
-
const isGemini3 = lower.includes("gemini-3");
|
|
19513
|
-
const isStrictSignatureModel = lower.includes("gemini-3.5") || lower.includes("flash-preview");
|
|
19514
|
-
const isClaude = lower.includes("claude");
|
|
19515
|
-
return {
|
|
19516
|
-
requiresThoughtSignature: isGemini3,
|
|
19517
|
-
allowsThoughtSignatureSentinel: isGemini3 && !isStrictSignatureModel,
|
|
19518
|
-
isClaudeCrossModel: isClaude
|
|
19519
|
-
};
|
|
19520
|
-
}
|
|
19521
|
-
function isGemini3Model(modelId) {
|
|
19522
|
-
return resolveGeminiModelQuirks(modelId).requiresThoughtSignature;
|
|
19523
|
-
}
|
|
19524
|
-
function messageText(content) {
|
|
19525
|
-
if (typeof content === "string") return content;
|
|
19526
|
-
if (!Array.isArray(content)) return "";
|
|
19527
|
-
return content.filter(
|
|
19528
|
-
(part) => part?.type === "text"
|
|
19529
|
-
).map((part) => part.text).join("\n").trim();
|
|
19530
|
-
}
|
|
19531
|
-
function parseDataUrlToInlineData(url) {
|
|
19532
|
-
const match7 = /^data:([A-Za-z0-9.+-]+\/[A-Za-z0-9.+-]+);base64,([A-Za-z0-9+/=]*)$/.exec(
|
|
19533
|
-
url
|
|
19534
|
-
);
|
|
19535
|
-
if (!match7) return null;
|
|
19536
|
-
return { mimeType: match7[1], data: match7[2] };
|
|
19537
|
-
}
|
|
19538
|
-
function extractInlineDataParts(content) {
|
|
19539
|
-
if (!Array.isArray(content)) return [];
|
|
19540
|
-
const parts2 = [];
|
|
19541
|
-
for (const part of content) {
|
|
19542
|
-
if (!part || typeof part !== "object") continue;
|
|
19543
|
-
if (part.type !== "image_url") continue;
|
|
19544
|
-
const url = part.image_url?.url;
|
|
19545
|
-
if (typeof url !== "string" || !url.trim()) continue;
|
|
19546
|
-
const inline = parseDataUrlToInlineData(url);
|
|
19547
|
-
if (inline) parts2.push({ inlineData: inline });
|
|
19548
|
-
}
|
|
19549
|
-
return parts2;
|
|
19550
|
-
}
|
|
19551
|
-
function convertOpenAiMessagesToGemini(messages, options) {
|
|
19552
|
-
const contents = [];
|
|
19553
|
-
const systemTexts = [];
|
|
19554
|
-
let toolCallIndex = 0;
|
|
19555
|
-
let pendingFunctionCalls = [];
|
|
19556
|
-
const pushOrMergeContent = (role, parts2) => {
|
|
19557
|
-
if (parts2.length === 0) return;
|
|
19558
|
-
const last = contents[contents.length - 1];
|
|
19559
|
-
if (last && last.role === role) {
|
|
19560
|
-
last.parts.push(...parts2);
|
|
19561
|
-
} else {
|
|
19562
|
-
contents.push({ role, parts: parts2 });
|
|
19563
|
-
}
|
|
19564
|
-
};
|
|
19565
|
-
const flushPendingFunctionCalls = () => {
|
|
19566
|
-
if (pendingFunctionCalls.length === 0) return;
|
|
19567
|
-
const dummyResponses = pendingFunctionCalls.map(
|
|
19568
|
-
({ name, id }) => ({
|
|
19569
|
-
functionResponse: {
|
|
19570
|
-
name,
|
|
19571
|
-
response: { output: "{}" },
|
|
19572
|
-
...id ? { id } : {}
|
|
19573
|
-
}
|
|
19574
|
-
})
|
|
19575
|
-
);
|
|
19576
|
-
pendingFunctionCalls = [];
|
|
19577
|
-
pushOrMergeContent("user", dummyResponses);
|
|
19578
|
-
};
|
|
19579
|
-
for (const raw of messages) {
|
|
19580
|
-
if (!raw || typeof raw !== "object" || !("role" in raw)) continue;
|
|
19581
|
-
const role = String(raw.role);
|
|
19582
|
-
const content = "content" in raw ? raw.content : null;
|
|
19583
|
-
if (role === "system") {
|
|
19584
|
-
const text = messageText(
|
|
19585
|
-
content
|
|
19586
|
-
);
|
|
19587
|
-
if (text) systemTexts.push(text);
|
|
19588
|
-
continue;
|
|
19589
|
-
}
|
|
19590
|
-
if (role === "user") {
|
|
19591
|
-
flushPendingFunctionCalls();
|
|
19592
|
-
const text = messageText(
|
|
19593
|
-
content
|
|
19594
|
-
);
|
|
19595
|
-
const imageParts = extractInlineDataParts(
|
|
19596
|
-
content
|
|
19597
|
-
);
|
|
19598
|
-
if (!text && imageParts.length === 0) continue;
|
|
19599
|
-
const parts2 = [];
|
|
19600
|
-
if (text) parts2.push({ text });
|
|
19601
|
-
for (const img of imageParts) parts2.push(img);
|
|
19602
|
-
pushOrMergeContent("user", parts2);
|
|
19603
|
-
continue;
|
|
19604
|
-
}
|
|
19605
|
-
if (role === "assistant") {
|
|
19606
|
-
flushPendingFunctionCalls();
|
|
19607
|
-
const text = messageText(
|
|
19608
|
-
content
|
|
19609
|
-
);
|
|
19610
|
-
const toolCalls = "tool_calls" in raw && Array.isArray(raw.tool_calls) ? raw.tool_calls ?? [] : [];
|
|
19611
|
-
const parts2 = [];
|
|
19612
|
-
if (text) {
|
|
19613
|
-
parts2.push({ text });
|
|
19614
|
-
}
|
|
19615
|
-
for (const call of toolCalls) {
|
|
19616
|
-
const name = call?.function?.name?.trim();
|
|
19617
|
-
if (!name) continue;
|
|
19618
|
-
const id = call.id?.trim() || `${name}_${toolCallIndex++}`;
|
|
19619
|
-
pendingFunctionCalls.push({ name, id });
|
|
19620
|
-
const realSignature = typeof call.thought_signature === "string" && call.thought_signature ? call.thought_signature : void 0;
|
|
19621
|
-
const isFirstFunctionCallPart = !parts2.some(
|
|
19622
|
-
(p) => "functionCall" in p
|
|
19623
|
-
);
|
|
19624
|
-
const signature = realSignature ?? (options.attachSkipThoughtSignature && isFirstFunctionCallPart ? SKIP_THOUGHT_SIGNATURE : void 0);
|
|
19625
|
-
const part = {
|
|
19626
|
-
functionCall: {
|
|
19627
|
-
name,
|
|
19628
|
-
args: parseToolArgs(call.function?.arguments),
|
|
19629
|
-
...id ? { id } : {}
|
|
19630
|
-
},
|
|
19631
|
-
...signature ? { thoughtSignature: signature } : {}
|
|
19632
|
-
};
|
|
19633
|
-
parts2.push(part);
|
|
19634
|
-
}
|
|
19635
|
-
pushOrMergeContent("model", parts2);
|
|
19636
|
-
continue;
|
|
19637
|
-
}
|
|
19638
|
-
if (role === "tool") {
|
|
19639
|
-
const toolCallId = "tool_call_id" in raw && typeof raw.tool_call_id === "string" ? raw.tool_call_id : "";
|
|
19640
|
-
const rawName = "name" in raw && typeof raw.name === "string" ? raw.name.trim() : "";
|
|
19641
|
-
const pendingIndex = pendingFunctionCalls.findIndex(
|
|
19642
|
-
(p) => toolCallId ? p.id === toolCallId : rawName ? p.name === rawName : true
|
|
19643
|
-
);
|
|
19644
|
-
if (pendingIndex === -1) continue;
|
|
19645
|
-
const [{ name, id }] = pendingFunctionCalls.splice(pendingIndex, 1);
|
|
19646
|
-
const output = messageText(content) || "{}";
|
|
19647
|
-
pushOrMergeContent("user", [
|
|
19648
|
-
{
|
|
19649
|
-
functionResponse: {
|
|
19650
|
-
name,
|
|
19651
|
-
response: { output },
|
|
19652
|
-
// 保留 OpenAI tool_call_id:antigravity Cloud Code Assist 网关把
|
|
19653
|
-
// Gemini contents 转成 Claude messages 时需要 functionResponse →
|
|
19654
|
-
// tool_result 的 tool_use_id;缺 id 时网关报
|
|
19655
|
-
// "tool_result.tool_use_id: Field required"(HTTP 400)。
|
|
19656
|
-
...id ? { id } : {}
|
|
19657
|
-
}
|
|
19658
|
-
}
|
|
19659
|
-
]);
|
|
19660
|
-
}
|
|
19661
|
-
}
|
|
19662
|
-
flushPendingFunctionCalls();
|
|
19663
|
-
if (contents.length > 0 && contents[0]?.role === "model") {
|
|
19664
|
-
contents.unshift({
|
|
19665
|
-
role: "user",
|
|
19666
|
-
parts: [{ text: "Continue the conversation." }]
|
|
19667
|
-
});
|
|
19668
|
-
}
|
|
19669
|
-
return { contents, systemTexts };
|
|
19670
|
-
}
|
|
19671
|
-
function parseToolArgs(raw) {
|
|
19672
|
-
if (typeof raw === "string") {
|
|
19673
|
-
try {
|
|
19674
|
-
const parsed = JSON.parse(raw);
|
|
19675
|
-
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
19676
|
-
return parsed;
|
|
19677
|
-
}
|
|
19678
|
-
} catch {
|
|
19679
|
-
}
|
|
19680
|
-
}
|
|
19681
|
-
if (raw && typeof raw === "object" && !Array.isArray(raw)) {
|
|
19682
|
-
return raw;
|
|
19683
|
-
}
|
|
19684
|
-
return {};
|
|
19685
|
-
}
|
|
19686
|
-
function sanitizeGeminiSchemaNode(node, active) {
|
|
19687
|
-
const out = {};
|
|
19688
|
-
if (!node || typeof node !== "object" || Array.isArray(node)) {
|
|
19689
|
-
return { type: "string" };
|
|
19690
|
-
}
|
|
19691
|
-
if (active?.has(node)) {
|
|
19692
|
-
return { type: "object", description: "(circular schema reference)" };
|
|
19693
|
-
}
|
|
19694
|
-
const seen = active ?? /* @__PURE__ */ new WeakSet();
|
|
19695
|
-
seen.add(node);
|
|
19696
|
-
try {
|
|
19697
|
-
return sanitizeGeminiSchemaNodeInner(node, out, seen);
|
|
19698
|
-
} finally {
|
|
19699
|
-
seen.delete(node);
|
|
19700
|
-
}
|
|
19701
|
-
}
|
|
19702
|
-
function sanitizeGeminiSchemaNodeInner(src, out, seen) {
|
|
19703
|
-
if (Array.isArray(src.type)) {
|
|
19704
|
-
const firstNonNull = src.type.find((t) => t !== "null");
|
|
19705
|
-
if (typeof firstNonNull === "string") out.type = firstNonNull;
|
|
19706
|
-
out.nullable = true;
|
|
19707
|
-
} else if (typeof src.type === "string") {
|
|
19708
|
-
out.type = src.type;
|
|
19709
|
-
}
|
|
19710
|
-
if (typeof src.description === "string") out.description = src.description;
|
|
19711
|
-
if (typeof src.minimum === "number") out.minimum = src.minimum;
|
|
19712
|
-
if (typeof src.maximum === "number") out.maximum = src.maximum;
|
|
19713
|
-
if (Array.isArray(src.enum) && src.enum.length > 0) out.enum = src.enum;
|
|
19714
|
-
if (src.nullable === true) out.nullable = true;
|
|
19715
|
-
if ("const" in src && src.const !== void 0 && !out.enum) {
|
|
19716
|
-
out.enum = [src.const];
|
|
19717
|
-
}
|
|
19718
|
-
const variantBranches = [
|
|
19719
|
-
...Array.isArray(src.oneOf) ? src.oneOf : [],
|
|
19720
|
-
...Array.isArray(src.anyOf) ? src.anyOf : []
|
|
19721
|
-
];
|
|
19722
|
-
if (variantBranches.length > 0) {
|
|
19723
|
-
const mergedProperties = {};
|
|
19724
|
-
let requiredIntersection;
|
|
19725
|
-
for (const branch of variantBranches) {
|
|
19726
|
-
const sanitized = sanitizeGeminiSchemaNode(branch, seen);
|
|
19727
|
-
const branchProperties = sanitized.properties ?? {};
|
|
19728
|
-
for (const [key, value] of Object.entries(branchProperties)) {
|
|
19729
|
-
const previous = mergedProperties[key];
|
|
19730
|
-
const prevEnum = previous?.enum;
|
|
19731
|
-
const nextEnum = value?.enum;
|
|
19732
|
-
if (prevEnum && nextEnum) {
|
|
19733
|
-
mergedProperties[key] = {
|
|
19734
|
-
...value,
|
|
19735
|
-
enum: [.../* @__PURE__ */ new Set([...prevEnum, ...nextEnum])]
|
|
19736
|
-
};
|
|
19737
|
-
} else {
|
|
19738
|
-
mergedProperties[key] = value;
|
|
19739
|
-
}
|
|
19740
|
-
}
|
|
19741
|
-
const branchRequired = Array.isArray(sanitized.required) ? sanitized.required : [];
|
|
19742
|
-
requiredIntersection = requiredIntersection === void 0 ? [...branchRequired] : requiredIntersection.filter((r) => branchRequired.includes(r));
|
|
19743
|
-
}
|
|
19744
|
-
out.properties = {
|
|
19745
|
-
...out.properties ?? {},
|
|
19746
|
-
...mergedProperties
|
|
19747
|
-
};
|
|
19748
|
-
if (requiredIntersection !== void 0 && requiredIntersection.length > 0) {
|
|
19749
|
-
out.required = requiredIntersection;
|
|
19750
|
-
}
|
|
19751
|
-
if (typeof out.type !== "string") out.type = "object";
|
|
19752
|
-
}
|
|
19753
|
-
if (Array.isArray(src.allOf)) {
|
|
19754
|
-
for (const branch of src.allOf) {
|
|
19755
|
-
const sanitized = sanitizeGeminiSchemaNode(branch, seen);
|
|
19756
|
-
out.properties = {
|
|
19757
|
-
...out.properties ?? {},
|
|
19758
|
-
...sanitized.properties ?? {}
|
|
19759
|
-
};
|
|
19760
|
-
if (Array.isArray(sanitized.required)) {
|
|
19761
|
-
out.required = [
|
|
19762
|
-
.../* @__PURE__ */ new Set([
|
|
19763
|
-
...out.required ?? [],
|
|
19764
|
-
...sanitized.required ?? []
|
|
19765
|
-
])
|
|
19766
|
-
];
|
|
19767
|
-
}
|
|
19768
|
-
}
|
|
19769
|
-
if (typeof out.type !== "string") out.type = "object";
|
|
19770
|
-
}
|
|
19771
|
-
if (src.properties && typeof src.properties === "object") {
|
|
19772
|
-
const properties = {};
|
|
19773
|
-
for (const [key, value] of Object.entries(
|
|
19774
|
-
src.properties
|
|
19775
|
-
)) {
|
|
19776
|
-
properties[key] = sanitizeGeminiSchemaNode(value, seen);
|
|
19777
|
-
}
|
|
19778
|
-
out.properties = properties;
|
|
19779
|
-
if (typeof out.type !== "string") out.type = "object";
|
|
19780
|
-
}
|
|
19781
|
-
if (Array.isArray(src.required)) {
|
|
19782
|
-
const properties = out.properties ?? {};
|
|
19783
|
-
const required = [...new Set(src.required)].filter(
|
|
19784
|
-
(r) => typeof r === "string" && r in properties
|
|
19785
|
-
);
|
|
19786
|
-
if (required.length > 0) out.required = required;
|
|
19787
|
-
}
|
|
19788
|
-
if (src.items !== void 0) {
|
|
19789
|
-
out.items = sanitizeGeminiSchemaNode(src.items, seen);
|
|
19790
|
-
if (typeof out.type !== "string") out.type = "array";
|
|
19791
|
-
}
|
|
19792
|
-
if (typeof out.type !== "string") out.type = "object";
|
|
19793
|
-
return out;
|
|
19794
|
-
}
|
|
19795
|
-
function convertOpenAiToolsToGemini(tools) {
|
|
19796
|
-
if (!Array.isArray(tools) || tools.length === 0) return void 0;
|
|
19797
|
-
const declarations = [];
|
|
19798
|
-
for (const tool of tools) {
|
|
19799
|
-
if (!tool || typeof tool !== "object" || !("function" in tool)) continue;
|
|
19800
|
-
const fn3 = tool.function;
|
|
19801
|
-
const name = typeof fn3.name === "string" ? fn3.name : "";
|
|
19802
|
-
if (!name) continue;
|
|
19803
|
-
declarations.push({
|
|
19804
|
-
name,
|
|
19805
|
-
description: typeof fn3.description === "string" ? fn3.description : "",
|
|
19806
|
-
parameters: sanitizeGeminiSchemaNode(
|
|
19807
|
-
fn3.parameters ?? { type: "object", properties: {} }
|
|
19808
|
-
)
|
|
19809
|
-
});
|
|
19810
|
-
}
|
|
19811
|
-
if (declarations.length === 0) return void 0;
|
|
19812
|
-
return [{ functionDeclarations: declarations }];
|
|
19813
|
-
}
|
|
19814
|
-
function createGeminiAccumulatorState() {
|
|
19815
|
-
return {
|
|
19816
|
-
text: "",
|
|
19817
|
-
toolCalls: [],
|
|
19818
|
-
reasoning: "",
|
|
19819
|
-
events: []
|
|
19820
|
-
};
|
|
19821
|
-
}
|
|
19822
|
-
function applyGeminiChunk(chunk, state, options) {
|
|
19823
|
-
if (!chunk || typeof chunk !== "object") return;
|
|
19824
|
-
const response = "response" in chunk && chunk.response && typeof chunk.response === "object" ? chunk.response : chunk;
|
|
19825
|
-
if ("usageMetadata" in response && response.usageMetadata && typeof response.usageMetadata === "object") {
|
|
19826
|
-
const meta = response.usageMetadata;
|
|
19827
|
-
const prompt = typeof meta.promptTokenCount === "number" ? meta.promptTokenCount : 0;
|
|
19828
|
-
const candidates2 = typeof meta.candidatesTokenCount === "number" ? meta.candidatesTokenCount : 0;
|
|
19829
|
-
const total = typeof meta.totalTokenCount === "number" ? meta.totalTokenCount : prompt + candidates2;
|
|
19830
|
-
const cached3 = typeof meta.cachedContentTokenCount === "number" && Number.isFinite(meta.cachedContentTokenCount) ? (
|
|
19831
|
-
// cached ⊆ prompt;对畸形上游防御性钳位,避免 cache_read > input 破坏归一化与计费
|
|
19832
|
-
Math.min(Math.max(0, Math.floor(meta.cachedContentTokenCount)), prompt)
|
|
19833
|
-
) : 0;
|
|
19834
|
-
state.usage = {
|
|
19835
|
-
prompt_tokens: prompt,
|
|
19836
|
-
completion_tokens: candidates2,
|
|
19837
|
-
total_tokens: total,
|
|
19838
|
-
...cached3 > 0 ? { cache_read_input_tokens: cached3 } : {}
|
|
19839
|
-
};
|
|
19840
|
-
state.events.push({ kind: "usage", usage: state.usage });
|
|
19841
|
-
}
|
|
19842
|
-
const candidates = Array.isArray(response.candidates) ? response.candidates : [];
|
|
19843
|
-
for (const candidate of candidates) {
|
|
19844
|
-
if (!candidate || typeof candidate !== "object") continue;
|
|
19845
|
-
const candidateFinishReason = candidate.finishReason;
|
|
19846
|
-
if (typeof candidateFinishReason === "string" && candidateFinishReason.trim()) {
|
|
19847
|
-
state.finishReason = candidateFinishReason.trim();
|
|
19848
|
-
state.events.push({ kind: "finish", reason: state.finishReason });
|
|
19849
|
-
}
|
|
19850
|
-
const parts2 = Array.isArray(
|
|
19851
|
-
candidate.content?.parts
|
|
19852
|
-
) ? candidate.content.parts : [];
|
|
19853
|
-
for (const part of parts2) {
|
|
19854
|
-
if (!part || typeof part !== "object") continue;
|
|
19855
|
-
const partSignature = part.thoughtSignature;
|
|
19856
|
-
const isThought = Boolean(part.thought);
|
|
19857
|
-
if ("text" in part && typeof part.text === "string") {
|
|
19858
|
-
const piece = part.text;
|
|
19859
|
-
if (!isThought) {
|
|
19860
|
-
state.text += piece;
|
|
19861
|
-
if (piece) {
|
|
19862
|
-
state.events.push({ kind: "text", text: piece });
|
|
19863
|
-
if (options?.onTextDelta) options.onTextDelta(piece);
|
|
19864
|
-
}
|
|
19865
|
-
} else {
|
|
19866
|
-
state.reasoning += piece;
|
|
19867
|
-
if (piece) {
|
|
19868
|
-
state.events.push({ kind: "reasoning", text: piece });
|
|
19869
|
-
if (options?.onReasoningDelta) options.onReasoningDelta(piece);
|
|
19870
|
-
}
|
|
19871
|
-
}
|
|
19872
|
-
}
|
|
19873
|
-
if (isThought && typeof partSignature === "string" && partSignature) {
|
|
19874
|
-
state.pendingThoughtSignature = partSignature;
|
|
19875
|
-
}
|
|
19876
|
-
if ("functionCall" in part && part.functionCall) {
|
|
19877
|
-
const call = part.functionCall;
|
|
19878
|
-
const name = typeof call.name === "string" ? call.name : "tool";
|
|
19879
|
-
const id = typeof call.id === "string" ? call.id : `${name}_${state.toolCalls.length}`;
|
|
19880
|
-
const argsObj = call.args && typeof call.args === "object" ? call.args : {};
|
|
19881
|
-
const resolvedSignature = typeof partSignature === "string" && partSignature ? partSignature : state.pendingThoughtSignature;
|
|
19882
|
-
state.pendingThoughtSignature = void 0;
|
|
19883
|
-
const toolCall = {
|
|
19884
|
-
id,
|
|
19885
|
-
type: "function",
|
|
19886
|
-
function: { name, arguments: JSON.stringify(argsObj) },
|
|
19887
|
-
...typeof resolvedSignature === "string" && resolvedSignature ? { thought_signature: resolvedSignature } : {}
|
|
19888
|
-
};
|
|
19889
|
-
state.toolCalls.push(toolCall);
|
|
19890
|
-
state.events.push({ kind: "tool_call", toolCall });
|
|
19891
|
-
}
|
|
19892
|
-
}
|
|
19893
|
-
}
|
|
19894
|
-
}
|
|
19895
|
-
function accumulateGeminiChunks(chunks2, options) {
|
|
19896
|
-
const state = createGeminiAccumulatorState();
|
|
19897
|
-
for (const chunk of chunks2) {
|
|
19898
|
-
applyGeminiChunk(chunk, state, options);
|
|
19899
|
-
}
|
|
19900
|
-
return {
|
|
19901
|
-
text: state.text,
|
|
19902
|
-
toolCalls: state.toolCalls,
|
|
19903
|
-
usage: state.usage,
|
|
19904
|
-
finishReason: state.finishReason,
|
|
19905
|
-
reasoningContent: state.reasoning,
|
|
19906
|
-
events: state.events
|
|
19907
|
-
};
|
|
19908
|
-
}
|
|
19909
|
-
async function accumulateGeminiStream(stream, options) {
|
|
19910
|
-
const state = createGeminiAccumulatorState();
|
|
19911
|
-
for await (const chunk of stream) {
|
|
19912
|
-
applyGeminiChunk(chunk, state, options);
|
|
19913
|
-
}
|
|
19914
|
-
return {
|
|
19915
|
-
text: state.text,
|
|
19916
|
-
toolCalls: state.toolCalls,
|
|
19917
|
-
usage: state.usage,
|
|
19918
|
-
finishReason: state.finishReason,
|
|
19919
|
-
reasoningContent: state.reasoning,
|
|
19920
|
-
events: state.events
|
|
19921
|
-
};
|
|
19922
|
-
}
|
|
19923
|
-
function shouldUseGeminiNativeToolRoute(provider, model, tools, isImageModel) {
|
|
19924
|
-
return provider === "google" && !isImageModel(model) && isGemini3Model(model) && Array.isArray(tools) && tools.length > 0;
|
|
19925
|
-
}
|
|
19926
|
-
function buildGeminiGenerateContentRequest(args2) {
|
|
19927
|
-
const { contents, systemTexts } = convertOpenAiMessagesToGemini(
|
|
19928
|
-
args2.messages,
|
|
19929
|
-
{ attachSkipThoughtSignature: args2.attachSkipThoughtSignature }
|
|
19930
|
-
);
|
|
19931
|
-
const request3 = { contents };
|
|
19932
|
-
if (systemTexts.length > 0) {
|
|
19933
|
-
request3.systemInstruction = {
|
|
19934
|
-
role: "user",
|
|
19935
|
-
parts: systemTexts.map((text) => ({ text }))
|
|
19936
|
-
};
|
|
19937
|
-
}
|
|
19938
|
-
const toolsResult = convertOpenAiToolsToGemini(args2.tools);
|
|
19939
|
-
if (toolsResult) {
|
|
19940
|
-
request3.tools = toolsResult;
|
|
19941
|
-
request3.toolConfig = { functionCallingConfig: { mode: "VALIDATED" } };
|
|
19942
|
-
}
|
|
19943
|
-
const generationConfig = {};
|
|
19944
|
-
if (typeof args2.maxTokens === "number" && args2.maxTokens > 0) {
|
|
19945
|
-
generationConfig.maxOutputTokens = args2.maxTokens;
|
|
19946
|
-
}
|
|
19947
|
-
if (typeof args2.temperature === "number") {
|
|
19948
|
-
generationConfig.temperature = args2.temperature;
|
|
19949
|
-
}
|
|
19950
|
-
if (Object.keys(generationConfig).length > 0) {
|
|
19951
|
-
request3.generationConfig = generationConfig;
|
|
19952
|
-
}
|
|
19953
|
-
return request3;
|
|
19954
|
-
}
|
|
19955
|
-
|
|
19956
|
-
// packages/agent-runtime/antigravityCloudCodeProvider.ts
|
|
19957
|
-
var STREAM_PATH = "/v1internal:streamGenerateContent?alt=sse";
|
|
19958
|
-
function buildCloudCodeAssistPayload(args2) {
|
|
19959
|
-
const projectId = readAntigravityProjectId(args2.metadata);
|
|
19960
|
-
if (!projectId) {
|
|
19961
|
-
throw new Error(
|
|
19962
|
-
"Antigravity OAuth credential is missing metadata.projectId. Re-run `nolo auth antigravity`."
|
|
19963
|
-
);
|
|
19964
|
-
}
|
|
19965
|
-
const logicalModel = asOptionalTrimmedString(args2.openAiBody.model) ?? asOptionalTrimmedString(args2.agentConfig.model) ?? "gemini-3.1-pro";
|
|
19966
|
-
const { wireModelId: model, profile } = resolveAntigravityWireModel(logicalModel);
|
|
19967
|
-
const rawMessages = Array.isArray(args2.openAiBody.messages) ? args2.openAiBody.messages : [];
|
|
19968
|
-
const quirks = resolveGeminiModelQuirks(model);
|
|
19969
|
-
const isClaude = quirks.isClaudeCrossModel;
|
|
19970
|
-
const { contents, systemTexts } = convertOpenAiMessagesToGemini(rawMessages, {
|
|
19971
|
-
attachSkipThoughtSignature: quirks.allowsThoughtSignatureSentinel
|
|
19972
|
-
});
|
|
19973
|
-
if (contents.length === 0) {
|
|
19974
|
-
throw new Error("Antigravity Cloud Code Assist request has no user/model contents.");
|
|
19975
|
-
}
|
|
19976
|
-
const prompt = args2.agentConfig.prompt?.trim();
|
|
19977
|
-
if (prompt) systemTexts.unshift(prompt);
|
|
19978
|
-
const request3 = { contents };
|
|
19979
|
-
if (systemTexts.length > 0) {
|
|
19980
|
-
request3.systemInstruction = {
|
|
19981
|
-
role: "user",
|
|
19982
|
-
parts: systemTexts.map((text) => ({ text }))
|
|
19983
|
-
};
|
|
19984
|
-
}
|
|
19985
|
-
const tools = convertOpenAiToolsToGemini(
|
|
19986
|
-
Array.isArray(args2.openAiBody.tools) ? args2.openAiBody.tools : void 0
|
|
19987
|
-
);
|
|
19988
|
-
if (tools) {
|
|
19989
|
-
request3.tools = tools;
|
|
19990
|
-
request3.toolConfig = { functionCallingConfig: { mode: "VALIDATED" } };
|
|
19991
|
-
}
|
|
19992
|
-
const generationConfig = {};
|
|
19993
|
-
if (profile?.maxOutputTokens) {
|
|
19994
|
-
generationConfig.maxOutputTokens = profile.maxOutputTokens;
|
|
19995
|
-
} else if (typeof args2.agentConfig.max_tokens === "number" && args2.agentConfig.max_tokens > 0) {
|
|
19996
|
-
generationConfig.maxOutputTokens = args2.agentConfig.max_tokens;
|
|
19997
|
-
}
|
|
19998
|
-
if (typeof args2.agentConfig.temperature === "number") {
|
|
19999
|
-
generationConfig.temperature = args2.agentConfig.temperature;
|
|
20000
|
-
}
|
|
20001
|
-
if (Object.keys(generationConfig).length > 0) {
|
|
20002
|
-
request3.generationConfig = generationConfig;
|
|
20003
|
-
}
|
|
20004
|
-
const agentId = randomUUID();
|
|
20005
|
-
const trajectoryId = randomUUID();
|
|
20006
|
-
const step = 2;
|
|
20007
|
-
const requestId = `agent/${agentId}/${Date.now()}/${trajectoryId}/${step}`;
|
|
20008
|
-
const labels = {
|
|
20009
|
-
trajectory_id: trajectoryId,
|
|
20010
|
-
last_step_index: String(step - 1),
|
|
20011
|
-
used_claude: String(isClaude),
|
|
20012
|
-
used_claude_conservative: String(isClaude)
|
|
20013
|
-
};
|
|
20014
|
-
if (profile?.modelEnum) {
|
|
20015
|
-
labels.model_enum = profile.modelEnum;
|
|
20016
|
-
}
|
|
20017
|
-
request3.labels = labels;
|
|
20018
|
-
request3.sessionId = `-${Math.floor(Math.random() * 9e15)}`;
|
|
20019
|
-
return {
|
|
20020
|
-
url: `${resolveAntigravityCloudCodeBaseUrl(args2.agentConfig.customProviderUrl)}${STREAM_PATH}`,
|
|
20021
|
-
envelope: {
|
|
20022
|
-
project: projectId,
|
|
20023
|
-
model,
|
|
20024
|
-
request: request3,
|
|
20025
|
-
requestId,
|
|
20026
|
-
requestType: "agent",
|
|
20027
|
-
userAgent: "antigravity"
|
|
20028
|
-
}
|
|
20029
|
-
};
|
|
20030
|
-
}
|
|
20031
|
-
function resolveAntigravityFinishReason(upstream) {
|
|
20032
|
-
const normalized = (upstream ?? "").trim().toUpperCase();
|
|
20033
|
-
if (normalized === "MAX_TOKENS") return "length";
|
|
20034
|
-
if (normalized === "SAFETY" || normalized === "RECITATION" || normalized === "PROHIBITED_CONTENT" || normalized === "BLOCKLIST") {
|
|
20035
|
-
return "content_filter";
|
|
20036
|
-
}
|
|
20037
|
-
return "stop";
|
|
20038
|
-
}
|
|
20039
|
-
function normalizeAntigravityCompletion(decoded) {
|
|
20040
|
-
const { text, toolCalls, usage, finishReason, reasoningContent, events } = decoded;
|
|
20041
|
-
const normalizedFinishReason = (finishReason ?? "").trim().toUpperCase();
|
|
20042
|
-
if (!text && !reasoningContent && toolCalls.length === 0 && !finishReason && !usage) {
|
|
20043
|
-
const body = {
|
|
20044
|
-
error: {
|
|
20045
|
-
message: "antigravity upstream returned an empty stream (no content, finishReason or usage); channel degradation, not model emptiness"
|
|
20046
|
-
},
|
|
20047
|
-
provider_events: events
|
|
20048
|
-
};
|
|
20049
|
-
return {
|
|
20050
|
-
status: 502,
|
|
20051
|
-
text: "",
|
|
20052
|
-
toolCalls: [],
|
|
20053
|
-
providerEvents: events,
|
|
20054
|
-
body
|
|
20055
|
-
};
|
|
20056
|
-
}
|
|
20057
|
-
if (normalizedFinishReason === "MALFORMED_FUNCTION_CALL") {
|
|
20058
|
-
const message2 = "antigravity upstream returned MALFORMED_FUNCTION_CALL (model generated an invalid function call or tool arguments were rejected by upstream)";
|
|
20059
|
-
const providerFailure = {
|
|
20060
|
-
kind: "provider_failure",
|
|
20061
|
-
provider: "antigravity",
|
|
20062
|
-
code: "MALFORMED_FUNCTION_CALL",
|
|
20063
|
-
message: message2,
|
|
20064
|
-
providerReason: "MALFORMED_FUNCTION_CALL",
|
|
20065
|
-
retryable: false,
|
|
20066
|
-
status: 502
|
|
20067
|
-
};
|
|
20068
|
-
return {
|
|
20069
|
-
status: 502,
|
|
20070
|
-
text: "",
|
|
20071
|
-
toolCalls: [],
|
|
20072
|
-
finishReason,
|
|
20073
|
-
providerEvents: events,
|
|
20074
|
-
providerFailure,
|
|
20075
|
-
runtimeProviderFailure: {
|
|
20076
|
-
message: providerFailure.message,
|
|
20077
|
-
retryable: providerFailure.retryable
|
|
20078
|
-
},
|
|
20079
|
-
body: {
|
|
20080
|
-
error: {
|
|
20081
|
-
message: message2,
|
|
20082
|
-
code: "MALFORMED_FUNCTION_CALL",
|
|
20083
|
-
category: "malformed_function_call",
|
|
20084
|
-
providerReason: "MALFORMED_FUNCTION_CALL",
|
|
20085
|
-
retryable: false
|
|
20086
|
-
},
|
|
20087
|
-
provider_failure: providerFailure,
|
|
20088
|
-
provider_events: events
|
|
20089
|
-
}
|
|
20090
|
-
};
|
|
20091
|
-
}
|
|
20092
|
-
const message = {
|
|
20093
|
-
role: "assistant",
|
|
20094
|
-
content: text || null
|
|
20095
|
-
};
|
|
20096
|
-
if (toolCalls.length > 0) message.tool_calls = toolCalls;
|
|
20097
|
-
if (reasoningContent) message.reasoning_content = reasoningContent;
|
|
20098
|
-
return {
|
|
20099
|
-
status: 200,
|
|
20100
|
-
text,
|
|
20101
|
-
...reasoningContent ? { reasoningContent } : {},
|
|
20102
|
-
toolCalls,
|
|
20103
|
-
...usage ? { usage } : {},
|
|
20104
|
-
...finishReason ? { finishReason } : {},
|
|
20105
|
-
providerEvents: events,
|
|
20106
|
-
body: {
|
|
20107
|
-
choices: [{
|
|
20108
|
-
index: 0,
|
|
20109
|
-
message,
|
|
20110
|
-
finish_reason: toolCalls.length > 0 ? "tool_calls" : resolveAntigravityFinishReason(finishReason)
|
|
20111
|
-
}],
|
|
20112
|
-
...usage ? { usage } : {},
|
|
20113
|
-
provider_events: events
|
|
20114
|
-
}
|
|
20115
|
-
};
|
|
20116
|
-
}
|
|
20117
|
-
async function fetchAntigravityCloudCodeCompletion(args2) {
|
|
20118
|
-
const fetchImpl = args2.fetchImpl ?? fetch;
|
|
20119
|
-
const { url, envelope } = buildCloudCodeAssistPayload(args2);
|
|
20120
|
-
const response = await fetchImpl(url, {
|
|
20121
|
-
method: "POST",
|
|
20122
|
-
headers: {
|
|
20123
|
-
Authorization: `Bearer ${args2.accessToken}`,
|
|
20124
|
-
"Content-Type": "application/json",
|
|
20125
|
-
"User-Agent": getAntigravityUserAgent()
|
|
20126
|
-
},
|
|
20127
|
-
body: JSON.stringify(envelope),
|
|
20128
|
-
signal: args2.signal
|
|
20129
|
-
});
|
|
20130
|
-
if (!response.ok) {
|
|
20131
|
-
const errorText = await response.text();
|
|
20132
|
-
return {
|
|
20133
|
-
status: response.status,
|
|
20134
|
-
text: "",
|
|
20135
|
-
toolCalls: [],
|
|
20136
|
-
providerEvents: [],
|
|
20137
|
-
// 保留上游结构:Antigravity 的限流 body 同样携带结构化的重置信息,
|
|
20138
|
-
// 压成字符串会让冷却退化成 5 分钟默认值。
|
|
20139
|
-
body: parseUpstreamErrorBody(errorText, response.statusText)
|
|
20140
|
-
};
|
|
20141
|
-
}
|
|
20142
|
-
const chunkStream = streamSseDataValues(response, parseSseDataLineJson);
|
|
20143
|
-
const { text, toolCalls, usage, finishReason, reasoningContent, events } = await accumulateGeminiStream(chunkStream, {
|
|
20144
|
-
onTextDelta: args2.onTextDelta,
|
|
20145
|
-
onReasoningDelta: args2.onReasoningDelta
|
|
20146
|
-
});
|
|
20147
|
-
const normalized = normalizeAntigravityCompletion({
|
|
20148
|
-
text,
|
|
20149
|
-
toolCalls,
|
|
20150
|
-
usage,
|
|
20151
|
-
finishReason,
|
|
20152
|
-
reasoningContent,
|
|
20153
|
-
events
|
|
20154
|
-
});
|
|
20155
|
-
if (normalized.status !== 200 || !text && toolCalls.length === 0) {
|
|
20156
|
-
console.warn(
|
|
20157
|
-
`[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}`
|
|
20158
|
-
);
|
|
20159
|
-
}
|
|
20160
|
-
return normalized;
|
|
20161
|
-
}
|
|
20162
|
-
|
|
20163
20105
|
// packages/agent-runtime/devin/devinProvider.ts
|
|
20164
|
-
import { randomBytes, randomUUID
|
|
20106
|
+
import { randomBytes, randomUUID } from "node:crypto";
|
|
20165
20107
|
var CLIENT_NAME = "chisel";
|
|
20166
|
-
var CLIENT_VERSION = "
|
|
20108
|
+
var CLIENT_VERSION = "3000.11.3";
|
|
20167
20109
|
function writeVarint(fieldNum, value) {
|
|
20168
20110
|
const tag = fieldNum << 3 | 0;
|
|
20169
20111
|
const bytes = [];
|
|
@@ -20223,7 +20165,7 @@ function encodeDevinClientMetadata(token) {
|
|
|
20223
20165
|
function encodeDevinChatMessage(msg) {
|
|
20224
20166
|
const source = msg.role === "assistant" ? 2 : msg.role === "tool" ? 4 : 1;
|
|
20225
20167
|
return Buffer.concat([
|
|
20226
|
-
writeStringField(1,
|
|
20168
|
+
writeStringField(1, randomUUID()),
|
|
20227
20169
|
writeVarint(2, source),
|
|
20228
20170
|
writeStringField(3, msg.text),
|
|
20229
20171
|
...(msg.toolCalls ?? []).map(
|
|
@@ -20311,7 +20253,7 @@ ${item.text}`;
|
|
|
20311
20253
|
const chatMessageBuffers = coalesced.map((m) => encodeDevinChatMessage(m));
|
|
20312
20254
|
const completionConfig = buildCompletionConfig({ temperature });
|
|
20313
20255
|
const modelConfig = Buffer.concat([
|
|
20314
|
-
writeStringField(1,
|
|
20256
|
+
writeStringField(1, randomUUID()),
|
|
20315
20257
|
writeVarint(2, 1),
|
|
20316
20258
|
writeVarint(3, 4)
|
|
20317
20259
|
]);
|
|
@@ -20323,7 +20265,7 @@ ${item.text}`;
|
|
|
20323
20265
|
writeMessageField(8, completionConfig),
|
|
20324
20266
|
...tools.map((tool) => writeMessageField(10, encodeDevinToolDefinition(tool))),
|
|
20325
20267
|
writeMessageField(15, modelConfig),
|
|
20326
|
-
writeStringField(16,
|
|
20268
|
+
writeStringField(16, randomUUID()),
|
|
20327
20269
|
writeVarint(20, 1),
|
|
20328
20270
|
writeStringField(21, model)
|
|
20329
20271
|
]);
|
|
@@ -20408,6 +20350,21 @@ function parseDevinMetadataUsage(metaBytes) {
|
|
|
20408
20350
|
}
|
|
20409
20351
|
return sawAny ? { prompt, completion, cacheRead, cacheWrite } : null;
|
|
20410
20352
|
}
|
|
20353
|
+
function attachDevinUpstreamFailure(error, failure) {
|
|
20354
|
+
if (failure) {
|
|
20355
|
+
error.devinUpstreamFailure = failure;
|
|
20356
|
+
}
|
|
20357
|
+
return error;
|
|
20358
|
+
}
|
|
20359
|
+
function readDevinUpstreamFailure(error) {
|
|
20360
|
+
if (!error || typeof error !== "object") return void 0;
|
|
20361
|
+
const failure = error.devinUpstreamFailure;
|
|
20362
|
+
if (!failure || typeof failure !== "object") return void 0;
|
|
20363
|
+
if (typeof failure.status !== "number" || !Number.isFinite(failure.status)) {
|
|
20364
|
+
return void 0;
|
|
20365
|
+
}
|
|
20366
|
+
return failure;
|
|
20367
|
+
}
|
|
20411
20368
|
function parseDevinConnectTrailer(payload) {
|
|
20412
20369
|
const text = payload.toString("utf8").trim();
|
|
20413
20370
|
if (!text || text === "{}") return null;
|
|
@@ -20418,7 +20375,11 @@ function parseDevinConnectTrailer(payload) {
|
|
|
20418
20375
|
}
|
|
20419
20376
|
const code = typeof parsed.error.code === "string" ? parsed.error.code : "unknown";
|
|
20420
20377
|
const message = typeof parsed.error.message === "string" ? parsed.error.message : "Unknown error";
|
|
20421
|
-
return
|
|
20378
|
+
return attachDevinUpstreamFailure(
|
|
20379
|
+
new Error(`Devin Connect upstream error ${code}: ${message}`),
|
|
20380
|
+
// Connect/gRPC 的 resource_exhausted 与 HTTP 429 同义(限流/配额耗尽)。
|
|
20381
|
+
code === "resource_exhausted" ? { status: 429, body: parsed.error } : void 0
|
|
20382
|
+
);
|
|
20422
20383
|
} catch {
|
|
20423
20384
|
return new Error(`Devin Connect invalid terminal trailer: ${text}`);
|
|
20424
20385
|
}
|
|
@@ -20545,8 +20506,11 @@ function createDevinProvider(options) {
|
|
|
20545
20506
|
});
|
|
20546
20507
|
if (!response.ok) {
|
|
20547
20508
|
const errText = await response.text().catch(() => "");
|
|
20548
|
-
throw
|
|
20549
|
-
|
|
20509
|
+
throw attachDevinUpstreamFailure(
|
|
20510
|
+
new Error(
|
|
20511
|
+
`Devin Connect upstream returned error ${response.status}: ${errText}`
|
|
20512
|
+
),
|
|
20513
|
+
{ status: response.status, body: errText }
|
|
20550
20514
|
);
|
|
20551
20515
|
}
|
|
20552
20516
|
if (!response.body) {
|
|
@@ -20663,20 +20627,18 @@ function createDevinProvider(options) {
|
|
|
20663
20627
|
}
|
|
20664
20628
|
|
|
20665
20629
|
export {
|
|
20630
|
+
readCommandActionGatePayload,
|
|
20631
|
+
readActionGate,
|
|
20666
20632
|
Option_exports,
|
|
20667
20633
|
Duration_exports,
|
|
20668
20634
|
Exit_exports,
|
|
20669
20635
|
Effect_exports,
|
|
20670
|
-
readCommandActionGatePayload,
|
|
20671
|
-
readActionGate,
|
|
20672
20636
|
evaluateFileWritePolicy,
|
|
20673
20637
|
summarizeToolArguments,
|
|
20674
20638
|
formatToolOverflowMarker,
|
|
20675
20639
|
LOCAL_AGENT_CONFIG_MISSING_CODE,
|
|
20676
20640
|
LOCAL_TURN_ABORTED_CODE,
|
|
20677
20641
|
runLocalAgentTurn,
|
|
20678
|
-
parseSseDataLineJson,
|
|
20679
|
-
parseSseDataLineObject,
|
|
20680
20642
|
codexStreamFailureStatus,
|
|
20681
20643
|
aggregateResponsesStream,
|
|
20682
20644
|
buildOpenAiCompatibleChatCompletionRequest,
|
|
@@ -20692,8 +20654,6 @@ export {
|
|
|
20692
20654
|
createHybridRecordStore,
|
|
20693
20655
|
isDestructiveShellCommand,
|
|
20694
20656
|
evaluateShellCommandPolicy,
|
|
20695
|
-
resolveLocalToolPolicy,
|
|
20696
|
-
executeLocalToolWithPolicy,
|
|
20697
20657
|
filterRetainedLedgerRecords,
|
|
20698
20658
|
isLineRangeCovered,
|
|
20699
20659
|
getProcessRegistry,
|
|
@@ -20704,16 +20664,14 @@ export {
|
|
|
20704
20664
|
internalSearchWorkspace,
|
|
20705
20665
|
internalListWorkspaceEntries,
|
|
20706
20666
|
createLocalWorkspaceToolExecutors,
|
|
20667
|
+
buildToolParametersIndex,
|
|
20668
|
+
getAgentRuntimeToolParametersIndex,
|
|
20669
|
+
resolveLocalToolPolicy,
|
|
20670
|
+
executeLocalToolWithPolicy,
|
|
20707
20671
|
localDialogMessageRecordToRuntimeMessage,
|
|
20708
20672
|
buildLocalDialogWritePlan,
|
|
20709
20673
|
buildNoloWorkspaceCliToolExecutors,
|
|
20710
20674
|
buildLoadSkillExecutor,
|
|
20711
|
-
|
|
20712
|
-
isGemini3Model,
|
|
20713
|
-
accumulateGeminiChunks,
|
|
20714
|
-
shouldUseGeminiNativeToolRoute,
|
|
20715
|
-
buildGeminiGenerateContentRequest,
|
|
20716
|
-
resolveAntigravityFinishReason,
|
|
20717
|
-
fetchAntigravityCloudCodeCompletion,
|
|
20675
|
+
readDevinUpstreamFailure,
|
|
20718
20676
|
createDevinProvider
|
|
20719
20677
|
};
|