@nifrajs/coding-agent 3.2.0 → 3.5.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.
- package/dist/context.js +29 -1
- package/dist/context.js.map +1 -1
- package/dist/diff.js +38 -2
- package/dist/diff.js.map +1 -1
- package/dist/host.d.ts.map +1 -1
- package/dist/host.js +217 -24
- package/dist/host.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/isolated.js +37 -2
- package/dist/isolated.js.map +1 -1
- package/dist/native.d.ts +17 -0
- package/dist/native.d.ts.map +1 -1
- package/dist/native.js +265 -41
- package/dist/native.js.map +1 -1
- package/dist/replay.d.ts +4 -0
- package/dist/replay.d.ts.map +1 -1
- package/dist/replay.js +189 -24
- package/dist/replay.js.map +1 -1
- package/dist/rpc.d.ts +10 -0
- package/dist/rpc.d.ts.map +1 -1
- package/dist/rpc.js +208 -29
- package/dist/rpc.js.map +1 -1
- package/dist/sessions.d.ts +14 -2
- package/dist/sessions.d.ts.map +1 -1
- package/dist/sessions.js +253 -59
- package/dist/sessions.js.map +1 -1
- package/dist/verification.d.ts +23 -0
- package/dist/verification.d.ts.map +1 -1
- package/dist/verification.js +113 -1
- package/dist/verification.js.map +1 -1
- package/dist/workflows.d.ts +1 -0
- package/dist/workflows.d.ts.map +1 -1
- package/dist/workflows.js +43 -21
- package/dist/workflows.js.map +1 -1
- package/package.json +6 -5
- package/src/context.ts +32 -1
- package/src/diff.ts +40 -2
- package/src/host.ts +219 -24
- package/src/index.ts +5 -0
- package/src/isolated.ts +39 -2
- package/src/native.ts +408 -42
- package/src/replay.ts +206 -25
- package/src/rpc.ts +261 -33
- package/src/sessions.ts +271 -56
- package/src/verification.ts +140 -1
- package/src/workflows.ts +37 -25
package/src/workflows.ts
CHANGED
|
@@ -88,6 +88,7 @@ export interface WorkflowResult {
|
|
|
88
88
|
export class WorkflowRunner {
|
|
89
89
|
private readonly options: Required<Pick<WorkflowRunnerOptions, "maxSteps" | "maxDepth">> &
|
|
90
90
|
WorkflowRunnerOptions
|
|
91
|
+
private readonly signal: AbortSignal
|
|
91
92
|
private readonly values = new Map<string, unknown>()
|
|
92
93
|
private readonly completed: string[] = []
|
|
93
94
|
private steps = 0
|
|
@@ -98,6 +99,7 @@ export class WorkflowRunner {
|
|
|
98
99
|
maxSteps: options.maxSteps ?? 128,
|
|
99
100
|
maxDepth: options.maxDepth ?? 8,
|
|
100
101
|
}
|
|
102
|
+
this.signal = options.signal ?? new AbortController().signal
|
|
101
103
|
if (!Number.isSafeInteger(this.options.maxSteps) || this.options.maxSteps < 1)
|
|
102
104
|
throw new RangeError("workflow: maxSteps must be positive")
|
|
103
105
|
if (!Number.isSafeInteger(this.options.maxDepth) || this.options.maxDepth < 1)
|
|
@@ -128,12 +130,12 @@ export class WorkflowRunner {
|
|
|
128
130
|
}
|
|
129
131
|
}
|
|
130
132
|
|
|
131
|
-
private context(): WorkflowContext {
|
|
133
|
+
private context(depth: number): WorkflowContext {
|
|
132
134
|
return {
|
|
133
|
-
signal: this.
|
|
135
|
+
signal: this.signal,
|
|
134
136
|
values: this.values,
|
|
135
137
|
set: (name, value) => this.values.set(name, value),
|
|
136
|
-
run: (step) => this.execute(step, 1),
|
|
138
|
+
run: (step) => this.execute(step, depth + 1),
|
|
137
139
|
}
|
|
138
140
|
}
|
|
139
141
|
|
|
@@ -143,51 +145,55 @@ export class WorkflowRunner {
|
|
|
143
145
|
if (this.options.signal?.aborted) throw new Error("workflow cancelled")
|
|
144
146
|
switch (step.type) {
|
|
145
147
|
case "task":
|
|
146
|
-
return this.single(step.id, () => step.run(this.context()))
|
|
148
|
+
return this.single(step.id, () => step.run(this.context(depth)))
|
|
147
149
|
case "verify": {
|
|
148
|
-
const result = await this.single(step.id, () => step.run(this.context()))
|
|
150
|
+
const result = await this.single(step.id, () => step.run(this.context(depth)))
|
|
149
151
|
const ok = typeof result === "boolean" ? result : isVerificationResult(result) && result.ok
|
|
150
152
|
if (!ok) throw new Error(`verification failed: ${step.id}`)
|
|
151
153
|
return result
|
|
152
154
|
}
|
|
153
155
|
case "approve": {
|
|
154
156
|
await this.emit({ type: "approval.required", id: step.id, reason: step.reason })
|
|
155
|
-
const approved = await this.single(step.id, () => step.run(this.context()))
|
|
157
|
+
const approved = await this.single(step.id, () => step.run(this.context(depth)))
|
|
156
158
|
if (approved !== true) throw new Error(`approval denied: ${step.id}`)
|
|
157
159
|
return approved
|
|
158
160
|
}
|
|
159
161
|
case "checkpoint": {
|
|
160
|
-
const result = await this.single(step.id, () => step.run(this.context()))
|
|
162
|
+
const result = await this.single(step.id, () => step.run(this.context(depth)))
|
|
161
163
|
await this.emit({ type: "checkpoint.created", id: step.id })
|
|
162
164
|
return result
|
|
163
165
|
}
|
|
164
166
|
case "handoff":
|
|
165
|
-
return this.single(step.id, () => step.run(this.context()))
|
|
167
|
+
return this.single(step.id, () => step.run(this.context(depth)))
|
|
166
168
|
case "sequence": {
|
|
167
169
|
const results: unknown[] = []
|
|
168
170
|
for (const child of step.steps) results.push(await this.execute(child, depth + 1))
|
|
169
171
|
return results
|
|
170
172
|
}
|
|
171
173
|
case "parallel":
|
|
174
|
+
if (step.steps.length === 0) return []
|
|
172
175
|
return this.parallel(step.steps, step.maxConcurrency ?? step.steps.length, depth)
|
|
173
176
|
case "retry": {
|
|
174
177
|
const attempts = step.attempts ?? 3
|
|
175
178
|
if (!Number.isSafeInteger(attempts) || attempts < 1 || attempts > 16)
|
|
176
179
|
throw new RangeError("workflow: attempts must be between 1 and 16")
|
|
180
|
+
const backoffMs = step.backoffMs ?? 0
|
|
181
|
+
if (!Number.isSafeInteger(backoffMs) || backoffMs < 0)
|
|
182
|
+
throw new RangeError("workflow: backoffMs must be a non-negative safe integer")
|
|
177
183
|
let last: unknown
|
|
178
184
|
for (let attempt = 0; attempt < attempts; attempt++) {
|
|
179
185
|
try {
|
|
180
186
|
return await this.execute(step.step, depth + 1)
|
|
181
187
|
} catch (error) {
|
|
182
188
|
last = error
|
|
183
|
-
if (attempt + 1 < attempts &&
|
|
184
|
-
await delay(Math.min(
|
|
189
|
+
if (attempt + 1 < attempts && backoffMs > 0)
|
|
190
|
+
await delay(Math.min(backoffMs * (attempt + 1), 10_000), this.options.signal)
|
|
185
191
|
}
|
|
186
192
|
}
|
|
187
193
|
throw last instanceof Error ? last : new Error(String(last))
|
|
188
194
|
}
|
|
189
195
|
case "branch": {
|
|
190
|
-
const selected = await this.single(step.id, () => step.when(this.context()))
|
|
196
|
+
const selected = await this.single(step.id, () => step.when(this.context(depth)))
|
|
191
197
|
return selected === true
|
|
192
198
|
? this.execute(step.then, depth + 1)
|
|
193
199
|
: step.otherwise === undefined
|
|
@@ -249,21 +255,27 @@ export class WorkflowRunner {
|
|
|
249
255
|
|
|
250
256
|
async function delay(ms: number, signal: AbortSignal | undefined): Promise<void> {
|
|
251
257
|
await new Promise<void>((resolve, reject) => {
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
+
let settled = false
|
|
259
|
+
let timer: ReturnType<typeof setTimeout> | undefined
|
|
260
|
+
let onAbort: (() => void) | undefined
|
|
261
|
+
const cleanup = (): void => {
|
|
262
|
+
if (timer !== undefined) clearTimeout(timer)
|
|
263
|
+
if (signal !== undefined && onAbort !== undefined)
|
|
264
|
+
signal.removeEventListener("abort", onAbort)
|
|
258
265
|
}
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
)
|
|
266
|
+
const settle = (error?: Error): void => {
|
|
267
|
+
if (settled) return
|
|
268
|
+
settled = true
|
|
269
|
+
cleanup()
|
|
270
|
+
if (error === undefined) resolve()
|
|
271
|
+
else reject(error)
|
|
272
|
+
}
|
|
273
|
+
timer = setTimeout(() => settle(), ms)
|
|
274
|
+
if (signal === undefined) return
|
|
275
|
+
onAbort = () => settle(new Error("workflow cancelled"))
|
|
276
|
+
signal.addEventListener("abort", onAbort, { once: true })
|
|
277
|
+
// Abort can race listener registration; check again after subscribing.
|
|
278
|
+
if (signal.aborted) onAbort()
|
|
267
279
|
})
|
|
268
280
|
}
|
|
269
281
|
|