Skip to content

ToolAdapterService

Target

This page describes intended behaviour or structure. No implementation is claimed unless a section is explicitly marked Current implementation or Evidence.

Bounded context BC-08 Tool Execution
Platform / plane Tools & MCP Platform / Capability & Tools
Deployment granularity module of host · host ToolExecutorHost
Status target · ConnectSoft.Factory.Tools.Execution
Built from connectsoft-microservice · libraries: connectsoft-extensions-model-context-protocol, connectsoft-extensions-saas-abstractions, connectsoft-extensions-messaging-model, connectsoft-extensions-messaging-model-orleans, connectsoft-extensions-persistence-model-nhibernate, connectsoft-extensions-audit-net, connectsoft-extensions-rate-limiting
Decisions ADR-0014, ADR-0015, ADR-0021, ADR-0022
Traceability FR-05 FR-06 FR-10 FUX-05 FUX-07 NFR-02 NFR-04 NFR-05 NFR-10 XL-03 XL-06 XL-10 XL-16

Purpose and responsibilities

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).

Context and boundaries

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

Domain model

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.

Events: ToolDescriptorActivated, ToolDescriptorRetired · Tables: ToolDescriptors · Repository: ToolDescriptorRepository

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).
stateDiagram-v2
    Received --> Validated : SchemaValid
    Received --> Denied : SchemaInvalidOrToolInactive
    Validated --> Authorized : PermissionAndPolicyPassed
    Validated --> Denied : PolicyDenied
    Authorized --> AwaitingApproval : GatedClassWithoutApproval
    AwaitingApproval --> Brokered : ApprovalBound
    AwaitingApproval --> Denied : ApprovalRejectedOrExpired
    Authorized --> Brokered : CredentialsAndSandboxLeased
    Brokered --> Executing : Started
    Executing --> Observed : ResultObserved
    Executing --> Failed : ErrorBeforeEffect
    Executing --> Uncertain : EffectUnconfirmed
    Executing --> Cancelled : InterruptedBeforeEffect
Hold "Alt" / "Option" to enable pan & zoom

Events: ToolInvoked, ToolInvocationDenied, ToolEffectUncertain, SandboxLeased, SandboxReleased · Tables: ToolInvocations, SandboxLeases · Repository: ToolInvocationRepository

erDiagram
    ToolDescriptor {
        string toolId PK
        string version
        string releaseId
        string tenantId
        enum_ToolKind kind
        string schemaRef
        string sideEffectClass
        enum_RiskClass riskClass
        json authorization
        list_string secretDependencies
        int timeoutSeconds
        json retryPolicy
        json rateLimits
        json auditRequirements
        enum_SandboxKind sandboxKind
        string mcpServerId
        bool healthy
        bool active
    }
    ToolInvocation {
        guid invocationId PK
        string tenantId
        string projectId
        string environmentId
        guid runId
        guid attemptId
        long fencingToken
        string callerKind
        string toolId
        string toolVersion
        hash requestHash
        string idempotencyKey
        string declaredClass
        string effectiveClass
        guid policyDecisionId
        guid approvalId
        enum_InvocationState state
        guid sandboxLeaseId
        string resultRef
        hash resultHash
        string receiptRef
        string auditRef
        string failureClass
        datetime startedAt
        datetime endedAt
    }
    SandboxLease {
        guid leaseId

        enum_SandboxKind kind

        string poolId

        string workspaceRef

        json limits

        datetime credentialExpiry

        datetime leasedAt

        datetime releasedAt

    }
    ToolInvocation ||--o{ SandboxLease : contains
Hold "Alt" / "Option" to enable pan & zoom
stateDiagram-v2
    [*] --> Received
    Received --> Validated: schema valid
    Received --> Denied: schema invalid or tool inactive
    Validated --> Authorized: permission and policy passed
    Validated --> Denied: policy denied
    Authorized --> AwaitingApproval: gated class without approval
    AwaitingApproval --> Brokered: approval bound to request hash
    AwaitingApproval --> Denied: rejected or expired
    Authorized --> Brokered: credentials and sandbox leased
    Brokered --> Executing
    Executing --> Observed: result observed
    Executing --> Failed: error before effect
    Executing --> Uncertain: effect unconfirmed
    Executing --> Cancelled: interrupted before effect
    Observed --> [*]
    Failed --> [*]
    Uncertain --> [*]
    Denied --> [*]
    Cancelled --> [*]
Hold "Alt" / "Option" to enable pan & zoom

Entities and value objects

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).
limits json yes cpu, memory, gpu, timeout, egress allow-list, read-only mounts
credentialExpiry datetime yes
leasedAt datetime yes
releasedAt datetime no

Data model and storage

Store Role Engine / profile Tables
Tool execution store primary azure-sql / nhibernate-sqlserver ToolDescriptors, ToolInvocations, SandboxLeases
Cache and coordination cache redis / azure-cache —
Table Owner Columns Indexes
dbo.ToolDescriptors ToolDescriptor 18 1
dbo.ToolInvocations ToolInvocation 25 3
dbo.SandboxLeases SandboxLease 10 1

