wear-sdk-node
v6.0.0-phase6
Published
Node.js SDK for WEAR Gateway
Readme
wear-sdk-node
Node.js SDK for the WEAR (Warehouse Exchange Agent Resources) Gateway.
Installation
npm install [email protected]Quick Start
import { WearClient } from 'wear-sdk-node';
const client = new WearClient({
baseURL: process.env.WEAR_BASE,
});
// Obtain JWT token (see Authentication section below)
const jwt = process.env.WEAR_TOKEN;
const agentId = 'hello';
// Start a run
const { run_id } = await client.startRun(agentId, jwt);
// Log access
await client.logAccess(run_id, {
run_id,
resource_type: 'database',
operation: 'read',
purpose: 'analysis',
allowed: true,
}, jwt);
// Log cost
await client.logCost(run_id, {
run_id,
tokens_output: 100,
model_cost_cents: 5,
}, jwt);
// Finish run
await client.finishRun(run_id, 'success', jwt);
console.log('Run completed:', run_id);Authentication
⚠️ IMPORTANT: Partners and external agents should NOT manage private keys.
Recommended: Token Endpoint (Partners)
Partners should obtain JWT tokens from the WEAR Gateway's token endpoint:
// Request a token from the gateway
const response = await fetch(`${WEAR_BASE}/v1/agents/token`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ agent_id: 'your-agent-id' }),
});
const { token } = await response.json();
// Use the token with the SDK
const client = new WearClient({ baseURL: WEAR_BASE });
await client.startRun('your-agent-id', token);Alternative: Delegated Issuer Service
For production integrations, use a dedicated token issuer service with proper access controls.
Internal Use Only: Private Keys
Private keys should only be used by:
- WEAR CI workflows (GitHub Secrets)
- Internal security workflows
- Emergency operations
See JWKS-SETUP.md for key management best practices.
Usage
Complete Run Lifecycle Example
import { WearClient, WearError } from 'wear-sdk-node';
const client = new WearClient({
baseURL: 'https://wear-gateway-staging-xxx.run.app',
timeoutMs: 10000, // optional, default 10s
});
const agentId = 'my-agent-id';
let runId: string;
try {
// 1. Start a run (requires JWT from /v1/agents/token)
const startResult = await client.startRun(agentId, jwt);
runId = startResult.run_id;
console.log(`Run started: ${runId} at ${startResult.started_at}`);
// 2. Log cost information during the run
await client.logCost(runId, {
run_id: runId,
tokens_prompt: 150,
tokens_output: 75,
model_cost_cents: 12,
tool_cost_cents: 3,
infra_cost_cents: 1,
}, jwt);
console.log('Cost logged');
// 3. Log access attempts
await client.logAccess(runId, {
run_id: runId,
resource_type: 'database',
operation: 'read',
purpose: 'analysis',
allowed: true,
resource_id: 'customers_table',
fields: ['email', 'name'],
pii_score: 0.8,
}, jwt);
console.log('Access logged');
// 4. Finish the run
await client.finishRun(runId, 'success', jwt, {
model_used: 'gpt-4',
});
console.log('Run finished successfully');
} catch (error) {
if (error instanceof WearError) {
console.error(`Error ${error.statusCode}: ${error.message}`);
// Check for specific denial types
if (error.isPolicyDenied()) {
console.error(`Policy denied: ${error.getDenialReason()}`);
console.error(`Rule ID: ${error.errorResponse?.rule_id}`);
} else if (error.isBudgetDenied()) {
console.error(`Budget exceeded: ${error.getDenialReason()}`);
}
// Best-effort finish on error
if (runId) {
await client.finishRun(runId, 'failed', jwt, {
failure_class: 'policy_denied',
});
}
}
}API
WearClient
Constructor
new WearClient(options: WearClientOptions)Options:
baseURL(string, required): Base URL of the WEAR GatewaytimeoutMs(number, optional): Request timeout in milliseconds (default: 10000)
Methods
startRun(agentId: string, jwt: string): Promise<StartRunResponse>
Starts a new agent run.
Parameters:
agentId: Agent identifierjwt: JWT token from/v1/agents/token
Returns: { run_id: string, started_at: string, correlation_id?: string }
Headers sent:
Authorization: Bearer <jwt>X-WEAR-Agent-ID: <agentId>
Returns:
{
run_id: string;
started_at: string;
correlation_id?: string;
}Throws: WearError on policy denial, budget exceeded, or other errors.
logCost(runId: string, body: LogCostRequest, jwt: string): Promise<LogCostResponse>
Log cost information for a run. Idempotent - safe to call multiple times with the same data.
Parameters:
runId: Run identifier (required, throws if missing)body: Cost detailsrun_id: Run identifiertokens_prompt?: Number of prompt tokenstokens_output?: Number of output tokensmodel_cost_cents?: Model cost in centstool_cost_cents?: Tool cost in centsinfra_cost_cents?: Infrastructure cost in cents
jwt: JWT token
Returns: { ok: boolean, correlation_id?: string }
Headers sent:
Authorization: Bearer <jwt>X-WEAR-Agent-ID: <extracted from JWT>X-WEAR-Run-ID: <runId>
Retry behavior: Automatic retry on 5xx errors (max 3 attempts, exponential backoff). No retry on 4xx errors.
Throws: WearError if runId is missing or on non-retryable errors.
logAccess(runId: string, body: LogAccessRequest, jwt: string): Promise<LogAccessResponse>
Log an access attempt for a run. Logs both allowed and denied access attempts.
Parameters:
runId: Run identifier (required, throws if missing)body: Access detailsrun_id: Run identifierresource_type: Type of resource accessedoperation: Operation performed (e.g., 'read', 'write', 'delete')purpose: Purpose of the accessallowed: Whether access was allowedresource_id?: Specific resource identifierfields?: Fields accessedpii_score?: PII sensitivity score (0-1)
jwt: JWT token
Returns: { ok: boolean, correlation_id?: string }
Headers sent:
Authorization: Bearer <jwt>X-WEAR-Agent-ID: <extracted from JWT>X-WEAR-Run-ID: <runId>
Retry behavior: Automatic retry on 5xx errors (max 3 attempts, exponential backoff). No retry on 4xx errors.
Throws: WearError if runId is missing or on non-retryable errors.
finishRun(runId: string, status: 'success' | 'failed' | 'blocked', jwt: string, extras?: object): Promise<FinishRunResponse>
Finish a run with a final status. Best-effort: On repeated 5xx errors, logs a warning and returns { ok: false } instead of throwing, so agents don't crash after completing work.
Parameters:
runId: Run identifier (required, throws if missing)status: Final run status ('success', 'failed', or 'blocked')jwt: JWT tokenextras?: Optional additional fieldsfailure_class?: Classification of failuremodel_used?: Model identifier used
Returns: { ok: boolean, correlation_id?: string }
Headers sent:
Authorization: Bearer <jwt>X-WEAR-Agent-ID: <extracted from JWT>X-WEAR-Run-ID: <runId>
Retry behavior: Automatic retry on 5xx errors (max 3 attempts, exponential backoff). On persistent 5xx after all retries, logs warning and returns { ok: false } instead of throwing. Still throws on 4xx errors.
Throws: WearError if runId is missing or on 4xx errors.
WearError
Custom error class with additional context.
Properties:
statusCode(number): HTTP status codeerrorResponse(WearErrorResponse): Parsed error response from Gateway
Methods:
isPolicyDenied(): Returns true if this is a policy denial (403 with code)isBudgetDenied(): Returns true if this is a budget denialgetDenialReason(): Returns the denial reason if available
Testing
pnpm testLicense
MIT
