@abelxiaoxing/cadence 1.4.0 → 1.4.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 (49) hide show
  1. package/README.md +58 -4
  2. package/agents/design-explorer.md +17 -11
  3. package/agents/diagnosis-worker.md +9 -1
  4. package/agents/implementation-worker.md +3 -1
  5. package/config/plan-draft.example.json +122 -0
  6. package/config/plan-draft.multiple-tasks.example.json +345 -0
  7. package/package.json +5 -3
  8. package/prompts/abel-design.md +93 -44
  9. package/src/activity-contracts.ts +82 -0
  10. package/src/candidate-artifact.ts +143 -0
  11. package/src/candidate-patch.ts +31 -11
  12. package/src/candidate-workspace.ts +74 -0
  13. package/src/change-contract-schema.ts +191 -0
  14. package/src/change-contract.ts +5 -0
  15. package/src/change-verification.ts +896 -0
  16. package/src/child-model.ts +129 -0
  17. package/src/child-session.ts +293 -326
  18. package/src/contracts.ts +184 -76
  19. package/src/delivery-compiler.ts +103 -120
  20. package/src/delivery-revision.ts +42 -0
  21. package/src/design-control.ts +113 -4
  22. package/src/design-diagnostics.ts +150 -0
  23. package/src/durable-contracts.ts +210 -0
  24. package/src/durable-workflow.ts +148 -3570
  25. package/src/evidence-draft.ts +122 -0
  26. package/src/implement-graph.ts +3 -0
  27. package/src/implement-plan.ts +70 -0
  28. package/src/index.ts +59 -522
  29. package/src/model-source.ts +22 -0
  30. package/src/package-candidate.ts +224 -0
  31. package/src/package-workflow.ts +253 -0
  32. package/src/packet-runtime.ts +27 -48
  33. package/src/parent-provider.ts +86 -198
  34. package/src/phase-execution.ts +2248 -0
  35. package/src/pi-adapter.ts +19 -0
  36. package/src/plan-draft-summary.ts +146 -0
  37. package/src/plan-draft.ts +493 -0
  38. package/src/subagent-activity.ts +32 -66
  39. package/src/submit-tool.ts +20 -59
  40. package/src/transport-budget.ts +32 -0
  41. package/src/worker-broker.ts +37 -57
  42. package/src/workflow-policy.ts +14 -53
  43. package/src/workflow-recovery-policy.ts +95 -0
  44. package/src/workflow-scheduling.ts +105 -0
  45. package/src/workflow-state-machine.ts +105 -497
  46. package/src/workflow-status.ts +384 -0
  47. package/src/workspace-io-worker.mjs +7 -0
  48. package/src/empty-resource-loader.ts +0 -38
  49. package/src/parent-payload-bridge.ts +0 -523
