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.
Files changed (168) hide show
  1. package/README.md +2 -2
  2. package/{_executeModel-IULR47HG.js → _executeModel-BPUR2QYH.js} +51 -50
  3. package/{action-D22U6CTH.js → action-P4TNFGAD.js} +11 -11
  4. package/{addContentAction-XAPUTGL4.js → addContentAction-MB2HHMDZ.js} +9 -9
  5. package/{addDialogAgentAction-M7VLLBZM.js → addDialogAgentAction-S2NRBCWW.js} +9 -9
  6. package/{agentDeleteCommand-2S4WCDQC.js → agentDeleteCommand-MNAA6MIG.js} +32 -30
  7. package/{agentEmailCommands-V3ADGHX7.js → agentEmailCommands-SK34WJKU.js} +70 -66
  8. package/{agentGrantCommands-R3VQEZJR.js → agentGrantCommands-M3XFO6EN.js} +2 -2
  9. package/{agentListCommands-EPK3S274.js → agentListCommands-I26MKI4T.js} +55 -36
  10. package/{agentMachineCommands-XMZWK7P3.js → agentMachineCommands-M6QDR6P3.js} +32 -30
  11. package/{agentProviderCommands-65ZC2WB4.js → agentProviderCommands-X3UNW77C.js} +87 -0
  12. package/{agentPullCommand-N7L2CT7L.js → agentPullCommand-O5MPVJ5E.js} +3 -3
  13. package/agentRecordCommands-HTHLO2MM.js +129 -0
  14. package/{agentRunCommand-VUWNWC7C.js → agentRunCommand-IAIRCMTH.js} +70 -65
  15. package/{agentRunControl-T44MESII.js → agentRunControl-AVJR4JW4.js} +2 -2
  16. package/{agentRuntimeLocal-YRONTDLM.js → agentRuntimeLocal-3WTYYIT2.js} +32 -26
  17. package/{agentSlice-2P7OJFES.js → agentSlice-TVP3HINW.js} +10 -10
  18. package/{appDeleteCommands-YS7UGMP3.js → appDeleteCommands-SB5TNLKY.js} +32 -30
  19. package/{appDeployCommands-XIE5Z4BE.js → appDeployCommands-2IPKZINV.js} +32 -30
  20. package/{appDeployStatusCommands-54UDVYET.js → appDeployStatusCommands-K63TFUID.js} +32 -30
  21. package/{appGetCommands-6XYLBCRN.js → appGetCommands-VU2SLNEH.js} +32 -30
  22. package/{appListCommands-VEGH7SF5.js → appListCommands-S3T4DJ36.js} +32 -30
  23. package/{authCommand-JIEOFHXW.js → authCommand-HGP2XTKC.js} +185 -28
  24. package/{authCommands-ILTBI6JV.js → authCommands-RGOGCPP6.js} +4 -5
  25. package/builtinSkillRegistry-Q2VVY3SC.js +33 -0
  26. package/{chatQueueReduxAdapter-GPYCH5Z2.js → chatQueueReduxAdapter-TWIYKVIZ.js} +25 -25
  27. package/{chromeCommands-VOIRNJBL.js → chromeCommands-FZYAU75D.js} +1 -1
  28. package/{chromeOpsCommands-M7DPCX2T.js → chromeOpsCommands-62P2Q2YB.js} +31 -1
  29. package/{chunk-C3FZR5EC.js → chunk-2F7RJC6L.js} +1 -1
  30. package/{chunk-BOYUESO7.js → chunk-3AMA42ZI.js} +1 -1
  31. package/{chunk-RZOJRTKR.js → chunk-3BGIKIPF.js} +444 -920
  32. package/{chunk-HQUORJTM.js → chunk-3BMYXEUW.js} +1 -1
  33. package/{chunk-EBKMQULC.js → chunk-3IUWIAHP.js} +13 -15
  34. package/{chunk-NTW5GWDM.js → chunk-3VNWWVKB.js} +2 -0
  35. package/{chunk-4SZ37KLL.js → chunk-3VUWPRFW.js} +50 -30
  36. package/{chunk-WL2RKIBF.js → chunk-3YIAR5UI.js} +1 -1
  37. package/{chunk-DWUCB2A3.js → chunk-42V6BK2E.js} +1 -1
  38. package/{chunk-AX7RMXSH.js → chunk-4MK3I7Y4.js} +38 -4
  39. package/{chunk-PF6O3GR3.js → chunk-52Q2IW2X.js} +1340 -1273
  40. package/{chunk-Y3NZYLPG.js → chunk-5MEYHVIB.js} +1 -1
  41. package/{chunk-5XTOKQLW.js → chunk-5UTFL4QJ.js} +6 -2
  42. package/chunk-5ZUL4CUO.js +10 -0
  43. package/{chunk-6YTOJY35.js → chunk-6D2JFXLY.js} +35 -0
  44. package/{chunk-E6RGHPDR.js → chunk-6D6VBVEW.js} +4 -6
  45. package/{chunk-FZGV4FGK.js → chunk-6GFOD3TK.js} +260 -140
  46. package/{chunk-TMPLPCVX.js → chunk-6OZ36FXI.js} +2 -2
  47. package/{chunk-PZM3EENV.js → chunk-6Z7MY3V7.js} +1 -1
  48. package/{chunk-BYEJ7K2Z.js → chunk-7S4YWN7P.js} +1 -1
  49. package/{chunk-SREASRV5.js → chunk-ABQYVJBJ.js} +1 -1
  50. package/chunk-ACTMNVHM.js +93 -0
  51. package/{chunk-ZZCJUXUI.js → chunk-AHAHBQMU.js} +2 -2
  52. package/{chunk-BJCWNHVU.js → chunk-BFDFRLLQ.js} +2 -2
  53. package/chunk-BMQ2MJUK.js +153 -0
  54. package/chunk-BNGW5ASC.js +344 -0
  55. package/{chunk-2KDR4CWE.js → chunk-BYMV6QZG.js} +24 -1
  56. package/{chunk-73BR2IQT.js → chunk-CWQINZEA.js} +127 -7
  57. package/{chunk-HTMVBPOF.js → chunk-DD6XE56O.js} +19 -72
  58. package/{chunk-CADAR6QU.js → chunk-EYAQT56M.js} +4 -3
  59. package/{chunk-CJCJF5XB.js → chunk-FDTR4QJ6.js} +4 -2
  60. package/{chunk-D6XYLSOS.js → chunk-FKNWP6SG.js} +1 -1
  61. package/{chunk-3VPDELAP.js → chunk-FP76KI2Y.js} +1500 -84
  62. package/chunk-FV3JEYR3.js +870 -0
  63. package/{chunk-GCJ3IS5M.js → chunk-GIVFXPWK.js} +177 -6
  64. package/chunk-GMZLP5DV.js +82 -0
  65. package/{chunk-LHDV2QUI.js → chunk-GNCCNNZD.js} +4 -2
  66. package/{chunk-XWNRAIUL.js → chunk-GP5LKBUZ.js} +6 -16
  67. package/{chunk-PZCTYKGU.js → chunk-GQBOR3G6.js} +2 -2
  68. package/{chunk-NFT2AOK5.js → chunk-H4AHY5BU.js} +13 -85
  69. package/{chunk-FNGAF7C4.js → chunk-HAFJ3NDE.js} +137 -12
  70. package/{chunk-ZVN6I33J.js → chunk-HCT7U36O.js} +9 -5
  71. package/{chunk-7QVPPOEC.js → chunk-HKNXJGEC.js} +43 -43
  72. package/{chunk-3JQ2NRYU.js → chunk-HVURBGF3.js} +4 -4
  73. package/{chunk-OZX2IPKM.js → chunk-HYJFRTLW.js} +2 -2
  74. package/{chunk-HH65VA5U.js → chunk-I3TQJXQ7.js} +109 -6
  75. package/{chunk-UDQWGU7F.js → chunk-J4MOO56S.js} +1 -1
  76. package/{chunk-KC5FAHVS.js → chunk-JEDZAO7L.js} +1 -1
  77. package/{chunk-6XIE5ZGI.js → chunk-JPGCXHNM.js} +1 -1
  78. package/{chunk-DUJWWUGV.js → chunk-K36IXSCQ.js} +1 -1
  79. package/{chunk-KRMWO2NN.js → chunk-KAUSRTO6.js} +3 -3
  80. package/{chunk-7FWPLK4M.js → chunk-LJ5VW2UJ.js} +1 -1
  81. package/{chunk-GHEJJGJI.js → chunk-LMREEBWT.js} +833 -109
  82. package/{chunk-RXX4GDIH.js → chunk-LS2ZANRJ.js} +1 -1
  83. package/chunk-LVIFM7VW.js +1625 -0
  84. package/{chunk-BJIRLHJR.js → chunk-M2EJHDJP.js} +4 -0
  85. package/{chunk-EVBFYPDC.js → chunk-MC4XLIJ7.js} +6 -2
  86. package/{chunk-KEZNSFGD.js → chunk-MZYBSTMH.js} +11 -173
  87. package/chunk-OCZKATRC.js +129 -0
  88. package/{chunk-MXUSPS2N.js → chunk-OIVSQH2O.js} +1510 -1592
  89. package/{chunk-E36HZARC.js → chunk-P5EVSOPA.js} +93 -17
  90. package/{chunk-SZLVDREM.js → chunk-PBA4UJBK.js} +3 -3
  91. package/{chunk-URWDSZRW.js → chunk-PMAIQX7A.js} +3 -3
  92. package/{chunk-AETZ7AD6.js → chunk-Q554LLSI.js} +1 -1
  93. package/{chunk-AJHEFRGJ.js → chunk-Q67DOFOO.js} +214 -5
  94. package/{chunk-UZ6XXCVR.js → chunk-QDSINZM3.js} +15 -2
  95. package/{chunk-NRALD3CC.js → chunk-QSHEEA5N.js} +54 -10
  96. package/chunk-QU7KDSZX.js +677 -0
  97. package/{chunk-T25L377S.js → chunk-RPJUFEGR.js} +10 -10
  98. package/{chunk-QCZX4FTW.js → chunk-SH43IESU.js} +173 -15
  99. package/{chunk-SPAQ4PVV.js → chunk-SV5IJK6K.js} +1 -1
  100. package/{chunk-BKJO7LDP.js → chunk-U4OKDZFH.js} +6 -6
  101. package/{chunk-DM4FBSWG.js → chunk-UDVH2P4A.js} +7 -7
  102. package/{chunk-4EJ5QYB5.js → chunk-UEVXFHQB.js} +2 -2
  103. package/{chunk-JYYZCK2Z.js → chunk-V7E4PXQD.js} +1 -1
  104. package/{chunk-NHRQCXIQ.js → chunk-VMFTFOWF.js} +13 -3
  105. package/{chunk-YFADVSZE.js → chunk-VRTTFDBM.js} +7 -6
  106. package/{chunk-U7YP7ECK.js → chunk-WP5UXDA5.js} +84 -13
  107. package/{chunk-5J7W2VWW.js → chunk-WV42OMV7.js} +6 -265
  108. package/{chunk-3QPYFHAH.js → chunk-XD2MJFUG.js} +1 -1
  109. package/{chunk-IDGYOD2O.js → chunk-XP3VVAPG.js} +3174 -223
  110. package/{chunk-ETLZZQJE.js → chunk-Z2PV6O2T.js} +121 -26
  111. package/{chunk-BZNGCVAW.js → chunk-Z5625XML.js} +4 -4
  112. package/{contentThunks-THSCADSK.js → contentThunks-JYWI7G7I.js} +26 -26
  113. package/{cooldownCommands-BSCH2W7P.js → cooldownCommands-REAWYVTY.js} +2 -2
  114. package/{createAgentAutomationAction-WGN3UQ5A.js → createAgentAutomationAction-Z4SUJ54Y.js} +26 -26
  115. package/{createDialogAction-3EN2NLH7.js → createDialogAction-RCHFLVJ2.js} +29 -29
  116. package/{createPageAction-4VK473QV.js → createPageAction-YK2253XQ.js} +28 -28
  117. package/{dbSlice-GKGGFNOB.js → dbSlice-A6C6H32X.js} +8 -8
  118. package/{deleteFile-LWSR674W.js → deleteFile-YG6QMJLU.js} +3 -3
  119. package/{dialogCommands-PS4NWYY7.js → dialogCommands-X4UOZQWX.js} +36 -32
  120. package/{dialogSlice-CLV7SVOZ.js → dialogSlice-IVTWLCE2.js} +31 -25
  121. package/{docCreateCommands-4KANZJR6.js → docCreateCommands-VD6TGHG4.js} +33 -31
  122. package/{docDeleteCommands-F2S2TRUF.js → docDeleteCommands-OT3R2G4W.js} +34 -32
  123. package/{docReadCommands-B2WDPZQE.js → docReadCommands-2G7BIXSH.js} +33 -31
  124. package/{docStore-TDLCHWPF.js → docStore-UENKCCDX.js} +9 -9
  125. package/{docUpdateCommands-E7TKHRIO.js → docUpdateCommands-45MVJKZA.js} +33 -31
  126. package/{fetchMessages-DRABNDPZ.js → fetchMessages-EIU7UFFK.js} +3 -4
  127. package/{getPricing-QVTUQQTM.js → getPricing-LUSEABA6.js} +4 -4
  128. package/{handleSendMessageAction-AHL3ZHE4.js → handleSendMessageAction-LM2J4HC3.js} +66 -74
  129. package/index.js +99 -86
  130. package/{localDialogRead-PUQKFI73.js → localDialogRead-BTFJ4V2I.js} +2 -2
  131. package/{localRuntimeDb-P37ZTX55.js → localRuntimeDb-SYQGUF4U.js} +1 -1
  132. package/{machineCommands-OTABVXOA.js → machineCommands-6N6MQIE6.js} +69 -65
  133. package/{machineWsRunDispatch-V4EVQSMZ.js → machineWsRunDispatch-7MFKVQCR.js} +65 -61
  134. package/{memberThunks-KATHH3F4.js → memberThunks-P2ECUJ56.js} +9 -9
  135. package/{models-GS72DVJS.js → models-T3SG6MJ5.js} +2 -2
  136. package/{offlineMarxistsAgentCommand-GEH6SNNA.js → offlineMarxistsAgentCommand-HGXZV4XJ.js} +1 -1
  137. package/package.json +1 -1
  138. package/pdf-U6KSUEZZ.js +26435 -0
  139. package/providerPresetApply-XI3WUPTI.js +214 -0
  140. package/providerRegistry-KEPWWGXD.js +31 -0
  141. package/{read-LC6HVYBN.js → read-COE3ZYR6.js} +5 -4
  142. package/{readDocTool-N3ERJHHF.js → readDocTool-5USN4A6V.js} +1 -1
  143. package/{readlineWorkspace-IIT3FQ6I.js → readlineWorkspace-JWBON5CX.js} +291 -135
  144. package/{removeDialogAgentAction-F5GPTALR.js → removeDialogAgentAction-W66BJ7CF.js} +12 -12
  145. package/{runAgentClientLoop-7TQM7IAR.js → runAgentClientLoop-TA4SSPHE.js} +49 -49
  146. package/{runtimeDoctorCommands-CROTMULY.js → runtimeDoctorCommands-X6WDBEQX.js} +2 -2
  147. package/{setDialogExtraReferencesAction-AY4ZCF3A.js → setDialogExtraReferencesAction-2ALKG3WA.js} +10 -10
  148. package/{setPrimaryDialogAgentAction-HPMG7V3R.js → setPrimaryDialogAgentAction-TQZB55F6.js} +12 -12
  149. package/{settingSlice-OEJA4NQO.js → settingSlice-P4ZW7K5X.js} +10 -10
  150. package/{spaceCommands-FSYH7AL4.js → spaceCommands-6NSAXB7D.js} +31 -29
  151. package/{streamAgentChatTurn-6EF6TVFK.js → streamAgentChatTurn-X5ENGUIS.js} +126 -65
  152. package/{switchDialogAgentAction-HMDZTZ4I.js → switchDialogAgentAction-3KI72HHS.js} +9 -9
  153. package/{tableCommands-SUNTHAYX.js → tableCommands-O6NWHFKV.js} +1 -1
  154. package/{toolApiClient-VGYUB4P5.js → toolApiClient-G3M73RTB.js} +3 -3
  155. package/{tools-R3QNWWTD.js → tools-XRQR7ZZR.js} +45 -45
  156. package/tuiSummaryLlmCaller-UFGFOIIW.js +128 -0
  157. package/{updateCommands-Y363MC3L.js → updateCommands-2M74UL7P.js} +2 -2
  158. package/{updateDialogTitleAction-F3EUOWOB.js → updateDialogTitleAction-ESUUD3GT.js} +46 -29
  159. package/agentRecordCommands-WFPWLWOF.js +0 -125
  160. package/chunk-FMODTASJ.js +0 -109
  161. package/chunk-I42VC5KR.js +0 -15
  162. package/chunk-NB5SIWC4.js +0 -611
  163. package/chunk-NG4UT4K4.js +0 -79
  164. package/codingSkills-7S6523WH.js +0 -48
  165. package/tuiSummaryLlmCaller-PWOXTCBF.js +0 -116
  166. package/{chunk-3RAG2NAD.js → chunk-UKWGR5SS.js} +3 -3
  167. package/{db-VQSAOWAO.js → db-WK5MDZVN.js} +1 -1
  168. 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-JYYZCK2Z.js";
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
- } from "./chunk-GHEJJGJI.js";
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-HH65VA5U.js";
42
+ } from "./chunk-I3TQJXQ7.js";
39
43
  import {
44
+ clearCredentialAvailability,
40
45
  readCredentialEntry,
41
46
  recordCredentialProbe,
42
47
  resolveCredentialKeyWithFallback
43
- } from "./chunk-DWUCB2A3.js";
48
+ } from "./chunk-42V6BK2E.js";
44
49
  import {
45
50
  getReadableCliDb
46
- } from "./chunk-RXX4GDIH.js";
51
+ } from "./chunk-LS2ZANRJ.js";
47
52
  import {
48
53
  readDbRecord,
49
54
  resolveAgentRecordFromHybridStore
50
- } from "./chunk-NRALD3CC.js";
55
+ } from "./chunk-QSHEEA5N.js";
51
56
  import {
52
57
  isLocalCliAgentKey
53
- } from "./chunk-SPAQ4PVV.js";
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-RZOJRTKR.js";
68
+ } from "./chunk-3BGIKIPF.js";
67
69
  import {
68
70
  isTransientFetchError
69
- } from "./chunk-5XTOKQLW.js";
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-NTW5GWDM.js";
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-KEZNSFGD.js";
92
+ } from "./chunk-MZYBSTMH.js";
88
93
  import {
89
94
  API_REPORTED_COST_MULTIPLIER,
90
95
  parseUiAskChoiceContent
91
- } from "./chunk-IDGYOD2O.js";
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-C3FZR5EC.js";
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-AETZ7AD6.js";
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-PF6O3GR3.js";
119
+ } from "./chunk-52Q2IW2X.js";
115
120
  import {
116
121
  resolveAgentRuntimeConfigFromRecord
117
- } from "./chunk-AX7RMXSH.js";
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-CJCJF5XB.js";
134
+ } from "./chunk-FDTR4QJ6.js";
129
135
  import {
130
136
  isAntigravityOAuthAgent
131
- } from "./chunk-LHDV2QUI.js";
137
+ } from "./chunk-GNCCNNZD.js";
132
138
  import {
133
139
  resolveClientVersion
134
- } from "./chunk-TMPLPCVX.js";
140
+ } from "./chunk-6OZ36FXI.js";
135
141
  import {
136
142
  DEFAULT_CONTEXT_WINDOW,
137
143
  getModelContextWindow,
138
144
  normalizeUsage
139
- } from "./chunk-7QVPPOEC.js";
145
+ } from "./chunk-HKNXJGEC.js";
140
146
  import {
141
147
  clipCompactText
142
- } from "./chunk-E36HZARC.js";
148
+ } from "./chunk-P5EVSOPA.js";
143
149
  import {
144
150
  findModelConfig
145
- } from "./chunk-MXUSPS2N.js";
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-AJHEFRGJ.js";
176
+ } from "./chunk-Q67DOFOO.js";
171
177
  import {
172
178
  parsePositiveFiniteNumberOrFallback
173
179
  } from "./chunk-Y5GCAMGP.js";
