@profy-ai/sdk is the official TypeScript SDK for the Profy platform. It uses the native fetch API and supports both Node.js and browser environments.
Installation
npm install @profy-ai/sdk
fetch support needed).
Quick Start
import { Profy } from "@profy-ai/sdk";
const client = new Profy({ apiKey: "sk-pro-your-key" });
// Call an Expert
const result = await client.agents.run("my-expert", "你好");
console.log(result.text);
Client Configuration
import { Profy } from "@profy-ai/sdk";
const client = new Profy({
apiKey: "sk-pro-your-key",
baseUrl: "https://api.profy.cn", // default
timeout: 300_000, // default (milliseconds)
});
| Parameter | Type | Default | Description |
|---|---|---|---|
apiKey | string | (required) | API Key or OAuth Access Token |
baseUrl | string | https://api.profy.cn | API base URL |
timeout | number | 300000 | Request timeout (milliseconds) |
Resource Namespaces
| Namespace | Methods | Endpoint |
|---|---|---|
client.agents | run(), runStream() | POST /v1/agents/run |
client.chat.completions | create() | POST /v1/chat/completions |
client.models | list() | GET /v1/models |
client.events | report() | POST /v1/events |
Agents
agents.run() — Invoke an Expert
const result = await client.agents.run(
"my-expert",
"帮我分析这段代码的性能问题",
{
sessionId: "abc123", // Optional: continue a session
model: "deepseek-v3", // Optional: specify a model
}
);
console.log(result.text); // Full reply
console.log(result.model); // Model used
console.log(result.sessionId); // Session ID
console.log(result.toolCalls); // Tool call list
console.log(result.usage); // Token usage
console.log(result.elapsedMs); // Elapsed time (ms)
AgentRunResult type definition:
interface AgentRunResult {
text: string;
model?: string;
sessionId?: string;
toolCalls: ToolCall[];
usage: TokenUsage;
error?: string;
partial: boolean;
elapsedMs: number;
}
interface ToolCall {
name: string;
status: "started" | "completed";
}
interface TokenUsage {
promptTokens: number;
completionTokens: number;
totalTokens: number;
}
agents.runStream() — Stream an Expert Invocation
for await (const chunk of client.agents.runStream("my-expert", "你好")) {
switch (chunk.type) {
case "run.in_progress":
console.log(`Model: ${chunk.raw.model_name}`);
console.log(`Session: ${chunk.raw.session_id}`);
break;
case "output.text.delta":
process.stdout.write(chunk.delta ?? "");
break;
case "tool_call.created":
console.log(`\n🔧 Tool call: ${chunk.raw.tool_name}`);
break;
case "tool_call.completed":
console.log(`✅ Tool completed`);
break;
case "run.completed":
console.log("\n--- Done ---");
break;
case "run.failed":
console.error(`❌ Error: ${chunk.raw.message}`);
break;
}
}
AgentRunChunk type definition:
interface AgentRunChunk {
type: string;
delta?: string;
raw: Record<string, unknown>;
}
Chat Completions
chat.completions.create() — Chat Completion
Non-streaming (returns ChatResponse):
const resp = await client.chat.completions.create({
model: "deepseek-v3",
messages: [
{ role: "system", content: "You are a helpful assistant" },
{ role: "user", content: "你好" },
],
temperature: 0.7,
maxTokens: 1000,
});
console.log(resp.text);
console.log(`Tokens: ${resp.usage.totalTokens}`);
AsyncGenerator<ChatChunk>):
const stream = await client.chat.completions.create({
model: "deepseek-v3",
messages: [{ role: "user", content: "讲一个故事" }],
stream: true,
});
for await (const chunk of stream) {
if (chunk.delta) {
process.stdout.write(chunk.delta);
}
}
// stream: false → Promise<ChatResponse>
const response: ChatResponse = await client.chat.completions.create({
model: "deepseek-v3",
messages: [...],
stream: false, // or omit
});
// stream: true → Promise<AsyncGenerator<ChatChunk>>
const stream: AsyncGenerator<ChatChunk> = await client.chat.completions.create({
model: "deepseek-v3",
messages: [...],
stream: true,
});
Models
models.list() — Get Model List
const models = await client.models.list();
for (const m of models) {
console.log(`${m.id}: ${m.name}`);
const caps = m.capabilities as Record<string, unknown>;
console.log(` Tools: ${caps?.supportsTools ? "✅" : "❌"}`);
console.log(` Vision: ${caps?.supportsVision ? "✅" : "❌"}`);
console.log(` Max Input: ${caps?.maxInputTokens ?? "unknown"}`);
}
Events
events.report() — Report a Custom Event
const result = await client.events.report("image_generation", {
idempotencyKey: "order_123_gen_1",
metadata: { style: "watercolor" },
});
console.log(`Charged: ${result.charged}`);
console.log(`Remaining: ${result.balance_remaining}`);
The Events API only supports OAuth Tokens. Calling with an API Key will return a 401 error.
Error Handling
The SDK throwsProfyApiError when the API returns a non-2xx status code:
import { Profy, ProfyApiError } from "@profy-ai/sdk";
const client = new Profy({ apiKey: "sk-pro-your-key" });
try {
await client.agents.run("non-existent", "你好");
} catch (e) {
if (e instanceof ProfyApiError) {
console.log(`HTTP Status: ${e.statusCode}`);
console.log(`Error:`, e.body);
switch (e.statusCode) {
case 401:
console.log("Invalid API Key");
break;
case 403:
console.log("Access denied");
break;
case 404:
console.log("Expert not found");
break;
case 429:
console.log("Rate limited");
break;
}
}
throw e;
}
Timeout Handling
const client = new Profy({
apiKey: "sk-pro-your-key",
timeout: 60_000, // 60 seconds
});
try {
const result = await client.agents.run("my-expert", "复杂任务");
} catch (e) {
if (e instanceof DOMException && e.name === "AbortError") {
console.log("Request timed out");
}
}
agents.run() will attempt to return partial results already received on timeout (result.partial = true).
Browser Environment
The SDK uses nativefetch and works in the browser:
import { Profy } from "@profy-ai/sdk";
const client = new Profy({
apiKey: oauthAccessToken,
// In the browser, use OAuth Tokens — do not expose API Keys
});
const result = await client.agents.run("my-expert", userMessage);
document.getElementById("output")!.textContent = result.text;
Do not use API Keys in browser frontend code. Use OAuth Tokens on the browser side. API Keys should only be used in Node.js server-side code.
Full Example: Express API Proxy
import express from "express";
import { Profy } from "@profy-ai/sdk";
const app = express();
const client = new Profy({ apiKey: process.env.PROFY_API_KEY! });
app.use(express.json());
app.post("/api/chat", async (req, res) => {
const { message, sessionId, expert } = req.body;
try {
res.setHeader("Content-Type", "text/event-stream");
res.setHeader("Cache-Control", "no-cache");
for await (const chunk of client.agents.runStream(
expert ?? "my-expert",
message,
{ sessionId }
)) {
res.write(`data: ${JSON.stringify(chunk)}\n\n`);
}
res.write("data: [DONE]\n\n");
res.end();
} catch (e) {
res.status(500).json({ error: String(e) });
}
});
app.listen(3000, () => console.log("Server running on :3000"));
Full Example: Multi-Turn Conversation
import { Profy } from "@profy-ai/sdk";
import * as readline from "readline";
const client = new Profy({ apiKey: process.env.PROFY_API_KEY! });
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
async function main() {
let sessionId: string | undefined;
console.log("Start chatting (type quit to exit)\n");
const ask = () => new Promise<string>((resolve) => rl.question("You: ", resolve));
while (true) {
const input = await ask();
if (input.toLowerCase() === "quit") break;
process.stdout.write("AI: ");
for await (const chunk of client.agents.runStream("my-expert", input, { sessionId })) {
if (chunk.type === "run.in_progress") {
sessionId = chunk.raw.session_id as string;
} else if (chunk.type === "output.text.delta") {
process.stdout.write(chunk.delta ?? "");
}
}
console.log();
}
rl.close();
}
main();
Next Steps
Python SDK
Python SDK guide
API Reference
Complete API documentation

