-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathmevedel-directive.el
More file actions
302 lines (266 loc) · 13.1 KB
/
Copy pathmevedel-directive.el
File metadata and controls
302 lines (266 loc) · 13.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
;;; mevedel-directive.el -- Directive lifecycle and rewind -*- lexical-binding: t -*-
;;; Commentary:
;; Directive mutation and derived lifecycle: nested-detail ordering, available
;; actions, state recomputed from surviving model activity, plan invalidation
;; on authored edits, and chronological workspace rewind. The underlying
;; record structs remain in `mevedel-structs'.
;;; Code:
(eval-when-compile
(require 'cl-lib)
;; Required for the cl-defstruct accessors and `setf' expanders of
;; directive record slots.
(require 'mevedel-structs))
;; `mevedel-plan-mode'
(declare-function mevedel-plan-approval-abort
"mevedel-plan-mode" (&optional session outcome))
;; `mevedel-structs'
(declare-function mevedel-directive-attempt-sequence
"mevedel-structs" (cl-x) t)
(declare-function mevedel-directive-discussion-turn-sequence
"mevedel-structs" (cl-x) t)
(declare-function mevedel-subdirective-id "mevedel-structs" (cl-x) t)
;;
;;; Directive mutation
(defun mevedel-directive-set-anchor (directive anchor)
"Set DIRECTIVE's current ANCHOR."
(setf (mevedel-directive-anchor directive) anchor))
(defun mevedel-directive-set-state (directive state)
"Set DIRECTIVE's transient lifecycle STATE."
(setf (mevedel-directive-state directive) state))
(defun mevedel-directive-set-planning-enabled (directive enabled)
"Set DIRECTIVE's Plan-before-implementation preference to ENABLED."
(setf (mevedel-directive-planning-enabled directive) (and enabled t)))
(defun mevedel-directive-set-skills (directive skills)
"Set DIRECTIVE's implementation skill selection to SKILLS."
(setf (mevedel-directive-skills directive) skills))
(defun mevedel-subdirective-copy (subdirective)
"Return an independent snapshot of SUBDIRECTIVE."
(mevedel-subdirective--create
:id (substring-no-properties (mevedel-subdirective-id subdirective))
:request (substring-no-properties (mevedel-subdirective-request subdirective))
:anchor (copy-tree (mevedel-subdirective-anchor subdirective))))
(defun mevedel-subdirective-set-anchor (subdirective anchor)
"Set SUBDIRECTIVE's current ANCHOR."
(setf (mevedel-subdirective-anchor subdirective) anchor))
(defun mevedel-subdirective-set-request (subdirective request)
"Set SUBDIRECTIVE's current REQUEST."
(setf (mevedel-subdirective-request subdirective) request))
(defun mevedel-directive-sort-subdirectives (directive)
"Sort DIRECTIVE's nested details by their source anchors."
(setf
(mevedel-directive-subdirectives directive)
(sort
(copy-sequence (mevedel-directive-subdirectives directive))
(lambda (a b)
(let* ((a-anchor (mevedel-subdirective-anchor a))
(b-anchor (mevedel-subdirective-anchor b))
(a-start (or (plist-get a-anchor :start) 0))
(b-start (or (plist-get b-anchor :start) 0))
(a-end (or (plist-get a-anchor :end) a-start))
(b-end (or (plist-get b-anchor :end) b-start)))
(or (< a-start b-start)
(and (= a-start b-start)
(or (> a-end b-end)
(and (= a-end b-end)
(string-lessp (mevedel-subdirective-id a)
(mevedel-subdirective-id b)))))))))))
(defun mevedel-workspace-add-directive (workspace directive)
"Add DIRECTIVE to WORKSPACE."
(push directive (mevedel-workspace-directives workspace))
directive)
(defun mevedel-workspace-remove-directive (workspace directive)
"Remove DIRECTIVE from WORKSPACE."
(setf (mevedel-workspace-directives workspace)
(delq directive (mevedel-workspace-directives workspace))))
(defun mevedel-workspace-set-directives (workspace directives)
"Replace WORKSPACE's directive records with DIRECTIVES."
(setf (mevedel-workspace-directives workspace) directives))
;;
;;; Derived lifecycle
(defun mevedel-directive-invalidate-plan (directive)
"Invalidate DIRECTIVE's unstarted Plan authority."
(when-let* ((plan (mevedel-directive-plan directive))
((not (eq (plist-get plan :status) 'implementing))))
(setq plan (plist-put plan :status 'draft)
plan (plist-put plan :invalidated t))
(setf (mevedel-directive-plan directive) plan)
(when-let* ((chat-buffer (plist-get plan :chat-buffer))
((buffer-live-p chat-buffer))
(session (buffer-local-value 'mevedel--session chat-buffer))
(entry (mevedel-session-pending-plan-approval session))
((equal (plist-get entry :directive-id)
(mevedel-directive-id directive))))
(mevedel-plan-approval-abort session 'invalidated))
t))
(defun mevedel-directive-add-subdirective (directive subdirective)
"Add SUBDIRECTIVE to DIRECTIVE unless its identity is already present."
(unless (cl-find (mevedel-subdirective-id subdirective)
(mevedel-directive-subdirectives directive)
:key #'mevedel-subdirective-id :test #'equal)
(push subdirective (mevedel-directive-subdirectives directive))
(mevedel-directive-sort-subdirectives directive)
(mevedel-directive-invalidate-plan directive))
subdirective)
(defun mevedel-directive-remove-subdirective (directive subdirective)
"Remove SUBDIRECTIVE from DIRECTIVE."
(setf (mevedel-directive-subdirectives directive)
(delq subdirective (mevedel-directive-subdirectives directive)))
(mevedel-directive-invalidate-plan directive)
subdirective)
(defun mevedel-directive-set-request (directive request)
"Set DIRECTIVE's current REQUEST and return it to Ready."
(setf (mevedel-directive-request directive) request
(mevedel-directive-state directive) nil)
(mevedel-directive-invalidate-plan directive)
request)
(defun mevedel-directive-request-changed-p (directive)
"Return non-nil when DIRECTIVE differs from its latest attempt snapshot."
(when-let* ((attempt (car (last (mevedel-directive-attempts directive)))))
(not (equal (mevedel-directive-request directive)
(mevedel-directive-attempt-directive-request attempt)))))
(defun mevedel-directive-actions (directive)
"Return lifecycle actions currently available for DIRECTIVE."
(pcase (if (memq (mevedel-directive-state directive)
'(implementing discussing planning))
(mevedel-directive-state directive)
(mevedel-directive-recompute-state directive))
((or 'nil 'ready) '(discuss implement))
('discussed '(continue-discussion implement-this))
('implemented '(discuss-result request-changes))
((or 'failed 'aborted) '(discuss-result retry))
((or 'implementing 'discussing 'planning) '(abort))))
(defun mevedel-directive-has-activity-p (directive)
"Return non-nil when DIRECTIVE owns model-produced activity."
(or (mevedel-directive-attempts directive)
(mevedel-directive-discussion directive)
(mevedel-directive-planning directive)))
(defun mevedel-directive-activity-sequences (directive)
"Return every activity settlement sequence DIRECTIVE stores.
One sequence identifies one settlement event across all three activity
collections, so they are allocated and validated against the union."
(delq nil
(append
(mapcar #'mevedel-directive-attempt-sequence
(mevedel-directive-attempts directive))
(mapcar #'mevedel-directive-discussion-turn-sequence
(mevedel-directive-discussion directive))
(mapcar (lambda (turn) (plist-get turn :sequence))
(mevedel-directive-planning directive)))))
(defun mevedel-directive-next-activity-sequence (directive)
"Return the next monotonic activity sequence for DIRECTIVE."
(1+ (apply #'max 0 (mevedel-directive-activity-sequences directive))))
(defun mevedel-directive-recompute-state (directive)
"Recompute DIRECTIVE state from its surviving model activity."
(let* ((attempt (car (last (mevedel-directive-attempts directive))))
(discussed-p
(cl-some
(lambda (turn)
(and (eq 'success (mevedel-directive-discussion-turn-outcome turn))
(equal (mevedel-directive-request directive)
(mevedel-directive-discussion-turn-directive-request
turn))))
(mevedel-directive-discussion directive)))
(state
(cond
((and discussed-p
(or (null attempt)
(mevedel-directive-request-changed-p directive)))
'discussed)
((and attempt
(not (mevedel-directive-request-changed-p directive)))
(pcase (mevedel-directive-attempt-outcome attempt)
('success 'implemented)
('aborted 'aborted)
(_ 'failed))))))
(setf (mevedel-directive-state directive) state)))
(defun mevedel-workspace-rewind-directives
(workspace session-id target-turn)
"Discard directive activity in WORKSPACE from SESSION-ID TARGET-TURN onward."
(dolist (directive (mevedel-workspace-directives workspace))
(let ((selection
(copy-tree (plist-get (mevedel-directive-plan directive)
:selection)))
rewound-planned-attempt)
(dolist (attempt (mevedel-directive-attempts directive))
(let ((checkpoint (mevedel-directive-attempt-checkpoint attempt)))
(when (and (equal session-id (plist-get checkpoint :session-id))
(>= (or (plist-get checkpoint :turn) 0) target-turn))
(when (and (null rewound-planned-attempt)
(mevedel-directive-attempt-plan attempt))
(setq rewound-planned-attempt attempt))
(dolist
(subdirective
(mevedel-directive-attempt-consumed-subdirectives attempt))
(mevedel-directive-add-subdirective
directive (mevedel-subdirective-copy subdirective))))))
(setf
(mevedel-directive-attempts directive)
(cl-remove-if
(lambda (attempt)
(let ((checkpoint (mevedel-directive-attempt-checkpoint attempt)))
(and (equal session-id (plist-get checkpoint :session-id))
(>= (or (plist-get checkpoint :turn) 0) target-turn))))
(mevedel-directive-attempts directive))
(mevedel-directive-discussion directive)
(cl-remove-if
(lambda (turn)
(let ((checkpoint
(mevedel-directive-discussion-turn-checkpoint turn)))
(and (equal session-id (plist-get checkpoint :session-id))
(>= (or (plist-get checkpoint :turn) 0) target-turn))))
(mevedel-directive-discussion directive))
(mevedel-directive-planning directive)
(cl-remove-if
(lambda (turn)
(let ((checkpoint (plist-get turn :checkpoint)))
(and (equal session-id (plist-get checkpoint :session-id))
(>= (or (plist-get checkpoint :turn) 0) target-turn))))
(mevedel-directive-planning directive)))
(when (and rewound-planned-attempt
(not
(equal
(mevedel-directive-attempt-plan-context
rewound-planned-attempt)
(list
:request (mevedel-directive-request directive)
:subdirectives
(mapcar
(lambda (subdirective)
(cons (mevedel-subdirective-id subdirective)
(mevedel-subdirective-request subdirective)))
(mevedel-directive-subdirectives directive))))))
(setq rewound-planned-attempt nil))
(if rewound-planned-attempt
(setf (mevedel-directive-plan directive)
(list :status 'accepted
:action (mevedel-directive-attempt-action
rewound-planned-attempt)
:proposal (mevedel-directive-attempt-plan
rewound-planned-attempt)
:selection
(copy-tree
(mevedel-directive-attempt-plan-selection
rewound-planned-attempt))
:accepted-prompt
(mevedel-directive-attempt-request
rewound-planned-attempt)))
(let* ((turns (mevedel-directive-planning directive))
(latest (car (last turns)))
(proposal-turn
(car (last (cl-remove-if-not
(lambda (turn) (plist-get turn :proposal))
turns)))))
(setf (mevedel-directive-plan directive)
(and latest
(list :status (if (plist-get latest :proposal)
'proposed
'draft)
:action (plist-get latest :action)
:implementation-prompt
(plist-get latest :implementation-prompt)
:proposal (plist-get proposal-turn :proposal)
:selection selection)))))
(mevedel-directive-recompute-state directive)))
workspace)
(provide 'mevedel-directive)
;;; mevedel-directive.el ends here