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 🙏

© 2026 – Pkg Stats / Ryan Hefner

@jambudipa/agent-protocol

v0.1.0

Published

Agent Protocol v1 server and client for Effect v4.

Readme

@jambudipa/agent-protocol

Agent Protocol v1 for Effect v4: a server, a typed client and the OpenAPI document, all derived from one HttpApi definition.

It keeps feature parity with npm agent-protocol 1.0.5: you supply a task handler that returns a step handler, tasks live in memory, and artifacts live in a workspace directory. It adds a typed client, which the reference SDK does not have.

Install

npm install @jambudipa/agent-protocol effect@~4.0.6 @effect/platform-node@~4.0.6

effect and @effect/platform-node are peer dependencies.

Serve an agent

import { NodeRuntime } from '@effect/platform-node';
import { Effect, Layer, Option, Ref } from 'effect';
import { StepResult, type TaskHandler } from '@jambudipa/agent-protocol';
import * as AgentProtocolNode from '@jambudipa/agent-protocol/node';

// Runs once for each new task, and returns the step handler of that task.
const taskHandler: TaskHandler = Effect.fnUntraced(function* (task) {
  const steps = yield* Ref.make(0);
  // Runs once for each step. `input` is `Option.none()` for a step without a body.
  return (input) =>
    Ref.updateAndGet(steps, (n) => n + 1).pipe(
      Effect.map(
        (n) =>
          new StepResult({
            name: Option.some(`step ${n}`),
            output: Option.some(`task ${task.task_id}, step ${n}`),
            is_last: n === 3,
          })
      )
    );
});

Layer.launch(
  AgentProtocolNode.layer(taskHandler, { port: 8000, workspace: './workspace' })
).pipe(NodeRuntime.runMain);

The defaults are port 8000 and workspace ./workspace, as in the reference SDK. The generated OpenAPI document is at GET /openapi.json.

To serve on another platform, provide AgentProtocolServer.layer(taskHandler, { workspace }) to HttpRouter.serve with that platform's HTTP server layer.

Handler contract

type TaskHandler = (task: Task) => Effect.Effect<StepHandler, TaskFailed>;
type StepHandler = (
  input: Option.Option<StepRequestBody>
) => Effect.Effect<StepResult, StepFailed>;
  • A TaskFailed from the task handler answers 500, and the server stores no task.
  • A StepFailed from the step handler answers 500, and the server stores no step. The task stays readable.
  • Each step has status completed. The artifacts of a step are added to its task.
  • An artifact in StepResult.artifacts is metadata. As in the reference SDK, the agent writes the file itself, at <workspace>/<task_id>/<relative_path>/<file_name>.

Call an agent

import { FetchHttpClient } from 'effect/http';
import { Effect, Layer, Option } from 'effect';
import { AgentProtocolClient } from '@jambudipa/agent-protocol';

const program = Effect.gen(function* () {
  const client = yield* AgentProtocolClient;
  const task = yield* client.createAgentTask({
    payload: {
      input: Option.some("Write 'Washington' to output.txt"),
      additional_input: Option.none(),
    },
  });
  const step = yield* client.executeAgentTaskStep({
    params: { task_id: task.task_id },
    payload: { input: Option.none(), additional_input: Option.none() },
  });
  return step.output;
}).pipe(
  Effect.provide(
    AgentProtocolClient.layer({ baseUrl: 'http://localhost:8000' }).pipe(
      Layer.provide(FetchHttpClient.layer)
    )
  )
);

Each client method is named after its operationId in the specification. Upload an artifact with a FormData payload that has a file part and an optional relative_path field.

Wire format

  • Field names are snake_case, as in the specification.
  • An optional or nullable field decodes to an Option. A missing key and null both decode to Option.none(), and Option.none() encodes to a missing key.
  • List operations take current_page and page_size (default 1 and 10, each at least 1).
  • An unknown task, step or artifact answers 404 with { "message": ... }.
  • A request whose path, query or body does not decode answers 422 with { "message": ... }. This includes an upload without a file part, and a relative_path that is absolute or has a .. segment.

Conformance

spec/openapi.yml is the specification at commit 5047199152dc6e1ba83320b1b59f94af24046dcf. The conformance test checks that the generated OpenAPI document declares the same paths, methods and operationId values, and that a running server routes each of them to a handler.