@noetic-tools/core 0.0.1 → 0.1.1

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.
Files changed (254) hide show
  1. package/README.md +31 -11
  2. package/dist/adapters/in-memory-fs-adapter.d.ts +1 -1
  3. package/dist/adapters/in-memory-fs-adapter.js +1 -1
  4. package/dist/adapters/in-memory-shell-adapter.d.ts +1 -1
  5. package/dist/adapters/in-memory-subprocess/manifest-persistence.d.ts +8 -0
  6. package/dist/adapters/in-memory-subprocess/manifest-persistence.js +56 -0
  7. package/dist/adapters/in-memory-subprocess/metadata.d.ts +12 -0
  8. package/dist/adapters/in-memory-subprocess/metadata.js +58 -0
  9. package/dist/adapters/in-memory-subprocess/step-completion.d.ts +3 -0
  10. package/dist/adapters/in-memory-subprocess/step-completion.js +86 -0
  11. package/dist/adapters/in-memory-subprocess/types.d.ts +88 -0
  12. package/dist/adapters/in-memory-subprocess/types.js +2 -0
  13. package/dist/adapters/in-memory-subprocess-adapter.d.ts +12 -4
  14. package/dist/adapters/in-memory-subprocess-adapter.js +164 -55
  15. package/dist/adapters/openrouter.d.ts +16 -7
  16. package/dist/adapters/openrouter.js +68 -7
  17. package/dist/builders/channel-builder.d.ts +1 -1
  18. package/dist/builders/control-flow-builders.d.ts +3 -3
  19. package/dist/builders/control-flow-builders.js +9 -4
  20. package/dist/builders/every.d.ts +3 -3
  21. package/dist/builders/every.js +5 -2
  22. package/dist/builders/layer-provides-builders.d.ts +1 -32
  23. package/dist/builders/layer-provides-builders.js +1 -33
  24. package/dist/builders/loop-builder.d.ts +2 -2
  25. package/dist/builders/loop-builder.js +5 -2
  26. package/dist/builders/memory-builder.d.ts +1 -1
  27. package/dist/builders/memory-builder.js +1 -1
  28. package/dist/builders/provide-builder.d.ts +2 -2
  29. package/dist/builders/provide-builder.js +5 -2
  30. package/dist/builders/spawn-builder.d.ts +22 -9
  31. package/dist/builders/spawn-builder.js +17 -3
  32. package/dist/builders/step-builders.d.ts +51 -30
  33. package/dist/builders/step-builders.js +31 -12
  34. package/dist/builders/tool-builder.d.ts +7 -3
  35. package/dist/builders/tool-builder.js +3 -1
  36. package/dist/builders/workflow-hydrator.d.ts +38 -0
  37. package/dist/builders/workflow-hydrator.js +336 -0
  38. package/dist/conditions/conditions.d.ts +4 -4
  39. package/dist/conditions/conditions.js +2 -2
  40. package/dist/errors/noetic-error.d.ts +1 -1
  41. package/dist/errors/noetic-error.js +2 -0
  42. package/dist/{runtime → harness}/agent-harness.d.ts +65 -45
  43. package/dist/harness/agent-harness.js +576 -0
  44. package/dist/harness/deps/adapters.d.ts +4 -0
  45. package/dist/harness/deps/adapters.js +4 -0
  46. package/dist/harness/deps/interpreter.d.ts +5 -0
  47. package/dist/harness/deps/interpreter.js +4 -0
  48. package/dist/harness/deps/memory.d.ts +5 -0
  49. package/dist/harness/deps/memory.js +4 -0
  50. package/dist/harness/deps/runtime.d.ts +10 -0
  51. package/dist/harness/deps/runtime.js +7 -0
  52. package/dist/harness/deps/types.d.ts +17 -0
  53. package/dist/harness/deps/types.js +1 -0
  54. package/dist/harness/model-call.d.ts +50 -0
  55. package/dist/harness/model-call.js +694 -0
  56. package/dist/harness/model-schema.d.ts +19 -0
  57. package/dist/harness/model-schema.js +46 -0
  58. package/dist/harness/step-bootstrap.d.ts +25 -0
  59. package/dist/harness/step-bootstrap.js +170 -0
  60. package/dist/index.d.ts +114 -76
  61. package/dist/index.js +74 -50
  62. package/dist/internal-test.d.ts +4 -4
  63. package/dist/internal-test.js +4 -4
  64. package/dist/interpreter/action-deps.d.ts +12 -0
  65. package/dist/interpreter/action-deps.js +10 -0
  66. package/dist/interpreter/action-types.d.ts +8 -0
  67. package/dist/interpreter/action-types.js +1 -0
  68. package/dist/interpreter/collect-tools.d.ts +2 -2
  69. package/dist/interpreter/collect-tools.js +6 -2
  70. package/dist/interpreter/execute-action.d.ts +22 -0
  71. package/dist/interpreter/execute-action.js +527 -0
  72. package/dist/interpreter/{execute-every.d.ts → execute-control.d.ts} +8 -2
  73. package/dist/interpreter/execute-control.js +530 -0
  74. package/dist/interpreter/execute.d.ts +16 -3
  75. package/dist/interpreter/execute.js +154 -51
  76. package/dist/interpreter/message-helpers.d.ts +1 -9
  77. package/dist/interpreter/message-helpers.js +1 -42
  78. package/dist/interpreter/step-dispatcher.d.ts +61 -0
  79. package/dist/interpreter/step-dispatcher.js +67 -0
  80. package/dist/interpreter/typeguards.d.ts +8 -15
  81. package/dist/interpreter/typeguards.js +4 -21
  82. package/dist/memory/budget.d.ts +2 -2
  83. package/dist/memory/budget.js +1 -1
  84. package/dist/{runtime → memory}/exec-context-factory.d.ts +2 -2
  85. package/dist/{runtime → memory}/exec-context-factory.js +1 -1
  86. package/dist/memory/flow-schema.d.ts +52 -0
  87. package/dist/memory/flow-schema.js +102 -0
  88. package/dist/memory/function-call-utils.d.ts +1 -1
  89. package/dist/memory/function-call-utils.js +4 -2
  90. package/dist/memory/layer-api.d.ts +4 -4
  91. package/dist/memory/layer-api.js +2 -2
  92. package/dist/memory/layer-lifecycle.d.ts +6 -6
  93. package/dist/memory/layer-lifecycle.js +6 -6
  94. package/dist/memory/layer-provides.d.ts +32 -0
  95. package/dist/memory/layer-provides.js +33 -0
  96. package/dist/memory/layer-usage.d.ts +4 -3
  97. package/dist/memory/layer-usage.js +9 -3
  98. package/dist/memory/layers/durable-task-state.d.ts +8 -8
  99. package/dist/memory/layers/durable-task-state.js +2 -2
  100. package/dist/memory/layers/file-reference.d.ts +1 -1
  101. package/dist/memory/layers/file-reference.js +303 -247
  102. package/dist/memory/layers/history-window.d.ts +1 -1
  103. package/dist/memory/layers/history-window.js +4 -4
  104. package/dist/memory/layers/observational-memory.d.ts +5 -5
  105. package/dist/memory/layers/observational-memory.js +2 -3
  106. package/dist/memory/layers/plan.d.ts +2 -2
  107. package/dist/memory/layers/plan.js +15 -10
  108. package/dist/memory/layers/static-content.d.ts +2 -2
  109. package/dist/memory/layers/static-content.js +1 -1
  110. package/dist/memory/layers/steering.d.ts +7 -7
  111. package/dist/memory/layers/steering.js +5 -5
  112. package/dist/memory/layers/tool-memory-layer.d.ts +2 -2
  113. package/dist/memory/layers/tool-memory-layer.js +1 -1
  114. package/dist/memory/layers/working-memory.d.ts +7 -7
  115. package/dist/memory/layers/working-memory.js +4 -4
  116. package/dist/memory/projector.d.ts +2 -2
  117. package/dist/memory/scope.d.ts +1 -1
  118. package/dist/memory/strip-unresolved.d.ts +1 -1
  119. package/dist/observability/span-impl.d.ts +1 -1
  120. package/dist/observability/trace-exporter.d.ts +2 -2
  121. package/dist/observability/trace-exporter.js +1 -1
  122. package/dist/patterns/dynamic-workflow.d.ts +55 -0
  123. package/dist/patterns/dynamic-workflow.js +194 -0
  124. package/dist/patterns/flow.d.ts +2 -52
  125. package/dist/patterns/flow.js +1 -103
  126. package/dist/patterns/interview.d.ts +2 -2
  127. package/dist/patterns/interview.js +5 -5
  128. package/dist/patterns/plans.d.ts +6 -6
  129. package/dist/patterns/plans.js +4 -4
  130. package/dist/patterns/ralph-wiggum.d.ts +4 -4
  131. package/dist/patterns/ralph-wiggum.js +5 -5
  132. package/dist/patterns/react.d.ts +3 -3
  133. package/dist/patterns/react.js +5 -5
  134. package/dist/portable/adapters.d.ts +6 -0
  135. package/dist/portable/adapters.js +6 -0
  136. package/dist/portable/ask-user.d.ts +4 -0
  137. package/dist/portable/ask-user.js +2 -0
  138. package/dist/portable/builders.d.ts +12 -0
  139. package/dist/portable/builders.js +12 -0
  140. package/dist/portable/memory-layers.d.ts +12 -0
  141. package/dist/portable/memory-layers.js +12 -0
  142. package/dist/portable/runtime.d.ts +4 -0
  143. package/dist/portable/runtime.js +4 -0
  144. package/dist/portable/until.d.ts +4 -0
  145. package/dist/portable/until.js +4 -0
  146. package/dist/portable.d.ts +8 -26
  147. package/dist/portable.js +8 -34
  148. package/dist/runtime/broadcaster-utils.d.ts +7 -3
  149. package/dist/runtime/broadcaster-utils.js +11 -6
  150. package/dist/runtime/channel-store.d.ts +1 -1
  151. package/dist/runtime/channel-store.js +2 -2
  152. package/dist/runtime/context-deps.d.ts +4 -0
  153. package/dist/runtime/context-deps.js +2 -0
  154. package/dist/runtime/context-impl.d.ts +42 -12
  155. package/dist/runtime/context-impl.js +52 -5
  156. package/dist/runtime/context-type-deps.d.ts +14 -0
  157. package/dist/runtime/context-type-deps.js +1 -0
  158. package/dist/runtime/cwd-helpers.d.ts +1 -1
  159. package/dist/runtime/detached-handle.d.ts +52 -4
  160. package/dist/runtime/detached-handle.js +218 -14
  161. package/dist/runtime/durable/checkpoint-store.d.ts +38 -0
  162. package/dist/runtime/durable/checkpoint-store.js +101 -0
  163. package/dist/runtime/durable/detached-signal.d.ts +37 -0
  164. package/dist/runtime/durable/detached-signal.js +52 -0
  165. package/dist/runtime/durable/harness-checkpoints.d.ts +51 -0
  166. package/dist/runtime/durable/harness-checkpoints.js +104 -0
  167. package/dist/runtime/durable/index.d.ts +10 -0
  168. package/dist/runtime/durable/index.js +5 -0
  169. package/dist/runtime/durable/runnable-loop.d.ts +100 -0
  170. package/dist/runtime/durable/runnable-loop.js +90 -0
  171. package/dist/runtime/durable/session-seed.d.ts +28 -0
  172. package/dist/runtime/durable/session-seed.js +27 -0
  173. package/dist/runtime/durable/stall-nudge.d.ts +82 -0
  174. package/dist/runtime/durable/stall-nudge.js +87 -0
  175. package/dist/runtime/event-broadcaster.d.ts +1 -1
  176. package/dist/runtime/in-memory-storage.d.ts +1 -1
  177. package/dist/runtime/in-memory-storage.js +1 -1
  178. package/dist/runtime/item-log-impl.d.ts +3 -3
  179. package/dist/runtime/item-log-impl.js +1 -1
  180. package/dist/runtime/message-queue.d.ts +2 -2
  181. package/dist/runtime/session-runner.d.ts +7 -7
  182. package/dist/runtime/session-runner.js +3 -3
  183. package/dist/runtime/session-streams.d.ts +3 -3
  184. package/dist/runtime/session-streams.js +1 -1
  185. package/dist/runtime/step-registry.d.ts +42 -0
  186. package/dist/runtime/step-registry.js +77 -0
  187. package/dist/runtime/tool-memory.d.ts +3 -3
  188. package/dist/schemas/item.d.ts +1 -1
  189. package/dist/schemas/workflow.d.ts +139 -0
  190. package/dist/schemas/workflow.js +232 -0
  191. package/dist/types/ask-user-types.d.ts +57 -0
  192. package/dist/types/ask-user-types.js +74 -0
  193. package/dist/types/checkpoint.d.ts +98 -0
  194. package/dist/types/checkpoint.js +81 -0
  195. package/dist/types/common.d.ts +1 -50
  196. package/dist/types/context-parts/item-log.d.ts +6 -0
  197. package/dist/types/context-parts/item-log.js +1 -0
  198. package/dist/types/context-parts/layer-usage.d.ts +18 -0
  199. package/dist/types/context-parts/layer-usage.js +1 -0
  200. package/dist/types/context.d.ts +140 -31
  201. package/dist/types/error.d.ts +15 -0
  202. package/dist/types/harness-result.d.ts +2 -2
  203. package/dist/types/items.d.ts +18 -2
  204. package/dist/types/memory-context.d.ts +39 -0
  205. package/dist/types/memory-context.js +1 -0
  206. package/dist/types/memory.d.ts +38 -68
  207. package/dist/types/mutable-context.d.ts +3 -3
  208. package/dist/types/runtime.d.ts +14 -13
  209. package/dist/types/steering.d.ts +2 -2
  210. package/dist/types/step-registrar.d.ts +46 -0
  211. package/dist/types/step-registrar.js +56 -0
  212. package/dist/types/step.d.ts +34 -9
  213. package/dist/types/subprocess-adapter.d.ts +119 -3
  214. package/dist/types/subprocess-adapter.js +2 -0
  215. package/dist/types/tool-context.d.ts +6 -6
  216. package/dist/types/tool.d.ts +64 -0
  217. package/dist/types/tool.js +1 -0
  218. package/dist/unstable.d.ts +9 -9
  219. package/dist/unstable.js +7 -7
  220. package/dist/until/combinators.d.ts +1 -1
  221. package/dist/until/never.d.ts +1 -1
  222. package/dist/until/predicates.d.ts +13 -4
  223. package/dist/until/predicates.js +16 -2
  224. package/dist/util/message-helpers.d.ts +17 -0
  225. package/dist/util/message-helpers.js +64 -0
  226. package/package.json +6 -4
  227. package/dist/adapters/local-fs-adapter.d.ts +0 -3
  228. package/dist/adapters/local-fs-adapter.js +0 -43
  229. package/dist/adapters/local-shell-adapter.d.ts +0 -51
  230. package/dist/adapters/local-shell-adapter.js +0 -167
  231. package/dist/adapters/local-subprocess-adapter.d.ts +0 -16
  232. package/dist/adapters/local-subprocess-adapter.js +0 -187
  233. package/dist/conditions/index.d.ts +0 -3
  234. package/dist/conditions/index.js +0 -2
  235. package/dist/interpreter/execute-branch.d.ts +0 -3
  236. package/dist/interpreter/execute-branch.js +0 -10
  237. package/dist/interpreter/execute-every.js +0 -143
  238. package/dist/interpreter/execute-fork.d.ts +0 -3
  239. package/dist/interpreter/execute-fork.js +0 -215
  240. package/dist/interpreter/execute-llm.d.ts +0 -4
  241. package/dist/interpreter/execute-llm.js +0 -217
  242. package/dist/interpreter/execute-loop.d.ts +0 -3
  243. package/dist/interpreter/execute-loop.js +0 -171
  244. package/dist/interpreter/execute-provide.d.ts +0 -10
  245. package/dist/interpreter/execute-provide.js +0 -64
  246. package/dist/interpreter/execute-run.d.ts +0 -3
  247. package/dist/interpreter/execute-run.js +0 -39
  248. package/dist/interpreter/execute-spawn.d.ts +0 -11
  249. package/dist/interpreter/execute-spawn.js +0 -113
  250. package/dist/interpreter/execute-tool.d.ts +0 -5
  251. package/dist/interpreter/execute-tool.js +0 -81
  252. package/dist/runtime/agent-harness.js +0 -1170
  253. /package/dist/{interpreter → util}/framework-cast.d.ts +0 -0
  254. /package/dist/{interpreter → util}/framework-cast.js +0 -0
