npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

@iucteam/horizon

v2.2.30

Published

> Version: 2.2.x • Audience: Developers / Contributors • Licence: Apache‑2.0

Readme

Horizon Framework — Developer Documentation

Version: 2.2.x • Audience: Developers / Contributors • Licence: Apache‑2.0


Contents

  1. Overview
  2. Quick start (run and test locally)
  3. Think → Reason → Evaluate lifecycle (canonical phases)
  4. Agent reference (Director, Sensor, Recorder, RemoteAgent)
  5. EvaluationBrain — detailed behaviour
  6. Workflows, Tasks, Observations — domain model
  7. Models, Prompts and Memory
  8. Service primitives (TaskProcessor, Discovery, EventBus)
  9. Extending Horizon (Probes, Repositories, Models, Agents)
  10. Examples (end‑to‑end) + PlantUML diagrams
  11. Tests, CI and contributing

1. Overview

Horizon is a TypeScript framework for building hierarchical multi‑agent systems that combine programmatic workflows and LLM‑assisted reasoning. It is explicitly designed for developers: small, composable primitives (Agents, Brains, Probes, Repositories, Models and Workflows) that you can extend and compose into production systems or research prototypes.

Design principles:

  • Single responsibility: each agent type has a narrow role.
  • Observations as the lingua franca: agents exchange state as Observation objects (named or unnamed).
  • Pluggable reasoning: Brains mediate between requirements and actionable plans using models and memory.
  • Deterministic + AI workflows: support both hand‑coded Workflow graphs and LLM‑generated plans.
  • Testability: NoOp implementations and local discovery are available to write deterministic tests.

2. Quick start

Prerequisites: Node >= 18. Clone the repo, install, build and run tests.

git clone <your-repo>
cd packages/core
npm ci
npm run build
npm test

Run integration tests in packages/integration-test to see realistic scenarios (DynamoDB team, workflow directors).


3. Think → Reason → Evaluate (canonical phases)

Every agent in Horizon follows the same high‑level lifecycle. This lifecycle is the organising principle for how Brains, Models and Memory cooperate. It’s important to understand because unit tests, instrumentation and extension points align to these phases.

Phase 1 — THINK

  • Purpose: translate a requirement (natural language or structured) into an action plan.
  • Who: primarily Directors (planning) and SensorBrains (parameter extraction).
  • Input: PlanningSubject or RequirementSubject (includes requirement string, available agents, errors, and contextual observations).
  • Output: Plan, Workflow, or ParameterThought — structured enough to be executed.

Typical responsibilities of THINK:

  • Use a thinking model (e.g. LangChainThinkingModel, WorkflowThinkingModel) to decompose a goal into tasks.
  • Consult Memory (if available) using a minMemoryConfidence threshold — reuse cached plans when confidence is high.

Phase 2 — REASON

  • Purpose: process raw observations produced by actuation and produce candidate answers or intermediate inferences.
  • Who: Director (aggregating results), Sensor (optionally post‑processing), Recorder (validation of persisted result).
  • Input: ObservingSubject (observations, parameters, requirement).
  • Output: Candidate (an answer/value with confidence and provenance).

Typical responsibilities of REASON:

  • Run a reasoning model (e.g. LangChainReasoningModel) to synthesise observations.
  • Produce Candidate objects with confidence scores and optional provenance.

Phase 3 — EVALUATE

  • Purpose: determine whether a Candidate satisfies the original requirement and decide to accept, retry, or escalate.
  • Who: Director or Evaluation brain responsible for final acceptance gating.
  • Input: EvaluatingSubject (requirement, candidate, observations, additional params).
  • Output: Evaluation (accepted: boolean, score, optional feedback).

Typical responsibilities of EVALUATE:

  • Apply heuristics, policies or an evaluating LLM to accept or reject a Candidate.
  • Provide explicit feedback to be stored or used in subsequent planning iterations.

4. Agents (reference)

Base Agent

All agents implement a common interface and lifecycle. Key fields:

  • metadata: AgentMetadata — { agentId, agentType, name, description, endpoint }
  • brain: Brain — pluggable decision maker
  • runtimeConfig: RuntimeConfig — execution limits (maxSteps, minMemoryConfidence)

