N AgentNava
AgentNava · Reference

Types and errors

The whole surface on one page.

Every call

Five entry points. Everything else is a method on what you already hold.

// GETTING IN
new AgentNava(options?)                      -> Workspace     // no request
ws.get()                                     -> Workspace
ws.agents.create(fields)                     -> Agent
ws.agents.list()                             -> Agent[]
ws.projects.create(fields)                   -> Project
ws.projects.list()                           -> Project[]

ws.agent(agentId)                            -> Agent         // no request
ws.conversation(conversationId)                        -> Conversation       // no request
ws.project(projectId)                        -> Project       // no request

// AN AGENT
agent.start({ version?, parameters? })       -> Conversation
agent.update(fields)                         -> Agent         // publishes a version
agent.get({ version? })                      -> Agent
agent.versions()                             -> Agent[]
agent.delete()                               -> void
agent.conversations()                             -> Conversation[]

agent.setWorkflow(workflow)                  -> Agent         // publishes a version
agent.removeWorkflow(name)                   -> Agent         // publishes a version
agent.setTriggers(triggers)                  -> Agent         // publishes a version

agent.knowledge.put(path, bytes)             -> FileEntry
agent.knowledge.list(dir?)                   -> FileEntry[]
agent.knowledge.remove(path)                 -> void

agent.bind({ secrets?, connections? })       -> Agent
agent.connections()                          -> ConnectionStatus[]
agent.authorize(provider)                    -> { url }
agent.disconnect(provider)                   -> void

// A CONVERSATION, FROM AN AGENT OR A PROJECT
conversation.ask(text, { attachments? })          -> Turn
conversation.messages()                           -> Message[]
conversation.end()                                -> void
conversation.bind({ secrets?, connections? })     -> Conversation
conversation.authorize(provider)                  -> { url }
conversation.files(dir?)                          -> FileEntry[]
conversation.readFile(path)                       -> string
conversation.readFileBytes(path)                  -> Uint8Array
conversation.writeFile(path, bytes)               -> FileEntry
conversation.removeFile(path)                     -> void
conversation.fileUrl(path, { download?, ttl? })   -> string

// A PROJECT
project.start({ parameters? })               -> Conversation
project.update(fields)                       -> Project
project.get()                                -> Project
project.addAgent(agentId)                    -> Project
project.removeAgent(agentId)                 -> Project
project.archive()                            -> Project
project.delete()                             -> void
project.conversations()                           -> Conversation[]
project.files(dir?)                          -> FileEntry[]
project.readFile(path)                       -> string
project.fileUrl(path, { download?, ttl? })   -> string

// HELPERS
loadWorkflows(dir)                           -> Workflow[]

ws.agent(id), ws.conversation(id) and ws.project(id) make no network call. You get something you can call methods on, and the first request happens when you call one. A returned object carries methods, so store the id and use ws.agent(id) to come back in.

Types

type Workspace = { id: string; name: string; credits: number; createdAt: string };

type Agent = {
  id:           string;
  name:         string;
  instructions: string;
  greeting?:    string;
  grade:        'standard' | 'premium';
  filesystem:   'drive' | 'none';
  tools:        string[];
  workflows:    Workflow[];
  connections:  Connection[];
  secrets:      Secret[];
  parameters:   Parameter[];
  triggers:     Trigger[];
  mcpServers:   McpServer[];
  httpTools:    HttpTool[];
  version:      number;
  createdAt:    string;
  updatedAt:    string;
};

type Workflow = { name: string; when: string; content: string };

type Trigger =
  | { kind: 'chat' }
  | { kind: 'schedule'; cron: string; timezone?: string; message: string }
  | { kind: 'interval'; seconds: number; maxRuns?: number; message: string }
  | { kind: 'webhook';  message?: string; url?: string };

type Connection = { provider: string; scope: Scope; required?: boolean };
type Secret     = { name: string;     scope: Scope; required?: boolean };
type Scope      = 'fixed' | 'conversation';

type Parameter = {
  name: string;
  type: 'string' | 'number' | 'date' | 'choice';
  required?: boolean;
  default?: string;
  choices?: string[];
};

