@polyweave/harness-base (1.0.5)
Installation
@polyweave:registry=https://hub.kl1.tenere.ai/api/packages/Polyweave/npm/npm install @polyweave/harness-base@1.0.5"@polyweave/harness-base": "1.0.5"About this package
@polyweave/harness-base
Shared primitives for LLM execution harnesses — bounded pushable output source, lifecycle wrapper with iteration tracking, and standardized harness error frame factories.
Synopsis
import { createBoundedPushable, createLifecycleWrapper, createHarnessErrorFrame } from '@polyweave/harness-base';
const output = createBoundedPushable({ maxBufferedFrames: 64, overflowStrategy: 'drop-oldest' });
output.pipe(mySink);
output.write({ type: 'TEXT', content: { text: 'Hello' } });
const lifecycle = createLifecycleWrapper(adapterDuplex, { maxIterations: 5 });
lifecycle.startRun();
const errorFrame = createHarnessErrorFrame(new Error('failed'), 'my-component');
Install
npm install @polyweave/harness-base
Why
Multiple harness implementations (bt-harness, meta-bt-harness, agent-loop, gatto-agent-harness) need the same primitives: a writable push-stream source that can buffer frames safely, a lifecycle tracker that gates iteration count and CANCEL/ABORT signals, and a canonical error frame shape. Rather than duplicate these across every harness, this package provides the single-source-of-truth implementations used by all harnesses.
API
createBoundedPushable(options)
Creates a writable push-stream source with configurable bounded buffering.
Signature: createBoundedPushable(options?: Object): BoundedPushable
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
options |
Object |
No | {} |
Configuration object |
options.maxBufferedFrames |
number|null |
No | 100 |
Maximum frames to buffer before triggering overflow strategy. null disables the limit. |
options.overflowStrategy |
string |
No | 'drop-oldest' |
One of 'drop-oldest', 'drop-newest', or 'error' |
options.onBufferOverflow |
Function |
No | undefined |
Callback invoked when buffer exceeds maxBufferedFrames. Receives { bufferedLength, maxBufferedFrames, strategy }. |
Returns: BoundedPushable — a writable source with these methods and properties:
| Member | Type | Description |
|---|---|---|
pipe(sink) |
Function |
Connects this pushable to a downstream sink. Returns the sink. |
write(frame) |
Function |
Writes a frame. If downstream sink is paused, buffers the frame. If buffer overflow, applies overflowStrategy. |
end(err?) |
Function |
Flushes buffer then ends downstream. Ignores subsequent write() calls. |
abort(err?) |
Function |
Immediately discards buffer and aborts downstream. |
resume() |
Function |
Resumes drained frames from buffer. Called automatically on pipe(). |
paused |
boolean |
Reports downstream sink paused state. |
ended |
boolean |
Reports whether end() or abort() was called. |
getBufferedFrameCount() |
Function |
Returns current number of pending frames in the buffer. |
Overflow strategies:
'drop-oldest'(default): Shifts the oldest buffered frame and pushes the new one.'drop-newest': Drops the incoming frame silently.'error': Callsend(new Error('Buffer overflow: max N frames')), shutting down the pushable.
Throws: Does not throw. Errors from 'error' overflow strategy are delivered via end() to the downstream sink.
createLifecycleWrapper(innerDuplex, options)
Wraps a duplex stream with lifecycle state tracking — iteration count, running/aborted/completed flags, and CANCEL/ABORT signal interception.
Signature: createLifecycleWrapper(innerDuplex: IFrameDuplex, options?: Object): LifecycleWrapper
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
innerDuplex |
IFrameDuplex |
Yes | — | The duplex to wrap (e.g., an LLM adapter). |
options |
Object |
No | {} |
Configuration object |
options.maxIterations |
number |
No | 10 |
Maximum iteration count before onMaxIterations fires. Overridable at runtime via PARAM frame with key 'maxIterations'. |
options.onMaxIterations |
Function |
No | undefined |
Callback invoked when iteration >= maxIterations. Receives a state snapshot object. |
options.onAbort |
Function |
No | undefined |
Callback invoked on CANCEL or ABORT. Receives the abort reason string. |
options.name |
string |
No | null |
Name forwarded to createBidirectionalWrapper. |
Returns: LifecycleWrapper object with:
| Member | Type | Description |
|---|---|---|
source |
IFrameSource |
The wrapped duplex source, interleaved with observable state frames. |
sink |
IFrameSink |
The wrapped duplex sink. |
getState() |
Function |
Returns a state snapshot: { iteration, running, aborted, completed, maxIterations }. |
startRun() |
Function |
Resets running=true, aborted=false, completed=false, iteration=0. |
incrementIteration() |
Function |
Increments iteration. Fires onMaxIterations if iteration >= maxIterations. |
abort(reason?) |
Function |
Triggers abort sequence: sets aborted/running flags, calls onAbort, writes an ABORT frame downstream, then ends. |
isMaxIterations() |
Function |
Returns true if iteration >= maxIterations. |
isAborted() |
Function |
Returns true if abort has been triggered. |
isRunning() |
Function |
Returns true if the lifecycle is in running state. |
Frame protocol:
| Direction | Frame Type | Behavior |
|---|---|---|
| Input | PARAM { key: 'maxIterations', value } |
Updates maxIterations in state. |
| Input | CANCEL |
Triggers abort with message 'aborted via CANCEL'. |
| Input | ABORT |
Triggers abort with message 'aborted via ABORT'. |
| Output (response) | END |
Sets running=false. |
| Output (response) | ERROR |
Sets running=false, completed=true. |
Throws: Does not throw. Errors propagate as ABORT frames to the downstream sink.
createHarnessErrorFrame(error, source)
Produces a standardized ERROR frame for harness error reporting.
Signature: createHarnessErrorFrame(error: Error, source?: string): IFrame
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
error |
Error |
Yes | — | The error to encode in the frame. |
source |
string |
No | 'harness' |
Identifier for the error source component. |
Returns: IFrame — { type: FrameType.ERROR, content: { message: error.message, source } }
Throws: Does not throw.
Tests
npm test
Covers: bounded pushable overflow strategies (drop-oldest, drop-newest, error), buffer counting, end/abort semantics, lifecycle wrapper state transitions (start, iteration increment, max iterations callback, cancel/abort interception), and harness error frame shape.
Requirements
- Node.js 22+
- ESM only
- Peer:
@polyweave/core
Dependencies
Development Dependencies
| ID | Version |
|---|---|
| @rigor/core | * |
Peer Dependencies
| ID | Version |
|---|---|
| @polyweave/core | * |