Core methods:

  • accept(task: Task): Promise<Future> — entry point to accept and process a task
  • doExecute(task: Task, sync?: boolean) — internal executor performing THINK→ACT→REASON→EVALUATE

Agents emit lifecycle events via the global EventBus (onTaskStarted, onTaskCompleted, onTaskFailed).

Director

Role: plan and coordinate.

Behaviour:

  • think() produces a Workflow.
  • Executes each planned Task by discovering collaborators (local or remote) and delegating execution.
  • Runs REASON on aggregated observations and EVALUATE on returned Candidates.

Important: Directors use DirectorBrain which wires thinking, observing and memory models.

Sensor

Role: collect data.

Behaviour:

  • Use SensorBrain THINK to extract parameters according to a probe schema.
  • Call its Probe.generateObservations() (async iterator) to produce observations.
  • Optionally run REASON to post‑process observations.

Probes include RestApiProbe, WebSearchProbe, WikipediaProbe and a NoOpProbe for tests.

Recorder

Role: persist data.

Behaviour:

  • THINK to extract persistence parameters (e.g. which fields to save)
  • Repository.execute() to perform save/delete
  • Generate an Observation representing storage success/failure

Repository interface is intentionally small so you can implement connectors for DynamoDB, filesystem, SQL, etc.

RemoteAgent

Role: forward tasks to remote Horizon instances over HTTP.

Behaviour: wrap remote endpoints behind the same Agent API so Directors can be location‑agnostic.


5. EvaluationBrain (detailed)

The EvaluationBrain (referred to in code as the RecorderBrain or evaluation component depending on agent) is responsible for the EVALUATE phase: deciding if the produced Candidate satisfies the requirement.

Key responsibilities:

  • Take an EvaluatingSubject which contains:

    • requirement (Stringifiable)
    • candidate (Candidate)
    • observations (Observation[])
    • additionalParameters
  • Use a configured evaluating model (via ModelFactory.get(agentId, 'evaluating')) to produce an Evaluation object.

  • Return an Evaluation with:

    • accepted: boolean — whether the candidate is acceptable
    • score: number — numeric metric useful for ranking / thresholding
    • feedback?: Stringifiable — optional textual guidance for retries or human readable reason

Implementation notes:

  • The default LangChainEvaluatingModel uses a system + human prompt split and yields a short evaluated string that is then wrapped by DefaultStringifiable.
  • Evaluators should be idempotent and deterministic where possible — otherwise tests will be flaky.
  • The Director will check Evaluation.accepted to either finish or continue to the next attempt (based on runtimeConfig.maxSteps).

Example: accept only if score >= 0.8 and no critical feedback.

const evaluation = await evaluationBrain.evaluate(new EvaluatingSubject(requirement, candidate, observations, { agentId }))
if (!evaluation.accepted) {
  // feed back into planning or raise a manual review event
}

6. Workflows, Tasks, Observations — domain model

Workflow

A Workflow is a directed graph of Nodes. Nodes can be:

  • Simple nodes that contain a list of Step objects
  • End nodes
  • Default/start nodes

Workflows support parameterised tasks: nodes can set requirement and observationName and pass contextual observations forward.

Task

A Task contains:

  • id
  • taskType
  • agentType (director, sensor, recorder)
  • parameters (including requirement)
  • deliveryMetadata (transport hints)

Observation

Observations can be:

  • SimpleObservation (string)
  • ObjectObservation (structured JSON)
  • DocumentObservation (long text)

Observations include parameters (metadata) and name (optional named observation). Use aggregateNamedObservations() helpers to collect named results.


7. Models, Prompts and Memory

Horizon decouples Model implementations from Brains. Models implement process(subject) and return types appropriate to the phase.

ModelFactory

  • register models with ModelFactory.registerModel(agentId, modelType, model)
  • ModelType is 'thinking' | 'reasoning' | 'evaluating'
  • ModelFactory.loose() returns a factory that yields NoOpModel when missing (handy for tests)

