@noetic-tools/core 0.0.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 (207) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +38 -0
  3. package/dist/adapters/in-memory-fs-adapter.d.ts +3 -0
  4. package/dist/adapters/in-memory-fs-adapter.js +245 -0
  5. package/dist/adapters/in-memory-shell-adapter.d.ts +9 -0
  6. package/dist/adapters/in-memory-shell-adapter.js +20 -0
  7. package/dist/adapters/in-memory-subprocess-adapter.d.ts +5 -0
  8. package/dist/adapters/in-memory-subprocess-adapter.js +126 -0
  9. package/dist/adapters/local-fs-adapter.d.ts +3 -0
  10. package/dist/adapters/local-fs-adapter.js +43 -0
  11. package/dist/adapters/local-shell-adapter.d.ts +51 -0
  12. package/dist/adapters/local-shell-adapter.js +167 -0
  13. package/dist/adapters/local-subprocess-adapter.d.ts +16 -0
  14. package/dist/adapters/local-subprocess-adapter.js +187 -0
  15. package/dist/adapters/openrouter.d.ts +57 -0
  16. package/dist/adapters/openrouter.js +248 -0
  17. package/dist/builders/channel-builder.d.ts +36 -0
  18. package/dist/builders/channel-builder.js +15 -0
  19. package/dist/builders/control-flow-builders.d.ts +79 -0
  20. package/dist/builders/control-flow-builders.js +53 -0
  21. package/dist/builders/every.d.ts +45 -0
  22. package/dist/builders/every.js +60 -0
  23. package/dist/builders/layer-provides-builders.d.ts +32 -0
  24. package/dist/builders/layer-provides-builders.js +33 -0
  25. package/dist/builders/loop-builder.d.ts +23 -0
  26. package/dist/builders/loop-builder.js +46 -0
  27. package/dist/builders/memory-builder.d.ts +11 -0
  28. package/dist/builders/memory-builder.js +15 -0
  29. package/dist/builders/provide-builder.d.ts +20 -0
  30. package/dist/builders/provide-builder.js +34 -0
  31. package/dist/builders/spawn-builder.d.ts +20 -0
  32. package/dist/builders/spawn-builder.js +33 -0
  33. package/dist/builders/step-builders.d.ts +62 -0
  34. package/dist/builders/step-builders.js +99 -0
  35. package/dist/builders/tool-builder.d.ts +52 -0
  36. package/dist/builders/tool-builder.js +59 -0
  37. package/dist/conditions/conditions.d.ts +114 -0
  38. package/dist/conditions/conditions.js +271 -0
  39. package/dist/conditions/cosine-similarity.d.ts +11 -0
  40. package/dist/conditions/cosine-similarity.js +28 -0
  41. package/dist/conditions/index.d.ts +3 -0
  42. package/dist/conditions/index.js +2 -0
  43. package/dist/errors/noetic-config-error.d.ts +41 -0
  44. package/dist/errors/noetic-config-error.js +44 -0
  45. package/dist/errors/noetic-error.d.ts +18 -0
  46. package/dist/errors/noetic-error.js +52 -0
  47. package/dist/index.d.ts +152 -0
  48. package/dist/index.js +112 -0
  49. package/dist/internal-test.d.ts +11 -0
  50. package/dist/internal-test.js +11 -0
  51. package/dist/interpreter/clone-guard.d.ts +4 -0
  52. package/dist/interpreter/clone-guard.js +18 -0
  53. package/dist/interpreter/collect-tools.d.ts +12 -0
  54. package/dist/interpreter/collect-tools.js +70 -0
  55. package/dist/interpreter/execute-branch.d.ts +3 -0
  56. package/dist/interpreter/execute-branch.js +10 -0
  57. package/dist/interpreter/execute-every.d.ts +15 -0
  58. package/dist/interpreter/execute-every.js +143 -0
  59. package/dist/interpreter/execute-fork.d.ts +3 -0
  60. package/dist/interpreter/execute-fork.js +215 -0
  61. package/dist/interpreter/execute-llm.d.ts +4 -0
  62. package/dist/interpreter/execute-llm.js +217 -0
  63. package/dist/interpreter/execute-loop.d.ts +3 -0
  64. package/dist/interpreter/execute-loop.js +171 -0
  65. package/dist/interpreter/execute-provide.d.ts +10 -0
  66. package/dist/interpreter/execute-provide.js +64 -0
  67. package/dist/interpreter/execute-run.d.ts +3 -0
  68. package/dist/interpreter/execute-run.js +39 -0
  69. package/dist/interpreter/execute-spawn.d.ts +11 -0
  70. package/dist/interpreter/execute-spawn.js +113 -0
  71. package/dist/interpreter/execute-tool.d.ts +5 -0
  72. package/dist/interpreter/execute-tool.js +81 -0
  73. package/dist/interpreter/execute.d.ts +14 -0
  74. package/dist/interpreter/execute.js +119 -0
  75. package/dist/interpreter/framework-cast.d.ts +10 -0
  76. package/dist/interpreter/framework-cast.js +16 -0
  77. package/dist/interpreter/message-helpers.d.ts +9 -0
  78. package/dist/interpreter/message-helpers.js +42 -0
  79. package/dist/interpreter/typeguards.d.ts +25 -0
  80. package/dist/interpreter/typeguards.js +50 -0
  81. package/dist/memory/budget.d.ts +23 -0
  82. package/dist/memory/budget.js +117 -0
  83. package/dist/memory/function-call-utils.d.ts +6 -0
  84. package/dist/memory/function-call-utils.js +25 -0
  85. package/dist/memory/layer-api.d.ts +14 -0
  86. package/dist/memory/layer-api.js +91 -0
  87. package/dist/memory/layer-lifecycle.d.ts +160 -0
  88. package/dist/memory/layer-lifecycle.js +552 -0
  89. package/dist/memory/layer-usage.d.ts +15 -0
  90. package/dist/memory/layer-usage.js +48 -0
  91. package/dist/memory/layers/durable-task-state.d.ts +79 -0
  92. package/dist/memory/layers/durable-task-state.js +118 -0
  93. package/dist/memory/layers/file-reference.d.ts +55 -0
  94. package/dist/memory/layers/file-reference.js +538 -0
  95. package/dist/memory/layers/history-window.d.ts +29 -0
  96. package/dist/memory/layers/history-window.js +114 -0
  97. package/dist/memory/layers/observational-memory.d.ts +53 -0
  98. package/dist/memory/layers/observational-memory.js +110 -0
  99. package/dist/memory/layers/plan.d.ts +55 -0
  100. package/dist/memory/layers/plan.js +369 -0
  101. package/dist/memory/layers/static-content.d.ts +27 -0
  102. package/dist/memory/layers/static-content.js +35 -0
  103. package/dist/memory/layers/steering.d.ts +51 -0
  104. package/dist/memory/layers/steering.js +258 -0
  105. package/dist/memory/layers/tool-memory-layer.d.ts +16 -0
  106. package/dist/memory/layers/tool-memory-layer.js +43 -0
  107. package/dist/memory/layers/working-memory.d.ts +44 -0
  108. package/dist/memory/layers/working-memory.js +92 -0
  109. package/dist/memory/projector.d.ts +10 -0
  110. package/dist/memory/projector.js +19 -0
  111. package/dist/memory/scope.d.ts +3 -0
  112. package/dist/memory/scope.js +31 -0
  113. package/dist/memory/strip-unresolved.d.ts +13 -0
  114. package/dist/memory/strip-unresolved.js +35 -0
  115. package/dist/observability/genai-attributes.d.ts +11 -0
  116. package/dist/observability/genai-attributes.js +12 -0
  117. package/dist/observability/span-impl.d.ts +20 -0
  118. package/dist/observability/span-impl.js +33 -0
  119. package/dist/observability/trace-exporter.d.ts +15 -0
  120. package/dist/observability/trace-exporter.js +26 -0
  121. package/dist/patterns/flow.d.ts +52 -0
  122. package/dist/patterns/flow.js +103 -0
  123. package/dist/patterns/interview.d.ts +53 -0
  124. package/dist/patterns/interview.js +113 -0
  125. package/dist/patterns/plans.d.ts +45 -0
  126. package/dist/patterns/plans.js +125 -0
  127. package/dist/patterns/ralph-wiggum.d.ts +20 -0
  128. package/dist/patterns/ralph-wiggum.js +37 -0
  129. package/dist/patterns/react.d.ts +18 -0
  130. package/dist/patterns/react.js +39 -0
  131. package/dist/portable.d.ts +26 -0
  132. package/dist/portable.js +34 -0
  133. package/dist/runtime/agent-harness.d.ts +206 -0
  134. package/dist/runtime/agent-harness.js +1170 -0
  135. package/dist/runtime/broadcaster-utils.d.ts +30 -0
  136. package/dist/runtime/broadcaster-utils.js +53 -0
  137. package/dist/runtime/channel-store.d.ts +18 -0
  138. package/dist/runtime/channel-store.js +187 -0
  139. package/dist/runtime/context-impl.d.ts +80 -0
  140. package/dist/runtime/context-impl.js +140 -0
  141. package/dist/runtime/cwd-helpers.d.ts +42 -0
  142. package/dist/runtime/cwd-helpers.js +68 -0
  143. package/dist/runtime/detached-handle.d.ts +14 -0
  144. package/dist/runtime/detached-handle.js +56 -0
  145. package/dist/runtime/event-broadcaster.d.ts +61 -0
  146. package/dist/runtime/event-broadcaster.js +187 -0
  147. package/dist/runtime/exec-context-factory.d.ts +25 -0
  148. package/dist/runtime/exec-context-factory.js +30 -0
  149. package/dist/runtime/in-memory-storage.d.ts +9 -0
  150. package/dist/runtime/in-memory-storage.js +33 -0
  151. package/dist/runtime/item-log-impl.d.ts +11 -0
  152. package/dist/runtime/item-log-impl.js +25 -0
  153. package/dist/runtime/message-queue.d.ts +30 -0
  154. package/dist/runtime/message-queue.js +46 -0
  155. package/dist/runtime/session-runner.d.ts +77 -0
  156. package/dist/runtime/session-runner.js +253 -0
  157. package/dist/runtime/session-streams.d.ts +11 -0
  158. package/dist/runtime/session-streams.js +204 -0
  159. package/dist/runtime/tool-memory.d.ts +6 -0
  160. package/dist/runtime/tool-memory.js +22 -0
  161. package/dist/schemas/item.d.ts +35 -0
  162. package/dist/schemas/item.js +155 -0
  163. package/dist/types/channel.d.ts +29 -0
  164. package/dist/types/channel.js +1 -0
  165. package/dist/types/common.d.ts +111 -0
  166. package/dist/types/common.js +1 -0
  167. package/dist/types/context.d.ts +93 -0
  168. package/dist/types/context.js +1 -0
  169. package/dist/types/detached.d.ts +17 -0
  170. package/dist/types/detached.js +7 -0
  171. package/dist/types/embed.d.ts +5 -0
  172. package/dist/types/embed.js +1 -0
  173. package/dist/types/error.d.ts +51 -0
  174. package/dist/types/error.js +1 -0
  175. package/dist/types/fs-adapter.d.ts +51 -0
  176. package/dist/types/fs-adapter.js +3 -0
  177. package/dist/types/harness-result.d.ts +43 -0
  178. package/dist/types/harness-result.js +2 -0
  179. package/dist/types/items.d.ts +115 -0
  180. package/dist/types/items.js +2 -0
  181. package/dist/types/memory.d.ts +336 -0
  182. package/dist/types/memory.js +13 -0
  183. package/dist/types/mutable-context.d.ts +13 -0
  184. package/dist/types/mutable-context.js +1 -0
  185. package/dist/types/observability.d.ts +30 -0
  186. package/dist/types/observability.js +1 -0
  187. package/dist/types/runtime.d.ts +255 -0
  188. package/dist/types/runtime.js +1 -0
  189. package/dist/types/shell-adapter.d.ts +34 -0
  190. package/dist/types/shell-adapter.js +10 -0
  191. package/dist/types/steering.d.ts +89 -0
  192. package/dist/types/steering.js +14 -0
  193. package/dist/types/step.d.ts +206 -0
  194. package/dist/types/step.js +1 -0
  195. package/dist/types/subprocess-adapter.d.ts +41 -0
  196. package/dist/types/subprocess-adapter.js +1 -0
  197. package/dist/types/tool-context.d.ts +34 -0
  198. package/dist/types/tool-context.js +1 -0
  199. package/dist/unstable.d.ts +28 -0
  200. package/dist/unstable.js +24 -0
  201. package/dist/until/combinators.d.ts +17 -0
  202. package/dist/until/combinators.js +49 -0
  203. package/dist/until/never.d.ts +9 -0
  204. package/dist/until/never.js +12 -0
  205. package/dist/until/predicates.d.ts +43 -0
  206. package/dist/until/predicates.js +126 -0
  207. package/package.json +81 -0