174
180
  import {
175
- createMemoryKey
176
- } from "./chunk-NHRQCXIQ.js";
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-5J7W2VWW.js";
191
+ } from "./chunk-BNGW5ASC.js";
185
192
  import {
186
193
  parsePublicAgentId
187
- } from "./chunk-BJIRLHJR.js";
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 = displayWidth(line);
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 (cur === "" || next === void 0 || next === "") continue;
8276
- if (LIST_LIKE.test(cur) === LIST_LIKE.test(next)) continue;
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
- if (TASK_LIST_RE.test(line) || UNORDERED_LIST_RE.test(line) || ORDERED_LIST_RE.test(line) || /^\s*(?:•|☐|☑)\s/.test(line) || /^\s*[\u2460-\u2473]/.test(line)) {
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
- const prevList = prev === "list";
8446
- const nextList = next === "list";
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 showThinking = options.showThinking !== false;
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
- compactionEvent = event;
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-YRONTDLM.js");
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 (!m) return { kind: "generic" };
10682
- const status = Number(m[2]);
10683
- const transport = PLATFORM_TRANSPORT_RE.test(message) ? "platform" : "local";
10684
- if (status === 401) {
10685
- return { kind: "auth", transport, status };
10686
- }
10687
- if (status === 403) {
10688
- return isQuotaLimited403Body(message) ? { kind: "rate-limit", transport, status } : { kind: "auth", transport, status };
10689
- }
10690
- if (status === 400 || status === 422) {
10691
- return { kind: "rejected-payload", transport, status };
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
- if (status === 429) {
10694
- return { kind: "rate-limit", transport, status };
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
- if (status >= 500 && status <= 599) {
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: "upstream", transport, status };
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
- return `${RUN_UNAVAILABLE_PREFIX} (${ctx.where} returned HTTP ${ctx.status}, rate limited). Detail: ${ctx.message} ${NO_FALLBACK} Retry shortly, ${SERVER_FALLBACK_HINT}.${cooldownNote}
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
- ...cooldownUntil ? { cooldownUntil } : {}
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 ?? ulid();
11082
- const turnId = `turn-${ulid()}`;
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
- options.output.write(
11203
- `[nolo] Local agent run failed: ${toErrorMessage(error)}
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) return null;
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 null;
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 null;
11560
+ return { credentialKey };
11256
11561
  }
11257
- if (gateDecision !== "blocked") return null;
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 localBlock = await checkLocalAvailabilityBeforeHttpDispatch(options);
11341
- if (localBlock) {
11342
- return { exitCode: localBlock.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 runHttpAgentTurn(options, authToken);
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: buildMemoryOverlay(selected, { maxTokens: MEMORY_OVERLAY_TOKEN_BUDGET })
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 ?? process.stdout;
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;