@@ -0,0 +1,576 @@
1
+ import { NoeticConfigError } from '../errors/noetic-config-error.js';
2
+ import { SpanImpl } from '../observability/span-impl.js';
3
+ import { NoopExporter } from '../observability/trace-exporter.js';
4
+ import { ItemSchemaRegistry } from '../schemas/item.js';
5
+ import { frameworkCast } from '../util/framework-cast.js';
6
+ import { createInMemoryFsAdapter, createInMemoryShellAdapter, createInMemorySubprocessAdapter, OpenRouter, } from './deps/adapters.js';
7
+ import { collectAllTools, deduplicateTools, dispatchStepThroughAdapter, execute, } from './deps/interpreter.js';
8
+ import { afterModelCallLayers, assembleView, beforeToolCallLayers, contextToExecCtx, createLayerStateStore, disposeLayers, executeRerender, initLayers, projectHistoryLayers, recallLayers, resolveLayerBudgets, resolveLayerTools, runAppendPipeline, storeLayers, } from './deps/memory.js';
9
+ import { buildItemStream, ChannelStore, ContextImpl, captureCheckpoint, createInMemoryStorage, filterReasoningStream, filterTextStream, restoreFromCheckpoint, SessionRunner, snapshotCwdState, } from './deps/runtime.js';
10
+ import { SteeringAction } from './deps/types.js';
11
+ import { AgentHarnessModelCaller } from './model-call.js';
12
+ export { createStreamIdleWatchdog } from './model-call.js';
13
+ import { buildItemSchemaRegistry } from './model-schema.js';
14
+ //#endregion
15
+ const DEFAULT_THREAD_ID = '__default__';
16
+ /** Default idle-timeout for a single model call's streaming response. Chosen to be
17
+ * long enough that slow models aren't falsely aborted, but short enough that a
18
+ * stalled SSE becomes a visible error rather than a silent hang. */
19
+ const DEFAULT_STREAM_IDLE_TIMEOUT_MS = 120e3;
20
+ //#region Helpers
21
+ /**
22
+ * Pick the right `cwdState` for a new Context.
23
+ *
24
+ * - `cwdInit` explicitly overrides everything (worktree isolation).
25
+ * - Parent snapshot if present (snapshot, not shared reference — child `cd`
26
+ * does not leak to parent).
27
+ * - Otherwise share the harness `rootCwdState` reference so successive root
28
+ * contexts see TUI/agent `cd`s carry across runs.
29
+ */
30
+ function resolveContextCwdState(rootCwdState, parent, cwdInit) {
31
+ if (cwdInit !== undefined) {
32
+ return {
33
+ cwd: cwdInit,
34
+ };
35
+ }
36
+ if (parent) {
37
+ return snapshotCwdState(parent);
38
+ }
39
+ return rootCwdState;
40
+ }
41
+ function createClient(config) {
42
+ const processValue = 'process' in globalThis ? globalThis.process : undefined;
43
+ const envValue = typeof processValue === 'object' && processValue !== null && 'env' in processValue
44
+ ? processValue.env
45
+ : undefined;
46
+ const openRouterApiKey = typeof envValue === 'object' && envValue !== null && 'OPENROUTER_API_KEY' in envValue
47
+ ? envValue.OPENROUTER_API_KEY
48
+ : undefined;
49
+ const apiKey = config?.apiKey ?? (typeof openRouterApiKey === 'string' ? openRouterApiKey : undefined);
50
+ if (!apiKey) {
51
+ return undefined;
52
+ }
53
+ return new OpenRouter({
54
+ apiKey,
55
+ });
56
+ }
57
+ //#region AgentHarness
58
+ /**
59
+ * Default agent harness for executing agent steps with built-in channel, memory, and trace support.
60
+ * Provides channel store, memory layer lifecycle, and trace export with no external dependencies.
61
+ *
62
+ * Messages submitted via `execute()` are enqueued on a per-thread session and
63
+ * processed by a `SessionRunner`. Consumers observe responses via the session-
64
+ * scoped accessors: `getAgentResponse`, `getItemStream`, etc.
65
+ *
66
+ * @public
67
+ */
68
+ export class AgentHarness {
69
+ config;
70
+ fs;
71
+ shell;
72
+ subprocess;
73
+ /**
74
+ * Optional durable-execution store. When present, `checkpoint(ctx)` writes
75
+ * a `CheckpointSnapshot`; when absent, it's a no-op.
76
+ * @internal
77
+ */
78
+ checkpointStore;
79
+ initialStep;
80
+ /** Harness-wide tool pool merged into every context's `unifiedTools`. */
81
+ harnessTools;
82
+ /** @internal Memory layers configured for this harness. Exposed non-private
83
+ * so free functions in `runtime/durable/` (checkpoint/restore) can read it
84
+ * without friend-class gymnastics. Do not access from outside core. */
85
+ _memory;
86
+ client;
87
+ channelStore;
88
+ callModelOverride;
89
+ defaultDeliveryMode;
90
+ streamIdleTimeoutMs;
91
+ sessions = new Map();
92
+ layerStateStore;
93
+ traceExporter;
94
+ /**
95
+ * Long-lived shared cwd state. The same reference is seeded into every
96
+ * root Context this harness creates, so successive `run()` calls — and the
97
+ * TUI — observe each other's `cd`s.
98
+ */
99
+ rootCwdState;
100
+ /** @internal Item schema registry. Exposed non-private so free functions
101
+ * in `runtime/durable/` (restore) can parse persisted items. Do not
102
+ * access from outside core. */
103
+ itemSchemas;
104
+ constructor(opts) {
105
+ const validatedParams = opts.paramsSchema ? opts.paramsSchema.parse(opts.params) : opts.params;
106
+ this.config = {
107
+ name: opts.name,
108
+ storage: opts.storage ?? createInMemoryStorage(),
109
+ hooks: opts.hooks,
110
+ params: validatedParams,
111
+ itemSchemas: opts.itemSchemas,
112
+ strictItemSchemas: opts.strictItemSchemas ?? true,
113
+ };
114
+ this.fs = opts.fs ?? createInMemoryFsAdapter();
115
+ this.shell = opts.shell ?? createInMemoryShellAdapter();
116
+ this.subprocess = opts.subprocess ?? createInMemorySubprocessAdapter();
117
+ this.checkpointStore = opts.checkpointStore;
118
+ this.initialStep = opts.initialStep;
119
+ this.harnessTools = opts.tools ?? [];
120
+ this._memory = opts.memory;
121
+ this.callModelOverride = opts._testCallModel;
122
+ this.client = opts._testCallModel ? undefined : createClient(opts.llm);
123
+ this.channelStore = new ChannelStore();
124
+ this.traceExporter = opts.traceExporter ?? new NoopExporter();
125
+ this.layerStateStore = opts.layerStateStore ?? createLayerStateStore();
126
+ this.defaultDeliveryMode = opts.defaultDeliveryMode ?? 'next-turn';
127
+ this.streamIdleTimeoutMs = opts.streamIdleTimeoutMs ?? DEFAULT_STREAM_IDLE_TIMEOUT_MS;
128
+ this.itemSchemas = new ItemSchemaRegistry(opts.itemSchemas, {
129
+ strictUnknownExtensions: opts.strictItemSchemas ?? true,
130
+ });
131
+ this.rootCwdState = {
132
+ cwd: opts.initialCwd ?? '/',
133
+ };
134
+ }
135
+ /**
136
+ * Update the harness-wide root cwd. The TUI calls this in response to a
137
+ * user-issued `! cd`, so the next root Context (and any tool inspecting
138
+ * `harness.rootCwdState.cwd`) observes the new value. Caller is responsible
139
+ * for passing an absolute, validated path.
140
+ */
141
+ setRootCwd(nextCwd) {
142
+ if (nextCwd === this.rootCwdState.cwd) {
143
+ return;
144
+ }
145
+ this.rootCwdState.previousCwd = this.rootCwdState.cwd;
146
+ this.rootCwdState.cwd = nextCwd;
147
+ }
148
+ //#region Session Accessors
149
+ execute(input, options) {
150
+ if (!this.initialStep) {
151
+ return Promise.reject(new NoeticConfigError({
152
+ code: 'NO_STEP_CONFIGURED',
153
+ message: 'No initialStep configured on this harness.',
154
+ hint: 'Pass `initialStep` in constructor options, or use run() directly.',
155
+ }));
156
+ }
157
+ const threadId = options?.threadId ?? DEFAULT_THREAD_ID;
158
+ const deliveryMode = options?.deliveryMode ?? this.defaultDeliveryMode;
159
+ const session = this.getOrCreateSession(threadId);
160
+ const message = {
161
+ id: options?.messageId ?? `msg-${crypto.randomUUID()}`,
162
+ input,
163
+ deliveryMode,
164
+ options: options ?? {},
165
+ enqueuedAt: Date.now(),
166
+ };
167
+ if (deliveryMode === 'interrupt' && session.runner.getStatus().kind === 'generating') {
168
+ session.runner.queue.prepend(message);
169
+ // Abort kicks the runner via queue subscription after the in-flight turn settles.
170
+ void session.runner.abort('interrupt');
171
+ return Promise.resolve();
172
+ }
173
+ session.runner.queue.enqueue(message);
174
+ return Promise.resolve();
175
+ }
176
+ getAgentResponse(scope) {
177
+ const session = this.requireSession(scope);
178
+ return session.runner.getAgentResponse();
179
+ }
180
+ getItemStream(scope) {
181
+ const session = this.requireSession(scope);
182
+ return buildItemStream(session.runner.broadcaster, this.itemSchemas);
183
+ }
184
+ getTextStream(scope) {
185
+ const session = this.requireSession(scope);
186
+ return filterTextStream(session.runner.broadcaster);
187
+ }
188
+ getReasoningStream(scope) {
189
+ const session = this.requireSession(scope);
190
+ return filterReasoningStream(session.runner.broadcaster);
191
+ }
192
+ getFullStream(scope) {
193
+ const session = this.requireSession(scope);
194
+ return session.runner.broadcaster;
195
+ }
196
+ async abort(scope) {
197
+ const threadId = scope?.threadId ?? DEFAULT_THREAD_ID;
198
+ const session = this.sessions.get(threadId);
199
+ if (!session) {
200
+ return;
201
+ }
202
+ await session.runner.abort(scope?.reason);
203
+ }
204
+ getStatus(scope) {
205
+ const threadId = scope?.threadId ?? DEFAULT_THREAD_ID;
206
+ const session = this.sessions.get(threadId);
207
+ if (!session) {
208
+ return {
209
+ kind: 'idle',
210
+ };
211
+ }
212
+ return session.runner.getStatus();
213
+ }
214
+ getQueueSize(scope) {
215
+ const threadId = scope?.threadId ?? DEFAULT_THREAD_ID;
216
+ const session = this.sessions.get(threadId);
217
+ return session ? session.runner.queue.size : 0;
218
+ }
219
+ seedSessionHistory(threadId, items) {
220
+ const session = this.getOrCreateSession(threadId);
221
+ session.accumulatedItems = [
222
+ ...items,
223
+ ];
224
+ }
225
+ getOrCreateSession(threadId) {
226
+ const existing = this.sessions.get(threadId);
227
+ if (existing) {
228
+ return existing;
229
+ }
230
+ const session = {
231
+ accumulatedItems: [],
232
+ runner: new SessionRunner({
233
+ threadId,
234
+ agentName: this.config.name,
235
+ // The first queued message in a batch establishes `resourceId` /
236
+ // `state` / `memory` for the turn. If multiple messages are drained
237
+ // together (queue flush), later messages' values for these fields
238
+ // are ignored. `deliveryMode` is resolved per-message at enqueue
239
+ // time and doesn't apply here.
240
+ createContext: (items, _turnId, messages) => {
241
+ const perTurnOptions = messages[0]?.options ?? {};
242
+ const allItems = [
243
+ ...session.accumulatedItems,
244
+ ...items,
245
+ ];
246
+ const ctx = this.createContext({
247
+ items: allItems,
248
+ threadId,
249
+ resourceId: perTurnOptions.resourceId,
250
+ state: perTurnOptions.state,
251
+ memory: perTurnOptions.memory,
252
+ _broadcaster: session.runner.broadcaster,
253
+ });
254
+ const ext = frameworkCast(ctx);
255
+ ext._sessionQueue = session.runner.queue;
256
+ ext._sessionBetweenRounds = true;
257
+ ext._sessionRunnerAgentName = this.config.name;
258
+ if (this.initialStep || this.harnessTools.length > 0) {
259
+ const stepTools = this.initialStep ? collectAllTools(this.initialStep) : [];
260
+ this.setUnifiedTools(ctx, [
261
+ ...stepTools,
262
+ ...this.harnessTools,
263
+ ]);
264
+ }
265
+ return ctx;
266
+ },
267
+ runTurn: async (ctx, _turn, signal) => {
268
+ if (!this.initialStep) {
269
+ throw new NoeticConfigError({
270
+ code: 'NO_STEP_CONFIGURED',
271
+ message: 'No initialStep configured on this harness.',
272
+ hint: 'Pass `initialStep` in constructor options.',
273
+ });
274
+ }
275
+ // Wire signal-abort to context-abort so the interpreter bails cleanly.
276
+ if (signal.aborted) {
277
+ ctx.abort(signal.reason ? String(signal.reason) : 'aborted');
278
+ }
279
+ else {
280
+ signal.addEventListener('abort', () => {
281
+ ctx.abort(signal.reason ? String(signal.reason) : 'aborted');
282
+ }, {
283
+ once: true,
284
+ });
285
+ }
286
+ const result = await this.initAndRun(this.initialStep, '', ctx);
287
+ // Snapshot final items into session history for the next turn.
288
+ session.accumulatedItems = [
289
+ ...ctx.itemLog.items,
290
+ ];
291
+ return result;
292
+ },
293
+ }),
294
+ };
295
+ this.sessions.set(threadId, session);
296
+ return session;
297
+ }
298
+ requireSession(scope) {
299
+ const threadId = scope?.threadId ?? DEFAULT_THREAD_ID;
300
+ let session = this.sessions.get(threadId);
301
+ if (session) {
302
+ return session;
303
+ }
304
+ // Lazily create so consumers can attach stream listeners before the first execute.
305
+ session = this.getOrCreateSession(threadId);
306
+ return session;
307
+ }
308
+ //#endregion
309
+ //#region callModel
310
+ async callModel(request) {
311
+ return new AgentHarnessModelCaller({
312
+ agentName: this.config.name,
313
+ itemSchemas: this.itemSchemas,
314
+ client: this.client,
315
+ callModelOverride: this.callModelOverride,
316
+ streamIdleTimeoutMs: this.streamIdleTimeoutMs,
317
+ harness: this,
318
+ }).callModel(request);
319
+ }
320
+ //#endregion
321
+ async run(s, input, ctx) {
322
+ return execute(s, input, ctx);
323
+ }
324
+ /** Run all layer `init` hooks before the first step executes. Per spec 11,
325
+ * init MUST complete before any recall fires so layer state is populated. */
326
+ async initAndRun(s, input, ctx) {
327
+ const layers = ctx.layers;
328
+ const storage = this.config.storage;
329
+ if (layers && layers.length > 0 && storage) {
330
+ await this.initLayers(layers, ctx, storage);
331
+ }
332
+ return execute(s, input, ctx);
333
+ }
334
+ detachedSpawn(s, input, parentCtx, overrides) {
335
+ return dispatchStepThroughAdapter(this, s, input, parentCtx, overrides);
336
+ }
337
+ createContext(opts) {
338
+ const { memory: memoryLayers, cwdInit, ...rest } = opts ?? {};
339
+ const effectiveMemory = memoryLayers ?? this._memory;
340
+ const itemSchemas = buildItemSchemaRegistry({
341
+ base: this.itemSchemas,
342
+ layers: effectiveMemory,
343
+ });
344
+ return new ContextImpl({
345
+ ...rest,
346
+ harness: this,
347
+ channelStore: this.channelStore,
348
+ layers: effectiveMemory,
349
+ itemSchemas,
350
+ cwdState: resolveContextCwdState(this.rootCwdState, opts?.parent, cwdInit),
351
+ });
352
+ }
353
+ send(channel, value, _ctx) {
354
+ this.channelStore.send(channel, value);
355
+ }
356
+ recv(channel, _ctx, opts) {
357
+ return this.channelStore.recv(channel, opts?.timeout);
358
+ }
359
+ tryRecv(channel, _ctx) {
360
+ return this.channelStore.tryRecv(channel);
361
+ }
362
+ getChannelHandle(channel, executionId) {
363
+ return this.channelStore.getHandle(channel, executionId);
364
+ }
365
+ /** Resolves layer-provided tools and merges with step tools into ctx.unifiedTools. */
366
+ setUnifiedTools(ctx, stepTools) {
367
+ const layers = ctx.layers;
368
+ const layerTools = layers && layers.length > 0 ? resolveLayerTools(layers, this, ctx) : [];
369
+ const allTools = deduplicateTools([
370
+ ...stepTools,
371
+ ...layerTools,
372
+ ]);
373
+ if (allTools.length > 0) {
374
+ const impl = frameworkCast(ctx);
375
+ impl.unifiedTools = allTools;
376
+ }
377
+ }
378
+ toExecCtx(ctx) {
379
+ return contextToExecCtx(ctx, {
380
+ callModel: (request) => this.callModel(request),
381
+ });
382
+ }
383
+ async initLayers(layers, ctx, storage) {
384
+ await initLayers({
385
+ layers,
386
+ ctx: this.toExecCtx(ctx),
387
+ storage,
388
+ store: this.layerStateStore,
389
+ });
390
+ }
391
+ async recallLayers(layers, input, ctx) {
392
+ return recallLayers({
393
+ layers,
394
+ query: input,
395
+ ctx: this.toExecCtx(ctx),
396
+ log: ctx.itemLog,
397
+ budgets: resolveLayerBudgets(layers),
398
+ store: this.layerStateStore,
399
+ itemSchemas: this.itemSchemas,
400
+ });
401
+ }
402
+ /**
403
+ * Compute the items array that would be sent to the model on the next turn —
404
+ * the same arrangement `executeLLM` builds: harness-level memory layers'
405
+ * recall outputs concatenated with the session's accumulated history.
406
+ *
407
+ * Read-mostly: `recallLayers` writes layer-state snapshots to
408
+ * `layerStateStore` exactly as a real turn would, so successive previews
409
+ * remain consistent with what the next real turn produces.
410
+ */
411
+ async previewRequestItems(scope) {
412
+ const threadId = scope?.threadId ?? DEFAULT_THREAD_ID;
413
+ // Read-only: if the session doesn't exist, treat history as empty rather
414
+ // than allocating a SessionRunner for a debug/preview call.
415
+ const existingSession = this.sessions.get(threadId);
416
+ const historyItems = existingSession
417
+ ? [
418
+ ...existingSession.accumulatedItems,
419
+ ]
420
+ : [];
421
+ const ctx = this.createContext({
422
+ items: historyItems,
423
+ threadId,
424
+ memory: this._memory,
425
+ });
426
+ const layers = ctx.layers ?? [];
427
+ if (layers.length === 0) {
428
+ return historyItems;
429
+ }
430
+ const recallResults = await this.recallLayers(layers, '', ctx);
431
+ const layerOutputItems = recallResults.flatMap((r) => r.items);
432
+ if (layerOutputItems.length === 0) {
433
+ return historyItems;
434
+ }
435
+ return assembleView({
436
+ systemPromptItems: [],
437
+ layerOutputItems,
438
+ historyItems,
439
+ });
440
+ }
441
+ async storeLayers(layers, response, ctx) {
442
+ const storage = this.config.storage;
443
+ if (!storage) {
444
+ return;
445
+ }
446
+ await storeLayers({
447
+ layers,
448
+ response,
449
+ ctx: this.toExecCtx(ctx),
450
+ log: ctx.itemLog,
451
+ store: this.layerStateStore,
452
+ storage,
453
+ });
454
+ }
455
+ async disposeLayers(layers, ctx) {
456
+ await disposeLayers({
457
+ layers,
458
+ ctx: this.toExecCtx(ctx),
459
+ store: this.layerStateStore,
460
+ });
461
+ }
462
+ //#region Checkpoint boundaries
463
+ /**
464
+ * Snapshot the execution state at a checkpoint boundary.
465
+ *
466
+ * Fires at four well-defined points on the happy path:
467
+ * 1. End of every `execute()` that mutated the item log — so a crash
468
+ * between turns lands on a snapshot that includes the user/assistant
469
+ * items that actually flowed.
470
+ * 2. After `detachedSpawn()` settles (success or failure) — the parent's
471
+ * record of running/completed children stays consistent with the
472
+ * adapter's handle manifest.
473
+ * 3. After an ask-user enqueue — a restart can replay the pending modal
474
+ * to the TUI.
475
+ * 4. After `runAppendPipeline` — layer state can mutate as items land,
476
+ * so the snapshot must follow the mutation.
477
+ *
478
+ * Delegates to `captureCheckpoint` / `restoreFromCheckpoint` in
479
+ * `runtime/durable/harness-checkpoints` so the ~140 lines of snapshot
480
+ * logic live beside the other durability machinery.
481
+ */
482
+ async checkpoint(ctx) {
483
+ return captureCheckpoint(this, ctx);
484
+ }
485
+ /**
486
+ * Rebuild a `Context` from a previously-persisted snapshot. Returns `null`
487
+ * if no snapshot is recorded for `executionId`. Surface a typed
488
+ * `NoeticConfigError(CHECKPOINT_SCHEMA_MISMATCH)` when the snapshot's
489
+ * schema version is unrecognised — the caller is expected to discard the
490
+ * checkpoint via `CheckpointStore.clear()` and start a fresh execution.
491
+ */
492
+ async restore(executionId) {
493
+ return restoreFromCheckpoint(this, executionId);
494
+ }
495
+ //#endregion
496
+ async cancel(_ctx, _reason) { }
497
+ createSpan(name, parent) {
498
+ return new SpanImpl(name, parent);
499
+ }
500
+ getLayerState(executionId, layerId) {
501
+ return this.layerStateStore.get(executionId, layerId);
502
+ }
503
+ setLayerState(executionId, layerId, state) {
504
+ this.layerStateStore.set(executionId, layerId, state);
505
+ }
506
+ async beforeToolCall(layers, toolName, toolArgs, ctx) {
507
+ const hasHook = layers.some((l) => l.hooks.beforeToolCall);
508
+ if (!hasHook) {
509
+ return {
510
+ action: SteeringAction.Allow,
511
+ };
512
+ }
513
+ return beforeToolCallLayers({
514
+ layers,
515
+ toolName,
516
+ toolArgs,
517
+ ctx: this.toExecCtx(ctx),
518
+ store: this.layerStateStore,
519
+ });
520
+ }
521
+ async afterModelCall(layers, response, ctx) {
522
+ const hasHook = layers.some((l) => l.hooks.afterModelCall);
523
+ if (!hasHook) {
524
+ return {
525
+ action: SteeringAction.Allow,
526
+ };
527
+ }
528
+ return afterModelCallLayers({
529
+ layers,
530
+ response,
531
+ ctx: this.toExecCtx(ctx),
532
+ store: this.layerStateStore,
533
+ });
534
+ }
535
+ async projectHistory(layers, items, ctx) {
536
+ const hasHook = layers.some((l) => l.hooks.projectHistory);
537
+ if (!hasHook) {
538
+ return items;
539
+ }
540
+ return projectHistoryLayers({
541
+ layers,
542
+ items,
543
+ ctx: this.toExecCtx(ctx),
544
+ store: this.layerStateStore,
545
+ });
546
+ }
547
+ async runAppendPipeline(layers, items, ctx) {
548
+ const hasHook = layers.some((l) => l.hooks.onItemAppend);
549
+ if (!hasHook) {
550
+ return {
551
+ items,
552
+ rerenderRequests: [],
553
+ };
554
+ }
555
+ return runAppendPipeline({
556
+ layers,
557
+ items,
558
+ ctx: this.toExecCtx(ctx),
559
+ log: ctx.itemLog,
560
+ store: this.layerStateStore,
561
+ });
562
+ }
563
+ async executeRerender(requests, layers, ctx, budgets, query) {
564
+ return executeRerender({
565
+ requests,
566
+ layers,
567
+ ctx: this.toExecCtx(ctx),
568
+ log: ctx.itemLog,
569
+ budgets,
570
+ store: this.layerStateStore,
571
+ query,
572
+ itemSchemas: this.itemSchemas,
573
+ });
574
+ }
575
+ }
576
+ //#endregion
@@ -0,0 +1,4 @@
1
+ export { OpenRouter } from '@openrouter/agent';
2
+ export { createInMemoryFsAdapter } from '../../adapters/in-memory-fs-adapter.js';
3
+ export { createInMemoryShellAdapter } from '../../adapters/in-memory-shell-adapter.js';
4
+ export { createInMemorySubprocessAdapter } from '../../adapters/in-memory-subprocess-adapter.js';
@@ -0,0 +1,4 @@
1
+ export { OpenRouter } from '@openrouter/agent';
2
+ export { createInMemoryFsAdapter } from '../../adapters/in-memory-fs-adapter.js';
3
+ export { createInMemoryShellAdapter } from '../../adapters/in-memory-shell-adapter.js';
4
+ export { createInMemorySubprocessAdapter } from '../../adapters/in-memory-subprocess-adapter.js';
@@ -0,0 +1,5 @@
1
+ export { collectAllTools, deduplicateTools } from '../../interpreter/collect-tools.js';
2
+ export { execute } from '../../interpreter/execute.js';
3
+ export type { DetachedSpawnOverrides } from '../../interpreter/step-dispatcher.js';
4
+ export { dispatchStepThroughAdapter } from '../../interpreter/step-dispatcher.js';
5
+ export { isFunctionCall } from '../../interpreter/typeguards.js';
@@ -0,0 +1,4 @@
1
+ export { collectAllTools, deduplicateTools } from '../../interpreter/collect-tools.js';
2
+ export { execute } from '../../interpreter/execute.js';
3
+ export { dispatchStepThroughAdapter } from '../../interpreter/step-dispatcher.js';
4
+ export { isFunctionCall } from '../../interpreter/typeguards.js';
@@ -0,0 +1,5 @@
1
+ export { contextToExecCtx } from '../../memory/exec-context-factory.js';
2
+ export { resolveLayerTools } from '../../memory/layer-api.js';
3
+ export type { LayerStateStore } from '../../memory/layer-lifecycle.js';
4
+ export { afterModelCallLayers, beforeToolCallLayers, createLayerStateStore, disposeLayers, executeRerender, initLayers, projectHistoryLayers, recallLayers, resolveLayerBudgets, runAppendPipeline, storeLayers, } from '../../memory/layer-lifecycle.js';
5
+ export { assembleView } from '../../memory/projector.js';
@@ -0,0 +1,4 @@
1
+ export { contextToExecCtx } from '../../memory/exec-context-factory.js';
2
+ export { resolveLayerTools } from '../../memory/layer-api.js';
3
+ export { afterModelCallLayers, beforeToolCallLayers, createLayerStateStore, disposeLayers, executeRerender, initLayers, projectHistoryLayers, recallLayers, resolveLayerBudgets, runAppendPipeline, storeLayers, } from '../../memory/layer-lifecycle.js';
4
+ export { assembleView } from '../../memory/projector.js';
@@ -0,0 +1,10 @@
1
+ export { ChannelStore } from '../../runtime/channel-store.js';
2
+ export { ContextImpl } from '../../runtime/context-impl.js';
3
+ export { snapshotCwdState } from '../../runtime/cwd-helpers.js';
4
+ export type { CheckpointStore } from '../../runtime/durable/index.js';
5
+ export { captureCheckpoint, restoreFromCheckpoint, } from '../../runtime/durable/harness-checkpoints.js';
6
+ export type { EventBroadcaster } from '../../runtime/event-broadcaster.js';
7
+ export { createInMemoryStorage } from '../../runtime/in-memory-storage.js';
8
+ export type { QueuedMessage } from '../../runtime/message-queue.js';
9
+ export { SessionRunner } from '../../runtime/session-runner.js';
10
+ export { buildItemStream, filterReasoningStream, filterTextStream, } from '../../runtime/session-streams.js';
@@ -0,0 +1,7 @@
1
+ export { ChannelStore } from '../../runtime/channel-store.js';
2
+ export { ContextImpl } from '../../runtime/context-impl.js';
3
+ export { snapshotCwdState } from '../../runtime/cwd-helpers.js';
4
+ export { captureCheckpoint, restoreFromCheckpoint, } from '../../runtime/durable/harness-checkpoints.js';
5
+ export { createInMemoryStorage } from '../../runtime/in-memory-storage.js';
6
+ export { SessionRunner } from '../../runtime/session-runner.js';
7
+ export { buildItemStream, filterReasoningStream, filterTextStream, } from '../../runtime/session-streams.js';
@@ -0,0 +1,17 @@
1
+ export type { ZodType } from 'zod';
2
+ export type { Channel, ChannelHandle, ExternalChannel } from '../../types/channel.js';
3
+ export type { LLMResponse, LlmProviderConfig } from '../../types/common.js';
4
+ export type { Context, CwdState } from '../../types/context.js';
5
+ export type { DetachedHandle } from '../../types/detached.js';
6
+ export type { FsAdapter } from '../../types/fs-adapter.js';
7
+ export type { HarnessResponse, StreamEvent, StreamingItem } from '../../types/harness-result.js';
8
+ export type { ExecuteInput, Item, ItemSchemaExtensions } from '../../types/items.js';
9
+ export type { ContextMemory, ExecutionContext, MemoryLayer, StorageAdapter, } from '../../types/memory.js';
10
+ export type { Span, TraceExporter } from '../../types/observability.js';
11
+ export type { AgentConfig, AgentHarnessContract, AgentHooks, CallModelRequest, DeliveryMode, ExecuteOptions, HarnessStatus, RecallLayerOutput, SessionScope, } from '../../types/runtime.js';
12
+ export type { ShellAdapter } from '../../types/shell-adapter.js';
13
+ export type { SteeringDecision } from '../../types/steering.js';
14
+ export { SteeringAction } from '../../types/steering.js';
15
+ export type { Step } from '../../types/step.js';
16
+ export type { SubprocessAdapter } from '../../types/subprocess-adapter.js';
17
+ export type { Tool } from '../../types/tool.js';
@@ -0,0 +1 @@
1
+ export { SteeringAction } from '../../types/steering.js';