Custom Intents
Custom intents are how you introduce your own intent names into the protocol.
Think of them as domain-level events that you define yourself.
Instead of forcing the model to express a behavior through free text, you declare a named contract and let the model emit that contract directly.
DSL format
Section titled “DSL format”You define custom intents as top-level intent declarations, then attach them to an agent (or helper) through intent: config.
1) Define intent(s)
Section titled “1) Define intent(s)”intent Planning { description: "Emit a structured execution plan before taking action" fields { step: string confidence: number rationale: string }}
intent Dialogue { description: "Emit the user-facing dialogue decision" fields { tone: string summary: string }}2) Attach to agent
Section titled “2) Attach to agent”agent Main { default config { model: gemini("gemini-2.5-flash") prompt: "You are a planning assistant" }
intent: Planning + Dialogue}You can also inline custom intents directly inside intent::
agent Main { default config { model: gemini("gemini-2.5-flash") prompt: "You are a planning assistant" }
intent: { Planning { description: "Emit plan" fields { step: string } } }}How SDKs consume custom intents
Section titled “How SDKs consume custom intents”The runtime callback signature pattern stays the same:
- TypeScript callback receives
(name, value, agentName). - Python class method receives
(value, agent_name), where method name maps to intent name.
agent.onIntent((name, value, agentName) => { if (name === "Planning") { console.log("step:", value.step) console.log("confidence:", value.confidence) }
if (name === "Dialogue") { console.log("tone:", value.tone) console.log("summary:", value.summary) }})class HandleIntent(AuwgentBaseIntentHandler): async def Planning(self, intent, agent_name): print("step:", intent.get("step")) print("confidence:", intent.get("confidence"))
async def Dialogue(self, intent, agent_name): print("tone:", intent.get("tone")) print("summary:", intent.get("summary"))
agent.on_intent(HandleIntent)Python note: method lookup tries exact intent name first, then a sanitized lowercase form.
Custom intent payload shape
Section titled “Custom intent payload shape”For custom intents, the intent name comes from the callback’s name parameter.
The payload is the declared fields object directly.
So if the emitted intent is Planning, payload looks like:
// name === "Planning"{ step: "Collect user constraints", confidence: 0.92, rationale: "Need constraints before proposing options"}# name == "Planning" (method: Planning){ "step": "Collect user constraints", "confidence": 0.92, "rationale": "Need constraints before proposing options"}And for Dialogue:
// name === "Dialogue"{ tone: "calm", summary: "I will ask two questions before making a recommendation"}# name == "Dialogue" (method: Dialogue){ "tone": "calm", "summary": "I will ask two questions before making a recommendation"}Partial payloads for custom intents
Section titled “Partial payloads for custom intents”If a custom intent is emitted during streaming, onIntentPartial / on_intent_partial receives the same partial envelope style used by other structured intents.
At completion, onIntent / on_intent receives the final fields object.