nolo-cli 0.81.0-alpha.1 → 0.81.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-L4LCNFID.js → _executeModel-JIG7MRXQ.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-D2WHTH7S.js → agentDeleteCommand-THAZ5GQS.js} +31 -29
- package/{agentEmailCommands-IHSX56GO.js → agentEmailCommands-A7T7AJA4.js} +67 -63
- package/{agentGrantCommands-R3VQEZJR.js → agentGrantCommands-M3XFO6EN.js} +2 -2
- package/{agentListCommands-R2DGZMFP.js → agentListCommands-BRZFEJQM.js} +40 -32
- package/{agentMachineCommands-UYDID3HQ.js → agentMachineCommands-DM4N5PK3.js} +31 -29
- package/{agentProviderCommands-65ZC2WB4.js → agentProviderCommands-GNPTL5XR.js} +87 -0
- package/{agentPullCommand-N7L2CT7L.js → agentPullCommand-O5MPVJ5E.js} +3 -3
- package/agentRecordCommands-TTAEMNHB.js +128 -0
- package/{agentRunCommand-5PJF27JP.js → agentRunCommand-JVSTGVG2.js} +65 -61
- package/{agentRunControl-T44MESII.js → agentRunControl-WCTKX5VL.js} +2 -2
- package/{agentRuntimeLocal-VD4O2QFQ.js → agentRuntimeLocal-73CVIWBB.js} +27 -25
- package/{agentSlice-43ORUHTC.js → agentSlice-6X4JL2E3.js} +10 -10
- package/{appDeleteCommands-DXJA7XOZ.js → appDeleteCommands-S7CK4OYL.js} +31 -29
- package/{appDeployCommands-JL6XJZJE.js → appDeployCommands-U6TMS5GO.js} +31 -29
- package/{appDeployStatusCommands-MS2D2R6R.js → appDeployStatusCommands-DTNQJ3LJ.js} +31 -29
- package/{appGetCommands-BV2RDCEV.js → appGetCommands-3SHZEQD5.js} +31 -29
- package/{appListCommands-E2AM636N.js → appListCommands-E2ZMIUB6.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-F3IRDXDQ.js → chatQueueReduxAdapter-LAQEZQKE.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-KIS76A2P.js → chunk-3IIEFNGY.js} +38 -4
- package/{chunk-NTW5GWDM.js → chunk-3VNWWVKB.js} +2 -0
- package/{chunk-JQBONKAV.js → chunk-3WD6RUUJ.js} +11 -173
- package/{chunk-DWUCB2A3.js → chunk-42V6BK2E.js} +1 -1
- package/{chunk-GBPZKFYK.js → chunk-53HEEOTT.js} +4 -4
- package/{chunk-GEH7MMBB.js → chunk-54ADB4W7.js} +1 -1
- 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-QNWHWBB7.js → chunk-6FVRQBRR.js} +52 -30
- package/{chunk-CMH2SYHX.js → chunk-6OZ36FXI.js} +2 -2
- package/{chunk-NRALD3CC.js → chunk-76WEAXJB.js} +49 -10
- package/{chunk-DFJFH53D.js → chunk-7OLPQSMQ.js} +6 -6
- 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-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-MYU3MJCF.js → chunk-DHDMC6FO.js} +175 -7
- package/{chunk-4YCRJUQ2.js → chunk-ESWUWEFS.js} +10 -10
- package/{chunk-EXMHJN7C.js → chunk-EYAQT56M.js} +4 -3
- package/{chunk-CJCJF5XB.js → chunk-FDTR4QJ6.js} +4 -2
- 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-DAIOZ3ZO.js → chunk-HWIZU4OL.js} +13 -15
- package/{chunk-ZVN6I33J.js → chunk-IIVGDG4I.js} +6 -5
- package/{chunk-UDQWGU7F.js → chunk-J4MOO56S.js} +1 -1
- package/{chunk-DSRXPQWA.js → chunk-JAXOVNM4.js} +43 -43
- package/{chunk-QQ7SX52C.js → chunk-JCIHVIVG.js} +15 -15
- 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-J4R5XRX5.js → chunk-K4YGZD3P.js} +419 -72
- package/chunk-KQ4ONNQD.js +677 -0
- package/{chunk-RXX4GDIH.js → chunk-LS2ZANRJ.js} +1 -1
- package/{chunk-ODWEZBU6.js → chunk-LXF6XQDT.js} +1219 -57
- package/{chunk-CPSZJBLK.js → chunk-LZIWMYX4.js} +105 -26
- package/{chunk-BJIRLHJR.js → chunk-M2EJHDJP.js} +4 -0
- package/{chunk-EVBFYPDC.js → chunk-MC4XLIJ7.js} +6 -2
- package/{chunk-QC5LGHYP.js → chunk-OF7AQZUG.js} +10 -5
- package/{chunk-UJ63UXGE.js → chunk-OIVSQH2O.js} +1006 -801
- 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-IHTVDCWH.js → chunk-R2B3MIZA.js} +3 -3
- 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-XKNBWXDH.js → chunk-SQQVLHMH.js} +7 -7
- 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-QQBO3LQW.js → chunk-TZJJ77KQ.js} +155 -795
- 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-E36HZARC.js → chunk-WADCY6G6.js} +3 -3
- package/{chunk-HH65VA5U.js → chunk-WGR3J4Q6.js} +101 -4
- package/{chunk-5J7W2VWW.js → chunk-WV42OMV7.js} +6 -265
- package/{chunk-7QHSEMMD.js → chunk-Y5HW6GM2.js} +3 -3
- package/{chunk-DUJWWUGV.js → chunk-YQTQQX2H.js} +1 -1
- package/{chunk-QPJBFU7R.js → chunk-YVIV7WT4.js} +752 -80
- package/{chunk-BOYUESO7.js → chunk-Z77CRGTW.js} +1 -1
- package/{chunk-KSHYBTYH.js → chunk-ZWUOR654.js} +932 -299
- package/{contentThunks-FSQPOFYG.js → contentThunks-ATLWNC2D.js} +25 -25
- package/{cooldownCommands-BSCH2W7P.js → cooldownCommands-REAWYVTY.js} +2 -2
- package/{createAgentAutomationAction-VCHDRJ6X.js → createAgentAutomationAction-QYYWTVUR.js} +25 -25
- package/{createDialogAction-KZM5IE4P.js → createDialogAction-7I5VGWCR.js} +28 -28
- package/{createPageAction-IGMXJOY3.js → createPageAction-WNURYCWU.js} +26 -26
- package/{dbSlice-GKGGFNOB.js → dbSlice-XVWBAGYN.js} +8 -8
- package/{deleteFile-LWSR674W.js → deleteFile-YG6QMJLU.js} +3 -3
- package/{dialogCommands-KJS57EDF.js → dialogCommands-RILHDRQ5.js} +35 -31
- package/{dialogSlice-YBTC3GAW.js → dialogSlice-W5BYELVR.js} +24 -24
- package/{docCreateCommands-MRGXJTB4.js → docCreateCommands-GSTPU7SG.js} +32 -30
- package/{docDeleteCommands-YCI75CBU.js → docDeleteCommands-2FC3LSUT.js} +33 -31
- package/{docReadCommands-JN3VHTQY.js → docReadCommands-27POBA34.js} +32 -30
- package/{docStore-SDPT23I6.js → docStore-7LAHBFP2.js} +9 -9
- package/{docUpdateCommands-7KBOENX7.js → docUpdateCommands-U4II6VCO.js} +32 -30
- package/{fetchMessages-DRABNDPZ.js → fetchMessages-EIU7UFFK.js} +3 -4
- package/{getPricing-HRMSOF3E.js → getPricing-LUSEABA6.js} +4 -4
- package/{handleSendMessageAction-356IDG72.js → handleSendMessageAction-SKMJMVRU.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-FYIRYMDE.js → machineCommands-S2RNYKVJ.js} +64 -60
- package/{machineWsRunDispatch-J2FEYI4T.js → machineWsRunDispatch-JC44LBLP.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-OWBGR7QO.js → readlineWorkspace-VZSBXUH4.js} +188 -109
- package/{removeDialogAgentAction-F5GPTALR.js → removeDialogAgentAction-IX3MN2ZO.js} +11 -11
- package/{runAgentClientLoop-DKUUFUKT.js → runAgentClientLoop-ZYENU7GH.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-SSLCOSBH.js → spaceCommands-QB3NNEMN.js} +30 -28
- package/{streamAgentChatTurn-FHZZCANP.js → streamAgentChatTurn-43GPPQSN.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-QZJX3BIC.js → tools-SX6Y4STZ.js} +43 -43
- package/tuiSummaryLlmCaller-T2SHYMDZ.js +127 -0
- package/{updateCommands-Y363MC3L.js → updateCommands-2M74UL7P.js} +2 -2
- package/{updateDialogTitleAction-JJPNGTAP.js → updateDialogTitleAction-VAKA4ZNY.js} +45 -28
- package/agentRecordCommands-OFYTWZAA.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-OF7AQZUG.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-3IIEFNGY.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-LZIWMYX4.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-JAXOVNM4.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-WADCY6G6.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) => {
|
|
@@ -12556,224 +12760,39 @@ async function maybeAutoCompactLocalHistory(args2) {
|
|
|
12556
12760
|
}
|
|
12557
12761
|
}
|
|
12558
12762
|
|
|
12559
|
-
// packages/agent-runtime/
|
|
12560
|
-
var
|
|
12561
|
-
var
|
|
12562
|
-
|
|
12563
|
-
|
|
12564
|
-
|
|
12565
|
-
|
|
12566
|
-
|
|
12567
|
-
|
|
12763
|
+
// packages/agent-runtime/localLoop.ts
|
|
12764
|
+
var LOOP_TIMING_ENABLED = typeof process !== "undefined" && process.env?.NOLO_LOOP_TIMING === "1";
|
|
12765
|
+
var LOOP_TIMING_FILE = typeof process !== "undefined" ? process.env?.NOLO_LOOP_TIMING_FILE : void 0;
|
|
12766
|
+
var loopTimingRows = [];
|
|
12767
|
+
var loopTimingLastMark;
|
|
12768
|
+
function loopTimingMark(phase, round) {
|
|
12769
|
+
if (!LOOP_TIMING_ENABLED) return;
|
|
12770
|
+
const now = performance.now();
|
|
12771
|
+
if (loopTimingLastMark !== void 0) {
|
|
12772
|
+
loopTimingRows.push({ phase, round, durationMs: now - loopTimingLastMark });
|
|
12568
12773
|
}
|
|
12569
|
-
|
|
12774
|
+
loopTimingLastMark = now;
|
|
12570
12775
|
}
|
|
12571
|
-
function
|
|
12572
|
-
if (
|
|
12776
|
+
async function loopTimingFlush() {
|
|
12777
|
+
if (!LOOP_TIMING_ENABLED) return;
|
|
12778
|
+
const lines = loopTimingRows.map((row) => JSON.stringify(row)).join("\n");
|
|
12779
|
+
loopTimingRows = [];
|
|
12780
|
+
loopTimingLastMark = void 0;
|
|
12781
|
+
if (!lines) return;
|
|
12782
|
+
if (LOOP_TIMING_FILE) {
|
|
12573
12783
|
try {
|
|
12574
|
-
|
|
12784
|
+
const { appendFileSync } = await import("node:fs");
|
|
12785
|
+
appendFileSync(LOOP_TIMING_FILE, lines + "\n");
|
|
12575
12786
|
} catch {
|
|
12576
|
-
return String(rawArgs ?? "");
|
|
12577
12787
|
}
|
|
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;
|
|
12788
|
+
} else {
|
|
12789
|
+
process.stderr.write(lines + "\n");
|
|
12586
12790
|
}
|
|
12587
12791
|
}
|
|
12588
|
-
|
|
12589
|
-
|
|
12590
|
-
|
|
12591
|
-
return
|
|
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");
|
|
12771
|
-
}
|
|
12772
|
-
}
|
|
12773
|
-
var LOCAL_AGENT_CONFIG_MISSING_CODE = "LOCAL_AGENT_CONFIG_MISSING";
|
|
12774
|
-
function formatToolExecutionError(args2) {
|
|
12775
|
-
const message = toErrorMessage(args2.error);
|
|
12776
|
-
return `${args2.toolName} failed: ${message}`;
|
|
12792
|
+
var LOCAL_AGENT_CONFIG_MISSING_CODE = "LOCAL_AGENT_CONFIG_MISSING";
|
|
12793
|
+
function formatToolExecutionError(args2) {
|
|
12794
|
+
const message = toErrorMessage(args2.error);
|
|
12795
|
+
return `${args2.toolName} failed: ${message}`;
|
|
12777
12796
|
}
|
|
12778
12797
|
function formatStructuredToolExecutionError(args2) {
|
|
12779
12798
|
if (!args2.error || typeof args2.error !== "object") return null;
|
|
@@ -13046,10 +13065,10 @@ var TOOL_METADATA_KEYS = [
|
|
|
13046
13065
|
"pasteId",
|
|
13047
13066
|
"source"
|
|
13048
13067
|
];
|
|
13049
|
-
function trimHistoryToContextBudget(history, model) {
|
|
13068
|
+
function trimHistoryToContextBudget(history, model, contextWindowOverride) {
|
|
13050
13069
|
if (history.length === 0) return { history, droppedCount: 0 };
|
|
13051
13070
|
const { rawMessageBudget } = planContextUsage({
|
|
13052
|
-
contextWindow: getModelContextWindow(model ?? ""),
|
|
13071
|
+
contextWindow: contextWindowOverride ?? getModelContextWindow(model ?? ""),
|
|
13053
13072
|
summaryTokens: 0,
|
|
13054
13073
|
// localLoop 没有 web 端的负载分档器;medium 是中性默认值,
|
|
13055
13074
|
// 不为了省几个 token 在这里复制一份分类逻辑。
|
|
@@ -13512,7 +13531,14 @@ async function runLocalAgentTurn(input) {
|
|
|
13512
13531
|
agentConfig.exposedToolNames ?? agentConfig.toolNames ?? []
|
|
13513
13532
|
);
|
|
13514
13533
|
const guidanceBlocks = buildRuntimeGuidanceBlocks(agentTools);
|
|
13515
|
-
const toolGuidedSections = resolveToolGuidedSections(agentTools
|
|
13534
|
+
const toolGuidedSections = resolveToolGuidedSections(agentTools, {
|
|
13535
|
+
// 单调锁定:历史里任一 user 消息命中派发关键词、或已出现过
|
|
13536
|
+
// startAgentRun/controlAgentRun 的 tool_calls,后续每轮都保持 true,
|
|
13537
|
+
// 防止 session-scope 的 agentCollaboration 段逐轮翻转击穿前缀缓存。
|
|
13538
|
+
dispatchIntent: detectDispatchIntentFromMessages(history) || detectDispatchIntent(
|
|
13539
|
+
typeof input.input === "string" ? input.input : void 0
|
|
13540
|
+
)
|
|
13541
|
+
});
|
|
13516
13542
|
const guidanceScopes = [
|
|
13517
13543
|
...input.userLanguage?.trim() ? [buildUserResponseLanguageContext({ language: input.userLanguage })] : [],
|
|
13518
13544
|
guidanceBlocks.startupProtocol,
|
|
@@ -13540,7 +13566,7 @@ async function runLocalAgentTurn(input) {
|
|
|
13540
13566
|
}
|
|
13541
13567
|
return resolvedProvider;
|
|
13542
13568
|
};
|
|
13543
|
-
const contextWindow =
|
|
13569
|
+
const contextWindow = resolveAgentContextWindow(agentConfig);
|
|
13544
13570
|
const compressionTriggerRatio = resolveCompressionTriggerRatio(contextWindow);
|
|
13545
13571
|
let realContextUsagePercent;
|
|
13546
13572
|
if (input.continueDialogId && typeof input.adapter.loadLastContextUsage === "function") {
|
|
@@ -13582,6 +13608,7 @@ async function runLocalAgentTurn(input) {
|
|
|
13582
13608
|
history,
|
|
13583
13609
|
model: agentConfig.model,
|
|
13584
13610
|
resolveProvider: resolveProviderOnce,
|
|
13611
|
+
contextWindow,
|
|
13585
13612
|
realContextUsagePercent
|
|
13586
13613
|
});
|
|
13587
13614
|
history = compacted.history;
|
|
@@ -13591,7 +13618,7 @@ async function runLocalAgentTurn(input) {
|
|
|
13591
13618
|
console.warn("[localLoop] auto-compaction unexpected error:", error);
|
|
13592
13619
|
}
|
|
13593
13620
|
loopTimingMark("maybeAutoCompactLocalHistory", 0);
|
|
13594
|
-
const trimmedHistory = trimHistoryToContextBudget(history, agentConfig.model);
|
|
13621
|
+
const trimmedHistory = trimHistoryToContextBudget(history, agentConfig.model, contextWindow);
|
|
13595
13622
|
if (trimmedHistory.droppedCount > 0) {
|
|
13596
13623
|
history = trimmedHistory.history;
|
|
13597
13624
|
}
|
|
@@ -13678,6 +13705,7 @@ async function runLocalAgentTurn(input) {
|
|
|
13678
13705
|
],
|
|
13679
13706
|
model: agentConfig.model,
|
|
13680
13707
|
resolveProvider: resolveProviderOnce,
|
|
13708
|
+
contextWindow,
|
|
13681
13709
|
realContextUsagePercent: ratio
|
|
13682
13710
|
});
|
|
13683
13711
|
if (compacted.usage) {
|
|
@@ -13946,6 +13974,7 @@ ${reasoningTailLog}
|
|
|
13946
13974
|
const startedAt = Date.now();
|
|
13947
13975
|
loopTimingMark("toolCallStart", round);
|
|
13948
13976
|
const argumentsPreview = summarizeToolArguments(toolName, toolCall.function.arguments);
|
|
13977
|
+
const argumentsFingerprint = buildToolArgumentsFingerprint(toolCall.function.arguments);
|
|
13949
13978
|
emitLoopEvent(
|
|
13950
13979
|
observationBoundary,
|
|
13951
13980
|
{
|
|
@@ -13954,7 +13983,8 @@ ${reasoningTailLog}
|
|
|
13954
13983
|
toolCallId: toolCall.id,
|
|
13955
13984
|
toolName,
|
|
13956
13985
|
atMs: startedAt,
|
|
13957
|
-
...argumentsPreview ? { argumentsPreview } : {}
|
|
13986
|
+
...argumentsPreview ? { argumentsPreview } : {},
|
|
13987
|
+
...argumentsFingerprint ? { argumentsFingerprint } : {}
|
|
13958
13988
|
},
|
|
13959
13989
|
{
|
|
13960
13990
|
type: "tool-call",
|
|
@@ -15568,13 +15598,13 @@ var DEFAULT_LOCAL_TOOLS = /* @__PURE__ */ new Set([
|
|
|
15568
15598
|
"execShell",
|
|
15569
15599
|
"launchProcess",
|
|
15570
15600
|
"listProcesses",
|
|
15571
|
-
// ProcessTask follow-up tools
|
|
15572
|
-
//
|
|
15573
|
-
//
|
|
15601
|
+
// ProcessTask follow-up tools. Same tier as listProcesses: they observe/stop
|
|
15602
|
+
// tasks the agent itself already spawned, so their blast radius is strictly
|
|
15603
|
+
// narrower than launchProcess (which is default-enabled). Model-facing
|
|
15604
|
+
// follow-ups are taskWait/taskStop only — lifecycle history (taskLogs) stays
|
|
15605
|
+
// runtime-internal.
|
|
15574
15606
|
"taskWait",
|
|
15575
|
-
"taskLogs",
|
|
15576
15607
|
"taskStop",
|
|
15577
|
-
"tasks",
|
|
15578
15608
|
// Scheduling tools: forking/observing sub-agents is a declared capability
|
|
15579
15609
|
// of capable agents, and the blast radius is strictly narrower than
|
|
15580
15610
|
// execShell (already default-enabled). Requiring an env allowlist for these
|
|
@@ -16210,6 +16240,24 @@ var ProcessTaskEventLog = class {
|
|
|
16210
16240
|
};
|
|
16211
16241
|
|
|
16212
16242
|
// packages/agent-runtime/processRegistry.ts
|
|
16243
|
+
function toProcessTaskView(record) {
|
|
16244
|
+
const capsule = record.resultCapsule;
|
|
16245
|
+
return {
|
|
16246
|
+
taskId: record.taskId,
|
|
16247
|
+
pid: record.pid,
|
|
16248
|
+
pgid: record.pgid,
|
|
16249
|
+
command: record.command,
|
|
16250
|
+
label: record.label,
|
|
16251
|
+
startedAt: record.startedAt,
|
|
16252
|
+
status: record.status,
|
|
16253
|
+
...record.exitCode !== void 0 ? { exitCode: record.exitCode } : {},
|
|
16254
|
+
persist: record.persist,
|
|
16255
|
+
promoted: record.promoted,
|
|
16256
|
+
transient: record.transient,
|
|
16257
|
+
...capsule?.durationMs !== void 0 ? { durationMs: capsule.durationMs } : {},
|
|
16258
|
+
...capsule?.spill ? { outputRef: capsule.spill.displayPath } : {}
|
|
16259
|
+
};
|
|
16260
|
+
}
|
|
16213
16261
|
var taskIdCounter = 0;
|
|
16214
16262
|
function mintTaskId(pid) {
|
|
16215
16263
|
taskIdCounter += 1;
|
|
@@ -16398,10 +16446,11 @@ var ProcessRegistry = class {
|
|
|
16398
16446
|
}
|
|
16399
16447
|
}
|
|
16400
16448
|
}
|
|
16401
|
-
markExited(pid, exitCode) {
|
|
16449
|
+
markExited(pid, exitCode, resultCapsule) {
|
|
16402
16450
|
const item = this.processes.get(pid);
|
|
16403
16451
|
if (item && item.status === "running") {
|
|
16404
16452
|
item.exitCode = exitCode;
|
|
16453
|
+
if (resultCapsule) item.resultCapsule = resultCapsule;
|
|
16405
16454
|
item.status = exitCode === 0 ? "exited" : "failed";
|
|
16406
16455
|
this.eventLog.append({
|
|
16407
16456
|
taskId: item.taskId,
|
|
@@ -16416,7 +16465,8 @@ var ProcessRegistry = class {
|
|
|
16416
16465
|
command: item.command,
|
|
16417
16466
|
status: item.status,
|
|
16418
16467
|
exitCode,
|
|
16419
|
-
promoted: item.promoted
|
|
16468
|
+
promoted: item.promoted,
|
|
16469
|
+
...item.resultCapsule ? { resultCapsule: item.resultCapsule } : {}
|
|
16420
16470
|
});
|
|
16421
16471
|
}
|
|
16422
16472
|
}
|
|
@@ -16479,6 +16529,62 @@ function readProcessOwner(runtimeContext) {
|
|
|
16479
16529
|
// packages/agent-runtime/workspaceShell.ts
|
|
16480
16530
|
import { resolve as resolve3 } from "node:path";
|
|
16481
16531
|
import { spawn as spawnChildProcess2 } from "node:child_process";
|
|
16532
|
+
|
|
16533
|
+
// packages/agent-runtime/processTaskResult.ts
|
|
16534
|
+
var PROCESS_RESULT_CAPSULE_TAIL_CHARS = 4e3;
|
|
16535
|
+
var PROCESS_RESULT_CAPSULE_SPILL_THRESHOLD_CHARS = 2e4;
|
|
16536
|
+
function tailText(value, maxChars) {
|
|
16537
|
+
if (value.length <= maxChars) return { text: value, truncated: false };
|
|
16538
|
+
return { text: value.slice(-maxChars), truncated: true };
|
|
16539
|
+
}
|
|
16540
|
+
function formatCapsuleStream(name, value) {
|
|
16541
|
+
return value.trim() ? `${name}:
|
|
16542
|
+
${value.replace(/\n+$/, "")}` : "";
|
|
16543
|
+
}
|
|
16544
|
+
function buildProcessTaskResultCapsule(args2) {
|
|
16545
|
+
const tailChars = args2.tailChars ?? PROCESS_RESULT_CAPSULE_TAIL_CHARS;
|
|
16546
|
+
const spillThresholdChars = args2.spillThresholdChars ?? PROCESS_RESULT_CAPSULE_SPILL_THRESHOLD_CHARS;
|
|
16547
|
+
const stdout = typeof args2.stdout === "string" ? args2.stdout : "";
|
|
16548
|
+
const stderr = typeof args2.stderr === "string" ? args2.stderr : "";
|
|
16549
|
+
const exitCode = args2.exitCode;
|
|
16550
|
+
const captureError = args2.captureError?.trim() || void 0;
|
|
16551
|
+
const durationMs = typeof args2.startedAt === "number" && Number.isFinite(args2.startedAt) ? Math.max(0, (args2.endedAt ?? Date.now()) - args2.startedAt) : void 0;
|
|
16552
|
+
const stdoutTail = tailText(stdout, tailChars);
|
|
16553
|
+
const stderrTail = tailText(stderr, tailChars);
|
|
16554
|
+
const inlineSize = stdout.length + stderr.length;
|
|
16555
|
+
const inlineTruncated = stdoutTail.truncated || stderrTail.truncated;
|
|
16556
|
+
const shouldSpill = inlineTruncated || inlineSize > spillThresholdChars;
|
|
16557
|
+
let spill;
|
|
16558
|
+
if (shouldSpill) {
|
|
16559
|
+
try {
|
|
16560
|
+
const result4 = spillToolOutput({
|
|
16561
|
+
content: [
|
|
16562
|
+
formatCapsuleStream("stdout", stdout),
|
|
16563
|
+
formatCapsuleStream("stderr", stderr)
|
|
16564
|
+
].filter(Boolean).join("\n\n"),
|
|
16565
|
+
toolName: "execShell",
|
|
16566
|
+
...args2.workspaceRoot !== void 0 ? { workspaceRoot: args2.workspaceRoot } : {}
|
|
16567
|
+
});
|
|
16568
|
+
spill = {
|
|
16569
|
+
displayPath: result4.displayPath,
|
|
16570
|
+
totalChars: result4.totalChars,
|
|
16571
|
+
totalLines: result4.totalLines
|
|
16572
|
+
};
|
|
16573
|
+
} catch {
|
|
16574
|
+
}
|
|
16575
|
+
}
|
|
16576
|
+
return {
|
|
16577
|
+
stdout: stdoutTail.text,
|
|
16578
|
+
stderr: stderrTail.text,
|
|
16579
|
+
exitCode,
|
|
16580
|
+
...durationMs !== void 0 ? { durationMs } : {},
|
|
16581
|
+
...captureError ? { captureError } : {},
|
|
16582
|
+
truncated: inlineTruncated || Boolean(captureError),
|
|
16583
|
+
...spill ? { spill } : {}
|
|
16584
|
+
};
|
|
16585
|
+
}
|
|
16586
|
+
|
|
16587
|
+
// packages/agent-runtime/workspaceShell.ts
|
|
16482
16588
|
var EXEC_SHELL_TIMEOUT_ENV = "NOLO_EXEC_SHELL_TIMEOUT_MS";
|
|
16483
16589
|
var EXEC_SHELL_DETACH_ENV = "NOLO_EXEC_SHELL_DETACH_MS";
|
|
16484
16590
|
var DEFAULT_EXEC_SHELL_DETACH_MS = 12e4;
|
|
@@ -16858,6 +16964,15 @@ ${stderr.trim()}`, "exitCode: 127"].filter(Boolean).join("\n\n"),
|
|
|
16858
16964
|
)
|
|
16859
16965
|
};
|
|
16860
16966
|
}
|
|
16967
|
+
function stdoutPromiseResult(promise3) {
|
|
16968
|
+
return promise3.then(
|
|
16969
|
+
(value) => ({ value }),
|
|
16970
|
+
(error) => ({
|
|
16971
|
+
value: "",
|
|
16972
|
+
error: error instanceof Error ? error.message : String(error)
|
|
16973
|
+
})
|
|
16974
|
+
);
|
|
16975
|
+
}
|
|
16861
16976
|
async function runWorkspaceCommand(args2) {
|
|
16862
16977
|
const timeoutMs = asOptionalPositiveFiniteNumber(args2.timeoutMs);
|
|
16863
16978
|
const detached = process.platform !== "win32";
|
|
@@ -16916,8 +17031,8 @@ async function runWorkspaceCommand(args2) {
|
|
|
16916
17031
|
process.removeListener("SIGINT", cleanupChildOnHostSignal);
|
|
16917
17032
|
};
|
|
16918
17033
|
exitPromise.then(detachSignalCleanup, detachSignalCleanup);
|
|
16919
|
-
const
|
|
16920
|
-
const
|
|
17034
|
+
const stdoutCapture = stdoutPromiseResult(readNodeStream(proc.stdout));
|
|
17035
|
+
const stderrCapture = stdoutPromiseResult(readNodeStream(proc.stderr));
|
|
16921
17036
|
const killChild = (signal) => {
|
|
16922
17037
|
if (detached && typeof proc.pid === "number") {
|
|
16923
17038
|
try {
|
|
@@ -17016,7 +17131,30 @@ async function runWorkspaceCommand(args2) {
|
|
|
17016
17131
|
const taskId = envelope.taskId;
|
|
17017
17132
|
proc.on("close", (code) => {
|
|
17018
17133
|
detachSignalCleanup();
|
|
17019
|
-
|
|
17134
|
+
const exitCode2 = code ?? 1;
|
|
17135
|
+
void (async () => {
|
|
17136
|
+
const [stdoutResult, stderrResult] = await Promise.all([
|
|
17137
|
+
stdoutCapture,
|
|
17138
|
+
stderrCapture
|
|
17139
|
+
]);
|
|
17140
|
+
const stdout2 = stdoutResult.value;
|
|
17141
|
+
const stderr2 = stderrResult.value;
|
|
17142
|
+
let capsule;
|
|
17143
|
+
try {
|
|
17144
|
+
capsule = buildProcessTaskResultCapsule({
|
|
17145
|
+
stdout: stdout2,
|
|
17146
|
+
stderr: stderr2,
|
|
17147
|
+
exitCode: exitCode2,
|
|
17148
|
+
// Duration is measured from the registry envelope's startedAt
|
|
17149
|
+
// (spawn moment), not from the detach moment.
|
|
17150
|
+
startedAt: registry2.get(pid)?.startedAt,
|
|
17151
|
+
workspaceRoot: args2.workspaceRoot,
|
|
17152
|
+
captureError: [stdoutResult.error, stderrResult.error].filter(Boolean).join("; ")
|
|
17153
|
+
});
|
|
17154
|
+
} catch {
|
|
17155
|
+
}
|
|
17156
|
+
registry2.markExited(pid, exitCode2, capsule);
|
|
17157
|
+
})();
|
|
17020
17158
|
});
|
|
17021
17159
|
const immediate = effectiveDetachMs === 0;
|
|
17022
17160
|
const reason = immediate ? `command looks long-running; moved to background immediately (pid=${pid}, label=${label})` : `command detached to background after ${effectiveDetachMs}ms (pid=${pid}, label=${label})`;
|
|
@@ -17040,10 +17178,13 @@ Use listProcesses to inspect or stop it.`,
|
|
|
17040
17178
|
})
|
|
17041
17179
|
};
|
|
17042
17180
|
}
|
|
17043
|
-
const [
|
|
17044
|
-
|
|
17045
|
-
|
|
17181
|
+
const [stdoutCaptureResult, stderrCaptureResult] = await Promise.all([
|
|
17182
|
+
stdoutCapture,
|
|
17183
|
+
stderrCapture
|
|
17046
17184
|
]);
|
|
17185
|
+
const stdout = stdoutCaptureResult.value;
|
|
17186
|
+
const rawStderr = stderrCaptureResult.value;
|
|
17187
|
+
const streamCaptureError = [stdoutCaptureResult.error, stderrCaptureResult.error].filter(Boolean).join("; ");
|
|
17047
17188
|
const exitCode = aborted ? 130 : timedOut ? 124 : Number(raceWinner);
|
|
17048
17189
|
if (typeof proc.pid === "number") {
|
|
17049
17190
|
registry2.completeTransient(proc.pid, exitCode);
|
|
@@ -17460,9 +17601,7 @@ var WORKSPACE_TOOL_NAMES = [
|
|
|
17460
17601
|
"launchProcess",
|
|
17461
17602
|
"listProcesses",
|
|
17462
17603
|
"taskWait",
|
|
17463
|
-
"taskLogs",
|
|
17464
17604
|
"taskStop",
|
|
17465
|
-
"tasks",
|
|
17466
17605
|
"openDesktopPreview"
|
|
17467
17606
|
];
|
|
17468
17607
|
var SHELL_TOOL_NAMES = [
|
|
@@ -17470,9 +17609,7 @@ var SHELL_TOOL_NAMES = [
|
|
|
17470
17609
|
"launchProcess",
|
|
17471
17610
|
"listProcesses",
|
|
17472
17611
|
"taskWait",
|
|
17473
|
-
"
|
|
17474
|
-
"taskStop",
|
|
17475
|
-
"tasks"
|
|
17612
|
+
"taskStop"
|
|
17476
17613
|
];
|
|
17477
17614
|
var WORKSPACE_TOOL_NAME_SET = new Set(WORKSPACE_TOOL_NAMES);
|
|
17478
17615
|
function buildWorkspacePathProperty() {
|
|
@@ -17721,7 +17858,7 @@ function buildTaskWaitTool() {
|
|
|
17721
17858
|
type: "function",
|
|
17722
17859
|
function: {
|
|
17723
17860
|
name: "taskWait",
|
|
17724
|
-
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).
|
|
17861
|
+
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.',
|
|
17725
17862
|
parameters: {
|
|
17726
17863
|
type: "object",
|
|
17727
17864
|
properties: {
|
|
@@ -17740,30 +17877,6 @@ function buildTaskWaitTool() {
|
|
|
17740
17877
|
}
|
|
17741
17878
|
};
|
|
17742
17879
|
}
|
|
17743
|
-
function buildTaskLogsTool() {
|
|
17744
|
-
return {
|
|
17745
|
-
type: "function",
|
|
17746
|
-
function: {
|
|
17747
|
-
name: "taskLogs",
|
|
17748
|
-
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.",
|
|
17749
|
-
parameters: {
|
|
17750
|
-
type: "object",
|
|
17751
|
-
properties: {
|
|
17752
|
-
taskId: {
|
|
17753
|
-
type: "string",
|
|
17754
|
-
minLength: 1,
|
|
17755
|
-
description: "Task id returned by launchProcess or by a detached execShell result."
|
|
17756
|
-
},
|
|
17757
|
-
cursor: {
|
|
17758
|
-
type: "number",
|
|
17759
|
-
description: "Last event seq you already consumed; only events with a higher seq are returned. Defaults to 0 (all retained events)."
|
|
17760
|
-
}
|
|
17761
|
-
},
|
|
17762
|
-
required: ["taskId"]
|
|
17763
|
-
}
|
|
17764
|
-
}
|
|
17765
|
-
};
|
|
17766
|
-
}
|
|
17767
17880
|
function buildTaskStopTool() {
|
|
17768
17881
|
return {
|
|
17769
17882
|
type: "function",
|
|
@@ -17784,19 +17897,6 @@ function buildTaskStopTool() {
|
|
|
17784
17897
|
}
|
|
17785
17898
|
};
|
|
17786
17899
|
}
|
|
17787
|
-
function buildTasksTool() {
|
|
17788
|
-
return {
|
|
17789
|
-
type: "function",
|
|
17790
|
-
function: {
|
|
17791
|
-
name: "tasks",
|
|
17792
|
-
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.",
|
|
17793
|
-
parameters: {
|
|
17794
|
-
type: "object",
|
|
17795
|
-
properties: {}
|
|
17796
|
-
}
|
|
17797
|
-
}
|
|
17798
|
-
};
|
|
17799
|
-
}
|
|
17800
17900
|
function buildWorkspaceToolDefinition(toolName) {
|
|
17801
17901
|
if (toolName === "readFile") {
|
|
17802
17902
|
return buildReadWorkspaceFileTool();
|
|
@@ -17816,9 +17916,7 @@ function buildWorkspaceToolDefinition(toolName) {
|
|
|
17816
17916
|
if (toolName === "openDesktopPreview") return buildOpenDesktopPreviewTool();
|
|
17817
17917
|
if (toolName === "listProcesses") return buildListProcessesTool();
|
|
17818
17918
|
if (toolName === "taskWait") return buildTaskWaitTool();
|
|
17819
|
-
if (toolName === "taskLogs") return buildTaskLogsTool();
|
|
17820
17919
|
if (toolName === "taskStop") return buildTaskStopTool();
|
|
17821
|
-
if (toolName === "tasks") return buildTasksTool();
|
|
17822
17920
|
return null;
|
|
17823
17921
|
}
|
|
17824
17922
|
function filterDeclaredWorkspaceToolNames(args2) {
|
|
@@ -18927,7 +19025,7 @@ async function launchProcessTool(args2) {
|
|
|
18927
19025
|
};
|
|
18928
19026
|
}
|
|
18929
19027
|
async function listProcessesTool(args2) {
|
|
18930
|
-
const list = getProcessRegistry().list();
|
|
19028
|
+
const list = getProcessRegistry().list().map(toProcessTaskView);
|
|
18931
19029
|
return {
|
|
18932
19030
|
content: JSON.stringify(list),
|
|
18933
19031
|
metadata: {
|
|
@@ -19284,15 +19382,23 @@ function buildLoadSkillExecutor(args2) {
|
|
|
19284
19382
|
const { resolveSkillByName } = await import("./skillDiscovery-CYUCJMAG.js");
|
|
19285
19383
|
const resolved = resolveSkillByName(args2.cwd, name);
|
|
19286
19384
|
if (!resolved) {
|
|
19287
|
-
const {
|
|
19288
|
-
const
|
|
19289
|
-
if (
|
|
19290
|
-
const body = buildCodingSkillContentBySlug(builtinSlug);
|
|
19385
|
+
const { resolveBuiltinSkillByName } = await import("./builtinSkillRegistry-FUAVTRVZ.js");
|
|
19386
|
+
const builtin = resolveBuiltinSkillByName(name);
|
|
19387
|
+
if (builtin) {
|
|
19291
19388
|
return {
|
|
19292
19389
|
content: `Skill "${name}" loaded inline. Follow its instructions.
|
|
19293
19390
|
|
|
19294
|
-
${
|
|
19295
|
-
|
|
19391
|
+
${builtin.content}`,
|
|
19392
|
+
// toolNames 进 metadata:回退面已扩到全注册表,其中授工具型 skill
|
|
19393
|
+
// (search-* 等)的工具在本宿主未必接线,宿主可据此降级提示。
|
|
19394
|
+
metadata: {
|
|
19395
|
+
loadSkill: true,
|
|
19396
|
+
resolved: true,
|
|
19397
|
+
name,
|
|
19398
|
+
requestedName: name,
|
|
19399
|
+
builtin: true,
|
|
19400
|
+
...builtin.config.toolNames?.length ? { toolNames: [...builtin.config.toolNames] } : {}
|
|
19401
|
+
}
|
|
19296
19402
|
};
|
|
19297
19403
|
}
|
|
19298
19404
|
return {
|
|
@@ -20063,6 +20169,530 @@ async function fetchAntigravityCloudCodeCompletion(args2) {
|
|
|
20063
20169
|
return normalized;
|
|
20064
20170
|
}
|
|
20065
20171
|
|
|
20172
|
+
// packages/agent-runtime/devin/devinProvider.ts
|
|
20173
|
+
import { randomBytes, randomUUID as randomUUID2 } from "node:crypto";
|
|
20174
|
+
var CLIENT_NAME = "chisel";
|
|
20175
|
+
var CLIENT_VERSION = "2026.8.18";
|
|
20176
|
+
function writeVarint(fieldNum, value) {
|
|
20177
|
+
const tag = fieldNum << 3 | 0;
|
|
20178
|
+
const bytes = [];
|
|
20179
|
+
let t = tag;
|
|
20180
|
+
while (t >= 128) {
|
|
20181
|
+
bytes.push(t & 127 | 128);
|
|
20182
|
+
t >>>= 7;
|
|
20183
|
+
}
|
|
20184
|
+
bytes.push(t);
|
|
20185
|
+
let v = value;
|
|
20186
|
+
while (v >= 128) {
|
|
20187
|
+
bytes.push(v & 127 | 128);
|
|
20188
|
+
v >>>= 7;
|
|
20189
|
+
}
|
|
20190
|
+
bytes.push(v);
|
|
20191
|
+
return Buffer.from(bytes);
|
|
20192
|
+
}
|
|
20193
|
+
function writeLengthDelimited(fieldNum, content) {
|
|
20194
|
+
const tag = fieldNum << 3 | 2;
|
|
20195
|
+
const tagBytes = [];
|
|
20196
|
+
let t = tag;
|
|
20197
|
+
while (t >= 128) {
|
|
20198
|
+
tagBytes.push(t & 127 | 128);
|
|
20199
|
+
t >>>= 7;
|
|
20200
|
+
}
|
|
20201
|
+
tagBytes.push(t);
|
|
20202
|
+
const lenBytes = [];
|
|
20203
|
+
let len = content.length;
|
|
20204
|
+
while (len >= 128) {
|
|
20205
|
+
lenBytes.push(len & 127 | 128);
|
|
20206
|
+
len >>>= 7;
|
|
20207
|
+
}
|
|
20208
|
+
lenBytes.push(len);
|
|
20209
|
+
return Buffer.concat([Buffer.from(tagBytes), Buffer.from(lenBytes), content]);
|
|
20210
|
+
}
|
|
20211
|
+
function writeStringField(fieldNum, str) {
|
|
20212
|
+
return writeLengthDelimited(fieldNum, Buffer.from(str, "utf8"));
|
|
20213
|
+
}
|
|
20214
|
+
function writeMessageField(fieldNum, message) {
|
|
20215
|
+
return writeLengthDelimited(fieldNum, message);
|
|
20216
|
+
}
|
|
20217
|
+
function generateFingerprint() {
|
|
20218
|
+
return randomBytes(366).toString("hex");
|
|
20219
|
+
}
|
|
20220
|
+
function encodeDevinClientMetadata(token) {
|
|
20221
|
+
return Buffer.concat([
|
|
20222
|
+
writeStringField(1, CLIENT_NAME),
|
|
20223
|
+
writeStringField(2, CLIENT_VERSION),
|
|
20224
|
+
writeStringField(3, token),
|
|
20225
|
+
writeStringField(4, "en"),
|
|
20226
|
+
writeStringField(5, process.platform === "win32" ? "windows" : "linux"),
|
|
20227
|
+
writeStringField(7, CLIENT_VERSION),
|
|
20228
|
+
writeStringField(12, CLIENT_NAME),
|
|
20229
|
+
writeStringField(31, generateFingerprint())
|
|
20230
|
+
]);
|
|
20231
|
+
}
|
|
20232
|
+
function encodeDevinChatMessage(msg) {
|
|
20233
|
+
const source = msg.role === "assistant" ? 2 : msg.role === "tool" ? 4 : 1;
|
|
20234
|
+
return Buffer.concat([
|
|
20235
|
+
writeStringField(1, randomUUID2()),
|
|
20236
|
+
writeVarint(2, source),
|
|
20237
|
+
writeStringField(3, msg.text),
|
|
20238
|
+
...(msg.toolCalls ?? []).map(
|
|
20239
|
+
(toolCall) => writeMessageField(
|
|
20240
|
+
6,
|
|
20241
|
+
Buffer.concat([
|
|
20242
|
+
writeStringField(1, toolCall.id),
|
|
20243
|
+
writeStringField(2, toolCall.function.name),
|
|
20244
|
+
writeStringField(3, toolCall.function.arguments)
|
|
20245
|
+
])
|
|
20246
|
+
)
|
|
20247
|
+
),
|
|
20248
|
+
...msg.toolCallId ? [writeStringField(7, msg.toolCallId)] : []
|
|
20249
|
+
]);
|
|
20250
|
+
}
|
|
20251
|
+
function encodeDevinToolDefinition(tool) {
|
|
20252
|
+
const fn3 = tool.function ?? {};
|
|
20253
|
+
const name = typeof fn3.name === "string" ? fn3.name : "";
|
|
20254
|
+
const description = typeof fn3.description === "string" ? fn3.description : "";
|
|
20255
|
+
const parameters = fn3.parameters ?? {};
|
|
20256
|
+
return Buffer.concat([
|
|
20257
|
+
writeStringField(1, name),
|
|
20258
|
+
writeStringField(2, description.length > 6998 ? `${description.slice(0, 6995)}...` : description),
|
|
20259
|
+
writeStringField(3, JSON.stringify(parameters))
|
|
20260
|
+
]);
|
|
20261
|
+
}
|
|
20262
|
+
function writeFixed64Field(fieldNum, val) {
|
|
20263
|
+
const b = Buffer.alloc(8);
|
|
20264
|
+
b.writeDoubleLE(val, 0);
|
|
20265
|
+
const tag = fieldNum << 3 | 1;
|
|
20266
|
+
const tagBytes = [];
|
|
20267
|
+
let t = tag;
|
|
20268
|
+
while (t >= 128) {
|
|
20269
|
+
tagBytes.push(t & 127 | 128);
|
|
20270
|
+
t >>>= 7;
|
|
20271
|
+
}
|
|
20272
|
+
tagBytes.push(t);
|
|
20273
|
+
return Buffer.concat([Buffer.from(tagBytes), b]);
|
|
20274
|
+
}
|
|
20275
|
+
function buildCompletionConfig(params) {
|
|
20276
|
+
const maxTokens = params?.maxTokens ?? 128e3;
|
|
20277
|
+
const maxNewlines = params?.maxNewlines ?? 400;
|
|
20278
|
+
const temp = params?.temperature ?? 1;
|
|
20279
|
+
const topP = params?.topP ?? 0.95;
|
|
20280
|
+
return Buffer.concat([
|
|
20281
|
+
writeVarint(1, 1),
|
|
20282
|
+
writeVarint(2, maxTokens),
|
|
20283
|
+
writeVarint(3, maxNewlines),
|
|
20284
|
+
writeFixed64Field(5, temp),
|
|
20285
|
+
writeVarint(7, 40),
|
|
20286
|
+
writeFixed64Field(8, topP)
|
|
20287
|
+
]);
|
|
20288
|
+
}
|
|
20289
|
+
function buildGetChatMessageRequest(params) {
|
|
20290
|
+
const { token, messages, model, tools = [], temperature } = params;
|
|
20291
|
+
const metadata = encodeDevinClientMetadata(token);
|
|
20292
|
+
let systemPrompt = "";
|
|
20293
|
+
const filteredMessages = [];
|
|
20294
|
+
for (const m of messages) {
|
|
20295
|
+
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") : "";
|
|
20296
|
+
if (m.role === "system") {
|
|
20297
|
+
systemPrompt = systemPrompt ? `${systemPrompt}
|
|
20298
|
+
|
|
20299
|
+
${text}` : text;
|
|
20300
|
+
} else if (m.role === "user" || m.role === "assistant" || m.role === "tool") {
|
|
20301
|
+
filteredMessages.push({
|
|
20302
|
+
role: m.role,
|
|
20303
|
+
text,
|
|
20304
|
+
...m.tool_call_id ? { toolCallId: m.tool_call_id } : {},
|
|
20305
|
+
...m.tool_calls?.length ? { toolCalls: m.tool_calls } : {}
|
|
20306
|
+
});
|
|
20307
|
+
}
|
|
20308
|
+
}
|
|
20309
|
+
const coalesced = [];
|
|
20310
|
+
for (const item of filteredMessages) {
|
|
20311
|
+
const last = coalesced[coalesced.length - 1];
|
|
20312
|
+
if (last && last.role === item.role && item.role !== "tool" && !last.toolCalls?.length && !item.toolCalls?.length) {
|
|
20313
|
+
last.text = `${last.text}
|
|
20314
|
+
|
|
20315
|
+
${item.text}`;
|
|
20316
|
+
} else {
|
|
20317
|
+
coalesced.push({ ...item });
|
|
20318
|
+
}
|
|
20319
|
+
}
|
|
20320
|
+
const chatMessageBuffers = coalesced.map((m) => encodeDevinChatMessage(m));
|
|
20321
|
+
const completionConfig = buildCompletionConfig({ temperature });
|
|
20322
|
+
const modelConfig = Buffer.concat([
|
|
20323
|
+
writeStringField(1, randomUUID2()),
|
|
20324
|
+
writeVarint(2, 1),
|
|
20325
|
+
writeVarint(3, 4)
|
|
20326
|
+
]);
|
|
20327
|
+
return Buffer.concat([
|
|
20328
|
+
writeMessageField(1, metadata),
|
|
20329
|
+
writeStringField(2, systemPrompt),
|
|
20330
|
+
...chatMessageBuffers.map((b) => writeMessageField(3, b)),
|
|
20331
|
+
writeVarint(7, 5),
|
|
20332
|
+
writeMessageField(8, completionConfig),
|
|
20333
|
+
...tools.map((tool) => writeMessageField(10, encodeDevinToolDefinition(tool))),
|
|
20334
|
+
writeMessageField(15, modelConfig),
|
|
20335
|
+
writeStringField(16, randomUUID2()),
|
|
20336
|
+
writeVarint(20, 1),
|
|
20337
|
+
writeStringField(21, model)
|
|
20338
|
+
]);
|
|
20339
|
+
}
|
|
20340
|
+
function buildDevinConnectFrame(payload, flags = 0) {
|
|
20341
|
+
const header = Buffer.alloc(5);
|
|
20342
|
+
header[0] = flags & 255;
|
|
20343
|
+
header.writeUInt32BE(payload.length, 1);
|
|
20344
|
+
return Buffer.concat([header, payload]);
|
|
20345
|
+
}
|
|
20346
|
+
function parseDevinConnectFrames(buffer3) {
|
|
20347
|
+
const frames = [];
|
|
20348
|
+
let offset = 0;
|
|
20349
|
+
while (offset + 5 <= buffer3.length) {
|
|
20350
|
+
const flags = buffer3[offset];
|
|
20351
|
+
const length = buffer3.readUInt32BE(offset + 1);
|
|
20352
|
+
if (offset + 5 + length > buffer3.length) {
|
|
20353
|
+
break;
|
|
20354
|
+
}
|
|
20355
|
+
const payload = buffer3.subarray(offset + 5, offset + 5 + length);
|
|
20356
|
+
frames.push({ flags, payload });
|
|
20357
|
+
offset += 5 + length;
|
|
20358
|
+
}
|
|
20359
|
+
return {
|
|
20360
|
+
frames,
|
|
20361
|
+
remainder: buffer3.subarray(offset)
|
|
20362
|
+
};
|
|
20363
|
+
}
|
|
20364
|
+
function parseDevinMetadataUsage(metaBytes) {
|
|
20365
|
+
let prompt = 0;
|
|
20366
|
+
let completion;
|
|
20367
|
+
let cacheRead = 0;
|
|
20368
|
+
let cacheWrite = 0;
|
|
20369
|
+
let sawAny = false;
|
|
20370
|
+
let offset = 0;
|
|
20371
|
+
while (offset < metaBytes.length) {
|
|
20372
|
+
let tag = 0;
|
|
20373
|
+
let shift = 0;
|
|
20374
|
+
while (offset < metaBytes.length) {
|
|
20375
|
+
const b = metaBytes[offset++];
|
|
20376
|
+
tag |= (b & 127) << shift;
|
|
20377
|
+
if (!(b & 128)) break;
|
|
20378
|
+
shift += 7;
|
|
20379
|
+
}
|
|
20380
|
+
const fieldNum = tag >>> 3;
|
|
20381
|
+
const wireType = tag & 7;
|
|
20382
|
+
if (wireType === 0) {
|
|
20383
|
+
let val = 0;
|
|
20384
|
+
let s = 0;
|
|
20385
|
+
while (offset < metaBytes.length) {
|
|
20386
|
+
const b = metaBytes[offset++];
|
|
20387
|
+
val |= (b & 127) << s;
|
|
20388
|
+
if (!(b & 128)) break;
|
|
20389
|
+
s += 7;
|
|
20390
|
+
}
|
|
20391
|
+
if (fieldNum === 2) {
|
|
20392
|
+
prompt = val;
|
|
20393
|
+
sawAny = true;
|
|
20394
|
+
} else if (fieldNum === 3) {
|
|
20395
|
+
completion = val;
|
|
20396
|
+
sawAny = true;
|
|
20397
|
+
} else if (fieldNum === 4) {
|
|
20398
|
+
cacheWrite = val;
|
|
20399
|
+
sawAny = true;
|
|
20400
|
+
} else if (fieldNum === 5) {
|
|
20401
|
+
cacheRead = val;
|
|
20402
|
+
sawAny = true;
|
|
20403
|
+
}
|
|
20404
|
+
} else if (wireType === 2) {
|
|
20405
|
+
let len = 0;
|
|
20406
|
+
let s = 0;
|
|
20407
|
+
while (offset < metaBytes.length) {
|
|
20408
|
+
const b = metaBytes[offset++];
|
|
20409
|
+
len |= (b & 127) << s;
|
|
20410
|
+
if (!(b & 128)) break;
|
|
20411
|
+
s += 7;
|
|
20412
|
+
}
|
|
20413
|
+
offset += len;
|
|
20414
|
+
} else {
|
|
20415
|
+
break;
|
|
20416
|
+
}
|
|
20417
|
+
}
|
|
20418
|
+
return sawAny ? { prompt, completion, cacheRead, cacheWrite } : null;
|
|
20419
|
+
}
|
|
20420
|
+
function attachDevinUpstreamFailure(error, failure) {
|
|
20421
|
+
if (failure) {
|
|
20422
|
+
error.devinUpstreamFailure = failure;
|
|
20423
|
+
}
|
|
20424
|
+
return error;
|
|
20425
|
+
}
|
|
20426
|
+
function readDevinUpstreamFailure(error) {
|
|
20427
|
+
if (!error || typeof error !== "object") return void 0;
|
|
20428
|
+
const failure = error.devinUpstreamFailure;
|
|
20429
|
+
if (!failure || typeof failure !== "object") return void 0;
|
|
20430
|
+
if (typeof failure.status !== "number" || !Number.isFinite(failure.status)) {
|
|
20431
|
+
return void 0;
|
|
20432
|
+
}
|
|
20433
|
+
return failure;
|
|
20434
|
+
}
|
|
20435
|
+
function parseDevinConnectTrailer(payload) {
|
|
20436
|
+
const text = payload.toString("utf8").trim();
|
|
20437
|
+
if (!text || text === "{}") return null;
|
|
20438
|
+
try {
|
|
20439
|
+
const parsed = JSON.parse(text);
|
|
20440
|
+
if (!parsed.error) {
|
|
20441
|
+
return new Error(`Devin Connect invalid terminal trailer: ${text}`);
|
|
20442
|
+
}
|
|
20443
|
+
const code = typeof parsed.error.code === "string" ? parsed.error.code : "unknown";
|
|
20444
|
+
const message = typeof parsed.error.message === "string" ? parsed.error.message : "Unknown error";
|
|
20445
|
+
return attachDevinUpstreamFailure(
|
|
20446
|
+
new Error(`Devin Connect upstream error ${code}: ${message}`),
|
|
20447
|
+
// Connect/gRPC 的 resource_exhausted 与 HTTP 429 同义(限流/配额耗尽)。
|
|
20448
|
+
code === "resource_exhausted" ? { status: 429, body: parsed.error } : void 0
|
|
20449
|
+
);
|
|
20450
|
+
} catch {
|
|
20451
|
+
return new Error(`Devin Connect invalid terminal trailer: ${text}`);
|
|
20452
|
+
}
|
|
20453
|
+
}
|
|
20454
|
+
function decodeDevinResponsePayload(payload) {
|
|
20455
|
+
let offset = 0;
|
|
20456
|
+
let content = "";
|
|
20457
|
+
let reasoning = "";
|
|
20458
|
+
let finishReason = null;
|
|
20459
|
+
let usage = null;
|
|
20460
|
+
const events = [];
|
|
20461
|
+
while (offset < payload.length) {
|
|
20462
|
+
let tag = 0;
|
|
20463
|
+
let shift = 0;
|
|
20464
|
+
while (offset < payload.length) {
|
|
20465
|
+
const b = payload[offset++];
|
|
20466
|
+
tag |= (b & 127) << shift;
|
|
20467
|
+
if (!(b & 128)) break;
|
|
20468
|
+
shift += 7;
|
|
20469
|
+
}
|
|
20470
|
+
const fieldNum = tag >>> 3;
|
|
20471
|
+
const wireType = tag & 7;
|
|
20472
|
+
if (wireType === 0) {
|
|
20473
|
+
let val = 0;
|
|
20474
|
+
let s = 0;
|
|
20475
|
+
while (offset < payload.length) {
|
|
20476
|
+
const b = payload[offset++];
|
|
20477
|
+
val |= (b & 127) << s;
|
|
20478
|
+
if (!(b & 128)) break;
|
|
20479
|
+
s += 7;
|
|
20480
|
+
}
|
|
20481
|
+
if (fieldNum === 5) {
|
|
20482
|
+
finishReason = val === 10 ? "tool_calls" : val === 1 || val === 3 ? "length" : "stop";
|
|
20483
|
+
}
|
|
20484
|
+
} else if (wireType === 2) {
|
|
20485
|
+
let len = 0;
|
|
20486
|
+
let s = 0;
|
|
20487
|
+
while (offset < payload.length) {
|
|
20488
|
+
const b = payload[offset++];
|
|
20489
|
+
len |= (b & 127) << s;
|
|
20490
|
+
if (!(b & 128)) break;
|
|
20491
|
+
s += 7;
|
|
20492
|
+
}
|
|
20493
|
+
const valBytes = payload.subarray(offset, offset + len);
|
|
20494
|
+
offset += len;
|
|
20495
|
+
if (fieldNum === 3) {
|
|
20496
|
+
const text = valBytes.toString("utf8");
|
|
20497
|
+
content += text;
|
|
20498
|
+
events.push({ type: "content", text });
|
|
20499
|
+
} else if (fieldNum === 9) {
|
|
20500
|
+
const text = valBytes.toString("utf8");
|
|
20501
|
+
reasoning += text;
|
|
20502
|
+
events.push({ type: "reasoning", text });
|
|
20503
|
+
} else if (fieldNum === 6) {
|
|
20504
|
+
let nestedOffset = 0;
|
|
20505
|
+
let id;
|
|
20506
|
+
let name;
|
|
20507
|
+
let argsDelta;
|
|
20508
|
+
while (nestedOffset < valBytes.length) {
|
|
20509
|
+
let nestedTag = 0;
|
|
20510
|
+
let nestedShift = 0;
|
|
20511
|
+
while (nestedOffset < valBytes.length) {
|
|
20512
|
+
const b = valBytes[nestedOffset++];
|
|
20513
|
+
nestedTag |= (b & 127) << nestedShift;
|
|
20514
|
+
if (!(b & 128)) break;
|
|
20515
|
+
nestedShift += 7;
|
|
20516
|
+
}
|
|
20517
|
+
const nestedField = nestedTag >>> 3;
|
|
20518
|
+
const nestedWire = nestedTag & 7;
|
|
20519
|
+
if (nestedWire !== 2) break;
|
|
20520
|
+
let nestedLength = 0;
|
|
20521
|
+
let lengthShift = 0;
|
|
20522
|
+
while (nestedOffset < valBytes.length) {
|
|
20523
|
+
const b = valBytes[nestedOffset++];
|
|
20524
|
+
nestedLength |= (b & 127) << lengthShift;
|
|
20525
|
+
if (!(b & 128)) break;
|
|
20526
|
+
lengthShift += 7;
|
|
20527
|
+
}
|
|
20528
|
+
const nestedValue = valBytes.subarray(nestedOffset, nestedOffset + nestedLength);
|
|
20529
|
+
nestedOffset += nestedLength;
|
|
20530
|
+
const text = nestedValue.toString("utf8");
|
|
20531
|
+
if (nestedField === 1) id = text;
|
|
20532
|
+
else if (nestedField === 2) name = text;
|
|
20533
|
+
else if (nestedField === 3) argsDelta = (argsDelta ?? "") + text;
|
|
20534
|
+
}
|
|
20535
|
+
if (id !== void 0 && name !== void 0) {
|
|
20536
|
+
events.push({ type: "tool-call-start", id, name });
|
|
20537
|
+
}
|
|
20538
|
+
if (argsDelta !== void 0) {
|
|
20539
|
+
events.push({ type: "tool-call-args", argsDelta, ...id ? { id } : {} });
|
|
20540
|
+
}
|
|
20541
|
+
} else if (fieldNum === 7) {
|
|
20542
|
+
usage = parseDevinMetadataUsage(valBytes);
|
|
20543
|
+
}
|
|
20544
|
+
} else {
|
|
20545
|
+
break;
|
|
20546
|
+
}
|
|
20547
|
+
}
|
|
20548
|
+
return { content, reasoning, finishReason, events, usage };
|
|
20549
|
+
}
|
|
20550
|
+
function createDevinProvider(options) {
|
|
20551
|
+
const { token, model = "swe-2-max", fetchImpl = fetch, tools = [], temperature } = options;
|
|
20552
|
+
return {
|
|
20553
|
+
model,
|
|
20554
|
+
async complete(messages, opts) {
|
|
20555
|
+
const selectedModel = model;
|
|
20556
|
+
const requestPayload = buildGetChatMessageRequest({
|
|
20557
|
+
token,
|
|
20558
|
+
messages,
|
|
20559
|
+
model: selectedModel,
|
|
20560
|
+
tools,
|
|
20561
|
+
temperature
|
|
20562
|
+
});
|
|
20563
|
+
const frame = buildDevinConnectFrame(requestPayload);
|
|
20564
|
+
const response = await fetchImpl(DEVIN_CONNECT_URL, {
|
|
20565
|
+
method: "POST",
|
|
20566
|
+
headers: {
|
|
20567
|
+
"authorization": `Basic ${token}-${token}`,
|
|
20568
|
+
"content-type": "application/connect+proto",
|
|
20569
|
+
"connect-protocol-version": "1"
|
|
20570
|
+
},
|
|
20571
|
+
body: new Uint8Array(frame),
|
|
20572
|
+
signal: opts?.signal
|
|
20573
|
+
});
|
|
20574
|
+
if (!response.ok) {
|
|
20575
|
+
const errText = await response.text().catch(() => "");
|
|
20576
|
+
throw attachDevinUpstreamFailure(
|
|
20577
|
+
new Error(
|
|
20578
|
+
`Devin Connect upstream returned error ${response.status}: ${errText}`
|
|
20579
|
+
),
|
|
20580
|
+
{ status: response.status, body: errText }
|
|
20581
|
+
);
|
|
20582
|
+
}
|
|
20583
|
+
if (!response.body) {
|
|
20584
|
+
throw new Error("Devin Connect response body is null");
|
|
20585
|
+
}
|
|
20586
|
+
let text = "";
|
|
20587
|
+
let reasoning = "";
|
|
20588
|
+
let finishReason = null;
|
|
20589
|
+
let frameUsage = null;
|
|
20590
|
+
const toolCallOrder = [];
|
|
20591
|
+
const toolCallById = /* @__PURE__ */ new Map();
|
|
20592
|
+
let currentToolCallId = null;
|
|
20593
|
+
let buffer3 = Buffer.alloc(0);
|
|
20594
|
+
let sawTrailer = false;
|
|
20595
|
+
const reader = response.body.getReader();
|
|
20596
|
+
try {
|
|
20597
|
+
while (true) {
|
|
20598
|
+
const { done: done4, value } = await reader.read();
|
|
20599
|
+
if (done4) break;
|
|
20600
|
+
buffer3 = Buffer.concat([buffer3, Buffer.from(value)]);
|
|
20601
|
+
const { frames, remainder } = parseDevinConnectFrames(buffer3);
|
|
20602
|
+
buffer3 = Buffer.from(remainder);
|
|
20603
|
+
for (const f of frames) {
|
|
20604
|
+
if (sawTrailer) {
|
|
20605
|
+
throw new Error("Devin Connect received a frame after the terminal trailer");
|
|
20606
|
+
}
|
|
20607
|
+
if (f.flags & 2) {
|
|
20608
|
+
sawTrailer = true;
|
|
20609
|
+
const trailerError = parseDevinConnectTrailer(f.payload);
|
|
20610
|
+
if (trailerError) throw trailerError;
|
|
20611
|
+
continue;
|
|
20612
|
+
}
|
|
20613
|
+
const delta = decodeDevinResponsePayload(f.payload);
|
|
20614
|
+
if (delta.usage?.completion !== void 0) {
|
|
20615
|
+
frameUsage = delta.usage;
|
|
20616
|
+
}
|
|
20617
|
+
text += delta.content;
|
|
20618
|
+
reasoning += delta.reasoning;
|
|
20619
|
+
if (delta.finishReason) finishReason = delta.finishReason;
|
|
20620
|
+
for (const event of delta.events) {
|
|
20621
|
+
if (event.type === "reasoning") {
|
|
20622
|
+
opts?.onReasoningDelta?.(event.text);
|
|
20623
|
+
} else if (event.type === "content") {
|
|
20624
|
+
opts?.onTextDelta?.(event.text);
|
|
20625
|
+
} else if (event.type === "tool-call-start") {
|
|
20626
|
+
const existing = toolCallById.get(event.id);
|
|
20627
|
+
if (existing) {
|
|
20628
|
+
existing.name = event.name;
|
|
20629
|
+
} else {
|
|
20630
|
+
toolCallOrder.push(event.id);
|
|
20631
|
+
toolCallById.set(event.id, {
|
|
20632
|
+
id: event.id,
|
|
20633
|
+
name: event.name,
|
|
20634
|
+
argumentsText: ""
|
|
20635
|
+
});
|
|
20636
|
+
}
|
|
20637
|
+
currentToolCallId = event.id;
|
|
20638
|
+
} else {
|
|
20639
|
+
const targetId = event.id ?? currentToolCallId;
|
|
20640
|
+
const target = targetId ? toolCallById.get(targetId) : void 0;
|
|
20641
|
+
if (target) target.argumentsText += event.argsDelta;
|
|
20642
|
+
}
|
|
20643
|
+
}
|
|
20644
|
+
}
|
|
20645
|
+
}
|
|
20646
|
+
} finally {
|
|
20647
|
+
reader.releaseLock();
|
|
20648
|
+
}
|
|
20649
|
+
if (buffer3.length > 0) {
|
|
20650
|
+
throw new Error("Devin Connect upstream ended with an incomplete frame");
|
|
20651
|
+
}
|
|
20652
|
+
if (!sawTrailer) {
|
|
20653
|
+
throw new Error("Devin Connect upstream ended before the terminal trailer");
|
|
20654
|
+
}
|
|
20655
|
+
const toolCalls = toolCallOrder.map((id) => {
|
|
20656
|
+
const call = toolCallById.get(id);
|
|
20657
|
+
return {
|
|
20658
|
+
id: call.id,
|
|
20659
|
+
type: "function",
|
|
20660
|
+
function: {
|
|
20661
|
+
name: call.name,
|
|
20662
|
+
arguments: call.argumentsText || "{}"
|
|
20663
|
+
}
|
|
20664
|
+
};
|
|
20665
|
+
});
|
|
20666
|
+
if (!text && !reasoning && toolCalls.length === 0) {
|
|
20667
|
+
throw new Error("Devin Connect upstream completed without content or tool calls");
|
|
20668
|
+
}
|
|
20669
|
+
const usage = frameUsage ? {
|
|
20670
|
+
prompt_tokens: frameUsage.prompt + frameUsage.cacheRead,
|
|
20671
|
+
completion_tokens: frameUsage.completion ?? 0,
|
|
20672
|
+
total_tokens: frameUsage.prompt + frameUsage.cacheRead + (frameUsage.completion ?? 0) + frameUsage.cacheWrite,
|
|
20673
|
+
...frameUsage.cacheRead > 0 ? { prompt_tokens_details: { cached_tokens: frameUsage.cacheRead } } : {},
|
|
20674
|
+
...frameUsage.cacheWrite > 0 ? { cache_creation_input_tokens: frameUsage.cacheWrite } : {}
|
|
20675
|
+
} : void 0;
|
|
20676
|
+
return {
|
|
20677
|
+
content: text,
|
|
20678
|
+
model: selectedModel,
|
|
20679
|
+
provider: "devin",
|
|
20680
|
+
...usage ? { usage } : {},
|
|
20681
|
+
...reasoning ? { reasoning_content: reasoning } : {},
|
|
20682
|
+
...toolCalls.length > 0 ? { tool_calls: toolCalls } : {},
|
|
20683
|
+
// The upstream finish event wins whenever it is present. A tool call
|
|
20684
|
+
// cut off by the length limit has to stay "length" instead of being
|
|
20685
|
+
// relabelled "tool_calls", so probes/telemetry and any downstream
|
|
20686
|
+
// consumer of the final finish_reason no longer see a truncated turn
|
|
20687
|
+
// mislabelled as a normal one. localLoop keeps its own truncation
|
|
20688
|
+
// gates and excludes tool-bearing turns from them.
|
|
20689
|
+
finish_reason: finishReason ?? (toolCalls.length > 0 ? "tool_calls" : "stop"),
|
|
20690
|
+
stream_complete: true
|
|
20691
|
+
};
|
|
20692
|
+
}
|
|
20693
|
+
};
|
|
20694
|
+
}
|
|
20695
|
+
|
|
20066
20696
|
export {
|
|
20067
20697
|
Option_exports,
|
|
20068
20698
|
Duration_exports,
|
|
@@ -20072,6 +20702,7 @@ export {
|
|
|
20072
20702
|
readActionGate,
|
|
20073
20703
|
evaluateFileWritePolicy,
|
|
20074
20704
|
summarizeToolArguments,
|
|
20705
|
+
formatToolOverflowMarker,
|
|
20075
20706
|
LOCAL_AGENT_CONFIG_MISSING_CODE,
|
|
20076
20707
|
LOCAL_TURN_ABORTED_CODE,
|
|
20077
20708
|
runLocalAgentTurn,
|
|
@@ -20114,5 +20745,7 @@ export {
|
|
|
20114
20745
|
shouldUseGeminiNativeToolRoute,
|
|
20115
20746
|
buildGeminiGenerateContentRequest,
|
|
20116
20747
|
resolveAntigravityFinishReason,
|
|
20117
|
-
fetchAntigravityCloudCodeCompletion
|
|
20748
|
+
fetchAntigravityCloudCodeCompletion,
|
|
20749
|
+
readDevinUpstreamFailure,
|
|
20750
|
+
createDevinProvider
|
|
20118
20751
|
};
|