@mhingston5/lasso 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 (124) hide show
  1. package/README.md +707 -0
  2. package/docs/agent-wrangling.png +0 -0
  3. package/package.json +26 -0
  4. package/src/capabilities/matcher.ts +25 -0
  5. package/src/capabilities/registry.ts +103 -0
  6. package/src/capabilities/types.ts +15 -0
  7. package/src/cir/lower.ts +253 -0
  8. package/src/cir/optimize.ts +251 -0
  9. package/src/cir/types.ts +131 -0
  10. package/src/cir/validate.ts +265 -0
  11. package/src/compiler/compile.ts +601 -0
  12. package/src/compiler/feedback.ts +471 -0
  13. package/src/compiler/runtime-helpers.ts +455 -0
  14. package/src/composition/chain.ts +58 -0
  15. package/src/composition/conditional.ts +76 -0
  16. package/src/composition/parallel.ts +75 -0
  17. package/src/composition/types.ts +105 -0
  18. package/src/environment/analyzer.ts +56 -0
  19. package/src/environment/discovery.ts +179 -0
  20. package/src/environment/types.ts +68 -0
  21. package/src/failures/classifiers.ts +134 -0
  22. package/src/failures/generator.ts +421 -0
  23. package/src/failures/map-reference-failures.ts +23 -0
  24. package/src/failures/ontology.ts +210 -0
  25. package/src/failures/recovery.ts +214 -0
  26. package/src/failures/types.ts +14 -0
  27. package/src/index.ts +67 -0
  28. package/src/memory/advisor.ts +132 -0
  29. package/src/memory/extractor.ts +166 -0
  30. package/src/memory/store.ts +107 -0
  31. package/src/memory/types.ts +53 -0
  32. package/src/metaharness/engine.ts +256 -0
  33. package/src/metaharness/predictor.ts +168 -0
  34. package/src/metaharness/types.ts +40 -0
  35. package/src/mutation/derive.ts +308 -0
  36. package/src/mutation/diff.ts +52 -0
  37. package/src/mutation/engine.ts +256 -0
  38. package/src/mutation/types.ts +84 -0
  39. package/src/pi/command-input.ts +209 -0
  40. package/src/pi/commands.ts +351 -0
  41. package/src/pi/extension.ts +16 -0
  42. package/src/planner/synthesize.ts +83 -0
  43. package/src/planner/template-rules.ts +183 -0
  44. package/src/planner/types.ts +42 -0
  45. package/src/reference/catalog.ts +128 -0
  46. package/src/reference/patch-validation-strategies.ts +170 -0
  47. package/src/reference/patch-validation.ts +174 -0
  48. package/src/reference/pr-review-merge.ts +155 -0
  49. package/src/reference/strategies.ts +126 -0
  50. package/src/reference/types.ts +33 -0
  51. package/src/replanner/risk-rules.ts +161 -0
  52. package/src/replanner/runtime.ts +308 -0
  53. package/src/replanner/synthesize.ts +619 -0
  54. package/src/replanner/types.ts +73 -0
  55. package/src/spec/schema.ts +254 -0
  56. package/src/spec/types.ts +319 -0
  57. package/src/spec/validate.ts +296 -0
  58. package/src/state/snapshots.ts +43 -0
  59. package/src/state/types.ts +12 -0
  60. package/src/synthesis/graph-builder.ts +267 -0
  61. package/src/synthesis/harness-builder.ts +113 -0
  62. package/src/synthesis/intent-ir.ts +63 -0
  63. package/src/synthesis/policy-builder.ts +320 -0
  64. package/src/synthesis/risk-analyzer.ts +182 -0
  65. package/src/synthesis/skill-parser.ts +441 -0
  66. package/src/verification/engine.ts +230 -0
  67. package/src/versioning/file-store.ts +103 -0
  68. package/src/versioning/history.ts +43 -0
  69. package/src/versioning/store.ts +16 -0
  70. package/src/versioning/types.ts +31 -0
  71. package/test/capabilities/matcher.test.ts +67 -0
  72. package/test/capabilities/registry.test.ts +136 -0
  73. package/test/capabilities/synthesis.test.ts +264 -0
  74. package/test/cir/lower.test.ts +417 -0
  75. package/test/cir/optimize.test.ts +266 -0
  76. package/test/cir/validate.test.ts +368 -0
  77. package/test/compiler/adaptive-runtime.test.ts +157 -0
  78. package/test/compiler/compile.test.ts +1198 -0
  79. package/test/compiler/feedback.test.ts +784 -0
  80. package/test/compiler/guardrails.test.ts +191 -0
  81. package/test/compiler/trace.test.ts +404 -0
  82. package/test/composition/chain.test.ts +328 -0
  83. package/test/composition/conditional.test.ts +241 -0
  84. package/test/composition/parallel.test.ts +215 -0
  85. package/test/environment/analyzer.test.ts +204 -0
  86. package/test/environment/discovery.test.ts +149 -0
  87. package/test/failures/classifiers.test.ts +287 -0
  88. package/test/failures/generator.test.ts +203 -0
  89. package/test/failures/ontology.test.ts +439 -0
  90. package/test/failures/recovery.test.ts +300 -0
  91. package/test/helpers/createFixtureRepo.ts +84 -0
  92. package/test/helpers/createPatchValidationFixture.ts +144 -0
  93. package/test/helpers/runCompiledWorkflow.ts +208 -0
  94. package/test/memory/advisor.test.ts +332 -0
  95. package/test/memory/extractor.test.ts +295 -0
  96. package/test/memory/store.test.ts +244 -0
  97. package/test/metaharness/engine.test.ts +575 -0
  98. package/test/metaharness/predictor.test.ts +436 -0
  99. package/test/mutation/derive-failure.test.ts +209 -0
  100. package/test/mutation/engine.test.ts +622 -0
  101. package/test/package-smoke.test.ts +29 -0
  102. package/test/pi/command-input.test.ts +153 -0
  103. package/test/pi/commands.test.ts +623 -0
  104. package/test/planner/classify-template.test.ts +32 -0
  105. package/test/planner/synthesize.test.ts +901 -0
  106. package/test/reference/PatchValidation.failures.test.ts +137 -0
  107. package/test/reference/PatchValidation.test.ts +326 -0
  108. package/test/reference/PrReviewMerge.failures.test.ts +121 -0
  109. package/test/reference/PrReviewMerge.test.ts +55 -0
  110. package/test/reference/catalog-open.test.ts +70 -0
  111. package/test/replanner/runtime.test.ts +207 -0
  112. package/test/replanner/synthesize.test.ts +303 -0
  113. package/test/spec/validate.test.ts +1056 -0
  114. package/test/state/snapshots.test.ts +264 -0
  115. package/test/synthesis/custom-workflow.test.ts +264 -0
  116. package/test/synthesis/graph-builder.test.ts +370 -0
  117. package/test/synthesis/harness-builder.test.ts +128 -0
  118. package/test/synthesis/policy-builder.test.ts +149 -0
  119. package/test/synthesis/risk-analyzer.test.ts +230 -0
  120. package/test/synthesis/skill-parser.test.ts +796 -0
  121. package/test/verification/engine.test.ts +509 -0
  122. package/test/versioning/history.test.ts +144 -0
  123. package/test/versioning/store.test.ts +254 -0
  124. package/vitest.config.ts +9 -0
