nolo-cli 0.84.0-alpha.1 → 0.84.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-IULR47HG.js → _executeModel-BPUR2QYH.js} +51 -50
- package/{action-D22U6CTH.js → action-P4TNFGAD.js} +11 -11
- package/{addContentAction-XAPUTGL4.js → addContentAction-MB2HHMDZ.js} +9 -9
- package/{addDialogAgentAction-M7VLLBZM.js → addDialogAgentAction-S2NRBCWW.js} +9 -9
- package/{agentDeleteCommand-2S4WCDQC.js → agentDeleteCommand-MNAA6MIG.js} +32 -30
- package/{agentEmailCommands-V3ADGHX7.js → agentEmailCommands-SK34WJKU.js} +70 -66
- package/{agentGrantCommands-R3VQEZJR.js → agentGrantCommands-M3XFO6EN.js} +2 -2
- package/{agentListCommands-EPK3S274.js → agentListCommands-I26MKI4T.js} +55 -36
- package/{agentMachineCommands-XMZWK7P3.js → agentMachineCommands-M6QDR6P3.js} +32 -30
- package/{agentProviderCommands-65ZC2WB4.js → agentProviderCommands-X3UNW77C.js} +87 -0
- package/{agentPullCommand-N7L2CT7L.js → agentPullCommand-O5MPVJ5E.js} +3 -3
- package/agentRecordCommands-HTHLO2MM.js +129 -0
- package/{agentRunCommand-VUWNWC7C.js → agentRunCommand-IAIRCMTH.js} +70 -65
- package/{agentRunControl-T44MESII.js → agentRunControl-AVJR4JW4.js} +2 -2
- package/{agentRuntimeLocal-YRONTDLM.js → agentRuntimeLocal-3WTYYIT2.js} +32 -26
- package/{agentSlice-2P7OJFES.js → agentSlice-TVP3HINW.js} +10 -10
- package/{appDeleteCommands-YS7UGMP3.js → appDeleteCommands-SB5TNLKY.js} +32 -30
- package/{appDeployCommands-XIE5Z4BE.js → appDeployCommands-2IPKZINV.js} +32 -30
- package/{appDeployStatusCommands-54UDVYET.js → appDeployStatusCommands-K63TFUID.js} +32 -30
- package/{appGetCommands-6XYLBCRN.js → appGetCommands-VU2SLNEH.js} +32 -30
- package/{appListCommands-VEGH7SF5.js → appListCommands-S3T4DJ36.js} +32 -30
- package/{authCommand-JIEOFHXW.js → authCommand-HGP2XTKC.js} +185 -28
- package/{authCommands-ILTBI6JV.js → authCommands-RGOGCPP6.js} +4 -5
- package/builtinSkillRegistry-Q2VVY3SC.js +33 -0
- package/{chatQueueReduxAdapter-GPYCH5Z2.js → chatQueueReduxAdapter-TWIYKVIZ.js} +25 -25
- 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-BOYUESO7.js → chunk-3AMA42ZI.js} +1 -1
- package/{chunk-RZOJRTKR.js → chunk-3BGIKIPF.js} +444 -920
- package/{chunk-HQUORJTM.js → chunk-3BMYXEUW.js} +1 -1
- package/{chunk-EBKMQULC.js → chunk-3IUWIAHP.js} +13 -15
- package/{chunk-NTW5GWDM.js → chunk-3VNWWVKB.js} +2 -0
- package/{chunk-4SZ37KLL.js → chunk-3VUWPRFW.js} +50 -30
- package/{chunk-WL2RKIBF.js → chunk-3YIAR5UI.js} +1 -1
- package/{chunk-DWUCB2A3.js → chunk-42V6BK2E.js} +1 -1
- package/{chunk-AX7RMXSH.js → chunk-4MK3I7Y4.js} +38 -4
- package/{chunk-PF6O3GR3.js → chunk-52Q2IW2X.js} +1340 -1273
- package/{chunk-Y3NZYLPG.js → chunk-5MEYHVIB.js} +1 -1
- package/{chunk-5XTOKQLW.js → chunk-5UTFL4QJ.js} +6 -2
- package/chunk-5ZUL4CUO.js +10 -0
- package/{chunk-6YTOJY35.js → chunk-6D2JFXLY.js} +35 -0
- package/{chunk-E6RGHPDR.js → chunk-6D6VBVEW.js} +4 -6
- package/{chunk-FZGV4FGK.js → chunk-6GFOD3TK.js} +260 -140
- package/{chunk-TMPLPCVX.js → chunk-6OZ36FXI.js} +2 -2
- package/{chunk-PZM3EENV.js → chunk-6Z7MY3V7.js} +1 -1
- 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-ZZCJUXUI.js → chunk-AHAHBQMU.js} +2 -2
- package/{chunk-BJCWNHVU.js → chunk-BFDFRLLQ.js} +2 -2
- package/chunk-BMQ2MJUK.js +153 -0
- package/chunk-BNGW5ASC.js +344 -0
- package/{chunk-2KDR4CWE.js → chunk-BYMV6QZG.js} +24 -1
- package/{chunk-73BR2IQT.js → chunk-CWQINZEA.js} +127 -7
- package/{chunk-HTMVBPOF.js → chunk-DD6XE56O.js} +19 -72
- package/{chunk-CADAR6QU.js → chunk-EYAQT56M.js} +4 -3
- package/{chunk-CJCJF5XB.js → chunk-FDTR4QJ6.js} +4 -2
- package/{chunk-D6XYLSOS.js → chunk-FKNWP6SG.js} +1 -1
- package/{chunk-3VPDELAP.js → chunk-FP76KI2Y.js} +1500 -84
- package/chunk-FV3JEYR3.js +870 -0
- package/{chunk-GCJ3IS5M.js → chunk-GIVFXPWK.js} +177 -6
- package/chunk-GMZLP5DV.js +82 -0
- package/{chunk-LHDV2QUI.js → chunk-GNCCNNZD.js} +4 -2
- package/{chunk-XWNRAIUL.js → chunk-GP5LKBUZ.js} +6 -16
- package/{chunk-PZCTYKGU.js → chunk-GQBOR3G6.js} +2 -2
- package/{chunk-NFT2AOK5.js → chunk-H4AHY5BU.js} +13 -85
- package/{chunk-FNGAF7C4.js → chunk-HAFJ3NDE.js} +137 -12
- package/{chunk-ZVN6I33J.js → chunk-HCT7U36O.js} +9 -5
- package/{chunk-7QVPPOEC.js → chunk-HKNXJGEC.js} +43 -43
- package/{chunk-3JQ2NRYU.js → chunk-HVURBGF3.js} +4 -4
- package/{chunk-OZX2IPKM.js → chunk-HYJFRTLW.js} +2 -2
- package/{chunk-HH65VA5U.js → chunk-I3TQJXQ7.js} +109 -6
- 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-DUJWWUGV.js → chunk-K36IXSCQ.js} +1 -1
- package/{chunk-KRMWO2NN.js → chunk-KAUSRTO6.js} +3 -3
- package/{chunk-7FWPLK4M.js → chunk-LJ5VW2UJ.js} +1 -1
- package/{chunk-GHEJJGJI.js → chunk-LMREEBWT.js} +833 -109
- package/{chunk-RXX4GDIH.js → chunk-LS2ZANRJ.js} +1 -1
- package/chunk-LVIFM7VW.js +1625 -0
- package/{chunk-BJIRLHJR.js → chunk-M2EJHDJP.js} +4 -0
- package/{chunk-EVBFYPDC.js → chunk-MC4XLIJ7.js} +6 -2
- package/{chunk-KEZNSFGD.js → chunk-MZYBSTMH.js} +11 -173
- package/chunk-OCZKATRC.js +129 -0
- package/{chunk-MXUSPS2N.js → chunk-OIVSQH2O.js} +1510 -1592
- package/{chunk-E36HZARC.js → chunk-P5EVSOPA.js} +93 -17
- package/{chunk-SZLVDREM.js → chunk-PBA4UJBK.js} +3 -3
- package/{chunk-URWDSZRW.js → chunk-PMAIQX7A.js} +3 -3
- package/{chunk-AETZ7AD6.js → chunk-Q554LLSI.js} +1 -1
- package/{chunk-AJHEFRGJ.js → chunk-Q67DOFOO.js} +214 -5
- package/{chunk-UZ6XXCVR.js → chunk-QDSINZM3.js} +15 -2
- package/{chunk-NRALD3CC.js → chunk-QSHEEA5N.js} +54 -10
- package/chunk-QU7KDSZX.js +677 -0
- package/{chunk-T25L377S.js → chunk-RPJUFEGR.js} +10 -10
- package/{chunk-QCZX4FTW.js → chunk-SH43IESU.js} +173 -15
- package/{chunk-SPAQ4PVV.js → chunk-SV5IJK6K.js} +1 -1
- package/{chunk-BKJO7LDP.js → chunk-U4OKDZFH.js} +6 -6
- package/{chunk-DM4FBSWG.js → chunk-UDVH2P4A.js} +7 -7
- package/{chunk-4EJ5QYB5.js → chunk-UEVXFHQB.js} +2 -2
- package/{chunk-JYYZCK2Z.js → chunk-V7E4PXQD.js} +1 -1
- package/{chunk-NHRQCXIQ.js → chunk-VMFTFOWF.js} +13 -3
- package/{chunk-YFADVSZE.js → chunk-VRTTFDBM.js} +7 -6
- package/{chunk-U7YP7ECK.js → chunk-WP5UXDA5.js} +84 -13
- package/{chunk-5J7W2VWW.js → chunk-WV42OMV7.js} +6 -265
- package/{chunk-3QPYFHAH.js → chunk-XD2MJFUG.js} +1 -1
- package/{chunk-IDGYOD2O.js → chunk-XP3VVAPG.js} +3174 -223
- package/{chunk-ETLZZQJE.js → chunk-Z2PV6O2T.js} +121 -26
- package/{chunk-BZNGCVAW.js → chunk-Z5625XML.js} +4 -4
- package/{contentThunks-THSCADSK.js → contentThunks-JYWI7G7I.js} +26 -26
- package/{cooldownCommands-BSCH2W7P.js → cooldownCommands-REAWYVTY.js} +2 -2
- package/{createAgentAutomationAction-WGN3UQ5A.js → createAgentAutomationAction-Z4SUJ54Y.js} +26 -26
- package/{createDialogAction-3EN2NLH7.js → createDialogAction-RCHFLVJ2.js} +29 -29
- package/{createPageAction-4VK473QV.js → createPageAction-YK2253XQ.js} +28 -28
- package/{dbSlice-GKGGFNOB.js → dbSlice-A6C6H32X.js} +8 -8
- package/{deleteFile-LWSR674W.js → deleteFile-YG6QMJLU.js} +3 -3
- package/{dialogCommands-PS4NWYY7.js → dialogCommands-X4UOZQWX.js} +36 -32
- package/{dialogSlice-CLV7SVOZ.js → dialogSlice-IVTWLCE2.js} +31 -25
- package/{docCreateCommands-4KANZJR6.js → docCreateCommands-VD6TGHG4.js} +33 -31
- package/{docDeleteCommands-F2S2TRUF.js → docDeleteCommands-OT3R2G4W.js} +34 -32
- package/{docReadCommands-B2WDPZQE.js → docReadCommands-2G7BIXSH.js} +33 -31
- package/{docStore-TDLCHWPF.js → docStore-UENKCCDX.js} +9 -9
- package/{docUpdateCommands-E7TKHRIO.js → docUpdateCommands-45MVJKZA.js} +33 -31
- package/{fetchMessages-DRABNDPZ.js → fetchMessages-EIU7UFFK.js} +3 -4
- package/{getPricing-QVTUQQTM.js → getPricing-LUSEABA6.js} +4 -4
- package/{handleSendMessageAction-AHL3ZHE4.js → handleSendMessageAction-LM2J4HC3.js} +66 -74
- 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-OTABVXOA.js → machineCommands-6N6MQIE6.js} +69 -65
- package/{machineWsRunDispatch-V4EVQSMZ.js → machineWsRunDispatch-7MFKVQCR.js} +65 -61
- package/{memberThunks-KATHH3F4.js → memberThunks-P2ECUJ56.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/pdf-U6KSUEZZ.js +26435 -0
- package/providerPresetApply-XI3WUPTI.js +214 -0
- package/providerRegistry-KEPWWGXD.js +31 -0
- package/{read-LC6HVYBN.js → read-COE3ZYR6.js} +5 -4
- package/{readDocTool-N3ERJHHF.js → readDocTool-5USN4A6V.js} +1 -1
- package/{readlineWorkspace-IIT3FQ6I.js → readlineWorkspace-JWBON5CX.js} +291 -135
- package/{removeDialogAgentAction-F5GPTALR.js → removeDialogAgentAction-W66BJ7CF.js} +12 -12
- package/{runAgentClientLoop-7TQM7IAR.js → runAgentClientLoop-TA4SSPHE.js} +49 -49
- package/{runtimeDoctorCommands-CROTMULY.js → runtimeDoctorCommands-X6WDBEQX.js} +2 -2
- package/{setDialogExtraReferencesAction-AY4ZCF3A.js → setDialogExtraReferencesAction-2ALKG3WA.js} +10 -10
- package/{setPrimaryDialogAgentAction-HPMG7V3R.js → setPrimaryDialogAgentAction-TQZB55F6.js} +12 -12
- package/{settingSlice-OEJA4NQO.js → settingSlice-P4ZW7K5X.js} +10 -10
- package/{spaceCommands-FSYH7AL4.js → spaceCommands-6NSAXB7D.js} +31 -29
- package/{streamAgentChatTurn-6EF6TVFK.js → streamAgentChatTurn-X5ENGUIS.js} +126 -65
- package/{switchDialogAgentAction-HMDZTZ4I.js → switchDialogAgentAction-3KI72HHS.js} +9 -9
- package/{tableCommands-SUNTHAYX.js → tableCommands-O6NWHFKV.js} +1 -1
- package/{toolApiClient-VGYUB4P5.js → toolApiClient-G3M73RTB.js} +3 -3
- package/{tools-R3QNWWTD.js → tools-XRQR7ZZR.js} +45 -45
- package/tuiSummaryLlmCaller-UFGFOIIW.js +128 -0
- package/{updateCommands-Y363MC3L.js → updateCommands-2M74UL7P.js} +2 -2
- package/{updateDialogTitleAction-F3EUOWOB.js → updateDialogTitleAction-ESUUD3GT.js} +46 -29
- package/agentRecordCommands-WFPWLWOF.js +0 -125
- package/chunk-FMODTASJ.js +0 -109
- 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-PWOXTCBF.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
|
@@ -9,7 +9,10 @@ import {
|
|
|
9
9
|
resolveRawAgentInput,
|
|
10
10
|
resolveServerUrl,
|
|
11
11
|
writeUsage
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-V7E4PXQD.js";
|
|
13
|
+
import {
|
|
14
|
+
resolveMachineId
|
|
15
|
+
} from "./chunk-ESHYE7WU.js";
|
|
13
16
|
import {
|
|
14
17
|
agentRunCardLabels,
|
|
15
18
|
createCliLocalRuntimeAdapter,
|
|
@@ -26,8 +29,9 @@ import {
|
|
|
26
29
|
resolveFileWriteGateEnabled,
|
|
27
30
|
resolveLocalUserId,
|
|
28
31
|
t,
|
|
29
|
-
toolLabel
|
|
30
|
-
|
|
32
|
+
toolLabel,
|
|
33
|
+
toolLabelVariants
|
|
34
|
+
} from "./chunk-LMREEBWT.js";
|
|
31
35
|
import {
|
|
32
36
|
createRunActivityTracker,
|
|
33
37
|
popSingleQueueMessage,
|
|
@@ -35,38 +39,36 @@ import {
|
|
|
35
39
|
resolveRunQueuePath,
|
|
36
40
|
settleRunTerminalAuthoritatively,
|
|
37
41
|
spawnLocalBackgroundRun
|
|
38
|
-
} from "./chunk-
|
|
42
|
+
} from "./chunk-I3TQJXQ7.js";
|
|
39
43
|
import {
|
|
44
|
+
clearCredentialAvailability,
|
|
40
45
|
readCredentialEntry,
|
|
41
46
|
recordCredentialProbe,
|
|
42
47
|
resolveCredentialKeyWithFallback
|
|
43
|
-
} from "./chunk-
|
|
48
|
+
} from "./chunk-42V6BK2E.js";
|
|
44
49
|
import {
|
|
45
50
|
getReadableCliDb
|
|
46
|
-
} from "./chunk-
|
|
51
|
+
} from "./chunk-LS2ZANRJ.js";
|
|
47
52
|
import {
|
|
48
53
|
readDbRecord,
|
|
49
54
|
resolveAgentRecordFromHybridStore
|
|
50
|
-
} from "./chunk-
|
|
55
|
+
} from "./chunk-QSHEEA5N.js";
|
|
51
56
|
import {
|
|
52
57
|
isLocalCliAgentKey
|
|
53
|
-
} from "./chunk-
|
|
58
|
+
} from "./chunk-SV5IJK6K.js";
|
|
54
59
|
import {
|
|
55
60
|
CliProviderQuotaError
|
|
56
61
|
} from "./chunk-MP64VFGD.js";
|
|
57
|
-
import {
|
|
58
|
-
resolveMachineId
|
|
59
|
-
} from "./chunk-ESHYE7WU.js";
|
|
60
62
|
import {
|
|
61
63
|
applyModelLayerOverride,
|
|
62
64
|
buildModelLayerOverride
|
|
63
65
|
} from "./chunk-LTRXGFMS.js";
|
|
64
66
|
import {
|
|
65
67
|
formatAgentListCard
|
|
66
|
-
} from "./chunk-
|
|
68
|
+
} from "./chunk-3BGIKIPF.js";
|
|
67
69
|
import {
|
|
68
70
|
isTransientFetchError
|
|
69
|
-
} from "./chunk-
|
|
71
|
+
} from "./chunk-5UTFL4QJ.js";
|
|
70
72
|
import {
|
|
71
73
|
isGatewayHttpStatus
|
|
72
74
|
} from "./chunk-NF64D32W.js";
|
|
@@ -78,17 +80,20 @@ import {
|
|
|
78
80
|
formatStatusRunCard,
|
|
79
81
|
formatStopRunCard,
|
|
80
82
|
isAgentRunTerminalStatus
|
|
81
|
-
} from "./chunk-
|
|
83
|
+
} from "./chunk-3VNWWVKB.js";
|
|
84
|
+
import {
|
|
85
|
+
extractGoogleValidationLink
|
|
86
|
+
} from "./chunk-BMQ2MJUK.js";
|
|
82
87
|
import {
|
|
83
88
|
buildMemorySubjectsForAgent,
|
|
84
89
|
chooseMemoryOwners,
|
|
85
90
|
loadMemoryCandidatesFromDb,
|
|
86
91
|
resolveAgentMemoryPolicy
|
|
87
|
-
} from "./chunk-
|
|
92
|
+
} from "./chunk-MZYBSTMH.js";
|
|
88
93
|
import {
|
|
89
94
|
API_REPORTED_COST_MULTIPLIER,
|
|
90
95
|
parseUiAskChoiceContent
|
|
91
|
-
} from "./chunk-
|
|
96
|
+
} from "./chunk-XP3VVAPG.js";
|
|
92
97
|
import {
|
|
93
98
|
isOAuthApiKeyRef
|
|
94
99
|
} from "./chunk-YYLHWIW6.js";
|
|
@@ -99,50 +104,51 @@ import {
|
|
|
99
104
|
} from "./chunk-TRV2MIDW.js";
|
|
100
105
|
import {
|
|
101
106
|
getDefaultCliLocalRuntimeDb
|
|
102
|
-
} from "./chunk-
|
|
107
|
+
} from "./chunk-2F7RJC6L.js";
|
|
103
108
|
import {
|
|
104
109
|
buildSkillDiscoveryContextLayer
|
|
105
110
|
} from "./chunk-E4MARS3Q.js";
|
|
106
111
|
import {
|
|
107
112
|
parseExternalSkillMarkdown,
|
|
108
113
|
parseSkillDocProtocol
|
|
109
|
-
} from "./chunk-
|
|
114
|
+
} from "./chunk-Q554LLSI.js";
|
|
110
115
|
import {
|
|
111
116
|
LOCAL_AGENT_CONFIG_MISSING_CODE,
|
|
112
117
|
LOCAL_TURN_ABORTED_CODE,
|
|
113
118
|
readActionGate
|
|
114
|
-
} from "./chunk-
|
|
119
|
+
} from "./chunk-52Q2IW2X.js";
|
|
115
120
|
import {
|
|
116
121
|
resolveAgentRuntimeConfigFromRecord
|
|
117
|
-
} from "./chunk-
|
|
122
|
+
} from "./chunk-4MK3I7Y4.js";
|
|
118
123
|
import {
|
|
119
124
|
createThinkParserState,
|
|
120
125
|
flushThinkParser,
|
|
121
126
|
processThinkChunk
|
|
122
127
|
} from "./chunk-N7J63Q6C.js";
|
|
123
128
|
import {
|
|
129
|
+
QUOTA_ERROR_PATTERNS,
|
|
124
130
|
isQuotaExhaustedError,
|
|
125
131
|
isQuotaLimited403Body,
|
|
126
132
|
mergeAvailabilityDeadline,
|
|
127
133
|
resolveCooldownGate
|
|
128
|
-
} from "./chunk-
|
|
134
|
+
} from "./chunk-FDTR4QJ6.js";
|
|
129
135
|
import {
|
|
130
136
|
isAntigravityOAuthAgent
|
|
131
|
-
} from "./chunk-
|
|
137
|
+
} from "./chunk-GNCCNNZD.js";
|
|
132
138
|
import {
|
|
133
139
|
resolveClientVersion
|
|
134
|
-
} from "./chunk-
|
|
140
|
+
} from "./chunk-6OZ36FXI.js";
|
|
135
141
|
import {
|
|
136
142
|
DEFAULT_CONTEXT_WINDOW,
|
|
137
143
|
getModelContextWindow,
|
|
138
144
|
normalizeUsage
|
|
139
|
-
} from "./chunk-
|
|
145
|
+
} from "./chunk-HKNXJGEC.js";
|
|
140
146
|
import {
|
|
141
147
|
clipCompactText
|
|
142
|
-
} from "./chunk-
|
|
148
|
+
} from "./chunk-P5EVSOPA.js";
|
|
143
149
|
import {
|
|
144
150
|
findModelConfig
|
|
145
|
-
} from "./chunk-
|
|
151
|
+
} from "./chunk-OIVSQH2O.js";
|
|
146
152
|
import {
|
|
147
153
|
compactWhitespace
|
|
148
154
|
} from "./chunk-DWLEOOGR.js";
|
|
@@ -167,13 +173,14 @@ import {
|
|
|
167
173
|
CLIENT_VERSION_TOO_OLD_CODE,
|
|
168
174
|
NOLO_CLIENT_VERSION_HEADER,
|
|
169
175
|
buildClientVersionUpgradeMessage
|
|
170
|
-
} from "./chunk-
|
|
176
|
+
} from "./chunk-Q67DOFOO.js";
|
|
171
177
|
import {
|
|
172
178
|
parsePositiveFiniteNumberOrFallback
|
|
173
179
|
} from "./chunk-Y5GCAMGP.js";
|
|
174
180
|
import {
|
|
175
|
-
createMemoryKey
|
|
176
|
-
|
|
181
|
+
createMemoryKey,
|
|
182
|
+
ulid
|
|
183
|
+
} from "./chunk-VMFTFOWF.js";
|
|
177
184
|
import {
|
|
178
185
|
asTrimmedLowercaseString
|
|
179
186
|
} from "./chunk-QSJ3HFEF.js";
|
|
@@ -181,10 +188,13 @@ import {
|
|
|
181
188
|
BUILTIN_NOLO_AGENT_KEY,
|
|
182
189
|
BUILTIN_NOLO_AGENT_NAME,
|
|
183
190
|
builtinAgentCatalogEntryById
|
|
184
|
-
} from "./chunk-
|
|
191
|
+
} from "./chunk-BNGW5ASC.js";
|
|
185
192
|
import {
|
|
186
193
|
parsePublicAgentId
|
|
187
|
-
} from "./chunk-
|
|
194
|
+
} from "./chunk-M2EJHDJP.js";
|
|
195
|
+
import {
|
|
196
|
+
isLevelNotFoundError
|
|
197
|
+
} from "./chunk-OW765XBU.js";
|
|
188
198
|
import {
|
|
189
199
|
asTrimmedString
|
|
190
200
|
} from "./chunk-3EUW3WEO.js";
|
|
@@ -380,6 +390,24 @@ function styleCliText(text, style, enabled = resolveCliColorEnabled()) {
|
|
|
380
390
|
function dimCliText(text, enabled = resolveCliColorEnabled()) {
|
|
381
391
|
return styleCliText(text, "dim", enabled);
|
|
382
392
|
}
|
|
393
|
+
var OSC8_OPEN = "\x1B]8;;";
|
|
394
|
+
var OSC8_CLOSE = "\x1B\\";
|
|
395
|
+
function sanitizeHyperlinkLabel(label) {
|
|
396
|
+
return label.replace(/[\u0000-\u001f\u007f]/g, "");
|
|
397
|
+
}
|
|
398
|
+
function resolveCliHyperlinkEnabled(env = process.env, isTTY = Boolean(process.stdout.isTTY)) {
|
|
399
|
+
const setting = asTrimmedLowercaseString(env.NOLO_CLI_HYPERLINKS);
|
|
400
|
+
if (setting === "0" || setting === "false" || setting === "off") return false;
|
|
401
|
+
if (setting === "1" || setting === "true" || setting === "on") return true;
|
|
402
|
+
return isTTY;
|
|
403
|
+
}
|
|
404
|
+
function formatCliHyperlink(url, label, enabled = resolveCliHyperlinkEnabled()) {
|
|
405
|
+
if (!url) return label;
|
|
406
|
+
const safeLabel = sanitizeHyperlinkLabel(label);
|
|
407
|
+
if (!enabled) return `${safeLabel} (${url})`;
|
|
408
|
+
if (!safeLabel) return url;
|
|
409
|
+
return `${OSC8_OPEN}${url}${OSC8_CLOSE}${safeLabel}${OSC8_OPEN}${OSC8_CLOSE}`;
|
|
410
|
+
}
|
|
383
411
|
|
|
384
412
|
// node_modules/ansi-regex/index.js
|
|
385
413
|
function ansiRegex({ onlyFirst = false } = {}) {
|
|
@@ -614,8 +642,12 @@ function stringWidth(input, options = {}) {
|
|
|
614
642
|
|
|
615
643
|
// packages/cli/tui/tuiAnsi.ts
|
|
616
644
|
var ANSI_ESCAPE_REGEX = /\x1b\[[\x30-\x3f]*[\x20-\x2f]*[\x40-\x7e]/g;
|
|
645
|
+
var OSC8_HYPERLINK_REGEX = /\x1b\]8;;[^\x1b]*\x1b\\/g;
|
|
617
646
|
var ALL_ANSI_ESCAPE_REGEX = ansiRegex();
|
|
618
647
|
var FIRST_ANSI_ESCAPE_REGEX = ansiRegex({ onlyFirst: true });
|
|
648
|
+
function stripOsc8Hyperlinks(text) {
|
|
649
|
+
return text.replace(OSC8_HYPERLINK_REGEX, "");
|
|
650
|
+
}
|
|
619
651
|
function stripAnsi2(text) {
|
|
620
652
|
return text.replace(ANSI_ESCAPE_REGEX, "").replace(ALL_ANSI_ESCAPE_REGEX, "");
|
|
621
653
|
}
|
|
@@ -777,6 +809,7 @@ function visibleWidth(str) {
|
|
|
777
809
|
}
|
|
778
810
|
function truncateAnsi(text, maxWidth) {
|
|
779
811
|
if (maxWidth <= 0) return "";
|
|
812
|
+
text = stripOsc8Hyperlinks(text);
|
|
780
813
|
if (visibleWidth(text) <= maxWidth) return text;
|
|
781
814
|
let width = 0;
|
|
782
815
|
let out = "";
|
|
@@ -817,7 +850,7 @@ function countPhysicalLines(text, columns) {
|
|
|
817
850
|
const lines = text.split("\n");
|
|
818
851
|
let total = 0;
|
|
819
852
|
for (const line of lines) {
|
|
820
|
-
const width =
|
|
853
|
+
const width = visibleWidth(stripOsc8Hyperlinks(line));
|
|
821
854
|
total += Math.max(1, Math.ceil(width / columns));
|
|
822
855
|
}
|
|
823
856
|
return Math.max(total, 1);
|
|
@@ -8190,12 +8223,79 @@ function normalizeListLine(line) {
|
|
|
8190
8223
|
}
|
|
8191
8224
|
return line;
|
|
8192
8225
|
}
|
|
8226
|
+
var TOOL_TREE_HEADER_RE = /^•\s+(.+?)\s+\((\d+)\)$/;
|
|
8227
|
+
var TOOL_TREE_LEAF_RE = /^([├└]──\s+)(.*?)\s{2}(✓|✗|!)(?:\s+(.*))?$/;
|
|
8228
|
+
var TOOL_SINGLE_RE = /^▸\s+(.+?)(?:\s+·\s+(.*?))?(?:\s{2}(✓|✗|!)(?:\s+(.*))?)$/;
|
|
8229
|
+
function plainToolLine(line) {
|
|
8230
|
+
return stripAnsi2(line);
|
|
8231
|
+
}
|
|
8232
|
+
var TOOL_TREE_GROUP_LABELS = new Set(
|
|
8233
|
+
["execShell", "readFile", "fetchWebpage", "exa_search"].flatMap(toolLabelVariants)
|
|
8234
|
+
);
|
|
8235
|
+
function isKnownToolGroupLabel(label) {
|
|
8236
|
+
return TOOL_TREE_GROUP_LABELS.has(label);
|
|
8237
|
+
}
|
|
8238
|
+
function toolTreeHeaderMatch(line) {
|
|
8239
|
+
const match = plainToolLine(line).match(TOOL_TREE_HEADER_RE);
|
|
8240
|
+
return match && isKnownToolGroupLabel(match[1]) ? match : null;
|
|
8241
|
+
}
|
|
8242
|
+
function isToolTreeHeaderLine(line) {
|
|
8243
|
+
return toolTreeHeaderMatch(line) !== null;
|
|
8244
|
+
}
|
|
8245
|
+
function isToolTreeLeafLine(line) {
|
|
8246
|
+
return TOOL_TREE_LEAF_RE.test(plainToolLine(line));
|
|
8247
|
+
}
|
|
8248
|
+
function isToolSingleLine(line) {
|
|
8249
|
+
return TOOL_SINGLE_RE.test(plainToolLine(line));
|
|
8250
|
+
}
|
|
8251
|
+
function isToolGroupBoundary(cur, next) {
|
|
8252
|
+
return isToolTreeLeafLine(cur) && isToolTreeHeaderLine(next);
|
|
8253
|
+
}
|
|
8254
|
+
function statusColorSeq(marker, brightness) {
|
|
8255
|
+
if (marker === "\u2713") return colorSeq("success", brightness);
|
|
8256
|
+
if (marker === "\u2717") return colorSeq("danger", brightness);
|
|
8257
|
+
return colorSeq("warning", brightness);
|
|
8258
|
+
}
|
|
8259
|
+
function styleTuiToolLine(line, brightness) {
|
|
8260
|
+
const plain = plainToolLine(line);
|
|
8261
|
+
const chrome = colorSeq("chrome", brightness);
|
|
8262
|
+
const muted = colorSeq("muted", brightness);
|
|
8263
|
+
const header = toolTreeHeaderMatch(plain);
|
|
8264
|
+
if (header) {
|
|
8265
|
+
return `${chrome}\u2022${STYLE.reset} ${STYLE.bold}${muted}${header[1]}${STYLE.reset} ${chrome}${STYLE.dim}(${header[2]})${STYLE.reset}`;
|
|
8266
|
+
}
|
|
8267
|
+
const leaf = plain.match(TOOL_TREE_LEAF_RE);
|
|
8268
|
+
if (leaf) {
|
|
8269
|
+
const [, connector, detail, marker, statusDetail] = leaf;
|
|
8270
|
+
let rendered = `${chrome}${connector}${STYLE.reset}${chrome}${detail}${STYLE.reset}`;
|
|
8271
|
+
rendered += ` ${statusColorSeq(marker, brightness)}${marker}${STYLE.reset}`;
|
|
8272
|
+
if (statusDetail) {
|
|
8273
|
+
const metaSeq = marker === "\u2713" ? chrome : statusColorSeq(marker, brightness);
|
|
8274
|
+
rendered += ` ${metaSeq}${STYLE.dim}${statusDetail}${STYLE.reset}`;
|
|
8275
|
+
}
|
|
8276
|
+
return rendered;
|
|
8277
|
+
}
|
|
8278
|
+
const single = plain.match(TOOL_SINGLE_RE);
|
|
8279
|
+
if (single) {
|
|
8280
|
+
const [, label, detail, marker, statusDetail] = single;
|
|
8281
|
+
let rendered = `${chrome}\u25B8${STYLE.reset} ${STYLE.bold}${muted}${label}${STYLE.reset}`;
|
|
8282
|
+
if (detail) rendered += ` ${chrome}\xB7 ${detail}${STYLE.reset}`;
|
|
8283
|
+
rendered += ` ${statusColorSeq(marker, brightness)}${marker}${STYLE.reset}`;
|
|
8284
|
+
if (statusDetail) {
|
|
8285
|
+
const metaSeq = marker === "\u2713" ? chrome : statusColorSeq(marker, brightness);
|
|
8286
|
+
rendered += ` ${metaSeq}${STYLE.dim}${statusDetail}${STYLE.reset}`;
|
|
8287
|
+
}
|
|
8288
|
+
return rendered;
|
|
8289
|
+
}
|
|
8290
|
+
return null;
|
|
8291
|
+
}
|
|
8193
8292
|
function isPolishListLikeLine(line) {
|
|
8194
|
-
return LIST_LIKE_RE_FOR_GUARD.test(normalizeListLine(line));
|
|
8293
|
+
return LIST_LIKE_RE_FOR_GUARD.test(normalizeListLine(plainToolLine(line)));
|
|
8195
8294
|
}
|
|
8196
|
-
var LIST_LIKE_RE_FOR_GUARD = /^\s*(?:•|☐|☑|\d+\.)\s|^\s*[\u2460-\u2473]|^\s*[├└]──\s/;
|
|
8295
|
+
var LIST_LIKE_RE_FOR_GUARD = /^\s*(?:•|☐|☑|\d+\.)\s|^\s*[\u2460-\u2473]|^\s*[├└]──\s|^\s*▸\s/;
|
|
8197
8296
|
function polishBreathInsertsBlankBetween(cur, next) {
|
|
8198
8297
|
if (cur === "" || next === "") return false;
|
|
8298
|
+
if (isToolGroupBoundary(cur, next)) return true;
|
|
8199
8299
|
return isPolishListLikeLine(cur) !== isPolishListLikeLine(next);
|
|
8200
8300
|
}
|
|
8201
8301
|
function convertMarkdownTablesForTerminal(text) {
|
|
@@ -8265,16 +8365,14 @@ function polishAssistantStructure(text, options = {}) {
|
|
|
8265
8365
|
return line;
|
|
8266
8366
|
});
|
|
8267
8367
|
const afterHeading = maskedLines.join("\n").replace(/([^\n])\n(#{1,3} )/g, "$1\n\n$2").replace(/^(#{1,3} .+)\n(?!\n)/gm, "$1\n\n").replace(/\n{4,}/g, "\n\n\n");
|
|
8268
|
-
const LIST_LIKE = /^\s*(?:•|☐|☑|\d+\.)\s|^\s*[\u2460-\u2473]|^\s*[├└]──\s/;
|
|
8269
8368
|
const headingLines = afterHeading.split("\n");
|
|
8270
8369
|
const breathed = [];
|
|
8271
8370
|
for (let i = 0; i < headingLines.length; i++) {
|
|
8272
8371
|
breathed.push(headingLines[i]);
|
|
8273
8372
|
const cur = headingLines[i];
|
|
8274
8373
|
const next = headingLines[i + 1];
|
|
8275
|
-
if (
|
|
8276
|
-
if (
|
|
8277
|
-
breathed.push("");
|
|
8374
|
+
if (next === void 0) continue;
|
|
8375
|
+
if (polishBreathInsertsBlankBetween(cur, next)) breathed.push("");
|
|
8278
8376
|
}
|
|
8279
8377
|
const polishedMasked = breathed.join("\n");
|
|
8280
8378
|
const polished = polishedMasked.replace(
|
|
@@ -8284,6 +8382,8 @@ function polishAssistantStructure(text, options = {}) {
|
|
|
8284
8382
|
return options.trimEdges === false ? polished : polished.trim();
|
|
8285
8383
|
}
|
|
8286
8384
|
function styleRichMarkdownLine(line, brightness) {
|
|
8385
|
+
const toolLine = styleTuiToolLine(line, brightness);
|
|
8386
|
+
if (toolLine !== null) return toolLine;
|
|
8287
8387
|
const heading = line.match(/^(#{1,3})\s+(.+)$/);
|
|
8288
8388
|
if (heading) {
|
|
8289
8389
|
const level = heading[1].length;
|
|
@@ -8435,16 +8535,23 @@ function emitFormattedAssistantBlock(write, text, trailingNewline = false) {
|
|
|
8435
8535
|
}
|
|
8436
8536
|
function classifyStreamLine(line) {
|
|
8437
8537
|
if (line === "") return "blank";
|
|
8438
|
-
|
|
8538
|
+
const plain = plainToolLine(line);
|
|
8539
|
+
if (isToolTreeHeaderLine(plain)) return "tool-header";
|
|
8540
|
+
if (isToolTreeLeafLine(plain)) return "tool-leaf";
|
|
8541
|
+
if (isToolSingleLine(plain)) return "tool";
|
|
8542
|
+
if (TASK_LIST_RE.test(plain) || UNORDERED_LIST_RE.test(plain) || ORDERED_LIST_RE.test(plain) || /^\s*(?:•|☐|☑)\s/.test(plain) || /^\s*[\u2460-\u2473]/.test(plain)) {
|
|
8439
8543
|
return "list";
|
|
8440
8544
|
}
|
|
8545
|
+
if (isPolishListLikeLine(plain)) return "list";
|
|
8441
8546
|
return "prose";
|
|
8442
8547
|
}
|
|
8548
|
+
function isStreamListLike(kind) {
|
|
8549
|
+
return kind === "list" || kind === "tool-header" || kind === "tool-leaf" || kind === "tool";
|
|
8550
|
+
}
|
|
8443
8551
|
function needsListProseBreath(prev, next) {
|
|
8444
8552
|
if (prev === null || prev === "blank" || next === "blank") return false;
|
|
8445
|
-
|
|
8446
|
-
|
|
8447
|
-
return prevList !== nextList;
|
|
8553
|
+
if (prev === "tool-leaf" && next === "tool-header") return true;
|
|
8554
|
+
return isStreamListLike(prev) !== isStreamListLike(next);
|
|
8448
8555
|
}
|
|
8449
8556
|
function createRenderAwareStreamWriter(args) {
|
|
8450
8557
|
const brightness = resolveTuiBrightness();
|
|
@@ -9802,6 +9909,7 @@ ${this.text}
|
|
|
9802
9909
|
// packages/cli/client/agentRunOutput.ts
|
|
9803
9910
|
var IDENTITY_LABEL_SEPARATOR = " > ";
|
|
9804
9911
|
var THINKING_PREVIEW_BUFFER_LIMIT = 512;
|
|
9912
|
+
var TUI_PROGRESS_BUFFER_LIMIT = 1200;
|
|
9805
9913
|
function appendThinkingPreview(current, chunk, limit = THINKING_PREVIEW_BUFFER_LIMIT) {
|
|
9806
9914
|
if (limit <= 0) return "";
|
|
9807
9915
|
const combined = current + chunk;
|
|
@@ -9815,6 +9923,14 @@ function formatCompactionSummaryLine(event) {
|
|
|
9815
9923
|
return `${STYLE.dim}\u81EA\u52A8\u4E0A\u4E0B\u6587\u538B\u7F29\u5931\u8D25${reason}\uFF0C\u672C\u8F6E\u4EE5\u672A\u538B\u7F29\u4E0A\u4E0B\u6587\u7EE7\u7EED\u3002\u82E5\u53CD\u590D\u51FA\u73B0\u53EF\u624B\u52A8 /compact\u3002${STYLE.reset}
|
|
9816
9924
|
`;
|
|
9817
9925
|
}
|
|
9926
|
+
if (event.skipped) {
|
|
9927
|
+
if (event.skipReason === "adapter-missing-summary-methods" || event.skipReason === "load-summary-failed") {
|
|
9928
|
+
return `${STYLE.dim}\u81EA\u52A8\u4E0A\u4E0B\u6587\u538B\u7F29\u4E0D\u53EF\u7528\uFF08${event.skipReason}\uFF09\uFF0C\u672C\u8F6E\u4E0D\u538B\u7F29\u3002${STYLE.reset}
|
|
9929
|
+
`;
|
|
9930
|
+
}
|
|
9931
|
+
return "";
|
|
9932
|
+
}
|
|
9933
|
+
if (!event.summaryGenerated) return "";
|
|
9818
9934
|
let detail = "\u751F\u6210\u5386\u53F2\u6458\u8981";
|
|
9819
9935
|
const saved = typeof event.savedTokens === "number" ? event.savedTokens : void 0;
|
|
9820
9936
|
let line = `\u5DF2\u538B\u7F29\u4E0A\u4E0B\u6587\uFF1A${detail}`;
|
|
@@ -9855,6 +9971,14 @@ function formatToolJsonEvent(event) {
|
|
|
9855
9971
|
})}
|
|
9856
9972
|
`;
|
|
9857
9973
|
}
|
|
9974
|
+
function shouldPromoteTuiNarration(text) {
|
|
9975
|
+
if (text.length >= TUI_PROGRESS_BUFFER_LIMIT) return true;
|
|
9976
|
+
return /(^|\n)\s*(?:#{1,3}\s|```|[-*+]\s|\d+[.)]\s)/.test(text);
|
|
9977
|
+
}
|
|
9978
|
+
function narrationActivityLabel(text) {
|
|
9979
|
+
const oneLine = stripAnsi2(text).replace(/[`*_#>]/g, "").replace(/\s+/g, " ").trim();
|
|
9980
|
+
return truncateThinkingHint(oneLine, 60);
|
|
9981
|
+
}
|
|
9858
9982
|
function createCliTurnOutput(params) {
|
|
9859
9983
|
const { options } = params;
|
|
9860
9984
|
const workingLabel = params.workingLabel ?? `${options.agentName} -> working`;
|
|
@@ -9863,7 +9987,8 @@ function createCliTurnOutput(params) {
|
|
|
9863
9987
|
tuiTrees: options.output.tuiTrees === true
|
|
9864
9988
|
});
|
|
9865
9989
|
const eventMode = resolveAgentEventMode(options);
|
|
9866
|
-
const
|
|
9990
|
+
const assistantLabelManaged = options.output.assistantLabelManaged === true;
|
|
9991
|
+
const showThinking = !assistantLabelManaged && options.showThinking !== false;
|
|
9867
9992
|
let streamedAssistantText = false;
|
|
9868
9993
|
let everStreamedAnyText = false;
|
|
9869
9994
|
let printedAssistantLabel = false;
|
|
@@ -9900,7 +10025,6 @@ function createCliTurnOutput(params) {
|
|
|
9900
10025
|
}
|
|
9901
10026
|
};
|
|
9902
10027
|
let compactionEvent = null;
|
|
9903
|
-
const assistantLabelManaged = options.output.assistantLabelManaged === true;
|
|
9904
10028
|
const writeToolOutput = (chunk) => {
|
|
9905
10029
|
if (!chunk) return;
|
|
9906
10030
|
if (typeof options.output.writeToolBlock === "function") {
|
|
@@ -9912,9 +10036,25 @@ function createCliTurnOutput(params) {
|
|
|
9912
10036
|
const renderWriter = createRenderAwareStreamWriter({
|
|
9913
10037
|
write: (chunk) => options.output.write(chunk)
|
|
9914
10038
|
});
|
|
10039
|
+
let pendingTuiNarration = "";
|
|
10040
|
+
let tuiNarrationPromoted = false;
|
|
10041
|
+
const flushPendingTuiNarration = () => {
|
|
10042
|
+
if (!pendingTuiNarration) return;
|
|
10043
|
+
formatToolEvent.reset?.();
|
|
10044
|
+
renderWriter.push(pendingTuiNarration);
|
|
10045
|
+
pendingTuiNarration = "";
|
|
10046
|
+
tuiNarrationPromoted = true;
|
|
10047
|
+
streamedAssistantText = true;
|
|
10048
|
+
options.activityReporter?.(null);
|
|
10049
|
+
};
|
|
10050
|
+
const dropPendingTuiProgress = () => {
|
|
10051
|
+
pendingTuiNarration = "";
|
|
10052
|
+
tuiNarrationPromoted = false;
|
|
10053
|
+
options.activityReporter?.(null);
|
|
10054
|
+
};
|
|
9915
10055
|
const writeVisibleAssistantChunk = (chunk) => {
|
|
9916
10056
|
if (!chunk) return;
|
|
9917
|
-
formatToolEvent.reset?.();
|
|
10057
|
+
if (!assistantLabelManaged) formatToolEvent.reset?.();
|
|
9918
10058
|
const parsed = processThinkChunk(chunk, thinkState);
|
|
9919
10059
|
thinkState = parsed.state;
|
|
9920
10060
|
if (!parsed.content && !parsed.reasoning) return;
|
|
@@ -9930,8 +10070,23 @@ ${options.agentName}${IDENTITY_LABEL_SEPARATOR}`);
|
|
|
9930
10070
|
}
|
|
9931
10071
|
printedAssistantLabel = true;
|
|
9932
10072
|
}
|
|
9933
|
-
streamedAssistantText = true;
|
|
9934
10073
|
everStreamedAnyText = true;
|
|
10074
|
+
if (assistantLabelManaged) {
|
|
10075
|
+
if (tuiNarrationPromoted) {
|
|
10076
|
+
renderWriter.push(parsed.content);
|
|
10077
|
+
streamedAssistantText = true;
|
|
10078
|
+
return;
|
|
10079
|
+
}
|
|
10080
|
+
pendingTuiNarration += parsed.content;
|
|
10081
|
+
if (shouldPromoteTuiNarration(pendingTuiNarration)) {
|
|
10082
|
+
flushPendingTuiNarration();
|
|
10083
|
+
} else {
|
|
10084
|
+
const label = narrationActivityLabel(pendingTuiNarration);
|
|
10085
|
+
if (label) options.activityReporter?.(label);
|
|
10086
|
+
}
|
|
10087
|
+
return;
|
|
10088
|
+
}
|
|
10089
|
+
streamedAssistantText = true;
|
|
9935
10090
|
renderWriter.push(parsed.content);
|
|
9936
10091
|
};
|
|
9937
10092
|
const handleToolEvent = (event) => {
|
|
@@ -9947,6 +10102,9 @@ ${options.agentName}${IDENTITY_LABEL_SEPARATOR}`);
|
|
|
9947
10102
|
return;
|
|
9948
10103
|
}
|
|
9949
10104
|
if (event.type === "tool-call") {
|
|
10105
|
+
if (assistantLabelManaged && pendingTuiNarration) {
|
|
10106
|
+
dropPendingTuiProgress();
|
|
10107
|
+
}
|
|
9950
10108
|
renderWriter.flush();
|
|
9951
10109
|
formatToolEvent(event);
|
|
9952
10110
|
endThinkingPhase();
|
|
@@ -9954,6 +10112,7 @@ ${options.agentName}${IDENTITY_LABEL_SEPARATOR}`);
|
|
|
9954
10112
|
options.output.write("\n");
|
|
9955
10113
|
streamedAssistantText = false;
|
|
9956
10114
|
}
|
|
10115
|
+
if (assistantLabelManaged) tuiNarrationPromoted = false;
|
|
9957
10116
|
const activeLabel = formatConservativeActiveToolLabel(event);
|
|
9958
10117
|
spinner.show(activeLabel);
|
|
9959
10118
|
options.activityReporter?.(activeLabel);
|
|
@@ -9977,6 +10136,26 @@ ${options.agentName}${IDENTITY_LABEL_SEPARATOR}`);
|
|
|
9977
10136
|
return {
|
|
9978
10137
|
spinner,
|
|
9979
10138
|
eventMode,
|
|
10139
|
+
/**
|
|
10140
|
+
* Terminal cleanup for abort/error paths that never reach `finish()`.
|
|
10141
|
+
*
|
|
10142
|
+
* A user abort discards the transient TUI progress buffer: the user stopped
|
|
10143
|
+
* on purpose and the dock already showed that text as activity. A genuine
|
|
10144
|
+
* failure must not swallow prose that never got the chance to be *proven*
|
|
10145
|
+
* durable (only a following tool call proves "progress"), so it promotes the
|
|
10146
|
+
* pending buffer and flushes what was already promoted — otherwise a short
|
|
10147
|
+
* final answer followed by a transport error disappears from the transcript.
|
|
10148
|
+
*/
|
|
10149
|
+
cancel(cleanup) {
|
|
10150
|
+
if (assistantLabelManaged && cleanup?.preservePendingNarration) {
|
|
10151
|
+
flushPendingTuiNarration();
|
|
10152
|
+
if (streamedAssistantText) {
|
|
10153
|
+
renderWriter.flush();
|
|
10154
|
+
options.output.write("\n");
|
|
10155
|
+
}
|
|
10156
|
+
}
|
|
10157
|
+
dropPendingTuiProgress();
|
|
10158
|
+
},
|
|
9980
10159
|
pushText(chunk) {
|
|
9981
10160
|
writeVisibleAssistantChunk(chunk);
|
|
9982
10161
|
},
|
|
@@ -9984,21 +10163,39 @@ ${options.agentName}${IDENTITY_LABEL_SEPARATOR}`);
|
|
|
9984
10163
|
markThinkingDelta(chunk);
|
|
9985
10164
|
},
|
|
9986
10165
|
handleToolEvent,
|
|
9987
|
-
/** 记录一条 compaction 观测事件(TUI 在 turn 结束时渲染一行 dim 摘要)。 */
|
|
9988
10166
|
recordCompaction(event) {
|
|
9989
|
-
|
|
10167
|
+
const significance = (e) => e.failed ? 4 : e.summaryGenerated ? 3 : e.compressed ? 2 : 1;
|
|
10168
|
+
if (!compactionEvent || significance(event) >= significance(compactionEvent)) {
|
|
10169
|
+
compactionEvent = event;
|
|
10170
|
+
}
|
|
9990
10171
|
},
|
|
9991
10172
|
showWorking(label) {
|
|
9992
10173
|
const activeLabel = label ?? workingLabel;
|
|
9993
10174
|
spinner.show(activeLabel);
|
|
9994
10175
|
options.activityReporter?.(activeLabel);
|
|
9995
10176
|
},
|
|
10177
|
+
/**
|
|
10178
|
+
* Pre-delta turn phase label (ctx-overflow-feedback batch 3).
|
|
10179
|
+
*
|
|
10180
|
+
* localLoop 在首个 provider delta 之前依次发出 turn-phase 事件
|
|
10181
|
+
* (validating-context → compacting → waiting-provider);此前 CLI 只有
|
|
10182
|
+
* llm-start 才进入明确 working 状态,压缩期间 spinner 停在通用
|
|
10183
|
+
* working 文案上,用户无法区分「卡在检查上下文 / 压缩 / 等模型」。
|
|
10184
|
+
* 两个显示面(bare CLI 的 spinner 与 TUI 的 dock activityReporter)与
|
|
10185
|
+
* showWorking 走同一条投影,保证两端文案不漂移。
|
|
10186
|
+
*/
|
|
10187
|
+
showPhase(phase) {
|
|
10188
|
+
const label = phase === "validating-context" ? t("contextChecking") : phase === "compacting" ? t("contextCompacting") : t("waitingForModel");
|
|
10189
|
+
spinner.show(label);
|
|
10190
|
+
options.activityReporter?.(label);
|
|
10191
|
+
},
|
|
9996
10192
|
finish(fallbackContent) {
|
|
9997
10193
|
const flushedThink = flushThinkParser(thinkState);
|
|
9998
10194
|
thinkState = flushedThink.state;
|
|
9999
10195
|
if (flushedThink.content) {
|
|
10000
10196
|
writeVisibleAssistantChunk(flushedThink.content);
|
|
10001
10197
|
}
|
|
10198
|
+
if (assistantLabelManaged) flushPendingTuiNarration();
|
|
10002
10199
|
endThinkingPhase();
|
|
10003
10200
|
spinner.stop();
|
|
10004
10201
|
options.activityReporter?.(null);
|
|
@@ -10103,6 +10300,7 @@ async function readStreamingAgentRun(options, res, existingSpinner) {
|
|
|
10103
10300
|
let content = "";
|
|
10104
10301
|
let dialogId;
|
|
10105
10302
|
let usage;
|
|
10303
|
+
let sawDone = false;
|
|
10106
10304
|
const handlePayload = (payload) => {
|
|
10107
10305
|
if (typeof payload?.dialogId === "string" && payload.dialogId.trim()) {
|
|
10108
10306
|
dialogId = payload.dialogId;
|
|
@@ -10115,6 +10313,7 @@ async function readStreamingAgentRun(options, res, existingSpinner) {
|
|
|
10115
10313
|
}
|
|
10116
10314
|
if (payload?.type === "done") {
|
|
10117
10315
|
usage = payload.usage;
|
|
10316
|
+
sawDone = true;
|
|
10118
10317
|
return;
|
|
10119
10318
|
}
|
|
10120
10319
|
if (payload?.type === "dialog" || payload?.type === "status") {
|
|
@@ -10168,6 +10367,9 @@ async function readStreamingAgentRun(options, res, existingSpinner) {
|
|
|
10168
10367
|
}
|
|
10169
10368
|
} catch (error) {
|
|
10170
10369
|
turnOutput.spinner.stop();
|
|
10370
|
+
turnOutput.cancel({
|
|
10371
|
+
preservePendingNarration: !options.abortSignal?.aborted
|
|
10372
|
+
});
|
|
10171
10373
|
if (options.abortSignal?.aborted) {
|
|
10172
10374
|
return {
|
|
10173
10375
|
exitCode: 0,
|
|
@@ -10197,6 +10399,15 @@ ${describeClientVersionTooOldFailure(message, error)}`);
|
|
|
10197
10399
|
`);
|
|
10198
10400
|
return { exitCode: 1 };
|
|
10199
10401
|
}
|
|
10402
|
+
if (options.abortSignal?.aborted && !sawDone) {
|
|
10403
|
+
turnOutput.spinner.stop();
|
|
10404
|
+
turnOutput.cancel();
|
|
10405
|
+
return {
|
|
10406
|
+
exitCode: 0,
|
|
10407
|
+
...dialogId ? { dialogId } : {},
|
|
10408
|
+
streamInterrupted: true
|
|
10409
|
+
};
|
|
10410
|
+
}
|
|
10200
10411
|
turnOutput.finish(content);
|
|
10201
10412
|
const usageText = formatUsage(usage, dialogId);
|
|
10202
10413
|
if (usageText && shouldShowUsage(options.env))
|
|
@@ -10411,9 +10622,9 @@ function findCollapsedPasteSpanAt(buffer, pos, opts = {}) {
|
|
|
10411
10622
|
}
|
|
10412
10623
|
|
|
10413
10624
|
// packages/cli/client/agentRun.ts
|
|
10414
|
-
import { ulid } from "ulid";
|
|
10625
|
+
import { ulid as ulid2 } from "ulid";
|
|
10415
10626
|
async function loadRunLocalAgentTurn() {
|
|
10416
|
-
const { runLocalAgentTurn } = await import("./agentRuntimeLocal-
|
|
10627
|
+
const { runLocalAgentTurn } = await import("./agentRuntimeLocal-3WTYYIT2.js");
|
|
10417
10628
|
return runLocalAgentTurn;
|
|
10418
10629
|
}
|
|
10419
10630
|
var stripDebugNoise = (s) => s.replace(/\s*raw="[\s\S]*"/g, "").replace(/\s*raw=\S+/g, "").replace(/\s*headers=\[[^\]]*\]/g, "").replace(/\s*headers=\S+/g, "").trim();
|
|
@@ -10676,27 +10887,62 @@ function isMissingLocalAgentConfigError(error, agentRef) {
|
|
|
10676
10887
|
}
|
|
10677
10888
|
var PROVIDER_HTTP_FAILED_RE = /(.+?) provider failed:\s*HTTP\s+(\d+)\b/i;
|
|
10678
10889
|
var PLATFORM_TRANSPORT_RE = /\bplatform provider failed\b/i;
|
|
10890
|
+
var EXTRA_RATE_LIMIT_TEXT_RE = /\brate[\s_-]?limit(?:ed|ing|s)?\b|\bresource[_\s-]?exhausted\b|\bmax_concurrent_reached\b/i;
|
|
10891
|
+
function looksLikeRateLimitedText(message) {
|
|
10892
|
+
return EXTRA_RATE_LIMIT_TEXT_RE.test(message) || QUOTA_ERROR_PATTERNS.some((pattern) => pattern.test(message));
|
|
10893
|
+
}
|
|
10894
|
+
var AUTH_TEXT_SIGNAL_RE = /\b401\b|unauthori[sz]ed|invalid[_\s-]?(?:api[_\s-]?key|token|credential)s?|(?:api[_\s-]?key|token|credential)s?[_\s-](?:invalid|expired|rejected|missing|not[_\s-]?found)|authentication[_\s-]?(?:error|failed|required)/i;
|
|
10895
|
+
var QUOTA_EXHAUSTED_EXTRA_RE = /insufficient[_\s-]?(?:quota|balance|credits?)|余额不足|额度已?用尽/i;
|
|
10896
|
+
function looksLikeQuotaExhaustedText(message) {
|
|
10897
|
+
return isQuotaLimited403Body(message) || QUOTA_EXHAUSTED_EXTRA_RE.test(message);
|
|
10898
|
+
}
|
|
10899
|
+
var BARE_UPSTREAM_5XX_RE = /\bHTTP[:\s]+(5\d\d)\b|\bstatus[:\s=]+(5\d\d)\b|\breturned error\s+(5\d\d)\b/i;
|
|
10679
10900
|
function classifyLocalRunError(message) {
|
|
10680
10901
|
const m = message.match(PROVIDER_HTTP_FAILED_RE);
|
|
10681
|
-
if (
|
|
10682
|
-
|
|
10683
|
-
|
|
10684
|
-
|
|
10685
|
-
|
|
10686
|
-
|
|
10687
|
-
|
|
10688
|
-
|
|
10689
|
-
|
|
10690
|
-
|
|
10691
|
-
|
|
10902
|
+
if (m) {
|
|
10903
|
+
const status = Number(m[2]);
|
|
10904
|
+
const transport2 = PLATFORM_TRANSPORT_RE.test(message) ? "platform" : "local";
|
|
10905
|
+
const quotaExhausted = looksLikeQuotaExhaustedText(message);
|
|
10906
|
+
if (status === 401) {
|
|
10907
|
+
return { kind: "auth", transport: transport2, status };
|
|
10908
|
+
}
|
|
10909
|
+
if (status === 403) {
|
|
10910
|
+
return quotaExhausted ? { kind: "rate-limit", transport: transport2, status, quotaExhausted: true } : { kind: "auth", transport: transport2, status };
|
|
10911
|
+
}
|
|
10912
|
+
if (status === 400 || status === 422) {
|
|
10913
|
+
return { kind: "rejected-payload", transport: transport2, status };
|
|
10914
|
+
}
|
|
10915
|
+
if (status === 429) {
|
|
10916
|
+
return {
|
|
10917
|
+
kind: "rate-limit",
|
|
10918
|
+
transport: transport2,
|
|
10919
|
+
status,
|
|
10920
|
+
...quotaExhausted ? { quotaExhausted: true } : {}
|
|
10921
|
+
};
|
|
10922
|
+
}
|
|
10923
|
+
if (status >= 500 && status <= 599) {
|
|
10924
|
+
return { kind: "transient", transport: transport2, status };
|
|
10925
|
+
}
|
|
10926
|
+
return { kind: "upstream", transport: transport2, status };
|
|
10692
10927
|
}
|
|
10693
|
-
|
|
10694
|
-
|
|
10928
|
+
const transport = PLATFORM_TRANSPORT_RE.test(message) ? "platform" : "local";
|
|
10929
|
+
if (AUTH_TEXT_SIGNAL_RE.test(message)) return { kind: "generic" };
|
|
10930
|
+
if (looksLikeRateLimitedText(message)) {
|
|
10931
|
+
const quotaExhausted = looksLikeQuotaExhaustedText(message);
|
|
10932
|
+
return {
|
|
10933
|
+
kind: "rate-limit",
|
|
10934
|
+
transport,
|
|
10935
|
+
status: 429,
|
|
10936
|
+
statusInferred: true,
|
|
10937
|
+
...quotaExhausted ? { quotaExhausted: true } : {}
|
|
10938
|
+
};
|
|
10695
10939
|
}
|
|
10696
|
-
|
|
10940
|
+
const bare5xx = message.match(BARE_UPSTREAM_5XX_RE);
|
|
10941
|
+
if (bare5xx) {
|
|
10942
|
+
const status = Number(bare5xx[1] ?? bare5xx[2] ?? bare5xx[3]);
|
|
10697
10943
|
return { kind: "transient", transport, status };
|
|
10698
10944
|
}
|
|
10699
|
-
return { kind: "
|
|
10945
|
+
return { kind: "generic" };
|
|
10700
10946
|
}
|
|
10701
10947
|
var HISTORY_REPLAY_REJECTION_RE = /invalid_request_error|invalid\s+tool\s+call\s+arguments?/i;
|
|
10702
10948
|
var RUN_UNAVAILABLE_PREFIX = "[nolo] auto runtime: local run unavailable";
|
|
@@ -10705,6 +10951,22 @@ var SERVER_FALLBACK_HINT = "or use --server to run on the server explicitly.";
|
|
|
10705
10951
|
function buildAuthFailure(ctx) {
|
|
10706
10952
|
const platformNoToken = ctx.where === "server chat proxy" && isAuthNoTokenBody(ctx.message);
|
|
10707
10953
|
const fix = platformNoToken ? `This install is not logged in \u2014 run \`nolo login\`, or set AUTH_TOKEN / NOLO_SERVER` : ctx.where === "server chat proxy" ? `Check the agent's provider/api-key settings on nolo.chat` : `Fix the local credential/config and retry`;
|
|
10954
|
+
const { url: validationUrl, text: validationText } = extractGoogleValidationLink(ctx.message);
|
|
10955
|
+
const validationLabel = validationText || "Verify your account";
|
|
10956
|
+
if (validationUrl) {
|
|
10957
|
+
const linkLine = `
|
|
10958
|
+
${formatCliHyperlink(validationUrl, validationLabel)}`;
|
|
10959
|
+
const rawLine = resolveCliHyperlinkEnabled() ? `
|
|
10960
|
+
\u70B9\u4E0D\u4E86\u5C31\u590D\u5236\u8FD9\u884C: ${validationUrl}` : "";
|
|
10961
|
+
const verifyHint = `
|
|
10962
|
+
\u24D8 \u60F3\u4E00\u952E\u6253\u5F00\uFF1F\u8DD1 \`nolo auth antigravity --verify\` \u2014\u2014 \u5B83\u4F1A\u7528\u672C\u5730\u51ED\u8BC1\u62FF\u5230\u5F53\u524D\u9A8C\u8BC1\u94FE\u63A5\u5E76\u76F4\u63A5\u62C9\u8D77\u6D4F\u89C8\u5668\u3002`;
|
|
10963
|
+
const retryLine = `
|
|
10964
|
+
\u9A8C\u8BC1\u5B8C\u6210\u540E\u76F4\u63A5\u91CD\u8BD5\u521A\u624D\u7684\u547D\u4EE4\u5373\u53EF\uFF0Ctoken \u4E0D\u7528\u91CD\u65B0\u767B\u5F55\u3002`;
|
|
10965
|
+
return `${RUN_UNAVAILABLE_PREFIX} (${ctx.where} returned HTTP ${ctx.status}: Google requires a one-time account verification \u2014 your credential is fine).
|
|
10966
|
+
Open this link in a browser signed into ${ctx.credentialAccountId ? `\`${ctx.credentialAccountId}\`` : "the Google account behind this credential"}:${linkLine}${rawLine}${verifyHint}${retryLine}
|
|
10967
|
+
Detail: ${ctx.message} ${NO_FALLBACK} Use --server to run on the server explicitly.
|
|
10968
|
+
`;
|
|
10969
|
+
}
|
|
10708
10970
|
return `${RUN_UNAVAILABLE_PREFIX} (${ctx.where} returned HTTP ${ctx.status}, auth rejected). Detail: ${ctx.message} ${NO_FALLBACK} ${fix}, ${SERVER_FALLBACK_HINT}.
|
|
10709
10971
|
`;
|
|
10710
10972
|
}
|
|
@@ -10717,9 +10979,18 @@ function buildRejectedPayloadFailure(ctx) {
|
|
|
10717
10979
|
return `${RUN_UNAVAILABLE_PREFIX} (${ctx.where} returned HTTP ${ctx.status}, the provider rejected the request body \u2014 this is NOT a local credential/config issue). Detail: ${ctx.message}${cause} ${NO_FALLBACK} Use --server to run on the server explicitly, or start a fresh dialog.
|
|
10718
10980
|
`;
|
|
10719
10981
|
}
|
|
10982
|
+
var RATE_LIMIT_RESET_HINT_RE = /retry[-_\s]?after\s*[:=]?\s*\d[\w:-]*|resets?\s+(?:in|at)\s+\d[\w:-]*(?:[ T]\d[\w:-]*)?/i;
|
|
10983
|
+
function extractRateLimitResetHint(message) {
|
|
10984
|
+
const match = message.match(RATE_LIMIT_RESET_HINT_RE);
|
|
10985
|
+
return match ? match[0].trim() : void 0;
|
|
10986
|
+
}
|
|
10720
10987
|
function buildRateLimitFailure(ctx) {
|
|
10721
10988
|
const cooldownNote = ctx.cooldownUntil ? ` \u5DF2\u6807\u8BB0\u51B7\u5374\u81F3 ${ctx.cooldownUntil}\uFF0C\u5230\u671F\u524D\u6D3E\u53D1\u4F1A\u88AB\u51B7\u5374\u95E8\u63A7\u62E6\u622A\uFF08\u5230\u671F\u81EA\u52A8 probe \u6062\u590D\uFF09\u3002` : "";
|
|
10722
|
-
|
|
10989
|
+
const headline = ctx.statusInferred ? `${ctx.where} hit an upstream rate-limit/quota error` : `${ctx.where} returned HTTP ${ctx.status}, rate limited`;
|
|
10990
|
+
const cause = ctx.quotaExhausted ? "The upstream quota/balance for this agent is exhausted \u2014 NOT a local credential/config issue" : "This agent is being throttled by the upstream provider \u2014 NOT a local credential/config issue";
|
|
10991
|
+
const reset = extractRateLimitResetHint(ctx.message);
|
|
10992
|
+
const advice = ctx.quotaExhausted ? `Retry after the upstream quota resets${reset ? ` (${reset})` : ""}` : `Retry shortly${reset ? ` (${reset})` : ""}`;
|
|
10993
|
+
return `${RUN_UNAVAILABLE_PREFIX} (${headline}). Detail: ${ctx.message} ${NO_FALLBACK} ${cause}. ${advice}, switch to another agent (\`nolo agent list\`), ${SERVER_FALLBACK_HINT}${cooldownNote}
|
|
10723
10994
|
`;
|
|
10724
10995
|
}
|
|
10725
10996
|
function buildTransientFailure(ctx) {
|
|
@@ -10731,6 +11002,17 @@ function buildUpstreamFailure(ctx) {
|
|
|
10731
11002
|
return `${RUN_UNAVAILABLE_PREFIX} (${ctx.where} returned HTTP ${ctx.status}). Detail: ${ctx.message} ${NO_FALLBACK} ${fix}, ${SERVER_FALLBACK_HINT}.
|
|
10732
11003
|
`;
|
|
10733
11004
|
}
|
|
11005
|
+
function formatLocalTurnFailureLine(error) {
|
|
11006
|
+
const message = toErrorMessage(error);
|
|
11007
|
+
if (error?.code === "LLM_REQUEST_TIMEOUT") {
|
|
11008
|
+
const msMatch = /after (\d+)ms/.exec(message);
|
|
11009
|
+
const deadline = msMatch && Number.isFinite(Number(msMatch[1])) ? formatElapsed(Math.round(Number(msMatch[1]) / 1e3)) : "the configured window";
|
|
11010
|
+
return `[nolo] ${t("llmRequestTimedOut", deadline)}
|
|
11011
|
+
`;
|
|
11012
|
+
}
|
|
11013
|
+
return `[nolo] Local agent run failed: ${message}
|
|
11014
|
+
`;
|
|
11015
|
+
}
|
|
10734
11016
|
var FAILURE_BUILDERS = {
|
|
10735
11017
|
auth: buildAuthFailure,
|
|
10736
11018
|
"rejected-payload": buildRejectedPayloadFailure,
|
|
@@ -10739,6 +11021,7 @@ var FAILURE_BUILDERS = {
|
|
|
10739
11021
|
upstream: buildUpstreamFailure
|
|
10740
11022
|
};
|
|
10741
11023
|
function describeLocalRunFailure(message, rawError) {
|
|
11024
|
+
const credentialAccountId = rawError && typeof rawError === "object" && typeof rawError.credentialAccountId === "string" ? rawError.credentialAccountId.trim() || void 0 : void 0;
|
|
10742
11025
|
if (rawError && typeof rawError === "object" && "code" in rawError && rawError.code === "PLATFORM_STREAM_INTERRUPTED") {
|
|
10743
11026
|
return "[nolo] The platform LLM stream was interrupted before the turn completed. Your conversation was preserved. Send another message to continue.\n";
|
|
10744
11027
|
}
|
|
@@ -10814,7 +11097,10 @@ function describeLocalRunFailure(message, rawError) {
|
|
|
10814
11097
|
message,
|
|
10815
11098
|
where: cls.transport === "platform" ? "server chat proxy" : "local provider",
|
|
10816
11099
|
status: cls.status,
|
|
10817
|
-
...
|
|
11100
|
+
...cls.statusInferred ? { statusInferred: true } : {},
|
|
11101
|
+
...cls.quotaExhausted ? { quotaExhausted: true } : {},
|
|
11102
|
+
...cooldownUntil ? { cooldownUntil } : {},
|
|
11103
|
+
...credentialAccountId ? { credentialAccountId } : {}
|
|
10818
11104
|
};
|
|
10819
11105
|
return FAILURE_BUILDERS[cls.kind](ctx);
|
|
10820
11106
|
}
|
|
@@ -11078,8 +11364,8 @@ async function runLocalAgentTurnForCli(options, settings) {
|
|
|
11078
11364
|
...options.parentWakeOnTerminal ? { parentWakeOnTerminal: true } : {},
|
|
11079
11365
|
...options.parentDialogId ? { parentThreadId: options.parentDialogId } : {}
|
|
11080
11366
|
} : void 0;
|
|
11081
|
-
const currentDialogId = options.continueDialogId ??
|
|
11082
|
-
const turnId = `turn-${
|
|
11367
|
+
const currentDialogId = options.continueDialogId ?? ulid2();
|
|
11368
|
+
const turnId = `turn-${ulid2()}`;
|
|
11083
11369
|
const runtimeContextWithOwnership = {
|
|
11084
11370
|
...runtimeContext ?? {},
|
|
11085
11371
|
dialogId: currentDialogId,
|
|
@@ -11131,6 +11417,18 @@ async function runLocalAgentTurnForCli(options, settings) {
|
|
|
11131
11417
|
if (event.kind === "llm-start") {
|
|
11132
11418
|
turnOutput.showWorking();
|
|
11133
11419
|
}
|
|
11420
|
+
if (event.kind === "turn-phase") {
|
|
11421
|
+
turnOutput.showPhase(event.phase);
|
|
11422
|
+
}
|
|
11423
|
+
if (event.kind === "compaction-start") {
|
|
11424
|
+
turnOutput.showPhase("compacting");
|
|
11425
|
+
}
|
|
11426
|
+
if (event.kind === "compaction-end" || // 压缩失败(timeout/provider-error)时 localLoop 按失败原子性语义
|
|
11427
|
+
// 带着裁剪后的历史继续本轮,切回等待模型文案;aborted 时 turn 随即
|
|
11428
|
+
// 结束,不再切文案(终态由 abort 路径收尾)。
|
|
11429
|
+
event.kind === "compaction-failed" && event.reason !== "aborted") {
|
|
11430
|
+
turnOutput.showPhase("waiting-provider");
|
|
11431
|
+
}
|
|
11134
11432
|
if (event.kind === "image-downgraded") {
|
|
11135
11433
|
options.output.write(
|
|
11136
11434
|
"[nolo] \u5F53\u524D agent \u88AB\u914D\u7F6E\u4E3A\u4E0D\u652F\u6301\u56FE\u7247\u8F93\u5165\uFF0C\u56FE\u7247\u5DF2\u7528\u5360\u4F4D\u6587\u672C\u66FF\u4EE3\u3002\u8BF7\u68C0\u67E5\u6A21\u578B\u7684\u56FE\u7247\u80FD\u529B\u914D\u7F6E\uFF0C\u6216\u7528 /switch \u9009\u62E9\u652F\u6301\u56FE\u7247\u7684 agent \u540E\u91CD\u65B0\u53D1\u9001\u56FE\u7247\u3002\n"
|
|
@@ -11176,6 +11474,9 @@ async function runLocalAgentTurnForCli(options, settings) {
|
|
|
11176
11474
|
};
|
|
11177
11475
|
} catch (error) {
|
|
11178
11476
|
turnOutput.spinner.stop();
|
|
11477
|
+
turnOutput.cancel({
|
|
11478
|
+
preservePendingNarration: error?.code !== LOCAL_TURN_ABORTED_CODE && !options.abortSignal?.aborted
|
|
11479
|
+
});
|
|
11179
11480
|
const savedDialogId = error?.dialogId;
|
|
11180
11481
|
const abortedUsageRecords = error?.usageRecords;
|
|
11181
11482
|
const abortedTurnCredits = sumPlatformCredits(abortedUsageRecords);
|
|
@@ -11199,10 +11500,12 @@ async function runLocalAgentTurnForCli(options, settings) {
|
|
|
11199
11500
|
error.cooldownUntil = cooldownUntil;
|
|
11200
11501
|
}
|
|
11201
11502
|
if (settings.reportFailure) {
|
|
11202
|
-
|
|
11203
|
-
|
|
11204
|
-
|
|
11205
|
-
|
|
11503
|
+
const failureLine = formatLocalTurnFailureLine(error);
|
|
11504
|
+
if (typeof options.output.writeErr === "function") {
|
|
11505
|
+
options.output.writeErr(failureLine);
|
|
11506
|
+
} else {
|
|
11507
|
+
options.output.write(failureLine);
|
|
11508
|
+
}
|
|
11206
11509
|
if (cooldownUntil) {
|
|
11207
11510
|
options.output.write(
|
|
11208
11511
|
`[nolo] \u5DF2\u6807\u8BB0\u51B7\u5374\u81F3 ${cooldownUntil}\uFF0C\u5230\u671F\u524D\u6D3E\u53D1\u8BE5 agent \u4F1A\u88AB\u51B7\u5374\u95E8\u63A7\u62E6\u622A\u3002
|
|
@@ -11239,22 +11542,24 @@ async function checkLocalAvailabilityBeforeHttpDispatch(options) {
|
|
|
11239
11542
|
}
|
|
11240
11543
|
const agentLevelAt = baseRecord.nextAvailableAt;
|
|
11241
11544
|
const agentLevelNextAvailableAt = typeof agentLevelAt === "number" && Number.isFinite(agentLevelAt) ? agentLevelAt : void 0;
|
|
11242
|
-
if (!credentialKey && agentLevelNextAvailableAt === void 0)
|
|
11545
|
+
if (!credentialKey && agentLevelNextAvailableAt === void 0) {
|
|
11546
|
+
return { credentialKey };
|
|
11547
|
+
}
|
|
11243
11548
|
const env = options.env;
|
|
11244
11549
|
const now = Date.now();
|
|
11245
11550
|
const entry = credentialKey ? await readCredentialEntry(credentialKey, env, now).catch(() => void 0) : void 0;
|
|
11246
11551
|
const entryAt = entry?.nextAvailableAt;
|
|
11247
11552
|
const effectiveNextAvailableAt = typeof entryAt === "number" ? mergeAvailabilityDeadline(agentLevelNextAvailableAt, entryAt) : agentLevelNextAvailableAt;
|
|
11248
|
-
if (typeof effectiveNextAvailableAt !== "number") return
|
|
11553
|
+
if (typeof effectiveNextAvailableAt !== "number") return { credentialKey };
|
|
11249
11554
|
const gateDecision = resolveCooldownGate(
|
|
11250
11555
|
{ nextAvailableAt: effectiveNextAvailableAt, lastProbeAt: entry?.lastProbeAt },
|
|
11251
11556
|
now
|
|
11252
11557
|
);
|
|
11253
11558
|
if (gateDecision === "probe" && credentialKey) {
|
|
11254
11559
|
await recordCredentialProbe(credentialKey, env, now).catch(() => void 0);
|
|
11255
|
-
return
|
|
11560
|
+
return { credentialKey };
|
|
11256
11561
|
}
|
|
11257
|
-
if (gateDecision !== "blocked") return
|
|
11562
|
+
if (gateDecision !== "blocked") return { credentialKey };
|
|
11258
11563
|
options.output.write(
|
|
11259
11564
|
`[nolo] Agent ${options.agentName || options.agentKey} is temporarily unavailable (429 cooldown) until ${new Date(Number(effectiveNextAvailableAt)).toISOString()}.
|
|
11260
11565
|
Dispatch aborted before reaching the server. Pick another agent via listAgents, or retry after the cooldown.
|
|
@@ -11337,11 +11642,18 @@ async function runAgentTurn(options) {
|
|
|
11337
11642
|
);
|
|
11338
11643
|
return { exitCode: 1 };
|
|
11339
11644
|
}
|
|
11340
|
-
const
|
|
11341
|
-
if (
|
|
11342
|
-
return { exitCode:
|
|
11645
|
+
const localAvailability = await checkLocalAvailabilityBeforeHttpDispatch(options);
|
|
11646
|
+
if (localAvailability?.exitCode) {
|
|
11647
|
+
return { exitCode: localAvailability.exitCode };
|
|
11648
|
+
}
|
|
11649
|
+
const httpResult = await runHttpAgentTurn(options, authToken);
|
|
11650
|
+
if (httpResult.exitCode === 0 && !httpResult.streamInterrupted && localAvailability?.credentialKey) {
|
|
11651
|
+
await clearCredentialAvailability(
|
|
11652
|
+
localAvailability.credentialKey,
|
|
11653
|
+
options.env
|
|
11654
|
+
).catch(() => void 0);
|
|
11343
11655
|
}
|
|
11344
|
-
return
|
|
11656
|
+
return httpResult;
|
|
11345
11657
|
}
|
|
11346
11658
|
|
|
11347
11659
|
// packages/cli/agentRunCommand.ts
|
|
@@ -12073,6 +12385,1078 @@ var rankMemoryCandidates = (items, query, context) => {
|
|
|
12073
12385
|
});
|
|
12074
12386
|
};
|
|
12075
12387
|
|
|
12388
|
+
// packages/ai/memory/vnext/store.ts
|
|
12389
|
+
var enc = (value) => encodeURIComponent(value).replace(/-/g, "%2D");
|
|
12390
|
+
var rangeOf = (prefix) => ({ gte: prefix, lte: `${prefix}\uFFFF` });
|
|
12391
|
+
var entityKey = (ownerId, id) => `mem2-e-${enc(ownerId)}-${enc(id)}`;
|
|
12392
|
+
var entityOwnerPrefix = (ownerId) => `mem2-e-${enc(ownerId)}-`;
|
|
12393
|
+
var stateKey = (ownerId, id) => `mem2-s-${enc(ownerId)}-${enc(id)}`;
|
|
12394
|
+
var stateEntityIndexKey = (ownerId, entityId, stateId) => `mem2-si-${enc(ownerId)}-${enc(entityId)}-${enc(stateId)}`;
|
|
12395
|
+
var stateEntityIndexPrefix = (ownerId, entityId) => `mem2-si-${enc(ownerId)}-${enc(entityId)}-`;
|
|
12396
|
+
var evidenceKey = (ownerId, id) => `mem2-v-${enc(ownerId)}-${enc(id)}`;
|
|
12397
|
+
var relationKey = (ownerId, id) => `mem2-r-${enc(ownerId)}-${enc(id)}`;
|
|
12398
|
+
var relationFromIndexKey = (ownerId, from, relationId) => `mem2-rf-${enc(ownerId)}-${enc(from)}-${enc(relationId)}`;
|
|
12399
|
+
var relationToIndexKey = (ownerId, to, relationId) => `mem2-rt-${enc(ownerId)}-${enc(to)}-${enc(relationId)}`;
|
|
12400
|
+
var readIndexed = async (db, prefix) => {
|
|
12401
|
+
const refs = [];
|
|
12402
|
+
for await (const [, value] of db.iterator({ ...rangeOf(prefix), reverse: false })) {
|
|
12403
|
+
if (typeof value?.key === "string") refs.push(value.key);
|
|
12404
|
+
}
|
|
12405
|
+
const rows = await Promise.all(refs.map((key) => db.get(key).catch(() => null)));
|
|
12406
|
+
return rows.filter((row) => !!row);
|
|
12407
|
+
};
|
|
12408
|
+
var getMemoryEntityVNext = async (db, ownerId, entityId) => db.get(entityKey(ownerId, entityId)).catch(() => null);
|
|
12409
|
+
var listMemoryEntitiesVNext = async (db, ownerId) => {
|
|
12410
|
+
const rows = [];
|
|
12411
|
+
for await (const [, value] of db.iterator({
|
|
12412
|
+
...rangeOf(entityOwnerPrefix(ownerId)),
|
|
12413
|
+
reverse: false
|
|
12414
|
+
})) {
|
|
12415
|
+
if (value) rows.push(value);
|
|
12416
|
+
}
|
|
12417
|
+
return rows;
|
|
12418
|
+
};
|
|
12419
|
+
var getMemoryStateVNext = async (db, ownerId, stateId) => db.get(stateKey(ownerId, stateId)).catch(() => null);
|
|
12420
|
+
var listMemoryStatesForEntityVNext = (db, ownerId, entityId) => readIndexed(db, stateEntityIndexPrefix(ownerId, entityId));
|
|
12421
|
+
var putMemoryEvidenceVNext = async (db, evidence) => {
|
|
12422
|
+
await db.put(evidenceKey(evidence.ownerId, evidence.id), evidence);
|
|
12423
|
+
};
|
|
12424
|
+
var getMemoryEvidenceVNext = async (db, ownerId, evidenceId) => db.get(evidenceKey(ownerId, evidenceId)).catch(() => null);
|
|
12425
|
+
var getMemoryEvidenceVNextStrict = async (db, ownerId, evidenceId) => {
|
|
12426
|
+
try {
|
|
12427
|
+
return await db.get(evidenceKey(ownerId, evidenceId));
|
|
12428
|
+
} catch (error) {
|
|
12429
|
+
if (isLevelNotFoundError(error)) return null;
|
|
12430
|
+
throw error;
|
|
12431
|
+
}
|
|
12432
|
+
};
|
|
12433
|
+
var _appendEntityBatch = (batch, entity) => {
|
|
12434
|
+
batch.put(entityKey(entity.ownerId, entity.id), entity);
|
|
12435
|
+
};
|
|
12436
|
+
var _appendEvidenceBatch = (batch, evidence) => {
|
|
12437
|
+
batch.put(evidenceKey(evidence.ownerId, evidence.id), evidence);
|
|
12438
|
+
};
|
|
12439
|
+
var _appendStateBatch = (batch, state2) => {
|
|
12440
|
+
const key = stateKey(state2.ownerId, state2.id);
|
|
12441
|
+
batch.put(key, state2);
|
|
12442
|
+
batch.put(stateEntityIndexKey(state2.ownerId, state2.entityId, state2.id), { key });
|
|
12443
|
+
};
|
|
12444
|
+
var _appendRetiredStateBatch = (batch, state2) => {
|
|
12445
|
+
batch.put(stateKey(state2.ownerId, state2.id), state2);
|
|
12446
|
+
};
|
|
12447
|
+
var _appendRelationBatch = (batch, relation) => {
|
|
12448
|
+
const key = relationKey(relation.ownerId, relation.id);
|
|
12449
|
+
batch.put(key, relation);
|
|
12450
|
+
batch.put(relationFromIndexKey(relation.ownerId, relation.from, relation.id), { key });
|
|
12451
|
+
batch.put(relationToIndexKey(relation.ownerId, relation.to, relation.id), { key });
|
|
12452
|
+
};
|
|
12453
|
+
|
|
12454
|
+
// packages/ai/memory/vnext/recall.ts
|
|
12455
|
+
var MAX_RECALL_REFS = 6;
|
|
12456
|
+
var stripFence = (raw) => {
|
|
12457
|
+
const trimmed = raw.trim();
|
|
12458
|
+
const match = trimmed.match(/^```(?:json)?\s*([\s\S]*?)\s*```$/i);
|
|
12459
|
+
return match ? match[1].trim() : trimmed;
|
|
12460
|
+
};
|
|
12461
|
+
var parseSelection = (raw) => {
|
|
12462
|
+
let parsed;
|
|
12463
|
+
try {
|
|
12464
|
+
parsed = JSON.parse(stripFence(raw));
|
|
12465
|
+
} catch {
|
|
12466
|
+
throw new Error("memory recall selector output is not valid JSON");
|
|
12467
|
+
}
|
|
12468
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
12469
|
+
throw new Error("memory recall selector output must be an object");
|
|
12470
|
+
}
|
|
12471
|
+
const obj = parsed;
|
|
12472
|
+
if (!Array.isArray(obj.refs) || !obj.refs.every((item) => typeof item === "string")) {
|
|
12473
|
+
throw new Error("memory recall selector refs must be string[]");
|
|
12474
|
+
}
|
|
12475
|
+
if (typeof obj.reason !== "string") {
|
|
12476
|
+
throw new Error("memory recall selector reason must be string");
|
|
12477
|
+
}
|
|
12478
|
+
return {
|
|
12479
|
+
refs: [...new Set(obj.refs)].slice(0, MAX_RECALL_REFS),
|
|
12480
|
+
reason: obj.reason
|
|
12481
|
+
};
|
|
12482
|
+
};
|
|
12483
|
+
var buildCatalog = async (db, ownerId) => {
|
|
12484
|
+
const entities = await listMemoryEntitiesVNext(db, ownerId);
|
|
12485
|
+
const states = [];
|
|
12486
|
+
for (const entity of entities) {
|
|
12487
|
+
states.push(...await listMemoryStatesForEntityVNext(db, ownerId, entity.id));
|
|
12488
|
+
}
|
|
12489
|
+
return { entities, states };
|
|
12490
|
+
};
|
|
12491
|
+
var catalogText = (entities, states) => JSON.stringify(
|
|
12492
|
+
{
|
|
12493
|
+
entities: entities.map((entity) => ({
|
|
12494
|
+
id: entity.id,
|
|
12495
|
+
type: entity.type,
|
|
12496
|
+
name: entity.name,
|
|
12497
|
+
...entity.subtype ? { subtype: entity.subtype } : {},
|
|
12498
|
+
...entity.aliases?.length ? { aliases: entity.aliases } : {}
|
|
12499
|
+
})),
|
|
12500
|
+
states: states.map((state2) => ({
|
|
12501
|
+
id: state2.id,
|
|
12502
|
+
entityId: state2.entityId,
|
|
12503
|
+
facet: state2.facet,
|
|
12504
|
+
text: state2.text,
|
|
12505
|
+
// Retired (superseded) States stay listed as recoverable history; the
|
|
12506
|
+
// boolean — not the retiredAt timestamp — enters the prompt so no
|
|
12507
|
+
// timestamps reach LLM text.
|
|
12508
|
+
...state2.retiredAt ? { retired: true } : {}
|
|
12509
|
+
}))
|
|
12510
|
+
},
|
|
12511
|
+
null,
|
|
12512
|
+
2
|
|
12513
|
+
);
|
|
12514
|
+
var createMemoryVNextRecall = (input) => async (query) => {
|
|
12515
|
+
const startedAt = performance.now();
|
|
12516
|
+
const { entities, states } = await buildCatalog(input.db, input.ownerId);
|
|
12517
|
+
if (entities.length === 0 && states.length === 0) {
|
|
12518
|
+
return {
|
|
12519
|
+
query,
|
|
12520
|
+
refs: [],
|
|
12521
|
+
entities: [],
|
|
12522
|
+
states: [],
|
|
12523
|
+
reason: "memory catalog is empty",
|
|
12524
|
+
trace: {
|
|
12525
|
+
candidateEntities: 0,
|
|
12526
|
+
candidateStates: 0,
|
|
12527
|
+
selectedRefs: 0,
|
|
12528
|
+
elapsedMs: Math.round((performance.now() - startedAt) * 10) / 10
|
|
12529
|
+
}
|
|
12530
|
+
};
|
|
12531
|
+
}
|
|
12532
|
+
const result = await input.provider.complete(
|
|
12533
|
+
[
|
|
12534
|
+
{
|
|
12535
|
+
role: "system",
|
|
12536
|
+
content: [
|
|
12537
|
+
"Select the smallest useful set of long-lived memory entrances for the user query.",
|
|
12538
|
+
'Return ONLY JSON: {"refs":["exact-id"],"reason":"short explanation"}.',
|
|
12539
|
+
`Select at most ${MAX_RECALL_REFS} exact ids from the supplied catalog.`,
|
|
12540
|
+
"Prefer State ids when current durable understanding answers the query.",
|
|
12541
|
+
"Select an Entity id when it is a useful navigation anchor and no single State is enough.",
|
|
12542
|
+
"Do not select unrelated memories merely because they are personal or interesting.",
|
|
12543
|
+
"Historical-detail questions may select the relevant current State/Entity as an entrance; deeper evidence is handled by inspect, not here."
|
|
12544
|
+
].join("\n")
|
|
12545
|
+
},
|
|
12546
|
+
{
|
|
12547
|
+
role: "user",
|
|
12548
|
+
content: `Query:
|
|
12549
|
+
${query}
|
|
12550
|
+
|
|
12551
|
+
Memory catalog:
|
|
12552
|
+
${catalogText(entities, states)}`
|
|
12553
|
+
}
|
|
12554
|
+
],
|
|
12555
|
+
input.timeoutMs ? { timeoutMs: input.timeoutMs } : void 0
|
|
12556
|
+
);
|
|
12557
|
+
const selected = parseSelection(result.content);
|
|
12558
|
+
const entityById = new Map(entities.map((entity) => [entity.id, entity]));
|
|
12559
|
+
const stateById = new Map(states.map((state2) => [state2.id, state2]));
|
|
12560
|
+
const validRefs = selected.refs.filter((ref) => entityById.has(ref) || stateById.has(ref));
|
|
12561
|
+
return {
|
|
12562
|
+
query,
|
|
12563
|
+
refs: validRefs,
|
|
12564
|
+
entities: validRefs.flatMap((ref) => {
|
|
12565
|
+
const entity = entityById.get(ref);
|
|
12566
|
+
return entity ? [entity] : [];
|
|
12567
|
+
}),
|
|
12568
|
+
states: validRefs.flatMap((ref) => {
|
|
12569
|
+
const state2 = stateById.get(ref);
|
|
12570
|
+
return state2 ? [state2] : [];
|
|
12571
|
+
}),
|
|
12572
|
+
reason: selected.reason,
|
|
12573
|
+
trace: {
|
|
12574
|
+
candidateEntities: entities.length,
|
|
12575
|
+
candidateStates: states.length,
|
|
12576
|
+
selectedRefs: validRefs.length,
|
|
12577
|
+
elapsedMs: Math.round((performance.now() - startedAt) * 10) / 10
|
|
12578
|
+
}
|
|
12579
|
+
};
|
|
12580
|
+
};
|
|
12581
|
+
|
|
12582
|
+
// packages/ai/memory/vnext/legacyMigration.ts
|
|
12583
|
+
import { createHash } from "crypto";
|
|
12584
|
+
var LEGACY_MEMORY_SOURCE_REF_PREFIX = "legacy-memory";
|
|
12585
|
+
var LEGACY_MEMORY_EVIDENCE_ID_PREFIX = "mem-legacy-";
|
|
12586
|
+
var resolveLegacyMemoryPrincipal = (item) => ({
|
|
12587
|
+
ownerType: item.ownerType,
|
|
12588
|
+
ownerId: item.ownerId,
|
|
12589
|
+
principalId: `${item.ownerType}:${encodeURIComponent(item.ownerId)}`
|
|
12590
|
+
});
|
|
12591
|
+
var buildLegacyMemorySourceRef = (item) => {
|
|
12592
|
+
const { principalId } = resolveLegacyMemoryPrincipal(item);
|
|
12593
|
+
return `${LEGACY_MEMORY_SOURCE_REF_PREFIX}:${principalId}:${encodeURIComponent(item.id)}`;
|
|
12594
|
+
};
|
|
12595
|
+
var legacyEvidenceSeed = (principalId, itemId) => JSON.stringify([principalId, itemId]);
|
|
12596
|
+
var buildLegacyEvidenceId = (item) => {
|
|
12597
|
+
const { principalId } = resolveLegacyMemoryPrincipal(item);
|
|
12598
|
+
const digest = createHash("sha256").update(legacyEvidenceSeed(principalId, item.id)).digest("hex");
|
|
12599
|
+
return `${LEGACY_MEMORY_EVIDENCE_ID_PREFIX}${digest.slice(0, 32)}`;
|
|
12600
|
+
};
|
|
12601
|
+
var clampLegacyConfidence = (value) => {
|
|
12602
|
+
if (typeof value !== "number" || !Number.isFinite(value)) return 0;
|
|
12603
|
+
if (value < 0) return 0;
|
|
12604
|
+
if (value > 1) return 1;
|
|
12605
|
+
return value;
|
|
12606
|
+
};
|
|
12607
|
+
var buildLegacyMemoryEvidence = (item) => {
|
|
12608
|
+
const { principalId } = resolveLegacyMemoryPrincipal(item);
|
|
12609
|
+
return {
|
|
12610
|
+
id: buildLegacyEvidenceId(item),
|
|
12611
|
+
ownerId: principalId,
|
|
12612
|
+
text: item.content,
|
|
12613
|
+
sourceRef: buildLegacyMemorySourceRef(item),
|
|
12614
|
+
confidence: clampLegacyConfidence(item.confidence),
|
|
12615
|
+
createdAt: item.createdAt
|
|
12616
|
+
};
|
|
12617
|
+
};
|
|
12618
|
+
|
|
12619
|
+
// packages/ai/memory/vnext/shadowRead.ts
|
|
12620
|
+
var SHADOW_TIMEOUT_MS = 2e4;
|
|
12621
|
+
var ERROR_MESSAGE_MAX = 120;
|
|
12622
|
+
var normalizeTextKey = (text) => text.trim().replace(/\s+/g, " ").toLowerCase();
|
|
12623
|
+
var legacyItemKeys = (item) => {
|
|
12624
|
+
const keys = [normalizeTextKey(item.content ?? "")];
|
|
12625
|
+
return keys.filter((key) => key.length > 0);
|
|
12626
|
+
};
|
|
12627
|
+
var vnextResultKeys = (result) => {
|
|
12628
|
+
const keys = [];
|
|
12629
|
+
for (const entity of result.entities) {
|
|
12630
|
+
if (entity.name) keys.push(normalizeTextKey(entity.name));
|
|
12631
|
+
}
|
|
12632
|
+
for (const state2 of result.states) {
|
|
12633
|
+
if (state2.text) keys.push(normalizeTextKey(state2.text));
|
|
12634
|
+
}
|
|
12635
|
+
return keys.filter((key) => key.length > 0);
|
|
12636
|
+
};
|
|
12637
|
+
var vnextContextChars = (result) => result.entities.reduce(
|
|
12638
|
+
(sum, entity) => sum + (entity.name?.length ?? 0),
|
|
12639
|
+
result.states.reduce((sum, state2) => sum + (state2.text?.length ?? 0), 0)
|
|
12640
|
+
);
|
|
12641
|
+
var shortError = (error) => {
|
|
12642
|
+
const message = error instanceof Error ? `${error.name}: ${error.message}` : String(error);
|
|
12643
|
+
return message.length > ERROR_MESSAGE_MAX ? `${message.slice(0, ERROR_MESSAGE_MAX)}\u2026` : message;
|
|
12644
|
+
};
|
|
12645
|
+
var withTimeout = async (promise, timeoutMs, label) => {
|
|
12646
|
+
let timer;
|
|
12647
|
+
const timeout = new Promise((_, reject) => {
|
|
12648
|
+
timer = setTimeout(() => reject(new Error(label)), timeoutMs);
|
|
12649
|
+
});
|
|
12650
|
+
try {
|
|
12651
|
+
return await Promise.race([promise, timeout]);
|
|
12652
|
+
} finally {
|
|
12653
|
+
if (timer) clearTimeout(timer);
|
|
12654
|
+
}
|
|
12655
|
+
};
|
|
12656
|
+
var runMemoryVNextShadowRead = async (input) => {
|
|
12657
|
+
const now = input.ctx.now ?? (() => performance.now());
|
|
12658
|
+
const defaultEmit = (observation2) => {
|
|
12659
|
+
const payload = {
|
|
12660
|
+
event: "memory_vnext_shadow_read",
|
|
12661
|
+
...observation2
|
|
12662
|
+
};
|
|
12663
|
+
console.info("[memory] vnext shadow read", payload);
|
|
12664
|
+
};
|
|
12665
|
+
const emit = input.emit ?? defaultEmit;
|
|
12666
|
+
const legacyKeys = new Set(
|
|
12667
|
+
input.legacyItems.flatMap((item) => legacyItemKeys(item))
|
|
12668
|
+
);
|
|
12669
|
+
const vnextStartedAt = now();
|
|
12670
|
+
let vnextHitCount = 0;
|
|
12671
|
+
let vnextChars = 0;
|
|
12672
|
+
const vnextKeys = /* @__PURE__ */ new Set();
|
|
12673
|
+
let vnextError;
|
|
12674
|
+
try {
|
|
12675
|
+
const shadowTimeoutMs = input.ctx.shadowTimeoutMs ?? SHADOW_TIMEOUT_MS;
|
|
12676
|
+
const perOwner = async (owner) => {
|
|
12677
|
+
const principal = resolveLegacyMemoryPrincipal({
|
|
12678
|
+
ownerType: owner.ownerType,
|
|
12679
|
+
ownerId: owner.ownerId
|
|
12680
|
+
});
|
|
12681
|
+
const recall = createMemoryVNextRecall({
|
|
12682
|
+
db: input.ctx.db,
|
|
12683
|
+
ownerId: principal.principalId,
|
|
12684
|
+
provider: input.ctx.provider,
|
|
12685
|
+
timeoutMs: input.ctx.timeoutMs
|
|
12686
|
+
});
|
|
12687
|
+
return recall(input.ctx.query);
|
|
12688
|
+
};
|
|
12689
|
+
const results = await withTimeout(
|
|
12690
|
+
Promise.all(input.ctx.owners.map((owner) => perOwner(owner))),
|
|
12691
|
+
shadowTimeoutMs,
|
|
12692
|
+
`memory vnext shadow read timed out after ${shadowTimeoutMs}ms`
|
|
12693
|
+
);
|
|
12694
|
+
for (const result of results) {
|
|
12695
|
+
vnextHitCount += result.refs.length;
|
|
12696
|
+
vnextChars += vnextContextChars(result);
|
|
12697
|
+
for (const key of vnextResultKeys(result)) vnextKeys.add(key);
|
|
12698
|
+
}
|
|
12699
|
+
} catch (error) {
|
|
12700
|
+
vnextError = shortError(error);
|
|
12701
|
+
}
|
|
12702
|
+
const vnextLatencyMs = Math.round((now() - vnextStartedAt) * 10) / 10;
|
|
12703
|
+
let overlapCount = null;
|
|
12704
|
+
let legacyOnlyCount = null;
|
|
12705
|
+
let vnextOnlyCount = null;
|
|
12706
|
+
if (!vnextError) {
|
|
12707
|
+
let overlap = 0;
|
|
12708
|
+
for (const key of vnextKeys) if (legacyKeys.has(key)) overlap += 1;
|
|
12709
|
+
overlapCount = overlap;
|
|
12710
|
+
legacyOnlyCount = Math.max(0, legacyKeys.size - overlap);
|
|
12711
|
+
vnextOnlyCount = Math.max(0, vnextKeys.size - overlap);
|
|
12712
|
+
}
|
|
12713
|
+
const observation = {
|
|
12714
|
+
legacyHitCount: input.legacyItems.length,
|
|
12715
|
+
vnextHitCount,
|
|
12716
|
+
overlapCount,
|
|
12717
|
+
legacyOnlyCount,
|
|
12718
|
+
vnextOnlyCount,
|
|
12719
|
+
legacyLatencyMs: input.legacyLatencyMs,
|
|
12720
|
+
vnextLatencyMs,
|
|
12721
|
+
legacyContextChars: input.legacyContextChars,
|
|
12722
|
+
vnextContextChars: vnextChars,
|
|
12723
|
+
...vnextError ? { vnextError } : {}
|
|
12724
|
+
};
|
|
12725
|
+
emit(observation);
|
|
12726
|
+
return observation;
|
|
12727
|
+
};
|
|
12728
|
+
var isMemoryVNextShadowReadEnabled = (env = typeof process !== "undefined" ? process.env : {}) => env.NOLO_MEMORY_VNEXT_SHADOW_READ === "1" || env.NOLO_MEMORY_VNEXT_SHADOW_READ === "true";
|
|
12729
|
+
|
|
12730
|
+
// packages/ai/memory/vnext/applyMutation.ts
|
|
12731
|
+
async function validateMutation(db, ownerId, mutation) {
|
|
12732
|
+
const pending = {
|
|
12733
|
+
evidenceIds: /* @__PURE__ */ new Set(),
|
|
12734
|
+
entityIds: /* @__PURE__ */ new Set(),
|
|
12735
|
+
stateIds: /* @__PURE__ */ new Set(),
|
|
12736
|
+
relationIds: /* @__PURE__ */ new Set()
|
|
12737
|
+
};
|
|
12738
|
+
for (const ev of mutation.evidence ?? []) {
|
|
12739
|
+
if (!ev.id || typeof ev.id !== "string") {
|
|
12740
|
+
throw new Error("evidence id must be a non-empty string");
|
|
12741
|
+
}
|
|
12742
|
+
if (pending.evidenceIds.has(ev.id)) {
|
|
12743
|
+
throw new Error(`duplicate evidence id in mutation: ${ev.id}`);
|
|
12744
|
+
}
|
|
12745
|
+
pending.evidenceIds.add(ev.id);
|
|
12746
|
+
}
|
|
12747
|
+
for (const ent of mutation.entities ?? []) {
|
|
12748
|
+
if (!ent.id || typeof ent.id !== "string") {
|
|
12749
|
+
throw new Error("entity id must be a non-empty string");
|
|
12750
|
+
}
|
|
12751
|
+
if (pending.entityIds.has(ent.id)) {
|
|
12752
|
+
throw new Error(`duplicate entity id in mutation: ${ent.id}`);
|
|
12753
|
+
}
|
|
12754
|
+
pending.entityIds.add(ent.id);
|
|
12755
|
+
}
|
|
12756
|
+
for (const st of mutation.states ?? []) {
|
|
12757
|
+
if (!st.id || typeof st.id !== "string") {
|
|
12758
|
+
throw new Error("state id must be a non-empty string");
|
|
12759
|
+
}
|
|
12760
|
+
if (pending.stateIds.has(st.id)) {
|
|
12761
|
+
throw new Error(`duplicate state id in mutation: ${st.id}`);
|
|
12762
|
+
}
|
|
12763
|
+
pending.stateIds.add(st.id);
|
|
12764
|
+
}
|
|
12765
|
+
for (const rel of mutation.relations ?? []) {
|
|
12766
|
+
if (!rel.id || typeof rel.id !== "string") {
|
|
12767
|
+
throw new Error("relation id must be a non-empty string");
|
|
12768
|
+
}
|
|
12769
|
+
if (pending.relationIds.has(rel.id)) {
|
|
12770
|
+
throw new Error(`duplicate relation id in mutation: ${rel.id}`);
|
|
12771
|
+
}
|
|
12772
|
+
pending.relationIds.add(rel.id);
|
|
12773
|
+
}
|
|
12774
|
+
const supersededIds = /* @__PURE__ */ new Set();
|
|
12775
|
+
for (const sid of mutation.supersededStateIds ?? []) {
|
|
12776
|
+
if (supersededIds.has(sid)) {
|
|
12777
|
+
throw new Error(`duplicate supersededStateId in mutation: ${sid}`);
|
|
12778
|
+
}
|
|
12779
|
+
supersededIds.add(sid);
|
|
12780
|
+
}
|
|
12781
|
+
for (const ev of mutation.evidence ?? []) {
|
|
12782
|
+
if (ev.ownerId !== ownerId) {
|
|
12783
|
+
throw new Error(
|
|
12784
|
+
`evidence ${ev.id} has ownerId ${ev.ownerId}, expected ${ownerId}`
|
|
12785
|
+
);
|
|
12786
|
+
}
|
|
12787
|
+
}
|
|
12788
|
+
for (const ent of mutation.entities ?? []) {
|
|
12789
|
+
if (ent.ownerId !== ownerId) {
|
|
12790
|
+
throw new Error(
|
|
12791
|
+
`entity ${ent.id} has ownerId ${ent.ownerId}, expected ${ownerId}`
|
|
12792
|
+
);
|
|
12793
|
+
}
|
|
12794
|
+
}
|
|
12795
|
+
for (const st of mutation.states ?? []) {
|
|
12796
|
+
if (st.ownerId !== ownerId) {
|
|
12797
|
+
throw new Error(
|
|
12798
|
+
`state ${st.id} has ownerId ${st.ownerId}, expected ${ownerId}`
|
|
12799
|
+
);
|
|
12800
|
+
}
|
|
12801
|
+
}
|
|
12802
|
+
for (const rel of mutation.relations ?? []) {
|
|
12803
|
+
if (rel.ownerId !== ownerId) {
|
|
12804
|
+
throw new Error(
|
|
12805
|
+
`relation ${rel.id} has ownerId ${rel.ownerId}, expected ${ownerId}`
|
|
12806
|
+
);
|
|
12807
|
+
}
|
|
12808
|
+
}
|
|
12809
|
+
for (const st of mutation.states ?? []) {
|
|
12810
|
+
if (supersededIds.has(st.id)) {
|
|
12811
|
+
throw new Error(
|
|
12812
|
+
`state ${st.id} appears in both states and supersededStateIds; a record cannot be created and retired in the same mutation`
|
|
12813
|
+
);
|
|
12814
|
+
}
|
|
12815
|
+
}
|
|
12816
|
+
const facetSlots = /* @__PURE__ */ new Set();
|
|
12817
|
+
for (const st of mutation.states ?? []) {
|
|
12818
|
+
const slot = `${st.entityId} ${st.facet}`;
|
|
12819
|
+
if (facetSlots.has(slot)) {
|
|
12820
|
+
throw new Error(
|
|
12821
|
+
`mutation writes parallel current states for entity ${st.entityId} facet ${st.facet}`
|
|
12822
|
+
);
|
|
12823
|
+
}
|
|
12824
|
+
facetSlots.add(slot);
|
|
12825
|
+
}
|
|
12826
|
+
for (const ev of mutation.evidence ?? []) {
|
|
12827
|
+
const existing = await getMemoryEvidenceVNext(db, ownerId, ev.id);
|
|
12828
|
+
if (existing) {
|
|
12829
|
+
throw new Error(
|
|
12830
|
+
`evidence ${ev.id} already exists (owner ${ownerId}); use a unique id`
|
|
12831
|
+
);
|
|
12832
|
+
}
|
|
12833
|
+
}
|
|
12834
|
+
for (const ent of mutation.entities ?? []) {
|
|
12835
|
+
const existing = await getMemoryEntityVNext(db, ownerId, ent.id);
|
|
12836
|
+
if (existing) {
|
|
12837
|
+
throw new Error(
|
|
12838
|
+
`entity ${ent.id} already exists (owner ${ownerId}); use a unique id`
|
|
12839
|
+
);
|
|
12840
|
+
}
|
|
12841
|
+
}
|
|
12842
|
+
for (const st of mutation.states ?? []) {
|
|
12843
|
+
if (!pending.entityIds.has(st.entityId)) {
|
|
12844
|
+
const entity = await getMemoryEntityVNext(db, ownerId, st.entityId);
|
|
12845
|
+
if (!entity) {
|
|
12846
|
+
throw new Error(
|
|
12847
|
+
`memory state ${st.id} references missing entity ${st.entityId} (owner ${ownerId})`
|
|
12848
|
+
);
|
|
12849
|
+
}
|
|
12850
|
+
}
|
|
12851
|
+
for (const evidenceId of st.evidenceIds) {
|
|
12852
|
+
if (!pending.evidenceIds.has(evidenceId)) {
|
|
12853
|
+
const ev = await getMemoryEvidenceVNext(db, ownerId, evidenceId);
|
|
12854
|
+
if (!ev) {
|
|
12855
|
+
throw new Error(
|
|
12856
|
+
`memory state ${st.id} references missing evidence ${evidenceId} (owner ${ownerId})`
|
|
12857
|
+
);
|
|
12858
|
+
}
|
|
12859
|
+
}
|
|
12860
|
+
}
|
|
12861
|
+
const existing = await getMemoryStateVNext(db, ownerId, st.id);
|
|
12862
|
+
if (existing) {
|
|
12863
|
+
if (existing.retiredAt) {
|
|
12864
|
+
throw new Error(
|
|
12865
|
+
`cannot update retired memory state ${st.id} (owner ${ownerId})`
|
|
12866
|
+
);
|
|
12867
|
+
}
|
|
12868
|
+
if (existing.entityId !== st.entityId || existing.facet !== st.facet) {
|
|
12869
|
+
throw new Error(
|
|
12870
|
+
`state ${st.id} already exists with different entity/facet (${existing.entityId}/${existing.facet} vs ${st.entityId}/${st.facet}); use supersede instead`
|
|
12871
|
+
);
|
|
12872
|
+
}
|
|
12873
|
+
}
|
|
12874
|
+
if (!existing) {
|
|
12875
|
+
const existingStates = await listMemoryStatesForEntityVNext(db, ownerId, st.entityId);
|
|
12876
|
+
for (const es of existingStates) {
|
|
12877
|
+
if (es.facet === st.facet && !es.retiredAt) {
|
|
12878
|
+
if (!supersededIds.has(es.id)) {
|
|
12879
|
+
throw new Error(
|
|
12880
|
+
`entity ${st.entityId} facet ${st.facet} already has current state ${es.id}; supersede it or use a different facet`
|
|
12881
|
+
);
|
|
12882
|
+
}
|
|
12883
|
+
}
|
|
12884
|
+
}
|
|
12885
|
+
}
|
|
12886
|
+
}
|
|
12887
|
+
for (const sid of mutation.supersededStateIds ?? []) {
|
|
12888
|
+
const existing = await getMemoryStateVNext(db, ownerId, sid);
|
|
12889
|
+
if (!existing) {
|
|
12890
|
+
throw new Error(
|
|
12891
|
+
`cannot supersede missing memory state: ${sid} (owner ${ownerId})`
|
|
12892
|
+
);
|
|
12893
|
+
}
|
|
12894
|
+
if (existing.retiredAt) {
|
|
12895
|
+
throw new Error(
|
|
12896
|
+
`cannot supersede already retired memory state: ${sid} (owner ${ownerId})`
|
|
12897
|
+
);
|
|
12898
|
+
}
|
|
12899
|
+
const replacement = (mutation.states ?? []).find(
|
|
12900
|
+
(st) => st.entityId === existing.entityId && st.facet === existing.facet
|
|
12901
|
+
);
|
|
12902
|
+
if (!replacement) {
|
|
12903
|
+
throw new Error(
|
|
12904
|
+
`superseded state ${sid} (entity ${existing.entityId} facet ${existing.facet}) has no replacement in this mutation`
|
|
12905
|
+
);
|
|
12906
|
+
}
|
|
12907
|
+
}
|
|
12908
|
+
for (const rel of mutation.relations ?? []) {
|
|
12909
|
+
for (const [side, ref] of [
|
|
12910
|
+
["from", rel.from],
|
|
12911
|
+
["to", rel.to]
|
|
12912
|
+
]) {
|
|
12913
|
+
if (pending.entityIds.has(ref) || pending.stateIds.has(ref) || pending.evidenceIds.has(ref)) {
|
|
12914
|
+
continue;
|
|
12915
|
+
}
|
|
12916
|
+
const resolved = await getMemoryEntityVNext(db, ownerId, ref) ?? await getMemoryStateVNext(db, ownerId, ref) ?? await getMemoryEvidenceVNext(db, ownerId, ref);
|
|
12917
|
+
if (!resolved) {
|
|
12918
|
+
throw new Error(
|
|
12919
|
+
`memory relation ${rel.id} references missing ${side} ${ref} (owner ${ownerId})`
|
|
12920
|
+
);
|
|
12921
|
+
}
|
|
12922
|
+
}
|
|
12923
|
+
}
|
|
12924
|
+
}
|
|
12925
|
+
var applyMemoryInterpreterMutation = async (db, ownerId, mutation) => {
|
|
12926
|
+
await validateMutation(db, ownerId, mutation);
|
|
12927
|
+
const batch = db.batch();
|
|
12928
|
+
for (const ev of mutation.evidence ?? []) {
|
|
12929
|
+
_appendEvidenceBatch(batch, ev);
|
|
12930
|
+
}
|
|
12931
|
+
for (const ent of mutation.entities ?? []) {
|
|
12932
|
+
_appendEntityBatch(batch, ent);
|
|
12933
|
+
}
|
|
12934
|
+
for (const st of mutation.states ?? []) {
|
|
12935
|
+
_appendStateBatch(batch, st);
|
|
12936
|
+
}
|
|
12937
|
+
for (const sid of mutation.supersededStateIds ?? []) {
|
|
12938
|
+
const existing = await getMemoryStateVNext(db, ownerId, sid);
|
|
12939
|
+
if (!existing) {
|
|
12940
|
+
throw new Error(
|
|
12941
|
+
`cannot supersede missing memory state: ${sid} (owner ${ownerId})`
|
|
12942
|
+
);
|
|
12943
|
+
}
|
|
12944
|
+
const replacement = (mutation.states ?? []).find(
|
|
12945
|
+
(st) => st.entityId === existing.entityId && st.facet === existing.facet
|
|
12946
|
+
);
|
|
12947
|
+
const retired = {
|
|
12948
|
+
...existing,
|
|
12949
|
+
retiredAt: replacement?.updatedAt ?? (/* @__PURE__ */ new Date()).toISOString()
|
|
12950
|
+
};
|
|
12951
|
+
_appendRetiredStateBatch(batch, retired);
|
|
12952
|
+
}
|
|
12953
|
+
for (const rel of mutation.relations ?? []) {
|
|
12954
|
+
_appendRelationBatch(batch, rel);
|
|
12955
|
+
}
|
|
12956
|
+
await batch.write();
|
|
12957
|
+
};
|
|
12958
|
+
|
|
12959
|
+
// packages/ai/memory/vnext/legacyMigrationApply.ts
|
|
12960
|
+
var isSameLegacyMemoryEvidence = (left, right) => left.id === right.id && left.ownerId === right.ownerId && left.text === right.text && left.sourceRef === right.sourceRef && left.confidence === right.confidence && left.createdAt === right.createdAt;
|
|
12961
|
+
var applyLegacyMemoryEvidence = async (db, item) => {
|
|
12962
|
+
const incoming = buildLegacyMemoryEvidence(item);
|
|
12963
|
+
const existing = await getMemoryEvidenceVNextStrict(db, incoming.ownerId, incoming.id);
|
|
12964
|
+
if (existing) {
|
|
12965
|
+
return isSameLegacyMemoryEvidence(existing, incoming) ? { status: "already_exists", evidence: existing } : { status: "conflict", existing, incoming };
|
|
12966
|
+
}
|
|
12967
|
+
await putMemoryEvidenceVNext(db, incoming);
|
|
12968
|
+
return { status: "created", evidence: incoming };
|
|
12969
|
+
};
|
|
12970
|
+
|
|
12971
|
+
// packages/ai/memory/vnext/types.ts
|
|
12972
|
+
var MEMORY_ENTITY_TYPES = [
|
|
12973
|
+
"person",
|
|
12974
|
+
"organization",
|
|
12975
|
+
"project",
|
|
12976
|
+
"place",
|
|
12977
|
+
"object",
|
|
12978
|
+
"activity",
|
|
12979
|
+
"concept"
|
|
12980
|
+
];
|
|
12981
|
+
var MEMORY_RELATION_TYPES = [
|
|
12982
|
+
"related_to",
|
|
12983
|
+
"part_of",
|
|
12984
|
+
"uses",
|
|
12985
|
+
"involves",
|
|
12986
|
+
"supersedes"
|
|
12987
|
+
];
|
|
12988
|
+
|
|
12989
|
+
// packages/ai/memory/vnext/interpreterWireProtocol.ts
|
|
12990
|
+
var isObject = (value) => !!value && typeof value === "object" && !Array.isArray(value);
|
|
12991
|
+
var isString = (value) => typeof value === "string" && value.trim().length > 0;
|
|
12992
|
+
var isStringArray = (value) => Array.isArray(value) && value.every(isString);
|
|
12993
|
+
var optionalArray = (value, validate2) => value === void 0 || Array.isArray(value) && value.every(validate2);
|
|
12994
|
+
var ACTIONS = /* @__PURE__ */ new Set([
|
|
12995
|
+
"no_op",
|
|
12996
|
+
"create",
|
|
12997
|
+
"update",
|
|
12998
|
+
"specialize",
|
|
12999
|
+
"supersede",
|
|
13000
|
+
"ambiguous"
|
|
13001
|
+
]);
|
|
13002
|
+
var validateEvidence = (value) => {
|
|
13003
|
+
if (!isObject(value)) return false;
|
|
13004
|
+
return isString(value.key) && isString(value.text) && typeof value.confidence === "number" && Number.isFinite(value.confidence) && value.confidence >= 0 && value.confidence <= 1 && (value.sourceRef === void 0 || isString(value.sourceRef));
|
|
13005
|
+
};
|
|
13006
|
+
var validateEntity = (value) => {
|
|
13007
|
+
if (!isObject(value)) return false;
|
|
13008
|
+
return isString(value.key) && MEMORY_ENTITY_TYPES.includes(value.type) && isString(value.name) && (value.subtype === void 0 || isString(value.subtype)) && (value.aliases === void 0 || isStringArray(value.aliases));
|
|
13009
|
+
};
|
|
13010
|
+
var validateState = (value) => {
|
|
13011
|
+
if (!isObject(value)) return false;
|
|
13012
|
+
return (value.stateId === void 0 || isString(value.stateId)) && (value.supersedes === void 0 || isString(value.supersedes)) && isString(value.entityRef) && isString(value.facet) && "value" in value && isString(value.text) && isStringArray(value.evidenceRefs);
|
|
13013
|
+
};
|
|
13014
|
+
var validateRelation = (value) => {
|
|
13015
|
+
if (!isObject(value)) return false;
|
|
13016
|
+
return isString(value.fromRef) && MEMORY_RELATION_TYPES.includes(value.type) && isString(value.toRef);
|
|
13017
|
+
};
|
|
13018
|
+
var stripJsonFence = (raw) => {
|
|
13019
|
+
const trimmed = raw.trim();
|
|
13020
|
+
const match = trimmed.match(/^```(?:json)?\s*([\s\S]*?)\s*```$/i);
|
|
13021
|
+
return match ? match[1].trim() : trimmed;
|
|
13022
|
+
};
|
|
13023
|
+
var parseMemoryInterpreterWireMutation = (raw) => {
|
|
13024
|
+
let parsed;
|
|
13025
|
+
try {
|
|
13026
|
+
parsed = JSON.parse(stripJsonFence(raw));
|
|
13027
|
+
} catch {
|
|
13028
|
+
return { ok: false, error: "interpreter output is not valid JSON" };
|
|
13029
|
+
}
|
|
13030
|
+
if (!isObject(parsed)) return { ok: false, error: "interpreter output must be an object" };
|
|
13031
|
+
if (!isString(parsed.action) || !ACTIONS.has(parsed.action)) {
|
|
13032
|
+
return { ok: false, error: "invalid reconciliation action" };
|
|
13033
|
+
}
|
|
13034
|
+
if (!isString(parsed.reason)) return { ok: false, error: "reason is required" };
|
|
13035
|
+
if (!optionalArray(parsed.evidence, validateEvidence)) return { ok: false, error: "invalid evidence array" };
|
|
13036
|
+
if (!optionalArray(parsed.entities, validateEntity)) return { ok: false, error: "invalid entities array" };
|
|
13037
|
+
if (!optionalArray(parsed.states, validateState)) return { ok: false, error: "invalid states array" };
|
|
13038
|
+
if (!optionalArray(parsed.relations, validateRelation)) return { ok: false, error: "invalid relations array" };
|
|
13039
|
+
return { ok: true, value: parsed };
|
|
13040
|
+
};
|
|
13041
|
+
var buildMemoryInterpreterWireContract = () => `
|
|
13042
|
+
Return ONLY one JSON object:
|
|
13043
|
+
{
|
|
13044
|
+
"action": "no_op|create|update|specialize|supersede|ambiguous",
|
|
13045
|
+
"reason": "short explanation",
|
|
13046
|
+
"evidence": [{ "key": "e1", "text": "...", "confidence": 0.9, "sourceRef": "optional" }],
|
|
13047
|
+
"entities": [{ "key": "n1", "type": "person|organization|project|place|object|activity|concept", "name": "...", "subtype": "optional", "aliases": [] }],
|
|
13048
|
+
"states": [{ "stateId": "optional-existing-state-id", "supersedes": "optional-existing-state-id-this-statement-replaces", "entityRef": "existing-entity-id-or-new-entity-key", "facet": "...", "value": {}, "text": "...", "evidenceRefs": ["e1"] }],
|
|
13049
|
+
"relations": [{ "fromRef": "existing-id-or-local-key", "type": "related_to|part_of|uses|involves|supersedes", "toRef": "existing-id-or-local-key" }]
|
|
13050
|
+
}
|
|
13051
|
+
|
|
13052
|
+
Do not generate persistent ids, owner ids, timestamps or storage keys. Runtime owns identity and time.
|
|
13053
|
+
Use short local keys only to connect records created in the SAME response. Every local key must be unique across evidence/entities.
|
|
13054
|
+
State evidenceRefs may reference Evidence emitted in this response. Evidence ids marked referenceable in the supplied memory context may be referenced directly. Do not reference any other prior Evidence id.
|
|
13055
|
+
When updating an existing State, reuse its exact stateId, exact entityRef and exact facet. Runtime preserves that State's original entity/facet/createdAt and appends new Evidence provenance.
|
|
13056
|
+
When creating a new State, omit stateId.
|
|
13057
|
+
For supersede: emit the replacing statement as a NEW State (omit stateId) and set supersedes to the exact id of the replaced current State. Runtime retires the replaced State \u2014 it stays recoverable as history but is no longer current, and the new State becomes the only current one for that facet. Never update or supersede an already retired State.
|
|
13058
|
+
supersedes and stateId are mutually exclusive on one State.
|
|
13059
|
+
Do not emit an existing Entity again merely to update its State; reference its exact id in entityRef.
|
|
13060
|
+
Relations may reference only known persisted Entity/State/Evidence ids or local Entity/Evidence keys emitted in the same response.
|
|
13061
|
+
Do not invent new Entity or Relation types. Keep expressive detail in subtype/facet/value/text.
|
|
13062
|
+
`.trim();
|
|
13063
|
+
var assertUniqueLocalKeys = (wire) => {
|
|
13064
|
+
const seen = /* @__PURE__ */ new Set();
|
|
13065
|
+
for (const item of [...wire.evidence ?? [], ...wire.entities ?? []]) {
|
|
13066
|
+
if (seen.has(item.key)) throw new Error(`duplicate local key: ${item.key}`);
|
|
13067
|
+
seen.add(item.key);
|
|
13068
|
+
}
|
|
13069
|
+
};
|
|
13070
|
+
var materializeMemoryInterpreterMutation = (input) => {
|
|
13071
|
+
assertUniqueLocalKeys(input.wire);
|
|
13072
|
+
const now = input.now ?? (/* @__PURE__ */ new Date()).toISOString();
|
|
13073
|
+
const nextId = input.nextId ?? ulid;
|
|
13074
|
+
const existingStates = new Map((input.existingStates ?? []).map((state2) => [state2.id, state2]));
|
|
13075
|
+
const existingStateIds = new Set(existingStates.keys());
|
|
13076
|
+
const existingEvidenceIds = new Set(
|
|
13077
|
+
[...existingStates.values()].flatMap((state2) => state2.evidenceIds)
|
|
13078
|
+
);
|
|
13079
|
+
const existingEntityIds = new Set(input.existingEntityIds ?? []);
|
|
13080
|
+
const entityRefs = /* @__PURE__ */ new Map();
|
|
13081
|
+
const evidenceRefs = /* @__PURE__ */ new Map();
|
|
13082
|
+
const evidence = (input.wire.evidence ?? []).map((item) => {
|
|
13083
|
+
const id = nextId();
|
|
13084
|
+
evidenceRefs.set(item.key, id);
|
|
13085
|
+
return {
|
|
13086
|
+
id,
|
|
13087
|
+
ownerId: input.ownerId,
|
|
13088
|
+
text: item.text,
|
|
13089
|
+
...item.sourceRef ? { sourceRef: item.sourceRef } : {},
|
|
13090
|
+
confidence: item.confidence,
|
|
13091
|
+
createdAt: now
|
|
13092
|
+
};
|
|
13093
|
+
});
|
|
13094
|
+
const entities = (input.wire.entities ?? []).map((item) => {
|
|
13095
|
+
const id = nextId();
|
|
13096
|
+
entityRefs.set(item.key, id);
|
|
13097
|
+
return {
|
|
13098
|
+
id,
|
|
13099
|
+
ownerId: input.ownerId,
|
|
13100
|
+
type: item.type,
|
|
13101
|
+
name: item.name,
|
|
13102
|
+
...item.subtype ? { subtype: item.subtype } : {},
|
|
13103
|
+
...item.aliases ? { aliases: item.aliases } : {},
|
|
13104
|
+
createdAt: now,
|
|
13105
|
+
updatedAt: now
|
|
13106
|
+
};
|
|
13107
|
+
});
|
|
13108
|
+
const resolveEntityRef = (ref) => {
|
|
13109
|
+
const created = entityRefs.get(ref);
|
|
13110
|
+
if (created) return created;
|
|
13111
|
+
if (existingEntityIds.has(ref)) return ref;
|
|
13112
|
+
throw new Error(`unknown entity ref: ${ref}`);
|
|
13113
|
+
};
|
|
13114
|
+
const supersededStateIds = [];
|
|
13115
|
+
const referenceableEvidenceIds = new Set(input.referenceableEvidenceIds ?? []);
|
|
13116
|
+
const resolveEvidenceRef = (ref) => {
|
|
13117
|
+
const created = evidenceRefs.get(ref);
|
|
13118
|
+
if (created) return created;
|
|
13119
|
+
if (referenceableEvidenceIds.has(ref)) return ref;
|
|
13120
|
+
throw new Error(`unknown evidence ref: ${ref}`);
|
|
13121
|
+
};
|
|
13122
|
+
const states = (input.wire.states ?? []).map((item) => {
|
|
13123
|
+
const prior = item.stateId ? existingStates.get(item.stateId) : void 0;
|
|
13124
|
+
if (item.stateId && !prior) {
|
|
13125
|
+
throw new Error(`unknown existing state: ${item.stateId}`);
|
|
13126
|
+
}
|
|
13127
|
+
if (prior?.retiredAt) {
|
|
13128
|
+
throw new Error(`retired state cannot be updated: ${item.stateId}`);
|
|
13129
|
+
}
|
|
13130
|
+
if (prior && item.entityRef !== prior.entityId) {
|
|
13131
|
+
throw new Error(`existing state entityRef changed: ${item.stateId}`);
|
|
13132
|
+
}
|
|
13133
|
+
if (prior && item.facet !== prior.facet) {
|
|
13134
|
+
throw new Error(`existing state facet changed: ${item.stateId}`);
|
|
13135
|
+
}
|
|
13136
|
+
let supersededStateId;
|
|
13137
|
+
if (item.supersedes !== void 0) {
|
|
13138
|
+
if (input.wire.action !== "supersede") {
|
|
13139
|
+
throw new Error(
|
|
13140
|
+
`supersedes is only valid for the supersede action, got ${input.wire.action}`
|
|
13141
|
+
);
|
|
13142
|
+
}
|
|
13143
|
+
if (item.stateId !== void 0) {
|
|
13144
|
+
throw new Error("supersedes and stateId are mutually exclusive on one state");
|
|
13145
|
+
}
|
|
13146
|
+
const superseded = existingStates.get(item.supersedes);
|
|
13147
|
+
if (!superseded) {
|
|
13148
|
+
throw new Error(`unknown superseded state id: ${item.supersedes}`);
|
|
13149
|
+
}
|
|
13150
|
+
if (superseded.retiredAt) {
|
|
13151
|
+
throw new Error(`retired state cannot be superseded: ${item.supersedes}`);
|
|
13152
|
+
}
|
|
13153
|
+
if (supersededStateIds.includes(item.supersedes)) {
|
|
13154
|
+
throw new Error(`duplicate superseded state id: ${item.supersedes}`);
|
|
13155
|
+
}
|
|
13156
|
+
supersededStateId = item.supersedes;
|
|
13157
|
+
}
|
|
13158
|
+
const newEvidenceIds = item.evidenceRefs.map(resolveEvidenceRef);
|
|
13159
|
+
const id = prior?.id ?? nextId();
|
|
13160
|
+
if (supersededStateId !== void 0) supersededStateIds.push(supersededStateId);
|
|
13161
|
+
return {
|
|
13162
|
+
id,
|
|
13163
|
+
ownerId: input.ownerId,
|
|
13164
|
+
entityId: prior?.entityId ?? resolveEntityRef(item.entityRef),
|
|
13165
|
+
facet: prior?.facet ?? item.facet,
|
|
13166
|
+
value: item.value,
|
|
13167
|
+
text: item.text,
|
|
13168
|
+
evidenceIds: [.../* @__PURE__ */ new Set([...prior?.evidenceIds ?? [], ...newEvidenceIds])],
|
|
13169
|
+
createdAt: prior?.createdAt ?? now,
|
|
13170
|
+
updatedAt: now
|
|
13171
|
+
};
|
|
13172
|
+
});
|
|
13173
|
+
const resolveRelationRef = (ref) => {
|
|
13174
|
+
const createdEntity = entityRefs.get(ref);
|
|
13175
|
+
if (createdEntity) return createdEntity;
|
|
13176
|
+
const createdEvidence = evidenceRefs.get(ref);
|
|
13177
|
+
if (createdEvidence) return createdEvidence;
|
|
13178
|
+
if (existingEntityIds.has(ref) || existingStateIds.has(ref) || existingEvidenceIds.has(ref)) {
|
|
13179
|
+
return ref;
|
|
13180
|
+
}
|
|
13181
|
+
throw new Error(`unknown relation ref: ${ref}`);
|
|
13182
|
+
};
|
|
13183
|
+
const relations = (input.wire.relations ?? []).map((item) => ({
|
|
13184
|
+
id: nextId(),
|
|
13185
|
+
ownerId: input.ownerId,
|
|
13186
|
+
from: resolveRelationRef(item.fromRef),
|
|
13187
|
+
type: item.type,
|
|
13188
|
+
to: resolveRelationRef(item.toRef),
|
|
13189
|
+
createdAt: now
|
|
13190
|
+
}));
|
|
13191
|
+
return {
|
|
13192
|
+
action: input.wire.action,
|
|
13193
|
+
reason: input.wire.reason,
|
|
13194
|
+
...evidence.length ? { evidence } : {},
|
|
13195
|
+
...entities.length ? { entities } : {},
|
|
13196
|
+
...states.length ? { states } : {},
|
|
13197
|
+
...supersededStateIds.length ? { supersededStateIds } : {},
|
|
13198
|
+
...relations.length ? { relations } : {}
|
|
13199
|
+
};
|
|
13200
|
+
};
|
|
13201
|
+
|
|
13202
|
+
// packages/ai/memory/vnext/interpreterPrompt.ts
|
|
13203
|
+
var MEMORY_VNEXT_ENTITY_CREATION_CONTRACT = `
|
|
13204
|
+
Entity creation is NOT named-entity recognition.
|
|
13205
|
+
|
|
13206
|
+
Create a new long-lived Entity only when the subject has future continuity value.
|
|
13207
|
+
A mention alone is insufficient.
|
|
13208
|
+
|
|
13209
|
+
Prefer leaving information as Evidence until at least one strong continuity signal exists:
|
|
13210
|
+
1. The subject recurs across independent dialogs, or the user explicitly describes it as enduring.
|
|
13211
|
+
2. The user connects it to their own preferences, relationships, goals, identity, worldview, ongoing work, or repeated activity.
|
|
13212
|
+
3. Future conversations are likely to refer back to it under different wording, so a stable anchor materially improves cross-dialog continuity.
|
|
13213
|
+
4. Creating the anchor is necessary to update or relate existing long-lived State.
|
|
13214
|
+
|
|
13215
|
+
Do NOT create an Entity merely because the text contains a named person, product, place, historical event, book, philosopher, food, device, or concept.
|
|
13216
|
+
When uncertain, keep Evidence and defer Entity creation.
|
|
13217
|
+
|
|
13218
|
+
Concept-specific rule:
|
|
13219
|
+
- concept is for abstract subjects that become part of the user's personal meaning world, such as freedom, absurdism, privacy, modernity, beauty, loneliness, safety, or maintainability.
|
|
13220
|
+
- Do not create a Concept Entity for every topic discussed or external fact queried.
|
|
13221
|
+
- Promote a concept only when it recurs, carries a durable user stance/interest/tension, connects multiple memories, or is likely to become a future recall/navigation anchor.
|
|
13222
|
+
- A one-off question such as "when was Kant born?" should normally create no long-lived Concept or Person Entity. Repeated discussion about Kant, freedom, and the user's own values may justify them.
|
|
13223
|
+
`.trim();
|
|
13224
|
+
var MEMORY_VNEXT_THIRD_PARTY_RELEVANCE_CONTRACT = `
|
|
13225
|
+
Third-party relevance test:
|
|
13226
|
+
- A fact about another person is durable only when it concerns the user's own world. Observation-only third-party facts \u2014 someone's appearance, news, habits, or the doings of a person the user merely encounters \u2014 stay Evidence, no matter how often they recur.
|
|
13227
|
+
- Closeness of that person, and repeated mentions across independent dialogs, do not by themselves make such an observation durable: never invent a user-world consequence to justify promotion (for example "the user keeps watching this person").
|
|
13228
|
+
- Matters that are part of the user's own shared life \u2014 household or family arrangements the user takes part in, a family member's health, or what the user relies on someone for \u2014 do belong to the user's world: state the user-world side (caregiving, changed time, changed plans, a sustained constraint) instead of a chronicle of the other person's doings.
|
|
13229
|
+
`.trim();
|
|
13230
|
+
var MEMORY_VNEXT_RECONCILIATION_CONTRACT = `
|
|
13231
|
+
When durable understanding changes, choose the smallest correct reconciliation:
|
|
13232
|
+
- no_op: no durable change.
|
|
13233
|
+
- create: genuinely new durable state/entity.
|
|
13234
|
+
- update: advance an existing state without changing its scope.
|
|
13235
|
+
- specialize: add a scoped exception/qualification; do not replace the broader state.
|
|
13236
|
+
- supersede: a newer statement explicitly replaces old current state. Emit the replacement as a NEW State and name the replaced current State in its supersedes field; runtime retires the old one (kept as recoverable history, no longer current).
|
|
13237
|
+
- ambiguous: evidence conflicts with current state, but replacement vs exception cannot be determined reliably.
|
|
13238
|
+
|
|
13239
|
+
Examples:
|
|
13240
|
+
- "\u56DE\u7B54\u7B80\u5355" then "\u5B89\u5168\u548C bug \u6392\u67E5\u8BE6\u7EC6" => specialize, not supersede.
|
|
13241
|
+
- "\u6211\u6709 Ollama Pro" then "\u6211\u5DF2\u7ECF\u4E0D\u7528 Ollama Pro \u4E86" => supersede.
|
|
13242
|
+
- Repeatedly choosing thin noodles without explicitly rejecting thick noodles => update or ambiguous, not automatic supersession.
|
|
13243
|
+
|
|
13244
|
+
Preserve ambiguity. Do not ask the user merely to clean memory. A later task may ask only if the unresolved state materially changes the answer.
|
|
13245
|
+
`.trim();
|
|
13246
|
+
var buildMemoryVNextInterpreterPrompt = () => [
|
|
13247
|
+
"You maintain long-lived adaptive relationship memory backed by evidence.",
|
|
13248
|
+
"External dialogs/files/web facts remain authoritative outside memory.",
|
|
13249
|
+
"Prefer a small stable set of Entities and updateable States over an ever-growing bag of facts.",
|
|
13250
|
+
MEMORY_VNEXT_ENTITY_CREATION_CONTRACT,
|
|
13251
|
+
MEMORY_VNEXT_THIRD_PARTY_RELEVANCE_CONTRACT,
|
|
13252
|
+
MEMORY_VNEXT_RECONCILIATION_CONTRACT,
|
|
13253
|
+
buildMemoryInterpreterWireContract()
|
|
13254
|
+
].join("\n\n");
|
|
13255
|
+
|
|
13256
|
+
// packages/ai/memory/vnext/legacyMigrationShadow.ts
|
|
13257
|
+
var LEGACY_MIGRATION_SHADOW_INSTRUCTION = `
|
|
13258
|
+
This Evidence came from a legacy memory record.
|
|
13259
|
+
Legacy kind and subject metadata are advisory hints only.
|
|
13260
|
+
Re-evaluate it under the current vNext contract.
|
|
13261
|
+
Do not mechanically map:
|
|
13262
|
+
- semantic -> State
|
|
13263
|
+
- procedural -> procedure State
|
|
13264
|
+
- subjectType=agent -> agent Entity
|
|
13265
|
+
- visibility -> scope
|
|
13266
|
+
Prefer Evidence-only when durable semantic value is unclear.
|
|
13267
|
+
`.trim();
|
|
13268
|
+
var serializeExisting = (existing) => JSON.stringify({
|
|
13269
|
+
entityIds: existing?.entityIds ?? [],
|
|
13270
|
+
states: (existing?.states ?? []).map((state2) => ({
|
|
13271
|
+
stateId: state2.id,
|
|
13272
|
+
entityId: state2.entityId,
|
|
13273
|
+
facet: state2.facet,
|
|
13274
|
+
text: state2.text
|
|
13275
|
+
}))
|
|
13276
|
+
});
|
|
13277
|
+
var buildLegacyMigrationInterpreterInput = (input) => [
|
|
13278
|
+
LEGACY_MIGRATION_SHADOW_INSTRUCTION,
|
|
13279
|
+
`The legacy record's Evidence is marked referenceable with id "${input.evidence.id}" and sourceRef "${input.evidence.sourceRef}". Evidence ids marked referenceable in the supplied memory context may be referenced directly. When a State cites it, reference that exact id in evidenceRefs. Do not emit another Evidence for this legacy record.`,
|
|
13280
|
+
`Imported Evidence (text is the authoritative legacy content, referenceable directly):
|
|
13281
|
+
${JSON.stringify(
|
|
13282
|
+
{
|
|
13283
|
+
...input.evidence,
|
|
13284
|
+
referenceable: true
|
|
13285
|
+
},
|
|
13286
|
+
null,
|
|
13287
|
+
2
|
|
13288
|
+
)}`,
|
|
13289
|
+
`Legacy metadata (advisory hints only, NOT vNext semantics):
|
|
13290
|
+
${JSON.stringify(
|
|
13291
|
+
{
|
|
13292
|
+
kind: input.item.kind,
|
|
13293
|
+
visibility: input.item.visibility,
|
|
13294
|
+
subjectType: input.item.subjectType,
|
|
13295
|
+
subjectId: input.item.subjectId,
|
|
13296
|
+
facet: input.item.facet,
|
|
13297
|
+
importance: input.item.importance,
|
|
13298
|
+
resident: input.item.resident
|
|
13299
|
+
},
|
|
13300
|
+
null,
|
|
13301
|
+
2
|
|
13302
|
+
)}`,
|
|
13303
|
+
`Existing vNext context for this principal (caller-supplied shadow snapshot):
|
|
13304
|
+
${serializeExisting(
|
|
13305
|
+
input.existing
|
|
13306
|
+
)}`
|
|
13307
|
+
].join("\n\n");
|
|
13308
|
+
var mergeImportedEvidence = (mutation, imported) => {
|
|
13309
|
+
const emitted = mutation.evidence ?? [];
|
|
13310
|
+
const duplicatedIds = new Set(
|
|
13311
|
+
emitted.filter(
|
|
13312
|
+
(item) => item.sourceRef === imported.sourceRef || // A re-emitted copy that drops sourceRef is still the same legacy record:
|
|
13313
|
+
// text equality is the only identity left on the wire to catch it.
|
|
13314
|
+
item.sourceRef === void 0 && item.text === imported.text
|
|
13315
|
+
).map((item) => item.id)
|
|
13316
|
+
);
|
|
13317
|
+
const rewrite = (id) => duplicatedIds.has(id) ? imported.id : id;
|
|
13318
|
+
return {
|
|
13319
|
+
...mutation,
|
|
13320
|
+
evidence: [imported, ...emitted.filter((item) => !duplicatedIds.has(item.id))],
|
|
13321
|
+
...mutation.states ? {
|
|
13322
|
+
states: mutation.states.map((state2) => ({
|
|
13323
|
+
...state2,
|
|
13324
|
+
evidenceIds: [...new Set(state2.evidenceIds.map(rewrite))]
|
|
13325
|
+
}))
|
|
13326
|
+
} : {},
|
|
13327
|
+
...mutation.relations ? {
|
|
13328
|
+
relations: mutation.relations.map((relation) => ({
|
|
13329
|
+
...relation,
|
|
13330
|
+
from: rewrite(relation.from),
|
|
13331
|
+
to: rewrite(relation.to)
|
|
13332
|
+
}))
|
|
13333
|
+
} : {}
|
|
13334
|
+
};
|
|
13335
|
+
};
|
|
13336
|
+
var runLegacyMemoryMigrationShadow = async (input) => {
|
|
13337
|
+
const principal = resolveLegacyMemoryPrincipal(input.item);
|
|
13338
|
+
const evidence = buildLegacyMemoryEvidence(input.item);
|
|
13339
|
+
const completion = await input.provider.complete(
|
|
13340
|
+
[
|
|
13341
|
+
{ role: "system", content: buildMemoryVNextInterpreterPrompt() },
|
|
13342
|
+
{
|
|
13343
|
+
role: "user",
|
|
13344
|
+
content: buildLegacyMigrationInterpreterInput({
|
|
13345
|
+
item: input.item,
|
|
13346
|
+
evidence,
|
|
13347
|
+
...input.existing ? { existing: input.existing } : {}
|
|
13348
|
+
})
|
|
13349
|
+
}
|
|
13350
|
+
],
|
|
13351
|
+
input.timeoutMs === void 0 ? void 0 : { timeoutMs: input.timeoutMs }
|
|
13352
|
+
);
|
|
13353
|
+
const parsed = parseMemoryInterpreterWireMutation(completion.content);
|
|
13354
|
+
if (!parsed.ok) {
|
|
13355
|
+
throw new Error(`legacy migration shadow: unparsable interpreter response (${parsed.error})`);
|
|
13356
|
+
}
|
|
13357
|
+
const candidate = materializeMemoryInterpreterMutation({
|
|
13358
|
+
// The principal identity (user:/space:/system:<id>) is the migration owner
|
|
13359
|
+
// space, so a space migration can never land in a user space.
|
|
13360
|
+
ownerId: evidence.ownerId,
|
|
13361
|
+
wire: parsed.value,
|
|
13362
|
+
...input.existing?.states ? { existingStates: [...input.existing.states] } : {},
|
|
13363
|
+
...input.existing?.entityIds ? { existingEntityIds: [...input.existing.entityIds] } : {},
|
|
13364
|
+
referenceableEvidenceIds: [evidence.id],
|
|
13365
|
+
...input.now === void 0 ? {} : { now: input.now },
|
|
13366
|
+
...input.nextId ? { nextId: input.nextId } : {}
|
|
13367
|
+
});
|
|
13368
|
+
const mutation = mergeImportedEvidence(candidate, evidence);
|
|
13369
|
+
return {
|
|
13370
|
+
principal,
|
|
13371
|
+
evidence,
|
|
13372
|
+
wire: parsed.value,
|
|
13373
|
+
mutation,
|
|
13374
|
+
action: mutation.action,
|
|
13375
|
+
reason: mutation.reason
|
|
13376
|
+
};
|
|
13377
|
+
};
|
|
13378
|
+
|
|
13379
|
+
// packages/ai/memory/vnext/lazyPromotion.ts
|
|
13380
|
+
var ERROR_MESSAGE_MAX2 = 120;
|
|
13381
|
+
var inFlight = /* @__PURE__ */ new Set();
|
|
13382
|
+
var shortError2 = (error) => {
|
|
13383
|
+
const message = error instanceof Error ? `${error.name}: ${error.message}` : String(error);
|
|
13384
|
+
return message.length > ERROR_MESSAGE_MAX2 ? `${message.slice(0, ERROR_MESSAGE_MAX2)}\u2026` : message;
|
|
13385
|
+
};
|
|
13386
|
+
var loadExistingContext = async (db, ownerId) => {
|
|
13387
|
+
const entities = await listMemoryEntitiesVNext(db, ownerId);
|
|
13388
|
+
const states = (await Promise.all(
|
|
13389
|
+
entities.map((entity) => listMemoryStatesForEntityVNext(db, ownerId, entity.id))
|
|
13390
|
+
)).flat();
|
|
13391
|
+
return {
|
|
13392
|
+
entityIds: entities.map((entity) => entity.id),
|
|
13393
|
+
states
|
|
13394
|
+
};
|
|
13395
|
+
};
|
|
13396
|
+
var withoutImportedEvidence = (mutation, importedEvidenceId) => ({
|
|
13397
|
+
...mutation,
|
|
13398
|
+
evidence: (mutation.evidence ?? []).filter((evidence) => evidence.id !== importedEvidenceId)
|
|
13399
|
+
});
|
|
13400
|
+
var hasWrites = (mutation) => (mutation.evidence?.length ?? 0) > 0 || (mutation.entities?.length ?? 0) > 0 || (mutation.states?.length ?? 0) > 0 || (mutation.supersededStateIds?.length ?? 0) > 0 || (mutation.relations?.length ?? 0) > 0;
|
|
13401
|
+
var runMemoryVNextLazyPromotion = async (input) => {
|
|
13402
|
+
const clock = input.clock ?? (() => performance.now());
|
|
13403
|
+
const startedAt = clock();
|
|
13404
|
+
const emit = input.emit ?? ((observation) => console.info("[memory] vnext lazy promotion", {
|
|
13405
|
+
event: "memory_vnext_lazy_promotion",
|
|
13406
|
+
...observation
|
|
13407
|
+
}));
|
|
13408
|
+
const finish = (partial) => {
|
|
13409
|
+
const observation = {
|
|
13410
|
+
...partial,
|
|
13411
|
+
latencyMs: Math.round((clock() - startedAt) * 10) / 10
|
|
13412
|
+
};
|
|
13413
|
+
try {
|
|
13414
|
+
emit(observation);
|
|
13415
|
+
} catch {
|
|
13416
|
+
}
|
|
13417
|
+
return observation;
|
|
13418
|
+
};
|
|
13419
|
+
const deterministicEvidence = buildLegacyMemoryEvidence(input.item);
|
|
13420
|
+
const flightKey = `${deterministicEvidence.ownerId}\0${deterministicEvidence.id}`;
|
|
13421
|
+
if (inFlight.has(flightKey)) {
|
|
13422
|
+
return finish({ status: "in_flight" });
|
|
13423
|
+
}
|
|
13424
|
+
inFlight.add(flightKey);
|
|
13425
|
+
try {
|
|
13426
|
+
const evidenceResult = await applyLegacyMemoryEvidence(input.db, input.item);
|
|
13427
|
+
if (evidenceResult.status === "conflict") {
|
|
13428
|
+
return finish({ status: "conflict" });
|
|
13429
|
+
}
|
|
13430
|
+
const evidence = evidenceResult.evidence;
|
|
13431
|
+
const existing = await loadExistingContext(input.db, evidence.ownerId);
|
|
13432
|
+
const alreadyCovered = (existing.states ?? []).some(
|
|
13433
|
+
(state2) => !state2.retiredAt && state2.evidenceIds.includes(evidence.id)
|
|
13434
|
+
);
|
|
13435
|
+
if (alreadyCovered) {
|
|
13436
|
+
return finish({ status: "already_covered" });
|
|
13437
|
+
}
|
|
13438
|
+
const interpreted = await runLegacyMemoryMigrationShadow({
|
|
13439
|
+
item: input.item,
|
|
13440
|
+
provider: input.provider,
|
|
13441
|
+
existing,
|
|
13442
|
+
...input.timeoutMs === void 0 ? {} : { timeoutMs: input.timeoutMs },
|
|
13443
|
+
...input.now === void 0 ? {} : { now: input.now },
|
|
13444
|
+
...input.nextId ? { nextId: input.nextId } : {}
|
|
13445
|
+
});
|
|
13446
|
+
const semanticMutation = withoutImportedEvidence(interpreted.mutation, evidence.id);
|
|
13447
|
+
if (!hasWrites(semanticMutation)) {
|
|
13448
|
+
return finish({ status: "no_op", action: semanticMutation.action });
|
|
13449
|
+
}
|
|
13450
|
+
await applyMemoryInterpreterMutation(input.db, evidence.ownerId, semanticMutation);
|
|
13451
|
+
return finish({ status: "promoted", action: semanticMutation.action });
|
|
13452
|
+
} catch (error) {
|
|
13453
|
+
return finish({ status: "error", error: shortError2(error) });
|
|
13454
|
+
} finally {
|
|
13455
|
+
inFlight.delete(flightKey);
|
|
13456
|
+
}
|
|
13457
|
+
};
|
|
13458
|
+
var isMemoryVNextLazyPromotionEnabled = (env = typeof process !== "undefined" ? process.env : {}) => env.NOLO_MEMORY_VNEXT_LAZY_PROMOTION === "1" || env.NOLO_MEMORY_VNEXT_LAZY_PROMOTION === "true";
|
|
13459
|
+
|
|
12076
13460
|
// packages/ai/memory/runtime.ts
|
|
12077
13461
|
var COLD_STORAGE_CONFIDENCE = 0.3;
|
|
12078
13462
|
var MEMORY_OVERLAY_TOKEN_BUDGET = DEFAULT_MEMORY_OVERLAY_TOKEN_BUDGET;
|
|
@@ -12196,6 +13580,7 @@ var resolveMemoryRuntime = async (input) => {
|
|
|
12196
13580
|
return { selectedItems: [], promptBlock: null };
|
|
12197
13581
|
}
|
|
12198
13582
|
const policy = resolveAgentMemoryPolicy({ agentKey: input.agentKey });
|
|
13583
|
+
const legacyStartedAt = performance.now();
|
|
12199
13584
|
const candidates = await loadMemoryCandidatesFromDb(input.db, {
|
|
12200
13585
|
owners,
|
|
12201
13586
|
subjects: buildMemorySubjectsForAgent({
|
|
@@ -12222,13 +13607,40 @@ var resolveMemoryRuntime = async (input) => {
|
|
|
12222
13607
|
input.userInput
|
|
12223
13608
|
);
|
|
12224
13609
|
const selected = [...residentItems, ...ranked];
|
|
13610
|
+
const legacyLatencyMs = Math.round((performance.now() - legacyStartedAt) * 10) / 10;
|
|
13611
|
+
const promptBlock = selected.length === 0 ? null : buildMemoryOverlay(selected, { maxTokens: MEMORY_OVERLAY_TOKEN_BUDGET });
|
|
13612
|
+
const shadowEnabled = input.vNextShadowProvider != null && isMemoryVNextShadowReadEnabled();
|
|
13613
|
+
if (shadowEnabled) {
|
|
13614
|
+
await runMemoryVNextShadowRead({
|
|
13615
|
+
ctx: {
|
|
13616
|
+
db: input.db,
|
|
13617
|
+
owners,
|
|
13618
|
+
query: input.userInput,
|
|
13619
|
+
provider: input.vNextShadowProvider
|
|
13620
|
+
},
|
|
13621
|
+
legacyItems: selected,
|
|
13622
|
+
legacyLatencyMs,
|
|
13623
|
+
legacyContextChars: promptBlock?.length ?? 0
|
|
13624
|
+
});
|
|
13625
|
+
}
|
|
13626
|
+
const promotionCandidate = selected[0];
|
|
13627
|
+
const lazyPromotionEnabled = input.vNextShadowProvider != null && isMemoryVNextLazyPromotionEnabled();
|
|
13628
|
+
if (lazyPromotionEnabled && promotionCandidate) {
|
|
13629
|
+
void runMemoryVNextLazyPromotion({
|
|
13630
|
+
db: input.db,
|
|
13631
|
+
item: promotionCandidate,
|
|
13632
|
+
provider: input.vNextShadowProvider,
|
|
13633
|
+
...input.lazyPromotionEmit ? { emit: input.lazyPromotionEmit } : {}
|
|
13634
|
+
}).catch(() => {
|
|
13635
|
+
});
|
|
13636
|
+
}
|
|
12225
13637
|
if (selected.length === 0) {
|
|
12226
13638
|
return { selectedItems: [], promptBlock: null };
|
|
12227
13639
|
}
|
|
12228
13640
|
await touchMemoryItemsInDb(input.db, selected);
|
|
12229
13641
|
return {
|
|
12230
13642
|
selectedItems: selected,
|
|
12231
|
-
promptBlock
|
|
13643
|
+
promptBlock
|
|
12232
13644
|
};
|
|
12233
13645
|
};
|
|
12234
13646
|
|
|
@@ -12272,7 +13684,8 @@ var queryLocalMemory = async (env, agentKey, userInput, spaceId) => {
|
|
|
12272
13684
|
userId: machineId,
|
|
12273
13685
|
agentKey,
|
|
12274
13686
|
userInput,
|
|
12275
|
-
...spaceId ? { spaceId } : {}
|
|
13687
|
+
...spaceId ? { spaceId } : {},
|
|
13688
|
+
...isMemoryVNextShadowReadEnabled(env) ? { vNextShadowProvider: void 0 } : {}
|
|
12276
13689
|
});
|
|
12277
13690
|
return resolution.promptBlock;
|
|
12278
13691
|
};
|
|
@@ -12350,7 +13763,10 @@ async function resolveAgentRunAgentKey(args) {
|
|
|
12350
13763
|
}
|
|
12351
13764
|
async function runAgentRunCommand(args, deps) {
|
|
12352
13765
|
const env = deps.env ?? process.env;
|
|
12353
|
-
const output = deps.output ??
|
|
13766
|
+
const output = deps.output ?? {
|
|
13767
|
+
write: (chunk) => process.stdout.write(chunk),
|
|
13768
|
+
writeErr: (chunk) => process.stderr.write(chunk)
|
|
13769
|
+
};
|
|
12354
13770
|
if (args.includes("--help") || args.includes("-h")) {
|
|
12355
13771
|
writeUsage(output, deps.commandPath);
|
|
12356
13772
|
return 0;
|