Full DDL: appendix.

APIs

Method Path Operation Scope Side effects Idempotency Gateway Summary
GET /factory/tools ListTools factory.tools.read read natural GW-03 Active tool descriptors visible to the caller with side-effect and risk class, kind, server and health.
GET /factory/tools/{toolId} GetTool factory.tools.read read natural GW-03 A descriptor with schema, authorization, secret dependencies, limits and audit requirements.
POST /factory/tools/{toolId}/dry-run DryRunTool factory.tools.read sandbox natural GW-03 Validate arguments and show the pipeline outcome (class, policy, approval needed, sandbox kind) without executing.
GET /factory/runs/{runId}/tool-receipts ListRunToolReceipts factory.runs.read read natural GW-03 Tool receipts of a run: tool, version, effective class, decision, approval, outcome, hashes.
GET /factory/tool-invocations/{invocationId} GetToolInvocation factory.runs.read read natural GW-03 One invocation with its pipeline stages, sandbox lease and receipt.
POST /factory/tool-invocations/{invocationId}/confirm-effect ConfirmToolEffect factory.tools.operate shared-write natural GW-03 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.

Example receipt (tool-invocation-v1):

{
  "invocationId": "3f0e…", "toolId": "propose-change-set", "toolVersion": "1.2.0",
  "declaredClass": "shared-write", "effectiveClass": "shared-write",
  "policyDecisionId": "7a…", "approvalId": "c1…", "requestHash": "sha256:…",
  "state": "Observed", "resultHash": "sha256:…", "sandbox": { "kind": "Container", "poolId": "default" },
  "startedAt": "…", "endedAt": "…", "auditRef": "audit://…"
}

Messages

Event Topic Scope / v Aggregate Consumers Summary
ToolDescriptorActivated tool-execution.descriptors.v1.tool-descriptor-activated integration / 1 ToolDescriptor StudioBff, DashboardService, AuditService A Published tool version is callable.
ToolDescriptorRetired tool-execution.descriptors.v1.tool-descriptor-retired integration / 1 ToolDescriptor StudioBff, AuditService A tool version is no longer callable.
ToolInvoked tool-execution.invocations.v1.tool-invoked integration / 1 ToolInvocation CostUsageService, AuditService, DashboardService, QualityScoreService, AgentTelemetryService A receipt was written (observed, failed or cancelled).
ToolInvocationDenied tool-execution.invocations.v1.tool-invocation-denied integration / 1 ToolInvocation AuditService, DashboardService, StudioBff Denied by schema, permission, policy, block-list or approval outcome.
ToolEffectUncertain tool-execution.invocations.v1.tool-effect-uncertain integration / 1 ToolInvocation AlertRuleService, AgentRuntimeService, StudioBff, StudioNotificationService, AuditService, DashboardService An effect may have happened and could not be confirmed; an operator must confirm before any retry.
SandboxLeased tool-execution.sandboxes.v1.sandbox-leased integration / 1 ToolInvocation DashboardService A sandbox and workspace were leased for an invocation.
SandboxReleased tool-execution.sandboxes.v1.sandbox-released integration / 1 ToolInvocation ExecutionCapacityService, SecretBrokerService, DashboardService A sandbox was released or reaped.

ToolDescriptorActivated payload:

Field Type Required Description
toolId string yes
version string yes
tenantId string yes
sideEffectClass string yes
kind enum:ToolKind yes

ToolDescriptorRetired payload:

Field Type Required Description
toolId string yes
version string yes
tenantId string yes
reason string yes

ToolInvoked payload:

Field Type Required Description
invocationId guid yes
tenantId string yes
projectId string yes
runId guid no
attemptId guid no
toolId string yes
toolVersion string yes
effectiveClass string yes
state enum:InvocationState yes
policyDecisionId guid no
approvalId guid no
requestHash hash yes
resultHash hash no

ToolInvocationDenied payload:

Field Type Required Description
invocationId guid yes
tenantId string yes
toolId string yes
reason string yes
stage string yes

ToolEffectUncertain payload:

Field Type Required Description
invocationId guid yes
tenantId string yes
runId guid no
attemptId guid no
toolId string yes
effectiveClass string yes

SandboxLeased payload:

Field Type Required Description
leaseId guid yes
invocationId guid yes
tenantId string yes
kind enum:SandboxKind yes
poolId string yes

SandboxReleased payload:

Field Type Required Description
leaseId guid yes
tenantId string yes
reason string yes
Command Handled by Result events Summary
Invoke ToolInvocation ToolInvoked, ToolInvocationDenied, ToolEffectUncertain
Interrupt ToolInvocation ToolInvoked, ToolEffectUncertain
ConfirmToolEffect ToolInvocation ToolInvoked
Event Producer Handler Purpose
AssetReleasePublished AgentRegistryService ActivateDescriptors Project Published tool assets into active descriptors.
AssetReleaseDeprecated AgentRegistryService RetireDescriptors Retire descriptors per in-flight policy.
AssetReleaseRevoked AgentRegistryService RetireDescriptors Retire revoked descriptors immediately.
EnvironmentStateChanged EnvironmentService ApplyFreeze Refuse shared-write and production calls targeting a Frozen environment.
McpServerStateChanged McpServerRegistryService UpdateServerHealth Mark descriptors of a degraded or retired server unhealthy.