@@ -0,0 +1,308 @@
1
+ import type { CompiledHarnessResult } from "../compiler/compile.js";
2
+ import type { HarnessSpec } from "../spec/types.js";
3
+ import { buildReferenceHarnessSpec, type ReferenceWorkflowRequest } from "../reference/catalog.js";
4
+ import { replanWorkflowRequest, type ReplanRequest, type ReplanResult } from "./synthesize.js";
5
+ import { createInitialVersion, createNextVersion, createLineageEntry } from "../versioning/history.js";
6
+ import type { HarnessVersion, LineageEntry, HarnessExecutionTrace } from "../versioning/types.js";
7
+ import { deriveMutationsFromTrace } from "../mutation/derive.js";
8
+ import { mutateHarness } from "../mutation/engine.js";
9
+ import type { HarnessMutation, MutationResult } from "../mutation/types.js";
10
+ import type { MemoryStore, HarnessMemory, MemoryAdvice, MemoryUpdate } from "../memory/types.js";
11
+ import { extractPatternsFromTrace } from "../memory/extractor.js";
12
+ import { adviseFromMemory } from "../memory/advisor.js";
13
+
14
+ export const MAX_ADAPTIVE_VERSIONS = 5;
15
+
16
+ export interface AdaptiveRuntimeMetadata {
17
+ currentRequest: ReferenceWorkflowRequest;
18
+ currentVersion: HarnessVersion;
19
+ lineage: LineageEntry[];
20
+ pendingMutations?: HarnessMutation[];
21
+ }
22
+
23
+ export interface AdaptiveRuntimeInput {
24
+ input: unknown;
25
+ __lassoAdaptiveRuntime: AdaptiveRuntimeMetadata;
26
+ }
27
+
28
+ export type UnwrappedAdaptiveInput =
29
+ | { hasAdaptive: true; metadata: AdaptiveRuntimeMetadata; input: unknown }
30
+ | { hasAdaptive: false; metadata: null; input: unknown };
31
+
32
+ export type RuntimeReplanDecision =
33
+ | {
34
+ decision: "continue_as_new";
35
+ nextRequest: ReferenceWorkflowRequest;
36
+ nextVersion: HarnessVersion;
37
+ nextInput: AdaptiveRuntimeInput;
38
+ lineageEntry: LineageEntry;
39
+ }
40
+ | {
41
+ decision: "needs_operator_input";
42
+ lineageEntry: LineageEntry;
43
+ replanResult: ReplanResult;
44
+ }
45
+ | {
46
+ decision: "stop";
47
+ lineageEntry: LineageEntry;
48
+ replanResult: ReplanResult;
49
+ };
50
+
51
+ export function prepareInitialAdaptiveInput(
52
+ request: ReferenceWorkflowRequest,
53
+ spec: HarnessSpec,
54
+ runtimeInput: unknown,
55
+ ): AdaptiveRuntimeInput {
56
+ const initialVersion = createInitialVersion(spec);
57
+
58
+ return {
59
+ input: structuredClone(runtimeInput),
60
+ __lassoAdaptiveRuntime: {
61
+ currentRequest: structuredClone(request),
62
+ currentVersion: initialVersion,
63
+ lineage: [],
64
+ },
65
+ };
66
+ }
67
+
68
+ export function unwrapAdaptiveInput(input: unknown): UnwrappedAdaptiveInput {
69
+ if (
70
+ input
71
+ && typeof input === "object"
72
+ && "__lassoAdaptiveRuntime" in input
73
+ && isAdaptiveMetadata(input.__lassoAdaptiveRuntime)
74
+ ) {
75
+ const record = input as Record<string, unknown>;
76
+ return {
77
+ hasAdaptive: true,
78
+ metadata: input.__lassoAdaptiveRuntime as AdaptiveRuntimeMetadata,
79
+ input: Object.prototype.hasOwnProperty.call(record, "input") ? record.input : {},
80
+ };
81
+ }
82
+
83
+ return { hasAdaptive: false, metadata: null, input };
84
+ }
85
+
86
+ export function prepareRuntimeReplan(
87
+ adaptive: AdaptiveRuntimeMetadata,
88
+ runtimeInput: unknown,
89
+ result: CompiledHarnessResult,
90
+ ): RuntimeReplanDecision {
91
+ const lineageEntry = createLineageEntry(adaptive.currentVersion, result);
92
+
93
+ if (adaptive.currentVersion.version >= MAX_ADAPTIVE_VERSIONS) {
94
+ return {
95
+ decision: "stop",
96
+ lineageEntry,
97
+ replanResult: {
98
+ status: "stop",
99
+ workflow: adaptive.currentRequest.workflow,
100
+ riskLevel: "high",
101
+ reasons: ["Max adaptive version limit reached"],
102
+ guidance: ["Manual intervention required to continue workflow evolution"],
103
+ },
104
+ };
105
+ }
106
+
107
+ const replanRequest = buildReplanRequest(
108
+ adaptive.currentRequest,
109
+ result.terminalNodeId,
110
+ result.harnessState,
111
+ );
112
+
113
+ const replanResult = replanWorkflowRequest(replanRequest);
114
+
115
+ const mutationDecision = prepareRuntimeReplanWithMutations(adaptive, result, {
116
+ entries: result.trace.entries,
117
+ totalDurationMs: result.harnessState.metrics.durationMs,
118
+ nodeCount: result.trace.entries.length,
119
+ failureCount: result.harnessState.failures.length,
120
+ startTimeMs: Date.now() - result.harnessState.metrics.durationMs,
121
+ endTimeMs: Date.now(),
122
+ });
123
+
124
+ if (replanResult.status === "draft_request") {
125
+ const baseSpec = mutationDecision.mutationResult
126
+ ? mutationDecision.mutationResult.spec
127
+ : buildReferenceHarnessSpec(replanResult.request);
128
+ const mutationSuffix = mutationDecision.mutations
129
+ ? ` + ${mutationDecision.mutations.length} structural mutation(s)`
130
+ : "";
131
+ const nextVersion = createNextVersion(
132
+ adaptive.currentVersion,
133
+ baseSpec,
134
+ `${replanResult.trigger}: ${replanResult.rationale[0] || "workflow evolution"}${mutationSuffix}`,
135
+ );
136
+
137
+ const nextInput: AdaptiveRuntimeInput = {
138
+ input: structuredClone(runtimeInput),
139
+ __lassoAdaptiveRuntime: {
140
+ currentRequest: structuredClone(replanResult.request),
141
+ currentVersion: nextVersion,
142
+ lineage: [...adaptive.lineage, lineageEntry],
143
+ pendingMutations: mutationDecision.mutations,
144
+ },
145
+ };
146
+
147
+ return {
148
+ decision: "continue_as_new",
149
+ nextRequest: replanResult.request,
150
+ nextVersion,
151
+ nextInput,
152
+ lineageEntry,
153
+ };
154
+ }
155
+
156
+ if (replanResult.status === "needs_operator_input") {
157
+ return {
158
+ decision: "needs_operator_input",
159
+ lineageEntry,
160
+ replanResult,
161
+ };
162
+ }
163
+
164
+ return {
165
+ decision: "stop",
166
+ lineageEntry,
167
+ replanResult,
168
+ };
169
+ }
170
+
171
+ export interface MutationReplanDecision {
172
+ decision: "mutate_spec" | "no_mutations";
173
+ mutationResult?: MutationResult;
174
+ mutations?: HarnessMutation[];
175
+ }
176
+
177
+ export function prepareRuntimeReplanWithMutations(
178
+ adaptive: AdaptiveRuntimeMetadata,
179
+ result: CompiledHarnessResult,
180
+ trace: HarnessExecutionTrace,
181
+ ): MutationReplanDecision {
182
+ const currentSpec = adaptive.currentVersion.spec;
183
+ const derivedMutations = deriveMutationsFromTrace(trace, currentSpec);
184
+
185
+ if (derivedMutations.length === 0) {
186
+ return { decision: "no_mutations" };
187
+ }
188
+
189
+ const mutationResult = mutateHarness(currentSpec, derivedMutations);
190
+
191
+ return {
192
+ decision: "mutate_spec",
193
+ mutationResult,
194
+ mutations: derivedMutations,
195
+ };
196
+ }
197
+
198
+ function buildReplanRequest(
199
+ originalRequest: ReferenceWorkflowRequest,
200
+ terminalNodeId: string,
201
+ harnessState: CompiledHarnessResult["harnessState"],
202
+ ): ReplanRequest {
203
+ if (originalRequest.workflow === "patch-validation") {
204
+ return {
205
+ workflow: "patch-validation",
206
+ originalRequest,
207
+ observedOutcome: {
208
+ terminalNodeId: terminalNodeId as any,
209
+ notes: harnessState.failures.map(f => f.message),
210
+ },
211
+ };
212
+ }
213
+
214
+ return {
215
+ workflow: "pr-review-merge",
216
+ originalRequest,
217
+ observedOutcome: {
218
+ terminalNodeId: terminalNodeId as any,
219
+ notes: harnessState.failures.map(f => f.message),
220
+ },
221
+ };
222
+ }
223
+
224
+ function isAdaptiveMetadata(value: unknown): value is AdaptiveRuntimeMetadata {
225
+ if (!value || typeof value !== "object") {
226
+ return false;
227
+ }
228
+
229
+ const record = value as Record<string, unknown>;
230
+
231
+ return (
232
+ "currentRequest" in record
233
+ && typeof record.currentRequest === "object"
234
+ && "currentVersion" in record
235
+ && typeof record.currentVersion === "object"
236
+ && "lineage" in record
237
+ && Array.isArray(record.lineage)
238
+ );
239
+ }
240
+
241
+ export interface MemoryAwareReplanInput {
242
+ adaptive: AdaptiveRuntimeMetadata;
243
+ runtimeInput: unknown;
244
+ result: CompiledHarnessResult;
245
+ memoryStore: MemoryStore;
246
+ taskSignature?: string;
247
+ }
248
+
249
+ export interface MemoryAwareReplanOutput {
250
+ advice: MemoryAdvice;
251
+ updatedMemory?: HarnessMemory;
252
+ decision: RuntimeReplanDecision;
253
+ }
254
+
255
+ export async function prepareMemoryAwareRuntimeReplan(
256
+ input: MemoryAwareReplanInput,
257
+ ): Promise<MemoryAwareReplanOutput> {
258
+ const { adaptive, runtimeInput, result, memoryStore, taskSignature } = input;
259
+
260
+ const trace: HarnessExecutionTrace = {
261
+ entries: result.trace.entries,
262
+ totalDurationMs: result.harnessState.metrics.durationMs,
263
+ nodeCount: result.trace.entries.length,
264
+ failureCount: result.harnessState.failures.length,
265
+ startTimeMs: Date.now() - result.harnessState.metrics.durationMs,
266
+ endTimeMs: Date.now(),
267
+ };
268
+
269
+ const advice = await adviseFromMemory(
270
+ taskSignature ?? adaptive.currentRequest.workflow,
271
+ memoryStore,
272
+ { taskSignature },
273
+ adaptive.currentVersion.spec,
274
+ );
275
+
276
+ const decision = prepareRuntimeReplan(adaptive, runtimeInput, result);
277
+
278
+ let updatedMemory: HarnessMemory | undefined;
279
+
280
+ if (decision.decision === "continue_as_new" || decision.decision === "stop") {
281
+ const patterns = extractPatternsFromTrace(trace, adaptive.currentVersion.spec);
282
+
283
+ const taskId = taskSignature ?? `${adaptive.currentRequest.workflow}-v${adaptive.currentVersion.version}`;
284
+ const existingMemory = await memoryStore.getMemory(taskId);
285
+
286
+ if (existingMemory) {
287
+ const update: MemoryUpdate = {
288
+ effectivenessDelta: result.harnessState.failures.length === 0 ? 0.05 : -0.05,
289
+ };
290
+ updatedMemory = await memoryStore.updateMemory(taskId, update);
291
+ } else {
292
+ const effectivenessScore = result.harnessState.failures.length === 0 ? 0.7 : 0.3;
293
+ const memory: HarnessMemory = {
294
+ taskId,
295
+ taskEmbedding: taskSignature,
296
+ successfulPatterns: patterns.successful,
297
+ failedPatterns: patterns.failed,
298
+ mutationHistory: [],
299
+ effectivenessScore,
300
+ lastUpdated: Date.now(),
301
+ };
302
+ await memoryStore.saveMemory(memory);
303
+ updatedMemory = memory;
304
+ }
305
+ }
306
+
307
+ return { advice, updatedMemory, decision };
308
+ }