@relayflows/sdk 2.0.35 → 2.0.37

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 (228) hide show
  1. package/dist/adapters/base.d.ts +16 -0
  2. package/dist/adapters/base.d.ts.map +1 -1
  3. package/dist/adapters/claude.d.ts.map +1 -1
  4. package/dist/adapters/claude.js +15 -0
  5. package/dist/adapters/claude.js.map +1 -1
  6. package/dist/adapters/codex.d.ts.map +1 -1
  7. package/dist/adapters/codex.js +4 -0
  8. package/dist/adapters/codex.js.map +1 -1
  9. package/dist/adapters/usage-limit.d.ts +2 -0
  10. package/dist/adapters/usage-limit.d.ts.map +1 -0
  11. package/dist/adapters/usage-limit.js +17 -0
  12. package/dist/adapters/usage-limit.js.map +1 -0
  13. package/dist/authored-activity.d.ts +17 -0
  14. package/dist/authored-activity.d.ts.map +1 -0
  15. package/dist/authored-activity.js +218 -0
  16. package/dist/authored-activity.js.map +1 -0
  17. package/dist/authored-child-run.d.ts +34 -0
  18. package/dist/authored-child-run.d.ts.map +1 -0
  19. package/dist/authored-child-run.js +128 -0
  20. package/dist/authored-child-run.js.map +1 -0
  21. package/dist/authored-flow-error.d.ts +32 -3
  22. package/dist/authored-flow-error.d.ts.map +1 -1
  23. package/dist/authored-flow-error.js +3 -1
  24. package/dist/authored-flow-error.js.map +1 -1
  25. package/dist/authored-flow-executor.d.ts +11 -1
  26. package/dist/authored-flow-executor.d.ts.map +1 -1
  27. package/dist/authored-flow-executor.js +32 -1
  28. package/dist/authored-flow-executor.js.map +1 -1
  29. package/dist/authored-helper-effect.d.ts.map +1 -1
  30. package/dist/authored-helper-effect.js +3 -2
  31. package/dist/authored-helper-effect.js.map +1 -1
  32. package/dist/authored-mcp.d.ts.map +1 -1
  33. package/dist/authored-mcp.js +4 -2
  34. package/dist/authored-mcp.js.map +1 -1
  35. package/dist/authored-node-entry.js +9 -1
  36. package/dist/authored-node-entry.js.map +1 -1
  37. package/dist/authored-node-runner.d.ts.map +1 -1
  38. package/dist/authored-node-runner.js +42 -9
  39. package/dist/authored-node-runner.js.map +1 -1
  40. package/dist/authored-plugin-effect.d.ts.map +1 -1
  41. package/dist/authored-plugin-effect.js +4 -2
  42. package/dist/authored-plugin-effect.js.map +1 -1
  43. package/dist/authored-preflight.d.ts +1 -1
  44. package/dist/authored-preflight.d.ts.map +1 -1
  45. package/dist/authored-preflight.js +2 -2
  46. package/dist/authored-preflight.js.map +1 -1
  47. package/dist/authored-root.d.ts +12 -7
  48. package/dist/authored-root.d.ts.map +1 -1
  49. package/dist/authored-root.js +24 -0
  50. package/dist/authored-root.js.map +1 -1
  51. package/dist/authored-step-output.d.ts +24 -8
  52. package/dist/authored-step-output.d.ts.map +1 -1
  53. package/dist/authored-step-output.js +81 -15
  54. package/dist/authored-step-output.js.map +1 -1
  55. package/dist/authored-subscription-park.d.ts +5 -0
  56. package/dist/authored-subscription-park.d.ts.map +1 -0
  57. package/dist/authored-subscription-park.js +47 -0
  58. package/dist/authored-subscription-park.js.map +1 -0
  59. package/dist/authored-verdict.d.ts +2 -0
  60. package/dist/authored-verdict.d.ts.map +1 -1
  61. package/dist/authored-verdict.js +2 -1
  62. package/dist/authored-verdict.js.map +1 -1
  63. package/dist/authored-worker-step.d.ts +1 -1
  64. package/dist/authored-worker-step.d.ts.map +1 -1
  65. package/dist/authored-worker-step.js +9 -4
  66. package/dist/authored-worker-step.js.map +1 -1
  67. package/dist/cli/check-activities.d.ts +8 -0
  68. package/dist/cli/check-activities.d.ts.map +1 -0
  69. package/dist/cli/check-activities.js +155 -0
  70. package/dist/cli/check-activities.js.map +1 -0
  71. package/dist/cli/check.d.ts +2 -0
  72. package/dist/cli/check.d.ts.map +1 -1
  73. package/dist/cli/check.js +3 -3
  74. package/dist/cli/check.js.map +1 -1
  75. package/dist/cli/cli-probe.d.ts +2 -2
  76. package/dist/cli/cli-probe.d.ts.map +1 -1
  77. package/dist/cli/cli-probe.js +22 -9
  78. package/dist/cli/cli-probe.js.map +1 -1
  79. package/dist/cli/direct-run.d.ts.map +1 -1
  80. package/dist/cli/direct-run.js +17 -4
  81. package/dist/cli/direct-run.js.map +1 -1
  82. package/dist/cli/run.d.ts +18 -5
  83. package/dist/cli/run.d.ts.map +1 -1
  84. package/dist/cli/run.js +37 -12
  85. package/dist/cli/run.js.map +1 -1
  86. package/dist/cli/subscription-report.d.ts +5 -0
  87. package/dist/cli/subscription-report.d.ts.map +1 -0
  88. package/dist/cli/subscription-report.js +48 -0
  89. package/dist/cli/subscription-report.js.map +1 -0
  90. package/dist/cli-adapter.d.ts +4 -2
  91. package/dist/cli-adapter.d.ts.map +1 -1
  92. package/dist/cli-adapter.js +4 -0
  93. package/dist/cli-adapter.js.map +1 -1
  94. package/dist/cli.d.ts +1 -1
  95. package/dist/cli.d.ts.map +1 -1
  96. package/dist/cli.js +13 -5
  97. package/dist/cli.js.map +1 -1
  98. package/dist/communication/local.d.ts +1 -1
  99. package/dist/communication/local.d.ts.map +1 -1
  100. package/dist/communication/local.js +2 -2
  101. package/dist/communication/local.js.map +1 -1
  102. package/dist/communication/worker.d.ts +1 -1
  103. package/dist/communication/worker.d.ts.map +1 -1
  104. package/dist/communication/worker.js +4 -4
  105. package/dist/communication/worker.js.map +1 -1
  106. package/dist/decimal-dollars.d.ts +12 -0
  107. package/dist/decimal-dollars.d.ts.map +1 -0
  108. package/dist/decimal-dollars.js +39 -0
  109. package/dist/decimal-dollars.js.map +1 -0
  110. package/dist/effect-channel.d.ts.map +1 -1
  111. package/dist/effect-channel.js +2 -0
  112. package/dist/effect-channel.js.map +1 -1
  113. package/dist/failure-kinds.d.ts +2 -2
  114. package/dist/failure-kinds.d.ts.map +1 -1
  115. package/dist/failure-kinds.js +2 -0
  116. package/dist/failure-kinds.js.map +1 -1
  117. package/dist/helper-instruction.d.ts +3 -0
  118. package/dist/helper-instruction.d.ts.map +1 -0
  119. package/dist/helper-instruction.js +3 -0
  120. package/dist/helper-instruction.js.map +1 -0
  121. package/dist/index.d.ts +1 -1
  122. package/dist/index.d.ts.map +1 -1
  123. package/dist/index.js.map +1 -1
  124. package/dist/journal-client.d.ts +21 -3
  125. package/dist/journal-client.d.ts.map +1 -1
  126. package/dist/journal-client.js +45 -6
  127. package/dist/journal-client.js.map +1 -1
  128. package/dist/journal-reader.d.ts.map +1 -1
  129. package/dist/journal-reader.js +2 -0
  130. package/dist/journal-reader.js.map +1 -1
  131. package/dist/llm-worker.d.ts +2 -1
  132. package/dist/llm-worker.d.ts.map +1 -1
  133. package/dist/llm-worker.js +7 -2
  134. package/dist/llm-worker.js.map +1 -1
  135. package/dist/local-agent-environment.d.ts +13 -0
  136. package/dist/local-agent-environment.d.ts.map +1 -0
  137. package/dist/local-agent-environment.js +104 -0
  138. package/dist/local-agent-environment.js.map +1 -0
  139. package/dist/local-agent.d.ts +4 -1
  140. package/dist/local-agent.d.ts.map +1 -1
  141. package/dist/local-agent.js +15 -5
  142. package/dist/local-agent.js.map +1 -1
  143. package/dist/preflight.d.ts +6 -0
  144. package/dist/preflight.d.ts.map +1 -1
  145. package/dist/preflight.js +36 -10
  146. package/dist/preflight.js.map +1 -1
  147. package/dist/protocol.d.ts +187 -1
  148. package/dist/protocol.d.ts.map +1 -1
  149. package/dist/reported-cost-total.d.ts +41 -0
  150. package/dist/reported-cost-total.d.ts.map +1 -0
  151. package/dist/reported-cost-total.js +63 -0
  152. package/dist/reported-cost-total.js.map +1 -0
  153. package/dist/reported-cost.d.ts +24 -0
  154. package/dist/reported-cost.d.ts.map +1 -0
  155. package/dist/reported-cost.js +49 -0
  156. package/dist/reported-cost.js.map +1 -0
  157. package/dist/run-state.d.ts +9 -11
  158. package/dist/run-state.d.ts.map +1 -1
  159. package/dist/run-state.js +15 -38
  160. package/dist/run-state.js.map +1 -1
  161. package/dist/step-settling.d.ts +11 -0
  162. package/dist/step-settling.d.ts.map +1 -0
  163. package/dist/step-settling.js +22 -0
  164. package/dist/step-settling.js.map +1 -0
  165. package/dist/worker-cli.d.ts +1 -1
  166. package/dist/worker-cli.d.ts.map +1 -1
  167. package/dist/worker-cli.js +3 -3
  168. package/dist/worker-cli.js.map +1 -1
  169. package/dist/worker.d.ts +2 -0
  170. package/dist/worker.d.ts.map +1 -1
  171. package/dist/worker.js +5 -2
  172. package/dist/worker.js.map +1 -1
  173. package/dist/yaml-helper-effect.d.ts.map +1 -1
  174. package/dist/yaml-helper-effect.js +2 -1
  175. package/dist/yaml-helper-effect.js.map +1 -1
  176. package/dist/yaml-helpers.d.ts.map +1 -1
  177. package/dist/yaml-helpers.js +2 -1
  178. package/dist/yaml-helpers.js.map +1 -1
  179. package/package.json +2 -2
  180. package/src/adapters/base.ts +19 -0
  181. package/src/adapters/claude.ts +15 -0
  182. package/src/adapters/codex.ts +6 -0
  183. package/src/adapters/usage-limit.ts +17 -0
  184. package/src/authored-activity.ts +251 -0
  185. package/src/authored-child-run.ts +138 -0
  186. package/src/authored-flow-error.ts +33 -0
  187. package/src/authored-flow-executor.ts +44 -1
  188. package/src/authored-helper-effect.ts +3 -2
  189. package/src/authored-mcp.ts +4 -2
  190. package/src/authored-node-entry.ts +11 -2
  191. package/src/authored-node-runner.ts +43 -9
  192. package/src/authored-plugin-effect.ts +4 -2
  193. package/src/authored-preflight.ts +2 -2
  194. package/src/authored-root.ts +34 -4
  195. package/src/authored-step-output.ts +88 -15
  196. package/src/authored-subscription-park.ts +46 -0
  197. package/src/authored-verdict.ts +2 -1
  198. package/src/authored-worker-step.ts +9 -3
  199. package/src/cli/check-activities.ts +144 -0
  200. package/src/cli/check.ts +6 -3
  201. package/src/cli/cli-probe.ts +23 -9
  202. package/src/cli/direct-run.ts +16 -1
  203. package/src/cli/run.ts +59 -14
  204. package/src/cli/subscription-report.ts +51 -0
  205. package/src/cli-adapter.ts +8 -2
  206. package/src/cli.ts +13 -6
  207. package/src/communication/local.ts +3 -2
  208. package/src/communication/worker.ts +7 -4
  209. package/src/decimal-dollars.ts +38 -0
  210. package/src/effect-channel.ts +2 -0
  211. package/src/failure-kinds.ts +2 -0
  212. package/src/helper-instruction.ts +2 -0
  213. package/src/index.ts +6 -0
  214. package/src/journal-client.ts +60 -7
  215. package/src/journal-reader.ts +2 -0
  216. package/src/llm-worker.ts +6 -1
  217. package/src/local-agent-environment.ts +92 -0
  218. package/src/local-agent.ts +19 -4
  219. package/src/preflight.ts +46 -10
  220. package/src/protocol.ts +151 -0
  221. package/src/reported-cost-total.ts +82 -0
  222. package/src/reported-cost.ts +51 -0
  223. package/src/run-state.ts +25 -37
  224. package/src/step-settling.ts +19 -0
  225. package/src/worker-cli.ts +3 -2
  226. package/src/worker.ts +9 -2
  227. package/src/yaml-helper-effect.ts +2 -1
  228. package/src/yaml-helpers.ts +2 -1
