@noetic-tools/types 3.4.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.
|
@@ -120,6 +120,8 @@ export interface ContextHarness {
|
|
|
120
120
|
detachedSpawn<I, O>(step: unknown, input: I, parentCtx: Context, overrides?: ContextDetachedSpawnOverrides): DetachedHandle<O>;
|
|
121
121
|
createContext(opts?: {
|
|
122
122
|
parent?: Context;
|
|
123
|
+
/** Charge this context's usage to `parent` as it is spent. Default `true`. */
|
|
124
|
+
rollUpUsage?: boolean;
|
|
123
125
|
items?: Item[];
|
|
124
126
|
state?: unknown;
|
|
125
127
|
threadId?: string;
|
package/dist/types/context.d.ts
CHANGED
|
@@ -42,6 +42,8 @@ export interface CwdState {
|
|
|
42
42
|
export interface RestoreContextOptions {
|
|
43
43
|
/** Live parent context, when the restored execution hangs under one. */
|
|
44
44
|
parent?: Context;
|
|
45
|
+
/** Charge the restored context's usage to `parent`, same as `createContext({ rollUpUsage })`. Default `true`. */
|
|
46
|
+
rollUpUsage?: boolean;
|
|
45
47
|
/** Opaque per-execution state, same as `createContext({ state })`. */
|
|
46
48
|
state?: unknown;
|
|
47
49
|
/** Context layers for the restored context. Defaults to the harness's configured layers. */
|
|
@@ -56,6 +58,17 @@ export interface Context<TContext = ContextData, TState = unknown> {
|
|
|
56
58
|
readonly cost: number;
|
|
57
59
|
state: TState;
|
|
58
60
|
readonly parent: Context<ContextData> | null;
|
|
61
|
+
/**
|
|
62
|
+
* Where this context's token/cost usage is also charged. Every charge
|
|
63
|
+
* recorded here is added to this context and then to each ancestor along
|
|
64
|
+
* this chain, so `tokens` / `cost` cover this context plus every descendant,
|
|
65
|
+
* live — whether the descendant succeeds, fails, or is abandoned.
|
|
66
|
+
*
|
|
67
|
+
* Equals `parent` unless the context was created with `rollUpUsage: false`,
|
|
68
|
+
* in which case it is `null` and the context keeps its spend to itself. When
|
|
69
|
+
* absent (a hand-rolled `Context` implementation), `parent` is used.
|
|
70
|
+
*/
|
|
71
|
+
readonly usageParent?: Context<ContextData> | null;
|
|
59
72
|
readonly depth: number;
|
|
60
73
|
readonly span: Span;
|
|
61
74
|
readonly threadId: string;
|
package/dist/types/runtime.d.ts
CHANGED
|
@@ -253,6 +253,12 @@ export interface AgentHarnessContract<TParams extends Record<string, unknown> =
|
|
|
253
253
|
}): DetachedHandle<O>;
|
|
254
254
|
createContext(opts?: {
|
|
255
255
|
parent?: Context;
|
|
256
|
+
/**
|
|
257
|
+
* Charge this context's token/cost usage to `parent` as it is spent, so
|
|
258
|
+
* the parent's `tokens` / `cost` include it. Default `true`; pass `false`
|
|
259
|
+
* to keep the child's spend off the parent.
|
|
260
|
+
*/
|
|
261
|
+
rollUpUsage?: boolean;
|
|
256
262
|
items?: Item[];
|
|
257
263
|
state?: unknown;
|
|
258
264
|
threadId?: string;
|
|
@@ -33,5 +33,23 @@ export declare function createMessage(text: string, role: 'user' | 'developer'):
|
|
|
33
33
|
export declare function extractAssistantText(items: ReadonlyArray<Item>): string;
|
|
34
34
|
/** Naive token estimate: ~4 chars per token */
|
|
35
35
|
export declare function estimateTokens(text: string): number;
|
|
36
|
-
/**
|
|
36
|
+
/** @public One unit of spend to charge to a context: a model call, or any other billed work. */
|
|
37
|
+
export interface UsageCharge {
|
|
38
|
+
inputTokens: number;
|
|
39
|
+
outputTokens: number;
|
|
40
|
+
cachedTokens?: number;
|
|
41
|
+
/** USD. */
|
|
42
|
+
cost?: number;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* @public Charge `charge` to `ctx` and to every ancestor on its `usageParent`
|
|
46
|
+
* chain. Charging at the moment of spend — rather than merging a child's
|
|
47
|
+
* totals into its parent when the child settles — is what keeps spend from a
|
|
48
|
+
* failed spawn, a fork path, or an abandoned `race` loser from being lost, and
|
|
49
|
+
* lets `until.maxCost` / `checkBudget` on an ancestor see siblings' spend live.
|
|
50
|
+
* Use this, not direct writes to `ctx.cost`, for any billed work outside a
|
|
51
|
+
* model call; a direct write stays on that one context.
|
|
52
|
+
*/
|
|
53
|
+
export declare function recordUsage(ctx: Context, charge: UsageCharge): void;
|
|
54
|
+
/** Accumulate token usage and cost from an LLM response onto a context and its usage ancestors. */
|
|
37
55
|
export declare function trackUsage(ctx: Context, response: LLMResponse): void;
|
|
@@ -90,23 +90,50 @@ export function extractAssistantText(items) {
|
|
|
90
90
|
export function estimateTokens(text) {
|
|
91
91
|
return Math.ceil(text.length / 4);
|
|
92
92
|
}
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
ctx.tokens.input += response.usage.inputTokens;
|
|
99
|
-
ctx.tokens.output += response.usage.outputTokens;
|
|
100
|
-
ctx.tokens.total += response.usage.inputTokens + response.usage.outputTokens;
|
|
101
|
-
// Only write `cached` when the response actually carried a figure. Defaulting
|
|
93
|
+
function addCharge(ctx, charge) {
|
|
94
|
+
ctx.tokens.input += charge.inputTokens;
|
|
95
|
+
ctx.tokens.output += charge.outputTokens;
|
|
96
|
+
ctx.tokens.total += charge.inputTokens + charge.outputTokens;
|
|
97
|
+
// Only write `cached` when the charge actually carried a figure. Defaulting
|
|
102
98
|
// a missing report to 0 would erase the `RoundUsage` invariant that
|
|
103
99
|
// `undefined` means "this provider says nothing about caching" — callers that
|
|
104
100
|
// steer on cache behaviour could no longer tell that from "nothing was
|
|
105
|
-
// cached".
|
|
106
|
-
if (
|
|
107
|
-
ctx.tokens.cached = (ctx.tokens.cached ?? 0) +
|
|
101
|
+
// cached".
|
|
102
|
+
if (charge.cachedTokens !== undefined) {
|
|
103
|
+
ctx.tokens.cached = (ctx.tokens.cached ?? 0) + charge.cachedTokens;
|
|
104
|
+
}
|
|
105
|
+
if (charge.cost) {
|
|
106
|
+
ctx.cost = ctx.cost + charge.cost;
|
|
108
107
|
}
|
|
109
|
-
|
|
110
|
-
|
|
108
|
+
}
|
|
109
|
+
function usageParentOf(ctx) {
|
|
110
|
+
return ctx.usageParent !== undefined ? ctx.usageParent : ctx.parent;
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* @public Charge `charge` to `ctx` and to every ancestor on its `usageParent`
|
|
114
|
+
* chain. Charging at the moment of spend — rather than merging a child's
|
|
115
|
+
* totals into its parent when the child settles — is what keeps spend from a
|
|
116
|
+
* failed spawn, a fork path, or an abandoned `race` loser from being lost, and
|
|
117
|
+
* lets `until.maxCost` / `checkBudget` on an ancestor see siblings' spend live.
|
|
118
|
+
* Use this, not direct writes to `ctx.cost`, for any billed work outside a
|
|
119
|
+
* model call; a direct write stays on that one context.
|
|
120
|
+
*/
|
|
121
|
+
export function recordUsage(ctx, charge) {
|
|
122
|
+
// The chain is acyclic for every ContextImpl (parents are fixed at
|
|
123
|
+
// construction); the guard only protects against a hand-rolled Context.
|
|
124
|
+
const seen = new Set();
|
|
125
|
+
for (let current = ctx; current && !seen.has(current);) {
|
|
126
|
+
seen.add(current);
|
|
127
|
+
if (canTrackUsage(current)) {
|
|
128
|
+
addCharge(current, charge);
|
|
129
|
+
}
|
|
130
|
+
current = usageParentOf(current);
|
|
111
131
|
}
|
|
112
132
|
}
|
|
133
|
+
/** Accumulate token usage and cost from an LLM response onto a context and its usage ancestors. */
|
|
134
|
+
export function trackUsage(ctx, response) {
|
|
135
|
+
recordUsage(ctx, {
|
|
136
|
+
...response.usage,
|
|
137
|
+
cost: response.cost,
|
|
138
|
+
});
|
|
139
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@noetic-tools/types",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.5.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Foundational type contracts and primitives shared across the Noetic framework (items, LLM config, adapters, steering, errors).",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -60,8 +60,8 @@
|
|
|
60
60
|
"zod": "^4.0.0"
|
|
61
61
|
},
|
|
62
62
|
"scripts": {
|
|
63
|
-
"build": "bunx tsc -p tsconfig.build.json && bun scripts/add-js-extensions.ts",
|
|
64
|
-
"verify:esm": "bun scripts/verify-node-esm.ts",
|
|
63
|
+
"build": "bunx tsc -p tsconfig.build.json && bun ../../scripts/add-js-extensions.ts",
|
|
64
|
+
"verify:esm": "bun ../../scripts/verify-node-esm.ts",
|
|
65
65
|
"prepublishOnly": "rm -rf dist && bun run build && bun run verify:esm && bun scripts/strip-dev-conditions.ts",
|
|
66
66
|
"test": "bun test",
|
|
67
67
|
"test:coverage": "bun test --coverage --coverage-reporter=text --coverage-reporter=lcov",
|