@sweny-ai/core 0.1.156 → 0.1.158

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/schema.d.ts CHANGED
@@ -848,6 +848,26 @@ export declare const nodePermissionsZ: z.ZodUnion<[z.ZodEnum<["read", "write"]>,
848
848
  deny?: ("shell" | "write" | "edit" | "net" | "subagent")[] | undefined;
849
849
  access?: "write" | "read" | undefined;
850
850
  }>]>;
851
+ /**
852
+ * Spend ceiling (#449): input + output tokens and/or reported USD. The object
853
+ * must declare at least one of the two.
854
+ */
855
+ export declare const budgetZ: z.ZodEffects<z.ZodObject<{
856
+ tokens: z.ZodOptional<z.ZodNumber>;
857
+ cost_usd: z.ZodOptional<z.ZodNumber>;
858
+ }, "strict", z.ZodTypeAny, {
859
+ tokens?: number | undefined;
860
+ cost_usd?: number | undefined;
861
+ }, {
862
+ tokens?: number | undefined;
863
+ cost_usd?: number | undefined;
864
+ }>, {
865
+ tokens?: number | undefined;
866
+ cost_usd?: number | undefined;
867
+ }, {
868
+ tokens?: number | undefined;
869
+ cost_usd?: number | undefined;
870
+ }>;
851
871
  /** One typed write intent a node may emit (#365). */
