@noetic-tools/core 2.5.0 → 3.1.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/dist/conditions/conditions.js +8 -5
- package/dist/harness/agent-harness.d.ts +14 -2
- package/dist/harness/agent-harness.js +14 -2
- package/dist/harness/deps/runtime.d.ts +1 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -1
- package/dist/runtime/durable/harness-checkpoints.d.ts +24 -4
- package/dist/runtime/durable/harness-checkpoints.js +14 -2
- package/dist/runtime/durable/step-ledger.js +8 -2
- package/dist/runtime/in-memory-storage.js +11 -0
- package/package.json +3 -3
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { storageGetMany } from '@noetic-tools/memory';
|
|
1
2
|
import { createMessage, extractAssistantText, trackUsage } from '@noetic-tools/types';
|
|
2
3
|
import { z } from 'zod';
|
|
3
4
|
import { cosineSimilarity } from './cosine-similarity.js';
|
|
@@ -13,10 +14,12 @@ async function getLabelVectors(embed, labels, ref) {
|
|
|
13
14
|
if (ref.storage) {
|
|
14
15
|
const storage = ref.storage;
|
|
15
16
|
const keys = labels.map(hashLabel);
|
|
16
|
-
|
|
17
|
+
// One batch read where the adapter supports it, a parallel `get` sweep where
|
|
18
|
+
// it does not — either way, not one round trip per label.
|
|
19
|
+
const cached = await storageGetMany(storage, keys);
|
|
17
20
|
const missingIndices = [];
|
|
18
|
-
for (let i = 0; i <
|
|
19
|
-
if (!
|
|
21
|
+
for (let i = 0; i < keys.length; i++) {
|
|
22
|
+
if (!cached.has(keys[i])) {
|
|
20
23
|
missingIndices.push(i);
|
|
21
24
|
}
|
|
22
25
|
}
|
|
@@ -29,8 +32,8 @@ async function getLabelVectors(embed, labels, ref) {
|
|
|
29
32
|
}
|
|
30
33
|
const results = new Array(labels.length);
|
|
31
34
|
let freshIndex = 0;
|
|
32
|
-
for (let i = 0; i <
|
|
33
|
-
results[i] =
|
|
35
|
+
for (let i = 0; i < keys.length; i++) {
|
|
36
|
+
results[i] = cached.get(keys[i]) ?? freshEmbeddings[freshIndex++];
|
|
34
37
|
}
|
|
35
38
|
return results;
|
|
36
39
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { ItemSchemaRegistry } from '@noetic-tools/types';
|
|
2
2
|
import type { DetachedSpawnOverrides } from './deps/interpreter.js';
|
|
3
3
|
import type { LayerStateStore, RecallCache } from './deps/memory.js';
|
|
4
|
-
import type { CheckpointStore, EventBroadcaster, StepLedgerStore } from './deps/runtime.js';
|
|
4
|
+
import type { CheckpointStore, EventBroadcaster, RestoreCheckpointOptions, StepLedgerStore } from './deps/runtime.js';
|
|
5
5
|
import type { AgentConfig, AgentHarnessContract, AgentHooks, CallModelRequest, Channel, ChannelHandle, Context, ContextMemory, CwdState, DeliveryMode, DetachedHandle, ExecuteInput, ExecuteOptions, ExternalChannel, FsAdapter, HarnessResponse, HarnessStatus, Item, ItemSchemaExtensions, LLMResponse, LlmProviderConfig, MemoryLayer, ProjectionPolicy, RecallLayerOutput, SessionScope, 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
7
|
interface AgentHarnessOpts<TParams extends Record<string, unknown> = Record<string, unknown>> {
|
|
@@ -256,8 +256,20 @@ export declare class AgentHarness<TParams extends Record<string, unknown> = Reco
|
|
|
256
256
|
* `NoeticConfigError(CHECKPOINT_SCHEMA_MISMATCH)` when the snapshot's
|
|
257
257
|
* schema version is unrecognised — the caller is expected to discard the
|
|
258
258
|
* checkpoint via `CheckpointStore.clear()` and start a fresh execution.
|
|
259
|
+
*
|
|
260
|
+
* `opts` is the `createContext`-shaped wiring the host attached to the
|
|
261
|
+
* original context (broadcaster, parent, state, memory overrides). A
|
|
262
|
+
* snapshot recovers data, not live objects — pass the same wiring here or
|
|
263
|
+
* the resumed run gets an undecorated context and whatever depended on that
|
|
264
|
+
* wiring (event streaming, mid-turn injection) stops working without
|
|
265
|
+
* failing. Fields the snapshot owns — items, threadId, resourceId, cwd —
|
|
266
|
+
* are not accepted; they always come from the persisted record.
|
|
267
|
+
*
|
|
268
|
+
* Decoration applied *after* construction (`Object.assign`ed fields, abort
|
|
269
|
+
* registration) stays the host's job: apply it to the context this returns,
|
|
270
|
+
* whose `id` is already the original `executionId`.
|
|
259
271
|
*/
|
|
260
|
-
restore(executionId: string): Promise<Context | null>;
|
|
272
|
+
restore(executionId: string, opts?: RestoreCheckpointOptions): Promise<Context | null>;
|
|
261
273
|
cancel(_ctx: Context, _reason?: string): Promise<void>;
|
|
262
274
|
createSpan(name: string, parent: Span | null): Span;
|
|
263
275
|
getLayerState<T>(executionId: string, layerId: string): T | undefined;
|
|
@@ -669,9 +669,21 @@ export class AgentHarness {
|
|
|
669
669
|
* `NoeticConfigError(CHECKPOINT_SCHEMA_MISMATCH)` when the snapshot's
|
|
670
670
|
* schema version is unrecognised — the caller is expected to discard the
|
|
671
671
|
* checkpoint via `CheckpointStore.clear()` and start a fresh execution.
|
|
672
|
+
*
|
|
673
|
+
* `opts` is the `createContext`-shaped wiring the host attached to the
|
|
674
|
+
* original context (broadcaster, parent, state, memory overrides). A
|
|
675
|
+
* snapshot recovers data, not live objects — pass the same wiring here or
|
|
676
|
+
* the resumed run gets an undecorated context and whatever depended on that
|
|
677
|
+
* wiring (event streaming, mid-turn injection) stops working without
|
|
678
|
+
* failing. Fields the snapshot owns — items, threadId, resourceId, cwd —
|
|
679
|
+
* are not accepted; they always come from the persisted record.
|
|
680
|
+
*
|
|
681
|
+
* Decoration applied *after* construction (`Object.assign`ed fields, abort
|
|
682
|
+
* registration) stays the host's job: apply it to the context this returns,
|
|
683
|
+
* whose `id` is already the original `executionId`.
|
|
672
684
|
*/
|
|
673
|
-
async restore(executionId) {
|
|
674
|
-
return restoreFromCheckpoint(this, executionId);
|
|
685
|
+
async restore(executionId, opts) {
|
|
686
|
+
return restoreFromCheckpoint(this, executionId, opts);
|
|
675
687
|
}
|
|
676
688
|
//#endregion
|
|
677
689
|
async cancel(_ctx, _reason) { }
|
|
@@ -2,6 +2,7 @@ export { ChannelStore } from '../../runtime/channel-store.js';
|
|
|
2
2
|
export { ContextImpl } from '../../runtime/context-impl.js';
|
|
3
3
|
export { snapshotCwdState } from '../../runtime/cwd-helpers.js';
|
|
4
4
|
export type { CheckpointStore } from '../../runtime/durable/index.js';
|
|
5
|
+
export type { RestoreCheckpointOptions } from '../../runtime/durable/harness-checkpoints.js';
|
|
5
6
|
export { captureCheckpoint, restoreFromCheckpoint, } from '../../runtime/durable/harness-checkpoints.js';
|
|
6
7
|
export type { StepLedgerEntry, StepLedgerStore } from '../../runtime/durable/step-ledger.js';
|
|
7
8
|
export { createStepLedgerStore, StepLedger } from '../../runtime/durable/step-ledger.js';
|
package/dist/index.d.ts
CHANGED
|
@@ -68,7 +68,7 @@ export type { DurableTaskState, FactExtractor, FactSearcher, HistoryWindowConfig
|
|
|
68
68
|
/** @public */
|
|
69
69
|
/** @public */
|
|
70
70
|
/** @public */
|
|
71
|
-
export { durableTaskState, fileReference, findFunctionCall, historyWindow, observationalMemory, PlanPhase, planMemory, staticContent, steering, stripUnresolvedToolCalls, temporalMemory, toolMemoryLayer, workingMemory, } from '@noetic-tools/memory';
|
|
71
|
+
export { durableTaskState, fileReference, findFunctionCall, historyWindow, observationalMemory, PlanPhase, planMemory, staticContent, steering, storageGetMany, stripUnresolvedToolCalls, temporalMemory, toolMemoryLayer, workingMemory, } from '@noetic-tools/memory';
|
|
72
72
|
/** @public */
|
|
73
73
|
export { createMessage, estimateTokens } from '@noetic-tools/types';
|
|
74
74
|
/** @public */
|
|
@@ -121,7 +121,7 @@ export { isServerToolSpec } from '@noetic-tools/types';
|
|
|
121
121
|
/** @public */
|
|
122
122
|
/** @public */
|
|
123
123
|
/** @public */
|
|
124
|
-
export type { Context, ContextHarness, CwdState, ItemLog, LastLayerUsage, LayerUsageEntry, } from '@noetic-tools/types';
|
|
124
|
+
export type { Context, ContextHarness, CwdState, ItemLog, LastLayerUsage, LayerUsageEntry, RestoreContextOptions, } from '@noetic-tools/types';
|
|
125
125
|
/** @public */
|
|
126
126
|
export { getToolCwd, setToolCwd, snapshotCwdState } from './runtime/cwd-helpers.js';
|
|
127
127
|
/** @public */
|
package/dist/index.js
CHANGED
|
@@ -58,7 +58,7 @@ export { execute } from './interpreter/execute.js';
|
|
|
58
58
|
/** @public */
|
|
59
59
|
/** @public */
|
|
60
60
|
/** @public */
|
|
61
|
-
export { durableTaskState, fileReference, findFunctionCall, historyWindow, observationalMemory, PlanPhase, planMemory, staticContent, steering, stripUnresolvedToolCalls, temporalMemory, toolMemoryLayer, workingMemory, } from '@noetic-tools/memory';
|
|
61
|
+
export { durableTaskState, fileReference, findFunctionCall, historyWindow, observationalMemory, PlanPhase, planMemory, staticContent, steering, storageGetMany, stripUnresolvedToolCalls, temporalMemory, toolMemoryLayer, workingMemory, } from '@noetic-tools/memory';
|
|
62
62
|
//#endregion
|
|
63
63
|
//#region Message Utilities
|
|
64
64
|
/** @public */
|
|
@@ -1,7 +1,20 @@
|
|
|
1
1
|
import type { LayerStateStore, MemoryLayer } from '@noetic-tools/memory';
|
|
2
|
-
import type { Context, Item, ItemSchemaRegistry } from '@noetic-tools/types';
|
|
2
|
+
import type { Context, Item, ItemSchemaRegistry, RestoreContextOptions } from '@noetic-tools/types';
|
|
3
|
+
import type { EventBroadcaster } from '../event-broadcaster.js';
|
|
3
4
|
import type { CheckpointStore } from './checkpoint-store.js';
|
|
4
5
|
import type { StepLedgerStore } from './step-ledger.js';
|
|
6
|
+
/**
|
|
7
|
+
* Host wiring forwarded into the context `restoreFromCheckpoint` builds.
|
|
8
|
+
* `RestoreContextOptions` covers the portable fields; core widens it with the
|
|
9
|
+
* internal `_broadcaster` seam so a resumed turn keeps streaming framework UI
|
|
10
|
+
* events.
|
|
11
|
+
*
|
|
12
|
+
* @internal
|
|
13
|
+
*/
|
|
14
|
+
export type RestoreCheckpointOptions = RestoreContextOptions & {
|
|
15
|
+
/** @internal Event broadcaster the host attached to the original context. */
|
|
16
|
+
_broadcaster?: EventBroadcaster;
|
|
17
|
+
};
|
|
5
18
|
/**
|
|
6
19
|
* Minimum harness surface `captureCheckpoint` / `restoreFromCheckpoint`
|
|
7
20
|
* require. `AgentHarness` already satisfies this shape via its
|
|
@@ -16,12 +29,11 @@ export interface CheckpointHarnessHandle {
|
|
|
16
29
|
readonly layerStateStore: LayerStateStore;
|
|
17
30
|
readonly itemSchemas: ItemSchemaRegistry;
|
|
18
31
|
readonly _memory?: MemoryLayer[];
|
|
19
|
-
createContext(opts?: {
|
|
32
|
+
createContext(opts?: RestoreCheckpointOptions & {
|
|
20
33
|
items?: Item[];
|
|
21
34
|
threadId?: string;
|
|
22
35
|
resourceId?: string;
|
|
23
36
|
cwdInit?: string;
|
|
24
|
-
memory?: MemoryLayer[];
|
|
25
37
|
}): Context;
|
|
26
38
|
}
|
|
27
39
|
/**
|
|
@@ -41,10 +53,18 @@ export declare function captureCheckpoint(h: CheckpointHarnessHandle, ctx: Conte
|
|
|
41
53
|
* the restored context observes the pre-crash state through
|
|
42
54
|
* `readLayerState` and the memory projectors.
|
|
43
55
|
*
|
|
56
|
+
* `opts` carries the host's own context wiring (broadcaster, parent, state,
|
|
57
|
+
* layer overrides) into the rebuilt context. A snapshot cannot round-trip live
|
|
58
|
+
* objects, so a host that decorated the original context has to hand the same
|
|
59
|
+
* decoration back here — otherwise the resumed run gets a bare context and
|
|
60
|
+
* whatever depended on that wiring stops working silently. Snapshot-owned
|
|
61
|
+
* fields always win: identity, item log, and cwd come from the persisted
|
|
62
|
+
* record, never from `opts`.
|
|
63
|
+
*
|
|
44
64
|
* Preserves the original executionId on the returned context via
|
|
45
65
|
* `Object.defineProperty` — adapter correlation across crash/restart
|
|
46
66
|
* requires a stable id.
|
|
47
67
|
*
|
|
48
68
|
* @internal
|
|
49
69
|
*/
|
|
50
|
-
export declare function restoreFromCheckpoint(h: CheckpointHarnessHandle, executionId: string): Promise<Context | null>;
|
|
70
|
+
export declare function restoreFromCheckpoint(h: CheckpointHarnessHandle, executionId: string, opts?: RestoreCheckpointOptions): Promise<Context | null>;
|
|
@@ -65,13 +65,21 @@ export async function captureCheckpoint(h, ctx) {
|
|
|
65
65
|
* the restored context observes the pre-crash state through
|
|
66
66
|
* `readLayerState` and the memory projectors.
|
|
67
67
|
*
|
|
68
|
+
* `opts` carries the host's own context wiring (broadcaster, parent, state,
|
|
69
|
+
* layer overrides) into the rebuilt context. A snapshot cannot round-trip live
|
|
70
|
+
* objects, so a host that decorated the original context has to hand the same
|
|
71
|
+
* decoration back here — otherwise the resumed run gets a bare context and
|
|
72
|
+
* whatever depended on that wiring stops working silently. Snapshot-owned
|
|
73
|
+
* fields always win: identity, item log, and cwd come from the persisted
|
|
74
|
+
* record, never from `opts`.
|
|
75
|
+
*
|
|
68
76
|
* Preserves the original executionId on the returned context via
|
|
69
77
|
* `Object.defineProperty` — adapter correlation across crash/restart
|
|
70
78
|
* requires a stable id.
|
|
71
79
|
*
|
|
72
80
|
* @internal
|
|
73
81
|
*/
|
|
74
|
-
export async function restoreFromCheckpoint(h, executionId) {
|
|
82
|
+
export async function restoreFromCheckpoint(h, executionId, opts) {
|
|
75
83
|
const store = h.checkpointStore;
|
|
76
84
|
if (!store) {
|
|
77
85
|
return null;
|
|
@@ -85,12 +93,16 @@ export async function restoreFromCheckpoint(h, executionId) {
|
|
|
85
93
|
}
|
|
86
94
|
const items = h.itemSchemas.parseMany(snapshot.itemLog.items);
|
|
87
95
|
const cwdInit = snapshot.cwd?.current ?? undefined;
|
|
96
|
+
/* Caller wiring first, snapshot second: a host may legitimately swap the memory
|
|
97
|
+
* layers or hang the restored execution under a new parent, but it must never be
|
|
98
|
+
* able to override the identity/history the snapshot is the record of. */
|
|
88
99
|
const ctx = h.createContext({
|
|
100
|
+
...opts,
|
|
89
101
|
items,
|
|
90
102
|
threadId: snapshot.threadId,
|
|
91
103
|
resourceId: snapshot.resourceId,
|
|
92
104
|
cwdInit,
|
|
93
|
-
memory: h._memory,
|
|
105
|
+
memory: opts?.memory ?? h._memory,
|
|
94
106
|
});
|
|
95
107
|
if (ctx instanceof ContextImpl) {
|
|
96
108
|
Object.defineProperty(ctx, 'id', {
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
* into the single `execution:<id>:snapshot` key would rewrite a growing blob on every
|
|
12
12
|
* step — O(n²) bytes over a run.
|
|
13
13
|
*/
|
|
14
|
+
import { storageGetMany } from '@noetic-tools/memory';
|
|
14
15
|
import { z } from 'zod';
|
|
15
16
|
/** @public One completed step, keyed by its execution path. */
|
|
16
17
|
export const StepLedgerEntrySchema = z.object({
|
|
@@ -38,10 +39,15 @@ export function createStepLedgerStore(opts) {
|
|
|
38
39
|
},
|
|
39
40
|
load: async (executionId) => {
|
|
40
41
|
const keys = await storage.list(stepLedgerPrefix(executionId));
|
|
42
|
+
/* One batch read, not one round trip per completed step. Recovery is the
|
|
43
|
+
* moment a network-backed adapter can least afford an N+1. */
|
|
44
|
+
const entries = await storageGetMany(storage, keys);
|
|
41
45
|
const byPath = new Map();
|
|
46
|
+
// Walk `keys`, not the map: `seqKey`'s zero-padding makes `list()` order
|
|
47
|
+
// dispatch order, and a later entry at a path must win over an earlier one.
|
|
42
48
|
for (const key of keys) {
|
|
43
|
-
const raw =
|
|
44
|
-
if (raw ===
|
|
49
|
+
const raw = entries.get(key);
|
|
50
|
+
if (raw === undefined) {
|
|
45
51
|
continue;
|
|
46
52
|
}
|
|
47
53
|
const parsed = StepLedgerEntrySchema.safeParse(raw);
|
|
@@ -28,6 +28,17 @@ export function createInMemoryStorage() {
|
|
|
28
28
|
...store.keys(),
|
|
29
29
|
].filter((k) => k.startsWith(prefix));
|
|
30
30
|
},
|
|
31
|
+
async getMany(keys) {
|
|
32
|
+
const found = new Map();
|
|
33
|
+
for (const key of keys) {
|
|
34
|
+
const val = store.get(key);
|
|
35
|
+
if (val === undefined) {
|
|
36
|
+
continue;
|
|
37
|
+
}
|
|
38
|
+
found.set(key, frameworkCast(val));
|
|
39
|
+
}
|
|
40
|
+
return found;
|
|
41
|
+
},
|
|
31
42
|
};
|
|
32
43
|
}
|
|
33
44
|
//#endregion
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@noetic-tools/core",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.1.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Step primitives, interpreter, runtime, and memory layer contract for Noetic agents.",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -66,8 +66,8 @@
|
|
|
66
66
|
}
|
|
67
67
|
},
|
|
68
68
|
"dependencies": {
|
|
69
|
-
"@noetic-tools/memory": "^
|
|
70
|
-
"@noetic-tools/types": "^1.
|
|
69
|
+
"@noetic-tools/memory": "^2.0.0",
|
|
70
|
+
"@noetic-tools/types": "^2.1.0",
|
|
71
71
|
"@openrouter/agent": "^0.6.0",
|
|
72
72
|
"zod": "^4.0.0"
|
|
73
73
|
},
|