Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 29 additions & 12 deletions scenarios/sidecar-runtime/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -98,28 +98,45 @@ bash scripts/stop.sh

## How the agents use the SDK

Both agents follow the same shape a real integration uses:
Both agents demonstrate governance through the SDK. A real integration uses the
published SDK surface (the two SDKs differ β€” Python governs via the runtime
interceptor the framework examples wire up; Node wraps tools with `withAssembly`):

```python
# Python β€” real integration:
# Python β€” real integration. init_assembly() registers the agent and wires the
# detected framework adapter; the runtime interceptor governs each tool call via
# check_tool_start (see the python/ framework examples). To dispatch a governed
# call through the client directly, dispatch_tool takes a tool name and an args
# dict and is async β€” there is no client.call_tool:
import asyncio
from agent_assembly import init_assembly

with init_assembly(gateway_url=GATEWAY_URL, agent_id="my-agent") as ctx:
ctx.client.call_tool("read_file", path="/data/report.csv")
async def main():
with init_assembly(gateway_url=GATEWAY_URL, agent_id="my-agent") as ctx:
await ctx.client.dispatch_tool("read_file", {"path": "/data/report.csv"})

asyncio.run(main())
```

```js
// Node β€” real integration:
import { initAssembly } from "@agent-assembly/sdk";

const ctx = await initAssembly({ gatewayUrl: GATEWAY_URL, agentId: "my-agent" });
await ctx.client.callTool("read_file", { path: "/data/report.csv" });
// Node β€” real integration. withAssembly() wraps each tool's execute() with a
// pre-execution governance check; a deny throws PolicyViolationError before the
// tool body runs. There is no ctx.client.callTool:
import { withAssembly, PolicyViolationError } from "@agent-assembly/sdk";

const tools = withAssembly(
{ read_file: { execute: async ({ path }) => readReport(path) } },
{ gatewayClient, agentId: "my-agent" },
);
await tools.read_file.execute({ path: "/data/report.csv" });
```

To keep this scenario install-free and runnable offline, each agent ships a tiny
local stand-in for the SDK surface (clearly marked in the source). It exposes the
same `init_assembly` β†’ `client.call_tool` flow and routes governed calls through
the SDK client to core β€” never via ad-hoc HTTP from the agent.
local stand-in for the SDK (clearly marked in the source). The stand-in uses a
simplified `init_assembly` β†’ `client.call_tool` shape purely for readability; the
published SDK governs calls through the interceptor / `withAssembly` wrapper shown
above, not a `call_tool` method. Either way, governed calls route through the SDK
client to core β€” never via ad-hoc HTTP from the agent.

## Expected output

Expand Down
42 changes: 24 additions & 18 deletions scenarios/sidecar-runtime/examples/node-agent/agent.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,27 +6,32 @@
* sidecar *through the SDK*, the way a real integration does:
*
* your agent
* β”‚ initAssembly(...) / client.callTool(...)
* β”‚ withAssembly(tools, { gatewayClient }) governs each tool.execute()
* β–Ό
* Agent Assembly SDK (@agent-assembly/sdk)
* β”‚ aa-sdk-client (gRPC / UDS)
* β–Ό
* Agent Assembly core (the gateway / runtime sidecar)
*
* The agent never speaks the gateway's wire protocol itself. It calls the SDK's
* `initAssembly` entrypoint, and the SDK's client transport (aa-sdk-client)
* talks to core. This mirrors ADR 0004: examples demonstrate the SDK path,
* never hand-rolled HTTP calls to core endpoints.
* The agent never speaks the gateway's wire protocol itself. The SDK's client
* transport (aa-sdk-client) talks to core. This mirrors ADR 0004: examples
* demonstrate the SDK path, never hand-rolled HTTP calls to core endpoints.
*
* In a real project you would write:
* In a real project you would write (there is no ctx.client.callTool β€” a deny
* throws PolicyViolationError before the tool body runs):
*
* import { initAssembly } from '@agent-assembly/sdk';
* const ctx = await initAssembly({ gatewayUrl, agentId: 'my-agent' });
* await ctx.client.callTool('read_file', { path: '/data/report.csv' });
* import { withAssembly, PolicyViolationError } from '@agent-assembly/sdk';
* const tools = withAssembly(
* { read_file: { execute: async ({ path }) => readReport(path) } },
* { gatewayClient, agentId: 'my-agent' },
* );
* await tools.read_file.execute({ path: '/data/report.csv' });
*
* This standalone example ships a tiny local stand-in for that SDK surface so
* it runs with no extra install (and offline, with no Docker), while keeping
* the same init -> callTool -> audit-event shape as the real SDK.
* This standalone example ships a tiny local stand-in for the SDK so it runs
* with no extra install (and offline, with no Docker). The stand-in uses a
* simplified initAssembly -> client.callTool shape for readability; the
* published SDK governs calls through the withAssembly wrapper shown above, not
* a callTool method.
*
* Usage (with the local runtime / mock core):
* bash scripts/start.sh
Expand All @@ -44,12 +49,13 @@ const http = require('node:http');
// ---------------------------------------------------------------------------
// Minimal stand-in for the Agent Assembly SDK.
//
// In a real integration you would `import { initAssembly } from
// '@agent-assembly/sdk'` instead of defining these helpers. The SDK's client
// owns *all* transport to core (aa-sdk-client over gRPC/UDS); the agent only
// ever calls `initAssembly` and `client.callTool`. This shim keeps that exact
// surface so the example is faithful to the SDK path while remaining
// install-free and runnable offline.
// In a real integration you would `import { withAssembly } from
// '@agent-assembly/sdk'` and wrap your tools instead of defining these helpers.
// The SDK's client owns *all* transport to core (aa-sdk-client over gRPC/UDS).
// This shim uses a simplified `initAssembly` -> `client.callTool` shape purely
// so the example stays install-free and runnable offline; it is a teaching
// stand-in, not the exact published surface (see the module header for the real
// `withAssembly` API).
// ---------------------------------------------------------------------------

// Offline fallback policy, applied by the SDK shim when no core is reachable.
Expand Down
Loading