852
872
  export declare const safeOutputDeclarationZ: z.ZodObject<{
853
873
  type: z.ZodEnum<["comment", "issue", "pr", "label", "issue_state"]>;
@@ -940,6 +960,22 @@ export declare const nodeZ: z.ZodObject<{
940
960
  skills: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
941
961
  output: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
942
962
  max_turns: z.ZodOptional<z.ZodNumber>;
963
+ budget: z.ZodOptional<z.ZodEffects<z.ZodObject<{
964
+ tokens: z.ZodOptional<z.ZodNumber>;
965
+ cost_usd: z.ZodOptional<z.ZodNumber>;
966
+ }, "strict", z.ZodTypeAny, {
967
+ tokens?: number | undefined;
968
+ cost_usd?: number | undefined;
969
+ }, {
970
+ tokens?: number | undefined;
971
+ cost_usd?: number | undefined;
972
+ }>, {
973
+ tokens?: number | undefined;
974
+ cost_usd?: number | undefined;
975
+ }, {
976
+ tokens?: number | undefined;
977
+ cost_usd?: number | undefined;
978
+ }>>;
943
979
  disallowed_tools: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
944
980
  tools: z.ZodOptional<z.ZodEffects<z.ZodObject<{
945
981
  allow: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
@@ -1426,6 +1462,10 @@ export declare const nodeZ: z.ZodObject<{
1426
1462
  model?: string | undefined;
1427
1463
  on_fail?: "halt" | "continue" | undefined;
1428
1464
  max_turns?: number | undefined;
1465
+ budget?: {
1466
+ tokens?: number | undefined;
1467
+ cost_usd?: number | undefined;
1468
+ } | undefined;
1429
1469
  disallowed_tools?: string[] | undefined;
1430
1470
  fail_soft?: boolean | undefined;
1431
1471
  permissions?: "write" | "read" | {
@@ -1540,6 +1580,10 @@ export declare const nodeZ: z.ZodObject<{
1540
1580
  on_fail?: "halt" | "continue" | undefined;
1541
1581
  skills?: string[] | undefined;
1542
1582
  max_turns?: number | undefined;
1583
+ budget?: {
1584
+ tokens?: number | undefined;
1585
+ cost_usd?: number | undefined;
1586
+ } | undefined;
1543
1587
  disallowed_tools?: string[] | undefined;
1544
1588
  fail_soft?: boolean | undefined;
1545
1589
  permissions?: "write" | "read" | {
@@ -1698,6 +1742,22 @@ export declare const workflowZ: z.ZodObject<{
1698
1742
  skills: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
1699
1743
  output: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
1700
1744
  max_turns: z.ZodOptional<z.ZodNumber>;
1745
+ budget: z.ZodOptional<z.ZodEffects<z.ZodObject<{
1746
+ tokens: z.ZodOptional<z.ZodNumber>;
1747
+ cost_usd: z.ZodOptional<z.ZodNumber>;
1748
+ }, "strict", z.ZodTypeAny, {
1749
+ tokens?: number | undefined;
1750
+ cost_usd?: number | undefined;
1751
+ }, {
1752
+ tokens?: number | undefined;
1753
+ cost_usd?: number | undefined;
1754
+ }>, {
1755
+ tokens?: number | undefined;
1756
+ cost_usd?: number | undefined;
1757
+ }, {
1758
+ tokens?: number | undefined;
1759
+ cost_usd?: number | undefined;
1760
+ }>>;
1701
1761
  disallowed_tools: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
1702
1762
  tools: z.ZodOptional<z.ZodEffects<z.ZodObject<{
1703
1763
  allow: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
@@ -2184,6 +2244,10 @@ export declare const workflowZ: z.ZodObject<{
2184
2244
  model?: string | undefined;
2185
2245
  on_fail?: "halt" | "continue" | undefined;
2186
2246
  max_turns?: number | undefined;
2247
+ budget?: {
2248
+ tokens?: number | undefined;
2249
+ cost_usd?: number | undefined;
2250
+ } | undefined;
2187
2251
  disallowed_tools?: string[] | undefined;
2188
2252
  fail_soft?: boolean | undefined;
2189
2253
  permissions?: "write" | "read" | {
@@ -2298,6 +2362,10 @@ export declare const workflowZ: z.ZodObject<{
2298
2362
  on_fail?: "halt" | "continue" | undefined;
2299
2363
  skills?: string[] | undefined;
2300
2364
  max_turns?: number | undefined;
2365
+ budget?: {
2366
+ tokens?: number | undefined;
2367
+ cost_usd?: number | undefined;
2368
+ } | undefined;
2301
2369
  disallowed_tools?: string[] | undefined;
2302
2370
  fail_soft?: boolean | undefined;
2303
2371
  permissions?: "write" | "read" | {
@@ -2547,6 +2615,23 @@ export declare const workflowZ: z.ZodObject<{
2547
2615
  judge_model: z.ZodOptional<z.ZodString>;
2548
2616
  model: z.ZodOptional<z.ZodString>;
2549
2617
  judge_budget: z.ZodOptional<z.ZodNumber>;
2618
+ budget: z.ZodOptional<z.ZodEffects<z.ZodObject<{
2619
+ tokens: z.ZodOptional<z.ZodNumber>;
2620
+ cost_usd: z.ZodOptional<z.ZodNumber>;
2621
+ }, "strict", z.ZodTypeAny, {
2622
+ tokens?: number | undefined;
2623
+ cost_usd?: number | undefined;
2624
+ }, {
2625
+ tokens?: number | undefined;
2626
+ cost_usd?: number | undefined;
2627
+ }>, {
2628
+ tokens?: number | undefined;
2629
+ cost_usd?: number | undefined;
2630
+ }, {
2631
+ tokens?: number | undefined;
2632
+ cost_usd?: number | undefined;
2633
+ }>>;
2634
+ context_mode: z.ZodOptional<z.ZodEnum<["bounded", "full"]>>;
2550
2635
  inputs: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodEffects<z.ZodObject<{
2551
2636
  type: z.ZodEnum<["string", "number", "boolean", "string[]"]>;
2552
2637
  description: z.ZodOptional<z.ZodString>;
@@ -2657,6 +2742,10 @@ export declare const workflowZ: z.ZodObject<{
2657
2742
  model?: string | undefined;
2658
2743
  on_fail?: "halt" | "continue" | undefined;
2659
2744
  max_turns?: number | undefined;
2745
+ budget?: {
2746
+ tokens?: number | undefined;
2747
+ cost_usd?: number | undefined;
2748
+ } | undefined;
2660
2749
  disallowed_tools?: string[] | undefined;
2661
2750
  fail_soft?: boolean | undefined;
2662
2751
  permissions?: "write" | "read" | {
@@ -2761,6 +2850,10 @@ export declare const workflowZ: z.ZodObject<{
2761
2850
  }[];
2762
2851
  entry: string;
2763
2852
  model?: string | undefined;
2853
+ budget?: {
2854
+ tokens?: number | undefined;
2855
+ cost_usd?: number | undefined;
2856
+ } | undefined;
2764
2857
  permissions?: "write" | "read" | {
2765
2858
  strict?: boolean | undefined;
2766
2859
  deny?: ("shell" | "write" | "edit" | "net" | "subagent")[] | undefined;
@@ -2785,6 +2878,7 @@ export declare const workflowZ: z.ZodObject<{
2785
2878
  judge_model?: string | undefined;
2786
2879
  workflow_type?: "pr_review" | "e2e_test" | "content_generation" | "monitor" | "data_sync" | "generic" | undefined;
2787
2880
  judge_budget?: number | undefined;
2881
+ context_mode?: "full" | "bounded" | undefined;
2788
2882
  inputs?: Record<string, {
2789
2883
  type: "string" | "number" | "boolean" | "string[]";
2790
2884
  description?: string | undefined;
@@ -2822,6 +2916,10 @@ export declare const workflowZ: z.ZodObject<{
2822
2916
  on_fail?: "halt" | "continue" | undefined;
2823
2917
  skills?: string[] | undefined;
2824
2918
  max_turns?: number | undefined;
2919
+ budget?: {
2920
+ tokens?: number | undefined;
2921
+ cost_usd?: number | undefined;
2922
+ } | undefined;
2825
2923
  disallowed_tools?: string[] | undefined;
2826
2924
  fail_soft?: boolean | undefined;
2827
2925
  permissions?: "write" | "read" | {
@@ -2940,6 +3038,10 @@ export declare const workflowZ: z.ZodObject<{
2940
3038
  env?: Record<string, string> | undefined;
2941
3039
  } | undefined;
2942
3040
  }> | undefined;
3041
+ budget?: {
3042
+ tokens?: number | undefined;
3043
+ cost_usd?: number | undefined;
3044
+ } | undefined;
2943
3045
  permissions?: "write" | "read" | {
2944
3046
  strict?: boolean | undefined;
2945
3047
  deny?: ("shell" | "write" | "edit" | "net" | "subagent")[] | undefined;
@@ -2964,6 +3066,7 @@ export declare const workflowZ: z.ZodObject<{
2964
3066
  judge_model?: string | undefined;
2965
3067
  workflow_type?: "pr_review" | "e2e_test" | "content_generation" | "monitor" | "data_sync" | "generic" | undefined;
2966
3068
  judge_budget?: number | undefined;
3069
+ context_mode?: "full" | "bounded" | undefined;
2967
3070
  inputs?: Record<string, {
2968
3071
  type: "string" | "number" | "boolean" | "string[]";
2969
3072
  description?: string | undefined;
@@ -3029,6 +3132,10 @@ export declare function parseWorkflow(raw: unknown): {
3029
3132
  model?: string | undefined;
3030
3133
  on_fail?: "halt" | "continue" | undefined;
3031
3134
  max_turns?: number | undefined;
3135
+ budget?: {
3136
+ tokens?: number | undefined;
3137
+ cost_usd?: number | undefined;
3138
+ } | undefined;
3032
3139
  disallowed_tools?: string[] | undefined;
3033
3140
  fail_soft?: boolean | undefined;
3034
3141
  permissions?: "write" | "read" | {
@@ -3133,6 +3240,10 @@ export declare function parseWorkflow(raw: unknown): {
3133
3240
  }[];
3134
3241
  entry: string;
3135
3242
  model?: string | undefined;
3243
+ budget?: {
3244
+ tokens?: number | undefined;
3245
+ cost_usd?: number | undefined;
3246
+ } | undefined;
3136
3247
  permissions?: "write" | "read" | {
3137
3248
  strict?: boolean | undefined;
3138
3249
  deny?: ("shell" | "write" | "edit" | "net" | "subagent")[] | undefined;
@@ -3157,6 +3268,7 @@ export declare function parseWorkflow(raw: unknown): {
3157
3268
  judge_model?: string | undefined;
3158
3269
  workflow_type?: "pr_review" | "e2e_test" | "content_generation" | "monitor" | "data_sync" | "generic" | undefined;
3159
3270
  judge_budget?: number | undefined;
3271
+ context_mode?: "full" | "bounded" | undefined;
3160
3272
  inputs?: Record<string, {
3161
3273
  type: "string" | "number" | "boolean" | "string[]";
3162
3274
  description?: string | undefined;
@@ -3174,7 +3286,7 @@ export declare function parseWorkflow(raw: unknown): {
3174
3286
  } | undefined;
3175
3287
  };
3176
3288
  export interface WorkflowError {
3177
- code: "MISSING_ENTRY" | "UNKNOWN_EDGE_SOURCE" | "UNKNOWN_EDGE_TARGET" | "UNREACHABLE_NODE" | "UNKNOWN_SKILL" | "SELF_LOOP" | "UNBOUNDED_CYCLE" | "AMBIGUOUS_EDGES" | "UNSUPPORTED_EVAL_POLICY" | "INVALID_INLINE_SKILL" | "EDGE_ITERATIONS_EXCEEDED" | "RETRY_MAX_EXCEEDED" | "PERMISSION_CEILING" | "OUTPUT_NOT_ALLOWED" | "DUPLICATE_OUTPUT" | "UNSUPPORTED_OUTPUT";
3289
+ code: "MISSING_ENTRY" | "UNKNOWN_EDGE_SOURCE" | "UNKNOWN_EDGE_TARGET" | "UNREACHABLE_NODE" | "UNKNOWN_SKILL" | "SELF_LOOP" | "UNBOUNDED_CYCLE" | "AMBIGUOUS_EDGES" | "UNSUPPORTED_EVAL_POLICY" | "INVALID_INLINE_SKILL" | "EDGE_ITERATIONS_EXCEEDED" | "RETRY_MAX_EXCEEDED" | "PERMISSION_CEILING" | "BUDGET_CEILING" | "OUTPUT_NOT_ALLOWED" | "DUPLICATE_OUTPUT" | "UNSUPPORTED_OUTPUT";
3178
3290
  message: string;
3179
3291
  nodeId?: string;
3180
3292
  }
@@ -3434,6 +3546,24 @@ export declare const workflowJsonSchema: {
3434
3546
  };
3435
3547
  }];
3436
3548
  };
3549
+ readonly Budget: {
3550
+ readonly type: "object";
3551
+ readonly additionalProperties: false;
3552
+ readonly minProperties: 1;
3553
+ readonly description: "A spend ceiling. 'tokens' counts input plus output tokens as the harness reports them; 'cost_usd' is the harness-reported cost (never estimated). A crossing stops the agent and fails the node; the run halts.";
3554
+ readonly properties: {
3555
+ readonly tokens: {
3556
+ readonly type: "integer";
3557
+ readonly minimum: 1;
3558
+ readonly description: "Max input plus output tokens.";
3559
+ };
3560
+ readonly cost_usd: {
3561
+ readonly type: "number";
3562
+ readonly exclusiveMinimum: 0;
3563
+ readonly description: "Max reported cost in USD.";
3564
+ };
3565
+ };
3566
+ };
3437
3567
  readonly SafeOutput: {
3438
3568
  readonly type: "object";
3439
3569
  readonly required: readonly ["type"];
@@ -3610,6 +3740,15 @@ export declare const workflowJsonSchema: {
3610
3740
  readonly minimum: 0;
3611
3741
  readonly description: "Soft cap on expected judge calls per workflow run. Executor warns at load time if exceeded; not a hard runtime cap in v1.";
3612
3742
  };
3743
+ readonly budget: {
3744
+ readonly $ref: "#/$defs/Budget";
3745
+ readonly description: "Spend ceiling for the whole run and for every node. A node's own budget may only narrow it. The CLI's --max-tokens and --max-cost tighten it further.";
3746
+ };
3747
+ readonly context_mode: {
3748
+ readonly type: "string";
3749
+ readonly enum: readonly ["bounded", "full"];
3750
+ readonly description: "What prior results a node's prompt receives. bounded (default): only nodes it can depend on, and a schema'd node's declared fields instead of its free-text summary. full: every prior node's complete data.";
3751
+ };
3613
3752
  readonly inputs: {
3614
3753
  readonly type: "object";
3615
3754
  readonly description: "Declared per-run input contract. Each entry names a parameter the caller may supply via --input. The CLI validates against this declaration, applies defaults for omitted optional fields, and rejects unknown types before the executor runs. Optional; workflows without an inputs block accept any JSON object (back-compat).";
@@ -3770,6 +3909,10 @@ export declare const workflowJsonSchema: {
3770
3909
  readonly minimum: 1;
3771
3910
  readonly description: "Max AI model turns for this node. When absent, the executor's default applies.";
3772
3911
  };
3912
+ readonly budget: {
3913
+ readonly $ref: "#/$defs/Budget";
3914
+ readonly description: "Spend ceiling for one visit to this node, retry attempts included. Never above the workflow's budget. Crossing it stops the agent and fails the node (fail_soft and on_fail: continue do not apply) and the run halts.";
3915
+ };
3773
3916
  readonly disallowed_tools: {
3774
3917
  readonly type: "array";
3775
3918
  readonly items: {
package/dist/schema.js CHANGED
@@ -7,7 +7,7 @@
7
7
  * parsing untrusted input (JSON/YAML import, Studio editor).
8
8
  */
9
9
  import { z } from "zod";
10
- import { AUTHOR_ASSOCIATIONS, EVALUATOR_KINDS, EVAL_POLICIES, MCP_TRANSPORTS, NODE_ACCESS, NODE_ON_FAIL, REQUIRES_ON_FAIL, SAFE_OUTPUT_APPLIERS, SAFE_OUTPUT_EXPIRES_PATTERN, SAFE_OUTPUT_MAX_CEILING, SAFE_OUTPUT_STATES, SAFE_OUTPUT_TYPES, SKILL_CATEGORIES, SKILL_ID_MAX_LENGTH, SKILL_ID_PATTERN, TOOL_ACCESS, TOOL_CLASSES, WORKFLOW_TYPES, } from "./types.js";
10
+ import { AUTHOR_ASSOCIATIONS, CONTEXT_MODES, EVALUATOR_KINDS, EVAL_POLICIES, MCP_TRANSPORTS, NODE_ACCESS, NODE_ON_FAIL, REQUIRES_ON_FAIL, SAFE_OUTPUT_APPLIERS, SAFE_OUTPUT_EXPIRES_PATTERN, SAFE_OUTPUT_MAX_CEILING, SAFE_OUTPUT_STATES, SAFE_OUTPUT_TYPES, SKILL_CATEGORIES, SKILL_ID_MAX_LENGTH, SKILL_ID_PATTERN, TOOL_ACCESS, TOOL_CLASSES, WORKFLOW_TYPES, } from "./types.js";
11
11
  import { sourceZ } from "./sources.js";
12
12
  import { workflowInputsZ, WORKFLOW_INPUT_TYPES } from "./inputs.js";
13
13
  export { sourceZ };
@@ -262,6 +262,19 @@ export const nodePermissionsZ = z.union([
262
262
  message: "permissions must declare at least one of access, deny, strict",
263
263
  }),
264
264
  ]);
265
+ /**
266
+ * Spend ceiling (#449): input + output tokens and/or reported USD. The object
267
+ * must declare at least one of the two.
268
+ */
269
+ export const budgetZ = z
270
+ .object({
271
+ tokens: z.number().int().min(1).optional(),
272
+ cost_usd: z.number().positive().optional(),
273
+ })
274
+ .strict()
275
+ .refine((b) => b.tokens !== undefined || b.cost_usd !== undefined, {
276
+ message: "budget must declare at least one of tokens, cost_usd",
277
+ });
265
278
  /** One typed write intent a node may emit (#365). */
266
279
  export const safeOutputDeclarationZ = z
267
280
  .object({
@@ -296,6 +309,7 @@ export const nodeZ = z
296
309
  skills: z.array(z.string()).default([]),
297
310
  output: jsonSchemaZ.optional(),
298
311
  max_turns: z.number().int().min(1).optional(),
312
+ budget: budgetZ.optional(),
299
313
  disallowed_tools: z.array(z.string().min(1)).optional(),
300
314
  tools: nodeToolsZ.optional(),
301
315
  fail_soft: z.boolean().optional(),
@@ -353,6 +367,8 @@ export const workflowZ = z.object({
353
367
  judge_model: z.string().min(1).optional(),
354
368
  model: z.string().min(1).optional(),
355
369
  judge_budget: z.number().int().min(0).optional(),
370
+ budget: budgetZ.optional(),
371
+ context_mode: z.enum(CONTEXT_MODES).optional(),
356
372
  inputs: workflowInputsZ.optional(),
357
373
  permissions: nodePermissionsZ.optional(),
358
374
  safe_outputs: safeOutputsPolicyZ.optional(),
@@ -610,6 +626,27 @@ export function validateWorkflow(workflow, knownSkills) {
610
626
  nodeId,
611
627
  });
612
628
  }
629
+ // Budgets (#449): the workflow's `budget` is the ceiling for every node.
630
+ const wfBudget = workflow.budget;
631
+ const nodeBudget = node.budget;
632
+ if (wfBudget && nodeBudget) {
633
+ if (wfBudget.tokens !== undefined && nodeBudget.tokens !== undefined && nodeBudget.tokens > wfBudget.tokens) {
634
+ errors.push({
635
+ code: "BUDGET_CEILING",
636
+ message: `Node "${nodeId}" declares budget.tokens ${nodeBudget.tokens}, above the workflow's budget.tokens ${wfBudget.tokens}`,
637
+ nodeId,
638
+ });
639
+ }
640
+ if (wfBudget.cost_usd !== undefined &&
641
+ nodeBudget.cost_usd !== undefined &&
642
+ nodeBudget.cost_usd > wfBudget.cost_usd) {
643
+ errors.push({
644
+ code: "BUDGET_CEILING",
645
+ message: `Node "${nodeId}" declares budget.cost_usd ${nodeBudget.cost_usd}, above the workflow's budget.cost_usd ${wfBudget.cost_usd}`,
646
+ nodeId,
647
+ });
648
+ }
649
+ }
613
650
  const seenTypes = new Set();
614
651
  for (const out of node.outputs ?? []) {
615
652
  if (seenTypes.has(out.type)) {
@@ -843,6 +880,16 @@ export const workflowJsonSchema = {
843
880
  },
844
881
  ],
845
882
  },
883
+ Budget: {
884
+ type: "object",
885
+ additionalProperties: false,
886
+ minProperties: 1,
887
+ description: "A spend ceiling. 'tokens' counts input plus output tokens as the harness reports them; 'cost_usd' is the harness-reported cost (never estimated). A crossing stops the agent and fails the node; the run halts.",
888
+ properties: {
889
+ tokens: { type: "integer", minimum: 1, description: "Max input plus output tokens." },
890
+ cost_usd: { type: "number", exclusiveMinimum: 0, description: "Max reported cost in USD." },
891
+ },
892
+ },
846
893
  SafeOutput: {
847
894
  type: "object",
848
895
  required: ["type"],
@@ -983,6 +1030,15 @@ export const workflowJsonSchema = {
983
1030
  // applies the soft-cap default at use-time. See judge_model above.
984
1031
  description: "Soft cap on expected judge calls per workflow run. Executor warns at load time if exceeded; not a hard runtime cap in v1.",
985
1032
  },
1033
+ budget: {
1034
+ $ref: "#/$defs/Budget",
1035
+ description: "Spend ceiling for the whole run and for every node. A node's own budget may only narrow it. The CLI's --max-tokens and --max-cost tighten it further.",
1036
+ },
1037
+ context_mode: {
1038
+ type: "string",
1039
+ enum: [...CONTEXT_MODES],
1040
+ description: "What prior results a node's prompt receives. bounded (default): only nodes it can depend on, and a schema'd node's declared fields instead of its free-text summary. full: every prior node's complete data.",
1041
+ },
986
1042
  inputs: {
987
1043
  type: "object",
988
1044
  description: "Declared per-run input contract. Each entry names a parameter the caller may supply via --input. The CLI validates against this declaration, applies defaults for omitted optional fields, and rejects unknown types before the executor runs. Optional; workflows without an inputs block accept any JSON object (back-compat).",
@@ -1094,6 +1150,10 @@ export const workflowJsonSchema = {
1094
1150
  minimum: 1,
1095
1151
  description: "Max AI model turns for this node. When absent, the executor's default applies.",
1096
1152
  },
1153
+ budget: {
1154
+ $ref: "#/$defs/Budget",
1155
+ description: "Spend ceiling for one visit to this node, retry attempts included. Never above the workflow's budget. Crossing it stops the agent and fails the node (fail_soft and on_fail: continue do not apply) and the run halts.",
1156
+ },
1097
1157
  disallowed_tools: {
1098
1158
  type: "array",
1099
1159
  items: { type: "string", minLength: 1 },
package/dist/types.d.ts CHANGED
@@ -3,6 +3,7 @@ export type { WorkflowInputs, WorkflowInputField, WorkflowInputType, InputValida
3
3
  export { WORKFLOW_INPUT_TYPES } from "./inputs.js";
4
4
  import type { Source as _Source, ResolvedSource as _ResolvedSource } from "./sources.js";
5
5
  import type { ToolClass } from "./harness/types.js";
6
+ import type { Budget, BudgetOverrun } from "./budget.js";
6
7
  export type JSONSchema = Record<string, unknown>;
7
8
  /** Context passed to tool handlers at execution time */
8
9
  export interface ToolContext {
@@ -137,6 +138,9 @@ export type EvaluatorKind = (typeof EVALUATOR_KINDS)[number];
137
138
  /** Aggregation policy for a node's evaluator results. v1 implements `all_pass`. */
138
139
  export declare const EVAL_POLICIES: readonly ["all_pass", "any_pass", "weighted"];
139
140
  export type EvalPolicy = (typeof EVAL_POLICIES)[number];
141
+ /** What prior results a node's prompt receives (#337). See {@link Workflow.context_mode}. */
142
+ export declare const CONTEXT_MODES: readonly ["bounded", "full"];
143
+ export type ContextMode = (typeof CONTEXT_MODES)[number];
140
144
  /** Action when a `requires` precondition fails. */
141
145
  export declare const REQUIRES_ON_FAIL: readonly ["fail", "skip"];
142
146
  export type RequiresOnFail = (typeof REQUIRES_ON_FAIL)[number];
@@ -291,6 +295,12 @@ export interface Node {
291
295
  output?: JSONSchema;
292
296
  /** Max AI model turns for this node. When absent, the executor's default applies. */
293
297
  max_turns?: number;
298
+ /**
299
+ * Spend ceiling for one visit to this node (all retry attempts included),
300
+ * in input + output tokens and/or reported USD. Never above the workflow's
301
+ * `budget`. A crossing stops the agent and fails the node (see `budget.ts`).
302
+ */
303
+ budget?: Budget;
294
304
  /** Per-node directives. Additive by default; set `{ only: true, sources: [...] }` to block cascade. */
295
305
  rules?: NodeSources;
296
306
  /** Per-node background knowledge. Additive by default; set `{ only: true, sources: [...] }` to block cascade. */
@@ -520,6 +530,18 @@ export interface Workflow {
520
530
  model?: string;
521
531
  /** Soft cap on expected judge calls per workflow run. Warning at load time when exceeded. */
522
532
  judge_budget?: number;
533
+ /**
534
+ * Spend ceiling for the whole run and for every node (#449). A node's own
535
+ * `budget` may only narrow it. The CLI's `--max-tokens` / `--max-cost` tighten it.
536
+ */
537
+ budget?: Budget;
538
+ /**
539
+ * What prior results a node's prompt receives (#337). `bounded` (default):
540
+ * only nodes it can depend on (graph ancestors, nodes named by `requires`
541
+ * or its instruction), and a schema'd node's declared fields instead of its
542
+ * free-text `summary`. `full`: every prior node's complete data.
543
+ */
544
+ context_mode?: ContextMode;
523
545
  /**
524
546
  * Declared per-run input contract. When present, the CLI validates the
525
547
  * caller-provided `--input` JSON against this declaration, applies defaults
@@ -602,6 +624,12 @@ export interface NodeResult {
602
624
  degraded?: string[];
603
625
  /** Safe outputs (#365): what the write stage did with each intent. Absent when the node declares none. */
604
626
  outputs?: SafeOutputReceipt[];
627
+ /**
628
+ * Set when this node's spend crossed a token or cost budget (#449), or when
629
+ * the run's budget was already spent before it could start. The node is
630
+ * `failed`, `fail_soft` and `on_fail: continue` do not apply, and the run halts.
631
+ */
632
+ budget?: BudgetOverrun;
605
633
  }
606
634
  export interface ToolCall {
607
635
  tool: string;
@@ -770,6 +798,13 @@ export interface Claude {
770
798
  * carry the same read-only and native-deny intent.
771
799
  */
772
800
  policy?: import("./harness/types.js").NodePolicy;
801
+ /**
802
+ * Live spend (#449): a harness that declares `capabilities.usage.live`
803
+ * calls this with the run's cumulative usage as it grows. The executor
804
+ * aborts `signal` when a budget is crossed. Harnesses that report usage
805
+ * only at the end never call it.
806
+ */
807
+ onUsage?: (usage: NodeUsage) => void;
773
808
  }): Promise<NodeResult>;
774
809
  /**
775
810
  * Evaluate a routing condition — pick one of N choices.
package/dist/types.js CHANGED
@@ -51,6 +51,8 @@ export function isValidSkillId(id) {
51
51
  export const EVALUATOR_KINDS = ["value", "function", "judge"];
52
52
  /** Aggregation policy for a node's evaluator results. v1 implements `all_pass`. */
53
53
  export const EVAL_POLICIES = ["all_pass", "any_pass", "weighted"];
54
+ /** What prior results a node's prompt receives (#337). See {@link Workflow.context_mode}. */
55
+ export const CONTEXT_MODES = ["bounded", "full"];
54
56
  /** Action when a `requires` precondition fails. */
55
57
  export const REQUIRES_ON_FAIL = ["fail", "skip"];
56
58
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sweny-ai/core",
3
- "version": "0.1.156",
3
+ "version": "0.1.158",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "sweny": "./dist/cli/main.js"