@noetic-tools/core 5.2.0 → 5.4.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.
- package/README.md +8 -6
- package/dist/adapters/in-memory-subprocess/step-completion.js +1 -1
- package/dist/adapters/openrouter.d.ts +20 -2
- package/dist/adapters/openrouter.js +102 -6
- package/dist/builders/control-flow-builders.d.ts +13 -13
- package/dist/builders/control-flow-builders.js +11 -11
- package/dist/{patterns → builders}/dynamic-workflow.d.ts +1 -1
- package/dist/{patterns → builders}/dynamic-workflow.js +18 -12
- package/dist/builders/every.d.ts +14 -14
- package/dist/builders/every.js +16 -16
- package/dist/builders/layer-provides-builders.d.ts +1 -1
- package/dist/builders/layer-provides-builders.js +1 -1
- package/dist/builders/provide-builder.d.ts +5 -12
- package/dist/builders/provide-builder.js +9 -10
- package/dist/builders/spawn-builder.d.ts +0 -2
- package/dist/builders/spawn-builder.js +2 -3
- package/dist/builders/step-builders.d.ts +66 -55
- package/dist/builders/step-builders.js +118 -111
- package/dist/builders/tool-builder.d.ts +18 -22
- package/dist/builders/tool-builder.js +6 -4
- package/dist/builders/workflow-hydrator.d.ts +3 -3
- package/dist/builders/workflow-hydrator.js +59 -63
- package/dist/builders/workflow-step.d.ts +13 -25
- package/dist/builders/workflow-step.js +13 -18
- package/dist/conditions/conditions.d.ts +2 -2
- package/dist/conditions/conditions.js +1 -1
- package/dist/harness/agent-harness.d.ts +58 -40
- package/dist/harness/agent-harness.js +125 -51
- package/dist/harness/deps/context.d.ts +1 -1
- package/dist/harness/deps/context.js +1 -1
- package/dist/harness/deps/interpreter.d.ts +1 -0
- package/dist/harness/deps/interpreter.js +1 -0
- package/dist/harness/deps/types.d.ts +2 -2
- package/dist/harness/model-call.d.ts +1 -1
- package/dist/harness/model-call.js +45 -23
- package/dist/index.d.ts +23 -35
- package/dist/index.js +10 -26
- package/dist/interpreter/action-deps.d.ts +2 -2
- package/dist/interpreter/action-deps.js +1 -1
- package/dist/interpreter/action-types.d.ts +1 -1
- package/dist/interpreter/collect-tools.js +7 -7
- package/dist/interpreter/context-assembly.d.ts +50 -0
- package/dist/interpreter/context-assembly.js +547 -0
- package/dist/interpreter/execute-action.d.ts +5 -5
- package/dist/interpreter/execute-action.js +337 -208
- package/dist/interpreter/execute-control.d.ts +9 -9
- package/dist/interpreter/execute-control.js +27 -27
- package/dist/interpreter/execute-sub-harness.d.ts +1 -1
- package/dist/interpreter/execute-sub-harness.js +7 -26
- package/dist/interpreter/execute.d.ts +1 -1
- package/dist/interpreter/execute.js +26 -25
- package/dist/interpreter/step-dispatcher.d.ts +1 -1
- package/dist/interpreter/step-dispatcher.js +3 -3
- package/dist/interpreter/structured-output.d.ts +14 -0
- package/dist/interpreter/structured-output.js +40 -0
- package/dist/interpreter/typeguards.d.ts +1 -1
- package/dist/interpreter/typeguards.js +1 -1
- package/dist/observability/genai-attributes.d.ts +20 -0
- package/dist/observability/genai-attributes.js +20 -0
- package/dist/portable/builders.d.ts +3 -3
- package/dist/portable/builders.js +6 -5
- package/dist/portable/context-layers.d.ts +1 -1
- package/dist/portable/context-layers.js +1 -1
- package/dist/runtime/broadcaster-utils.d.ts +1 -1
- package/dist/runtime/broadcaster-utils.js +1 -1
- package/dist/runtime/context-impl.d.ts +8 -10
- package/dist/runtime/context-impl.js +8 -12
- package/dist/runtime/durable/step-ledger.d.ts +2 -2
- package/dist/runtime/durable/step-ledger.js +3 -3
- package/dist/runtime/session-runner.d.ts +12 -1
- package/dist/runtime/session-runner.js +33 -1
- package/dist/runtime/tool-context.js +0 -2
- package/dist/schemas/workflow.d.ts +3 -3
- package/dist/schemas/workflow.js +2 -2
- package/dist/types/checkpoint.d.ts +11 -2
- package/dist/types/checkpoint.js +10 -1
- package/dist/{runtime → util}/detached-handle.js +1 -1
- package/package.json +6 -4
- package/schema/noetic-workflow.schema.json +24 -11
- package/dist/builders/context-option.d.ts +0 -23
- package/dist/builders/context-option.js +0 -22
- package/dist/deprecated.d.ts +0 -30
- package/dist/deprecated.js +0 -28
- package/dist/patterns/interview.d.ts +0 -53
- package/dist/patterns/interview.js +0 -113
- package/dist/patterns/plans.d.ts +0 -44
- package/dist/patterns/plans.js +0 -125
- package/dist/patterns/ralph-wiggum.d.ts +0 -19
- package/dist/patterns/ralph-wiggum.js +0 -37
- package/dist/patterns/react.d.ts +0 -19
- package/dist/patterns/react.js +0 -41
- /package/dist/{runtime → util}/detached-handle.d.ts +0 -0
|
@@ -2,32 +2,19 @@ import { ItemSchemaRegistry } from '@noetic-tools/types';
|
|
|
2
2
|
import type { LayerStateStore, RecallCache } from './deps/context.js';
|
|
3
3
|
import type { DetachedSpawnOverrides } from './deps/interpreter.js';
|
|
4
4
|
import type { CheckpointStore, EventBroadcaster, RestoreCheckpointOptions, StepLedgerRetention, StepLedgerStore } from './deps/runtime.js';
|
|
5
|
-
import type { AgentConfig, AgentHarnessContract, AgentHooks, CallModelRequest, Channel, ChannelHandle, Context, ContextData, ContextLayer, CwdState, DeliveryMode, DetachedHandle, ExecuteInput, ExecuteOptions, ExternalChannel, FsAdapter, HarnessResponse, HarnessStatus, Item,
|
|
5
|
+
import type { AgentConfig, AgentHarnessContract, AgentHooks, CallModelRequest, Channel, ChannelHandle, Context, ContextCacheConfig, ContextCacheStore, ContextData, ContextLayer, CwdState, DeliveryMode, DetachedHandle, ExecuteInput, ExecuteOptions, ExternalChannel, FsAdapter, HarnessResponse, HarnessStatus, Item, ItemSchemaConfig, LLMResponse, LlmProviderConfig, ProjectionPolicy, RecallLayerOutput, SessionScope, SessionUsage, ShellAdapter, Span, SteeringDecision, Step, StorageAdapter, StreamEvent, StreamingItem, SubHarnessSession, SubprocessAdapter, Tool, TraceExporter, ZodType } from './deps/types.js';
|
|
6
6
|
export { createStreamIdleWatchdog } from './model-call.js';
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
memory?: ContextLayer[];
|
|
14
|
-
storage?: StorageAdapter;
|
|
15
|
-
hooks?: AgentHooks;
|
|
7
|
+
/**
|
|
8
|
+
* Storage-scoped environment configuration for `AgentHarness`.
|
|
9
|
+
*
|
|
10
|
+
* @public
|
|
11
|
+
*/
|
|
12
|
+
export interface StorageEnvironmentConfig {
|
|
16
13
|
/**
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
* Use this when the workflow step tree is static and tools are supplied
|
|
20
|
-
* per harness instance rather than baked into individual `step.llm` calls.
|
|
14
|
+
* Key-value storage adapter backing context-layer persistence and the
|
|
15
|
+
* step-completion ledger. Defaults to an in-memory adapter.
|
|
21
16
|
*/
|
|
22
|
-
|
|
23
|
-
params: TParams;
|
|
24
|
-
paramsSchema?: ZodType<TParams>;
|
|
25
|
-
/** Filesystem adapter. Defaults to local node:fs when not provided. */
|
|
26
|
-
fs?: FsAdapter;
|
|
27
|
-
/** Shell adapter. Defaults to local sh when not provided. */
|
|
28
|
-
shell?: ShellAdapter;
|
|
29
|
-
/** Subprocess adapter. Defaults to an in-memory, same-process adapter. */
|
|
30
|
-
subprocess?: SubprocessAdapter;
|
|
17
|
+
adapter?: StorageAdapter;
|
|
31
18
|
/**
|
|
32
19
|
* Checkpoint store used by `harness.checkpoint(ctx)` / `harness.restore()`.
|
|
33
20
|
* When absent, checkpoint/restore are no-ops — a zero-config harness keeps
|
|
@@ -35,6 +22,8 @@ interface AgentHarnessOpts<TParams extends Record<string, unknown> = Record<stri
|
|
|
35
22
|
* to enable durable execution.
|
|
36
23
|
*/
|
|
37
24
|
checkpointStore?: CheckpointStore;
|
|
25
|
+
/** Layer-state store override. Defaults to an in-memory store. */
|
|
26
|
+
layerStateStore?: LayerStateStore;
|
|
38
27
|
/**
|
|
39
28
|
* Bounds on the step-completion ledger that backs step-level resume. Only meaningful
|
|
40
29
|
* alongside a `checkpointStore`. Defaults to `DEFAULT_STEP_LEDGER_RETENTION` — 128 KiB
|
|
@@ -43,25 +32,54 @@ interface AgentHarnessOpts<TParams extends Record<string, unknown> = Record<stri
|
|
|
43
32
|
* never correctness.
|
|
44
33
|
*/
|
|
45
34
|
stepLedgerRetention?: StepLedgerRetention;
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Execution-environment configuration for `AgentHarness`: the storage,
|
|
38
|
+
* filesystem, shell, and subprocess surfaces the agent runs against.
|
|
39
|
+
*
|
|
40
|
+
* @public
|
|
41
|
+
*/
|
|
42
|
+
export interface AgentEnvironmentConfig {
|
|
43
|
+
/** Storage configuration: adapter, durability stores, ledger retention. */
|
|
44
|
+
storage?: StorageEnvironmentConfig;
|
|
45
|
+
/** Filesystem adapter. Defaults to an in-memory adapter. */
|
|
46
|
+
fs?: FsAdapter;
|
|
47
|
+
/** Shell adapter. Defaults to an in-memory adapter. */
|
|
48
|
+
shell?: ShellAdapter;
|
|
49
|
+
/** Subprocess adapter. Defaults to an in-memory, same-process adapter. */
|
|
50
|
+
subprocess?: SubprocessAdapter;
|
|
51
|
+
}
|
|
52
|
+
interface AgentHarnessOpts<TParams extends Record<string, unknown> = Record<string, unknown>> {
|
|
53
|
+
name: string;
|
|
54
|
+
/** Root step tree executed for every turn submitted via `execute()`. */
|
|
55
|
+
agentGraph?: Step<ContextData, string, string>;
|
|
56
|
+
/** Default context layers applied to every context created via `createContext()` / `execute()`. */
|
|
57
|
+
contextLayers?: ContextLayer[];
|
|
58
|
+
hooks?: AgentHooks;
|
|
59
|
+
/**
|
|
60
|
+
* Harness-wide tool pool. Merged (identity-deduplicated) with tools
|
|
61
|
+
* collected from `agentGraph` to form every context's `unifiedTools`.
|
|
62
|
+
* Use this when the workflow step tree is static and tools are supplied
|
|
63
|
+
* per harness instance rather than baked into individual `step.callModel` calls.
|
|
64
|
+
*/
|
|
65
|
+
tools?: Tool[];
|
|
66
|
+
params: TParams;
|
|
67
|
+
paramsSchema?: ZodType<TParams>;
|
|
68
|
+
/** Execution environment: storage, filesystem, shell, subprocess. */
|
|
69
|
+
environment?: AgentEnvironmentConfig;
|
|
70
|
+
/** Default provider configuration for model calls made through this harness. */
|
|
71
|
+
callModelDefaults?: LlmProviderConfig;
|
|
72
|
+
/** Harness-wide item schema extensions and validation strictness. */
|
|
73
|
+
itemSchemas?: ItemSchemaConfig;
|
|
51
74
|
/** Default projection policy for all LLM steps. Individual steps override via `step.projection`. */
|
|
52
75
|
projection?: ProjectionPolicy;
|
|
53
76
|
/** When true, every layer is recalled atomically regardless of its `recallMode`. */
|
|
54
77
|
forceAtomicRecall?: boolean;
|
|
78
|
+
/** Tuning for prompt-cache anchoring. See `ContextCacheConfig` for the defaults. */
|
|
79
|
+
contextCache?: ContextCacheConfig;
|
|
55
80
|
traceExporter?: TraceExporter;
|
|
56
|
-
layerStateStore?: LayerStateStore;
|
|
57
81
|
/** Default delivery mode for messages that don't specify one. Defaults to `next-turn`. */
|
|
58
82
|
defaultDeliveryMode?: DeliveryMode;
|
|
59
|
-
/**
|
|
60
|
-
* Abort the in-flight model call if the provider stream emits no events for this
|
|
61
|
-
* many milliseconds. Defaults to `DEFAULT_STREAM_IDLE_TIMEOUT_MS` (120s).
|
|
62
|
-
* Pass `0` or a negative number to disable the watchdog.
|
|
63
|
-
*/
|
|
64
|
-
streamIdleTimeoutMs?: number;
|
|
65
83
|
/**
|
|
66
84
|
* Initial working directory for the harness. Used as the seed value for the
|
|
67
85
|
* shared `cwdState.cwd` on every Context this harness creates, including
|
|
@@ -127,7 +145,7 @@ export declare class AgentHarness<TParams extends Record<string, unknown> = Reco
|
|
|
127
145
|
* @internal
|
|
128
146
|
*/
|
|
129
147
|
readonly stepLedgerRetention: Required<StepLedgerRetention>;
|
|
130
|
-
private readonly
|
|
148
|
+
private readonly agentGraph?;
|
|
131
149
|
/** Harness-wide tool pool merged into every context's `unifiedTools`. */
|
|
132
150
|
private readonly harnessTools;
|
|
133
151
|
/** @internal Context layers configured for this harness. Exposed non-private
|
|
@@ -140,7 +158,6 @@ export declare class AgentHarness<TParams extends Record<string, unknown> = Reco
|
|
|
140
158
|
private readonly rootRunDepth;
|
|
141
159
|
private readonly callModelOverride?;
|
|
142
160
|
private readonly defaultDeliveryMode;
|
|
143
|
-
private readonly streamIdleTimeoutMs;
|
|
144
161
|
private readonly sessions;
|
|
145
162
|
/**
|
|
146
163
|
* @internal Cross-step harness sessions keyed by `step.session.reuse`, kept
|
|
@@ -152,6 +169,8 @@ export declare class AgentHarness<TParams extends Record<string, unknown> = Reco
|
|
|
152
169
|
readonly layerStateStore: LayerStateStore;
|
|
153
170
|
/** Per-harness memoization cache for `recallMode: 'eventual'` layers. */
|
|
154
171
|
readonly recallCache: RecallCache;
|
|
172
|
+
/** Per-harness pinned anchor output and epoch bookkeeping, keyed by cache lineage. */
|
|
173
|
+
readonly contextCache: ContextCacheStore;
|
|
155
174
|
/**
|
|
156
175
|
* Execution ids whose layer `init` hooks have already run, so repeated/nested
|
|
157
176
|
* `run()` calls and the session turn path never re-init (which would clobber
|
|
@@ -189,6 +208,7 @@ export declare class AgentHarness<TParams extends Record<string, unknown> = Reco
|
|
|
189
208
|
}): Promise<void>;
|
|
190
209
|
getStatus(scope?: SessionScope): HarnessStatus;
|
|
191
210
|
getQueueSize(scope?: SessionScope): number;
|
|
211
|
+
getUsage(scope?: SessionScope): SessionUsage;
|
|
192
212
|
seedSessionHistory(threadId: string, items: ReadonlyArray<Item>): void;
|
|
193
213
|
private getOrCreateSession;
|
|
194
214
|
private requireSession;
|
|
@@ -221,9 +241,7 @@ export declare class AgentHarness<TParams extends Record<string, unknown> = Reco
|
|
|
221
241
|
state?: unknown;
|
|
222
242
|
threadId?: string;
|
|
223
243
|
resourceId?: string;
|
|
224
|
-
|
|
225
|
-
/** @deprecated Renamed to `context`. */
|
|
226
|
-
memory?: ContextLayer[];
|
|
244
|
+
contextLayers?: ContextLayer[];
|
|
227
245
|
/**
|
|
228
246
|
* Initial cwd for the new context. When set, takes precedence over both
|
|
229
247
|
* the parent snapshot and the harness root cwd — used by worktree
|
|
@@ -2,13 +2,12 @@ import { frameworkCast, ItemSchemaRegistry, NoeticConfigError } from '@noetic-to
|
|
|
2
2
|
import { SpanImpl } from '../observability/span-impl.js';
|
|
3
3
|
import { NoopExporter } from '../observability/trace-exporter.js';
|
|
4
4
|
import { createInMemoryFsAdapter, createInMemoryShellAdapter, createInMemorySubprocessAdapter, OpenRouter, } from './deps/adapters.js';
|
|
5
|
-
import { afterModelCallLayers, allocateBudgets, assembleView, beforeToolCallLayers, completeLayers, contextToExecCtx, createLayerStateStore, createRecallCache, DEFAULT_PROJECTION, disposeLayers, executeRerender, initLayers, projectHistoryLayers, recallLayers, recallLayersAtomic, recallLayersEventual, resolveLayerTools, runAppendPipeline, storeLayers, } from './deps/context.js';
|
|
6
|
-
import { collectAllTools, deduplicateTools, dispatchStepThroughAdapter, execute, } from './deps/interpreter.js';
|
|
5
|
+
import { afterModelCallLayers, allocateBudgets, assembleView, beforeToolCallLayers, completeLayers, contextToExecCtx, createContextCacheStore, createLayerStateStore, createRecallCache, DEFAULT_PROJECTION, disposeLayers, executeRerender, initLayers, projectHistoryLayers, recallLayers, recallLayersAtomic, recallLayersEventual, resolveLayerTools, runAppendPipeline, storeLayers, } from './deps/context.js';
|
|
6
|
+
import { collectAllTools, deduplicateTools, dispatchStepThroughAdapter, execute, prepareBandedView, } from './deps/interpreter.js';
|
|
7
7
|
import { buildItemStream, ChannelStore, ContextImpl, captureCheckpoint, clearCheckpoint, collectContextTree, createInMemoryStorage, createStepLedgerStore, filterReasoningStream, filterTextStream, resolveStepLedgerRetention, restoreFromCheckpoint, SessionRunner, StepLedger, snapshotCwdState, } from './deps/runtime.js';
|
|
8
8
|
import { SteeringAction } from './deps/types.js';
|
|
9
9
|
import { AgentHarnessModelCaller } from './model-call.js';
|
|
10
10
|
export { createStreamIdleWatchdog } from './model-call.js';
|
|
11
|
-
import { resolveContextOption } from '../builders/context-option.js';
|
|
12
11
|
import { buildItemSchemaRegistry } from './model-schema.js';
|
|
13
12
|
//#endregion
|
|
14
13
|
const DEFAULT_THREAD_ID = '__default__';
|
|
@@ -77,7 +76,43 @@ export function resolveLlmClient(config, env) {
|
|
|
77
76
|
cache: config?.cache ?? false,
|
|
78
77
|
};
|
|
79
78
|
}
|
|
80
|
-
|
|
79
|
+
/**
|
|
80
|
+
* Ask the provider to cache the prompt prefix.
|
|
81
|
+
*
|
|
82
|
+
* Anthropic caching is opt-in — without a breakpoint it caches nothing however
|
|
83
|
+
* stable the prefix is, measured against live models. OpenRouter accepts a
|
|
84
|
+
* `cache_control` directive on the request and places the breakpoints itself;
|
|
85
|
+
* providers that cache on their own (OpenAI, Gemini) ignore it.
|
|
86
|
+
*
|
|
87
|
+
* It has to be injected here rather than passed with the other request fields:
|
|
88
|
+
* the SDK validates the request against a generated schema that drops keys it
|
|
89
|
+
* does not know, and `cache_control` is one of them.
|
|
90
|
+
*/
|
|
91
|
+
async function addCacheBreakpoint(request) {
|
|
92
|
+
const body = await request.clone().text();
|
|
93
|
+
if (!body) {
|
|
94
|
+
return request;
|
|
95
|
+
}
|
|
96
|
+
let payload;
|
|
97
|
+
try {
|
|
98
|
+
payload = JSON.parse(body);
|
|
99
|
+
}
|
|
100
|
+
catch {
|
|
101
|
+
return request;
|
|
102
|
+
}
|
|
103
|
+
if (typeof payload !== 'object' || payload === null || Array.isArray(payload)) {
|
|
104
|
+
return request;
|
|
105
|
+
}
|
|
106
|
+
return new Request(request, {
|
|
107
|
+
body: JSON.stringify({
|
|
108
|
+
...payload,
|
|
109
|
+
cache_control: {
|
|
110
|
+
type: 'ephemeral',
|
|
111
|
+
},
|
|
112
|
+
}),
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
function createClient(config, contextCache) {
|
|
81
116
|
const resolved = resolveLlmClient(config, readLlmEnv());
|
|
82
117
|
if (!resolved) {
|
|
83
118
|
return undefined;
|
|
@@ -88,20 +123,25 @@ function createClient(config) {
|
|
|
88
123
|
if (resolved.serverURL) {
|
|
89
124
|
options.serverURL = resolved.serverURL;
|
|
90
125
|
}
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
126
|
+
// A cache write costs more than a plain read, so the breakpoint only pays off
|
|
127
|
+
// when something is holding the prefix still — which is what anchoring does.
|
|
128
|
+
const wantsBreakpoint = contextCache?.enabled !== false;
|
|
129
|
+
if (!resolved.cache && !wantsBreakpoint) {
|
|
130
|
+
return new OpenRouter(options);
|
|
131
|
+
}
|
|
132
|
+
return new OpenRouter({
|
|
133
|
+
...options,
|
|
134
|
+
hooks: {
|
|
135
|
+
beforeRequest: async (_ctx, request) => {
|
|
136
|
+
if (resolved.cache) {
|
|
137
|
+
// Serve identical model calls from OpenRouter's own response cache
|
|
138
|
+
// without re-billing (deterministic re-runs).
|
|
98
139
|
request.headers.set('X-OpenRouter-Cache', 'true');
|
|
99
|
-
|
|
100
|
-
|
|
140
|
+
}
|
|
141
|
+
return wantsBreakpoint ? addCacheBreakpoint(request) : request;
|
|
101
142
|
},
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
return new OpenRouter(options);
|
|
143
|
+
},
|
|
144
|
+
});
|
|
105
145
|
}
|
|
106
146
|
//#region AgentHarness
|
|
107
147
|
/**
|
|
@@ -137,7 +177,7 @@ export class AgentHarness {
|
|
|
137
177
|
* @internal
|
|
138
178
|
*/
|
|
139
179
|
stepLedgerRetention;
|
|
140
|
-
|
|
180
|
+
agentGraph;
|
|
141
181
|
/** Harness-wide tool pool merged into every context's `unifiedTools`. */
|
|
142
182
|
harnessTools;
|
|
143
183
|
/** @internal Context layers configured for this harness. Exposed non-private
|
|
@@ -150,7 +190,6 @@ export class AgentHarness {
|
|
|
150
190
|
rootRunDepth = new Map();
|
|
151
191
|
callModelOverride;
|
|
152
192
|
defaultDeliveryMode;
|
|
153
|
-
streamIdleTimeoutMs;
|
|
154
193
|
sessions = new Map();
|
|
155
194
|
/**
|
|
156
195
|
* @internal Cross-step harness sessions keyed by `step.session.reuse`, kept
|
|
@@ -162,6 +201,8 @@ export class AgentHarness {
|
|
|
162
201
|
layerStateStore;
|
|
163
202
|
/** Per-harness memoization cache for `recallMode: 'eventual'` layers. */
|
|
164
203
|
recallCache;
|
|
204
|
+
/** Per-harness pinned anchor output and epoch bookkeeping, keyed by cache lineage. */
|
|
205
|
+
contextCache;
|
|
165
206
|
/**
|
|
166
207
|
* Execution ids whose layer `init` hooks have already run, so repeated/nested
|
|
167
208
|
* `run()` calls and the session turn path never re-init (which would clobber
|
|
@@ -182,43 +223,47 @@ export class AgentHarness {
|
|
|
182
223
|
itemSchemas;
|
|
183
224
|
constructor(opts) {
|
|
184
225
|
const validatedParams = opts.paramsSchema ? opts.paramsSchema.parse(opts.params) : opts.params;
|
|
226
|
+
const environment = opts.environment;
|
|
227
|
+
const storageEnv = environment?.storage;
|
|
185
228
|
this.config = {
|
|
186
229
|
name: opts.name,
|
|
187
|
-
storage:
|
|
230
|
+
storage: storageEnv?.adapter ?? createInMemoryStorage(),
|
|
188
231
|
hooks: opts.hooks,
|
|
189
232
|
params: validatedParams,
|
|
190
233
|
itemSchemas: opts.itemSchemas,
|
|
191
|
-
strictItemSchemas: opts.strictItemSchemas ?? true,
|
|
192
234
|
projection: opts.projection,
|
|
193
235
|
forceAtomicRecall: opts.forceAtomicRecall,
|
|
236
|
+
contextCache: opts.contextCache,
|
|
194
237
|
};
|
|
195
|
-
this.fs =
|
|
196
|
-
this.shell =
|
|
197
|
-
this.subprocess =
|
|
198
|
-
this.checkpointStore =
|
|
199
|
-
this.stepLedgerStore =
|
|
238
|
+
this.fs = environment?.fs ?? createInMemoryFsAdapter();
|
|
239
|
+
this.shell = environment?.shell ?? createInMemoryShellAdapter();
|
|
240
|
+
this.subprocess = environment?.subprocess ?? createInMemorySubprocessAdapter();
|
|
241
|
+
this.checkpointStore = storageEnv?.checkpointStore;
|
|
242
|
+
this.stepLedgerStore = storageEnv?.checkpointStore
|
|
200
243
|
? createStepLedgerStore({
|
|
201
244
|
storage: this.config.storage ?? createInMemoryStorage(),
|
|
202
245
|
})
|
|
203
246
|
: undefined;
|
|
204
|
-
this.stepLedgerRetention = resolveStepLedgerRetention(
|
|
205
|
-
this.
|
|
247
|
+
this.stepLedgerRetention = resolveStepLedgerRetention(storageEnv?.stepLedgerRetention);
|
|
248
|
+
this.agentGraph = opts.agentGraph;
|
|
206
249
|
this.harnessTools = opts.tools ?? [];
|
|
207
|
-
this._contextLayers =
|
|
250
|
+
this._contextLayers = opts.contextLayers;
|
|
208
251
|
this.callModelOverride = opts._testCallModel;
|
|
209
|
-
this.client = opts._testCallModel
|
|
252
|
+
this.client = opts._testCallModel
|
|
253
|
+
? undefined
|
|
254
|
+
: createClient(opts.callModelDefaults, opts.contextCache);
|
|
210
255
|
this.channelStore = new ChannelStore();
|
|
211
256
|
this.traceExporter = opts.traceExporter ?? new NoopExporter();
|
|
212
257
|
this.layerStateStore =
|
|
213
|
-
|
|
258
|
+
storageEnv?.layerStateStore ??
|
|
214
259
|
createLayerStateStore((layerId, hook, error) => {
|
|
215
260
|
console.warn(`[noetic] context layer '${layerId}' ${hook} error:`, error);
|
|
216
261
|
});
|
|
217
262
|
this.recallCache = createRecallCache();
|
|
263
|
+
this.contextCache = createContextCacheStore();
|
|
218
264
|
this.defaultDeliveryMode = opts.defaultDeliveryMode ?? 'next-turn';
|
|
219
|
-
this.
|
|
220
|
-
|
|
221
|
-
strictUnknownExtensions: opts.strictItemSchemas ?? true,
|
|
265
|
+
this.itemSchemas = new ItemSchemaRegistry(opts.itemSchemas?.schemas, {
|
|
266
|
+
strictUnknownExtensions: opts.itemSchemas?.strict ?? true,
|
|
222
267
|
});
|
|
223
268
|
this.rootCwdState = {
|
|
224
269
|
cwd: opts.initialCwd ?? '/',
|
|
@@ -239,11 +284,11 @@ export class AgentHarness {
|
|
|
239
284
|
}
|
|
240
285
|
//#region Session Accessors
|
|
241
286
|
execute(input, options) {
|
|
242
|
-
if (!this.
|
|
287
|
+
if (!this.agentGraph) {
|
|
243
288
|
return Promise.reject(new NoeticConfigError({
|
|
244
289
|
code: 'NO_STEP_CONFIGURED',
|
|
245
|
-
message: 'No
|
|
246
|
-
hint: 'Pass `
|
|
290
|
+
message: 'No agentGraph configured on this harness.',
|
|
291
|
+
hint: 'Pass `agentGraph` in constructor options, or use run() directly.',
|
|
247
292
|
}));
|
|
248
293
|
}
|
|
249
294
|
const threadId = options?.threadId ?? DEFAULT_THREAD_ID;
|
|
@@ -308,6 +353,17 @@ export class AgentHarness {
|
|
|
308
353
|
const session = this.sessions.get(threadId);
|
|
309
354
|
return session ? session.runner.queue.size : 0;
|
|
310
355
|
}
|
|
356
|
+
getUsage(scope) {
|
|
357
|
+
const threadId = scope?.threadId ?? DEFAULT_THREAD_ID;
|
|
358
|
+
const session = this.sessions.get(threadId);
|
|
359
|
+
if (!session) {
|
|
360
|
+
return {
|
|
361
|
+
inputTokens: 0,
|
|
362
|
+
outputTokens: 0,
|
|
363
|
+
};
|
|
364
|
+
}
|
|
365
|
+
return session.runner.getUsage();
|
|
366
|
+
}
|
|
311
367
|
seedSessionHistory(threadId, items) {
|
|
312
368
|
const session = this.getOrCreateSession(threadId);
|
|
313
369
|
session.accumulatedItems = [
|
|
@@ -340,15 +396,15 @@ export class AgentHarness {
|
|
|
340
396
|
threadId,
|
|
341
397
|
resourceId: perTurnOptions.resourceId,
|
|
342
398
|
state: perTurnOptions.state,
|
|
343
|
-
|
|
399
|
+
contextLayers: perTurnOptions.contextLayers,
|
|
344
400
|
_broadcaster: session.runner.broadcaster,
|
|
345
401
|
});
|
|
346
402
|
const ext = frameworkCast(ctx);
|
|
347
403
|
ext._sessionQueue = session.runner.queue;
|
|
348
404
|
ext._sessionBetweenRounds = true;
|
|
349
405
|
ext._sessionRunnerAgentName = this.config.name;
|
|
350
|
-
if (this.
|
|
351
|
-
const stepTools = this.
|
|
406
|
+
if (this.agentGraph || this.harnessTools.length > 0) {
|
|
407
|
+
const stepTools = this.agentGraph ? collectAllTools(this.agentGraph) : [];
|
|
352
408
|
this.setUnifiedTools(ctx, [
|
|
353
409
|
...stepTools,
|
|
354
410
|
...this.harnessTools,
|
|
@@ -357,11 +413,11 @@ export class AgentHarness {
|
|
|
357
413
|
return ctx;
|
|
358
414
|
},
|
|
359
415
|
runTurn: async (ctx, _turn, signal) => {
|
|
360
|
-
if (!this.
|
|
416
|
+
if (!this.agentGraph) {
|
|
361
417
|
throw new NoeticConfigError({
|
|
362
418
|
code: 'NO_STEP_CONFIGURED',
|
|
363
|
-
message: 'No
|
|
364
|
-
hint: 'Pass `
|
|
419
|
+
message: 'No agentGraph configured on this harness.',
|
|
420
|
+
hint: 'Pass `agentGraph` in constructor options.',
|
|
365
421
|
});
|
|
366
422
|
}
|
|
367
423
|
// Wire signal-abort to context-abort so the interpreter bails cleanly.
|
|
@@ -375,7 +431,7 @@ export class AgentHarness {
|
|
|
375
431
|
once: true,
|
|
376
432
|
});
|
|
377
433
|
}
|
|
378
|
-
const result = await this.initAndRun(this.
|
|
434
|
+
const result = await this.initAndRun(this.agentGraph, '', ctx);
|
|
379
435
|
// Snapshot final items into session history for the next turn.
|
|
380
436
|
session.accumulatedItems = [
|
|
381
437
|
...ctx.itemLog.items,
|
|
@@ -405,7 +461,7 @@ export class AgentHarness {
|
|
|
405
461
|
itemSchemas: this.itemSchemas,
|
|
406
462
|
client: this.client,
|
|
407
463
|
callModelOverride: this.callModelOverride,
|
|
408
|
-
streamIdleTimeoutMs:
|
|
464
|
+
streamIdleTimeoutMs: DEFAULT_STREAM_IDLE_TIMEOUT_MS,
|
|
409
465
|
harness: this,
|
|
410
466
|
traceExporter: this.traceExporter,
|
|
411
467
|
}).callModel(request);
|
|
@@ -495,10 +551,10 @@ export class AgentHarness {
|
|
|
495
551
|
}
|
|
496
552
|
createContext(opts) {
|
|
497
553
|
const resolved = opts ?? {};
|
|
498
|
-
// `ContextImpl` takes the layers as `layers`, so
|
|
554
|
+
// `ContextImpl` takes the layers as `layers`, so the option spelling is
|
|
499
555
|
// dropped from `rest` rather than spread through under the wrong name.
|
|
500
|
-
const {
|
|
501
|
-
const effectiveLayers =
|
|
556
|
+
const { contextLayers, cwdInit, ...rest } = resolved;
|
|
557
|
+
const effectiveLayers = contextLayers ?? this._contextLayers;
|
|
502
558
|
const itemSchemas = buildItemSchemaRegistry({
|
|
503
559
|
base: this.itemSchemas,
|
|
504
560
|
layers: effectiveLayers,
|
|
@@ -651,7 +707,7 @@ export class AgentHarness {
|
|
|
651
707
|
const ctx = this.createContext({
|
|
652
708
|
items: historyItems,
|
|
653
709
|
threadId,
|
|
654
|
-
|
|
710
|
+
contextLayers: this._contextLayers,
|
|
655
711
|
});
|
|
656
712
|
const layers = ctx.layers ?? [];
|
|
657
713
|
if (layers.length === 0) {
|
|
@@ -660,14 +716,32 @@ export class AgentHarness {
|
|
|
660
716
|
try {
|
|
661
717
|
await this.ensureLayersInit(ctx);
|
|
662
718
|
const recallResults = await this.recallLayers(layers, '', ctx);
|
|
663
|
-
|
|
664
|
-
|
|
719
|
+
// Band the output the way a real turn would, but read-only: a preview
|
|
720
|
+
// must not pin, count churn, or age the epoch, or looking at a
|
|
721
|
+
// conversation would change what the next turn sends.
|
|
722
|
+
const banded = await prepareBandedView({
|
|
723
|
+
recallResults,
|
|
724
|
+
layers,
|
|
725
|
+
execCtx: contextToExecCtx(ctx),
|
|
726
|
+
store: this.contextCache,
|
|
727
|
+
config: this.config.contextCache,
|
|
728
|
+
instructions: undefined,
|
|
729
|
+
policy: this.config.projection ?? DEFAULT_PROJECTION,
|
|
730
|
+
systemPromptItems: [],
|
|
731
|
+
budgets: new Map(),
|
|
732
|
+
readOnly: true,
|
|
733
|
+
});
|
|
734
|
+
if (banded.anchorItems.length === 0 &&
|
|
735
|
+
banded.liveItems.length === 0 &&
|
|
736
|
+
banded.deltaItems.length === 0) {
|
|
665
737
|
return historyItems;
|
|
666
738
|
}
|
|
667
739
|
return assembleView({
|
|
668
740
|
systemPromptItems: [],
|
|
669
|
-
layerOutputItems,
|
|
741
|
+
layerOutputItems: banded.anchorItems,
|
|
670
742
|
historyItems,
|
|
743
|
+
liveLayerItems: banded.liveItems,
|
|
744
|
+
deltaItems: banded.deltaItems,
|
|
671
745
|
});
|
|
672
746
|
}
|
|
673
747
|
finally {
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
export type { LayerStateStore, RecallCache } from '@noetic-tools/context';
|
|
2
|
-
export { afterModelCallLayers, allocateBudgets, assembleView, beforeToolCallLayers, completeLayers, contextToExecCtx, createLayerStateStore, createRecallCache, DEFAULT_PROJECTION, disposeLayers, executeRerender, initLayers, projectHistoryLayers, recallLayers, recallLayersAtomic, recallLayersEventual, resolveLayerTools, runAppendPipeline, storeLayers, } from '@noetic-tools/context';
|
|
2
|
+
export { afterModelCallLayers, allocateBudgets, assembleView, beforeToolCallLayers, completeLayers, contextToExecCtx, createContextCacheStore, createLayerStateStore, createRecallCache, DEFAULT_PROJECTION, disposeLayers, executeRerender, initLayers, projectHistoryLayers, recallLayers, recallLayersAtomic, recallLayersEventual, resolveLayerTools, runAppendPipeline, storeLayers, } from '@noetic-tools/context';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export { afterModelCallLayers, allocateBudgets, assembleView, beforeToolCallLayers, completeLayers, contextToExecCtx, createLayerStateStore, createRecallCache, DEFAULT_PROJECTION, disposeLayers, executeRerender, initLayers, projectHistoryLayers, recallLayers, recallLayersAtomic, recallLayersEventual, resolveLayerTools, runAppendPipeline, storeLayers, } from '@noetic-tools/context';
|
|
1
|
+
export { afterModelCallLayers, allocateBudgets, assembleView, beforeToolCallLayers, completeLayers, contextToExecCtx, createContextCacheStore, createLayerStateStore, createRecallCache, DEFAULT_PROJECTION, disposeLayers, executeRerender, initLayers, projectHistoryLayers, recallLayers, recallLayersAtomic, recallLayersEventual, resolveLayerTools, runAppendPipeline, storeLayers, } from '@noetic-tools/context';
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export { collectAllTools, deduplicateTools } from '../../interpreter/collect-tools.js';
|
|
2
|
+
export { prepareBandedView } from '../../interpreter/context-assembly.js';
|
|
2
3
|
export { execute } from '../../interpreter/execute.js';
|
|
3
4
|
export type { DetachedSpawnOverrides } from '../../interpreter/step-dispatcher.js';
|
|
4
5
|
export { dispatchStepThroughAdapter } from '../../interpreter/step-dispatcher.js';
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export { collectAllTools, deduplicateTools } from '../../interpreter/collect-tools.js';
|
|
2
|
+
export { prepareBandedView } from '../../interpreter/context-assembly.js';
|
|
2
3
|
export { execute } from '../../interpreter/execute.js';
|
|
3
4
|
export { dispatchStepThroughAdapter } from '../../interpreter/step-dispatcher.js';
|
|
4
5
|
export { isFunctionCall } from '../../interpreter/typeguards.js';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export type { ContextData, ContextLayer, ExecutionContext, ProjectionPolicy, StorageAdapter, } from '@noetic-tools/context';
|
|
2
|
-
export type { AgentConfig, AgentHarnessContract, AgentHooks, CallModelRequest, Channel, ChannelHandle, Context, CwdState, DeliveryMode, DetachedHandle, ExecuteInput, ExecuteOptions, ExternalChannel, FsAdapter, HarnessResponse, HarnessStatus, Item, ItemSchemaExtensions, LLMResponse, LlmProviderConfig, RecallLayerOutput, SessionScope, ShellAdapter, Span, SteeringDecision, Step, StreamEvent, StreamingItem, SubHarnessSession, SubprocessAdapter, Tool, TraceExporter, } from '@noetic-tools/types';
|
|
1
|
+
export type { ContextCacheConfig, ContextCacheStore, ContextData, ContextLayer, ExecutionContext, ProjectionPolicy, StorageAdapter, } from '@noetic-tools/context';
|
|
2
|
+
export type { AgentConfig, AgentHarnessContract, AgentHooks, CallModelRequest, Channel, ChannelHandle, Context, CwdState, DeliveryMode, DetachedHandle, ExecuteInput, ExecuteOptions, ExternalChannel, FsAdapter, HarnessResponse, HarnessStatus, Item, ItemSchemaConfig, ItemSchemaExtensions, LLMResponse, LlmProviderConfig, RecallLayerOutput, SessionScope, SessionUsage, ShellAdapter, Span, SteeringDecision, Step, StreamEvent, StreamingItem, SubHarnessSession, SubprocessAdapter, Tool, TraceExporter, } from '@noetic-tools/types';
|
|
3
3
|
export { SteeringAction } from '@noetic-tools/types';
|
|
4
4
|
export type { ZodType } from 'zod';
|
|
@@ -10,7 +10,7 @@ interface StreamIdleWatchdog {
|
|
|
10
10
|
/** @internal Create a watchdog that aborts `controller` when no
|
|
11
11
|
* {@link StreamIdleWatchdog.reset reset} is called within `timeoutMs`. When
|
|
12
12
|
* `timeoutMs <= 0`, returns an inert no-op so callers can always call `.reset()`
|
|
13
|
-
* / `.stop()` without
|
|
13
|
+
* / `.stop()` without branching. Starts armed: the caller is responsible for
|
|
14
14
|
* `.stop()` in a `finally`. `onTimeout` runs before the abort so observers can
|
|
15
15
|
* emit a framework event with the original cause. Exported only for unit tests. */
|
|
16
16
|
export declare function createStreamIdleWatchdog(timeoutMs: number, controller: AbortController, onTimeout?: () => void): StreamIdleWatchdog;
|