atmon docs

SDKS/TYPESCRIPT.MD

TypeScript

The TypeScript client: install, authenticate, make the first call, and reach the four verbs from your own code.

Install

The package is not published yet. Through the beta it runs from source, out of sdk/typescript in the repository:

cd sdk/typescript
npm install
npm run generate

npm run generate writes the typed client from the contracts. It needs no network. Run it again after pulling a change to the contracts.

When the package is published, this section becomes one npm install line and nothing else on this page changes.

Authenticate

import { createAutomatonClient } from "@rudrite/automaton";

const atmon = createAutomatonClient({
  baseUrl: "https://api.atmon.ai",
  apiKey: process.env.ATMON_API_KEY ?? "",
});

The key rides on every request on every call. It resolves to one project, and that project scopes everything you can read or write.

Construction throws on an empty key or on an address that is not an http or https URL, so a missing environment variable is a startup failure rather than a mystery on the first call. A key the server rejects comes back as an error with the code unauthenticated.

If you run atmon on your own machines, baseUrl is your own node's address instead.

The first call

Find the tool by describing the task:

const { resolutionId, matches } = await atmon.searchTools(
  "file a bug about the failing build",
  { entityId: "user-42", limit: 5 },
);

entityId names the person you are acting for. What comes back is scoped to what that person has connected.

Read the tool, when the compact schema in the match is not enough:

const tool = await atmon.describeTool(matches[0].toolSlug);

Then act:

const call = await atmon.callTool(
  "github.create_issue",
  { owner: "rudrite", repo: "automaton", title: "build is red" },
  { entityId: "user-42", resolutionId, idempotencyKey: "issue-build-red-1" },
);

args is a plain object; the helper encodes it. entityId is required. idempotencyKey makes a retry return the original call rather than acting twice. confirm clears the gate on a destructive tool and means the person was told what would change.

Read the answer

What comes back is the receipt, not a bare result. Check the status before you use it:

if (call.status === ToolCallStatus.SUCCEEDED) {
  const result = JSON.parse(call.resultJson);
} else {
  // errorCode is one of the stable codes; errorDetail says more
}

A destructive call with no confirmation comes back refused, with the reason in the detail, and nothing reached the app: the gate runs before any credential is unlocked.

Close the loop when you can. Reporting whether the tool you chose was the right one is what improves the next ranking:

await atmon.router.reportOutcome({ resolutionId, /* ... */ });

Each resolution is reportable once.

Hand over a whole job

More than about twenty rows, or work that outlives the request you are serving, belongs in a job rather than a loop:

const { job } = await atmon.jobs.submitJob({ program, idempotencyKey: "quarterly-invites" });
const state = await atmon.jobs.getJob({ id: job.id });

See Jobs for what a plan is made of and how to dry-run one first.

Everything else

Every call in the API reference is on the same object: atmon.catalog, atmon.connections, atmon.router, atmon.execution, atmon.jobs, atmon.traces, atmon.triggers, atmon.usage, and atmon.keys. They are standard typed clients, so methods are camelCase and fields follow the contract.

const { authorizationUrl } = await atmon.connections.initiateConnection({
  entityId: "user-42",
  toolkitSlug: "github",
});