Polyweave

@polyweave/agent-loop (1.0.4)

Published 2026-07-17 15:33:07 +00:00 by Dvorak

Installation

@polyweave:registry=https://hub.kl1.tenere.ai/api/packages/Polyweave/npm/
npm install @polyweave/agent-loop@1.0.4
"@polyweave/agent-loop": "1.0.4"

About this package

@polyweave/agent-loop

Agent-evaluator loop with symbolic state, deterministic checks, lifecycle wrapping, and iterative retry orchestration for Polyweave behavior trees.

Synopsis

import { createAgentLoop, createLoopingAgentLoop, createSymbolicState, createDefaultDeterministicChecks, createDefaultEvaluatorParser, NodeStatus } from '@polyweave/agent-loop';
import { createOpenAIAdapter } from '@polyweave/openai';

const agentAdapter = createOpenAIAdapter({ apiKey: process.env.OPENAI_API_KEY });
const evaluatorAdapter = createOpenAIAdapter({ apiKey: process.env.OPENAI_API_KEY });

const loop = createAgentLoop({
  agentAdapter,
  evaluatorAdapter,
  buildAgentPrompt: (ctx) => ({
    type: 'TEXT',
    content: { text: `You are an agent. Task: ${ctx.runtime.task}` }
  }),
  buildEvaluatorPrompt: (ctx, history) => ({
    type: 'TEXT',
    content: { text: `Evaluate the agent's work. History: ${JSON.stringify(history)}` }
  }),
  parseEvaluatorOutput: createDefaultEvaluatorParser(),
  deterministicChecks: createDefaultDeterministicChecks({ workspaceDir: '/tmp/workspace' }),
  checksList: ['file_exists:output.txt', 'exit_code:0'],
  maxRetries: 3,
  maxIterations: 10
});

loop.source.pipe(mySink);
loop.sink.write({ type: 'TICK' });

Install

npm install @polyweave/agent-loop

Why

The agent-evaluator loop is the core orchestration pattern in Polyweave behavior trees. Rather than making a single LLM call, the loop iterates: the agent produces output (with tool calls), the evaluator assesses quality against criteria, and the cycle repeats until success, failure, or exhaustion. Symbolic state persists facts across cycles. Deterministic checks short-circuit the evaluator for testable conditions (file existence, exit codes, stdout patterns). Lifecycle wrapping enforces iteration limits.

API

createAgentLoop(options)

Returns { source, sink, symbolics, context, abort }. A frame duplex that runs agent-evaluator cycles.

Parameter Type Required Default Description
agentAdapter IFrameDuplex Yes LLM adapter producing agent output
evaluatorAdapter IFrameDuplex Yes LLM adapter producing evaluator judgments
buildAgentPrompt(context) function Yes Returns a frame prompting the agent. Receives { symbolics, runtime, node, iteration, retryCount }
buildEvaluatorPrompt(context, history) function Yes Returns a frame prompting the evaluator. Receives context and agent history array
parseEvaluatorOutput(frames) function Yes Parses evaluator output frames. Must return { status, evidence, symbolicUpdates? }. Use createDefaultEvaluatorParser() for JSON format
deterministicChecks(checksList, toolTrace) function No null Runs before evaluator. If all pass, skips evaluator entirely. Use createDefaultDeterministicChecks()
checksList string[] No null List of check strings passed to deterministicChecks
maxRetries number No 5 Max retries for deterministic check failures before falling through to evaluator
maxIterations number No 10 Max total agent-evaluator cycles
toolAdapters object No {} Map of tool name to duplex adapter (e.g. { filesystem: fsAdapter })
toolTimeoutMs number No 30000 Timeout for tool calls routed through the tool adapter wrapper
initialSymbolics object No {} Initial values for the symbolic state store
context object No Additional context passed to prompt builders (symbolics and runtime are auto-extracted)
onProgress(type, data) function No null Progress callback. Fires on agent_loop:node_started, agent_loop:node_completed, agent_loop:node_retry, agent_loop:node_failed, agent_loop:tree_failed, agent_loop:symbolic_asserted
maxBufferedOutputFrames number No null Max frames buffered in output source before overflow
outputOverflowStrategy string No 'drop-oldest' Strategy for output overflow: 'drop-oldest' or 'drop-newest'

Output frames on source:

Frame When
agent_loop:node_started Cycle begins; content: { iteration, agentText }
agent_loop:node_completed Evaluator returns SUCCESS; content: { evidence, iteration }
agent_loop:node_retry Retry triggered; content: { evidence, retryCount }
agent_loop:node_failed Evaluator returns FAILURE; content: { evidence, iteration }
agent_loop:tree_failed Max iterations or abort; content: { reason, evidence? }
agent_loop:symbolic_asserted Symbolic update applied; content: { name, value, op }
TEXT Agent or evaluator text output (forwarded from adapters)
ABORT Execution aborted via sink CANCEL/ABORT or loop.abort()