package/src/run-state.ts CHANGED
@@ -10,8 +10,13 @@
10
10
  // No I/O, no clock: the caller passes `now_ms`, so a test folds a hand-built
11
11
  // journal against a fixed instant and asserts exact elapsed and overdue values.
12
12
 
13
+ import { addDollars } from './decimal-dollars.js';
14
+ import { addReportedCost, modelFreeSteps, NO_REPORTED_COST, type ReportedCostTotal } from './reported-cost-total.js';
13
15
  import type { JournalEvent } from './journal-reader.js';
14
16
 
17
+ export { addDollars } from './decimal-dollars.js';
18
+ export type { ReportedCostTotal } from './reported-cost-total.js';
19
+
15
20
  export type RunStatus = 'running' | 'parked' | 'completed' | 'failed' | 'cancelling' | 'cancelled';
16
21
 
17
22
  /** `StepState` variant names from state.rs, snake_case. */
@@ -25,6 +30,7 @@ export interface Spend {
25
30
  dollars_unmetered: boolean;
26
31
  }
27
32
 
33
+
28
34
  export interface StepCounts {
29
35
  total: number;
30
36
  done: number;
@@ -91,6 +97,10 @@ export interface StepView {
91
97
  completion_reason: string | null;
92
98
  /** Paths the worker journaled for the last attempt, when its output carried them. */
93
99
  artifacts: { paths: string[]; journaled: boolean };
100
+ /** Metered charges of this step's attempts: what counted toward the budget. */
101
+ spend: Spend;
102
+ /** Actual cost of this step's attempts. Null until an attempt completes. */
103
+ reported_cost: ReportedCostTotal | null;
94
104
  }
95
105
 
96
106
  export interface RunView {
@@ -101,6 +111,8 @@ export interface RunView {
101
111
  spawned_at_ms: number;
102
112
  now_ms: number;
103
113
  spend: Spend;
114
+ /** Actual cost of this run's own attempts; see {@link ReportedCostTotal}. */
115
+ reported_cost: ReportedCostTotal;
104
116
  counts: StepCounts;
105
117
  steps: StepView[];
106
118
  }
@@ -127,42 +139,6 @@ function text(value: unknown, fallback = ''): string {
127
139
  return typeof value === 'string' ? value : fallback;
128
140
  }
129
141
 
130
- /**
131
- * Sum two decimal dollar strings exactly, at whatever scale they carry — the
132
- * kernel's budget fold (`relayflowd-core/src/state/budget.rs`) aligns every
133
- * fractional digit before adding, and it accepts arbitrary precision. Scaling
134
- * to a fixed six fractional digits dropped a charge of `0.0000001` to zero, so
135
- * `flows status` underreported spend the kernel had totalled exactly.
136
- *
137
- * A value that is not a decimal number is left out of the sum rather than
138
- * counted as zero, and the caller is told by `malformed`.
139
- */
140
- export function addDollars(left: string, right: string): string {
141
- const parsed = [left, right].map((value) => /^\d+(?:\.\d+)?$/.test(value) ? value : null);
142
- const usable = parsed.filter((value): value is string => value !== null);
143
- if (usable.length === 0) return '0';
144
- if (usable.length === 1) return normalizeDollars(usable[0]!);
145
- const scale = Math.max(...usable.map((value) => (value.split('.')[1] ?? '').length));
146
- const scaled = usable.map((value) => {
147
- const [whole, fraction = ''] = value.split('.');
148
- return BigInt(`${whole}${fraction.padEnd(scale, '0')}`);
149
- });
150
- return fromScaled(scaled[0]! + scaled[1]!, scale);
151
- }
152
-
153
- /** `12.3400` -> `12.34`, `0.000` -> `0`; the journal's own spelling otherwise. */
154
- function normalizeDollars(value: string): string {
155
- const [whole, fraction = ''] = value.split('.');
156
- return fromScaled(BigInt(`${whole}${fraction}`), fraction.length);
157
- }
158
-
159
- function fromScaled(total: bigint, scale: number): string {
160
- if (scale === 0) return String(total);
161
- const digits = String(total).padStart(scale + 1, '0');
162
- const whole = digits.slice(0, digits.length - scale);
163
- const fraction = digits.slice(digits.length - scale).replace(/0+$/, '');
164
- return fraction.length === 0 ? whole : `${whole}.${fraction}`;
165
- }
166
142
 
167
143
  /**
168
144
  * Reduce `trajectory_tail.transcript` (the digest flows#491 journals) to the
@@ -209,6 +185,7 @@ function addSpend(total: Spend, charge: unknown): Spend {
209
185
 
210
186
  const ZERO_SPEND: Spend = { tokens_in: 0, tokens_out: 0, dollars: '0', dollars_unmetered: false };
211
187
 
188
+
212
189
  interface StepFold {
213
190
  view: StepView;
214
191
  depends_on: string[];
@@ -221,6 +198,7 @@ function freshStep(id: string, type: string, maxIterations: number | null, depen
221
198
  id, type, state: 'pending', attempt: 0, max_iterations: maxIterations,
222
199
  started_at_ms: null, elapsed_ms: null, lease: null, backoff_until_ms: null, wait: null,
223
200
  last_attempt: null, completion_reason: null, artifacts: { paths: [], journaled: false },
201
+ spend: ZERO_SPEND, reported_cost: null,
224
202
  },
225
203
  };
226
204
  }
@@ -268,6 +246,8 @@ export function foldRunState(events: readonly JournalEvent[], now_ms: number): R
268
246
  // An authored child run carries its parent's totals so ceilings hold across
269
247
  // the family (state.rs `prior_spend`); the view reports the same running total.
270
248
  let spend = addSpend(ZERO_SPEND, budget['prior_spend']);
249
+ let reportedCost = NO_REPORTED_COST;
250
+ const modelFree = modelFreeSteps(first);
271
251
  let completion: string | null = null;
272
252
  let cancelRequested = false;
273
253
 
@@ -297,6 +277,9 @@ export function foldRunState(events: readonly JournalEvent[], now_ms: number): R
297
277
  const attempt = event.attempt ?? view.attempt;
298
278
  view.attempt = Math.max(view.attempt, attempt);
299
279
  spend = addSpend(spend, payload['budget']);
280
+ view.spend = addSpend(view.spend, payload['budget']);
281
+ reportedCost = addReportedCost(reportedCost, payload, modelFree.has(view.id));
282
+ view.reported_cost = addReportedCost(view.reported_cost ?? NO_REPORTED_COST, payload, modelFree.has(view.id));
300
283
  const verification = payload['verification'] !== null && typeof payload['verification'] === 'object'
301
284
  ? payload['verification'] as Payload : undefined;
302
285
  view.last_attempt = {
@@ -362,8 +345,12 @@ export function foldRunState(events: readonly JournalEvent[], now_ms: number): R
362
345
  // A new epoch restarts every step (state.rs `apply_epoch`); the
363
346
  // summary then restores the ones it carries forward.
364
347
  for (const step of steps.values()) {
365
- const { id, type, max_iterations } = step.view;
348
+ const { id, type, max_iterations, spend: stepSpend, reported_cost: stepCost } = step.view;
366
349
  step.view = freshStep(id, type, max_iterations, step.depends_on).view;
350
+ // Rollover keeps the earlier segments' completions in the journal,
351
+ // and this fold has already read them: what the step cost stays.
352
+ step.view.spend = stepSpend;
353
+ step.view.reported_cost = stepCost;
367
354
  }
368
355
  spend = addSpend(ZERO_SPEND, payload['budget_spent']);
369
356
  const done = payload['steps_done'] !== null && typeof payload['steps_done'] === 'object' ? payload['steps_done'] as Payload : {};
@@ -462,6 +449,7 @@ export function foldRunState(events: readonly JournalEvent[], now_ms: number): R
462
449
  spawned_at_ms: first.at_ms,
463
450
  now_ms,
464
451
  spend,
452
+ reported_cost: reportedCost,
465
453
  counts,
466
454
  steps: views,
467
455
  };
@@ -0,0 +1,19 @@
1
+ /**
2
+ * A step's LAST settling `step.completed`: the verdict the kernel settled the
3
+ * step on. `retry` and `park` completions record an attempt the kernel did
4
+ * NOT settle it on (relayflowd-core `Disposition`) — crash recovery's
5
+ * `crashed`, a `worker_error` with iterations left — and precede the attempt
6
+ * that did, so neither the first completion nor a completion count is the
7
+ * step's verdict. Shared by the authored reader and the Bun result verifier,
8
+ * which must agree on which completion a claim is judged against.
9
+ */
10
+ export function settlingCompletion<T>(entries: readonly T[], stepId: string): T | undefined {
11
+ return entries.filter(entry => {
12
+ if (typeof entry !== 'object' || entry === null) return false;
13
+ const { entry_type: type, step_id: step, payload } = entry as Record<string, unknown>;
14
+ if (type !== 'step.completed' || step !== stepId) return false;
15
+ const disposition = typeof payload === 'object' && payload !== null
16
+ ? (payload as Record<string, unknown>)['disposition'] : undefined;
17
+ return disposition !== 'retry' && disposition !== 'park';
18
+ }).at(-1);
19
+ }
package/src/worker-cli.ts CHANGED
@@ -91,6 +91,7 @@ export async function runAgentCli(
91
91
  cwd?: string,
92
92
  transport: AgentTransport = 'direct',
93
93
  relayContext?: AgentRelayContext,
94
+ processEnvironment: NodeJS.ProcessEnv = process.env,
94
95
  ): Promise<WorkerCliResult> {
95
96
  signal?.throwIfAborted();
96
97
  if (signal !== undefined && process.platform === 'win32') {
@@ -134,7 +135,7 @@ export async function runAgentCli(
134
135
  if (kind === 'relayflows-wrapper-v1') {
135
136
  // The closed allowlist admits no ambient RELAYFLOW_* value; the four
136
137
  // discovery names are set from this dispatch, exactly as for a direct spawn.
137
- const wrapperEnv = wrapperEnvironment(process.env);
138
+ const wrapperEnv = wrapperEnvironment(processEnvironment);
138
139
  applyStepEnvironment(wrapperEnv, sidechannel);
139
140
  return requirePricedUsage(decodeWrapperResult(await runWrapperSession(
140
141
  cli,
@@ -148,7 +149,7 @@ export async function runAgentCli(
148
149
  )), effectiveModel);
149
150
  }
150
151
 
151
- const env: NodeJS.ProcessEnv = { ...process.env };
152
+ const env: NodeJS.ProcessEnv = { ...processEnvironment };
152
153
  delete env[WAKE_CONTEXT_ENV];
153
154
  delete env[MODEL_ENV];
154
155
  // Where this attempt's journal is, so the agent can run `flows status` on
package/src/worker.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import { communicationInstruction } from './communication/spec.js';
2
2
  import { workerSpend } from './worker-spend.js';
3
+ import { reportedCost } from './reported-cost.js';
3
4
  import type { WorkerCliResult } from './worker-cli.js';
4
5
  import { EventEmitter } from 'node:events';
5
6
  import type { JournalClient } from './journal-client.js';
@@ -31,6 +32,8 @@ export interface AgentWorkerOptions {
31
32
  * the root a dispatch is measured against is a value, not an assumption.
32
33
  */
33
34
  runRoot?: string;
35
+ /** Environment inherited by provider CLIs, including agent-only secrets. */
36
+ environment?: NodeJS.ProcessEnv;
34
37
  }
35
38
 
36
39
  /**
@@ -122,7 +125,8 @@ export class AgentWorker extends EventEmitter {
122
125
  if (communication) {
123
126
  if (!this.options.dataDir) throw new Error('Agent communication requires a worker data directory');
124
127
  const { completeCommunicationDispatch } = await import('./communication/worker.js');
125
- await completeCommunicationDispatch(this.client, dispatch, communication, this.options.dataDir, this.options.runRoot);
128
+ await completeCommunicationDispatch(this.client, dispatch, communication, this.options.dataDir,
129
+ this.options.runRoot, this.options.environment);
126
130
  return;
127
131
  }
128
132
  let humanIntervention = false;
@@ -142,9 +146,11 @@ export class AgentWorker extends EventEmitter {
142
146
  }, cwd.directory ?? (spec.transport === 'relay' ? undefined : this.options.runRoot),
143
147
  spec.transport === 'relay' ? 'relay' : 'direct',
144
148
  { runId: dispatch.run_id, stepId: dispatch.step_id, idempotencyKey: dispatch.idempotency_key,
145
- dataDir: this.options.dataDir, resultSchema: spec.verification?.json_schema })
149
+ dataDir: this.options.dataDir, resultSchema: spec.verification?.json_schema },
150
+ this.options.environment)
146
151
  : Promise.resolve({ exit_code: null, stdout_tail: '', stderr_tail: 'agent step has no declared CLI' }));
147
152
  const { result, usage } = workerSpend(completed, effectiveModel);
153
+ const cost = reportedCost(completed, effectiveModel);
148
154
  const completionReason = result.exit_code === 0 ? 'success' : 'worker_error';
149
155
 
150
156
  // Output shape: if the CLI's stdout parses as JSON, promote THAT
@@ -195,6 +201,7 @@ export class AgentWorker extends EventEmitter {
195
201
  ...(Object.keys(trajectoryTail).length === 0 ? {} : { trajectory_tail: trajectoryTail }),
196
202
  ...(humanIntervention ? { human_intervention: true } : {}),
197
203
  ...(usage !== undefined ? { usage } : {}),
204
+ ...(cost === undefined ? {} : { reported_cost: cost }),
198
205
  started_pins: dispatch.pins,
199
206
  end_pins: dispatch.pins,
200
207
  },
@@ -8,6 +8,7 @@ import type { StepDispatchEvent } from './protocol.js';
8
8
  import { atomicJson, readSlackReceipt, receiptPath, slackWriteback } from './slack-writeback.js';
9
9
  import { invokeHelper, type HelperCall } from './yaml-helpers.js';
10
10
  import { withWorkerLease } from './worker-lease.js';
11
+ import { NO_MODEL_COST } from './reported-cost.js';
11
12
 
12
13
  export function helperMount(provider: string, env = process.env): string | undefined {
13
14
  const root = [env.RELAYFILE_MOUNT_PATH, env.WORKSPACE_ROOT, env.WORKFORCE_SANDBOX_ROOT,
@@ -73,6 +74,6 @@ export async function completeHelperDispatch(
73
74
  return { ...call, idempotencyKey: `${dispatch.run_id}:${dispatch.step_id}`, receipt };
74
75
  });
75
76
  await client.stepComplete(dispatch.run_id, dispatch.step_id, dispatch.attempt,
76
- dispatch.idempotency_key, 'success', { output, started_pins: dispatch.pins, end_pins: dispatch.pins,
77
+ dispatch.idempotency_key, 'success', { output, started_pins: dispatch.pins, end_pins: dispatch.pins, reported_cost: NO_MODEL_COST,
77
78
  effects: [{ surface_path: surfacePath, idempotency_key: dispatch.idempotency_key }] });
78
79
  }
@@ -3,6 +3,7 @@ import { githubClient, linearClient, slackClient, type RelayTransport } from '@r
3
3
  import type { AgentStepSpec, KernelAgentStep, YamlHelperParams } from './spec.js';
4
4
  import { canonicalize } from './canonical.js';
5
5
  import { unknownKeyErrors } from './unknown-keys.js';
6
+ import { HELPER_INSTRUCTION_PREFIX } from './helper-instruction.js';
6
7
 
7
8
  const string = { type: 'string', minLength: 1 };
8
9
  const text = { type: 'string' };
@@ -61,7 +62,7 @@ export type HelperCall = { [P in keyof YamlHelperParams]: { [V in keyof YamlHelp
61
62
  { type: 'effect'; provider: P; verb: V; params: YamlHelperParams[P][V] }
62
63
  }[keyof YamlHelperParams[P]] }[keyof YamlHelperParams];
63
64
 
64
- const prefix = 'relayflows:helper:v1\n';
65
+ const prefix = HELPER_INSTRUCTION_PREFIX;
65
66
  const commonFields = ['id', 'dependsOn', 'maxIterations', 'verification', 'output'] as const;
66
67
  const isObject = (value: unknown): value is Record<string, unknown> =>
67
68
  value !== null && typeof value === 'object' && !Array.isArray(value);