@noetic-tools/core 5.6.0 → 5.7.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.
@@ -279,6 +279,8 @@ export declare class AgentHarness<TParams extends Record<string, unknown> = Reco
279
279
  detachedSpawn<I, O>(s: Step<ContextData, I, O>, input: I, parentCtx: Context, overrides?: DetachedSpawnOverrides): DetachedHandle<O>;
280
280
  createContext(opts?: {
281
281
  parent?: Context;
282
+ /** Charge this context's usage to `parent` as it is spent. Default `true`. */
283
+ rollUpUsage?: boolean;
282
284
  items?: Item[];
283
285
  state?: unknown;
284
286
  threadId?: string;
package/dist/index.d.ts CHANGED
@@ -82,7 +82,7 @@ export type { DecisionsHistoryConfig, DecisionsHistoryLayer, DecisionsHistorySta
82
82
  /** @public */
83
83
  export { DECISION_PROJECTION, decisionsHistoryLayer, filesystem, findFunctionCall, history, instructions, observations, PlanPhase, PlanStyle, plan, scratchpad, steering, storageGetMany, stripUnresolvedToolCalls, taskState, temporal, toolCalls, } from '@noetic-tools/context';
84
84
  /** @public */
85
- export { createMessage, estimateTokens } from '@noetic-tools/types';
85
+ export { createMessage, estimateTokens, recordUsage } from '@noetic-tools/types';
86
86
  /** @public */
87
87
  export { GenAI, NoeticAttr, ToolAttr } from './observability/genai-attributes.js';
88
88
  /** @public */
@@ -113,7 +113,7 @@ export { MergeStrategySchema, UntilPredicateSchema, validateWorkflow, WorkflowDo
113
113
  export type { Channel, ChannelHandle, ExternalChannel } from '@noetic-tools/types';
114
114
  /** @public */
115
115
  /** @public */
116
- export type { InferSchemaInput, InferSchemaOutput, InputSchemaConfig, LLMResponse, LlmProviderConfig, ModelParams, RetryPolicy, RoundUsage, SchemaValidationFailure, SchemaValidationResult, SchemaValidationSuccess, ServerToolSpec, StandardJSONSchemaV1, StandardSchemaV1, StepMeta, TokenUsage, Tool, ToolContextDeclaration, } from '@noetic-tools/types';
116
+ export type { InferSchemaInput, InferSchemaOutput, InputSchemaConfig, LLMResponse, LlmProviderConfig, ModelParams, RetryPolicy, RoundUsage, SchemaValidationFailure, SchemaValidationResult, SchemaValidationSuccess, ServerToolSpec, StandardJSONSchemaV1, StandardSchemaV1, StepMeta, TokenUsage, Tool, ToolContextDeclaration, UsageCharge, } from '@noetic-tools/types';
117
117
  /** @public */
118
118
  export { isServerToolSpec, isStandardJsonSchema, isZodSchema, standardIssuesToZodError, validateSchema, } from '@noetic-tools/types';
119
119
  /** @public */
package/dist/index.js CHANGED
@@ -66,7 +66,7 @@ export { DECISION_PROJECTION, decisionsHistoryLayer, filesystem, findFunctionCal
66
66
  //#endregion
67
67
  //#region Message Utilities
68
68
  /** @public */
69
- export { createMessage, estimateTokens } from '@noetic-tools/types';
69
+ export { createMessage, estimateTokens, recordUsage } from '@noetic-tools/types';
70
70
  //#endregion
71
71
  //#region Observability
72
72
  /** @public */
@@ -656,19 +656,6 @@ async function collectSpawnItems({ layers, parentExecutionCtx, childExecutionCtx
656
656
  });
657
657
  return spawnResults.flatMap((r) => r.items);
658
658
  }
659
- /** Adds a spawned child's accumulated token/cost usage to its parent. */
660
- function rollUpSpawnUsage(parent, child) {
661
- if (!isMutableContext(parent)) {
662
- return;
663
- }
664
- parent.tokens.input += child.tokens.input;
665
- parent.tokens.output += child.tokens.output;
666
- parent.tokens.total += child.tokens.total;
667
- if (child.tokens.cached !== undefined) {
668
- parent.tokens.cached = (parent.tokens.cached ?? 0) + child.tokens.cached;
669
- }
670
- parent.cost += child.cost;
671
- }
672
659
  export async function executeSpawn(step, input, ctx, executeStep, opts) {
673
660
  const baseCtx = frameworkCast(ctx);
674
661
  const layers = resolveLayersForSpawn(step, opts?.parentLayers);
@@ -736,14 +723,10 @@ export async function executeSpawn(step, input, ctx, executeStep, opts) {
736
723
  ledger: baseCtx instanceof ContextImpl ? baseCtx.ledger : undefined,
737
724
  });
738
725
  try {
739
- // Execute the child step
726
+ // Execute the child step. Its token/cost usage needs no merge here: every
727
+ // charge recorded on `childCtx` is also charged up its `usageParent`
728
+ // chain as it is spent, so a child that throws still bills the parent.
740
729
  const childOutput = await executeStep(step.child, input, frameworkCast(childCtx));
741
- // Roll the child's token/cost usage up into the parent. A sub-agent's
742
- // spend is the parent's spend; without this it would be stranded on the
743
- // child context and invisible to `ctx.tokens` / `ctx.cost` / until.maxCost.
744
- // Because every spawn boundary rolls up, nested sub-agents propagate to the
745
- // root recursively.
746
- rollUpSpawnUsage(baseCtx, childCtx);
747
730
  // Pipeline result through layer onReturn hooks
748
731
  if (!hasLayers || !parentExecutionCtx) {
749
732
  return childOutput;
@@ -14,6 +14,7 @@ export declare class ContextImpl implements Context<ContextData> {
14
14
  cost: number;
15
15
  state: unknown;
16
16
  readonly parent: Context<ContextData> | null;
17
+ readonly usageParent: Context<ContextData> | null;
17
18
  readonly depth: number;
18
19
  readonly span: Span;
19
20
  readonly threadId: string;
@@ -98,6 +99,8 @@ export declare class ContextImpl implements Context<ContextData> {
98
99
  constructor(opts: {
99
100
  harness: AgentHarnessContract;
100
101
  parent?: Context;
102
+ /** Charge this context's usage to `parent` as it is spent. Default `true`. */
103
+ rollUpUsage?: boolean;
101
104
  items?: Item[];
102
105
  state?: unknown;
103
106
  threadId?: string;
@@ -38,6 +38,7 @@ export class ContextImpl {
38
38
  cost = 0;
39
39
  state;
40
40
  parent;
41
+ usageParent;
41
42
  depth;
42
43
  span;
43
44
  threadId;
@@ -125,6 +126,7 @@ export class ContextImpl {
125
126
  this.harness = opts.harness;
126
127
  this.state = opts.state ?? {};
127
128
  this.parent = opts.parent ?? null;
129
+ this.usageParent = opts.rollUpUsage === false ? null : this.parent;
128
130
  this.depth = this.parent ? this.parent.depth + 1 : 0;
129
131
  this.span = opts.span ?? new NoopSpan();
130
132
  this.threadId = opts.threadId ?? crypto.randomUUID();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@noetic-tools/core",
3
- "version": "5.6.0",
3
+ "version": "5.7.0",
4
4
  "type": "module",
5
5
  "description": "Step primitives, interpreter, runtime, and context layer contract for Noetic agents.",
6
6
  "license": "Apache-2.0",
@@ -69,7 +69,7 @@
69
69
  },
70
70
  "dependencies": {
71
71
  "@noetic-tools/context": "^1.4.0",
72
- "@noetic-tools/types": "^3.4.0",
72
+ "@noetic-tools/types": "^3.5.0",
73
73
  "@openrouter/agent": "^0.11.0",
74
74
  "@openrouter/sdk": "1.4.25",
75
75
  "zod": "^4.0.0"