Skip to content
AgentField
Building Blocks

Skills

Deterministic functions for business logic, integrations, and data processing

Skill — deterministic function, no LLM needed

Deterministic functions for business logic that need the same infrastructure as reasoners -- without the AI.

This separation matters in production. When something breaks, you want to know whether the failure came from AI judgment or deterministic code. Skills are where you put systems-of-record access, calculations, API calls, and repeatable side effects.

from agentfield import Agent
from pydantic import BaseModel

app = Agent(node_id="inventory-service", version="1.0.0")

class StockQuery(BaseModel):
    sku: str
    warehouse: str = "us-east"

@app.skill(tags=["database", "inventory"])
async def check_stock(query: StockQuery) -> dict:
    """Fetch deterministic inventory state."""
    row = await db.execute(
        "SELECT sku, qty, reserved FROM stock WHERE sku = $1 AND warehouse = $2",
        query.sku, query.warehouse,
    )
    if not row:
        return {"sku": query.sku, "available": 0, "status": "not_found"}
    available = row["qty"] - row["reserved"]
    return {"sku": query.sku, "available": available, "status": "in_stock" if available > 0 else "out_of_stock"}

@app.skill(tags=["integrations", "shipping", "policy"])
async def fulfillable_quote(sku: str, dest: str, weight_kg: float) -> dict:
    stock = await check_stock(StockQuery(sku=sku))
    if stock["available"] <= 0:
        return {"sku": sku, "fulfillable": False, "reason": "out_of_stock"}

    rates = await fedex_client.rate_quote(origin="us-east", dest=dest, weight=weight_kg)
    return {"sku": sku, "fulfillable": True, "rates": rates, "currency": "USD"}

app.run()
# → POST /skills/check_stock  — auto-generated REST endpoint with input validation
# → POST /skills/fulfillable_quote  — discoverable by any agent in the fleet
import { Agent } from '@agentfield/sdk';

const agent = new Agent({ nodeId: 'inventory-service', version: '1.0.0' });

agent.skill('check_stock', async (ctx) => {
  const { sku, warehouse = 'us-east' } = ctx.input;
  const row = await db.query('SELECT sku, qty, reserved FROM stock WHERE sku = $1 AND warehouse = $2', [sku, warehouse]);
  if (!row) return { sku, available: 0, status: 'not_found' };
  const available = row.qty - row.reserved;
  return { sku, available, status: available > 0 ? 'in_stock' : 'out_of_stock' };
}, {
  tags: ['database', 'inventory'],
  description: 'Query real-time inventory by SKU and warehouse',
});

agent.skill('fulfillableQuote', async (ctx) => {
  const stock = await agent.call('inventory-service.check_stock', {
    sku: ctx.input.sku,
    warehouse: 'us-east',
  });
  if (stock.available <= 0) {
    return { sku: ctx.input.sku, fulfillable: false, reason: 'out_of_stock' };
  }

  const rates = await fedexClient.rateQuote({
    origin: 'us-east',
    dest: ctx.input.dest,
    weight: ctx.input.weightKg,
  });
  return { sku: ctx.input.sku, fulfillable: true, rates, currency: 'USD' };
}, {
  tags: ['integrations', 'shipping', 'policy'],
  description: 'Check fulfillment viability and return shipping options',
});

agent.serve();
// → POST /skills/check_stock  — auto-generated REST endpoint with input validation
// → POST /skills/fulfillableQuote  — discoverable by any agent in the fleet
// The Go SDK does not have a separate skill registration method.
// Use RegisterReasoner for all functions, whether AI-powered or deterministic.
// This registers /reasoners/check_stock, not /skills/check_stock.

a.RegisterReasoner("check_stock", func(ctx context.Context, input map[string]any) (any, error) {
    sku, _ := input["sku"].(string)
    warehouse, _ := input["warehouse"].(string)
    if warehouse == "" {
        warehouse = "us-east"
    }

    row, err := db.QueryRow(ctx, "SELECT qty, reserved FROM stock WHERE sku = $1 AND warehouse = $2", sku, warehouse)
    if err != nil {
        return map[string]any{"sku": sku, "available": 0, "status": "not_found"}, nil
    }

    available := row.Qty - row.Reserved
    status := "out_of_stock"
    if available > 0 {
        status = "in_stock"
    }
    return map[string]any{"sku": sku, "available": available, "status": status}, nil
},
    agent.WithDescription("Query real-time inventory by SKU and warehouse"),
    agent.WithReasonerTags("database", "inventory"),
)

What just happened

  • Skills handled deterministic state and policy logic without any model call
  • The second skill composed the first skill into a production-shaped workflow
  • Both skills inherited the same endpoint generation, discoverability, and execution tracking as reasoners
  • In Go, the same deterministic pattern is registered with RegisterReasoner and exposed under /reasoners/{name} instead of /skills/{name}

Example proof:

Python/TypeScript:
POST /skills/check_stock
POST /skills/fulfillable_quote
discoverable target: inventory-service.fulfillable_quote

Go:
POST /reasoners/check_stock