@llm4ts/flow 2.8.0 → 2.9.1

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 (56) hide show
  1. package/dist/Approval.d.ts +1 -1
  2. package/dist/Approval.d.ts.map +1 -1
  3. package/dist/Artifacts.d.ts +2 -2
  4. package/dist/Artifacts.d.ts.map +1 -1
  5. package/dist/BenchReport.d.ts +2 -2
  6. package/dist/BenchReport.d.ts.map +1 -1
  7. package/dist/CostLedger.d.ts +2 -2
  8. package/dist/CostLedger.d.ts.map +1 -1
  9. package/dist/Equiv.d.ts +3 -3
  10. package/dist/Equiv.d.ts.map +1 -1
  11. package/dist/Flow.d.ts +1 -1
  12. package/dist/Flow.d.ts.map +1 -1
  13. package/dist/FlowContext.d.ts +15 -1
  14. package/dist/FlowContext.d.ts.map +1 -1
  15. package/dist/FlowContext.js.map +1 -1
  16. package/dist/FlowError.d.ts +24 -1
  17. package/dist/FlowError.d.ts.map +1 -1
  18. package/dist/FlowError.js +29 -0
  19. package/dist/FlowError.js.map +1 -1
  20. package/dist/FlowEvents.d.ts +45 -0
  21. package/dist/FlowEvents.d.ts.map +1 -1
  22. package/dist/FlowEvents.js +87 -7
  23. package/dist/FlowEvents.js.map +1 -1
  24. package/dist/Judgment.d.ts +2 -2
  25. package/dist/Judgment.d.ts.map +1 -1
  26. package/dist/Persistence.d.ts +2 -2
  27. package/dist/Persistence.d.ts.map +1 -1
  28. package/dist/PlanExecution.d.ts +1 -1
  29. package/dist/PlanExecution.d.ts.map +1 -1
  30. package/dist/ProgramJudge.d.ts +1 -1
  31. package/dist/ProgramJudge.d.ts.map +1 -1
  32. package/dist/Replay.d.ts +2 -2
  33. package/dist/Replay.d.ts.map +1 -1
  34. package/dist/Review.d.ts +3 -3
  35. package/dist/Review.d.ts.map +1 -1
  36. package/dist/ReviewCache.d.ts +1 -1
  37. package/dist/ReviewCache.d.ts.map +1 -1
  38. package/dist/Roster.d.ts +164 -0
  39. package/dist/Roster.d.ts.map +1 -0
  40. package/dist/Roster.js +583 -0
  41. package/dist/Roster.js.map +1 -0
  42. package/dist/RosterSeats.d.ts +71 -0
  43. package/dist/RosterSeats.d.ts.map +1 -0
  44. package/dist/RosterSeats.js +167 -0
  45. package/dist/RosterSeats.js.map +1 -0
  46. package/dist/Stories.d.ts +9 -5
  47. package/dist/Stories.d.ts.map +1 -1
  48. package/dist/Stories.js +95 -24
  49. package/dist/Stories.js.map +1 -1
  50. package/package.json +4 -2
  51. package/src/FlowContext.ts +19 -1
  52. package/src/FlowError.ts +32 -0
  53. package/src/FlowEvents.ts +108 -7
  54. package/src/Roster.ts +849 -0
  55. package/src/RosterSeats.ts +360 -0
  56. package/src/Stories.ts +129 -28
package/src/FlowEvents.ts CHANGED
@@ -38,16 +38,28 @@ export class JudgmentObserved extends Schema.TaggedClass<JudgmentObserved>()("Ju
38
38
  }) {}
39
39
 
40
40
  export class StageStarted extends Schema.TaggedClass<StageStarted>()("StageStarted", {
41
- stage: Schema.String
41
+ stage: Schema.String,
42
+ /** The concurrent unit (a story) this event belongs to; absent for run-wide events. */
43
+ lane: Schema.optionalKey(Schema.String),
44
+ /** The roster executor working that lane, when there is one (ADR 0019). */
45
+ executor: Schema.optionalKey(Schema.String)
42
46
  }) {}
43
47
 
44
48
  export class StageCompleted extends Schema.TaggedClass<StageCompleted>()("StageCompleted", {
45
- stage: Schema.String
49
+ stage: Schema.String,
50
+ /** The concurrent unit (a story) this event belongs to; absent for run-wide events. */
51
+ lane: Schema.optionalKey(Schema.String),
52
+ /** The roster executor working that lane, when there is one (ADR 0019). */
53
+ executor: Schema.optionalKey(Schema.String)
46
54
  }) {}
47
55
 
48
56
  export class StageFailed extends Schema.TaggedClass<StageFailed>()("StageFailed", {
49
57
  stage: Schema.String,
50
- message: Schema.String
58
+ message: Schema.String,
59
+ /** The concurrent unit (a story) this event belongs to; absent for run-wide events. */
60
+ lane: Schema.optionalKey(Schema.String),
61
+ /** The roster executor working that lane, when there is one (ADR 0019). */
62
+ executor: Schema.optionalKey(Schema.String)
51
63
  }) {}
52
64
 
