EdgeStream
Node Explorer (ANCP)
The Node Explorer at /ancp connects directly to ANCP-enabled nodes — independent of the EdgeStream SignalR pipeline. It lets you ping nodes, discover capabilities, invoke actions, and monitor streaming tasks all from a single panel-based UI.
Route and Component
// Route in App.tsx
<Route path="/ancp" element={<AncpPage />} />
// AncpPage source: packages/app-pages-react/src/AncpPage.tsx
// Uses @bizfirst/ancp-react hooks + AncpProvider
Three-Panel Layout
AncpPage renders three stacked panels. Panels B and C appear only once a connection is established (Panel A).
| Panel | Name | Purpose |
|---|---|---|
| A | Node Connection | Enter Base URL, Node ID, auth mode, and timeout. Click Connect to establish an ANCP session. |
| B | Node Info | Ping status, capability table (actions + patterns + pricing), and raw Discovery JSON viewer. |
| C | Action Invoker | Select action + pattern, enter payload JSON, send and view the response or stream. |
Panel A — Node Connection
// AncpClientOptions supplied to AncpProvider:
interface AncpClientOptions {
baseUrl: string; // e.g. 'https://server2.bizfirst.internal'
nodeId: number; // integer node ID
auth?: { jwtToken?: string } | { apiKey?: string } | { didProof?: string };
timeout?: number; // default 30000 ms
}
// Auth modes supported: None | JWT | ApiKey | DID
// Selecting a mode reveals a text field for the credential.
// Once Connect is clicked, AncpProvider wraps Panels B and C:
<AncpProvider options={ancpOptions}>
<NodeInfoPanel />
<ActionInvokerPanel />
</AncpProvider>
Panel B — Node Info
// Hooks used in NodeInfoPanel:
import {
useAncpPing, // fires ping on mount, returns { response, isLoading, isReachable, error }
useAncpCapabilities, // fetches capability list, returns { actions, isLoading, error, refresh }
useAncpClient, // raw ANCP client for custom calls
} from '@bizfirst/ancp-react';
// Ping response fields:
// { nodeId, tenantId, status, timestamp }
// Capability table columns:
// Action | Pattern | Description | Price (USDC)
// Each row is an AncpActionDescriptor:
interface AncpActionDescriptor {
action: string; // e.g. 'get-order-status'
pattern: AncpMessagePattern;
description?: string;
requiresPayment: boolean;
priceUsdc?: number;
}
// Discovery JSON: client.discover() fetches full capability document
const doc = await client.discover(); // shown in JsonViewer
ANCP vs EdgeStream
The Node Explorer connects to ANCP nodes directly via REST/HTTP — it does not use the EdgeStream SignalR hub. ANCP nodes expose their own HTTP endpoint separate from the EdgeStream hub URL.
Panel C — Action Invoker (ANCP)
The Action Invoker in the ANCP panel supports all four ANCP message patterns. This is different from the Demo page Action Invoker, which sends EdgeStream messages. The ANCP Action Invoker sends directly to the node's HTTP endpoint.
// AncpMessagePattern type:
type AncpMessagePattern =
| 'request-reply' // synchronous: send + await response
| 'fire-and-forget' // async: POST returns 202 Accepted
| 'streaming' // chunked SSE stream: collect chunks until done
| 'task-start'; // long-running: returns taskId, then poll status
// Hooks used per pattern:
const invokeHook = useAncpInvoke(actionName); // request-reply
const streamHook = useAncpStream(actionName); // streaming
const taskHook = useAncpTask(actionName); // task-start
// fire-and-forget: client.fireAndForget(action, payload)
// Pattern: request-reply
invokeHook.invoke(payload, { timeout: 5000 });
// Response shown in JsonViewer
// Pattern: streaming
streamHook.start(payload);
// streamHook.chunks[] grows as server sends chunks
// streamHook.isDone === true when stream ends
// Pattern: task-start
taskHook.start(payload);
// taskHook.taskId = 'task-abc-123'
// taskHook.status = { state: 'Running' | 'Completed' | 'Failed' | 'Cancelled', result?, error? }
// Poll: taskHook.refresh() (auto-polled every 1500ms while Running)
// Cancel: taskHook.cancel()
Streaming Log Display
// Chunk display format in the streaming log:
[0] {"type":"partial","text":"Hello"}
[1] {"type":"partial","text":" world"}
[2] [last] {"type":"done","text":""}
// Auto-scrolls as chunks arrive:
useEffect(() => {
if (streamLogRef.current) {
streamLogRef.current.scrollTop = streamLogRef.current.scrollHeight;
}
}, [streamHook.chunks.length]);
Task Status Badges
| State | Badge Color | Meaning |
|---|---|---|
| Running | Blue | Task is executing — polling active every 1500ms (configurable) |
| Completed | Green | Task finished — result available in taskHook.status.result |
| Failed | Red | Task errored — message in taskHook.status.error |
| Cancelled | Gray | Task was cancelled via Cancel Task button |
Use Case: Debugging Agent Nodes
The Node Explorer is the primary tool for verifying that an ANCP-enabled agent node is reachable, advertising the correct capabilities, and responding to actions with the right payload shapes — without writing any client code.