@alecsibilia/luca 14.0.0-alpha.2 → 14.0.0-alpha.21

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 (321) hide show
  1. package/CHANGELOG.md +76 -0
  2. package/README.md +7 -2
  3. package/board/client/board-look.ts +31 -1
  4. package/board/client/board-panel-parts.tsx +150 -0
  5. package/board/client/board-panel-stages.ts +99 -0
  6. package/board/client/board-panel-styles.ts +223 -0
  7. package/board/client/board-panel.tsx +77 -1275
  8. package/board/client/engine-life.ts +48 -0
  9. package/board/client/final-review-stack.tsx +144 -0
  10. package/board/client/heartbeat.tsx +61 -0
  11. package/board/client/helper-lines.tsx +69 -0
  12. package/board/client/live-feed.tsx +86 -0
  13. package/board/client/live-line.ts +73 -0
  14. package/board/client/model-line.tsx +178 -0
  15. package/board/client/needs-you-section.tsx +133 -0
  16. package/board/client/one-line.tsx +193 -0
  17. package/board/client/repo-wait-banner.tsx +69 -0
  18. package/board/client/run-footer.tsx +68 -0
  19. package/board/client/run-header.tsx +189 -0
  20. package/board/client/run-picker.tsx +98 -0
  21. package/board/client/status-bar.tsx +131 -0
  22. package/board/client/step-dots.tsx +127 -0
  23. package/board/client/stuck-actions.tsx +269 -0
  24. package/board/client/ticket-card-view.tsx +238 -0
  25. package/board/client/ticket-detail.tsx +87 -0
  26. package/board/client/ticket-stack.tsx +119 -0
  27. package/board/client/ticket-wait.ts +188 -0
  28. package/board/client/timeline-rows.tsx +41 -14
  29. package/board/client/usage-line.tsx +51 -0
  30. package/board/client/wait-line.tsx +39 -0
  31. package/board/index.client.tsx +1 -1
  32. package/board/index.server.ts +7 -1
  33. package/board/package.json +1 -1
  34. package/board/server/board-panel-state-helpers.ts +67 -0
  35. package/board/server/board-server-check.ts +294 -0
  36. package/board/server/board-server-engine.ts +129 -0
  37. package/board/server/board-server-events.ts +134 -0
  38. package/board/server/board-server-read.ts +190 -0
  39. package/board/server/board-server-resume.ts +164 -0
  40. package/board/server/board-server-start.ts +174 -0
  41. package/board/server/board-server-store.ts +281 -0
  42. package/board/server/board-server-types.ts +114 -0
  43. package/board/server/board-server-util.ts +4 -0
  44. package/board/server/board-server.ts +52 -943
  45. package/board/server/board-vocabulary-engine.ts +144 -0
  46. package/board/server/board-vocabulary-review.ts +115 -0
  47. package/board/server/board-vocabulary-run.ts +145 -0
  48. package/board/server/board-vocabulary-shapes.ts +153 -0
  49. package/board/server/board-vocabulary.ts +20 -375
  50. package/board/server/current-step-panel-helpers.ts +108 -0
  51. package/board/server/describe-record.ts +403 -0
  52. package/board/server/engine-launch.ts +20 -3
  53. package/board/server/engine-restart-helpers.ts +105 -0
  54. package/board/server/engine-watch.ts +45 -5
  55. package/board/server/journal-rebuild-helpers.ts +169 -0
  56. package/board/server/live-file.ts +130 -0
  57. package/board/server/luca-version.ts +1 -1
  58. package/board/server/make-rows.ts +14 -629
  59. package/board/server/record-texts.ts +350 -0
  60. package/board/server/reduce-board-agent-start.ts +224 -0
  61. package/board/server/reduce-board-agents.ts +160 -0
  62. package/board/server/reduce-board-counters.ts +138 -0
  63. package/board/server/reduce-board-create.ts +148 -0
  64. package/board/server/reduce-board-final-review.ts +174 -0
  65. package/board/server/reduce-board-needs-you.ts +283 -0
  66. package/board/server/reduce-board-reasons.ts +59 -0
  67. package/board/server/reduce-board-run.ts +255 -0
  68. package/board/server/reduce-board-settle.ts +88 -0
  69. package/board/server/reduce-board-steps.ts +226 -0
  70. package/board/server/reduce-board-text.ts +139 -0
  71. package/board/server/reduce-board-ticket-checks.ts +168 -0
  72. package/board/server/reduce-board-ticket-join.ts +144 -0
  73. package/board/server/reduce-board-ticket-start.ts +132 -0
  74. package/board/server/reduce-board-update.ts +117 -0
  75. package/board/server/reduce-board-usage.ts +247 -0
  76. package/board/server/reduce-board.ts +100 -1917
  77. package/board/server/reply-post.ts +407 -0
  78. package/board/server/run-registry.ts +8 -4
  79. package/board/server/ticket-stages-panel-helpers.ts +296 -0
  80. package/board/shared/board-rows.ts +9 -0
  81. package/board/shared/board-rpc.ts +42 -0
  82. package/board/shared/board-state-counts.ts +77 -0
  83. package/board/shared/board-state-live.ts +99 -0
  84. package/board/shared/board-state-review.ts +59 -0
  85. package/board/shared/board-state-run.ts +236 -0
  86. package/board/shared/board-state-ticket.ts +257 -0
  87. package/board/shared/board-state-usage.ts +107 -0
  88. package/board/shared/board-state.ts +97 -567
  89. package/board/shared/reply-actions.ts +207 -0
  90. package/engine/agents/agent-launcher.ts +27 -4
  91. package/engine/agents/claude-launcher-helpers.ts +233 -0
  92. package/engine/agents/claude-launcher.ts +28 -669
  93. package/engine/agents/claude-messages.ts +212 -0
  94. package/engine/agents/claude-options.ts +43 -8
  95. package/engine/agents/common-instructions.ts +138 -0
  96. package/engine/agents/input-channel.ts +36 -0
  97. package/engine/agents/launch-paths.ts +29 -0
  98. package/engine/agents/launch-session.ts +227 -0
  99. package/engine/agents/learner-instructions.ts +31 -0
  100. package/engine/agents/open-session.ts +210 -0
  101. package/engine/agents/prompt-sections.ts +95 -0
  102. package/engine/agents/rejoin-prompts.ts +135 -0
  103. package/engine/agents/reviewer-instructions.ts +99 -0
  104. package/engine/agents/role-instructions.ts +31 -244
  105. package/engine/agents/role-prompts.ts +39 -109
  106. package/engine/agents/role-results.ts +106 -7
  107. package/engine/agents/scripted-launcher.ts +21 -6
  108. package/engine/agents/session-pool.ts +124 -0
  109. package/engine/agents/turn-progress.ts +283 -0
  110. package/engine/agents/writer-instructions.ts +151 -0
  111. package/engine/cli/computer-adapters-real.ts +15 -3
  112. package/engine/cli/computer-adapters.ts +2 -0
  113. package/engine/cli/computer-checks.ts +87 -4
  114. package/engine/cli/config-reload-text.ts +39 -0
  115. package/engine/cli/decision-model-setup.ts +70 -0
  116. package/engine/cli/doctor-command.ts +1 -0
  117. package/engine/cli/doctor.ts +21 -3
  118. package/engine/cli/going-runs.ts +192 -36
  119. package/engine/cli/init-command.ts +1 -0
  120. package/engine/cli/init.ts +23 -1
  121. package/engine/cli/live-runs.ts +73 -0
  122. package/engine/cli/luca-run.ts +42 -7
  123. package/engine/cli/luca-skills.ts +183 -0
  124. package/engine/cli/luca.ts +8 -1
  125. package/engine/cli/models-command.ts +119 -0
  126. package/engine/cli/read-run.ts +81 -0
  127. package/engine/cli/run-args.ts +33 -6
  128. package/engine/cli/run-demo.ts +143 -0
  129. package/engine/cli/run-end.ts +184 -0
  130. package/engine/cli/run-modes-helpers.ts +81 -0
  131. package/engine/cli/run-modes.ts +62 -439
  132. package/engine/cli/setup.ts +5 -48
  133. package/engine/cli/unfinished-runs.ts +122 -0
  134. package/engine/cli/upgrade-command.ts +212 -30
  135. package/engine/cli/upgrade-finish.ts +149 -0
  136. package/engine/cli/upgrade.ts +112 -71
  137. package/engine/config/config-fields.ts +127 -0
  138. package/engine/config/config-reload.ts +250 -0
  139. package/engine/config/engine-config-schema.ts +235 -0
  140. package/engine/config/engine-config.ts +72 -142
  141. package/engine/config/test-commands.ts +102 -0
  142. package/engine/core/agent-guards-helpers.ts +84 -0
  143. package/engine/core/agent-turn.ts +395 -0
  144. package/engine/core/already-done.ts +44 -1
  145. package/engine/core/build-action.ts +214 -0
  146. package/engine/core/build-context.ts +135 -0
  147. package/engine/core/build-launch.ts +259 -0
  148. package/engine/core/commit-in.ts +282 -0
  149. package/engine/core/decide-build-early.ts +108 -0
  150. package/engine/core/decide-build-ending.ts +145 -0
  151. package/engine/core/decide-build-helpers.ts +87 -0
  152. package/engine/core/decide-build-tickets.ts +207 -0
  153. package/engine/core/decide-build-view.ts +103 -0
  154. package/engine/core/decide-build.ts +101 -1368
  155. package/engine/core/decide-final-fix.ts +203 -0
  156. package/engine/core/decide-final-review.ts +55 -310
  157. package/engine/core/decide-red-green.ts +398 -0
  158. package/engine/core/decide-rejoin.ts +259 -0
  159. package/engine/core/decide-repo-wait.ts +129 -0
  160. package/engine/core/decide-run-budget.ts +86 -12
  161. package/engine/core/decide-stuck-helpers.ts +127 -0
  162. package/engine/core/decide-stuck.ts +60 -8
  163. package/engine/core/decide-ticket-review.ts +95 -0
  164. package/engine/core/decide-ticket.ts +267 -0
  165. package/engine/core/decide-waits.ts +47 -0
  166. package/engine/core/decide.ts +74 -23
  167. package/engine/core/engine-chores.ts +163 -0
  168. package/engine/core/environment-rerun.ts +83 -0
  169. package/engine/core/evidence-text.ts +84 -0
  170. package/engine/core/execute-action.ts +303 -0
  171. package/engine/core/execute-already-done-check.ts +133 -0
  172. package/engine/core/execute-build.ts +68 -944
  173. package/engine/core/execute-changeset.ts +5 -7
  174. package/engine/core/execute-final-review.ts +125 -13
  175. package/engine/core/execute-gates.ts +182 -0
  176. package/engine/core/execute-intake.ts +130 -0
  177. package/engine/core/execute-join.ts +276 -0
  178. package/engine/core/execute-memory.ts +12 -0
  179. package/engine/core/execute-pull-request.ts +84 -0
  180. package/engine/core/execute-red-check.ts +219 -0
  181. package/engine/core/execute-repo-wait.ts +129 -0
  182. package/engine/core/execute-stuck.ts +25 -10
  183. package/engine/core/execute-waits.ts +158 -0
  184. package/engine/core/execute-with-jev.ts +118 -0
  185. package/engine/core/execute.ts +124 -831
  186. package/engine/core/final-failure-cap.ts +38 -0
  187. package/engine/core/final-review-action.ts +125 -0
  188. package/engine/core/final-review-text.ts +63 -17
  189. package/engine/core/final-stuck-text.ts +86 -0
  190. package/engine/core/fix-loop-text.ts +49 -2
  191. package/engine/core/left-out.ts +120 -0
  192. package/engine/core/live-file.ts +372 -0
  193. package/engine/core/loop-caps.ts +25 -2
  194. package/engine/core/not-in-run.ts +7 -3
  195. package/engine/core/pull-request-text.ts +255 -6
  196. package/engine/core/repo-wait-text.ts +81 -0
  197. package/engine/core/review-text.ts +55 -1
  198. package/engine/core/run-crash-recovery-helpers.ts +16 -0
  199. package/engine/core/run-session-close-helpers.ts +96 -0
  200. package/engine/core/run-start.ts +148 -0
  201. package/engine/core/run-stuck-text.ts +86 -0
  202. package/engine/core/schedule-rules.ts +193 -0
  203. package/engine/core/stuck-detail-text.ts +89 -0
  204. package/engine/core/stuck-format.ts +22 -0
  205. package/engine/core/stuck-text.ts +29 -332
  206. package/engine/core/ticket-stuck-text.ts +192 -0
  207. package/engine/core/worktree-changes.ts +106 -0
  208. package/engine/gates/already-done-check.ts +120 -0
  209. package/engine/gates/feature-map.ts +96 -0
  210. package/engine/gates/gate-runner.ts +108 -108
  211. package/engine/gates/gate-schemas.ts +61 -2
  212. package/engine/gates/leftover-scan.ts +154 -31
  213. package/engine/gates/new-tests.ts +45 -0
  214. package/engine/gates/own-files-check.ts +98 -0
  215. package/engine/gates/prepare-check.ts +60 -0
  216. package/engine/gates/prepare-slots.ts +99 -0
  217. package/engine/gates/red-check.ts +184 -16
  218. package/engine/gates/shell-check.ts +64 -0
  219. package/engine/gates/slot-waits.ts +55 -0
  220. package/engine/gates/slow-test-runner.ts +59 -0
  221. package/engine/gates/test-checks.ts +161 -0
  222. package/engine/gates/test-runner.ts +164 -5
  223. package/engine/gates/test-slots.ts +48 -0
  224. package/engine/git/git-adapter.ts +55 -396
  225. package/engine/git/git-commits.ts +132 -0
  226. package/engine/git/git-join.ts +139 -0
  227. package/engine/git/git-read.ts +123 -0
  228. package/engine/git/git-run.ts +32 -0
  229. package/engine/git/git-worktrees.ts +143 -0
  230. package/engine/git/outside-links.ts +55 -0
  231. package/engine/guards/after-turn-check.ts +31 -5
  232. package/engine/guards/guard-hook.ts +60 -12
  233. package/engine/guards/guard-roles.ts +68 -0
  234. package/engine/guards/helper-rules.ts +92 -0
  235. package/engine/guards/permission-rules.ts +161 -0
  236. package/engine/guards/role-rules-helpers.ts +48 -0
  237. package/engine/guards/role-rules.ts +34 -606
  238. package/engine/guards/shell-rules.ts +344 -0
  239. package/engine/guards/worktree-git.ts +208 -0
  240. package/engine/guards/worktree-snapshot.ts +412 -0
  241. package/engine/guards/worktree-state.ts +28 -825
  242. package/engine/guards/worktree-undo.ts +260 -0
  243. package/engine/guards/write-rules.ts +149 -0
  244. package/engine/index.ts +30 -9
  245. package/engine/intake/criteria-checks.ts +114 -0
  246. package/engine/intake/intake-checks.ts +164 -30
  247. package/engine/intake/intake-schemas.ts +37 -2
  248. package/engine/jev/clef-client.ts +259 -0
  249. package/engine/jev/decision-model-credentials.ts +212 -0
  250. package/engine/jev/jev-jobs.ts +144 -60
  251. package/engine/jev/jev-schemas.ts +86 -5
  252. package/engine/jev/jev-shadow-helpers.ts +218 -0
  253. package/engine/jev/jev-shadow.ts +109 -64
  254. package/engine/jev/model-pick.ts +275 -0
  255. package/engine/journal/agent-entries.ts +167 -0
  256. package/engine/journal/agent-message-entries.ts +72 -0
  257. package/engine/journal/agent-turn-replay.ts +203 -0
  258. package/engine/journal/already-done-entries.ts +55 -0
  259. package/engine/journal/commit-entries.ts +56 -0
  260. package/engine/journal/cross-ticket-replay.ts +222 -0
  261. package/engine/journal/decision-model-entries.ts +86 -0
  262. package/engine/journal/entry-fields.ts +10 -0
  263. package/engine/journal/final-review-entries.ts +128 -0
  264. package/engine/journal/final-review-replay.ts +324 -0
  265. package/engine/journal/final-review-round.ts +320 -0
  266. package/engine/journal/final-review-state.ts +180 -0
  267. package/engine/journal/gate-entries.ts +81 -0
  268. package/engine/journal/intake-entries.ts +87 -0
  269. package/engine/journal/join-entries.ts +126 -0
  270. package/engine/journal/journal-entry-schema.ts +218 -0
  271. package/engine/journal/journal-kinds.ts +97 -0
  272. package/engine/journal/journal-record-schema.ts +218 -0
  273. package/engine/journal/journal-record.ts +43 -1400
  274. package/engine/journal/journal.ts +6 -1
  275. package/engine/journal/limit-entries.ts +90 -0
  276. package/engine/journal/memory-entries.ts +124 -0
  277. package/engine/journal/memory-replay.ts +157 -0
  278. package/engine/journal/plan-replay.ts +139 -0
  279. package/engine/journal/pull-request-entries.ts +41 -0
  280. package/engine/journal/replay.ts +157 -2144
  281. package/engine/journal/reply-replay.ts +144 -0
  282. package/engine/journal/repo-wait-entries.ts +53 -0
  283. package/engine/journal/run-entries.ts +172 -0
  284. package/engine/journal/run-state.ts +264 -0
  285. package/engine/journal/shared-failure-replay.ts +133 -0
  286. package/engine/journal/stuck-entries.ts +193 -0
  287. package/engine/journal/ticket-progress.ts +392 -0
  288. package/engine/journal/ticket-replay.ts +411 -0
  289. package/engine/journal/ticket-result-replay.ts +364 -0
  290. package/engine/journal/ticket-retry-replay.ts +142 -0
  291. package/engine/journal/worktree-entries.ts +122 -0
  292. package/engine/models/model-score.ts +512 -0
  293. package/engine/shell/run-command.ts +187 -18
  294. package/engine/testing/agent-turn-fixtures.ts +287 -0
  295. package/engine/testing/already-done-fixtures.ts +97 -0
  296. package/engine/testing/build-fixtures.ts +68 -973
  297. package/engine/testing/checkouts-fixtures.ts +48 -0
  298. package/engine/testing/final-review-fixtures.ts +62 -1
  299. package/engine/testing/final-review-steps.ts +143 -0
  300. package/engine/testing/limit-fixtures.ts +85 -0
  301. package/engine/testing/live-file-fixtures.ts +57 -0
  302. package/engine/testing/practice-repo.ts +10 -4
  303. package/engine/testing/practice-run.ts +1 -1
  304. package/engine/testing/reply-fixtures.ts +88 -0
  305. package/engine/testing/run-budget-fixtures.ts +165 -0
  306. package/engine/testing/run-fixtures.ts +219 -0
  307. package/engine/testing/sdk-play.ts +177 -0
  308. package/engine/testing/setup-repo.ts +194 -0
  309. package/engine/testing/step-record-fixtures.ts +55 -0
  310. package/engine/testing/ticket-step-fixtures.ts +272 -0
  311. package/engine/testing/wait-scenarios.ts +186 -0
  312. package/engine/tracker/gh-retry.ts +217 -0
  313. package/engine/tracker/github-tracker.ts +310 -90
  314. package/engine/tracker/in-memory-tracker.ts +8 -4
  315. package/engine/tracker/tracker.ts +131 -6
  316. package/package.json +2 -1
  317. package/skills/luca-retro/SKILL.md +74 -0
  318. package/skills/luca-retro/scripts/retro-summary.ts +1356 -0
  319. package/skills/luca-unstick/SKILL.md +153 -0
  320. package/skills/luca-unstick/scripts/stuck-summary.ts +1063 -0
  321. package/engine/jev/jev-client.ts +0 -173