Workers and jobs

Worker Trigger Output events Retry Idempotency key Summary
UncertainEffectReconciler schedule */1 * * * * ToolEffectUncertain, ToolInvoked fixed invocationId + state 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.

Actors and grains

Grain Key State Reminders Reentrant Summary
ToolInvocationGrain guid = invocationId state, fencingToken, sandboxLeaseId timeout, credential-expiry no Serialises the pipeline of one invocation, holds the sandbox lease and the fencing token, streams progress and enforces the timeout reminder.

Sagas and long-running flows

None modelled

No sagas are modelled for this item yet.

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
Hold "Alt" / "Option" to enable pan & zoom

Options and configuration

Section Key Type Default Reloadable Secret Summary
Tools:Execution DefaultTimeoutSeconds int 300 yes no Timeout when the descriptor sets none.
Tools:Execution MaxResultBytes int 1048576 yes no Result size bound before sanitization truncates with a marker.
Tools:Shell AllowList string[] [dotnet restore, dotnet build, dotnet test, git diff, git status, npm test] yes no Low-risk commands that run as sandbox class (original design §38).
Tools:Shell BlockList string[] [terraform destroy, az group delete, kubectl delete namespace, DROP DATABASE, rm -rf] yes no Commands denied or escalated to production class.
Tools:Sandbox DefaultEgressAllowList string[] [github.com, dev.azure.com, api.nuget.org] yes no Explicit sandbox networking (original design §37); arbitrary internet access denied.

Metrics and observability

Metric Instrument Unit Dimensions Summary
connectsoft.factory.tools.invocations counter {invocation} tenant, tool, effectiveClass, state Invocations by outcome.
connectsoft.factory.tools.latency histogram s tool, kind Pipeline and execution latency.
connectsoft.factory.tools.denials counter {invocation} tenant, stage, reason Denials by stage.
connectsoft.factory.tools.uncertain updown {invocation} tenant Invocations awaiting effect confirmation.
connectsoft.factory.tools.approvals_waiting updown {invocation} tenant, effectiveClass Gated calls waiting for approval.
connectsoft.factory.tools.sandboxes_open updown {sandbox} tenant, kind Open sandbox leases.

Security

Authentication client-credentials
Scopes 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.)
Roles Requester, Reviewer, Operator, WorkspaceAdmin, PlatformAdmin, Observer
Tenant isolation row-filter
Data classification confidential
Max side-effect class production
Secrets —

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.

Dependencies

Outbound

Target Kind Purpose Failure mode Required
PolicyEngineService grpc Decision per invocation (agent permission, tenant policy, class). fail-fast yes
RunControlService grpc Validate the approval bound to the request hash; read run and lease state. fail-fast yes
EnvironmentService grpc Policy class and freeze state of the target environment. fail-fast yes
SecretBrokerService grpc Short-lived credentials per invocation. fail-fast yes
AgentPoolManager grpc Sandbox and workspace leases (BC-26). fail-fast yes
McpServerRegistryService grpc Resolve MCP tool bindings and server transport. fail-fast yes
IntegrationService grpc Connections for external tools. degrade no
RepositoryIntelligenceService grpc Repository read tools. degrade no
VectorMemoryService grpc knowledge-search tool. degrade no
ArtifactService grpc Store results and receipts by hash. fail-fast yes
CostUsageService grpc RecordUsage (ToolInvocations and SandboxMinutes meters). degrade yes

Inbound

Target Kind Purpose Failure mode Required
AgentRuntimeService grpc Invoke with fencing tokens; Interrupt on cancellation. — yes
StudioBff sync-http Descriptor, invocation and receipt views; effect confirmation. — yes

Failure and recovery

Scenario Detection Recovery Data impact RTO (min)
Approval expired while a gated call waited approval state Expired invocation Denied with reason; the attempt fails with class policy-denied none 0
Sandbox lost mid-execution lease heartbeat lost invocation Uncertain; operator confirms the effect from external evidence before any retry possible unconfirmed effect 10
MCP server degraded handshake failures from the registry descriptors unhealthy; calls fail fast with class transient none 30
Result contains secrets sanitizer patterns secrets redacted before the result reaches the model; audit records the redaction none 0

NFR targets

Target Class value (pilot-interactive) Override
latency_p95_ms 2000 —
availability_pct 99.5 —
throughput_rps 50 —
rpo_minutes 15 —
rto_minutes 240 —
cost_class low —

Deployment

Granularity module of host · host ToolExecutorHost
Topologies saas-default, hybrid, on-prem, hybrid-compute
Runtime —; replicas —–—
Ports —

Current implementation

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.

Later capabilities

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.

Decisions and traceability

Family Ids
FR FR-05, FR-06, FR-10
FUX FUX-05, FUX-07
NFR NFR-02, NFR-04, NFR-05, NFR-10
XL XL-03, XL-06, XL-10, XL-16