defineCapability()
Named typed requirement tools declare and createPai binds.
A capability is a declaration. The common one is sandbox: tools say capabilities: { sandbox }, and createPai binds sandboxCapability().
import { defineCapability } from "@pai/core";
export const sandbox = defineCapability<Sandbox>()({
id: "sandbox",
description: "Command and filesystem execution environment.",
});Apps almost never call this. They use @pai/sandbox.
Import
import { defineCapability } from "@pai/core";Signature
function defineCapability<TFacade>(): <const TId extends string>(input: {
id: TId;
description?: string;
}) => Capability<TFacade, TId>;Parameters
The inner factory:
input: { id: TId; description?: string }
id: string
Binding key in createPai / createAgentRuntime.
description?: string
Returns
A Capability<TFacade, TId>.
Token tools declare; bind a facade at createPai.
CapabilityScope
A binding's scope decides which operations share one instance. Core derives an opaque instance key from it; the binding maps keys to resources. Capability packages such as sandboxCapability() take it as an option, and createCapabilityBinding({ scope }) defaults to "thread".
type CapabilityScope =
| "thread"
| "rootThread"
| "user"
| "scope"
| "global"
| ((input: CapabilityScopeInput) => string);| Scope | One instance per | Disposed on thread delete |
|---|---|---|
"thread" | thread; a subagent's child thread gets its own | when that thread is deleted |
"rootThread" | top-level thread, shared by every thread delegated from it at any depth | when the top-level thread is deleted; deleting a delegated thread does not |
"user" | scopeKey + userKey | never |
"scope" | scopeKey | never |
"global" | provider keyspace | never |
PAI finds a thread's root by following its stored parentThreadId. The walk only runs for "rootThread" and custom scopes.
CapabilityScopeInput
A custom scope function receives:
threadId: ThreadId
Thread the operation runs in. For a subagent, its child thread.
rootThreadId: ThreadId
Top-level thread reached by following parentThreadId. Equals threadId for a top-level thread.
scopeKey: ScopeKey
userKey?: UserKey
identity: unknown
The app identity; narrow it yourself.
// One instance per user per top-level conversation, shared with subagents.
scope: ({ scopeKey, userKey, rootThreadId }) =>
JSON.stringify([scopeKey, userKey, rootThreadId]),