@llm4ts/flow 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (198) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +41 -0
  3. package/dist/AzureDevOpsTool.d.ts +60 -0
  4. package/dist/AzureDevOpsTool.d.ts.map +1 -0
  5. package/dist/AzureDevOpsTool.js +163 -0
  6. package/dist/AzureDevOpsTool.js.map +1 -0
  7. package/dist/Bench.d.ts +133 -0
  8. package/dist/Bench.d.ts.map +1 -0
  9. package/dist/Bench.js +272 -0
  10. package/dist/Bench.js.map +1 -0
  11. package/dist/BenchReport.d.ts +9 -0
  12. package/dist/BenchReport.d.ts.map +1 -0
  13. package/dist/BenchReport.js +360 -0
  14. package/dist/BenchReport.js.map +1 -0
  15. package/dist/CapabilityGuard.d.ts +6 -0
  16. package/dist/CapabilityGuard.d.ts.map +1 -0
  17. package/dist/CapabilityGuard.js +25 -0
  18. package/dist/CapabilityGuard.js.map +1 -0
  19. package/dist/Chat.d.ts +15 -0
  20. package/dist/Chat.d.ts.map +1 -0
  21. package/dist/Chat.js +36 -0
  22. package/dist/Chat.js.map +1 -0
  23. package/dist/Classified.d.ts +14 -0
  24. package/dist/Classified.d.ts.map +1 -0
  25. package/dist/Classified.js +48 -0
  26. package/dist/Classified.js.map +1 -0
  27. package/dist/CostLedger.d.ts +55 -0
  28. package/dist/CostLedger.d.ts.map +1 -0
  29. package/dist/CostLedger.js +126 -0
  30. package/dist/CostLedger.js.map +1 -0
  31. package/dist/CostTracker.d.ts +13 -0
  32. package/dist/CostTracker.d.ts.map +1 -0
  33. package/dist/CostTracker.js +116 -0
  34. package/dist/CostTracker.js.map +1 -0
  35. package/dist/Equiv.d.ts +163 -0
  36. package/dist/Equiv.d.ts.map +1 -0
  37. package/dist/Equiv.js +256 -0
  38. package/dist/Equiv.js.map +1 -0
  39. package/dist/EquivReport.d.ts +16 -0
  40. package/dist/EquivReport.d.ts.map +1 -0
  41. package/dist/EquivReport.js +77 -0
  42. package/dist/EquivReport.js.map +1 -0
  43. package/dist/Flow.d.ts +25 -0
  44. package/dist/Flow.d.ts.map +1 -0
  45. package/dist/Flow.js +39 -0
  46. package/dist/Flow.js.map +1 -0
  47. package/dist/FlowContext.d.ts +23 -0
  48. package/dist/FlowContext.d.ts.map +1 -0
  49. package/dist/FlowContext.js +4 -0
  50. package/dist/FlowContext.js.map +1 -0
  51. package/dist/FlowError.d.ts +80 -0
  52. package/dist/FlowError.d.ts.map +1 -0
  53. package/dist/FlowError.js +92 -0
  54. package/dist/FlowError.js.map +1 -0
  55. package/dist/FlowEvents.d.ts +101 -0
  56. package/dist/FlowEvents.d.ts.map +1 -0
  57. package/dist/FlowEvents.js +103 -0
  58. package/dist/FlowEvents.js.map +1 -0
  59. package/dist/FlowRecorder.d.ts +26 -0
  60. package/dist/FlowRecorder.d.ts.map +1 -0
  61. package/dist/FlowRecorder.js +74 -0
  62. package/dist/FlowRecorder.js.map +1 -0
  63. package/dist/GitHubTool.d.ts +53 -0
  64. package/dist/GitHubTool.d.ts.map +1 -0
  65. package/dist/GitHubTool.js +191 -0
  66. package/dist/GitHubTool.js.map +1 -0
  67. package/dist/GitTool.d.ts +46 -0
  68. package/dist/GitTool.d.ts.map +1 -0
  69. package/dist/GitTool.js +97 -0
  70. package/dist/GitTool.js.map +1 -0
  71. package/dist/Interaction.d.ts +21 -0
  72. package/dist/Interaction.d.ts.map +1 -0
  73. package/dist/Interaction.js +9 -0
  74. package/dist/Interaction.js.map +1 -0
  75. package/dist/McpServer.d.ts +18 -0
  76. package/dist/McpServer.d.ts.map +1 -0
  77. package/dist/McpServer.js +122 -0
  78. package/dist/McpServer.js.map +1 -0
  79. package/dist/Mermaid.d.ts +7 -0
  80. package/dist/Mermaid.d.ts.map +1 -0
  81. package/dist/Mermaid.js +98 -0
  82. package/dist/Mermaid.js.map +1 -0
  83. package/dist/Pack.d.ts +40 -0
  84. package/dist/Pack.d.ts.map +1 -0
  85. package/dist/Pack.js +141 -0
  86. package/dist/Pack.js.map +1 -0
  87. package/dist/Package.d.ts +2 -0
  88. package/dist/Package.d.ts.map +1 -0
  89. package/dist/Package.js +2 -0
  90. package/dist/Package.js.map +1 -0
  91. package/dist/Persistence.d.ts +32 -0
  92. package/dist/Persistence.d.ts.map +1 -0
  93. package/dist/Persistence.js +85 -0
  94. package/dist/Persistence.js.map +1 -0
  95. package/dist/Plan.d.ts +26 -0
  96. package/dist/Plan.d.ts.map +1 -0
  97. package/dist/Plan.js +101 -0
  98. package/dist/Plan.js.map +1 -0
  99. package/dist/PlanExecution.d.ts +7 -0
  100. package/dist/PlanExecution.d.ts.map +1 -0
  101. package/dist/PlanExecution.js +19 -0
  102. package/dist/PlanExecution.js.map +1 -0
  103. package/dist/Planner.d.ts +32 -0
  104. package/dist/Planner.d.ts.map +1 -0
  105. package/dist/Planner.js +97 -0
  106. package/dist/Planner.js.map +1 -0
  107. package/dist/PrSummary.d.ts +15 -0
  108. package/dist/PrSummary.d.ts.map +1 -0
  109. package/dist/PrSummary.js +29 -0
  110. package/dist/PrSummary.js.map +1 -0
  111. package/dist/PriceList.d.ts +11 -0
  112. package/dist/PriceList.d.ts.map +1 -0
  113. package/dist/PriceList.js +79 -0
  114. package/dist/PriceList.js.map +1 -0
  115. package/dist/Provenance.d.ts +27 -0
  116. package/dist/Provenance.d.ts.map +1 -0
  117. package/dist/Provenance.js +38 -0
  118. package/dist/Provenance.js.map +1 -0
  119. package/dist/Replay.d.ts +29 -0
  120. package/dist/Replay.d.ts.map +1 -0
  121. package/dist/Replay.js +181 -0
  122. package/dist/Replay.js.map +1 -0
  123. package/dist/Review.d.ts +71 -0
  124. package/dist/Review.d.ts.map +1 -0
  125. package/dist/Review.js +204 -0
  126. package/dist/Review.js.map +1 -0
  127. package/dist/ReviewCache.d.ts +6 -0
  128. package/dist/ReviewCache.d.ts.map +1 -0
  129. package/dist/ReviewCache.js +28 -0
  130. package/dist/ReviewCache.js.map +1 -0
  131. package/dist/Reviewer.d.ts +12 -0
  132. package/dist/Reviewer.d.ts.map +1 -0
  133. package/dist/Reviewer.js +30 -0
  134. package/dist/Reviewer.js.map +1 -0
  135. package/dist/SpecChecks.d.ts +17 -0
  136. package/dist/SpecChecks.d.ts.map +1 -0
  137. package/dist/SpecChecks.js +107 -0
  138. package/dist/SpecChecks.js.map +1 -0
  139. package/dist/Survey.d.ts +32 -0
  140. package/dist/Survey.d.ts.map +1 -0
  141. package/dist/Survey.js +119 -0
  142. package/dist/Survey.js.map +1 -0
  143. package/dist/TransientRetry.d.ts +16 -0
  144. package/dist/TransientRetry.d.ts.map +1 -0
  145. package/dist/TransientRetry.js +102 -0
  146. package/dist/TransientRetry.js.map +1 -0
  147. package/dist/Workspace.d.ts +39 -0
  148. package/dist/Workspace.d.ts.map +1 -0
  149. package/dist/Workspace.js +192 -0
  150. package/dist/Workspace.js.map +1 -0
  151. package/dist/WorkspaceLayout.d.ts +3 -0
  152. package/dist/WorkspaceLayout.d.ts.map +1 -0
  153. package/dist/WorkspaceLayout.js +19 -0
  154. package/dist/WorkspaceLayout.js.map +1 -0
  155. package/dist/WorkspaceTools.d.ts +4 -0
  156. package/dist/WorkspaceTools.d.ts.map +1 -0
  157. package/dist/WorkspaceTools.js +130 -0
  158. package/dist/WorkspaceTools.js.map +1 -0
  159. package/package.json +91 -0
  160. package/src/AzureDevOpsTool.ts +291 -0
  161. package/src/Bench.ts +340 -0
  162. package/src/BenchReport.ts +447 -0
  163. package/src/CapabilityGuard.ts +43 -0
  164. package/src/Chat.ts +60 -0
  165. package/src/Classified.ts +67 -0
  166. package/src/CostLedger.ts +171 -0
  167. package/src/CostTracker.ts +170 -0
  168. package/src/Equiv.ts +378 -0
  169. package/src/EquivReport.ts +92 -0
  170. package/src/Flow.ts +72 -0
  171. package/src/FlowContext.ts +23 -0
  172. package/src/FlowError.ts +112 -0
  173. package/src/FlowEvents.ts +147 -0
  174. package/src/FlowRecorder.ts +116 -0
  175. package/src/GitHubTool.ts +315 -0
  176. package/src/GitTool.ts +214 -0
  177. package/src/Interaction.ts +23 -0
  178. package/src/McpServer.ts +168 -0
  179. package/src/Mermaid.ts +112 -0
  180. package/src/Pack.ts +213 -0
  181. package/src/Package.ts +1 -0
  182. package/src/Persistence.ts +198 -0
  183. package/src/Plan.ts +119 -0
  184. package/src/PlanExecution.ts +46 -0
  185. package/src/Planner.ts +134 -0
  186. package/src/PrSummary.ts +37 -0
  187. package/src/PriceList.ts +91 -0
  188. package/src/Provenance.ts +85 -0
  189. package/src/Replay.ts +265 -0
  190. package/src/Review.ts +337 -0
  191. package/src/ReviewCache.ts +45 -0
  192. package/src/Reviewer.ts +31 -0
  193. package/src/SpecChecks.ts +143 -0
  194. package/src/Survey.ts +144 -0
  195. package/src/TransientRetry.ts +238 -0
  196. package/src/Workspace.ts +255 -0
  197. package/src/WorkspaceLayout.ts +22 -0
  198. package/src/WorkspaceTools.ts +188 -0
