ADIL EDGE SDK · INTEGRATION EXAMPLES

Register tools. Confirm actions.

Each example adapts the accepted SDK source as of the current candidate; the three interfaces behave the same way. Neither the Eco V1.1 A3b model nor the SDK is publicly released: there is no download, package or installer, and nothing on this page announces one.

Python: a read-only and a state-changing tool

The first request runs the read-only tool because the user wrote the city. The timer request produces a proposal that waits for your decision.

from adil_edge_sdk.native import NativeEdge

def decide(p) -> bool:
    # Show the person the stored tool, arguments and effect. Deny by default.
    print(f"proposal: {p.tool} {p.arguments} effect={p.effect} ungrounded={p.ungrounded}")
    return input("approve? [y/N] ").strip().lower() == "y"

with NativeEdge(model, sha) as edge:
    agent = edge.agent()
    agent.register_tool("get_forecast", "Get the weather forecast for a city.",
                        {"type": "object", "properties": {"city": {"type": "string"}}, "required": ["city"], "additionalProperties": False},
                        lambda args, ctx: {"city": args["city"], "high": 17, "conditions": "light rain"})
    agent.register_tool("set_timer", "Start a countdown timer.",
                        {"type": "object", "properties": {"minutes": {"type": "integer", "minimum": 1}}, "required": ["minutes"], "additionalProperties": False},
                        lambda args, ctx: {"status": "started", "minutes": args["minutes"]}, effect="state_changing")

    for message in ("What is the weather in Oslo?", "Set a timer for 18 minutes."):
        out = agent.run(message)
        while out.kind == "action_proposal":          # the host decides: ask the person, deny by default
            out = agent.confirm(out.proposal, approve=decide(out.proposal))
        print(f"{message!r} -> {out.kind}: {out.text or out.reason}")
Python adapter (adapted from the accepted SDK source as of the current candidate)

TypeScript / Node.js

Node starts the engine in a separate host process, so NativeHost is asynchronous and must be closed.

import { NativeHost } from "@thynkr/adil-edge-sdk";   // provisional package name; not published
import type { Proposal } from "@thynkr/adil-edge-sdk";

async function decide(p: Proposal): Promise<boolean> {
  // Show the person the stored tool, arguments and effect. Deny by default (no terminal means no approval).
  console.log(`proposal: ${p.tool} ${JSON.stringify(p.arguments)} effect=${p.effect}`);
  return false;   // replace with your own confirmation interface
}

const host = await NativeHost.open({ model, sha256 });
try {
  const agent = await host.agent();
  await agent.registerTool({
    name: "get_forecast", description: "Get the weather forecast for a city.",
    parameters: { type: "object", properties: { city: { type: "string" } }, required: ["city"], additionalProperties: false },
    handler: async (args) => ({ city: args.city, high: 17, conditions: "light rain" }),
  });
  await agent.registerTool({
    name: "set_timer", description: "Start a countdown timer.", effect: "state_changing",
    parameters: { type: "object", properties: { minutes: { type: "integer", minimum: 1 } }, required: ["minutes"], additionalProperties: false },
    handler: async (args) => ({ status: "started", minutes: args.minutes }),
  });
  let out = await agent.run("Set a timer for 18 minutes.");
  while (out.kind === "action_proposal") out = await agent.confirm(out.proposal!, await decide(out.proposal!));
  console.log(out.kind, out.text ?? out.reason);
} finally {
  await host.close();
}
TypeScript host (adapted from the accepted SDK source as of the current candidate). Package name provisional.

C and C++

In C, your callbacks are plain functions. Check every returned status, and dispose of handles in reverse order.

/* After engine, session and agent creation (see the quick start): */
adil_tool_def td; memset(&td, 0, sizeof td); td.struct_size = sizeof td;
td.name = "set_timer"; td.description = "Start a countdown timer.";
td.parameters_json = "{\"type\":\"object\",\"properties\":{\"minutes\":{\"type\":\"integer\",\"minimum\":1}},\"required\":[\"minutes\"],\"additionalProperties\":false}";
td.effect = ADIL_EFFECT_STATE_CHANGING;     /* always waits for the host */
td.callback = set_timer;                    /* your function; the engine calls it only after approval */
adil_agent_register_tool(agent, &td, err, sizeof err);

adil_outcome_kind kind; char *out = NULL;
adil_status st = adil_agent_run(agent, "Set a timer for 18 minutes.", &kind, &out);
if (st == ADIL_OK && kind == ADIL_OUTCOME_ACTION_PROPOSAL) {
    /* Parse "id" and "digest" from the outcome JSON with your own JSON parser, show the proposal to the person, then: */
    st = adil_agent_confirm(agent, id, digest, person_approved ? ADIL_DECISION_APPROVE : ADIL_DECISION_DENY, &kind, &out);
    /* A proposal resolves exactly once: confirming it again returns ADIL_E_CONFIRMATION. */
}
adil_string_free(out);
C interface version 2: registering a state-changing tool and resolving its proposal (abridged from the accepted minimal example as of the current candidate)

Before you adapt these

  • The handlers return fixed data. In a real application they validate their inputs again and enforce your own authorisation.
  • The examples decide for the person only by denying. Build a real confirmation interface that shows the tool, arguments, destination and scope, and approve one proposal at a time.
  • Register any tool that reads private data or sends data out of the process as confirmation-required.
  • These are candidate interfaces and may change before release.

Tools, permissions and errorsQuick start