nolo-cli 0.83.0-alpha.1 → 0.83.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/{_executeModel-TRYFRXDJ.js → _executeModel-LUNEV235.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-EKSPHWHV.js → agentDeleteCommand-2YAHAZFJ.js} +31 -30
- package/{agentEmailCommands-QD2K4YG6.js → agentEmailCommands-G6A7IRPQ.js} +67 -64
- package/{agentGrantCommands-R3VQEZJR.js → agentGrantCommands-M3XFO6EN.js} +2 -2
- package/{agentListCommands-WFBYAQKO.js → agentListCommands-KMS675GZ.js} +40 -33
- package/{agentMachineCommands-F5DKXCQP.js → agentMachineCommands-W2SMNSQ3.js} +31 -30
- package/{agentProviderCommands-65ZC2WB4.js → agentProviderCommands-GNPTL5XR.js} +87 -0
- package/{agentPullCommand-N7L2CT7L.js → agentPullCommand-O5MPVJ5E.js} +3 -3
- package/agentRecordCommands-D7BRMFNI.js +128 -0
- package/{agentRunCommand-4VMDFEQF.js → agentRunCommand-VL6MMEUB.js} +65 -62
- package/{agentRunControl-T44MESII.js → agentRunControl-AVJR4JW4.js} +2 -2
- package/{agentRuntimeLocal-FMOEMRUU.js → agentRuntimeLocal-VXZSDIGT.js} +27 -26
- package/{agentSlice-Q5XOM2PN.js → agentSlice-5YJHUO47.js} +10 -10
- package/{appDeleteCommands-AXB7XZE7.js → appDeleteCommands-32MHLR4L.js} +31 -30
- package/{appDeployCommands-ZLWI4QUC.js → appDeployCommands-WCQOUSOB.js} +31 -30
- package/{appDeployStatusCommands-2RAEYJQF.js → appDeployStatusCommands-6QKB7DYN.js} +31 -30
- package/{appGetCommands-QYUXS4W4.js → appGetCommands-SFAPP5PB.js} +31 -30
- package/{appListCommands-GQLN4J5X.js → appListCommands-EKUBDRUO.js} +31 -30
- package/{authCommand-7N2G6MXP.js → authCommand-F4EFRRX6.js} +89 -24
- package/{authCommands-ILTBI6JV.js → authCommands-RGOGCPP6.js} +4 -5
- package/builtinSkillRegistry-FUAVTRVZ.js +33 -0
- package/{chatQueueReduxAdapter-WICMMQZT.js → chatQueueReduxAdapter-PQMRR2PK.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-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-XRMBP7IW.js → chunk-45C5ER5U.js} +10 -10
- package/{chunk-DSRXPQWA.js → chunk-4OEFYTWL.js} +43 -43
- package/{chunk-6RUOYAPM.js → chunk-4S5QUMJP.js} +7 -7
- package/{chunk-GBPZKFYK.js → chunk-53HEEOTT.js} +4 -4
- package/{chunk-5Q5LYRJH.js → chunk-5FBTLSFG.js} +155 -795
- 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-KVDUCO4Q.js → chunk-6IG4XSS6.js} +16 -12
- package/{chunk-CMH2SYHX.js → chunk-6OZ36FXI.js} +2 -2
- package/{chunk-5BVAAVIF.js → chunk-6Q33GUCC.js} +1 -1
- package/{chunk-EWRS6HJ3.js → chunk-6VFARHZW.js} +625 -303
- 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-NRALD3CC.js → chunk-AEOE4Z6Q.js} +54 -10
- package/{chunk-XWNRAIUL.js → chunk-AFUORTY4.js} +6 -16
- package/chunk-BNGW5ASC.js +344 -0
- package/{chunk-SZLVDREM.js → chunk-BP4XNZRM.js} +3 -3
- package/{chunk-JZYXSXMZ.js → chunk-BTI7PJDX.js} +15 -15
- package/{chunk-2KDR4CWE.js → chunk-BYMV6QZG.js} +24 -1
- package/{chunk-GCJ3IS5M.js → chunk-DHDMC6FO.js} +175 -6
- package/{chunk-E36HZARC.js → chunk-DNCEALKX.js} +93 -17
- package/{chunk-N5KGQ5AD.js → chunk-DRGSDQBL.js} +3 -3
- package/{chunk-D6XYLSOS.js → chunk-ETI2NYVF.js} +1 -1
- package/{chunk-EXMHJN7C.js → chunk-EYAQT56M.js} +4 -3
- package/{chunk-CJCJF5XB.js → chunk-FDTR4QJ6.js} +4 -2
- package/{chunk-JPVNC5B2.js → chunk-G2O6V3HJ.js} +3 -3
- package/{chunk-WL2RKIBF.js → chunk-GEPUP7OO.js} +1 -1
- package/{chunk-PYXL2CJL.js → chunk-GPCZ7UXG.js} +1 -1
- package/{chunk-K7AG465Q.js → chunk-GQBOR3G6.js} +4 -2
- 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-DUJWWUGV.js → chunk-NA35QHCF.js} +1 -1
- package/{chunk-FNGAF7C4.js → chunk-OEVAY4J6.js} +137 -12
- package/{chunk-UJ63UXGE.js → chunk-OIVSQH2O.js} +1006 -801
- package/{chunk-LZIMZZYT.js → chunk-ORYWEJO4.js} +13 -15
- package/{chunk-LKSDMMY2.js → chunk-Q2XN3EOZ.js} +40 -30
- package/{chunk-AETZ7AD6.js → chunk-Q554LLSI.js} +1 -1
- package/{chunk-FMODTASJ.js → chunk-Q5FJJ6XI.js} +1 -7
- package/{chunk-AJHEFRGJ.js → chunk-Q67DOFOO.js} +214 -5
- package/{chunk-UZ6XXCVR.js → chunk-QDSINZM3.js} +15 -2
- package/{chunk-BHXK3KPV.js → chunk-QVKRR2SS.js} +2314 -66
- package/{chunk-BNQK6UPC.js → chunk-RFCKMYDK.js} +11 -173
- package/{chunk-YWG6EMH3.js → chunk-RG6JBBX5.js} +10 -6
- package/{chunk-QCZX4FTW.js → chunk-SH43IESU.js} +173 -15
- package/{chunk-YIR5OYHU.js → chunk-SSDAAEC2.js} +1235 -59
- package/{chunk-SPAQ4PVV.js → chunk-SV5IJK6K.js} +1 -1
- package/{chunk-BJCWNHVU.js → chunk-TOP2VXOR.js} +2 -2
- package/{chunk-4EJ5QYB5.js → chunk-UKZDAFYT.js} +1 -1
- package/{chunk-PGSKWZCB.js → chunk-UZGQNTVW.js} +1 -1
- 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-PFDKB7IZ.js → chunk-X6DN5HBD.js} +6 -6
- package/{chunk-Q7TA25PG.js → chunk-YFE4A4O7.js} +731 -90
- package/{chunk-BOYUESO7.js → chunk-Z77CRGTW.js} +1 -1
- package/{chunk-QC5LGHYP.js → chunk-ZCYXJSTU.js} +10 -5
- package/{contentThunks-A2ZG3SW6.js → contentThunks-GJV22WVZ.js} +25 -25
- package/{cooldownCommands-BSCH2W7P.js → cooldownCommands-REAWYVTY.js} +2 -2
- package/{createAgentAutomationAction-QFQQPG35.js → createAgentAutomationAction-6V25TZEO.js} +25 -25
- package/{createDialogAction-WI73R5EQ.js → createDialogAction-SX36BGSX.js} +28 -28
- package/{createPageAction-XN237WPJ.js → createPageAction-IR4BGJSI.js} +26 -26
- package/{dbSlice-GKGGFNOB.js → dbSlice-XVWBAGYN.js} +8 -8
- package/{deleteFile-LWSR674W.js → deleteFile-YG6QMJLU.js} +3 -3
- package/{dialogCommands-SFRDEMB3.js → dialogCommands-5J56DFWN.js} +35 -32
- package/{dialogSlice-56G4Q4RU.js → dialogSlice-UNX2FAPZ.js} +24 -24
- package/{docCreateCommands-OMQLZ3OW.js → docCreateCommands-KYI2DC2U.js} +32 -31
- package/{docDeleteCommands-7RCC6P23.js → docDeleteCommands-67REUSRY.js} +33 -32
- package/{docReadCommands-5FABO4UV.js → docReadCommands-HOSVSBDJ.js} +32 -31
- package/{docStore-PZSZWXX3.js → docStore-JWVG5NDO.js} +9 -9
- package/{docUpdateCommands-P5AQI6HB.js → docUpdateCommands-EMGCSMXY.js} +32 -31
- package/{fetchMessages-DRABNDPZ.js → fetchMessages-EIU7UFFK.js} +3 -4
- package/{getPricing-HRMSOF3E.js → getPricing-LUSEABA6.js} +4 -4
- package/{handleSendMessageAction-MHKC4R3Q.js → handleSendMessageAction-B75UOJKF.js} +24 -24
- package/index.js +99 -86
- package/{localDialogRead-PUQKFI73.js → localDialogRead-BTFJ4V2I.js} +2 -2
- package/{localRuntimeDb-P37ZTX55.js → localRuntimeDb-SYQGUF4U.js} +1 -1
- package/{machineCommands-VJABZGD2.js → machineCommands-GFPTOY6L.js} +64 -61
- package/{machineWsRunDispatch-5SPILS2O.js → machineWsRunDispatch-46PSZ3DJ.js} +62 -59
- 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-GMYIPMRU.js → readlineWorkspace-UFSWHFKD.js} +144 -109
- package/{removeDialogAgentAction-F5GPTALR.js → removeDialogAgentAction-IX3MN2ZO.js} +11 -11
- package/{runAgentClientLoop-U3GEPCQI.js → runAgentClientLoop-25LJ4XGV.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-FNXBNF5X.js → spaceCommands-NKJVJCQQ.js} +30 -29
- package/{streamAgentChatTurn-DAGDJH3L.js → streamAgentChatTurn-A46QFV4O.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-73VPBNX3.js → tools-TTDGRNY6.js} +43 -43
- package/tuiSummaryLlmCaller-WFRWERGK.js +127 -0
- package/{updateCommands-Y363MC3L.js → updateCommands-2M74UL7P.js} +2 -2
- package/{updateDialogTitleAction-RFQONESQ.js → updateDialogTitleAction-QJPZGF52.js} +45 -28
- package/agentRecordCommands-DAZ2FDZP.js +0 -125
- package/chunk-I42VC5KR.js +0 -15
- package/chunk-NB5SIWC4.js +0 -611
- package/chunk-NG4UT4K4.js +0 -79
- package/codingSkills-7S6523WH.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,18 +8,19 @@ import {
|
|
|
8
8
|
readSseFrames,
|
|
9
9
|
streamSseDataValues,
|
|
10
10
|
throwIfChatCompletionStreamFailed
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-ZCYXJSTU.js";
|
|
12
12
|
import {
|
|
13
13
|
DEVIN_CONNECT_URL
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-Q5FJJ6XI.js";
|
|
15
15
|
import {
|
|
16
16
|
clipToolText,
|
|
17
17
|
hasImageInRuntimeMessages,
|
|
18
|
+
resolveAgentContextWindow,
|
|
18
19
|
resolveAgentImageInputSupport,
|
|
19
20
|
resolveHistoricalToolContentCap,
|
|
20
21
|
resolveToolOutputProfile,
|
|
21
22
|
stripImagePartsFromMessages
|
|
22
|
-
} from "./chunk-
|
|
23
|
+
} from "./chunk-5H7KJX7J.js";
|
|
23
24
|
import {
|
|
24
25
|
downgradeUnparsableToolCalls,
|
|
25
26
|
hasParsableObjectArguments,
|
|
@@ -37,13 +38,15 @@ import {
|
|
|
37
38
|
TOOL_GUIDED_SECTION_ORDER,
|
|
38
39
|
buildIdentityBlock,
|
|
39
40
|
buildRuntimeGuidanceBlocks,
|
|
41
|
+
detectDispatchIntent,
|
|
42
|
+
detectDispatchIntentFromMessages,
|
|
40
43
|
estimateContextTokens,
|
|
41
44
|
hashStablePrefixContent,
|
|
42
45
|
normalizeChatCompletionsBodyForProvider,
|
|
43
46
|
requiresBareImageUrl,
|
|
44
47
|
resolveToolGuidedSections,
|
|
45
48
|
toBareImageUrlMessages
|
|
46
|
-
} from "./chunk-
|
|
49
|
+
} from "./chunk-L5UXH3B2.js";
|
|
47
50
|
import {
|
|
48
51
|
convertMessagesToResponsesInput,
|
|
49
52
|
extractReasoningFromResponseOutput,
|
|
@@ -67,16 +70,16 @@ import {
|
|
|
67
70
|
parseNoloWorkspaceToolArguments,
|
|
68
71
|
readTextStreamUpToChars,
|
|
69
72
|
resolveNoloDialogInput
|
|
70
|
-
} from "./chunk-
|
|
73
|
+
} from "./chunk-IIVGDG4I.js";
|
|
71
74
|
import {
|
|
72
75
|
getAntigravityUserAgent,
|
|
73
76
|
readAntigravityProjectId,
|
|
74
77
|
resolveAntigravityCloudCodeBaseUrl
|
|
75
|
-
} from "./chunk-
|
|
78
|
+
} from "./chunk-UZGQNTVW.js";
|
|
76
79
|
import {
|
|
77
80
|
buildProviderAuthHeaders,
|
|
78
81
|
buildProviderExecutionPlan
|
|
79
|
-
} from "./chunk-
|
|
82
|
+
} from "./chunk-6OZ36FXI.js";
|
|
80
83
|
import {
|
|
81
84
|
buildDialogFallbackTitleFromUserInput
|
|
82
85
|
} from "./chunk-2MBTWINN.js";
|
|
@@ -90,7 +93,7 @@ import {
|
|
|
90
93
|
resolveEmptyAssistantFallbackMessage,
|
|
91
94
|
resolveEmptyAssistantOutcome,
|
|
92
95
|
resolveTruncatedReasoningTailLog
|
|
93
|
-
} from "./chunk-
|
|
96
|
+
} from "./chunk-4OEFYTWL.js";
|
|
94
97
|
import {
|
|
95
98
|
COMPACTION_SUMMARY_SCHEMA_VERSION,
|
|
96
99
|
COMPACTION_SUMMARY_SYSTEM_PROMPT,
|
|
@@ -109,7 +112,7 @@ import {
|
|
|
109
112
|
resolveCompressionTriggerRatio,
|
|
110
113
|
truncateToolOutputForContext,
|
|
111
114
|
withProviderCallTimingFields
|
|
112
|
-
} from "./chunk-
|
|
115
|
+
} from "./chunk-DNCEALKX.js";
|
|
113
116
|
import {
|
|
114
117
|
estimateTokenCount
|
|
115
118
|
} from "./chunk-PSCNXBYA.js";
|
|
@@ -133,27 +136,25 @@ import {
|
|
|
133
136
|
asRecordOrEmpty
|
|
134
137
|
} from "./chunk-KX6YBIHG.js";
|
|
135
138
|
import {
|
|
139
|
+
asTrimmedNonEmptyStringArray,
|
|
136
140
|
dialogMessageKey,
|
|
137
141
|
dialogMessageRange
|
|
138
|
-
} from "./chunk-
|
|
142
|
+
} from "./chunk-VMFTFOWF.js";
|
|
139
143
|
import {
|
|
140
144
|
asOptionalFiniteNumber
|
|
141
145
|
} from "./chunk-WWC7I6TA.js";
|
|
142
|
-
import {
|
|
143
|
-
asTrimmedNonEmptyStringArray
|
|
144
|
-
} from "./chunk-I42VC5KR.js";
|
|
145
146
|
import {
|
|
146
147
|
asTrimmedLowercaseString
|
|
147
148
|
} from "./chunk-QSJ3HFEF.js";
|
|
149
|
+
import {
|
|
150
|
+
isRecord
|
|
151
|
+
} from "./chunk-KUG52IAP.js";
|
|
148
152
|
import {
|
|
149
153
|
asTrimmedString
|
|
150
154
|
} from "./chunk-3EUW3WEO.js";
|
|
151
155
|
import {
|
|
152
156
|
asOptionalPositiveFiniteNumber
|
|
153
157
|
} from "./chunk-U6VC4MU4.js";
|
|
154
|
-
import {
|
|
155
|
-
isRecord
|
|
156
|
-
} from "./chunk-KUG52IAP.js";
|
|
157
158
|
import {
|
|
158
159
|
normalizeServerOrigin
|
|
159
160
|
} from "./chunk-CF7PE763.js";
|
|
@@ -12203,8 +12204,208 @@ function summarizeToolArguments(toolName, rawArgs) {
|
|
|
12203
12204
|
);
|
|
12204
12205
|
}
|
|
12205
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
|
+
|
|
12206
12407
|
// packages/agent-runtime/leafFinalHandoff.ts
|
|
12207
|
-
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.`;
|
|
12208
12409
|
|
|
12209
12410
|
// packages/agent-runtime/contextBlockScope.ts
|
|
12210
12411
|
var isContextBlockScope = (value) => {
|
|
@@ -12426,20 +12627,33 @@ function isColdResume(history, nowMs) {
|
|
|
12426
12627
|
}
|
|
12427
12628
|
async function maybeAutoCompactLocalHistory(args2) {
|
|
12428
12629
|
const { adapter, dialogId, history } = args2;
|
|
12429
|
-
const unchanged = () => ({
|
|
12630
|
+
const unchanged = (decision) => ({
|
|
12430
12631
|
history,
|
|
12431
12632
|
compressed: false,
|
|
12432
|
-
summaryGenerated: false
|
|
12633
|
+
summaryGenerated: false,
|
|
12634
|
+
decision
|
|
12433
12635
|
});
|
|
12434
|
-
if (!dialogId
|
|
12435
|
-
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
|
+
});
|
|
12436
12647
|
}
|
|
12437
12648
|
let stored = null;
|
|
12438
12649
|
try {
|
|
12439
12650
|
stored = await adapter.loadDialogSummary(dialogId);
|
|
12440
12651
|
} catch (error) {
|
|
12441
12652
|
console.warn("[localLoop] loadDialogSummary failed:", error);
|
|
12442
|
-
return unchanged(
|
|
12653
|
+
return unchanged({
|
|
12654
|
+
outcome: "skipped",
|
|
12655
|
+
skipReason: "load-summary-failed"
|
|
12656
|
+
});
|
|
12443
12657
|
}
|
|
12444
12658
|
const bridged = toPlanCompressionMessages(history);
|
|
12445
12659
|
const validation = validateStoredSummary({ history, stored: stored ?? {} });
|
|
@@ -12475,7 +12689,21 @@ async function maybeAutoCompactLocalHistory(args2) {
|
|
|
12475
12689
|
...args2.realContextUsagePercent !== void 0 ? { realContextUsagePercent: args2.realContextUsagePercent } : {}
|
|
12476
12690
|
});
|
|
12477
12691
|
const projectExisting = () => {
|
|
12478
|
-
|
|
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);
|
|
12479
12707
|
return {
|
|
12480
12708
|
history: projectHistoryWithSummary({
|
|
12481
12709
|
history,
|
|
@@ -12483,7 +12711,12 @@ async function maybeAutoCompactLocalHistory(args2) {
|
|
|
12483
12711
|
summarizedBeforeId
|
|
12484
12712
|
}),
|
|
12485
12713
|
compressed: true,
|
|
12486
|
-
summaryGenerated: false
|
|
12714
|
+
summaryGenerated: false,
|
|
12715
|
+
decision: {
|
|
12716
|
+
outcome: "compressed",
|
|
12717
|
+
trigger: "existing-summary",
|
|
12718
|
+
...diagSnapshot
|
|
12719
|
+
}
|
|
12487
12720
|
};
|
|
12488
12721
|
};
|
|
12489
12722
|
if (!plan.shouldCompress) {
|
|
@@ -12513,7 +12746,11 @@ async function maybeAutoCompactLocalHistory(args2) {
|
|
|
12513
12746
|
);
|
|
12514
12747
|
return {
|
|
12515
12748
|
...projectExisting(),
|
|
12516
|
-
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
|
+
}
|
|
12517
12754
|
};
|
|
12518
12755
|
}
|
|
12519
12756
|
await adapter.saveDialogSummary({
|
|
@@ -12550,198 +12787,27 @@ async function maybeAutoCompactLocalHistory(args2) {
|
|
|
12550
12787
|
beforeTokens: metrics.previousSummaryTokens + metrics.compressedTokens,
|
|
12551
12788
|
afterTokens: metrics.newSummaryTokens + metrics.retainedTokens,
|
|
12552
12789
|
...result4.usage ? { usage: result4.usage } : {},
|
|
12553
|
-
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
|
+
}
|
|
12554
12801
|
};
|
|
12555
12802
|
} catch (error) {
|
|
12556
12803
|
console.warn("[localLoop] auto-compaction failed:", error);
|
|
12557
12804
|
const failureMessage = error instanceof Error && error.message ? error.message.slice(0, 200) : String(error).slice(0, 200);
|
|
12558
|
-
return {
|
|
12559
|
-
|
|
12560
|
-
|
|
12561
|
-
|
|
12562
|
-
|
|
12563
|
-
var DEFAULT_MAX_CONSECUTIVE_IDENTICAL_ROUNDS = 5;
|
|
12564
|
-
var DEFAULT_MAX_CONSECUTIVE_STAGNANT_TOOL_ROUNDS = 8;
|
|
12565
|
-
function sortJsonKeys(obj) {
|
|
12566
|
-
if (obj === null || typeof obj !== "object") return obj;
|
|
12567
|
-
if (Array.isArray(obj)) return obj.map(sortJsonKeys);
|
|
12568
|
-
const sorted = {};
|
|
12569
|
-
for (const key of Object.keys(obj).sort()) {
|
|
12570
|
-
sorted[key] = sortJsonKeys(obj[key]);
|
|
12571
|
-
}
|
|
12572
|
-
return sorted;
|
|
12573
|
-
}
|
|
12574
|
-
function normalizeToolArguments(rawArgs) {
|
|
12575
|
-
if (typeof rawArgs !== "string") {
|
|
12576
|
-
try {
|
|
12577
|
-
return JSON.stringify(sortJsonKeys(rawArgs ?? ""));
|
|
12578
|
-
} catch {
|
|
12579
|
-
return String(rawArgs ?? "");
|
|
12580
|
-
}
|
|
12581
|
-
}
|
|
12582
|
-
const trimmed = rawArgs.trim();
|
|
12583
|
-
if (!trimmed) return "";
|
|
12584
|
-
try {
|
|
12585
|
-
const parsed = JSON.parse(trimmed);
|
|
12586
|
-
return JSON.stringify(sortJsonKeys(parsed));
|
|
12587
|
-
} catch {
|
|
12588
|
-
return trimmed;
|
|
12589
|
-
}
|
|
12590
|
-
}
|
|
12591
|
-
function extractNormalizedContentText(content) {
|
|
12592
|
-
if (typeof content === "string") return content.trim();
|
|
12593
|
-
if (!Array.isArray(content)) return "";
|
|
12594
|
-
return content.map((part) => {
|
|
12595
|
-
if (part?.type === "text") return String(part.text ?? "").trim();
|
|
12596
|
-
if (part?.type === "image_url") return `[img:${part.image_url?.url ?? ""}]`;
|
|
12597
|
-
return "";
|
|
12598
|
-
}).filter(Boolean).join("\n");
|
|
12599
|
-
}
|
|
12600
|
-
function buildToolCallsSignature(toolCalls) {
|
|
12601
|
-
if (!toolCalls || toolCalls.length === 0) return "";
|
|
12602
|
-
return toolCalls.map(
|
|
12603
|
-
(tc) => `${tc.function?.name ?? ""}:${normalizeToolArguments(tc.function?.arguments)}`
|
|
12604
|
-
).join(";;");
|
|
12605
|
-
}
|
|
12606
|
-
function buildAssistantActionFingerprint(result4) {
|
|
12607
|
-
const content = extractNormalizedContentText(result4.content);
|
|
12608
|
-
const reasoning = typeof result4.reasoning_content === "string" ? result4.reasoning_content.trim() : "";
|
|
12609
|
-
let toolCallsSig = buildToolCallsSignature(result4.tool_calls);
|
|
12610
|
-
let hasToolCalls = Array.isArray(result4.tool_calls) && result4.tool_calls.length > 0;
|
|
12611
|
-
if (!toolCallsSig && Array.isArray(result4.output) && result4.output.length > 0) {
|
|
12612
|
-
const blocksToolCalls = result4.output.filter(
|
|
12613
|
-
(b) => b.type === "toolCall"
|
|
12614
|
-
).map((b) => b.toolCall);
|
|
12615
|
-
if (blocksToolCalls.length > 0) {
|
|
12616
|
-
toolCallsSig = buildToolCallsSignature(blocksToolCalls);
|
|
12617
|
-
hasToolCalls = true;
|
|
12618
|
-
}
|
|
12619
|
-
}
|
|
12620
|
-
const hasNonEmptyText = content.length > 0 || reasoning.length > 0;
|
|
12621
|
-
const fingerprint = `${content}##${reasoning}##${toolCallsSig}`;
|
|
12622
|
-
return {
|
|
12623
|
-
fingerprint,
|
|
12624
|
-
hasNonEmptyText,
|
|
12625
|
-
hasToolCalls,
|
|
12626
|
-
toolCallsSignature: toolCallsSig
|
|
12627
|
-
};
|
|
12628
|
-
}
|
|
12629
|
-
function buildToolResultsSignature(toolExecutions) {
|
|
12630
|
-
if (toolExecutions.length === 0) return "";
|
|
12631
|
-
return toolExecutions.map((exec) => {
|
|
12632
|
-
const contentStr = typeof exec.content === "string" ? exec.content.trim() : "";
|
|
12633
|
-
const metaStr = exec.metadata ? JSON.stringify(sortJsonKeys(exec.metadata)) : "";
|
|
12634
|
-
return `${exec.toolName}:${contentStr}:${metaStr}`;
|
|
12635
|
-
}).join(";;");
|
|
12636
|
-
}
|
|
12637
|
-
function resolveProgressGuardConfig(options, env = typeof process !== "undefined" ? process.env : {}) {
|
|
12638
|
-
const envDisabled = env.NOLO_LOOP_PROGRESS_GUARD_DISABLED === "true" || env.NOLO_LOOP_PROGRESS_GUARD_DISABLED === "1";
|
|
12639
|
-
const disabled = options?.disabled ?? envDisabled ?? false;
|
|
12640
|
-
const parsePositiveInt = (val, fallback) => {
|
|
12641
|
-
if (typeof val === "number" && Number.isFinite(val) && val >= 1) {
|
|
12642
|
-
return Math.floor(val);
|
|
12643
|
-
}
|
|
12644
|
-
if (typeof val === "string") {
|
|
12645
|
-
const parsed = parseInt(val, 10);
|
|
12646
|
-
if (Number.isFinite(parsed) && parsed >= 1) {
|
|
12647
|
-
return parsed;
|
|
12648
|
-
}
|
|
12649
|
-
}
|
|
12650
|
-
return fallback;
|
|
12651
|
-
};
|
|
12652
|
-
const maxConsecutiveIdenticalRounds = parsePositiveInt(
|
|
12653
|
-
options?.maxConsecutiveIdenticalRounds ?? env.NOLO_LOOP_MAX_IDENTICAL_ROUNDS,
|
|
12654
|
-
DEFAULT_MAX_CONSECUTIVE_IDENTICAL_ROUNDS
|
|
12655
|
-
);
|
|
12656
|
-
const maxConsecutiveStagnantToolRounds = parsePositiveInt(
|
|
12657
|
-
options?.maxConsecutiveStagnantToolRounds ?? env.NOLO_LOOP_MAX_STAGNANT_TOOL_ROUNDS,
|
|
12658
|
-
DEFAULT_MAX_CONSECUTIVE_STAGNANT_TOOL_ROUNDS
|
|
12659
|
-
);
|
|
12660
|
-
return {
|
|
12661
|
-
disabled,
|
|
12662
|
-
maxConsecutiveIdenticalRounds,
|
|
12663
|
-
maxConsecutiveStagnantToolRounds
|
|
12664
|
-
};
|
|
12665
|
-
}
|
|
12666
|
-
var LocalLoopProgressGuard = class {
|
|
12667
|
-
config;
|
|
12668
|
-
lastAssistantFingerprint = null;
|
|
12669
|
-
lastAssistantHasNonEmptyText = false;
|
|
12670
|
-
consecutiveIdenticalCount = 0;
|
|
12671
|
-
lastToolCallsSignature = null;
|
|
12672
|
-
lastToolResultsSignature = null;
|
|
12673
|
-
consecutiveStagnantToolCount = 0;
|
|
12674
|
-
constructor(config, env) {
|
|
12675
|
-
this.config = resolveProgressGuardConfig(config, env);
|
|
12676
|
-
}
|
|
12677
|
-
/**
|
|
12678
|
-
* 在 LLM 返回 assistant 响应后调用。
|
|
12679
|
-
* 仅在纯文本/无工具调用且实质文本相同达到阈值时直接熔断;
|
|
12680
|
-
* 若存在工具调用,则不在此处熔断,留待工具执行后结合工具结果综合判定。
|
|
12681
|
-
*/
|
|
12682
|
-
observeAssistantResponse(result4) {
|
|
12683
|
-
if (this.config.disabled) return { action: "continue" };
|
|
12684
|
-
const { fingerprint, hasNonEmptyText, hasToolCalls } = buildAssistantActionFingerprint(result4);
|
|
12685
|
-
if (this.lastAssistantFingerprint !== null && this.lastAssistantFingerprint === fingerprint) {
|
|
12686
|
-
this.consecutiveIdenticalCount += 1;
|
|
12687
|
-
if (!hasToolCalls && hasNonEmptyText && this.consecutiveIdenticalCount >= this.config.maxConsecutiveIdenticalRounds) {
|
|
12688
|
-
return {
|
|
12689
|
-
action: "stall",
|
|
12690
|
-
reason: "repetition_loop",
|
|
12691
|
-
detail: `Consecutive identical text-only assistant response for ${this.consecutiveIdenticalCount} rounds.`,
|
|
12692
|
-
consecutiveRounds: this.consecutiveIdenticalCount
|
|
12693
|
-
};
|
|
12694
|
-
}
|
|
12695
|
-
} else {
|
|
12696
|
-
this.lastAssistantFingerprint = fingerprint;
|
|
12697
|
-
this.lastAssistantHasNonEmptyText = hasNonEmptyText;
|
|
12698
|
-
this.consecutiveIdenticalCount = 1;
|
|
12699
|
-
}
|
|
12700
|
-
return { action: "continue" };
|
|
12701
|
-
}
|
|
12702
|
-
/**
|
|
12703
|
-
* 在本轮所有工具执行完毕后调用,检查是否陷入停滞死循环。
|
|
12704
|
-
* 只有当工具返回内容与元数据完全无变化时才计入无进展 streak;
|
|
12705
|
-
* 一旦工具结果发生变化(如合法轮询状态推进),立即重置 identical streak,确保绝不误杀正常长任务。
|
|
12706
|
-
*/
|
|
12707
|
-
observeToolExecution(toolCalls, toolResults) {
|
|
12708
|
-
if (this.config.disabled) return { action: "continue" };
|
|
12709
|
-
if (!toolCalls || toolCalls.length === 0) return { action: "continue" };
|
|
12710
|
-
const toolCallsSig = buildToolCallsSignature(toolCalls);
|
|
12711
|
-
const toolResultsSig = buildToolResultsSignature(toolResults);
|
|
12712
|
-
const toolCallsUnchanged = this.lastToolCallsSignature !== null && this.lastToolCallsSignature === toolCallsSig;
|
|
12713
|
-
const toolResultsUnchanged = this.lastToolResultsSignature !== null && this.lastToolResultsSignature === toolResultsSig;
|
|
12714
|
-
if (toolCallsUnchanged && toolResultsUnchanged) {
|
|
12715
|
-
this.consecutiveStagnantToolCount += 1;
|
|
12716
|
-
if (this.consecutiveIdenticalCount >= this.config.maxConsecutiveIdenticalRounds) {
|
|
12717
|
-
return {
|
|
12718
|
-
action: "stall",
|
|
12719
|
-
reason: "repetition_loop",
|
|
12720
|
-
detail: `Consecutive identical assistant response with unchanged tool results for ${this.consecutiveIdenticalCount} rounds.`,
|
|
12721
|
-
consecutiveRounds: this.consecutiveIdenticalCount
|
|
12722
|
-
};
|
|
12723
|
-
}
|
|
12724
|
-
if (this.consecutiveStagnantToolCount >= this.config.maxConsecutiveStagnantToolRounds) {
|
|
12725
|
-
return {
|
|
12726
|
-
action: "stall",
|
|
12727
|
-
reason: "stagnant_tool_calls",
|
|
12728
|
-
detail: `Consecutive stagnant tool calls with unchanged results for ${this.consecutiveStagnantToolCount} rounds.`,
|
|
12729
|
-
consecutiveRounds: this.consecutiveStagnantToolCount
|
|
12730
|
-
};
|
|
12731
|
-
}
|
|
12732
|
-
} else {
|
|
12733
|
-
this.lastToolCallsSignature = toolCallsSig;
|
|
12734
|
-
this.lastToolResultsSignature = toolResultsSig;
|
|
12735
|
-
this.consecutiveStagnantToolCount = 1;
|
|
12736
|
-
if (!toolResultsUnchanged) {
|
|
12737
|
-
this.consecutiveIdenticalCount = 1;
|
|
12738
|
-
}
|
|
12739
|
-
}
|
|
12740
|
-
return { action: "continue" };
|
|
12805
|
+
return {
|
|
12806
|
+
...projectExisting(),
|
|
12807
|
+
failureMessage,
|
|
12808
|
+
decision: { outcome: "failed", detail: failureMessage }
|
|
12809
|
+
};
|
|
12741
12810
|
}
|
|
12742
|
-
};
|
|
12743
|
-
function createLocalLoopProgressGuard(config, env) {
|
|
12744
|
-
return new LocalLoopProgressGuard(config, env);
|
|
12745
12811
|
}
|
|
12746
12812
|
|
|
12747
12813
|
// packages/agent-runtime/localLoop.ts
|
|
@@ -13049,10 +13115,10 @@ var TOOL_METADATA_KEYS = [
|
|
|
13049
13115
|
"pasteId",
|
|
13050
13116
|
"source"
|
|
13051
13117
|
];
|
|
13052
|
-
function trimHistoryToContextBudget(history, model) {
|
|
13118
|
+
function trimHistoryToContextBudget(history, model, contextWindowOverride) {
|
|
13053
13119
|
if (history.length === 0) return { history, droppedCount: 0 };
|
|
13054
13120
|
const { rawMessageBudget } = planContextUsage({
|
|
13055
|
-
contextWindow: getModelContextWindow(model ?? ""),
|
|
13121
|
+
contextWindow: contextWindowOverride ?? getModelContextWindow(model ?? ""),
|
|
13056
13122
|
summaryTokens: 0,
|
|
13057
13123
|
// localLoop 没有 web 端的负载分档器;medium 是中性默认值,
|
|
13058
13124
|
// 不为了省几个 token 在这里复制一份分类逻辑。
|
|
@@ -13515,7 +13581,14 @@ async function runLocalAgentTurn(input) {
|
|
|
13515
13581
|
agentConfig.exposedToolNames ?? agentConfig.toolNames ?? []
|
|
13516
13582
|
);
|
|
13517
13583
|
const guidanceBlocks = buildRuntimeGuidanceBlocks(agentTools);
|
|
13518
|
-
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
|
+
});
|
|
13519
13592
|
const guidanceScopes = [
|
|
13520
13593
|
...input.userLanguage?.trim() ? [buildUserResponseLanguageContext({ language: input.userLanguage })] : [],
|
|
13521
13594
|
guidanceBlocks.startupProtocol,
|
|
@@ -13543,7 +13616,7 @@ async function runLocalAgentTurn(input) {
|
|
|
13543
13616
|
}
|
|
13544
13617
|
return resolvedProvider;
|
|
13545
13618
|
};
|
|
13546
|
-
const contextWindow =
|
|
13619
|
+
const contextWindow = resolveAgentContextWindow(agentConfig);
|
|
13547
13620
|
const compressionTriggerRatio = resolveCompressionTriggerRatio(contextWindow);
|
|
13548
13621
|
let realContextUsagePercent;
|
|
13549
13622
|
if (input.continueDialogId && typeof input.adapter.loadLastContextUsage === "function") {
|
|
@@ -13564,19 +13637,29 @@ async function runLocalAgentTurn(input) {
|
|
|
13564
13637
|
}
|
|
13565
13638
|
let compactionUsage;
|
|
13566
13639
|
const emitCompactionObservation = (compacted) => {
|
|
13567
|
-
|
|
13568
|
-
|
|
13569
|
-
|
|
13570
|
-
|
|
13571
|
-
|
|
13572
|
-
summaryGenerated: compacted.summaryGenerated,
|
|
13573
|
-
compressed: compacted.compressed,
|
|
13574
|
-
...compacted.failureMessage ? { failed: true, detail: compacted.failureMessage } : {},
|
|
13575
|
-
...compacted.beforeTokens !== void 0 ? { beforeTokens: compacted.beforeTokens } : {},
|
|
13576
|
-
...compacted.afterTokens !== void 0 ? { afterTokens: compacted.afterTokens } : {},
|
|
13577
|
-
...compacted.savedTokens !== void 0 ? { savedTokens: compacted.savedTokens } : {}
|
|
13578
|
-
});
|
|
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;
|
|
13579
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
|
+
});
|
|
13580
13663
|
};
|
|
13581
13664
|
try {
|
|
13582
13665
|
const compacted = await maybeAutoCompactLocalHistory({
|
|
@@ -13585,6 +13668,7 @@ async function runLocalAgentTurn(input) {
|
|
|
13585
13668
|
history,
|
|
13586
13669
|
model: agentConfig.model,
|
|
13587
13670
|
resolveProvider: resolveProviderOnce,
|
|
13671
|
+
contextWindow,
|
|
13588
13672
|
realContextUsagePercent
|
|
13589
13673
|
});
|
|
13590
13674
|
history = compacted.history;
|
|
@@ -13594,7 +13678,7 @@ async function runLocalAgentTurn(input) {
|
|
|
13594
13678
|
console.warn("[localLoop] auto-compaction unexpected error:", error);
|
|
13595
13679
|
}
|
|
13596
13680
|
loopTimingMark("maybeAutoCompactLocalHistory", 0);
|
|
13597
|
-
const trimmedHistory = trimHistoryToContextBudget(history, agentConfig.model);
|
|
13681
|
+
const trimmedHistory = trimHistoryToContextBudget(history, agentConfig.model, contextWindow);
|
|
13598
13682
|
if (trimmedHistory.droppedCount > 0) {
|
|
13599
13683
|
history = trimmedHistory.history;
|
|
13600
13684
|
}
|
|
@@ -13656,17 +13740,26 @@ async function runLocalAgentTurn(input) {
|
|
|
13656
13740
|
let skipFinalAppend = false;
|
|
13657
13741
|
let partialContent = "";
|
|
13658
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;
|
|
13659
13753
|
const maybeCompactInLoop = async () => {
|
|
13660
|
-
|
|
13661
|
-
|
|
13662
|
-
|
|
13663
|
-
|
|
13664
|
-
|
|
13665
|
-
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
|
+
}
|
|
13666
13759
|
try {
|
|
13667
13760
|
const compacted = await maybeAutoCompactLocalHistory({
|
|
13668
|
-
adapter:
|
|
13669
|
-
dialogId:
|
|
13761
|
+
adapter: compactionAdapter,
|
|
13762
|
+
dialogId: compactionDialogId,
|
|
13670
13763
|
// canonical 坐标:store 全量历史 + 本轮消息的「持久化形态」
|
|
13671
13764
|
// (applyPersistedTurnInput 会把首条 user 消息换成 paste 展开形态)。
|
|
13672
13765
|
// 锚点与 sourceHash 都必须按持久化形态计算——否则下轮从 store
|
|
@@ -13681,7 +13774,8 @@ async function runLocalAgentTurn(input) {
|
|
|
13681
13774
|
],
|
|
13682
13775
|
model: agentConfig.model,
|
|
13683
13776
|
resolveProvider: resolveProviderOnce,
|
|
13684
|
-
|
|
13777
|
+
contextWindow,
|
|
13778
|
+
...ratio !== void 0 ? { realContextUsagePercent: ratio } : {}
|
|
13685
13779
|
});
|
|
13686
13780
|
if (compacted.usage) {
|
|
13687
13781
|
compactionUsage = addOutOfBandUsage(compactionUsage, compacted.usage);
|
|
@@ -13949,6 +14043,7 @@ ${reasoningTailLog}
|
|
|
13949
14043
|
const startedAt = Date.now();
|
|
13950
14044
|
loopTimingMark("toolCallStart", round);
|
|
13951
14045
|
const argumentsPreview = summarizeToolArguments(toolName, toolCall.function.arguments);
|
|
14046
|
+
const argumentsFingerprint = buildToolArgumentsFingerprint(toolCall.function.arguments);
|
|
13952
14047
|
emitLoopEvent(
|
|
13953
14048
|
observationBoundary,
|
|
13954
14049
|
{
|
|
@@ -13957,7 +14052,8 @@ ${reasoningTailLog}
|
|
|
13957
14052
|
toolCallId: toolCall.id,
|
|
13958
14053
|
toolName,
|
|
13959
14054
|
atMs: startedAt,
|
|
13960
|
-
...argumentsPreview ? { argumentsPreview } : {}
|
|
14055
|
+
...argumentsPreview ? { argumentsPreview } : {},
|
|
14056
|
+
...argumentsFingerprint ? { argumentsFingerprint } : {}
|
|
13961
14057
|
},
|
|
13962
14058
|
{
|
|
13963
14059
|
type: "tool-call",
|
|
@@ -15571,11 +15667,12 @@ var DEFAULT_LOCAL_TOOLS = /* @__PURE__ */ new Set([
|
|
|
15571
15667
|
"execShell",
|
|
15572
15668
|
"launchProcess",
|
|
15573
15669
|
"listProcesses",
|
|
15574
|
-
// ProcessTask follow-up tools
|
|
15575
|
-
//
|
|
15576
|
-
//
|
|
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.
|
|
15577
15675
|
"taskWait",
|
|
15578
|
-
"taskLogs",
|
|
15579
15676
|
"taskStop",
|
|
15580
15677
|
// Scheduling tools: forking/observing sub-agents is a declared capability
|
|
15581
15678
|
// of capable agents, and the blast radius is strictly narrower than
|
|
@@ -17573,7 +17670,6 @@ var WORKSPACE_TOOL_NAMES = [
|
|
|
17573
17670
|
"launchProcess",
|
|
17574
17671
|
"listProcesses",
|
|
17575
17672
|
"taskWait",
|
|
17576
|
-
"taskLogs",
|
|
17577
17673
|
"taskStop",
|
|
17578
17674
|
"openDesktopPreview"
|
|
17579
17675
|
];
|
|
@@ -17582,7 +17678,6 @@ var SHELL_TOOL_NAMES = [
|
|
|
17582
17678
|
"launchProcess",
|
|
17583
17679
|
"listProcesses",
|
|
17584
17680
|
"taskWait",
|
|
17585
|
-
"taskLogs",
|
|
17586
17681
|
"taskStop"
|
|
17587
17682
|
];
|
|
17588
17683
|
var WORKSPACE_TOOL_NAME_SET = new Set(WORKSPACE_TOOL_NAMES);
|
|
@@ -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",
|
|
@@ -17914,7 +17985,6 @@ function buildWorkspaceToolDefinition(toolName) {
|
|
|
17914
17985
|
if (toolName === "openDesktopPreview") return buildOpenDesktopPreviewTool();
|
|
17915
17986
|
if (toolName === "listProcesses") return buildListProcessesTool();
|
|
17916
17987
|
if (toolName === "taskWait") return buildTaskWaitTool();
|
|
17917
|
-
if (toolName === "taskLogs") return buildTaskLogsTool();
|
|
17918
17988
|
if (toolName === "taskStop") return buildTaskStopTool();
|
|
17919
17989
|
return null;
|
|
17920
17990
|
}
|
|
@@ -19381,15 +19451,23 @@ function buildLoadSkillExecutor(args2) {
|
|
|
19381
19451
|
const { resolveSkillByName } = await import("./skillDiscovery-CYUCJMAG.js");
|
|
19382
19452
|
const resolved = resolveSkillByName(args2.cwd, name);
|
|
19383
19453
|
if (!resolved) {
|
|
19384
|
-
const {
|
|
19385
|
-
const
|
|
19386
|
-
if (
|
|
19387
|
-
const body = buildCodingSkillContentBySlug(builtinSlug);
|
|
19454
|
+
const { resolveBuiltinSkillByName } = await import("./builtinSkillRegistry-FUAVTRVZ.js");
|
|
19455
|
+
const builtin = resolveBuiltinSkillByName(name);
|
|
19456
|
+
if (builtin) {
|
|
19388
19457
|
return {
|
|
19389
19458
|
content: `Skill "${name}" loaded inline. Follow its instructions.
|
|
19390
19459
|
|
|
19391
|
-
${
|
|
19392
|
-
|
|
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
|
+
}
|
|
19393
19471
|
};
|
|
19394
19472
|
}
|
|
19395
19473
|
return {
|
|
@@ -20221,11 +20299,33 @@ function encodeDevinClientMetadata(token) {
|
|
|
20221
20299
|
]);
|
|
20222
20300
|
}
|
|
20223
20301
|
function encodeDevinChatMessage(msg) {
|
|
20224
|
-
const source = msg.role === "assistant" ? 2 : 1;
|
|
20302
|
+
const source = msg.role === "assistant" ? 2 : msg.role === "tool" ? 4 : 1;
|
|
20225
20303
|
return Buffer.concat([
|
|
20226
20304
|
writeStringField(1, randomUUID2()),
|
|
20227
20305
|
writeVarint(2, source),
|
|
20228
|
-
writeStringField(3, msg.text)
|
|
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))
|
|
20229
20329
|
]);
|
|
20230
20330
|
}
|
|
20231
20331
|
function writeFixed64Field(fieldNum, val) {
|
|
@@ -20242,20 +20342,21 @@ function writeFixed64Field(fieldNum, val) {
|
|
|
20242
20342
|
return Buffer.concat([Buffer.from(tagBytes), b]);
|
|
20243
20343
|
}
|
|
20244
20344
|
function buildCompletionConfig(params) {
|
|
20245
|
-
const maxTokens = params?.maxTokens ??
|
|
20246
|
-
const
|
|
20345
|
+
const maxTokens = params?.maxTokens ?? 128e3;
|
|
20346
|
+
const maxNewlines = params?.maxNewlines ?? 400;
|
|
20347
|
+
const temp = params?.temperature ?? 1;
|
|
20247
20348
|
const topP = params?.topP ?? 0.95;
|
|
20248
20349
|
return Buffer.concat([
|
|
20249
20350
|
writeVarint(1, 1),
|
|
20250
20351
|
writeVarint(2, maxTokens),
|
|
20251
|
-
writeVarint(3,
|
|
20352
|
+
writeVarint(3, maxNewlines),
|
|
20252
20353
|
writeFixed64Field(5, temp),
|
|
20253
20354
|
writeVarint(7, 40),
|
|
20254
20355
|
writeFixed64Field(8, topP)
|
|
20255
20356
|
]);
|
|
20256
20357
|
}
|
|
20257
20358
|
function buildGetChatMessageRequest(params) {
|
|
20258
|
-
const { token, messages, model } = params;
|
|
20359
|
+
const { token, messages, model, tools = [], temperature } = params;
|
|
20259
20360
|
const metadata = encodeDevinClientMetadata(token);
|
|
20260
20361
|
let systemPrompt = "";
|
|
20261
20362
|
const filteredMessages = [];
|
|
@@ -20265,14 +20366,19 @@ function buildGetChatMessageRequest(params) {
|
|
|
20265
20366
|
systemPrompt = systemPrompt ? `${systemPrompt}
|
|
20266
20367
|
|
|
20267
20368
|
${text}` : text;
|
|
20268
|
-
} else if (m.role === "user" || m.role === "assistant") {
|
|
20269
|
-
filteredMessages.push({
|
|
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
|
+
});
|
|
20270
20376
|
}
|
|
20271
20377
|
}
|
|
20272
20378
|
const coalesced = [];
|
|
20273
20379
|
for (const item of filteredMessages) {
|
|
20274
20380
|
const last = coalesced[coalesced.length - 1];
|
|
20275
|
-
if (last && last.role === item.role) {
|
|
20381
|
+
if (last && last.role === item.role && item.role !== "tool" && !last.toolCalls?.length && !item.toolCalls?.length) {
|
|
20276
20382
|
last.text = `${last.text}
|
|
20277
20383
|
|
|
20278
20384
|
${item.text}`;
|
|
@@ -20281,7 +20387,7 @@ ${item.text}`;
|
|
|
20281
20387
|
}
|
|
20282
20388
|
}
|
|
20283
20389
|
const chatMessageBuffers = coalesced.map((m) => encodeDevinChatMessage(m));
|
|
20284
|
-
const completionConfig = buildCompletionConfig();
|
|
20390
|
+
const completionConfig = buildCompletionConfig({ temperature });
|
|
20285
20391
|
const modelConfig = Buffer.concat([
|
|
20286
20392
|
writeStringField(1, randomUUID2()),
|
|
20287
20393
|
writeVarint(2, 1),
|
|
@@ -20293,6 +20399,7 @@ ${item.text}`;
|
|
|
20293
20399
|
...chatMessageBuffers.map((b) => writeMessageField(3, b)),
|
|
20294
20400
|
writeVarint(7, 5),
|
|
20295
20401
|
writeMessageField(8, completionConfig),
|
|
20402
|
+
...tools.map((tool) => writeMessageField(10, encodeDevinToolDefinition(tool))),
|
|
20296
20403
|
writeMessageField(15, modelConfig),
|
|
20297
20404
|
writeStringField(16, randomUUID2()),
|
|
20298
20405
|
writeVarint(20, 1),
|
|
@@ -20323,11 +20430,103 @@ function parseDevinConnectFrames(buffer3) {
|
|
|
20323
20430
|
remainder: buffer3.subarray(offset)
|
|
20324
20431
|
};
|
|
20325
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
|
+
}
|
|
20326
20523
|
function decodeDevinResponsePayload(payload) {
|
|
20327
20524
|
let offset = 0;
|
|
20328
20525
|
let content = "";
|
|
20329
20526
|
let reasoning = "";
|
|
20330
20527
|
let finishReason = null;
|
|
20528
|
+
let usage = null;
|
|
20529
|
+
const events = [];
|
|
20331
20530
|
while (offset < payload.length) {
|
|
20332
20531
|
let tag = 0;
|
|
20333
20532
|
let shift = 0;
|
|
@@ -20349,7 +20548,7 @@ function decodeDevinResponsePayload(payload) {
|
|
|
20349
20548
|
s += 7;
|
|
20350
20549
|
}
|
|
20351
20550
|
if (fieldNum === 5) {
|
|
20352
|
-
finishReason = val ===
|
|
20551
|
+
finishReason = val === 10 ? "tool_calls" : val === 1 || val === 3 ? "length" : "stop";
|
|
20353
20552
|
}
|
|
20354
20553
|
} else if (wireType === 2) {
|
|
20355
20554
|
let len = 0;
|
|
@@ -20363,18 +20562,62 @@ function decodeDevinResponsePayload(payload) {
|
|
|
20363
20562
|
const valBytes = payload.subarray(offset, offset + len);
|
|
20364
20563
|
offset += len;
|
|
20365
20564
|
if (fieldNum === 3) {
|
|
20366
|
-
|
|
20565
|
+
const text = valBytes.toString("utf8");
|
|
20566
|
+
content += text;
|
|
20567
|
+
events.push({ type: "content", text });
|
|
20367
20568
|
} else if (fieldNum === 9) {
|
|
20368
|
-
|
|
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);
|
|
20369
20612
|
}
|
|
20370
20613
|
} else {
|
|
20371
20614
|
break;
|
|
20372
20615
|
}
|
|
20373
20616
|
}
|
|
20374
|
-
return { content, reasoning, finishReason };
|
|
20617
|
+
return { content, reasoning, finishReason, events, usage };
|
|
20375
20618
|
}
|
|
20376
20619
|
function createDevinProvider(options) {
|
|
20377
|
-
const { token, model = "swe-2", fetchImpl = fetch } = options;
|
|
20620
|
+
const { token, model = "swe-2-max", fetchImpl = fetch, tools = [], temperature } = options;
|
|
20378
20621
|
return {
|
|
20379
20622
|
model,
|
|
20380
20623
|
async complete(messages, opts) {
|
|
@@ -20382,7 +20625,9 @@ function createDevinProvider(options) {
|
|
|
20382
20625
|
const requestPayload = buildGetChatMessageRequest({
|
|
20383
20626
|
token,
|
|
20384
20627
|
messages,
|
|
20385
|
-
model: selectedModel
|
|
20628
|
+
model: selectedModel,
|
|
20629
|
+
tools,
|
|
20630
|
+
temperature
|
|
20386
20631
|
});
|
|
20387
20632
|
const frame = buildDevinConnectFrame(requestPayload);
|
|
20388
20633
|
const response = await fetchImpl(DEVIN_CONNECT_URL, {
|
|
@@ -20397,8 +20642,11 @@ function createDevinProvider(options) {
|
|
|
20397
20642
|
});
|
|
20398
20643
|
if (!response.ok) {
|
|
20399
20644
|
const errText = await response.text().catch(() => "");
|
|
20400
|
-
throw
|
|
20401
|
-
|
|
20645
|
+
throw attachDevinUpstreamFailure(
|
|
20646
|
+
new Error(
|
|
20647
|
+
`Devin Connect upstream returned error ${response.status}: ${errText}`
|
|
20648
|
+
),
|
|
20649
|
+
{ status: response.status, body: errText }
|
|
20402
20650
|
);
|
|
20403
20651
|
}
|
|
20404
20652
|
if (!response.body) {
|
|
@@ -20406,7 +20654,13 @@ function createDevinProvider(options) {
|
|
|
20406
20654
|
}
|
|
20407
20655
|
let text = "";
|
|
20408
20656
|
let reasoning = "";
|
|
20657
|
+
let finishReason = null;
|
|
20658
|
+
let frameUsage = null;
|
|
20659
|
+
const toolCallOrder = [];
|
|
20660
|
+
const toolCallById = /* @__PURE__ */ new Map();
|
|
20661
|
+
let currentToolCallId = null;
|
|
20409
20662
|
let buffer3 = Buffer.alloc(0);
|
|
20663
|
+
let sawTrailer = false;
|
|
20410
20664
|
const reader = response.body.getReader();
|
|
20411
20665
|
try {
|
|
20412
20666
|
while (true) {
|
|
@@ -20416,26 +20670,93 @@ function createDevinProvider(options) {
|
|
|
20416
20670
|
const { frames, remainder } = parseDevinConnectFrames(buffer3);
|
|
20417
20671
|
buffer3 = Buffer.from(remainder);
|
|
20418
20672
|
for (const f of frames) {
|
|
20419
|
-
if (
|
|
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
|
+
}
|
|
20420
20682
|
const delta = decodeDevinResponsePayload(f.payload);
|
|
20421
|
-
if (delta.
|
|
20422
|
-
|
|
20423
|
-
opts?.onReasoningDelta?.(delta.reasoning);
|
|
20683
|
+
if (delta.usage?.completion !== void 0) {
|
|
20684
|
+
frameUsage = delta.usage;
|
|
20424
20685
|
}
|
|
20425
|
-
|
|
20426
|
-
|
|
20427
|
-
|
|
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
|
+
}
|
|
20428
20712
|
}
|
|
20429
20713
|
}
|
|
20430
20714
|
}
|
|
20431
20715
|
} finally {
|
|
20432
20716
|
reader.releaseLock();
|
|
20433
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;
|
|
20434
20745
|
return {
|
|
20435
20746
|
content: text,
|
|
20436
20747
|
model: selectedModel,
|
|
20437
20748
|
provider: "devin",
|
|
20438
|
-
|
|
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
|
|
20439
20760
|
};
|
|
20440
20761
|
}
|
|
20441
20762
|
};
|
|
@@ -20494,5 +20815,6 @@ export {
|
|
|
20494
20815
|
buildGeminiGenerateContentRequest,
|
|
20495
20816
|
resolveAntigravityFinishReason,
|
|
20496
20817
|
fetchAntigravityCloudCodeCompletion,
|
|
20818
|
+
readDevinUpstreamFailure,
|
|
20497
20819
|
createDevinProvider
|
|
20498
20820
|
};
|