novo agents

Agents

Saved agent configurations. Durable context, band, capabilities, attached adapters, and Novo's default subagent orchestration policy.

The Console agent editor mirrors this same contract. Anything configurable on a saved agent through the SDK/API (context, band, capabilities, artifacts, workspace, approvals, policies, metadata) should have a 1:1 console control so teams can configure and test agents in the playground without switching surfaces.

Methods

| Method | Route | |---|---| | novo.agents.list({ limit?, cursor? }) | GET /v1/agents | | novo.agents.create({...}) | POST /v1/agents | | novo.agents.validate({...}) | POST /v1/agents/validate | | novo.agents.get(agentId) | GET /v1/agents/:id | | novo.agents.update(agentId, {...}) | PATCH /v1/agents/:id | | novo.agents.delete(agentId) | DELETE /v1/agents/:id |

Type signature

type AgentsNamespace = {
  list(input?: { limit?: number; cursor?: string }): Promise<Page<Agent>>;
  create(input: {
    context?: string | ContextBlock[];
    band?: Band;
    capabilities?: AgentCapabilities;
    artifacts?: AgentArtifacts;
    workspace?: AgentWorkspace;
    approvals?: AgentApprovals;
    policies?: AgentCreatePolicies;
    metadata?: Metadata;
  }): Promise<Agent>;
  validate(input: AgentCreateInput): Promise<{ valid: true }>;
  get(agentId: string): Promise<Agent>;
  update(agentId: string, input: {
    context?: string | ContextBlock[];
    band?: Band;
    capabilities?: AgentCapabilities;
    artifacts?: AgentArtifacts | null;
    workspace?: AgentWorkspace | null;
    approvals?: AgentApprovals | null;
    policies?: AgentPatchPolicies;
    metadata?: MetadataPatch;
  }): Promise<Agent>;
  delete(agentId: string): Promise<DeleteAgentResponse>;
};

// Stable named band. 'core' is the default when omitted.
// See the Bands API (GET /v1/bands) for live availability.
type Band = 'lite' | 'core' | 'frontier';

type ContextBlock = { id?: string; content: string };

type AgentArtifacts = {
  stream?: { urls?: 'durable-only' | 'include-novo-signed' };
  exports?: {
    resultHandlerId: string;
    include?: {
      generatedDeliverables?: boolean;
      workspaceExports?: boolean;
      browserScreenshots?: boolean;
      browserDownloads?: boolean;
    };
  };
  oversizedToolResults?: { resultHandlerId: string };
};

type MediaGenerationConfig = {
  image?: boolean;
  video?: boolean;
  speech?: boolean;
  music?: boolean;
  soundEffect?: boolean;
};

type AgentCapabilities = {
  web?: boolean;
  browser?: boolean | {
    authenticated?: { profileKey: string };
    files?: boolean;
    tabs?: boolean;
  };
  userInteraction?: boolean;
  subagents?: boolean;
  media?: boolean | MediaGenerationConfig;
  mediaView?: { output?: 'analysis' | 'auto' };
  github?: { connectionId: string; repositories?: string[] };
  http?: { connectionIds: string[] };
  mcp?: { toolServerIds: string[] };
  skills?: AgentSkill[];
};

type AgentSkill = {
  name: string;
  description: string;
  body: string;
  frontmatter?: Record<string, unknown>;
  metadata?: Record<string, unknown>;
};

type AgentWorkspace =
  | {
      type: 'managed';
      filesystem?: boolean;
      shell?: boolean;
      documents?: boolean;
      mediaEditing?: boolean;
      resources?: 'small' | 'standard' | 'large';
      lifecycle?: { idleMinutes?: number; retentionDays?: number };
      network?: { mode?: 'public' } | { mode: 'restricted'; allowDomains: string[] } | { mode: 'offline' };
      previews?: { enabled?: boolean; ports?: number[] };
      seed?: { type: 'git'; url: string; revision?: string; depth?: number };
      services?: Array<{ name: string; command: string; cwd?: string; port?: number; restartPolicy?: 'on-resume' | 'manual' }>;
      secretContexts?: string[];
    }
  | { type: 'remote'; environmentId: string; filesystem?: boolean; shell?: boolean };

type AgentCreatePolicies = {
  maxStepsDefault?: number | null;
  maxDurationMsDefault?: number | null;
  mediaFidelity?: 'standard' | 'spatial';
  dataHandling?: 'standard' | 'strict';
};

type AgentPatchPolicies = {
  maxStepsDefault?: number | null;
  maxDurationMsDefault?: number | null;
  mediaFidelity?: 'standard' | 'spatial' | null;
  dataHandling?: 'standard' | 'strict' | null;
};

validate runs the exact create schema, reference checks, workspace/capability checks, and approval-hook authorization without writing an agent row. A valid definition returns { valid: true }; an invalid definition returns the same structured 400 error it would receive from create.