PromptBuilderFactory

  • register prompts per agent + role (human/system + thinking/reasoning/evaluating)
  • default behaviour returns a StringPromptLoader('{{requirement}}') when allowMissing is true

Memory

  • DecayingHashMemory and NoOpMemory are provided
  • Brains consult Memory during THINK to reuse previous plans when confidence is high

8. Service primitives

TaskProcessor

The TaskProcessor is the orchestration entry point. It performs:

  • Agent discovery (local or remote)
  • Agent selection (via AgentSelector)
  • Delegation and synchronous/asynchronous execution

Factory helpers:

TaskProcessor.withLocalAgents(agents)
TaskProcessor.withAgentDiscovery(agentDiscovery)

AgentDiscovery

Local (in‑process) and remote discovery implementations available. Register your agents with the discovery service to make them discoverable by Directors.

EventBus

Event stream for lifecycle events: onTaskStarted, onTaskCompleted, onTaskFailed — useful for metrics and observability.


9. Extending Horizon

New Probe

Implement the Probe interface:

interface Probe {
  defineParameterSchema(): Promise<Record<string,string>>
  generateObservations(parameters: ParameterThought, context: Observation[]): AsyncIteratorObject<Observation, Observation, void>
}

Return observations using an async iterator so sensors can stream results without blocking.

New Repository

Implement RecorderRepository:

interface RecorderRepository {
  defineParameterSchema(): Promise<Record<string,string>>
  execute(parameters: ParameterThought, context: Observation[]): Promise<Observation>
}

New Model

Extend Model and implement process(subject) returning a Workflow | Stringifiable | Evaluation depending on phase. Register via ModelFactory.registerModel(agentId, modelType, model).

New Agent Type

Extend Agent and implement doExecute() and getPlanningSubject() appropriately. Use EventBus to emit lifecycle events.


10. Examples + PlantUML diagrams

Below are canonical diagrams you can paste into your .gitlab-ci or docs site to render. Replace names and ports to match your deployment.

High level architecture

@startuml
node "Director" as Director
node "Sensors" as Sensors
node "Recorders" as Recorders
node "EventBus" as EventBus

Director --> Sensors : plan / delegate
Sensors --> EventBus : observations
EventBus --> Director : publish
Director --> Recorders : persist
@enduml

Agent lifecycle (Think → Act → Reason → Evaluate)

@startuml
start
:Receive Task;
:THINK (Brain.think) -> Plan/Parameters;
if (plan contains steps?) then (yes)
  :ACT (Agent.act) -> call Probe/Repository/Remote;
  :COLLECT Observations;
  :REASON (Brain.reason) -> Candidate;
  :EVALUATE (Brain.evaluate) -> Evaluation;
  if (Evaluation.accepted) then (accepted)
    :Emit onTaskCompleted;
    stop
  else (retry)
    :if (steps < maxSteps) -> loop to THINK
    else -> Emit onTaskFailed
  endif
else (no)
  :Emit onTaskFailed
endif
@enduml

Sample workflow (documentation generator)

@startuml
title Documentation generation workflow

start
:translate_requirement -> create_diagram;
:create_diagram -> format_document;
:format_document -> write_document;
stop
@enduml

11. Tests, CI and contributing

  • Linting and formatting follow .eslintrc.json and .prettierrc.
  • Test suites are under packages/*/src/test/ts.
  • CI pipeline in .gitlab-ci.yml runs install, test, lint, audit and publish steps.
  • Use changesets to propose releases.

Contributing checklist:

  1. Create a branch from main.
  2. Add tests for new behaviour.
  3. Run npm run lint && npm run build && npm test.
  4. Open MR and request review.

12. Appendix — Useful snippets

Register a model (example)

const mf = ModelFactory.loose()
mf.registerModel('myAgent', 'thinking', new WorkflowThinkingModel(...))

Create a sensor (example)

const sensor = new Sensor(
  { agentId: 'webSensor', agentType: 'sensor', name: 'Web sensor' },
  new SensorBrain(...),
  new RestApiProbe(httpClient),
  { maxSteps: 3, minMemoryConfidence: 0.6 }
)