Integration

Tool Calling — Agent Actions

Register any function as a tool. The agent decides when to call it — your code does the work.

Three approaches

ApproachWhere definedBest for
registerTools JS at runtime Tools that need closures, live state, or complex logic
Tool Manifest Dashboard (JSON) Simple client actions or server calls, configured without a deploy
Server Tools (OpenAPI) Dashboard (URL) Calling your existing REST API endpoints directly

1 — registerTools (programmatic)

Call window.widgent('registerTools', ...) inside the widgent:ready handler. This registers browser-side behavior. The JSON Schema still belongs in the tool manifest.

window.addEventListener('widgent:ready', () => {
  window.widgent('registerTools', {
    navigateTo: async ({ path }) => {
      window.location.href = path;
      return { success: true, path };
    },

    getAccountInfo: async () => {
      const data = await fetch('/api/account').then(r => r.json());
      return data;
    },
  });
});

The function return value is sent back to the LLM as the tool result. Register the matching schema in toolsManifest so the LLM knows the tool exists.

2 — Tool Manifest (dashboard JSON)

Define tools in Dashboard → Tools, or via API with a session cookie (sign in at the dashboard first). X-Service-Key does not work for manifest writes.

GoalAPI
Add one toolPOST /v1/products/:id/tools
Update one toolPUT /v1/products/:id/tools/:name
Remove one toolDELETE /v1/products/:id/tools/:name
Replace all toolsPATCH /v1/products/:id with toolsManifest array
Add one tool (session cookie)
curl -X POST https://api.widgent.app/v1/products/YOUR_PRODUCT_ID/tools \
  -H "Content-Type: application/json" \
  -H "Cookie: YOUR_SESSION_COOKIE" \
  -d '{ "type": "client", "name": "navigate_to", ... }'

Release notes & curl examples

Client tool — runs a named function on window
{
  "type": "client",
  "name": "navigate_to",
  "description": "Navigate the user to a specific page",
  "parameters": {
    "type": "object",
    "properties": { "path": { "type": "string" } },
    "required": ["path"]
  },
  "handler": "myApp.router.push",
  "mockResponse": { "status": "success" }
}
Server tool — calls your backend endpoint
{
  "type": "server",
  "name": "search_docs",
  "description": "Search the product knowledge base",
  "parameters": {
    "type": "object",
    "properties": { "query": { "type": "string" } },
    "required": ["query"]
  },
  "url": "https://api.example.com/search",
  "method": "POST",
  "requiresApproval": false,
  "mockResponse": { "results": [{ "title": "Example result", "url": "/docs/example" }] }
}

For server tools that need auth, pass a toolToken at init time — it's forwarded with every call, never stored by Widgent:

window.widgent.init({
  productId: 'YOUR_PRODUCT_ID',
  serviceKey: 'YOUR_SERVICE_KEY',
  toolTokens: {
    search_docs: 'Bearer sk-...'
  }
});

Approval before side effects

Add "requiresApproval": true to any tool that writes data, deletes, sends messages, charges money, or triggers an irreversible action. Read-only tools usually do not need approval.

mockResponse — safe testing

Every tool in the manifest can have a mockResponse. In test sessions (Dashboard → Test tab), the LLM receives mockResponse instead of calling the real handler. This lets you test agent behavior without side effects.

Tool writing tips

  • Name clearlycreate_invoice beats action1. The LLM reads the name.
  • Describe the effect — "Creates a new invoice and returns the invoice ID." Tell the LLM what happens.
  • Return structured data — The LLM uses your return value to formulate the next response. Return JSON, not strings.
  • Keep tools focused — One action per tool. Compose in the agent, not in the handler.