@noetic-tools/core 0.0.1 → 0.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/adapters/in-memory-fs-adapter.js +1 -1
- package/dist/adapters/in-memory-subprocess/manifest-persistence.d.ts +8 -0
- package/dist/adapters/in-memory-subprocess/manifest-persistence.js +56 -0
- package/dist/adapters/in-memory-subprocess/metadata.d.ts +12 -0
- package/dist/adapters/in-memory-subprocess/metadata.js +58 -0
- package/dist/adapters/in-memory-subprocess/step-completion.d.ts +3 -0
- package/dist/adapters/in-memory-subprocess/step-completion.js +86 -0
- package/dist/adapters/in-memory-subprocess/types.d.ts +88 -0
- package/dist/adapters/in-memory-subprocess/types.js +2 -0
- package/dist/adapters/in-memory-subprocess-adapter.d.ts +12 -4
- package/dist/adapters/in-memory-subprocess-adapter.js +164 -55
- package/dist/adapters/openrouter.d.ts +11 -2
- package/dist/adapters/openrouter.js +66 -5
- package/dist/builders/control-flow-builders.js +8 -3
- package/dist/builders/every.js +4 -1
- package/dist/builders/layer-provides-builders.d.ts +1 -32
- package/dist/builders/layer-provides-builders.js +1 -33
- package/dist/builders/loop-builder.js +4 -1
- package/dist/builders/memory-builder.js +1 -1
- package/dist/builders/provide-builder.js +4 -1
- package/dist/builders/spawn-builder.d.ts +20 -7
- package/dist/builders/spawn-builder.js +16 -2
- package/dist/builders/step-builders.d.ts +49 -28
- package/dist/builders/step-builders.js +30 -11
- package/dist/builders/tool-builder.d.ts +5 -1
- package/dist/builders/tool-builder.js +2 -0
- package/dist/builders/workflow-hydrator.d.ts +38 -0
- package/dist/builders/workflow-hydrator.js +336 -0
- package/dist/conditions/conditions.js +1 -1
- package/dist/errors/noetic-error.js +2 -0
- package/dist/{runtime → harness}/agent-harness.d.ts +65 -45
- package/dist/harness/agent-harness.js +576 -0
- package/dist/harness/deps/adapters.d.ts +4 -0
- package/dist/harness/deps/adapters.js +4 -0
- package/dist/harness/deps/interpreter.d.ts +5 -0
- package/dist/harness/deps/interpreter.js +4 -0
- package/dist/harness/deps/memory.d.ts +5 -0
- package/dist/harness/deps/memory.js +4 -0
- package/dist/harness/deps/runtime.d.ts +10 -0
- package/dist/harness/deps/runtime.js +7 -0
- package/dist/harness/deps/types.d.ts +17 -0
- package/dist/harness/deps/types.js +1 -0
- package/dist/harness/model-call.d.ts +50 -0
- package/dist/harness/model-call.js +694 -0
- package/dist/harness/model-schema.d.ts +19 -0
- package/dist/harness/model-schema.js +46 -0
- package/dist/harness/step-bootstrap.d.ts +25 -0
- package/dist/harness/step-bootstrap.js +170 -0
- package/dist/index.d.ts +48 -12
- package/dist/index.js +29 -7
- package/dist/interpreter/action-deps.d.ts +12 -0
- package/dist/interpreter/action-deps.js +10 -0
- package/dist/interpreter/action-types.d.ts +8 -0
- package/dist/interpreter/action-types.js +1 -0
- package/dist/interpreter/collect-tools.d.ts +1 -1
- package/dist/interpreter/collect-tools.js +6 -2
- package/dist/interpreter/execute-action.d.ts +22 -0
- package/dist/interpreter/execute-action.js +527 -0
- package/dist/interpreter/{execute-every.d.ts → execute-control.d.ts} +7 -1
- package/dist/interpreter/execute-control.js +530 -0
- package/dist/interpreter/execute.d.ts +13 -0
- package/dist/interpreter/execute.js +151 -48
- package/dist/interpreter/message-helpers.d.ts +1 -9
- package/dist/interpreter/message-helpers.js +1 -42
- package/dist/interpreter/step-dispatcher.d.ts +61 -0
- package/dist/interpreter/step-dispatcher.js +67 -0
- package/dist/interpreter/typeguards.d.ts +3 -10
- package/dist/interpreter/typeguards.js +3 -20
- package/dist/{runtime → memory}/exec-context-factory.js +1 -1
- package/dist/memory/flow-schema.d.ts +52 -0
- package/dist/memory/flow-schema.js +102 -0
- package/dist/memory/function-call-utils.js +4 -2
- package/dist/memory/layer-api.d.ts +1 -1
- package/dist/memory/layer-api.js +2 -2
- package/dist/memory/layer-lifecycle.d.ts +1 -1
- package/dist/memory/layer-lifecycle.js +2 -2
- package/dist/memory/layer-provides.d.ts +32 -0
- package/dist/memory/layer-provides.js +33 -0
- package/dist/memory/layer-usage.d.ts +3 -2
- package/dist/memory/layer-usage.js +9 -3
- package/dist/memory/layers/durable-task-state.js +1 -1
- package/dist/memory/layers/file-reference.js +302 -246
- package/dist/memory/layers/history-window.js +1 -1
- package/dist/memory/layers/observational-memory.js +1 -2
- package/dist/memory/layers/plan.d.ts +1 -1
- package/dist/memory/layers/plan.js +13 -8
- package/dist/memory/layers/steering.js +1 -1
- package/dist/memory/layers/tool-memory-layer.d.ts +1 -1
- package/dist/memory/layers/working-memory.js +2 -2
- package/dist/patterns/dynamic-workflow.d.ts +55 -0
- package/dist/patterns/dynamic-workflow.js +194 -0
- package/dist/patterns/flow.d.ts +2 -52
- package/dist/patterns/flow.js +1 -103
- package/dist/patterns/interview.js +1 -1
- package/dist/patterns/plans.d.ts +3 -3
- package/dist/patterns/plans.js +3 -3
- package/dist/patterns/ralph-wiggum.d.ts +1 -1
- package/dist/patterns/react.d.ts +1 -1
- package/dist/portable/adapters.d.ts +6 -0
- package/dist/portable/adapters.js +6 -0
- package/dist/portable/ask-user.d.ts +4 -0
- package/dist/portable/ask-user.js +2 -0
- package/dist/portable/builders.d.ts +12 -0
- package/dist/portable/builders.js +12 -0
- package/dist/portable/memory-layers.d.ts +12 -0
- package/dist/portable/memory-layers.js +12 -0
- package/dist/portable/runtime.d.ts +4 -0
- package/dist/portable/runtime.js +4 -0
- package/dist/portable/until.d.ts +4 -0
- package/dist/portable/until.js +4 -0
- package/dist/portable.d.ts +8 -26
- package/dist/portable.js +8 -34
- package/dist/runtime/broadcaster-utils.d.ts +5 -1
- package/dist/runtime/broadcaster-utils.js +11 -6
- package/dist/runtime/channel-store.js +1 -1
- package/dist/runtime/context-deps.d.ts +4 -0
- package/dist/runtime/context-deps.js +2 -0
- package/dist/runtime/context-impl.d.ts +42 -12
- package/dist/runtime/context-impl.js +51 -4
- package/dist/runtime/context-type-deps.d.ts +14 -0
- package/dist/runtime/context-type-deps.js +1 -0
- package/dist/runtime/detached-handle.d.ts +50 -2
- package/dist/runtime/detached-handle.js +216 -12
- package/dist/runtime/durable/checkpoint-store.d.ts +38 -0
- package/dist/runtime/durable/checkpoint-store.js +101 -0
- package/dist/runtime/durable/detached-signal.d.ts +37 -0
- package/dist/runtime/durable/detached-signal.js +52 -0
- package/dist/runtime/durable/harness-checkpoints.d.ts +51 -0
- package/dist/runtime/durable/harness-checkpoints.js +104 -0
- package/dist/runtime/durable/index.d.ts +10 -0
- package/dist/runtime/durable/index.js +5 -0
- package/dist/runtime/durable/runnable-loop.d.ts +100 -0
- package/dist/runtime/durable/runnable-loop.js +90 -0
- package/dist/runtime/durable/session-seed.d.ts +28 -0
- package/dist/runtime/durable/session-seed.js +27 -0
- package/dist/runtime/durable/stall-nudge.d.ts +82 -0
- package/dist/runtime/durable/stall-nudge.js +87 -0
- package/dist/runtime/in-memory-storage.js +1 -1
- package/dist/runtime/item-log-impl.d.ts +1 -1
- package/dist/runtime/step-registry.d.ts +42 -0
- package/dist/runtime/step-registry.js +77 -0
- package/dist/schemas/workflow.d.ts +139 -0
- package/dist/schemas/workflow.js +232 -0
- package/dist/types/ask-user-types.d.ts +57 -0
- package/dist/types/ask-user-types.js +74 -0
- package/dist/types/checkpoint.d.ts +98 -0
- package/dist/types/checkpoint.js +81 -0
- package/dist/types/common.d.ts +1 -50
- package/dist/types/context-parts/item-log.d.ts +6 -0
- package/dist/types/context-parts/item-log.js +1 -0
- package/dist/types/context-parts/layer-usage.d.ts +18 -0
- package/dist/types/context-parts/layer-usage.js +1 -0
- package/dist/types/context.d.ts +135 -26
- package/dist/types/error.d.ts +15 -0
- package/dist/types/harness-result.d.ts +1 -1
- package/dist/types/items.d.ts +18 -2
- package/dist/types/memory-context.d.ts +39 -0
- package/dist/types/memory-context.js +1 -0
- package/dist/types/memory.d.ts +35 -65
- package/dist/types/runtime.d.ts +2 -1
- package/dist/types/steering.d.ts +1 -1
- package/dist/types/step-registrar.d.ts +46 -0
- package/dist/types/step-registrar.js +56 -0
- package/dist/types/step.d.ts +30 -5
- package/dist/types/subprocess-adapter.d.ts +119 -3
- package/dist/types/subprocess-adapter.js +2 -0
- package/dist/types/tool.d.ts +64 -0
- package/dist/types/tool.js +1 -0
- package/dist/unstable.d.ts +2 -2
- package/dist/unstable.js +2 -2
- package/dist/until/predicates.d.ts +9 -0
- package/dist/until/predicates.js +14 -0
- package/dist/util/message-helpers.d.ts +17 -0
- package/dist/util/message-helpers.js +64 -0
- package/package.json +1 -1
- package/dist/adapters/local-fs-adapter.d.ts +0 -3
- package/dist/adapters/local-fs-adapter.js +0 -43
- package/dist/adapters/local-shell-adapter.d.ts +0 -51
- package/dist/adapters/local-shell-adapter.js +0 -167
- package/dist/adapters/local-subprocess-adapter.d.ts +0 -16
- package/dist/adapters/local-subprocess-adapter.js +0 -187
- package/dist/interpreter/execute-branch.d.ts +0 -3
- package/dist/interpreter/execute-branch.js +0 -10
- package/dist/interpreter/execute-every.js +0 -143
- package/dist/interpreter/execute-fork.d.ts +0 -3
- package/dist/interpreter/execute-fork.js +0 -215
- package/dist/interpreter/execute-llm.d.ts +0 -4
- package/dist/interpreter/execute-llm.js +0 -217
- package/dist/interpreter/execute-loop.d.ts +0 -3
- package/dist/interpreter/execute-loop.js +0 -171
- package/dist/interpreter/execute-provide.d.ts +0 -10
- package/dist/interpreter/execute-provide.js +0 -64
- package/dist/interpreter/execute-run.d.ts +0 -3
- package/dist/interpreter/execute-run.js +0 -39
- package/dist/interpreter/execute-spawn.d.ts +0 -11
- package/dist/interpreter/execute-spawn.js +0 -113
- package/dist/interpreter/execute-tool.d.ts +0 -5
- package/dist/interpreter/execute-tool.js +0 -81
- package/dist/runtime/agent-harness.js +0 -1170
- /package/dist/{runtime → memory}/exec-context-factory.d.ts +0 -0
- /package/dist/{interpreter → util}/framework-cast.d.ts +0 -0
- /package/dist/{interpreter → util}/framework-cast.js +0 -0
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { StorageAdapter } from '../../types/memory';
|
|
2
|
+
import type { StepSubprocessRequest, SubprocessHandle } from '../../types/subprocess-adapter';
|
|
3
|
+
import type { InMemoryStepManifest } from './types';
|
|
4
|
+
export declare function isStepManifest(value: unknown): value is InMemoryStepManifest;
|
|
5
|
+
export declare function persistStepManifest(storage: StorageAdapter, request: StepSubprocessRequest, handle: SubprocessHandle): Promise<void>;
|
|
6
|
+
export declare function clearManifest(storage: StorageAdapter, handleId: string): Promise<void>;
|
|
7
|
+
export declare function loadManifest(storage: StorageAdapter, handleId: string): Promise<InMemoryStepManifest | null>;
|
|
8
|
+
export declare function listManifests(storage: StorageAdapter): Promise<InMemoryStepManifest[]>;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { isRecord } from './metadata';
|
|
2
|
+
//#region Key layout
|
|
3
|
+
const IN_MEMORY_MANIFEST_PREFIX = 'inMemorySubprocess:manifest:';
|
|
4
|
+
function manifestKey(handleId) {
|
|
5
|
+
return `${IN_MEMORY_MANIFEST_PREFIX}${handleId}`;
|
|
6
|
+
}
|
|
7
|
+
//#endregion
|
|
8
|
+
//#region Guards
|
|
9
|
+
export function isStepManifest(value) {
|
|
10
|
+
if (!isRecord(value)) {
|
|
11
|
+
return false;
|
|
12
|
+
}
|
|
13
|
+
return (value.kind === 'step' &&
|
|
14
|
+
typeof value.handleId === 'string' &&
|
|
15
|
+
typeof value.stepId === 'string' &&
|
|
16
|
+
typeof value.executionId === 'string' &&
|
|
17
|
+
typeof value.startedAt === 'string' &&
|
|
18
|
+
isRecord(value.overrides));
|
|
19
|
+
}
|
|
20
|
+
//#endregion
|
|
21
|
+
//#region CRUD
|
|
22
|
+
export async function persistStepManifest(storage, request, handle) {
|
|
23
|
+
const manifest = {
|
|
24
|
+
kind: 'step',
|
|
25
|
+
handleId: handle.id,
|
|
26
|
+
stepId: request.stepId,
|
|
27
|
+
executionId: request.executionId,
|
|
28
|
+
serializedInput: request.serializedInput,
|
|
29
|
+
overrides: request.overrides,
|
|
30
|
+
startedAt: handle.startedAt,
|
|
31
|
+
reattachMode: 'replay',
|
|
32
|
+
};
|
|
33
|
+
await storage.set(manifestKey(handle.id), manifest);
|
|
34
|
+
}
|
|
35
|
+
export async function clearManifest(storage, handleId) {
|
|
36
|
+
await storage.delete(manifestKey(handleId));
|
|
37
|
+
}
|
|
38
|
+
export async function loadManifest(storage, handleId) {
|
|
39
|
+
const raw = await storage.get(manifestKey(handleId));
|
|
40
|
+
if (raw === null) {
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
43
|
+
return isStepManifest(raw) ? raw : null;
|
|
44
|
+
}
|
|
45
|
+
export async function listManifests(storage) {
|
|
46
|
+
const keys = await storage.list(IN_MEMORY_MANIFEST_PREFIX);
|
|
47
|
+
const out = [];
|
|
48
|
+
for (const key of keys) {
|
|
49
|
+
const raw = await storage.get(key);
|
|
50
|
+
if (isStepManifest(raw)) {
|
|
51
|
+
out.push(raw);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return out;
|
|
55
|
+
}
|
|
56
|
+
//#endregion
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { ProcessSubprocessRequest, SerializedError, StepSubprocessRequest, SubprocessHandleMetadata, SubprocessRequest } from '../../types/subprocess-adapter';
|
|
2
|
+
export declare function nowIso(): string;
|
|
3
|
+
export declare function isStepRequest(request: SubprocessRequest): request is StepSubprocessRequest;
|
|
4
|
+
export declare function isProcessRequest(request: SubprocessRequest): request is ProcessSubprocessRequest;
|
|
5
|
+
export declare function isRecord(value: unknown): value is Record<string, unknown>;
|
|
6
|
+
/** Convert a thrown value into a `SerializedError`. `NoeticErrorImpl`
|
|
7
|
+
* instances (and anything exposing `noeticError`) retain their structured
|
|
8
|
+
* payload so consumers can rehydrate typed kinds without a brittle message
|
|
9
|
+
* regex. */
|
|
10
|
+
export declare function serializeError(err: unknown): SerializedError;
|
|
11
|
+
export declare function buildProcessMetadata(request: ProcessSubprocessRequest): SubprocessHandleMetadata;
|
|
12
|
+
export declare function buildStepMetadata(request: StepSubprocessRequest): SubprocessHandleMetadata;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
//#region Time
|
|
2
|
+
export function nowIso() {
|
|
3
|
+
return new Date().toISOString();
|
|
4
|
+
}
|
|
5
|
+
//#endregion
|
|
6
|
+
//#region Type guards
|
|
7
|
+
export function isStepRequest(request) {
|
|
8
|
+
return request.kind === 'step';
|
|
9
|
+
}
|
|
10
|
+
export function isProcessRequest(request) {
|
|
11
|
+
return request.kind !== 'step';
|
|
12
|
+
}
|
|
13
|
+
export function isRecord(value) {
|
|
14
|
+
return typeof value === 'object' && value !== null;
|
|
15
|
+
}
|
|
16
|
+
//#endregion
|
|
17
|
+
//#region Error serialisation
|
|
18
|
+
/** Convert a thrown value into a `SerializedError`. `NoeticErrorImpl`
|
|
19
|
+
* instances (and anything exposing `noeticError`) retain their structured
|
|
20
|
+
* payload so consumers can rehydrate typed kinds without a brittle message
|
|
21
|
+
* regex. */
|
|
22
|
+
export function serializeError(err) {
|
|
23
|
+
if (err instanceof Error) {
|
|
24
|
+
const payload = {
|
|
25
|
+
message: err.message,
|
|
26
|
+
name: err.name,
|
|
27
|
+
stack: err.stack,
|
|
28
|
+
};
|
|
29
|
+
if (isRecord(err) && 'noeticError' in err) {
|
|
30
|
+
payload.noeticError = err.noeticError;
|
|
31
|
+
}
|
|
32
|
+
return payload;
|
|
33
|
+
}
|
|
34
|
+
return {
|
|
35
|
+
message: typeof err === 'string' ? err : String(err),
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
//#endregion
|
|
39
|
+
//#region Metadata builders
|
|
40
|
+
export function buildProcessMetadata(request) {
|
|
41
|
+
return {
|
|
42
|
+
...(request.metadata ?? {}),
|
|
43
|
+
runtime: 'in-memory',
|
|
44
|
+
command: request.command,
|
|
45
|
+
args: request.args ?? [],
|
|
46
|
+
cwd: request.cwd,
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
export function buildStepMetadata(request) {
|
|
50
|
+
return {
|
|
51
|
+
...(request.metadata ?? {}),
|
|
52
|
+
runtime: 'in-memory',
|
|
53
|
+
kind: 'step',
|
|
54
|
+
stepId: request.stepId,
|
|
55
|
+
executionId: request.executionId,
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
//#endregion
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { CompleteProcessRunParams, CompleteStepRunParams } from './types';
|
|
2
|
+
export declare function completeProcessRun({ request, handle, run, handles, active, save, clearIfDurable, }: CompleteProcessRunParams): Promise<void>;
|
|
3
|
+
export declare function completeStepRun({ request, handle, stepRunner, handles, active, save, clearIfDurable, }: CompleteStepRunParams): Promise<void>;
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { nowIso, serializeError } from './metadata';
|
|
2
|
+
//#region Completion handlers
|
|
3
|
+
export async function completeProcessRun({ request, handle, run, handles, active, save, clearIfDurable, }) {
|
|
4
|
+
try {
|
|
5
|
+
await run?.(request, handle);
|
|
6
|
+
const latest = handles.get(handle.id);
|
|
7
|
+
if (!latest || latest.status !== 'running') {
|
|
8
|
+
return;
|
|
9
|
+
}
|
|
10
|
+
active.delete(handle.id);
|
|
11
|
+
await save({
|
|
12
|
+
...latest,
|
|
13
|
+
status: 'completed',
|
|
14
|
+
updatedAt: nowIso(),
|
|
15
|
+
});
|
|
16
|
+
// Clear the durable handle manifest once the run has terminated so
|
|
17
|
+
// `listLive()` stops returning this handle. Without this call the
|
|
18
|
+
// manifest would persist until `stop()` was called, making every
|
|
19
|
+
// completed step look live from the adapter's persistence layer.
|
|
20
|
+
await clearIfDurable(handle.id);
|
|
21
|
+
}
|
|
22
|
+
catch (err) {
|
|
23
|
+
active.delete(handle.id);
|
|
24
|
+
const latest = handles.get(handle.id) ?? handle;
|
|
25
|
+
await save({
|
|
26
|
+
...latest,
|
|
27
|
+
status: 'failed',
|
|
28
|
+
updatedAt: nowIso(),
|
|
29
|
+
metadata: {
|
|
30
|
+
...(latest.metadata ?? {}),
|
|
31
|
+
error: serializeError(err),
|
|
32
|
+
},
|
|
33
|
+
});
|
|
34
|
+
// Same rationale as the success branch above — clear the durable
|
|
35
|
+
// manifest so `listLive()` doesn't resurrect this handle on reboot.
|
|
36
|
+
await clearIfDurable(handle.id);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
export async function completeStepRun({ request, handle, stepRunner, handles, active, save, clearIfDurable, }) {
|
|
40
|
+
try {
|
|
41
|
+
const executor = request._localExecutor;
|
|
42
|
+
let result;
|
|
43
|
+
if (executor) {
|
|
44
|
+
result = await executor();
|
|
45
|
+
}
|
|
46
|
+
else if (stepRunner) {
|
|
47
|
+
result = await stepRunner(request, handle);
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
throw new Error(`In-memory subprocess adapter has no executor for step "${request.stepId}". ` +
|
|
51
|
+
'Provide a stepRunner option or dispatch via AgentHarness.');
|
|
52
|
+
}
|
|
53
|
+
const latest = handles.get(handle.id);
|
|
54
|
+
if (!latest || latest.status !== 'running') {
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
active.delete(handle.id);
|
|
58
|
+
await save({
|
|
59
|
+
...latest,
|
|
60
|
+
status: 'completed',
|
|
61
|
+
updatedAt: nowIso(),
|
|
62
|
+
metadata: {
|
|
63
|
+
...(latest.metadata ?? {}),
|
|
64
|
+
result,
|
|
65
|
+
},
|
|
66
|
+
});
|
|
67
|
+
// Clear the durable step manifest once the run has terminated —
|
|
68
|
+
// see `completeProcessRun` above for the rationale.
|
|
69
|
+
await clearIfDurable(handle.id);
|
|
70
|
+
}
|
|
71
|
+
catch (err) {
|
|
72
|
+
active.delete(handle.id);
|
|
73
|
+
const latest = handles.get(handle.id) ?? handle;
|
|
74
|
+
await save({
|
|
75
|
+
...latest,
|
|
76
|
+
status: 'failed',
|
|
77
|
+
updatedAt: nowIso(),
|
|
78
|
+
metadata: {
|
|
79
|
+
...(latest.metadata ?? {}),
|
|
80
|
+
error: serializeError(err),
|
|
81
|
+
},
|
|
82
|
+
});
|
|
83
|
+
await clearIfDurable(handle.id);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
//#endregion
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import type { StorageAdapter } from '../../types/memory';
|
|
2
|
+
import type { ProcessSubprocessRequest, StepSubprocessRequest, SubprocessHandle, SubprocessHandleMetadata, SubprocessRequest } from '../../types/subprocess-adapter';
|
|
3
|
+
/**
|
|
4
|
+
* @public
|
|
5
|
+
* Options for `createInMemorySubprocessAdapter`. All hooks are optional;
|
|
6
|
+
* when none is provided the adapter still handles `spawn` + `stop` +
|
|
7
|
+
* lifecycle transitions for test-double purposes.
|
|
8
|
+
*/
|
|
9
|
+
export interface CreateInMemorySubprocessAdapterOptions {
|
|
10
|
+
/**
|
|
11
|
+
* Invoked for `kind: 'process'` requests (the classic test-double hook).
|
|
12
|
+
* When absent the adapter marks the handle `completed` on the next
|
|
13
|
+
* microtask without running any body.
|
|
14
|
+
*/
|
|
15
|
+
run?: (request: SubprocessRequest, handle: SubprocessHandle) => Promise<void>;
|
|
16
|
+
/**
|
|
17
|
+
* Invoked for `kind: 'step'` requests that do not already carry a
|
|
18
|
+
* `_localExecutor` closure. Callers swap this out to simulate step
|
|
19
|
+
* execution in tests; the default harness-bound adapter provides an
|
|
20
|
+
* implementation that invokes the in-process execute pipeline.
|
|
21
|
+
*/
|
|
22
|
+
stepRunner?: (request: StepSubprocessRequest, handle: SubprocessHandle) => Promise<unknown>;
|
|
23
|
+
/**
|
|
24
|
+
* Optional synchronous metadata injector. Called during `spawn()` before
|
|
25
|
+
* the handle is returned, its result is merged on top of the adapter's
|
|
26
|
+
* intrinsic metadata (runtime, command/args/cwd, etc.). Use this to stamp
|
|
27
|
+
* pid / pidStarttime / test-only fields without having to wrap the adapter.
|
|
28
|
+
*
|
|
29
|
+
* Keys returned here win over the adapter's defaults — tests can override
|
|
30
|
+
* `runtime` if they need to simulate a different adapter variant.
|
|
31
|
+
*/
|
|
32
|
+
metadataInjector?: (request: SubprocessRequest) => Partial<SubprocessHandleMetadata>;
|
|
33
|
+
/**
|
|
34
|
+
* Optional `StorageAdapter` that gives the in-memory adapter a durable
|
|
35
|
+
* handle manifest. When supplied, `spawn()` persists a manifest per
|
|
36
|
+
* handle and `reattach(handleId)` / `listLive()` consult it across adapter
|
|
37
|
+
* restarts. When absent the adapter is purely ephemeral — matching the
|
|
38
|
+
* test-double semantics established in Phase A.
|
|
39
|
+
*
|
|
40
|
+
* For in-memory the "reattached" handle is an idempotent re-run of the
|
|
41
|
+
* step from the persisted `serializedInput`. We're honest about that in
|
|
42
|
+
* the manifest (`reattachMode: 'replay'`) — this is the sanest in-memory
|
|
43
|
+
* semantic because there is no long-lived process to bind back to.
|
|
44
|
+
*/
|
|
45
|
+
storage?: StorageAdapter;
|
|
46
|
+
}
|
|
47
|
+
export interface CompleteProcessRunParams {
|
|
48
|
+
request: ProcessSubprocessRequest;
|
|
49
|
+
handle: SubprocessHandle;
|
|
50
|
+
run: CreateInMemorySubprocessAdapterOptions['run'];
|
|
51
|
+
handles: Map<string, SubprocessHandle>;
|
|
52
|
+
active: Set<string>;
|
|
53
|
+
save: (handle: SubprocessHandle) => Promise<SubprocessHandle>;
|
|
54
|
+
/** Invoked on terminal transitions so the durable handle manifest
|
|
55
|
+
* does not linger after the step is done — otherwise `listLive()`
|
|
56
|
+
* would return phantom handles for every step ever completed
|
|
57
|
+
* against this storage. No-op when no storage was configured. */
|
|
58
|
+
clearIfDurable: (handleId: string) => Promise<void>;
|
|
59
|
+
}
|
|
60
|
+
export interface CompleteStepRunParams {
|
|
61
|
+
request: StepSubprocessRequest;
|
|
62
|
+
handle: SubprocessHandle;
|
|
63
|
+
stepRunner: CreateInMemorySubprocessAdapterOptions['stepRunner'];
|
|
64
|
+
handles: Map<string, SubprocessHandle>;
|
|
65
|
+
active: Set<string>;
|
|
66
|
+
save: (handle: SubprocessHandle) => Promise<SubprocessHandle>;
|
|
67
|
+
/** See `CompleteProcessRunParams.clearIfDurable`. */
|
|
68
|
+
clearIfDurable: (handleId: string) => Promise<void>;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Persistable manifest for an in-memory handle. Written to the
|
|
72
|
+
* StorageAdapter on spawn and cleared on stop — a restart can list live
|
|
73
|
+
* handles via this prefix and re-run the step from `serializedInput`.
|
|
74
|
+
*
|
|
75
|
+
* Scoped to `step`-kind requests because `process`-kind handles carry no
|
|
76
|
+
* replayable body (they represent already-launched OS processes whose state
|
|
77
|
+
* is not ours to recreate).
|
|
78
|
+
*/
|
|
79
|
+
export interface InMemoryStepManifest {
|
|
80
|
+
kind: 'step';
|
|
81
|
+
handleId: string;
|
|
82
|
+
stepId: string;
|
|
83
|
+
executionId: string;
|
|
84
|
+
serializedInput: unknown;
|
|
85
|
+
overrides: StepSubprocessRequest['overrides'];
|
|
86
|
+
startedAt: string;
|
|
87
|
+
reattachMode: 'replay';
|
|
88
|
+
}
|
|
@@ -1,5 +1,13 @@
|
|
|
1
|
-
import type { SubprocessAdapter
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
import type { SubprocessAdapter } from '../types/subprocess-adapter';
|
|
2
|
+
import type { CreateInMemorySubprocessAdapterOptions } from './in-memory-subprocess/types';
|
|
3
|
+
export type { CreateInMemorySubprocessAdapterOptions } from './in-memory-subprocess/types';
|
|
4
|
+
/**
|
|
5
|
+
* @public
|
|
6
|
+
* In-memory `SubprocessAdapter` for tests and non-durable in-process
|
|
7
|
+
* step execution. When an optional `StorageAdapter` is supplied the
|
|
8
|
+
* adapter persists per-handle manifests so `reattach()` / `listLive()`
|
|
9
|
+
* work across adapter instances — the reattached handle is an idempotent
|
|
10
|
+
* re-run of the step from the persisted `serializedInput`, not a bind to
|
|
11
|
+
* a live process (there is none to bind to for in-memory).
|
|
12
|
+
*/
|
|
5
13
|
export declare function createInMemorySubprocessAdapter(options?: CreateInMemorySubprocessAdapterOptions): SubprocessAdapter;
|
|
@@ -1,68 +1,135 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
}
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
1
|
+
import { clearManifest, listManifests, loadManifest, persistStepManifest, } from './in-memory-subprocess/manifest-persistence';
|
|
2
|
+
import { buildProcessMetadata, buildStepMetadata, isProcessRequest, isStepRequest, nowIso, } from './in-memory-subprocess/metadata';
|
|
3
|
+
import { completeProcessRun, completeStepRun } from './in-memory-subprocess/step-completion';
|
|
4
|
+
//#region Factory
|
|
5
|
+
/**
|
|
6
|
+
* @public
|
|
7
|
+
* In-memory `SubprocessAdapter` for tests and non-durable in-process
|
|
8
|
+
* step execution. When an optional `StorageAdapter` is supplied the
|
|
9
|
+
* adapter persists per-handle manifests so `reattach()` / `listLive()`
|
|
10
|
+
* work across adapter instances — the reattached handle is an idempotent
|
|
11
|
+
* re-run of the step from the persisted `serializedInput`, not a bind to
|
|
12
|
+
* a live process (there is none to bind to for in-memory).
|
|
13
|
+
*/
|
|
14
|
+
export function createInMemorySubprocessAdapter(options = {}) {
|
|
15
|
+
const handles = new Map();
|
|
16
|
+
const active = new Set();
|
|
17
|
+
const storage = options.storage;
|
|
18
|
+
async function save(handle) {
|
|
19
|
+
handles.set(handle.id, handle);
|
|
20
|
+
return handle;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Persist a step manifest after spawn so `reattach` and `listLive` can
|
|
24
|
+
* find this handle again on a subsequent adapter instance. Errors are
|
|
25
|
+
* logged rather than propagated — a failed manifest write must not break
|
|
26
|
+
* otherwise-successful step dispatch.
|
|
27
|
+
*/
|
|
28
|
+
async function persistIfDurable(request, handle) {
|
|
29
|
+
if (!storage) {
|
|
9
30
|
return;
|
|
10
31
|
}
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
32
|
+
try {
|
|
33
|
+
await persistStepManifest(storage, request, handle);
|
|
34
|
+
}
|
|
35
|
+
catch (err) {
|
|
36
|
+
console.warn(`createInMemorySubprocessAdapter: failed to persist manifest for "${handle.id}":`, err);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
async function clearIfDurable(handleId) {
|
|
40
|
+
if (!storage) {
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
try {
|
|
44
|
+
await clearManifest(storage, handleId);
|
|
45
|
+
}
|
|
46
|
+
catch (err) {
|
|
47
|
+
console.warn(`createInMemorySubprocessAdapter: failed to clear manifest for "${handleId}":`, err);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
function injectMetadata(request, intrinsic) {
|
|
51
|
+
if (!options.metadataInjector) {
|
|
52
|
+
return intrinsic;
|
|
53
|
+
}
|
|
54
|
+
return {
|
|
55
|
+
...intrinsic,
|
|
56
|
+
...options.metadataInjector(request),
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
async function spawnStepHandle(request) {
|
|
60
|
+
const now = nowIso();
|
|
61
|
+
const handle = {
|
|
62
|
+
id: `subprocess-${crypto.randomUUID()}`,
|
|
63
|
+
status: 'running',
|
|
64
|
+
startedAt: now,
|
|
65
|
+
updatedAt: now,
|
|
66
|
+
metadata: injectMetadata(request, buildStepMetadata(request)),
|
|
67
|
+
};
|
|
68
|
+
active.add(handle.id);
|
|
69
|
+
await save(handle);
|
|
70
|
+
await persistIfDurable(request, handle);
|
|
71
|
+
void completeStepRun({
|
|
72
|
+
request,
|
|
73
|
+
handle,
|
|
74
|
+
stepRunner: options.stepRunner,
|
|
75
|
+
handles,
|
|
76
|
+
active,
|
|
77
|
+
save,
|
|
78
|
+
clearIfDurable,
|
|
16
79
|
});
|
|
80
|
+
return handle;
|
|
17
81
|
}
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
const
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
82
|
+
async function spawnProcessHandle(request) {
|
|
83
|
+
const now = nowIso();
|
|
84
|
+
const handle = {
|
|
85
|
+
id: `subprocess-${crypto.randomUUID()}`,
|
|
86
|
+
status: 'running',
|
|
87
|
+
startedAt: now,
|
|
88
|
+
updatedAt: now,
|
|
89
|
+
metadata: injectMetadata(request, buildProcessMetadata(request)),
|
|
90
|
+
};
|
|
91
|
+
active.add(handle.id);
|
|
92
|
+
await save(handle);
|
|
93
|
+
void completeProcessRun({
|
|
94
|
+
request,
|
|
95
|
+
handle,
|
|
96
|
+
run: options.run,
|
|
97
|
+
handles,
|
|
98
|
+
active,
|
|
99
|
+
save,
|
|
100
|
+
clearIfDurable,
|
|
101
|
+
});
|
|
102
|
+
return handle;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Build a hydrated handle from a persisted manifest. Status is `running`
|
|
106
|
+
* so consumers see the handle as live; a subsequent `reattach` call
|
|
107
|
+
* re-dispatches the step via the supplied `stepRunner`.
|
|
108
|
+
*/
|
|
109
|
+
function handleFromManifest(manifest) {
|
|
110
|
+
return {
|
|
111
|
+
id: manifest.handleId,
|
|
112
|
+
status: 'running',
|
|
113
|
+
startedAt: manifest.startedAt,
|
|
24
114
|
updatedAt: nowIso(),
|
|
25
115
|
metadata: {
|
|
26
|
-
|
|
27
|
-
|
|
116
|
+
runtime: 'in-memory',
|
|
117
|
+
kind: 'step',
|
|
118
|
+
stepId: manifest.stepId,
|
|
119
|
+
executionId: manifest.executionId,
|
|
120
|
+
reattachMode: manifest.reattachMode,
|
|
28
121
|
},
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
export function createInMemorySubprocessAdapter(options = {}) {
|
|
33
|
-
const handles = new Map();
|
|
34
|
-
const active = new Set();
|
|
35
|
-
async function save(handle) {
|
|
36
|
-
handles.set(handle.id, handle);
|
|
37
|
-
return handle;
|
|
122
|
+
};
|
|
38
123
|
}
|
|
39
124
|
return {
|
|
40
125
|
async spawn(request) {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
...(request.metadata ?? {}),
|
|
49
|
-
runtime: 'in-memory',
|
|
50
|
-
command: request.command,
|
|
51
|
-
args: request.args ?? [],
|
|
52
|
-
cwd: request.cwd,
|
|
53
|
-
},
|
|
54
|
-
};
|
|
55
|
-
active.add(handle.id);
|
|
56
|
-
await save(handle);
|
|
57
|
-
void completeInMemoryRun({
|
|
58
|
-
request,
|
|
59
|
-
handle,
|
|
60
|
-
run: options.run,
|
|
61
|
-
handles,
|
|
62
|
-
active,
|
|
63
|
-
save,
|
|
64
|
-
});
|
|
65
|
-
return handle;
|
|
126
|
+
if (isStepRequest(request)) {
|
|
127
|
+
return spawnStepHandle(request);
|
|
128
|
+
}
|
|
129
|
+
if (isProcessRequest(request)) {
|
|
130
|
+
return spawnProcessHandle(request);
|
|
131
|
+
}
|
|
132
|
+
throw new Error('Unsupported subprocess request variant.');
|
|
66
133
|
},
|
|
67
134
|
async get(handleId) {
|
|
68
135
|
return handles.get(handleId) ?? null;
|
|
@@ -76,6 +143,7 @@ export function createInMemorySubprocessAdapter(options = {}) {
|
|
|
76
143
|
};
|
|
77
144
|
}
|
|
78
145
|
active.delete(handleId);
|
|
146
|
+
await clearIfDurable(handleId);
|
|
79
147
|
const next = await save({
|
|
80
148
|
...handle,
|
|
81
149
|
status: 'stopped',
|
|
@@ -122,5 +190,46 @@ export function createInMemorySubprocessAdapter(options = {}) {
|
|
|
122
190
|
async isAlive(handle) {
|
|
123
191
|
return active.has(handle.id);
|
|
124
192
|
},
|
|
193
|
+
/**
|
|
194
|
+
* Idempotent re-run of a persisted step, not a "resume" — for in-memory
|
|
195
|
+
* there is no long-lived process to bind back to. The adapter's
|
|
196
|
+
* `reattachMode` on the manifest reflects this honestly. When no
|
|
197
|
+
* storage was configured we fall back to the ephemeral semantics
|
|
198
|
+
* established in Phase A (returning `null`).
|
|
199
|
+
*/
|
|
200
|
+
async reattach(handleId) {
|
|
201
|
+
if (!storage) {
|
|
202
|
+
return null;
|
|
203
|
+
}
|
|
204
|
+
const manifest = await loadManifest(storage, handleId);
|
|
205
|
+
if (!manifest) {
|
|
206
|
+
return null;
|
|
207
|
+
}
|
|
208
|
+
const handle = handleFromManifest(manifest);
|
|
209
|
+
active.add(handle.id);
|
|
210
|
+
await save(handle);
|
|
211
|
+
return handle;
|
|
212
|
+
},
|
|
213
|
+
async listLive() {
|
|
214
|
+
const live = new Map();
|
|
215
|
+
for (const id of active) {
|
|
216
|
+
const handle = handles.get(id);
|
|
217
|
+
if (handle) {
|
|
218
|
+
live.set(handle.id, handle);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
if (storage) {
|
|
222
|
+
const manifests = await listManifests(storage);
|
|
223
|
+
for (const manifest of manifests) {
|
|
224
|
+
if (!live.has(manifest.handleId)) {
|
|
225
|
+
live.set(manifest.handleId, handleFromManifest(manifest));
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
return [
|
|
230
|
+
...live.values(),
|
|
231
|
+
];
|
|
232
|
+
},
|
|
125
233
|
};
|
|
126
234
|
}
|
|
235
|
+
//#endregion
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import type * as OpenRouterAgent from '@openrouter/agent';
|
|
2
|
-
import type { LLMResponse
|
|
2
|
+
import type { LLMResponse } from '../types/common';
|
|
3
3
|
import type { Context } from '../types/context';
|
|
4
4
|
import type { EmbedFn } from '../types/embed';
|
|
5
5
|
import type { Item } from '../types/items';
|
|
6
6
|
import type { MemoryLayer } from '../types/memory';
|
|
7
7
|
import type { AgentHarnessContract } from '../types/runtime';
|
|
8
|
+
import type { Tool } from '../types/tool';
|
|
8
9
|
type ProviderOutputItem = OpenRouterAgent.OpenResponsesResult['output'][number];
|
|
9
10
|
type OpenRouterInputItem = OpenRouterAgent.EasyInputMessage | OpenRouterAgent.FunctionCallItem | OpenRouterAgent.FunctionCallOutputItem | ProviderOutputItem;
|
|
10
11
|
/** @internal */
|
|
@@ -28,6 +29,14 @@ export declare function itemsToInput(items: ReadonlyArray<Item>): OpenRouterInpu
|
|
|
28
29
|
export declare function extractOutputItems(response: OpenRouterAgent.OpenResponsesResult): Item[];
|
|
29
30
|
/** @internal */
|
|
30
31
|
export declare function extractUsage(usage: OpenRouterAgent.Usage | null | undefined): LLMResponse['usage'];
|
|
32
|
+
/**
|
|
33
|
+
* Provider APIs (Anthropic via OpenRouter) enforce tool names match
|
|
34
|
+
* `^[a-zA-Z0-9_-]{1,64}$`. Noetic's internal layer-tool names use `layerId/fn`
|
|
35
|
+
* which contains a forbidden `/`. We translate to a wire-safe form only at
|
|
36
|
+
* the SDK boundary; internal tool-name identity (and every codebase reference
|
|
37
|
+
* to names like `plan/updatePrd`) is preserved.
|
|
38
|
+
*/
|
|
39
|
+
export declare function sanitizeToolNameForWire(name: string): string;
|
|
31
40
|
/** @internal */
|
|
32
41
|
export declare function convertTools({ tools }: ConvertToolsParams): SdkTool[];
|
|
33
42
|
/** @internal */
|
|
@@ -53,5 +62,5 @@ export declare function executeToolCall(params: ExecuteToolCallParams): Promise<
|
|
|
53
62
|
* @param embeddingModel - Model identifier (default: `'openai/text-embedding-3-small'`).
|
|
54
63
|
* @returns An `EmbedFn` that produces embedding vectors for the given texts.
|
|
55
64
|
*/
|
|
56
|
-
export declare function createOpenRouterEmbed(apiKey
|
|
65
|
+
export declare function createOpenRouterEmbed(apiKey?: string, embeddingModel?: string): EmbedFn;
|
|
57
66
|
export {};
|