synalinks-agents/SKILL.md
Use when working with Synalinks agents — FunctionCallingAgent (autonomous / interactive, max_iterations, return_inputs_with_trajectory), Tool definitions (async, type-annotated, register_synalinks_serializable), MCP integration via MultiServerMCPClient, parallel tool calling, or agent execution trajectories.
npx skillsauth add synalinks/synalinks-skills synalinks-agentsInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Build tool-using AI agents with structured outputs, autonomous or interactive execution, and MCP integration.
import synalinks
import asyncio
class Query(synalinks.DataModel):
query: str = synalinks.Field(description="The user query")
class FinalAnswer(synalinks.DataModel):
answer: str = synalinks.Field(description="The final answer")
@synalinks.utils.register_synalinks_serializable()
async def calculate(expression: str):
"""Calculate mathematical expression.
Args:
expression: Mathematical expression like '2 + 2'
"""
try:
result = eval(expression, {"__builtins__": None}, {})
return {"result": round(float(result), 4), "log": "Success"}
except Exception as e:
return {"result": None, "log": f"Error: {e}"}
async def main():
lm = synalinks.LanguageModel(model="ollama/mistral")
tools = [synalinks.Tool(calculate)]
inputs = synalinks.Input(data_model=Query)
outputs = await synalinks.FunctionCallingAgent(
data_model=FinalAnswer,
tools=tools,
language_model=lm,
max_iterations=5,
autonomous=True,
)(inputs)
agent = synalinks.Program(inputs=inputs, outputs=outputs, name="calc_agent")
result = await agent(Query(query="What is 15 * 7?"))
print(result.prettify_json())
asyncio.run(main())
async def@synalinks.utils.register_synalinks_serializable()log / status field@synalinks.utils.register_synalinks_serializable()
async def calculate(expression: str):
"""Calculate the result of a mathematical expression.
Args:
expression: Mathematical expression like '2 + 2' or '(10 * 5) / 2'
Returns:
dict with 'result' and 'log' keys
"""
try:
result = eval(expression, {"__builtins__": {}})
return {"result": result, "log": "Success"}
except Exception as e:
return {"result": None, "log": f"Error: {e}"}
tool = synalinks.Tool(calculate)
All parameters must be required (no defaults). LLM providers require every parameter in the structured-output JSON schema to be required, so Tool defaults are unsafe.
@synalinks.utils.register_synalinks_serializable()
async def search_database(
query: str,
limit: int,
category: str,
):
"""Search the database for matching records.
Args:
query: Search query string
limit: Maximum number of results (e.g. 10)
category: Category filter ('all', 'products', 'users')
"""
results = await db.search(query, limit=limit, category=category)
return {"results": results, "count": len(results), "log": f"Found {len(results)} results"}
@synalinks.utils.register_synalinks_serializable()
async def safe_calculate(expression: str):
"""Safely calculate mathematical expressions.
Args:
expression: Expression with numbers and +, -, *, /, (, ), . only
"""
allowed = set("0123456789+-*/(). ")
if not all(c in allowed for c in expression):
return {"result": None, "log": "Error: Invalid characters."}
try:
return {"result": round(float(eval(expression, {"__builtins__": None}, {})), 4), "log": "Success"}
except Exception as e:
return {"result": None, "log": f"Error: {e}"}
synalinks.FunctionCallingAgent(
data_model=FinalAnswer, # Required: final output schema
tools=tools, # Required: list of Tool instances
language_model=lm, # Optional if default LM is set
max_iterations=5, # Max tool calls before final answer
autonomous=True, # Run autonomously vs interactive
return_inputs_with_trajectory=True, # Include full execution trajectory
prompt_template=None,
instructions="", # MUST be a string
)
All arguments are keyword-only — FunctionCallingAgent(data_model, tools, lm)
(positional) raises TypeError. Same for Generator, ChainOfThought, and other
Module subclasses. Tool(my_function) is the exception: its first positional arg
is the wrapped function.
language_model may be omitted if synalinks.set_default_language_model(...)
was called — defaults flow via ops.predict.
instructions MUST be a string, not a list — see synalinks-modules for the full discussion.
When return_inputs_with_trajectory=True:
{
"query": "What is 15 * 7?",
"trajectory": [
{"tool": "calculate", "input": {"expression": "15 * 7"}, "output": {"result": 105, "log": "Success"}}
],
"answer": "105"
}
Agent runs until max_iterations or final answer:
synalinks.FunctionCallingAgent(autonomous=True, max_iterations=5, ...)
Agent pauses for human confirmation at each step:
synalinks.FunctionCallingAgent(autonomous=False, ...)
mcp_client = synalinks.MultiServerMCPClient({
"math_server": {"url": "http://localhost:8183/mcp/", "transport": "streamable_http"},
"search_server": {"url": "http://localhost:8184/mcp/", "transport": "streamable_http"},
})
tools = await mcp_client.get_tools()
outputs = await synalinks.FunctionCallingAgent(
data_model=FinalAnswer,
tools=tools,
language_model=lm,
)(inputs)
# mcp_server.py
from mcp.server.fastmcp import FastMCP
mcp = FastMCP("Math Server")
@mcp.tool()
def calculate(expression: str) -> dict:
"""Calculate mathematical expression."""
return {"result": eval(expression)}
# Run with: uvicorn mcp_server:app --port 8183
app = mcp.streamable_http_app()
Tool design
int, float, bool) over generic strlog / status field for debuggingAgent design
max_iterations to prevent runaway loopsdata_model to structure the final answerinstructions as a single stringdevelopment
Use when training Synalinks programs — program.compile() / fit() / evaluate() / predict(), validation_split, validation_data, batch_size, epochs, callbacks (ProgramCheckpoint, custom Callback subclasses), History, in-context reinforcement learning workflow. For reward functions see synalinks-rewards; for optimizer internals see synalinks-optimizers.
development
Use when configuring or writing Synalinks reward functions and metrics — ExactMatch, CosineSimilarity, LMAsJudge, ProgramAsJudge, RewardFunctionWrapper, custom reward functions (async, register_synalinks_serializable), in_mask / out_mask filtering, F1Score / FBetaScore / BinaryF1Score / ListF1Score metrics, MeanMetricWrapper, or whenever you're shaping the signal that drives optimization.
tools
Use when integrating Synalinks with LM providers — picking the right model prefix (openai/, anthropic/, ollama/, groq/, cohere/, openrouter/, bedrock/, deepseek/, together_ai/, doubleword/, hosted_vllm/ (alias vllm/), gemini/, xai/, mistral/, azure/), env vars per provider, structured-output dispatch (constrained json_schema vs tool-call), local OpenAI-compatible servers (LMStudio, vLLM) requiring litellm.register_model and a dummy OPENAI_API_KEY, and OpenRouter embeddings (LiteLLM doesn't support them — use OpenRouterEmbeddingModel).
development
Use when building or composing a Synalinks Program — the four building APIs (Functional, Sequential, Subclassing, Mixed), Input nodes, multi-input/multi-output graphs, the call/build lifecycle, training=True/False semantics, summary, get_module, plot_program, save/load, get_state_tree/set_state_tree, get_config/from_config and custom serialization. For DataModel/Field, JSON operators (+ & | ^ ~), and LanguageModel/EmbeddingModel basics see synalinks-core. For inner modules see synalinks-modules; for compile/fit/evaluate/predict see synalinks-training.