nolo-cli 0.102.0-alpha.1 → 0.102.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-LUNEV235.js → _executeModel-WLFACVFR.js} +74 -67
- package/action-PNPQLJHG.js +20 -0
- package/{addContentAction-O7R66HEX.js → addContentAction-RBOUD7SJ.js} +12 -11
- package/{addDialogAgentAction-74OA7KYP.js → addDialogAgentAction-IODCR6TB.js} +18 -19
- package/{agentDeleteCommand-2YAHAZFJ.js → agentDeleteCommand-XHHDYJ3U.js} +117 -42
- package/{agentEmailCommands-G6A7IRPQ.js → agentEmailCommands-GJ2TE3CV.js} +97 -87
- package/agentListCommands-B3YHJQNM.js +742 -0
- package/{agentMachineCommands-W2SMNSQ3.js → agentMachineCommands-KQLRJF5O.js} +48 -43
- package/{agentProviderCommands-GNPTL5XR.js → agentProviderCommands-XPJYZSCE.js} +97 -2
- package/{agentPullCommand-O5MPVJ5E.js → agentPullCommand-B4T2DJ5H.js} +1 -1
- package/agentRecordCommands-LXDIXYQM.js +138 -0
- package/agentRunCommand-P2KLVSYL.js +167 -0
- package/{agentRunControl-AVJR4JW4.js → agentRunControl-3HWA2LLQ.js} +2 -2
- package/{agentRuntimeLocal-VXZSDIGT.js → agentRuntimeLocal-SXYAKX3A.js} +48 -39
- package/{agentSlice-5YJHUO47.js → agentSlice-WBSSBKBB.js} +14 -13
- package/{appDeleteCommands-32MHLR4L.js → appDeleteCommands-4EX37I4K.js} +46 -41
- package/{appDeployCommands-WCQOUSOB.js → appDeployCommands-SDBR3J75.js} +46 -41
- package/{appDeployStatusCommands-6QKB7DYN.js → appDeployStatusCommands-764PQNYN.js} +46 -41
- package/{appGetCommands-SFAPP5PB.js → appGetCommands-BBCN3XJC.js} +46 -41
- package/{appListCommands-EKUBDRUO.js → appListCommands-OGTABCS3.js} +46 -41
- package/{authCommand-F4EFRRX6.js → authCommand-NHDLY3IB.js} +118 -24
- package/{authCommands-RGOGCPP6.js → authCommands-UDBJVSZU.js} +7 -5
- package/{builtinSkillRegistry-FUAVTRVZ.js → builtinSkillRegistry-MAR5LPAC.js} +10 -8
- package/{chromeCommands-FZYAU75D.js → chromeCommands-K27J4OVZ.js} +124 -28
- package/{chromeOpsCommands-62P2Q2YB.js → chromeOpsCommands-IXRLN57H.js} +4 -3
- package/{chunk-6OZ36FXI.js → chunk-27ONFIEY.js} +22 -4
- package/{chunk-JEDZAO7L.js → chunk-2SYTUTLI.js} +257 -37
- package/{chunk-53HEEOTT.js → chunk-2WJ57RJA.js} +83 -16
- package/{chunk-OIVSQH2O.js → chunk-3BXNTXYI.js} +299 -5
- package/{chunk-ABQYVJBJ.js → chunk-46Y5D2BZ.js} +5 -5
- package/{chunk-EYAQT56M.js → chunk-4DPP773Q.js} +2 -2
- package/{chunk-H62HCIUP.js → chunk-4FFUDT6D.js} +24 -21
- package/chunk-4LCOCOR5.js +50 -0
- package/{chunk-2GRGFCF6.js → chunk-4VJAC32I.js} +2 -1
- package/{chunk-IIVGDG4I.js → chunk-4YSOUKUR.js} +13 -7
- package/{chunk-MC4XLIJ7.js → chunk-523DITKR.js} +1 -1
- package/{chunk-E4MARS3Q.js → chunk-5GVBDNTO.js} +1 -1
- package/chunk-5J3PYNUP.js +255 -0
- package/{chunk-DRGSDQBL.js → chunk-5LTAPGPV.js} +10 -10
- package/chunk-5MMAK75Q.js +15 -0
- package/{chunk-JPGCXHNM.js → chunk-5OA5HMTL.js} +1 -1
- package/{chunk-42V6BK2E.js → chunk-62IL3KQV.js} +4 -34
- package/{chunk-3BMYXEUW.js → chunk-6O4IK4V2.js} +1 -1
- package/{chunk-AEOE4Z6Q.js → chunk-7EPXUZOX.js} +39 -15
- package/{chunk-GQBOR3G6.js → chunk-7KVZ5LDQ.js} +2 -2
- package/{chunk-DNCEALKX.js → chunk-7MMSLEPA.js} +22 -29
- package/{chunk-L5UXH3B2.js → chunk-7TKWCTSY.js} +22 -6
- package/chunk-A4SQRTZ6.js +15 -0
- package/{chunk-7S4YWN7P.js → chunk-ADBZWMFB.js} +4 -4
- package/chunk-AGIM7IMJ.js +147 -0
- package/{chunk-SSDAAEC2.js → chunk-AOJB5QYD.js} +873 -227
- package/{chunk-5UTFL4QJ.js → chunk-AOTBKDRK.js} +7 -0
- package/{chunk-Q554LLSI.js → chunk-AUDNYVRC.js} +1 -1
- package/chunk-BMQ2MJUK.js +153 -0
- package/{chunk-6YTOJY35.js → chunk-BZ7NPA6G.js} +35 -2
- package/{chunk-4S5QUMJP.js → chunk-CHNCM7EF.js} +11 -9
- package/chunk-CHOZJMJS.js +78 -0
- package/chunk-CJN5OERD.js +13545 -0
- package/{chunk-ACTMNVHM.js → chunk-CYSYR67N.js} +1 -1
- package/{chunk-GBRG75BQ.js → chunk-D2MDMY2M.js} +1 -0
- package/{chunk-RFCKMYDK.js → chunk-DNHENQ3T.js} +23 -28
- package/chunk-DZ7R5V3Y.js +164 -0
- package/{chunk-3VNWWVKB.js → chunk-E3YWHWCR.js} +50 -18
- package/{chunk-V4MJDUSR.js → chunk-E73ON47R.js} +2 -2
- package/{chunk-ETI2NYVF.js → chunk-EHER73LN.js} +4 -4
- package/{chunk-KQ4ONNQD.js → chunk-EKPKW6RM.js} +155 -8
- package/{chunk-TRV2MIDW.js → chunk-EXAJ6DCR.js} +1 -0
- package/{chunk-HJUYAD4A.js → chunk-FJ5BGMNM.js} +5 -5
- package/{chunk-2F7RJC6L.js → chunk-FOXQ7BAB.js} +1 -1
- package/{chunk-6VFARHZW.js → chunk-G53AA7RW.js} +934 -1091
- package/{chunk-J4MOO56S.js → chunk-GARACBQB.js} +10 -2
- package/chunk-GMZLP5DV.js +82 -0
- package/{chunk-5FBTLSFG.js → chunk-GUYEMTRK.js} +551 -516
- 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-VLTIYV3X.js → chunk-HP57OUJO.js} +4 -4
- package/{chunk-6IG4XSS6.js → chunk-HRYFI64G.js} +88 -17
- package/{chunk-GPCZ7UXG.js → chunk-K6U4NKFJ.js} +1 -1
- package/{chunk-6Q33GUCC.js → chunk-KLUBZL6X.js} +1 -1
- package/{chunk-4OEFYTWL.js → chunk-LKERWYPX.js} +67 -48
- package/{chunk-LS2ZANRJ.js → chunk-LOCNXNOU.js} +1 -1
- package/{chunk-PUOC4YRO.js → chunk-M7VLQGQP.js} +11 -0
- package/{chunk-NA35QHCF.js → chunk-N4QIAW6W.js} +1 -1
- package/{chunk-BFU6C242.js → chunk-NMFV26UG.js} +1 -1
- package/{chunk-OEVAY4J6.js → chunk-NTDEBTK5.js} +18 -20
- package/{chunk-FZGV4FGK.js → chunk-NUHHBEJC.js} +378 -187
- package/chunk-NWENLDMM.js +42 -0
- package/chunk-OCZKATRC.js +129 -0
- package/{chunk-G2O6V3HJ.js → chunk-ODTDLPBV.js} +20 -11
- package/chunk-OW4APERY.js +870 -0
- package/{chunk-KQHGZWSV.js → chunk-OXME3PEE.js} +1 -1
- package/{chunk-Q2XN3EOZ.js → chunk-OYPMWCIQ.js} +67 -45
- package/{chunk-TOP2VXOR.js → chunk-PCF3QU5Q.js} +5 -5
- package/chunk-PH275YDS.js +7881 -0
- package/{chunk-WV42OMV7.js → chunk-PTDYOADJ.js} +8 -8
- package/{chunk-GEPUP7OO.js → chunk-SEA64CDY.js} +3 -3
- package/{chunk-5H7KJX7J.js → chunk-SEB5HAUU.js} +5 -5
- package/{chunk-6D6VBVEW.js → chunk-SNMQMOD2.js} +80 -14
- package/{chunk-BYMV6QZG.js → chunk-TNIX77YM.js} +4 -0
- package/{chunk-Z77CRGTW.js → chunk-TVCAR26G.js} +1 -1
- package/chunk-TY3TIUJK.js +89 -0
- package/{chunk-I3TQJXQ7.js → chunk-U3C3IA32.js} +9 -2
- package/{chunk-ORYWEJO4.js → chunk-U6IGAJT4.js} +47 -67
- package/{chunk-RG6JBBX5.js → chunk-U7XXEI5R.js} +166 -13
- package/{chunk-UZGQNTVW.js → chunk-UA324D4O.js} +8 -6
- package/chunk-UJXNKP5V.js +760 -0
- package/{chunk-UKZDAFYT.js → chunk-UM4PH574.js} +6 -10
- package/{chunk-ZCYXJSTU.js → chunk-V5OWQOJZ.js} +19 -88
- package/{chunk-3DII57IT.js → chunk-VCAQFMVN.js} +1 -1
- package/{chunk-JRQFUXY7.js → chunk-VEYL5MO5.js} +99 -22
- package/chunk-VIWDGTDA.js +8 -0
- package/chunk-VJVNU77E.js +83 -0
- package/{chunk-UKWGR5SS.js → chunk-VY6VFGKR.js} +194 -1144
- package/{chunk-BP4XNZRM.js → chunk-W72ISAKC.js} +4 -4
- package/{chunk-DHDMC6FO.js → chunk-WCGC6S77.js} +14 -9
- package/{chunk-QDSINZM3.js → chunk-WJ3B6FX6.js} +1 -14
- package/{chunk-HVURBGF3.js → chunk-XFUBXRVI.js} +6 -6
- package/{chunk-45C5ER5U.js → chunk-XIRXOUBV.js} +19 -17
- package/{chunk-O6OSWFZQ.js → chunk-XUWRURDF.js} +6 -0
- package/{chunk-Q67DOFOO.js → chunk-Y3PMXGLH.js} +2 -0
- package/{chunk-SH43IESU.js → chunk-YUNJN43V.js} +44 -9
- package/chunk-YV25TM3R.js +780 -0
- package/{chunk-X6DN5HBD.js → chunk-YXZYNMYK.js} +29 -9
- package/{chunk-BTI7PJDX.js → chunk-Z56IK6UT.js} +29 -78
- package/chunk-ZRAU6T47.js +56 -0
- package/commandRegistry-TDXN5OP7.js +833 -0
- package/{contentThunks-GJV22WVZ.js → contentThunks-F2BNWOZV.js} +36 -34
- package/{cooldownCommands-REAWYVTY.js → cooldownCommands-ZLEPIB4A.js} +2 -2
- package/{createAgentAutomationAction-6V25TZEO.js → createAgentAutomationAction-5N2NRNR7.js} +38 -36
- package/createDialogAction-DSEG4L5Y.js +69 -0
- package/{createPageAction-IR4BGJSI.js → createPageAction-K32FYQPE.js} +45 -42
- package/{chunk-YFE4A4O7.js → cursorProvider-YGGNMVWX.js} +2496 -9897
- package/{dbSlice-XVWBAGYN.js → dbSlice-Q25STFGJ.js} +11 -10
- package/{deleteFile-YG6QMJLU.js → deleteFile-AJ2EZMHT.js} +7 -6
- package/{dialogCommands-5J56DFWN.js → dialogCommands-ODG2OKLO.js} +49 -45
- package/{dialogSlice-UNX2FAPZ.js → dialogSlice-4GBOUTGL.js} +40 -33
- package/{dist-VODFSGNG.js → dist-NJC2W7I4.js} +61 -54
- package/{docCreateCommands-KYI2DC2U.js → docCreateCommands-Q6FQUHUF.js} +48 -43
- package/{docDeleteCommands-67REUSRY.js → docDeleteCommands-N224CFZL.js} +49 -44
- package/{docReadCommands-HOSVSBDJ.js → docReadCommands-CJWAEAB4.js} +47 -42
- package/{docStore-JWVG5NDO.js → docStore-ZTYSP3YE.js} +16 -12
- package/{docUpdateCommands-EMGCSMXY.js → docUpdateCommands-OPG6ZY4H.js} +48 -43
- package/{fetchMessages-EIU7UFFK.js → fetchMessages-I5ICDDHM.js} +5 -5
- package/{getPricing-LUSEABA6.js → getPricing-NMMFT3YI.js} +4 -4
- package/{handleSendMessageAction-B75UOJKF.js → handleSendMessageAction-XFZH2TQS.js} +110 -86
- package/index.js +87 -884
- package/{lib-FRRS27KN.js → lib-PU2G2MSO.js} +523 -191
- package/{localDialogRead-BTFJ4V2I.js → localDialogRead-ZHZ3KXDM.js} +2 -2
- package/{localRuntimeAuthority-6IR6BBXE.js → localRuntimeAuthority-TU6OBC76.js} +9 -6
- package/{localRuntimeDb-SYQGUF4U.js → localRuntimeDb-VKWVOPPI.js} +1 -1
- package/{machineCommands-GFPTOY6L.js → machineCommands-KMU3D5I5.js} +91 -81
- package/machineWsRunDispatch-6GJ5YOSW.js +154 -0
- package/{memberThunks-QGFLFVCI.js → memberThunks-R75S3RWP.js} +20 -18
- package/{models-T3SG6MJ5.js → models-ZPU5EDF4.js} +2 -2
- package/oauthTokenStore-ITEB663N.js +23 -0
- package/package.json +1 -1
- package/pdf-U6KSUEZZ.js +26435 -0
- package/processSpawn-SOAV3FEV.js +11 -0
- package/profileConfig-ZGOFORWV.js +43 -0
- package/{providerPresetApply-FG6NZ57W.js → providerPresetApply-TEBH7FDX.js} +7 -7
- package/{providerRegistry-757OWH3O.js → providerRegistry-CBJLNCET.js} +11 -7
- package/{read-COE3ZYR6.js → read-SRQMNO26.js} +7 -6
- package/{readDocTool-5USN4A6V.js → readDocTool-RC3JUNJ2.js} +5 -3
- package/{readlineWorkspace-UFSWHFKD.js → readlineWorkspace-EXCG3IFX.js} +2704 -2060
- package/{removeDialogAgentAction-IX3MN2ZO.js → removeDialogAgentAction-46XQV5Q7.js} +21 -25
- package/{runAgentClientLoop-25LJ4XGV.js → runAgentClientLoop-URRDZ5WG.js} +75 -69
- package/{runtimeDoctorCommands-X6WDBEQX.js → runtimeDoctorCommands-PIVSBZRZ.js} +4 -4
- package/runtimeModeArgs-2Y7BALTO.js +31 -0
- package/{setDialogExtraReferencesAction-X4HCPNZL.js → setDialogExtraReferencesAction-J4V5ADQF.js} +15 -13
- package/{setPrimaryDialogAgentAction-4GMIQLOD.js → setPrimaryDialogAgentAction-UHHV2QZW.js} +22 -26
- package/{chunk-AFUORTY4.js → settingThunks-PPZZZOWN.js} +226 -940
- package/{skillDiscovery-CYUCJMAG.js → skillDiscovery-ZBU76COE.js} +3 -3
- package/{slateUtils-RIZES3PV.js → slateUtils-NGV2NMKM.js} +1 -1
- package/{spaceCommands-NKJVJCQQ.js → spaceCommands-7CLUNI2I.js} +51 -46
- package/{streamAgentChatTurn-A46QFV4O.js → streamAgentChatTurn-YPUYKXDX.js} +206 -105
- package/{switchDialogAgentAction-N52LRPA3.js → switchDialogAgentAction-A2TMVGAE.js} +18 -19
- package/{tableCommands-O6NWHFKV.js → tableCommands-6U4BMLRR.js} +10 -10
- package/{toolApiClient-QVJ6HDNN.js → toolApiClient-EJT6TMFG.js} +3 -3
- package/tools-M5ENXZRJ.js +116 -0
- package/{tuiSummaryLlmCaller-WFRWERGK.js → tuiSummaryLlmCaller-Q65IBDGO.js} +24 -21
- package/{updateCommands-2M74UL7P.js → updateCommands-4EHDLF5J.js} +3 -3
- package/{updateDialogTitleAction-QJPZGF52.js → updateDialogTitleAction-7PNUE23W.js} +82 -44
- package/action-YVYQEAAV.js +0 -31
- package/agentListCommands-KMS675GZ.js +0 -406
- package/agentRecordCommands-D7BRMFNI.js +0 -128
- package/agentRunCommand-VL6MMEUB.js +0 -155
- package/browser-image-compression-MFDTD7K6.js +0 -1763
- package/chatQueueReduxAdapter-PQMRR2PK.js +0 -186
- package/chunk-M76ECQRD.js +0 -13658
- package/chunk-MEYIRKDN.js +0 -8967
- package/chunk-Q5FJJ6XI.js +0 -103
- package/chunk-QVKRR2SS.js +0 -20782
- package/chunk-S7Z2HMCN.js +0 -25
- package/chunk-Y5GCAMGP.js +0 -9
- package/chunk-YPREESF4.js +0 -225
- package/createDialogAction-SX36BGSX.js +0 -65
- package/machineWsRunDispatch-46PSZ3DJ.js +0 -144
- package/settingSlice-ZQZVUPKK.js +0 -204
- package/syncMapping-N6RGXGBW.js +0 -437
- package/tools-TTDGRNY6.js +0 -110
- package/{chunk-VMFTFOWF.js → chunk-3AH7LNUB.js} +7 -7
- package/{chunk-X7HHHIOZ.js → chunk-Y6ROFCZO.js} +0 -0
- package/{db-WK5MDZVN.js → db-VQSAOWAO.js} +1 -1
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
import {
|
|
2
|
+
DEVIN_CONNECT_URL,
|
|
3
|
+
parseSseDataLineJson,
|
|
4
|
+
parseSseDataLineObject
|
|
5
|
+
} from "./chunk-OW4APERY.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-V5OWQOJZ.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,7 +27,7 @@ import {
|
|
|
20
27
|
resolveHistoricalToolContentCap,
|
|
21
28
|
resolveToolOutputProfile,
|
|
22
29
|
stripImagePartsFromMessages
|
|
23
|
-
} from "./chunk-
|
|
30
|
+
} from "./chunk-SEB5HAUU.js";
|
|
24
31
|
import {
|
|
25
32
|
downgradeUnparsableToolCalls,
|
|
26
33
|
hasParsableObjectArguments,
|
|
@@ -35,6 +42,7 @@ import {
|
|
|
35
42
|
finalizeAccumulatedToolCalls
|
|
36
43
|
} from "./chunk-N7J63Q6C.js";
|
|
37
44
|
import {
|
|
45
|
+
DELETE_SAFETY_RED_LINE,
|
|
38
46
|
TOOL_GUIDED_SECTION_ORDER,
|
|
39
47
|
buildIdentityBlock,
|
|
40
48
|
buildRuntimeGuidanceBlocks,
|
|
@@ -46,17 +54,18 @@ import {
|
|
|
46
54
|
requiresBareImageUrl,
|
|
47
55
|
resolveToolGuidedSections,
|
|
48
56
|
toBareImageUrlMessages
|
|
49
|
-
} from "./chunk-
|
|
57
|
+
} from "./chunk-7TKWCTSY.js";
|
|
50
58
|
import {
|
|
51
59
|
convertMessagesToResponsesInput,
|
|
52
60
|
extractReasoningFromResponseOutput,
|
|
53
61
|
extractTextFromResponseOutput,
|
|
54
62
|
extractToolCallsFromResponseOutput,
|
|
55
63
|
getUsageRequestOptions,
|
|
64
|
+
shouldReplayReasoningContentForOutbound,
|
|
56
65
|
shouldStripReasoningContentForOutbound,
|
|
57
66
|
toOpenAiCompatibleMessages,
|
|
58
67
|
toResponsesTools
|
|
59
|
-
} from "./chunk-
|
|
68
|
+
} from "./chunk-M7VLQGQP.js";
|
|
60
69
|
import {
|
|
61
70
|
BRIDGE_STREAM_MAX_CHARS,
|
|
62
71
|
DEFAULT_READ_DIALOG_MAX_RESPONSE_CHARS,
|
|
@@ -64,22 +73,14 @@ import {
|
|
|
64
73
|
applyToolSurfaceConstraints,
|
|
65
74
|
buildDialogReadEnvelope,
|
|
66
75
|
buildNoloWorkspaceCommandArgs,
|
|
76
|
+
buildNoloWorkspaceOpenAiTools,
|
|
67
77
|
createStreamingDialogReadProjector,
|
|
68
78
|
noloPositiveIntegerString,
|
|
69
79
|
noloStringArg,
|
|
70
80
|
parseNoloWorkspaceToolArguments,
|
|
71
81
|
readTextStreamUpToChars,
|
|
72
82
|
resolveNoloDialogInput
|
|
73
|
-
} from "./chunk-
|
|
74
|
-
import {
|
|
75
|
-
getAntigravityUserAgent,
|
|
76
|
-
readAntigravityProjectId,
|
|
77
|
-
resolveAntigravityCloudCodeBaseUrl
|
|
78
|
-
} from "./chunk-UZGQNTVW.js";
|
|
79
|
-
import {
|
|
80
|
-
buildProviderAuthHeaders,
|
|
81
|
-
buildProviderExecutionPlan
|
|
82
|
-
} from "./chunk-6OZ36FXI.js";
|
|
83
|
+
} from "./chunk-4YSOUKUR.js";
|
|
83
84
|
import {
|
|
84
85
|
buildDialogFallbackTitleFromUserInput
|
|
85
86
|
} from "./chunk-2MBTWINN.js";
|
|
@@ -93,13 +94,12 @@ import {
|
|
|
93
94
|
resolveEmptyAssistantFallbackMessage,
|
|
94
95
|
resolveEmptyAssistantOutcome,
|
|
95
96
|
resolveTruncatedReasoningTailLog
|
|
96
|
-
} from "./chunk-
|
|
97
|
+
} from "./chunk-LKERWYPX.js";
|
|
97
98
|
import {
|
|
98
99
|
COMPACTION_SUMMARY_SCHEMA_VERSION,
|
|
99
100
|
COMPACTION_SUMMARY_SYSTEM_PROMPT,
|
|
100
101
|
buildCompactionMetricsFromPlan,
|
|
101
102
|
buildCompactionUserContent,
|
|
102
|
-
clipCompactText,
|
|
103
103
|
createProviderCallTimingTracker,
|
|
104
104
|
finalizeProviderCallTiming,
|
|
105
105
|
formatCompactionMetricsLog,
|
|
@@ -112,37 +112,36 @@ import {
|
|
|
112
112
|
resolveCompressionTriggerRatio,
|
|
113
113
|
truncateToolOutputForContext,
|
|
114
114
|
withProviderCallTimingFields
|
|
115
|
-
} from "./chunk-
|
|
115
|
+
} from "./chunk-7MMSLEPA.js";
|
|
116
|
+
import {
|
|
117
|
+
clipCompactText
|
|
118
|
+
} from "./chunk-5MMAK75Q.js";
|
|
119
|
+
import {
|
|
120
|
+
asRecordOrEmpty
|
|
121
|
+
} from "./chunk-KX6YBIHG.js";
|
|
116
122
|
import {
|
|
117
123
|
estimateTokenCount
|
|
118
124
|
} from "./chunk-PSCNXBYA.js";
|
|
119
125
|
import {
|
|
120
126
|
resolveNoloStateDir
|
|
121
|
-
} from "./chunk-
|
|
122
|
-
import {
|
|
123
|
-
toErrorMessage
|
|
124
|
-
} from "./chunk-HNMXYYJR.js";
|
|
127
|
+
} from "./chunk-HNGRBWYF.js";
|
|
125
128
|
import {
|
|
126
129
|
buildDialogSummaryLayer
|
|
127
|
-
} from "./chunk-
|
|
130
|
+
} from "./chunk-HDLLCBRF.js";
|
|
128
131
|
import {
|
|
129
132
|
buildUserResponseLanguageContext
|
|
130
|
-
} from "./chunk-
|
|
133
|
+
} from "./chunk-4VJAC32I.js";
|
|
131
134
|
import {
|
|
132
135
|
canonicalizeToolName,
|
|
133
136
|
canonicalizeToolNames
|
|
134
|
-
} from "./chunk-
|
|
135
|
-
import {
|
|
136
|
-
asRecordOrEmpty
|
|
137
|
-
} from "./chunk-KX6YBIHG.js";
|
|
137
|
+
} from "./chunk-XUWRURDF.js";
|
|
138
138
|
import {
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
} from "./chunk-VMFTFOWF.js";
|
|
139
|
+
buildProviderAuthHeaders,
|
|
140
|
+
buildProviderExecutionPlan
|
|
141
|
+
} from "./chunk-27ONFIEY.js";
|
|
143
142
|
import {
|
|
144
|
-
|
|
145
|
-
} from "./chunk-
|
|
143
|
+
toErrorMessage
|
|
144
|
+
} from "./chunk-HNMXYYJR.js";
|
|
146
145
|
import {
|
|
147
146
|
asTrimmedLowercaseString
|
|
148
147
|
} from "./chunk-QSJ3HFEF.js";
|
|
@@ -150,11 +149,19 @@ import {
|
|
|
150
149
|
isRecord
|
|
151
150
|
} from "./chunk-KUG52IAP.js";
|
|
152
151
|
import {
|
|
153
|
-
|
|
154
|
-
|
|
152
|
+
asTrimmedNonEmptyStringArray,
|
|
153
|
+
dialogMessageKey,
|
|
154
|
+
dialogMessageRange
|
|
155
|
+
} from "./chunk-3AH7LNUB.js";
|
|
156
|
+
import {
|
|
157
|
+
asOptionalFiniteNumber
|
|
158
|
+
} from "./chunk-WWC7I6TA.js";
|
|
155
159
|
import {
|
|
156
160
|
asOptionalPositiveFiniteNumber
|
|
157
161
|
} from "./chunk-U6VC4MU4.js";
|
|
162
|
+
import {
|
|
163
|
+
asTrimmedString
|
|
164
|
+
} from "./chunk-3EUW3WEO.js";
|
|
158
165
|
import {
|
|
159
166
|
normalizeServerOrigin
|
|
160
167
|
} from "./chunk-CF7PE763.js";
|
|
@@ -11900,6 +11907,7 @@ var toQueue = /* @__PURE__ */ dual(2, (self, options) => toQueueArray(self.chann
|
|
|
11900
11907
|
var runIntoQueue = /* @__PURE__ */ dual(2, (self, queue) => runIntoQueueArray(self.channel, queue));
|
|
11901
11908
|
|
|
11902
11909
|
// packages/agent-runtime/abortableKernel.ts
|
|
11910
|
+
var IDLE_WATCHDOG_SLICES = 20;
|
|
11903
11911
|
function runAbortableWithTimeout(args2) {
|
|
11904
11912
|
const taskEffect = Effect_exports.callback(
|
|
11905
11913
|
(resume) => {
|
|
@@ -11935,12 +11943,26 @@ function runAbortableWithTimeout(args2) {
|
|
|
11935
11943
|
raced = Effect_exports.raceFirst(taskEffect, abortEffect);
|
|
11936
11944
|
}
|
|
11937
11945
|
if (typeof args2.timeoutMs === "number") {
|
|
11938
|
-
const
|
|
11946
|
+
const outer = raced;
|
|
11939
11947
|
const timeoutMs = args2.timeoutMs;
|
|
11940
|
-
|
|
11941
|
-
|
|
11942
|
-
|
|
11948
|
+
const activityVersion = args2.activityVersion;
|
|
11949
|
+
const idleWatchdog = Effect_exports.gen(function* () {
|
|
11950
|
+
const sliceCount = activityVersion ? IDLE_WATCHDOG_SLICES : 1;
|
|
11951
|
+
const baseSliceMs = Math.max(1, Math.floor(timeoutMs / sliceCount));
|
|
11952
|
+
let idleMs = 0;
|
|
11953
|
+
for (; ; ) {
|
|
11954
|
+
const versionAtSliceStart = activityVersion?.();
|
|
11955
|
+
const sliceMs = Math.max(1, Math.min(timeoutMs - idleMs, baseSliceMs));
|
|
11956
|
+
yield* Effect_exports.sleep(Duration_exports.millis(sliceMs));
|
|
11957
|
+
idleMs += sliceMs;
|
|
11958
|
+
if (activityVersion && activityVersion() !== versionAtSliceStart) {
|
|
11959
|
+
idleMs = 0;
|
|
11960
|
+
continue;
|
|
11961
|
+
}
|
|
11962
|
+
if (idleMs >= timeoutMs) return { kind: "timeout" };
|
|
11963
|
+
}
|
|
11943
11964
|
});
|
|
11965
|
+
raced = Effect_exports.raceFirst(outer, idleWatchdog);
|
|
11944
11966
|
}
|
|
11945
11967
|
return args2.runtime ? args2.runtime.runPromise(raced) : Effect_exports.runPromise(raced);
|
|
11946
11968
|
}
|
|
@@ -12039,26 +12061,6 @@ function createLocalLoopObservationBoundary(initialCallbacks) {
|
|
|
12039
12061
|
};
|
|
12040
12062
|
}
|
|
12041
12063
|
|
|
12042
|
-
// packages/agent-runtime/fileWritePolicy.ts
|
|
12043
|
-
function evaluateFileWritePolicy(args2) {
|
|
12044
|
-
if (args2.sessionApproved) return { permissionDecision: "allow" };
|
|
12045
|
-
return {
|
|
12046
|
-
permissionDecision: "ask",
|
|
12047
|
-
permissionRequest: {
|
|
12048
|
-
id: "permission-file-write-session",
|
|
12049
|
-
tool: args2.tool,
|
|
12050
|
-
action: "file_write",
|
|
12051
|
-
title: "\u786E\u8BA4\u5199\u5165\u6587\u4EF6",
|
|
12052
|
-
body: `\u672C\u4F1A\u8BDD\u9996\u6B21\u5199\u5165\u6587\u4EF6\uFF1A${args2.path}\u3002\u6279\u51C6\u540E\u672C\u4F1A\u8BDD\u540E\u7EED\u5199\u5165\u4E0D\u518D\u9010\u6B21\u786E\u8BA4\u3002`,
|
|
12053
|
-
command: args2.path,
|
|
12054
|
-
suggestedRule: {
|
|
12055
|
-
scope: "session",
|
|
12056
|
-
pattern: { capability: "file_write", target: "session" }
|
|
12057
|
-
}
|
|
12058
|
-
}
|
|
12059
|
-
};
|
|
12060
|
-
}
|
|
12061
|
-
|
|
12062
12064
|
// packages/agent-runtime/toolCallPairing.ts
|
|
12063
12065
|
function readToolCallId(message) {
|
|
12064
12066
|
if (typeof message.tool_call_id === "string" && message.tool_call_id) {
|
|
@@ -12160,50 +12162,6 @@ function sanitizeToolCallPairing(messages) {
|
|
|
12160
12162
|
return output;
|
|
12161
12163
|
}
|
|
12162
12164
|
|
|
12163
|
-
// packages/agent-runtime/parseToolArguments.ts
|
|
12164
|
-
function parseToolArgumentsJson(raw) {
|
|
12165
|
-
if (!raw?.trim()) return {};
|
|
12166
|
-
try {
|
|
12167
|
-
return asRecordOrEmpty(JSON.parse(raw));
|
|
12168
|
-
} catch {
|
|
12169
|
-
return {};
|
|
12170
|
-
}
|
|
12171
|
-
}
|
|
12172
|
-
|
|
12173
|
-
// packages/agent-runtime/summarizeToolArguments.ts
|
|
12174
|
-
function clip(value, max4 = 240) {
|
|
12175
|
-
return clipCompactText(value, max4);
|
|
12176
|
-
}
|
|
12177
|
-
function summarizeToolArguments(toolName, rawArgs) {
|
|
12178
|
-
const args2 = parseToolArgumentsJson(rawArgs);
|
|
12179
|
-
const pick = (...keys3) => {
|
|
12180
|
-
for (const key of keys3) {
|
|
12181
|
-
const value = asOptionalTrimmedString(args2[key]);
|
|
12182
|
-
if (value) return value;
|
|
12183
|
-
}
|
|
12184
|
-
return "";
|
|
12185
|
-
};
|
|
12186
|
-
const command = pick("command", "cmd", "runCommand", "executeCommand", "bash");
|
|
12187
|
-
if (command) return clip(command);
|
|
12188
|
-
const query = pick("query", "pattern", "search", "q");
|
|
12189
|
-
if (query) return clip(query);
|
|
12190
|
-
const filePath = pick("filePath", "file_path", "path", "filename", "file");
|
|
12191
|
-
if (filePath) return clip(filePath);
|
|
12192
|
-
const keys2 = Object.keys(args2);
|
|
12193
|
-
if (keys2.length === 0) return "";
|
|
12194
|
-
return clip(
|
|
12195
|
-
keys2.slice(0, 6).map((key) => {
|
|
12196
|
-
const value = args2[key];
|
|
12197
|
-
if (typeof value === "string") return `${key}=${clip(value, 80)}`;
|
|
12198
|
-
if (typeof value === "number" || typeof value === "boolean") {
|
|
12199
|
-
return `${key}=${String(value)}`;
|
|
12200
|
-
}
|
|
12201
|
-
if (Array.isArray(value)) return `${key}[${value.length}]`;
|
|
12202
|
-
return `${key}=${value === null ? "null" : typeof value}`;
|
|
12203
|
-
}).join(" ")
|
|
12204
|
-
);
|
|
12205
|
-
}
|
|
12206
|
-
|
|
12207
12165
|
// packages/agent-runtime/progressGuard.ts
|
|
12208
12166
|
var DEFAULT_MAX_CONSECUTIVE_IDENTICAL_ROUNDS = 5;
|
|
12209
12167
|
var DEFAULT_MAX_CONSECUTIVE_STAGNANT_TOOL_ROUNDS = 8;
|
|
@@ -12627,6 +12585,13 @@ function isColdResume(history, nowMs) {
|
|
|
12627
12585
|
}
|
|
12628
12586
|
async function maybeAutoCompactLocalHistory(args2) {
|
|
12629
12587
|
const { adapter, dialogId, history } = args2;
|
|
12588
|
+
const emitPhase = (phase) => {
|
|
12589
|
+
try {
|
|
12590
|
+
args2.onPhase?.(phase);
|
|
12591
|
+
} catch {
|
|
12592
|
+
}
|
|
12593
|
+
};
|
|
12594
|
+
emitPhase({ kind: "validating-context" });
|
|
12630
12595
|
const unchanged = (decision) => ({
|
|
12631
12596
|
history,
|
|
12632
12597
|
compressed: false,
|
|
@@ -12722,8 +12687,15 @@ async function maybeAutoCompactLocalHistory(args2) {
|
|
|
12722
12687
|
if (!plan.shouldCompress) {
|
|
12723
12688
|
return projectExisting();
|
|
12724
12689
|
}
|
|
12690
|
+
emitPhase({ kind: "compaction-start" });
|
|
12725
12691
|
try {
|
|
12692
|
+
if (args2.abortSignal?.aborted) {
|
|
12693
|
+
throw Object.assign(new Error("auto-compaction aborted"), { compactionReason: "aborted" });
|
|
12694
|
+
}
|
|
12726
12695
|
const provider = await args2.resolveProvider();
|
|
12696
|
+
if (args2.abortSignal?.aborted) {
|
|
12697
|
+
throw Object.assign(new Error("auto-compaction aborted"), { compactionReason: "aborted" });
|
|
12698
|
+
}
|
|
12727
12699
|
const msgsToCompress = plan.msgsToCompress;
|
|
12728
12700
|
const messagesText = formatMessagesForSummaryWithTruncation(msgsToCompress);
|
|
12729
12701
|
const fileOpsText = formatFileOperationsFromMessages(
|
|
@@ -12735,20 +12707,55 @@ async function maybeAutoCompactLocalHistory(args2) {
|
|
|
12735
12707
|
messagesText,
|
|
12736
12708
|
fileOpsText
|
|
12737
12709
|
});
|
|
12738
|
-
|
|
12739
|
-
|
|
12740
|
-
|
|
12741
|
-
|
|
12710
|
+
emitPhase({ kind: "waiting-provider" });
|
|
12711
|
+
const timeoutMs = typeof args2.timeoutMs === "number" && Number.isFinite(args2.timeoutMs) && args2.timeoutMs > 0 ? args2.timeoutMs : void 0;
|
|
12712
|
+
const requestController = new AbortController();
|
|
12713
|
+
let timeoutHandle;
|
|
12714
|
+
let abortListener;
|
|
12715
|
+
const request3 = provider.complete(
|
|
12716
|
+
[{ role: "system", content: COMPACTION_SUMMARY_SYSTEM_PROMPT }, { role: "user", content: promptContent }],
|
|
12717
|
+
{ signal: requestController.signal, ...timeoutMs ? { timeoutMs } : {} }
|
|
12718
|
+
).then(
|
|
12719
|
+
(value) => ({ kind: "done", value }),
|
|
12720
|
+
(error) => ({ kind: "provider-error", error })
|
|
12721
|
+
);
|
|
12722
|
+
const guards = [];
|
|
12723
|
+
if (timeoutMs) guards.push(new Promise((resolve5) => {
|
|
12724
|
+
timeoutHandle = setTimeout(() => {
|
|
12725
|
+
requestController.abort();
|
|
12726
|
+
resolve5({ kind: "timeout" });
|
|
12727
|
+
}, timeoutMs);
|
|
12728
|
+
}));
|
|
12729
|
+
if (args2.abortSignal) guards.push(new Promise((resolve5) => {
|
|
12730
|
+
abortListener = () => {
|
|
12731
|
+
requestController.abort(args2.abortSignal?.reason);
|
|
12732
|
+
resolve5({ kind: "aborted" });
|
|
12733
|
+
};
|
|
12734
|
+
args2.abortSignal?.addEventListener("abort", abortListener, { once: true });
|
|
12735
|
+
}));
|
|
12736
|
+
const outcome = guards.length ? await Promise.race([request3, ...guards]) : await request3;
|
|
12737
|
+
if (timeoutHandle) clearTimeout(timeoutHandle);
|
|
12738
|
+
if (abortListener) args2.abortSignal?.removeEventListener("abort", abortListener);
|
|
12739
|
+
if (outcome.kind !== "done") {
|
|
12740
|
+
const reason = outcome.kind === "timeout" ? "timeout" : outcome.kind === "aborted" ? "aborted" : "provider-error";
|
|
12741
|
+
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";
|
|
12742
|
+
throw Object.assign(new Error(detail), { compactionReason: reason });
|
|
12743
|
+
}
|
|
12744
|
+
const result4 = outcome.value;
|
|
12742
12745
|
const newSummary = typeof result4.content === "string" ? result4.content.trim() : "";
|
|
12743
12746
|
if (!newSummary) {
|
|
12744
12747
|
console.warn(
|
|
12745
12748
|
"[localLoop] auto-compaction produced empty summary; keeping prior projection"
|
|
12746
12749
|
);
|
|
12750
|
+
const failureReason = "provider-error";
|
|
12751
|
+
emitPhase({ kind: "compaction-failed", reason: failureReason });
|
|
12747
12752
|
return {
|
|
12748
12753
|
...projectExisting(),
|
|
12749
12754
|
failureMessage: "summary model returned empty content",
|
|
12755
|
+
failureReason,
|
|
12750
12756
|
decision: {
|
|
12751
12757
|
outcome: "failed",
|
|
12758
|
+
reason: failureReason,
|
|
12752
12759
|
detail: "summary model returned empty content"
|
|
12753
12760
|
}
|
|
12754
12761
|
};
|
|
@@ -12775,6 +12782,7 @@ async function maybeAutoCompactLocalHistory(args2) {
|
|
|
12775
12782
|
summaryUsage: result4.usage
|
|
12776
12783
|
});
|
|
12777
12784
|
console.log(formatCompactionMetricsLog(metrics));
|
|
12785
|
+
emitPhase({ kind: "compaction-end" });
|
|
12778
12786
|
return {
|
|
12779
12787
|
history: projectHistoryWithSummary({
|
|
12780
12788
|
history,
|
|
@@ -12802,10 +12810,13 @@ async function maybeAutoCompactLocalHistory(args2) {
|
|
|
12802
12810
|
} catch (error) {
|
|
12803
12811
|
console.warn("[localLoop] auto-compaction failed:", error);
|
|
12804
12812
|
const failureMessage = error instanceof Error && error.message ? error.message.slice(0, 200) : String(error).slice(0, 200);
|
|
12813
|
+
const failureReason = error instanceof Error && "compactionReason" in error ? error.compactionReason : "provider-error";
|
|
12814
|
+
emitPhase({ kind: "compaction-failed", reason: failureReason });
|
|
12805
12815
|
return {
|
|
12806
12816
|
...projectExisting(),
|
|
12807
12817
|
failureMessage,
|
|
12808
|
-
|
|
12818
|
+
failureReason,
|
|
12819
|
+
decision: { outcome: "failed", reason: failureReason, detail: failureMessage }
|
|
12809
12820
|
};
|
|
12810
12821
|
}
|
|
12811
12822
|
}
|
|
@@ -12862,6 +12873,8 @@ function emitLoopEvent(boundary, event, bridge) {
|
|
|
12862
12873
|
boundary.emit(bridge ? { event, bridge } : { event });
|
|
12863
12874
|
}
|
|
12864
12875
|
var LLM_REQUEST_TIMEOUT = "LLM_REQUEST_TIMEOUT";
|
|
12876
|
+
var DEFAULT_LLM_REQUEST_TIMEOUT_MS = 10 * 60 * 1e3;
|
|
12877
|
+
var DEFAULT_COMPACTION_TIMEOUT_MS = 60 * 1e3;
|
|
12865
12878
|
var LOCAL_TURN_ABORTED_CODE = "LOCAL_TURN_ABORTED";
|
|
12866
12879
|
function buildAbortedError() {
|
|
12867
12880
|
const error = new Error("local agent turn aborted by user");
|
|
@@ -12889,8 +12902,11 @@ async function runAbortableToolTask(input, task, pendingToolName) {
|
|
|
12889
12902
|
}
|
|
12890
12903
|
function resolveLlmRequestTimeoutMs(input) {
|
|
12891
12904
|
const raw = input.llmRequestTimeoutMs ?? input.timeoutMs;
|
|
12892
|
-
|
|
12893
|
-
|
|
12905
|
+
return typeof raw === "number" && Number.isFinite(raw) && raw > 0 ? raw : DEFAULT_LLM_REQUEST_TIMEOUT_MS;
|
|
12906
|
+
}
|
|
12907
|
+
function resolveCompactionTimeoutMs(input) {
|
|
12908
|
+
const raw = input.compactionTimeoutMs;
|
|
12909
|
+
return typeof raw === "number" && Number.isFinite(raw) && raw > 0 ? raw : DEFAULT_COMPACTION_TIMEOUT_MS;
|
|
12894
12910
|
}
|
|
12895
12911
|
async function runCompleteWithTimeout(args2) {
|
|
12896
12912
|
const { provider, messages, options, timeoutMs, round, input, boundary, context: context3, providerName, model } = args2;
|
|
@@ -12913,6 +12929,7 @@ async function runCompleteWithTimeout(args2) {
|
|
|
12913
12929
|
const outcome = await runAbortableWithTimeout({
|
|
12914
12930
|
task: complete,
|
|
12915
12931
|
timeoutMs: typeof timeoutMs === "number" ? timeoutMs : void 0,
|
|
12932
|
+
activityVersion: args2.activityVersion,
|
|
12916
12933
|
abortSignal: input.abortSignal,
|
|
12917
12934
|
runtime: input.effectRuntime
|
|
12918
12935
|
});
|
|
@@ -12923,7 +12940,7 @@ async function runCompleteWithTimeout(args2) {
|
|
|
12923
12940
|
}
|
|
12924
12941
|
if (outcome.kind === "timeout") {
|
|
12925
12942
|
const timeoutError = new Error(
|
|
12926
|
-
`LLM request timed out after ${timeoutMs}ms (round ${round})`
|
|
12943
|
+
`LLM request timed out after ${timeoutMs}ms without new output (idle window, round ${round})`
|
|
12927
12944
|
);
|
|
12928
12945
|
timeoutError.code = LLM_REQUEST_TIMEOUT;
|
|
12929
12946
|
throw timeoutError;
|
|
@@ -12967,16 +12984,16 @@ async function runCompleteWithTimeout(args2) {
|
|
|
12967
12984
|
});
|
|
12968
12985
|
}
|
|
12969
12986
|
}
|
|
12970
|
-
function
|
|
12987
|
+
function clip(value, max4 = 240) {
|
|
12971
12988
|
return clipCompactText(value, max4);
|
|
12972
12989
|
}
|
|
12973
12990
|
function projectSafeToolObservationMetadata(metadata) {
|
|
12974
12991
|
if (!metadata || typeof metadata !== "object") return void 0;
|
|
12975
12992
|
const safe = {};
|
|
12976
12993
|
if (typeof metadata.exitCode === "number") safe.exitCode = metadata.exitCode;
|
|
12977
|
-
if (typeof metadata.actionGate === "string") safe.actionGate =
|
|
12978
|
-
if (typeof metadata.command === "string") safe.command =
|
|
12979
|
-
if (typeof metadata.path === "string") safe.path =
|
|
12994
|
+
if (typeof metadata.actionGate === "string") safe.actionGate = clip(metadata.actionGate, 240);
|
|
12995
|
+
if (typeof metadata.command === "string") safe.command = clip(metadata.command, 240);
|
|
12996
|
+
if (typeof metadata.path === "string") safe.path = clip(metadata.path, 240);
|
|
12980
12997
|
if (typeof metadata.truncated === "boolean") safe.truncated = metadata.truncated;
|
|
12981
12998
|
if (typeof metadata.byteCount === "number") safe.byteCount = metadata.byteCount;
|
|
12982
12999
|
if (typeof metadata.lineCount === "number") safe.lineCount = metadata.lineCount;
|
|
@@ -12992,7 +13009,7 @@ function summarizeToolResult(content, metadata) {
|
|
|
12992
13009
|
const lines = trimmed.split(/\r?\n/).length;
|
|
12993
13010
|
parts2.push(`${lines} line${lines === 1 ? "" : "s"}`);
|
|
12994
13011
|
parts2.push(`${trimmed.length} chars`);
|
|
12995
|
-
const tail =
|
|
13012
|
+
const tail = clip(trimmed.slice(-160), 160);
|
|
12996
13013
|
if (tail) parts2.push(`tail="${tail}"`);
|
|
12997
13014
|
} else {
|
|
12998
13015
|
parts2.push("empty");
|
|
@@ -13604,6 +13621,9 @@ async function runLocalAgentTurn(input) {
|
|
|
13604
13621
|
input.contextBlockScopes
|
|
13605
13622
|
);
|
|
13606
13623
|
const mergedContextBlockScopes = [
|
|
13624
|
+
// 删除安全红线:系统层最高优先级约束,位于所有块之前(含身份信息块),
|
|
13625
|
+
// owner 要求常驻「根本提示词」的最顶部(2026-09-26 批量误删事故)。
|
|
13626
|
+
{ content: DELETE_SAFETY_RED_LINE, cacheScope: "session" },
|
|
13607
13627
|
{ content: identityBlock, cacheScope: "session" },
|
|
13608
13628
|
...guidanceScopes,
|
|
13609
13629
|
...callerScopes
|
|
@@ -13636,6 +13656,16 @@ async function runLocalAgentTurn(input) {
|
|
|
13636
13656
|
}
|
|
13637
13657
|
}
|
|
13638
13658
|
let compactionUsage;
|
|
13659
|
+
const emitCompactionPhase = (phase, scope3) => {
|
|
13660
|
+
const atMs = Date.now();
|
|
13661
|
+
if (phase.kind === "validating-context") emitLoopEvent(observationBoundary, { kind: "turn-phase", phase: "validating-context", atMs, compactionScope: scope3 });
|
|
13662
|
+
else if (phase.kind === "compaction-start") {
|
|
13663
|
+
emitLoopEvent(observationBoundary, { kind: "turn-phase", phase: "compacting", atMs, compactionScope: scope3 });
|
|
13664
|
+
emitLoopEvent(observationBoundary, { kind: "compaction-start", atMs, scope: scope3 });
|
|
13665
|
+
} else if (phase.kind === "waiting-provider") emitLoopEvent(observationBoundary, { kind: "turn-phase", phase: "waiting-provider", atMs, compactionScope: scope3 });
|
|
13666
|
+
else if (phase.kind === "compaction-end") emitLoopEvent(observationBoundary, { kind: "compaction-end", atMs, scope: scope3 });
|
|
13667
|
+
else emitLoopEvent(observationBoundary, { kind: "compaction-failed", atMs, scope: scope3, reason: phase.reason });
|
|
13668
|
+
};
|
|
13639
13669
|
const emitCompactionObservation = (compacted) => {
|
|
13640
13670
|
const decision = compacted.decision;
|
|
13641
13671
|
if (decision?.outcome === "skipped") {
|
|
@@ -13669,7 +13699,10 @@ async function runLocalAgentTurn(input) {
|
|
|
13669
13699
|
model: agentConfig.model,
|
|
13670
13700
|
resolveProvider: resolveProviderOnce,
|
|
13671
13701
|
contextWindow,
|
|
13672
|
-
realContextUsagePercent
|
|
13702
|
+
realContextUsagePercent,
|
|
13703
|
+
abortSignal: input.abortSignal,
|
|
13704
|
+
timeoutMs: resolveCompactionTimeoutMs(input),
|
|
13705
|
+
onPhase: (phase) => emitCompactionPhase(phase, "initial")
|
|
13673
13706
|
});
|
|
13674
13707
|
history = compacted.history;
|
|
13675
13708
|
compactionUsage = compacted.usage;
|
|
@@ -13775,7 +13808,10 @@ async function runLocalAgentTurn(input) {
|
|
|
13775
13808
|
model: agentConfig.model,
|
|
13776
13809
|
resolveProvider: resolveProviderOnce,
|
|
13777
13810
|
contextWindow,
|
|
13778
|
-
...ratio !== void 0 ? { realContextUsagePercent: ratio } : {}
|
|
13811
|
+
...ratio !== void 0 ? { realContextUsagePercent: ratio } : {},
|
|
13812
|
+
abortSignal: input.abortSignal,
|
|
13813
|
+
timeoutMs: resolveCompactionTimeoutMs(input),
|
|
13814
|
+
onPhase: (phase) => emitCompactionPhase(phase, "in-loop")
|
|
13779
13815
|
});
|
|
13780
13816
|
if (compacted.usage) {
|
|
13781
13817
|
compactionUsage = addOutOfBandUsage(compactionUsage, compacted.usage);
|
|
@@ -13845,11 +13881,12 @@ async function runLocalAgentTurn(input) {
|
|
|
13845
13881
|
const shouldPassToolEvents = Boolean(
|
|
13846
13882
|
input.onToolEvent || input.onObservationEvent || input.observationBoundary
|
|
13847
13883
|
);
|
|
13884
|
+
let llmStreamActivity = 0;
|
|
13848
13885
|
result4 = await runCompleteWithTimeout({
|
|
13849
13886
|
provider,
|
|
13850
13887
|
messages: requestMessages,
|
|
13851
13888
|
options: {
|
|
13852
|
-
|
|
13889
|
+
timeoutMs: resolveLlmRequestTimeoutMs(input),
|
|
13853
13890
|
// 用户取消信号穿进 provider options:providerStreamRetry 据此在
|
|
13854
13891
|
// 取消后跳过重试,provider 分支(如 antigravity/openai-compatible)
|
|
13855
13892
|
// 也可把 fetch 绑定到同一信号,实现真正的传输层取消。
|
|
@@ -13858,6 +13895,7 @@ async function runLocalAgentTurn(input) {
|
|
|
13858
13895
|
// 归到具体对话而不是 chat-proxy 兜底桶。新对话首轮 id 尚未分配。
|
|
13859
13896
|
...input.continueDialogId ? { dialogId: input.continueDialogId } : {},
|
|
13860
13897
|
...shouldStreamDeltas ? { onTextDelta: (chunk) => {
|
|
13898
|
+
llmStreamActivity += 1;
|
|
13861
13899
|
partialContent += chunk;
|
|
13862
13900
|
observationBoundary.emit({
|
|
13863
13901
|
kind: "text-delta",
|
|
@@ -13867,6 +13905,7 @@ async function runLocalAgentTurn(input) {
|
|
|
13867
13905
|
});
|
|
13868
13906
|
} } : {},
|
|
13869
13907
|
...shouldStreamReasoning ? { onReasoningDelta: (chunk) => {
|
|
13908
|
+
llmStreamActivity += 1;
|
|
13870
13909
|
observationBoundary.emit({
|
|
13871
13910
|
kind: "reasoning-delta",
|
|
13872
13911
|
chunk,
|
|
@@ -13875,6 +13914,7 @@ async function runLocalAgentTurn(input) {
|
|
|
13875
13914
|
});
|
|
13876
13915
|
} } : {},
|
|
13877
13916
|
...shouldPassToolEvents ? { onToolEvent: (event) => {
|
|
13917
|
+
llmStreamActivity += 1;
|
|
13878
13918
|
observationBoundary.emit({
|
|
13879
13919
|
kind: "tool-event",
|
|
13880
13920
|
event,
|
|
@@ -13885,6 +13925,7 @@ async function runLocalAgentTurn(input) {
|
|
|
13885
13925
|
...shouldPassToolEvents ? { toolEventRound: round } : {}
|
|
13886
13926
|
},
|
|
13887
13927
|
timeoutMs: resolveLlmRequestTimeoutMs(input),
|
|
13928
|
+
activityVersion: () => llmStreamActivity,
|
|
13888
13929
|
round,
|
|
13889
13930
|
input,
|
|
13890
13931
|
boundary: observationBoundary,
|
|
@@ -14356,33 +14397,6 @@ ${reasoningTailLog}
|
|
|
14356
14397
|
}
|
|
14357
14398
|
}
|
|
14358
14399
|
|
|
14359
|
-
// packages/agent-runtime/kimiUserAgent.ts
|
|
14360
|
-
var KIMI_CODE_CLI_VERSION = "0.29.2";
|
|
14361
|
-
var KIMI_CODE_USER_AGENT = `kimi-code-cli/${KIMI_CODE_CLI_VERSION} (nolo)`;
|
|
14362
|
-
function isKimiEndpoint(url) {
|
|
14363
|
-
return url.includes("api.kimi.com");
|
|
14364
|
-
}
|
|
14365
|
-
function kimiIdentityHeaders(url) {
|
|
14366
|
-
return isKimiEndpoint(url) ? { "User-Agent": KIMI_CODE_USER_AGENT } : {};
|
|
14367
|
-
}
|
|
14368
|
-
|
|
14369
|
-
// packages/agent-runtime/sseDataLine.ts
|
|
14370
|
-
function parseSseDataLineJson(line) {
|
|
14371
|
-
const trimmed = line.trim();
|
|
14372
|
-
if (!trimmed.startsWith("data:")) return null;
|
|
14373
|
-
const payload = trimmed.slice(5).trim();
|
|
14374
|
-
if (!payload || payload === "[DONE]") return null;
|
|
14375
|
-
try {
|
|
14376
|
-
return JSON.parse(payload);
|
|
14377
|
-
} catch {
|
|
14378
|
-
return null;
|
|
14379
|
-
}
|
|
14380
|
-
}
|
|
14381
|
-
function parseSseDataLineObject(line) {
|
|
14382
|
-
const parsed = parseSseDataLineJson(line);
|
|
14383
|
-
return parsed && typeof parsed === "object" ? parsed : null;
|
|
14384
|
-
}
|
|
14385
|
-
|
|
14386
14400
|
// packages/integrations/openai/responsesRequestBody.ts
|
|
14387
14401
|
function buildResponsesRequestBody(body, model) {
|
|
14388
14402
|
const tools = Array.isArray(body.tools) ? toResponsesTools(body.tools) : void 0;
|
|
@@ -14561,6 +14575,7 @@ async function readResponsesSseCompletion(args2) {
|
|
|
14561
14575
|
}
|
|
14562
14576
|
|
|
14563
14577
|
// packages/agent-runtime/openAiCompatibleProvider.ts
|
|
14578
|
+
var REASONING_REPLAY_PLACEHOLDER = "(reasoning not captured for this turn)";
|
|
14564
14579
|
function isOpenAiResponsesEndpoint(endpoint) {
|
|
14565
14580
|
return endpoint.includes("/responses");
|
|
14566
14581
|
}
|
|
@@ -14574,9 +14589,14 @@ function buildOpenAiCompatibleChatCompletionRequest(args2) {
|
|
|
14574
14589
|
args2.providerConfig.provider,
|
|
14575
14590
|
args2.providerConfig.model
|
|
14576
14591
|
);
|
|
14592
|
+
const shouldReplayReasoning = shouldReplayReasoningContentForOutbound(
|
|
14593
|
+
args2.providerConfig.provider,
|
|
14594
|
+
args2.providerConfig.model
|
|
14595
|
+
);
|
|
14577
14596
|
const sanitizedMessages = sanitizeForOutbound(args2.messages, args2.tools);
|
|
14578
14597
|
const messages = toOpenAiCompatibleMessages(sanitizedMessages, {
|
|
14579
|
-
stripReasoningContent: shouldStripReasoning
|
|
14598
|
+
stripReasoningContent: shouldStripReasoning,
|
|
14599
|
+
...shouldReplayReasoning && !shouldStripReasoning ? { replayReasoningPlaceholder: REASONING_REPLAY_PLACEHOLDER } : {}
|
|
14580
14600
|
});
|
|
14581
14601
|
const rawBody = {
|
|
14582
14602
|
model: args2.providerConfig.model,
|
|
@@ -14605,9 +14625,9 @@ function buildOpenAiCompatibleChatCompletionRequest(args2) {
|
|
|
14605
14625
|
...buildProviderAuthHeaders({
|
|
14606
14626
|
endpoint,
|
|
14607
14627
|
apiKey: args2.providerConfig.apiKey,
|
|
14608
|
-
apiKeyHeader: args2.providerConfig.apiKeyHeader
|
|
14609
|
-
|
|
14610
|
-
|
|
14628
|
+
apiKeyHeader: args2.providerConfig.apiKeyHeader,
|
|
14629
|
+
sessionId: args2.sessionId
|
|
14630
|
+
})
|
|
14611
14631
|
};
|
|
14612
14632
|
return {
|
|
14613
14633
|
url: endpoint,
|
|
@@ -14710,7 +14730,8 @@ async function executeOpenAiCompatibleChatCompletion(args2) {
|
|
|
14710
14730
|
providerConfig: apiKey2 === args2.providerConfig.apiKey ? args2.providerConfig : { ...args2.providerConfig, apiKey: apiKey2 },
|
|
14711
14731
|
messages: args2.messages,
|
|
14712
14732
|
tools: args2.tools,
|
|
14713
|
-
stream: args2.stream
|
|
14733
|
+
stream: args2.stream,
|
|
14734
|
+
sessionId: args2.sessionId
|
|
14714
14735
|
});
|
|
14715
14736
|
return args2.fetchImpl(request3.url, {
|
|
14716
14737
|
...request3.init,
|
|
@@ -15652,132 +15673,6 @@ async function evaluateCapabilityPolicy(capability, normalizedInput, ctx) {
|
|
|
15652
15673
|
}
|
|
15653
15674
|
}
|
|
15654
15675
|
|
|
15655
|
-
// packages/agent-runtime/localToolPolicy.ts
|
|
15656
|
-
var NEVER_LOCAL_TOOLS = /* @__PURE__ */ new Set([
|
|
15657
|
-
"deleteSpaces",
|
|
15658
|
-
"updateAgent",
|
|
15659
|
-
"updateSelf",
|
|
15660
|
-
"createAgent"
|
|
15661
|
-
]);
|
|
15662
|
-
var DEFAULT_LOCAL_TOOLS = /* @__PURE__ */ new Set([
|
|
15663
|
-
"readFile",
|
|
15664
|
-
"writeFile",
|
|
15665
|
-
"editFile",
|
|
15666
|
-
"globFiles",
|
|
15667
|
-
"execShell",
|
|
15668
|
-
"launchProcess",
|
|
15669
|
-
"listProcesses",
|
|
15670
|
-
// ProcessTask follow-up tools. Same tier as listProcesses: they observe/stop
|
|
15671
|
-
// tasks the agent itself already spawned, so their blast radius is strictly
|
|
15672
|
-
// narrower than launchProcess (which is default-enabled). Model-facing
|
|
15673
|
-
// follow-ups are taskWait/taskStop only — lifecycle history (taskLogs) stays
|
|
15674
|
-
// runtime-internal.
|
|
15675
|
-
"taskWait",
|
|
15676
|
-
"taskStop",
|
|
15677
|
-
// Scheduling tools: forking/observing sub-agents is a declared capability
|
|
15678
|
-
// of capable agents, and the blast radius is strictly narrower than
|
|
15679
|
-
// execShell (already default-enabled). Requiring an env allowlist for these
|
|
15680
|
-
// while execShell is open by default inverted the risk model and forced every
|
|
15681
|
-
// new local user to hand-edit .env files before sub-agent tasks worked.
|
|
15682
|
-
"startAgentRun",
|
|
15683
|
-
"controlAgentRun"
|
|
15684
|
-
]);
|
|
15685
|
-
function parseToolAllowlist(value) {
|
|
15686
|
-
return (value ?? "").split(",").flatMap((item) => {
|
|
15687
|
-
const trimmed = item.trim();
|
|
15688
|
-
return trimmed ? [trimmed] : [];
|
|
15689
|
-
});
|
|
15690
|
-
}
|
|
15691
|
-
function normalizeLocalToolName(toolName) {
|
|
15692
|
-
return canonicalizeToolName(
|
|
15693
|
-
String(toolName ?? "").replace(/^functions\./, "").trim()
|
|
15694
|
-
);
|
|
15695
|
-
}
|
|
15696
|
-
function isRestrictedLocalToolMode(env) {
|
|
15697
|
-
return env.NOLO_LOCAL_TOOL_MODE === "restricted";
|
|
15698
|
-
}
|
|
15699
|
-
function resolveLocalToolPolicy(args2) {
|
|
15700
|
-
const toolName = normalizeLocalToolName(args2.toolName);
|
|
15701
|
-
const restrictedMode = isRestrictedLocalToolMode(args2.env);
|
|
15702
|
-
if (!toolName) {
|
|
15703
|
-
return {
|
|
15704
|
-
allowed: false,
|
|
15705
|
-
toolName,
|
|
15706
|
-
reason: "Tool name is required."
|
|
15707
|
-
};
|
|
15708
|
-
}
|
|
15709
|
-
if (NEVER_LOCAL_TOOLS.has(toolName)) {
|
|
15710
|
-
return {
|
|
15711
|
-
allowed: false,
|
|
15712
|
-
toolName,
|
|
15713
|
-
reason: `${toolName} is blocked by the local runtime safety policy.`
|
|
15714
|
-
};
|
|
15715
|
-
}
|
|
15716
|
-
const allowedByEnv = new Set(parseToolAllowlist(args2.env.NOLO_LOCAL_ALLOWED_TOOLS));
|
|
15717
|
-
const agentTools = new Set(
|
|
15718
|
-
(args2.agentToolNames ?? []).flatMap((item) => {
|
|
15719
|
-
const normalized = normalizeLocalToolName(item);
|
|
15720
|
-
return normalized ? [normalized] : [];
|
|
15721
|
-
})
|
|
15722
|
-
);
|
|
15723
|
-
if (!restrictedMode && agentTools.has(toolName)) {
|
|
15724
|
-
return { allowed: true, toolName };
|
|
15725
|
-
}
|
|
15726
|
-
if (DEFAULT_LOCAL_TOOLS.has(toolName) && agentTools.has(toolName)) {
|
|
15727
|
-
return { allowed: true, toolName };
|
|
15728
|
-
}
|
|
15729
|
-
if (allowedByEnv.has(toolName) && agentTools.has(toolName)) {
|
|
15730
|
-
return { allowed: true, toolName };
|
|
15731
|
-
}
|
|
15732
|
-
return {
|
|
15733
|
-
allowed: false,
|
|
15734
|
-
toolName,
|
|
15735
|
-
reason: `${toolName} is not enabled for local runtime runs. The agent must declare the tool in its manifest; in restricted mode (NOLO_LOCAL_TOOL_MODE=restricted) non-default tools also require adding to NOLO_LOCAL_ALLOWED_TOOLS (e.g. NOLO_LOCAL_ALLOWED_TOOLS=someCustomTool) and restarting the session so the env var loads.`
|
|
15736
|
-
};
|
|
15737
|
-
}
|
|
15738
|
-
async function executeLocalToolWithPolicy(args2) {
|
|
15739
|
-
if (args2.runToolNames !== void 0 && !args2.runToolNames.includes(normalizeLocalToolName(args2.call.name))) {
|
|
15740
|
-
throw new Error(`${args2.call.name} is outside the final run tool surface.`);
|
|
15741
|
-
}
|
|
15742
|
-
const decision = resolveLocalToolPolicy({
|
|
15743
|
-
env: args2.env,
|
|
15744
|
-
agentToolNames: args2.agentToolNames,
|
|
15745
|
-
toolName: args2.call.name
|
|
15746
|
-
});
|
|
15747
|
-
if (!decision.allowed) throw new Error(decision.reason);
|
|
15748
|
-
const executor = args2.executors?.[decision.toolName];
|
|
15749
|
-
if (!executor) {
|
|
15750
|
-
throw new Error(`${decision.toolName} is allowed by policy but no local executor is registered.`);
|
|
15751
|
-
}
|
|
15752
|
-
const opts = {
|
|
15753
|
-
...args2.abortSignal ? { abortSignal: args2.abortSignal } : {},
|
|
15754
|
-
...args2.detachMs !== void 0 ? { detachMs: args2.detachMs } : {},
|
|
15755
|
-
...args2.confirmed !== void 0 ? { confirmed: args2.confirmed } : {},
|
|
15756
|
-
...args2.enableDestructiveShellGuard !== void 0 ? { enableDestructiveShellGuard: args2.enableDestructiveShellGuard } : {},
|
|
15757
|
-
...args2.confirmDestructiveAction ? { confirmDestructiveAction: args2.confirmDestructiveAction } : {},
|
|
15758
|
-
...args2.blockDestructiveWithoutConfirmation !== void 0 ? { blockDestructiveWithoutConfirmation: args2.blockDestructiveWithoutConfirmation } : {}
|
|
15759
|
-
};
|
|
15760
|
-
if (decision.toolName === "execShell") {
|
|
15761
|
-
let parsedInput = args2.call.arguments;
|
|
15762
|
-
if (typeof parsedInput === "string") {
|
|
15763
|
-
try {
|
|
15764
|
-
parsedInput = JSON.parse(parsedInput);
|
|
15765
|
-
} catch {
|
|
15766
|
-
parsedInput = { command: parsedInput };
|
|
15767
|
-
}
|
|
15768
|
-
}
|
|
15769
|
-
await evaluateExecShellDestructiveGuard(parsedInput, opts);
|
|
15770
|
-
opts.confirmed = true;
|
|
15771
|
-
}
|
|
15772
|
-
return executor(
|
|
15773
|
-
{
|
|
15774
|
-
...args2.call,
|
|
15775
|
-
name: decision.toolName
|
|
15776
|
-
},
|
|
15777
|
-
opts
|
|
15778
|
-
);
|
|
15779
|
-
}
|
|
15780
|
-
|
|
15781
15676
|
// packages/agent-runtime/localWorkspaceTools.ts
|
|
15782
15677
|
import { existsSync as existsSync3 } from "node:fs";
|
|
15783
15678
|
import { createHash as createHash3 } from "node:crypto";
|
|
@@ -16576,29 +16471,6 @@ function getProcessRegistry() {
|
|
|
16576
16471
|
return registry;
|
|
16577
16472
|
}
|
|
16578
16473
|
|
|
16579
|
-
// packages/agent-runtime/processOwnership.ts
|
|
16580
|
-
var asNonEmptyString = (value) => {
|
|
16581
|
-
if (typeof value !== "string") return null;
|
|
16582
|
-
const trimmed = value.trim();
|
|
16583
|
-
return trimmed ? trimmed : null;
|
|
16584
|
-
};
|
|
16585
|
-
function readProcessOwner(runtimeContext) {
|
|
16586
|
-
if (!runtimeContext || typeof runtimeContext !== "object") return null;
|
|
16587
|
-
const dialogId = asNonEmptyString(runtimeContext.dialogId) ?? asNonEmptyString(runtimeContext.parentThreadId);
|
|
16588
|
-
if (!dialogId) return null;
|
|
16589
|
-
const turnId = asNonEmptyString(runtimeContext.turnId);
|
|
16590
|
-
const ownerId = asNonEmptyString(runtimeContext.ownerId);
|
|
16591
|
-
return {
|
|
16592
|
-
dialogId,
|
|
16593
|
-
...turnId ? { turnId } : {},
|
|
16594
|
-
...ownerId ? { ownerId } : {}
|
|
16595
|
-
};
|
|
16596
|
-
}
|
|
16597
|
-
|
|
16598
|
-
// packages/agent-runtime/workspaceShell.ts
|
|
16599
|
-
import { resolve as resolve3 } from "node:path";
|
|
16600
|
-
import { spawn as spawnChildProcess2 } from "node:child_process";
|
|
16601
|
-
|
|
16602
16474
|
// packages/agent-runtime/processTaskResult.ts
|
|
16603
16475
|
var PROCESS_RESULT_CAPSULE_TAIL_CHARS = 4e3;
|
|
16604
16476
|
var PROCESS_RESULT_CAPSULE_SPILL_THRESHOLD_CHARS = 2e4;
|
|
@@ -16618,11 +16490,17 @@ function buildProcessTaskResultCapsule(args2) {
|
|
|
16618
16490
|
const exitCode = args2.exitCode;
|
|
16619
16491
|
const captureError = args2.captureError?.trim() || void 0;
|
|
16620
16492
|
const durationMs = typeof args2.startedAt === "number" && Number.isFinite(args2.startedAt) ? Math.max(0, (args2.endedAt ?? Date.now()) - args2.startedAt) : void 0;
|
|
16621
|
-
const
|
|
16622
|
-
const
|
|
16493
|
+
const stdoutProvenance = args2.streamProvenance?.stdout;
|
|
16494
|
+
const stderrProvenance = args2.streamProvenance?.stderr;
|
|
16495
|
+
const ringEvicted = Boolean(stdoutProvenance?.evicted || stderrProvenance?.evicted);
|
|
16496
|
+
const stdoutTailSource = typeof args2.stdoutTail === "string" ? args2.stdoutTail : stdout;
|
|
16497
|
+
const stderrTailSource = typeof args2.stderrTail === "string" ? args2.stderrTail : stderr;
|
|
16498
|
+
const stdoutTail = tailText(stdoutTailSource, tailChars);
|
|
16499
|
+
const stderrTail = tailText(stderrTailSource, tailChars);
|
|
16623
16500
|
const inlineSize = stdout.length + stderr.length;
|
|
16624
16501
|
const inlineTruncated = stdoutTail.truncated || stderrTail.truncated;
|
|
16625
|
-
const
|
|
16502
|
+
const truncated = inlineTruncated || ringEvicted || Boolean(captureError);
|
|
16503
|
+
const shouldSpill = truncated || inlineSize > spillThresholdChars;
|
|
16626
16504
|
let spill;
|
|
16627
16505
|
if (shouldSpill) {
|
|
16628
16506
|
try {
|
|
@@ -16636,8 +16514,11 @@ function buildProcessTaskResultCapsule(args2) {
|
|
|
16636
16514
|
});
|
|
16637
16515
|
spill = {
|
|
16638
16516
|
displayPath: result4.displayPath,
|
|
16639
|
-
|
|
16640
|
-
|
|
16517
|
+
// Prefer the caller's live provenance counters: they count every
|
|
16518
|
+
// byte of the original stream, while the buffered content above may
|
|
16519
|
+
// be a capped prefix of it.
|
|
16520
|
+
totalChars: (stdoutProvenance?.totalChars ?? stdout.length) + (stderrProvenance?.totalChars ?? stderr.length),
|
|
16521
|
+
totalLines: (stdoutProvenance?.totalLines ?? countLines(stdout)) + (stderrProvenance?.totalLines ?? countLines(stderr))
|
|
16641
16522
|
};
|
|
16642
16523
|
} catch {
|
|
16643
16524
|
}
|
|
@@ -16648,27 +16529,48 @@ function buildProcessTaskResultCapsule(args2) {
|
|
|
16648
16529
|
exitCode,
|
|
16649
16530
|
...durationMs !== void 0 ? { durationMs } : {},
|
|
16650
16531
|
...captureError ? { captureError } : {},
|
|
16651
|
-
truncated
|
|
16532
|
+
truncated,
|
|
16652
16533
|
...spill ? { spill } : {}
|
|
16653
16534
|
};
|
|
16654
16535
|
}
|
|
16655
16536
|
|
|
16656
|
-
// packages/agent-runtime/
|
|
16657
|
-
var
|
|
16658
|
-
|
|
16659
|
-
|
|
16660
|
-
|
|
16661
|
-
|
|
16662
|
-
|
|
16663
|
-
|
|
16664
|
-
|
|
16665
|
-
|
|
16666
|
-
|
|
16667
|
-
|
|
16668
|
-
|
|
16669
|
-
|
|
16670
|
-
|
|
16671
|
-
|
|
16537
|
+
// packages/agent-runtime/processOwnership.ts
|
|
16538
|
+
var asNonEmptyString = (value) => {
|
|
16539
|
+
if (typeof value !== "string") return null;
|
|
16540
|
+
const trimmed = value.trim();
|
|
16541
|
+
return trimmed ? trimmed : null;
|
|
16542
|
+
};
|
|
16543
|
+
function readProcessOwner(runtimeContext) {
|
|
16544
|
+
if (!runtimeContext || typeof runtimeContext !== "object") return null;
|
|
16545
|
+
const dialogId = asNonEmptyString(runtimeContext.dialogId) ?? asNonEmptyString(runtimeContext.parentThreadId);
|
|
16546
|
+
if (!dialogId) return null;
|
|
16547
|
+
const turnId = asNonEmptyString(runtimeContext.turnId);
|
|
16548
|
+
const ownerId = asNonEmptyString(runtimeContext.ownerId);
|
|
16549
|
+
return {
|
|
16550
|
+
dialogId,
|
|
16551
|
+
...turnId ? { turnId } : {},
|
|
16552
|
+
...ownerId ? { ownerId } : {}
|
|
16553
|
+
};
|
|
16554
|
+
}
|
|
16555
|
+
|
|
16556
|
+
// packages/agent-runtime/workspaceShell.ts
|
|
16557
|
+
import { resolve as resolve3 } from "node:path";
|
|
16558
|
+
import { spawn as spawnChildProcess2 } from "node:child_process";
|
|
16559
|
+
var EXEC_SHELL_TIMEOUT_ENV = "NOLO_EXEC_SHELL_TIMEOUT_MS";
|
|
16560
|
+
var EXEC_SHELL_DETACH_ENV = "NOLO_EXEC_SHELL_DETACH_MS";
|
|
16561
|
+
var DEFAULT_EXEC_SHELL_DETACH_MS = 12e4;
|
|
16562
|
+
function readTrimmedString(value) {
|
|
16563
|
+
return asOptionalTrimmedString(value);
|
|
16564
|
+
}
|
|
16565
|
+
function extractActivityRefs(rawRefs) {
|
|
16566
|
+
if (!Array.isArray(rawRefs)) return void 0;
|
|
16567
|
+
const refs = rawRefs.flatMap((entry) => {
|
|
16568
|
+
if (typeof entry === "string" && entry.trim()) {
|
|
16569
|
+
return [{ type: "file", path: entry.trim() }];
|
|
16570
|
+
}
|
|
16571
|
+
if (!isRecord(entry)) return [];
|
|
16572
|
+
const path = readTrimmedString(entry.path);
|
|
16573
|
+
if (path) return [{ type: "file", path }];
|
|
16672
16574
|
const terminalId = readTrimmedString(entry.id);
|
|
16673
16575
|
const terminalLabel = readTrimmedString(entry.label);
|
|
16674
16576
|
if (entry.type === "terminal" || terminalId || terminalLabel) {
|
|
@@ -17522,13 +17424,169 @@ function runTasks(args2) {
|
|
|
17522
17424
|
return { tasks, count: tasks.length };
|
|
17523
17425
|
}
|
|
17524
17426
|
|
|
17427
|
+
// packages/agent-runtime/execShellCompletionWarnings.ts
|
|
17428
|
+
var BG_ESCAPE_WORD_PATTERN = /(?:^|[\s;|(&/\\])(nohup|disown|setsid|start-process)(?=$|[\s;|)&])/i;
|
|
17429
|
+
var SHELL_SPLIT_CHARS = /* @__PURE__ */ new Set([";", "|", "&", "(", ")", "<", ">", "\n", " ", " "]);
|
|
17430
|
+
function maskQuotedAndEscaped(command) {
|
|
17431
|
+
const out = Array.from(command);
|
|
17432
|
+
let quote = null;
|
|
17433
|
+
for (let i = 0; i < out.length; i += 1) {
|
|
17434
|
+
const ch = out[i];
|
|
17435
|
+
if (quote) {
|
|
17436
|
+
out[i] = " ";
|
|
17437
|
+
if (ch === "\\" && quote !== "'") {
|
|
17438
|
+
if (i + 1 < out.length) out[i + 1] = " ";
|
|
17439
|
+
i += 1;
|
|
17440
|
+
} else if (ch === quote) {
|
|
17441
|
+
quote = null;
|
|
17442
|
+
}
|
|
17443
|
+
continue;
|
|
17444
|
+
}
|
|
17445
|
+
if (ch === "\\") {
|
|
17446
|
+
out[i] = " ";
|
|
17447
|
+
if (i + 1 < out.length) out[i + 1] = " ";
|
|
17448
|
+
i += 1;
|
|
17449
|
+
continue;
|
|
17450
|
+
}
|
|
17451
|
+
if (ch === "'" || ch === '"' || ch === "`") {
|
|
17452
|
+
quote = ch;
|
|
17453
|
+
out[i] = " ";
|
|
17454
|
+
continue;
|
|
17455
|
+
}
|
|
17456
|
+
if (ch === "#" && (i === 0 || /[\s;]/.test(out[i - 1] ?? " "))) {
|
|
17457
|
+
while (i < out.length && out[i] !== "\n") {
|
|
17458
|
+
out[i] = " ";
|
|
17459
|
+
i += 1;
|
|
17460
|
+
}
|
|
17461
|
+
}
|
|
17462
|
+
}
|
|
17463
|
+
return out.join("");
|
|
17464
|
+
}
|
|
17465
|
+
function readRedirectTarget(original, start) {
|
|
17466
|
+
let i = start;
|
|
17467
|
+
while (i < original.length && /\s/.test(original[i] ?? "")) {
|
|
17468
|
+
i += 1;
|
|
17469
|
+
}
|
|
17470
|
+
if (i >= original.length) return void 0;
|
|
17471
|
+
let text = "";
|
|
17472
|
+
let j = i;
|
|
17473
|
+
while (j < original.length) {
|
|
17474
|
+
const o = original[j];
|
|
17475
|
+
if (o === "'" || o === '"' || o === "`") {
|
|
17476
|
+
const quote = o;
|
|
17477
|
+
j += 1;
|
|
17478
|
+
while (j < original.length && original[j] !== quote) {
|
|
17479
|
+
if (original[j] === "\\" && quote !== "'" && j + 1 < original.length) {
|
|
17480
|
+
text += original[j + 1];
|
|
17481
|
+
j += 2;
|
|
17482
|
+
continue;
|
|
17483
|
+
}
|
|
17484
|
+
text += original[j];
|
|
17485
|
+
j += 1;
|
|
17486
|
+
}
|
|
17487
|
+
j += 1;
|
|
17488
|
+
continue;
|
|
17489
|
+
}
|
|
17490
|
+
if (/\s/.test(o) || SHELL_SPLIT_CHARS.has(o)) break;
|
|
17491
|
+
text += o;
|
|
17492
|
+
j += 1;
|
|
17493
|
+
}
|
|
17494
|
+
if (!text || text === "$") return void 0;
|
|
17495
|
+
return { text, end: j };
|
|
17496
|
+
}
|
|
17497
|
+
function isIgnoredRedirectTarget(target) {
|
|
17498
|
+
return target === "/dev/null";
|
|
17499
|
+
}
|
|
17500
|
+
function detectExecShellSynchronousWarnings(command, shell) {
|
|
17501
|
+
const masked = maskQuotedAndEscaped(command);
|
|
17502
|
+
const isPowerShell = shell?.resolvedShell === "powershell";
|
|
17503
|
+
const redirectTargets = [];
|
|
17504
|
+
let backgrounded = false;
|
|
17505
|
+
let i = 0;
|
|
17506
|
+
while (i < masked.length) {
|
|
17507
|
+
const ch = masked[i];
|
|
17508
|
+
if (ch === "&") {
|
|
17509
|
+
const next = masked[i + 1];
|
|
17510
|
+
if (next === "&") {
|
|
17511
|
+
i += 2;
|
|
17512
|
+
continue;
|
|
17513
|
+
}
|
|
17514
|
+
if (next === ">") {
|
|
17515
|
+
let j = i + 2;
|
|
17516
|
+
if (masked[j] === ">") j += 1;
|
|
17517
|
+
const target = readRedirectTarget(command, j);
|
|
17518
|
+
if (target && !isIgnoredRedirectTarget(target.text)) redirectTargets.push(target.text);
|
|
17519
|
+
i = target ? target.end : j;
|
|
17520
|
+
continue;
|
|
17521
|
+
}
|
|
17522
|
+
const prev = masked[i - 1];
|
|
17523
|
+
if (prev === ">" || prev === "<") {
|
|
17524
|
+
i += 1;
|
|
17525
|
+
continue;
|
|
17526
|
+
}
|
|
17527
|
+
if (isPowerShell) {
|
|
17528
|
+
i += 1;
|
|
17529
|
+
continue;
|
|
17530
|
+
}
|
|
17531
|
+
backgrounded = true;
|
|
17532
|
+
i += 1;
|
|
17533
|
+
continue;
|
|
17534
|
+
}
|
|
17535
|
+
if (ch === ">") {
|
|
17536
|
+
const prev = masked[i - 1];
|
|
17537
|
+
if (prev === ">" || prev === "&" || prev === "<") {
|
|
17538
|
+
i += 1;
|
|
17539
|
+
continue;
|
|
17540
|
+
}
|
|
17541
|
+
let j = i + 1;
|
|
17542
|
+
if (masked[j] === ">") j += 1;
|
|
17543
|
+
if (masked[j] === "&") {
|
|
17544
|
+
const ampTarget = readRedirectTarget(command, j + 1);
|
|
17545
|
+
const isFdDuplication = ampTarget !== void 0 && (/^\d+$/.test(ampTarget.text) || ampTarget.text === "-");
|
|
17546
|
+
if (ampTarget && !isFdDuplication && !isIgnoredRedirectTarget(ampTarget.text)) {
|
|
17547
|
+
redirectTargets.push(ampTarget.text);
|
|
17548
|
+
}
|
|
17549
|
+
i = ampTarget ? ampTarget.end : j + 1;
|
|
17550
|
+
continue;
|
|
17551
|
+
}
|
|
17552
|
+
const target = readRedirectTarget(command, j);
|
|
17553
|
+
if (target && !isIgnoredRedirectTarget(target.text)) redirectTargets.push(target.text);
|
|
17554
|
+
i = target ? target.end : j;
|
|
17555
|
+
continue;
|
|
17556
|
+
}
|
|
17557
|
+
if (ch === "<") {
|
|
17558
|
+
i += masked[i + 1] === "<" || masked[i + 1] === "&" ? 2 : 1;
|
|
17559
|
+
continue;
|
|
17560
|
+
}
|
|
17561
|
+
i += 1;
|
|
17562
|
+
}
|
|
17563
|
+
const wordMatch = BG_ESCAPE_WORD_PATTERN.exec(masked);
|
|
17564
|
+
if (wordMatch) backgrounded = true;
|
|
17565
|
+
const warnings = [];
|
|
17566
|
+
if (redirectTargets.length > 0) {
|
|
17567
|
+
const target = redirectTargets[0];
|
|
17568
|
+
warnings.push({
|
|
17569
|
+
kind: "output-redirect",
|
|
17570
|
+
redirectTarget: target,
|
|
17571
|
+
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.`
|
|
17572
|
+
});
|
|
17573
|
+
}
|
|
17574
|
+
if (backgrounded) {
|
|
17575
|
+
warnings.push({
|
|
17576
|
+
kind: "shell-backgrounding",
|
|
17577
|
+
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.`
|
|
17578
|
+
});
|
|
17579
|
+
}
|
|
17580
|
+
return warnings;
|
|
17581
|
+
}
|
|
17582
|
+
|
|
17525
17583
|
// packages/agent-runtime/capabilities/execShellCapability.ts
|
|
17526
17584
|
function buildExecShellToolDefinition(toolName = "execShell") {
|
|
17527
17585
|
return {
|
|
17528
17586
|
type: "function",
|
|
17529
17587
|
function: {
|
|
17530
17588
|
name: toolName,
|
|
17531
|
-
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.`,
|
|
17589
|
+
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.`,
|
|
17532
17590
|
parameters: {
|
|
17533
17591
|
type: "object",
|
|
17534
17592
|
properties: {
|
|
@@ -17539,6 +17597,10 @@ function buildExecShellToolDefinition(toolName = "execShell") {
|
|
|
17539
17597
|
cmd: {
|
|
17540
17598
|
type: "string",
|
|
17541
17599
|
description: "Compatibility alias for command."
|
|
17600
|
+
},
|
|
17601
|
+
background: {
|
|
17602
|
+
type: "boolean",
|
|
17603
|
+
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."
|
|
17542
17604
|
}
|
|
17543
17605
|
}
|
|
17544
17606
|
}
|
|
@@ -17579,11 +17641,13 @@ function normalizeExecShellInput(input) {
|
|
|
17579
17641
|
throw new Error("execShell requires a non-empty command.");
|
|
17580
17642
|
}
|
|
17581
17643
|
const activity = extractActivity(record);
|
|
17644
|
+
const background = record.background === true || typeof record.background === "string" && record.background.trim().toLowerCase() === "true";
|
|
17582
17645
|
return {
|
|
17583
17646
|
command,
|
|
17584
17647
|
...record.shell !== void 0 ? { shell: record.shell } : {},
|
|
17585
17648
|
...activity ? { activity } : {},
|
|
17586
|
-
...record.input !== void 0 ? { input: record.input } : {}
|
|
17649
|
+
...record.input !== void 0 ? { input: record.input } : {},
|
|
17650
|
+
...background ? { background: true } : {}
|
|
17587
17651
|
};
|
|
17588
17652
|
}
|
|
17589
17653
|
throw new Error("execShell requires a non-empty command.");
|
|
@@ -17621,6 +17685,7 @@ var execShellCapability = {
|
|
|
17621
17685
|
command,
|
|
17622
17686
|
shell: normalized.shell
|
|
17623
17687
|
});
|
|
17688
|
+
const background = normalized.background === true;
|
|
17624
17689
|
const result4 = await runWorkspaceCommand({
|
|
17625
17690
|
workspaceRoot,
|
|
17626
17691
|
command: shellPlan.argv,
|
|
@@ -17628,15 +17693,18 @@ var execShellCapability = {
|
|
|
17628
17693
|
outputLimit: ctx.commandOutputLimit,
|
|
17629
17694
|
commandPrefix: ctx.commandPrefix,
|
|
17630
17695
|
abortSignal: ctx.abortSignal,
|
|
17631
|
-
detachMs: isImmediateDetachShellCommand({ command }) ? 0 : ctx.detachMs,
|
|
17696
|
+
detachMs: background ? 0 : isImmediateDetachShellCommand({ command }) ? 0 : ctx.detachMs,
|
|
17632
17697
|
stdin: typeof normalized.input === "string" ? normalized.input : void 0,
|
|
17633
17698
|
// Ownership of the turn that invoked this command: an auto-detached
|
|
17634
17699
|
// command keeps its parent dialog so its terminal can resume that
|
|
17635
17700
|
// conversation (see processOwnership.ts). Absent ctx.owner = unowned.
|
|
17636
17701
|
owner: ctx.owner ?? null
|
|
17637
17702
|
});
|
|
17703
|
+
const warnings = result4.detached || result4.spawnFailed ? [] : detectExecShellSynchronousWarnings(command, {
|
|
17704
|
+
resolvedShell: shellPlan.resolvedShell
|
|
17705
|
+
});
|
|
17638
17706
|
return {
|
|
17639
|
-
content: result4.content,
|
|
17707
|
+
content: warnings.length > 0 ? [result4.content, ...warnings.map((warning) => warning.message)].join("\n\n") : result4.content,
|
|
17640
17708
|
metadata: {
|
|
17641
17709
|
command,
|
|
17642
17710
|
exitCode: result4.exitCode,
|
|
@@ -17651,8 +17719,21 @@ var execShellCapability = {
|
|
|
17651
17719
|
// Phase 0: stable taskId from the pre-registered Execution
|
|
17652
17720
|
// Envelope (additive; existing detached fields untouched).
|
|
17653
17721
|
taskId: result4.taskId,
|
|
17654
|
-
status: "running"
|
|
17655
|
-
|
|
17722
|
+
status: "running",
|
|
17723
|
+
// P0 machine-readable execution state: an explicit positive
|
|
17724
|
+
// signal instead of requiring the model to infer "not detached"
|
|
17725
|
+
// from absence. Mirrors the real lifecycle contract.
|
|
17726
|
+
executionState: "detached",
|
|
17727
|
+
trackedBackgroundTask: true,
|
|
17728
|
+
completionNotification: "terminal-resume"
|
|
17729
|
+
} : {
|
|
17730
|
+
// P0 machine-readable execution state: the command already
|
|
17731
|
+
// finished inside the synchronous window; no background task
|
|
17732
|
+
// exists, so no completion notification will ever arrive.
|
|
17733
|
+
executionState: "synchronous-complete",
|
|
17734
|
+
trackedBackgroundTask: false,
|
|
17735
|
+
completionNotification: "none"
|
|
17736
|
+
},
|
|
17656
17737
|
...normalized.activity ? { activity: normalized.activity } : {}
|
|
17657
17738
|
}
|
|
17658
17739
|
};
|
|
@@ -17868,7 +17949,7 @@ function buildLaunchProcessTool() {
|
|
|
17868
17949
|
type: "function",
|
|
17869
17950
|
function: {
|
|
17870
17951
|
name: "launchProcess",
|
|
17871
|
-
description: "Start a long-running background process (dev server, watcher, REPL) and return immediately with {pid, label, status}. Use listProcesses to inspect or stop it.",
|
|
17952
|
+
description: "Start a long-running ambient background process (dev server, watcher, REPL) and return immediately with {pid, label, taskId, status}. Real boundaries: this registers a tracked background task, but completion does NOT automatically start a new turn \u2014 the process is intentionally notice-only (an exited dev server must not silently burn a model turn). When it reaches a terminal state the bounded result (exitCode, duration, stdout/stderr tail) is recorded and surfaced as a notice injected only on your next real turn in the same conversation. Use listProcesses to inspect, taskWait to block for its terminal state, or taskStop to stop it. For a finite job (tests, builds, batch) whose result must resume the conversation automatically, use execShell with background: true instead.",
|
|
17872
17953
|
parameters: {
|
|
17873
17954
|
type: "object",
|
|
17874
17955
|
properties: {
|
|
@@ -18654,6 +18735,87 @@ async function writeFileTool(args2) {
|
|
|
18654
18735
|
}
|
|
18655
18736
|
};
|
|
18656
18737
|
}
|
|
18738
|
+
function extractSnippetWords(text) {
|
|
18739
|
+
const tokens = [];
|
|
18740
|
+
const latinWords = text.match(/[A-Za-z0-9_]{2,}/g);
|
|
18741
|
+
if (latinWords) {
|
|
18742
|
+
for (const w of latinWords) tokens.push(w.toLowerCase());
|
|
18743
|
+
}
|
|
18744
|
+
const cjkChars = text.match(new RegExp("\\p{Script=Han}", "gu"));
|
|
18745
|
+
if (cjkChars) {
|
|
18746
|
+
for (let i = 0; i < cjkChars.length - 1; i++) {
|
|
18747
|
+
tokens.push(cjkChars[i] + cjkChars[i + 1]);
|
|
18748
|
+
}
|
|
18749
|
+
if (cjkChars.length === 1) tokens.push(cjkChars[0]);
|
|
18750
|
+
}
|
|
18751
|
+
return tokens;
|
|
18752
|
+
}
|
|
18753
|
+
function calculateEditLineSimilarity(a, b) {
|
|
18754
|
+
if (a === b) return 1;
|
|
18755
|
+
if (!a || !b) return 0;
|
|
18756
|
+
if (a.includes(b) || b.includes(a)) return 0.8;
|
|
18757
|
+
const wordsA = extractSnippetWords(a);
|
|
18758
|
+
const wordsB = extractSnippetWords(b);
|
|
18759
|
+
if (wordsA.length === 0 || wordsB.length === 0) return 0;
|
|
18760
|
+
const setB = new Set(wordsB);
|
|
18761
|
+
let matches = 0;
|
|
18762
|
+
for (const w of wordsA) {
|
|
18763
|
+
if (setB.has(w)) matches++;
|
|
18764
|
+
}
|
|
18765
|
+
return 2 * matches / (wordsA.length + wordsB.length);
|
|
18766
|
+
}
|
|
18767
|
+
function findClosestEditSnippet(content, oldText) {
|
|
18768
|
+
const contentLines = content.split(/\r?\n/);
|
|
18769
|
+
const oldLinesRaw = oldText.split(/\r?\n/);
|
|
18770
|
+
const oldTrimmedLines = oldLinesRaw.map((l) => l.trim()).filter(Boolean);
|
|
18771
|
+
if (contentLines.length === 0 || oldTrimmedLines.length === 0) return null;
|
|
18772
|
+
if (oldTrimmedLines.length > 0 && contentLines.length >= oldTrimmedLines.length) {
|
|
18773
|
+
for (let i = 0; i <= contentLines.length - oldTrimmedLines.length; i++) {
|
|
18774
|
+
let allMatch = true;
|
|
18775
|
+
for (let j = 0; j < oldTrimmedLines.length; j++) {
|
|
18776
|
+
if (contentLines[i + j].trim() !== oldTrimmedLines[j]) {
|
|
18777
|
+
allMatch = false;
|
|
18778
|
+
break;
|
|
18779
|
+
}
|
|
18780
|
+
}
|
|
18781
|
+
if (allMatch) {
|
|
18782
|
+
const startLine2 = i + 1;
|
|
18783
|
+
const endLine2 = i + oldTrimmedLines.length;
|
|
18784
|
+
const snippetLines2 = [];
|
|
18785
|
+
for (let k = i; k < i + oldTrimmedLines.length; k++) {
|
|
18786
|
+
snippetLines2.push(`> ${k + 1}: ${contentLines[k]}`);
|
|
18787
|
+
}
|
|
18788
|
+
return `Exact match found with different indentation/whitespace (lines ${startLine2}-${endLine2}):
|
|
18789
|
+
${snippetLines2.join("\n")}`;
|
|
18790
|
+
}
|
|
18791
|
+
}
|
|
18792
|
+
}
|
|
18793
|
+
const candidateTargetLines = oldTrimmedLines.filter((l) => l.length >= 4);
|
|
18794
|
+
const targetLine = candidateTargetLines[0] || oldTrimmedLines[0];
|
|
18795
|
+
if (!targetLine || targetLine.length < 3) return null;
|
|
18796
|
+
let bestIndex = -1;
|
|
18797
|
+
let bestScore = 0;
|
|
18798
|
+
for (let i = 0; i < contentLines.length; i++) {
|
|
18799
|
+
const line = contentLines[i].trim();
|
|
18800
|
+
if (!line || line.length < 3) continue;
|
|
18801
|
+
const score = calculateEditLineSimilarity(line, targetLine);
|
|
18802
|
+
if (score > bestScore && score >= 0.45) {
|
|
18803
|
+
bestScore = score;
|
|
18804
|
+
bestIndex = i;
|
|
18805
|
+
if (score === 1) break;
|
|
18806
|
+
}
|
|
18807
|
+
}
|
|
18808
|
+
if (bestIndex === -1) return null;
|
|
18809
|
+
const startLine = Math.max(0, bestIndex - 2);
|
|
18810
|
+
const endLine = Math.min(contentLines.length - 1, bestIndex + 2);
|
|
18811
|
+
const snippetLines = [];
|
|
18812
|
+
for (let i = startLine; i <= endLine; i++) {
|
|
18813
|
+
const prefix = i === bestIndex ? "> " : " ";
|
|
18814
|
+
snippetLines.push(`${prefix}${i + 1}: ${contentLines[i]}`);
|
|
18815
|
+
}
|
|
18816
|
+
return `Closest match near line ${bestIndex + 1}:
|
|
18817
|
+
${snippetLines.join("\n")}`;
|
|
18818
|
+
}
|
|
18657
18819
|
async function editFileTool(args2) {
|
|
18658
18820
|
const parsed = parseWorkspaceToolArguments(args2.call.arguments);
|
|
18659
18821
|
const requestedPath = requireWorkspaceToolPath(parsed);
|
|
@@ -18672,8 +18834,11 @@ async function editFileTool(args2) {
|
|
|
18672
18834
|
newText
|
|
18673
18835
|
});
|
|
18674
18836
|
if (replacementCount !== expectedReplacements) {
|
|
18837
|
+
const hint = replacementCount === 0 ? findClosestEditSnippet(content, oldText) : null;
|
|
18675
18838
|
throw new Error(
|
|
18676
|
-
`editFile expected ${expectedReplacements} ${pluralizeReplacement(expectedReplacements)} but found ${replacementCount} in ${requestedPath} (matched after EOL normalization; verify the exact text).`
|
|
18839
|
+
`editFile expected ${expectedReplacements} ${pluralizeReplacement(expectedReplacements)} but found ${replacementCount} in ${requestedPath} (matched after EOL normalization; verify the exact text).` + (hint ? `
|
|
18840
|
+
|
|
18841
|
+
${hint}` : "")
|
|
18677
18842
|
);
|
|
18678
18843
|
}
|
|
18679
18844
|
await writeFile(absolutePath, nextContent, "utf8");
|
|
@@ -19009,6 +19174,55 @@ async function execShellTool(args2) {
|
|
|
19009
19174
|
}
|
|
19010
19175
|
);
|
|
19011
19176
|
}
|
|
19177
|
+
var LAUNCH_PROCESS_STREAM_RING_CHARS = 65536;
|
|
19178
|
+
var LAUNCH_PROCESS_STREAM_CAPTURE_MAX_CHARS = 4e6;
|
|
19179
|
+
function createLaunchProcessStreamCapture() {
|
|
19180
|
+
let ring = "";
|
|
19181
|
+
let full = null;
|
|
19182
|
+
let capturedChars = 0;
|
|
19183
|
+
let totalChars = 0;
|
|
19184
|
+
let totalNewlines = 0;
|
|
19185
|
+
return {
|
|
19186
|
+
push(chunk) {
|
|
19187
|
+
const str = typeof chunk === "string" ? chunk : chunk.toString("utf8");
|
|
19188
|
+
if (!str) return;
|
|
19189
|
+
totalChars += str.length;
|
|
19190
|
+
for (let i = 0; i < str.length; i += 1) {
|
|
19191
|
+
if (str.charCodeAt(i) === 10) totalNewlines += 1;
|
|
19192
|
+
}
|
|
19193
|
+
const combined = ring + str;
|
|
19194
|
+
if (combined.length <= LAUNCH_PROCESS_STREAM_RING_CHARS) {
|
|
19195
|
+
ring = combined;
|
|
19196
|
+
return;
|
|
19197
|
+
}
|
|
19198
|
+
if (full === null) {
|
|
19199
|
+
full = [combined];
|
|
19200
|
+
capturedChars = combined.length;
|
|
19201
|
+
} else if (capturedChars < LAUNCH_PROCESS_STREAM_CAPTURE_MAX_CHARS) {
|
|
19202
|
+
const room = LAUNCH_PROCESS_STREAM_CAPTURE_MAX_CHARS - capturedChars;
|
|
19203
|
+
const slice = str.length <= room ? str : str.slice(0, room);
|
|
19204
|
+
full.push(slice);
|
|
19205
|
+
capturedChars += slice.length;
|
|
19206
|
+
}
|
|
19207
|
+
ring = combined.slice(-LAUNCH_PROCESS_STREAM_RING_CHARS);
|
|
19208
|
+
},
|
|
19209
|
+
text() {
|
|
19210
|
+
return full === null ? ring : full.join("");
|
|
19211
|
+
},
|
|
19212
|
+
tailText() {
|
|
19213
|
+
return ring;
|
|
19214
|
+
},
|
|
19215
|
+
evicted() {
|
|
19216
|
+
return full !== null;
|
|
19217
|
+
},
|
|
19218
|
+
totalChars() {
|
|
19219
|
+
return totalChars;
|
|
19220
|
+
},
|
|
19221
|
+
totalLines() {
|
|
19222
|
+
return totalChars > 0 ? totalNewlines + 1 : 0;
|
|
19223
|
+
}
|
|
19224
|
+
};
|
|
19225
|
+
}
|
|
19012
19226
|
async function launchProcessTool(args2) {
|
|
19013
19227
|
const parsed = parseWorkspaceToolArguments(args2.call.arguments);
|
|
19014
19228
|
const command = requireShellCommand(parsed, args2.call.name);
|
|
@@ -19036,6 +19250,14 @@ async function launchProcessTool(args2) {
|
|
|
19036
19250
|
stdio: ["ignore", "pipe", "pipe"],
|
|
19037
19251
|
detached
|
|
19038
19252
|
});
|
|
19253
|
+
const stdoutCapture = createLaunchProcessStreamCapture();
|
|
19254
|
+
const stderrCapture = createLaunchProcessStreamCapture();
|
|
19255
|
+
proc.stdout?.on("data", (chunk) => stdoutCapture.push(chunk));
|
|
19256
|
+
proc.stderr?.on("data", (chunk) => stderrCapture.push(chunk));
|
|
19257
|
+
proc.stdout?.on("error", () => {
|
|
19258
|
+
});
|
|
19259
|
+
proc.stderr?.on("error", () => {
|
|
19260
|
+
});
|
|
19039
19261
|
const pid = proc.pid;
|
|
19040
19262
|
if (typeof pid !== "number") {
|
|
19041
19263
|
return {
|
|
@@ -19076,7 +19298,38 @@ async function launchProcessTool(args2) {
|
|
|
19076
19298
|
process.removeListener("SIGTERM", cleanupChildOnHostSignal);
|
|
19077
19299
|
process.removeListener("SIGINT", cleanupChildOnHostSignal);
|
|
19078
19300
|
}
|
|
19079
|
-
|
|
19301
|
+
const exitCode = code ?? 1;
|
|
19302
|
+
let capsule;
|
|
19303
|
+
try {
|
|
19304
|
+
capsule = buildProcessTaskResultCapsule({
|
|
19305
|
+
// The full captured output (bounded prefix when the process was
|
|
19306
|
+
// extremely chatty): the module tails it for the inline capsule and
|
|
19307
|
+
// spills it for recovery. Provenance carries the live original-stream
|
|
19308
|
+
// counters so truncated/spill metadata never derives from the ring.
|
|
19309
|
+
stdout: stdoutCapture.text(),
|
|
19310
|
+
stderr: stderrCapture.text(),
|
|
19311
|
+
stdoutTail: stdoutCapture.tailText(),
|
|
19312
|
+
stderrTail: stderrCapture.tailText(),
|
|
19313
|
+
exitCode,
|
|
19314
|
+
// Duration measured from the registry envelope's startedAt (spawn).
|
|
19315
|
+
startedAt: envelope.startedAt,
|
|
19316
|
+
workspaceRoot: args2.workspaceRoot,
|
|
19317
|
+
streamProvenance: {
|
|
19318
|
+
stdout: {
|
|
19319
|
+
evicted: stdoutCapture.evicted(),
|
|
19320
|
+
totalChars: stdoutCapture.totalChars(),
|
|
19321
|
+
totalLines: stdoutCapture.totalLines()
|
|
19322
|
+
},
|
|
19323
|
+
stderr: {
|
|
19324
|
+
evicted: stderrCapture.evicted(),
|
|
19325
|
+
totalChars: stderrCapture.totalChars(),
|
|
19326
|
+
totalLines: stderrCapture.totalLines()
|
|
19327
|
+
}
|
|
19328
|
+
}
|
|
19329
|
+
});
|
|
19330
|
+
} catch {
|
|
19331
|
+
}
|
|
19332
|
+
registry2.markExited(pid, exitCode, capsule);
|
|
19080
19333
|
});
|
|
19081
19334
|
const activity = extractActivity(parsed);
|
|
19082
19335
|
const resultData = { pid, label, taskId: envelope.taskId, status: "running" };
|
|
@@ -19088,6 +19341,13 @@ async function launchProcessTool(args2) {
|
|
|
19088
19341
|
label,
|
|
19089
19342
|
status: "running",
|
|
19090
19343
|
taskId: envelope.taskId,
|
|
19344
|
+
// P0 machine-readable execution state (consistent with the real wake
|
|
19345
|
+
// contract): a real background task from birth, but ambient — its
|
|
19346
|
+
// terminal result rides the next real turn's notice, not an automatic
|
|
19347
|
+
// completion turn.
|
|
19348
|
+
executionState: "background",
|
|
19349
|
+
trackedBackgroundTask: true,
|
|
19350
|
+
completionNotification: "next-turn-notice",
|
|
19091
19351
|
processLaunch: resultData,
|
|
19092
19352
|
...activity ? { activity } : {}
|
|
19093
19353
|
}
|
|
@@ -19190,7 +19450,7 @@ async function tasksTool(_args) {
|
|
|
19190
19450
|
}
|
|
19191
19451
|
async function openDesktopPreviewTool(args2) {
|
|
19192
19452
|
const parsed = parseWorkspaceToolArguments(args2.call.arguments);
|
|
19193
|
-
const url =
|
|
19453
|
+
const url = asTrimmedString(parsed.url);
|
|
19194
19454
|
if (!url) {
|
|
19195
19455
|
return {
|
|
19196
19456
|
content: JSON.stringify({ error: "openDesktopPreview requires a non-empty url." }),
|
|
@@ -19312,6 +19572,292 @@ function createLocalWorkspaceToolExecutors(args2) {
|
|
|
19312
19572
|
};
|
|
19313
19573
|
}
|
|
19314
19574
|
|
|
19575
|
+
// packages/agent-runtime/toolArgumentGate.ts
|
|
19576
|
+
var FIELD_ALIAS_GROUPS = [
|
|
19577
|
+
// localWorkspaceTools.ts:336 导出常量(readFile/writeFile/editFile/globFiles)
|
|
19578
|
+
PATH_FIELD_ALIASES,
|
|
19579
|
+
// localWorkspaceTools.ts:339-340 导出常量(editFile)
|
|
19580
|
+
OLD_TEXT_FIELD_ALIASES,
|
|
19581
|
+
NEW_TEXT_FIELD_ALIASES,
|
|
19582
|
+
// localWorkspaceTools.ts:733 `args.cmd || args.command`(launchProcess);
|
|
19583
|
+
// launchProcess 的 required ["command"] 见 localWorkspaceToolDefs.ts:283。
|
|
19584
|
+
// 注:execShell 的 schema 无 required(command 在 executor 层强制,
|
|
19585
|
+
// capabilities/execShellCapability.ts:42 声明 cmd 兼容字段),本组对它不产生拦截。
|
|
19586
|
+
["command", "cmd"],
|
|
19587
|
+
// localWorkspaceTools.ts:698-699 `args.pattern ?? args.glob`(globFiles)
|
|
19588
|
+
["pattern", "glob"],
|
|
19589
|
+
// noloWorkspaceTools.ts:492 `args.dialog ?? args.dialogId ?? args.id`(readDialog)
|
|
19590
|
+
["dialog", "dialogId", "id"],
|
|
19591
|
+
// noloWorkspaceTools.ts:545 `args.agent ?? args.agentKey ?? args.id`(readAgent)
|
|
19592
|
+
["agent", "agentKey", "id"],
|
|
19593
|
+
// noloWorkspaceTools.ts:552 `args.space ?? args.spaceId ?? args.id`(readSpace)
|
|
19594
|
+
["space", "spaceId", "id"],
|
|
19595
|
+
// noloWorkspaceTools.ts:561/567 `args.doc ?? args.docKey ?? args.pageKey ?? args.key`
|
|
19596
|
+
// (readDoc / readSkillDoc)
|
|
19597
|
+
["doc", "docKey", "pageKey", "key"],
|
|
19598
|
+
// noloWorkspaceTools.node.ts:238 `parsed.name ?? parsed.skillName ?? parsed.skill`(loadSkill)
|
|
19599
|
+
["name", "skillName", "skill"],
|
|
19600
|
+
// noloWorkspaceTools.ts:593 `args.table ?? args.tableId ?? args.metaKey`(queryTableRows)
|
|
19601
|
+
["table", "tableId", "metaKey"]
|
|
19602
|
+
];
|
|
19603
|
+
var TYPE_MATCHERS = {
|
|
19604
|
+
string: (value) => typeof value === "string",
|
|
19605
|
+
// 数字字符串视为可接受:executor 普遍 Number()/clamp 宽松处理,拦截会误报。
|
|
19606
|
+
number: (value) => typeof value === "number" || typeof value === "string" && value.trim() !== "" && Number.isFinite(Number(value)),
|
|
19607
|
+
integer: (value) => typeof value === "number" || typeof value === "string" && value.trim() !== "" && Number.isFinite(Number(value)),
|
|
19608
|
+
boolean: (value) => typeof value === "boolean" || value === "true" || value === "false",
|
|
19609
|
+
object: (value) => typeof value === "object" && value !== null && !Array.isArray(value),
|
|
19610
|
+
array: (value) => Array.isArray(value)
|
|
19611
|
+
};
|
|
19612
|
+
function describeValueType(value) {
|
|
19613
|
+
if (value === null) return "null";
|
|
19614
|
+
if (Array.isArray(value)) return "array";
|
|
19615
|
+
return typeof value;
|
|
19616
|
+
}
|
|
19617
|
+
function isAliasSatisfied(args2, field) {
|
|
19618
|
+
for (const group of FIELD_ALIAS_GROUPS) {
|
|
19619
|
+
if (!group.includes(field)) continue;
|
|
19620
|
+
if (group.some((alias) => args2[alias] !== void 0)) return true;
|
|
19621
|
+
}
|
|
19622
|
+
return false;
|
|
19623
|
+
}
|
|
19624
|
+
function readRequiredFields(parameters) {
|
|
19625
|
+
const required = parameters.required;
|
|
19626
|
+
if (!Array.isArray(required)) return [];
|
|
19627
|
+
return required.filter((field) => typeof field === "string");
|
|
19628
|
+
}
|
|
19629
|
+
function readProperties(parameters) {
|
|
19630
|
+
const properties = parameters.properties;
|
|
19631
|
+
if (!properties || typeof properties !== "object" || Array.isArray(properties)) {
|
|
19632
|
+
return {};
|
|
19633
|
+
}
|
|
19634
|
+
return properties;
|
|
19635
|
+
}
|
|
19636
|
+
function validateToolArguments(args2) {
|
|
19637
|
+
const { toolName, rawArguments, parameters } = args2;
|
|
19638
|
+
if (!parameters || typeof parameters !== "object" || Array.isArray(parameters)) {
|
|
19639
|
+
return { ok: true, args: {} };
|
|
19640
|
+
}
|
|
19641
|
+
const schema = parameters;
|
|
19642
|
+
const requiredFields = readRequiredFields(schema);
|
|
19643
|
+
const properties = readProperties(schema);
|
|
19644
|
+
if (requiredFields.length === 0 && Object.keys(properties).length === 0) {
|
|
19645
|
+
return { ok: true, args: {} };
|
|
19646
|
+
}
|
|
19647
|
+
const raw = typeof rawArguments === "string" ? rawArguments.trim() : "";
|
|
19648
|
+
let record = {};
|
|
19649
|
+
if (raw !== "") {
|
|
19650
|
+
let parsed;
|
|
19651
|
+
try {
|
|
19652
|
+
parsed = JSON.parse(raw);
|
|
19653
|
+
} catch {
|
|
19654
|
+
return { ok: true, args: {} };
|
|
19655
|
+
}
|
|
19656
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
19657
|
+
return { ok: true, args: {} };
|
|
19658
|
+
}
|
|
19659
|
+
record = parsed;
|
|
19660
|
+
}
|
|
19661
|
+
for (const field of requiredFields) {
|
|
19662
|
+
if (record[field] !== void 0) continue;
|
|
19663
|
+
if (isAliasSatisfied(record, field)) continue;
|
|
19664
|
+
return {
|
|
19665
|
+
ok: false,
|
|
19666
|
+
message: `${toolName} \u53C2\u6570\u6821\u9A8C\u5931\u8D25\uFF1A\u7F3A\u5C11\u5FC5\u586B\u53C2\u6570 "${field}"\u3002\u8BF7\u8865\u4E0A\u540E\u91CD\u65B0\u8C03\u7528 ${toolName}\u3002`
|
|
19667
|
+
};
|
|
19668
|
+
}
|
|
19669
|
+
for (const [field, spec] of Object.entries(properties)) {
|
|
19670
|
+
const value = record[field];
|
|
19671
|
+
if (value === void 0 || value === null) continue;
|
|
19672
|
+
if (!spec || typeof spec !== "object" || Array.isArray(spec)) continue;
|
|
19673
|
+
const declared = spec.type;
|
|
19674
|
+
if (typeof declared !== "string") continue;
|
|
19675
|
+
const matcher = TYPE_MATCHERS[declared];
|
|
19676
|
+
if (!matcher) continue;
|
|
19677
|
+
if (!matcher(value)) {
|
|
19678
|
+
return {
|
|
19679
|
+
ok: false,
|
|
19680
|
+
message: `${toolName} \u53C2\u6570\u6821\u9A8C\u5931\u8D25\uFF1A\u53C2\u6570 "${field}" \u5E94\u4E3A ${declared}\uFF0C\u5B9E\u9645\u6536\u5230 ${describeValueType(value)}\u3002\u8BF7\u4FEE\u6B63\u540E\u91CD\u65B0\u8C03\u7528 ${toolName}\u3002`
|
|
19681
|
+
};
|
|
19682
|
+
}
|
|
19683
|
+
}
|
|
19684
|
+
return { ok: true, args: record };
|
|
19685
|
+
}
|
|
19686
|
+
function buildToolParametersIndex(tools) {
|
|
19687
|
+
const index = /* @__PURE__ */ new Map();
|
|
19688
|
+
for (const tool of tools) {
|
|
19689
|
+
if (!tool || typeof tool !== "object") continue;
|
|
19690
|
+
const fn3 = tool.function;
|
|
19691
|
+
if (!fn3 || typeof fn3 !== "object") continue;
|
|
19692
|
+
const name = fn3.name;
|
|
19693
|
+
const parameters = fn3.parameters;
|
|
19694
|
+
if (typeof name === "string" && name && parameters !== void 0) {
|
|
19695
|
+
index.set(name, parameters);
|
|
19696
|
+
}
|
|
19697
|
+
}
|
|
19698
|
+
return index;
|
|
19699
|
+
}
|
|
19700
|
+
var cachedAgentRuntimeIndex = null;
|
|
19701
|
+
function getAgentRuntimeToolParametersIndex() {
|
|
19702
|
+
if (cachedAgentRuntimeIndex) return cachedAgentRuntimeIndex;
|
|
19703
|
+
const index = /* @__PURE__ */ new Map();
|
|
19704
|
+
try {
|
|
19705
|
+
const workspaceTools = buildLocalWorkspaceOpenAiTools({
|
|
19706
|
+
toolNames: [...WORKSPACE_TOOL_NAMES],
|
|
19707
|
+
exposeShellTools: true
|
|
19708
|
+
});
|
|
19709
|
+
for (const [name, parameters] of buildToolParametersIndex(workspaceTools)) {
|
|
19710
|
+
index.set(name, parameters);
|
|
19711
|
+
}
|
|
19712
|
+
const noloTools = buildNoloWorkspaceOpenAiTools({
|
|
19713
|
+
toolNames: [...NOLO_WORKSPACE_TOOL_NAMES]
|
|
19714
|
+
});
|
|
19715
|
+
for (const [name, parameters] of buildToolParametersIndex(noloTools)) {
|
|
19716
|
+
index.set(name, parameters);
|
|
19717
|
+
}
|
|
19718
|
+
} catch {
|
|
19719
|
+
}
|
|
19720
|
+
cachedAgentRuntimeIndex = index;
|
|
19721
|
+
return index;
|
|
19722
|
+
}
|
|
19723
|
+
|
|
19724
|
+
// packages/agent-runtime/localToolPolicy.ts
|
|
19725
|
+
var NEVER_LOCAL_TOOLS = /* @__PURE__ */ new Set([
|
|
19726
|
+
"deleteSpaces",
|
|
19727
|
+
"updateAgent",
|
|
19728
|
+
"updateSelf",
|
|
19729
|
+
"createAgent"
|
|
19730
|
+
]);
|
|
19731
|
+
var DEFAULT_LOCAL_TOOLS = /* @__PURE__ */ new Set([
|
|
19732
|
+
"readFile",
|
|
19733
|
+
"writeFile",
|
|
19734
|
+
"editFile",
|
|
19735
|
+
"globFiles",
|
|
19736
|
+
"execShell",
|
|
19737
|
+
"launchProcess",
|
|
19738
|
+
"listProcesses",
|
|
19739
|
+
// ProcessTask follow-up tools. Same tier as listProcesses: they observe/stop
|
|
19740
|
+
// tasks the agent itself already spawned, so their blast radius is strictly
|
|
19741
|
+
// narrower than launchProcess (which is default-enabled). Model-facing
|
|
19742
|
+
// follow-ups are taskWait/taskStop only — lifecycle history (taskLogs) stays
|
|
19743
|
+
// runtime-internal.
|
|
19744
|
+
"taskWait",
|
|
19745
|
+
"taskStop",
|
|
19746
|
+
// Scheduling tools: forking/observing sub-agents is a declared capability
|
|
19747
|
+
// of capable agents, and the blast radius is strictly narrower than
|
|
19748
|
+
// execShell (already default-enabled). Requiring an env allowlist for these
|
|
19749
|
+
// while execShell is open by default inverted the risk model and forced every
|
|
19750
|
+
// new local user to hand-edit .env files before sub-agent tasks worked.
|
|
19751
|
+
"startAgentRun",
|
|
19752
|
+
"controlAgentRun"
|
|
19753
|
+
]);
|
|
19754
|
+
function parseToolAllowlist(value) {
|
|
19755
|
+
return (value ?? "").split(",").flatMap((item) => {
|
|
19756
|
+
const trimmed = item.trim();
|
|
19757
|
+
return trimmed ? [trimmed] : [];
|
|
19758
|
+
});
|
|
19759
|
+
}
|
|
19760
|
+
function normalizeLocalToolName(toolName) {
|
|
19761
|
+
return canonicalizeToolName(
|
|
19762
|
+
String(toolName ?? "").replace(/^functions\./, "").trim()
|
|
19763
|
+
);
|
|
19764
|
+
}
|
|
19765
|
+
function isRestrictedLocalToolMode(env) {
|
|
19766
|
+
return env.NOLO_LOCAL_TOOL_MODE === "restricted";
|
|
19767
|
+
}
|
|
19768
|
+
function resolveLocalToolPolicy(args2) {
|
|
19769
|
+
const toolName = normalizeLocalToolName(args2.toolName);
|
|
19770
|
+
const restrictedMode = isRestrictedLocalToolMode(args2.env);
|
|
19771
|
+
if (!toolName) {
|
|
19772
|
+
return {
|
|
19773
|
+
allowed: false,
|
|
19774
|
+
toolName,
|
|
19775
|
+
reason: "Tool name is required."
|
|
19776
|
+
};
|
|
19777
|
+
}
|
|
19778
|
+
if (NEVER_LOCAL_TOOLS.has(toolName)) {
|
|
19779
|
+
return {
|
|
19780
|
+
allowed: false,
|
|
19781
|
+
toolName,
|
|
19782
|
+
reason: `${toolName} is blocked by the local runtime safety policy.`
|
|
19783
|
+
};
|
|
19784
|
+
}
|
|
19785
|
+
const allowedByEnv = new Set(
|
|
19786
|
+
parseToolAllowlist(args2.env.NOLO_LOCAL_ALLOWED_TOOLS).map(normalizeLocalToolName)
|
|
19787
|
+
);
|
|
19788
|
+
const agentTools = new Set(
|
|
19789
|
+
(args2.agentToolNames ?? []).flatMap((item) => {
|
|
19790
|
+
const normalized = normalizeLocalToolName(item);
|
|
19791
|
+
return normalized ? [normalized] : [];
|
|
19792
|
+
})
|
|
19793
|
+
);
|
|
19794
|
+
if (!restrictedMode && agentTools.has(toolName)) {
|
|
19795
|
+
return { allowed: true, toolName };
|
|
19796
|
+
}
|
|
19797
|
+
if (DEFAULT_LOCAL_TOOLS.has(toolName) && agentTools.has(toolName)) {
|
|
19798
|
+
return { allowed: true, toolName };
|
|
19799
|
+
}
|
|
19800
|
+
if (allowedByEnv.has(toolName) && agentTools.has(toolName)) {
|
|
19801
|
+
return { allowed: true, toolName };
|
|
19802
|
+
}
|
|
19803
|
+
return {
|
|
19804
|
+
allowed: false,
|
|
19805
|
+
toolName,
|
|
19806
|
+
reason: `${toolName} is not enabled for local runtime runs. The agent must declare the tool in its manifest; in restricted mode (NOLO_LOCAL_TOOL_MODE=restricted) non-default tools also require adding to NOLO_LOCAL_ALLOWED_TOOLS (e.g. NOLO_LOCAL_ALLOWED_TOOLS=someCustomTool) and restarting the session so the env var loads.`
|
|
19807
|
+
};
|
|
19808
|
+
}
|
|
19809
|
+
async function executeLocalToolWithPolicy(args2) {
|
|
19810
|
+
if (args2.runToolNames !== void 0 && !args2.runToolNames.map(normalizeLocalToolName).includes(normalizeLocalToolName(args2.call.name))) {
|
|
19811
|
+
throw new Error(`${args2.call.name} is outside the final run tool surface.`);
|
|
19812
|
+
}
|
|
19813
|
+
const decision = resolveLocalToolPolicy({
|
|
19814
|
+
env: args2.env,
|
|
19815
|
+
agentToolNames: args2.agentToolNames,
|
|
19816
|
+
toolName: args2.call.name
|
|
19817
|
+
});
|
|
19818
|
+
if (!decision.allowed) throw new Error(decision.reason);
|
|
19819
|
+
const executor = args2.executors?.[decision.toolName];
|
|
19820
|
+
if (!executor) {
|
|
19821
|
+
throw new Error(`${decision.toolName} is allowed by policy but no local executor is registered.`);
|
|
19822
|
+
}
|
|
19823
|
+
const parametersSchema = args2.toolParametersIndex?.get(decision.toolName);
|
|
19824
|
+
if (parametersSchema !== void 0) {
|
|
19825
|
+
const gate = validateToolArguments({
|
|
19826
|
+
toolName: decision.toolName,
|
|
19827
|
+
rawArguments: args2.call.arguments,
|
|
19828
|
+
parameters: parametersSchema
|
|
19829
|
+
});
|
|
19830
|
+
if (!gate.ok) throw new Error(gate.message);
|
|
19831
|
+
}
|
|
19832
|
+
const opts = {
|
|
19833
|
+
...args2.abortSignal ? { abortSignal: args2.abortSignal } : {},
|
|
19834
|
+
...args2.detachMs !== void 0 ? { detachMs: args2.detachMs } : {},
|
|
19835
|
+
...args2.confirmed !== void 0 ? { confirmed: args2.confirmed } : {},
|
|
19836
|
+
...args2.enableDestructiveShellGuard !== void 0 ? { enableDestructiveShellGuard: args2.enableDestructiveShellGuard } : {},
|
|
19837
|
+
...args2.confirmDestructiveAction ? { confirmDestructiveAction: args2.confirmDestructiveAction } : {},
|
|
19838
|
+
...args2.blockDestructiveWithoutConfirmation !== void 0 ? { blockDestructiveWithoutConfirmation: args2.blockDestructiveWithoutConfirmation } : {}
|
|
19839
|
+
};
|
|
19840
|
+
if (decision.toolName === "execShell") {
|
|
19841
|
+
let parsedInput = args2.call.arguments;
|
|
19842
|
+
if (typeof parsedInput === "string") {
|
|
19843
|
+
try {
|
|
19844
|
+
parsedInput = JSON.parse(parsedInput);
|
|
19845
|
+
} catch {
|
|
19846
|
+
parsedInput = { command: parsedInput };
|
|
19847
|
+
}
|
|
19848
|
+
}
|
|
19849
|
+
await evaluateExecShellDestructiveGuard(parsedInput, opts);
|
|
19850
|
+
opts.confirmed = true;
|
|
19851
|
+
}
|
|
19852
|
+
return executor(
|
|
19853
|
+
{
|
|
19854
|
+
...args2.call,
|
|
19855
|
+
name: decision.toolName
|
|
19856
|
+
},
|
|
19857
|
+
opts
|
|
19858
|
+
);
|
|
19859
|
+
}
|
|
19860
|
+
|
|
19315
19861
|
// packages/cli/client/localDialogRecords.ts
|
|
19316
19862
|
var localDialogMessageRecordToRuntimeMessage = dialogMessageRecordToAgentRuntimeMessage;
|
|
19317
19863
|
function buildLocalDialogWritePlan(args2) {
|
|
@@ -19448,10 +19994,10 @@ function buildLoadSkillExecutor(args2) {
|
|
|
19448
19994
|
metadata: { loadSkill: true, resolved: false }
|
|
19449
19995
|
};
|
|
19450
19996
|
}
|
|
19451
|
-
const { resolveSkillByName } = await import("./skillDiscovery-
|
|
19997
|
+
const { resolveSkillByName } = await import("./skillDiscovery-ZBU76COE.js");
|
|
19452
19998
|
const resolved = resolveSkillByName(args2.cwd, name);
|
|
19453
19999
|
if (!resolved) {
|
|
19454
|
-
const { resolveBuiltinSkillByName } = await import("./builtinSkillRegistry-
|
|
20000
|
+
const { resolveBuiltinSkillByName } = await import("./builtinSkillRegistry-MAR5LPAC.js");
|
|
19455
20001
|
const builtin = resolveBuiltinSkillByName(name);
|
|
19456
20002
|
if (builtin) {
|
|
19457
20003
|
return {
|
|
@@ -19494,7 +20040,7 @@ ${body}`,
|
|
|
19494
20040
|
};
|
|
19495
20041
|
}
|
|
19496
20042
|
async function formatUnknownSkillMessage(cwd, requestedName) {
|
|
19497
|
-
const { discoverSkills } = await import("./skillDiscovery-
|
|
20043
|
+
const { discoverSkills } = await import("./skillDiscovery-ZBU76COE.js");
|
|
19498
20044
|
let available = [];
|
|
19499
20045
|
try {
|
|
19500
20046
|
available = discoverSkills(cwd).map((s) => s.name);
|
|
@@ -19509,739 +20055,29 @@ No skills were discovered in this workspace.`;
|
|
|
19509
20055
|
Available skills: ${available.join(", ")}`;
|
|
19510
20056
|
}
|
|
19511
20057
|
|
|
19512
|
-
// packages/
|
|
19513
|
-
|
|
19514
|
-
|
|
19515
|
-
|
|
19516
|
-
|
|
19517
|
-
|
|
19518
|
-
|
|
19519
|
-
|
|
19520
|
-
|
|
19521
|
-
|
|
19522
|
-
|
|
19523
|
-
|
|
19524
|
-
|
|
19525
|
-
|
|
19526
|
-
|
|
19527
|
-
|
|
19528
|
-
|
|
19529
|
-
// packages/agent-runtime/antigravityCloudCodeProvider.ts
|
|
19530
|
-
import { randomUUID } from "node:crypto";
|
|
19531
|
-
|
|
19532
|
-
// packages/agent-runtime/antigravityWireModel.ts
|
|
19533
|
-
var WIRE_PROFILES = {
|
|
19534
|
-
// Antigravity discovery exposes 3.7 Flash as one tiered wire model.
|
|
19535
|
-
// The UI labels its effort variants (Low/Medium/High), but the literal
|
|
19536
|
-
// -medium/-high ids return 404 from streamGenerateContent.
|
|
19537
|
-
"gemini-3.7-flash-tiered": { modelEnum: "MODEL_PLACEHOLDER_M301", maxOutputTokens: 65536 },
|
|
19538
|
-
// Gemini 3.8 Flash 沿用 3.7 的 tiered 兼容策略:仓库内暂无 Antigravity discovery
|
|
19539
|
-
// 证据确认 3.8 的 wire modelEnum,禁止虚构,先只声明同档输出上限;enum 待
|
|
19540
|
-
// discovery 证据到位后补齐。
|
|
19541
|
-
"gemini-3.8-flash-tiered": { maxOutputTokens: 65536 },
|
|
19542
|
-
"gemini-3.6-flash-low": { maxOutputTokens: 65536 },
|
|
19543
|
-
"gemini-3.6-flash-medium": { maxOutputTokens: 65536 },
|
|
19544
|
-
"gemini-3.6-flash-high": { maxOutputTokens: 65536 },
|
|
19545
|
-
// 旧模型 wire 映射保留:存量自定义 agent 仍可能引用(注册表已下线不影响此处)。
|
|
19546
|
-
"gemini-3.5-flash-extra-low": { modelEnum: "MODEL_PLACEHOLDER_M187", maxOutputTokens: 65536 },
|
|
19547
|
-
"gemini-3.5-flash-low": { modelEnum: "MODEL_PLACEHOLDER_M20", maxOutputTokens: 65536 },
|
|
19548
|
-
"gemini-3-flash-agent": { modelEnum: "MODEL_PLACEHOLDER_M132", maxOutputTokens: 65536 },
|
|
19549
|
-
"gemini-3.1-pro-low": { modelEnum: "MODEL_PLACEHOLDER_M36", maxOutputTokens: 65535 },
|
|
19550
|
-
"gemini-pro-agent": { modelEnum: "MODEL_PLACEHOLDER_M16", maxOutputTokens: 65535 },
|
|
19551
|
-
"claude-sonnet-5": { maxOutputTokens: 64e3 },
|
|
19552
|
-
"claude-sonnet-4-6": { maxOutputTokens: 64e3 },
|
|
19553
|
-
"claude-opus-4-6-thinking": { maxOutputTokens: 64e3 },
|
|
19554
|
-
"gemini-2.5-flash": { maxOutputTokens: 65536 },
|
|
19555
|
-
"gemini-2.5-pro": { maxOutputTokens: 65536 }
|
|
19556
|
-
};
|
|
19557
|
-
function resolveAntigravityWireModel(logicalModelId) {
|
|
19558
|
-
const id = logicalModelId.trim();
|
|
19559
|
-
const lower = id.toLowerCase();
|
|
19560
|
-
if (lower === "gemini-3.5-flash") {
|
|
19561
|
-
const wireModelId = "gemini-3.5-flash-low";
|
|
19562
|
-
return { wireModelId, profile: WIRE_PROFILES[wireModelId] };
|
|
19563
|
-
}
|
|
19564
|
-
if (lower === "gemini-3.7-flash" || ["gemini-3.7-flash-low", "gemini-3.7-flash-medium", "gemini-3.7-flash-high"].includes(lower)) {
|
|
19565
|
-
const wireModelId = "gemini-3.7-flash-tiered";
|
|
19566
|
-
return { wireModelId, profile: WIRE_PROFILES[wireModelId] };
|
|
19567
|
-
}
|
|
19568
|
-
if (lower === "gemini-3.8-flash" || ["gemini-3.8-flash-low", "gemini-3.8-flash-medium", "gemini-3.8-flash-high"].includes(lower)) {
|
|
19569
|
-
const wireModelId = "gemini-3.8-flash-tiered";
|
|
19570
|
-
return { wireModelId, profile: WIRE_PROFILES[wireModelId] };
|
|
19571
|
-
}
|
|
19572
|
-
if (lower === "gemini-3.6-flash") {
|
|
19573
|
-
const wireModelId = "gemini-3.6-flash-low";
|
|
19574
|
-
return { wireModelId, profile: WIRE_PROFILES[wireModelId] };
|
|
19575
|
-
}
|
|
19576
|
-
if (lower === "gemini-3.1-pro" || lower === "gemini-3.1-pro-preview") {
|
|
19577
|
-
const wireModelId = "gemini-3.1-pro-low";
|
|
19578
|
-
return { wireModelId, profile: WIRE_PROFILES[wireModelId] };
|
|
19579
|
-
}
|
|
19580
|
-
if (WIRE_PROFILES[id]) {
|
|
19581
|
-
return { wireModelId: id, profile: WIRE_PROFILES[id] };
|
|
19582
|
-
}
|
|
19583
|
-
return { wireModelId: id };
|
|
19584
|
-
}
|
|
19585
|
-
|
|
19586
|
-
// packages/agent-runtime/geminiNativeShared.ts
|
|
19587
|
-
var SKIP_THOUGHT_SIGNATURE = "skip_thought_signature_validator";
|
|
19588
|
-
function resolveGeminiModelQuirks(modelId) {
|
|
19589
|
-
const lower = modelId.toLowerCase();
|
|
19590
|
-
const isGemini3 = lower.includes("gemini-3");
|
|
19591
|
-
const isStrictSignatureModel = lower.includes("gemini-3.5") || lower.includes("flash-preview");
|
|
19592
|
-
const isClaude = lower.includes("claude");
|
|
19593
|
-
return {
|
|
19594
|
-
requiresThoughtSignature: isGemini3,
|
|
19595
|
-
allowsThoughtSignatureSentinel: isGemini3 && !isStrictSignatureModel,
|
|
19596
|
-
isClaudeCrossModel: isClaude
|
|
19597
|
-
};
|
|
19598
|
-
}
|
|
19599
|
-
function isGemini3Model(modelId) {
|
|
19600
|
-
return resolveGeminiModelQuirks(modelId).requiresThoughtSignature;
|
|
19601
|
-
}
|
|
19602
|
-
function messageText(content) {
|
|
19603
|
-
if (typeof content === "string") return content;
|
|
19604
|
-
if (!Array.isArray(content)) return "";
|
|
19605
|
-
return content.filter(
|
|
19606
|
-
(part) => part?.type === "text"
|
|
19607
|
-
).map((part) => part.text).join("\n").trim();
|
|
19608
|
-
}
|
|
19609
|
-
function parseDataUrlToInlineData(url) {
|
|
19610
|
-
const match7 = /^data:([A-Za-z0-9.+-]+\/[A-Za-z0-9.+-]+);base64,([A-Za-z0-9+/=]*)$/.exec(
|
|
19611
|
-
url
|
|
19612
|
-
);
|
|
19613
|
-
if (!match7) return null;
|
|
19614
|
-
return { mimeType: match7[1], data: match7[2] };
|
|
19615
|
-
}
|
|
19616
|
-
function extractInlineDataParts(content) {
|
|
19617
|
-
if (!Array.isArray(content)) return [];
|
|
19618
|
-
const parts2 = [];
|
|
19619
|
-
for (const part of content) {
|
|
19620
|
-
if (!part || typeof part !== "object") continue;
|
|
19621
|
-
if (part.type !== "image_url") continue;
|
|
19622
|
-
const url = part.image_url?.url;
|
|
19623
|
-
if (typeof url !== "string" || !url.trim()) continue;
|
|
19624
|
-
const inline = parseDataUrlToInlineData(url);
|
|
19625
|
-
if (inline) parts2.push({ inlineData: inline });
|
|
19626
|
-
}
|
|
19627
|
-
return parts2;
|
|
19628
|
-
}
|
|
19629
|
-
function convertOpenAiMessagesToGemini(messages, options) {
|
|
19630
|
-
const contents = [];
|
|
19631
|
-
const systemTexts = [];
|
|
19632
|
-
let toolCallIndex = 0;
|
|
19633
|
-
let pendingFunctionCalls = [];
|
|
19634
|
-
const pushOrMergeContent = (role, parts2) => {
|
|
19635
|
-
if (parts2.length === 0) return;
|
|
19636
|
-
const last = contents[contents.length - 1];
|
|
19637
|
-
if (last && last.role === role) {
|
|
19638
|
-
last.parts.push(...parts2);
|
|
19639
|
-
} else {
|
|
19640
|
-
contents.push({ role, parts: parts2 });
|
|
19641
|
-
}
|
|
19642
|
-
};
|
|
19643
|
-
const flushPendingFunctionCalls = () => {
|
|
19644
|
-
if (pendingFunctionCalls.length === 0) return;
|
|
19645
|
-
const dummyResponses = pendingFunctionCalls.map(
|
|
19646
|
-
({ name, id }) => ({
|
|
19647
|
-
functionResponse: {
|
|
19648
|
-
name,
|
|
19649
|
-
response: { output: "{}" },
|
|
19650
|
-
...id ? { id } : {}
|
|
19651
|
-
}
|
|
19652
|
-
})
|
|
19653
|
-
);
|
|
19654
|
-
pendingFunctionCalls = [];
|
|
19655
|
-
pushOrMergeContent("user", dummyResponses);
|
|
19656
|
-
};
|
|
19657
|
-
for (const raw of messages) {
|
|
19658
|
-
if (!raw || typeof raw !== "object" || !("role" in raw)) continue;
|
|
19659
|
-
const role = String(raw.role);
|
|
19660
|
-
const content = "content" in raw ? raw.content : null;
|
|
19661
|
-
if (role === "system") {
|
|
19662
|
-
const text = messageText(
|
|
19663
|
-
content
|
|
19664
|
-
);
|
|
19665
|
-
if (text) systemTexts.push(text);
|
|
19666
|
-
continue;
|
|
19667
|
-
}
|
|
19668
|
-
if (role === "user") {
|
|
19669
|
-
flushPendingFunctionCalls();
|
|
19670
|
-
const text = messageText(
|
|
19671
|
-
content
|
|
19672
|
-
);
|
|
19673
|
-
const imageParts = extractInlineDataParts(
|
|
19674
|
-
content
|
|
19675
|
-
);
|
|
19676
|
-
if (!text && imageParts.length === 0) continue;
|
|
19677
|
-
const parts2 = [];
|
|
19678
|
-
if (text) parts2.push({ text });
|
|
19679
|
-
for (const img of imageParts) parts2.push(img);
|
|
19680
|
-
pushOrMergeContent("user", parts2);
|
|
19681
|
-
continue;
|
|
19682
|
-
}
|
|
19683
|
-
if (role === "assistant") {
|
|
19684
|
-
flushPendingFunctionCalls();
|
|
19685
|
-
const text = messageText(
|
|
19686
|
-
content
|
|
19687
|
-
);
|
|
19688
|
-
const toolCalls = "tool_calls" in raw && Array.isArray(raw.tool_calls) ? raw.tool_calls ?? [] : [];
|
|
19689
|
-
const parts2 = [];
|
|
19690
|
-
if (text) {
|
|
19691
|
-
parts2.push({ text });
|
|
19692
|
-
}
|
|
19693
|
-
for (const call of toolCalls) {
|
|
19694
|
-
const name = call?.function?.name?.trim();
|
|
19695
|
-
if (!name) continue;
|
|
19696
|
-
const id = call.id?.trim() || `${name}_${toolCallIndex++}`;
|
|
19697
|
-
pendingFunctionCalls.push({ name, id });
|
|
19698
|
-
const realSignature = typeof call.thought_signature === "string" && call.thought_signature ? call.thought_signature : void 0;
|
|
19699
|
-
const isFirstFunctionCallPart = !parts2.some(
|
|
19700
|
-
(p) => "functionCall" in p
|
|
19701
|
-
);
|
|
19702
|
-
const signature = realSignature ?? (options.attachSkipThoughtSignature && isFirstFunctionCallPart ? SKIP_THOUGHT_SIGNATURE : void 0);
|
|
19703
|
-
const part = {
|
|
19704
|
-
functionCall: {
|
|
19705
|
-
name,
|
|
19706
|
-
args: parseToolArgs(call.function?.arguments),
|
|
19707
|
-
...id ? { id } : {}
|
|
19708
|
-
},
|
|
19709
|
-
...signature ? { thoughtSignature: signature } : {}
|
|
19710
|
-
};
|
|
19711
|
-
parts2.push(part);
|
|
19712
|
-
}
|
|
19713
|
-
pushOrMergeContent("model", parts2);
|
|
19714
|
-
continue;
|
|
19715
|
-
}
|
|
19716
|
-
if (role === "tool") {
|
|
19717
|
-
const toolCallId = "tool_call_id" in raw && typeof raw.tool_call_id === "string" ? raw.tool_call_id : "";
|
|
19718
|
-
const rawName = "name" in raw && typeof raw.name === "string" ? raw.name.trim() : "";
|
|
19719
|
-
const pendingIndex = pendingFunctionCalls.findIndex(
|
|
19720
|
-
(p) => toolCallId ? p.id === toolCallId : rawName ? p.name === rawName : true
|
|
19721
|
-
);
|
|
19722
|
-
if (pendingIndex === -1) continue;
|
|
19723
|
-
const [{ name, id }] = pendingFunctionCalls.splice(pendingIndex, 1);
|
|
19724
|
-
const output = messageText(content) || "{}";
|
|
19725
|
-
pushOrMergeContent("user", [
|
|
19726
|
-
{
|
|
19727
|
-
functionResponse: {
|
|
19728
|
-
name,
|
|
19729
|
-
response: { output },
|
|
19730
|
-
// 保留 OpenAI tool_call_id:antigravity Cloud Code Assist 网关把
|
|
19731
|
-
// Gemini contents 转成 Claude messages 时需要 functionResponse →
|
|
19732
|
-
// tool_result 的 tool_use_id;缺 id 时网关报
|
|
19733
|
-
// "tool_result.tool_use_id: Field required"(HTTP 400)。
|
|
19734
|
-
...id ? { id } : {}
|
|
19735
|
-
}
|
|
19736
|
-
}
|
|
19737
|
-
]);
|
|
19738
|
-
}
|
|
19739
|
-
}
|
|
19740
|
-
flushPendingFunctionCalls();
|
|
19741
|
-
if (contents.length > 0 && contents[0]?.role === "model") {
|
|
19742
|
-
contents.unshift({
|
|
19743
|
-
role: "user",
|
|
19744
|
-
parts: [{ text: "Continue the conversation." }]
|
|
19745
|
-
});
|
|
19746
|
-
}
|
|
19747
|
-
return { contents, systemTexts };
|
|
19748
|
-
}
|
|
19749
|
-
function parseToolArgs(raw) {
|
|
19750
|
-
if (typeof raw === "string") {
|
|
19751
|
-
try {
|
|
19752
|
-
const parsed = JSON.parse(raw);
|
|
19753
|
-
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
19754
|
-
return parsed;
|
|
19755
|
-
}
|
|
19756
|
-
} catch {
|
|
19757
|
-
}
|
|
19758
|
-
}
|
|
19759
|
-
if (raw && typeof raw === "object" && !Array.isArray(raw)) {
|
|
19760
|
-
return raw;
|
|
19761
|
-
}
|
|
19762
|
-
return {};
|
|
19763
|
-
}
|
|
19764
|
-
function sanitizeGeminiSchemaNode(node, active) {
|
|
19765
|
-
const out = {};
|
|
19766
|
-
if (!node || typeof node !== "object" || Array.isArray(node)) {
|
|
19767
|
-
return { type: "string" };
|
|
19768
|
-
}
|
|
19769
|
-
if (active?.has(node)) {
|
|
19770
|
-
return { type: "object", description: "(circular schema reference)" };
|
|
19771
|
-
}
|
|
19772
|
-
const seen = active ?? /* @__PURE__ */ new WeakSet();
|
|
19773
|
-
seen.add(node);
|
|
19774
|
-
try {
|
|
19775
|
-
return sanitizeGeminiSchemaNodeInner(node, out, seen);
|
|
19776
|
-
} finally {
|
|
19777
|
-
seen.delete(node);
|
|
19778
|
-
}
|
|
19779
|
-
}
|
|
19780
|
-
function sanitizeGeminiSchemaNodeInner(src, out, seen) {
|
|
19781
|
-
if (Array.isArray(src.type)) {
|
|
19782
|
-
const firstNonNull = src.type.find((t) => t !== "null");
|
|
19783
|
-
if (typeof firstNonNull === "string") out.type = firstNonNull;
|
|
19784
|
-
out.nullable = true;
|
|
19785
|
-
} else if (typeof src.type === "string") {
|
|
19786
|
-
out.type = src.type;
|
|
19787
|
-
}
|
|
19788
|
-
if (typeof src.description === "string") out.description = src.description;
|
|
19789
|
-
if (typeof src.minimum === "number") out.minimum = src.minimum;
|
|
19790
|
-
if (typeof src.maximum === "number") out.maximum = src.maximum;
|
|
19791
|
-
if (Array.isArray(src.enum) && src.enum.length > 0) out.enum = src.enum;
|
|
19792
|
-
if (src.nullable === true) out.nullable = true;
|
|
19793
|
-
if ("const" in src && src.const !== void 0 && !out.enum) {
|
|
19794
|
-
out.enum = [src.const];
|
|
19795
|
-
}
|
|
19796
|
-
const variantBranches = [
|
|
19797
|
-
...Array.isArray(src.oneOf) ? src.oneOf : [],
|
|
19798
|
-
...Array.isArray(src.anyOf) ? src.anyOf : []
|
|
19799
|
-
];
|
|
19800
|
-
if (variantBranches.length > 0) {
|
|
19801
|
-
const mergedProperties = {};
|
|
19802
|
-
let requiredIntersection;
|
|
19803
|
-
for (const branch of variantBranches) {
|
|
19804
|
-
const sanitized = sanitizeGeminiSchemaNode(branch, seen);
|
|
19805
|
-
const branchProperties = sanitized.properties ?? {};
|
|
19806
|
-
for (const [key, value] of Object.entries(branchProperties)) {
|
|
19807
|
-
const previous = mergedProperties[key];
|
|
19808
|
-
const prevEnum = previous?.enum;
|
|
19809
|
-
const nextEnum = value?.enum;
|
|
19810
|
-
if (prevEnum && nextEnum) {
|
|
19811
|
-
mergedProperties[key] = {
|
|
19812
|
-
...value,
|
|
19813
|
-
enum: [.../* @__PURE__ */ new Set([...prevEnum, ...nextEnum])]
|
|
19814
|
-
};
|
|
19815
|
-
} else {
|
|
19816
|
-
mergedProperties[key] = value;
|
|
19817
|
-
}
|
|
19818
|
-
}
|
|
19819
|
-
const branchRequired = Array.isArray(sanitized.required) ? sanitized.required : [];
|
|
19820
|
-
requiredIntersection = requiredIntersection === void 0 ? [...branchRequired] : requiredIntersection.filter((r) => branchRequired.includes(r));
|
|
19821
|
-
}
|
|
19822
|
-
out.properties = {
|
|
19823
|
-
...out.properties ?? {},
|
|
19824
|
-
...mergedProperties
|
|
19825
|
-
};
|
|
19826
|
-
if (requiredIntersection !== void 0 && requiredIntersection.length > 0) {
|
|
19827
|
-
out.required = requiredIntersection;
|
|
19828
|
-
}
|
|
19829
|
-
if (typeof out.type !== "string") out.type = "object";
|
|
19830
|
-
}
|
|
19831
|
-
if (Array.isArray(src.allOf)) {
|
|
19832
|
-
for (const branch of src.allOf) {
|
|
19833
|
-
const sanitized = sanitizeGeminiSchemaNode(branch, seen);
|
|
19834
|
-
out.properties = {
|
|
19835
|
-
...out.properties ?? {},
|
|
19836
|
-
...sanitized.properties ?? {}
|
|
19837
|
-
};
|
|
19838
|
-
if (Array.isArray(sanitized.required)) {
|
|
19839
|
-
out.required = [
|
|
19840
|
-
.../* @__PURE__ */ new Set([
|
|
19841
|
-
...out.required ?? [],
|
|
19842
|
-
...sanitized.required ?? []
|
|
19843
|
-
])
|
|
19844
|
-
];
|
|
19845
|
-
}
|
|
19846
|
-
}
|
|
19847
|
-
if (typeof out.type !== "string") out.type = "object";
|
|
19848
|
-
}
|
|
19849
|
-
if (src.properties && typeof src.properties === "object") {
|
|
19850
|
-
const properties = {};
|
|
19851
|
-
for (const [key, value] of Object.entries(
|
|
19852
|
-
src.properties
|
|
19853
|
-
)) {
|
|
19854
|
-
properties[key] = sanitizeGeminiSchemaNode(value, seen);
|
|
19855
|
-
}
|
|
19856
|
-
out.properties = properties;
|
|
19857
|
-
if (typeof out.type !== "string") out.type = "object";
|
|
19858
|
-
}
|
|
19859
|
-
if (Array.isArray(src.required)) {
|
|
19860
|
-
const properties = out.properties ?? {};
|
|
19861
|
-
const required = [...new Set(src.required)].filter(
|
|
19862
|
-
(r) => typeof r === "string" && r in properties
|
|
19863
|
-
);
|
|
19864
|
-
if (required.length > 0) out.required = required;
|
|
19865
|
-
}
|
|
19866
|
-
if (src.items !== void 0) {
|
|
19867
|
-
out.items = sanitizeGeminiSchemaNode(src.items, seen);
|
|
19868
|
-
if (typeof out.type !== "string") out.type = "array";
|
|
19869
|
-
}
|
|
19870
|
-
if (typeof out.type !== "string") out.type = "object";
|
|
19871
|
-
return out;
|
|
19872
|
-
}
|
|
19873
|
-
function convertOpenAiToolsToGemini(tools) {
|
|
19874
|
-
if (!Array.isArray(tools) || tools.length === 0) return void 0;
|
|
19875
|
-
const declarations = [];
|
|
19876
|
-
for (const tool of tools) {
|
|
19877
|
-
if (!tool || typeof tool !== "object" || !("function" in tool)) continue;
|
|
19878
|
-
const fn3 = tool.function;
|
|
19879
|
-
const name = typeof fn3.name === "string" ? fn3.name : "";
|
|
19880
|
-
if (!name) continue;
|
|
19881
|
-
declarations.push({
|
|
19882
|
-
name,
|
|
19883
|
-
description: typeof fn3.description === "string" ? fn3.description : "",
|
|
19884
|
-
parameters: sanitizeGeminiSchemaNode(
|
|
19885
|
-
fn3.parameters ?? { type: "object", properties: {} }
|
|
19886
|
-
)
|
|
19887
|
-
});
|
|
19888
|
-
}
|
|
19889
|
-
if (declarations.length === 0) return void 0;
|
|
19890
|
-
return [{ functionDeclarations: declarations }];
|
|
19891
|
-
}
|
|
19892
|
-
function createGeminiAccumulatorState() {
|
|
19893
|
-
return {
|
|
19894
|
-
text: "",
|
|
19895
|
-
toolCalls: [],
|
|
19896
|
-
reasoning: "",
|
|
19897
|
-
events: []
|
|
19898
|
-
};
|
|
19899
|
-
}
|
|
19900
|
-
function applyGeminiChunk(chunk, state, options) {
|
|
19901
|
-
if (!chunk || typeof chunk !== "object") return;
|
|
19902
|
-
const response = "response" in chunk && chunk.response && typeof chunk.response === "object" ? chunk.response : chunk;
|
|
19903
|
-
if ("usageMetadata" in response && response.usageMetadata && typeof response.usageMetadata === "object") {
|
|
19904
|
-
const meta = response.usageMetadata;
|
|
19905
|
-
const prompt = typeof meta.promptTokenCount === "number" ? meta.promptTokenCount : 0;
|
|
19906
|
-
const candidates2 = typeof meta.candidatesTokenCount === "number" ? meta.candidatesTokenCount : 0;
|
|
19907
|
-
const total = typeof meta.totalTokenCount === "number" ? meta.totalTokenCount : prompt + candidates2;
|
|
19908
|
-
const cached3 = typeof meta.cachedContentTokenCount === "number" && Number.isFinite(meta.cachedContentTokenCount) ? (
|
|
19909
|
-
// cached ⊆ prompt;对畸形上游防御性钳位,避免 cache_read > input 破坏归一化与计费
|
|
19910
|
-
Math.min(Math.max(0, Math.floor(meta.cachedContentTokenCount)), prompt)
|
|
19911
|
-
) : 0;
|
|
19912
|
-
state.usage = {
|
|
19913
|
-
prompt_tokens: prompt,
|
|
19914
|
-
completion_tokens: candidates2,
|
|
19915
|
-
total_tokens: total,
|
|
19916
|
-
...cached3 > 0 ? { cache_read_input_tokens: cached3 } : {}
|
|
19917
|
-
};
|
|
19918
|
-
state.events.push({ kind: "usage", usage: state.usage });
|
|
19919
|
-
}
|
|
19920
|
-
const candidates = Array.isArray(response.candidates) ? response.candidates : [];
|
|
19921
|
-
for (const candidate of candidates) {
|
|
19922
|
-
if (!candidate || typeof candidate !== "object") continue;
|
|
19923
|
-
const candidateFinishReason = candidate.finishReason;
|
|
19924
|
-
if (typeof candidateFinishReason === "string" && candidateFinishReason.trim()) {
|
|
19925
|
-
state.finishReason = candidateFinishReason.trim();
|
|
19926
|
-
state.events.push({ kind: "finish", reason: state.finishReason });
|
|
19927
|
-
}
|
|
19928
|
-
const parts2 = Array.isArray(
|
|
19929
|
-
candidate.content?.parts
|
|
19930
|
-
) ? candidate.content.parts : [];
|
|
19931
|
-
for (const part of parts2) {
|
|
19932
|
-
if (!part || typeof part !== "object") continue;
|
|
19933
|
-
const partSignature = part.thoughtSignature;
|
|
19934
|
-
const isThought = Boolean(part.thought);
|
|
19935
|
-
if ("text" in part && typeof part.text === "string") {
|
|
19936
|
-
const piece = part.text;
|
|
19937
|
-
if (!isThought) {
|
|
19938
|
-
state.text += piece;
|
|
19939
|
-
if (piece) {
|
|
19940
|
-
state.events.push({ kind: "text", text: piece });
|
|
19941
|
-
if (options?.onTextDelta) options.onTextDelta(piece);
|
|
19942
|
-
}
|
|
19943
|
-
} else {
|
|
19944
|
-
state.reasoning += piece;
|
|
19945
|
-
if (piece) {
|
|
19946
|
-
state.events.push({ kind: "reasoning", text: piece });
|
|
19947
|
-
if (options?.onReasoningDelta) options.onReasoningDelta(piece);
|
|
19948
|
-
}
|
|
19949
|
-
}
|
|
19950
|
-
}
|
|
19951
|
-
if (isThought && typeof partSignature === "string" && partSignature) {
|
|
19952
|
-
state.pendingThoughtSignature = partSignature;
|
|
19953
|
-
}
|
|
19954
|
-
if ("functionCall" in part && part.functionCall) {
|
|
19955
|
-
const call = part.functionCall;
|
|
19956
|
-
const name = typeof call.name === "string" ? call.name : "tool";
|
|
19957
|
-
const id = typeof call.id === "string" ? call.id : `${name}_${state.toolCalls.length}`;
|
|
19958
|
-
const argsObj = call.args && typeof call.args === "object" ? call.args : {};
|
|
19959
|
-
const resolvedSignature = typeof partSignature === "string" && partSignature ? partSignature : state.pendingThoughtSignature;
|
|
19960
|
-
state.pendingThoughtSignature = void 0;
|
|
19961
|
-
const toolCall = {
|
|
19962
|
-
id,
|
|
19963
|
-
type: "function",
|
|
19964
|
-
function: { name, arguments: JSON.stringify(argsObj) },
|
|
19965
|
-
...typeof resolvedSignature === "string" && resolvedSignature ? { thought_signature: resolvedSignature } : {}
|
|
19966
|
-
};
|
|
19967
|
-
state.toolCalls.push(toolCall);
|
|
19968
|
-
state.events.push({ kind: "tool_call", toolCall });
|
|
19969
|
-
}
|
|
19970
|
-
}
|
|
19971
|
-
}
|
|
19972
|
-
}
|
|
19973
|
-
function accumulateGeminiChunks(chunks2, options) {
|
|
19974
|
-
const state = createGeminiAccumulatorState();
|
|
19975
|
-
for (const chunk of chunks2) {
|
|
19976
|
-
applyGeminiChunk(chunk, state, options);
|
|
19977
|
-
}
|
|
19978
|
-
return {
|
|
19979
|
-
text: state.text,
|
|
19980
|
-
toolCalls: state.toolCalls,
|
|
19981
|
-
usage: state.usage,
|
|
19982
|
-
finishReason: state.finishReason,
|
|
19983
|
-
reasoningContent: state.reasoning,
|
|
19984
|
-
events: state.events
|
|
19985
|
-
};
|
|
19986
|
-
}
|
|
19987
|
-
async function accumulateGeminiStream(stream, options) {
|
|
19988
|
-
const state = createGeminiAccumulatorState();
|
|
19989
|
-
for await (const chunk of stream) {
|
|
19990
|
-
applyGeminiChunk(chunk, state, options);
|
|
19991
|
-
}
|
|
19992
|
-
return {
|
|
19993
|
-
text: state.text,
|
|
19994
|
-
toolCalls: state.toolCalls,
|
|
19995
|
-
usage: state.usage,
|
|
19996
|
-
finishReason: state.finishReason,
|
|
19997
|
-
reasoningContent: state.reasoning,
|
|
19998
|
-
events: state.events
|
|
19999
|
-
};
|
|
20000
|
-
}
|
|
20001
|
-
function shouldUseGeminiNativeToolRoute(provider, model, tools, isImageModel) {
|
|
20002
|
-
return provider === "google" && !isImageModel(model) && isGemini3Model(model) && Array.isArray(tools) && tools.length > 0;
|
|
20003
|
-
}
|
|
20004
|
-
function buildGeminiGenerateContentRequest(args2) {
|
|
20005
|
-
const { contents, systemTexts } = convertOpenAiMessagesToGemini(
|
|
20006
|
-
args2.messages,
|
|
20007
|
-
{ attachSkipThoughtSignature: args2.attachSkipThoughtSignature }
|
|
20008
|
-
);
|
|
20009
|
-
const request3 = { contents };
|
|
20010
|
-
if (systemTexts.length > 0) {
|
|
20011
|
-
request3.systemInstruction = {
|
|
20012
|
-
role: "user",
|
|
20013
|
-
parts: systemTexts.map((text) => ({ text }))
|
|
20014
|
-
};
|
|
20015
|
-
}
|
|
20016
|
-
const toolsResult = convertOpenAiToolsToGemini(args2.tools);
|
|
20017
|
-
if (toolsResult) {
|
|
20018
|
-
request3.tools = toolsResult;
|
|
20019
|
-
request3.toolConfig = { functionCallingConfig: { mode: "VALIDATED" } };
|
|
20020
|
-
}
|
|
20021
|
-
const generationConfig = {};
|
|
20022
|
-
if (typeof args2.maxTokens === "number" && args2.maxTokens > 0) {
|
|
20023
|
-
generationConfig.maxOutputTokens = args2.maxTokens;
|
|
20024
|
-
}
|
|
20025
|
-
if (typeof args2.temperature === "number") {
|
|
20026
|
-
generationConfig.temperature = args2.temperature;
|
|
20027
|
-
}
|
|
20028
|
-
if (Object.keys(generationConfig).length > 0) {
|
|
20029
|
-
request3.generationConfig = generationConfig;
|
|
20030
|
-
}
|
|
20031
|
-
return request3;
|
|
20032
|
-
}
|
|
20033
|
-
|
|
20034
|
-
// packages/agent-runtime/antigravityCloudCodeProvider.ts
|
|
20035
|
-
var STREAM_PATH = "/v1internal:streamGenerateContent?alt=sse";
|
|
20036
|
-
function buildCloudCodeAssistPayload(args2) {
|
|
20037
|
-
const projectId = readAntigravityProjectId(args2.metadata);
|
|
20038
|
-
if (!projectId) {
|
|
20039
|
-
throw new Error(
|
|
20040
|
-
"Antigravity OAuth credential is missing metadata.projectId. Re-run `nolo auth antigravity`."
|
|
20041
|
-
);
|
|
20042
|
-
}
|
|
20043
|
-
const logicalModel = asOptionalTrimmedString(args2.openAiBody.model) ?? asOptionalTrimmedString(args2.agentConfig.model) ?? "gemini-3.1-pro";
|
|
20044
|
-
const { wireModelId: model, profile } = resolveAntigravityWireModel(logicalModel);
|
|
20045
|
-
const rawMessages = Array.isArray(args2.openAiBody.messages) ? args2.openAiBody.messages : [];
|
|
20046
|
-
const quirks = resolveGeminiModelQuirks(model);
|
|
20047
|
-
const isClaude = quirks.isClaudeCrossModel;
|
|
20048
|
-
const { contents, systemTexts } = convertOpenAiMessagesToGemini(rawMessages, {
|
|
20049
|
-
attachSkipThoughtSignature: quirks.allowsThoughtSignatureSentinel
|
|
20050
|
-
});
|
|
20051
|
-
if (contents.length === 0) {
|
|
20052
|
-
throw new Error("Antigravity Cloud Code Assist request has no user/model contents.");
|
|
20053
|
-
}
|
|
20054
|
-
const prompt = args2.agentConfig.prompt?.trim();
|
|
20055
|
-
if (prompt) systemTexts.unshift(prompt);
|
|
20056
|
-
const request3 = { contents };
|
|
20057
|
-
if (systemTexts.length > 0) {
|
|
20058
|
-
request3.systemInstruction = {
|
|
20059
|
-
role: "user",
|
|
20060
|
-
parts: systemTexts.map((text) => ({ text }))
|
|
20061
|
-
};
|
|
20062
|
-
}
|
|
20063
|
-
const tools = convertOpenAiToolsToGemini(
|
|
20064
|
-
Array.isArray(args2.openAiBody.tools) ? args2.openAiBody.tools : void 0
|
|
20065
|
-
);
|
|
20066
|
-
if (tools) {
|
|
20067
|
-
request3.tools = tools;
|
|
20068
|
-
request3.toolConfig = { functionCallingConfig: { mode: "VALIDATED" } };
|
|
20069
|
-
}
|
|
20070
|
-
const generationConfig = {};
|
|
20071
|
-
if (profile?.maxOutputTokens) {
|
|
20072
|
-
generationConfig.maxOutputTokens = profile.maxOutputTokens;
|
|
20073
|
-
} else if (typeof args2.agentConfig.max_tokens === "number" && args2.agentConfig.max_tokens > 0) {
|
|
20074
|
-
generationConfig.maxOutputTokens = args2.agentConfig.max_tokens;
|
|
20075
|
-
}
|
|
20076
|
-
if (typeof args2.agentConfig.temperature === "number") {
|
|
20077
|
-
generationConfig.temperature = args2.agentConfig.temperature;
|
|
20078
|
-
}
|
|
20079
|
-
if (Object.keys(generationConfig).length > 0) {
|
|
20080
|
-
request3.generationConfig = generationConfig;
|
|
20081
|
-
}
|
|
20082
|
-
const agentId = randomUUID();
|
|
20083
|
-
const trajectoryId = randomUUID();
|
|
20084
|
-
const step = 2;
|
|
20085
|
-
const requestId = `agent/${agentId}/${Date.now()}/${trajectoryId}/${step}`;
|
|
20086
|
-
const labels = {
|
|
20087
|
-
trajectory_id: trajectoryId,
|
|
20088
|
-
last_step_index: String(step - 1),
|
|
20089
|
-
used_claude: String(isClaude),
|
|
20090
|
-
used_claude_conservative: String(isClaude)
|
|
20091
|
-
};
|
|
20092
|
-
if (profile?.modelEnum) {
|
|
20093
|
-
labels.model_enum = profile.modelEnum;
|
|
20094
|
-
}
|
|
20095
|
-
request3.labels = labels;
|
|
20096
|
-
request3.sessionId = `-${Math.floor(Math.random() * 9e15)}`;
|
|
20097
|
-
return {
|
|
20098
|
-
url: `${resolveAntigravityCloudCodeBaseUrl(args2.agentConfig.customProviderUrl)}${STREAM_PATH}`,
|
|
20099
|
-
envelope: {
|
|
20100
|
-
project: projectId,
|
|
20101
|
-
model,
|
|
20102
|
-
request: request3,
|
|
20103
|
-
requestId,
|
|
20104
|
-
requestType: "agent",
|
|
20105
|
-
userAgent: "antigravity"
|
|
20106
|
-
}
|
|
20107
|
-
};
|
|
20108
|
-
}
|
|
20109
|
-
function resolveAntigravityFinishReason(upstream) {
|
|
20110
|
-
const normalized = (upstream ?? "").trim().toUpperCase();
|
|
20111
|
-
if (normalized === "MAX_TOKENS") return "length";
|
|
20112
|
-
if (normalized === "SAFETY" || normalized === "RECITATION" || normalized === "PROHIBITED_CONTENT" || normalized === "BLOCKLIST") {
|
|
20113
|
-
return "content_filter";
|
|
20114
|
-
}
|
|
20115
|
-
return "stop";
|
|
20116
|
-
}
|
|
20117
|
-
function normalizeAntigravityCompletion(decoded) {
|
|
20118
|
-
const { text, toolCalls, usage, finishReason, reasoningContent, events } = decoded;
|
|
20119
|
-
const normalizedFinishReason = (finishReason ?? "").trim().toUpperCase();
|
|
20120
|
-
if (!text && !reasoningContent && toolCalls.length === 0 && !finishReason && !usage) {
|
|
20121
|
-
const body = {
|
|
20122
|
-
error: {
|
|
20123
|
-
message: "antigravity upstream returned an empty stream (no content, finishReason or usage); channel degradation, not model emptiness"
|
|
20124
|
-
},
|
|
20125
|
-
provider_events: events
|
|
20126
|
-
};
|
|
20127
|
-
return {
|
|
20128
|
-
status: 502,
|
|
20129
|
-
text: "",
|
|
20130
|
-
toolCalls: [],
|
|
20131
|
-
providerEvents: events,
|
|
20132
|
-
body
|
|
20133
|
-
};
|
|
20134
|
-
}
|
|
20135
|
-
if (normalizedFinishReason === "MALFORMED_FUNCTION_CALL") {
|
|
20136
|
-
const message2 = "antigravity upstream returned MALFORMED_FUNCTION_CALL (model generated an invalid function call or tool arguments were rejected by upstream)";
|
|
20137
|
-
const providerFailure = {
|
|
20138
|
-
kind: "provider_failure",
|
|
20139
|
-
provider: "antigravity",
|
|
20140
|
-
code: "MALFORMED_FUNCTION_CALL",
|
|
20141
|
-
message: message2,
|
|
20142
|
-
providerReason: "MALFORMED_FUNCTION_CALL",
|
|
20143
|
-
retryable: false,
|
|
20144
|
-
status: 502
|
|
20145
|
-
};
|
|
20146
|
-
return {
|
|
20147
|
-
status: 502,
|
|
20148
|
-
text: "",
|
|
20149
|
-
toolCalls: [],
|
|
20150
|
-
finishReason,
|
|
20151
|
-
providerEvents: events,
|
|
20152
|
-
providerFailure,
|
|
20153
|
-
runtimeProviderFailure: {
|
|
20154
|
-
message: providerFailure.message,
|
|
20155
|
-
retryable: providerFailure.retryable
|
|
20156
|
-
},
|
|
20157
|
-
body: {
|
|
20158
|
-
error: {
|
|
20159
|
-
message: message2,
|
|
20160
|
-
code: "MALFORMED_FUNCTION_CALL",
|
|
20161
|
-
category: "malformed_function_call",
|
|
20162
|
-
providerReason: "MALFORMED_FUNCTION_CALL",
|
|
20163
|
-
retryable: false
|
|
20164
|
-
},
|
|
20165
|
-
provider_failure: providerFailure,
|
|
20166
|
-
provider_events: events
|
|
20167
|
-
}
|
|
20168
|
-
};
|
|
20169
|
-
}
|
|
20170
|
-
const message = {
|
|
20171
|
-
role: "assistant",
|
|
20172
|
-
content: text || null
|
|
20173
|
-
};
|
|
20174
|
-
if (toolCalls.length > 0) message.tool_calls = toolCalls;
|
|
20175
|
-
if (reasoningContent) message.reasoning_content = reasoningContent;
|
|
20176
|
-
return {
|
|
20177
|
-
status: 200,
|
|
20178
|
-
text,
|
|
20179
|
-
...reasoningContent ? { reasoningContent } : {},
|
|
20180
|
-
toolCalls,
|
|
20181
|
-
...usage ? { usage } : {},
|
|
20182
|
-
...finishReason ? { finishReason } : {},
|
|
20183
|
-
providerEvents: events,
|
|
20184
|
-
body: {
|
|
20185
|
-
choices: [{
|
|
20186
|
-
index: 0,
|
|
20187
|
-
message,
|
|
20188
|
-
finish_reason: toolCalls.length > 0 ? "tool_calls" : resolveAntigravityFinishReason(finishReason)
|
|
20189
|
-
}],
|
|
20190
|
-
...usage ? { usage } : {},
|
|
20191
|
-
provider_events: events
|
|
20192
|
-
}
|
|
20193
|
-
};
|
|
20194
|
-
}
|
|
20195
|
-
async function fetchAntigravityCloudCodeCompletion(args2) {
|
|
20196
|
-
const fetchImpl = args2.fetchImpl ?? fetch;
|
|
20197
|
-
const { url, envelope } = buildCloudCodeAssistPayload(args2);
|
|
20198
|
-
const response = await fetchImpl(url, {
|
|
20199
|
-
method: "POST",
|
|
20200
|
-
headers: {
|
|
20201
|
-
Authorization: `Bearer ${args2.accessToken}`,
|
|
20202
|
-
"Content-Type": "application/json",
|
|
20203
|
-
"User-Agent": getAntigravityUserAgent()
|
|
20204
|
-
},
|
|
20205
|
-
body: JSON.stringify(envelope),
|
|
20206
|
-
signal: args2.signal
|
|
20207
|
-
});
|
|
20208
|
-
if (!response.ok) {
|
|
20209
|
-
const errorText = await response.text();
|
|
20210
|
-
return {
|
|
20211
|
-
status: response.status,
|
|
20212
|
-
text: "",
|
|
20213
|
-
toolCalls: [],
|
|
20214
|
-
providerEvents: [],
|
|
20215
|
-
// 保留上游结构:Antigravity 的限流 body 同样携带结构化的重置信息,
|
|
20216
|
-
// 压成字符串会让冷却退化成 5 分钟默认值。
|
|
20217
|
-
body: parseUpstreamErrorBody(errorText, response.statusText)
|
|
20218
|
-
};
|
|
20219
|
-
}
|
|
20220
|
-
const chunkStream = streamSseDataValues(response, parseSseDataLineJson);
|
|
20221
|
-
const { text, toolCalls, usage, finishReason, reasoningContent, events } = await accumulateGeminiStream(chunkStream, {
|
|
20222
|
-
onTextDelta: args2.onTextDelta,
|
|
20223
|
-
onReasoningDelta: args2.onReasoningDelta
|
|
20224
|
-
});
|
|
20225
|
-
const normalized = normalizeAntigravityCompletion({
|
|
20226
|
-
text,
|
|
20227
|
-
toolCalls,
|
|
20228
|
-
usage,
|
|
20229
|
-
finishReason,
|
|
20230
|
-
reasoningContent,
|
|
20231
|
-
events
|
|
20232
|
-
});
|
|
20233
|
-
if (normalized.status !== 200 || !text && toolCalls.length === 0) {
|
|
20234
|
-
console.warn(
|
|
20235
|
-
`[antigravity] empty completion: finishReason=${JSON.stringify(finishReason)} reasoningLen=${reasoningContent?.length ?? 0} usage=${JSON.stringify(usage) ?? "none"} model=${String(envelope.model)} base=${new URL(url).host}`
|
|
20236
|
-
);
|
|
20237
|
-
}
|
|
20238
|
-
return normalized;
|
|
20058
|
+
// packages/agent-runtime/sessionIdentity.ts
|
|
20059
|
+
import { createHash as createHash4 } from "node:crypto";
|
|
20060
|
+
var SALT = "nolo-session-identity-v1";
|
|
20061
|
+
function isStableSessionIdentityEnabled(env = process.env) {
|
|
20062
|
+
const v = env.NOLO_STABLE_SESSION_IDENTITY?.trim().toLowerCase();
|
|
20063
|
+
return !(v === "0" || v === "false" || v === "off");
|
|
20064
|
+
}
|
|
20065
|
+
function deriveStableUuid(sessionKey, purpose) {
|
|
20066
|
+
const h = createHash4("sha256").update(`${SALT}\0${purpose}\0${sessionKey}`).digest();
|
|
20067
|
+
h[6] = h[6] & 15 | 80;
|
|
20068
|
+
h[8] = h[8] & 63 | 128;
|
|
20069
|
+
const x = h.subarray(0, 16).toString("hex");
|
|
20070
|
+
return `${x.slice(0, 8)}-${x.slice(8, 12)}-${x.slice(12, 16)}-${x.slice(16, 20)}-${x.slice(20, 32)}`;
|
|
20071
|
+
}
|
|
20072
|
+
function resolveSessionKey(args2) {
|
|
20073
|
+
const d = args2.dialogId?.trim();
|
|
20074
|
+
return d ? `dialog:${d}` : void 0;
|
|
20239
20075
|
}
|
|
20240
20076
|
|
|
20241
20077
|
// packages/agent-runtime/devin/devinProvider.ts
|
|
20242
|
-
import { randomBytes, randomUUID
|
|
20078
|
+
import { randomBytes, randomUUID } from "node:crypto";
|
|
20243
20079
|
var CLIENT_NAME = "chisel";
|
|
20244
|
-
var CLIENT_VERSION = "
|
|
20080
|
+
var CLIENT_VERSION = "3000.11.3";
|
|
20245
20081
|
function writeVarint(fieldNum, value) {
|
|
20246
20082
|
const tag = fieldNum << 3 | 0;
|
|
20247
20083
|
const bytes = [];
|
|
@@ -20298,10 +20134,13 @@ function encodeDevinClientMetadata(token) {
|
|
|
20298
20134
|
writeStringField(31, generateFingerprint())
|
|
20299
20135
|
]);
|
|
20300
20136
|
}
|
|
20301
|
-
function
|
|
20137
|
+
function devinId(id, purpose) {
|
|
20138
|
+
return id?.sessionKey && isStableSessionIdentityEnabled() ? deriveStableUuid(id.sessionKey, purpose) : randomUUID();
|
|
20139
|
+
}
|
|
20140
|
+
function encodeDevinChatMessage(msg, identity2, index = 0) {
|
|
20302
20141
|
const source = msg.role === "assistant" ? 2 : msg.role === "tool" ? 4 : 1;
|
|
20303
20142
|
return Buffer.concat([
|
|
20304
|
-
writeStringField(1,
|
|
20143
|
+
writeStringField(1, devinId(identity2, `msg:${index}:${msg.role}`)),
|
|
20305
20144
|
writeVarint(2, source),
|
|
20306
20145
|
writeStringField(3, msg.text),
|
|
20307
20146
|
...(msg.toolCalls ?? []).map(
|
|
@@ -20357,6 +20196,7 @@ function buildCompletionConfig(params) {
|
|
|
20357
20196
|
}
|
|
20358
20197
|
function buildGetChatMessageRequest(params) {
|
|
20359
20198
|
const { token, messages, model, tools = [], temperature } = params;
|
|
20199
|
+
const identity2 = { sessionKey: params.sessionKey };
|
|
20360
20200
|
const metadata = encodeDevinClientMetadata(token);
|
|
20361
20201
|
let systemPrompt = "";
|
|
20362
20202
|
const filteredMessages = [];
|
|
@@ -20386,10 +20226,10 @@ ${item.text}`;
|
|
|
20386
20226
|
coalesced.push({ ...item });
|
|
20387
20227
|
}
|
|
20388
20228
|
}
|
|
20389
|
-
const chatMessageBuffers = coalesced.map((m) => encodeDevinChatMessage(m));
|
|
20229
|
+
const chatMessageBuffers = coalesced.map((m, i) => encodeDevinChatMessage(m, identity2, i));
|
|
20390
20230
|
const completionConfig = buildCompletionConfig({ temperature });
|
|
20391
20231
|
const modelConfig = Buffer.concat([
|
|
20392
|
-
writeStringField(1,
|
|
20232
|
+
writeStringField(1, randomUUID()),
|
|
20393
20233
|
writeVarint(2, 1),
|
|
20394
20234
|
writeVarint(3, 4)
|
|
20395
20235
|
]);
|
|
@@ -20401,7 +20241,7 @@ ${item.text}`;
|
|
|
20401
20241
|
writeMessageField(8, completionConfig),
|
|
20402
20242
|
...tools.map((tool) => writeMessageField(10, encodeDevinToolDefinition(tool))),
|
|
20403
20243
|
writeMessageField(15, modelConfig),
|
|
20404
|
-
writeStringField(16,
|
|
20244
|
+
writeStringField(16, randomUUID()),
|
|
20405
20245
|
writeVarint(20, 1),
|
|
20406
20246
|
writeStringField(21, model)
|
|
20407
20247
|
]);
|
|
@@ -20616,6 +20456,11 @@ function decodeDevinResponsePayload(payload) {
|
|
|
20616
20456
|
}
|
|
20617
20457
|
return { content, reasoning, finishReason, events, usage };
|
|
20618
20458
|
}
|
|
20459
|
+
function isMeaningfulDevinEvent(event) {
|
|
20460
|
+
if (event.type === "reasoning" || event.type === "content") return event.text.length > 0;
|
|
20461
|
+
if (event.type === "tool-call-start") return !!event.name;
|
|
20462
|
+
return event.argsDelta.length > 0;
|
|
20463
|
+
}
|
|
20619
20464
|
function createDevinProvider(options) {
|
|
20620
20465
|
const { token, model = "swe-2-max", fetchImpl = fetch, tools = [], temperature } = options;
|
|
20621
20466
|
return {
|
|
@@ -20627,9 +20472,11 @@ function createDevinProvider(options) {
|
|
|
20627
20472
|
messages,
|
|
20628
20473
|
model: selectedModel,
|
|
20629
20474
|
tools,
|
|
20630
|
-
temperature
|
|
20475
|
+
temperature,
|
|
20476
|
+
sessionKey: resolveSessionKey({ dialogId: opts?.dialogId })
|
|
20631
20477
|
});
|
|
20632
20478
|
const frame = buildDevinConnectFrame(requestPayload);
|
|
20479
|
+
const timingTracker = createProviderCallTimingTracker();
|
|
20633
20480
|
const response = await fetchImpl(DEVIN_CONNECT_URL, {
|
|
20634
20481
|
method: "POST",
|
|
20635
20482
|
headers: {
|
|
@@ -20687,6 +20534,7 @@ function createDevinProvider(options) {
|
|
|
20687
20534
|
reasoning += delta.reasoning;
|
|
20688
20535
|
if (delta.finishReason) finishReason = delta.finishReason;
|
|
20689
20536
|
for (const event of delta.events) {
|
|
20537
|
+
if (isMeaningfulDevinEvent(event)) observeMeaningfulProviderResponse(timingTracker);
|
|
20690
20538
|
if (event.type === "reasoning") {
|
|
20691
20539
|
opts?.onReasoningDelta?.(event.text);
|
|
20692
20540
|
} else if (event.type === "content") {
|
|
@@ -20735,13 +20583,14 @@ function createDevinProvider(options) {
|
|
|
20735
20583
|
if (!text && !reasoning && toolCalls.length === 0) {
|
|
20736
20584
|
throw new Error("Devin Connect upstream completed without content or tool calls");
|
|
20737
20585
|
}
|
|
20738
|
-
const
|
|
20586
|
+
const timing = finalizeProviderCallTiming(timingTracker);
|
|
20587
|
+
const usage = frameUsage ? withProviderCallTimingFields({
|
|
20739
20588
|
prompt_tokens: frameUsage.prompt + frameUsage.cacheRead,
|
|
20740
20589
|
completion_tokens: frameUsage.completion ?? 0,
|
|
20741
20590
|
total_tokens: frameUsage.prompt + frameUsage.cacheRead + (frameUsage.completion ?? 0) + frameUsage.cacheWrite,
|
|
20742
20591
|
...frameUsage.cacheRead > 0 ? { prompt_tokens_details: { cached_tokens: frameUsage.cacheRead } } : {},
|
|
20743
20592
|
...frameUsage.cacheWrite > 0 ? { cache_creation_input_tokens: frameUsage.cacheWrite } : {}
|
|
20744
|
-
} : void 0;
|
|
20593
|
+
}, timing) : void 0;
|
|
20745
20594
|
return {
|
|
20746
20595
|
content: text,
|
|
20747
20596
|
model: selectedModel,
|
|
@@ -20763,20 +20612,16 @@ function createDevinProvider(options) {
|
|
|
20763
20612
|
}
|
|
20764
20613
|
|
|
20765
20614
|
export {
|
|
20615
|
+
readCommandActionGatePayload,
|
|
20616
|
+
readActionGate,
|
|
20766
20617
|
Option_exports,
|
|
20767
20618
|
Duration_exports,
|
|
20768
20619
|
Exit_exports,
|
|
20769
20620
|
Effect_exports,
|
|
20770
|
-
readCommandActionGatePayload,
|
|
20771
|
-
readActionGate,
|
|
20772
|
-
evaluateFileWritePolicy,
|
|
20773
|
-
summarizeToolArguments,
|
|
20774
20621
|
formatToolOverflowMarker,
|
|
20775
20622
|
LOCAL_AGENT_CONFIG_MISSING_CODE,
|
|
20776
20623
|
LOCAL_TURN_ABORTED_CODE,
|
|
20777
20624
|
runLocalAgentTurn,
|
|
20778
|
-
parseSseDataLineJson,
|
|
20779
|
-
parseSseDataLineObject,
|
|
20780
20625
|
codexStreamFailureStatus,
|
|
20781
20626
|
aggregateResponsesStream,
|
|
20782
20627
|
buildOpenAiCompatibleChatCompletionRequest,
|
|
@@ -20792,8 +20637,6 @@ export {
|
|
|
20792
20637
|
createHybridRecordStore,
|
|
20793
20638
|
isDestructiveShellCommand,
|
|
20794
20639
|
evaluateShellCommandPolicy,
|
|
20795
|
-
resolveLocalToolPolicy,
|
|
20796
|
-
executeLocalToolWithPolicy,
|
|
20797
20640
|
filterRetainedLedgerRecords,
|
|
20798
20641
|
isLineRangeCovered,
|
|
20799
20642
|
getProcessRegistry,
|
|
@@ -20804,17 +20647,17 @@ export {
|
|
|
20804
20647
|
internalSearchWorkspace,
|
|
20805
20648
|
internalListWorkspaceEntries,
|
|
20806
20649
|
createLocalWorkspaceToolExecutors,
|
|
20650
|
+
buildToolParametersIndex,
|
|
20651
|
+
getAgentRuntimeToolParametersIndex,
|
|
20652
|
+
resolveLocalToolPolicy,
|
|
20653
|
+
executeLocalToolWithPolicy,
|
|
20807
20654
|
localDialogMessageRecordToRuntimeMessage,
|
|
20808
20655
|
buildLocalDialogWritePlan,
|
|
20809
20656
|
buildNoloWorkspaceCliToolExecutors,
|
|
20810
20657
|
buildLoadSkillExecutor,
|
|
20811
|
-
|
|
20812
|
-
|
|
20813
|
-
|
|
20814
|
-
shouldUseGeminiNativeToolRoute,
|
|
20815
|
-
buildGeminiGenerateContentRequest,
|
|
20816
|
-
resolveAntigravityFinishReason,
|
|
20817
|
-
fetchAntigravityCloudCodeCompletion,
|
|
20658
|
+
isStableSessionIdentityEnabled,
|
|
20659
|
+
deriveStableUuid,
|
|
20660
|
+
resolveSessionKey,
|
|
20818
20661
|
readDevinUpstreamFailure,
|
|
20819
20662
|
createDevinProvider
|
|
20820
20663
|
};
|