npm package: @promptev/client
Description: JavaScript/TypeScript SDK for Promptev — run AI prompts and agents programmatically
Author: Promptev Inc.
Latest version: 0.1.0

# Promptev JavaScript SDK

The official JavaScript/TypeScript SDK for [Promptev.ai](https://promptev.ai) — run AI prompts and agents programmatically using your project API key.

## Installation

```bash
npm install @promptev/client
# or
yarn add @promptev/client
# or
pnpm add @promptev/client
```

Requires Node.js 18+ or any modern browser. Zero dependencies.

## Platform Support

Works everywhere — backend, frontend, and edge runtimes. Built entirely on [Web Platform APIs](https://wintercg.org/) (`fetch`, `ReadableStream`, `AbortController`, `TextDecoder`) with no Node.js-specific modules.

| Environment | Supported | Notes |
|---|---|---|
| **Node.js 18+** | ✅ | ESM and CommonJS |
| **Bun** | ✅ | Native Web API support |
| **Deno** | ✅ | Native Web API support |
| **React / Next.js** | ✅ | Works with any bundler |
| **Angular** | ✅ | Full TypeScript types included |
| **Vue / Nuxt** | ✅ | Standard ESM import |
| **Svelte / SvelteKit** | ✅ | Standard ESM import |
| **Vanilla JS** | ✅ | No framework required |
| **Cloudflare Workers** | ✅ | Edge runtime compatible |
| **Vercel Edge Functions** | ✅ | Edge runtime compatible |

```js
// ESM (Node 18+, React, Next.js, Vue, Angular, Svelte, etc.)
import { PromptevClient } from "@promptev/client";

// CommonJS (legacy Node.js projects)
const { PromptevClient } = require("@promptev/client");
```

## Quick Start

```ts
import { PromptevClient } from "@promptev/client";

const client = new PromptevClient({ projectKey: "pv_sk_your_key_here" });

// Run a prompt
const result = await client.runPrompt("support-agent",
  "What is the refund policy?",
  { company: "Acme Corp" }
);
console.log(result);

// Chat with an AI agent
const session = await client.startAgent("your-agent-id");

for await (const event of client.streamAgent(session.chatbotId, {
  sessionToken: session.sessionToken,
  query: "Summarize our Q4 sales report",
})) {
  if (event.type === "done") console.log(event.output);
}
```

## Prompts

Promptev prompts are versioned, server-managed templates. `runPrompt` compiles the template with your variables — and if the prompt has a model configured in Promptev, it also executes it against the LLM and returns the AI response directly.

### Run a prompt with variables

```ts
const result = await client.runPrompt("support-agent",
  "How do I reset my password?",
  { company: "Acme Corp", tone: "professional" }
);
```

### Run a prompt without variables

```ts
const result = await client.runPrompt("knowledge-base",
  "What is the refund policy?"
);
```

### With a model configured (auto-execute)

If your prompt has a model and/or context packs attached in Promptev, `runPrompt` compiles the template, retrieves relevant context via RAG, sends it to the LLM, and returns the AI response:

```ts
const answer = await client.runPrompt("support-agent",
  "What is the refund policy?",
  { company: "Acme Corp" }
);
console.log(answer); // "Our refund policy allows returns within 30 days..."
```

### Without a model (use with your own LLM)

If no model is configured, `runPrompt` returns the compiled template — use it with any LLM:

```ts
import OpenAI from "openai";

const client = new PromptevClient({ projectKey: "pv_sk_..." });
const openai = new OpenAI({ apiKey: "sk-..." });

const systemPrompt = await client.runPrompt("support-agent",
  "How do I reset my password?",
  { company: "Acme Corp", tone: "professional" }
);

const response = await openai.chat.completions.create({
  model: "gpt-4",
  messages: [
    { role: "system", content: systemPrompt },
    { role: "user", content: "How do I reset my password?" },
  ],
});
console.log(response.choices[0].message.content);
```

### Stream a prompt (with tools or real-time output)

When a prompt has tools attached (Jira, Slack, GitHub, etc.) or you want real-time output, use `streamPrompt`. It returns SSE events — same format as agent streaming:

```ts
for await (const event of client.streamPrompt("research-assistant",
  "Find all P1 bugs assigned to me",
  { project: "ACME" }
)) {
  if (event.type === "thoughts") console.log(`Thinking: ${event.output}`);
  else if (event.type === "processing") console.log(`Running: ${event.output}`);
  else if (event.type === "done") console.log(event.output);
}
```

> **When to use which:**
> - `runPrompt()` — simple prompt execution, no tools, returns a string
> - `streamPrompt()` — prompts with tools, RAG-heavy queries, or when you want real-time output

## Agents

Promptev agents are deployed AI assistants with built-in memory, tools (Jira, Slack, GitHub, etc.), and RAG context packs. The SDK lets you start sessions and stream responses in real time.

### Start a session

```ts
const session = await client.startAgent("your-agent-id", { visitor: "John" });

console.log(session.sessionToken);  // Use this for all subsequent messages
console.log(session.name);          // Agent display name
console.log(session.memoryEnabled); // Whether agent retains conversation context
```

### Stream a response

The agent responds via Server-Sent Events (SSE). Each event has a `type` and `output`:

| Event Type | Description |
|---|---|
| `thoughts` | Agent's internal reasoning |
| `processing` | Tool execution status (e.g., "Searching Jira...") |
| `approval_required` | Agent needs permission to run a tool |
| `done` | Final response text |
| `error` | Something went wrong |

```ts
for await (const event of client.streamAgent(session.chatbotId, {
  sessionToken: session.sessionToken,
  query: "What are the open P1 bugs in our backlog?",
})) {
  if (event.type === "thoughts") console.log(`Thinking: ${event.output}`);
  else if (event.type === "processing") console.log(`Running: ${event.output}`);
  else if (event.type === "done") console.log(`\n${event.output}`);
  else if (event.type === "error") console.log(`Error: ${event.output}`);
}
```

### Multi-turn conversation

The session token maintains conversation context across messages:

```ts
const session = await client.startAgent("your-agent-id", { visitor: "Sarah" });

// First message
for await (const event of client.streamAgent(session.chatbotId, {
  sessionToken: session.sessionToken,
  query: "Summarize our Q4 sales report",
})) {
  if (event.type === "done") console.log(event.output);
}

// Follow-up — agent remembers the previous context
for await (const event of client.streamAgent(session.chatbotId, {
  sessionToken: session.sessionToken,
  query: "Compare that with Q3",
})) {
  if (event.type === "done") console.log(event.output);
}
```

### Collect the final response only

```ts
async function askAgent(client, session, query) {
  for await (const event of client.streamAgent(session.chatbotId, {
    sessionToken: session.sessionToken,
    query,
  })) {
    if (event.type === "done") return event.output;
    if (event.type === "error") throw new Error(event.output);
  }
}

const answer = await askAgent(client, session, "What's our monthly churn rate?");
```

## Error Handling

The SDK raises typed errors for each failure scenario:

```ts
import {
  PromptevClient,
  ValidationError,
  AuthenticationError,
  NotFoundError,
  RateLimitError,
  ServerError,
  NetworkError,
} from "@promptev/client";

const client = new PromptevClient({ projectKey: "pv_sk_..." });

try {
  const result = await client.runPrompt("my-prompt", "Hello", { name: "Ava" });
} catch (err) {
  if (err instanceof ValidationError) {
    // 400 — missing variables, bad input
    console.log(`Invalid request: ${err.message}`);
  } else if (err instanceof NotFoundError) {
    // 404 — prompt or project not found
    console.log(`Not found: ${err.message}`);
  } else if (err instanceof AuthenticationError) {
    // 401/403 — invalid API key or agent not active
    console.log(`Auth error: ${err.message}`);
  } else if (err instanceof RateLimitError) {
    // 429 — API usage quota exceeded
    console.log(`Rate limited: ${err.message}`);
  } else if (err instanceof ServerError) {
    // 5xx — server error (after retries exhausted)
    console.log(`Server error: ${err.message}`);
  } else if (err instanceof NetworkError) {
    // Connection failed, timeout, DNS error
    console.log(`Network error: ${err.message}`);
  }
}
```

All errors extend `PromptevError` and include:
- `err.statusCode` — HTTP status code (if applicable)
- `err.responseText` — Raw response body (for debugging)

## Configuration

```ts
const client = new PromptevClient({
  projectKey: "pv_sk_...",              // Required — your project API key
  baseUrl: "https://api.promptev.ai",   // Default — override for self-hosted
  timeout: 30000,                        // Default — request timeout in ms
  maxRetries: 2,                         // Default — retries for 502/503/504
  headers: { "X-Custom": "value" },      // Optional — extra HTTP headers
});
```

| Parameter | Default | Description |
|---|---|---|
| `projectKey` | *required* | Your Promptev project API key |
| `baseUrl` | `https://api.promptev.ai` | API base URL |
| `timeout` | `30000` | Request timeout in milliseconds |
| `maxRetries` | `2` | Automatic retries for transient server errors (502, 503, 504) |
| `headers` | `{}` | Additional HTTP headers |

## API Reference

### `PromptevClient`

| Method | Description | Returns |
|---|---|---|
| `runPrompt(promptKey, query, variables?)` | Compile and execute a prompt | `Promise<string>` |
| `streamPrompt(promptKey, query, variables?)` | Stream prompt execution with tools | `AsyncGenerator<AgentEvent>` |
| `startAgent(chatbotId, options?)` | Start agent session | `Promise<AgentSession>` |
| `streamAgent(chatbotId, options)` | Stream agent response | `AsyncGenerator<AgentEvent>` |

### `AgentSession`

| Field | Type | Description |
|---|---|---|
| `sessionToken` | `string` | Token for subsequent stream calls |
| `chatbotId` | `string` | Agent identifier |
| `name` | `string` | Agent display name |
| `memoryEnabled` | `boolean` | Whether agent retains conversation context |
| `messages` | `array` | Previous messages (populated when resuming a session) |

### `AgentEvent`

| Field | Type | Description |
|---|---|---|
| `type` | `string` | Event type: `thoughts`, `processing`, `done`, `error`, `approval_required` |
| `output` | `string` | Event content text |
| `raw` | `object` | Full parsed SSE event data |

### Exceptions

| Error | HTTP Status | When |
|---|---|---|
| `ValidationError` | 400 | Missing required variables, bad input |
| `AuthenticationError` | 401, 403 | Invalid API key, agent not active |
| `NotFoundError` | 404 | Project, prompt, or agent not found |
| `RateLimitError` | 429 | API usage quota exceeded |
| `ServerError` | 5xx | Server error (after retries exhausted) |
| `NetworkError` | — | Connection failed, timeout, DNS error |
| `PromptevError` | any | Base class for all above errors |

## Framework Examples

### React

```tsx
import { useState } from "react";
import { PromptevClient } from "@promptev/client";

const client = new PromptevClient({ projectKey: "pv_sk_..." });

export function AskAI() {
  const [answer, setAnswer] = useState("");
  const [loading, setLoading] = useState(false);

  async function handleAsk() {
    setLoading(true);
    try {
      const result = await client.runPrompt("support-agent", "What is your refund policy?");
      setAnswer(result);
    } finally {
      setLoading(false);
    }
  }

  return (
    <div>
      <button onClick={handleAsk} disabled={loading}>Ask AI</button>
      {answer && <p>{answer}</p>}
    </div>
  );
}
```

### React — Streaming Agent Chat

```tsx
import { useState, useRef } from "react";
import { PromptevClient } from "@promptev/client";

const client = new PromptevClient({ projectKey: "pv_sk_..." });

export function AgentChat() {
  const [messages, setMessages] = useState<string[]>([]);
  const [input, setInput] = useState("");
  const sessionRef = useRef(null);

  async function startChat() {
    sessionRef.current = await client.startAgent("your-agent-id", { visitor: "user" });
  }

  async function sendMessage() {
    if (!sessionRef.current) await startChat();

    setMessages((prev) => [...prev, `You: ${input}`]);
    const query = input;
    setInput("");

    for await (const event of client.streamAgent(sessionRef.current.chatbotId, {
      sessionToken: sessionRef.current.sessionToken,
      query,
    })) {
      if (event.type === "done") {
        setMessages((prev) => [...prev, `Agent: ${event.output}`]);
      }
    }
  }

  return (
    <div>
      {messages.map((msg, i) => <p key={i}>{msg}</p>)}
      <input value={input} onChange={(e) => setInput(e.target.value)} />
      <button onClick={sendMessage}>Send</button>
    </div>
  );
}
```

### Node.js / Express API

```js
import express from "express";
import { PromptevClient } from "@promptev/client";

const app = express();
const client = new PromptevClient({ projectKey: "pv_sk_..." });

app.post("/api/ask", express.json(), async (req, res) => {
  const answer = await client.runPrompt("support-agent", req.body.question);
  res.json({ answer });
});

app.listen(3000);
```

### Vanilla HTML

```html
<script type="module">
  import { PromptevClient } from "https://cdn.jsdelivr.net/npm/@promptev/client/dist/esm/index.js";

  const client = new PromptevClient({ projectKey: "pv_sk_..." });

  document.getElementById("ask-btn").addEventListener("click", async () => {
    const answer = await client.runPrompt("support-agent", "What is the refund policy?");
    document.getElementById("output").textContent = answer;
  });
</script>
```

## License

This SDK is commercial software by [Promptev Inc](https://promptev.ai).

- Free tier use allowed
- Production use requires an active subscription

See [LICENSE](./LICENSE.txt) for full terms.

## Support

- Website: [promptev.ai](https://promptev.ai)
- Email: support@promptev.ai