53
65
  export class Aborted extends Schema.TaggedClass<Aborted>()("Aborted", {
@@ -55,22 +67,38 @@ export class Aborted extends Schema.TaggedClass<Aborted>()("Aborted", {
55
67
  }) {}
56
68
 
57
69
  export class Info extends Schema.TaggedClass<Info>()("Info", {
58
- message: Schema.String
70
+ message: Schema.String,
71
+ /** The concurrent unit (a story) this event belongs to; absent for run-wide events. */
72
+ lane: Schema.optionalKey(Schema.String),
73
+ /** The roster executor working that lane, when there is one (ADR 0019). */
74
+ executor: Schema.optionalKey(Schema.String)
59
75
  }) {}
60
76
 
61
77
  export class ToolUse extends Schema.TaggedClass<ToolUse>()("ToolUse", {
62
78
  tool: Schema.String,
63
- args: Schema.String
79
+ args: Schema.String,
80
+ /** The concurrent unit (a story) this event belongs to; absent for run-wide events. */
81
+ lane: Schema.optionalKey(Schema.String),
82
+ /** The roster executor working that lane, when there is one (ADR 0019). */
83
+ executor: Schema.optionalKey(Schema.String)
64
84
  }) {}
65
85
 
66
86
  export class AssistantMessage extends Schema.TaggedClass<AssistantMessage>()("AssistantMessage", {
67
- text: Schema.String
87
+ text: Schema.String,
88
+ /** The concurrent unit (a story) this event belongs to; absent for run-wide events. */
89
+ lane: Schema.optionalKey(Schema.String),
90
+ /** The roster executor working that lane, when there is one (ADR 0019). */
91
+ executor: Schema.optionalKey(Schema.String)
68
92
  }) {}
69
93
 
70
94
  export class TokensUsed extends Schema.TaggedClass<TokensUsed>()("TokensUsed", {
71
95
  agent: Schema.String,
72
96
  model: Schema.optionalKey(Schema.String),
73
- usage: TokenUsage
97
+ usage: TokenUsage,
98
+ /** The concurrent unit (a story) this event belongs to; absent for run-wide events. */
99
+ lane: Schema.optionalKey(Schema.String),
100
+ /** The roster executor working that lane, when there is one (ADR 0019). */
101
+ executor: Schema.optionalKey(Schema.String)
74
102
  }) {}
75
103
 
76
104
  export class CapabilityUsedEvent extends Schema.TaggedClass<CapabilityUsedEvent>()(
@@ -131,6 +159,79 @@ export interface FlowEventsShape {
131
159
  readonly publish: (event: FlowEvent) => Effect.Effect<void>
132
160
  }
133
161
 
162
+ /** A concurrent unit of work whose events should say so (a story, ADR 0013/0019). */
163
+ export interface Lane {
164
+ /** Stable key: the story id. */
165
+ readonly lane: string
166
+ /** The executor working it now; read at every publish, so a handover shows. */
167
+ readonly executor?: Effect.Effect<string | undefined>
168
+ /** The lane's working directory, dropped from tool arguments (the lane already names it). */
169
+ readonly workDir?: string
170
+ }
171
+
172
+ /** Tool arguments without the lane's own directory: `cd <dir> && x` → `x`, `<dir>/src/a` → `src/a`. */
173
+ export const shortenLaneArgs = (args: string, workDir: string | undefined): string => {
174
+ if (workDir === undefined || workDir.length === 0) {
175
+ return args
176
+ }
177
+ const root = workDir.replace(/\/+$/, "")
178
+ return args.split(`cd ${root} && `).join("").split(`${root}/`).join("")
179
+ }
180
+
181
+ const stamped = (
182
+ event: FlowEvent,
183
+ lane: string,
184
+ executor: string | undefined,
185
+ workDir: string | undefined
186
+ ): FlowEvent => {
187
+ const tags = { lane, ...(executor === undefined ? {} : { executor }) }
188
+ switch (event._tag) {
189
+ case "StageStarted":
190
+ return event.lane !== undefined ? event : StageStarted.make({ stage: event.stage, ...tags })
191
+ case "StageCompleted":
192
+ return event.lane !== undefined ? event : StageCompleted.make({ stage: event.stage, ...tags })
193
+ case "StageFailed":
194
+ return event.lane !== undefined
195
+ ? event
196
+ : StageFailed.make({ stage: event.stage, message: event.message, ...tags })
197
+ case "Info":
198
+ return event.lane !== undefined ? event : Info.make({ message: event.message, ...tags })
199
+ case "ToolUse":
200
+ return event.lane !== undefined
201
+ ? event
202
+ : ToolUse.make({
203
+ tool: event.tool,
204
+ args: shortenLaneArgs(event.args, workDir),
205
+ ...tags
206
+ })
207
+ case "AssistantMessage":
208
+ return event.lane !== undefined ? event : AssistantMessage.make({ text: event.text, ...tags })
209
+ case "TokensUsed":
210
+ return event.lane !== undefined
211
+ ? event
212
+ : TokensUsed.make({
213
+ agent: event.agent,
214
+ usage: event.usage,
215
+ ...(event.model === undefined ? {} : { model: event.model }),
216
+ ...tags
217
+ })
218
+ default:
219
+ return event
220
+ }
221
+ }
222
+
223
+ /**
224
+ * The same events, stamped with a lane: every stage, message, tool call and
225
+ * token report says which story it belongs to and which executor works it.
226
+ * An event already stamped (a nested context) keeps its own lane.
227
+ */
228
+ export const withLane = (events: FlowEventsShape, lane: Lane): FlowEventsShape => ({
229
+ publish: (event) =>
230
+ Effect.flatMap(lane.executor ?? Effect.succeed(undefined), (executor) =>
231
+ events.publish(stamped(event, lane.lane, executor, lane.workDir))
232
+ )
233
+ })
234
+
134
235
  /** Publish an observation, rendering the same decision and outcome in advise mode. */
135
236
  export const publishJudgmentObserved = Effect.fn("@llm4ts/flow/FlowEvents.publishJudgmentObserved")(
136
237
  function* (events: FlowEventsShape, observation: JudgmentObserved): Effect.fn.Return<void> {