package/dist/Bench.js ADDED
@@ -0,0 +1,272 @@
1
+ import * as Effect from "effect/Effect";
2
+ import * as Ref from "effect/Ref";
3
+ import * as Schema from "effect/Schema";
4
+ import * as Stream from "effect/Stream";
5
+ import { TokenUsage } from "@llm4ts/core/Models";
6
+ import { estimateCostUsd } from "./PriceList.js";
7
+ export class BenchTokens extends Schema.Class("BenchTokens")({
8
+ prompt: Schema.Int,
9
+ completion: Schema.Int,
10
+ cached: Schema.Int
11
+ }) {
12
+ get total() {
13
+ return this.prompt + this.completion;
14
+ }
15
+ add(that) {
16
+ return new BenchTokens({
17
+ prompt: this.prompt + that.prompt,
18
+ completion: this.completion + that.completion,
19
+ cached: this.cached + that.cached
20
+ });
21
+ }
22
+ }
23
+ export const emptyBenchTokens = () => BenchTokens.make({ prompt: 0, completion: 0, cached: 0 });
24
+ export const benchTokensFromUsage = (usage) => BenchTokens.make({
25
+ prompt: usage.prompt,
26
+ completion: usage.completion,
27
+ cached: usage.cached ?? 0
28
+ });
29
+ export class BenchCounters extends Schema.Class("BenchCounters")({
30
+ flakyRetries: Schema.Int,
31
+ transientRetries: Schema.Int,
32
+ autoResumes: Schema.Int,
33
+ turnLimitTrips: Schema.Int,
34
+ shrinks: Schema.Int
35
+ }) {
36
+ get selfHealing() {
37
+ return this.flakyRetries + this.transientRetries + this.autoResumes + this.shrinks;
38
+ }
39
+ }
40
+ export const emptyBenchCounters = () => BenchCounters.make({
41
+ flakyRetries: 0,
42
+ transientRetries: 0,
43
+ autoResumes: 0,
44
+ turnLimitTrips: 0,
45
+ shrinks: 0
46
+ });
47
+ export class BenchPhase extends Schema.Class("BenchPhase")({
48
+ name: Schema.String,
49
+ ms: Schema.Int,
50
+ tokens: BenchTokens,
51
+ costUsd: Schema.optionalKey(Schema.Number),
52
+ counters: BenchCounters,
53
+ detail: Schema.Record(Schema.String, Schema.String)
54
+ }) {
55
+ }
56
+ export class BenchScore extends Schema.Class("BenchScore")({
57
+ name: Schema.String,
58
+ score: Schema.Int,
59
+ max: Schema.Int,
60
+ reasoning: Schema.String
61
+ }) {
62
+ }
63
+ export class BenchJudge extends Schema.Class("BenchJudge")({
64
+ provider: Schema.String,
65
+ model: Schema.String,
66
+ fixed: Schema.Boolean
67
+ }) {
68
+ }
69
+ export class BenchMachine extends Schema.Class("BenchMachine")({
70
+ hostname: Schema.String,
71
+ os: Schema.String,
72
+ arch: Schema.String,
73
+ cores: Schema.Int,
74
+ memoryGb: Schema.Number,
75
+ runtime: Schema.String
76
+ }) {
77
+ }
78
+ export class BenchQuality extends Schema.Class("BenchQuality")({
79
+ buildPassed: Schema.optionalKey(Schema.Boolean),
80
+ testsRun: Schema.optionalKey(Schema.Int),
81
+ testsFailed: Schema.optionalKey(Schema.Int),
82
+ coveragePct: Schema.optionalKey(Schema.Number),
83
+ featureFiles: Schema.Int,
84
+ scenarios: Schema.Int,
85
+ malformedFeatures: Schema.Int,
86
+ specFiles: Schema.Int,
87
+ programs: Schema.Int,
88
+ sourceFiles: Schema.Int,
89
+ sourceLines: Schema.Int,
90
+ testFiles: Schema.Int,
91
+ testLines: Schema.Int,
92
+ deterministicFindings: Schema.Int,
93
+ judgeFindings: Schema.Int,
94
+ gateCleared: Schema.optionalKey(Schema.Boolean),
95
+ gateRounds: Schema.optionalKey(Schema.Int),
96
+ gateOpenIssues: Schema.optionalKey(Schema.Int),
97
+ judgeScores: Schema.Array(BenchScore)
98
+ }) {
99
+ }
100
+ export class BenchRecord extends Schema.Class("BenchRecord")({
101
+ schemaVersion: Schema.Int,
102
+ runId: Schema.String,
103
+ label: Schema.optionalKey(Schema.String),
104
+ startedAt: Schema.String,
105
+ finishedAt: Schema.String,
106
+ provider: Schema.String,
107
+ modelRequested: Schema.String,
108
+ modelsServed: Schema.Array(Schema.String),
109
+ judge: BenchJudge,
110
+ toolVersion: Schema.optionalKey(Schema.String),
111
+ llm4tsVersion: Schema.String,
112
+ pack: Schema.String,
113
+ fixtureFingerprint: Schema.String,
114
+ machine: BenchMachine,
115
+ outcome: Schema.String,
116
+ resumed: Schema.optionalKey(Schema.Boolean),
117
+ totalMs: Schema.Int,
118
+ phases: Schema.Array(BenchPhase),
119
+ quality: Schema.optionalKey(BenchQuality)
120
+ }) {
121
+ get completed() {
122
+ return this.outcome === "completed";
123
+ }
124
+ get totalTokens() {
125
+ return this.phases.reduce((sum, phase) => sum + phase.tokens.total + phase.tokens.cached, 0);
126
+ }
127
+ get totalCostUsd() {
128
+ const values = this.phases.flatMap((phase) => phase.costUsd === undefined ? [] : [phase.costUsd]);
129
+ return values.length === 0 ? undefined : values.reduce((sum, value) => sum + value, 0);
130
+ }
131
+ get selfHealing() {
132
+ return this.phases.reduce((sum, phase) => sum + phase.counters.selfHealing, 0);
133
+ }
134
+ }
135
+ export const CurrentBenchSchema = 1;
136
+ export const BenchUnstaged = "(none)";
137
+ export const emptyBenchObservation = () => ({
138
+ openStages: [],
139
+ cells: new Map(),
140
+ cellKeys: new Map(),
141
+ counters: new Map(),
142
+ modelsServed: new Set()
143
+ });
144
+ const currentStage = (observation) => observation.openStages[observation.openStages.length - 1] ?? BenchUnstaged;
145
+ const dropFirst = (values, value) => {
146
+ const index = values.indexOf(value);
147
+ return index < 0 ? values : [...values.slice(0, index), ...values.slice(index + 1)];
148
+ };
149
+ const classifyNotice = (message, counters) => {
150
+ if (message.startsWith("⟳ flaky")) {
151
+ return new BenchCounters({
152
+ ...counters,
153
+ flakyRetries: counters.flakyRetries + 1
154
+ });
155
+ }
156
+ if (message.startsWith("⟳ transient")) {
157
+ return new BenchCounters({
158
+ ...counters,
159
+ transientRetries: counters.transientRetries + 1
160
+ });
161
+ }
162
+ if (message.startsWith("↻ auto-resume")) {
163
+ return new BenchCounters({
164
+ ...counters,
165
+ autoResumes: counters.autoResumes + 1
166
+ });
167
+ }
168
+ if (message.includes("turn limit hit")) {
169
+ return new BenchCounters({
170
+ ...counters,
171
+ turnLimitTrips: counters.turnLimitTrips + 1
172
+ });
173
+ }
174
+ if (message.includes("shrinking to")) {
175
+ return new BenchCounters({
176
+ ...counters,
177
+ shrinks: counters.shrinks + 1
178
+ });
179
+ }
180
+ return undefined;
181
+ };
182
+ export const observeBench = (observation, event) => {
183
+ switch (event._tag) {
184
+ case "StageStarted":
185
+ return {
186
+ ...observation,
187
+ openStages: [event.stage, ...observation.openStages]
188
+ };
189
+ case "StageCompleted":
190
+ case "StageFailed":
191
+ return {
192
+ ...observation,
193
+ openStages: dropFirst(observation.openStages, event.stage)
194
+ };
195
+ case "TokensUsed": {
196
+ const stage = currentStage(observation);
197
+ const model = event.model ?? "";
198
+ const key = JSON.stringify([stage, model]);
199
+ const cells = new Map(observation.cells);
200
+ cells.set(key, (cells.get(key) ?? emptyBenchTokens()).add(benchTokensFromUsage(event.usage)));
201
+ return {
202
+ ...observation,
203
+ cells,
204
+ cellKeys: new Map(observation.cellKeys).set(key, [stage, model]),
205
+ modelsServed: event.model === undefined
206
+ ? observation.modelsServed
207
+ : new Set([...observation.modelsServed, event.model])
208
+ };
209
+ }
210
+ case "Info": {
211
+ const stage = currentStage(observation);
212
+ const current = observation.counters.get(stage) ?? emptyBenchCounters();
213
+ const next = classifyNotice(event.message, current);
214
+ return next === undefined
215
+ ? observation
216
+ : {
217
+ ...observation,
218
+ counters: new Map(observation.counters).set(stage, next)
219
+ };
220
+ }
221
+ default:
222
+ return observation;
223
+ }
224
+ };
225
+ export const stageBenchTokens = (observation, stage) => [...observation.cells.entries()].reduce((total, [key, tokens]) => {
226
+ const parts = observation.cellKeys.get(key);
227
+ return parts?.[0] === stage ? total.add(tokens) : total;
228
+ }, emptyBenchTokens());
229
+ export const stageBenchCounters = (observation, stage) => observation.counters.get(stage) ?? emptyBenchCounters();
230
+ export const makeBenchPhase = (observation, stage, ms, detail = {}) => {
231
+ const costs = [...observation.cells.entries()].flatMap(([key, tokens]) => {
232
+ const parts = observation.cellKeys.get(key);
233
+ if (parts?.[0] !== stage) {
234
+ return [];
235
+ }
236
+ const cost = estimateCostUsd(parts[1], TokenUsage.make({
237
+ prompt: tokens.prompt,
238
+ completion: tokens.completion,
239
+ total: tokens.total,
240
+ ...(tokens.cached <= 0 ? {} : { cached: tokens.cached })
241
+ }));
242
+ return cost === undefined ? [] : [cost];
243
+ });
244
+ return BenchPhase.make({
245
+ name: stage,
246
+ ms,
247
+ tokens: stageBenchTokens(observation, stage),
248
+ counters: stageBenchCounters(observation, stage),
249
+ detail,
250
+ ...(costs.length === 0 ? {} : { costUsd: costs.reduce((sum, cost) => sum + cost, 0) })
251
+ });
252
+ };
253
+ const isHub = (events) => "subscribe" in events && "publishedCount" in events && "stream" in events;
254
+ export const makeBenchTap = Effect.fn("@llm4ts/flow/Bench.makeTap")(function* (events) {
255
+ const observation = yield* Ref.make(emptyBenchObservation());
256
+ const consumed = yield* Ref.make(0);
257
+ if (!isHub(events)) {
258
+ return {
259
+ get: Ref.get(observation),
260
+ reset: Ref.set(observation, emptyBenchObservation())
261
+ };
262
+ }
263
+ const subscription = yield* events.subscribe;
264
+ const baseline = yield* events.publishedCount;
265
+ yield* Stream.fromSubscription(subscription).pipe(Stream.runForEach((event) => Ref.update(observation, (current) => observeBench(current, event)).pipe(Effect.andThen(Ref.update(consumed, (count) => count + 1)))), Effect.forkScoped);
266
+ const drain = Effect.suspend(() => Effect.all([events.publishedCount, Ref.get(consumed)]).pipe(Effect.flatMap(([published, seen]) => seen >= published - baseline ? Effect.void : Effect.yieldNow.pipe(Effect.andThen(drain)))));
267
+ return {
268
+ get: drain.pipe(Effect.andThen(Ref.get(observation))),
269
+ reset: drain.pipe(Effect.andThen(Ref.set(observation, emptyBenchObservation())))
270
+ };
271
+ });
272
+ //# sourceMappingURL=Bench.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Bench.js","sourceRoot":"","sources":["../src/Bench.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AACvC,OAAO,KAAK,GAAG,MAAM,YAAY,CAAA;AACjC,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AAEvC,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AACvC,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAA;AAEhD,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAA;AAEhD,MAAM,OAAO,WAAY,SAAQ,MAAM,CAAC,KAAK,CAAc,aAAa,CAAC,CAAC;IACxE,MAAM,EAAE,MAAM,CAAC,GAAG;IAClB,UAAU,EAAE,MAAM,CAAC,GAAG;IACtB,MAAM,EAAE,MAAM,CAAC,GAAG;CACnB,CAAC;IACA,IAAI,KAAK;QACP,OAAO,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,UAAU,CAAA;IACtC,CAAC;IAED,GAAG,CAAC,IAAiB;QACnB,OAAO,IAAI,WAAW,CAAC;YACrB,MAAM,EAAE,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM;YACjC,UAAU,EAAE,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,UAAU;YAC7C,MAAM,EAAE,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM;SAClC,CAAC,CAAA;IACJ,CAAC;CACF;AAED,MAAM,CAAC,MAAM,gBAAgB,GAAG,GAAgB,EAAE,CAChD,WAAW,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC,CAAA;AAE3D,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAAC,KAAiB,EAAe,EAAE,CACrE,WAAW,CAAC,IAAI,CAAC;IACf,MAAM,EAAE,KAAK,CAAC,MAAM;IACpB,UAAU,EAAE,KAAK,CAAC,UAAU;IAC5B,MAAM,EAAE,KAAK,CAAC,MAAM,IAAI,CAAC;CAC1B,CAAC,CAAA;AAEJ,MAAM,OAAO,aAAc,SAAQ,MAAM,CAAC,KAAK,CAAgB,eAAe,CAAC,CAAC;IAC9E,YAAY,EAAE,MAAM,CAAC,GAAG;IACxB,gBAAgB,EAAE,MAAM,CAAC,GAAG;IAC5B,WAAW,EAAE,MAAM,CAAC,GAAG;IACvB,cAAc,EAAE,MAAM,CAAC,GAAG;IAC1B,OAAO,EAAE,MAAM,CAAC,GAAG;CACpB,CAAC;IACA,IAAI,WAAW;QACb,OAAO,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC,gBAAgB,GAAG,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,OAAO,CAAA;IACpF,CAAC;CACF;AAED,MAAM,CAAC,MAAM,kBAAkB,GAAG,GAAkB,EAAE,CACpD,aAAa,CAAC,IAAI,CAAC;IACjB,YAAY,EAAE,CAAC;IACf,gBAAgB,EAAE,CAAC;IACnB,WAAW,EAAE,CAAC;IACd,cAAc,EAAE,CAAC;IACjB,OAAO,EAAE,CAAC;CACX,CAAC,CAAA;AAEJ,MAAM,OAAO,UAAW,SAAQ,MAAM,CAAC,KAAK,CAAa,YAAY,CAAC,CAAC;IACrE,IAAI,EAAE,MAAM,CAAC,MAAM;IACnB,EAAE,EAAE,MAAM,CAAC,GAAG;IACd,MAAM,EAAE,WAAW;IACnB,OAAO,EAAE,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,MAAM,CAAC;IAC1C,QAAQ,EAAE,aAAa;IACvB,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC;CACpD,CAAC;CAAG;AAEL,MAAM,OAAO,UAAW,SAAQ,MAAM,CAAC,KAAK,CAAa,YAAY,CAAC,CAAC;IACrE,IAAI,EAAE,MAAM,CAAC,MAAM;IACnB,KAAK,EAAE,MAAM,CAAC,GAAG;IACjB,GAAG,EAAE,MAAM,CAAC,GAAG;IACf,SAAS,EAAE,MAAM,CAAC,MAAM;CACzB,CAAC;CAAG;AAEL,MAAM,OAAO,UAAW,SAAQ,MAAM,CAAC,KAAK,CAAa,YAAY,CAAC,CAAC;IACrE,QAAQ,EAAE,MAAM,CAAC,MAAM;IACvB,KAAK,EAAE,MAAM,CAAC,MAAM;IACpB,KAAK,EAAE,MAAM,CAAC,OAAO;CACtB,CAAC;CAAG;AAEL,MAAM,OAAO,YAAa,SAAQ,MAAM,CAAC,KAAK,CAAe,cAAc,CAAC,CAAC;IAC3E,QAAQ,EAAE,MAAM,CAAC,MAAM;IACvB,EAAE,EAAE,MAAM,CAAC,MAAM;IACjB,IAAI,EAAE,MAAM,CAAC,MAAM;IACnB,KAAK,EAAE,MAAM,CAAC,GAAG;IACjB,QAAQ,EAAE,MAAM,CAAC,MAAM;IACvB,OAAO,EAAE,MAAM,CAAC,MAAM;CACvB,CAAC;CAAG;AAEL,MAAM,OAAO,YAAa,SAAQ,MAAM,CAAC,KAAK,CAAe,cAAc,CAAC,CAAC;IAC3E,WAAW,EAAE,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,OAAO,CAAC;IAC/C,QAAQ,EAAE,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,GAAG,CAAC;IACxC,WAAW,EAAE,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,GAAG,CAAC;IAC3C,WAAW,EAAE,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,MAAM,CAAC;IAC9C,YAAY,EAAE,MAAM,CAAC,GAAG;IACxB,SAAS,EAAE,MAAM,CAAC,GAAG;IACrB,iBAAiB,EAAE,MAAM,CAAC,GAAG;IAC7B,SAAS,EAAE,MAAM,CAAC,GAAG;IACrB,QAAQ,EAAE,MAAM,CAAC,GAAG;IACpB,WAAW,EAAE,MAAM,CAAC,GAAG;IACvB,WAAW,EAAE,MAAM,CAAC,GAAG;IACvB,SAAS,EAAE,MAAM,CAAC,GAAG;IACrB,SAAS,EAAE,MAAM,CAAC,GAAG;IACrB,qBAAqB,EAAE,MAAM,CAAC,GAAG;IACjC,aAAa,EAAE,MAAM,CAAC,GAAG;IACzB,WAAW,EAAE,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,OAAO,CAAC;IAC/C,UAAU,EAAE,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,GAAG,CAAC;IAC1C,cAAc,EAAE,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,GAAG,CAAC;IAC9C,WAAW,EAAE,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC;CACtC,CAAC;CAAG;AAEL,MAAM,OAAO,WAAY,SAAQ,MAAM,CAAC,KAAK,CAAc,aAAa,CAAC,CAAC;IACxE,aAAa,EAAE,MAAM,CAAC,GAAG;IACzB,KAAK,EAAE,MAAM,CAAC,MAAM;IACpB,KAAK,EAAE,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,MAAM,CAAC;IACxC,SAAS,EAAE,MAAM,CAAC,MAAM;IACxB,UAAU,EAAE,MAAM,CAAC,MAAM;IACzB,QAAQ,EAAE,MAAM,CAAC,MAAM;IACvB,cAAc,EAAE,MAAM,CAAC,MAAM;IAC7B,YAAY,EAAE,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC;IACzC,KAAK,EAAE,UAAU;IACjB,WAAW,EAAE,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,MAAM,CAAC;IAC9C,aAAa,EAAE,MAAM,CAAC,MAAM;IAC5B,IAAI,EAAE,MAAM,CAAC,MAAM;IACnB,kBAAkB,EAAE,MAAM,CAAC,MAAM;IACjC,OAAO,EAAE,YAAY;IACrB,OAAO,EAAE,MAAM,CAAC,MAAM;IACtB,OAAO,EAAE,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,OAAO,CAAC;IAC3C,OAAO,EAAE,MAAM,CAAC,GAAG;IACnB,MAAM,EAAE,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC;IAChC,OAAO,EAAE,MAAM,CAAC,WAAW,CAAC,YAAY,CAAC;CAC1C,CAAC;IACA,IAAI,SAAS;QACX,OAAO,IAAI,CAAC,OAAO,KAAK,WAAW,CAAA;IACrC,CAAC;IAED,IAAI,WAAW;QACb,OAAO,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,KAAK,EAAE,EAAE,CAAC,GAAG,GAAG,KAAK,CAAC,MAAM,CAAC,KAAK,GAAG,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,CAAA;IAC9F,CAAC;IAED,IAAI,YAAY;QACd,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,EAAE,CAC3C,KAAK,CAAC,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CACnD,CAAA;QACD,OAAO,MAAM,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,KAAK,EAAE,EAAE,CAAC,GAAG,GAAG,KAAK,EAAE,CAAC,CAAC,CAAA;IACxF,CAAC;IAED,IAAI,WAAW;QACb,OAAO,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,KAAK,EAAE,EAAE,CAAC,GAAG,GAAG,KAAK,CAAC,QAAQ,CAAC,WAAW,EAAE,CAAC,CAAC,CAAA;IAChF,CAAC;CACF;AAED,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,CAAA;AACnC,MAAM,CAAC,MAAM,aAAa,GAAG,QAAQ,CAAA;AAUrC,MAAM,CAAC,MAAM,qBAAqB,GAAG,GAAqB,EAAE,CAAC,CAAC;IAC5D,UAAU,EAAE,EAAE;IACd,KAAK,EAAE,IAAI,GAAG,EAAE;IAChB,QAAQ,EAAE,IAAI,GAAG,EAAE;IACnB,QAAQ,EAAE,IAAI,GAAG,EAAE;IACnB,YAAY,EAAE,IAAI,GAAG,EAAE;CACxB,CAAC,CAAA;AAEF,MAAM,YAAY,GAAG,CAAC,WAA6B,EAAU,EAAE,CAC7D,WAAW,CAAC,UAAU,CAAC,WAAW,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC,CAAC,IAAI,aAAa,CAAA;AAE5E,MAAM,SAAS,GAAG,CAAC,MAA6B,EAAE,KAAa,EAAyB,EAAE;IACxF,MAAM,KAAK,GAAG,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAA;IACnC,OAAO,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,EAAE,GAAG,MAAM,CAAC,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,CAAA;AACrF,CAAC,CAAA;AAED,MAAM,cAAc,GAAG,CAAC,OAAe,EAAE,QAAuB,EAA6B,EAAE;IAC7F,IAAI,OAAO,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;QAClC,OAAO,IAAI,aAAa,CAAC;YACvB,GAAG,QAAQ;YACX,YAAY,EAAE,QAAQ,CAAC,YAAY,GAAG,CAAC;SACxC,CAAC,CAAA;IACJ,CAAC;IACD,IAAI,OAAO,CAAC,UAAU,CAAC,aAAa,CAAC,EAAE,CAAC;QACtC,OAAO,IAAI,aAAa,CAAC;YACvB,GAAG,QAAQ;YACX,gBAAgB,EAAE,QAAQ,CAAC,gBAAgB,GAAG,CAAC;SAChD,CAAC,CAAA;IACJ,CAAC;IACD,IAAI,OAAO,CAAC,UAAU,CAAC,eAAe,CAAC,EAAE,CAAC;QACxC,OAAO,IAAI,aAAa,CAAC;YACvB,GAAG,QAAQ;YACX,WAAW,EAAE,QAAQ,CAAC,WAAW,GAAG,CAAC;SACtC,CAAC,CAAA;IACJ,CAAC;IACD,IAAI,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAC,EAAE,CAAC;QACvC,OAAO,IAAI,aAAa,CAAC;YACvB,GAAG,QAAQ;YACX,cAAc,EAAE,QAAQ,CAAC,cAAc,GAAG,CAAC;SAC5C,CAAC,CAAA;IACJ,CAAC;IACD,IAAI,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAC,EAAE,CAAC;QACrC,OAAO,IAAI,aAAa,CAAC;YACvB,GAAG,QAAQ;YACX,OAAO,EAAE,QAAQ,CAAC,OAAO,GAAG,CAAC;SAC9B,CAAC,CAAA;IACJ,CAAC;IACD,OAAO,SAAS,CAAA;AAClB,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,WAA6B,EAAE,KAAgB,EAAoB,EAAE;IAChG,QAAQ,KAAK,CAAC,IAAI,EAAE,CAAC;QACnB,KAAK,cAAc;YACjB,OAAO;gBACL,GAAG,WAAW;gBACd,UAAU,EAAE,CAAC,KAAK,CAAC,KAAK,EAAE,GAAG,WAAW,CAAC,UAAU,CAAC;aACrD,CAAA;QACH,KAAK,gBAAgB,CAAC;QACtB,KAAK,aAAa;YAChB,OAAO;gBACL,GAAG,WAAW;gBACd,UAAU,EAAE,SAAS,CAAC,WAAW,CAAC,UAAU,EAAE,KAAK,CAAC,KAAK,CAAC;aAC3D,CAAA;QACH,KAAK,YAAY,CAAC,CAAC,CAAC;YAClB,MAAM,KAAK,GAAG,YAAY,CAAC,WAAW,CAAC,CAAA;YACvC,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,IAAI,EAAE,CAAA;YAC/B,MAAM,GAAG,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,CAAA;YAC1C,MAAM,KAAK,GAAG,IAAI,GAAG,CAAC,WAAW,CAAC,KAAK,CAAC,CAAA;YACxC,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,gBAAgB,EAAE,CAAC,CAAC,GAAG,CAAC,oBAAoB,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA;YAC7F,OAAO;gBACL,GAAG,WAAW;gBACd,KAAK;gBACL,QAAQ,EAAE,IAAI,GAAG,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;gBAChE,YAAY,EACV,KAAK,CAAC,KAAK,KAAK,SAAS;oBACvB,CAAC,CAAC,WAAW,CAAC,YAAY;oBAC1B,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,GAAG,WAAW,CAAC,YAAY,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC;aAC1D,CAAA;QACH,CAAC;QACD,KAAK,MAAM,CAAC,CAAC,CAAC;YACZ,MAAM,KAAK,GAAG,YAAY,CAAC,WAAW,CAAC,CAAA;YACvC,MAAM,OAAO,GAAG,WAAW,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,kBAAkB,EAAE,CAAA;YACvE,MAAM,IAAI,GAAG,cAAc,CAAC,KAAK,CAAC,OAAO,EAAE,OAAO,CAAC,CAAA;YACnD,OAAO,IAAI,KAAK,SAAS;gBACvB,CAAC,CAAC,WAAW;gBACb,CAAC,CAAC;oBACE,GAAG,WAAW;oBACd,QAAQ,EAAE,IAAI,GAAG,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,KAAK,EAAE,IAAI,CAAC;iBACzD,CAAA;QACP,CAAC;QACD;YACE,OAAO,WAAW,CAAA;IACtB,CAAC;AACH,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,WAA6B,EAAE,KAAa,EAAe,EAAE,CAC5F,CAAC,GAAG,WAAW,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,CAAC,GAAG,EAAE,MAAM,CAAC,EAAE,EAAE;IAC/D,MAAM,KAAK,GAAG,WAAW,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;IAC3C,OAAO,KAAK,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,KAAK,CAAA;AACzD,CAAC,EAAE,gBAAgB,EAAE,CAAC,CAAA;AAExB,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,WAA6B,EAAE,KAAa,EAAiB,EAAE,CAChG,WAAW,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,kBAAkB,EAAE,CAAA;AAEzD,MAAM,CAAC,MAAM,cAAc,GAAG,CAC5B,WAA6B,EAC7B,KAAa,EACb,EAAU,EACV,SAA2C,EAAE,EACjC,EAAE;IACd,MAAM,KAAK,GAAG,CAAC,GAAG,WAAW,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,EAAE,MAAM,CAAC,EAAE,EAAE;QACvE,MAAM,KAAK,GAAG,WAAW,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;QAC3C,IAAI,KAAK,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,EAAE,CAAC;YACzB,OAAO,EAAE,CAAA;QACX,CAAC;QACD,MAAM,IAAI,GAAG,eAAe,CAC1B,KAAK,CAAC,CAAC,CAAC,EACR,UAAU,CAAC,IAAI,CAAC;YACd,MAAM,EAAE,MAAM,CAAC,MAAM;YACrB,UAAU,EAAE,MAAM,CAAC,UAAU;YAC7B,KAAK,EAAE,MAAM,CAAC,KAAK;YACnB,GAAG,CAAC,MAAM,CAAC,MAAM,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC;SACzD,CAAC,CACH,CAAA;QACD,OAAO,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAA;IACzC,CAAC,CAAC,CAAA;IACF,OAAO,UAAU,CAAC,IAAI,CAAC;QACrB,IAAI,EAAE,KAAK;QACX,EAAE;QACF,MAAM,EAAE,gBAAgB,CAAC,WAAW,EAAE,KAAK,CAAC;QAC5C,QAAQ,EAAE,kBAAkB,CAAC,WAAW,EAAE,KAAK,CAAC;QAChD,MAAM;QACN,GAAG,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE,CAAC,GAAG,GAAG,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;KACvF,CAAC,CAAA;AACJ,CAAC,CAAA;AAED,MAAM,KAAK,GAAG,CAAC,MAAuB,EAA0B,EAAE,CAChE,WAAW,IAAI,MAAM,IAAI,gBAAgB,IAAI,MAAM,IAAI,QAAQ,IAAI,MAAM,CAAA;AAO3E,MAAM,CAAC,MAAM,YAAY,GAAG,MAAM,CAAC,EAAE,CAAC,4BAA4B,CAAC,CAAC,QAAQ,CAAC,EAC3E,MAAuB;IAEvB,MAAM,WAAW,GAAG,KAAK,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,qBAAqB,EAAE,CAAC,CAAA;IAC5D,MAAM,QAAQ,GAAG,KAAK,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;IACnC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC;QACnB,OAAO;YACL,GAAG,EAAE,GAAG,CAAC,GAAG,CAAC,WAAW,CAAC;YACzB,KAAK,EAAE,GAAG,CAAC,GAAG,CAAC,WAAW,EAAE,qBAAqB,EAAE,CAAC;SACrD,CAAA;IACH,CAAC;IACD,MAAM,YAAY,GAAG,KAAK,CAAC,CAAC,MAAM,CAAC,SAAS,CAAA;IAC5C,MAAM,QAAQ,GAAG,KAAK,CAAC,CAAC,MAAM,CAAC,cAAc,CAAA;IAC7C,KAAK,CAAC,CAAC,MAAM,CAAC,gBAAgB,CAAC,YAAY,CAAC,CAAC,IAAI,CAC/C,MAAM,CAAC,UAAU,CAAC,CAAC,KAAK,EAAE,EAAE,CAC1B,GAAG,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,YAAY,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC,CAAC,IAAI,CACrE,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,CAC3D,CACF,EACD,MAAM,CAAC,UAAU,CAClB,CAAA;IACD,MAAM,KAAK,GAAwB,MAAM,CAAC,OAAO,CAAC,GAAG,EAAE,CACrD,MAAM,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,cAAc,EAAE,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI,CACzD,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,EAAE,IAAI,CAAC,EAAE,EAAE,CACnC,IAAI,IAAI,SAAS,GAAG,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CACzF,CACF,CACF,CAAA;IACD,OAAO;QACL,GAAG,EAAE,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC;QACrD,KAAK,EAAE,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,WAAW,EAAE,qBAAqB,EAAE,CAAC,CAAC,CAAC;KACjF,CAAA;AACH,CAAC,CAAC,CAAA"}
@@ -0,0 +1,9 @@
1
+ import * as Effect from "effect/Effect";
2
+ import { BenchRecord } from "./Bench.ts";
3
+ import { PlanParseError, UnsupportedSchemaVersion } from "./FlowError.ts";
4
+ import type { PlainFileStoreShape } from "./Persistence.ts";
5
+ export declare const median: (values: ReadonlyArray<number>) => number;
6
+ export declare const renderBenchReport: (records: ReadonlyArray<BenchRecord>, projectPrograms?: number) => string;
7
+ export declare const appendBenchRecord: (files: PlainFileStoreShape, path: string, record: BenchRecord) => Effect.Effect<void, import("./FlowError.ts").PersistenceError | PlanParseError | UnsupportedSchemaVersion | import("./FlowError.ts").WorkspacePathError | import("./FlowError.ts").WorkspaceLimitError | import("./FlowError.ts").WorkspaceIoError | import("./FlowError.ts").FlowAborted | import("./FlowError.ts").ProcessError | import("./FlowError.ts").FlowLlmError | import("./FlowError.ts").FlowCapabilityDenied | import("./FlowError.ts").BudgetExceeded, never>;
8
+ export declare const loadBenchRecords: (files: PlainFileStoreShape, path: string) => Effect.Effect<readonly BenchRecord[], import("./FlowError.ts").PersistenceError | PlanParseError | UnsupportedSchemaVersion | import("./FlowError.ts").WorkspacePathError | import("./FlowError.ts").WorkspaceLimitError | import("./FlowError.ts").WorkspaceIoError | import("./FlowError.ts").FlowAborted | import("./FlowError.ts").ProcessError | import("./FlowError.ts").FlowLlmError | import("./FlowError.ts").FlowCapabilityDenied | import("./FlowError.ts").BudgetExceeded, never>;
9
+ //# sourceMappingURL=BenchReport.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BenchReport.d.ts","sourceRoot":"","sources":["../src/BenchReport.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AAEvC,OAAO,EAAE,WAAW,EAAuC,MAAM,YAAY,CAAA;AAC7E,OAAO,EAAE,cAAc,EAAE,wBAAwB,EAAkB,MAAM,gBAAgB,CAAA;AACzF,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAA;AAI3D,eAAO,MAAM,MAAM,GAAI,QAAQ,aAAa,CAAC,MAAM,CAAC,KAAG,MAStD,CAAA;AA4WD,eAAO,MAAM,iBAAiB,GAC5B,SAAS,aAAa,CAAC,WAAW,CAAC,EACnC,kBAAkB,MAAM,KACvB,MAUF,CAAA;AAID,eAAO,MAAM,iBAAiB,ghBAa5B,CAAA;AAEF,eAAO,MAAM,gBAAgB,6gBAiC3B,CAAA"}
@@ -0,0 +1,360 @@
1
+ import * as Effect from "effect/Effect";
2
+ import * as Schema from "effect/Schema";
3
+ import { BenchRecord, CurrentBenchSchema } from "./Bench.js";
4
+ import { PlanParseError, UnsupportedSchemaVersion } from "./FlowError.js";
5
+ import { estimateCostUsd } from "./PriceList.js";
6
+ import { TokenUsage } from "@llm4ts/core/Models";
7
+ export const median = (values) => {
8
+ if (values.length === 0) {
9
+ return 0;
10
+ }
11
+ const sorted = [...values].sort((left, right) => left - right);
12
+ const middle = Math.floor(sorted.length / 2);
13
+ return sorted.length % 2 === 1
14
+ ? (sorted[middle] ?? 0)
15
+ : ((sorted[middle - 1] ?? 0) + (sorted[middle] ?? 0)) / 2;
16
+ };
17
+ const formatDuration = (milliseconds) => {
18
+ if (milliseconds >= 3_600_000) {
19
+ return `${(milliseconds / 3_600_000).toFixed(1)}h`;
20
+ }
21
+ if (milliseconds >= 60_000) {
22
+ return `${(milliseconds / 60_000).toFixed(1)}m`;
23
+ }
24
+ return `${(milliseconds / 1_000).toFixed(1)}s`;
25
+ };
26
+ const formatTokens = (tokens) => {
27
+ if (Math.abs(tokens) >= 1_000_000) {
28
+ return `${(tokens / 1_000_000).toFixed(1)}M`;
29
+ }
30
+ if (Math.abs(tokens) >= 1_000) {
31
+ return `${(tokens / 1_000).toFixed(1)}k`;
32
+ }
33
+ return Math.round(tokens).toString();
34
+ };
35
+ const formatInteger = (value) => Math.round(value).toString();
36
+ const formatPercent = (value) => `${value.toFixed(1)}%`;
37
+ const formatBoolean = (value) => (value >= 0.5 ? "yes" : "no");
38
+ const spread = (records, metric) => {
39
+ const values = records.flatMap((record) => {
40
+ const value = metric.value(record);
41
+ return value === undefined ? [] : [value];
42
+ });
43
+ if (values.length === 0) {
44
+ return "–";
45
+ }
46
+ const center = median(values);
47
+ const base = metric.format(center);
48
+ return values.length > 1 && Math.min(...values) !== Math.max(...values)
49
+ ? `${base} (${metric.format(Math.min(...values))}–${metric.format(Math.max(...values))})`
50
+ : base;
51
+ };
52
+ const judgePercent = (record) => {
53
+ const scores = record.quality?.judgeScores ?? [];
54
+ const maximum = scores.reduce((sum, score) => sum + score.max, 0);
55
+ return maximum <= 0
56
+ ? undefined
57
+ : (scores.reduce((sum, score) => sum + score.score, 0) / maximum) * 100;
58
+ };
59
+ const totalOutputTokens = (record) => record.phases.reduce((sum, phase) => sum + phase.tokens.completion, 0);
60
+ const totalCachedTokens = (record) => record.phases.reduce((sum, phase) => sum + phase.tokens.cached, 0);
61
+ const headlineMetrics = (judgesComparable) => [
62
+ {
63
+ label: "Total time",
64
+ direction: "lower",
65
+ value: (record) => record.totalMs,
66
+ format: formatDuration
67
+ },
68
+ {
69
+ label: "Total tokens",
70
+ direction: "lower",
71
+ value: (record) => record.totalTokens,
72
+ format: formatTokens
73
+ },
74
+ {
75
+ label: "Output tokens",
76
+ direction: "lower",
77
+ value: totalOutputTokens,
78
+ format: formatTokens
79
+ },
80
+ {
81
+ label: "Cached reads",
82
+ direction: "neutral",
83
+ value: totalCachedTokens,
84
+ format: formatTokens
85
+ },
86
+ {
87
+ label: "Self-healing actions",
88
+ direction: "lower",
89
+ value: (record) => record.selfHealing,
90
+ format: formatInteger
91
+ },
92
+ {
93
+ label: "Gate cleared",
94
+ direction: "higher",
95
+ value: (record) => record.quality?.gateCleared === undefined ? undefined : record.quality.gateCleared ? 1 : 0,
96
+ format: formatBoolean,
97
+ gap: formatInteger
98
+ },
99
+ {
100
+ label: "Build passed",
101
+ direction: "higher",
102
+ value: (record) => record.quality?.buildPassed === undefined ? undefined : record.quality.buildPassed ? 1 : 0,
103
+ format: formatBoolean,
104
+ gap: formatInteger
105
+ },
106
+ {
107
+ label: "Coverage %",
108
+ direction: "higher",
109
+ value: (record) => record.quality?.coveragePct,
110
+ format: formatPercent
111
+ },
112
+ {
113
+ label: "Judge score",
114
+ direction: judgesComparable ? "higher" : "neutral",
115
+ value: judgePercent,
116
+ format: formatPercent
117
+ }
118
+ ];
119
+ const gapCell = (metric, values) => {
120
+ if (values.length < 2) {
121
+ return "";
122
+ }
123
+ const low = Math.min(...values);
124
+ const high = Math.max(...values);
125
+ const difference = high - low;
126
+ const percent = low === 0 ? 100 : (difference / Math.abs(low)) * 100;
127
+ return `+${(metric.gap ?? metric.format)(difference)} (+${percent.toFixed(1)}%)`;
128
+ };
129
+ const metricRow = (metric, providers, byProvider) => {
130
+ const centers = providers.map((provider) => {
131
+ const values = (byProvider.get(provider) ?? []).flatMap((record) => {
132
+ const value = metric.value(record);
133
+ return value === undefined ? [] : [value];
134
+ });
135
+ return values.length === 0 ? undefined : median(values);
136
+ });
137
+ const comparable = centers.filter((value) => value !== undefined);
138
+ const best = metric.direction === "neutral" || comparable.length < 2
139
+ ? undefined
140
+ : metric.direction === "lower"
141
+ ? Math.min(...comparable)
142
+ : Math.max(...comparable);
143
+ const worst = metric.direction === "neutral" || comparable.length < 2
144
+ ? undefined
145
+ : metric.direction === "lower"
146
+ ? Math.max(...comparable)
147
+ : Math.min(...comparable);
148
+ const cells = providers.map((provider, index) => {
149
+ const value = centers[index];
150
+ const display = spread(byProvider.get(provider) ?? [], metric);
151
+ if (value === undefined || best === undefined || best === worst) {
152
+ return display;
153
+ }
154
+ return value === best ? `**${display} ✅**` : value === worst ? `${display} ⚠️` : display;
155
+ });
156
+ return `| ${metric.label} | ${cells.join(" | ")} | ${gapCell(metric, comparable)} |`;
157
+ };
158
+ const costForPhase = (record, phase) => {
159
+ if (phase.costUsd !== undefined) {
160
+ return [phase.costUsd, false];
161
+ }
162
+ if (phase.tokens.prompt === 0 && phase.tokens.completion === 0 && phase.tokens.cached === 0) {
163
+ return undefined;
164
+ }
165
+ const cost = estimateCostUsd(record.modelRequested, TokenUsage.make({
166
+ prompt: phase.tokens.prompt,
167
+ completion: phase.tokens.completion,
168
+ total: phase.tokens.total,
169
+ ...(phase.tokens.cached <= 0 ? {} : { cached: phase.tokens.cached })
170
+ }));
171
+ return cost === undefined ? undefined : [cost, true];
172
+ };
173
+ const costForRecord = (record) => {
174
+ const values = record.phases.flatMap((phase) => {
175
+ const cost = costForPhase(record, phase);
176
+ return cost === undefined ? [] : [cost];
177
+ });
178
+ return values.length === 0
179
+ ? undefined
180
+ : [values.reduce((sum, [cost]) => sum + cost, 0), values.some(([, estimated]) => estimated)];
181
+ };
182
+ const costRow = (providers, byProvider, select) => {
183
+ const cells = providers.map((provider) => {
184
+ const values = (byProvider.get(provider) ?? []).flatMap((record) => {
185
+ const value = select(record);
186
+ return value === undefined ? [] : [value];
187
+ });
188
+ if (values.length === 0) {
189
+ return "–";
190
+ }
191
+ const suffix = values.some(([, estimated]) => estimated) ? "*" : "";
192
+ const costs = values.map(([cost]) => cost);
193
+ return `$${median(costs).toFixed(2)}${suffix}`;
194
+ });
195
+ return `| Est. cost (USD) | ${cells.join(" | ")} | |`;
196
+ };
197
+ const projection = (programs, providers, byProvider) => {
198
+ const rows = providers.map((provider) => {
199
+ const records = byProvider.get(provider) ?? [];
200
+ const perProgramTokens = records.flatMap((record) => {
201
+ const count = record.quality?.programs ?? 0;
202
+ return count <= 0 ? [] : [record.totalTokens / count];
203
+ });
204
+ const perProgramMs = records.flatMap((record) => {
205
+ const count = record.quality?.programs ?? 0;
206
+ return count <= 0 ? [] : [record.totalMs / count];
207
+ });
208
+ if (perProgramTokens.length === 0 || perProgramMs.length === 0) {
209
+ return `| ${provider} | – | – | – |`;
210
+ }
211
+ const tokens = median(perProgramTokens);
212
+ const milliseconds = median(perProgramMs);
213
+ return `| ${provider} | ${formatTokens(tokens)} | ${formatTokens(tokens * programs)} | ${formatDuration(milliseconds * programs)} |`;
214
+ });
215
+ return [
216
+ `## Projection @ ${programs} programs`,
217
+ "",
218
+ "| Provider | Tokens/program | Projected tokens | Projected time |",
219
+ "| -------- | -------------- | ---------------- | -------------- |",
220
+ ...rows,
221
+ "",
222
+ "_Linear extrapolation from recorded medians; not a delivery forecast._"
223
+ ].join("\n");
224
+ };
225
+ const renderSection = (records, projectPrograms) => {
226
+ const providers = [...new Set(records.map((record) => record.provider))].sort();
227
+ const byProvider = new Map(providers.map((provider) => [
228
+ provider,
229
+ records.filter((record) => record.provider === provider)
230
+ ]));
231
+ const first = records[0];
232
+ if (first === undefined) {
233
+ return "";
234
+ }
235
+ const judgesComparable = new Set(records.map((record) => `${record.judge.provider}\0${record.judge.model}`)).size === 1;
236
+ const judgeLine = judgesComparable
237
+ ? `Judge: ${first.judge.provider}/${first.judge.model} — same examiner for all runs`
238
+ : "Judges: self-graded — scores NOT cross-comparable";
239
+ const header = `| Metric | ${providers.join(" | ")} | Gap |`;
240
+ const separator = `| ------ | ${providers.map(() => "------").join(" | ")} | --- |`;
241
+ const outcomes = `| Outcome | ${providers
242
+ .map((provider) => {
243
+ const group = byProvider.get(provider) ?? [];
244
+ return group.some((record) => record.resumed === true)
245
+ ? `${group[0]?.outcome ?? "unknown"} ♻`
246
+ : (group[0]?.outcome ?? "unknown");
247
+ })
248
+ .join(" | ")} | |`;
249
+ const phaseNames = [
250
+ ...new Set(records.flatMap((record) => record.phases.map((phase) => phase.name)))
251
+ ];
252
+ const phaseSections = phaseNames.map((phaseName) => {
253
+ const duration = {
254
+ label: "Duration",
255
+ direction: "lower",
256
+ value: (record) => record.phases.find((phase) => phase.name === phaseName)?.ms,
257
+ format: formatDuration
258
+ };
259
+ const tokens = {
260
+ label: "Tokens",
261
+ direction: "lower",
262
+ value: (record) => {
263
+ const phase = record.phases.find((item) => item.name === phaseName);
264
+ return phase === undefined ? undefined : phase.tokens.total + phase.tokens.cached;
265
+ },
266
+ format: formatTokens
267
+ };
268
+ return [
269
+ `### ${phaseName}`,
270
+ "",
271
+ header,
272
+ separator,
273
+ metricRow(duration, providers, byProvider),
274
+ metricRow(tokens, providers, byProvider),
275
+ costRow(providers, byProvider, (record) => {
276
+ const phase = record.phases.find((item) => item.name === phaseName);
277
+ return phase === undefined ? undefined : costForPhase(record, phase);
278
+ })
279
+ ].join("\n");
280
+ });
281
+ const failures = records.filter((record) => !record.completed);
282
+ const estimated = records.some((record) => costForRecord(record)?.[1] === true);
283
+ const extras = [
284
+ ...(failures.length === 0
285
+ ? []
286
+ : [
287
+ "## Failures",
288
+ ...failures.map((record) => `- ${record.provider} ${record.runId}: ${record.outcome}`)
289
+ ]),
290
+ ...(projectPrograms === undefined ? [] : [projection(projectPrograms, providers, byProvider)]),
291
+ ...(records.some((record) => record.resumed === true)
292
+ ? [
293
+ "_♻ resumed run: duration and tokens include only work after resume and are not fresh-run comparable._"
294
+ ]
295
+ : []),
296
+ ...(estimated
297
+ ? ["_\\* Cost estimated at report time from recorded tokens × the requested model._"]
298
+ : []),
299
+ `_Machines: ${[...new Set(records.map((record) => record.machine.hostname))].sort().join(", ")}._`
300
+ ];
301
+ return [
302
+ `# Benchmark — ${first.pack} @ ${first.fixtureFingerprint.slice(0, 8)}`,
303
+ "",
304
+ `_${judgeLine}_`,
305
+ "",
306
+ "## Headline",
307
+ "",
308
+ header,
309
+ separator,
310
+ outcomes,
311
+ ...headlineMetrics(judgesComparable).map((metric) => metricRow(metric, providers, byProvider)),
312
+ costRow(providers, byProvider, costForRecord),
313
+ "",
314
+ "## Phases",
315
+ "",
316
+ ...phaseSections,
317
+ ...extras
318
+ ].join("\n");
319
+ };
320
+ export const renderBenchReport = (records, projectPrograms) => {
321
+ const groups = new Map();
322
+ for (const record of records) {
323
+ const key = `${record.pack}\0${record.fixtureFingerprint}`;
324
+ groups.set(key, [...(groups.get(key) ?? []), record]);
325
+ }
326
+ return [...groups.entries()]
327
+ .sort(([left], [right]) => left.localeCompare(right))
328
+ .map(([, group]) => renderSection(group, projectPrograms))
329
+ .join("\n\n");
330
+ };
331
+ const benchCodec = Schema.fromJsonString(BenchRecord);
332
+ export const appendBenchRecord = Effect.fn("@llm4ts/flow/BenchReport.append")(function* (files, path, record) {
333
+ const encoded = yield* Schema.encodeEffect(benchCodec)(record).pipe(Effect.mapError((error) => PlanParseError.make({
334
+ message: `failed to encode benchmark record: ${String(error)}`
335
+ })));
336
+ yield* files.append(path, `${encoded}\n`);
337
+ });
338
+ export const loadBenchRecords = Effect.fn("@llm4ts/flow/BenchReport.load")(function* (files, path) {
339
+ const contents = yield* files.read(path);
340
+ if (contents === undefined) {
341
+ return [];
342
+ }
343
+ const records = yield* Effect.forEach(contents
344
+ .split(/\r?\n/u)
345
+ .map((line) => line.trim())
346
+ .filter((line) => line.length > 0), (line, index) => Schema.decodeUnknownEffect(benchCodec)(line).pipe(Effect.mapError((error) => PlanParseError.make({
347
+ message: `malformed benchmark record at ${path}:${index + 1}: ${String(error)}`
348
+ }))), { concurrency: 1 });
349
+ for (const record of records) {
350
+ if (record.schemaVersion !== CurrentBenchSchema) {
351
+ return yield* UnsupportedSchemaVersion.make({
352
+ path,
353
+ expected: CurrentBenchSchema,
354
+ actual: record.schemaVersion
355
+ });
356
+ }
357
+ }
358
+ return records;
359
+ });
360
+ //# sourceMappingURL=BenchReport.js.map