
Security News
pnpm 11.5 Adds Support for Recognizing npm Staged Publishes
pnpm 11.5 now recognizes npm staged publish approvals in release metadata, preventing those releases from being mistaken for lower-trust package publishes.
@agentick/client
Advanced tools
Client SDK for multiplexed session access to a Agentick server. One client per app, many sessions per client.
pnpm add @agentick/client
# or
npm install @agentick/client
import { createClient } from "@agentick/client";
const client = createClient({ baseUrl: "https://api.example.com" });
// Subscribe to a session (hot)
const conv = client.subscribe("conv-123");
// Listen for all events from this session
conv.onEvent((event) => {
if (event.type === "content_delta") {
process.stdout.write(event.delta);
}
});
// Send a message and await result
const handle = conv.send({
message: { role: "user", content: [{ type: "text", text: "Hello!" }] },
});
const result = await handle.result;
console.log(result.response);
createClient(config)Creates a new AgentickClient instance.
const client = createClient({
baseUrl: "https://api.example.com",
token: "bearer_token",
headers: { "x-tenant": "acme" },
paths: {
events: "/events",
send: "/send",
subscribe: "/subscribe",
abort: "/abort",
close: "/close",
toolResponse: "/tool-response",
channel: "/channel",
},
});
client.session(sessionId)Returns a cold session accessor. No side effects until subscribe() or send() is called.
const conv = client.session("conv-123");
conv.subscribe(); // make hot
client.subscribe(sessionId)Returns a hot session accessor. Subscribes immediately (auto-connects if needed).
const conv = client.subscribe("conv-123");
client.send(input)Ephemeral send. Creates a session, executes, then closes.
const handle = client.send({
message: { role: "user", content: [{ type: "text", text: "Quick question" }] },
props: { mode: "fast" },
});
for await (const event of handle) {
if (event.type === "content_delta") {
process.stdout.write(event.delta);
}
}
const result = await handle.result;
accessor.subscribe() / accessor.unsubscribe()Turns a cold accessor hot, or turns it cold again. Subscriptions are scoped to the session.
accessor.send(input)Send to a session and return a ClientExecutionHandle.
accessor.onEvent(handler)Receives events for this session only.
accessor.onResult(handler)Receives final results for this session only (same as listening for type: "result").
accessor.onToolConfirmation(handler)Receives tool confirmation requests for this session.
accessor.abort(reason?) / accessor.close()Abort the current execution or close the session server-side.
accessor.invoke(method, params?)Invoke a custom gateway method with auto-injected sessionId.
const session = client.subscribe("conv-123");
// Invoke custom methods defined in gateway
const tasks = await session.invoke("tasks:list");
const newTask = await session.invoke("tasks:create", {
title: "Buy groceries",
priority: "high",
});
// Nested namespaces
await session.invoke("tasks:admin:archive");
accessor.stream(method, params?)Invoke a streaming method with auto-injected sessionId. Returns an async generator.
const session = client.subscribe("conv-123");
// Stream updates from a custom method
for await (const change of session.stream("tasks:watch")) {
console.log("Task changed:", change);
}
accessor.channel(name)Session-scoped channel for app-defined pub/sub.
const conv = client.subscribe("conv-123");
const todos = conv.channel("todos");
todos.subscribe((payload) => {
console.log("Todo update:", payload);
});
await todos.publish("add", { title: "Buy milk" });
client.onEvent(handler)Receives events from all subscribed sessions. Events include sessionId for routing.
client.onEvent((event) => {
console.log(event.sessionId, event.type);
});
client.on(type, handler)Convenience subscription by event type (e.g., "content_delta", "tool_call").
client.onStreamingText((state) => {
console.log(state.text, state.isStreaming);
});
const session = client.subscribe("conv-123");
session.onToolConfirmation((request, respond) => {
const approved = window.confirm(`Allow ${request.name}?`);
respond({
approved,
reason: approved ? undefined : "User denied",
});
});
client.onConnectionChange((state) => {
if (state === "error") {
console.error("Connection error");
}
});
Framework-agnostic line editor with readline-quality editing: cursor movement, word navigation, kill/yank, history, and a match-based completion engine.
import { LineEditor } from "@agentick/client";
const editor = new LineEditor({ onSubmit: (text) => console.log(text) });
editor.handleInput(null, "hello"); // insert text
editor.handleInput("ctrl+a", ""); // move to start
editor.handleInput("return", ""); // submit
Register completion sources with match/resolve. The source's match function decides when to activate based on the current buffer and cursor; resolve produces items.
const unregister = editor.registerCompletion({
id: "file",
match({ value, cursor }) {
const idx = value.lastIndexOf("#", cursor - 1);
if (idx < 0) return null;
return { from: idx, query: value.slice(idx + 1, cursor) };
},
resolve: async ({ query }) => searchFiles(query),
debounce: 150,
});
When active, editor.state.completion contains the current CompletionState (items, selectedIndex, query, loading, from). Accepted completions are tracked as CompletedRange entries in editor.state.completedRanges.
See COMPLETION.md for the full completion system reference covering match/resolve API, resolution paths, keybindings, range tracking, slash commands, and custom sources.
Composable building blocks for chat UIs. Use ChatSession for the common case, or compose individual primitives for custom architectures.
Complete chat controller — messages, steering, tool confirmations, and attachments in one snapshot.
import { ChatSession } from "@agentick/client";
const chat = new ChatSession(client, {
sessionId: "conv-123",
autoSubscribe: true, // Subscribe to SSE transport (default: true)
initialMessages: [], // Pre-loaded history
transform: undefined, // Custom MessageTransform (default: timelineToMessages)
renderMode: undefined, // Progressive rendering: "streaming" | "block" | "message"
confirmationPolicy: undefined, // Auto-approve/deny policy (default: prompt all)
deriveMode: undefined, // Custom ChatModeDeriver (default: idle/streaming/confirming_tool)
onEvent: undefined, // Raw event hook
attachments: undefined, // AttachmentManagerOptions (validator, toBlock, maxAttachments)
// Inherits all MessageSteering options: mode, flushMode, autoFlush
});
// State (read-only snapshot, updated on every mutation)
chat.messages; // ChatMessage[]
chat.chatMode; // "idle" | "streaming" | "confirming_tool"
chat.toolConfirmation; // { request, respond } | null
chat.lastSubmitted; // Optimistic user message text
chat.queued; // Queued messages (queue mode)
chat.isExecuting; // Whether an execution is in progress
chat.mode; // "steer" | "queue"
chat.state.attachments; // Attachment[] (read-only snapshot)
// Attachments — add files before submit()
chat.attachments.add({ name: "photo.png", mimeType: "image/png", source: base64Data });
chat.attachments.remove(id);
chat.attachments.clear();
chat.attachments.count; // number
chat.attachments.isEmpty; // boolean
// Actions — submit(), steer(), and interrupt() drain pending attachments
chat.submit("Describe this image"); // Sends [ImageBlock, TextBlock]
chat.steer("Force send"); // Always send immediately (drains attachments)
chat.queue("Later"); // Always queue (no attachments)
chat.interrupt("Stop"); // Abort + send (drains attachments)
chat.flush(); // Flush next queued message
chat.respondToConfirmation({ approved: true });
chat.clearMessages();
chat.prependMessages(olderMessages); // Load older history on scroll-back
chat.appendMessages(newMessages); // Initial load or external sources
// Subscribe
const unsub = chat.onStateChange(() => {
console.log(chat.state);
});
chat.destroy();
Control how progressively messages appear in the message list. Without renderMode, messages only appear at execution_end (the entire execution must finish). With a render mode, content appears earlier:
| Mode | Granularity | Updates on |
|---|---|---|
"streaming" | Token-by-token | content_delta, reasoning_delta, tool_call_delta |
"block" | Full blocks | content, reasoning, tool_call |
"message" | Full message | message |
| (none) | Execution end | execution_end |
Each tier is a superset of the one above — "streaming" handles everything "block" does, plus finer deltas.
// Block-at-a-time (recommended for terminal UIs)
const chat = new ChatSession(client, {
sessionId: "conv-123",
renderMode: "block",
});
// Token-by-token (recommended for web UIs)
const chat = new ChatSession(client, {
sessionId: "conv-123",
renderMode: "streaming",
});
When renderMode is set, user messages appear immediately on submit() (before the server responds). Reasoning blocks are included in progressive rendering for all modes.
The deriveMode option lets you define custom chat mode enums:
type MyMode = "idle" | "working" | "needs_approval" | "error";
const chat = new ChatSession<MyMode>(client, {
sessionId: "conv-123",
deriveMode: ({ isExecuting, hasPendingConfirmation }) => {
if (hasPendingConfirmation) return "needs_approval";
if (isExecuting) return "working";
return "idle";
},
});
chat.chatMode; // MyMode — fully type-safe
Auto-approve safe tools, prompt for dangerous ones:
const chat = new ChatSession(client, {
sessionId: "conv-123",
confirmationPolicy: (request) => {
if (["read_file", "glob", "grep"].includes(request.name)) {
return { action: "approve" };
}
if (request.name === "rm") {
return { action: "deny", reason: "Destructive operation" };
}
return { action: "prompt" };
},
});
Send images, PDFs, and other files alongside text. Platforms add files to the attachment manager, and submit() drains them into the user message automatically.
// Add attachments before submitting
chat.attachments.add({
name: "screenshot.png",
mimeType: "image/png",
source: base64String, // or URL string, or { type: "base64", data } / { type: "url", url }
size: 102400, // optional
});
chat.submit("What's in this image?");
// Sends: [ImageBlock(screenshot.png), TextBlock("What's in this image?")]
// Attachments are cleared atomically on submit
The default validator accepts image/png, image/jpeg, image/gif, image/webp, and application/pdf. Customize via options:
import { defaultAttachmentValidator } from "@agentick/client";
const chat = new ChatSession(client, {
sessionId: "conv-123",
attachments: {
maxAttachments: 5,
validator: (input) => {
// Compose with the default, or replace entirely
if (input.size && input.size > 10_000_000) {
return { valid: false, reason: "File too large (max 10MB)" };
}
return defaultAttachmentValidator(input);
},
toBlock: undefined, // Custom Attachment → ContentBlock mapper
},
});
Source strings are auto-detected: https://, http://, data:, and blob: prefixes produce URL sources; everything else is treated as base64 data.
For custom architectures, use the primitives directly. Each supports standalone mode (self-subscribes) or composed mode (subscribe: false + manual processEvent()).
Accumulates messages from execution lifecycle events with tool duration tracking.
import { MessageLog } from "@agentick/client";
const log = new MessageLog(client, {
sessionId: "conv-123",
initialMessages: [],
transform: undefined, // Custom MessageTransform
renderMode: "block", // Progressive rendering (see below)
});
log.messages; // ChatMessage[]
log.pushUserMessage("Hello"); // Immediate (progressive modes)
log.prependMessages(olderMessages); // Paginated history (scroll-back)
log.appendMessages(newMessages); // Initial load or external sources
log.clear();
log.destroy();
Manages tool confirmation lifecycle with policy-based auto-resolution.
import { ToolConfirmations } from "@agentick/client";
const tc = new ToolConfirmations(client, {
sessionId: "conv-123",
policy: (req) => (req.name === "read_file" ? { action: "approve" } : { action: "prompt" }),
});
tc.pending; // { request, respond } | null
tc.respond({ approved: true });
tc.destroy();
Input-side message routing with queue/steer modes and auto-flush.
import { MessageSteering } from "@agentick/client";
const steering = new MessageSteering(client, {
sessionId: "conv-123",
mode: "queue", // "queue" | "steer"
flushMode: "sequential", // "sequential" | "batched"
autoFlush: true,
});
steering.submit("Hello"); // Queue or send based on mode + execution state
steering.steer("Now"); // Always send
steering.queue("Later"); // Always queue
steering.flush();
steering.destroy();
All primitives support subscribe: false for parent-controlled event fan-out:
const log = new MessageLog(client, { sessionId: "s1", subscribe: false });
const tc = new ToolConfirmations(client, { sessionId: "s1", subscribe: false });
const steering = new MessageSteering(client, { sessionId: "s1", subscribe: false });
// Single subscription, deterministic fan-out
const accessor = client.session("s1");
accessor.onEvent((event) => {
steering.processEvent(event);
log.processEvent(event);
});
accessor.onToolConfirmation((request, respond) => {
tc.handleConfirmation(request, respond);
});
This is exactly what ChatSession does internally.
import { timelineToMessages, extractToolCalls, defaultDeriveMode } from "@agentick/client";
// Convert timeline entries to chat messages with tool durations
const messages = timelineToMessages(entries, toolDurations);
// Extract tool calls from content blocks
const toolCalls = extractToolCalls(contentBlocks);
// Default chatMode derivation
const mode = defaultDeriveMode({ isExecuting: true, hasPendingConfirmation: false });
// → "streaming"
client.destroy();
FAQs
Client SDK for Agentick - multiplexed sessions over SSE
We found that @agentick/client demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 2 open source maintainers collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
pnpm 11.5 now recognizes npm staged publish approvals in release metadata, preventing those releases from being mistaken for lower-trust package publishes.

Security News
Federal audit finds NIST lacked a plan to clear the NVD backlog, wasted funds on duplicate work, and delayed use of CISA data.

Research
/Security News
A mini Shai-Hulud campaign compromised Red Hat Cloud Services npm packages to steal developer and CI/CD secrets during installation.