context is the agent's durable shared system framing. Pass a bare string for the trivial single-block case, or an array of ContextBlocks to keep independently-addressable pieces (e.g. immutable rules + an editable persona). The Agent resource always exposes it normalized to context: ContextBlock[].

Create

const agent = await novo.agents.create({
  context: 'You are a refund triage assistant.',
  band: 'core',
  capabilities: { web: true, userInteraction: true },
});

Returns the full Agent resource with a stable id prefixed agent_….

Update

PATCH is a partial update. Config edits bump configVersion; agent context is captured when a run is created, so the next run picks up the change without resetting the thread. A managed workspace's resolved runtime spec is pinned when its thread workspace is first created, so workspace config changes apply to new threads. Delete and recreate a thread when its workspace must adopt a new resource, network, lifecycle, service, preview, or seed configuration.

await novo.agents.update(agent.id, {
  context: [
    { id: 'rules', content: 'Never issue a refund over $500 without approval.' },
    { id: 'persona', content: 'Always confirm with the customer first.' },
  ],
});

Editing agent context rebuilds the prompt cache on the next run: cheap, and never a conversation reset. Keep separate concerns in separate blocks so an update to one (the persona) can't drop another (the rules). See Context.

Pass artifacts: null to clear artifact delivery config and return to default stream projection (durable-only with no export or oversized-result handler). approvals, workspace, and individual policies fields can also be cleared with null where supported by their field type. To clear agent context, send context: [].

capabilities and the top-level workspace are replace-semantics, not a field merge: the object you send becomes the agent's full desired state, so omit a capability key to disable it (e.g. drop github to revoke GitHub access). This differs from metadata (key-level merge; send null to delete a key) and individual policies fields (per-field patch). The lone exception is the managed workspace's documents/mediaEditing flags, which carry forward if a workspace patch omits them; every other workspace sub-field, including secretContexts, replaces. Always send the full capability and workspace state you want on each update.

Capability and workspace edits take effect on the next run. A run already executing keeps the capability snapshot it captured at run start, so revoking a capability does not interrupt an in-flight run. Cancel the run when access must stop immediately. For GitHub, removing or suspending the App installation also prevents new operation tokens from being minted; sync the connection afterward to project that state into Novo.

policies.dataHandling: 'strict' requires verified zero-data-retention, no-training, and providers based in the US or Europe (EU and UK) for AI inference routes, with matching strict gates for managed capabilities that receive customer data. Eligibility is route-specific: Novo uses verified BYOK ZDR where the account qualifies, managed system ZDR where it does not, and rejects before inference where neither route exists. It does not claim regional processing or data residency. standard remains the default and does not promise ZDR. A strict agent cannot be relaxed by a thread, run, or subagent.

Capabilities

The full list and what each flag enables is on Capabilities. On update, capabilities is replace-semantics: send the full set you want and omit a key to turn that capability off, rather than expecting a field merge (see Update).

Artifacts

Use top-level artifacts for delivery configuration, separate from model/tool capabilities:

await novo.agents.update(agent.id, {
  artifacts: {
    exports: { resultHandlerId: 'rh_drive' },
    oversizedToolResults: { resultHandlerId: 'rh_archive' },
  },
});

artifacts.exports promotes generated deliverables and explicit workspace_export_artifact({ path }) outputs to your result handler. artifacts.oversizedToolResults handles only oversized tool-output recovery/archive. artifacts.stream.urls defaults to durable-only, which emits handler durable URLs or id-only refs instead of temporary Novo signed URLs.

Workspace

Use top-level workspace for filesystem and shell tools:

await novo.agents.create({
  context: 'You maintain this app.',
  band: 'core',
  workspace: {
    type: 'managed',
    seed: { type: 'git', url: 'https://github.com/acme/app.git' },
    services: [{ name: 'web', command: 'pnpm dev', port: 3000 }],
  },
});

workspace: { type: 'remote', environmentId } attaches customer-owned runtimes. If shell is enabled, filesystem access must also be enabled because shell commands can read and mutate files. See Workspaces.

Managed workspaces can attach Secret contexts through secretContexts. Only workspace_env projections are injected into managed workspace commands and declared services. Remote workspaces do not accept secret contexts; pass secrets through your remote adapter if you own the runtime.

On update, the workspace object replaces wholesale, except the managed documents and mediaEditing capability flags, which carry forward if a managed-workspace patch omits them (they are capabilities surfaced on the workspace, not runtime settings that reset to a default). Every other field, including secretContexts, replaces, so send the full workspace state you want.

Errors

  • 404 agent_not_found: bad ID or deleted agent.
  • 400 invalid_request_error: bad input (context block too long or over the aggregate cap, duplicate block id, unknown capability, invalid or unavailable band, invalid workspace config).
  • 403 permission_denied: agent belongs to another workspace.