This page describes intended behaviour or structure. No implementation is claimed unless a section is explicitly marked Current implementation or Evidence.
Every tool call in the Factory, whether from an agent attempt, an IDE client or a partner agent, passes this service. The pipeline is the original design's §70 made exact: model → tool call → schema validation → agent permission → tenant policy → side-effect classification → approval if required → credential broker → sandbox → execute → result sanitization → audit → model. Tools carry a descriptor (identifier, version, schema, authorization, secret dependencies, timeout, retry, rate limits, side-effect and risk class, audit requirements, health) published as an asset (BC-04); the executor never lowers a declared class, the environment class may raise it (Production), and gated classes execute only with an approval bound to the exact request hash and tool version (D21).
flowchart LR
S["ToolAdapterService"]
AgentRuntimeService["AgentRuntimeService"] -->|grpc| S
StudioBff["StudioBff"] -->|sync-http| S
S -->|grpc| PolicyEngineService["PolicyEngineService"]
S -->|grpc| RunControlService["RunControlService"]
S -->|grpc| EnvironmentService["EnvironmentService"]
S -->|grpc| SecretBrokerService["SecretBrokerService"]
S -->|grpc| AgentPoolManager["AgentPoolManager"]
S -->|grpc| McpServerRegistryService["McpServerRegistryService"]
S -->|grpc| IntegrationService["IntegrationService"]
S -->|grpc| RepositoryIntelligenceService["RepositoryIntelligenceService"]
S -->|grpc| VectorMemoryService["VectorMemoryService"]
S -->|grpc| ArtifactService["ArtifactService"]
S -->|grpc| CostUsageService["CostUsageService"]
S -. "ToolDescriptorActivated" .-> E_ToolDescriptorActivated(("event"))
S -. "ToolDescriptorRetired" .-> E_ToolDescriptorRetired(("event"))
S -. "ToolInvoked" .-> E_ToolInvoked(("event"))
S -. "ToolInvocationDenied" .-> E_ToolInvocationDenied(("event"))
S -. "ToolEffectUncertain" .-> E_ToolEffectUncertain(("event"))
S -. "SandboxLeased" .-> E_SandboxLeased(("event"))
S -. "SandboxReleased" .-> E_SandboxReleased(("event"))
Hold "Alt" / "Option" to enable pan & zoom
Risk classes of the original design map onto the Factory's side-effect classes:
Original risk class
Side-effect class
Example
Outcome without approval
READ_ONLY
read
read_logs, search_symbols
executes
sandbox work
sandbox
apply_patch in an isolated workspace, dotnet test
executes
REVERSIBLE_WRITE
shared-write
create_git_branch, propose_change_set
approval required
external effect
external
http_call to a partner system
approval required
IRREVERSIBLE_WRITE, PRODUCTION
production
deploy_environment, delete_database
approval required; block-list may deny
SECURITY_SENSITIVE
production with policy flag
secret rotation, role grant
approval required, Platform admin policy
FINANCIAL
spend
send_payment
approval required above threshold, policy may prohibit
ToolDescriptor — Runtime read model of a Published tool asset — identifier, version, JSON schema, description, side-effect and risk class, authorization and secret requirements, timeout, retry, rate limits, audit requirements, health, kind and server binding. (catalog entry)
Field
Type
Required
Description
toolId
string
yes
version
string
yes
releaseId
string
yes
Published asset release (BC-04).
tenantId
string
yes
kind
enum:ToolKind
yes
schemaRef
string
yes
JSON schema of input and output (tool-invocation-v1 envelope).
sideEffectClass
string
yes
read
riskClass
enum:RiskClass
yes
authorization
json
yes
Scopes and roles required of the caller.
secretDependencies
list:string
yes
Connection or secret references brokered at call time.
timeoutSeconds
int
yes
retryPolicy
json
yes
rateLimits
json
yes
auditRequirements
json
yes
What the receipt must capture (arguments hash, outputs hash, command line…).
sandboxKind
enum:SandboxKind
yes
mcpServerId
string
no
healthy
bool
yes
active
bool
yes
Invariants:
A descriptor is usable only while its release is Published and the descriptor is healthy; deprecation and revocation deactivate it with the release's in-flight policy.
The side-effect class is declared by the tool owner at publication and validated against the policy of every agent that lists the tool (model rule D21); the executor never lowers it, the environment class may raise it.
Shell tools carry an allow-list and a block-list of command patterns; a command matching the block-list (terraform destroy, az group delete, kubectl delete namespace, DROP DATABASE, rm -rf …) is Denied or escalated to production class per policy.
ToolInvocation — One tool call from reception to receipt — scope, tool version, request hash, idempotency key, effective side-effect class, policy decision, approval binding, sandbox lease, execution, sanitized result reference, receipt and audit reference. (catalog entry)
Field
Type
Required
Description
invocationId
guid
yes
tenantId
string
yes
projectId
string
yes
environmentId
string
no
runId
guid
no
attemptId
guid
no
fencingToken
long
no
callerKind
string
yes
agent
toolId
string
yes
toolVersion
string
yes
requestHash
hash
yes
idempotencyKey
string
yes
declaredClass
string
yes
effectiveClass
string
yes
Declared class raised by the environment class (Production) or policy.
policyDecisionId
guid
no
approvalId
guid
no
state
enum:InvocationState
yes
sandboxLeaseId
guid
no
resultRef
string
no
Artifact reference of the sanitized result.
resultHash
hash
no
receiptRef
string
no
tool-invocation-v1 receipt artifact.
auditRef
string
no
failureClass
string
no
transient
startedAt
datetime
yes
endedAt
datetime
no
Invariants:
The pipeline order is fixed: schema validation → agent permission → tenant policy → side-effect classification → approval if required → credential broker → sandbox → execute → result sanitization → audit; no stage may be skipped.
Gated classes (shared-write, external, production, publication, spend above threshold) execute only with an approval bound to this invocation's request hash and the exact tool version; a different hash is a new approval (D21).
The same idempotency key within scope returns the existing receipt; a call is never executed twice for one key.
A call whose effect cannot be confirmed (lost sandbox, timeout after side effect, host loss) ends Uncertain, is reported to the runtime as such and is never retried automatically.
Results are sanitized before they reach a model (secrets stripped, size bounded, provenance tagged as tool-result, instructions in results treated as data).
SandboxLease (entity, in ToolInvocation) — A sandbox and workspace leased from Execution Capacity for one invocation (or one attempt when the workspace is shared across calls).
Field
Type
Required
Description
leaseId
guid
yes
kind
enum:SandboxKind
yes
poolId
string
yes
workspaceRef
string
no
Isolated workspace (git worktree or equivalent) per run (original design §34).
An operator confirms or denies that an Uncertain invocation's effect happened, from the receipt and external evidence.
gRPC service
Method
Streaming
Visibility
Side effects
Summary
ToolExecutor
Invoke
server
internal
production
Execute a tool call for an attempt (fencing token), IDE client or partner caller through the full pipeline; streams progress for long tools and ends with the receipt (tool-invocation-v1).
ToolExecutor
Validate
none
internal
read
Schema validation and pipeline preview without execution.
ToolExecutor
Interrupt
none
internal
shared-write
Stop an executing invocation (cancellation); the effect is settled as observed, cancelled or uncertain.
Finds Executing invocations whose grain is inactive or whose sandbox lease expired and settles them as Uncertain (or Failed when no effect was possible), notifying the runtime.
SandboxReaper
schedule */2 * * * *
SandboxReleased
exponential
leaseId
Releases sandboxes and workspaces whose invocation ended or whose lease expired; reports to Execution Capacity.
DescriptorHealthProbe
schedule */5 * * * *
—
fixed
toolId + version + probeWindow
Probes native and MCP tools (handshake, schema fetch) and marks descriptors healthy or unhealthy.
sequenceDiagram
participant A as AgentRuntimeService
participant X as ToolAdapterService
participant P as PolicyEngineService
participant RC as RunControlService
participant S as SecretBrokerService
participant C as AgentPoolManager (sandboxes)
participant T as Tool (native, MCP, shell)
A->>X: Invoke (tool, args, fencing token, idempotency key)
X->>X: schema validation against the descriptor
X->>P: agent permission, tenant policy, class
alt gated class
X->>RC: validate approval bound to request hash
end
X->>S: short-lived credential
X->>C: sandbox and workspace lease
X->>T: execute with limits and egress allow-list
T-->>X: result
X->>X: sanitize, receipt, audit
X-->>A: sanitized result and receipt
factory.tools.read (Read descriptors, dry-run.); factory.tools.invoke (Invoke tools (attempts, IDE clients, partner callers within their scope).); factory.tools.operate (Confirm uncertain effects (Operator).); factory.runs.read (Receipts of a run.)
Results are data: secrets are stripped, size is bounded and the provenance tag tool-result tells context assembly and the model that any instruction inside is content, not a command. Shell tools run only allow-listed commands as sandbox class; block-listed commands (terraform destroy, az group delete, kubectl delete namespace, DROP DATABASE, rm -rf) are denied or escalated to production class, and every command line is on the receipt.
The agents framework offers explicit tools and file skills (script runner disabled) and the MCP library offers governance options; the agent host's MCP sample bypasses the lifecycle entirely. No descriptor registry, pipeline, sandbox lease, receipt or uncertain-effect handling exists. See tool policies and tool registry.
Computer-use and browser agents at scale; tool-call reliability scoring per tool and agent feeding the evaluation gates; per-tenant tool allow-lists in the Studio; dry-run of whole workflows against descriptors.