nolo-cli 0.107.0-alpha.4 → 0.107.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-UDCSOTD2.js → _executeModel-M573MKVE.js} +78 -70
- package/action-GVA5ARSJ.js +20 -0
- package/{addContentAction-MB2HHMDZ.js → addContentAction-M2WOWZCL.js} +13 -12
- package/{addDialogAgentAction-MCEABSBA.js → addDialogAgentAction-QMAQ5Z6N.js} +19 -20
- package/{agentDeleteCommand-OWYHN6D6.js → agentDeleteCommand-ZFHYRHBS.js} +118 -43
- package/{agentEmailCommands-AU5I4M4W.js → agentEmailCommands-X6AVPIVQ.js} +100 -90
- package/agentListCommands-PAD2CI2I.js +741 -0
- package/{agentMachineCommands-YMNME2L6.js → agentMachineCommands-UPH6RJCC.js} +50 -46
- package/{agentProviderCommands-GNPTL5XR.js → agentProviderCommands-CMVTBY5X.js} +97 -2
- package/{agentPullCommand-O5MPVJ5E.js → agentPullCommand-B4T2DJ5H.js} +1 -1
- package/agentRecordCommands-UMACPRAF.js +138 -0
- package/agentRunCommand-H6KKHHMU.js +167 -0
- package/{agentRunControl-AVJR4JW4.js → agentRunControl-3HWA2LLQ.js} +2 -2
- package/{agentRuntimeLocal-KCMC2TBD.js → agentRuntimeLocal-N4YGKL7M.js} +44 -40
- package/{agentSlice-R7PR6KYM.js → agentSlice-2LPP43XH.js} +15 -14
- package/{appDeleteCommands-JEPA3EWE.js → appDeleteCommands-7DAF33AM.js} +46 -42
- package/{appDeployCommands-UTB76XFM.js → appDeployCommands-ZPZSMFGZ.js} +46 -42
- package/{appDeployStatusCommands-LGHF2SBD.js → appDeployStatusCommands-FWBDSSS5.js} +46 -42
- package/{appGetCommands-PX2BFHOB.js → appGetCommands-SZZOHGEP.js} +46 -42
- package/{appListCommands-BSMPTWKC.js → appListCommands-FPMUBDPM.js} +46 -42
- package/{authCommand-YW42YZA4.js → authCommand-VL3G26NQ.js} +119 -25
- package/{authCommands-RGOGCPP6.js → authCommands-5RTUDYZW.js} +7 -5
- package/{builtinSkillRegistry-FUAVTRVZ.js → builtinSkillRegistry-ZK4K67Y5.js} +11 -9
- package/{chromeCommands-FZYAU75D.js → chromeCommands-AU5ZJXBG.js} +289 -37
- package/{chromeOpsCommands-62P2Q2YB.js → chromeOpsCommands-ZYTCMNHG.js} +156 -22
- package/{chunk-JEDZAO7L.js → chunk-2SYTUTLI.js} +257 -37
- package/{chunk-HVURBGF3.js → chunk-2U3NHADM.js} +6 -6
- package/{chunk-QTGQ2LTL.js → chunk-3DQY5IFB.js} +6 -10
- package/{chunk-XT35TTFG.js → chunk-3IXAHOJS.js} +19 -21
- package/{chunk-UVA7OYO3.js → chunk-3W67RV75.js} +29 -9
- package/chunk-4LCOCOR5.js +50 -0
- package/{chunk-JPGCXHNM.js → chunk-4LKMZ3RR.js} +1 -1
- package/{chunk-2GRGFCF6.js → chunk-4VJAC32I.js} +2 -1
- package/{chunk-6D6VBVEW.js → chunk-4W24JM32.js} +80 -14
- package/{chunk-MC4XLIJ7.js → chunk-523DITKR.js} +1 -1
- package/{chunk-E4MARS3Q.js → chunk-5GVBDNTO.js} +1 -1
- package/{chunk-C3M4465B.js → chunk-5HYJ3DSZ.js} +404 -659
- package/chunk-5MMAK75Q.js +15 -0
- package/{chunk-7S4YWN7P.js → chunk-5UUIGN6I.js} +4 -4
- package/{chunk-42V6BK2E.js → chunk-62IL3KQV.js} +4 -34
- package/{chunk-4MK3I7Y4.js → chunk-6MAW4XOF.js} +5 -5
- package/{chunk-3UZPUAES.js → chunk-74PPKIY2.js} +1 -1
- package/chunk-76HO2DP6.js +15 -0
- package/{chunk-ASIFZ2WY.js → chunk-7BBP7ZX3.js} +66 -54
- package/{chunk-VLTIYV3X.js → chunk-7I25CBT5.js} +34 -8
- package/{chunk-IBOZNTG2.js → chunk-7X5XZ34C.js} +23 -28
- package/chunk-AGIM7IMJ.js +147 -0
- package/{chunk-5UTFL4QJ.js → chunk-APO5TOXO.js} +1 -1
- package/{chunk-EEGDMATE.js → chunk-AZOVPTL6.js} +91 -81
- package/{chunk-6OZ36FXI.js → chunk-BIPGGSJS.js} +22 -4
- package/{chunk-EYAQT56M.js → chunk-BNQMNUKZ.js} +9 -6
- package/{chunk-62CATUYY.js → chunk-CBUMFIFE.js} +834 -962
- package/{chunk-OIVSQH2O.js → chunk-CDEEFJXN.js} +308 -11
- package/chunk-CHOZJMJS.js +78 -0
- package/{chunk-ETI2NYVF.js → chunk-CIP3AAMT.js} +4 -4
- package/{chunk-GBRG75BQ.js → chunk-D2MDMY2M.js} +1 -0
- package/{chunk-W7HLWAQ7.js → chunk-DE45KZNH.js} +118 -90
- package/{chunk-Q554LLSI.js → chunk-DMXLXZKL.js} +1 -1
- package/{chunk-3VNWWVKB.js → chunk-E3YWHWCR.js} +50 -18
- package/{chunk-HKNXJGEC.js → chunk-ECFHBYUW.js} +85 -50
- package/{chunk-ACTMNVHM.js → chunk-EHSYSKXV.js} +1 -1
- package/{chunk-WV42OMV7.js → chunk-ELUDRSRD.js} +8 -8
- package/{chunk-ABQYVJBJ.js → chunk-EV235ILT.js} +5 -5
- package/{chunk-TRV2MIDW.js → chunk-EXAJ6DCR.js} +1 -0
- package/{chunk-BFDFRLLQ.js → chunk-EZ4VZHAG.js} +5 -5
- package/{chunk-GO3Z72MT.js → chunk-FHLMQIU7.js} +65 -95
- package/{chunk-2F7RJC6L.js → chunk-FOXQ7BAB.js} +1 -1
- package/{chunk-SH43IESU.js → chunk-GGC55Q32.js} +199 -29
- package/chunk-GMZLP5DV.js +82 -0
- package/{chunk-FDTR4QJ6.js → chunk-H6A6X4EK.js} +32 -1
- package/{chunk-DVINR3PL.js → chunk-HDLLCBRF.js} +1 -1
- package/{chunk-QOKAKDPE.js → chunk-HIM3FCLF.js} +0 -1
- package/{chunk-ONXOABJR.js → chunk-HNGRBWYF.js} +3 -0
- package/{chunk-BNGW5ASC.js → chunk-I2RGRVQ7.js} +22 -2
- package/{chunk-O6OSWFZQ.js → chunk-IHPDK6UD.js} +6 -0
- package/{chunk-QDSINZM3.js → chunk-IXH3HKY2.js} +1 -22
- package/{chunk-GQBOR3G6.js → chunk-JBKHQOYK.js} +8 -4
- package/{chunk-XD2MJFUG.js → chunk-JEFXP73H.js} +1 -1
- package/{chunk-PBA4UJBK.js → chunk-JIXGJTBU.js} +4 -4
- package/{chunk-AEOE4Z6Q.js → chunk-K6L5PNXK.js} +39 -15
- package/{chunk-Z77CRGTW.js → chunk-KA5O5KQL.js} +1 -1
- package/{chunk-GPCZ7UXG.js → chunk-KD6D6BLA.js} +1 -1
- package/{chunk-4CR5I7BD.js → chunk-KFWDYYSS.js} +47 -67
- package/{chunk-UZGQNTVW.js → chunk-KHKTDMYG.js} +8 -6
- package/{chunk-JDPFV2JV.js → chunk-KWUKOQM2.js} +20 -11
- package/{chunk-MRIHM22T.js → chunk-LBFL6RZG.js} +58 -9
- package/{chunk-LS2ZANRJ.js → chunk-LOCNXNOU.js} +1 -1
- package/{chunk-DHDMC6FO.js → chunk-LUBFABMJ.js} +15 -14
- package/{chunk-NA35QHCF.js → chunk-LVBFKW65.js} +1 -1
- package/chunk-LWLNLZC5.js +265 -0
- package/chunk-N4NGJDT6.js +929 -0
- package/{chunk-BFU6C242.js → chunk-NMFV26UG.js} +1 -1
- package/{chunk-FZGV4FGK.js → chunk-NUHHBEJC.js} +378 -187
- package/chunk-NWENLDMM.js +42 -0
- package/chunk-O7SVKKLY.js +875 -0
- package/chunk-OCZKATRC.js +129 -0
- package/{chunk-6Z7MY3V7.js → chunk-OEJLGVBL.js} +5 -5
- package/{chunk-VMFTFOWF.js → chunk-OKGVNZTL.js} +35 -8
- package/{chunk-GEPUP7OO.js → chunk-OR2UWD6X.js} +3 -3
- package/{chunk-KQHGZWSV.js → chunk-OXME3PEE.js} +1 -1
- package/{chunk-J4MOO56S.js → chunk-PNXHPLRU.js} +10 -2
- package/{chunk-3BMYXEUW.js → chunk-R5AJODNI.js} +1 -1
- package/{chunk-P5EVSOPA.js → chunk-R6EBQEQE.js} +22 -29
- package/chunk-RQ6CTX2E.js +164 -0
- package/{chunk-MS7TSPZR.js → chunk-RU36ZYSG.js} +19 -17
- package/{chunk-ALXHV7NK.js → chunk-RWXLPUKI.js} +40 -4
- package/{chunk-KQ4ONNQD.js → chunk-RXA3HAVW.js} +190 -8
- package/{chunk-IIVGDG4I.js → chunk-SJKULPGX.js} +13 -7
- package/{chunk-Q67DOFOO.js → chunk-SZC4REES.js} +212 -105
- package/{chunk-JRQFUXY7.js → chunk-TBAXFWOS.js} +99 -22
- package/{chunk-PQFHGD77.js → chunk-TBM2RS3U.js} +161 -14
- package/{chunk-NOF3HDSN.js → chunk-TFOIJFCM.js} +11 -9
- package/{chunk-BYMV6QZG.js → chunk-TNIX77YM.js} +4 -0
- package/chunk-TY3TIUJK.js +89 -0
- package/{chunk-I3TQJXQ7.js → chunk-U3C3IA32.js} +9 -2
- package/{chunk-YYLHWIW6.js → chunk-UKZX3NHN.js} +1 -1
- package/chunk-UM7TA3K4.js +1008 -0
- package/{chunk-6YTOJY35.js → chunk-VBG7GWWR.js} +253 -8
- package/{chunk-GL3EHUR4.js → chunk-VHGYUYQ3.js} +69 -47
- package/chunk-VIWDGTDA.js +8 -0
- package/chunk-VJVNU77E.js +83 -0
- package/chunk-VM6IE2GN.js +8004 -0
- package/{chunk-UKWGR5SS.js → chunk-VY6VFGKR.js} +194 -1144
- package/chunk-VZLO4XJD.js +17 -0
- package/chunk-W32HPLTL.js +13692 -0
- package/{chunk-AHAHBQMU.js → chunk-WDLSZMTA.js} +2 -2
- package/{chunk-53HEEOTT.js → chunk-WF5X57VW.js} +83 -16
- package/{chunk-VRTTFDBM.js → chunk-WPHY3VPF.js} +35 -22
- package/{chunk-3L2WKC3W.js → chunk-XPWGOTBQ.js} +8 -1
- package/chunk-YV25TM3R.js +780 -0
- package/chunk-ZRAU6T47.js +56 -0
- package/{chunk-IBOOZVVD.js → chunk-ZTKZZY2A.js} +851 -279
- package/commandRegistry-ASW6IVZ3.js +833 -0
- package/{contentThunks-IV2T3EJC.js → contentThunks-4XNVOIR7.js} +39 -36
- package/{cooldownCommands-REAWYVTY.js → cooldownCommands-ZLEPIB4A.js} +2 -2
- package/{createAgentAutomationAction-JCOIEYY4.js → createAgentAutomationAction-NHHTCJMC.js} +40 -37
- package/createDialogAction-XEBTHDB3.js +70 -0
- package/{createPageAction-D2VOOLP3.js → createPageAction-VR3WW2AQ.js} +47 -43
- package/{chunk-FG3HKPQP.js → cursorProvider-YGGNMVWX.js} +2751 -10185
- package/{dbSlice-A6C6H32X.js → dbSlice-TG4MZ5EB.js} +12 -11
- package/{deleteFile-YG6QMJLU.js → deleteFile-KESP65GC.js} +7 -6
- package/{dialogCommands-H7FPUYUQ.js → dialogCommands-FJWQG3MX.js} +50 -47
- package/{dialogSlice-6JZOOTDS.js → dialogSlice-GVRDGCRG.js} +57 -37
- package/{dist-VODFSGNG.js → dist-NJC2W7I4.js} +61 -54
- package/{docCreateCommands-WRG2JLGM.js → docCreateCommands-AZSK4NAG.js} +48 -44
- package/{docDeleteCommands-SHWJIBJS.js → docDeleteCommands-DDJMSMFZ.js} +49 -45
- package/{docReadCommands-WJN3WT6O.js → docReadCommands-5F5Q6EBZ.js} +47 -43
- package/{docStore-HUPQ2FSS.js → docStore-SUZUUWDI.js} +17 -13
- package/{docUpdateCommands-IE32IL6O.js → docUpdateCommands-XPNPVZOC.js} +48 -44
- package/{fetchMessages-EIU7UFFK.js → fetchMessages-3PXAHKCR.js} +5 -5
- package/{getPricing-LUSEABA6.js → getPricing-DOBBZLOK.js} +4 -4
- package/{handleSendMessageAction-DFPMQ7YM.js → handleSendMessageAction-VC6VTFKS.js} +109 -42
- package/index.js +87 -884
- package/{lib-FRRS27KN.js → lib-PU2G2MSO.js} +523 -191
- package/{localDialogRead-BTFJ4V2I.js → localDialogRead-UYCKO7YZ.js} +2 -2
- package/{localRuntimeAuthority-6IR6BBXE.js → localRuntimeAuthority-TU6OBC76.js} +9 -6
- package/{localRuntimeDb-SYQGUF4U.js → localRuntimeDb-VKWVOPPI.js} +1 -1
- package/{machineCommands-M2T2I5NF.js → machineCommands-M634V2L3.js} +98 -89
- package/machineWsRunDispatch-Z3HUSTFI.js +154 -0
- package/{memberThunks-P2ECUJ56.js → memberThunks-5S5D3N4U.js} +20 -18
- package/{models-T3SG6MJ5.js → models-PQU25T6Q.js} +2 -2
- package/oauthTokenStore-ITEB663N.js +23 -0
- package/package.json +1 -1
- package/processSpawn-SOAV3FEV.js +11 -0
- package/profileConfig-ZGOFORWV.js +43 -0
- package/{providerPresetApply-FG6NZ57W.js → providerPresetApply-HAQWVAQX.js} +7 -7
- package/{providerRegistry-757OWH3O.js → providerRegistry-5FGWB3X5.js} +11 -7
- package/{read-COE3ZYR6.js → read-LSYFLSIM.js} +8 -7
- package/{readDocTool-5USN4A6V.js → readDocTool-XWRXV3DR.js} +5 -3
- package/{readlineWorkspace-XQRDGWRZ.js → readlineWorkspace-J3YD3DNW.js} +2596 -2032
- package/{removeDialogAgentAction-J6X5QMTA.js → removeDialogAgentAction-4TEFC3VL.js} +22 -26
- package/{runAgentClientLoop-5ZA62FBA.js → runAgentClientLoop-APSMCLAF.js} +79 -72
- package/{runtimeDoctorCommands-X6WDBEQX.js → runtimeDoctorCommands-PIVSBZRZ.js} +4 -4
- package/runtimeModeArgs-2Y7BALTO.js +31 -0
- package/{setDialogExtraReferencesAction-WX5VTY6O.js → setDialogExtraReferencesAction-LSEN44OY.js} +16 -14
- package/{setPrimaryDialogAgentAction-FN22THHT.js → setPrimaryDialogAgentAction-SR366X5A.js} +23 -27
- package/{chunk-GP5LKBUZ.js → settingThunks-CTVPPGIN.js} +226 -940
- package/{skillDiscovery-CYUCJMAG.js → skillDiscovery-ZBU76COE.js} +3 -3
- package/{slateUtils-RIZES3PV.js → slateUtils-NGV2NMKM.js} +1 -1
- package/{spaceCommands-5GLCWZPO.js → spaceCommands-3UK63WPE.js} +51 -47
- package/{streamAgentChatTurn-6UZJMYRB.js → streamAgentChatTurn-DNY2PSRW.js} +215 -115
- package/{switchDialogAgentAction-LVTEV3FR.js → switchDialogAgentAction-M6NAFOOU.js} +19 -20
- package/{tableCommands-O6NWHFKV.js → tableCommands-6U4BMLRR.js} +10 -10
- package/{toolApiClient-QVJ6HDNN.js → toolApiClient-AD7CXTA4.js} +4 -3
- package/tools-X5UWATZK.js +117 -0
- package/{tuiSummaryLlmCaller-OHHFTHMG.js → tuiSummaryLlmCaller-DEH7ZEM6.js} +25 -23
- package/{updateCommands-2M74UL7P.js → updateCommands-4EHDLF5J.js} +3 -3
- package/{updateDialogTitleAction-QTKNIURB.js → updateDialogTitleAction-YSY5BF5A.js} +84 -45
- package/action-P4TNFGAD.js +0 -31
- package/agentListCommands-B2V4YAC4.js +0 -410
- package/agentRecordCommands-G4KK4R7H.js +0 -128
- package/agentRunCommand-UTZJA23G.js +0 -156
- package/browser-image-compression-MFDTD7K6.js +0 -1763
- package/chatQueueReduxAdapter-2P6NFX64.js +0 -186
- package/chunk-CQ3WA2NE.js +0 -299
- package/chunk-M76ECQRD.js +0 -13658
- package/chunk-MEYIRKDN.js +0 -8967
- package/chunk-PUOC4YRO.js +0 -394
- package/chunk-Q5FJJ6XI.js +0 -103
- package/chunk-S7Z2HMCN.js +0 -25
- package/chunk-T75QD6AB.js +0 -20923
- package/chunk-Y5GCAMGP.js +0 -9
- package/chunk-YPREESF4.js +0 -225
- package/createDialogAction-NGG7YVNU.js +0 -65
- package/machineWsRunDispatch-ISBKOOD7.js +0 -144
- package/settingSlice-P4ZW7K5X.js +0 -204
- package/syncMapping-N6RGXGBW.js +0 -437
- package/tools-KMGFWO43.js +0 -110
- 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-N4NGJDT6.js";
|
|
1
6
|
import {
|
|
2
7
|
applyChatCompletionDelta,
|
|
3
8
|
applyResponsesToolEvent,
|
|
@@ -5,13 +10,15 @@ import {
|
|
|
5
10
|
finalizeResponsesToolCalls,
|
|
6
11
|
flushChatCompletionStream,
|
|
7
12
|
providerHttpFailure,
|
|
8
|
-
readSseFrames,
|
|
9
|
-
streamSseDataValues,
|
|
10
13
|
throwIfChatCompletionStreamFailed
|
|
11
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-FHLMQIU7.js";
|
|
12
15
|
import {
|
|
13
|
-
|
|
14
|
-
} from "./chunk-
|
|
16
|
+
readSseFrames
|
|
17
|
+
} from "./chunk-GMZLP5DV.js";
|
|
18
|
+
import {
|
|
19
|
+
evaluateFileWritePolicy,
|
|
20
|
+
summarizeToolArguments
|
|
21
|
+
} from "./chunk-CHOZJMJS.js";
|
|
15
22
|
import {
|
|
16
23
|
clipToolText,
|
|
17
24
|
hasImageInRuntimeMessages,
|
|
@@ -20,13 +27,7 @@ import {
|
|
|
20
27
|
resolveHistoricalToolContentCap,
|
|
21
28
|
resolveToolOutputProfile,
|
|
22
29
|
stripImagePartsFromMessages
|
|
23
|
-
} from "./chunk-
|
|
24
|
-
import {
|
|
25
|
-
downgradeUnparsableToolCalls,
|
|
26
|
-
hasParsableObjectArguments,
|
|
27
|
-
repairTruncatedToolArguments,
|
|
28
|
-
sanitizeForOutbound
|
|
29
|
-
} from "./chunk-CQ3WA2NE.js";
|
|
30
|
+
} from "./chunk-6MAW4XOF.js";
|
|
30
31
|
import {
|
|
31
32
|
createThinkParserState,
|
|
32
33
|
createToolCallAccumulator,
|
|
@@ -35,6 +36,7 @@ import {
|
|
|
35
36
|
finalizeAccumulatedToolCalls
|
|
36
37
|
} from "./chunk-N7J63Q6C.js";
|
|
37
38
|
import {
|
|
39
|
+
DELETE_SAFETY_RED_LINE,
|
|
38
40
|
TOOL_GUIDED_SECTION_ORDER,
|
|
39
41
|
buildIdentityBlock,
|
|
40
42
|
buildRuntimeGuidanceBlocks,
|
|
@@ -46,17 +48,22 @@ import {
|
|
|
46
48
|
requiresBareImageUrl,
|
|
47
49
|
resolveToolGuidedSections,
|
|
48
50
|
toBareImageUrlMessages
|
|
49
|
-
} from "./chunk-
|
|
51
|
+
} from "./chunk-LBFL6RZG.js";
|
|
50
52
|
import {
|
|
51
53
|
convertMessagesToResponsesInput,
|
|
54
|
+
downgradeUnparsableToolCalls,
|
|
52
55
|
extractReasoningFromResponseOutput,
|
|
53
56
|
extractTextFromResponseOutput,
|
|
54
57
|
extractToolCallsFromResponseOutput,
|
|
55
58
|
getUsageRequestOptions,
|
|
59
|
+
hasParsableObjectArguments,
|
|
60
|
+
repairTruncatedToolArguments,
|
|
61
|
+
sanitizeForOutbound,
|
|
62
|
+
shouldReplayReasoningContentForOutbound,
|
|
56
63
|
shouldStripReasoningContentForOutbound,
|
|
57
64
|
toOpenAiCompatibleMessages,
|
|
58
65
|
toResponsesTools
|
|
59
|
-
} from "./chunk-
|
|
66
|
+
} from "./chunk-UM7TA3K4.js";
|
|
60
67
|
import {
|
|
61
68
|
BRIDGE_STREAM_MAX_CHARS,
|
|
62
69
|
DEFAULT_READ_DIALOG_MAX_RESPONSE_CHARS,
|
|
@@ -71,16 +78,7 @@ import {
|
|
|
71
78
|
parseNoloWorkspaceToolArguments,
|
|
72
79
|
readTextStreamUpToChars,
|
|
73
80
|
resolveNoloDialogInput
|
|
74
|
-
} from "./chunk-
|
|
75
|
-
import {
|
|
76
|
-
getAntigravityUserAgent,
|
|
77
|
-
readAntigravityProjectId,
|
|
78
|
-
resolveAntigravityCloudCodeBaseUrl
|
|
79
|
-
} from "./chunk-UZGQNTVW.js";
|
|
80
|
-
import {
|
|
81
|
-
buildProviderAuthHeaders,
|
|
82
|
-
buildProviderExecutionPlan
|
|
83
|
-
} from "./chunk-6OZ36FXI.js";
|
|
81
|
+
} from "./chunk-SJKULPGX.js";
|
|
84
82
|
import {
|
|
85
83
|
buildDialogFallbackTitleFromUserInput
|
|
86
84
|
} from "./chunk-2MBTWINN.js";
|
|
@@ -94,13 +92,12 @@ import {
|
|
|
94
92
|
resolveEmptyAssistantFallbackMessage,
|
|
95
93
|
resolveEmptyAssistantOutcome,
|
|
96
94
|
resolveTruncatedReasoningTailLog
|
|
97
|
-
} from "./chunk-
|
|
95
|
+
} from "./chunk-ECFHBYUW.js";
|
|
98
96
|
import {
|
|
99
97
|
COMPACTION_SUMMARY_SCHEMA_VERSION,
|
|
100
98
|
COMPACTION_SUMMARY_SYSTEM_PROMPT,
|
|
101
99
|
buildCompactionMetricsFromPlan,
|
|
102
100
|
buildCompactionUserContent,
|
|
103
|
-
clipCompactText,
|
|
104
101
|
createProviderCallTimingTracker,
|
|
105
102
|
finalizeProviderCallTiming,
|
|
106
103
|
formatCompactionMetricsLog,
|
|
@@ -113,37 +110,36 @@ import {
|
|
|
113
110
|
resolveCompressionTriggerRatio,
|
|
114
111
|
truncateToolOutputForContext,
|
|
115
112
|
withProviderCallTimingFields
|
|
116
|
-
} from "./chunk-
|
|
113
|
+
} from "./chunk-R6EBQEQE.js";
|
|
114
|
+
import {
|
|
115
|
+
clipCompactText
|
|
116
|
+
} from "./chunk-5MMAK75Q.js";
|
|
117
|
+
import {
|
|
118
|
+
asRecordOrEmpty
|
|
119
|
+
} from "./chunk-KX6YBIHG.js";
|
|
117
120
|
import {
|
|
118
121
|
estimateTokenCount
|
|
119
122
|
} from "./chunk-PSCNXBYA.js";
|
|
120
123
|
import {
|
|
121
124
|
resolveNoloStateDir
|
|
122
|
-
} from "./chunk-
|
|
123
|
-
import {
|
|
124
|
-
toErrorMessage
|
|
125
|
-
} from "./chunk-HNMXYYJR.js";
|
|
125
|
+
} from "./chunk-HNGRBWYF.js";
|
|
126
126
|
import {
|
|
127
127
|
buildDialogSummaryLayer
|
|
128
|
-
} from "./chunk-
|
|
128
|
+
} from "./chunk-HDLLCBRF.js";
|
|
129
129
|
import {
|
|
130
130
|
buildUserResponseLanguageContext
|
|
131
|
-
} from "./chunk-
|
|
131
|
+
} from "./chunk-4VJAC32I.js";
|
|
132
132
|
import {
|
|
133
133
|
canonicalizeToolName,
|
|
134
134
|
canonicalizeToolNames
|
|
135
|
-
} from "./chunk-
|
|
135
|
+
} from "./chunk-IHPDK6UD.js";
|
|
136
136
|
import {
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
asTrimmedNonEmptyStringArray,
|
|
141
|
-
dialogMessageKey,
|
|
142
|
-
dialogMessageRange
|
|
143
|
-
} from "./chunk-VMFTFOWF.js";
|
|
137
|
+
buildProviderAuthHeaders,
|
|
138
|
+
buildProviderExecutionPlan
|
|
139
|
+
} from "./chunk-BIPGGSJS.js";
|
|
144
140
|
import {
|
|
145
|
-
|
|
146
|
-
} from "./chunk-
|
|
141
|
+
toErrorMessage
|
|
142
|
+
} from "./chunk-HNMXYYJR.js";
|
|
147
143
|
import {
|
|
148
144
|
asTrimmedLowercaseString
|
|
149
145
|
} from "./chunk-QSJ3HFEF.js";
|
|
@@ -151,11 +147,19 @@ import {
|
|
|
151
147
|
isRecord
|
|
152
148
|
} from "./chunk-KUG52IAP.js";
|
|
153
149
|
import {
|
|
154
|
-
|
|
155
|
-
|
|
150
|
+
asTrimmedNonEmptyStringArray,
|
|
151
|
+
dialogMessageKey,
|
|
152
|
+
dialogMessageRange
|
|
153
|
+
} from "./chunk-OKGVNZTL.js";
|
|
154
|
+
import {
|
|
155
|
+
asOptionalFiniteNumber
|
|
156
|
+
} from "./chunk-WWC7I6TA.js";
|
|
156
157
|
import {
|
|
157
158
|
asOptionalPositiveFiniteNumber
|
|
158
159
|
} from "./chunk-U6VC4MU4.js";
|
|
160
|
+
import {
|
|
161
|
+
asTrimmedString
|
|
162
|
+
} from "./chunk-3EUW3WEO.js";
|
|
159
163
|
import {
|
|
160
164
|
normalizeServerOrigin
|
|
161
165
|
} from "./chunk-CF7PE763.js";
|
|
@@ -11901,6 +11905,7 @@ var toQueue = /* @__PURE__ */ dual(2, (self, options) => toQueueArray(self.chann
|
|
|
11901
11905
|
var runIntoQueue = /* @__PURE__ */ dual(2, (self, queue) => runIntoQueueArray(self.channel, queue));
|
|
11902
11906
|
|
|
11903
11907
|
// packages/agent-runtime/abortableKernel.ts
|
|
11908
|
+
var IDLE_WATCHDOG_SLICES = 20;
|
|
11904
11909
|
function runAbortableWithTimeout(args2) {
|
|
11905
11910
|
const taskEffect = Effect_exports.callback(
|
|
11906
11911
|
(resume) => {
|
|
@@ -11936,12 +11941,26 @@ function runAbortableWithTimeout(args2) {
|
|
|
11936
11941
|
raced = Effect_exports.raceFirst(taskEffect, abortEffect);
|
|
11937
11942
|
}
|
|
11938
11943
|
if (typeof args2.timeoutMs === "number") {
|
|
11939
|
-
const
|
|
11944
|
+
const outer = raced;
|
|
11940
11945
|
const timeoutMs = args2.timeoutMs;
|
|
11941
|
-
|
|
11942
|
-
|
|
11943
|
-
|
|
11946
|
+
const activityVersion = args2.activityVersion;
|
|
11947
|
+
const idleWatchdog = Effect_exports.gen(function* () {
|
|
11948
|
+
const sliceCount = activityVersion ? IDLE_WATCHDOG_SLICES : 1;
|
|
11949
|
+
const baseSliceMs = Math.max(1, Math.floor(timeoutMs / sliceCount));
|
|
11950
|
+
let idleMs = 0;
|
|
11951
|
+
for (; ; ) {
|
|
11952
|
+
const versionAtSliceStart = activityVersion?.();
|
|
11953
|
+
const sliceMs = Math.max(1, Math.min(timeoutMs - idleMs, baseSliceMs));
|
|
11954
|
+
yield* Effect_exports.sleep(Duration_exports.millis(sliceMs));
|
|
11955
|
+
idleMs += sliceMs;
|
|
11956
|
+
if (activityVersion && activityVersion() !== versionAtSliceStart) {
|
|
11957
|
+
idleMs = 0;
|
|
11958
|
+
continue;
|
|
11959
|
+
}
|
|
11960
|
+
if (idleMs >= timeoutMs) return { kind: "timeout" };
|
|
11961
|
+
}
|
|
11944
11962
|
});
|
|
11963
|
+
raced = Effect_exports.raceFirst(outer, idleWatchdog);
|
|
11945
11964
|
}
|
|
11946
11965
|
return args2.runtime ? args2.runtime.runPromise(raced) : Effect_exports.runPromise(raced);
|
|
11947
11966
|
}
|
|
@@ -12040,26 +12059,6 @@ function createLocalLoopObservationBoundary(initialCallbacks) {
|
|
|
12040
12059
|
};
|
|
12041
12060
|
}
|
|
12042
12061
|
|
|
12043
|
-
// packages/agent-runtime/fileWritePolicy.ts
|
|
12044
|
-
function evaluateFileWritePolicy(args2) {
|
|
12045
|
-
if (args2.sessionApproved) return { permissionDecision: "allow" };
|
|
12046
|
-
return {
|
|
12047
|
-
permissionDecision: "ask",
|
|
12048
|
-
permissionRequest: {
|
|
12049
|
-
id: "permission-file-write-session",
|
|
12050
|
-
tool: args2.tool,
|
|
12051
|
-
action: "file_write",
|
|
12052
|
-
title: "\u786E\u8BA4\u5199\u5165\u6587\u4EF6",
|
|
12053
|
-
body: `\u672C\u4F1A\u8BDD\u9996\u6B21\u5199\u5165\u6587\u4EF6\uFF1A${args2.path}\u3002\u6279\u51C6\u540E\u672C\u4F1A\u8BDD\u540E\u7EED\u5199\u5165\u4E0D\u518D\u9010\u6B21\u786E\u8BA4\u3002`,
|
|
12054
|
-
command: args2.path,
|
|
12055
|
-
suggestedRule: {
|
|
12056
|
-
scope: "session",
|
|
12057
|
-
pattern: { capability: "file_write", target: "session" }
|
|
12058
|
-
}
|
|
12059
|
-
}
|
|
12060
|
-
};
|
|
12061
|
-
}
|
|
12062
|
-
|
|
12063
12062
|
// packages/agent-runtime/toolCallPairing.ts
|
|
12064
12063
|
function readToolCallId(message) {
|
|
12065
12064
|
if (typeof message.tool_call_id === "string" && message.tool_call_id) {
|
|
@@ -12161,50 +12160,6 @@ function sanitizeToolCallPairing(messages) {
|
|
|
12161
12160
|
return output;
|
|
12162
12161
|
}
|
|
12163
12162
|
|
|
12164
|
-
// packages/agent-runtime/parseToolArguments.ts
|
|
12165
|
-
function parseToolArgumentsJson(raw) {
|
|
12166
|
-
if (!raw?.trim()) return {};
|
|
12167
|
-
try {
|
|
12168
|
-
return asRecordOrEmpty(JSON.parse(raw));
|
|
12169
|
-
} catch {
|
|
12170
|
-
return {};
|
|
12171
|
-
}
|
|
12172
|
-
}
|
|
12173
|
-
|
|
12174
|
-
// packages/agent-runtime/summarizeToolArguments.ts
|
|
12175
|
-
function clip(value, max4 = 240) {
|
|
12176
|
-
return clipCompactText(value, max4);
|
|
12177
|
-
}
|
|
12178
|
-
function summarizeToolArguments(toolName, rawArgs) {
|
|
12179
|
-
const args2 = parseToolArgumentsJson(rawArgs);
|
|
12180
|
-
const pick = (...keys3) => {
|
|
12181
|
-
for (const key of keys3) {
|
|
12182
|
-
const value = asOptionalTrimmedString(args2[key]);
|
|
12183
|
-
if (value) return value;
|
|
12184
|
-
}
|
|
12185
|
-
return "";
|
|
12186
|
-
};
|
|
12187
|
-
const command = pick("command", "cmd", "runCommand", "executeCommand", "bash");
|
|
12188
|
-
if (command) return clip(command);
|
|
12189
|
-
const query = pick("query", "pattern", "search", "q");
|
|
12190
|
-
if (query) return clip(query);
|
|
12191
|
-
const filePath = pick("filePath", "file_path", "path", "filename", "file");
|
|
12192
|
-
if (filePath) return clip(filePath);
|
|
12193
|
-
const keys2 = Object.keys(args2);
|
|
12194
|
-
if (keys2.length === 0) return "";
|
|
12195
|
-
return clip(
|
|
12196
|
-
keys2.slice(0, 6).map((key) => {
|
|
12197
|
-
const value = args2[key];
|
|
12198
|
-
if (typeof value === "string") return `${key}=${clip(value, 80)}`;
|
|
12199
|
-
if (typeof value === "number" || typeof value === "boolean") {
|
|
12200
|
-
return `${key}=${String(value)}`;
|
|
12201
|
-
}
|
|
12202
|
-
if (Array.isArray(value)) return `${key}[${value.length}]`;
|
|
12203
|
-
return `${key}=${value === null ? "null" : typeof value}`;
|
|
12204
|
-
}).join(" ")
|
|
12205
|
-
);
|
|
12206
|
-
}
|
|
12207
|
-
|
|
12208
12163
|
// packages/agent-runtime/progressGuard.ts
|
|
12209
12164
|
var DEFAULT_MAX_CONSECUTIVE_IDENTICAL_ROUNDS = 5;
|
|
12210
12165
|
var DEFAULT_MAX_CONSECUTIVE_STAGNANT_TOOL_ROUNDS = 8;
|
|
@@ -12560,7 +12515,7 @@ function formatToolOverflowMarker(args2) {
|
|
|
12560
12515
|
}
|
|
12561
12516
|
|
|
12562
12517
|
// packages/agent-runtime/localAutoCompaction.ts
|
|
12563
|
-
import { createHash as createHash2 } from "node:crypto";
|
|
12518
|
+
import { createHash as createHash2, randomUUID } from "node:crypto";
|
|
12564
12519
|
function toPlanCompressionMessages(history) {
|
|
12565
12520
|
return history.map((message, index) => ({
|
|
12566
12521
|
id: `local-${index}`,
|
|
@@ -12628,6 +12583,13 @@ function isColdResume(history, nowMs) {
|
|
|
12628
12583
|
}
|
|
12629
12584
|
async function maybeAutoCompactLocalHistory(args2) {
|
|
12630
12585
|
const { adapter, dialogId, history } = args2;
|
|
12586
|
+
const emitPhase = (phase) => {
|
|
12587
|
+
try {
|
|
12588
|
+
args2.onPhase?.(phase);
|
|
12589
|
+
} catch {
|
|
12590
|
+
}
|
|
12591
|
+
};
|
|
12592
|
+
emitPhase({ kind: "validating-context" });
|
|
12631
12593
|
const unchanged = (decision) => ({
|
|
12632
12594
|
history,
|
|
12633
12595
|
compressed: false,
|
|
@@ -12723,8 +12685,46 @@ async function maybeAutoCompactLocalHistory(args2) {
|
|
|
12723
12685
|
if (!plan.shouldCompress) {
|
|
12724
12686
|
return projectExisting();
|
|
12725
12687
|
}
|
|
12688
|
+
emitPhase({ kind: "compaction-start" });
|
|
12689
|
+
const compactionAttemptId = randomUUID();
|
|
12690
|
+
let compactionT0 = Date.now();
|
|
12691
|
+
let compactionInputTokens;
|
|
12692
|
+
let compactionPrevSummaryTokens;
|
|
12693
|
+
let compactionInputSource;
|
|
12694
|
+
let compactionPrevSummarySource;
|
|
12695
|
+
let primaryElapsedMs;
|
|
12696
|
+
let saveElapsedMs;
|
|
12697
|
+
const logCompactionTiming = (outcome, fields) => {
|
|
12698
|
+
if (compactionInputTokens === void 0 && compactionInputSource !== void 0) {
|
|
12699
|
+
compactionInputTokens = estimateTokenCount(compactionInputSource);
|
|
12700
|
+
}
|
|
12701
|
+
if (compactionPrevSummaryTokens === void 0 && compactionPrevSummarySource !== void 0) {
|
|
12702
|
+
compactionPrevSummaryTokens = estimateTokenCount(compactionPrevSummarySource);
|
|
12703
|
+
}
|
|
12704
|
+
console.log(
|
|
12705
|
+
`[compaction-timing] ${JSON.stringify({
|
|
12706
|
+
attemptId: compactionAttemptId,
|
|
12707
|
+
model: fields.model ?? args2.model ?? null,
|
|
12708
|
+
inputTokens: compactionInputTokens ?? null,
|
|
12709
|
+
prevSummaryTokens: compactionPrevSummaryTokens ?? null,
|
|
12710
|
+
outputChars: fields.outputChars ?? null,
|
|
12711
|
+
elapsedMs: Date.now() - compactionT0,
|
|
12712
|
+
primaryElapsedMs: primaryElapsedMs ?? null,
|
|
12713
|
+
// main 无 fallback 通道,保留该字段以兼容日志 schema。
|
|
12714
|
+
fallbackElapsedMs: null,
|
|
12715
|
+
saveElapsedMs: saveElapsedMs ?? null,
|
|
12716
|
+
outcome
|
|
12717
|
+
})}`
|
|
12718
|
+
);
|
|
12719
|
+
};
|
|
12726
12720
|
try {
|
|
12721
|
+
if (args2.abortSignal?.aborted) {
|
|
12722
|
+
throw Object.assign(new Error("auto-compaction aborted"), { compactionReason: "aborted" });
|
|
12723
|
+
}
|
|
12727
12724
|
const provider = await args2.resolveProvider();
|
|
12725
|
+
if (args2.abortSignal?.aborted) {
|
|
12726
|
+
throw Object.assign(new Error("auto-compaction aborted"), { compactionReason: "aborted" });
|
|
12727
|
+
}
|
|
12728
12728
|
const msgsToCompress = plan.msgsToCompress;
|
|
12729
12729
|
const messagesText = formatMessagesForSummaryWithTruncation(msgsToCompress);
|
|
12730
12730
|
const fileOpsText = formatFileOperationsFromMessages(
|
|
@@ -12736,24 +12736,71 @@ async function maybeAutoCompactLocalHistory(args2) {
|
|
|
12736
12736
|
messagesText,
|
|
12737
12737
|
fileOpsText
|
|
12738
12738
|
});
|
|
12739
|
-
|
|
12740
|
-
|
|
12741
|
-
|
|
12742
|
-
|
|
12739
|
+
emitPhase({ kind: "waiting-provider" });
|
|
12740
|
+
compactionInputSource = messagesText;
|
|
12741
|
+
compactionPrevSummarySource = existingSummary;
|
|
12742
|
+
compactionT0 = Date.now();
|
|
12743
|
+
const timeoutMs = typeof args2.timeoutMs === "number" && Number.isFinite(args2.timeoutMs) && args2.timeoutMs > 0 ? args2.timeoutMs : void 0;
|
|
12744
|
+
const requestController = new AbortController();
|
|
12745
|
+
let timeoutHandle;
|
|
12746
|
+
let abortListener;
|
|
12747
|
+
const request3 = provider.complete(
|
|
12748
|
+
[{ role: "system", content: COMPACTION_SUMMARY_SYSTEM_PROMPT }, { role: "user", content: promptContent }],
|
|
12749
|
+
{
|
|
12750
|
+
signal: requestController.signal,
|
|
12751
|
+
...timeoutMs ? { timeoutMs } : {},
|
|
12752
|
+
// 仅日志用的 attempt id:让 compaction 埋点与 transport 诊断日志 /
|
|
12753
|
+
// 服务端 x-request-id 可对上,用于关联请求级证据。不进 prompt/摘要/持久化。
|
|
12754
|
+
requestId: compactionAttemptId
|
|
12755
|
+
}
|
|
12756
|
+
).then(
|
|
12757
|
+
(value) => ({ kind: "done", value }),
|
|
12758
|
+
(error) => ({ kind: "provider-error", error })
|
|
12759
|
+
);
|
|
12760
|
+
const guards = [];
|
|
12761
|
+
if (timeoutMs) guards.push(new Promise((resolve5) => {
|
|
12762
|
+
timeoutHandle = setTimeout(() => {
|
|
12763
|
+
requestController.abort();
|
|
12764
|
+
resolve5({ kind: "timeout" });
|
|
12765
|
+
}, timeoutMs);
|
|
12766
|
+
}));
|
|
12767
|
+
if (args2.abortSignal) guards.push(new Promise((resolve5) => {
|
|
12768
|
+
abortListener = () => {
|
|
12769
|
+
requestController.abort(args2.abortSignal?.reason);
|
|
12770
|
+
resolve5({ kind: "aborted" });
|
|
12771
|
+
};
|
|
12772
|
+
args2.abortSignal?.addEventListener("abort", abortListener, { once: true });
|
|
12773
|
+
}));
|
|
12774
|
+
const outcome = guards.length ? await Promise.race([request3, ...guards]) : await request3;
|
|
12775
|
+
primaryElapsedMs = Date.now() - compactionT0;
|
|
12776
|
+
if (timeoutHandle) clearTimeout(timeoutHandle);
|
|
12777
|
+
if (abortListener) args2.abortSignal?.removeEventListener("abort", abortListener);
|
|
12778
|
+
if (outcome.kind !== "done") {
|
|
12779
|
+
const reason = outcome.kind === "timeout" ? "timeout" : outcome.kind === "aborted" ? "aborted" : "provider-error";
|
|
12780
|
+
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";
|
|
12781
|
+
throw Object.assign(new Error(detail), { compactionReason: reason });
|
|
12782
|
+
}
|
|
12783
|
+
const result4 = outcome.value;
|
|
12743
12784
|
const newSummary = typeof result4.content === "string" ? result4.content.trim() : "";
|
|
12744
12785
|
if (!newSummary) {
|
|
12745
12786
|
console.warn(
|
|
12746
12787
|
"[localLoop] auto-compaction produced empty summary; keeping prior projection"
|
|
12747
12788
|
);
|
|
12789
|
+
logCompactionTiming("empty", {});
|
|
12790
|
+
const failureReason = "provider-error";
|
|
12791
|
+
emitPhase({ kind: "compaction-failed", reason: failureReason });
|
|
12748
12792
|
return {
|
|
12749
12793
|
...projectExisting(),
|
|
12750
12794
|
failureMessage: "summary model returned empty content",
|
|
12795
|
+
failureReason,
|
|
12751
12796
|
decision: {
|
|
12752
12797
|
outcome: "failed",
|
|
12798
|
+
reason: failureReason,
|
|
12753
12799
|
detail: "summary model returned empty content"
|
|
12754
12800
|
}
|
|
12755
12801
|
};
|
|
12756
12802
|
}
|
|
12803
|
+
const saveT0 = Date.now();
|
|
12757
12804
|
await adapter.saveDialogSummary({
|
|
12758
12805
|
dialogId,
|
|
12759
12806
|
summary: newSummary,
|
|
@@ -12767,6 +12814,7 @@ async function maybeAutoCompactLocalHistory(args2) {
|
|
|
12767
12814
|
})(),
|
|
12768
12815
|
schemaVersion: COMPACTION_SUMMARY_SCHEMA_VERSION
|
|
12769
12816
|
});
|
|
12817
|
+
saveElapsedMs = Date.now() - saveT0;
|
|
12770
12818
|
const metricsReason = invalidSummary ? "invalid_summary" : coldResume ? "cold_resume" : "context_budget";
|
|
12771
12819
|
const metrics = buildCompactionMetricsFromPlan({
|
|
12772
12820
|
reason: metricsReason,
|
|
@@ -12776,6 +12824,11 @@ async function maybeAutoCompactLocalHistory(args2) {
|
|
|
12776
12824
|
summaryUsage: result4.usage
|
|
12777
12825
|
});
|
|
12778
12826
|
console.log(formatCompactionMetricsLog(metrics));
|
|
12827
|
+
logCompactionTiming("success", {
|
|
12828
|
+
model: result4?.model ?? args2.model ?? null,
|
|
12829
|
+
outputChars: newSummary.length
|
|
12830
|
+
});
|
|
12831
|
+
emitPhase({ kind: "compaction-end" });
|
|
12779
12832
|
return {
|
|
12780
12833
|
history: projectHistoryWithSummary({
|
|
12781
12834
|
history,
|
|
@@ -12803,10 +12856,14 @@ async function maybeAutoCompactLocalHistory(args2) {
|
|
|
12803
12856
|
} catch (error) {
|
|
12804
12857
|
console.warn("[localLoop] auto-compaction failed:", error);
|
|
12805
12858
|
const failureMessage = error instanceof Error && error.message ? error.message.slice(0, 200) : String(error).slice(0, 200);
|
|
12859
|
+
const failureReason = error instanceof Error && "compactionReason" in error ? error.compactionReason : "provider-error";
|
|
12860
|
+
logCompactionTiming(failureReason, {});
|
|
12861
|
+
emitPhase({ kind: "compaction-failed", reason: failureReason });
|
|
12806
12862
|
return {
|
|
12807
12863
|
...projectExisting(),
|
|
12808
12864
|
failureMessage,
|
|
12809
|
-
|
|
12865
|
+
failureReason,
|
|
12866
|
+
decision: { outcome: "failed", reason: failureReason, detail: failureMessage }
|
|
12810
12867
|
};
|
|
12811
12868
|
}
|
|
12812
12869
|
}
|
|
@@ -12863,6 +12920,8 @@ function emitLoopEvent(boundary, event, bridge) {
|
|
|
12863
12920
|
boundary.emit(bridge ? { event, bridge } : { event });
|
|
12864
12921
|
}
|
|
12865
12922
|
var LLM_REQUEST_TIMEOUT = "LLM_REQUEST_TIMEOUT";
|
|
12923
|
+
var DEFAULT_LLM_REQUEST_TIMEOUT_MS = 10 * 60 * 1e3;
|
|
12924
|
+
var DEFAULT_COMPACTION_TIMEOUT_MS = 60 * 1e3;
|
|
12866
12925
|
var LOCAL_TURN_ABORTED_CODE = "LOCAL_TURN_ABORTED";
|
|
12867
12926
|
function buildAbortedError() {
|
|
12868
12927
|
const error = new Error("local agent turn aborted by user");
|
|
@@ -12890,8 +12949,11 @@ async function runAbortableToolTask(input, task, pendingToolName) {
|
|
|
12890
12949
|
}
|
|
12891
12950
|
function resolveLlmRequestTimeoutMs(input) {
|
|
12892
12951
|
const raw = input.llmRequestTimeoutMs ?? input.timeoutMs;
|
|
12893
|
-
|
|
12894
|
-
|
|
12952
|
+
return typeof raw === "number" && Number.isFinite(raw) && raw > 0 ? raw : DEFAULT_LLM_REQUEST_TIMEOUT_MS;
|
|
12953
|
+
}
|
|
12954
|
+
function resolveCompactionTimeoutMs(input) {
|
|
12955
|
+
const raw = input.compactionTimeoutMs;
|
|
12956
|
+
return typeof raw === "number" && Number.isFinite(raw) && raw > 0 ? raw : DEFAULT_COMPACTION_TIMEOUT_MS;
|
|
12895
12957
|
}
|
|
12896
12958
|
async function runCompleteWithTimeout(args2) {
|
|
12897
12959
|
const { provider, messages, options, timeoutMs, round, input, boundary, context: context3, providerName, model } = args2;
|
|
@@ -12914,6 +12976,7 @@ async function runCompleteWithTimeout(args2) {
|
|
|
12914
12976
|
const outcome = await runAbortableWithTimeout({
|
|
12915
12977
|
task: complete,
|
|
12916
12978
|
timeoutMs: typeof timeoutMs === "number" ? timeoutMs : void 0,
|
|
12979
|
+
activityVersion: args2.activityVersion,
|
|
12917
12980
|
abortSignal: input.abortSignal,
|
|
12918
12981
|
runtime: input.effectRuntime
|
|
12919
12982
|
});
|
|
@@ -12924,7 +12987,7 @@ async function runCompleteWithTimeout(args2) {
|
|
|
12924
12987
|
}
|
|
12925
12988
|
if (outcome.kind === "timeout") {
|
|
12926
12989
|
const timeoutError = new Error(
|
|
12927
|
-
`LLM request timed out after ${timeoutMs}ms (round ${round})`
|
|
12990
|
+
`LLM request timed out after ${timeoutMs}ms without new output (idle window, round ${round})`
|
|
12928
12991
|
);
|
|
12929
12992
|
timeoutError.code = LLM_REQUEST_TIMEOUT;
|
|
12930
12993
|
throw timeoutError;
|
|
@@ -12968,16 +13031,16 @@ async function runCompleteWithTimeout(args2) {
|
|
|
12968
13031
|
});
|
|
12969
13032
|
}
|
|
12970
13033
|
}
|
|
12971
|
-
function
|
|
13034
|
+
function clip(value, max4 = 240) {
|
|
12972
13035
|
return clipCompactText(value, max4);
|
|
12973
13036
|
}
|
|
12974
13037
|
function projectSafeToolObservationMetadata(metadata) {
|
|
12975
13038
|
if (!metadata || typeof metadata !== "object") return void 0;
|
|
12976
13039
|
const safe = {};
|
|
12977
13040
|
if (typeof metadata.exitCode === "number") safe.exitCode = metadata.exitCode;
|
|
12978
|
-
if (typeof metadata.actionGate === "string") safe.actionGate =
|
|
12979
|
-
if (typeof metadata.command === "string") safe.command =
|
|
12980
|
-
if (typeof metadata.path === "string") safe.path =
|
|
13041
|
+
if (typeof metadata.actionGate === "string") safe.actionGate = clip(metadata.actionGate, 240);
|
|
13042
|
+
if (typeof metadata.command === "string") safe.command = clip(metadata.command, 240);
|
|
13043
|
+
if (typeof metadata.path === "string") safe.path = clip(metadata.path, 240);
|
|
12981
13044
|
if (typeof metadata.truncated === "boolean") safe.truncated = metadata.truncated;
|
|
12982
13045
|
if (typeof metadata.byteCount === "number") safe.byteCount = metadata.byteCount;
|
|
12983
13046
|
if (typeof metadata.lineCount === "number") safe.lineCount = metadata.lineCount;
|
|
@@ -12993,7 +13056,7 @@ function summarizeToolResult(content, metadata) {
|
|
|
12993
13056
|
const lines = trimmed.split(/\r?\n/).length;
|
|
12994
13057
|
parts2.push(`${lines} line${lines === 1 ? "" : "s"}`);
|
|
12995
13058
|
parts2.push(`${trimmed.length} chars`);
|
|
12996
|
-
const tail =
|
|
13059
|
+
const tail = clip(trimmed.slice(-160), 160);
|
|
12997
13060
|
if (tail) parts2.push(`tail="${tail}"`);
|
|
12998
13061
|
} else {
|
|
12999
13062
|
parts2.push("empty");
|
|
@@ -13605,6 +13668,9 @@ async function runLocalAgentTurn(input) {
|
|
|
13605
13668
|
input.contextBlockScopes
|
|
13606
13669
|
);
|
|
13607
13670
|
const mergedContextBlockScopes = [
|
|
13671
|
+
// 删除安全红线:系统层最高优先级约束,位于所有块之前(含身份信息块),
|
|
13672
|
+
// owner 要求常驻「根本提示词」的最顶部(2026-09-26 批量误删事故)。
|
|
13673
|
+
{ content: DELETE_SAFETY_RED_LINE, cacheScope: "session" },
|
|
13608
13674
|
{ content: identityBlock, cacheScope: "session" },
|
|
13609
13675
|
...guidanceScopes,
|
|
13610
13676
|
...callerScopes
|
|
@@ -13637,6 +13703,16 @@ async function runLocalAgentTurn(input) {
|
|
|
13637
13703
|
}
|
|
13638
13704
|
}
|
|
13639
13705
|
let compactionUsage;
|
|
13706
|
+
const emitCompactionPhase = (phase, scope3) => {
|
|
13707
|
+
const atMs = Date.now();
|
|
13708
|
+
if (phase.kind === "validating-context") emitLoopEvent(observationBoundary, { kind: "turn-phase", phase: "validating-context", atMs, compactionScope: scope3 });
|
|
13709
|
+
else if (phase.kind === "compaction-start") {
|
|
13710
|
+
emitLoopEvent(observationBoundary, { kind: "turn-phase", phase: "compacting", atMs, compactionScope: scope3 });
|
|
13711
|
+
emitLoopEvent(observationBoundary, { kind: "compaction-start", atMs, scope: scope3 });
|
|
13712
|
+
} else if (phase.kind === "waiting-provider") emitLoopEvent(observationBoundary, { kind: "turn-phase", phase: "waiting-provider", atMs, compactionScope: scope3 });
|
|
13713
|
+
else if (phase.kind === "compaction-end") emitLoopEvent(observationBoundary, { kind: "compaction-end", atMs, scope: scope3 });
|
|
13714
|
+
else emitLoopEvent(observationBoundary, { kind: "compaction-failed", atMs, scope: scope3, reason: phase.reason });
|
|
13715
|
+
};
|
|
13640
13716
|
const emitCompactionObservation = (compacted) => {
|
|
13641
13717
|
const decision = compacted.decision;
|
|
13642
13718
|
if (decision?.outcome === "skipped") {
|
|
@@ -13670,7 +13746,10 @@ async function runLocalAgentTurn(input) {
|
|
|
13670
13746
|
model: agentConfig.model,
|
|
13671
13747
|
resolveProvider: resolveProviderOnce,
|
|
13672
13748
|
contextWindow,
|
|
13673
|
-
realContextUsagePercent
|
|
13749
|
+
realContextUsagePercent,
|
|
13750
|
+
abortSignal: input.abortSignal,
|
|
13751
|
+
timeoutMs: resolveCompactionTimeoutMs(input),
|
|
13752
|
+
onPhase: (phase) => emitCompactionPhase(phase, "initial")
|
|
13674
13753
|
});
|
|
13675
13754
|
history = compacted.history;
|
|
13676
13755
|
compactionUsage = compacted.usage;
|
|
@@ -13776,7 +13855,10 @@ async function runLocalAgentTurn(input) {
|
|
|
13776
13855
|
model: agentConfig.model,
|
|
13777
13856
|
resolveProvider: resolveProviderOnce,
|
|
13778
13857
|
contextWindow,
|
|
13779
|
-
...ratio !== void 0 ? { realContextUsagePercent: ratio } : {}
|
|
13858
|
+
...ratio !== void 0 ? { realContextUsagePercent: ratio } : {},
|
|
13859
|
+
abortSignal: input.abortSignal,
|
|
13860
|
+
timeoutMs: resolveCompactionTimeoutMs(input),
|
|
13861
|
+
onPhase: (phase) => emitCompactionPhase(phase, "in-loop")
|
|
13780
13862
|
});
|
|
13781
13863
|
if (compacted.usage) {
|
|
13782
13864
|
compactionUsage = addOutOfBandUsage(compactionUsage, compacted.usage);
|
|
@@ -13846,11 +13928,12 @@ async function runLocalAgentTurn(input) {
|
|
|
13846
13928
|
const shouldPassToolEvents = Boolean(
|
|
13847
13929
|
input.onToolEvent || input.onObservationEvent || input.observationBoundary
|
|
13848
13930
|
);
|
|
13931
|
+
let llmStreamActivity = 0;
|
|
13849
13932
|
result4 = await runCompleteWithTimeout({
|
|
13850
13933
|
provider,
|
|
13851
13934
|
messages: requestMessages,
|
|
13852
13935
|
options: {
|
|
13853
|
-
|
|
13936
|
+
timeoutMs: resolveLlmRequestTimeoutMs(input),
|
|
13854
13937
|
// 用户取消信号穿进 provider options:providerStreamRetry 据此在
|
|
13855
13938
|
// 取消后跳过重试,provider 分支(如 antigravity/openai-compatible)
|
|
13856
13939
|
// 也可把 fetch 绑定到同一信号,实现真正的传输层取消。
|
|
@@ -13859,6 +13942,7 @@ async function runLocalAgentTurn(input) {
|
|
|
13859
13942
|
// 归到具体对话而不是 chat-proxy 兜底桶。新对话首轮 id 尚未分配。
|
|
13860
13943
|
...input.continueDialogId ? { dialogId: input.continueDialogId } : {},
|
|
13861
13944
|
...shouldStreamDeltas ? { onTextDelta: (chunk) => {
|
|
13945
|
+
llmStreamActivity += 1;
|
|
13862
13946
|
partialContent += chunk;
|
|
13863
13947
|
observationBoundary.emit({
|
|
13864
13948
|
kind: "text-delta",
|
|
@@ -13868,6 +13952,7 @@ async function runLocalAgentTurn(input) {
|
|
|
13868
13952
|
});
|
|
13869
13953
|
} } : {},
|
|
13870
13954
|
...shouldStreamReasoning ? { onReasoningDelta: (chunk) => {
|
|
13955
|
+
llmStreamActivity += 1;
|
|
13871
13956
|
observationBoundary.emit({
|
|
13872
13957
|
kind: "reasoning-delta",
|
|
13873
13958
|
chunk,
|
|
@@ -13876,6 +13961,7 @@ async function runLocalAgentTurn(input) {
|
|
|
13876
13961
|
});
|
|
13877
13962
|
} } : {},
|
|
13878
13963
|
...shouldPassToolEvents ? { onToolEvent: (event) => {
|
|
13964
|
+
llmStreamActivity += 1;
|
|
13879
13965
|
observationBoundary.emit({
|
|
13880
13966
|
kind: "tool-event",
|
|
13881
13967
|
event,
|
|
@@ -13886,6 +13972,7 @@ async function runLocalAgentTurn(input) {
|
|
|
13886
13972
|
...shouldPassToolEvents ? { toolEventRound: round } : {}
|
|
13887
13973
|
},
|
|
13888
13974
|
timeoutMs: resolveLlmRequestTimeoutMs(input),
|
|
13975
|
+
activityVersion: () => llmStreamActivity,
|
|
13889
13976
|
round,
|
|
13890
13977
|
input,
|
|
13891
13978
|
boundary: observationBoundary,
|
|
@@ -14357,33 +14444,6 @@ ${reasoningTailLog}
|
|
|
14357
14444
|
}
|
|
14358
14445
|
}
|
|
14359
14446
|
|
|
14360
|
-
// packages/agent-runtime/kimiUserAgent.ts
|
|
14361
|
-
var KIMI_CODE_CLI_VERSION = "0.29.2";
|
|
14362
|
-
var KIMI_CODE_USER_AGENT = `kimi-code-cli/${KIMI_CODE_CLI_VERSION} (nolo)`;
|
|
14363
|
-
function isKimiEndpoint(url) {
|
|
14364
|
-
return url.includes("api.kimi.com");
|
|
14365
|
-
}
|
|
14366
|
-
function kimiIdentityHeaders(url) {
|
|
14367
|
-
return isKimiEndpoint(url) ? { "User-Agent": KIMI_CODE_USER_AGENT } : {};
|
|
14368
|
-
}
|
|
14369
|
-
|
|
14370
|
-
// packages/agent-runtime/sseDataLine.ts
|
|
14371
|
-
function parseSseDataLineJson(line) {
|
|
14372
|
-
const trimmed = line.trim();
|
|
14373
|
-
if (!trimmed.startsWith("data:")) return null;
|
|
14374
|
-
const payload = trimmed.slice(5).trim();
|
|
14375
|
-
if (!payload || payload === "[DONE]") return null;
|
|
14376
|
-
try {
|
|
14377
|
-
return JSON.parse(payload);
|
|
14378
|
-
} catch {
|
|
14379
|
-
return null;
|
|
14380
|
-
}
|
|
14381
|
-
}
|
|
14382
|
-
function parseSseDataLineObject(line) {
|
|
14383
|
-
const parsed = parseSseDataLineJson(line);
|
|
14384
|
-
return parsed && typeof parsed === "object" ? parsed : null;
|
|
14385
|
-
}
|
|
14386
|
-
|
|
14387
14447
|
// packages/integrations/openai/responsesRequestBody.ts
|
|
14388
14448
|
function buildResponsesRequestBody(body, model) {
|
|
14389
14449
|
const tools = Array.isArray(body.tools) ? toResponsesTools(body.tools) : void 0;
|
|
@@ -14428,6 +14488,18 @@ function responsesStreamFailureStatus(failure) {
|
|
|
14428
14488
|
return 502;
|
|
14429
14489
|
}
|
|
14430
14490
|
var codexStreamFailureStatus = responsesStreamFailureStatus;
|
|
14491
|
+
function extractOutputTextFromItem(item) {
|
|
14492
|
+
const parts2 = item.content;
|
|
14493
|
+
if (!Array.isArray(parts2)) return "";
|
|
14494
|
+
return parts2.filter(
|
|
14495
|
+
(part) => !!part && typeof part === "object" && part.type === "output_text" && typeof part.text === "string"
|
|
14496
|
+
).map((part) => String(part.text)).join("");
|
|
14497
|
+
}
|
|
14498
|
+
function hasNumericTokenCount(u) {
|
|
14499
|
+
return ["input_tokens", "output_tokens", "prompt_tokens", "completion_tokens", "total_tokens"].some(
|
|
14500
|
+
(key) => typeof u[key] === "number" && Number.isFinite(u[key])
|
|
14501
|
+
);
|
|
14502
|
+
}
|
|
14431
14503
|
function createResponsesStreamCollector(callbacks) {
|
|
14432
14504
|
let content = "";
|
|
14433
14505
|
let reasoning = "";
|
|
@@ -14435,6 +14507,11 @@ function createResponsesStreamCollector(callbacks) {
|
|
|
14435
14507
|
let usage;
|
|
14436
14508
|
let failure;
|
|
14437
14509
|
let completedResponse;
|
|
14510
|
+
const requireResponseCompleted = callbacks?.requireResponseCompleted === true;
|
|
14511
|
+
const authoritativeCompletedTools = callbacks?.authoritativeCompletedTools === true;
|
|
14512
|
+
const failurePrefix = callbacks?.fallbackPrefix ?? "Responses";
|
|
14513
|
+
let sawTerminalSuccess = false;
|
|
14514
|
+
let sawTerminalEvent = false;
|
|
14438
14515
|
let sawMeaningfulDelta = false;
|
|
14439
14516
|
const observeMeaningfulOnce = () => {
|
|
14440
14517
|
if (sawMeaningfulDelta) return;
|
|
@@ -14442,18 +14519,38 @@ function createResponsesStreamCollector(callbacks) {
|
|
|
14442
14519
|
callbacks?.onMeaningfulDelta?.();
|
|
14443
14520
|
};
|
|
14444
14521
|
const processEvent = (ev) => {
|
|
14522
|
+
callbacks?.onEvent?.(ev);
|
|
14445
14523
|
if (isMeaningfulResponsesOutput(ev)) observeMeaningfulOnce();
|
|
14446
14524
|
const type = String(ev.type ?? "");
|
|
14447
14525
|
if (type === "error") {
|
|
14448
|
-
|
|
14526
|
+
sawTerminalEvent = true;
|
|
14527
|
+
failure = failure ?? toResponsesStreamFailure(ev.error, callbacks?.fallbackPrefix) ?? {
|
|
14528
|
+
code: "response_error",
|
|
14529
|
+
message: `${callbacks?.fallbackPrefix ?? "Responses"} upstream emitted an error event.`
|
|
14530
|
+
};
|
|
14449
14531
|
return;
|
|
14450
14532
|
}
|
|
14451
14533
|
if (type === "response.failed" || type === "response.incomplete") {
|
|
14534
|
+
sawTerminalEvent = true;
|
|
14452
14535
|
const response = ev.response;
|
|
14453
14536
|
failure = failure ?? toResponsesStreamFailure(response?.error, callbacks?.fallbackPrefix) ?? toResponsesStreamFailure(response?.incomplete_details, callbacks?.fallbackPrefix) ?? {
|
|
14454
14537
|
code: type === "response.incomplete" ? "response_incomplete" : "response_failed",
|
|
14455
14538
|
message: `${callbacks?.fallbackPrefix ?? "Responses"} upstream ended with ${type}.`
|
|
14456
14539
|
};
|
|
14540
|
+
{
|
|
14541
|
+
const u = response?.usage;
|
|
14542
|
+
if (u && hasNumericTokenCount(u)) {
|
|
14543
|
+
const prompt = typeof u.input_tokens === "number" ? u.input_tokens : typeof u.prompt_tokens === "number" ? u.prompt_tokens : 0;
|
|
14544
|
+
const completion = typeof u.output_tokens === "number" ? u.output_tokens : typeof u.completion_tokens === "number" ? u.completion_tokens : 0;
|
|
14545
|
+
usage = {
|
|
14546
|
+
prompt_tokens: prompt,
|
|
14547
|
+
completion_tokens: completion,
|
|
14548
|
+
total_tokens: typeof u.total_tokens === "number" ? u.total_tokens : prompt + completion,
|
|
14549
|
+
...u.input_tokens_details && typeof u.input_tokens_details === "object" ? { input_tokens_details: u.input_tokens_details } : {},
|
|
14550
|
+
...u.output_tokens_details && typeof u.output_tokens_details === "object" ? { output_tokens_details: u.output_tokens_details } : {}
|
|
14551
|
+
};
|
|
14552
|
+
}
|
|
14553
|
+
}
|
|
14457
14554
|
return;
|
|
14458
14555
|
}
|
|
14459
14556
|
if (type === "response.output_text.delta" && typeof ev.delta === "string") {
|
|
@@ -14466,16 +14563,38 @@ function createResponsesStreamCollector(callbacks) {
|
|
|
14466
14563
|
callbacks?.onReasoningDelta?.(ev.delta);
|
|
14467
14564
|
return;
|
|
14468
14565
|
}
|
|
14469
|
-
if (type === "response.output_item.added" || type === "response.output_item.done"
|
|
14566
|
+
if (type === "response.output_item.added" || type === "response.output_item.done") {
|
|
14567
|
+
const item = ev.item;
|
|
14568
|
+
if (item?.type === "message" && !content) {
|
|
14569
|
+
const itemText = extractOutputTextFromItem(item);
|
|
14570
|
+
if (itemText) {
|
|
14571
|
+
content = itemText;
|
|
14572
|
+
callbacks?.onTextDelta?.(itemText);
|
|
14573
|
+
}
|
|
14574
|
+
}
|
|
14575
|
+
applyResponsesToolEvent(toolCallsAcc, ev);
|
|
14576
|
+
return;
|
|
14577
|
+
}
|
|
14578
|
+
if (type === "response.function_call_arguments.delta" || type === "response.function_call_arguments.done") {
|
|
14470
14579
|
applyResponsesToolEvent(toolCallsAcc, ev);
|
|
14471
14580
|
return;
|
|
14472
14581
|
}
|
|
14473
14582
|
if (type === "response.completed") {
|
|
14583
|
+
sawTerminalEvent = true;
|
|
14474
14584
|
const response = ev.response;
|
|
14585
|
+
const envelopeStatus = response && typeof response.status === "string" ? response.status : void 0;
|
|
14586
|
+
if (requireResponseCompleted && envelopeStatus !== void 0 && envelopeStatus !== "completed") {
|
|
14587
|
+
failure = failure ?? {
|
|
14588
|
+
code: "response_not_completed",
|
|
14589
|
+
message: `${failurePrefix} emitted response.completed with status "${envelopeStatus}".`
|
|
14590
|
+
};
|
|
14591
|
+
return;
|
|
14592
|
+
}
|
|
14593
|
+
sawTerminalSuccess = true;
|
|
14475
14594
|
if (response) {
|
|
14476
14595
|
completedResponse = response;
|
|
14477
14596
|
const u = response.usage;
|
|
14478
|
-
if (u) {
|
|
14597
|
+
if (u && hasNumericTokenCount(u)) {
|
|
14479
14598
|
const prompt = typeof u.input_tokens === "number" ? u.input_tokens : typeof u.prompt_tokens === "number" ? u.prompt_tokens : 0;
|
|
14480
14599
|
const completion = typeof u.output_tokens === "number" ? u.output_tokens : typeof u.completion_tokens === "number" ? u.completion_tokens : 0;
|
|
14481
14600
|
const total = typeof u.total_tokens === "number" ? u.total_tokens : prompt + completion;
|
|
@@ -14494,8 +14613,60 @@ function createResponsesStreamCollector(callbacks) {
|
|
|
14494
14613
|
};
|
|
14495
14614
|
const finalize2 = () => {
|
|
14496
14615
|
let finalToolCalls = finalizeResponsesToolCalls(toolCallsAcc);
|
|
14497
|
-
if (
|
|
14498
|
-
|
|
14616
|
+
if (completedResponse) {
|
|
14617
|
+
const completedToolCalls = extractToolCallsFromResponseOutput(completedResponse);
|
|
14618
|
+
if (authoritativeCompletedTools) {
|
|
14619
|
+
for (const call of completedToolCalls) {
|
|
14620
|
+
const name = call.function?.name;
|
|
14621
|
+
if (typeof name !== "string" || !name.trim()) {
|
|
14622
|
+
failure = failure ?? {
|
|
14623
|
+
code: "tool_name_missing",
|
|
14624
|
+
message: `${failurePrefix} response.completed contained a tool call without a name.`
|
|
14625
|
+
};
|
|
14626
|
+
break;
|
|
14627
|
+
}
|
|
14628
|
+
const args2 = call.function?.arguments;
|
|
14629
|
+
if (typeof args2 === "string" && args2.trim()) {
|
|
14630
|
+
try {
|
|
14631
|
+
JSON.parse(args2);
|
|
14632
|
+
} catch {
|
|
14633
|
+
failure = failure ?? {
|
|
14634
|
+
code: "tool_arguments_malformed",
|
|
14635
|
+
message: `${failurePrefix} response.completed contained malformed tool arguments for "${name}".`
|
|
14636
|
+
};
|
|
14637
|
+
break;
|
|
14638
|
+
}
|
|
14639
|
+
}
|
|
14640
|
+
}
|
|
14641
|
+
finalToolCalls = completedToolCalls;
|
|
14642
|
+
} else {
|
|
14643
|
+
const completedById = new Map(completedToolCalls.map((call) => [call.id, call]));
|
|
14644
|
+
finalToolCalls = finalToolCalls.map((call) => {
|
|
14645
|
+
const completed = completedById.get(call.id);
|
|
14646
|
+
if (!completed) return call;
|
|
14647
|
+
let accumulatedParses = false;
|
|
14648
|
+
let completedParses = false;
|
|
14649
|
+
try {
|
|
14650
|
+
JSON.parse(call.function.arguments);
|
|
14651
|
+
accumulatedParses = true;
|
|
14652
|
+
} catch {
|
|
14653
|
+
}
|
|
14654
|
+
try {
|
|
14655
|
+
JSON.parse(completed.function.arguments);
|
|
14656
|
+
completedParses = true;
|
|
14657
|
+
} catch {
|
|
14658
|
+
return call;
|
|
14659
|
+
}
|
|
14660
|
+
if (completedParses && (!accumulatedParses || completed.function.arguments.startsWith(call.function.arguments))) {
|
|
14661
|
+
return { ...call, function: { ...call.function, arguments: completed.function.arguments } };
|
|
14662
|
+
}
|
|
14663
|
+
return call;
|
|
14664
|
+
});
|
|
14665
|
+
if (finalToolCalls.length === 0) finalToolCalls = completedToolCalls;
|
|
14666
|
+
}
|
|
14667
|
+
}
|
|
14668
|
+
if (authoritativeCompletedTools && failure) {
|
|
14669
|
+
finalToolCalls = [];
|
|
14499
14670
|
}
|
|
14500
14671
|
if (!content && completedResponse) {
|
|
14501
14672
|
content = extractTextFromResponseOutput(completedResponse);
|
|
@@ -14503,19 +14674,42 @@ function createResponsesStreamCollector(callbacks) {
|
|
|
14503
14674
|
if (!reasoning && completedResponse) {
|
|
14504
14675
|
reasoning = extractReasoningFromResponseOutput(completedResponse);
|
|
14505
14676
|
}
|
|
14677
|
+
const streamComplete = sawTerminalSuccess;
|
|
14678
|
+
const streamTruncated = !sawTerminalEvent;
|
|
14506
14679
|
return {
|
|
14507
14680
|
content,
|
|
14508
14681
|
...reasoning ? { reasoning_content: reasoning } : {},
|
|
14509
14682
|
...finalToolCalls.length > 0 ? { tool_calls: finalToolCalls } : {},
|
|
14510
14683
|
...usage ? { usage } : {},
|
|
14511
|
-
finish_reason: finalToolCalls.length > 0 ? "tool_calls" : "stop",
|
|
14512
|
-
stream_complete: true,
|
|
14684
|
+
...streamComplete ? { finish_reason: finalToolCalls.length > 0 ? "tool_calls" : "stop" } : {},
|
|
14685
|
+
...streamComplete ? { stream_complete: true } : {},
|
|
14686
|
+
...streamTruncated ? { stream_truncated: true } : {},
|
|
14687
|
+
...completedResponse ? { completed_response: completedResponse } : {},
|
|
14688
|
+
...completedResponse && typeof completedResponse.id === "string" ? { response_id: completedResponse.id } : {},
|
|
14513
14689
|
...failure ? { failure } : {}
|
|
14514
14690
|
};
|
|
14515
14691
|
};
|
|
14516
14692
|
return {
|
|
14517
14693
|
processEvent,
|
|
14518
|
-
finalize: finalize2
|
|
14694
|
+
finalize: finalize2,
|
|
14695
|
+
/**
|
|
14696
|
+
* legacy 非标准 provider 可能沿用 chat wire 的 `[DONE]` 收尾哨兵。
|
|
14697
|
+
* 原生 Responses(含 CF)的权威终局仍是 response.completed —— 认这个哨兵
|
|
14698
|
+
* 不为 CF 开豁免:CF 被截断时既没有 completed 也没有 [DONE]。
|
|
14699
|
+
*/
|
|
14700
|
+
markLegacyDone: () => {
|
|
14701
|
+
sawTerminalEvent = true;
|
|
14702
|
+
if (requireResponseCompleted) {
|
|
14703
|
+
if (!sawTerminalSuccess) {
|
|
14704
|
+
failure = failure ?? {
|
|
14705
|
+
code: "response_completed_missing",
|
|
14706
|
+
message: `${failurePrefix} upstream ended with a legacy [DONE] sentinel without response.completed.`
|
|
14707
|
+
};
|
|
14708
|
+
}
|
|
14709
|
+
return;
|
|
14710
|
+
}
|
|
14711
|
+
sawTerminalSuccess = true;
|
|
14712
|
+
}
|
|
14519
14713
|
};
|
|
14520
14714
|
}
|
|
14521
14715
|
function aggregateResponsesStream(events, options) {
|
|
@@ -14539,10 +14733,18 @@ async function readResponsesSseCompletion(args2) {
|
|
|
14539
14733
|
onTextDelta: args2.onTextDelta,
|
|
14540
14734
|
onReasoningDelta: args2.onReasoningDelta,
|
|
14541
14735
|
...args2.onMeaningfulDelta ? { onMeaningfulDelta: args2.onMeaningfulDelta } : {},
|
|
14542
|
-
|
|
14736
|
+
...args2.onEvent ? { onEvent: args2.onEvent } : {},
|
|
14737
|
+
fallbackPrefix: args2.fallbackPrefix ?? "Responses",
|
|
14738
|
+
...args2.requireResponseCompleted === true ? { requireResponseCompleted: true } : {},
|
|
14739
|
+
...args2.authoritativeCompletedTools === true ? { authoritativeCompletedTools: true } : {}
|
|
14543
14740
|
});
|
|
14544
14741
|
for await (const frame of readSseFrames(args2.response)) {
|
|
14545
14742
|
for (const line of frame.split("\n")) {
|
|
14743
|
+
const trimmedLine = line.trim();
|
|
14744
|
+
if (trimmedLine === "[DONE]" || trimmedLine === "data: [DONE]") {
|
|
14745
|
+
collector.markLegacyDone();
|
|
14746
|
+
continue;
|
|
14747
|
+
}
|
|
14546
14748
|
const parsed = parseSseDataLineObject(line);
|
|
14547
14749
|
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
14548
14750
|
collector.processEvent(parsed);
|
|
@@ -14556,12 +14758,14 @@ async function readResponsesSseCompletion(args2) {
|
|
|
14556
14758
|
err.status = status;
|
|
14557
14759
|
err.code = result4.failure.code;
|
|
14558
14760
|
err.type = result4.failure.type;
|
|
14761
|
+
if (result4.usage) err.usage = result4.usage;
|
|
14559
14762
|
throw err;
|
|
14560
14763
|
}
|
|
14561
14764
|
return result4;
|
|
14562
14765
|
}
|
|
14563
14766
|
|
|
14564
14767
|
// packages/agent-runtime/openAiCompatibleProvider.ts
|
|
14768
|
+
var REASONING_REPLAY_PLACEHOLDER = "(reasoning not captured for this turn)";
|
|
14565
14769
|
function isOpenAiResponsesEndpoint(endpoint) {
|
|
14566
14770
|
return endpoint.includes("/responses");
|
|
14567
14771
|
}
|
|
@@ -14575,9 +14779,14 @@ function buildOpenAiCompatibleChatCompletionRequest(args2) {
|
|
|
14575
14779
|
args2.providerConfig.provider,
|
|
14576
14780
|
args2.providerConfig.model
|
|
14577
14781
|
);
|
|
14782
|
+
const shouldReplayReasoning = shouldReplayReasoningContentForOutbound(
|
|
14783
|
+
args2.providerConfig.provider,
|
|
14784
|
+
args2.providerConfig.model
|
|
14785
|
+
);
|
|
14578
14786
|
const sanitizedMessages = sanitizeForOutbound(args2.messages, args2.tools);
|
|
14579
14787
|
const messages = toOpenAiCompatibleMessages(sanitizedMessages, {
|
|
14580
|
-
stripReasoningContent: shouldStripReasoning
|
|
14788
|
+
stripReasoningContent: shouldStripReasoning,
|
|
14789
|
+
...shouldReplayReasoning && !shouldStripReasoning ? { replayReasoningPlaceholder: REASONING_REPLAY_PLACEHOLDER } : {}
|
|
14581
14790
|
});
|
|
14582
14791
|
const rawBody = {
|
|
14583
14792
|
model: args2.providerConfig.model,
|
|
@@ -14606,9 +14815,9 @@ function buildOpenAiCompatibleChatCompletionRequest(args2) {
|
|
|
14606
14815
|
...buildProviderAuthHeaders({
|
|
14607
14816
|
endpoint,
|
|
14608
14817
|
apiKey: args2.providerConfig.apiKey,
|
|
14609
|
-
apiKeyHeader: args2.providerConfig.apiKeyHeader
|
|
14610
|
-
|
|
14611
|
-
|
|
14818
|
+
apiKeyHeader: args2.providerConfig.apiKeyHeader,
|
|
14819
|
+
sessionId: args2.sessionId
|
|
14820
|
+
})
|
|
14612
14821
|
};
|
|
14613
14822
|
return {
|
|
14614
14823
|
url: endpoint,
|
|
@@ -14711,7 +14920,8 @@ async function executeOpenAiCompatibleChatCompletion(args2) {
|
|
|
14711
14920
|
providerConfig: apiKey2 === args2.providerConfig.apiKey ? args2.providerConfig : { ...args2.providerConfig, apiKey: apiKey2 },
|
|
14712
14921
|
messages: args2.messages,
|
|
14713
14922
|
tools: args2.tools,
|
|
14714
|
-
stream: args2.stream
|
|
14923
|
+
stream: args2.stream,
|
|
14924
|
+
sessionId: args2.sessionId
|
|
14715
14925
|
});
|
|
14716
14926
|
return args2.fetchImpl(request3.url, {
|
|
14717
14927
|
...request3.init,
|
|
@@ -16451,29 +16661,6 @@ function getProcessRegistry() {
|
|
|
16451
16661
|
return registry;
|
|
16452
16662
|
}
|
|
16453
16663
|
|
|
16454
|
-
// packages/agent-runtime/processOwnership.ts
|
|
16455
|
-
var asNonEmptyString = (value) => {
|
|
16456
|
-
if (typeof value !== "string") return null;
|
|
16457
|
-
const trimmed = value.trim();
|
|
16458
|
-
return trimmed ? trimmed : null;
|
|
16459
|
-
};
|
|
16460
|
-
function readProcessOwner(runtimeContext) {
|
|
16461
|
-
if (!runtimeContext || typeof runtimeContext !== "object") return null;
|
|
16462
|
-
const dialogId = asNonEmptyString(runtimeContext.dialogId) ?? asNonEmptyString(runtimeContext.parentThreadId);
|
|
16463
|
-
if (!dialogId) return null;
|
|
16464
|
-
const turnId = asNonEmptyString(runtimeContext.turnId);
|
|
16465
|
-
const ownerId = asNonEmptyString(runtimeContext.ownerId);
|
|
16466
|
-
return {
|
|
16467
|
-
dialogId,
|
|
16468
|
-
...turnId ? { turnId } : {},
|
|
16469
|
-
...ownerId ? { ownerId } : {}
|
|
16470
|
-
};
|
|
16471
|
-
}
|
|
16472
|
-
|
|
16473
|
-
// packages/agent-runtime/workspaceShell.ts
|
|
16474
|
-
import { resolve as resolve3 } from "node:path";
|
|
16475
|
-
import { spawn as spawnChildProcess2 } from "node:child_process";
|
|
16476
|
-
|
|
16477
16664
|
// packages/agent-runtime/processTaskResult.ts
|
|
16478
16665
|
var PROCESS_RESULT_CAPSULE_TAIL_CHARS = 4e3;
|
|
16479
16666
|
var PROCESS_RESULT_CAPSULE_SPILL_THRESHOLD_CHARS = 2e4;
|
|
@@ -16493,11 +16680,17 @@ function buildProcessTaskResultCapsule(args2) {
|
|
|
16493
16680
|
const exitCode = args2.exitCode;
|
|
16494
16681
|
const captureError = args2.captureError?.trim() || void 0;
|
|
16495
16682
|
const durationMs = typeof args2.startedAt === "number" && Number.isFinite(args2.startedAt) ? Math.max(0, (args2.endedAt ?? Date.now()) - args2.startedAt) : void 0;
|
|
16496
|
-
const
|
|
16497
|
-
const
|
|
16683
|
+
const stdoutProvenance = args2.streamProvenance?.stdout;
|
|
16684
|
+
const stderrProvenance = args2.streamProvenance?.stderr;
|
|
16685
|
+
const ringEvicted = Boolean(stdoutProvenance?.evicted || stderrProvenance?.evicted);
|
|
16686
|
+
const stdoutTailSource = typeof args2.stdoutTail === "string" ? args2.stdoutTail : stdout;
|
|
16687
|
+
const stderrTailSource = typeof args2.stderrTail === "string" ? args2.stderrTail : stderr;
|
|
16688
|
+
const stdoutTail = tailText(stdoutTailSource, tailChars);
|
|
16689
|
+
const stderrTail = tailText(stderrTailSource, tailChars);
|
|
16498
16690
|
const inlineSize = stdout.length + stderr.length;
|
|
16499
16691
|
const inlineTruncated = stdoutTail.truncated || stderrTail.truncated;
|
|
16500
|
-
const
|
|
16692
|
+
const truncated = inlineTruncated || ringEvicted || Boolean(captureError);
|
|
16693
|
+
const shouldSpill = truncated || inlineSize > spillThresholdChars;
|
|
16501
16694
|
let spill;
|
|
16502
16695
|
if (shouldSpill) {
|
|
16503
16696
|
try {
|
|
@@ -16511,8 +16704,11 @@ function buildProcessTaskResultCapsule(args2) {
|
|
|
16511
16704
|
});
|
|
16512
16705
|
spill = {
|
|
16513
16706
|
displayPath: result4.displayPath,
|
|
16514
|
-
|
|
16515
|
-
|
|
16707
|
+
// Prefer the caller's live provenance counters: they count every
|
|
16708
|
+
// byte of the original stream, while the buffered content above may
|
|
16709
|
+
// be a capped prefix of it.
|
|
16710
|
+
totalChars: (stdoutProvenance?.totalChars ?? stdout.length) + (stderrProvenance?.totalChars ?? stderr.length),
|
|
16711
|
+
totalLines: (stdoutProvenance?.totalLines ?? countLines(stdout)) + (stderrProvenance?.totalLines ?? countLines(stderr))
|
|
16516
16712
|
};
|
|
16517
16713
|
} catch {
|
|
16518
16714
|
}
|
|
@@ -16523,12 +16719,33 @@ function buildProcessTaskResultCapsule(args2) {
|
|
|
16523
16719
|
exitCode,
|
|
16524
16720
|
...durationMs !== void 0 ? { durationMs } : {},
|
|
16525
16721
|
...captureError ? { captureError } : {},
|
|
16526
|
-
truncated
|
|
16722
|
+
truncated,
|
|
16527
16723
|
...spill ? { spill } : {}
|
|
16528
16724
|
};
|
|
16529
16725
|
}
|
|
16530
16726
|
|
|
16727
|
+
// packages/agent-runtime/processOwnership.ts
|
|
16728
|
+
var asNonEmptyString = (value) => {
|
|
16729
|
+
if (typeof value !== "string") return null;
|
|
16730
|
+
const trimmed = value.trim();
|
|
16731
|
+
return trimmed ? trimmed : null;
|
|
16732
|
+
};
|
|
16733
|
+
function readProcessOwner(runtimeContext) {
|
|
16734
|
+
if (!runtimeContext || typeof runtimeContext !== "object") return null;
|
|
16735
|
+
const dialogId = asNonEmptyString(runtimeContext.dialogId) ?? asNonEmptyString(runtimeContext.parentThreadId);
|
|
16736
|
+
if (!dialogId) return null;
|
|
16737
|
+
const turnId = asNonEmptyString(runtimeContext.turnId);
|
|
16738
|
+
const ownerId = asNonEmptyString(runtimeContext.ownerId);
|
|
16739
|
+
return {
|
|
16740
|
+
dialogId,
|
|
16741
|
+
...turnId ? { turnId } : {},
|
|
16742
|
+
...ownerId ? { ownerId } : {}
|
|
16743
|
+
};
|
|
16744
|
+
}
|
|
16745
|
+
|
|
16531
16746
|
// packages/agent-runtime/workspaceShell.ts
|
|
16747
|
+
import { resolve as resolve3 } from "node:path";
|
|
16748
|
+
import { spawn as spawnChildProcess2 } from "node:child_process";
|
|
16532
16749
|
var EXEC_SHELL_TIMEOUT_ENV = "NOLO_EXEC_SHELL_TIMEOUT_MS";
|
|
16533
16750
|
var EXEC_SHELL_DETACH_ENV = "NOLO_EXEC_SHELL_DETACH_MS";
|
|
16534
16751
|
var DEFAULT_EXEC_SHELL_DETACH_MS = 12e4;
|
|
@@ -17397,13 +17614,169 @@ function runTasks(args2) {
|
|
|
17397
17614
|
return { tasks, count: tasks.length };
|
|
17398
17615
|
}
|
|
17399
17616
|
|
|
17617
|
+
// packages/agent-runtime/execShellCompletionWarnings.ts
|
|
17618
|
+
var BG_ESCAPE_WORD_PATTERN = /(?:^|[\s;|(&/\\])(nohup|disown|setsid|start-process)(?=$|[\s;|)&])/i;
|
|
17619
|
+
var SHELL_SPLIT_CHARS = /* @__PURE__ */ new Set([";", "|", "&", "(", ")", "<", ">", "\n", " ", " "]);
|
|
17620
|
+
function maskQuotedAndEscaped(command) {
|
|
17621
|
+
const out = Array.from(command);
|
|
17622
|
+
let quote = null;
|
|
17623
|
+
for (let i = 0; i < out.length; i += 1) {
|
|
17624
|
+
const ch = out[i];
|
|
17625
|
+
if (quote) {
|
|
17626
|
+
out[i] = " ";
|
|
17627
|
+
if (ch === "\\" && quote !== "'") {
|
|
17628
|
+
if (i + 1 < out.length) out[i + 1] = " ";
|
|
17629
|
+
i += 1;
|
|
17630
|
+
} else if (ch === quote) {
|
|
17631
|
+
quote = null;
|
|
17632
|
+
}
|
|
17633
|
+
continue;
|
|
17634
|
+
}
|
|
17635
|
+
if (ch === "\\") {
|
|
17636
|
+
out[i] = " ";
|
|
17637
|
+
if (i + 1 < out.length) out[i + 1] = " ";
|
|
17638
|
+
i += 1;
|
|
17639
|
+
continue;
|
|
17640
|
+
}
|
|
17641
|
+
if (ch === "'" || ch === '"' || ch === "`") {
|
|
17642
|
+
quote = ch;
|
|
17643
|
+
out[i] = " ";
|
|
17644
|
+
continue;
|
|
17645
|
+
}
|
|
17646
|
+
if (ch === "#" && (i === 0 || /[\s;]/.test(out[i - 1] ?? " "))) {
|
|
17647
|
+
while (i < out.length && out[i] !== "\n") {
|
|
17648
|
+
out[i] = " ";
|
|
17649
|
+
i += 1;
|
|
17650
|
+
}
|
|
17651
|
+
}
|
|
17652
|
+
}
|
|
17653
|
+
return out.join("");
|
|
17654
|
+
}
|
|
17655
|
+
function readRedirectTarget(original, start) {
|
|
17656
|
+
let i = start;
|
|
17657
|
+
while (i < original.length && /\s/.test(original[i] ?? "")) {
|
|
17658
|
+
i += 1;
|
|
17659
|
+
}
|
|
17660
|
+
if (i >= original.length) return void 0;
|
|
17661
|
+
let text = "";
|
|
17662
|
+
let j = i;
|
|
17663
|
+
while (j < original.length) {
|
|
17664
|
+
const o = original[j];
|
|
17665
|
+
if (o === "'" || o === '"' || o === "`") {
|
|
17666
|
+
const quote = o;
|
|
17667
|
+
j += 1;
|
|
17668
|
+
while (j < original.length && original[j] !== quote) {
|
|
17669
|
+
if (original[j] === "\\" && quote !== "'" && j + 1 < original.length) {
|
|
17670
|
+
text += original[j + 1];
|
|
17671
|
+
j += 2;
|
|
17672
|
+
continue;
|
|
17673
|
+
}
|
|
17674
|
+
text += original[j];
|
|
17675
|
+
j += 1;
|
|
17676
|
+
}
|
|
17677
|
+
j += 1;
|
|
17678
|
+
continue;
|
|
17679
|
+
}
|
|
17680
|
+
if (/\s/.test(o) || SHELL_SPLIT_CHARS.has(o)) break;
|
|
17681
|
+
text += o;
|
|
17682
|
+
j += 1;
|
|
17683
|
+
}
|
|
17684
|
+
if (!text || text === "$") return void 0;
|
|
17685
|
+
return { text, end: j };
|
|
17686
|
+
}
|
|
17687
|
+
function isIgnoredRedirectTarget(target) {
|
|
17688
|
+
return target === "/dev/null";
|
|
17689
|
+
}
|
|
17690
|
+
function detectExecShellSynchronousWarnings(command, shell) {
|
|
17691
|
+
const masked = maskQuotedAndEscaped(command);
|
|
17692
|
+
const isPowerShell = shell?.resolvedShell === "powershell";
|
|
17693
|
+
const redirectTargets = [];
|
|
17694
|
+
let backgrounded = false;
|
|
17695
|
+
let i = 0;
|
|
17696
|
+
while (i < masked.length) {
|
|
17697
|
+
const ch = masked[i];
|
|
17698
|
+
if (ch === "&") {
|
|
17699
|
+
const next = masked[i + 1];
|
|
17700
|
+
if (next === "&") {
|
|
17701
|
+
i += 2;
|
|
17702
|
+
continue;
|
|
17703
|
+
}
|
|
17704
|
+
if (next === ">") {
|
|
17705
|
+
let j = i + 2;
|
|
17706
|
+
if (masked[j] === ">") j += 1;
|
|
17707
|
+
const target = readRedirectTarget(command, j);
|
|
17708
|
+
if (target && !isIgnoredRedirectTarget(target.text)) redirectTargets.push(target.text);
|
|
17709
|
+
i = target ? target.end : j;
|
|
17710
|
+
continue;
|
|
17711
|
+
}
|
|
17712
|
+
const prev = masked[i - 1];
|
|
17713
|
+
if (prev === ">" || prev === "<") {
|
|
17714
|
+
i += 1;
|
|
17715
|
+
continue;
|
|
17716
|
+
}
|
|
17717
|
+
if (isPowerShell) {
|
|
17718
|
+
i += 1;
|
|
17719
|
+
continue;
|
|
17720
|
+
}
|
|
17721
|
+
backgrounded = true;
|
|
17722
|
+
i += 1;
|
|
17723
|
+
continue;
|
|
17724
|
+
}
|
|
17725
|
+
if (ch === ">") {
|
|
17726
|
+
const prev = masked[i - 1];
|
|
17727
|
+
if (prev === ">" || prev === "&" || prev === "<") {
|
|
17728
|
+
i += 1;
|
|
17729
|
+
continue;
|
|
17730
|
+
}
|
|
17731
|
+
let j = i + 1;
|
|
17732
|
+
if (masked[j] === ">") j += 1;
|
|
17733
|
+
if (masked[j] === "&") {
|
|
17734
|
+
const ampTarget = readRedirectTarget(command, j + 1);
|
|
17735
|
+
const isFdDuplication = ampTarget !== void 0 && (/^\d+$/.test(ampTarget.text) || ampTarget.text === "-");
|
|
17736
|
+
if (ampTarget && !isFdDuplication && !isIgnoredRedirectTarget(ampTarget.text)) {
|
|
17737
|
+
redirectTargets.push(ampTarget.text);
|
|
17738
|
+
}
|
|
17739
|
+
i = ampTarget ? ampTarget.end : j + 1;
|
|
17740
|
+
continue;
|
|
17741
|
+
}
|
|
17742
|
+
const target = readRedirectTarget(command, j);
|
|
17743
|
+
if (target && !isIgnoredRedirectTarget(target.text)) redirectTargets.push(target.text);
|
|
17744
|
+
i = target ? target.end : j;
|
|
17745
|
+
continue;
|
|
17746
|
+
}
|
|
17747
|
+
if (ch === "<") {
|
|
17748
|
+
i += masked[i + 1] === "<" || masked[i + 1] === "&" ? 2 : 1;
|
|
17749
|
+
continue;
|
|
17750
|
+
}
|
|
17751
|
+
i += 1;
|
|
17752
|
+
}
|
|
17753
|
+
const wordMatch = BG_ESCAPE_WORD_PATTERN.exec(masked);
|
|
17754
|
+
if (wordMatch) backgrounded = true;
|
|
17755
|
+
const warnings = [];
|
|
17756
|
+
if (redirectTargets.length > 0) {
|
|
17757
|
+
const target = redirectTargets[0];
|
|
17758
|
+
warnings.push({
|
|
17759
|
+
kind: "output-redirect",
|
|
17760
|
+
redirectTarget: target,
|
|
17761
|
+
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.`
|
|
17762
|
+
});
|
|
17763
|
+
}
|
|
17764
|
+
if (backgrounded) {
|
|
17765
|
+
warnings.push({
|
|
17766
|
+
kind: "shell-backgrounding",
|
|
17767
|
+
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.`
|
|
17768
|
+
});
|
|
17769
|
+
}
|
|
17770
|
+
return warnings;
|
|
17771
|
+
}
|
|
17772
|
+
|
|
17400
17773
|
// packages/agent-runtime/capabilities/execShellCapability.ts
|
|
17401
17774
|
function buildExecShellToolDefinition(toolName = "execShell") {
|
|
17402
17775
|
return {
|
|
17403
17776
|
type: "function",
|
|
17404
17777
|
function: {
|
|
17405
17778
|
name: toolName,
|
|
17406
|
-
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.`,
|
|
17779
|
+
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.`,
|
|
17407
17780
|
parameters: {
|
|
17408
17781
|
type: "object",
|
|
17409
17782
|
properties: {
|
|
@@ -17414,6 +17787,10 @@ function buildExecShellToolDefinition(toolName = "execShell") {
|
|
|
17414
17787
|
cmd: {
|
|
17415
17788
|
type: "string",
|
|
17416
17789
|
description: "Compatibility alias for command."
|
|
17790
|
+
},
|
|
17791
|
+
background: {
|
|
17792
|
+
type: "boolean",
|
|
17793
|
+
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."
|
|
17417
17794
|
}
|
|
17418
17795
|
}
|
|
17419
17796
|
}
|
|
@@ -17454,11 +17831,13 @@ function normalizeExecShellInput(input) {
|
|
|
17454
17831
|
throw new Error("execShell requires a non-empty command.");
|
|
17455
17832
|
}
|
|
17456
17833
|
const activity = extractActivity(record);
|
|
17834
|
+
const background = record.background === true || typeof record.background === "string" && record.background.trim().toLowerCase() === "true";
|
|
17457
17835
|
return {
|
|
17458
17836
|
command,
|
|
17459
17837
|
...record.shell !== void 0 ? { shell: record.shell } : {},
|
|
17460
17838
|
...activity ? { activity } : {},
|
|
17461
|
-
...record.input !== void 0 ? { input: record.input } : {}
|
|
17839
|
+
...record.input !== void 0 ? { input: record.input } : {},
|
|
17840
|
+
...background ? { background: true } : {}
|
|
17462
17841
|
};
|
|
17463
17842
|
}
|
|
17464
17843
|
throw new Error("execShell requires a non-empty command.");
|
|
@@ -17496,6 +17875,7 @@ var execShellCapability = {
|
|
|
17496
17875
|
command,
|
|
17497
17876
|
shell: normalized.shell
|
|
17498
17877
|
});
|
|
17878
|
+
const background = normalized.background === true;
|
|
17499
17879
|
const result4 = await runWorkspaceCommand({
|
|
17500
17880
|
workspaceRoot,
|
|
17501
17881
|
command: shellPlan.argv,
|
|
@@ -17503,15 +17883,18 @@ var execShellCapability = {
|
|
|
17503
17883
|
outputLimit: ctx.commandOutputLimit,
|
|
17504
17884
|
commandPrefix: ctx.commandPrefix,
|
|
17505
17885
|
abortSignal: ctx.abortSignal,
|
|
17506
|
-
detachMs: isImmediateDetachShellCommand({ command }) ? 0 : ctx.detachMs,
|
|
17886
|
+
detachMs: background ? 0 : isImmediateDetachShellCommand({ command }) ? 0 : ctx.detachMs,
|
|
17507
17887
|
stdin: typeof normalized.input === "string" ? normalized.input : void 0,
|
|
17508
17888
|
// Ownership of the turn that invoked this command: an auto-detached
|
|
17509
17889
|
// command keeps its parent dialog so its terminal can resume that
|
|
17510
17890
|
// conversation (see processOwnership.ts). Absent ctx.owner = unowned.
|
|
17511
17891
|
owner: ctx.owner ?? null
|
|
17512
17892
|
});
|
|
17893
|
+
const warnings = result4.detached || result4.spawnFailed ? [] : detectExecShellSynchronousWarnings(command, {
|
|
17894
|
+
resolvedShell: shellPlan.resolvedShell
|
|
17895
|
+
});
|
|
17513
17896
|
return {
|
|
17514
|
-
content: result4.content,
|
|
17897
|
+
content: warnings.length > 0 ? [result4.content, ...warnings.map((warning) => warning.message)].join("\n\n") : result4.content,
|
|
17515
17898
|
metadata: {
|
|
17516
17899
|
command,
|
|
17517
17900
|
exitCode: result4.exitCode,
|
|
@@ -17526,8 +17909,21 @@ var execShellCapability = {
|
|
|
17526
17909
|
// Phase 0: stable taskId from the pre-registered Execution
|
|
17527
17910
|
// Envelope (additive; existing detached fields untouched).
|
|
17528
17911
|
taskId: result4.taskId,
|
|
17529
|
-
status: "running"
|
|
17530
|
-
|
|
17912
|
+
status: "running",
|
|
17913
|
+
// P0 machine-readable execution state: an explicit positive
|
|
17914
|
+
// signal instead of requiring the model to infer "not detached"
|
|
17915
|
+
// from absence. Mirrors the real lifecycle contract.
|
|
17916
|
+
executionState: "detached",
|
|
17917
|
+
trackedBackgroundTask: true,
|
|
17918
|
+
completionNotification: "terminal-resume"
|
|
17919
|
+
} : {
|
|
17920
|
+
// P0 machine-readable execution state: the command already
|
|
17921
|
+
// finished inside the synchronous window; no background task
|
|
17922
|
+
// exists, so no completion notification will ever arrive.
|
|
17923
|
+
executionState: "synchronous-complete",
|
|
17924
|
+
trackedBackgroundTask: false,
|
|
17925
|
+
completionNotification: "none"
|
|
17926
|
+
},
|
|
17531
17927
|
...normalized.activity ? { activity: normalized.activity } : {}
|
|
17532
17928
|
}
|
|
17533
17929
|
};
|
|
@@ -17743,7 +18139,7 @@ function buildLaunchProcessTool() {
|
|
|
17743
18139
|
type: "function",
|
|
17744
18140
|
function: {
|
|
17745
18141
|
name: "launchProcess",
|
|
17746
|
-
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.",
|
|
18142
|
+
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.",
|
|
17747
18143
|
parameters: {
|
|
17748
18144
|
type: "object",
|
|
17749
18145
|
properties: {
|
|
@@ -18529,6 +18925,87 @@ async function writeFileTool(args2) {
|
|
|
18529
18925
|
}
|
|
18530
18926
|
};
|
|
18531
18927
|
}
|
|
18928
|
+
function extractSnippetWords(text) {
|
|
18929
|
+
const tokens = [];
|
|
18930
|
+
const latinWords = text.match(/[A-Za-z0-9_]{2,}/g);
|
|
18931
|
+
if (latinWords) {
|
|
18932
|
+
for (const w of latinWords) tokens.push(w.toLowerCase());
|
|
18933
|
+
}
|
|
18934
|
+
const cjkChars = text.match(new RegExp("\\p{Script=Han}", "gu"));
|
|
18935
|
+
if (cjkChars) {
|
|
18936
|
+
for (let i = 0; i < cjkChars.length - 1; i++) {
|
|
18937
|
+
tokens.push(cjkChars[i] + cjkChars[i + 1]);
|
|
18938
|
+
}
|
|
18939
|
+
if (cjkChars.length === 1) tokens.push(cjkChars[0]);
|
|
18940
|
+
}
|
|
18941
|
+
return tokens;
|
|
18942
|
+
}
|
|
18943
|
+
function calculateEditLineSimilarity(a, b) {
|
|
18944
|
+
if (a === b) return 1;
|
|
18945
|
+
if (!a || !b) return 0;
|
|
18946
|
+
if (a.includes(b) || b.includes(a)) return 0.8;
|
|
18947
|
+
const wordsA = extractSnippetWords(a);
|
|
18948
|
+
const wordsB = extractSnippetWords(b);
|
|
18949
|
+
if (wordsA.length === 0 || wordsB.length === 0) return 0;
|
|
18950
|
+
const setB = new Set(wordsB);
|
|
18951
|
+
let matches = 0;
|
|
18952
|
+
for (const w of wordsA) {
|
|
18953
|
+
if (setB.has(w)) matches++;
|
|
18954
|
+
}
|
|
18955
|
+
return 2 * matches / (wordsA.length + wordsB.length);
|
|
18956
|
+
}
|
|
18957
|
+
function findClosestEditSnippet(content, oldText) {
|
|
18958
|
+
const contentLines = content.split(/\r?\n/);
|
|
18959
|
+
const oldLinesRaw = oldText.split(/\r?\n/);
|
|
18960
|
+
const oldTrimmedLines = oldLinesRaw.map((l) => l.trim()).filter(Boolean);
|
|
18961
|
+
if (contentLines.length === 0 || oldTrimmedLines.length === 0) return null;
|
|
18962
|
+
if (oldTrimmedLines.length > 0 && contentLines.length >= oldTrimmedLines.length) {
|
|
18963
|
+
for (let i = 0; i <= contentLines.length - oldTrimmedLines.length; i++) {
|
|
18964
|
+
let allMatch = true;
|
|
18965
|
+
for (let j = 0; j < oldTrimmedLines.length; j++) {
|
|
18966
|
+
if (contentLines[i + j].trim() !== oldTrimmedLines[j]) {
|
|
18967
|
+
allMatch = false;
|
|
18968
|
+
break;
|
|
18969
|
+
}
|
|
18970
|
+
}
|
|
18971
|
+
if (allMatch) {
|
|
18972
|
+
const startLine2 = i + 1;
|
|
18973
|
+
const endLine2 = i + oldTrimmedLines.length;
|
|
18974
|
+
const snippetLines2 = [];
|
|
18975
|
+
for (let k = i; k < i + oldTrimmedLines.length; k++) {
|
|
18976
|
+
snippetLines2.push(`> ${k + 1}: ${contentLines[k]}`);
|
|
18977
|
+
}
|
|
18978
|
+
return `Exact match found with different indentation/whitespace (lines ${startLine2}-${endLine2}):
|
|
18979
|
+
${snippetLines2.join("\n")}`;
|
|
18980
|
+
}
|
|
18981
|
+
}
|
|
18982
|
+
}
|
|
18983
|
+
const candidateTargetLines = oldTrimmedLines.filter((l) => l.length >= 4);
|
|
18984
|
+
const targetLine = candidateTargetLines[0] || oldTrimmedLines[0];
|
|
18985
|
+
if (!targetLine || targetLine.length < 3) return null;
|
|
18986
|
+
let bestIndex = -1;
|
|
18987
|
+
let bestScore = 0;
|
|
18988
|
+
for (let i = 0; i < contentLines.length; i++) {
|
|
18989
|
+
const line = contentLines[i].trim();
|
|
18990
|
+
if (!line || line.length < 3) continue;
|
|
18991
|
+
const score = calculateEditLineSimilarity(line, targetLine);
|
|
18992
|
+
if (score > bestScore && score >= 0.45) {
|
|
18993
|
+
bestScore = score;
|
|
18994
|
+
bestIndex = i;
|
|
18995
|
+
if (score === 1) break;
|
|
18996
|
+
}
|
|
18997
|
+
}
|
|
18998
|
+
if (bestIndex === -1) return null;
|
|
18999
|
+
const startLine = Math.max(0, bestIndex - 2);
|
|
19000
|
+
const endLine = Math.min(contentLines.length - 1, bestIndex + 2);
|
|
19001
|
+
const snippetLines = [];
|
|
19002
|
+
for (let i = startLine; i <= endLine; i++) {
|
|
19003
|
+
const prefix = i === bestIndex ? "> " : " ";
|
|
19004
|
+
snippetLines.push(`${prefix}${i + 1}: ${contentLines[i]}`);
|
|
19005
|
+
}
|
|
19006
|
+
return `Closest match near line ${bestIndex + 1}:
|
|
19007
|
+
${snippetLines.join("\n")}`;
|
|
19008
|
+
}
|
|
18532
19009
|
async function editFileTool(args2) {
|
|
18533
19010
|
const parsed = parseWorkspaceToolArguments(args2.call.arguments);
|
|
18534
19011
|
const requestedPath = requireWorkspaceToolPath(parsed);
|
|
@@ -18547,8 +19024,11 @@ async function editFileTool(args2) {
|
|
|
18547
19024
|
newText
|
|
18548
19025
|
});
|
|
18549
19026
|
if (replacementCount !== expectedReplacements) {
|
|
19027
|
+
const hint = replacementCount === 0 ? findClosestEditSnippet(content, oldText) : null;
|
|
18550
19028
|
throw new Error(
|
|
18551
|
-
`editFile expected ${expectedReplacements} ${pluralizeReplacement(expectedReplacements)} but found ${replacementCount} in ${requestedPath} (matched after EOL normalization; verify the exact text).`
|
|
19029
|
+
`editFile expected ${expectedReplacements} ${pluralizeReplacement(expectedReplacements)} but found ${replacementCount} in ${requestedPath} (matched after EOL normalization; verify the exact text).` + (hint ? `
|
|
19030
|
+
|
|
19031
|
+
${hint}` : "")
|
|
18552
19032
|
);
|
|
18553
19033
|
}
|
|
18554
19034
|
await writeFile(absolutePath, nextContent, "utf8");
|
|
@@ -18884,6 +19364,55 @@ async function execShellTool(args2) {
|
|
|
18884
19364
|
}
|
|
18885
19365
|
);
|
|
18886
19366
|
}
|
|
19367
|
+
var LAUNCH_PROCESS_STREAM_RING_CHARS = 65536;
|
|
19368
|
+
var LAUNCH_PROCESS_STREAM_CAPTURE_MAX_CHARS = 4e6;
|
|
19369
|
+
function createLaunchProcessStreamCapture() {
|
|
19370
|
+
let ring = "";
|
|
19371
|
+
let full = null;
|
|
19372
|
+
let capturedChars = 0;
|
|
19373
|
+
let totalChars = 0;
|
|
19374
|
+
let totalNewlines = 0;
|
|
19375
|
+
return {
|
|
19376
|
+
push(chunk) {
|
|
19377
|
+
const str = typeof chunk === "string" ? chunk : chunk.toString("utf8");
|
|
19378
|
+
if (!str) return;
|
|
19379
|
+
totalChars += str.length;
|
|
19380
|
+
for (let i = 0; i < str.length; i += 1) {
|
|
19381
|
+
if (str.charCodeAt(i) === 10) totalNewlines += 1;
|
|
19382
|
+
}
|
|
19383
|
+
const combined = ring + str;
|
|
19384
|
+
if (combined.length <= LAUNCH_PROCESS_STREAM_RING_CHARS) {
|
|
19385
|
+
ring = combined;
|
|
19386
|
+
return;
|
|
19387
|
+
}
|
|
19388
|
+
if (full === null) {
|
|
19389
|
+
full = [combined];
|
|
19390
|
+
capturedChars = combined.length;
|
|
19391
|
+
} else if (capturedChars < LAUNCH_PROCESS_STREAM_CAPTURE_MAX_CHARS) {
|
|
19392
|
+
const room = LAUNCH_PROCESS_STREAM_CAPTURE_MAX_CHARS - capturedChars;
|
|
19393
|
+
const slice = str.length <= room ? str : str.slice(0, room);
|
|
19394
|
+
full.push(slice);
|
|
19395
|
+
capturedChars += slice.length;
|
|
19396
|
+
}
|
|
19397
|
+
ring = combined.slice(-LAUNCH_PROCESS_STREAM_RING_CHARS);
|
|
19398
|
+
},
|
|
19399
|
+
text() {
|
|
19400
|
+
return full === null ? ring : full.join("");
|
|
19401
|
+
},
|
|
19402
|
+
tailText() {
|
|
19403
|
+
return ring;
|
|
19404
|
+
},
|
|
19405
|
+
evicted() {
|
|
19406
|
+
return full !== null;
|
|
19407
|
+
},
|
|
19408
|
+
totalChars() {
|
|
19409
|
+
return totalChars;
|
|
19410
|
+
},
|
|
19411
|
+
totalLines() {
|
|
19412
|
+
return totalChars > 0 ? totalNewlines + 1 : 0;
|
|
19413
|
+
}
|
|
19414
|
+
};
|
|
19415
|
+
}
|
|
18887
19416
|
async function launchProcessTool(args2) {
|
|
18888
19417
|
const parsed = parseWorkspaceToolArguments(args2.call.arguments);
|
|
18889
19418
|
const command = requireShellCommand(parsed, args2.call.name);
|
|
@@ -18911,6 +19440,14 @@ async function launchProcessTool(args2) {
|
|
|
18911
19440
|
stdio: ["ignore", "pipe", "pipe"],
|
|
18912
19441
|
detached
|
|
18913
19442
|
});
|
|
19443
|
+
const stdoutCapture = createLaunchProcessStreamCapture();
|
|
19444
|
+
const stderrCapture = createLaunchProcessStreamCapture();
|
|
19445
|
+
proc.stdout?.on("data", (chunk) => stdoutCapture.push(chunk));
|
|
19446
|
+
proc.stderr?.on("data", (chunk) => stderrCapture.push(chunk));
|
|
19447
|
+
proc.stdout?.on("error", () => {
|
|
19448
|
+
});
|
|
19449
|
+
proc.stderr?.on("error", () => {
|
|
19450
|
+
});
|
|
18914
19451
|
const pid = proc.pid;
|
|
18915
19452
|
if (typeof pid !== "number") {
|
|
18916
19453
|
return {
|
|
@@ -18951,7 +19488,38 @@ async function launchProcessTool(args2) {
|
|
|
18951
19488
|
process.removeListener("SIGTERM", cleanupChildOnHostSignal);
|
|
18952
19489
|
process.removeListener("SIGINT", cleanupChildOnHostSignal);
|
|
18953
19490
|
}
|
|
18954
|
-
|
|
19491
|
+
const exitCode = code ?? 1;
|
|
19492
|
+
let capsule;
|
|
19493
|
+
try {
|
|
19494
|
+
capsule = buildProcessTaskResultCapsule({
|
|
19495
|
+
// The full captured output (bounded prefix when the process was
|
|
19496
|
+
// extremely chatty): the module tails it for the inline capsule and
|
|
19497
|
+
// spills it for recovery. Provenance carries the live original-stream
|
|
19498
|
+
// counters so truncated/spill metadata never derives from the ring.
|
|
19499
|
+
stdout: stdoutCapture.text(),
|
|
19500
|
+
stderr: stderrCapture.text(),
|
|
19501
|
+
stdoutTail: stdoutCapture.tailText(),
|
|
19502
|
+
stderrTail: stderrCapture.tailText(),
|
|
19503
|
+
exitCode,
|
|
19504
|
+
// Duration measured from the registry envelope's startedAt (spawn).
|
|
19505
|
+
startedAt: envelope.startedAt,
|
|
19506
|
+
workspaceRoot: args2.workspaceRoot,
|
|
19507
|
+
streamProvenance: {
|
|
19508
|
+
stdout: {
|
|
19509
|
+
evicted: stdoutCapture.evicted(),
|
|
19510
|
+
totalChars: stdoutCapture.totalChars(),
|
|
19511
|
+
totalLines: stdoutCapture.totalLines()
|
|
19512
|
+
},
|
|
19513
|
+
stderr: {
|
|
19514
|
+
evicted: stderrCapture.evicted(),
|
|
19515
|
+
totalChars: stderrCapture.totalChars(),
|
|
19516
|
+
totalLines: stderrCapture.totalLines()
|
|
19517
|
+
}
|
|
19518
|
+
}
|
|
19519
|
+
});
|
|
19520
|
+
} catch {
|
|
19521
|
+
}
|
|
19522
|
+
registry2.markExited(pid, exitCode, capsule);
|
|
18955
19523
|
});
|
|
18956
19524
|
const activity = extractActivity(parsed);
|
|
18957
19525
|
const resultData = { pid, label, taskId: envelope.taskId, status: "running" };
|
|
@@ -18963,6 +19531,13 @@ async function launchProcessTool(args2) {
|
|
|
18963
19531
|
label,
|
|
18964
19532
|
status: "running",
|
|
18965
19533
|
taskId: envelope.taskId,
|
|
19534
|
+
// P0 machine-readable execution state (consistent with the real wake
|
|
19535
|
+
// contract): a real background task from birth, but ambient — its
|
|
19536
|
+
// terminal result rides the next real turn's notice, not an automatic
|
|
19537
|
+
// completion turn.
|
|
19538
|
+
executionState: "background",
|
|
19539
|
+
trackedBackgroundTask: true,
|
|
19540
|
+
completionNotification: "next-turn-notice",
|
|
18966
19541
|
processLaunch: resultData,
|
|
18967
19542
|
...activity ? { activity } : {}
|
|
18968
19543
|
}
|
|
@@ -19065,7 +19640,7 @@ async function tasksTool(_args) {
|
|
|
19065
19640
|
}
|
|
19066
19641
|
async function openDesktopPreviewTool(args2) {
|
|
19067
19642
|
const parsed = parseWorkspaceToolArguments(args2.call.arguments);
|
|
19068
|
-
const url =
|
|
19643
|
+
const url = asTrimmedString(parsed.url);
|
|
19069
19644
|
if (!url) {
|
|
19070
19645
|
return {
|
|
19071
19646
|
content: JSON.stringify({ error: "openDesktopPreview requires a non-empty url." }),
|
|
@@ -19397,7 +19972,9 @@ function resolveLocalToolPolicy(args2) {
|
|
|
19397
19972
|
reason: `${toolName} is blocked by the local runtime safety policy.`
|
|
19398
19973
|
};
|
|
19399
19974
|
}
|
|
19400
|
-
const allowedByEnv = new Set(
|
|
19975
|
+
const allowedByEnv = new Set(
|
|
19976
|
+
parseToolAllowlist(args2.env.NOLO_LOCAL_ALLOWED_TOOLS).map(normalizeLocalToolName)
|
|
19977
|
+
);
|
|
19401
19978
|
const agentTools = new Set(
|
|
19402
19979
|
(args2.agentToolNames ?? []).flatMap((item) => {
|
|
19403
19980
|
const normalized = normalizeLocalToolName(item);
|
|
@@ -19420,7 +19997,7 @@ function resolveLocalToolPolicy(args2) {
|
|
|
19420
19997
|
};
|
|
19421
19998
|
}
|
|
19422
19999
|
async function executeLocalToolWithPolicy(args2) {
|
|
19423
|
-
if (args2.runToolNames !== void 0 && !args2.runToolNames.includes(normalizeLocalToolName(args2.call.name))) {
|
|
20000
|
+
if (args2.runToolNames !== void 0 && !args2.runToolNames.map(normalizeLocalToolName).includes(normalizeLocalToolName(args2.call.name))) {
|
|
19424
20001
|
throw new Error(`${args2.call.name} is outside the final run tool surface.`);
|
|
19425
20002
|
}
|
|
19426
20003
|
const decision = resolveLocalToolPolicy({
|
|
@@ -19607,10 +20184,10 @@ function buildLoadSkillExecutor(args2) {
|
|
|
19607
20184
|
metadata: { loadSkill: true, resolved: false }
|
|
19608
20185
|
};
|
|
19609
20186
|
}
|
|
19610
|
-
const { resolveSkillByName } = await import("./skillDiscovery-
|
|
20187
|
+
const { resolveSkillByName } = await import("./skillDiscovery-ZBU76COE.js");
|
|
19611
20188
|
const resolved = resolveSkillByName(args2.cwd, name);
|
|
19612
20189
|
if (!resolved) {
|
|
19613
|
-
const { resolveBuiltinSkillByName } = await import("./builtinSkillRegistry-
|
|
20190
|
+
const { resolveBuiltinSkillByName } = await import("./builtinSkillRegistry-ZK4K67Y5.js");
|
|
19614
20191
|
const builtin = resolveBuiltinSkillByName(name);
|
|
19615
20192
|
if (builtin) {
|
|
19616
20193
|
return {
|
|
@@ -19653,7 +20230,7 @@ ${body}`,
|
|
|
19653
20230
|
};
|
|
19654
20231
|
}
|
|
19655
20232
|
async function formatUnknownSkillMessage(cwd, requestedName) {
|
|
19656
|
-
const { discoverSkills } = await import("./skillDiscovery-
|
|
20233
|
+
const { discoverSkills } = await import("./skillDiscovery-ZBU76COE.js");
|
|
19657
20234
|
let available = [];
|
|
19658
20235
|
try {
|
|
19659
20236
|
available = discoverSkills(cwd).map((s) => s.name);
|
|
@@ -19668,739 +20245,29 @@ No skills were discovered in this workspace.`;
|
|
|
19668
20245
|
Available skills: ${available.join(", ")}`;
|
|
19669
20246
|
}
|
|
19670
20247
|
|
|
19671
|
-
// packages/
|
|
19672
|
-
|
|
19673
|
-
|
|
19674
|
-
|
|
19675
|
-
|
|
19676
|
-
|
|
19677
|
-
|
|
19678
|
-
|
|
19679
|
-
|
|
19680
|
-
|
|
19681
|
-
|
|
19682
|
-
|
|
19683
|
-
|
|
19684
|
-
|
|
19685
|
-
|
|
19686
|
-
|
|
19687
|
-
|
|
19688
|
-
// packages/agent-runtime/antigravityCloudCodeProvider.ts
|
|
19689
|
-
import { randomUUID } from "node:crypto";
|
|
19690
|
-
|
|
19691
|
-
// packages/agent-runtime/antigravityWireModel.ts
|
|
19692
|
-
var WIRE_PROFILES = {
|
|
19693
|
-
// Antigravity discovery exposes 3.7 Flash as one tiered wire model.
|
|
19694
|
-
// The UI labels its effort variants (Low/Medium/High), but the literal
|
|
19695
|
-
// -medium/-high ids return 404 from streamGenerateContent.
|
|
19696
|
-
"gemini-3.7-flash-tiered": { modelEnum: "MODEL_PLACEHOLDER_M301", maxOutputTokens: 65536 },
|
|
19697
|
-
// Gemini 3.8 Flash 沿用 3.7 的 tiered 兼容策略:仓库内暂无 Antigravity discovery
|
|
19698
|
-
// 证据确认 3.8 的 wire modelEnum,禁止虚构,先只声明同档输出上限;enum 待
|
|
19699
|
-
// discovery 证据到位后补齐。
|
|
19700
|
-
"gemini-3.8-flash-tiered": { maxOutputTokens: 65536 },
|
|
19701
|
-
"gemini-3.6-flash-low": { maxOutputTokens: 65536 },
|
|
19702
|
-
"gemini-3.6-flash-medium": { maxOutputTokens: 65536 },
|
|
19703
|
-
"gemini-3.6-flash-high": { maxOutputTokens: 65536 },
|
|
19704
|
-
// 旧模型 wire 映射保留:存量自定义 agent 仍可能引用(注册表已下线不影响此处)。
|
|
19705
|
-
"gemini-3.5-flash-extra-low": { modelEnum: "MODEL_PLACEHOLDER_M187", maxOutputTokens: 65536 },
|
|
19706
|
-
"gemini-3.5-flash-low": { modelEnum: "MODEL_PLACEHOLDER_M20", maxOutputTokens: 65536 },
|
|
19707
|
-
"gemini-3-flash-agent": { modelEnum: "MODEL_PLACEHOLDER_M132", maxOutputTokens: 65536 },
|
|
19708
|
-
"gemini-3.1-pro-low": { modelEnum: "MODEL_PLACEHOLDER_M36", maxOutputTokens: 65535 },
|
|
19709
|
-
"gemini-pro-agent": { modelEnum: "MODEL_PLACEHOLDER_M16", maxOutputTokens: 65535 },
|
|
19710
|
-
"claude-sonnet-5": { maxOutputTokens: 64e3 },
|
|
19711
|
-
"claude-sonnet-4-6": { maxOutputTokens: 64e3 },
|
|
19712
|
-
"claude-opus-4-6-thinking": { maxOutputTokens: 64e3 },
|
|
19713
|
-
"gemini-2.5-flash": { maxOutputTokens: 65536 },
|
|
19714
|
-
"gemini-2.5-pro": { maxOutputTokens: 65536 }
|
|
19715
|
-
};
|
|
19716
|
-
function resolveAntigravityWireModel(logicalModelId) {
|
|
19717
|
-
const id = logicalModelId.trim();
|
|
19718
|
-
const lower = id.toLowerCase();
|
|
19719
|
-
if (lower === "gemini-3.5-flash") {
|
|
19720
|
-
const wireModelId = "gemini-3.5-flash-low";
|
|
19721
|
-
return { wireModelId, profile: WIRE_PROFILES[wireModelId] };
|
|
19722
|
-
}
|
|
19723
|
-
if (lower === "gemini-3.7-flash" || ["gemini-3.7-flash-low", "gemini-3.7-flash-medium", "gemini-3.7-flash-high"].includes(lower)) {
|
|
19724
|
-
const wireModelId = "gemini-3.7-flash-tiered";
|
|
19725
|
-
return { wireModelId, profile: WIRE_PROFILES[wireModelId] };
|
|
19726
|
-
}
|
|
19727
|
-
if (lower === "gemini-3.8-flash" || ["gemini-3.8-flash-low", "gemini-3.8-flash-medium", "gemini-3.8-flash-high"].includes(lower)) {
|
|
19728
|
-
const wireModelId = "gemini-3.8-flash-tiered";
|
|
19729
|
-
return { wireModelId, profile: WIRE_PROFILES[wireModelId] };
|
|
19730
|
-
}
|
|
19731
|
-
if (lower === "gemini-3.6-flash") {
|
|
19732
|
-
const wireModelId = "gemini-3.6-flash-low";
|
|
19733
|
-
return { wireModelId, profile: WIRE_PROFILES[wireModelId] };
|
|
19734
|
-
}
|
|
19735
|
-
if (lower === "gemini-3.1-pro" || lower === "gemini-3.1-pro-preview") {
|
|
19736
|
-
const wireModelId = "gemini-3.1-pro-low";
|
|
19737
|
-
return { wireModelId, profile: WIRE_PROFILES[wireModelId] };
|
|
19738
|
-
}
|
|
19739
|
-
if (WIRE_PROFILES[id]) {
|
|
19740
|
-
return { wireModelId: id, profile: WIRE_PROFILES[id] };
|
|
19741
|
-
}
|
|
19742
|
-
return { wireModelId: id };
|
|
19743
|
-
}
|
|
19744
|
-
|
|
19745
|
-
// packages/agent-runtime/geminiNativeShared.ts
|
|
19746
|
-
var SKIP_THOUGHT_SIGNATURE = "skip_thought_signature_validator";
|
|
19747
|
-
function resolveGeminiModelQuirks(modelId) {
|
|
19748
|
-
const lower = modelId.toLowerCase();
|
|
19749
|
-
const isGemini3 = lower.includes("gemini-3");
|
|
19750
|
-
const isStrictSignatureModel = lower.includes("gemini-3.5") || lower.includes("flash-preview");
|
|
19751
|
-
const isClaude = lower.includes("claude");
|
|
19752
|
-
return {
|
|
19753
|
-
requiresThoughtSignature: isGemini3,
|
|
19754
|
-
allowsThoughtSignatureSentinel: isGemini3 && !isStrictSignatureModel,
|
|
19755
|
-
isClaudeCrossModel: isClaude
|
|
19756
|
-
};
|
|
19757
|
-
}
|
|
19758
|
-
function isGemini3Model(modelId) {
|
|
19759
|
-
return resolveGeminiModelQuirks(modelId).requiresThoughtSignature;
|
|
19760
|
-
}
|
|
19761
|
-
function messageText(content) {
|
|
19762
|
-
if (typeof content === "string") return content;
|
|
19763
|
-
if (!Array.isArray(content)) return "";
|
|
19764
|
-
return content.filter(
|
|
19765
|
-
(part) => part?.type === "text"
|
|
19766
|
-
).map((part) => part.text).join("\n").trim();
|
|
19767
|
-
}
|
|
19768
|
-
function parseDataUrlToInlineData(url) {
|
|
19769
|
-
const match7 = /^data:([A-Za-z0-9.+-]+\/[A-Za-z0-9.+-]+);base64,([A-Za-z0-9+/=]*)$/.exec(
|
|
19770
|
-
url
|
|
19771
|
-
);
|
|
19772
|
-
if (!match7) return null;
|
|
19773
|
-
return { mimeType: match7[1], data: match7[2] };
|
|
19774
|
-
}
|
|
19775
|
-
function extractInlineDataParts(content) {
|
|
19776
|
-
if (!Array.isArray(content)) return [];
|
|
19777
|
-
const parts2 = [];
|
|
19778
|
-
for (const part of content) {
|
|
19779
|
-
if (!part || typeof part !== "object") continue;
|
|
19780
|
-
if (part.type !== "image_url") continue;
|
|
19781
|
-
const url = part.image_url?.url;
|
|
19782
|
-
if (typeof url !== "string" || !url.trim()) continue;
|
|
19783
|
-
const inline = parseDataUrlToInlineData(url);
|
|
19784
|
-
if (inline) parts2.push({ inlineData: inline });
|
|
19785
|
-
}
|
|
19786
|
-
return parts2;
|
|
19787
|
-
}
|
|
19788
|
-
function convertOpenAiMessagesToGemini(messages, options) {
|
|
19789
|
-
const contents = [];
|
|
19790
|
-
const systemTexts = [];
|
|
19791
|
-
let toolCallIndex = 0;
|
|
19792
|
-
let pendingFunctionCalls = [];
|
|
19793
|
-
const pushOrMergeContent = (role, parts2) => {
|
|
19794
|
-
if (parts2.length === 0) return;
|
|
19795
|
-
const last = contents[contents.length - 1];
|
|
19796
|
-
if (last && last.role === role) {
|
|
19797
|
-
last.parts.push(...parts2);
|
|
19798
|
-
} else {
|
|
19799
|
-
contents.push({ role, parts: parts2 });
|
|
19800
|
-
}
|
|
19801
|
-
};
|
|
19802
|
-
const flushPendingFunctionCalls = () => {
|
|
19803
|
-
if (pendingFunctionCalls.length === 0) return;
|
|
19804
|
-
const dummyResponses = pendingFunctionCalls.map(
|
|
19805
|
-
({ name, id }) => ({
|
|
19806
|
-
functionResponse: {
|
|
19807
|
-
name,
|
|
19808
|
-
response: { output: "{}" },
|
|
19809
|
-
...id ? { id } : {}
|
|
19810
|
-
}
|
|
19811
|
-
})
|
|
19812
|
-
);
|
|
19813
|
-
pendingFunctionCalls = [];
|
|
19814
|
-
pushOrMergeContent("user", dummyResponses);
|
|
19815
|
-
};
|
|
19816
|
-
for (const raw of messages) {
|
|
19817
|
-
if (!raw || typeof raw !== "object" || !("role" in raw)) continue;
|
|
19818
|
-
const role = String(raw.role);
|
|
19819
|
-
const content = "content" in raw ? raw.content : null;
|
|
19820
|
-
if (role === "system") {
|
|
19821
|
-
const text = messageText(
|
|
19822
|
-
content
|
|
19823
|
-
);
|
|
19824
|
-
if (text) systemTexts.push(text);
|
|
19825
|
-
continue;
|
|
19826
|
-
}
|
|
19827
|
-
if (role === "user") {
|
|
19828
|
-
flushPendingFunctionCalls();
|
|
19829
|
-
const text = messageText(
|
|
19830
|
-
content
|
|
19831
|
-
);
|
|
19832
|
-
const imageParts = extractInlineDataParts(
|
|
19833
|
-
content
|
|
19834
|
-
);
|
|
19835
|
-
if (!text && imageParts.length === 0) continue;
|
|
19836
|
-
const parts2 = [];
|
|
19837
|
-
if (text) parts2.push({ text });
|
|
19838
|
-
for (const img of imageParts) parts2.push(img);
|
|
19839
|
-
pushOrMergeContent("user", parts2);
|
|
19840
|
-
continue;
|
|
19841
|
-
}
|
|
19842
|
-
if (role === "assistant") {
|
|
19843
|
-
flushPendingFunctionCalls();
|
|
19844
|
-
const text = messageText(
|
|
19845
|
-
content
|
|
19846
|
-
);
|
|
19847
|
-
const toolCalls = "tool_calls" in raw && Array.isArray(raw.tool_calls) ? raw.tool_calls ?? [] : [];
|
|
19848
|
-
const parts2 = [];
|
|
19849
|
-
if (text) {
|
|
19850
|
-
parts2.push({ text });
|
|
19851
|
-
}
|
|
19852
|
-
for (const call of toolCalls) {
|
|
19853
|
-
const name = call?.function?.name?.trim();
|
|
19854
|
-
if (!name) continue;
|
|
19855
|
-
const id = call.id?.trim() || `${name}_${toolCallIndex++}`;
|
|
19856
|
-
pendingFunctionCalls.push({ name, id });
|
|
19857
|
-
const realSignature = typeof call.thought_signature === "string" && call.thought_signature ? call.thought_signature : void 0;
|
|
19858
|
-
const isFirstFunctionCallPart = !parts2.some(
|
|
19859
|
-
(p) => "functionCall" in p
|
|
19860
|
-
);
|
|
19861
|
-
const signature = realSignature ?? (options.attachSkipThoughtSignature && isFirstFunctionCallPart ? SKIP_THOUGHT_SIGNATURE : void 0);
|
|
19862
|
-
const part = {
|
|
19863
|
-
functionCall: {
|
|
19864
|
-
name,
|
|
19865
|
-
args: parseToolArgs(call.function?.arguments),
|
|
19866
|
-
...id ? { id } : {}
|
|
19867
|
-
},
|
|
19868
|
-
...signature ? { thoughtSignature: signature } : {}
|
|
19869
|
-
};
|
|
19870
|
-
parts2.push(part);
|
|
19871
|
-
}
|
|
19872
|
-
pushOrMergeContent("model", parts2);
|
|
19873
|
-
continue;
|
|
19874
|
-
}
|
|
19875
|
-
if (role === "tool") {
|
|
19876
|
-
const toolCallId = "tool_call_id" in raw && typeof raw.tool_call_id === "string" ? raw.tool_call_id : "";
|
|
19877
|
-
const rawName = "name" in raw && typeof raw.name === "string" ? raw.name.trim() : "";
|
|
19878
|
-
const pendingIndex = pendingFunctionCalls.findIndex(
|
|
19879
|
-
(p) => toolCallId ? p.id === toolCallId : rawName ? p.name === rawName : true
|
|
19880
|
-
);
|
|
19881
|
-
if (pendingIndex === -1) continue;
|
|
19882
|
-
const [{ name, id }] = pendingFunctionCalls.splice(pendingIndex, 1);
|
|
19883
|
-
const output = messageText(content) || "{}";
|
|
19884
|
-
pushOrMergeContent("user", [
|
|
19885
|
-
{
|
|
19886
|
-
functionResponse: {
|
|
19887
|
-
name,
|
|
19888
|
-
response: { output },
|
|
19889
|
-
// 保留 OpenAI tool_call_id:antigravity Cloud Code Assist 网关把
|
|
19890
|
-
// Gemini contents 转成 Claude messages 时需要 functionResponse →
|
|
19891
|
-
// tool_result 的 tool_use_id;缺 id 时网关报
|
|
19892
|
-
// "tool_result.tool_use_id: Field required"(HTTP 400)。
|
|
19893
|
-
...id ? { id } : {}
|
|
19894
|
-
}
|
|
19895
|
-
}
|
|
19896
|
-
]);
|
|
19897
|
-
}
|
|
19898
|
-
}
|
|
19899
|
-
flushPendingFunctionCalls();
|
|
19900
|
-
if (contents.length > 0 && contents[0]?.role === "model") {
|
|
19901
|
-
contents.unshift({
|
|
19902
|
-
role: "user",
|
|
19903
|
-
parts: [{ text: "Continue the conversation." }]
|
|
19904
|
-
});
|
|
19905
|
-
}
|
|
19906
|
-
return { contents, systemTexts };
|
|
19907
|
-
}
|
|
19908
|
-
function parseToolArgs(raw) {
|
|
19909
|
-
if (typeof raw === "string") {
|
|
19910
|
-
try {
|
|
19911
|
-
const parsed = JSON.parse(raw);
|
|
19912
|
-
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
19913
|
-
return parsed;
|
|
19914
|
-
}
|
|
19915
|
-
} catch {
|
|
19916
|
-
}
|
|
19917
|
-
}
|
|
19918
|
-
if (raw && typeof raw === "object" && !Array.isArray(raw)) {
|
|
19919
|
-
return raw;
|
|
19920
|
-
}
|
|
19921
|
-
return {};
|
|
19922
|
-
}
|
|
19923
|
-
function sanitizeGeminiSchemaNode(node, active) {
|
|
19924
|
-
const out = {};
|
|
19925
|
-
if (!node || typeof node !== "object" || Array.isArray(node)) {
|
|
19926
|
-
return { type: "string" };
|
|
19927
|
-
}
|
|
19928
|
-
if (active?.has(node)) {
|
|
19929
|
-
return { type: "object", description: "(circular schema reference)" };
|
|
19930
|
-
}
|
|
19931
|
-
const seen = active ?? /* @__PURE__ */ new WeakSet();
|
|
19932
|
-
seen.add(node);
|
|
19933
|
-
try {
|
|
19934
|
-
return sanitizeGeminiSchemaNodeInner(node, out, seen);
|
|
19935
|
-
} finally {
|
|
19936
|
-
seen.delete(node);
|
|
19937
|
-
}
|
|
19938
|
-
}
|
|
19939
|
-
function sanitizeGeminiSchemaNodeInner(src, out, seen) {
|
|
19940
|
-
if (Array.isArray(src.type)) {
|
|
19941
|
-
const firstNonNull = src.type.find((t) => t !== "null");
|
|
19942
|
-
if (typeof firstNonNull === "string") out.type = firstNonNull;
|
|
19943
|
-
out.nullable = true;
|
|
19944
|
-
} else if (typeof src.type === "string") {
|
|
19945
|
-
out.type = src.type;
|
|
19946
|
-
}
|
|
19947
|
-
if (typeof src.description === "string") out.description = src.description;
|
|
19948
|
-
if (typeof src.minimum === "number") out.minimum = src.minimum;
|
|
19949
|
-
if (typeof src.maximum === "number") out.maximum = src.maximum;
|
|
19950
|
-
if (Array.isArray(src.enum) && src.enum.length > 0) out.enum = src.enum;
|
|
19951
|
-
if (src.nullable === true) out.nullable = true;
|
|
19952
|
-
if ("const" in src && src.const !== void 0 && !out.enum) {
|
|
19953
|
-
out.enum = [src.const];
|
|
19954
|
-
}
|
|
19955
|
-
const variantBranches = [
|
|
19956
|
-
...Array.isArray(src.oneOf) ? src.oneOf : [],
|
|
19957
|
-
...Array.isArray(src.anyOf) ? src.anyOf : []
|
|
19958
|
-
];
|
|
19959
|
-
if (variantBranches.length > 0) {
|
|
19960
|
-
const mergedProperties = {};
|
|
19961
|
-
let requiredIntersection;
|
|
19962
|
-
for (const branch of variantBranches) {
|
|
19963
|
-
const sanitized = sanitizeGeminiSchemaNode(branch, seen);
|
|
19964
|
-
const branchProperties = sanitized.properties ?? {};
|
|
19965
|
-
for (const [key, value] of Object.entries(branchProperties)) {
|
|
19966
|
-
const previous = mergedProperties[key];
|
|
19967
|
-
const prevEnum = previous?.enum;
|
|
19968
|
-
const nextEnum = value?.enum;
|
|
19969
|
-
if (prevEnum && nextEnum) {
|
|
19970
|
-
mergedProperties[key] = {
|
|
19971
|
-
...value,
|
|
19972
|
-
enum: [.../* @__PURE__ */ new Set([...prevEnum, ...nextEnum])]
|
|
19973
|
-
};
|
|
19974
|
-
} else {
|
|
19975
|
-
mergedProperties[key] = value;
|
|
19976
|
-
}
|
|
19977
|
-
}
|
|
19978
|
-
const branchRequired = Array.isArray(sanitized.required) ? sanitized.required : [];
|
|
19979
|
-
requiredIntersection = requiredIntersection === void 0 ? [...branchRequired] : requiredIntersection.filter((r) => branchRequired.includes(r));
|
|
19980
|
-
}
|
|
19981
|
-
out.properties = {
|
|
19982
|
-
...out.properties ?? {},
|
|
19983
|
-
...mergedProperties
|
|
19984
|
-
};
|
|
19985
|
-
if (requiredIntersection !== void 0 && requiredIntersection.length > 0) {
|
|
19986
|
-
out.required = requiredIntersection;
|
|
19987
|
-
}
|
|
19988
|
-
if (typeof out.type !== "string") out.type = "object";
|
|
19989
|
-
}
|
|
19990
|
-
if (Array.isArray(src.allOf)) {
|
|
19991
|
-
for (const branch of src.allOf) {
|
|
19992
|
-
const sanitized = sanitizeGeminiSchemaNode(branch, seen);
|
|
19993
|
-
out.properties = {
|
|
19994
|
-
...out.properties ?? {},
|
|
19995
|
-
...sanitized.properties ?? {}
|
|
19996
|
-
};
|
|
19997
|
-
if (Array.isArray(sanitized.required)) {
|
|
19998
|
-
out.required = [
|
|
19999
|
-
.../* @__PURE__ */ new Set([
|
|
20000
|
-
...out.required ?? [],
|
|
20001
|
-
...sanitized.required ?? []
|
|
20002
|
-
])
|
|
20003
|
-
];
|
|
20004
|
-
}
|
|
20005
|
-
}
|
|
20006
|
-
if (typeof out.type !== "string") out.type = "object";
|
|
20007
|
-
}
|
|
20008
|
-
if (src.properties && typeof src.properties === "object") {
|
|
20009
|
-
const properties = {};
|
|
20010
|
-
for (const [key, value] of Object.entries(
|
|
20011
|
-
src.properties
|
|
20012
|
-
)) {
|
|
20013
|
-
properties[key] = sanitizeGeminiSchemaNode(value, seen);
|
|
20014
|
-
}
|
|
20015
|
-
out.properties = properties;
|
|
20016
|
-
if (typeof out.type !== "string") out.type = "object";
|
|
20017
|
-
}
|
|
20018
|
-
if (Array.isArray(src.required)) {
|
|
20019
|
-
const properties = out.properties ?? {};
|
|
20020
|
-
const required = [...new Set(src.required)].filter(
|
|
20021
|
-
(r) => typeof r === "string" && r in properties
|
|
20022
|
-
);
|
|
20023
|
-
if (required.length > 0) out.required = required;
|
|
20024
|
-
}
|
|
20025
|
-
if (src.items !== void 0) {
|
|
20026
|
-
out.items = sanitizeGeminiSchemaNode(src.items, seen);
|
|
20027
|
-
if (typeof out.type !== "string") out.type = "array";
|
|
20028
|
-
}
|
|
20029
|
-
if (typeof out.type !== "string") out.type = "object";
|
|
20030
|
-
return out;
|
|
20031
|
-
}
|
|
20032
|
-
function convertOpenAiToolsToGemini(tools) {
|
|
20033
|
-
if (!Array.isArray(tools) || tools.length === 0) return void 0;
|
|
20034
|
-
const declarations = [];
|
|
20035
|
-
for (const tool of tools) {
|
|
20036
|
-
if (!tool || typeof tool !== "object" || !("function" in tool)) continue;
|
|
20037
|
-
const fn3 = tool.function;
|
|
20038
|
-
const name = typeof fn3.name === "string" ? fn3.name : "";
|
|
20039
|
-
if (!name) continue;
|
|
20040
|
-
declarations.push({
|
|
20041
|
-
name,
|
|
20042
|
-
description: typeof fn3.description === "string" ? fn3.description : "",
|
|
20043
|
-
parameters: sanitizeGeminiSchemaNode(
|
|
20044
|
-
fn3.parameters ?? { type: "object", properties: {} }
|
|
20045
|
-
)
|
|
20046
|
-
});
|
|
20047
|
-
}
|
|
20048
|
-
if (declarations.length === 0) return void 0;
|
|
20049
|
-
return [{ functionDeclarations: declarations }];
|
|
20050
|
-
}
|
|
20051
|
-
function createGeminiAccumulatorState() {
|
|
20052
|
-
return {
|
|
20053
|
-
text: "",
|
|
20054
|
-
toolCalls: [],
|
|
20055
|
-
reasoning: "",
|
|
20056
|
-
events: []
|
|
20057
|
-
};
|
|
20058
|
-
}
|
|
20059
|
-
function applyGeminiChunk(chunk, state, options) {
|
|
20060
|
-
if (!chunk || typeof chunk !== "object") return;
|
|
20061
|
-
const response = "response" in chunk && chunk.response && typeof chunk.response === "object" ? chunk.response : chunk;
|
|
20062
|
-
if ("usageMetadata" in response && response.usageMetadata && typeof response.usageMetadata === "object") {
|
|
20063
|
-
const meta = response.usageMetadata;
|
|
20064
|
-
const prompt = typeof meta.promptTokenCount === "number" ? meta.promptTokenCount : 0;
|
|
20065
|
-
const candidates2 = typeof meta.candidatesTokenCount === "number" ? meta.candidatesTokenCount : 0;
|
|
20066
|
-
const total = typeof meta.totalTokenCount === "number" ? meta.totalTokenCount : prompt + candidates2;
|
|
20067
|
-
const cached3 = typeof meta.cachedContentTokenCount === "number" && Number.isFinite(meta.cachedContentTokenCount) ? (
|
|
20068
|
-
// cached ⊆ prompt;对畸形上游防御性钳位,避免 cache_read > input 破坏归一化与计费
|
|
20069
|
-
Math.min(Math.max(0, Math.floor(meta.cachedContentTokenCount)), prompt)
|
|
20070
|
-
) : 0;
|
|
20071
|
-
state.usage = {
|
|
20072
|
-
prompt_tokens: prompt,
|
|
20073
|
-
completion_tokens: candidates2,
|
|
20074
|
-
total_tokens: total,
|
|
20075
|
-
...cached3 > 0 ? { cache_read_input_tokens: cached3 } : {}
|
|
20076
|
-
};
|
|
20077
|
-
state.events.push({ kind: "usage", usage: state.usage });
|
|
20078
|
-
}
|
|
20079
|
-
const candidates = Array.isArray(response.candidates) ? response.candidates : [];
|
|
20080
|
-
for (const candidate of candidates) {
|
|
20081
|
-
if (!candidate || typeof candidate !== "object") continue;
|
|
20082
|
-
const candidateFinishReason = candidate.finishReason;
|
|
20083
|
-
if (typeof candidateFinishReason === "string" && candidateFinishReason.trim()) {
|
|
20084
|
-
state.finishReason = candidateFinishReason.trim();
|
|
20085
|
-
state.events.push({ kind: "finish", reason: state.finishReason });
|
|
20086
|
-
}
|
|
20087
|
-
const parts2 = Array.isArray(
|
|
20088
|
-
candidate.content?.parts
|
|
20089
|
-
) ? candidate.content.parts : [];
|
|
20090
|
-
for (const part of parts2) {
|
|
20091
|
-
if (!part || typeof part !== "object") continue;
|
|
20092
|
-
const partSignature = part.thoughtSignature;
|
|
20093
|
-
const isThought = Boolean(part.thought);
|
|
20094
|
-
if ("text" in part && typeof part.text === "string") {
|
|
20095
|
-
const piece = part.text;
|
|
20096
|
-
if (!isThought) {
|
|
20097
|
-
state.text += piece;
|
|
20098
|
-
if (piece) {
|
|
20099
|
-
state.events.push({ kind: "text", text: piece });
|
|
20100
|
-
if (options?.onTextDelta) options.onTextDelta(piece);
|
|
20101
|
-
}
|
|
20102
|
-
} else {
|
|
20103
|
-
state.reasoning += piece;
|
|
20104
|
-
if (piece) {
|
|
20105
|
-
state.events.push({ kind: "reasoning", text: piece });
|
|
20106
|
-
if (options?.onReasoningDelta) options.onReasoningDelta(piece);
|
|
20107
|
-
}
|
|
20108
|
-
}
|
|
20109
|
-
}
|
|
20110
|
-
if (isThought && typeof partSignature === "string" && partSignature) {
|
|
20111
|
-
state.pendingThoughtSignature = partSignature;
|
|
20112
|
-
}
|
|
20113
|
-
if ("functionCall" in part && part.functionCall) {
|
|
20114
|
-
const call = part.functionCall;
|
|
20115
|
-
const name = typeof call.name === "string" ? call.name : "tool";
|
|
20116
|
-
const id = typeof call.id === "string" ? call.id : `${name}_${state.toolCalls.length}`;
|
|
20117
|
-
const argsObj = call.args && typeof call.args === "object" ? call.args : {};
|
|
20118
|
-
const resolvedSignature = typeof partSignature === "string" && partSignature ? partSignature : state.pendingThoughtSignature;
|
|
20119
|
-
state.pendingThoughtSignature = void 0;
|
|
20120
|
-
const toolCall = {
|
|
20121
|
-
id,
|
|
20122
|
-
type: "function",
|
|
20123
|
-
function: { name, arguments: JSON.stringify(argsObj) },
|
|
20124
|
-
...typeof resolvedSignature === "string" && resolvedSignature ? { thought_signature: resolvedSignature } : {}
|
|
20125
|
-
};
|
|
20126
|
-
state.toolCalls.push(toolCall);
|
|
20127
|
-
state.events.push({ kind: "tool_call", toolCall });
|
|
20128
|
-
}
|
|
20129
|
-
}
|
|
20130
|
-
}
|
|
20131
|
-
}
|
|
20132
|
-
function accumulateGeminiChunks(chunks2, options) {
|
|
20133
|
-
const state = createGeminiAccumulatorState();
|
|
20134
|
-
for (const chunk of chunks2) {
|
|
20135
|
-
applyGeminiChunk(chunk, state, options);
|
|
20136
|
-
}
|
|
20137
|
-
return {
|
|
20138
|
-
text: state.text,
|
|
20139
|
-
toolCalls: state.toolCalls,
|
|
20140
|
-
usage: state.usage,
|
|
20141
|
-
finishReason: state.finishReason,
|
|
20142
|
-
reasoningContent: state.reasoning,
|
|
20143
|
-
events: state.events
|
|
20144
|
-
};
|
|
20145
|
-
}
|
|
20146
|
-
async function accumulateGeminiStream(stream, options) {
|
|
20147
|
-
const state = createGeminiAccumulatorState();
|
|
20148
|
-
for await (const chunk of stream) {
|
|
20149
|
-
applyGeminiChunk(chunk, state, options);
|
|
20150
|
-
}
|
|
20151
|
-
return {
|
|
20152
|
-
text: state.text,
|
|
20153
|
-
toolCalls: state.toolCalls,
|
|
20154
|
-
usage: state.usage,
|
|
20155
|
-
finishReason: state.finishReason,
|
|
20156
|
-
reasoningContent: state.reasoning,
|
|
20157
|
-
events: state.events
|
|
20158
|
-
};
|
|
20159
|
-
}
|
|
20160
|
-
function shouldUseGeminiNativeToolRoute(provider, model, tools, isImageModel) {
|
|
20161
|
-
return provider === "google" && !isImageModel(model) && isGemini3Model(model) && Array.isArray(tools) && tools.length > 0;
|
|
20162
|
-
}
|
|
20163
|
-
function buildGeminiGenerateContentRequest(args2) {
|
|
20164
|
-
const { contents, systemTexts } = convertOpenAiMessagesToGemini(
|
|
20165
|
-
args2.messages,
|
|
20166
|
-
{ attachSkipThoughtSignature: args2.attachSkipThoughtSignature }
|
|
20167
|
-
);
|
|
20168
|
-
const request3 = { contents };
|
|
20169
|
-
if (systemTexts.length > 0) {
|
|
20170
|
-
request3.systemInstruction = {
|
|
20171
|
-
role: "user",
|
|
20172
|
-
parts: systemTexts.map((text) => ({ text }))
|
|
20173
|
-
};
|
|
20174
|
-
}
|
|
20175
|
-
const toolsResult = convertOpenAiToolsToGemini(args2.tools);
|
|
20176
|
-
if (toolsResult) {
|
|
20177
|
-
request3.tools = toolsResult;
|
|
20178
|
-
request3.toolConfig = { functionCallingConfig: { mode: "AUTO" } };
|
|
20179
|
-
}
|
|
20180
|
-
const generationConfig = {};
|
|
20181
|
-
if (typeof args2.maxTokens === "number" && args2.maxTokens > 0) {
|
|
20182
|
-
generationConfig.maxOutputTokens = args2.maxTokens;
|
|
20183
|
-
}
|
|
20184
|
-
if (typeof args2.temperature === "number") {
|
|
20185
|
-
generationConfig.temperature = args2.temperature;
|
|
20186
|
-
}
|
|
20187
|
-
if (Object.keys(generationConfig).length > 0) {
|
|
20188
|
-
request3.generationConfig = generationConfig;
|
|
20189
|
-
}
|
|
20190
|
-
return request3;
|
|
20191
|
-
}
|
|
20192
|
-
|
|
20193
|
-
// packages/agent-runtime/antigravityCloudCodeProvider.ts
|
|
20194
|
-
var STREAM_PATH = "/v1internal:streamGenerateContent?alt=sse";
|
|
20195
|
-
function buildCloudCodeAssistPayload(args2) {
|
|
20196
|
-
const projectId = readAntigravityProjectId(args2.metadata);
|
|
20197
|
-
if (!projectId) {
|
|
20198
|
-
throw new Error(
|
|
20199
|
-
"Antigravity OAuth credential is missing metadata.projectId. Re-run `nolo auth antigravity`."
|
|
20200
|
-
);
|
|
20201
|
-
}
|
|
20202
|
-
const logicalModel = asOptionalTrimmedString(args2.openAiBody.model) ?? asOptionalTrimmedString(args2.agentConfig.model) ?? "gemini-3.1-pro";
|
|
20203
|
-
const { wireModelId: model, profile } = resolveAntigravityWireModel(logicalModel);
|
|
20204
|
-
const rawMessages = Array.isArray(args2.openAiBody.messages) ? args2.openAiBody.messages : [];
|
|
20205
|
-
const quirks = resolveGeminiModelQuirks(model);
|
|
20206
|
-
const isClaude = quirks.isClaudeCrossModel;
|
|
20207
|
-
const { contents, systemTexts } = convertOpenAiMessagesToGemini(rawMessages, {
|
|
20208
|
-
attachSkipThoughtSignature: quirks.allowsThoughtSignatureSentinel
|
|
20209
|
-
});
|
|
20210
|
-
if (contents.length === 0) {
|
|
20211
|
-
throw new Error("Antigravity Cloud Code Assist request has no user/model contents.");
|
|
20212
|
-
}
|
|
20213
|
-
const prompt = args2.agentConfig.prompt?.trim();
|
|
20214
|
-
if (prompt) systemTexts.unshift(prompt);
|
|
20215
|
-
const request3 = { contents };
|
|
20216
|
-
if (systemTexts.length > 0) {
|
|
20217
|
-
request3.systemInstruction = {
|
|
20218
|
-
role: "user",
|
|
20219
|
-
parts: systemTexts.map((text) => ({ text }))
|
|
20220
|
-
};
|
|
20221
|
-
}
|
|
20222
|
-
const tools = convertOpenAiToolsToGemini(
|
|
20223
|
-
Array.isArray(args2.openAiBody.tools) ? args2.openAiBody.tools : void 0
|
|
20224
|
-
);
|
|
20225
|
-
if (tools) {
|
|
20226
|
-
request3.tools = tools;
|
|
20227
|
-
request3.toolConfig = { functionCallingConfig: { mode: "AUTO" } };
|
|
20228
|
-
}
|
|
20229
|
-
const generationConfig = {};
|
|
20230
|
-
if (profile?.maxOutputTokens) {
|
|
20231
|
-
generationConfig.maxOutputTokens = profile.maxOutputTokens;
|
|
20232
|
-
} else if (typeof args2.agentConfig.max_tokens === "number" && args2.agentConfig.max_tokens > 0) {
|
|
20233
|
-
generationConfig.maxOutputTokens = args2.agentConfig.max_tokens;
|
|
20234
|
-
}
|
|
20235
|
-
if (typeof args2.agentConfig.temperature === "number") {
|
|
20236
|
-
generationConfig.temperature = args2.agentConfig.temperature;
|
|
20237
|
-
}
|
|
20238
|
-
if (Object.keys(generationConfig).length > 0) {
|
|
20239
|
-
request3.generationConfig = generationConfig;
|
|
20240
|
-
}
|
|
20241
|
-
const agentId = randomUUID();
|
|
20242
|
-
const trajectoryId = randomUUID();
|
|
20243
|
-
const step = 2;
|
|
20244
|
-
const requestId = `agent/${agentId}/${Date.now()}/${trajectoryId}/${step}`;
|
|
20245
|
-
const labels = {
|
|
20246
|
-
trajectory_id: trajectoryId,
|
|
20247
|
-
last_step_index: String(step - 1),
|
|
20248
|
-
used_claude: String(isClaude),
|
|
20249
|
-
used_claude_conservative: String(isClaude)
|
|
20250
|
-
};
|
|
20251
|
-
if (profile?.modelEnum) {
|
|
20252
|
-
labels.model_enum = profile.modelEnum;
|
|
20253
|
-
}
|
|
20254
|
-
request3.labels = labels;
|
|
20255
|
-
request3.sessionId = `-${Math.floor(Math.random() * 9e15)}`;
|
|
20256
|
-
return {
|
|
20257
|
-
url: `${resolveAntigravityCloudCodeBaseUrl(args2.agentConfig.customProviderUrl)}${STREAM_PATH}`,
|
|
20258
|
-
envelope: {
|
|
20259
|
-
project: projectId,
|
|
20260
|
-
model,
|
|
20261
|
-
request: request3,
|
|
20262
|
-
requestId,
|
|
20263
|
-
requestType: "agent",
|
|
20264
|
-
userAgent: "antigravity"
|
|
20265
|
-
}
|
|
20266
|
-
};
|
|
20267
|
-
}
|
|
20268
|
-
function resolveAntigravityFinishReason(upstream) {
|
|
20269
|
-
const normalized = (upstream ?? "").trim().toUpperCase();
|
|
20270
|
-
if (normalized === "MAX_TOKENS") return "length";
|
|
20271
|
-
if (normalized === "SAFETY" || normalized === "RECITATION" || normalized === "PROHIBITED_CONTENT" || normalized === "BLOCKLIST") {
|
|
20272
|
-
return "content_filter";
|
|
20273
|
-
}
|
|
20274
|
-
return "stop";
|
|
20275
|
-
}
|
|
20276
|
-
function normalizeAntigravityCompletion(decoded) {
|
|
20277
|
-
const { text, toolCalls, usage, finishReason, reasoningContent, events } = decoded;
|
|
20278
|
-
const normalizedFinishReason = (finishReason ?? "").trim().toUpperCase();
|
|
20279
|
-
if (!text && !reasoningContent && toolCalls.length === 0 && !finishReason && !usage) {
|
|
20280
|
-
const body = {
|
|
20281
|
-
error: {
|
|
20282
|
-
message: "antigravity upstream returned an empty stream (no content, finishReason or usage); channel degradation, not model emptiness"
|
|
20283
|
-
},
|
|
20284
|
-
provider_events: events
|
|
20285
|
-
};
|
|
20286
|
-
return {
|
|
20287
|
-
status: 502,
|
|
20288
|
-
text: "",
|
|
20289
|
-
toolCalls: [],
|
|
20290
|
-
providerEvents: events,
|
|
20291
|
-
body
|
|
20292
|
-
};
|
|
20293
|
-
}
|
|
20294
|
-
if (normalizedFinishReason === "MALFORMED_FUNCTION_CALL") {
|
|
20295
|
-
const message2 = "antigravity upstream returned MALFORMED_FUNCTION_CALL (model generated an invalid function call or tool arguments were rejected by upstream)";
|
|
20296
|
-
const providerFailure = {
|
|
20297
|
-
kind: "provider_failure",
|
|
20298
|
-
provider: "antigravity",
|
|
20299
|
-
code: "MALFORMED_FUNCTION_CALL",
|
|
20300
|
-
message: message2,
|
|
20301
|
-
providerReason: "MALFORMED_FUNCTION_CALL",
|
|
20302
|
-
retryable: false,
|
|
20303
|
-
status: 502
|
|
20304
|
-
};
|
|
20305
|
-
return {
|
|
20306
|
-
status: 502,
|
|
20307
|
-
text: "",
|
|
20308
|
-
toolCalls: [],
|
|
20309
|
-
finishReason,
|
|
20310
|
-
providerEvents: events,
|
|
20311
|
-
providerFailure,
|
|
20312
|
-
runtimeProviderFailure: {
|
|
20313
|
-
message: providerFailure.message,
|
|
20314
|
-
retryable: providerFailure.retryable
|
|
20315
|
-
},
|
|
20316
|
-
body: {
|
|
20317
|
-
error: {
|
|
20318
|
-
message: message2,
|
|
20319
|
-
code: "MALFORMED_FUNCTION_CALL",
|
|
20320
|
-
category: "malformed_function_call",
|
|
20321
|
-
providerReason: "MALFORMED_FUNCTION_CALL",
|
|
20322
|
-
retryable: false
|
|
20323
|
-
},
|
|
20324
|
-
provider_failure: providerFailure,
|
|
20325
|
-
provider_events: events
|
|
20326
|
-
}
|
|
20327
|
-
};
|
|
20328
|
-
}
|
|
20329
|
-
const message = {
|
|
20330
|
-
role: "assistant",
|
|
20331
|
-
content: text || null
|
|
20332
|
-
};
|
|
20333
|
-
if (toolCalls.length > 0) message.tool_calls = toolCalls;
|
|
20334
|
-
if (reasoningContent) message.reasoning_content = reasoningContent;
|
|
20335
|
-
return {
|
|
20336
|
-
status: 200,
|
|
20337
|
-
text,
|
|
20338
|
-
...reasoningContent ? { reasoningContent } : {},
|
|
20339
|
-
toolCalls,
|
|
20340
|
-
...usage ? { usage } : {},
|
|
20341
|
-
...finishReason ? { finishReason } : {},
|
|
20342
|
-
providerEvents: events,
|
|
20343
|
-
body: {
|
|
20344
|
-
choices: [{
|
|
20345
|
-
index: 0,
|
|
20346
|
-
message,
|
|
20347
|
-
finish_reason: toolCalls.length > 0 ? "tool_calls" : resolveAntigravityFinishReason(finishReason)
|
|
20348
|
-
}],
|
|
20349
|
-
...usage ? { usage } : {},
|
|
20350
|
-
provider_events: events
|
|
20351
|
-
}
|
|
20352
|
-
};
|
|
20353
|
-
}
|
|
20354
|
-
async function fetchAntigravityCloudCodeCompletion(args2) {
|
|
20355
|
-
const fetchImpl = args2.fetchImpl ?? fetch;
|
|
20356
|
-
const { url, envelope } = buildCloudCodeAssistPayload(args2);
|
|
20357
|
-
const response = await fetchImpl(url, {
|
|
20358
|
-
method: "POST",
|
|
20359
|
-
headers: {
|
|
20360
|
-
Authorization: `Bearer ${args2.accessToken}`,
|
|
20361
|
-
"Content-Type": "application/json",
|
|
20362
|
-
"User-Agent": getAntigravityUserAgent()
|
|
20363
|
-
},
|
|
20364
|
-
body: JSON.stringify(envelope),
|
|
20365
|
-
signal: args2.signal
|
|
20366
|
-
});
|
|
20367
|
-
if (!response.ok) {
|
|
20368
|
-
const errorText = await response.text();
|
|
20369
|
-
return {
|
|
20370
|
-
status: response.status,
|
|
20371
|
-
text: "",
|
|
20372
|
-
toolCalls: [],
|
|
20373
|
-
providerEvents: [],
|
|
20374
|
-
// 保留上游结构:Antigravity 的限流 body 同样携带结构化的重置信息,
|
|
20375
|
-
// 压成字符串会让冷却退化成 5 分钟默认值。
|
|
20376
|
-
body: parseUpstreamErrorBody(errorText, response.statusText)
|
|
20377
|
-
};
|
|
20378
|
-
}
|
|
20379
|
-
const chunkStream = streamSseDataValues(response, parseSseDataLineJson);
|
|
20380
|
-
const { text, toolCalls, usage, finishReason, reasoningContent, events } = await accumulateGeminiStream(chunkStream, {
|
|
20381
|
-
onTextDelta: args2.onTextDelta,
|
|
20382
|
-
onReasoningDelta: args2.onReasoningDelta
|
|
20383
|
-
});
|
|
20384
|
-
const normalized = normalizeAntigravityCompletion({
|
|
20385
|
-
text,
|
|
20386
|
-
toolCalls,
|
|
20387
|
-
usage,
|
|
20388
|
-
finishReason,
|
|
20389
|
-
reasoningContent,
|
|
20390
|
-
events
|
|
20391
|
-
});
|
|
20392
|
-
if (normalized.status !== 200 || !text && toolCalls.length === 0) {
|
|
20393
|
-
console.warn(
|
|
20394
|
-
`[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}`
|
|
20395
|
-
);
|
|
20396
|
-
}
|
|
20397
|
-
return normalized;
|
|
20248
|
+
// packages/agent-runtime/sessionIdentity.ts
|
|
20249
|
+
import { createHash as createHash4 } from "node:crypto";
|
|
20250
|
+
var SALT = "nolo-session-identity-v1";
|
|
20251
|
+
function isStableSessionIdentityEnabled(env = process.env) {
|
|
20252
|
+
const v = env.NOLO_STABLE_SESSION_IDENTITY?.trim().toLowerCase();
|
|
20253
|
+
return !(v === "0" || v === "false" || v === "off");
|
|
20254
|
+
}
|
|
20255
|
+
function deriveStableUuid(sessionKey, purpose) {
|
|
20256
|
+
const h = createHash4("sha256").update(`${SALT}\0${purpose}\0${sessionKey}`).digest();
|
|
20257
|
+
h[6] = h[6] & 15 | 80;
|
|
20258
|
+
h[8] = h[8] & 63 | 128;
|
|
20259
|
+
const x = h.subarray(0, 16).toString("hex");
|
|
20260
|
+
return `${x.slice(0, 8)}-${x.slice(8, 12)}-${x.slice(12, 16)}-${x.slice(16, 20)}-${x.slice(20, 32)}`;
|
|
20261
|
+
}
|
|
20262
|
+
function resolveSessionKey(args2) {
|
|
20263
|
+
const d = args2.dialogId?.trim();
|
|
20264
|
+
return d ? `dialog:${d}` : void 0;
|
|
20398
20265
|
}
|
|
20399
20266
|
|
|
20400
20267
|
// packages/agent-runtime/devin/devinProvider.ts
|
|
20401
20268
|
import { randomBytes, randomUUID as randomUUID2 } from "node:crypto";
|
|
20402
20269
|
var CLIENT_NAME = "chisel";
|
|
20403
|
-
var CLIENT_VERSION = "
|
|
20270
|
+
var CLIENT_VERSION = "3000.11.3";
|
|
20404
20271
|
function writeVarint(fieldNum, value) {
|
|
20405
20272
|
const tag = fieldNum << 3 | 0;
|
|
20406
20273
|
const bytes = [];
|
|
@@ -20457,10 +20324,13 @@ function encodeDevinClientMetadata(token) {
|
|
|
20457
20324
|
writeStringField(31, generateFingerprint())
|
|
20458
20325
|
]);
|
|
20459
20326
|
}
|
|
20460
|
-
function
|
|
20327
|
+
function devinId(id, purpose) {
|
|
20328
|
+
return id?.sessionKey && isStableSessionIdentityEnabled() ? deriveStableUuid(id.sessionKey, purpose) : randomUUID2();
|
|
20329
|
+
}
|
|
20330
|
+
function encodeDevinChatMessage(msg, identity2, index = 0) {
|
|
20461
20331
|
const source = msg.role === "assistant" ? 2 : msg.role === "tool" ? 4 : 1;
|
|
20462
20332
|
return Buffer.concat([
|
|
20463
|
-
writeStringField(1,
|
|
20333
|
+
writeStringField(1, devinId(identity2, `msg:${index}:${msg.role}`)),
|
|
20464
20334
|
writeVarint(2, source),
|
|
20465
20335
|
writeStringField(3, msg.text),
|
|
20466
20336
|
...(msg.toolCalls ?? []).map(
|
|
@@ -20516,6 +20386,7 @@ function buildCompletionConfig(params) {
|
|
|
20516
20386
|
}
|
|
20517
20387
|
function buildGetChatMessageRequest(params) {
|
|
20518
20388
|
const { token, messages, model, tools = [], temperature } = params;
|
|
20389
|
+
const identity2 = { sessionKey: params.sessionKey };
|
|
20519
20390
|
const metadata = encodeDevinClientMetadata(token);
|
|
20520
20391
|
let systemPrompt = "";
|
|
20521
20392
|
const filteredMessages = [];
|
|
@@ -20545,7 +20416,7 @@ ${item.text}`;
|
|
|
20545
20416
|
coalesced.push({ ...item });
|
|
20546
20417
|
}
|
|
20547
20418
|
}
|
|
20548
|
-
const chatMessageBuffers = coalesced.map((m) => encodeDevinChatMessage(m));
|
|
20419
|
+
const chatMessageBuffers = coalesced.map((m, i) => encodeDevinChatMessage(m, identity2, i));
|
|
20549
20420
|
const completionConfig = buildCompletionConfig({ temperature });
|
|
20550
20421
|
const modelConfig = Buffer.concat([
|
|
20551
20422
|
writeStringField(1, randomUUID2()),
|
|
@@ -20775,6 +20646,11 @@ function decodeDevinResponsePayload(payload) {
|
|
|
20775
20646
|
}
|
|
20776
20647
|
return { content, reasoning, finishReason, events, usage };
|
|
20777
20648
|
}
|
|
20649
|
+
function isMeaningfulDevinEvent(event) {
|
|
20650
|
+
if (event.type === "reasoning" || event.type === "content") return event.text.length > 0;
|
|
20651
|
+
if (event.type === "tool-call-start") return !!event.name;
|
|
20652
|
+
return event.argsDelta.length > 0;
|
|
20653
|
+
}
|
|
20778
20654
|
function createDevinProvider(options) {
|
|
20779
20655
|
const { token, model = "swe-2-max", fetchImpl = fetch, tools = [], temperature } = options;
|
|
20780
20656
|
return {
|
|
@@ -20786,9 +20662,11 @@ function createDevinProvider(options) {
|
|
|
20786
20662
|
messages,
|
|
20787
20663
|
model: selectedModel,
|
|
20788
20664
|
tools,
|
|
20789
|
-
temperature
|
|
20665
|
+
temperature,
|
|
20666
|
+
sessionKey: resolveSessionKey({ dialogId: opts?.dialogId })
|
|
20790
20667
|
});
|
|
20791
20668
|
const frame = buildDevinConnectFrame(requestPayload);
|
|
20669
|
+
const timingTracker = createProviderCallTimingTracker();
|
|
20792
20670
|
const response = await fetchImpl(DEVIN_CONNECT_URL, {
|
|
20793
20671
|
method: "POST",
|
|
20794
20672
|
headers: {
|
|
@@ -20846,6 +20724,7 @@ function createDevinProvider(options) {
|
|
|
20846
20724
|
reasoning += delta.reasoning;
|
|
20847
20725
|
if (delta.finishReason) finishReason = delta.finishReason;
|
|
20848
20726
|
for (const event of delta.events) {
|
|
20727
|
+
if (isMeaningfulDevinEvent(event)) observeMeaningfulProviderResponse(timingTracker);
|
|
20849
20728
|
if (event.type === "reasoning") {
|
|
20850
20729
|
opts?.onReasoningDelta?.(event.text);
|
|
20851
20730
|
} else if (event.type === "content") {
|
|
@@ -20894,13 +20773,14 @@ function createDevinProvider(options) {
|
|
|
20894
20773
|
if (!text && !reasoning && toolCalls.length === 0) {
|
|
20895
20774
|
throw new Error("Devin Connect upstream completed without content or tool calls");
|
|
20896
20775
|
}
|
|
20897
|
-
const
|
|
20776
|
+
const timing = finalizeProviderCallTiming(timingTracker);
|
|
20777
|
+
const usage = frameUsage ? withProviderCallTimingFields({
|
|
20898
20778
|
prompt_tokens: frameUsage.prompt + frameUsage.cacheRead,
|
|
20899
20779
|
completion_tokens: frameUsage.completion ?? 0,
|
|
20900
20780
|
total_tokens: frameUsage.prompt + frameUsage.cacheRead + (frameUsage.completion ?? 0) + frameUsage.cacheWrite,
|
|
20901
20781
|
...frameUsage.cacheRead > 0 ? { prompt_tokens_details: { cached_tokens: frameUsage.cacheRead } } : {},
|
|
20902
20782
|
...frameUsage.cacheWrite > 0 ? { cache_creation_input_tokens: frameUsage.cacheWrite } : {}
|
|
20903
|
-
} : void 0;
|
|
20783
|
+
}, timing) : void 0;
|
|
20904
20784
|
return {
|
|
20905
20785
|
content: text,
|
|
20906
20786
|
model: selectedModel,
|
|
@@ -20922,20 +20802,16 @@ function createDevinProvider(options) {
|
|
|
20922
20802
|
}
|
|
20923
20803
|
|
|
20924
20804
|
export {
|
|
20805
|
+
readCommandActionGatePayload,
|
|
20806
|
+
readActionGate,
|
|
20925
20807
|
Option_exports,
|
|
20926
20808
|
Duration_exports,
|
|
20927
20809
|
Exit_exports,
|
|
20928
20810
|
Effect_exports,
|
|
20929
|
-
readCommandActionGatePayload,
|
|
20930
|
-
readActionGate,
|
|
20931
|
-
evaluateFileWritePolicy,
|
|
20932
|
-
summarizeToolArguments,
|
|
20933
20811
|
formatToolOverflowMarker,
|
|
20934
20812
|
LOCAL_AGENT_CONFIG_MISSING_CODE,
|
|
20935
20813
|
LOCAL_TURN_ABORTED_CODE,
|
|
20936
20814
|
runLocalAgentTurn,
|
|
20937
|
-
parseSseDataLineJson,
|
|
20938
|
-
parseSseDataLineObject,
|
|
20939
20815
|
codexStreamFailureStatus,
|
|
20940
20816
|
aggregateResponsesStream,
|
|
20941
20817
|
buildOpenAiCompatibleChatCompletionRequest,
|
|
@@ -20969,13 +20845,9 @@ export {
|
|
|
20969
20845
|
buildLocalDialogWritePlan,
|
|
20970
20846
|
buildNoloWorkspaceCliToolExecutors,
|
|
20971
20847
|
buildLoadSkillExecutor,
|
|
20972
|
-
|
|
20973
|
-
|
|
20974
|
-
|
|
20975
|
-
shouldUseGeminiNativeToolRoute,
|
|
20976
|
-
buildGeminiGenerateContentRequest,
|
|
20977
|
-
resolveAntigravityFinishReason,
|
|
20978
|
-
fetchAntigravityCloudCodeCompletion,
|
|
20848
|
+
isStableSessionIdentityEnabled,
|
|
20849
|
+
deriveStableUuid,
|
|
20850
|
+
resolveSessionKey,
|
|
20979
20851
|
readDevinUpstreamFailure,
|
|
20980
20852
|
createDevinProvider
|
|
20981
20853
|
};
|