@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.
- package/CHANGELOG.md +76 -0
- package/README.md +7 -2
- package/board/client/board-look.ts +31 -1
- package/board/client/board-panel-parts.tsx +150 -0
- package/board/client/board-panel-stages.ts +99 -0
- package/board/client/board-panel-styles.ts +223 -0
- package/board/client/board-panel.tsx +77 -1275
- package/board/client/engine-life.ts +48 -0
- package/board/client/final-review-stack.tsx +144 -0
- package/board/client/heartbeat.tsx +61 -0
- package/board/client/helper-lines.tsx +69 -0
- package/board/client/live-feed.tsx +86 -0
- package/board/client/live-line.ts +73 -0
- package/board/client/model-line.tsx +178 -0
- package/board/client/needs-you-section.tsx +133 -0
- package/board/client/one-line.tsx +193 -0
- package/board/client/repo-wait-banner.tsx +69 -0
- package/board/client/run-footer.tsx +68 -0
- package/board/client/run-header.tsx +189 -0
- package/board/client/run-picker.tsx +98 -0
- package/board/client/status-bar.tsx +131 -0
- package/board/client/step-dots.tsx +127 -0
- package/board/client/stuck-actions.tsx +269 -0
- package/board/client/ticket-card-view.tsx +238 -0
- package/board/client/ticket-detail.tsx +87 -0
- package/board/client/ticket-stack.tsx +119 -0
- package/board/client/ticket-wait.ts +188 -0
- package/board/client/timeline-rows.tsx +41 -14
- package/board/client/usage-line.tsx +51 -0
- package/board/client/wait-line.tsx +39 -0
- package/board/index.client.tsx +1 -1
- package/board/index.server.ts +7 -1
- package/board/package.json +1 -1
- package/board/server/board-panel-state-helpers.ts +67 -0
- package/board/server/board-server-check.ts +294 -0
- package/board/server/board-server-engine.ts +129 -0
- package/board/server/board-server-events.ts +134 -0
- package/board/server/board-server-read.ts +190 -0
- package/board/server/board-server-resume.ts +164 -0
- package/board/server/board-server-start.ts +174 -0
- package/board/server/board-server-store.ts +281 -0
- package/board/server/board-server-types.ts +114 -0
- package/board/server/board-server-util.ts +4 -0
- package/board/server/board-server.ts +52 -943
- package/board/server/board-vocabulary-engine.ts +144 -0
- package/board/server/board-vocabulary-review.ts +115 -0
- package/board/server/board-vocabulary-run.ts +145 -0
- package/board/server/board-vocabulary-shapes.ts +153 -0
- package/board/server/board-vocabulary.ts +20 -375
- package/board/server/current-step-panel-helpers.ts +108 -0
- package/board/server/describe-record.ts +403 -0
- package/board/server/engine-launch.ts +20 -3
- package/board/server/engine-restart-helpers.ts +105 -0
- package/board/server/engine-watch.ts +45 -5
- package/board/server/journal-rebuild-helpers.ts +169 -0
- package/board/server/live-file.ts +130 -0
- package/board/server/luca-version.ts +1 -1
- package/board/server/make-rows.ts +14 -629
- package/board/server/record-texts.ts +350 -0
- package/board/server/reduce-board-agent-start.ts +224 -0
- package/board/server/reduce-board-agents.ts +160 -0
- package/board/server/reduce-board-counters.ts +138 -0
- package/board/server/reduce-board-create.ts +148 -0
- package/board/server/reduce-board-final-review.ts +174 -0
- package/board/server/reduce-board-needs-you.ts +283 -0
- package/board/server/reduce-board-reasons.ts +59 -0
- package/board/server/reduce-board-run.ts +255 -0
- package/board/server/reduce-board-settle.ts +88 -0
- package/board/server/reduce-board-steps.ts +226 -0
- package/board/server/reduce-board-text.ts +139 -0
- package/board/server/reduce-board-ticket-checks.ts +168 -0
- package/board/server/reduce-board-ticket-join.ts +144 -0
- package/board/server/reduce-board-ticket-start.ts +132 -0
- package/board/server/reduce-board-update.ts +117 -0
- package/board/server/reduce-board-usage.ts +247 -0
- package/board/server/reduce-board.ts +100 -1917
- package/board/server/reply-post.ts +407 -0
- package/board/server/run-registry.ts +8 -4
- package/board/server/ticket-stages-panel-helpers.ts +296 -0
- package/board/shared/board-rows.ts +9 -0
- package/board/shared/board-rpc.ts +42 -0
- package/board/shared/board-state-counts.ts +77 -0
- package/board/shared/board-state-live.ts +99 -0
- package/board/shared/board-state-review.ts +59 -0
- package/board/shared/board-state-run.ts +236 -0
- package/board/shared/board-state-ticket.ts +257 -0
- package/board/shared/board-state-usage.ts +107 -0
- package/board/shared/board-state.ts +97 -567
- package/board/shared/reply-actions.ts +207 -0
- package/engine/agents/agent-launcher.ts +27 -4
- package/engine/agents/claude-launcher-helpers.ts +233 -0
- package/engine/agents/claude-launcher.ts +28 -669
- package/engine/agents/claude-messages.ts +212 -0
- package/engine/agents/claude-options.ts +43 -8
- package/engine/agents/common-instructions.ts +138 -0
- package/engine/agents/input-channel.ts +36 -0
- package/engine/agents/launch-paths.ts +29 -0
- package/engine/agents/launch-session.ts +227 -0
- package/engine/agents/learner-instructions.ts +31 -0
- package/engine/agents/open-session.ts +210 -0
- package/engine/agents/prompt-sections.ts +95 -0
- package/engine/agents/rejoin-prompts.ts +135 -0
- package/engine/agents/reviewer-instructions.ts +99 -0
- package/engine/agents/role-instructions.ts +31 -244
- package/engine/agents/role-prompts.ts +39 -109
- package/engine/agents/role-results.ts +106 -7
- package/engine/agents/scripted-launcher.ts +21 -6
- package/engine/agents/session-pool.ts +124 -0
- package/engine/agents/turn-progress.ts +283 -0
- package/engine/agents/writer-instructions.ts +151 -0
- package/engine/cli/computer-adapters-real.ts +15 -3
- package/engine/cli/computer-adapters.ts +2 -0
- package/engine/cli/computer-checks.ts +87 -4
- package/engine/cli/config-reload-text.ts +39 -0
- package/engine/cli/decision-model-setup.ts +70 -0
- package/engine/cli/doctor-command.ts +1 -0
- package/engine/cli/doctor.ts +21 -3
- package/engine/cli/going-runs.ts +192 -36
- package/engine/cli/init-command.ts +1 -0
- package/engine/cli/init.ts +23 -1
- package/engine/cli/live-runs.ts +73 -0
- package/engine/cli/luca-run.ts +42 -7
- package/engine/cli/luca-skills.ts +183 -0
- package/engine/cli/luca.ts +8 -1
- package/engine/cli/models-command.ts +119 -0
- package/engine/cli/read-run.ts +81 -0
- package/engine/cli/run-args.ts +33 -6
- package/engine/cli/run-demo.ts +143 -0
- package/engine/cli/run-end.ts +184 -0
- package/engine/cli/run-modes-helpers.ts +81 -0
- package/engine/cli/run-modes.ts +62 -439
- package/engine/cli/setup.ts +5 -48
- package/engine/cli/unfinished-runs.ts +122 -0
- package/engine/cli/upgrade-command.ts +212 -30
- package/engine/cli/upgrade-finish.ts +149 -0
- package/engine/cli/upgrade.ts +112 -71
- package/engine/config/config-fields.ts +127 -0
- package/engine/config/config-reload.ts +250 -0
- package/engine/config/engine-config-schema.ts +235 -0
- package/engine/config/engine-config.ts +72 -142
- package/engine/config/test-commands.ts +102 -0
- package/engine/core/agent-guards-helpers.ts +84 -0
- package/engine/core/agent-turn.ts +395 -0
- package/engine/core/already-done.ts +44 -1
- package/engine/core/build-action.ts +214 -0
- package/engine/core/build-context.ts +135 -0
- package/engine/core/build-launch.ts +259 -0
- package/engine/core/commit-in.ts +282 -0
- package/engine/core/decide-build-early.ts +108 -0
- package/engine/core/decide-build-ending.ts +145 -0
- package/engine/core/decide-build-helpers.ts +87 -0
- package/engine/core/decide-build-tickets.ts +207 -0
- package/engine/core/decide-build-view.ts +103 -0
- package/engine/core/decide-build.ts +101 -1368
- package/engine/core/decide-final-fix.ts +203 -0
- package/engine/core/decide-final-review.ts +55 -310
- package/engine/core/decide-red-green.ts +398 -0
- package/engine/core/decide-rejoin.ts +259 -0
- package/engine/core/decide-repo-wait.ts +129 -0
- package/engine/core/decide-run-budget.ts +86 -12
- package/engine/core/decide-stuck-helpers.ts +127 -0
- package/engine/core/decide-stuck.ts +60 -8
- package/engine/core/decide-ticket-review.ts +95 -0
- package/engine/core/decide-ticket.ts +267 -0
- package/engine/core/decide-waits.ts +47 -0
- package/engine/core/decide.ts +74 -23
- package/engine/core/engine-chores.ts +163 -0
- package/engine/core/environment-rerun.ts +83 -0
- package/engine/core/evidence-text.ts +84 -0
- package/engine/core/execute-action.ts +303 -0
- package/engine/core/execute-already-done-check.ts +133 -0
- package/engine/core/execute-build.ts +68 -944
- package/engine/core/execute-changeset.ts +5 -7
- package/engine/core/execute-final-review.ts +125 -13
- package/engine/core/execute-gates.ts +182 -0
- package/engine/core/execute-intake.ts +130 -0
- package/engine/core/execute-join.ts +276 -0
- package/engine/core/execute-memory.ts +12 -0
- package/engine/core/execute-pull-request.ts +84 -0
- package/engine/core/execute-red-check.ts +219 -0
- package/engine/core/execute-repo-wait.ts +129 -0
- package/engine/core/execute-stuck.ts +25 -10
- package/engine/core/execute-waits.ts +158 -0
- package/engine/core/execute-with-jev.ts +118 -0
- package/engine/core/execute.ts +124 -831
- package/engine/core/final-failure-cap.ts +38 -0
- package/engine/core/final-review-action.ts +125 -0
- package/engine/core/final-review-text.ts +63 -17
- package/engine/core/final-stuck-text.ts +86 -0
- package/engine/core/fix-loop-text.ts +49 -2
- package/engine/core/left-out.ts +120 -0
- package/engine/core/live-file.ts +372 -0
- package/engine/core/loop-caps.ts +25 -2
- package/engine/core/not-in-run.ts +7 -3
- package/engine/core/pull-request-text.ts +255 -6
- package/engine/core/repo-wait-text.ts +81 -0
- package/engine/core/review-text.ts +55 -1
- package/engine/core/run-crash-recovery-helpers.ts +16 -0
- package/engine/core/run-session-close-helpers.ts +96 -0
- package/engine/core/run-start.ts +148 -0
- package/engine/core/run-stuck-text.ts +86 -0
- package/engine/core/schedule-rules.ts +193 -0
- package/engine/core/stuck-detail-text.ts +89 -0
- package/engine/core/stuck-format.ts +22 -0
- package/engine/core/stuck-text.ts +29 -332
- package/engine/core/ticket-stuck-text.ts +192 -0
- package/engine/core/worktree-changes.ts +106 -0
- package/engine/gates/already-done-check.ts +120 -0
- package/engine/gates/feature-map.ts +96 -0
- package/engine/gates/gate-runner.ts +108 -108
- package/engine/gates/gate-schemas.ts +61 -2
- package/engine/gates/leftover-scan.ts +154 -31
- package/engine/gates/new-tests.ts +45 -0
- package/engine/gates/own-files-check.ts +98 -0
- package/engine/gates/prepare-check.ts +60 -0
- package/engine/gates/prepare-slots.ts +99 -0
- package/engine/gates/red-check.ts +184 -16
- package/engine/gates/shell-check.ts +64 -0
- package/engine/gates/slot-waits.ts +55 -0
- package/engine/gates/slow-test-runner.ts +59 -0
- package/engine/gates/test-checks.ts +161 -0
- package/engine/gates/test-runner.ts +164 -5
- package/engine/gates/test-slots.ts +48 -0
- package/engine/git/git-adapter.ts +55 -396
- package/engine/git/git-commits.ts +132 -0
- package/engine/git/git-join.ts +139 -0
- package/engine/git/git-read.ts +123 -0
- package/engine/git/git-run.ts +32 -0
- package/engine/git/git-worktrees.ts +143 -0
- package/engine/git/outside-links.ts +55 -0
- package/engine/guards/after-turn-check.ts +31 -5
- package/engine/guards/guard-hook.ts +60 -12
- package/engine/guards/guard-roles.ts +68 -0
- package/engine/guards/helper-rules.ts +92 -0
- package/engine/guards/permission-rules.ts +161 -0
- package/engine/guards/role-rules-helpers.ts +48 -0
- package/engine/guards/role-rules.ts +34 -606
- package/engine/guards/shell-rules.ts +344 -0
- package/engine/guards/worktree-git.ts +208 -0
- package/engine/guards/worktree-snapshot.ts +412 -0
- package/engine/guards/worktree-state.ts +28 -825
- package/engine/guards/worktree-undo.ts +260 -0
- package/engine/guards/write-rules.ts +149 -0
- package/engine/index.ts +30 -9
- package/engine/intake/criteria-checks.ts +114 -0
- package/engine/intake/intake-checks.ts +164 -30
- package/engine/intake/intake-schemas.ts +37 -2
- package/engine/jev/clef-client.ts +259 -0
- package/engine/jev/decision-model-credentials.ts +212 -0
- package/engine/jev/jev-jobs.ts +144 -60
- package/engine/jev/jev-schemas.ts +86 -5
- package/engine/jev/jev-shadow-helpers.ts +218 -0
- package/engine/jev/jev-shadow.ts +109 -64
- package/engine/jev/model-pick.ts +275 -0
- package/engine/journal/agent-entries.ts +167 -0
- package/engine/journal/agent-message-entries.ts +72 -0
- package/engine/journal/agent-turn-replay.ts +203 -0
- package/engine/journal/already-done-entries.ts +55 -0
- package/engine/journal/commit-entries.ts +56 -0
- package/engine/journal/cross-ticket-replay.ts +222 -0
- package/engine/journal/decision-model-entries.ts +86 -0
- package/engine/journal/entry-fields.ts +10 -0
- package/engine/journal/final-review-entries.ts +128 -0
- package/engine/journal/final-review-replay.ts +324 -0
- package/engine/journal/final-review-round.ts +320 -0
- package/engine/journal/final-review-state.ts +180 -0
- package/engine/journal/gate-entries.ts +81 -0
- package/engine/journal/intake-entries.ts +87 -0
- package/engine/journal/join-entries.ts +126 -0
- package/engine/journal/journal-entry-schema.ts +218 -0
- package/engine/journal/journal-kinds.ts +97 -0
- package/engine/journal/journal-record-schema.ts +218 -0
- package/engine/journal/journal-record.ts +43 -1400
- package/engine/journal/journal.ts +6 -1
- package/engine/journal/limit-entries.ts +90 -0
- package/engine/journal/memory-entries.ts +124 -0
- package/engine/journal/memory-replay.ts +157 -0
- package/engine/journal/plan-replay.ts +139 -0
- package/engine/journal/pull-request-entries.ts +41 -0
- package/engine/journal/replay.ts +157 -2144
- package/engine/journal/reply-replay.ts +144 -0
- package/engine/journal/repo-wait-entries.ts +53 -0
- package/engine/journal/run-entries.ts +172 -0
- package/engine/journal/run-state.ts +264 -0
- package/engine/journal/shared-failure-replay.ts +133 -0
- package/engine/journal/stuck-entries.ts +193 -0
- package/engine/journal/ticket-progress.ts +392 -0
- package/engine/journal/ticket-replay.ts +411 -0
- package/engine/journal/ticket-result-replay.ts +364 -0
- package/engine/journal/ticket-retry-replay.ts +142 -0
- package/engine/journal/worktree-entries.ts +122 -0
- package/engine/models/model-score.ts +512 -0
- package/engine/shell/run-command.ts +187 -18
- package/engine/testing/agent-turn-fixtures.ts +287 -0
- package/engine/testing/already-done-fixtures.ts +97 -0
- package/engine/testing/build-fixtures.ts +68 -973
- package/engine/testing/checkouts-fixtures.ts +48 -0
- package/engine/testing/final-review-fixtures.ts +62 -1
- package/engine/testing/final-review-steps.ts +143 -0
- package/engine/testing/limit-fixtures.ts +85 -0
- package/engine/testing/live-file-fixtures.ts +57 -0
- package/engine/testing/practice-repo.ts +10 -4
- package/engine/testing/practice-run.ts +1 -1
- package/engine/testing/reply-fixtures.ts +88 -0
- package/engine/testing/run-budget-fixtures.ts +165 -0
- package/engine/testing/run-fixtures.ts +219 -0
- package/engine/testing/sdk-play.ts +177 -0
- package/engine/testing/setup-repo.ts +194 -0
- package/engine/testing/step-record-fixtures.ts +55 -0
- package/engine/testing/ticket-step-fixtures.ts +272 -0
- package/engine/testing/wait-scenarios.ts +186 -0
- package/engine/tracker/gh-retry.ts +217 -0
- package/engine/tracker/github-tracker.ts +310 -90
- package/engine/tracker/in-memory-tracker.ts +8 -4
- package/engine/tracker/tracker.ts +131 -6
- package/package.json +2 -1
- package/skills/luca-retro/SKILL.md +74 -0
- package/skills/luca-retro/scripts/retro-summary.ts +1356 -0
- package/skills/luca-unstick/SKILL.md +153 -0
- package/skills/luca-unstick/scripts/stuck-summary.ts +1063 -0
- package/engine/jev/jev-client.ts +0 -173
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Small pure reads of an agent turn, shared by ticket and final review
|
|
3
|
+
* replay: a finished agent's assumptions and bad test, the sessions after a
|
|
4
|
+
* turn, the out-of-turns counts, the fixer roles, a fix round's answers and `other_role` hand-offs,
|
|
5
|
+
* and the "won't fix" answers a review let go.
|
|
6
|
+
*/
|
|
7
|
+
import omit from 'lodash/omit'
|
|
8
|
+
import uniq from 'lodash/uniq'
|
|
9
|
+
|
|
10
|
+
import type { JournalRecord } from './journal-record'
|
|
11
|
+
import type { DeclinedFinding, ReviewFix, WriterRole } from './ticket-progress'
|
|
12
|
+
|
|
13
|
+
import type {
|
|
14
|
+
AgentRole,
|
|
15
|
+
BadTest,
|
|
16
|
+
FindingResponse,
|
|
17
|
+
ImplementerResult,
|
|
18
|
+
TicketReviewResult,
|
|
19
|
+
} from '../agents/role-results'
|
|
20
|
+
import { DEFAULT_MODEL } from '../config/engine-config'
|
|
21
|
+
|
|
22
|
+
export type FinishedContent = Extract<
|
|
23
|
+
JournalRecord,
|
|
24
|
+
{ kind: 'agent_finished' }
|
|
25
|
+
>['content']
|
|
26
|
+
|
|
27
|
+
/** A finished agent's assumptions; the learner makes none. */
|
|
28
|
+
export const assumptionsOf = (finished: FinishedContent): string[] =>
|
|
29
|
+
'assumptions' in finished.result ? finished.result.assumptions : []
|
|
30
|
+
|
|
31
|
+
/** A fixer's bad test, or the implementer's summary as its reason. */
|
|
32
|
+
export const badTestOf = (result: ImplementerResult): BadTest | null =>
|
|
33
|
+
result.outcome === 'bad_test'
|
|
34
|
+
? (result.bad_test ?? { file: '', name: '', reason: result.summary })
|
|
35
|
+
: null
|
|
36
|
+
|
|
37
|
+
/** The sessions after a turn: the role's latest, or none if unknown. */
|
|
38
|
+
export const sessionsAfter = ({
|
|
39
|
+
sessions,
|
|
40
|
+
role,
|
|
41
|
+
session_id,
|
|
42
|
+
}: {
|
|
43
|
+
sessions: Partial<Record<AgentRole, string>>
|
|
44
|
+
role: AgentRole
|
|
45
|
+
session_id: string | null
|
|
46
|
+
}): Partial<Record<AgentRole, string>> => {
|
|
47
|
+
const rest = omit(sessions, role)
|
|
48
|
+
return session_id === null ? rest : { ...rest, [role]: session_id }
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/** The out-of-turns counts after a failed turn (#543): one more for its role if it reached its limit. */
|
|
52
|
+
export const outOfTurnsAfter = ({
|
|
53
|
+
counts,
|
|
54
|
+
failed,
|
|
55
|
+
}: {
|
|
56
|
+
counts: Partial<Record<AgentRole, number>>
|
|
57
|
+
failed: { role: AgentRole; out_of_turns: boolean }
|
|
58
|
+
}): Partial<Record<AgentRole, number>> =>
|
|
59
|
+
failed.out_of_turns
|
|
60
|
+
? { ...counts, [failed.role]: (counts[failed.role] ?? 0) + 1 }
|
|
61
|
+
: counts
|
|
62
|
+
|
|
63
|
+
export const isFixerRole = (role: AgentRole): boolean =>
|
|
64
|
+
role === 'test-writer' || role === 'implementer'
|
|
65
|
+
|
|
66
|
+
const OTHER_ROLE: Record<WriterRole, WriterRole> = {
|
|
67
|
+
'test-writer': 'implementer',
|
|
68
|
+
implementer: 'test-writer',
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
type FixAnswers = Pick<ReviewFix, 'findings' | 'responses' | 'handed_off'>
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* A fixer's answers in its fix round, kept, with the round's findings it
|
|
75
|
+
* answered `other_role` handed to the other writer role (#616).
|
|
76
|
+
*/
|
|
77
|
+
export const fixerAnswered = ({
|
|
78
|
+
fix,
|
|
79
|
+
role,
|
|
80
|
+
responses,
|
|
81
|
+
}: {
|
|
82
|
+
fix: FixAnswers
|
|
83
|
+
role: WriterRole
|
|
84
|
+
responses: FindingResponse[]
|
|
85
|
+
}): Pick<ReviewFix, 'responses' | 'handed_off'> => {
|
|
86
|
+
const handed = responses.flatMap(({ finding_id, response }) =>
|
|
87
|
+
response === 'other_role' &&
|
|
88
|
+
fix.findings.some(({ id }) => id === finding_id)
|
|
89
|
+
? [finding_id]
|
|
90
|
+
: []
|
|
91
|
+
)
|
|
92
|
+
const other = OTHER_ROLE[role]
|
|
93
|
+
return {
|
|
94
|
+
responses: [...fix.responses, ...responses],
|
|
95
|
+
handed_off:
|
|
96
|
+
handed.length === 0
|
|
97
|
+
? fix.handed_off
|
|
98
|
+
: {
|
|
99
|
+
...fix.handed_off,
|
|
100
|
+
[other]: uniq([
|
|
101
|
+
...(fix.handed_off[other] ?? []),
|
|
102
|
+
...handed,
|
|
103
|
+
]),
|
|
104
|
+
},
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* The other role's answers to the findings handed to it (#616). Each one
|
|
110
|
+
* replaces the first fixer's `other_role`, and is final: a second
|
|
111
|
+
* `other_role` counts as `wont_fix`. Answers to findings not handed to it
|
|
112
|
+
* are dropped.
|
|
113
|
+
*/
|
|
114
|
+
export const handoffAnswered = ({
|
|
115
|
+
fix,
|
|
116
|
+
role,
|
|
117
|
+
responses,
|
|
118
|
+
}: {
|
|
119
|
+
fix: FixAnswers
|
|
120
|
+
role: WriterRole
|
|
121
|
+
responses: FindingResponse[]
|
|
122
|
+
}): Pick<ReviewFix, 'responses' | 'handed_off'> => {
|
|
123
|
+
const ids = fix.handed_off[role] ?? []
|
|
124
|
+
const answers = responses.flatMap((answer) => {
|
|
125
|
+
if (!ids.includes(answer.finding_id)) return []
|
|
126
|
+
return answer.response === 'other_role'
|
|
127
|
+
? [{ ...answer, response: 'wont_fix' as const }]
|
|
128
|
+
: [answer]
|
|
129
|
+
})
|
|
130
|
+
const answered = new Set(answers.map(({ finding_id }) => finding_id))
|
|
131
|
+
return {
|
|
132
|
+
responses: [
|
|
133
|
+
...fix.responses.filter(
|
|
134
|
+
({ finding_id }) => !answered.has(finding_id)
|
|
135
|
+
),
|
|
136
|
+
...answers,
|
|
137
|
+
],
|
|
138
|
+
handed_off: omit(fix.handed_off, role),
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* The writer role a fix round hands findings to next, once its fixers
|
|
144
|
+
* answered: the test-writer first, then the implementer. `null` with none,
|
|
145
|
+
* or while a fixer has yet to answer.
|
|
146
|
+
*/
|
|
147
|
+
export const handoffRole = ({
|
|
148
|
+
fix,
|
|
149
|
+
}: {
|
|
150
|
+
fix: Pick<ReviewFix, 'handed_off' | 'tests_answered' | 'code_answered'>
|
|
151
|
+
}): WriterRole | null => {
|
|
152
|
+
if (!fix.tests_answered || !fix.code_answered) return null
|
|
153
|
+
return (
|
|
154
|
+
(['test-writer', 'implementer'] as const).find(
|
|
155
|
+
(role) => (fix.handed_off[role] ?? []).length > 0
|
|
156
|
+
) ?? null
|
|
157
|
+
)
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Whether a fixer's answer declines its finding: `wont_fix`, or an
|
|
162
|
+
* `other_role` the other role never answered (#616).
|
|
163
|
+
*/
|
|
164
|
+
export const isDeclined = ({ response }: FindingResponse): boolean =>
|
|
165
|
+
response === 'wont_fix' || response === 'other_role'
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Whether an agent launched on a model cheaper than Opus (#604). Older
|
|
169
|
+
* journals name no model, and ran Opus.
|
|
170
|
+
*/
|
|
171
|
+
export const ranCheaper = (model: string | null | undefined): boolean =>
|
|
172
|
+
model !== null && model !== undefined && model !== DEFAULT_MODEL
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* The fixers' "won't fix" answers the new review let go: its ruling was
|
|
176
|
+
* `accepted`, or it gave none and did not list the finding again.
|
|
177
|
+
*/
|
|
178
|
+
export const declinedBy = ({
|
|
179
|
+
fix,
|
|
180
|
+
review,
|
|
181
|
+
}: {
|
|
182
|
+
fix: Pick<ReviewFix, 'findings' | 'responses'> | null
|
|
183
|
+
review: TicketReviewResult
|
|
184
|
+
}): DeclinedFinding[] => {
|
|
185
|
+
if (fix === null) return []
|
|
186
|
+
const listed = new Set(review.findings.map(({ id }) => id))
|
|
187
|
+
return fix.responses.flatMap((answer) => {
|
|
188
|
+
const { finding_id, reason } = answer
|
|
189
|
+
if (!isDeclined(answer)) return []
|
|
190
|
+
const finding = fix.findings.find(({ id }) => id === finding_id)
|
|
191
|
+
if (finding === undefined) return []
|
|
192
|
+
const ruling = review.rulings.find(
|
|
193
|
+
(entry) => entry.finding_id === finding_id
|
|
194
|
+
)
|
|
195
|
+
const accepted =
|
|
196
|
+
ruling === undefined
|
|
197
|
+
? !listed.has(finding_id)
|
|
198
|
+
: ruling.ruling === 'accepted'
|
|
199
|
+
return accepted
|
|
200
|
+
? [{ finding, reason, ruling: ruling?.reason ?? '' }]
|
|
201
|
+
: []
|
|
202
|
+
})
|
|
203
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { z } from 'zod'
|
|
2
|
+
|
|
3
|
+
import { ENTRY_FIELDS } from './entry-fields'
|
|
4
|
+
|
|
5
|
+
import { TestRunSchema } from '../gates/gate-schemas'
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* The journal entries of a ticket whose work is already on the base branch
|
|
9
|
+
* (#484): the evidence check, the ticket counted done, and its closing.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* The engine checked a test-writer's `already_done` evidence (#495) in the
|
|
14
|
+
* ticket's worktree, at `base_sha`, the commit it started from: each named
|
|
15
|
+
* commit is on the base, and each named test exists and passes there.
|
|
16
|
+
* `problems` says what did not check out; `tests` is the run of the named
|
|
17
|
+
* test files (`null` if none ran). A failed check is a failed try for the
|
|
18
|
+
* test-writer.
|
|
19
|
+
*/
|
|
20
|
+
export const AlreadyDoneCheckedEntrySchema = z.object({
|
|
21
|
+
...ENTRY_FIELDS,
|
|
22
|
+
kind: z.literal('already_done_checked'),
|
|
23
|
+
content: z.object({
|
|
24
|
+
ok: z.boolean(),
|
|
25
|
+
problems: z.array(z.string()),
|
|
26
|
+
base_sha: z.string(),
|
|
27
|
+
tests: TestRunSchema.nullable(),
|
|
28
|
+
}),
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* A ticket whose work is already on the base branch (#484): its
|
|
33
|
+
* test-writer answered `already_done`, and `shas` are the commits that did
|
|
34
|
+
* the work. The ticket counts as done, not stuck, and tickets that wait on
|
|
35
|
+
* it go on. The engine said so on the spec issue, in its comment
|
|
36
|
+
* `comment_id`. The run's PR closes it; with no PR, `ticket_closed` follows.
|
|
37
|
+
*/
|
|
38
|
+
export const TicketAlreadyDoneEntrySchema = z.object({
|
|
39
|
+
...ENTRY_FIELDS,
|
|
40
|
+
kind: z.literal('ticket_already_done'),
|
|
41
|
+
content: z.object({
|
|
42
|
+
shas: z.array(z.string().min(1)),
|
|
43
|
+
comment_id: z.number().int(),
|
|
44
|
+
}),
|
|
45
|
+
})
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* The engine closed an already-done ticket itself, as the run opens no PR
|
|
49
|
+
* to close it, after its comment `comment_id` on the ticket said why.
|
|
50
|
+
*/
|
|
51
|
+
export const TicketClosedEntrySchema = z.object({
|
|
52
|
+
...ENTRY_FIELDS,
|
|
53
|
+
kind: z.literal('ticket_closed'),
|
|
54
|
+
content: z.object({ comment_id: z.number().int() }),
|
|
55
|
+
})
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { z } from 'zod'
|
|
2
|
+
|
|
3
|
+
import { ENTRY_FIELDS } from './entry-fields'
|
|
4
|
+
|
|
5
|
+
import { LeftoverHitSchema, LeftoverPassSchema } from '../gates/gate-schemas'
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* The journal entries of the engine's commits on a ticket: the leftover
|
|
9
|
+
* scan, dropped changesets, and the commit itself.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* The commits the engine makes on a ticket: tests first (`red`), then code
|
|
14
|
+
* (`green`), then one per review fix round (`fix`).
|
|
15
|
+
*/
|
|
16
|
+
export const CommitStageSchema = z.enum(['red', 'green', 'fix'])
|
|
17
|
+
|
|
18
|
+
export type CommitStage = z.infer<typeof CommitStageSchema>
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* The leftover scan before an engine commit. Any hit blocks the commit.
|
|
22
|
+
* `passed` lists the new markdown it let through and why (#520); left out
|
|
23
|
+
* when there was none, and in journals from before it.
|
|
24
|
+
*/
|
|
25
|
+
export const LeftoverScanEntrySchema = z.object({
|
|
26
|
+
...ENTRY_FIELDS,
|
|
27
|
+
kind: z.literal('leftover_scan'),
|
|
28
|
+
content: z.object({
|
|
29
|
+
stage: CommitStageSchema,
|
|
30
|
+
hits: z.array(LeftoverHitSchema),
|
|
31
|
+
passed: z.array(LeftoverPassSchema).optional(),
|
|
32
|
+
}),
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Before an engine commit's leftover scan, in a repo with changesets, the
|
|
37
|
+
* engine removed the changesets an agent wrote (new `.changeset/*.md` files
|
|
38
|
+
* other than the README) from the worktree: it writes the run's one itself.
|
|
39
|
+
* No ticket for the final review's fix commit.
|
|
40
|
+
*/
|
|
41
|
+
export const ChangesetDroppedEntrySchema = z.object({
|
|
42
|
+
...ENTRY_FIELDS,
|
|
43
|
+
kind: z.literal('changeset_dropped'),
|
|
44
|
+
content: z.object({ paths: z.array(z.string().min(1)).min(1) }),
|
|
45
|
+
})
|
|
46
|
+
|
|
47
|
+
export const CommitMadeEntrySchema = z.object({
|
|
48
|
+
...ENTRY_FIELDS,
|
|
49
|
+
kind: z.literal('commit_made'),
|
|
50
|
+
content: z.object({
|
|
51
|
+
stage: CommitStageSchema,
|
|
52
|
+
sha: z.string().min(1),
|
|
53
|
+
message: z.string(),
|
|
54
|
+
files: z.array(z.string()),
|
|
55
|
+
}),
|
|
56
|
+
})
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Records that reach across tickets in replay: a restarted engine's
|
|
3
|
+
* `run_resumed`, a closed or gone session, and the other joins an undo took
|
|
4
|
+
* off the run branch.
|
|
5
|
+
*/
|
|
6
|
+
import mapValues from 'lodash/mapValues'
|
|
7
|
+
import omit from 'lodash/omit'
|
|
8
|
+
import omitBy from 'lodash/omitBy'
|
|
9
|
+
import uniq from 'lodash/uniq'
|
|
10
|
+
|
|
11
|
+
import { isFixerRole } from './agent-turn-replay'
|
|
12
|
+
import type { JournalRecord } from './journal-record'
|
|
13
|
+
import type { RunState } from './run-state'
|
|
14
|
+
import { EMPTY_TICKET_PROGRESS } from './ticket-progress'
|
|
15
|
+
|
|
16
|
+
import { AgentRoleSchema, type AgentRole } from '../agents/role-results'
|
|
17
|
+
|
|
18
|
+
/** A failed turn's session forgotten, when it is this role's. */
|
|
19
|
+
const failureWithoutSession = <
|
|
20
|
+
Failure extends { role: AgentRole; session_id: string | null },
|
|
21
|
+
>({
|
|
22
|
+
failure,
|
|
23
|
+
role,
|
|
24
|
+
}: {
|
|
25
|
+
failure: Failure | null | undefined
|
|
26
|
+
role: AgentRole
|
|
27
|
+
}): Failure | null =>
|
|
28
|
+
failure === null || failure === undefined
|
|
29
|
+
? null
|
|
30
|
+
: failure.role === role
|
|
31
|
+
? { ...failure, session_id: null }
|
|
32
|
+
: failure
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* A restarted engine's `run_resumed`: each agent turn a crash cut off is
|
|
36
|
+
* taken again in a fresh session, so its role's session (and a failed
|
|
37
|
+
* turn's session, for a follow-up) is forgotten, on its ticket or in the
|
|
38
|
+
* final review, and the fresh agent is told of the crash. The counts it
|
|
39
|
+
* adds live in `crashes`.
|
|
40
|
+
*/
|
|
41
|
+
export const resumedAfter = ({
|
|
42
|
+
state,
|
|
43
|
+
record,
|
|
44
|
+
}: {
|
|
45
|
+
state: RunState
|
|
46
|
+
record: Extract<JournalRecord, { kind: 'run_resumed' }>
|
|
47
|
+
}): RunState =>
|
|
48
|
+
record.content.interrupted.reduce((current, { key, ticket, role }) => {
|
|
49
|
+
const parsed = AgentRoleSchema.safeParse(role)
|
|
50
|
+
if (!parsed.success) return current
|
|
51
|
+
const agent = parsed.data
|
|
52
|
+
if (key === 'final') {
|
|
53
|
+
const review = current.final_review
|
|
54
|
+
const failed = failureWithoutSession({
|
|
55
|
+
failure: review.agent_failures[agent],
|
|
56
|
+
role: agent,
|
|
57
|
+
})
|
|
58
|
+
return {
|
|
59
|
+
...current,
|
|
60
|
+
final_review: {
|
|
61
|
+
...review,
|
|
62
|
+
sessions: omit(review.sessions, agent),
|
|
63
|
+
agent_failures:
|
|
64
|
+
failed === null
|
|
65
|
+
? review.agent_failures
|
|
66
|
+
: { ...review.agent_failures, [agent]: failed },
|
|
67
|
+
crashed_turn: isFixerRole(agent)
|
|
68
|
+
? agent
|
|
69
|
+
: review.crashed_turn,
|
|
70
|
+
},
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
if (ticket === null || key !== String(ticket)) return current
|
|
74
|
+
const progress = current.tickets[ticket] ?? EMPTY_TICKET_PROGRESS
|
|
75
|
+
return {
|
|
76
|
+
...current,
|
|
77
|
+
tickets: {
|
|
78
|
+
...current.tickets,
|
|
79
|
+
[ticket]: {
|
|
80
|
+
...progress,
|
|
81
|
+
sessions: omit(progress.sessions, agent),
|
|
82
|
+
agent_failure: failureWithoutSession({
|
|
83
|
+
failure: progress.agent_failure,
|
|
84
|
+
role: agent,
|
|
85
|
+
}),
|
|
86
|
+
crashed_turn: agent,
|
|
87
|
+
},
|
|
88
|
+
},
|
|
89
|
+
}
|
|
90
|
+
}, state)
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* A closed session can take no follow-up: it is forgotten wherever the
|
|
94
|
+
* decision step would follow it up (a role's latest session, or a failed
|
|
95
|
+
* turn's), on its ticket, in the final review, or the learner's, so a fix
|
|
96
|
+
* round that would have gone to it goes to a fresh agent.
|
|
97
|
+
*/
|
|
98
|
+
export const closedSessionAfter = ({
|
|
99
|
+
state,
|
|
100
|
+
session_id,
|
|
101
|
+
}: {
|
|
102
|
+
state: RunState
|
|
103
|
+
session_id: string
|
|
104
|
+
}): RunState => {
|
|
105
|
+
const forget = <Failure extends { session_id: string | null }>(
|
|
106
|
+
failure: Failure
|
|
107
|
+
): Failure =>
|
|
108
|
+
failure.session_id === session_id
|
|
109
|
+
? { ...failure, session_id: null }
|
|
110
|
+
: failure
|
|
111
|
+
const withoutIt = (sessions: Partial<Record<AgentRole, string>>) =>
|
|
112
|
+
omitBy(sessions, (id) => id === session_id)
|
|
113
|
+
const review = state.final_review
|
|
114
|
+
const { learner } = state.memory
|
|
115
|
+
return {
|
|
116
|
+
...state,
|
|
117
|
+
tickets: mapValues(state.tickets, (progress) => ({
|
|
118
|
+
...progress,
|
|
119
|
+
sessions: withoutIt(progress.sessions),
|
|
120
|
+
agent_failure:
|
|
121
|
+
progress.agent_failure === null
|
|
122
|
+
? null
|
|
123
|
+
: forget(progress.agent_failure),
|
|
124
|
+
})),
|
|
125
|
+
final_review: {
|
|
126
|
+
...review,
|
|
127
|
+
sessions: withoutIt(review.sessions),
|
|
128
|
+
agent_failures: mapValues(review.agent_failures, (failure) =>
|
|
129
|
+
failure === undefined ? failure : forget(failure)
|
|
130
|
+
),
|
|
131
|
+
},
|
|
132
|
+
memory: {
|
|
133
|
+
...state.memory,
|
|
134
|
+
learner: {
|
|
135
|
+
...learner,
|
|
136
|
+
agent_failure:
|
|
137
|
+
learner.agent_failure === null
|
|
138
|
+
? null
|
|
139
|
+
: forget(learner.agent_failure),
|
|
140
|
+
},
|
|
141
|
+
},
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* The session a follow-up found gone (#521), or `null`: no agent ran, so the
|
|
147
|
+
* record changes no step and counts no engine failure.
|
|
148
|
+
*/
|
|
149
|
+
export const goneSessionOf = (record: JournalRecord): string | null =>
|
|
150
|
+
record.kind === 'agent_failed' && record.content.session_gone
|
|
151
|
+
? record.content.session_id
|
|
152
|
+
: null
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Closed sessions after a record: one journaled as closed, or found gone by
|
|
156
|
+
* a follow-up (#521), joins them and is forgotten; a later turn's end that
|
|
157
|
+
* names a closed session again (`agent_finished`, `agent_failed`) has it
|
|
158
|
+
* forgotten again, so it is never a follow-up target.
|
|
159
|
+
*/
|
|
160
|
+
export const closedSessionsAfter = ({
|
|
161
|
+
state,
|
|
162
|
+
record,
|
|
163
|
+
}: {
|
|
164
|
+
state: RunState
|
|
165
|
+
record: JournalRecord
|
|
166
|
+
}): RunState => {
|
|
167
|
+
const closed =
|
|
168
|
+
record.kind === 'agent_session_closed'
|
|
169
|
+
? record.content.session_id
|
|
170
|
+
: goneSessionOf(record)
|
|
171
|
+
if (closed !== null) {
|
|
172
|
+
return closedSessionAfter({
|
|
173
|
+
state: {
|
|
174
|
+
...state,
|
|
175
|
+
closed_sessions: uniq([...state.closed_sessions, closed]),
|
|
176
|
+
},
|
|
177
|
+
session_id: closed,
|
|
178
|
+
})
|
|
179
|
+
}
|
|
180
|
+
if (record.kind !== 'agent_finished' && record.kind !== 'agent_failed') {
|
|
181
|
+
return state
|
|
182
|
+
}
|
|
183
|
+
const { session_id } = record.content
|
|
184
|
+
return session_id !== null && state.closed_sessions.includes(session_id)
|
|
185
|
+
? closedSessionAfter({ state, session_id })
|
|
186
|
+
: state
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* The other tickets whose joins an undo took off the run branch (#519): an
|
|
191
|
+
* undo resets the run branch to before the undone ticket's join, so any
|
|
192
|
+
* join on top of it goes too. Each such ticket's join and join gates are
|
|
193
|
+
* cleared, as its own undo would, so it joins again on the run branch as it
|
|
194
|
+
* is now, and a stuck one is never undone a second time. Its push, stuck,
|
|
195
|
+
* and reply are kept.
|
|
196
|
+
*/
|
|
197
|
+
export const undoneJoinsAfter = ({
|
|
198
|
+
state,
|
|
199
|
+
ticket,
|
|
200
|
+
shas,
|
|
201
|
+
}: {
|
|
202
|
+
state: RunState
|
|
203
|
+
/** The ticket whose join was undone. */
|
|
204
|
+
ticket: number | null
|
|
205
|
+
/** Every commit the undo took off the run branch. */
|
|
206
|
+
shas: string[]
|
|
207
|
+
}): RunState => {
|
|
208
|
+
if (shas.length === 0) return state
|
|
209
|
+
return {
|
|
210
|
+
...state,
|
|
211
|
+
tickets: mapValues(state.tickets, (progress, number) => {
|
|
212
|
+
const { joined } = progress
|
|
213
|
+
const taken =
|
|
214
|
+
Number(number) !== ticket &&
|
|
215
|
+
joined?.ok === true &&
|
|
216
|
+
joined.shas.some((sha) => shas.includes(sha))
|
|
217
|
+
return taken
|
|
218
|
+
? { ...progress, joined: null, join_gates: null }
|
|
219
|
+
: progress
|
|
220
|
+
}),
|
|
221
|
+
}
|
|
222
|
+
}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { z } from 'zod'
|
|
2
|
+
|
|
3
|
+
import { ENTRY_FIELDS } from './entry-fields'
|
|
4
|
+
|
|
5
|
+
import {
|
|
6
|
+
DecisionModelOffReasonSchema,
|
|
7
|
+
JevAnswerSchema,
|
|
8
|
+
JevFailureReasonSchema,
|
|
9
|
+
JevFixedSchema,
|
|
10
|
+
JevJobSchema,
|
|
11
|
+
JevRequestSchema,
|
|
12
|
+
} from '../jev/jev-schemas'
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* The journal entries of the decision model in shadow mode: each ask, its
|
|
16
|
+
* answers or failure, and the model turned off for the run.
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* The engine asked the decision model (Clef; Jev in older journals), in
|
|
21
|
+
* shadow mode, with its own fixed choice beside. `model` is the model asked;
|
|
22
|
+
* journals from before #534 have none. `acted` is true when the answer can
|
|
23
|
+
* change what the engine does, false for a shadow ask; older journals read
|
|
24
|
+
* it as false.
|
|
25
|
+
*/
|
|
26
|
+
export const JevAskedEntrySchema = z.object({
|
|
27
|
+
...ENTRY_FIELDS,
|
|
28
|
+
kind: z.literal('jev_asked'),
|
|
29
|
+
content: z.object({
|
|
30
|
+
job: JevJobSchema,
|
|
31
|
+
request: JevRequestSchema,
|
|
32
|
+
fixed: JevFixedSchema,
|
|
33
|
+
model: z.string().optional(),
|
|
34
|
+
acted: z.boolean().default(false),
|
|
35
|
+
}),
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* The decision model's answers to the `jev_asked` record at `asked_seq`.
|
|
40
|
+
* The engine ignores them. `model` is the model that answered, as it named
|
|
41
|
+
* itself (such as `clef`); journals from before #534 have none.
|
|
42
|
+
*/
|
|
43
|
+
export const JevAnsweredEntrySchema = z.object({
|
|
44
|
+
...ENTRY_FIELDS,
|
|
45
|
+
kind: z.literal('jev_answered'),
|
|
46
|
+
content: z.object({
|
|
47
|
+
job: JevJobSchema,
|
|
48
|
+
asked_seq: z.number().int().min(1),
|
|
49
|
+
answers: z.record(z.string(), JevAnswerSchema),
|
|
50
|
+
/** How long the call took. */
|
|
51
|
+
ms: z.number().min(0),
|
|
52
|
+
model: z.string().optional(),
|
|
53
|
+
}),
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
/** The decision model call at `asked_seq` gave no answers. The run goes on regardless. */
|
|
57
|
+
export const JevFailedEntrySchema = z.object({
|
|
58
|
+
...ENTRY_FIELDS,
|
|
59
|
+
kind: z.literal('jev_failed'),
|
|
60
|
+
content: z.object({
|
|
61
|
+
job: JevJobSchema,
|
|
62
|
+
asked_seq: z.number().int().min(1),
|
|
63
|
+
reason: JevFailureReasonSchema,
|
|
64
|
+
error: z.string(),
|
|
65
|
+
ms: z.number().min(0),
|
|
66
|
+
}),
|
|
67
|
+
})
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* The decision model is off for the rest of the run (#534), so the engine
|
|
71
|
+
* asks it nothing more: `no_credentials` at the start (Luca's env file and
|
|
72
|
+
* the process env have no Cloudflare account id or token), or `rejected`
|
|
73
|
+
* after an ask Cloudflare turned down. `model` is the model it would have
|
|
74
|
+
* asked; `detail` is one plain sentence (the file and keys to add, or
|
|
75
|
+
* Cloudflare's answer), never the token. Shadow mode only: it changes
|
|
76
|
+
* nothing in the run.
|
|
77
|
+
*/
|
|
78
|
+
export const DecisionModelOffEntrySchema = z.object({
|
|
79
|
+
...ENTRY_FIELDS,
|
|
80
|
+
kind: z.literal('decision_model_off'),
|
|
81
|
+
content: z.object({
|
|
82
|
+
model: z.string(),
|
|
83
|
+
reason: DecisionModelOffReasonSchema,
|
|
84
|
+
detail: z.string(),
|
|
85
|
+
}),
|
|
86
|
+
})
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { z } from 'zod'
|
|
2
|
+
|
|
3
|
+
/** The fields every journal entry has, whatever its kind. */
|
|
4
|
+
|
|
5
|
+
export const ENTRY_FIELDS = {
|
|
6
|
+
/** The ticket (or spec) a record is about, `null` for the whole run. */
|
|
7
|
+
ticket: z.number().int().positive().nullable(),
|
|
8
|
+
/** The role that produced the record, `null` for the engine itself. */
|
|
9
|
+
role: z.string().nullable(),
|
|
10
|
+
}
|