@@ -0,0 +1,22 @@
1
+ import type { Model, Provider } from "@earendil-works/pi-ai";
2
+
3
+ /** Code-owned capability boundary. No session events, tools, UI or host context. */
4
+ export interface ParentModelSource {
5
+ readonly model?: Model<string>;
6
+ readonly modelRegistry: {
7
+ getProvider(id: string): Provider | undefined;
8
+ getApiKeyAndHeaders(model: Model<string>): Promise<
9
+ | {
10
+ ok: true;
11
+ apiKey?: string;
12
+ headers?: Record<string, string | null>;
13
+ baseUrl?: string;
14
+ env?: Record<string, string>;
15
+ }
16
+ | { ok: false }
17
+ >;
18
+ };
19
+ }
20
+ export interface PackageContext extends ParentModelSource {
21
+ readonly cwd: string;
22
+ }
@@ -0,0 +1,224 @@
1
+ import { createHash } from "node:crypto";
2
+ import path from "node:path";
3
+ import { runChildSession } from "./child-session.ts";
4
+ import { LIMITS } from "./contracts.ts";
5
+ import type { DurableWorkflowEngineOptions } from "./durable-contracts.ts";
6
+ import type { ParentModelSource } from "./model-source.ts";
7
+ import { runtimeForWorkerRoute } from "./parent-provider.ts";
8
+ import type { WorkerRoutePolicy } from "./route-policy.ts";
9
+ import { isSafeRegularFile } from "./safe-path.ts";
10
+ import {
11
+ classifyCandidateContextRequest,
12
+ permitsContextRead,
13
+ } from "./submit-tool.ts";
14
+ import { transportFailureError } from "./transport-budget.ts";
15
+ import type { DurableCandidateProposal } from "./workflow-policy.ts";
16
+
17
+ function childRequestId(
18
+ operationId: string,
19
+ taskId: string,
20
+ phase: string,
21
+ ): string {
22
+ return `child-${createHash("sha256").update(`${operationId}\0${taskId}\0${phase}`).digest("hex").slice(0, 40)}`;
23
+ }
24
+ export async function proposePackageCandidate(
25
+ input: Parameters<DurableWorkflowEngineOptions["proposeCandidate"]>[0],
26
+ context: ParentModelSource | undefined,
27
+ implementationAgent: { content: string },
28
+ ): Promise<DurableCandidateProposal> {
29
+ if (!context) {
30
+ return { kind: "paused", code: "parent-context-unavailable" };
31
+ }
32
+ const phaseRuntime = await runtimeForWorkerRoute(
33
+ input.route as WorkerRoutePolicy,
34
+ context,
35
+ input.signal,
36
+ process.env,
37
+ );
38
+ if (!phaseRuntime.ok) {
39
+ if (phaseRuntime.failure.kind === "cancelled") {
40
+ return { kind: "operation-cancelled", code: "cancelled" };
41
+ }
42
+ throw new Error(phaseRuntime.failure.code);
43
+ }
44
+ const phase = input.task.phases[input.phase];
45
+ if (!phase) {
46
+ return { kind: "paused", code: "task-phase-unavailable" };
47
+ }
48
+ const taskPhases = Object.values(input.task.phases);
49
+ const executionBoundary = input.artifactCorrection
50
+ ? {
51
+ read: [
52
+ ...new Set(
53
+ taskPhases.flatMap((boundary) => [
54
+ ...boundary.read,
55
+ ...boundary.write,
56
+ ...boundary.delete,
57
+ ]),
58
+ ),
59
+ ].sort(),
60
+ write: [
61
+ ...new Set(taskPhases.flatMap((boundary) => boundary.write)),
62
+ ].sort(),
63
+ delete: [
64
+ ...new Set(taskPhases.flatMap((boundary) => boundary.delete)),
65
+ ].sort(),
66
+ }
67
+ : {
68
+ read: [
69
+ ...new Set(
70
+ taskPhases.flatMap((boundary) => [
71
+ ...boundary.read,
72
+ ...boundary.write,
73
+ ...boundary.delete,
74
+ ]),
75
+ ),
76
+ ].sort(),
77
+ write: [...phase.write],
78
+ delete: [...phase.delete],
79
+ };
80
+ executionBoundary.read = [
81
+ ...new Set([
82
+ ...executionBoundary.read,
83
+ ...(input.contextReadPaths ?? []).filter(
84
+ (relative) =>
85
+ permitsContextRead(relative, input.task.roots) &&
86
+ isSafeRegularFile(input.workspaceRoot, relative),
87
+ ),
88
+ ]),
89
+ ].sort();
90
+ const phaseContract = {
91
+ candidateId: input.candidateArtifact.identity.candidateId,
92
+ taskId: input.taskId,
93
+ phase: input.phase,
94
+ readSet: executionBoundary.read,
95
+ writeSet: executionBoundary.write,
96
+ deleteSet: executionBoundary.delete,
97
+ verification: structuredClone(phase.verification),
98
+ agentsImpact: input.task.agents.impact,
99
+ agentsTarget: input.task.agents.target ?? null,
100
+ agentsManagedOnly: true,
101
+ agentsWriteAllowed: false,
102
+ impactClosure: structuredClone(input.task.impactClosure),
103
+ ...(input.artifactCorrection
104
+ ? { artifactCorrection: structuredClone(input.artifactCorrection) }
105
+ : {}),
106
+ ...(input.contextRequest
107
+ ? { requestedContext: structuredClone(input.contextRequest) }
108
+ : {}),
109
+ ...(input.recoveryFeedback
110
+ ? { recoveryFeedback: structuredClone(input.recoveryFeedback) }
111
+ : {}),
112
+ ...(input.repair
113
+ ? {
114
+ repair: {
115
+ attempt: input.repair.attempt,
116
+ attribution: input.repair.attribution,
117
+ failureIdentities: [...input.repair.failureIdentities],
118
+ verification: structuredClone(input.task.repairVerification),
119
+ inBoundaryOnly: true,
120
+ },
121
+ }
122
+ : {}),
123
+ };
124
+ const child = await runChildSession({
125
+ cwd: input.workspaceRoot,
126
+ modelRuntime: phaseRuntime.modelRuntime,
127
+ model: phaseRuntime.model,
128
+ systemPrompt: [
129
+ implementationAgent.content,
130
+ input.task.objective,
131
+ input.task.context.agents,
132
+ input.task.context.contract,
133
+ "Use recoveryFeedback to change the failing approach. For compact-patch, prefer exact replace operations and omit unchanged bodies; submit one complete atomic patch. Never repeat an unchanged failing submission or weaken verification to obtain a pass.",
134
+ `<phase-contract>${JSON.stringify(phaseContract)}</phase-contract>`,
135
+ ].join("\n\n"),
136
+ requestId: childRequestId(input.operationId, input.taskId, input.phase),
137
+ taskId: input.taskId,
138
+ role: "implementation-worker",
139
+ phase: input.phase,
140
+ output: "diff",
141
+ roots: input.task.roots.map((root) =>
142
+ path.resolve(input.workspaceRoot, root),
143
+ ),
144
+ allowedPaths: [
145
+ ...new Set([
146
+ ...executionBoundary.read,
147
+ ...executionBoundary.write,
148
+ ...executionBoundary.delete,
149
+ ]),
150
+ ],
151
+ timeoutMs: LIMITS.phaseTimeoutMs,
152
+ signal: input.signal,
153
+ ledgerProjection: input.ledgerProjection,
154
+ candidateArtifact: input.candidateArtifact,
155
+ onStreamStart: input.onRequestStart,
156
+ onStreamHeaders: input.onHeaders,
157
+ onStreamProgress: input.onProgress,
158
+ });
159
+ if (!child.ok) {
160
+ if (child.failure.kind === "transport") {
161
+ throw transportFailureError(child.failure.code);
162
+ }
163
+ if (child.failure.kind === "cancelled") {
164
+ return { kind: "operation-cancelled", code: "cancelled" };
165
+ }
166
+ if (child.failure.kind === "approval-boundary") {
167
+ return { kind: "approval-needed", code: child.failure.code };
168
+ }
169
+ if (child.failure.kind === "execution-limit") {
170
+ return { kind: "paused", code: "needs-task-split" };
171
+ }
172
+ if (child.failure.kind === "result-limit") {
173
+ return { kind: "retryable", code: "needs-task-split" };
174
+ }
175
+ const attemptDiagnostic = {
176
+ finalCategory: child.classification.finalCategory,
177
+ submitAttempts: child.classification.attempts,
178
+ schema: child.classification.schema,
179
+ identityMismatch: Object.entries(child.classification.identity)
180
+ .filter(([, matches]) => !matches)
181
+ .map(([dimension]) => dimension),
182
+ };
183
+ return child.failure.kind === "environment" ||
184
+ child.failure.kind === "verification-adapter"
185
+ ? { kind: "paused", code: child.failure.code, attemptDiagnostic }
186
+ : { kind: "retryable", code: child.failure.code, attemptDiagnostic };
187
+ }
188
+ const result = child.result;
189
+ if (result.kind === "context-request") {
190
+ return classifyCandidateContextRequest(result, {
191
+ phase: input.phase,
192
+ contextReadRoots: input.task.roots,
193
+ readPaths: phase.read,
194
+ writePaths: phase.write,
195
+ deletePaths: phase.delete,
196
+ taskPaths: [
197
+ ...new Set(
198
+ Object.values(input.task.phases).flatMap((boundary) => [
199
+ ...boundary.read,
200
+ ...boundary.write,
201
+ ...boundary.delete,
202
+ ]),
203
+ ),
204
+ ],
205
+ redWritePaths: input.task.phases.red.write,
206
+ agents: {
207
+ impact: input.task.agents.impact,
208
+ ...(input.task.agents.target
209
+ ? { target: input.task.agents.target }
210
+ : {}),
211
+ },
212
+ });
213
+ }
214
+ if (result.kind !== "sealed-candidate") {
215
+ return { kind: "retryable", code: "candidate-diff-invalid" };
216
+ }
217
+ return {
218
+ kind: "sealed-candidate",
219
+ candidateId: result.candidateId,
220
+ artifactHash: result.artifactHash,
221
+ bytes: result.bytes,
222
+ paths: [...result.paths],
223
+ };
224
+ }
@@ -0,0 +1,253 @@
1
+ import { AsyncLocalStorage } from "node:async_hooks";
2
+ import { homedir } from "node:os";
3
+ import path from "node:path";
4
+ import type { WorkflowActivityUpdate } from "./activity-contracts.ts";
5
+ import { loadAgentDefinitions } from "./agent-registry.ts";
6
+ import type {
7
+ DesignEvidenceResult,
8
+ StructuredVerificationContract,
9
+ } from "./contracts.ts";
10
+ import { validateControlCommand } from "./control-contracts.ts";
11
+ import { DesignController } from "./design-control.ts";
12
+ import type { PackageContext } from "./model-source.ts";
13
+ import { inspectOpenSpecDelivery } from "./openspec-cli.ts";
14
+ import { proposePackageCandidate } from "./package-candidate.ts";
15
+ import { packageDeliverySource } from "./package-delivery.ts";
16
+ import {
17
+ changeVerificationResult,
18
+ executePackageVerification,
19
+ phaseVerificationResult,
20
+ } from "./package-verification.ts";
21
+ import {
22
+ inspectRoutePolicy,
23
+ loadRoutePolicy,
24
+ type RoutePolicyResolution,
25
+ unavailableRoutePolicy,
26
+ } from "./route-policy.ts";
27
+ import { resolveStateRoot } from "./state-root.ts";
28
+ import { captureVerificationEnvironmentIdentity } from "./verification-environment.ts";
29
+ import { openDurableWorkflowEngine } from "./workflow-engine.ts";
30
+ export interface PackageWorkflowService {
31
+ execute(
32
+ command: unknown,
33
+ context?: PackageContext,
34
+ signal?: AbortSignal,
35
+ onActivity?: (event: WorkflowActivityUpdate) => void,
36
+ ): Promise<Record<string, unknown>>;
37
+ executeDesign(request: unknown): Promise<Record<string, unknown>>;
38
+ executeAmendment(
39
+ change: string,
40
+ batchId: string,
41
+ request: unknown,
42
+ ): Promise<Record<string, unknown>>;
43
+ assertDesignRun(runId: string): void;
44
+ recordDesignEvidence(input: {
45
+ runId: string;
46
+ evidence: DesignEvidenceResult;
47
+ }): unknown;
48
+ close(): void | Promise<void>;
49
+ }
50
+
51
+ function affectedVerification(
52
+ task: Parameters<
53
+ Parameters<typeof openDurableWorkflowEngine>[0]["proposeCandidate"]
54
+ >[0]["task"],
55
+ ): StructuredVerificationContract {
56
+ if (task.affectedVerification) {
57
+ return structuredClone(task.affectedVerification);
58
+ }
59
+ const finalPhase = task.phases.refactor ?? task.phases.green;
60
+ const verification = structuredClone(finalPhase.verification);
61
+ const affected = [...new Set(task.impactClosure.affectedSuite)].sort();
62
+ if (affected.length === 0) return verification;
63
+ if (verification.kind === "vitest") {
64
+ return { ...verification, testFiles: affected };
65
+ }
66
+ if (verification.kind === "steps") {
67
+ return {
68
+ ...verification,
69
+ steps: verification.steps.map((step) =>
70
+ step.kind === "vitest" ? { ...step, testFiles: affected } : step,
71
+ ),
72
+ };
73
+ }
74
+ return verification;
75
+ }
76
+
77
+ export function openPackageWorkflowService(
78
+ initialContext: PackageContext,
79
+ ): PackageWorkflowService {
80
+ const consumerRoot = path.resolve(initialContext.cwd);
81
+ const routeResolution = loadRoutePolicy({
82
+ cwd: consumerRoot,
83
+ home: homedir(),
84
+ ...(initialContext.model ? { parentModel: initialContext.model } : {}),
85
+ });
86
+ const stateRoot = resolveStateRoot({
87
+ consumerRoot,
88
+ xdgStateHome: process.env.XDG_STATE_HOME,
89
+ });
90
+ const contexts = new AsyncLocalStorage<PackageContext>();
91
+ const design = DesignController.open({
92
+ consumerRoot,
93
+ stateRoot,
94
+ inspectOpenSpec: inspectOpenSpecDelivery,
95
+ });
96
+ const implementationAgent = loadAgentDefinitions().find(
97
+ (agent) => agent.role === "implementation-worker",
98
+ );
99
+ if (!implementationAgent) {
100
+ throw new Error("implementation-worker-agent-unavailable");
101
+ }
102
+ const hostLimit = (name: string, fallback: number): number => {
103
+ const value =
104
+ process.env[name] === undefined ? fallback : Number(process.env[name]);
105
+ if (!Number.isSafeInteger(value) || value < 1)
106
+ throw new Error("verification-host-limit-invalid");
107
+ return value;
108
+ };
109
+ const maxReportBytes = hostLimit(
110
+ "ABEL_VERIFICATION_MAX_REPORT_BYTES",
111
+ 64 * 1024 * 1024,
112
+ );
113
+ const workHardLimit = hostLimit("ABEL_WORK_MAX_UNITS", 512);
114
+ const engine = openDurableWorkflowEngine({
115
+ workHardLimit,
116
+ verificationPolicy: "report-file-v4",
117
+ verificationEnvironment: (plan, signal) =>
118
+ captureVerificationEnvironmentIdentity(
119
+ consumerRoot,
120
+ [
121
+ ...plan.tasks.flatMap((task) => [
122
+ ...Object.values(task.phases).map((phase) => phase.verification),
123
+ task.affectedVerification,
124
+ task.repairVerification,
125
+ ]),
126
+ plan.verification.baseline.fullSuite,
127
+ plan.verification.change.fullSuite,
128
+ plan.verification.change.postApply,
129
+ ...(plan.verification.agentsCheckpoint.verification
130
+ ? [plan.verification.agentsCheckpoint.verification]
131
+ : []),
132
+ ],
133
+ signal,
134
+ ),
135
+ consumerRoot,
136
+ stateRoot,
137
+ deliverySource: packageDeliverySource(consumerRoot, {
138
+ verifyGateProof: (input) => design.verifyGateProof(input),
139
+ verifyFinalizedDelivery: (input) => design.verifyFinalizedDelivery(input),
140
+ }),
141
+ routePolicy: routeResolution.ok
142
+ ? routeResolution.policy
143
+ : unavailableRoutePolicy(),
144
+ proposeCandidate: (input) =>
145
+ proposePackageCandidate(input, contexts.getStore(), implementationAgent),
146
+ verifyPhase: async (input) =>
147
+ phaseVerificationResult(
148
+ await executePackageVerification({
149
+ maxReportBytes,
150
+ executionWritePaths: input.executionWritePaths,
151
+ root: input.root,
152
+ dependencyOwner: consumerRoot,
153
+ verification: input.verification,
154
+ signal: input.signal,
155
+ }),
156
+ ),
157
+ verifyChange: async (input) => {
158
+ const verifications = input.verification
159
+ ? [input.verification]
160
+ : input.plan.tasks.map((task) => affectedVerification(task));
161
+ for (const verification of verifications) {
162
+ const result = await executePackageVerification({
163
+ maxReportBytes,
164
+ executionWritePaths: input.plan.tasks.flatMap((task) =>
165
+ Object.values(task.phases).flatMap((phase) => [
166
+ ...phase.write,
167
+ ...phase.delete,
168
+ ]),
169
+ ),
170
+ root: input.root,
171
+ dependencyOwner: consumerRoot,
172
+ verification,
173
+ signal: input.signal,
174
+ });
175
+ const observed = changeVerificationResult(result);
176
+ if (!observed.ok) return observed;
177
+ }
178
+ return {
179
+ ok: true,
180
+ exitCode: 0,
181
+ classification: "expected-green",
182
+ };
183
+ },
184
+ });
185
+ return {
186
+ async execute(
187
+ command: unknown,
188
+ context = initialContext,
189
+ signal,
190
+ onActivity,
191
+ ) {
192
+ const operationRouteResolution = loadRoutePolicy({
193
+ cwd: consumerRoot,
194
+ home: homedir(),
195
+ ...(context.model ? { parentModel: context.model } : {}),
196
+ });
197
+ engine.updateRoutePolicy(
198
+ operationRouteResolution.ok
199
+ ? operationRouteResolution.policy
200
+ : unavailableRoutePolicy(),
201
+ );
202
+ const validation = validateControlCommand(command);
203
+ if (!validation.ok) {
204
+ const error = new Error(validation.code);
205
+ error.name = "ControlCommandError";
206
+ throw error;
207
+ }
208
+ return contexts.run(context, async () => {
209
+ const outcome = await engine.execute(
210
+ validation.value,
211
+ signal,
212
+ onActivity,
213
+ );
214
+ const routePolicy = visibleRoutePolicyStatus(
215
+ operationRouteResolution,
216
+ engine.routePolicyStatus(),
217
+ );
218
+ return { ...outcome, routePolicy };
219
+ });
220
+ },
221
+ executeDesign(request: unknown) {
222
+ return design.execute(request);
223
+ },
224
+ executeAmendment(change: string, batchId: string, request: unknown) {
225
+ return engine.amend(change, batchId, request, (assertAuthority) =>
226
+ design.executeWithAuthority(request, assertAuthority),
227
+ );
228
+ },
229
+ assertDesignRun(runId: string) {
230
+ design.assertDesignRun(runId);
231
+ },
232
+ recordDesignEvidence(input) {
233
+ return design.recordEvidence(input);
234
+ },
235
+ async close() {
236
+ contexts.disable();
237
+ await engine.close();
238
+ design.close();
239
+ },
240
+ };
241
+ }
242
+
243
+ function visibleRoutePolicyStatus(
244
+ resolution: RoutePolicyResolution,
245
+ brokerStatus: Record<string, unknown> | undefined,
246
+ ): Record<string, unknown> {
247
+ if (!resolution.ok) return inspectRoutePolicy(resolution);
248
+ const inspected = brokerStatus ?? inspectRoutePolicy(resolution);
249
+ return {
250
+ ...inspected,
251
+ source: { kind: resolution.source.kind },
252
+ };
253
+ }
@@ -1,6 +1,5 @@
1
1
  import path from "node:path";