@@ -49,7 +49,12 @@ const parseLine = ({
49
49
  return parsed.data
50
50
  }
51
51
 
52
- const readRecords = ({ file }: { file: string }): JournalRecord[] => {
52
+ /**
53
+ * Reads and checks every record of the journal at `file`, oldest first,
54
+ * without opening it for appends: none when it has no file. Throws on a
55
+ * line that isn't a record.
56
+ */
57
+ export const readRecords = ({ file }: { file: string }): JournalRecord[] => {
53
58
  if (!existsSync(file)) return []
54
59
  return readFileSync(file, 'utf8')
55
60
  .split('\n')
@@ -0,0 +1,90 @@
1
+ import { z } from 'zod'
2
+
3
+ import { ENTRY_FIELDS } from './entry-fields'
4
+
5
+ import { AgentRoleSchema } from '../agents/role-results'
6
+ import { UsageRecordSchema } from '../limits/plan-usage'
7
+
8
+ /**
9
+ * The journal entries of plan limits: limit waits, usage-line waits, and
10
+ * recorded plan usage.
11
+ */
12
+
13
+ /**
14
+ * A plan window was used up (a rejected rate limit), so the whole run waits
15
+ * until `until`: the window's reset plus a margin, or a default wait when the
16
+ * reading named no reset. Written with `ticket: null`; the agent whose turn
17
+ * hit the limit is `hit_ticket` and `hit_role`.
18
+ */
19
+ export const LimitWaitStartedEntrySchema = z.object({
20
+ ...ENTRY_FIELDS,
21
+ kind: z.literal('limit_wait_started'),
22
+ content: z.object({
23
+ /** When the window resets, if the reading said. */
24
+ resets_at: z.iso.datetime().nullable(),
25
+ /** When the engine wakes and carries on. */
26
+ until: z.iso.datetime(),
27
+ /** The window, such as `five_hour`, `seven_day`, or `seven_day_opus`. */
28
+ rate_limit_type: z.string().nullable(),
29
+ hit_ticket: z.number().int().positive().nullable(),
30
+ hit_role: AgentRoleSchema.nullable(),
31
+ }),
32
+ })
33
+
34
+ /** The limit wait is over; the run carries on where it was cut off. */
35
+ export const LimitWaitEndedEntrySchema = z.object({
36
+ ...ENTRY_FIELDS,
37
+ kind: z.literal('limit_wait_ended'),
38
+ content: z.object({ until: z.iso.datetime() }),
39
+ })
40
+
41
+ /** The plan windows a usage line guards: all-models weekly, and 5-hour. */
42
+ export const UsageLineWindowSchema = z.enum(['seven_day', 'five_hour'])
43
+
44
+ export type UsageLineWindow = z.infer<typeof UsageLineWindowSchema>
45
+
46
+ /**
47
+ * The newest plan-window reading was at or over its **usage line**, so the
48
+ * whole run pauses until `until`: the window's reset plus a margin. The wait
49
+ * ends sooner once the line is raised above `percent`.
50
+ */
51
+ export const UsageLineWaitStartedEntrySchema = z.object({
52
+ ...ENTRY_FIELDS,
53
+ kind: z.literal('usage_line_wait_started'),
54
+ content: z.object({
55
+ window: UsageLineWindowSchema,
56
+ /** The line, in percent of the window. */
57
+ line: z.number(),
58
+ /** The reading's fill level, in percent. */
59
+ percent: z.number(),
60
+ /** When the window resets. */
61
+ resets_at: z.iso.datetime(),
62
+ /** When the engine wakes and carries on, at the latest. */
63
+ until: z.iso.datetime(),
64
+ }),
65
+ })
66
+
67
+ /**
68
+ * The usage-line wait is over: the window reset (`reset`), or the line was
69
+ * raised above the reading (`line_raised`).
70
+ */
71
+ export const UsageLineWaitEndedEntrySchema = z.object({
72
+ ...ENTRY_FIELDS,
73
+ kind: z.literal('usage_line_wait_ended'),
74
+ content: z.object({
75
+ until: z.iso.datetime(),
76
+ reason: z.enum(['reset', 'line_raised']),
77
+ }),
78
+ })
79
+
80
+ /**
81
+ * The plan usage of one ticket (when it was pushed, or got stuck) or of the
82
+ * whole run (when it ended): tokens from its agent sessions, and how far
83
+ * each plan window moved. A retried ticket that finishes again gets another,
84
+ * over all of its sessions: the latest is its whole usage.
85
+ */
86
+ export const UsageRecordedEntrySchema = z.object({
87
+ ...ENTRY_FIELDS,
88
+ kind: z.literal('usage_recorded'),
89
+ content: UsageRecordSchema,
90
+ })
@@ -0,0 +1,124 @@
1
+ import { z } from 'zod'
2
+
3
+ import { ENTRY_FIELDS } from './entry-fields'
4
+
5
+ import {
6
+ MemoryFeedbackSchema,
7
+ MemorySaveSchema,
8
+ RecalledMemorySchema,
9
+ RecallPointSchema,
10
+ VaultSearchSchema,
11
+ } from '../memory/memory-schemas'
12
+
13
+ /**
14
+ * The journal entries of memory (#370): recalls, the learner's saves and
15
+ * feedback, each MuninnDB write, and a skipped or reported learning.
16
+ */
17
+
18
+ /**
19
+ * The engine searched memory at a **recall point**: the vaults it searched
20
+ * (each with how it went and how many it found), and the memories it will
21
+ * show, merged by score, at most `MAX_MEMORIES_PER_RECALL`, each with its
22
+ * vault and score. `key` names the moment (such as `ticket:11`), so each is
23
+ * searched once. `ticket` is the ticket's, or `null` for the run's start
24
+ * and the final review.
25
+ */
26
+ export const MemoryRecalledEntrySchema = z.object({
27
+ ...ENTRY_FIELDS,
28
+ kind: z.literal('memory_recalled'),
29
+ content: z.object({
30
+ point: RecallPointSchema,
31
+ key: z.string().min(1),
32
+ query: z.string(),
33
+ vaults: z.array(VaultSearchSchema),
34
+ memories: z.array(RecalledMemorySchema),
35
+ }),
36
+ })
37
+
38
+ /**
39
+ * The learner's proposed memories were saved (or refused, or failed), each
40
+ * with its vault, what became of it, and the similar memory the engine
41
+ * found first; then the helped / didn't-help feedback on each memory shown
42
+ * in the run. Written once per run, with `ticket: null`.
43
+ */
44
+ export const MemoriesSavedEntrySchema = z.object({
45
+ ...ENTRY_FIELDS,
46
+ kind: z.literal('memories_saved'),
47
+ content: z.object({
48
+ saves: z.array(MemorySaveSchema),
49
+ feedback: z.array(MemoryFeedbackSchema),
50
+ }),
51
+ })
52
+
53
+ /**
54
+ * The engine is about to make one MuninnDB write of `save_memories` (#369):
55
+ * a save (`update_id` names the similar memory it updates, `muninn_evolve`;
56
+ * `null` adds a new one, `muninn_remember` with `op_id`) or a feedback on a
57
+ * shown memory. `write_key` names it within its step: `save:<op_id>` or
58
+ * `feedback:<vault>:<id>`. A redo of the step repeats a save started but
59
+ * not done the same way, and never sends such a feedback again.
60
+ */
61
+ export const MemoryWriteStartedEntrySchema = z.object({
62
+ ...ENTRY_FIELDS,
63
+ kind: z.literal('memory_write_started'),
64
+ content: z.discriminatedUnion('what', [
65
+ z.object({
66
+ write_key: z.string().min(1),
67
+ what: z.literal('save'),
68
+ vault: z.string().min(1),
69
+ concept: z.string(),
70
+ op_id: z.string().min(1),
71
+ update_id: z.string().nullable(),
72
+ similar: MemorySaveSchema.shape.similar,
73
+ }),
74
+ z.object({
75
+ write_key: z.string().min(1),
76
+ what: z.literal('feedback'),
77
+ vault: z.string().min(1),
78
+ id: z.string().min(1),
79
+ useful: z.boolean(),
80
+ }),
81
+ ]),
82
+ })
83
+
84
+ /**
85
+ * One MuninnDB write of `save_memories` settled (or a save failed before
86
+ * its write): its outcome, which a redo of the step reuses as it is. Its
87
+ * step's `memories_saved` lists them all.
88
+ */
89
+ export const MemoryWriteDoneEntrySchema = z.object({
90
+ ...ENTRY_FIELDS,
91
+ kind: z.literal('memory_write_done'),
92
+ content: z.discriminatedUnion('what', [
93
+ z.object({
94
+ write_key: z.string().min(1),
95
+ what: z.literal('save'),
96
+ save: MemorySaveSchema,
97
+ }),
98
+ z.object({
99
+ write_key: z.string().min(1),
100
+ what: z.literal('feedback'),
101
+ feedback: MemoryFeedbackSchema,
102
+ }),
103
+ ]),
104
+ })
105
+
106
+ /** The learner never gave a usable answer; the run ends without it. */
107
+ export const LearningSkippedEntrySchema = z.object({
108
+ ...ENTRY_FIELDS,
109
+ kind: z.literal('learning_skipped'),
110
+ content: z.object({ reason: z.string() }),
111
+ })
112
+
113
+ /**
114
+ * With no PR to list them in, the new memories went on the spec issue in
115
+ * the engine's comment `comment_id`.
116
+ */
117
+ export const MemoriesReportedEntrySchema = z.object({
118
+ ...ENTRY_FIELDS,
119
+ kind: z.literal('memories_reported'),
120
+ content: z.object({
121
+ comment_id: z.number().int(),
122
+ count: z.number().int().min(0),
123
+ }),
124
+ })
@@ -0,0 +1,157 @@
1
+ /**
2
+ * Memory as replay rebuilds it (#370): its state shape, a run with memory
3
+ * off, and the learner's own agent records.
4
+ */
5
+ import { ranCheaper } from './agent-turn-replay'
6
+ import type { ReplayedAgentFailure } from './final-review-state'
7
+ import type { JournalRecord } from './journal-record'
8
+
9
+ import type { LearnerResult } from '../agents/role-results'
10
+ import type {
11
+ MemoryFeedback,
12
+ MemorySave,
13
+ RecallPoint,
14
+ RecalledMemory,
15
+ } from '../memory/memory-schemas'
16
+
17
+ /**
18
+ * The learner at the end of a run (#370): its answer, or its failed tries,
19
+ * or that the engine gave up on it. Learner records have `ticket: null` and
20
+ * role `learner`; they never count as the final review's.
21
+ */
22
+ export type LearnerState = {
23
+ /** Its result, once it finished. */
24
+ result: LearnerResult | null
25
+ /** The seq of its `agent_finished`, for the saves' op ids. */
26
+ result_seq: number | null
27
+ /** Its latest failed turn, if none finished after it. */
28
+ agent_failure: ReplayedAgentFailure | null
29
+ /** Failed tries (agent, result, guard), in all. */
30
+ failed_tries: number
31
+ /** The model its latest agent launched on (#604); `null` in older journals. */
32
+ launched_on: string | null
33
+ /**
34
+ * It used up a try on a model cheaper than Opus (#604), so its later
35
+ * agents run Opus.
36
+ */
37
+ failed_cheaper: boolean
38
+ /** Engine failures in a row. */
39
+ engine_failures: number
40
+ /** Why the engine gave up on it (`learning_skipped`), if it did. */
41
+ skipped: string | null
42
+ }
43
+
44
+ /** Where memory stands in a run (#370), from its records. */
45
+ export type MemoryState = {
46
+ /** Memory is on for this run (`run_started.memory`). */
47
+ on: boolean
48
+ /** The project's vault; `null` searches only `default`. */
49
+ project_vault: string | null
50
+ /** Each recall point's memories, by its key, once searched. */
51
+ recalls: Record<string, { point: RecallPoint; memories: RecalledMemory[] }>
52
+ /** Every memory shown in the run, oldest first; may repeat. */
53
+ shown: RecalledMemory[]
54
+ learner: LearnerState
55
+ /** The learner's memories as saved, and the feedback sent. */
56
+ saved: { saves: MemorySave[]; feedback: MemoryFeedback[] } | null
57
+ /** The new memories went on the spec issue (a run with no PR). */
58
+ reported: boolean
59
+ }
60
+
61
+ /** A run with memory off, before any memory record. */
62
+ export const EMPTY_MEMORY: MemoryState = {
63
+ on: false,
64
+ project_vault: null,
65
+ recalls: {},
66
+ shown: [],
67
+ learner: {
68
+ result: null,
69
+ result_seq: null,
70
+ agent_failure: null,
71
+ failed_tries: 0,
72
+ launched_on: null,
73
+ failed_cheaper: false,
74
+ engine_failures: 0,
75
+ skipped: null,
76
+ },
77
+ saved: null,
78
+ reported: false,
79
+ }
80
+
81
+ /** The agent kinds a learner's turn journals. */
82
+ type LearnerRecord = Extract<
83
+ JournalRecord,
84
+ {
85
+ kind:
86
+ | 'agent_started'
87
+ | 'agent_finished'
88
+ | 'agent_failed'
89
+ | 'agent_session'
90
+ }
91
+ >
92
+
93
+ /** The record if it is one of the learner's agent records, else `null`. */
94
+ export const learnerRecordOf = ({
95
+ record,
96
+ }: {
97
+ record: JournalRecord
98
+ }): LearnerRecord | null => {
99
+ switch (record.kind) {
100
+ case 'agent_started':
101
+ case 'agent_finished':
102
+ case 'agent_failed':
103
+ case 'agent_session':
104
+ return record.content.role === 'learner' ? record : null
105
+ default:
106
+ return null
107
+ }
108
+ }
109
+
110
+ /**
111
+ * The learner after one of its records: its answer ends any failure; a
112
+ * failed turn counts a try (or an engine failure in a row), like any
113
+ * agent's.
114
+ */
115
+ export const learnerAfter = ({
116
+ learner,
117
+ record,
118
+ }: {
119
+ learner: LearnerState
120
+ record: LearnerRecord
121
+ }): LearnerState => {
122
+ switch (record.kind) {
123
+ case 'agent_started':
124
+ return { ...learner, launched_on: record.content.model }
125
+ case 'agent_session':
126
+ return learner
127
+ case 'agent_finished':
128
+ return record.content.role === 'learner'
129
+ ? {
130
+ ...learner,
131
+ result: record.content.result,
132
+ result_seq: record.seq,
133
+ agent_failure: null,
134
+ engine_failures: 0,
135
+ }
136
+ : learner
137
+ case 'agent_failed': {
138
+ const { role, error, failure, session_id } = record.content
139
+ const agent_failure = { role, error, failure, session_id }
140
+ return failure === 'engine'
141
+ ? {
142
+ ...learner,
143
+ agent_failure,
144
+ engine_failures: learner.engine_failures + 1,
145
+ }
146
+ : {
147
+ ...learner,
148
+ agent_failure,
149
+ engine_failures: 0,
150
+ failed_tries: learner.failed_tries + 1,
151
+ failed_cheaper:
152
+ learner.failed_cheaper ||
153
+ ranCheaper(learner.launched_on),
154
+ }
155
+ }
156
+ }
157
+ }
@@ -0,0 +1,139 @@
1
+ /**
2
+ * The plan as replay rebuilds it: rate limits hit, limit and usage-line
3
+ * waits, and billing stops, from agents' sessions and the wait records.
4
+ */
5
+ import type { JournalRecord, UsageLineWindow } from './journal-record'
6
+
7
+ import type { AgentRole } from '../agents/role-results'
8
+ import { sessionSignal } from '../limits/plan-signals'
9
+
10
+ /**
11
+ * Where the run stands with the plan, from agents' rate-limit readings and
12
+ * the limit-wait and stop records.
13
+ */
14
+ export type PlanState = {
15
+ /**
16
+ * The latest rejected rate limit no limit wait has started for yet: the
17
+ * window, its reset (seconds since the epoch), the agent that hit it, and
18
+ * when the session was journaled.
19
+ */
20
+ hit: {
21
+ rate_limit_type: string | null
22
+ resets_at: number | null
23
+ ticket: number | null
24
+ role: AgentRole | null
25
+ time: string
26
+ } | null
27
+ /** The limit wait under way: when it ends, and what it is for. */
28
+ wait: {
29
+ until: string
30
+ resets_at: string | null
31
+ rate_limit_type: string | null
32
+ } | null
33
+ /** Every limit wait's reset so far, oldest first; the spec hears of each new one once. */
34
+ resets_announced: (string | null)[]
35
+ /** The first sign of per-token billing in any session, if any. */
36
+ billing: { reason: string } | null
37
+ /** Set once a billing stop is journaled. It sticks. */
38
+ billing_stopped: { reason: string } | null
39
+ /** The usage-line wait under way: its window, line, reading, and end. */
40
+ usage_wait: {
41
+ window: UsageLineWindow
42
+ line: number
43
+ percent: number
44
+ until: string
45
+ } | null
46
+ /**
47
+ * The latest time the run is known to have waited until: the `until` of
48
+ * a limit wait that ended, or of a usage-line wait that ended at its
49
+ * reset. A reading whose window resets by then is out of date.
50
+ */
51
+ waited_until: string | null
52
+ }
53
+
54
+ type PlanRecord = Extract<
55
+ JournalRecord,
56
+ {
57
+ kind:
58
+ | 'agent_session'
59
+ | 'run_stopped'
60
+ | 'limit_wait_started'
61
+ | 'limit_wait_ended'
62
+ | 'usage_line_wait_started'
63
+ | 'usage_line_wait_ended'
64
+ }
65
+ >
66
+
67
+ /** The later of two ISO times; the first may be missing. */
68
+ const laterOf = (a: string | null, b: string): string =>
69
+ a !== null && Date.parse(a) >= Date.parse(b) ? a : b
70
+
71
+ /** The plan state after one record. */
72
+ export const planAfter = ({
73
+ plan,
74
+ record,
75
+ }: {
76
+ plan: PlanState
77
+ record: PlanRecord
78
+ }): PlanState => {
79
+ switch (record.kind) {
80
+ case 'agent_session': {
81
+ const signal = sessionSignal({ session: record.content.session })
82
+ if (signal.kind === 'billing') {
83
+ return {
84
+ ...plan,
85
+ billing: plan.billing ?? { reason: signal.reason },
86
+ }
87
+ }
88
+ if (signal.kind === 'ok') return plan
89
+ return {
90
+ ...plan,
91
+ hit: {
92
+ rate_limit_type: signal.rate_limit_type,
93
+ resets_at: signal.resets_at,
94
+ ticket: record.ticket,
95
+ role: record.content.role,
96
+ time: record.time,
97
+ },
98
+ }
99
+ }
100
+ case 'run_stopped':
101
+ return record.content.billing
102
+ ? {
103
+ ...plan,
104
+ billing: plan.billing ?? {
105
+ reason: record.content.reason,
106
+ },
107
+ billing_stopped: { reason: record.content.reason },
108
+ }
109
+ : plan
110
+ case 'limit_wait_started': {
111
+ const { until, resets_at, rate_limit_type } = record.content
112
+ return {
113
+ ...plan,
114
+ hit: null,
115
+ wait: { until, resets_at, rate_limit_type },
116
+ resets_announced: [...plan.resets_announced, resets_at],
117
+ }
118
+ }
119
+ case 'limit_wait_ended':
120
+ return {
121
+ ...plan,
122
+ wait: null,
123
+ waited_until: laterOf(plan.waited_until, record.content.until),
124
+ }
125
+ case 'usage_line_wait_started': {
126
+ const { window, line, percent, until } = record.content
127
+ return { ...plan, usage_wait: { window, line, percent, until } }
128
+ }
129
+ case 'usage_line_wait_ended':
130
+ return {
131
+ ...plan,
132
+ usage_wait: null,
133
+ waited_until:
134
+ record.content.reason === 'reset'
135
+ ? laterOf(plan.waited_until, record.content.until)
136
+ : plan.waited_until,
137
+ }
138
+ }
139
+ }
@@ -0,0 +1,41 @@
1
+ import { z } from 'zod'
2
+
3
+ import { ENTRY_FIELDS } from './entry-fields'
4
+
5
+ /** The journal entries of the run's pull request: its changeset, and the PR. */
6
+
7
+ /** A changeset's bump: from the spec's `release:*` label, patch with none. */
8
+ export const ChangesetBumpSchema = z.enum(['patch', 'minor', 'major', 'none'])
9
+
10
+ export type ChangesetBump = z.infer<typeof ChangesetBumpSchema>
11
+
12
+ /**
13
+ * The engine committed the run's one changeset (#461) at `path` on the run
14
+ * branch and pushed it (`sha` is the run branch's HEAD after). `packages`
15
+ * are the ones it names. `path` is `null` when nothing was written: the
16
+ * spec is `release:none` (#476), or the repo no longer had a changesets
17
+ * config.
18
+ */
19
+ export const ChangesetWrittenEntrySchema = z.object({
20
+ ...ENTRY_FIELDS,
21
+ kind: z.literal('changeset_written'),
22
+ content: z.object({
23
+ path: z.string().nullable(),
24
+ bump: ChangesetBumpSchema,
25
+ packages: z.array(z.string()),
26
+ sha: z.string(),
27
+ }),
28
+ })
29
+
30
+ export const PullRequestOpenedEntrySchema = z.object({
31
+ ...ENTRY_FIELDS,
32
+ kind: z.literal('pull_request_opened'),
33
+ content: z.object({
34
+ number: z.number().int().positive(),
35
+ url: z.string(),
36
+ head: z.string(),
37
+ base: z.string(),
38
+ title: z.string(),
39
+ body: z.string(),
40
+ }),
41
+ })