Errors:

  • Error('createAgentLoop requires an agentAdapter') — missing agent adapter
  • Error('createAgentLoop requires an evaluatorAdapter') — missing evaluator adapter
  • Error('createAgentLoop requires buildAgentPrompt') — missing prompt builder
  • Error('createAgentLoop requires buildEvaluatorPrompt') — missing evaluator prompt builder
  • Error('createAgentLoop requires parseEvaluatorOutput') — missing parser

createLoopingAgentLoop(options)

Returns { source, sink, abort }. Wraps createAgentLoop in an iterative outer loop that runs multiple inner agent-evaluator cycles, driven by a node provider and a continuation predicate.

Parameter Type Required Default Description
innerLoopFactory(innerOpts) function No createAgentLoop Factory to create each inner loop instance
shouldContinue(result, iteration) function No () => false Return true to continue looping
nodeProvider(iteration) function No null Returns a node descriptor for this iteration
maxIterations number No 10 Max outer loop iterations
onProgress(type, data) function No null Progress callback

All createAgentLoop options (agentAdapter, evaluatorAdapter, buildAgentPrompt, buildEvaluatorPrompt, parseEvaluatorOutput, toolAdapters, determincheckChecks, etc.) are forwarded through to each inner loop.

createSymbolicState(initial?)

Returns { assertValue, retractValue, getValue, getAll, applyUpdate, applyUpdates, subscribe }. A reactive key-value store with change notifications. Used to persist facts across agent-evaluator cycles (e.g., git commit hashes, file paths, task completion status).

Method Description
assertValue(name, value, metadata?) Set a value. Returns true if changed
retractValue(name) Remove a value. Returns true if existed
getValue(name) Get current value or undefined
getAll() Returns shallow copy of all values
applyUpdate({ name, value, op? }) Apply a single update. op: 'retract' removes the value
applyUpdates(updates[]) Apply array of updates. Returns changed count
subscribe(fn) Subscribe to changes. fn({ op, name, value, metadata })

createDefaultDeterministicChecks(options)

Returns a function(checksList, toolTrace) suitable for the deterministicChecks option. Runs fast file/process checks without calling the evaluator LLM.

Option Type Default Description
workspaceDir string null Prepended to relative paths in file_exists: checks
symbolics SymbolicState null Used for symbolic:name=value checks

Check syntax:

Check Description
file_exists:path Asserts the file exists (workspaceDir-relative if set)
symbolic:name=value Asserts symbolic state has the given value
stdout_contains:text Asserts any tool result stdout contains the text
exit_code:N Asserts any tool result has exit code N

Returns { allPassed, evidence }.

createDefaultEvaluatorParser()

Returns a function(frames) that parses evaluator JSON output. Expects evaluator to emit a TEXT frame containing JSON:

{ "status": "SUCCESS", "evidence": "Task completed", "symbolicUpdates": [] }
Status value Mapped to
"SUCCESS" NodeStatus.SUCCESS
"FAILURE" NodeStatus.FAILURE
"RUNNING" NodeStatus.RUNNING
anything else NodeStatus.FAILURE

Returns { status, evidence, symbolicUpdates }.

NodeStatus

Enum: { PENDING, RUNNING, SUCCESS, FAILURE }. Status values returned by evaluator parsers.

Tests

npm test

20 native tests + 500 js-rigor property cases covering agent-evaluator cycle lifecycle, symbolic state CRUD, deterministic checks (file_exists, symbolic, stdout_contains, exit_code), evaluator parser JSON variants, looping agent loop iteration control, frame buffering overflow, and abort/cancel behavior.

Requirements

Node.js 22 or later. ESM only.

Peer dependencies: @polyweave/core, @polyweave/tool-adapter, @polyweave/harness-base.

Dependencies

Dependencies

ID Version
@polyweave/bt-model *
@polyweave/harness-base *
@polyweave/tool-adapter *

Development Dependencies

ID Version
@rigor/core *

Peer Dependencies

ID Version
@polyweave/core *

Keywords

polyweave agent-loop evaluator execution-loop push-stream
Details
npm
2026-07-17 15:33:07 +00:00
43
John Dvorak
SEE LICENSE IN LICENSE
latest
8.5 KiB
Assets (1)
Versions (4) View all
1.0.4 2026-07-17
1.0.5 2026-07-11
1.0.2 2026-07-10
1.0.1 2026-07-10