2
2
  import type { Usage } from "@earendil-works/pi-ai";
3
- import type { ExtensionContext } from "@earendil-works/pi-coding-agent";
4
3
  import { Activation, type ActivationState } from "./activation.ts";
5
4
  import { loadAgentDefinitions } from "./agent-registry.ts";
6
5
  import {
@@ -15,51 +14,34 @@ import {
15
14
  type PacketEnvelope,
16
15
  validatePacketEnvelope,
17
16
  } from "./contracts.ts";
18
- import type { ParentPayloadBridge } from "./parent-payload-bridge.ts";
17
+ import type { PackageContext } from "./model-source.ts";
19
18
  import { runtimeForWorkerRoute } from "./parent-provider.ts";
20
19
  import {
21
20
  loadRoutePolicy,
22
21
  type RoutePolicy,
23
22
  type WorkerRole,
24
23
  } from "./route-policy.ts";
24
+ import {
25
+ isTransportTimeoutCode,
26
+ transportFailureError,
27
+ } from "./transport-budget.ts";
25
28
  import { type BrokerActivityUpdate, RunWorkerBroker } from "./worker-broker.ts";
26
29
 
27
30
  export const PACKET_ACTIONS = ["run", "cancel", "finish"] as const;
28
31
  export type PacketAction = (typeof PACKET_ACTIONS)[number];
29
32
 
30
- export type PacketActivityState =
31
- | "queued"
32
- | "connecting"
33
- | "waiting-first-response"
34
- | "running"
35
- | "retrying"
36
- | "completed"
37
- | "failed"
38
- | "cancelled"
39
- | "timed-out";
40
-
41
- export type PacketFailureReason =
42
- | "subagent failed"
43
- | "subagent cancelled"
44
- | "phase timed out";
45
-
46
- export interface PacketActivityEvent {
47
- state: PacketActivityState;
48
- requestId: string;
49
- role: string;
50
- phase: string;
51
- objective: string;
52
- sequence: number;
53
- attempt?: number;
54
- maxAttempts?: number;
55
- code?: string;
56
- wait?: string;
57
- failureReason?: PacketFailureReason;
58
- }
33
+ import type {
34
+ PacketActivityEvent,
35
+ PacketActivityObserver,
36
+ PacketActivityState,
37
+ } from "./activity-contracts.ts";
59
38
 
60
- export type PacketActivityObserver = (
61
- event: PacketActivityEvent,
62
- ) => void | Promise<void>;
39
+ export type {
40
+ PacketActivityEvent,
41
+ PacketActivityObserver,
42
+ PacketActivityState,
43
+ PacketFailureReason,
44
+ } from "./activity-contracts.ts";
63
45
 
64
46
  export type PacketDispatchResult =
65
47
  | {
@@ -78,7 +60,6 @@ export type PacketDispatchResult =
78
60
 
79
61
  export interface PacketRuntimeOptions {
80
62
  activation?: Activation;
81
- parentPayloadBridge: ParentPayloadBridge;
82
63
  routePolicy?: RoutePolicy;
83
64
  routePolicyHome?: string;
84
65
  environment?: Readonly<Record<string, string | undefined>>;
@@ -86,10 +67,7 @@ export interface PacketRuntimeOptions {
86
67
  childRunner?: PacketChildRunner;
87
68
  }
88
69
 
89
- export type PacketContext = Pick<
90
- ExtensionContext,
91
- "cwd" | "model" | "modelRegistry"
92
- >;
70
+ export type PacketContext = PackageContext;
93
71
 
94
72
  export type PacketChildRunner = (input: {
95
73
  packet: PacketEnvelope;
@@ -162,7 +140,6 @@ function syntheticChildFailure(
162
140
  export class PacketRuntime {
163
141
  readonly activation: Activation;
164
142
  readonly limits = LIMITS;
165
- readonly #parentPayloadBridge: ParentPayloadBridge;
166
143
  readonly #routePolicy?: RoutePolicy;
167
144
  readonly #routePolicyHome?: string;
168
145
  readonly #environment: Readonly<Record<string, string | undefined>>;
@@ -178,7 +155,6 @@ export class PacketRuntime {
178
155
 
179
156
  constructor(options: PacketRuntimeOptions) {
180
157
  this.activation = options.activation ?? new Activation();
181
- this.#parentPayloadBridge = options.parentPayloadBridge;
182
158
  this.#routePolicy = options.routePolicy;
183
159
  this.#routePolicyHome = options.routePolicyHome;
184
160
  this.#environment = options.environment ?? process.env;
@@ -375,10 +351,8 @@ export class PacketRuntime {
375
351
  const phase = await runtimeForWorkerRoute(
376
352
  attempt.route,
377
353
  context,
378
- this.#parentPayloadBridge,
379
354
  attempt.signal,
380
355
  this.#environment,
381
- { onResponse: attempt.onHeaders },
382
356
  );
383
357
  if (!phase.ok) {
384
358
  if (phase.failure.kind === "cancelled") {
@@ -422,19 +396,23 @@ export class PacketRuntime {
422
396
  ],
423
397
  timeoutMs: LIMITS.phaseTimeoutMs,
424
398
  signal: attempt.signal,
425
- failureOverride: phase.failureOverride,
399
+ onStreamStart: attempt.onRequestStart,
400
+ onStreamHeaders: attempt.onHeaders,
426
401
  onStreamProgress: attempt.onProgress,
427
402
  });
428
403
  brokerUsage.add(`attempt:${childAttempt++}`, child.usage);
429
404
  if (!child.ok && child.failure.kind === "transport") {
430
- throw new Error(child.failure.code);
405
+ throw transportFailureError(child.failure.code);
431
406
  }
432
407
  return { kind: "child" as const, child };
433
408
  },
434
409
  });
435
410
  if (!routed.ok) {
436
411
  const cancelled = routed.state === "cancelled" || signal.aborted;
437
- const timedOut = !cancelled && routed.code === "phase-timeout";
412
+ const timedOut =
413
+ !cancelled &&
414
+ (isTransportTimeoutCode(routed.code) ||
415
+ routed.code === "phase-timeout");
438
416
  return withBrokerUsage(
439
417
  syntheticChildFailure(
440
418
  cancelled ? "packet cancelled" : routed.code,
@@ -443,7 +421,9 @@ export class PacketRuntime {
443
421
  : timedOut
444
422
  ? {
445
423
  kind: "transport",
446
- code: "timeout",
424
+ code: isTransportTimeoutCode(routed.code)
425
+ ? routed.code
426
+ : "timeout",
447
427
  stage: "child-timeout",
448
428
  }
449
429
  : {
@@ -582,7 +562,6 @@ export class PacketRuntime {
582
562
  await this.cancel();
583
563
  this.#brokers.clear();
584
564
  this.#brokerPolicies.clear();
585
- this.#parentPayloadBridge.clear();
586
565
  }
587
566
 
588
567
  get state(): ActivationState {