toolplane-typescript-client
v0.1.0
Published
TypeScript gRPC client for the Toolplane control plane
Maintainers
Readme
Toolplane TypeScript Client
This package is the maintained JavaScript-family SDK for Toolplane's durable remote tool-execution control plane. Use it when TypeScript or Node code needs the maintained gRPC control-plane surface plus an explicit provider runtime over the canonical contract in server/proto/service.proto.
Decision Rule
Use Toolplane when one remote tool may outlive the caller, needs inspection or bounded replay after disconnect, needs explicit provider ownership or drain behavior, or is queue-backed enough that request lifecycle control matters. If the work is quick, in-process, same-lifecycle, and not operationally sensitive, direct tool calling is simpler.
A concrete first-offload workload is one sandboxed code-execution worker. TypeScript is the maintained JavaScript-family path for that provider or consumer lifecycle on gRPC; the repository-internal HTTP adapters remain conformance-only.
When To Start Here
- Your JavaScript-family code needs the maintained gRPC control-plane surface plus an explicit
ProviderRuntime. - You want a maintained provider or consumer path in TypeScript without treating the internal HTTP conformance adapters as public SDK surface.
- You want the same provider, request, recovery, and drain model as the broader platform story, but on the TypeScript-maintained path.
Support Status
- Supported secondary SDK and the maintained JavaScript-family path.
- The maintained control-plane story is the gRPC surface for session, tool, machine, request, and task lifecycle helpers.
- This SDK now ships a maintained explicit
ProviderRuntimefor the gRPC provider lifecycle: session create or attach, machine registration, request claim, heartbeat, chunk append, result submission, and drain-aware shutdown. - Repository-internal HTTP adapters still exist under
tests/conformance/so the shared fixture runner can exercise the maintained HTTP gateway. They are not part of the public SDK surface.
Integration Seam Role
This package spans two layers of the maintained agent-runtime seam:
- Layer 2: the maintained JavaScript-family gRPC projection for session, tool, machine, request, and task lifecycle helpers.
- Layer 3: the explicit
ProviderRuntimepackaging for session attach or create, machine registration, tool registration, polling, claim, heartbeat, chunk append, result submission, and drain.
Build foreign-protocol adapters on top of these surfaces instead of reimplementing claim, heartbeat, or drain logic in the adapter itself. Retained-window recovery is available through the public resumeStream() and getRequestChunksWindow() wrappers; capabilities outside the mapped RPC set stay server-side. For the full seam model and current gap caveats, see server/docs/agent-runtime-integration-seam.md.
Features
- Live grpc-js wrappers for the maintained public helpers.
- Explicit
ProviderRuntimelifecycle management for machine-backed providers. - Public
executeTool()plus numeric convenience helpersadd(),subtract(),multiply(), anddivide(). - Tool discovery helpers
listTools(),getToolById(),getToolByName(), anddeleteTool(). - Session, API-key, machine, request, and task lifecycle helpers, including provider-owned request claim and result submission.
- Promise-based connection management with
connect(),disconnect(),isConnected(), andgetConnectionStatus(). - Shared-fixture conformance coverage in
tests/conformance/.
Installation
npm install
npm run buildCanonical Flow
The canonical end-to-end path for Toolplane is to offload one painful remote tool first: register a provider, create or attach a session, execute a request, stream or recover results, and drain the machine. The TypeScript SDK ships that provider loop directly through the explicit ProviderRuntime over the maintained gRPC path.
Quick Start
import { ToolplaneClient } from 'toolplane-typescript-client';
const client = ToolplaneClient.createGRPCClient(
'localhost',
9001,
'grpc-session',
'grpc-user',
process.env.TOOLPLANE_API_KEY || 'toolplane-conformance-fixture-key',
{
enabled: true,
caCertPath: '../../server/deploy/reference/certs/ca.crt',
serverName: 'localhost',
},
);
await client.connect();
const session = await client.createSession(
'My Session',
'Session created from the TypeScript client',
'examples',
);
const machine = await client.registerMachine('', '1.0.0', [
{
sessionId: session.id,
name: 'session_status',
description: 'Report session context for a connected operator or automation client',
schema: JSON.stringify({
type: 'object',
properties: {
requester: { type: 'string' },
},
required: ['requester'],
}),
config: { version: '1.0' },
tags: ['session', 'status'],
},
]);
const tools = await client.listTools();
console.log(`Session ${session.id} has ${tools.length} tools on machine ${machine.id}`);
await client.disconnect();Tool registration is machine-aware, so register a machine first or embed tool definitions in registerMachine(...).
Explicit Provider Runtime
import { ToolplaneClient } from 'toolplane-typescript-client';
const client = ToolplaneClient.createGRPCClient(
'localhost',
9001,
'',
'provider-user',
process.env.TOOLPLANE_API_KEY || 'toolplane-conformance-fixture-key',
{
enabled: true,
caCertPath: '../../server/deploy/reference/certs/ca.crt',
serverName: 'localhost',
},
);
await client.connect();
const provider = client.providerRuntime({
pollIntervalMs: 250,
heartbeatIntervalMs: 30_000,
});
const session = await provider.createSession({
name: 'TypeScript Provider Session',
description: 'Maintained provider runtime example',
namespace: 'examples',
});
await provider.tool(
{
sessionId: session.id,
name: 'echo_tool',
description: 'Echo the caller message',
schema: {
type: 'object',
properties: {
message: { type: 'string' },
},
required: ['message'],
},
},
async (input) => ({ echo: input.message }),
);
await provider.startInBackground();See src/examples/provider_runtime_example.ts for a maintained end-to-end provider loop with graceful drain.
Public API Snapshot
Lifecycle
connect(): Promise<void>
disconnect(): Promise<void>
isConnected(): boolean
getConnectionStatus(): ConnectionStatus
providerRuntime(options?: ProviderRuntimeOptions): ProviderRuntimeExecution
executeTool(toolName: string, params?: Record<string, unknown>): Promise<Request>
add(a: number, b: number): Promise<number>
subtract(a: number, b: number): Promise<number>
multiply(a: number, b: number): Promise<number>
divide(a: number, b: number): Promise<number>
ping(): Promise<string>These helpers use the live request lifecycle on the Go server. They require a registered machine-backed provider to claim requests and submit results.
Lifecycle Wrappers
The client exposes public wrappers for:
- Sessions:
createSession,getSession,listSessions,updateSession - API keys:
createApiKey,listApiKeys,revokeApiKey - Tools:
registerTool,listTools,getToolById,getToolByName,deleteTool - Machines:
registerMachine,listMachines,getMachine,updateMachinePing,unregisterMachine,drainMachine - Requests:
createRequest,getRequest,listRequests,updateRequest,claimRequest,appendRequestChunks,submitRequestResult,renewRequestLease,cancelRequest,resumeStream,getRequestChunksWindow - Tasks:
createTask,getTask,listTasks,cancelTask
Provider Runtime
The explicit ProviderRuntime exposes:
- Session ownership:
createSession(),attachSession(),managedSessionIds() - Tool registration:
registerTool(),tool() - Runtime control:
pollOnce(),startInBackground(),runForever(),stop(),drain(),close()
For the reference deployment, set TOOLPLANE_SERVER_PORT=9001, TOOLPLANE_USE_TLS=true, TOOLPLANE_TLS_CA_CERT_PATH=/path/to/ca.crt, and TOOLPLANE_TLS_SERVER_NAME=localhost before running the maintained examples.
ToolplaneClient
Public methods parsed from src/core/toolplane_client.ts:
| Method | Returns |
| --- | --- |
| async connect() | Promise<void> |
| async disconnect() | Promise<void> |
| isConnected() | boolean |
| getConnectionStatus() | ConnectionStatus |
| async executeTool(toolName: string, params: Record<string, unknown> = {}, options: { idempotencyKey?: string } = {}) | Promise<RequestModel> |
| async ping() | Promise<string> |
| async registerTool(name: string, description: string, schema: string, config: Record<string, string> = {}, tags: string[] = [], options: RegisterToolOptions = {}) | Promise<Tool> |
| async listTools() | Promise<Tool[]> |
| async getToolById(toolId: string) | Promise<Tool> |
| async getToolByName(toolName: string) | Promise<Tool> |
| async deleteTool(toolId: string) | Promise<boolean> |
| async createSession(name: string, description: string, namespace: string = 'default', requestedSessionId: string = '') | Promise<Session> |
| async getSession() | Promise<Session> |
| async listSessions() | Promise<Session[]> |
| async updateSession(name: string = '', description: string = '', namespace: string = '') | Promise<Session> |
| async createApiKey(name: string, capabilities: string[]) | Promise<ApiKey> |
| async listApiKeys() | Promise<ApiKey[]> |
| async revokeApiKey(keyId: string) | Promise<boolean> |
| async registerMachine(machineId: string = '', sdkVersion: string = '1.0.0', tools: RegisterToolRequest[] = []) | Promise<Machine> |
| async listMachines() | Promise<Machine[]> |
| async getMachine(machineId: string) | Promise<Machine> |
| async updateMachinePing(machineId: string = '') | Promise<Machine> |
| async unregisterMachine(machineId: string = '') | Promise<boolean> |
| async drainMachine(machineId: string = '') | Promise<boolean> |
| async createTask(toolName: string, input: string, idempotencyKey: string = '') | Promise<Task> |
| async getTask(taskId: string) | Promise<Task> |
| async listTasks() | Promise<Task[]> |
| async cancelTask(taskId: string) | Promise<boolean> |
| async createRequest(toolName: string, input: string, idempotencyKey: string = '') | Promise<RequestModel> |
| async getRequest(requestId: string) | Promise<RequestModel> |
| async getRequestChunksWindow(requestId: string) | Promise<{ chunks: unknown[]; startSeq: number; nextSeq: number; }> |
| async listRequests(options: { status?: string; toolName?: string; limit?: number; /** Opaque cursor from a previous page; omit to start from the first page. */ pageToken?: string; } = {}) | Promise<RequestModel[]> |
| async updateRequest(requestId: string, update: RequestUpdate) | Promise<RequestModel> |
| async claimRequest(requestId: string, machineId: string = '') | Promise<RequestModel> |
| async claimNextRequest(toolNames: string[] = []) | Promise<{ claimed: boolean; request: RequestModel \| null }> |
| async appendRequestChunks(requestId: string, chunks: unknown[], resultType: string = 'streaming', lease?: LeaseContext) | Promise<boolean> |
| async submitRequestResult(requestId: string, result: unknown, resultType: string = 'resolution', meta: Record<string, string> = {}, lease?: LeaseContext) | Promise<boolean> |
| async renewRequestLease(requestId: string, machineId: string, leaseEpoch: number) | Promise<RequestModel> |
| async cancelRequest(requestId: string) | Promise<boolean> |
| providerRuntime(options: ProviderRuntimeOptions = {}) | ProviderRuntime |
| forkSession(sessionId: string) | ToolplaneClient |
| static createGRPCClient(serverHost: string, serverPort: number, sessionId: string, userId: string, apiKey?: string, tls?: GRPCTLSConfig) | ToolplaneClient |
| async resumeStream(requestId: string, lastSeq: number = 0, onChunk?: (chunk: ExecuteToolChunkModel) => void) | Promise<ExecuteToolChunkModel[]> |
ProviderRuntime
Public methods parsed from src/provider_runtime.ts:
| Method | Returns |
| --- | --- |
| get running() | boolean |
| managedSessionIds() | string[] |
| async attachSession(sessionId: string, options: ProviderSessionAttachOptions = {}) | Promise<Session> |
| async createSession(options: ProviderSessionCreateOptions) | Promise<Session> |
| async registerTool(definition: ProviderToolRegistration) | Promise<ProviderToolHandler> |
| tool(definition: Omit<ProviderToolRegistration, 'handler'>, handler: ProviderToolHandler) | Promise<ProviderToolHandler> |
| tool(definition: Omit<ProviderToolRegistration, 'handler'>) | (handler: ProviderToolHandler) => Promise<ProviderToolHandler> |
| tool(definition: Omit<ProviderToolRegistration, 'handler'>, handler?: ProviderToolHandler) | Promise<ProviderToolHandler> \| ((handler: ProviderToolHandler) => Promise<ProviderToolHandler>) |
| async pollOnce() | Promise<void> |
| async startInBackground(sessionIds?: Iterable<string>) | Promise<ProviderRuntime> |
| async runForever(sessionIds?: Iterable<string>) | Promise<void> |
| async stop() | Promise<void> |
| async drain() | Promise<void> |
| async close() | Promise<void> |
Error Handling
The client exposes a small public error hierarchy:
import {
ToolplaneError,
ConnectionError,
TimeoutError,
ProtocolError,
} from 'toolplane-typescript-client';
try {
await client.listTools();
} catch (error) {
if (error instanceof ConnectionError) {
console.log(`Connection error: ${error.message}`);
} else if (error instanceof ToolplaneError) {
console.log(`Toolplane error: ${error.message}`);
}
}Scripts
npm start
npm run dev
npm run example
npm run provider
npm run advanced
npm test
npm run test:conformance
npm run test:allConformance
- The shared fixture runner lives under
tests/conformance/and loads repository-wide cases from../../conformance/cases/. - The public SDK remains gRPC-only.
- The repository-internal conformance runner uses both gRPC and HTTP adapters so fixture behavior is validated across the maintained server transports.
- The gRPC provider-runtime cases are now backed by the public
ProviderRuntimesurface rather than a test-only request-processing loop.
Compatibility
- Node.js: 18+
- TypeScript: 5.0+
- Maintained server path: the Go server gRPC control-plane surface
- Public protocol: gRPC with Protocol Buffers