type McpServer = {
  name: string;
  url: string;
  transport?: 'http' | 'sse';
  headers?: Record<string, string>;
  timeoutMs?: number;
};

type HttpTool = {
  name: string;
  description: string;
  method: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH';
  url: string;
  headers?: Record<string, string>;
  body?: string;
  params?: Record<string, HttpToolParam>;
  secrets?: string[];
  timeoutMs?: number;
};

type ConnectionStatus = {
  provider: string;
  declared: boolean;
  required: boolean;
  scope?: Scope;
  connected: boolean;
  suppliedBy?: 'conversation' | 'agent' | 'workspace';
  accountLabel?: string;
  error?: string;
};

type AgentConversation = {
  id: string; agentId: string; version: number;
  startedAt: string; title?: string;
  ready: boolean; requires: Requirement[];
};

type ProjectConversation = {
  id: string; projectId: string;
  startedAt: string; title?: string;
  ready: boolean; requires: Requirement[];
};

type Project = {
  id: string;
  name: string;
  goal: string | null;
  managerInstructions: string | null;
  grade: 'standard' | 'premium';
  status: 'active' | 'archived';
  agents: Member[];
  createdAt: string;
  updatedAt: string;
};

type Member      = { agentId: string; name: string; addedAt: string };
type Requirement = { kind: 'secret' | 'connection'; name: string; required: boolean };

type Turn = Promise<string> & AsyncIterable<TurnEvent>;

type TurnEvent =
  | { type: 'start';    turnId: string }
  | { type: 'progress'; steps: Step[] }
  | { type: 'tool';     name: string; state: 'start' | 'end'; ok?: boolean }
  | { type: 'text';     text: string }
  | { type: 'file';     path: string }
  | { type: 'done';     reply: string }
  | { type: 'error';    message: string; retryable: boolean };

type Step = {
  id: string;
  label: string;
  kind: 'read' | 'write' | 'edit' | 'search' | 'shell'
      | 'web' | 'data' | 'task' | 'plan' | 'other';
  status: 'active' | 'done' | 'error';
};

type Message    = { role: 'user' | 'assistant'; content: string; at: string };
type Attachment = { kind: 'image' | 'file'; name?: string; mimeType: string; data: string };

type FileEntry = {
  path: string;
  kind: 'file' | 'directory';
  mimeType: string;
  size: number;
  modifiedAt: string;
};

type AgentNavaError = {
  code: string;
  message: string;
  status: number;
  retryable: boolean;
  retryAfter?: number;
};

There are two kinds of conversation and they are two types. You know which one you hold, because you know which call returned it.

Errors

Every failure throws AgentNavaError.

import { AgentNavaError } from '@cerebro-labs/agentnava-sdk';

try {
  await conversation.ask('...');
} catch (err) {
  if (err instanceof AgentNavaError) {
    err.code;       // 'agent_not_found'
    err.status;     // 404
    err.retryable;  // false
    err.retryAfter; // seconds, on 429
  }
}
status
400Something in the request was wrong
401Missing or invalid key
404It does not exist, or it is not in your workspace
409Conflicts with current state, such as reusing an agent id
429Rate limited. retryAfter says how long
5xxOurs. retryable is true

404 covers both "no such thing" and "not yours", so a caller probing ids cannot tell another customer's agent from one that never existed. There is no 403.

Branch on code, not on message

Codes are stable. Messages are written for a person reading a log and will be reworded. retryable is the only thing worth automating on: true for 5xx and 429, false for everything else, because a 400 will fail identically forever.

When you iterate a turn instead of awaiting it, a failure arrives as an error event and the loop ends.

Client options

new AgentNava();
new AgentNava({ apiKey, baseURL, timeout });
new AgentNava({ fetch: myFetch });
apiKeyDefaults to AGENTNAVA_API_KEY
baseURLDefaults to https://api.agentnava.com
timeoutPer request, in milliseconds. Not applied to a streaming turn
fetchYour own fetch, for custom transport or authentication

Construction is synchronous and makes no request. The SDK does not retry, cache or queue on your behalf: a call maps to a request, and what comes back is what the API returned.