npm package: @kognitivedev/agents
Description: AI agent framework with guardrails, memory, and multi-agent networks
Latest version: 0.2.22

# @kognitivedev/agents

> AI agent framework with guardrails, memory, and multi-agent networks — built on Vercel AI SDK.

## Installation

```bash
bun add @kognitivedev/agents ai @ai-sdk/openai zod
```

## Quick Start

```typescript
import { createAgent, tokenLimiter, contentFilter } from "@kognitivedev/agents";
import { openai } from "@ai-sdk/openai";

const agent = createAgent({
  name: "support",
  instructions: "You are a helpful support agent.",
  model: openai("gpt-4o"),
  tools: [searchTool],
  guardrails: [
    tokenLimiter({ maxTokens: 4000 }),
    contentFilter({ patterns: [/password/i], mode: "block" }),
  ],
  maxSteps: 5,
});

const result = await agent.generate({
  messages: [{ role: "user", content: "Help me" }],
  resourceId: {},
});
```

## Instructions can be declared in 3 ways

The `instructions` field supports three formats:

| Type | Purpose |
|------|---------|
| `string` | Static system prompt |
| `(ctx) => string \| Promise<string>` | Dynamic prompt built per run |
| `PromptHubConfig` | Runtime-resolved prompt from Prompt Hub |

### Static string instructions

```typescript
const agent = createAgent({
  name: "writer",
  instructions: "You are a professional copywriter.",
  model: openai("gpt-4o"),
});
```

### Function-based instructions

```typescript
const agent = createAgent({
  name: "localized-agent",
  instructions: async (ctx) => {
    const locale = ctx.resourceId.userId === "fr-user" ? "fr-FR" : "en-US";
    return `You are a support agent. Reply in ${locale}.`;
  },
  model: openai("gpt-4o"),
});
```

### Prompt Hub instructions

Use a `PromptHubConfig` object when instructions should be resolved from `@kognitivedev/prompthub` at runtime.

```typescript
const agent = createAgent({
  name: "support",
  instructions: {
    slug: "support-v2",
    tag: "production",
    variables: {
      brand: "Acme",
      tone: "formal",
    },
  },
  model: openai("gpt-4o"),
  apiKey: process.env.KOGNITIVE_API_KEY,
  baseUrl: "https://api.kognitive.dev",
});
```

`slug` is required. `tag` and `variables` are optional.

### Prompt variables and precedence

Definition-level variables are optional, and can be overridden per run by `promptVariables` on `generate`, `stream`, or `streamWithModes`.

```typescript
await agent.generate({
  messages: [{ role: "user", content: "Draft a reply" }],
  resourceId: { userId: "user_1" },
  promptVariables: {
    brand: "Acme",
    tone: "casual",
  },
});
```

Merge order is:
1. definition `variables`
2. run-level `promptVariables` (overrides duplicates)

### Resolved prompt metadata

When using Prompt Hub instructions, metadata from the backend resolution is attached to runtime context:

- `ctx.resolvedPrompt` inside agent hooks
- `prepare()` result metadata at `result.resolvedPrompt`

```typescript
const result = await agent.prepare({
  resourceId: { userId: "user_1" },
});

console.log(result.resolvedPrompt);
// { promptId, slug, version, tag?, abTestId?, variant? }
```

#### Prompt Hub requirements

Prompt Hub mode needs backend credentials:

- `apiKey` (required)
- `baseUrl` (optional, defaults to `http://localhost:3001`)

Set them directly on the agent, or inherit from a `Kognitive` registry. Missing credentials throw:

`Agent "<name>" uses prompt hub (slug: "<slug>") but no apiKey is configured...`

## Features

- **createAgent** — orchestrates AI SDK streamText/generateText with memory + tools
- **Guardrails** — 6 built-in (tokenLimiter, contentFilter, maxMessageLength, outputContentFilter, asyncLogger, judgeGuardrail) + composition (chain, all, toAsync)
- **Networks** — multi-agent routing via `createAgentNetwork()`
- **prepare()** — escape hatch returning raw AI SDK inputs + resolved prompt metadata (`result.resolvedPrompt`)
- **Memory** — automatic snapshot injection from cognitive backend
- **File processing** — preprocess file attachments (PDFs, images, documents) before they reach the LLM
- **Multi-mode streaming** — `streamWithModes()` emits `values`, `updates`, `messages`, `custom`, `debug`
- **Double-texting** — 4 strategies for handling concurrent requests: reject, queue, interrupt, rollback

## Multi-Mode Streaming

Beyond the default `stream()` (compatible with `useChat()`), use `streamWithModes()` for richer event streams:

```typescript
const eventStream = await agent.streamWithModes({
  messages: [{ role: "user", content: "Hello" }],
  resourceId: {},
  streamModes: ["messages", "debug"],
});

// eventStream is ReadableStream<StreamEvent>
// Events: { event: "messages", data: { token: "Hi" } }
//         { event: "debug", data: { type: "tool_call", ... } }
```

**Stream modes:**
| Mode | Events |
|------|--------|
| `messages` | Token-by-token LLM output |
| `values` | Full state snapshot after each step |
| `updates` | State deltas only |
| `debug` | Tool calls, tool results, step lifecycle |
| `custom` | Application-specific events |

## Double-Texting

Handle concurrent user inputs on the same session via the runtime API:

```typescript
// In request body:
{
  "messages": [...],
  "sessionId": "session-123",
  "doubleTexting": { "strategy": "reject" }
}
```

| Strategy | Behavior |
|----------|----------|
| `reject` | Return 409 if a run is already active |
| `queue` | Wait for current run, then execute sequentially |
| `interrupt` | Abort current run, start new one |
| `rollback` | Same as interrupt for agents |