@@ -0,0 +1,61 @@
1
+ import type { StreamEvent } from '../types/harness-result';
2
+ interface EventBroadcasterOpts {
3
+ maxBufferSize?: number;
4
+ }
5
+ /**
6
+ * Multi-consumer broadcast channel with replay support for streaming events.
7
+ *
8
+ * Each consumer gets an independent iterator that replays buffered events
9
+ * from the start, then receives new events as they are emitted.
10
+ *
11
+ * The buffer is bounded to `maxBufferSize` events (default 10,000). When the
12
+ * buffer exceeds this limit, oldest events are trimmed and iterator cursors
13
+ * are adjusted. Once all consumers have departed, new events are discarded
14
+ * to prevent unbounded memory growth. This bounded buffer serves as the
15
+ * backpressure mechanism — no additional flow control is needed for typical
16
+ * LLM response sizes.
17
+ *
18
+ * @internal
19
+ */
20
+ export declare class EventBroadcaster {
21
+ private readonly buffer;
22
+ private readonly maxBufferSize;
23
+ private isDone;
24
+ private err?;
25
+ private readonly iterators;
26
+ private hasHadConsumers;
27
+ constructor(opts?: EventBroadcasterOpts);
28
+ /** Push an event to all active iterators and the replay buffer. */
29
+ emit(event: StreamEvent): void;
30
+ /** Signal that no more events will be emitted. */
31
+ complete(): void;
32
+ /** Signal an error to all consumers. */
33
+ error(err: Error): void;
34
+ [Symbol.asyncIterator](): AsyncIterator<StreamEvent>;
35
+ /** @internal Access the buffer for iterators. */
36
+ getBuffer(): ReadonlyArray<StreamEvent>;
37
+ /** @internal Check if the broadcaster is finished. */
38
+ get finished(): boolean;
39
+ /** @internal Get the error if any. */
40
+ get streamError(): Error | undefined;
41
+ /** @internal Remove an iterator from the set. */
42
+ removeIterator(iter: BroadcastIterator): void;
43
+ /** @internal Current buffer length (for testing). */
44
+ get bufferSize(): number;
45
+ }
46
+ declare class BroadcastIterator implements AsyncIterator<StreamEvent> {
47
+ private cursor;
48
+ private waiter?;
49
+ private returned;
50
+ private readonly broadcaster;
51
+ constructor(broadcaster: EventBroadcaster);
52
+ /** Adjust cursor when buffer is trimmed. */
53
+ adjustCursor(trimCount: number): void;
54
+ /** Called by the broadcaster when new data or completion is available. */
55
+ notify(): void;
56
+ next(): Promise<IteratorResult<StreamEvent>>;
57
+ throw(err: Error): Promise<IteratorResult<StreamEvent>>;
58
+ return(): Promise<IteratorResult<StreamEvent>>;
59
+ private tryRead;
60
+ }
61
+ export {};
@@ -0,0 +1,187 @@
1
+ //#endregion
2
+ const DEFAULT_MAX_BUFFER_SIZE = 1e4;
3
+ //#region EventBroadcaster
4
+ /**
5
+ * Multi-consumer broadcast channel with replay support for streaming events.
6
+ *
7
+ * Each consumer gets an independent iterator that replays buffered events
8
+ * from the start, then receives new events as they are emitted.
9
+ *
10
+ * The buffer is bounded to `maxBufferSize` events (default 10,000). When the
11
+ * buffer exceeds this limit, oldest events are trimmed and iterator cursors
12
+ * are adjusted. Once all consumers have departed, new events are discarded
13
+ * to prevent unbounded memory growth. This bounded buffer serves as the
14
+ * backpressure mechanism — no additional flow control is needed for typical
15
+ * LLM response sizes.
16
+ *
17
+ * @internal
18
+ */
19
+ export class EventBroadcaster {
20
+ buffer = [];
21
+ maxBufferSize;
22
+ isDone = false;
23
+ err;
24
+ iterators = new Set();
25
+ hasHadConsumers = false;
26
+ constructor(opts) {
27
+ this.maxBufferSize = opts?.maxBufferSize ?? DEFAULT_MAX_BUFFER_SIZE;
28
+ }
29
+ /** Push an event to all active iterators and the replay buffer. */
30
+ emit(event) {
31
+ if (this.isDone) {
32
+ return;
33
+ }
34
+ // Skip buffering when all consumers have departed
35
+ if (this.hasHadConsumers && this.iterators.size === 0) {
36
+ return;
37
+ }
38
+ this.buffer.push(event);
39
+ // Trim buffer if it exceeds max size
40
+ if (this.buffer.length > this.maxBufferSize) {
41
+ const trimCount = this.buffer.length - this.maxBufferSize;
42
+ this.buffer.splice(0, trimCount);
43
+ // Adjust all active iterator cursors
44
+ for (const iter of this.iterators) {
45
+ iter.adjustCursor(trimCount);
46
+ }
47
+ }
48
+ for (const iter of this.iterators) {
49
+ iter.notify();
50
+ }
51
+ }
52
+ /** Signal that no more events will be emitted. */
53
+ complete() {
54
+ if (this.isDone) {
55
+ return;
56
+ }
57
+ this.isDone = true;
58
+ for (const iter of this.iterators) {
59
+ iter.notify();
60
+ }
61
+ }
62
+ /** Signal an error to all consumers. */
63
+ error(err) {
64
+ if (this.isDone) {
65
+ return;
66
+ }
67
+ this.isDone = true;
68
+ this.err = err;
69
+ for (const iter of this.iterators) {
70
+ iter.notify();
71
+ }
72
+ }
73
+ [Symbol.asyncIterator]() {
74
+ this.hasHadConsumers = true;
75
+ const iter = new BroadcastIterator(this);
76
+ this.iterators.add(iter);
77
+ return iter;
78
+ }
79
+ /** @internal Access the buffer for iterators. */
80
+ getBuffer() {
81
+ return this.buffer;
82
+ }
83
+ /** @internal Check if the broadcaster is finished. */
84
+ get finished() {
85
+ return this.isDone;
86
+ }
87
+ /** @internal Get the error if any. */
88
+ get streamError() {
89
+ return this.err;
90
+ }
91
+ /** @internal Remove an iterator from the set. */
92
+ removeIterator(iter) {
93
+ this.iterators.delete(iter);
94
+ }
95
+ /** @internal Current buffer length (for testing). */
96
+ get bufferSize() {
97
+ return this.buffer.length;
98
+ }
99
+ }
100
+ //#endregion
101
+ //#region BroadcastIterator
102
+ class BroadcastIterator {
103
+ cursor = 0;
104
+ waiter;
105
+ returned = false;
106
+ broadcaster;
107
+ constructor(broadcaster) {
108
+ this.broadcaster = broadcaster;
109
+ }
110
+ /** Adjust cursor when buffer is trimmed. */
111
+ adjustCursor(trimCount) {
112
+ this.cursor = Math.max(0, this.cursor - trimCount);
113
+ }
114
+ /** Called by the broadcaster when new data or completion is available. */
115
+ notify() {
116
+ if (!this.waiter) {
117
+ return;
118
+ }
119
+ const w = this.waiter;
120
+ this.waiter = undefined;
121
+ try {
122
+ const result = this.tryRead();
123
+ if (result) {
124
+ w.resolve(result);
125
+ }
126
+ }
127
+ catch (err) {
128
+ // Reject the waiter's promise so the error propagates through the async iterator
129
+ w.reject(err);
130
+ }
131
+ }
132
+ async next() {
133
+ if (this.returned) {
134
+ return {
135
+ done: true,
136
+ value: undefined,
137
+ };
138
+ }
139
+ const result = this.tryRead();
140
+ if (result) {
141
+ return result;
142
+ }
143
+ return new Promise((resolve, reject) => {
144
+ this.waiter = {
145
+ resolve,
146
+ reject,
147
+ };
148
+ });
149
+ }
150
+ async throw(err) {
151
+ this.returned = true;
152
+ this.broadcaster.removeIterator(this);
153
+ throw err;
154
+ }
155
+ async return() {
156
+ this.returned = true;
157
+ this.broadcaster.removeIterator(this);
158
+ return {
159
+ done: true,
160
+ value: undefined,
161
+ };
162
+ }
163
+ tryRead() {
164
+ const buffer = this.broadcaster.getBuffer();
165
+ if (this.cursor < buffer.length) {
166
+ const event = buffer[this.cursor];
167
+ this.cursor++;
168
+ return {
169
+ done: false,
170
+ value: event,
171
+ };
172
+ }
173
+ if (this.broadcaster.finished) {
174
+ this.broadcaster.removeIterator(this);
175
+ const err = this.broadcaster.streamError;
176
+ if (err) {
177
+ throw err;
178
+ }
179
+ return {
180
+ done: true,
181
+ value: undefined,
182
+ };
183
+ }
184
+ return null;
185
+ }
186
+ }
187
+ //#endregion
@@ -0,0 +1,25 @@
1
+ import type { Context } from '../types/context';
2
+ import type { ExecutionContext } from '../types/memory';
3
+ /**
4
+ * Optional overrides for `contextToExecCtx`. Used by `executeSpawn` to build
5
+ * parent and child execution contexts that reuse the same tokenize / trace /
6
+ * layer-state wiring as the main path, but with spawn-specific identity
7
+ * (`executionId`, `depth`, `stepNumber`, and the scope used for layer-state
8
+ * reads).
9
+ */
10
+ export interface ExecCtxOverrides {
11
+ callModel?: ExecutionContext['callModel'];
12
+ executionId?: string;
13
+ depth?: number;
14
+ stepNumber?: number;
15
+ tokenUsage?: ExecutionContext['tokenUsage'];
16
+ cost?: number;
17
+ /** Execution id to scope `readLayerState` to (defaults to `ctx.id`). */
18
+ readLayerStateId?: string;
19
+ }
20
+ /**
21
+ * Maps a full `Context` to the lightweight `ExecutionContext` consumed by memory layer hooks.
22
+ * Centralised here so the mapping stays consistent across agent-harness, layer-api, and the
23
+ * spawn interpreter.
24
+ */
25
+ export declare function contextToExecCtx(ctx: Context, overrides?: ExecCtxOverrides): ExecutionContext;
@@ -0,0 +1,30 @@
1
+ import { estimateTokens } from '../interpreter/message-helpers';
2
+ /**
3
+ * Maps a full `Context` to the lightweight `ExecutionContext` consumed by memory layer hooks.
4
+ * Centralised here so the mapping stays consistent across agent-harness, layer-api, and the
5
+ * spawn interpreter.
6
+ */
7
+ export function contextToExecCtx(ctx, overrides) {
8
+ const readLayerStateId = overrides?.readLayerStateId ?? ctx.id;
9
+ return {
10
+ executionId: overrides?.executionId ?? ctx.id,
11
+ threadId: ctx.threadId,
12
+ resourceId: ctx.resourceId,
13
+ depth: overrides?.depth ?? ctx.depth,
14
+ stepNumber: overrides?.stepNumber ?? ctx.stepCount,
15
+ tokenUsage: overrides?.tokenUsage ?? {
16
+ input: ctx.tokens.input,
17
+ output: ctx.tokens.output,
18
+ },
19
+ cost: overrides?.cost ?? ctx.cost,
20
+ fs: ctx.harness.fs,
21
+ shell: ctx.harness.shell,
22
+ callModel: overrides?.callModel,
23
+ tokenize: estimateTokens,
24
+ trace: {
25
+ setAttribute: (key, value) => ctx.span.setAttribute(key, value),
26
+ addEvent: (name, attributes) => ctx.span.addEvent(name, attributes),
27
+ },
28
+ readLayerState: (layerId) => ctx.harness.getLayerState(readLayerStateId, layerId),
29
+ };
30
+ }
@@ -0,0 +1,9 @@
1
+ import type { StorageAdapter } from '../types/memory';
2
+ /**
3
+ * @public Process-local, Map-backed StorageAdapter.
4
+ *
5
+ * The default when no storage is configured on AgentHarness. State lives only
6
+ * for the lifetime of the Map (i.e., this harness instance). Durable backends
7
+ * must be supplied explicitly by the caller.
8
+ */
9
+ export declare function createInMemoryStorage(): StorageAdapter;
@@ -0,0 +1,33 @@
1
+ import { frameworkCast } from '../interpreter/framework-cast';
2
+ //#region Public API
3
+ /**
4
+ * @public Process-local, Map-backed StorageAdapter.
5
+ *
6
+ * The default when no storage is configured on AgentHarness. State lives only
7
+ * for the lifetime of the Map (i.e., this harness instance). Durable backends
8
+ * must be supplied explicitly by the caller.
9
+ */
10
+ export function createInMemoryStorage() {
11
+ const store = new Map();
12
+ return {
13
+ async get(key) {
14
+ const val = store.get(key);
15
+ if (val === undefined) {
16
+ return null;
17
+ }
18
+ return frameworkCast(val);
19
+ },
20
+ async set(key, value) {
21
+ store.set(key, value);
22
+ },
23
+ async delete(key) {
24
+ store.delete(key);
25
+ },
26
+ async list(prefix) {
27
+ return [
28
+ ...store.keys(),
29
+ ].filter((k) => k.startsWith(prefix));
30
+ },
31
+ };
32
+ }
33
+ //#endregion
@@ -0,0 +1,11 @@
1
+ import type { ItemSchemaRegistry } from '../schemas/item';
2
+ import type { ItemLog } from '../types/context';
3
+ import type { Item } from '../types/items';
4
+ export declare class ItemLogImpl implements ItemLog {
5
+ private readonly itemSchemas;
6
+ private readonly _items;
7
+ private _frozenCache;
8
+ constructor(itemSchemas?: ItemSchemaRegistry);
9
+ get items(): ReadonlyArray<Item>;
10
+ append(item: Item): void;
11
+ }
@@ -0,0 +1,25 @@
1
+ import { defaultItemSchemaRegistry } from '../schemas/item';
2
+ export class ItemLogImpl {
3
+ itemSchemas;
4
+ _items = [];
5
+ _frozenCache = null;
6
+ constructor(itemSchemas = defaultItemSchemaRegistry) {
7
+ this.itemSchemas = itemSchemas;
8
+ }
9
+ get items() {
10
+ if (!this._frozenCache) {
11
+ this._frozenCache = Object.freeze([
12
+ ...this._items,
13
+ ]);
14
+ }
15
+ const frozenItems = this._frozenCache;
16
+ if (!frozenItems) {
17
+ return [];
18
+ }
19
+ return frozenItems;
20
+ }
21
+ append(item) {
22
+ this._items.push(this.itemSchemas.parse(item));
23
+ this._frozenCache = null;
24
+ }
25
+ }
@@ -0,0 +1,30 @@
1
+ import type { ExecuteInput } from '../types/items';
2
+ import type { DeliveryMode, ExecuteOptions } from '../types/runtime';
3
+ /** @internal A message accepted by `AgentHarness.execute()` and held until the
4
+ * session runner processes it. The effective `DeliveryMode` is resolved at
5
+ * enqueue time so the runner never has to look at harness defaults again. */
6
+ export interface QueuedMessage {
7
+ readonly id: string;
8
+ readonly input: ExecuteInput;
9
+ readonly deliveryMode: DeliveryMode;
10
+ readonly options: ExecuteOptions;
11
+ readonly enqueuedAt: number;
12
+ }
13
+ /** @internal Subscription callback fired after any mutation. */
14
+ export type QueueChangeListener = (size: number) => void;
15
+ /** @internal Per-thread FIFO of inbox messages with prepend + subscription.
16
+ *
17
+ * `prepend` is used when an in-flight turn is aborted — the aborting message
18
+ * is re-inserted at the head so the runner picks it up before any messages
19
+ * that arrived after the abort. */
20
+ export declare class MessageQueue {
21
+ private readonly items;
22
+ private readonly listeners;
23
+ enqueue(message: QueuedMessage): void;
24
+ prepend(message: QueuedMessage): void;
25
+ drainAll(): QueuedMessage[];
26
+ peekAll(): ReadonlyArray<QueuedMessage>;
27
+ get size(): number;
28
+ subscribe(listener: QueueChangeListener): () => void;
29
+ private notify;
30
+ }
@@ -0,0 +1,46 @@
1
+ //#endregion
2
+ //#region MessageQueue
3
+ /** @internal Per-thread FIFO of inbox messages with prepend + subscription.
4
+ *
5
+ * `prepend` is used when an in-flight turn is aborted — the aborting message
6
+ * is re-inserted at the head so the runner picks it up before any messages
7
+ * that arrived after the abort. */
8
+ export class MessageQueue {
9
+ items = [];
10
+ listeners = new Set();
11
+ enqueue(message) {
12
+ this.items.push(message);
13
+ this.notify();
14
+ }
15
+ prepend(message) {
16
+ this.items.unshift(message);
17
+ this.notify();
18
+ }
19
+ drainAll() {
20
+ if (this.items.length === 0) {
21
+ return [];
22
+ }
23
+ const drained = this.items.splice(0, this.items.length);
24
+ this.notify();
25
+ return drained;
26
+ }
27
+ peekAll() {
28
+ return this.items;
29
+ }
30
+ get size() {
31
+ return this.items.length;
32
+ }
33
+ subscribe(listener) {
34
+ this.listeners.add(listener);
35
+ return () => {
36
+ this.listeners.delete(listener);
37
+ };
38
+ }
39
+ notify() {
40
+ const size = this.items.length;
41
+ for (const listener of this.listeners) {
42
+ listener(size);
43
+ }
44
+ }
45
+ }
46
+ //#endregion
@@ -0,0 +1,77 @@
1
+ import type { Context } from '../types/context';
2
+ import type { HarnessResponse } from '../types/harness-result';
3
+ import type { Item } from '../types/items';
4
+ import type { HarnessStatus } from '../types/runtime';
5
+ import { EventBroadcaster } from './event-broadcaster';
6
+ import type { QueuedMessage } from './message-queue';
7
+ import { MessageQueue } from './message-queue';
8
+ /** @internal Callback the harness supplies to run a single turn against a
9
+ * prepared context. The runner invokes this once per turn; it returns the
10
+ * final text as a string and must append any produced items to `ctx.itemLog`. */
11
+ export type RunTurnFn = (ctx: Context, turn: TurnContext, signal: AbortSignal) => Promise<string>;
12
+ /** @internal Everything the harness needs to stamp the current turn. */
13
+ export interface TurnContext {
14
+ readonly turnId: string;
15
+ readonly session: SessionRunner;
16
+ }
17
+ /** @internal Callback the harness supplies to build a fresh context for a
18
+ * single turn. Receives the already-converted items to seed the context
19
+ * (so the runner is the single point of ExecuteInput → Item[] conversion),
20
+ * plus the messages being delivered this turn so the harness can honour
21
+ * per-turn `ExecuteOptions` (the first message's options establish
22
+ * resourceId/state/memory for the turn). */
23
+ export type CreateContextFn = (items: ReadonlyArray<Item>, turnId: string, messages: ReadonlyArray<QueuedMessage>) => Context;
24
+ export interface SessionRunnerOpts {
25
+ readonly threadId: string;
26
+ readonly agentName: string;
27
+ readonly runTurn: RunTurnFn;
28
+ readonly createContext: CreateContextFn;
29
+ }
30
+ /**
31
+ * @internal
32
+ *
33
+ * Per-thread runner. Drains the MessageQueue and drives turns on the shared
34
+ * session broadcaster. Emits `turn_started` / `turn_completed` /
35
+ * `inbox_injected` framework events so consumers can correlate queued
36
+ * messages with the turn that delivered them.
37
+ *
38
+ * Abort semantics: when `abort()` is called, the current AbortController is
39
+ * fired (cancelling the in-flight LLM call) and a flag is set so the runner
40
+ * does NOT auto-restart from the queue until the caller re-kicks. For the
41
+ * ESC-restart UX, callers typically enqueue the new message first, then
42
+ * abort — the new message is the head of the queue when the runner wakes.
43
+ */
44
+ export declare class SessionRunner {
45
+ readonly threadId: string;
46
+ readonly broadcaster: EventBroadcaster;
47
+ readonly queue: MessageQueue;
48
+ private readonly agentName;
49
+ private readonly runTurn;
50
+ private readonly createContext;
51
+ private status;
52
+ private currentController?;
53
+ private currentCtx?;
54
+ private loopPromise?;
55
+ private lastResponse?;
56
+ private lastError?;
57
+ private readonly responseWaiters;
58
+ constructor(opts: SessionRunnerOpts);
59
+ getStatus(): HarnessStatus;
60
+ /** Resolves once the queue has been drained and the runner is idle with a
61
+ * response available. If nothing has run yet, waits for the first turn.
62
+ *
63
+ * The cached `lastError` is only surfaced when the session is genuinely
64
+ * idle with no pending work. If a new turn is running or a message is
65
+ * queued, the caller is asking about the NEXT response — we must wait
66
+ * for that turn rather than reject with the stale error. */
67
+ getAgentResponse(): Promise<HarnessResponse>;
68
+ /** Cancel the in-flight turn. Does NOT re-kick — callers that want restart
69
+ * behaviour should enqueue a message before/after calling abort. */
70
+ abort(reason?: string): Promise<void>;
71
+ /** Start the drain loop if not already running. Safe to call many times. */
72
+ kick(): void;
73
+ private drain;
74
+ private runOneTurn;
75
+ private resolveWaiters;
76
+ private rejectWaiters;
77
+ }