nolo-cli 0.82.0-alpha.6 → 0.82.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 +2 -2
- package/{_executeModel-225YRU52.js → _executeModel-MA3D2J4W.js} +48 -48
- package/{action-D22U6CTH.js → action-YVYQEAAV.js} +11 -11
- package/{addContentAction-XAPUTGL4.js → addContentAction-O7R66HEX.js} +9 -9
- package/{addDialogAgentAction-M7VLLBZM.js → addDialogAgentAction-74OA7KYP.js} +8 -8
- package/{agentDeleteCommand-ZJNQGVR2.js → agentDeleteCommand-FHUJH5X4.js} +31 -29
- package/{agentEmailCommands-VLVWFWX2.js → agentEmailCommands-KNYBWNMA.js} +67 -63
- package/{agentGrantCommands-R3VQEZJR.js → agentGrantCommands-M3XFO6EN.js} +2 -2
- package/{agentListCommands-GHQGLAUU.js → agentListCommands-GATRXEMT.js} +40 -32
- package/{agentMachineCommands-QDXYENZJ.js → agentMachineCommands-N62I3D5Q.js} +31 -29
- package/{agentProviderCommands-65ZC2WB4.js → agentProviderCommands-GNPTL5XR.js} +87 -0
- package/{agentPullCommand-N7L2CT7L.js → agentPullCommand-O5MPVJ5E.js} +3 -3
- package/agentRecordCommands-GOC5K27T.js +128 -0
- package/{agentRunCommand-YSCD65HH.js → agentRunCommand-JP2U3MQF.js} +65 -61
- package/{agentRunControl-T44MESII.js → agentRunControl-AVJR4JW4.js} +2 -2
- package/{agentRuntimeLocal-ZOHB7OOO.js → agentRuntimeLocal-VXZSDIGT.js} +27 -25
- package/{agentSlice-O2SBU5TK.js → agentSlice-65ETD734.js} +10 -10
- package/{appDeleteCommands-PRT6K5N2.js → appDeleteCommands-PDZ7HQYH.js} +31 -29
- package/{appDeployCommands-63ZONFAN.js → appDeployCommands-KLLW32YA.js} +31 -29
- package/{appDeployStatusCommands-AFAYCVR3.js → appDeployStatusCommands-IPNJ445T.js} +31 -29
- package/{appGetCommands-TNZDZE36.js → appGetCommands-QA57XGXS.js} +31 -29
- package/{appListCommands-IA4SPG2X.js → appListCommands-YBTAUFZS.js} +31 -29
- package/{authCommand-EVGFLAHO.js → authCommand-F4EFRRX6.js} +164 -24
- package/{authCommands-ILTBI6JV.js → authCommands-RGOGCPP6.js} +4 -5
- package/builtinSkillRegistry-FUAVTRVZ.js +33 -0
- package/{chatQueueReduxAdapter-4SM3DAWX.js → chatQueueReduxAdapter-5QOW43T4.js} +24 -24
- package/{chromeCommands-VOIRNJBL.js → chromeCommands-FZYAU75D.js} +1 -1
- package/{chromeOpsCommands-M7DPCX2T.js → chromeOpsCommands-62P2Q2YB.js} +31 -1
- package/{chunk-C3FZR5EC.js → chunk-2F7RJC6L.js} +1 -1
- package/{chunk-A3NNC2LA.js → chunk-2FA3ITSX.js} +1235 -59
- package/{chunk-HQUORJTM.js → chunk-3BMYXEUW.js} +1 -1
- package/{chunk-3QPYFHAH.js → chunk-3DII57IT.js} +1 -1
- package/{chunk-NTW5GWDM.js → chunk-3VNWWVKB.js} +2 -0
- package/{chunk-DWUCB2A3.js → chunk-42V6BK2E.js} +1 -1
- package/{chunk-DSRXPQWA.js → chunk-4OEFYTWL.js} +43 -43
- package/{chunk-GBPZKFYK.js → chunk-53HEEOTT.js} +4 -4
- package/{chunk-KIS76A2P.js → chunk-5H7KJX7J.js} +38 -4
- package/{chunk-5XTOKQLW.js → chunk-5UTFL4QJ.js} +6 -2
- package/chunk-5ZUL4CUO.js +10 -0
- package/{chunk-E6RGHPDR.js → chunk-6D6VBVEW.js} +4 -6
- package/{chunk-CMH2SYHX.js → chunk-6OZ36FXI.js} +2 -2
- package/{chunk-HHLTFENG.js → chunk-6VFARHZW.js} +907 -317
- package/{chunk-NRALD3CC.js → chunk-76WEAXJB.js} +49 -10
- package/{chunk-BYEJ7K2Z.js → chunk-7S4YWN7P.js} +1 -1
- package/{chunk-SREASRV5.js → chunk-ABQYVJBJ.js} +1 -1
- package/chunk-ACTMNVHM.js +93 -0
- package/{chunk-3W2JJOH3.js → chunk-AD2L6YCC.js} +3 -3
- package/{chunk-XWNRAIUL.js → chunk-AFUORTY4.js} +6 -16
- package/{chunk-WL2RKIBF.js → chunk-BLJWCTRL.js} +1 -1
- package/chunk-BNGW5ASC.js +344 -0
- package/{chunk-SZLVDREM.js → chunk-BP4XNZRM.js} +3 -3
- package/{chunk-2KDR4CWE.js → chunk-BYMV6QZG.js} +24 -1
- package/{chunk-5LSS6MFZ.js → chunk-D2QT5FW4.js} +13 -15
- package/{chunk-MYU3MJCF.js → chunk-DHDMC6FO.js} +175 -7
- package/{chunk-SO7B7NW3.js → chunk-DHDVZFNC.js} +413 -62
- package/{chunk-E36HZARC.js → chunk-DNCEALKX.js} +93 -17
- package/{chunk-EXMHJN7C.js → chunk-EYAQT56M.js} +4 -3
- package/{chunk-CJCJF5XB.js → chunk-FDTR4QJ6.js} +4 -2
- package/{chunk-YSKEOTPH.js → chunk-FSX24MR3.js} +155 -795
- package/{chunk-NJ6WLAPS.js → chunk-FUUHG5LT.js} +1 -1
- package/{chunk-EM6MPSEI.js → chunk-GABFWSOQ.js} +52 -30
- package/{chunk-PYXL2CJL.js → chunk-GPCZ7UXG.js} +1 -1
- package/{chunk-K7AG465Q.js → chunk-GQBOR3G6.js} +4 -2
- package/{chunk-FP27MNSX.js → chunk-GZBATRJA.js} +3 -3
- package/{chunk-YFADVSZE.js → chunk-H62HCIUP.js} +6 -6
- package/{chunk-PZM3EENV.js → chunk-HJUYAD4A.js} +1 -1
- package/{chunk-3JQ2NRYU.js → chunk-HVURBGF3.js} +4 -4
- package/{chunk-HH65VA5U.js → chunk-I3TQJXQ7.js} +109 -6
- package/{chunk-ZVN6I33J.js → chunk-IIVGDG4I.js} +6 -5
- package/{chunk-UDQWGU7F.js → chunk-J4MOO56S.js} +1 -1
- package/{chunk-KC5FAHVS.js → chunk-JEDZAO7L.js} +1 -1
- package/{chunk-6XIE5ZGI.js → chunk-JPGCXHNM.js} +1 -1
- package/chunk-JRQFUXY7.js +1625 -0
- package/chunk-KQ4ONNQD.js +677 -0
- package/{chunk-CPSZJBLK.js → chunk-L5UXH3B2.js} +105 -26
- package/{chunk-RXX4GDIH.js → chunk-LS2ZANRJ.js} +1 -1
- package/{chunk-BJIRLHJR.js → chunk-M2EJHDJP.js} +4 -0
- package/{chunk-EVBFYPDC.js → chunk-MC4XLIJ7.js} +6 -2
- package/{chunk-6SD5OPQ4.js → chunk-N2WELJE7.js} +11 -173
- package/{chunk-UJ63UXGE.js → chunk-OIVSQH2O.js} +1006 -801
- package/{chunk-4UW2LDVA.js → chunk-PELKTR62.js} +15 -15
- package/{chunk-AETZ7AD6.js → chunk-Q554LLSI.js} +1 -1
- package/chunk-Q5FJJ6XI.js +103 -0
- package/{chunk-AJHEFRGJ.js → chunk-Q67DOFOO.js} +214 -5
- package/{chunk-UZ6XXCVR.js → chunk-QDSINZM3.js} +15 -2
- package/{chunk-D6XYLSOS.js → chunk-QIAVMDHY.js} +1 -1
- package/{chunk-YWG6EMH3.js → chunk-RG6JBBX5.js} +10 -6
- package/{chunk-QCZX4FTW.js → chunk-SH43IESU.js} +173 -15
- package/{chunk-FNGAF7C4.js → chunk-SNPMM7H3.js} +137 -12
- package/{chunk-SPAQ4PVV.js → chunk-SV5IJK6K.js} +1 -1
- package/{chunk-KVDUCO4Q.js → chunk-TDRTS7QW.js} +16 -12
- package/{chunk-BJCWNHVU.js → chunk-TOP2VXOR.js} +2 -2
- package/{chunk-Q46HQOW3.js → chunk-TVYSVSA2.js} +7 -7
- package/{chunk-4EJ5QYB5.js → chunk-UKZDAFYT.js} +1 -1
- package/{chunk-YXLXHIT2.js → chunk-UY2NBS4V.js} +6 -6
- package/{chunk-PGSKWZCB.js → chunk-UZGQNTVW.js} +1 -1
- package/{chunk-73IOJLK2.js → chunk-V4I3A7DR.js} +10 -10
- package/{chunk-ZZCJUXUI.js → chunk-V4MJDUSR.js} +2 -2
- package/{chunk-JYYZCK2Z.js → chunk-V7E4PXQD.js} +1 -1
- package/{chunk-OZX2IPKM.js → chunk-VLTIYV3X.js} +1 -1
- package/{chunk-NHRQCXIQ.js → chunk-VMFTFOWF.js} +13 -3
- package/{chunk-5J7W2VWW.js → chunk-WV42OMV7.js} +6 -265
- package/{chunk-DUJWWUGV.js → chunk-YQTQQX2H.js} +1 -1
- package/{chunk-BOYUESO7.js → chunk-Z77CRGTW.js} +1 -1
- package/{chunk-QC5LGHYP.js → chunk-ZCYXJSTU.js} +10 -5
- package/{chunk-LSZXYE64.js → chunk-ZMD2CQFC.js} +759 -80
- package/{contentThunks-ENAVF2YU.js → contentThunks-Y6FA2TCW.js} +25 -25
- package/{cooldownCommands-BSCH2W7P.js → cooldownCommands-REAWYVTY.js} +2 -2
- package/{createAgentAutomationAction-CH6BYC7K.js → createAgentAutomationAction-JXAFQO5V.js} +25 -25
- package/{createDialogAction-23UDOXSO.js → createDialogAction-O2QABXZF.js} +28 -28
- package/{createPageAction-J6AEMLHK.js → createPageAction-GUQDPKO5.js} +26 -26
- package/{dbSlice-GKGGFNOB.js → dbSlice-XVWBAGYN.js} +8 -8
- package/{deleteFile-LWSR674W.js → deleteFile-YG6QMJLU.js} +3 -3
- package/{dialogCommands-BJJGCCQR.js → dialogCommands-JJDASFIL.js} +35 -31
- package/{dialogSlice-F7RD6PUY.js → dialogSlice-J2YJNE6E.js} +24 -24
- package/{docCreateCommands-53GB2FU3.js → docCreateCommands-OB3X3EQM.js} +32 -30
- package/{docDeleteCommands-TAW5JEBU.js → docDeleteCommands-WMHRGF22.js} +33 -31
- package/{docReadCommands-F5N7N5E3.js → docReadCommands-NWGGLIAZ.js} +32 -30
- package/{docStore-WX4YBGXC.js → docStore-6KKYKAGQ.js} +9 -9
- package/{docUpdateCommands-YQ7TRT35.js → docUpdateCommands-3DDSOLPS.js} +32 -30
- package/{fetchMessages-DRABNDPZ.js → fetchMessages-EIU7UFFK.js} +3 -4
- package/{getPricing-HRMSOF3E.js → getPricing-LUSEABA6.js} +4 -4
- package/{handleSendMessageAction-CW4LULIR.js → handleSendMessageAction-A4XLEEPU.js} +24 -24
- package/index.js +102 -85
- package/{localDialogRead-PUQKFI73.js → localDialogRead-BTFJ4V2I.js} +2 -2
- package/{localRuntimeDb-P37ZTX55.js → localRuntimeDb-SYQGUF4U.js} +1 -1
- package/{machineCommands-FIYWY5EU.js → machineCommands-Y64KAIRW.js} +64 -60
- package/{machineWsRunDispatch-KQ4OFFNR.js → machineWsRunDispatch-M366L2LJ.js} +62 -58
- package/{memberThunks-KATHH3F4.js → memberThunks-QGFLFVCI.js} +9 -9
- package/{models-GS72DVJS.js → models-T3SG6MJ5.js} +2 -2
- package/{offlineMarxistsAgentCommand-GEH6SNNA.js → offlineMarxistsAgentCommand-HGXZV4XJ.js} +1 -1
- package/package.json +1 -1
- package/providerPresetApply-FG6NZ57W.js +214 -0
- package/providerRegistry-757OWH3O.js +31 -0
- package/{read-LC6HVYBN.js → read-COE3ZYR6.js} +5 -4
- package/{readDocTool-N3ERJHHF.js → readDocTool-5USN4A6V.js} +1 -1
- package/{readlineWorkspace-QYI6BRNA.js → readlineWorkspace-45XNHFXU.js} +144 -108
- package/{removeDialogAgentAction-F5GPTALR.js → removeDialogAgentAction-IX3MN2ZO.js} +11 -11
- package/{runAgentClientLoop-GZ5VUGAW.js → runAgentClientLoop-ADZRHNG6.js} +47 -47
- package/{runtimeDoctorCommands-CROTMULY.js → runtimeDoctorCommands-X6WDBEQX.js} +2 -2
- package/{setDialogExtraReferencesAction-AY4ZCF3A.js → setDialogExtraReferencesAction-X4HCPNZL.js} +9 -9
- package/{setPrimaryDialogAgentAction-HPMG7V3R.js → setPrimaryDialogAgentAction-4GMIQLOD.js} +11 -11
- package/{settingSlice-OEJA4NQO.js → settingSlice-ZQZVUPKK.js} +10 -10
- package/{spaceCommands-IYMIXCMC.js → spaceCommands-E7MQ4VU2.js} +30 -28
- package/{streamAgentChatTurn-EAXIUJTK.js → streamAgentChatTurn-TUP7YO3H.js} +59 -58
- package/{switchDialogAgentAction-HMDZTZ4I.js → switchDialogAgentAction-N52LRPA3.js} +8 -8
- package/{tableCommands-SUNTHAYX.js → tableCommands-O6NWHFKV.js} +1 -1
- package/{toolApiClient-VGYUB4P5.js → toolApiClient-QVJ6HDNN.js} +2 -2
- package/{tools-QWQOW6J4.js → tools-2VDNDFET.js} +43 -43
- package/tuiSummaryLlmCaller-WFRWERGK.js +127 -0
- package/{updateCommands-Y363MC3L.js → updateCommands-2M74UL7P.js} +2 -2
- package/{updateDialogTitleAction-2HCE2M7S.js → updateDialogTitleAction-KSWXWWFT.js} +45 -28
- package/agentRecordCommands-AQFYM5HS.js +0 -124
- package/chunk-3IT2PFHL.js +0 -611
- package/chunk-I42VC5KR.js +0 -15
- package/chunk-NG4UT4K4.js +0 -79
- package/codingSkills-E6KSDNSJ.js +0 -48
- package/tuiSummaryLlmCaller-3Z24VUWM.js +0 -116
- package/{chunk-3RAG2NAD.js → chunk-UKWGR5SS.js} +3 -3
- package/{db-VQSAOWAO.js → db-WK5MDZVN.js} +1 -1
- package/{localRuntimeAuthority-R5UBODT3.js → localRuntimeAuthority-6IR6BBXE.js} +3 -3
|
@@ -8,15 +8,19 @@ import {
|
|
|
8
8
|
readSseFrames,
|
|
9
9
|
streamSseDataValues,
|
|
10
10
|
throwIfChatCompletionStreamFailed
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-ZCYXJSTU.js";
|
|
12
|
+
import {
|
|
13
|
+
DEVIN_CONNECT_URL
|
|
14
|
+
} from "./chunk-Q5FJJ6XI.js";
|
|
12
15
|
import {
|
|
13
16
|
clipToolText,
|
|
14
17
|
hasImageInRuntimeMessages,
|
|
18
|
+
resolveAgentContextWindow,
|
|
15
19
|
resolveAgentImageInputSupport,
|
|
16
20
|
resolveHistoricalToolContentCap,
|
|
17
21
|
resolveToolOutputProfile,
|
|
18
22
|
stripImagePartsFromMessages
|
|
19
|
-
} from "./chunk-
|
|
23
|
+
} from "./chunk-5H7KJX7J.js";
|
|
20
24
|
import {
|
|
21
25
|
downgradeUnparsableToolCalls,
|
|
22
26
|
hasParsableObjectArguments,
|
|
@@ -34,13 +38,15 @@ import {
|
|
|
34
38
|
TOOL_GUIDED_SECTION_ORDER,
|
|
35
39
|
buildIdentityBlock,
|
|
36
40
|
buildRuntimeGuidanceBlocks,
|
|
41
|
+
detectDispatchIntent,
|
|
42
|
+
detectDispatchIntentFromMessages,
|
|
37
43
|
estimateContextTokens,
|
|
38
44
|
hashStablePrefixContent,
|
|
39
45
|
normalizeChatCompletionsBodyForProvider,
|
|
40
46
|
requiresBareImageUrl,
|
|
41
47
|
resolveToolGuidedSections,
|
|
42
48
|
toBareImageUrlMessages
|
|
43
|
-
} from "./chunk-
|
|
49
|
+
} from "./chunk-L5UXH3B2.js";
|
|
44
50
|
import {
|
|
45
51
|
convertMessagesToResponsesInput,
|
|
46
52
|
extractReasoningFromResponseOutput,
|
|
@@ -64,16 +70,16 @@ import {
|
|
|
64
70
|
parseNoloWorkspaceToolArguments,
|
|
65
71
|
readTextStreamUpToChars,
|
|
66
72
|
resolveNoloDialogInput
|
|
67
|
-
} from "./chunk-
|
|
73
|
+
} from "./chunk-IIVGDG4I.js";
|
|
68
74
|
import {
|
|
69
75
|
getAntigravityUserAgent,
|
|
70
76
|
readAntigravityProjectId,
|
|
71
77
|
resolveAntigravityCloudCodeBaseUrl
|
|
72
|
-
} from "./chunk-
|
|
78
|
+
} from "./chunk-UZGQNTVW.js";
|
|
73
79
|
import {
|
|
74
80
|
buildProviderAuthHeaders,
|
|
75
81
|
buildProviderExecutionPlan
|
|
76
|
-
} from "./chunk-
|
|
82
|
+
} from "./chunk-6OZ36FXI.js";
|
|
77
83
|
import {
|
|
78
84
|
buildDialogFallbackTitleFromUserInput
|
|
79
85
|
} from "./chunk-2MBTWINN.js";
|
|
@@ -87,7 +93,7 @@ import {
|
|
|
87
93
|
resolveEmptyAssistantFallbackMessage,
|
|
88
94
|
resolveEmptyAssistantOutcome,
|
|
89
95
|
resolveTruncatedReasoningTailLog
|
|
90
|
-
} from "./chunk-
|
|
96
|
+
} from "./chunk-4OEFYTWL.js";
|
|
91
97
|
import {
|
|
92
98
|
COMPACTION_SUMMARY_SCHEMA_VERSION,
|
|
93
99
|
COMPACTION_SUMMARY_SYSTEM_PROMPT,
|
|
@@ -106,7 +112,7 @@ import {
|
|
|
106
112
|
resolveCompressionTriggerRatio,
|
|
107
113
|
truncateToolOutputForContext,
|
|
108
114
|
withProviderCallTimingFields
|
|
109
|
-
} from "./chunk-
|
|
115
|
+
} from "./chunk-DNCEALKX.js";
|
|
110
116
|
import {
|
|
111
117
|
estimateTokenCount
|
|
112
118
|
} from "./chunk-PSCNXBYA.js";
|
|
@@ -130,27 +136,25 @@ import {
|
|
|
130
136
|
asRecordOrEmpty
|
|
131
137
|
} from "./chunk-KX6YBIHG.js";
|
|
132
138
|
import {
|
|
139
|
+
asTrimmedNonEmptyStringArray,
|
|
133
140
|
dialogMessageKey,
|
|
134
141
|
dialogMessageRange
|
|
135
|
-
} from "./chunk-
|
|
142
|
+
} from "./chunk-VMFTFOWF.js";
|
|
136
143
|
import {
|
|
137
144
|
asOptionalFiniteNumber
|
|
138
145
|
} from "./chunk-WWC7I6TA.js";
|
|
139
|
-
import {
|
|
140
|
-
asTrimmedNonEmptyStringArray
|
|
141
|
-
} from "./chunk-I42VC5KR.js";
|
|
142
146
|
import {
|
|
143
147
|
asTrimmedLowercaseString
|
|
144
148
|
} from "./chunk-QSJ3HFEF.js";
|
|
149
|
+
import {
|
|
150
|
+
isRecord
|
|
151
|
+
} from "./chunk-KUG52IAP.js";
|
|
145
152
|
import {
|
|
146
153
|
asTrimmedString
|
|
147
154
|
} from "./chunk-3EUW3WEO.js";
|
|
148
155
|
import {
|
|
149
156
|
asOptionalPositiveFiniteNumber
|
|
150
157
|
} from "./chunk-U6VC4MU4.js";
|
|
151
|
-
import {
|
|
152
|
-
isRecord
|
|
153
|
-
} from "./chunk-KUG52IAP.js";
|
|
154
158
|
import {
|
|
155
159
|
normalizeServerOrigin
|
|
156
160
|
} from "./chunk-CF7PE763.js";
|
|
@@ -12200,8 +12204,208 @@ function summarizeToolArguments(toolName, rawArgs) {
|
|
|
12200
12204
|
);
|
|
12201
12205
|
}
|
|
12202
12206
|
|
|
12207
|
+
// packages/agent-runtime/progressGuard.ts
|
|
12208
|
+
var DEFAULT_MAX_CONSECUTIVE_IDENTICAL_ROUNDS = 5;
|
|
12209
|
+
var DEFAULT_MAX_CONSECUTIVE_STAGNANT_TOOL_ROUNDS = 8;
|
|
12210
|
+
function sortJsonKeys(obj) {
|
|
12211
|
+
if (obj === null || typeof obj !== "object") return obj;
|
|
12212
|
+
if (Array.isArray(obj)) return obj.map(sortJsonKeys);
|
|
12213
|
+
const sorted = {};
|
|
12214
|
+
for (const key of Object.keys(obj).sort()) {
|
|
12215
|
+
sorted[key] = sortJsonKeys(obj[key]);
|
|
12216
|
+
}
|
|
12217
|
+
return sorted;
|
|
12218
|
+
}
|
|
12219
|
+
function normalizeToolArguments(rawArgs) {
|
|
12220
|
+
if (typeof rawArgs !== "string") {
|
|
12221
|
+
try {
|
|
12222
|
+
return JSON.stringify(sortJsonKeys(rawArgs ?? ""));
|
|
12223
|
+
} catch {
|
|
12224
|
+
return String(rawArgs ?? "");
|
|
12225
|
+
}
|
|
12226
|
+
}
|
|
12227
|
+
const trimmed = rawArgs.trim();
|
|
12228
|
+
if (!trimmed) return "";
|
|
12229
|
+
try {
|
|
12230
|
+
const parsed = JSON.parse(trimmed);
|
|
12231
|
+
return JSON.stringify(sortJsonKeys(parsed));
|
|
12232
|
+
} catch {
|
|
12233
|
+
return trimmed;
|
|
12234
|
+
}
|
|
12235
|
+
}
|
|
12236
|
+
function extractNormalizedContentText(content) {
|
|
12237
|
+
if (typeof content === "string") return content.trim();
|
|
12238
|
+
if (!Array.isArray(content)) return "";
|
|
12239
|
+
return content.map((part) => {
|
|
12240
|
+
if (part?.type === "text") return String(part.text ?? "").trim();
|
|
12241
|
+
if (part?.type === "image_url") return `[img:${part.image_url?.url ?? ""}]`;
|
|
12242
|
+
return "";
|
|
12243
|
+
}).filter(Boolean).join("\n");
|
|
12244
|
+
}
|
|
12245
|
+
function buildToolCallsSignature(toolCalls) {
|
|
12246
|
+
if (!toolCalls || toolCalls.length === 0) return "";
|
|
12247
|
+
return toolCalls.map(
|
|
12248
|
+
(tc) => `${tc.function?.name ?? ""}:${normalizeToolArguments(tc.function?.arguments)}`
|
|
12249
|
+
).join(";;");
|
|
12250
|
+
}
|
|
12251
|
+
function buildAssistantActionFingerprint(result4) {
|
|
12252
|
+
const content = extractNormalizedContentText(result4.content);
|
|
12253
|
+
const reasoning = typeof result4.reasoning_content === "string" ? result4.reasoning_content.trim() : "";
|
|
12254
|
+
let toolCallsSig = buildToolCallsSignature(result4.tool_calls);
|
|
12255
|
+
let hasToolCalls = Array.isArray(result4.tool_calls) && result4.tool_calls.length > 0;
|
|
12256
|
+
if (!toolCallsSig && Array.isArray(result4.output) && result4.output.length > 0) {
|
|
12257
|
+
const blocksToolCalls = result4.output.filter(
|
|
12258
|
+
(b) => b.type === "toolCall"
|
|
12259
|
+
).map((b) => b.toolCall);
|
|
12260
|
+
if (blocksToolCalls.length > 0) {
|
|
12261
|
+
toolCallsSig = buildToolCallsSignature(blocksToolCalls);
|
|
12262
|
+
hasToolCalls = true;
|
|
12263
|
+
}
|
|
12264
|
+
}
|
|
12265
|
+
const hasNonEmptyText = content.length > 0 || reasoning.length > 0;
|
|
12266
|
+
const fingerprint = `${content}##${reasoning}##${toolCallsSig}`;
|
|
12267
|
+
return {
|
|
12268
|
+
fingerprint,
|
|
12269
|
+
hasNonEmptyText,
|
|
12270
|
+
hasToolCalls,
|
|
12271
|
+
toolCallsSignature: toolCallsSig
|
|
12272
|
+
};
|
|
12273
|
+
}
|
|
12274
|
+
function buildToolResultsSignature(toolExecutions) {
|
|
12275
|
+
if (toolExecutions.length === 0) return "";
|
|
12276
|
+
return toolExecutions.map((exec) => {
|
|
12277
|
+
const contentStr = typeof exec.content === "string" ? exec.content.trim() : "";
|
|
12278
|
+
const metaStr = exec.metadata ? JSON.stringify(sortJsonKeys(exec.metadata)) : "";
|
|
12279
|
+
return `${exec.toolName}:${contentStr}:${metaStr}`;
|
|
12280
|
+
}).join(";;");
|
|
12281
|
+
}
|
|
12282
|
+
function resolveProgressGuardConfig(options, env = typeof process !== "undefined" ? process.env : {}) {
|
|
12283
|
+
const envDisabled = env.NOLO_LOOP_PROGRESS_GUARD_DISABLED === "true" || env.NOLO_LOOP_PROGRESS_GUARD_DISABLED === "1";
|
|
12284
|
+
const disabled = options?.disabled ?? envDisabled ?? false;
|
|
12285
|
+
const parsePositiveInt = (val, fallback) => {
|
|
12286
|
+
if (typeof val === "number" && Number.isFinite(val) && val >= 1) {
|
|
12287
|
+
return Math.floor(val);
|
|
12288
|
+
}
|
|
12289
|
+
if (typeof val === "string") {
|
|
12290
|
+
const parsed = parseInt(val, 10);
|
|
12291
|
+
if (Number.isFinite(parsed) && parsed >= 1) {
|
|
12292
|
+
return parsed;
|
|
12293
|
+
}
|
|
12294
|
+
}
|
|
12295
|
+
return fallback;
|
|
12296
|
+
};
|
|
12297
|
+
const maxConsecutiveIdenticalRounds = parsePositiveInt(
|
|
12298
|
+
options?.maxConsecutiveIdenticalRounds ?? env.NOLO_LOOP_MAX_IDENTICAL_ROUNDS,
|
|
12299
|
+
DEFAULT_MAX_CONSECUTIVE_IDENTICAL_ROUNDS
|
|
12300
|
+
);
|
|
12301
|
+
const maxConsecutiveStagnantToolRounds = parsePositiveInt(
|
|
12302
|
+
options?.maxConsecutiveStagnantToolRounds ?? env.NOLO_LOOP_MAX_STAGNANT_TOOL_ROUNDS,
|
|
12303
|
+
DEFAULT_MAX_CONSECUTIVE_STAGNANT_TOOL_ROUNDS
|
|
12304
|
+
);
|
|
12305
|
+
return {
|
|
12306
|
+
disabled,
|
|
12307
|
+
maxConsecutiveIdenticalRounds,
|
|
12308
|
+
maxConsecutiveStagnantToolRounds
|
|
12309
|
+
};
|
|
12310
|
+
}
|
|
12311
|
+
var LocalLoopProgressGuard = class {
|
|
12312
|
+
config;
|
|
12313
|
+
lastAssistantFingerprint = null;
|
|
12314
|
+
lastAssistantHasNonEmptyText = false;
|
|
12315
|
+
consecutiveIdenticalCount = 0;
|
|
12316
|
+
lastToolCallsSignature = null;
|
|
12317
|
+
lastToolResultsSignature = null;
|
|
12318
|
+
consecutiveStagnantToolCount = 0;
|
|
12319
|
+
constructor(config, env) {
|
|
12320
|
+
this.config = resolveProgressGuardConfig(config, env);
|
|
12321
|
+
}
|
|
12322
|
+
/**
|
|
12323
|
+
* 在 LLM 返回 assistant 响应后调用。
|
|
12324
|
+
* 仅在纯文本/无工具调用且实质文本相同达到阈值时直接熔断;
|
|
12325
|
+
* 若存在工具调用,则不在此处熔断,留待工具执行后结合工具结果综合判定。
|
|
12326
|
+
*/
|
|
12327
|
+
observeAssistantResponse(result4) {
|
|
12328
|
+
if (this.config.disabled) return { action: "continue" };
|
|
12329
|
+
const { fingerprint, hasNonEmptyText, hasToolCalls } = buildAssistantActionFingerprint(result4);
|
|
12330
|
+
if (this.lastAssistantFingerprint !== null && this.lastAssistantFingerprint === fingerprint) {
|
|
12331
|
+
this.consecutiveIdenticalCount += 1;
|
|
12332
|
+
if (!hasToolCalls && hasNonEmptyText && this.consecutiveIdenticalCount >= this.config.maxConsecutiveIdenticalRounds) {
|
|
12333
|
+
return {
|
|
12334
|
+
action: "stall",
|
|
12335
|
+
reason: "repetition_loop",
|
|
12336
|
+
detail: `Consecutive identical text-only assistant response for ${this.consecutiveIdenticalCount} rounds.`,
|
|
12337
|
+
consecutiveRounds: this.consecutiveIdenticalCount
|
|
12338
|
+
};
|
|
12339
|
+
}
|
|
12340
|
+
} else {
|
|
12341
|
+
this.lastAssistantFingerprint = fingerprint;
|
|
12342
|
+
this.lastAssistantHasNonEmptyText = hasNonEmptyText;
|
|
12343
|
+
this.consecutiveIdenticalCount = 1;
|
|
12344
|
+
}
|
|
12345
|
+
return { action: "continue" };
|
|
12346
|
+
}
|
|
12347
|
+
/**
|
|
12348
|
+
* 在本轮所有工具执行完毕后调用,检查是否陷入停滞死循环。
|
|
12349
|
+
* 只有当工具返回内容与元数据完全无变化时才计入无进展 streak;
|
|
12350
|
+
* 一旦工具结果发生变化(如合法轮询状态推进),立即重置 identical streak,确保绝不误杀正常长任务。
|
|
12351
|
+
*/
|
|
12352
|
+
observeToolExecution(toolCalls, toolResults) {
|
|
12353
|
+
if (this.config.disabled) return { action: "continue" };
|
|
12354
|
+
if (!toolCalls || toolCalls.length === 0) return { action: "continue" };
|
|
12355
|
+
const toolCallsSig = buildToolCallsSignature(toolCalls);
|
|
12356
|
+
const toolResultsSig = buildToolResultsSignature(toolResults);
|
|
12357
|
+
const toolCallsUnchanged = this.lastToolCallsSignature !== null && this.lastToolCallsSignature === toolCallsSig;
|
|
12358
|
+
const toolResultsUnchanged = this.lastToolResultsSignature !== null && this.lastToolResultsSignature === toolResultsSig;
|
|
12359
|
+
if (toolCallsUnchanged && toolResultsUnchanged) {
|
|
12360
|
+
this.consecutiveStagnantToolCount += 1;
|
|
12361
|
+
if (this.consecutiveIdenticalCount >= this.config.maxConsecutiveIdenticalRounds) {
|
|
12362
|
+
return {
|
|
12363
|
+
action: "stall",
|
|
12364
|
+
reason: "repetition_loop",
|
|
12365
|
+
detail: `Consecutive identical assistant response with unchanged tool results for ${this.consecutiveIdenticalCount} rounds.`,
|
|
12366
|
+
consecutiveRounds: this.consecutiveIdenticalCount
|
|
12367
|
+
};
|
|
12368
|
+
}
|
|
12369
|
+
if (this.consecutiveStagnantToolCount >= this.config.maxConsecutiveStagnantToolRounds) {
|
|
12370
|
+
return {
|
|
12371
|
+
action: "stall",
|
|
12372
|
+
reason: "stagnant_tool_calls",
|
|
12373
|
+
detail: `Consecutive stagnant tool calls with unchanged results for ${this.consecutiveStagnantToolCount} rounds.`,
|
|
12374
|
+
consecutiveRounds: this.consecutiveStagnantToolCount
|
|
12375
|
+
};
|
|
12376
|
+
}
|
|
12377
|
+
} else {
|
|
12378
|
+
this.lastToolCallsSignature = toolCallsSig;
|
|
12379
|
+
this.lastToolResultsSignature = toolResultsSig;
|
|
12380
|
+
this.consecutiveStagnantToolCount = 1;
|
|
12381
|
+
if (!toolResultsUnchanged) {
|
|
12382
|
+
this.consecutiveIdenticalCount = 1;
|
|
12383
|
+
}
|
|
12384
|
+
}
|
|
12385
|
+
return { action: "continue" };
|
|
12386
|
+
}
|
|
12387
|
+
};
|
|
12388
|
+
function createLocalLoopProgressGuard(config, env) {
|
|
12389
|
+
return new LocalLoopProgressGuard(config, env);
|
|
12390
|
+
}
|
|
12391
|
+
|
|
12392
|
+
// packages/agent-runtime/toolArgumentsFingerprint.ts
|
|
12393
|
+
var hashFingerprintInput = (value) => {
|
|
12394
|
+
let hash2 = 2166136261;
|
|
12395
|
+
for (let index = 0; index < value.length; index += 1) {
|
|
12396
|
+
hash2 ^= value.charCodeAt(index);
|
|
12397
|
+
hash2 = Math.imul(hash2, 16777619);
|
|
12398
|
+
}
|
|
12399
|
+
return (hash2 >>> 0).toString(16).padStart(8, "0");
|
|
12400
|
+
};
|
|
12401
|
+
function buildToolArgumentsFingerprint(rawArguments) {
|
|
12402
|
+
if (rawArguments === void 0 || rawArguments === null) return void 0;
|
|
12403
|
+
const normalized = normalizeToolArguments(rawArguments);
|
|
12404
|
+
return hashFingerprintInput(normalized);
|
|
12405
|
+
}
|
|
12406
|
+
|
|
12203
12407
|
// packages/agent-runtime/leafFinalHandoff.ts
|
|
12204
|
-
var LEAF_FINAL_HANDOFF_INSTRUCTIONS = `Leaf subtask final: return only the result, blockers/findings, and minimal evidence the parent needs. Do not narrate your process or restate the task. Keep success minimal (a one-line result is enough); on failure include the blocker, severity when relevant, and an evidence reference (file:line, test command, commit, artifact, or run/dialog). If the task explicitly requires a long-form deliverable (document, translation, dataset, code, or other artifact), provide that deliverable in full and keep only the handoff around it concise.`;
|
|
12408
|
+
var LEAF_FINAL_HANDOFF_INSTRUCTIONS = `Leaf subtask final: return only the result, blockers/findings, and minimal evidence the parent needs. Do not narrate your process or restate the task. Keep success minimal (a one-line result is enough); on failure include the blocker, severity when relevant, and an evidence reference (file:line, test command, commit, artifact, or run/dialog). If the task explicitly requires a long-form deliverable (document, translation, dataset, code, or other artifact), provide that deliverable in full and keep only the handoff around it concise. During execution, follow the brief as given: only when new evidence would materially change the goal, risk, irreversibility, or DoD should you surface it as a blocker/finding in the handoff \u2014 do not silently expand scope or re-litigate the settled direction.`;
|
|
12205
12409
|
|
|
12206
12410
|
// packages/agent-runtime/contextBlockScope.ts
|
|
12207
12411
|
var isContextBlockScope = (value) => {
|
|
@@ -12423,20 +12627,33 @@ function isColdResume(history, nowMs) {
|
|
|
12423
12627
|
}
|
|
12424
12628
|
async function maybeAutoCompactLocalHistory(args2) {
|
|
12425
12629
|
const { adapter, dialogId, history } = args2;
|
|
12426
|
-
const unchanged = () => ({
|
|
12630
|
+
const unchanged = (decision) => ({
|
|
12427
12631
|
history,
|
|
12428
12632
|
compressed: false,
|
|
12429
|
-
summaryGenerated: false
|
|
12633
|
+
summaryGenerated: false,
|
|
12634
|
+
decision
|
|
12430
12635
|
});
|
|
12431
|
-
if (!dialogId
|
|
12432
|
-
return unchanged();
|
|
12636
|
+
if (!dialogId) {
|
|
12637
|
+
return unchanged({ outcome: "skipped", skipReason: "no-dialog-id" });
|
|
12638
|
+
}
|
|
12639
|
+
if (history.length === 0) {
|
|
12640
|
+
return unchanged({ outcome: "skipped", skipReason: "empty-history" });
|
|
12641
|
+
}
|
|
12642
|
+
if (typeof adapter.loadDialogSummary !== "function" || typeof adapter.saveDialogSummary !== "function") {
|
|
12643
|
+
return unchanged({
|
|
12644
|
+
outcome: "skipped",
|
|
12645
|
+
skipReason: "adapter-missing-summary-methods"
|
|
12646
|
+
});
|
|
12433
12647
|
}
|
|
12434
12648
|
let stored = null;
|
|
12435
12649
|
try {
|
|
12436
12650
|
stored = await adapter.loadDialogSummary(dialogId);
|
|
12437
12651
|
} catch (error) {
|
|
12438
12652
|
console.warn("[localLoop] loadDialogSummary failed:", error);
|
|
12439
|
-
return unchanged(
|
|
12653
|
+
return unchanged({
|
|
12654
|
+
outcome: "skipped",
|
|
12655
|
+
skipReason: "load-summary-failed"
|
|
12656
|
+
});
|
|
12440
12657
|
}
|
|
12441
12658
|
const bridged = toPlanCompressionMessages(history);
|
|
12442
12659
|
const validation = validateStoredSummary({ history, stored: stored ?? {} });
|
|
@@ -12472,7 +12689,21 @@ async function maybeAutoCompactLocalHistory(args2) {
|
|
|
12472
12689
|
...args2.realContextUsagePercent !== void 0 ? { realContextUsagePercent: args2.realContextUsagePercent } : {}
|
|
12473
12690
|
});
|
|
12474
12691
|
const projectExisting = () => {
|
|
12475
|
-
|
|
12692
|
+
const diag = plan.diagnostics;
|
|
12693
|
+
const diagSnapshot = diag ? {
|
|
12694
|
+
estimatedTokens: diag.totalUsed,
|
|
12695
|
+
historyBudget: diag.historyBudget,
|
|
12696
|
+
triggerRatio: diag.triggerRatio,
|
|
12697
|
+
...diag.realUsageRatio !== void 0 ? { realUsageRatio: diag.realUsageRatio } : {}
|
|
12698
|
+
} : {};
|
|
12699
|
+
const skippedDecision = {
|
|
12700
|
+
outcome: "skipped",
|
|
12701
|
+
skipReason: diag?.emptyReason === "no-pending" ? "no-pending" : diag?.emptyReason === "below-min-compress-count" ? "below-min-compress-count" : "below-trigger",
|
|
12702
|
+
...diagSnapshot,
|
|
12703
|
+
...diag ? { pendingMsgCount: diag.pendingMsgCount } : {},
|
|
12704
|
+
...diag?.compressCount !== void 0 ? { compressCount: diag.compressCount } : {}
|
|
12705
|
+
};
|
|
12706
|
+
if (!existingSummary.trim()) return unchanged(skippedDecision);
|
|
12476
12707
|
return {
|
|
12477
12708
|
history: projectHistoryWithSummary({
|
|
12478
12709
|
history,
|
|
@@ -12480,7 +12711,12 @@ async function maybeAutoCompactLocalHistory(args2) {
|
|
|
12480
12711
|
summarizedBeforeId
|
|
12481
12712
|
}),
|
|
12482
12713
|
compressed: true,
|
|
12483
|
-
summaryGenerated: false
|
|
12714
|
+
summaryGenerated: false,
|
|
12715
|
+
decision: {
|
|
12716
|
+
outcome: "compressed",
|
|
12717
|
+
trigger: "existing-summary",
|
|
12718
|
+
...diagSnapshot
|
|
12719
|
+
}
|
|
12484
12720
|
};
|
|
12485
12721
|
};
|
|
12486
12722
|
if (!plan.shouldCompress) {
|
|
@@ -12510,7 +12746,11 @@ async function maybeAutoCompactLocalHistory(args2) {
|
|
|
12510
12746
|
);
|
|
12511
12747
|
return {
|
|
12512
12748
|
...projectExisting(),
|
|
12513
|
-
failureMessage: "summary model returned empty content"
|
|
12749
|
+
failureMessage: "summary model returned empty content",
|
|
12750
|
+
decision: {
|
|
12751
|
+
outcome: "failed",
|
|
12752
|
+
detail: "summary model returned empty content"
|
|
12753
|
+
}
|
|
12514
12754
|
};
|
|
12515
12755
|
}
|
|
12516
12756
|
await adapter.saveDialogSummary({
|
|
@@ -12547,227 +12787,56 @@ async function maybeAutoCompactLocalHistory(args2) {
|
|
|
12547
12787
|
beforeTokens: metrics.previousSummaryTokens + metrics.compressedTokens,
|
|
12548
12788
|
afterTokens: metrics.newSummaryTokens + metrics.retainedTokens,
|
|
12549
12789
|
...result4.usage ? { usage: result4.usage } : {},
|
|
12550
|
-
metrics
|
|
12790
|
+
metrics,
|
|
12791
|
+
decision: {
|
|
12792
|
+
outcome: "compressed",
|
|
12793
|
+
trigger: invalidSummary ? "invalid-summary" : coldResume ? "cold-resume" : plan.diagnostics?.triggeredByRealUsage ? "real-usage" : "estimate",
|
|
12794
|
+
...plan.diagnostics ? {
|
|
12795
|
+
estimatedTokens: plan.diagnostics.totalUsed,
|
|
12796
|
+
historyBudget: plan.diagnostics.historyBudget,
|
|
12797
|
+
triggerRatio: plan.diagnostics.triggerRatio,
|
|
12798
|
+
...plan.diagnostics.realUsageRatio !== void 0 ? { realUsageRatio: plan.diagnostics.realUsageRatio } : {}
|
|
12799
|
+
} : {}
|
|
12800
|
+
}
|
|
12551
12801
|
};
|
|
12552
12802
|
} catch (error) {
|
|
12553
12803
|
console.warn("[localLoop] auto-compaction failed:", error);
|
|
12554
12804
|
const failureMessage = error instanceof Error && error.message ? error.message.slice(0, 200) : String(error).slice(0, 200);
|
|
12555
|
-
return {
|
|
12805
|
+
return {
|
|
12806
|
+
...projectExisting(),
|
|
12807
|
+
failureMessage,
|
|
12808
|
+
decision: { outcome: "failed", detail: failureMessage }
|
|
12809
|
+
};
|
|
12556
12810
|
}
|
|
12557
12811
|
}
|
|
12558
12812
|
|
|
12559
|
-
// packages/agent-runtime/
|
|
12560
|
-
var
|
|
12561
|
-
var
|
|
12562
|
-
|
|
12563
|
-
|
|
12564
|
-
|
|
12565
|
-
|
|
12566
|
-
|
|
12567
|
-
|
|
12813
|
+
// packages/agent-runtime/localLoop.ts
|
|
12814
|
+
var LOOP_TIMING_ENABLED = typeof process !== "undefined" && process.env?.NOLO_LOOP_TIMING === "1";
|
|
12815
|
+
var LOOP_TIMING_FILE = typeof process !== "undefined" ? process.env?.NOLO_LOOP_TIMING_FILE : void 0;
|
|
12816
|
+
var loopTimingRows = [];
|
|
12817
|
+
var loopTimingLastMark;
|
|
12818
|
+
function loopTimingMark(phase, round) {
|
|
12819
|
+
if (!LOOP_TIMING_ENABLED) return;
|
|
12820
|
+
const now = performance.now();
|
|
12821
|
+
if (loopTimingLastMark !== void 0) {
|
|
12822
|
+
loopTimingRows.push({ phase, round, durationMs: now - loopTimingLastMark });
|
|
12568
12823
|
}
|
|
12569
|
-
|
|
12824
|
+
loopTimingLastMark = now;
|
|
12570
12825
|
}
|
|
12571
|
-
function
|
|
12572
|
-
if (
|
|
12826
|
+
async function loopTimingFlush() {
|
|
12827
|
+
if (!LOOP_TIMING_ENABLED) return;
|
|
12828
|
+
const lines = loopTimingRows.map((row) => JSON.stringify(row)).join("\n");
|
|
12829
|
+
loopTimingRows = [];
|
|
12830
|
+
loopTimingLastMark = void 0;
|
|
12831
|
+
if (!lines) return;
|
|
12832
|
+
if (LOOP_TIMING_FILE) {
|
|
12573
12833
|
try {
|
|
12574
|
-
|
|
12834
|
+
const { appendFileSync } = await import("node:fs");
|
|
12835
|
+
appendFileSync(LOOP_TIMING_FILE, lines + "\n");
|
|
12575
12836
|
} catch {
|
|
12576
|
-
return String(rawArgs ?? "");
|
|
12577
12837
|
}
|
|
12578
|
-
}
|
|
12579
|
-
|
|
12580
|
-
if (!trimmed) return "";
|
|
12581
|
-
try {
|
|
12582
|
-
const parsed = JSON.parse(trimmed);
|
|
12583
|
-
return JSON.stringify(sortJsonKeys(parsed));
|
|
12584
|
-
} catch {
|
|
12585
|
-
return trimmed;
|
|
12586
|
-
}
|
|
12587
|
-
}
|
|
12588
|
-
function extractNormalizedContentText(content) {
|
|
12589
|
-
if (typeof content === "string") return content.trim();
|
|
12590
|
-
if (!Array.isArray(content)) return "";
|
|
12591
|
-
return content.map((part) => {
|
|
12592
|
-
if (part?.type === "text") return String(part.text ?? "").trim();
|
|
12593
|
-
if (part?.type === "image_url") return `[img:${part.image_url?.url ?? ""}]`;
|
|
12594
|
-
return "";
|
|
12595
|
-
}).filter(Boolean).join("\n");
|
|
12596
|
-
}
|
|
12597
|
-
function buildToolCallsSignature(toolCalls) {
|
|
12598
|
-
if (!toolCalls || toolCalls.length === 0) return "";
|
|
12599
|
-
return toolCalls.map(
|
|
12600
|
-
(tc) => `${tc.function?.name ?? ""}:${normalizeToolArguments(tc.function?.arguments)}`
|
|
12601
|
-
).join(";;");
|
|
12602
|
-
}
|
|
12603
|
-
function buildAssistantActionFingerprint(result4) {
|
|
12604
|
-
const content = extractNormalizedContentText(result4.content);
|
|
12605
|
-
const reasoning = typeof result4.reasoning_content === "string" ? result4.reasoning_content.trim() : "";
|
|
12606
|
-
let toolCallsSig = buildToolCallsSignature(result4.tool_calls);
|
|
12607
|
-
let hasToolCalls = Array.isArray(result4.tool_calls) && result4.tool_calls.length > 0;
|
|
12608
|
-
if (!toolCallsSig && Array.isArray(result4.output) && result4.output.length > 0) {
|
|
12609
|
-
const blocksToolCalls = result4.output.filter(
|
|
12610
|
-
(b) => b.type === "toolCall"
|
|
12611
|
-
).map((b) => b.toolCall);
|
|
12612
|
-
if (blocksToolCalls.length > 0) {
|
|
12613
|
-
toolCallsSig = buildToolCallsSignature(blocksToolCalls);
|
|
12614
|
-
hasToolCalls = true;
|
|
12615
|
-
}
|
|
12616
|
-
}
|
|
12617
|
-
const hasNonEmptyText = content.length > 0 || reasoning.length > 0;
|
|
12618
|
-
const fingerprint = `${content}##${reasoning}##${toolCallsSig}`;
|
|
12619
|
-
return {
|
|
12620
|
-
fingerprint,
|
|
12621
|
-
hasNonEmptyText,
|
|
12622
|
-
hasToolCalls,
|
|
12623
|
-
toolCallsSignature: toolCallsSig
|
|
12624
|
-
};
|
|
12625
|
-
}
|
|
12626
|
-
function buildToolResultsSignature(toolExecutions) {
|
|
12627
|
-
if (toolExecutions.length === 0) return "";
|
|
12628
|
-
return toolExecutions.map((exec) => {
|
|
12629
|
-
const contentStr = typeof exec.content === "string" ? exec.content.trim() : "";
|
|
12630
|
-
const metaStr = exec.metadata ? JSON.stringify(sortJsonKeys(exec.metadata)) : "";
|
|
12631
|
-
return `${exec.toolName}:${contentStr}:${metaStr}`;
|
|
12632
|
-
}).join(";;");
|
|
12633
|
-
}
|
|
12634
|
-
function resolveProgressGuardConfig(options, env = typeof process !== "undefined" ? process.env : {}) {
|
|
12635
|
-
const envDisabled = env.NOLO_LOOP_PROGRESS_GUARD_DISABLED === "true" || env.NOLO_LOOP_PROGRESS_GUARD_DISABLED === "1";
|
|
12636
|
-
const disabled = options?.disabled ?? envDisabled ?? false;
|
|
12637
|
-
const parsePositiveInt = (val, fallback) => {
|
|
12638
|
-
if (typeof val === "number" && Number.isFinite(val) && val >= 1) {
|
|
12639
|
-
return Math.floor(val);
|
|
12640
|
-
}
|
|
12641
|
-
if (typeof val === "string") {
|
|
12642
|
-
const parsed = parseInt(val, 10);
|
|
12643
|
-
if (Number.isFinite(parsed) && parsed >= 1) {
|
|
12644
|
-
return parsed;
|
|
12645
|
-
}
|
|
12646
|
-
}
|
|
12647
|
-
return fallback;
|
|
12648
|
-
};
|
|
12649
|
-
const maxConsecutiveIdenticalRounds = parsePositiveInt(
|
|
12650
|
-
options?.maxConsecutiveIdenticalRounds ?? env.NOLO_LOOP_MAX_IDENTICAL_ROUNDS,
|
|
12651
|
-
DEFAULT_MAX_CONSECUTIVE_IDENTICAL_ROUNDS
|
|
12652
|
-
);
|
|
12653
|
-
const maxConsecutiveStagnantToolRounds = parsePositiveInt(
|
|
12654
|
-
options?.maxConsecutiveStagnantToolRounds ?? env.NOLO_LOOP_MAX_STAGNANT_TOOL_ROUNDS,
|
|
12655
|
-
DEFAULT_MAX_CONSECUTIVE_STAGNANT_TOOL_ROUNDS
|
|
12656
|
-
);
|
|
12657
|
-
return {
|
|
12658
|
-
disabled,
|
|
12659
|
-
maxConsecutiveIdenticalRounds,
|
|
12660
|
-
maxConsecutiveStagnantToolRounds
|
|
12661
|
-
};
|
|
12662
|
-
}
|
|
12663
|
-
var LocalLoopProgressGuard = class {
|
|
12664
|
-
config;
|
|
12665
|
-
lastAssistantFingerprint = null;
|
|
12666
|
-
lastAssistantHasNonEmptyText = false;
|
|
12667
|
-
consecutiveIdenticalCount = 0;
|
|
12668
|
-
lastToolCallsSignature = null;
|
|
12669
|
-
lastToolResultsSignature = null;
|
|
12670
|
-
consecutiveStagnantToolCount = 0;
|
|
12671
|
-
constructor(config, env) {
|
|
12672
|
-
this.config = resolveProgressGuardConfig(config, env);
|
|
12673
|
-
}
|
|
12674
|
-
/**
|
|
12675
|
-
* 在 LLM 返回 assistant 响应后调用。
|
|
12676
|
-
* 仅在纯文本/无工具调用且实质文本相同达到阈值时直接熔断;
|
|
12677
|
-
* 若存在工具调用,则不在此处熔断,留待工具执行后结合工具结果综合判定。
|
|
12678
|
-
*/
|
|
12679
|
-
observeAssistantResponse(result4) {
|
|
12680
|
-
if (this.config.disabled) return { action: "continue" };
|
|
12681
|
-
const { fingerprint, hasNonEmptyText, hasToolCalls } = buildAssistantActionFingerprint(result4);
|
|
12682
|
-
if (this.lastAssistantFingerprint !== null && this.lastAssistantFingerprint === fingerprint) {
|
|
12683
|
-
this.consecutiveIdenticalCount += 1;
|
|
12684
|
-
if (!hasToolCalls && hasNonEmptyText && this.consecutiveIdenticalCount >= this.config.maxConsecutiveIdenticalRounds) {
|
|
12685
|
-
return {
|
|
12686
|
-
action: "stall",
|
|
12687
|
-
reason: "repetition_loop",
|
|
12688
|
-
detail: `Consecutive identical text-only assistant response for ${this.consecutiveIdenticalCount} rounds.`,
|
|
12689
|
-
consecutiveRounds: this.consecutiveIdenticalCount
|
|
12690
|
-
};
|
|
12691
|
-
}
|
|
12692
|
-
} else {
|
|
12693
|
-
this.lastAssistantFingerprint = fingerprint;
|
|
12694
|
-
this.lastAssistantHasNonEmptyText = hasNonEmptyText;
|
|
12695
|
-
this.consecutiveIdenticalCount = 1;
|
|
12696
|
-
}
|
|
12697
|
-
return { action: "continue" };
|
|
12698
|
-
}
|
|
12699
|
-
/**
|
|
12700
|
-
* 在本轮所有工具执行完毕后调用,检查是否陷入停滞死循环。
|
|
12701
|
-
* 只有当工具返回内容与元数据完全无变化时才计入无进展 streak;
|
|
12702
|
-
* 一旦工具结果发生变化(如合法轮询状态推进),立即重置 identical streak,确保绝不误杀正常长任务。
|
|
12703
|
-
*/
|
|
12704
|
-
observeToolExecution(toolCalls, toolResults) {
|
|
12705
|
-
if (this.config.disabled) return { action: "continue" };
|
|
12706
|
-
if (!toolCalls || toolCalls.length === 0) return { action: "continue" };
|
|
12707
|
-
const toolCallsSig = buildToolCallsSignature(toolCalls);
|
|
12708
|
-
const toolResultsSig = buildToolResultsSignature(toolResults);
|
|
12709
|
-
const toolCallsUnchanged = this.lastToolCallsSignature !== null && this.lastToolCallsSignature === toolCallsSig;
|
|
12710
|
-
const toolResultsUnchanged = this.lastToolResultsSignature !== null && this.lastToolResultsSignature === toolResultsSig;
|
|
12711
|
-
if (toolCallsUnchanged && toolResultsUnchanged) {
|
|
12712
|
-
this.consecutiveStagnantToolCount += 1;
|
|
12713
|
-
if (this.consecutiveIdenticalCount >= this.config.maxConsecutiveIdenticalRounds) {
|
|
12714
|
-
return {
|
|
12715
|
-
action: "stall",
|
|
12716
|
-
reason: "repetition_loop",
|
|
12717
|
-
detail: `Consecutive identical assistant response with unchanged tool results for ${this.consecutiveIdenticalCount} rounds.`,
|
|
12718
|
-
consecutiveRounds: this.consecutiveIdenticalCount
|
|
12719
|
-
};
|
|
12720
|
-
}
|
|
12721
|
-
if (this.consecutiveStagnantToolCount >= this.config.maxConsecutiveStagnantToolRounds) {
|
|
12722
|
-
return {
|
|
12723
|
-
action: "stall",
|
|
12724
|
-
reason: "stagnant_tool_calls",
|
|
12725
|
-
detail: `Consecutive stagnant tool calls with unchanged results for ${this.consecutiveStagnantToolCount} rounds.`,
|
|
12726
|
-
consecutiveRounds: this.consecutiveStagnantToolCount
|
|
12727
|
-
};
|
|
12728
|
-
}
|
|
12729
|
-
} else {
|
|
12730
|
-
this.lastToolCallsSignature = toolCallsSig;
|
|
12731
|
-
this.lastToolResultsSignature = toolResultsSig;
|
|
12732
|
-
this.consecutiveStagnantToolCount = 1;
|
|
12733
|
-
if (!toolResultsUnchanged) {
|
|
12734
|
-
this.consecutiveIdenticalCount = 1;
|
|
12735
|
-
}
|
|
12736
|
-
}
|
|
12737
|
-
return { action: "continue" };
|
|
12738
|
-
}
|
|
12739
|
-
};
|
|
12740
|
-
function createLocalLoopProgressGuard(config, env) {
|
|
12741
|
-
return new LocalLoopProgressGuard(config, env);
|
|
12742
|
-
}
|
|
12743
|
-
|
|
12744
|
-
// packages/agent-runtime/localLoop.ts
|
|
12745
|
-
var LOOP_TIMING_ENABLED = typeof process !== "undefined" && process.env?.NOLO_LOOP_TIMING === "1";
|
|
12746
|
-
var LOOP_TIMING_FILE = typeof process !== "undefined" ? process.env?.NOLO_LOOP_TIMING_FILE : void 0;
|
|
12747
|
-
var loopTimingRows = [];
|
|
12748
|
-
var loopTimingLastMark;
|
|
12749
|
-
function loopTimingMark(phase, round) {
|
|
12750
|
-
if (!LOOP_TIMING_ENABLED) return;
|
|
12751
|
-
const now = performance.now();
|
|
12752
|
-
if (loopTimingLastMark !== void 0) {
|
|
12753
|
-
loopTimingRows.push({ phase, round, durationMs: now - loopTimingLastMark });
|
|
12754
|
-
}
|
|
12755
|
-
loopTimingLastMark = now;
|
|
12756
|
-
}
|
|
12757
|
-
async function loopTimingFlush() {
|
|
12758
|
-
if (!LOOP_TIMING_ENABLED) return;
|
|
12759
|
-
const lines = loopTimingRows.map((row) => JSON.stringify(row)).join("\n");
|
|
12760
|
-
loopTimingRows = [];
|
|
12761
|
-
loopTimingLastMark = void 0;
|
|
12762
|
-
if (!lines) return;
|
|
12763
|
-
if (LOOP_TIMING_FILE) {
|
|
12764
|
-
try {
|
|
12765
|
-
const { appendFileSync } = await import("node:fs");
|
|
12766
|
-
appendFileSync(LOOP_TIMING_FILE, lines + "\n");
|
|
12767
|
-
} catch {
|
|
12768
|
-
}
|
|
12769
|
-
} else {
|
|
12770
|
-
process.stderr.write(lines + "\n");
|
|
12838
|
+
} else {
|
|
12839
|
+
process.stderr.write(lines + "\n");
|
|
12771
12840
|
}
|
|
12772
12841
|
}
|
|
12773
12842
|
var LOCAL_AGENT_CONFIG_MISSING_CODE = "LOCAL_AGENT_CONFIG_MISSING";
|
|
@@ -13046,10 +13115,10 @@ var TOOL_METADATA_KEYS = [
|
|
|
13046
13115
|
"pasteId",
|
|
13047
13116
|
"source"
|
|
13048
13117
|
];
|
|
13049
|
-
function trimHistoryToContextBudget(history, model) {
|
|
13118
|
+
function trimHistoryToContextBudget(history, model, contextWindowOverride) {
|
|
13050
13119
|
if (history.length === 0) return { history, droppedCount: 0 };
|
|
13051
13120
|
const { rawMessageBudget } = planContextUsage({
|
|
13052
|
-
contextWindow: getModelContextWindow(model ?? ""),
|
|
13121
|
+
contextWindow: contextWindowOverride ?? getModelContextWindow(model ?? ""),
|
|
13053
13122
|
summaryTokens: 0,
|
|
13054
13123
|
// localLoop 没有 web 端的负载分档器;medium 是中性默认值,
|
|
13055
13124
|
// 不为了省几个 token 在这里复制一份分类逻辑。
|
|
@@ -13512,7 +13581,14 @@ async function runLocalAgentTurn(input) {
|
|
|
13512
13581
|
agentConfig.exposedToolNames ?? agentConfig.toolNames ?? []
|
|
13513
13582
|
);
|
|
13514
13583
|
const guidanceBlocks = buildRuntimeGuidanceBlocks(agentTools);
|
|
13515
|
-
const toolGuidedSections = resolveToolGuidedSections(agentTools
|
|
13584
|
+
const toolGuidedSections = resolveToolGuidedSections(agentTools, {
|
|
13585
|
+
// 单调锁定:历史里任一 user 消息命中派发关键词、或已出现过
|
|
13586
|
+
// startAgentRun/controlAgentRun 的 tool_calls,后续每轮都保持 true,
|
|
13587
|
+
// 防止 session-scope 的 agentCollaboration 段逐轮翻转击穿前缀缓存。
|
|
13588
|
+
dispatchIntent: detectDispatchIntentFromMessages(history) || detectDispatchIntent(
|
|
13589
|
+
typeof input.input === "string" ? input.input : void 0
|
|
13590
|
+
)
|
|
13591
|
+
});
|
|
13516
13592
|
const guidanceScopes = [
|
|
13517
13593
|
...input.userLanguage?.trim() ? [buildUserResponseLanguageContext({ language: input.userLanguage })] : [],
|
|
13518
13594
|
guidanceBlocks.startupProtocol,
|
|
@@ -13540,7 +13616,7 @@ async function runLocalAgentTurn(input) {
|
|
|
13540
13616
|
}
|
|
13541
13617
|
return resolvedProvider;
|
|
13542
13618
|
};
|
|
13543
|
-
const contextWindow =
|
|
13619
|
+
const contextWindow = resolveAgentContextWindow(agentConfig);
|
|
13544
13620
|
const compressionTriggerRatio = resolveCompressionTriggerRatio(contextWindow);
|
|
13545
13621
|
let realContextUsagePercent;
|
|
13546
13622
|
if (input.continueDialogId && typeof input.adapter.loadLastContextUsage === "function") {
|
|
@@ -13561,19 +13637,29 @@ async function runLocalAgentTurn(input) {
|
|
|
13561
13637
|
}
|
|
13562
13638
|
let compactionUsage;
|
|
13563
13639
|
const emitCompactionObservation = (compacted) => {
|
|
13564
|
-
|
|
13565
|
-
|
|
13566
|
-
|
|
13567
|
-
|
|
13568
|
-
|
|
13569
|
-
summaryGenerated: compacted.summaryGenerated,
|
|
13570
|
-
compressed: compacted.compressed,
|
|
13571
|
-
...compacted.failureMessage ? { failed: true, detail: compacted.failureMessage } : {},
|
|
13572
|
-
...compacted.beforeTokens !== void 0 ? { beforeTokens: compacted.beforeTokens } : {},
|
|
13573
|
-
...compacted.afterTokens !== void 0 ? { afterTokens: compacted.afterTokens } : {},
|
|
13574
|
-
...compacted.savedTokens !== void 0 ? { savedTokens: compacted.savedTokens } : {}
|
|
13575
|
-
});
|
|
13640
|
+
const decision = compacted.decision;
|
|
13641
|
+
if (decision?.outcome === "skipped") {
|
|
13642
|
+
const isProtectionGap = decision.skipReason === "adapter-missing-summary-methods" || decision.skipReason === "load-summary-failed";
|
|
13643
|
+
const approachingBudget = decision.skipReason === "below-trigger" && typeof decision.estimatedTokens === "number" && typeof decision.historyBudget === "number" && decision.historyBudget > 0 && decision.estimatedTokens >= decision.historyBudget * 0.5;
|
|
13644
|
+
if (!isProtectionGap && !approachingBudget) return;
|
|
13576
13645
|
}
|
|
13646
|
+
emitLoopEvent(observationBoundary, {
|
|
13647
|
+
kind: "compaction",
|
|
13648
|
+
atMs: Date.now(),
|
|
13649
|
+
...compacted.reason ? { reason: compacted.reason } : {},
|
|
13650
|
+
summaryGenerated: compacted.summaryGenerated,
|
|
13651
|
+
compressed: compacted.compressed,
|
|
13652
|
+
...compacted.failureMessage ? { failed: true, detail: compacted.failureMessage } : {},
|
|
13653
|
+
...decision?.outcome === "skipped" ? { skipped: true, skipReason: decision.skipReason } : {},
|
|
13654
|
+
...decision && "trigger" in decision && decision.trigger ? { trigger: decision.trigger } : {},
|
|
13655
|
+
...decision && "estimatedTokens" in decision && decision.estimatedTokens !== void 0 ? { estimatedTokens: decision.estimatedTokens } : {},
|
|
13656
|
+
...decision && "historyBudget" in decision && decision.historyBudget !== void 0 ? { historyBudget: decision.historyBudget } : {},
|
|
13657
|
+
...decision && "realUsageRatio" in decision && decision.realUsageRatio !== void 0 ? { realUsageRatio: decision.realUsageRatio } : {},
|
|
13658
|
+
...decision && "triggerRatio" in decision && decision.triggerRatio !== void 0 ? { triggerRatio: decision.triggerRatio } : {},
|
|
13659
|
+
...compacted.beforeTokens !== void 0 ? { beforeTokens: compacted.beforeTokens } : {},
|
|
13660
|
+
...compacted.afterTokens !== void 0 ? { afterTokens: compacted.afterTokens } : {},
|
|
13661
|
+
...compacted.savedTokens !== void 0 ? { savedTokens: compacted.savedTokens } : {}
|
|
13662
|
+
});
|
|
13577
13663
|
};
|
|
13578
13664
|
try {
|
|
13579
13665
|
const compacted = await maybeAutoCompactLocalHistory({
|
|
@@ -13582,6 +13668,7 @@ async function runLocalAgentTurn(input) {
|
|
|
13582
13668
|
history,
|
|
13583
13669
|
model: agentConfig.model,
|
|
13584
13670
|
resolveProvider: resolveProviderOnce,
|
|
13671
|
+
contextWindow,
|
|
13585
13672
|
realContextUsagePercent
|
|
13586
13673
|
});
|
|
13587
13674
|
history = compacted.history;
|
|
@@ -13591,7 +13678,7 @@ async function runLocalAgentTurn(input) {
|
|
|
13591
13678
|
console.warn("[localLoop] auto-compaction unexpected error:", error);
|
|
13592
13679
|
}
|
|
13593
13680
|
loopTimingMark("maybeAutoCompactLocalHistory", 0);
|
|
13594
|
-
const trimmedHistory = trimHistoryToContextBudget(history, agentConfig.model);
|
|
13681
|
+
const trimmedHistory = trimHistoryToContextBudget(history, agentConfig.model, contextWindow);
|
|
13595
13682
|
if (trimmedHistory.droppedCount > 0) {
|
|
13596
13683
|
history = trimmedHistory.history;
|
|
13597
13684
|
}
|
|
@@ -13653,17 +13740,26 @@ async function runLocalAgentTurn(input) {
|
|
|
13653
13740
|
let skipFinalAppend = false;
|
|
13654
13741
|
let partialContent = "";
|
|
13655
13742
|
const progressGuard = createLocalLoopProgressGuard(input.progressGuardConfig);
|
|
13743
|
+
let ephemeralSummary = null;
|
|
13744
|
+
const ephemeralDialogId = `ephemeral-${crypto.randomUUID()}`;
|
|
13745
|
+
const compactionAdapter = input.continueDialogId ? input.adapter : {
|
|
13746
|
+
...input.adapter,
|
|
13747
|
+
loadDialogSummary: async () => ephemeralSummary,
|
|
13748
|
+
saveDialogSummary: async (summaryInput) => {
|
|
13749
|
+
ephemeralSummary = summaryInput;
|
|
13750
|
+
}
|
|
13751
|
+
};
|
|
13752
|
+
const compactionDialogId = input.continueDialogId ?? ephemeralDialogId;
|
|
13656
13753
|
const maybeCompactInLoop = async () => {
|
|
13657
|
-
|
|
13658
|
-
|
|
13659
|
-
|
|
13660
|
-
|
|
13661
|
-
|
|
13662
|
-
if (ratio < compressionTriggerRatio) return;
|
|
13754
|
+
const inputTokens = contextUsage ? normalizeUsage(contextUsage).input_tokens : 0;
|
|
13755
|
+
const ratio = inputTokens > 0 ? Math.min(1, inputTokens / contextWindow) : void 0;
|
|
13756
|
+
if (ratio !== void 0 && ratio < compressionTriggerRatio * 0.85) {
|
|
13757
|
+
return;
|
|
13758
|
+
}
|
|
13663
13759
|
try {
|
|
13664
13760
|
const compacted = await maybeAutoCompactLocalHistory({
|
|
13665
|
-
adapter:
|
|
13666
|
-
dialogId:
|
|
13761
|
+
adapter: compactionAdapter,
|
|
13762
|
+
dialogId: compactionDialogId,
|
|
13667
13763
|
// canonical 坐标:store 全量历史 + 本轮消息的「持久化形态」
|
|
13668
13764
|
// (applyPersistedTurnInput 会把首条 user 消息换成 paste 展开形态)。
|
|
13669
13765
|
// 锚点与 sourceHash 都必须按持久化形态计算——否则下轮从 store
|
|
@@ -13678,7 +13774,8 @@ async function runLocalAgentTurn(input) {
|
|
|
13678
13774
|
],
|
|
13679
13775
|
model: agentConfig.model,
|
|
13680
13776
|
resolveProvider: resolveProviderOnce,
|
|
13681
|
-
|
|
13777
|
+
contextWindow,
|
|
13778
|
+
...ratio !== void 0 ? { realContextUsagePercent: ratio } : {}
|
|
13682
13779
|
});
|
|
13683
13780
|
if (compacted.usage) {
|
|
13684
13781
|
compactionUsage = addOutOfBandUsage(compactionUsage, compacted.usage);
|
|
@@ -13946,6 +14043,7 @@ ${reasoningTailLog}
|
|
|
13946
14043
|
const startedAt = Date.now();
|
|
13947
14044
|
loopTimingMark("toolCallStart", round);
|
|
13948
14045
|
const argumentsPreview = summarizeToolArguments(toolName, toolCall.function.arguments);
|
|
14046
|
+
const argumentsFingerprint = buildToolArgumentsFingerprint(toolCall.function.arguments);
|
|
13949
14047
|
emitLoopEvent(
|
|
13950
14048
|
observationBoundary,
|
|
13951
14049
|
{
|
|
@@ -13954,7 +14052,8 @@ ${reasoningTailLog}
|
|
|
13954
14052
|
toolCallId: toolCall.id,
|
|
13955
14053
|
toolName,
|
|
13956
14054
|
atMs: startedAt,
|
|
13957
|
-
...argumentsPreview ? { argumentsPreview } : {}
|
|
14055
|
+
...argumentsPreview ? { argumentsPreview } : {},
|
|
14056
|
+
...argumentsFingerprint ? { argumentsFingerprint } : {}
|
|
13958
14057
|
},
|
|
13959
14058
|
{
|
|
13960
14059
|
type: "tool-call",
|
|
@@ -15568,13 +15667,13 @@ var DEFAULT_LOCAL_TOOLS = /* @__PURE__ */ new Set([
|
|
|
15568
15667
|
"execShell",
|
|
15569
15668
|
"launchProcess",
|
|
15570
15669
|
"listProcesses",
|
|
15571
|
-
// ProcessTask follow-up tools
|
|
15572
|
-
//
|
|
15573
|
-
//
|
|
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.
|
|
15574
15675
|
"taskWait",
|
|
15575
|
-
"taskLogs",
|
|
15576
15676
|
"taskStop",
|
|
15577
|
-
"tasks",
|
|
15578
15677
|
// Scheduling tools: forking/observing sub-agents is a declared capability
|
|
15579
15678
|
// of capable agents, and the blast radius is strictly narrower than
|
|
15580
15679
|
// execShell (already default-enabled). Requiring an env allowlist for these
|
|
@@ -17571,9 +17670,7 @@ var WORKSPACE_TOOL_NAMES = [
|
|
|
17571
17670
|
"launchProcess",
|
|
17572
17671
|
"listProcesses",
|
|
17573
17672
|
"taskWait",
|
|
17574
|
-
"taskLogs",
|
|
17575
17673
|
"taskStop",
|
|
17576
|
-
"tasks",
|
|
17577
17674
|
"openDesktopPreview"
|
|
17578
17675
|
];
|
|
17579
17676
|
var SHELL_TOOL_NAMES = [
|
|
@@ -17581,9 +17678,7 @@ var SHELL_TOOL_NAMES = [
|
|
|
17581
17678
|
"launchProcess",
|
|
17582
17679
|
"listProcesses",
|
|
17583
17680
|
"taskWait",
|
|
17584
|
-
"
|
|
17585
|
-
"taskStop",
|
|
17586
|
-
"tasks"
|
|
17681
|
+
"taskStop"
|
|
17587
17682
|
];
|
|
17588
17683
|
var WORKSPACE_TOOL_NAME_SET = new Set(WORKSPACE_TOOL_NAMES);
|
|
17589
17684
|
function buildWorkspacePathProperty() {
|
|
@@ -17832,7 +17927,7 @@ function buildTaskWaitTool() {
|
|
|
17832
17927
|
type: "function",
|
|
17833
17928
|
function: {
|
|
17834
17929
|
name: "taskWait",
|
|
17835
|
-
description: 'Block until a background task (from launchProcess, or an execShell command that detached) reaches a terminal state, or until timeoutMs elapses. Returns {outcome, status, exitCode?, cursor, events}: outcome "terminal" with status exited|failed|stopped when it finished, outcome "timeout" with status "running" when it outlived the whole budget, outcome "not-found" for an unknown taskId, or outcome "evicted" when the event trail aged out (never wait again in that case). One call already waits the maximum budget and returns the moment the task ends, so a "timeout" means the task is genuinely longer than that \u2014 go do other work and come back, rather than re-waiting in a loop (each re-wait costs a full model round-trip).
|
|
17930
|
+
description: 'Block until a background task (from launchProcess, or an execShell command that detached) reaches a terminal state, or until timeoutMs elapses. Returns {outcome, status, exitCode?, cursor, events}: outcome "terminal" with status exited|failed|stopped when it finished, outcome "timeout" with status "running" when it outlived the whole budget, outcome "not-found" for an unknown taskId, or outcome "evicted" when the event trail aged out (never wait again in that case). One call already waits the maximum budget and returns the moment the task ends, so a "timeout" means the task is genuinely longer than that \u2014 go do other work and come back, rather than re-waiting in a loop (each re-wait costs a full model round-trip). Pass a small timeoutMs for a cheap liveness peek instead of the full result. `cursor` is the highest event seq covered by this response.',
|
|
17836
17931
|
parameters: {
|
|
17837
17932
|
type: "object",
|
|
17838
17933
|
properties: {
|
|
@@ -17851,30 +17946,6 @@ function buildTaskWaitTool() {
|
|
|
17851
17946
|
}
|
|
17852
17947
|
};
|
|
17853
17948
|
}
|
|
17854
|
-
function buildTaskLogsTool() {
|
|
17855
|
-
return {
|
|
17856
|
-
type: "function",
|
|
17857
|
-
function: {
|
|
17858
|
-
name: "taskLogs",
|
|
17859
|
-
description: "Read a background task's lifecycle events incrementally. Returns {outcome, status, cursor, events} where events are the started|promoted|exited|killed records with seq greater than the cursor you passed, and the returned `cursor` is the new high-water mark to pass next time (omit cursor to read from the beginning; repeating the same cursor is idempotent). Oversized output is spilled to a file and reported as `logRef`, which you can open with readFile.",
|
|
17860
|
-
parameters: {
|
|
17861
|
-
type: "object",
|
|
17862
|
-
properties: {
|
|
17863
|
-
taskId: {
|
|
17864
|
-
type: "string",
|
|
17865
|
-
minLength: 1,
|
|
17866
|
-
description: "Task id returned by launchProcess or by a detached execShell result."
|
|
17867
|
-
},
|
|
17868
|
-
cursor: {
|
|
17869
|
-
type: "number",
|
|
17870
|
-
description: "Last event seq you already consumed; only events with a higher seq are returned. Defaults to 0 (all retained events)."
|
|
17871
|
-
}
|
|
17872
|
-
},
|
|
17873
|
-
required: ["taskId"]
|
|
17874
|
-
}
|
|
17875
|
-
}
|
|
17876
|
-
};
|
|
17877
|
-
}
|
|
17878
17949
|
function buildTaskStopTool() {
|
|
17879
17950
|
return {
|
|
17880
17951
|
type: "function",
|
|
@@ -17895,19 +17966,6 @@ function buildTaskStopTool() {
|
|
|
17895
17966
|
}
|
|
17896
17967
|
};
|
|
17897
17968
|
}
|
|
17898
|
-
function buildTasksTool() {
|
|
17899
|
-
return {
|
|
17900
|
-
type: "function",
|
|
17901
|
-
function: {
|
|
17902
|
-
name: "tasks",
|
|
17903
|
-
description: "List background tasks you can still wait on, read logs from, or stop. Returns {count, tasks: {taskId, pid, label, status, startedAt, persist}[]}. Use it to recover a taskId you lost track of; foreground commands still running inside execShell are not listed.",
|
|
17904
|
-
parameters: {
|
|
17905
|
-
type: "object",
|
|
17906
|
-
properties: {}
|
|
17907
|
-
}
|
|
17908
|
-
}
|
|
17909
|
-
};
|
|
17910
|
-
}
|
|
17911
17969
|
function buildWorkspaceToolDefinition(toolName) {
|
|
17912
17970
|
if (toolName === "readFile") {
|
|
17913
17971
|
return buildReadWorkspaceFileTool();
|
|
@@ -17927,9 +17985,7 @@ function buildWorkspaceToolDefinition(toolName) {
|
|
|
17927
17985
|
if (toolName === "openDesktopPreview") return buildOpenDesktopPreviewTool();
|
|
17928
17986
|
if (toolName === "listProcesses") return buildListProcessesTool();
|
|
17929
17987
|
if (toolName === "taskWait") return buildTaskWaitTool();
|
|
17930
|
-
if (toolName === "taskLogs") return buildTaskLogsTool();
|
|
17931
17988
|
if (toolName === "taskStop") return buildTaskStopTool();
|
|
17932
|
-
if (toolName === "tasks") return buildTasksTool();
|
|
17933
17989
|
return null;
|
|
17934
17990
|
}
|
|
17935
17991
|
function filterDeclaredWorkspaceToolNames(args2) {
|
|
@@ -19395,15 +19451,23 @@ function buildLoadSkillExecutor(args2) {
|
|
|
19395
19451
|
const { resolveSkillByName } = await import("./skillDiscovery-CYUCJMAG.js");
|
|
19396
19452
|
const resolved = resolveSkillByName(args2.cwd, name);
|
|
19397
19453
|
if (!resolved) {
|
|
19398
|
-
const {
|
|
19399
|
-
const
|
|
19400
|
-
if (
|
|
19401
|
-
const body = buildCodingSkillContentBySlug(builtinSlug);
|
|
19454
|
+
const { resolveBuiltinSkillByName } = await import("./builtinSkillRegistry-FUAVTRVZ.js");
|
|
19455
|
+
const builtin = resolveBuiltinSkillByName(name);
|
|
19456
|
+
if (builtin) {
|
|
19402
19457
|
return {
|
|
19403
19458
|
content: `Skill "${name}" loaded inline. Follow its instructions.
|
|
19404
19459
|
|
|
19405
|
-
${
|
|
19406
|
-
|
|
19460
|
+
${builtin.content}`,
|
|
19461
|
+
// toolNames 进 metadata:回退面已扩到全注册表,其中授工具型 skill
|
|
19462
|
+
// (search-* 等)的工具在本宿主未必接线,宿主可据此降级提示。
|
|
19463
|
+
metadata: {
|
|
19464
|
+
loadSkill: true,
|
|
19465
|
+
resolved: true,
|
|
19466
|
+
name,
|
|
19467
|
+
requestedName: name,
|
|
19468
|
+
builtin: true,
|
|
19469
|
+
...builtin.config.toolNames?.length ? { toolNames: [...builtin.config.toolNames] } : {}
|
|
19470
|
+
}
|
|
19407
19471
|
};
|
|
19408
19472
|
}
|
|
19409
19473
|
return {
|
|
@@ -20174,6 +20238,530 @@ async function fetchAntigravityCloudCodeCompletion(args2) {
|
|
|
20174
20238
|
return normalized;
|
|
20175
20239
|
}
|
|
20176
20240
|
|
|
20241
|
+
// packages/agent-runtime/devin/devinProvider.ts
|
|
20242
|
+
import { randomBytes, randomUUID as randomUUID2 } from "node:crypto";
|
|
20243
|
+
var CLIENT_NAME = "chisel";
|
|
20244
|
+
var CLIENT_VERSION = "2026.8.18";
|
|
20245
|
+
function writeVarint(fieldNum, value) {
|
|
20246
|
+
const tag = fieldNum << 3 | 0;
|
|
20247
|
+
const bytes = [];
|
|
20248
|
+
let t = tag;
|
|
20249
|
+
while (t >= 128) {
|
|
20250
|
+
bytes.push(t & 127 | 128);
|
|
20251
|
+
t >>>= 7;
|
|
20252
|
+
}
|
|
20253
|
+
bytes.push(t);
|
|
20254
|
+
let v = value;
|
|
20255
|
+
while (v >= 128) {
|
|
20256
|
+
bytes.push(v & 127 | 128);
|
|
20257
|
+
v >>>= 7;
|
|
20258
|
+
}
|
|
20259
|
+
bytes.push(v);
|
|
20260
|
+
return Buffer.from(bytes);
|
|
20261
|
+
}
|
|
20262
|
+
function writeLengthDelimited(fieldNum, content) {
|
|
20263
|
+
const tag = fieldNum << 3 | 2;
|
|
20264
|
+
const tagBytes = [];
|
|
20265
|
+
let t = tag;
|
|
20266
|
+
while (t >= 128) {
|
|
20267
|
+
tagBytes.push(t & 127 | 128);
|
|
20268
|
+
t >>>= 7;
|
|
20269
|
+
}
|
|
20270
|
+
tagBytes.push(t);
|
|
20271
|
+
const lenBytes = [];
|
|
20272
|
+
let len = content.length;
|
|
20273
|
+
while (len >= 128) {
|
|
20274
|
+
lenBytes.push(len & 127 | 128);
|
|
20275
|
+
len >>>= 7;
|
|
20276
|
+
}
|
|
20277
|
+
lenBytes.push(len);
|
|
20278
|
+
return Buffer.concat([Buffer.from(tagBytes), Buffer.from(lenBytes), content]);
|
|
20279
|
+
}
|
|
20280
|
+
function writeStringField(fieldNum, str) {
|
|
20281
|
+
return writeLengthDelimited(fieldNum, Buffer.from(str, "utf8"));
|
|
20282
|
+
}
|
|
20283
|
+
function writeMessageField(fieldNum, message) {
|
|
20284
|
+
return writeLengthDelimited(fieldNum, message);
|
|
20285
|
+
}
|
|
20286
|
+
function generateFingerprint() {
|
|
20287
|
+
return randomBytes(366).toString("hex");
|
|
20288
|
+
}
|
|
20289
|
+
function encodeDevinClientMetadata(token) {
|
|
20290
|
+
return Buffer.concat([
|
|
20291
|
+
writeStringField(1, CLIENT_NAME),
|
|
20292
|
+
writeStringField(2, CLIENT_VERSION),
|
|
20293
|
+
writeStringField(3, token),
|
|
20294
|
+
writeStringField(4, "en"),
|
|
20295
|
+
writeStringField(5, process.platform === "win32" ? "windows" : "linux"),
|
|
20296
|
+
writeStringField(7, CLIENT_VERSION),
|
|
20297
|
+
writeStringField(12, CLIENT_NAME),
|
|
20298
|
+
writeStringField(31, generateFingerprint())
|
|
20299
|
+
]);
|
|
20300
|
+
}
|
|
20301
|
+
function encodeDevinChatMessage(msg) {
|
|
20302
|
+
const source = msg.role === "assistant" ? 2 : msg.role === "tool" ? 4 : 1;
|
|
20303
|
+
return Buffer.concat([
|
|
20304
|
+
writeStringField(1, randomUUID2()),
|
|
20305
|
+
writeVarint(2, source),
|
|
20306
|
+
writeStringField(3, msg.text),
|
|
20307
|
+
...(msg.toolCalls ?? []).map(
|
|
20308
|
+
(toolCall) => writeMessageField(
|
|
20309
|
+
6,
|
|
20310
|
+
Buffer.concat([
|
|
20311
|
+
writeStringField(1, toolCall.id),
|
|
20312
|
+
writeStringField(2, toolCall.function.name),
|
|
20313
|
+
writeStringField(3, toolCall.function.arguments)
|
|
20314
|
+
])
|
|
20315
|
+
)
|
|
20316
|
+
),
|
|
20317
|
+
...msg.toolCallId ? [writeStringField(7, msg.toolCallId)] : []
|
|
20318
|
+
]);
|
|
20319
|
+
}
|
|
20320
|
+
function encodeDevinToolDefinition(tool) {
|
|
20321
|
+
const fn3 = tool.function ?? {};
|
|
20322
|
+
const name = typeof fn3.name === "string" ? fn3.name : "";
|
|
20323
|
+
const description = typeof fn3.description === "string" ? fn3.description : "";
|
|
20324
|
+
const parameters = fn3.parameters ?? {};
|
|
20325
|
+
return Buffer.concat([
|
|
20326
|
+
writeStringField(1, name),
|
|
20327
|
+
writeStringField(2, description.length > 6998 ? `${description.slice(0, 6995)}...` : description),
|
|
20328
|
+
writeStringField(3, JSON.stringify(parameters))
|
|
20329
|
+
]);
|
|
20330
|
+
}
|
|
20331
|
+
function writeFixed64Field(fieldNum, val) {
|
|
20332
|
+
const b = Buffer.alloc(8);
|
|
20333
|
+
b.writeDoubleLE(val, 0);
|
|
20334
|
+
const tag = fieldNum << 3 | 1;
|
|
20335
|
+
const tagBytes = [];
|
|
20336
|
+
let t = tag;
|
|
20337
|
+
while (t >= 128) {
|
|
20338
|
+
tagBytes.push(t & 127 | 128);
|
|
20339
|
+
t >>>= 7;
|
|
20340
|
+
}
|
|
20341
|
+
tagBytes.push(t);
|
|
20342
|
+
return Buffer.concat([Buffer.from(tagBytes), b]);
|
|
20343
|
+
}
|
|
20344
|
+
function buildCompletionConfig(params) {
|
|
20345
|
+
const maxTokens = params?.maxTokens ?? 128e3;
|
|
20346
|
+
const maxNewlines = params?.maxNewlines ?? 400;
|
|
20347
|
+
const temp = params?.temperature ?? 1;
|
|
20348
|
+
const topP = params?.topP ?? 0.95;
|
|
20349
|
+
return Buffer.concat([
|
|
20350
|
+
writeVarint(1, 1),
|
|
20351
|
+
writeVarint(2, maxTokens),
|
|
20352
|
+
writeVarint(3, maxNewlines),
|
|
20353
|
+
writeFixed64Field(5, temp),
|
|
20354
|
+
writeVarint(7, 40),
|
|
20355
|
+
writeFixed64Field(8, topP)
|
|
20356
|
+
]);
|
|
20357
|
+
}
|
|
20358
|
+
function buildGetChatMessageRequest(params) {
|
|
20359
|
+
const { token, messages, model, tools = [], temperature } = params;
|
|
20360
|
+
const metadata = encodeDevinClientMetadata(token);
|
|
20361
|
+
let systemPrompt = "";
|
|
20362
|
+
const filteredMessages = [];
|
|
20363
|
+
for (const m of messages) {
|
|
20364
|
+
const text = typeof m.content === "string" ? m.content : Array.isArray(m.content) ? m.content.filter((p) => p?.type === "text").map((p) => p.text).join("\n") : "";
|
|
20365
|
+
if (m.role === "system") {
|
|
20366
|
+
systemPrompt = systemPrompt ? `${systemPrompt}
|
|
20367
|
+
|
|
20368
|
+
${text}` : text;
|
|
20369
|
+
} else if (m.role === "user" || m.role === "assistant" || m.role === "tool") {
|
|
20370
|
+
filteredMessages.push({
|
|
20371
|
+
role: m.role,
|
|
20372
|
+
text,
|
|
20373
|
+
...m.tool_call_id ? { toolCallId: m.tool_call_id } : {},
|
|
20374
|
+
...m.tool_calls?.length ? { toolCalls: m.tool_calls } : {}
|
|
20375
|
+
});
|
|
20376
|
+
}
|
|
20377
|
+
}
|
|
20378
|
+
const coalesced = [];
|
|
20379
|
+
for (const item of filteredMessages) {
|
|
20380
|
+
const last = coalesced[coalesced.length - 1];
|
|
20381
|
+
if (last && last.role === item.role && item.role !== "tool" && !last.toolCalls?.length && !item.toolCalls?.length) {
|
|
20382
|
+
last.text = `${last.text}
|
|
20383
|
+
|
|
20384
|
+
${item.text}`;
|
|
20385
|
+
} else {
|
|
20386
|
+
coalesced.push({ ...item });
|
|
20387
|
+
}
|
|
20388
|
+
}
|
|
20389
|
+
const chatMessageBuffers = coalesced.map((m) => encodeDevinChatMessage(m));
|
|
20390
|
+
const completionConfig = buildCompletionConfig({ temperature });
|
|
20391
|
+
const modelConfig = Buffer.concat([
|
|
20392
|
+
writeStringField(1, randomUUID2()),
|
|
20393
|
+
writeVarint(2, 1),
|
|
20394
|
+
writeVarint(3, 4)
|
|
20395
|
+
]);
|
|
20396
|
+
return Buffer.concat([
|
|
20397
|
+
writeMessageField(1, metadata),
|
|
20398
|
+
writeStringField(2, systemPrompt),
|
|
20399
|
+
...chatMessageBuffers.map((b) => writeMessageField(3, b)),
|
|
20400
|
+
writeVarint(7, 5),
|
|
20401
|
+
writeMessageField(8, completionConfig),
|
|
20402
|
+
...tools.map((tool) => writeMessageField(10, encodeDevinToolDefinition(tool))),
|
|
20403
|
+
writeMessageField(15, modelConfig),
|
|
20404
|
+
writeStringField(16, randomUUID2()),
|
|
20405
|
+
writeVarint(20, 1),
|
|
20406
|
+
writeStringField(21, model)
|
|
20407
|
+
]);
|
|
20408
|
+
}
|
|
20409
|
+
function buildDevinConnectFrame(payload, flags = 0) {
|
|
20410
|
+
const header = Buffer.alloc(5);
|
|
20411
|
+
header[0] = flags & 255;
|
|
20412
|
+
header.writeUInt32BE(payload.length, 1);
|
|
20413
|
+
return Buffer.concat([header, payload]);
|
|
20414
|
+
}
|
|
20415
|
+
function parseDevinConnectFrames(buffer3) {
|
|
20416
|
+
const frames = [];
|
|
20417
|
+
let offset = 0;
|
|
20418
|
+
while (offset + 5 <= buffer3.length) {
|
|
20419
|
+
const flags = buffer3[offset];
|
|
20420
|
+
const length = buffer3.readUInt32BE(offset + 1);
|
|
20421
|
+
if (offset + 5 + length > buffer3.length) {
|
|
20422
|
+
break;
|
|
20423
|
+
}
|
|
20424
|
+
const payload = buffer3.subarray(offset + 5, offset + 5 + length);
|
|
20425
|
+
frames.push({ flags, payload });
|
|
20426
|
+
offset += 5 + length;
|
|
20427
|
+
}
|
|
20428
|
+
return {
|
|
20429
|
+
frames,
|
|
20430
|
+
remainder: buffer3.subarray(offset)
|
|
20431
|
+
};
|
|
20432
|
+
}
|
|
20433
|
+
function parseDevinMetadataUsage(metaBytes) {
|
|
20434
|
+
let prompt = 0;
|
|
20435
|
+
let completion;
|
|
20436
|
+
let cacheRead = 0;
|
|
20437
|
+
let cacheWrite = 0;
|
|
20438
|
+
let sawAny = false;
|
|
20439
|
+
let offset = 0;
|
|
20440
|
+
while (offset < metaBytes.length) {
|
|
20441
|
+
let tag = 0;
|
|
20442
|
+
let shift = 0;
|
|
20443
|
+
while (offset < metaBytes.length) {
|
|
20444
|
+
const b = metaBytes[offset++];
|
|
20445
|
+
tag |= (b & 127) << shift;
|
|
20446
|
+
if (!(b & 128)) break;
|
|
20447
|
+
shift += 7;
|
|
20448
|
+
}
|
|
20449
|
+
const fieldNum = tag >>> 3;
|
|
20450
|
+
const wireType = tag & 7;
|
|
20451
|
+
if (wireType === 0) {
|
|
20452
|
+
let val = 0;
|
|
20453
|
+
let s = 0;
|
|
20454
|
+
while (offset < metaBytes.length) {
|
|
20455
|
+
const b = metaBytes[offset++];
|
|
20456
|
+
val |= (b & 127) << s;
|
|
20457
|
+
if (!(b & 128)) break;
|
|
20458
|
+
s += 7;
|
|
20459
|
+
}
|
|
20460
|
+
if (fieldNum === 2) {
|
|
20461
|
+
prompt = val;
|
|
20462
|
+
sawAny = true;
|
|
20463
|
+
} else if (fieldNum === 3) {
|
|
20464
|
+
completion = val;
|
|
20465
|
+
sawAny = true;
|
|
20466
|
+
} else if (fieldNum === 4) {
|
|
20467
|
+
cacheWrite = val;
|
|
20468
|
+
sawAny = true;
|
|
20469
|
+
} else if (fieldNum === 5) {
|
|
20470
|
+
cacheRead = val;
|
|
20471
|
+
sawAny = true;
|
|
20472
|
+
}
|
|
20473
|
+
} else if (wireType === 2) {
|
|
20474
|
+
let len = 0;
|
|
20475
|
+
let s = 0;
|
|
20476
|
+
while (offset < metaBytes.length) {
|
|
20477
|
+
const b = metaBytes[offset++];
|
|
20478
|
+
len |= (b & 127) << s;
|
|
20479
|
+
if (!(b & 128)) break;
|
|
20480
|
+
s += 7;
|
|
20481
|
+
}
|
|
20482
|
+
offset += len;
|
|
20483
|
+
} else {
|
|
20484
|
+
break;
|
|
20485
|
+
}
|
|
20486
|
+
}
|
|
20487
|
+
return sawAny ? { prompt, completion, cacheRead, cacheWrite } : null;
|
|
20488
|
+
}
|
|
20489
|
+
function attachDevinUpstreamFailure(error, failure) {
|
|
20490
|
+
if (failure) {
|
|
20491
|
+
error.devinUpstreamFailure = failure;
|
|
20492
|
+
}
|
|
20493
|
+
return error;
|
|
20494
|
+
}
|
|
20495
|
+
function readDevinUpstreamFailure(error) {
|
|
20496
|
+
if (!error || typeof error !== "object") return void 0;
|
|
20497
|
+
const failure = error.devinUpstreamFailure;
|
|
20498
|
+
if (!failure || typeof failure !== "object") return void 0;
|
|
20499
|
+
if (typeof failure.status !== "number" || !Number.isFinite(failure.status)) {
|
|
20500
|
+
return void 0;
|
|
20501
|
+
}
|
|
20502
|
+
return failure;
|
|
20503
|
+
}
|
|
20504
|
+
function parseDevinConnectTrailer(payload) {
|
|
20505
|
+
const text = payload.toString("utf8").trim();
|
|
20506
|
+
if (!text || text === "{}") return null;
|
|
20507
|
+
try {
|
|
20508
|
+
const parsed = JSON.parse(text);
|
|
20509
|
+
if (!parsed.error) {
|
|
20510
|
+
return new Error(`Devin Connect invalid terminal trailer: ${text}`);
|
|
20511
|
+
}
|
|
20512
|
+
const code = typeof parsed.error.code === "string" ? parsed.error.code : "unknown";
|
|
20513
|
+
const message = typeof parsed.error.message === "string" ? parsed.error.message : "Unknown error";
|
|
20514
|
+
return attachDevinUpstreamFailure(
|
|
20515
|
+
new Error(`Devin Connect upstream error ${code}: ${message}`),
|
|
20516
|
+
// Connect/gRPC 的 resource_exhausted 与 HTTP 429 同义(限流/配额耗尽)。
|
|
20517
|
+
code === "resource_exhausted" ? { status: 429, body: parsed.error } : void 0
|
|
20518
|
+
);
|
|
20519
|
+
} catch {
|
|
20520
|
+
return new Error(`Devin Connect invalid terminal trailer: ${text}`);
|
|
20521
|
+
}
|
|
20522
|
+
}
|
|
20523
|
+
function decodeDevinResponsePayload(payload) {
|
|
20524
|
+
let offset = 0;
|
|
20525
|
+
let content = "";
|
|
20526
|
+
let reasoning = "";
|
|
20527
|
+
let finishReason = null;
|
|
20528
|
+
let usage = null;
|
|
20529
|
+
const events = [];
|
|
20530
|
+
while (offset < payload.length) {
|
|
20531
|
+
let tag = 0;
|
|
20532
|
+
let shift = 0;
|
|
20533
|
+
while (offset < payload.length) {
|
|
20534
|
+
const b = payload[offset++];
|
|
20535
|
+
tag |= (b & 127) << shift;
|
|
20536
|
+
if (!(b & 128)) break;
|
|
20537
|
+
shift += 7;
|
|
20538
|
+
}
|
|
20539
|
+
const fieldNum = tag >>> 3;
|
|
20540
|
+
const wireType = tag & 7;
|
|
20541
|
+
if (wireType === 0) {
|
|
20542
|
+
let val = 0;
|
|
20543
|
+
let s = 0;
|
|
20544
|
+
while (offset < payload.length) {
|
|
20545
|
+
const b = payload[offset++];
|
|
20546
|
+
val |= (b & 127) << s;
|
|
20547
|
+
if (!(b & 128)) break;
|
|
20548
|
+
s += 7;
|
|
20549
|
+
}
|
|
20550
|
+
if (fieldNum === 5) {
|
|
20551
|
+
finishReason = val === 10 ? "tool_calls" : val === 1 || val === 3 ? "length" : "stop";
|
|
20552
|
+
}
|
|
20553
|
+
} else if (wireType === 2) {
|
|
20554
|
+
let len = 0;
|
|
20555
|
+
let s = 0;
|
|
20556
|
+
while (offset < payload.length) {
|
|
20557
|
+
const b = payload[offset++];
|
|
20558
|
+
len |= (b & 127) << s;
|
|
20559
|
+
if (!(b & 128)) break;
|
|
20560
|
+
s += 7;
|
|
20561
|
+
}
|
|
20562
|
+
const valBytes = payload.subarray(offset, offset + len);
|
|
20563
|
+
offset += len;
|
|
20564
|
+
if (fieldNum === 3) {
|
|
20565
|
+
const text = valBytes.toString("utf8");
|
|
20566
|
+
content += text;
|
|
20567
|
+
events.push({ type: "content", text });
|
|
20568
|
+
} else if (fieldNum === 9) {
|
|
20569
|
+
const text = valBytes.toString("utf8");
|
|
20570
|
+
reasoning += text;
|
|
20571
|
+
events.push({ type: "reasoning", text });
|
|
20572
|
+
} else if (fieldNum === 6) {
|
|
20573
|
+
let nestedOffset = 0;
|
|
20574
|
+
let id;
|
|
20575
|
+
let name;
|
|
20576
|
+
let argsDelta;
|
|
20577
|
+
while (nestedOffset < valBytes.length) {
|
|
20578
|
+
let nestedTag = 0;
|
|
20579
|
+
let nestedShift = 0;
|
|
20580
|
+
while (nestedOffset < valBytes.length) {
|
|
20581
|
+
const b = valBytes[nestedOffset++];
|
|
20582
|
+
nestedTag |= (b & 127) << nestedShift;
|
|
20583
|
+
if (!(b & 128)) break;
|
|
20584
|
+
nestedShift += 7;
|
|
20585
|
+
}
|
|
20586
|
+
const nestedField = nestedTag >>> 3;
|
|
20587
|
+
const nestedWire = nestedTag & 7;
|
|
20588
|
+
if (nestedWire !== 2) break;
|
|
20589
|
+
let nestedLength = 0;
|
|
20590
|
+
let lengthShift = 0;
|
|
20591
|
+
while (nestedOffset < valBytes.length) {
|
|
20592
|
+
const b = valBytes[nestedOffset++];
|
|
20593
|
+
nestedLength |= (b & 127) << lengthShift;
|
|
20594
|
+
if (!(b & 128)) break;
|
|
20595
|
+
lengthShift += 7;
|
|
20596
|
+
}
|
|
20597
|
+
const nestedValue = valBytes.subarray(nestedOffset, nestedOffset + nestedLength);
|
|
20598
|
+
nestedOffset += nestedLength;
|
|
20599
|
+
const text = nestedValue.toString("utf8");
|
|
20600
|
+
if (nestedField === 1) id = text;
|
|
20601
|
+
else if (nestedField === 2) name = text;
|
|
20602
|
+
else if (nestedField === 3) argsDelta = (argsDelta ?? "") + text;
|
|
20603
|
+
}
|
|
20604
|
+
if (id !== void 0 && name !== void 0) {
|
|
20605
|
+
events.push({ type: "tool-call-start", id, name });
|
|
20606
|
+
}
|
|
20607
|
+
if (argsDelta !== void 0) {
|
|
20608
|
+
events.push({ type: "tool-call-args", argsDelta, ...id ? { id } : {} });
|
|
20609
|
+
}
|
|
20610
|
+
} else if (fieldNum === 7) {
|
|
20611
|
+
usage = parseDevinMetadataUsage(valBytes);
|
|
20612
|
+
}
|
|
20613
|
+
} else {
|
|
20614
|
+
break;
|
|
20615
|
+
}
|
|
20616
|
+
}
|
|
20617
|
+
return { content, reasoning, finishReason, events, usage };
|
|
20618
|
+
}
|
|
20619
|
+
function createDevinProvider(options) {
|
|
20620
|
+
const { token, model = "swe-2-max", fetchImpl = fetch, tools = [], temperature } = options;
|
|
20621
|
+
return {
|
|
20622
|
+
model,
|
|
20623
|
+
async complete(messages, opts) {
|
|
20624
|
+
const selectedModel = model;
|
|
20625
|
+
const requestPayload = buildGetChatMessageRequest({
|
|
20626
|
+
token,
|
|
20627
|
+
messages,
|
|
20628
|
+
model: selectedModel,
|
|
20629
|
+
tools,
|
|
20630
|
+
temperature
|
|
20631
|
+
});
|
|
20632
|
+
const frame = buildDevinConnectFrame(requestPayload);
|
|
20633
|
+
const response = await fetchImpl(DEVIN_CONNECT_URL, {
|
|
20634
|
+
method: "POST",
|
|
20635
|
+
headers: {
|
|
20636
|
+
"authorization": `Basic ${token}-${token}`,
|
|
20637
|
+
"content-type": "application/connect+proto",
|
|
20638
|
+
"connect-protocol-version": "1"
|
|
20639
|
+
},
|
|
20640
|
+
body: new Uint8Array(frame),
|
|
20641
|
+
signal: opts?.signal
|
|
20642
|
+
});
|
|
20643
|
+
if (!response.ok) {
|
|
20644
|
+
const errText = await response.text().catch(() => "");
|
|
20645
|
+
throw attachDevinUpstreamFailure(
|
|
20646
|
+
new Error(
|
|
20647
|
+
`Devin Connect upstream returned error ${response.status}: ${errText}`
|
|
20648
|
+
),
|
|
20649
|
+
{ status: response.status, body: errText }
|
|
20650
|
+
);
|
|
20651
|
+
}
|
|
20652
|
+
if (!response.body) {
|
|
20653
|
+
throw new Error("Devin Connect response body is null");
|
|
20654
|
+
}
|
|
20655
|
+
let text = "";
|
|
20656
|
+
let reasoning = "";
|
|
20657
|
+
let finishReason = null;
|
|
20658
|
+
let frameUsage = null;
|
|
20659
|
+
const toolCallOrder = [];
|
|
20660
|
+
const toolCallById = /* @__PURE__ */ new Map();
|
|
20661
|
+
let currentToolCallId = null;
|
|
20662
|
+
let buffer3 = Buffer.alloc(0);
|
|
20663
|
+
let sawTrailer = false;
|
|
20664
|
+
const reader = response.body.getReader();
|
|
20665
|
+
try {
|
|
20666
|
+
while (true) {
|
|
20667
|
+
const { done: done4, value } = await reader.read();
|
|
20668
|
+
if (done4) break;
|
|
20669
|
+
buffer3 = Buffer.concat([buffer3, Buffer.from(value)]);
|
|
20670
|
+
const { frames, remainder } = parseDevinConnectFrames(buffer3);
|
|
20671
|
+
buffer3 = Buffer.from(remainder);
|
|
20672
|
+
for (const f of frames) {
|
|
20673
|
+
if (sawTrailer) {
|
|
20674
|
+
throw new Error("Devin Connect received a frame after the terminal trailer");
|
|
20675
|
+
}
|
|
20676
|
+
if (f.flags & 2) {
|
|
20677
|
+
sawTrailer = true;
|
|
20678
|
+
const trailerError = parseDevinConnectTrailer(f.payload);
|
|
20679
|
+
if (trailerError) throw trailerError;
|
|
20680
|
+
continue;
|
|
20681
|
+
}
|
|
20682
|
+
const delta = decodeDevinResponsePayload(f.payload);
|
|
20683
|
+
if (delta.usage?.completion !== void 0) {
|
|
20684
|
+
frameUsage = delta.usage;
|
|
20685
|
+
}
|
|
20686
|
+
text += delta.content;
|
|
20687
|
+
reasoning += delta.reasoning;
|
|
20688
|
+
if (delta.finishReason) finishReason = delta.finishReason;
|
|
20689
|
+
for (const event of delta.events) {
|
|
20690
|
+
if (event.type === "reasoning") {
|
|
20691
|
+
opts?.onReasoningDelta?.(event.text);
|
|
20692
|
+
} else if (event.type === "content") {
|
|
20693
|
+
opts?.onTextDelta?.(event.text);
|
|
20694
|
+
} else if (event.type === "tool-call-start") {
|
|
20695
|
+
const existing = toolCallById.get(event.id);
|
|
20696
|
+
if (existing) {
|
|
20697
|
+
existing.name = event.name;
|
|
20698
|
+
} else {
|
|
20699
|
+
toolCallOrder.push(event.id);
|
|
20700
|
+
toolCallById.set(event.id, {
|
|
20701
|
+
id: event.id,
|
|
20702
|
+
name: event.name,
|
|
20703
|
+
argumentsText: ""
|
|
20704
|
+
});
|
|
20705
|
+
}
|
|
20706
|
+
currentToolCallId = event.id;
|
|
20707
|
+
} else {
|
|
20708
|
+
const targetId = event.id ?? currentToolCallId;
|
|
20709
|
+
const target = targetId ? toolCallById.get(targetId) : void 0;
|
|
20710
|
+
if (target) target.argumentsText += event.argsDelta;
|
|
20711
|
+
}
|
|
20712
|
+
}
|
|
20713
|
+
}
|
|
20714
|
+
}
|
|
20715
|
+
} finally {
|
|
20716
|
+
reader.releaseLock();
|
|
20717
|
+
}
|
|
20718
|
+
if (buffer3.length > 0) {
|
|
20719
|
+
throw new Error("Devin Connect upstream ended with an incomplete frame");
|
|
20720
|
+
}
|
|
20721
|
+
if (!sawTrailer) {
|
|
20722
|
+
throw new Error("Devin Connect upstream ended before the terminal trailer");
|
|
20723
|
+
}
|
|
20724
|
+
const toolCalls = toolCallOrder.map((id) => {
|
|
20725
|
+
const call = toolCallById.get(id);
|
|
20726
|
+
return {
|
|
20727
|
+
id: call.id,
|
|
20728
|
+
type: "function",
|
|
20729
|
+
function: {
|
|
20730
|
+
name: call.name,
|
|
20731
|
+
arguments: call.argumentsText || "{}"
|
|
20732
|
+
}
|
|
20733
|
+
};
|
|
20734
|
+
});
|
|
20735
|
+
if (!text && !reasoning && toolCalls.length === 0) {
|
|
20736
|
+
throw new Error("Devin Connect upstream completed without content or tool calls");
|
|
20737
|
+
}
|
|
20738
|
+
const usage = frameUsage ? {
|
|
20739
|
+
prompt_tokens: frameUsage.prompt + frameUsage.cacheRead,
|
|
20740
|
+
completion_tokens: frameUsage.completion ?? 0,
|
|
20741
|
+
total_tokens: frameUsage.prompt + frameUsage.cacheRead + (frameUsage.completion ?? 0) + frameUsage.cacheWrite,
|
|
20742
|
+
...frameUsage.cacheRead > 0 ? { prompt_tokens_details: { cached_tokens: frameUsage.cacheRead } } : {},
|
|
20743
|
+
...frameUsage.cacheWrite > 0 ? { cache_creation_input_tokens: frameUsage.cacheWrite } : {}
|
|
20744
|
+
} : void 0;
|
|
20745
|
+
return {
|
|
20746
|
+
content: text,
|
|
20747
|
+
model: selectedModel,
|
|
20748
|
+
provider: "devin",
|
|
20749
|
+
...usage ? { usage } : {},
|
|
20750
|
+
...reasoning ? { reasoning_content: reasoning } : {},
|
|
20751
|
+
...toolCalls.length > 0 ? { tool_calls: toolCalls } : {},
|
|
20752
|
+
// The upstream finish event wins whenever it is present. A tool call
|
|
20753
|
+
// cut off by the length limit has to stay "length" instead of being
|
|
20754
|
+
// relabelled "tool_calls", so probes/telemetry and any downstream
|
|
20755
|
+
// consumer of the final finish_reason no longer see a truncated turn
|
|
20756
|
+
// mislabelled as a normal one. localLoop keeps its own truncation
|
|
20757
|
+
// gates and excludes tool-bearing turns from them.
|
|
20758
|
+
finish_reason: finishReason ?? (toolCalls.length > 0 ? "tool_calls" : "stop"),
|
|
20759
|
+
stream_complete: true
|
|
20760
|
+
};
|
|
20761
|
+
}
|
|
20762
|
+
};
|
|
20763
|
+
}
|
|
20764
|
+
|
|
20177
20765
|
export {
|
|
20178
20766
|
Option_exports,
|
|
20179
20767
|
Duration_exports,
|
|
@@ -20226,5 +20814,7 @@ export {
|
|
|
20226
20814
|
shouldUseGeminiNativeToolRoute,
|
|
20227
20815
|
buildGeminiGenerateContentRequest,
|
|
20228
20816
|
resolveAntigravityFinishReason,
|
|
20229
|
-
fetchAntigravityCloudCodeCompletion
|
|
20817
|
+
fetchAntigravityCloudCodeCompletion,
|
|
20818
|
+
readDevinUpstreamFailure,
|
|
20819
|
+
createDevinProvider
|
|
20230
20820
|
};
|