create-leafmesh 2.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (31) hide show
  1. create_leafmesh/__init__.py +3 -0
  2. create_leafmesh/cli.py +252 -0
  3. create_leafmesh/create.py +106 -0
  4. create_leafmesh/templates/Dockerfile +21 -0
  5. create_leafmesh/templates/README.md +309 -0
  6. create_leafmesh/templates/agency/__init__.py +0 -0
  7. create_leafmesh/templates/agency/advisor_agent.py +151 -0
  8. create_leafmesh/templates/agency/external_agents.py +278 -0
  9. create_leafmesh/templates/agency/fallback_researcher_agent.py +80 -0
  10. create_leafmesh/templates/agency/greeter_agent.py +79 -0
  11. create_leafmesh/templates/agency/processor_agent.py +90 -0
  12. create_leafmesh/templates/agency/researcher_agent.py +99 -0
  13. create_leafmesh/templates/agency/scheduler_agent.py +67 -0
  14. create_leafmesh/templates/agency/tools.py +123 -0
  15. create_leafmesh/templates/claude_skills/leafmesh/SKILL.md +2049 -0
  16. create_leafmesh/templates/claude_skills/leafmesh/agent-config-fields.md +1309 -0
  17. create_leafmesh/templates/claude_skills/leafmesh/examples.md +537 -0
  18. create_leafmesh/templates/claude_skills/leafmesh/reference.md +492 -0
  19. create_leafmesh/templates/configs/config.yaml +1028 -0
  20. create_leafmesh/templates/docker-compose.yml +28 -0
  21. create_leafmesh/templates/dockerignore +17 -0
  22. create_leafmesh/templates/env +109 -0
  23. create_leafmesh/templates/gitignore +33 -0
  24. create_leafmesh/templates/hitl_stub_receiver.py +149 -0
  25. create_leafmesh/templates/main.py +105 -0
  26. create_leafmesh/templates/requirements.txt +10 -0
  27. create_leafmesh-2.1.0.dist-info/METADATA +6 -0
  28. create_leafmesh-2.1.0.dist-info/RECORD +31 -0
  29. create_leafmesh-2.1.0.dist-info/WHEEL +5 -0
  30. create_leafmesh-2.1.0.dist-info/entry_points.txt +2 -0
  31. create_leafmesh-2.1.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,1028 @@
1
+ name: "{{project_name}}"
2
+ version: "1.0.0"
3
+ architecture: "managed_mesh"
4
+ environment: "development" # "development" or "production"
5
+ debug: true
6
+ log_level: "INFO"
7
+
8
+ redis:
9
+ host: "${REDIS_HOST:localhost}"
10
+ port: ${REDIS_PORT:6379}
11
+ db: 0
12
+ password: "${REDIS_PASSWORD:}"
13
+ auto_storage: true
14
+ decode_responses: true # Decode Redis byte responses to strings
15
+ default_ttl: 3600 # Default key TTL in seconds
16
+ session_ttl: 7200 # Session TTL in seconds
17
+ # cluster_mode: true # Enable Redis cluster mode
18
+ # cluster_nodes: # Cluster node addresses
19
+ # - "redis-node1:6379"
20
+ # - "redis-node2:6379"
21
+ # - "redis-node3:6379"
22
+
23
+ # TLS / encryption-in-transit
24
+ # Enable when your Redis server requires TLS (rediss://).
25
+ # ssl: true
26
+ # ssl_cert_reqs: required # required | optional | none
27
+ # ssl_ca_certs: /etc/ssl/certs/redis-ca.crt
28
+ # ssl_certfile: /etc/ssl/certs/redis-client.crt # mTLS, optional
29
+ # ssl_keyfile: /etc/ssl/private/redis-client.key # mTLS, optional
30
+ # ssl_check_hostname: true
31
+
32
+ # ═══════════════════════════════════════════════════
33
+ # API — HTTP server (CORS, etc.)
34
+ # ═══════════════════════════════════════════════════
35
+ # The SDK ships with a built-in CORS allowlist:
36
+ # - https://platform.leafcraft.ai (hosted Studio)
37
+ # - http://localhost:3000 / 3001 / 5173 / 5174 / 8080 (common dev ports)
38
+ # Add additional origins below if you serve your own UI from a different host.
39
+ # api:
40
+ # cors_origins:
41
+ # - https://my-internal-tool.example.com
42
+ # - https://my-staging-studio.acme.com
43
+
44
+ # Auto-discover agent files in agency/ directory
45
+ # SDK matches Python function names to YAML agent names
46
+ auto_discover:
47
+ directory: "./agency"
48
+ pattern: "*_agent.py"
49
+ # recursive: true # Search subdirectories (default: true)
50
+
51
+ # ═══════════════════════════════════════════════════
52
+ # MANAGER — Built-in mesh coordinator + conversation analyzer
53
+ #
54
+ # Two built-in agents, ONE config section:
55
+ # Summarizer — LLM-powered, analyzes every agent event automatically
56
+ # Manager — Pure logic, enforces rules, retries, halts, escalates
57
+ #
58
+ # The "model" and "domain" fields drive the Summarizer's LLM calls.
59
+ # The Manager never calls an LLM — it acts on the Summarizer's analysis.
60
+ # ═══════════════════════════════════════════════════
61
+ manager:
62
+ enabled: true
63
+ model: "gpt-4o-mini" # Used by Summarizer for LLM analysis
64
+ domain: "generic" # Summarizer domain: "generic" | "ecommerce" | "data_analysis"
65
+ # ── Learning-based routing (BRD-008) ──
66
+ # Routes mesh_call requests to agents based on past success patterns.
67
+ # "learning" mode accumulates routing decisions in Redis and improves over time.
68
+ # No external dependencies — works with Redis only.
69
+ routing:
70
+ mode: "learning" # "static" (YAML rules only) or "learning" (adaptive)
71
+ memory_size: 100 # Max routing decisions to remember
72
+ confidence_threshold: 0.7 # Min confidence to accept a learned route
73
+ fallback: "all" # Fallback when confidence too low: "all" evaluates every can_call
74
+ decay_days: 30 # Days before old routing memory decays
75
+
76
+ # ── Escalation targets (BRD-011) ──
77
+ # When the manager detects repeated failures or timeouts, it escalates.
78
+ # Human agent escalation works out of the box. Webhook/channel need credentials.
79
+ escalation:
80
+ targets:
81
+ # Human agent escalation — routes to the client human agent
82
+ - type: "human_agent"
83
+ agent: "client"
84
+ # entry_point: "human_contact" # Optional: specific entry point
85
+
86
+ # Webhook escalation (uncomment + configure URL)
87
+ # - type: "webhook"
88
+ # url: "${ESCALATION_WEBHOOK_URL:}"
89
+ # method: "POST"
90
+ # headers:
91
+ # Authorization: "Bearer ${ESCALATION_WEBHOOK_TOKEN:}"
92
+ # Content-Type: "application/json"
93
+ # payload_template:
94
+ # incident: "{{incident_id}}"
95
+ # severity: "{{severity}}"
96
+ # message: "{{message}}"
97
+
98
+ # Channel escalation (uncomment + configure provider)
99
+ # - type: "channel"
100
+ # provider: "slack" # slack | telegram | discord | whatsapp | teams
101
+ # channel_id: "${ESCALATION_SLACK_CHANNEL:}"
102
+ # message_template: "🚨 Escalation: {{message}} (session: {{session_id}})"
103
+
104
+ auto_escalate:
105
+ max_retries: 3 # Max retry attempts before escalating
106
+ max_errors_per_session: 5 # Error count threshold per session
107
+ timeout_threshold: 2 # Consecutive timeouts before escalating
108
+
109
+ # can_intervene: true # Allow manager interventions (default: true)
110
+ # # Set false for read-only monitoring mode
111
+
112
+ # ── Everything below has sensible defaults — uncomment only to override ──
113
+ # coordination_rules:
114
+ # score_threshold: 0.7
115
+ # max_retries: 3
116
+ # agent_rules:
117
+ # processor_agent:
118
+ # min_items: 1
119
+ # max_items: 100
120
+ # health_check_interval: 60 # Seconds between health checks (default: 60)
121
+ # agent_timeout_threshold: 180 # Seconds before agent considered timed out (default: 180)
122
+ # chain_completion_timeout: 60 # Seconds to wait for can_call chain (default: 60)
123
+
124
+ # Mesh settings — call timeout + cloud LLM provider configs
125
+ mesh:
126
+ call_timeout: 60
127
+
128
+ # ── Cloud LLM Providers (uncomment to use) ──
129
+ # bedrock:
130
+ # region: "us-east-1" # AWS region
131
+ # # profile: "default" # AWS profile from ~/.aws/credentials
132
+ # # endpoint_url: "" # Custom Bedrock endpoint (optional)
133
+ # # Auth: AWS_ACCESS_KEY_ID + AWS_SECRET_ACCESS_KEY env vars, or IAM role
134
+ #
135
+ # vertex:
136
+ # project: "my-gcp-project" # GCP project ID (required)
137
+ # location: "us-central1" # GCP region
138
+ # # Auth: GOOGLE_APPLICATION_CREDENTIALS or gcloud auth
139
+ #
140
+ # foundry:
141
+ # endpoint: "https://my-resource.openai.azure.com" # Azure AI Foundry endpoint (required)
142
+ # # api_version: "2024-10-21" # Omit for v1 mode (recommended), set for legacy Azure mode
143
+ # # Auth: AZURE_FOUNDRY_API_KEY or AZURE_FOUNDRY_TOKEN env vars
144
+ #
145
+ # ── Local model server (vLLM, SGLang, Ollama, llama.cpp, etc.) ──
146
+ # Most servers expose OpenAI-compatible /v1/chat/completions — use server_type: openai
147
+ # local:
148
+ # endpoint: "http://localhost:8000/v1/chat/completions" # vLLM/SGLang default
149
+ # server_type: "openai" # "openai" | "ollama" | "textgen" | "huggingface" (auto-detected if omitted)
150
+ # timeout: 120 # Seconds (local models can be slow on CPU)
151
+ # # headers:
152
+ # # Authorization: "Bearer ${VLLM_API_KEY:}"
153
+
154
+ # ═══════════════════════════════════════════════════
155
+ # ENTRY POINTS — Named portals into the mesh
156
+ # Use: await leafmesh.mesh_call("entry_point_name", data)
157
+ # This is the ONLY way to trigger agent workflows externally
158
+ # ═══════════════════════════════════════════════════
159
+ entry_points:
160
+ - name: "greet_user"
161
+ target: "greeter_agent"
162
+ description: "Main entry — greets user and starts the agent chain"
163
+ # condition: "always" # Optional trigger condition
164
+
165
+ - name: "human_contact"
166
+ target: "client"
167
+ description: "Human-initiated — client contacts the mesh via channel/webhook"
168
+
169
+ - name: "process_data"
170
+ target: "processor_agent"
171
+ description: "Direct data processing bypass"
172
+
173
+ - name: "research"
174
+ target: "researcher_agent"
175
+ description: "Direct research — bypasses greeting flow"
176
+
177
+ - name: "advise"
178
+ target: "advisor_agent"
179
+ description: "Direct advice request — ad-hoc recommendations"
180
+
181
+ - name: "scheduled_report"
182
+ target: "scheduler_agent"
183
+ description: "On-demand status report (also runs on cron schedule)"
184
+
185
+ # ═══════════════════════════════════════════════════
186
+ # AGENTS — 4 types: human, llm, programmatic, external
187
+ #
188
+ # Registration:
189
+ # - agency/*_agent.py → auto_discover matches function names to YAML names
190
+ # - Standalone decorators: @chain, @compose, @pre_compose (no leafmesh instance needed)
191
+ #
192
+ # Data flow — HITL (Human-in-the-Loop):
193
+ #
194
+ # Scenario 1 (system-initiated):
195
+ # mesh_call("greet_user", data) → greeter_agent → client (HITL)
196
+ # → [human reviews in ADK-Frontend inbox] → processor_agent
197
+ # → researcher_agent + fallback_researcher_agent
198
+ # → advisor_agent (OR fan-in)
199
+ #
200
+ # Scenario 2 (human-initiated):
201
+ # webhook to "human_contact" → client → greeter_agent → client (HITL)
202
+ # → [human reviews in ADK-Frontend inbox] → processor_agent
203
+ # → researcher_agent + fallback_researcher_agent
204
+ # → advisor_agent (OR fan-in)
205
+ #
206
+ # Direct entries:
207
+ # mesh_call("research", data) → researcher_agent (standalone)
208
+ # mesh_call("advise", data) → advisor_agent (standalone)
209
+ #
210
+ # Scheduled + on-demand:
211
+ # cron "0 9 * * *" → scheduler_agent → advisor_agent (daily report analysis)
212
+ # mesh_call("scheduled_report", data) → scheduler_agent → advisor_agent
213
+ # ═══════════════════════════════════════════════════
214
+ agents:
215
+
216
+ # ─────────────────────────────────────────────
217
+ # HUMAN AGENT — Receives input via ADK-Frontend inbox
218
+ # No Python file needed. The mesh handles everything.
219
+ #
220
+ # human_interface options:
221
+ # "default" — ADK-Frontend HITL inbox (recommended)
222
+ # Writes request to Redis, emits stream event.
223
+ # Human replies via the ADK-Frontend UI.
224
+ # Supports parallel requests per session.
225
+ # "webhook" — External webhook (self-hosted)
226
+ # POSTs to outbound_url, human responds via inbound webhook.
227
+ # Also supports native channel adapters (Slack, Telegram, etc.)
228
+ # "api" — Python callback handler (testing/custom integrations)
229
+ #
230
+ # HITL (Human-in-the-Loop) dual-mode flow:
231
+ # 1. System-initiated: greeter → client (HITL) → processor
232
+ # - Greeter sends result to client for human review
233
+ # - Human sees request in ADK-Frontend inbox
234
+ # - Human responds → routes to processor
235
+ #
236
+ # 2. Human-initiated: client → greeter → client (HITL) → processor
237
+ # - Human contacts mesh via webhook to "human_contact" entry point
238
+ # - Client routes to greeter (from_agent not set → first can_call match)
239
+ # - Greeter responds back to client (dual callback)
240
+ # - Human reviews in inbox → responds → routes to processor
241
+ #
242
+ # The can_call conditions use "from_agent" to distinguish who called:
243
+ # - No from_agent → first contact, route to greeter
244
+ # - from_agent == "greeter_agent" → greeter finished, route to processor
245
+ # ─────────────────────────────────────────────
246
+ client:
247
+ name: "client"
248
+ agent_type: "human"
249
+ is_human_powered: true
250
+ human_interface: "default" # ADK-Frontend inbox (recommended)
251
+ communication_type: "dual" # dual mode: request + wait for human response
252
+ human_timeout_seconds: 300
253
+ # operator_ids: # Operators who can see this agent's inbox requests
254
+ # - "alice@company.com" # Leave empty (or omit) for broadcast — all operators see it
255
+ # - "bob@company.com"
256
+
257
+ # Human-specific templates (customize how context/prompts are presented)
258
+ # human_context_template: "Session {{session_id}}: {{context}}"
259
+ # human_prompt_template: "Please review the following and respond: {{message}}"
260
+
261
+ # Require explicit human confirmation before proceeding
262
+ # require_human_confirmation: false
263
+
264
+ # Conditions that trigger human escalation (e.g. keywords in the request)
265
+ # human_escalation_triggers:
266
+ # - "urgent"
267
+ # - "high_value"
268
+
269
+ # Fallback when human doesn't respond in time
270
+ # fallback_on_timeout: true
271
+ # fallback_response:
272
+ # decision: "timeout_default"
273
+ # message: "Request timed out"
274
+
275
+ # ── Webhook config (only needed when human_interface: "webhook") ──
276
+ # For self-hosted deployments without ADK-Frontend.
277
+ # Outbound notifies external system, inbound receives human response.
278
+ # NOTE: inbound_endpoint is auto-derived from entry_points — no need to set it.
279
+ # webhook_config:
280
+ # outbound_url: "http://127.0.0.1:9999/human-notify"
281
+ # outbound_headers:
282
+ # Content-Type: "application/json"
283
+ # # Authorization: "Bearer ${WEBHOOK_TOKEN:}"
284
+ # outbound_timeout: 30
285
+ # # inbound_auth_token: "${WEBHOOK_AUTH_TOKEN:}"
286
+ # max_retries: 1
287
+ # retry_delay: 2
288
+ # # response_mapping:
289
+ # # user_reply: "response"
290
+
291
+ # ── Native channel adapters (only needed when human_interface: "webhook") ──
292
+ # Connect this human agent directly to messaging platforms.
293
+ # The SDK registers inbound webhook routes automatically on startup.
294
+ # Uncomment + add credentials for the channels you want.
295
+ #
296
+ # Inbound routes registered per channel:
297
+ # Slack: POST /channels/slack/client/events
298
+ # Telegram: POST /channels/telegram/client/webhook
299
+ # Discord: POST /channels/discord/client/interactions
300
+ # WhatsApp: GET /channels/whatsapp/client/webhook (verification)
301
+ # POST /channels/whatsapp/client/webhook (messages)
302
+ # Teams: POST /channels/teams/client/messages
303
+ # channels:
304
+ # slack:
305
+ # bot_token: "${SLACK_BOT_TOKEN:}" # xoxb-… Bot OAuth token
306
+ # signing_secret: "${SLACK_SIGNING_SECRET:}" # HMAC-SHA256 signing secret
307
+ # listen_channels: ["${SLACK_CHANNEL_ID:}"] # Channel IDs (empty = all)
308
+ # post_channel: "${SLACK_CHANNEL_ID:}"
309
+ #
310
+ # telegram:
311
+ # bot_token: "${TELEGRAM_BOT_TOKEN:}" # Token from @BotFather
312
+ # signing_secret: "${TELEGRAM_SECRET_TOKEN:}" # Optional webhook secret
313
+ # listen_channels: [] # Chat IDs (empty = all)
314
+ # post_channel: ""
315
+ #
316
+ # discord:
317
+ # bot_token: "${DISCORD_BOT_TOKEN:}" # Bot token (no "Bot " prefix)
318
+ # signing_secret: "${DISCORD_PUBLIC_KEY:}" # App public key (Ed25519)
319
+ # listen_channels: [] # Channel IDs (empty = all)
320
+ # post_channel: ""
321
+ #
322
+ # whatsapp:
323
+ # bot_token: "${WHATSAPP_ACCESS_TOKEN:}" # Meta Graph API access token
324
+ # signing_secret: "${META_APP_SECRET:}" # Meta app secret (HMAC-SHA256)
325
+ # post_channel: "${WHATSAPP_PHONE_NUMBER_ID:}" # Phone number ID (not phone number)
326
+ # verify_token: "leafmesh_whatsapp_verify" # Match this in Meta developer dashboard
327
+ #
328
+ # teams:
329
+ # bot_token: "${TEAMS_APP_ID:}" # Bot Framework App ID
330
+ # signing_secret: "${TEAMS_APP_PASSWORD:}" # Bot Framework App password
331
+ # post_channel: "" # Set at runtime from inbound activity
332
+
333
+ yields:
334
+ request_data: "object"
335
+
336
+ inputs:
337
+ user_message: "string"
338
+ request_type: "string"
339
+
340
+ # auto_store_response: true # Auto-store responses in Redis (default: true)
341
+ # auto_store_yields: true # Auto-store yields in Redis (default: true)
342
+
343
+ # HITL routing — from_agent distinguishes who called the human agent
344
+ # When greeter calls client: from_agent == "greeter_agent" → route to processor
345
+ # When human initiates (no from_agent): route to greeter first
346
+ can_call:
347
+ - agent: "greeter_agent"
348
+ condition: "not calling_agent_response.from_agent"
349
+ - agent: "processor_agent"
350
+ condition: "calling_agent_response.from_agent == 'greeter_agent'"
351
+
352
+ # ─────────────────────────────────────────────
353
+ # LLM AGENT — @pre_compose prepares data, context_parts shape tone
354
+ # auto_discover matches greeter_agent() in agency/greeter_agent.py
355
+ #
356
+ # Flow: processors run → context_parts injected → LLM called →
357
+ # agent function post-processes → can_call chains to next
358
+ # ─────────────────────────────────────────────
359
+ greeter_agent:
360
+ name: "greeter_agent"
361
+ agent_type: "llm"
362
+ description: "Greets the user and gathers their requirements"
363
+ # ── Supported models (auto-routed to correct provider by model name) ──
364
+ # OpenAI: gpt-4o-mini, gpt-4o, gpt-4.1, gpt-4.1-mini, gpt-4.1-nano, gpt-5.1, gpt-5.2
365
+ # OpenAI o: o1, o1-mini, o3, o3-mini, o4-mini (reasoning models — use thinking: true)
366
+ # Anthropic: claude-opus-4-6, claude-sonnet-4-6, claude-haiku-4-5-20251001
367
+ # Google: gemini-2.0-flash, gemini-2.5-pro, gemini-3-pro-preview
368
+ # DeepSeek: deepseek-chat, deepseek-reasoner (R1 — native chain-of-thought)
369
+ # Bedrock: bedrock/<model-id> (requires mesh.bedrock config)
370
+ # Vertex: vertex/<model-id> (requires mesh.vertex config)
371
+ # Foundry: foundry/<deployment> (requires mesh.foundry config)
372
+ # Local: any name (e.g. llama3, mistral-7b) — requires mesh.local config
373
+ model: "gpt-4o-mini"
374
+ temperature: 0.7
375
+ max_tokens: 1000
376
+ # max_completion_tokens: 2000 # For newer models (o1, gpt-5.x) — use instead of max_tokens
377
+ communication_type: "dual" # Options: "dual", "chain", "execute"
378
+ reasoning: true # SDK chain-of-thought tool injection (works with any model)
379
+ # thinking: true # Native model thinking (Anthropic/OpenAI o-series/Gemini 2.5+)
380
+ # thinking_budget: 8192 # Max thinking tokens (1024-32768)
381
+ # enable_prompt_caching: true # Provider-native prompt caching (Anthropic: ~90% savings)
382
+ # optimization_strategy: "performance" # "performance" | "cost" | "speed"
383
+
384
+ prompt: |
385
+ You are a friendly assistant. Given the user's message,
386
+ greet them warmly and summarize what they need help with.
387
+ Return a clear, structured JSON summary with keys:
388
+ "greeting", "user_need", "suggested_actions"
389
+
390
+ # Structured output — force LLM to respond with valid JSON matching this schema
391
+ # response_format:
392
+ # type: "object"
393
+ # properties:
394
+ # greeting: { type: "string" }
395
+ # user_need: { type: "string" }
396
+ # suggested_actions: { type: "array", items: { type: "string" } }
397
+ # required: ["greeting", "user_need"]
398
+
399
+ # Context parts — injected as separate system messages before LLM call
400
+ # Each part shapes HOW the LLM responds (tone, analysis, safety)
401
+ context_parts:
402
+ care: |
403
+ Always respond with empathy and warmth. Acknowledge the user's
404
+ situation before jumping to solutions. Use encouraging language
405
+ and offer reassurance when the user seems frustrated.
406
+ sentiment_analysis: |
407
+ Analyze the user's emotional tone before responding.
408
+ If negative sentiment detected, prioritize acknowledgment over action.
409
+ If positive, match their energy and build on momentum.
410
+ Include a 'detected_sentiment' field in your JSON response.
411
+ guardrails: |
412
+ Never share internal system details or agent architecture.
413
+ Do not make promises about timelines or guarantees.
414
+ If the request is outside your domain, clearly redirect.
415
+ Refuse harmful, illegal, or unethical requests.
416
+
417
+ yields:
418
+ greeting: "string"
419
+ user_input: "string"
420
+ detected_sentiment: "string"
421
+ status: "string"
422
+
423
+ inputs:
424
+ message: "string"
425
+
426
+ # LLM can call these tools during generation
427
+ tools: ["word_count", "timestamp"]
428
+ # tool_categories: ["data"] # Grant access to an entire tool category
429
+ tool_choice: "auto"
430
+ max_tool_calls_per_message: 5
431
+ # tool_call_timeout: 30 # Tool execution timeout in seconds (0.1-300, default: 30)
432
+ # allow_parallel_tool_calls: true # Allow tools to run in parallel (default: true)
433
+
434
+ # memory: true # Simple bool — enable with defaults
435
+ # memory: # Dict form — full control
436
+ # strategy: "recency" # "recency" | "relevance" | "hybrid"
437
+ # limit: 10
438
+ # cross_session: false
439
+ # memory_limit: 10 # Legacy: max feed posts (prefer memory.limit)
440
+
441
+ # auto_store_response: true
442
+ # auto_store_yields: true
443
+
444
+ # Mesh chain — routes to human agent for review before processing
445
+ # In HITL flow: greeter → client (human reviews) → processor
446
+ can_call:
447
+ - agent: "client"
448
+
449
+ # Narration — plain-English routing hints for the Manager.
450
+ # Evaluated by the Summarizer when conditions alone don't cover everything.
451
+ # The Manager can route to ANY registered agent, not just those in can_call.
452
+ narration: >
453
+ If the user's request is urgent or mentions an escalation keyword,
454
+ route directly to advisor_agent — skip the processing step.
455
+ If the user asks for a scheduled report, route to scheduler_agent.
456
+
457
+ # ─────────────────────────────────────────────
458
+ # PROGRAMMATIC AGENT — @conditional_chain for branching logic
459
+ # auto_discover matches processor_agent() in agency/processor_agent.py
460
+ #
461
+ # Flow: receives greeter output → processes → conditional_chain
462
+ # branches → can_call with conditions fans out to both agents
463
+ # ─────────────────────────────────────────────
464
+ processor_agent:
465
+ name: "processor_agent"
466
+ agent_type: "programmatic"
467
+ description: "Processes the greeter's output into actionable items"
468
+ communication_type: "chain"
469
+ parallel: true # Enable parallel processing
470
+ max_concurrent: 3 # Max concurrent invocations
471
+ # auto_store_response: true # Auto-store responses in Redis (default: true)
472
+ # auto_store_yields: true # Auto-store yields in Redis (default: true)
473
+
474
+ yields:
475
+ processed_items: "list"
476
+ item_count: "number"
477
+ status: "string"
478
+ alert: "string"
479
+
480
+ inputs:
481
+ greeter_result: "object"
482
+
483
+ # Fan-out: researcher, fallback_researcher, and advisor are all called
484
+ can_call:
485
+ - agent: "researcher_agent"
486
+ condition: "calling_agent_response.item_count > 0"
487
+ - agent: "fallback_researcher_agent"
488
+ condition: "calling_agent_response.item_count > 0"
489
+ - agent: "advisor_agent"
490
+ condition: "calling_agent_response.item_count > 0"
491
+
492
+ # Narration — non-definitive routing the Manager evaluates via the Summarizer.
493
+ # These hints catch cases conditions can't express as boolean checks.
494
+ narration: >
495
+ If the processed items contain anything safety-related or flagged as high-risk,
496
+ route to advisor_agent immediately without waiting for research.
497
+ If the alert field mentions a data quality issue, route to fallback_researcher_agent only.
498
+
499
+ # ─────────────────────────────────────────────
500
+ # LLM AGENT — @chain_with_results for accumulating pipeline
501
+ # auto_discover matches researcher_agent() in agency/researcher_agent.py
502
+ #
503
+ # Features: memory, tool_categories, reasoning, parallel tool calls
504
+ # optimization_strategy controls model selection:
505
+ # "performance" — pick the most capable model
506
+ # "cost" — pick the cheapest model that meets quality
507
+ # "speed" — pick the lowest-latency model
508
+ # ─────────────────────────────────────────────
509
+ researcher_agent:
510
+ name: "researcher_agent"
511
+ agent_type: "llm"
512
+ description: "Researches topics using tools and memory context"
513
+ model: "gpt-4o-mini"
514
+ temperature: 0.5
515
+ max_tokens: 1500
516
+ communication_type: "chain"
517
+ optimization_strategy: "performance"
518
+ reasoning: true # SDK chain-of-thought tool injection
519
+ thinking: true # Native model thinking for deep analysis
520
+ thinking_budget: 8192 # Max thinking tokens
521
+ enable_prompt_caching: true # Cache system prompt + tools (~90% savings on Anthropic)
522
+
523
+ # ── Smart memory (BRD-009) ──
524
+ # Dict form enables advanced memory strategies. No external deps — Redis only.
525
+ # "hybrid" blends recency + relevance scoring for context selection.
526
+ memory:
527
+ strategy: "hybrid" # "recency" | "relevance" | "hybrid"
528
+ limit: 10 # Max feed posts to load per invocation
529
+ cross_session: true # Persist memory across sessions
530
+ cross_session_limit: 50 # Max cross-session posts to retain
531
+ relevance_weight: 0.6 # Weight for relevance scoring (0.0-1.0)
532
+ recency_weight: 0.4 # Weight for recency scoring (0.0-1.0)
533
+ decay_hours: 24 # Hours before old entries decay
534
+
535
+ prompt: |
536
+ You are a research analyst. Analyze the provided data thoroughly.
537
+ Use available tools to gather additional information.
538
+ Return structured findings with confidence scores.
539
+
540
+ yields:
541
+ findings: "list"
542
+ query: "string"
543
+ analysis: "object"
544
+ report: "object"
545
+ status: "string"
546
+
547
+ inputs:
548
+ research_topic: "string"
549
+ processed_data: "object"
550
+
551
+ # Tools: specific tools + entire category
552
+ tools: ["math_eval", "timestamp", "sensitive_data_lookup"]
553
+ tool_categories: ["data"]
554
+ tool_choice: "auto"
555
+ allow_parallel_tool_calls: true
556
+ max_tool_calls_per_message: 10
557
+ # tool_call_timeout: 30
558
+ # auto_store_response: true
559
+ # auto_store_yields: true
560
+
561
+ can_call:
562
+ - agent: "advisor_agent"
563
+
564
+ # ─────────────────────────────────────────────
565
+ # PROGRAMMATIC AGENT — Fast fallback researcher (no LLM)
566
+ # auto_discover matches fallback_researcher_agent() in agency/fallback_researcher_agent.py
567
+ #
568
+ # Race pattern: runs instantly while researcher_agent waits for LLM.
569
+ # advisor_agent's OR fan-in resolves as soon as this completes.
570
+ # ─────────────────────────────────────────────
571
+ fallback_researcher_agent:
572
+ name: "fallback_researcher_agent"
573
+ agent_type: "programmatic"
574
+ description: "Fast template-based research fallback — instant, no LLM"
575
+ communication_type: "chain"
576
+
577
+ yields:
578
+ findings: "list"
579
+ query: "string"
580
+ analysis: "object"
581
+ report: "object"
582
+ status: "string"
583
+
584
+ inputs:
585
+ processed_data: "object"
586
+
587
+ can_call:
588
+ - agent: "advisor_agent"
589
+
590
+ # ─────────────────────────────────────────────
591
+ # LLM AGENT — @chain + @compose (fan-in advisor)
592
+ # auto_discover matches advisor_agent() in agency/advisor_agent.py
593
+ #
594
+ # Flow: waits for processor AND researcher → LLM analyzes →
595
+ # @compose shapes output → @chain validates + scores
596
+ # ─────────────────────────────────────────────
597
+ advisor_agent:
598
+ name: "advisor_agent"
599
+ agent_type: "llm"
600
+ description: "Analyzes upstream results and produces actionable recommendations"
601
+ model: "gpt-4o-mini"
602
+ temperature: 0.3
603
+ max_tokens: 1000
604
+ communication_type: "chain"
605
+ optimization_strategy: "performance"
606
+
607
+ # ── Fan-in with OR expression ──
608
+ # Waits for processor AND whichever research agent finishes first.
609
+ # The fallback_researcher_agent is instant (programmatic), so this
610
+ # typically resolves before researcher_agent's LLM call completes.
611
+ #
612
+ # Supported wait_for patterns:
613
+ # "A AND B" — waits for both A and B
614
+ # "A OR B" — waits for either A or B (first wins)
615
+ # "A AND B?" — A required, B optional
616
+ # "A AND (B OR C)" — A required + first of B or C (used here)
617
+ # "A AND (B OR C) AND D?" — A required + first of B/C + D optional
618
+ # When called from processor_agent chain: waits for processor + research
619
+ # When called from scheduler_agent: no wait_for needed (single upstream)
620
+ # The SDK evaluates wait_for only when multiple upstreams are pending.
621
+ wait_for: "processor_agent AND (researcher_agent OR fallback_researcher_agent)"
622
+ wait_for_timeout: 120
623
+
624
+ prompt: |
625
+ You are a strategic advisor. Analyze the processed data and research
626
+ findings provided. Produce actionable recommendations with priority
627
+ scoring. Identify risks and suggest concrete next steps.
628
+
629
+ yields:
630
+ recommendations: "list"
631
+ risk_assessment: "string"
632
+ priority_score: "number"
633
+ next_steps: "list"
634
+ status: "string"
635
+
636
+ # Strict yields contract — Manager auto-retries (with feedback) when the
637
+ # advisor's output doesn't match the schema above. Each retry sees the
638
+ # previous (wrong) output + validation errors as _rerun_context so the
639
+ # LLM can self-correct. After enforce_yields_retry attempts, the
640
+ # Manager escalates instead of looping forever.
641
+ # enforce_yields: true
642
+ # enforce_yields_retry: 2
643
+
644
+ inputs:
645
+ processed_data: "object"
646
+ research_findings: "object"
647
+
648
+ # auto_store_response: true
649
+ # auto_store_yields: true
650
+
651
+ # ─────────────────────────────────────────────
652
+ # SCHEDULED AGENT — Cron wake_up + on-demand entry point
653
+ # auto_discover matches scheduler_agent() in agency/scheduler_agent.py
654
+ # Runs daily at 9 AM UTC AND via mesh_call("scheduled_report", data)
655
+ # Chains output to advisor_agent for LLM-powered analysis
656
+ # ─────────────────────────────────────────────
657
+ scheduler_agent:
658
+ name: "scheduler_agent"
659
+ agent_type: "programmatic"
660
+ description: "Generates periodic status reports and chains to advisor for analysis"
661
+ communication_type: "chain" # Chain output to downstream agents
662
+ wake_up: "0 9 * * *" # Every day at 9 AM UTC
663
+
664
+ yields:
665
+ report: "string"
666
+ generated_at: "string"
667
+ checks: "object"
668
+ metrics: "object"
669
+ status: "string"
670
+
671
+ inputs:
672
+ trigger: "string"
673
+
674
+ # memory: false # Enable if scheduler needs historical context
675
+ # auto_store_response: true
676
+ # auto_store_yields: true
677
+
678
+ # Chain scheduled reports to advisor for analysis
679
+ can_call:
680
+ - agent: "advisor_agent"
681
+ condition: "calling_agent_response.status == 'report_generated'"
682
+
683
+ # ═══════════════════════════════════════════════════
684
+ # EXTERNAL AGENTS (uncomment when framework is installed)
685
+ # One agent = one specific action/workflow/graph.
686
+ # Create multiple agents with different connector_config for multiple workflows.
687
+ # See agency/external_agents.py for Python implementations
688
+ # ═══════════════════════════════════════════════════
689
+
690
+ # ─── CrewAI ───
691
+ # crewai_research:
692
+ # name: "crewai_research"
693
+ # agent_type: "external"
694
+ # framework: "crewai"
695
+ # description: "Delegates research to a CrewAI crew"
696
+ # connector_config:
697
+ # endpoint: "${CREWAI_ENDPOINT:http://localhost:9000}" # Required
698
+ # api_key: "${CREWAI_API_KEY:}" # Bearer Token
699
+ # # user_api_key: "${CREWAI_USER_API_KEY:}" # User Bearer Token (preferred over api_key)
700
+ # # poll_interval: 2.0 # Seconds between status polls (default: 2.0)
701
+ # # max_poll_seconds: 300.0 # Max total polling time (default: 300)
702
+ # # http_timeout: 30.0 # HTTP request timeout (default: 30)
703
+ # yields:
704
+ # research_result: "string"
705
+ # sources: "list"
706
+ # can_call:
707
+ # - agent: "advisor_agent"
708
+
709
+ # ─── LangGraph ───
710
+ # langgraph_workflow:
711
+ # name: "langgraph_workflow"
712
+ # agent_type: "external"
713
+ # framework: "langgraph"
714
+ # description: "Runs a LangGraph stateful workflow"
715
+ # connector_config:
716
+ # endpoint: "${LANGGRAPH_ENDPOINT:http://localhost:8123}" # Required
717
+ # api_key: "${LANGCHAIN_API_KEY:}"
718
+ # graph_id: "my_graph" # Workflow selector — which graph to run (default: "agent")
719
+ # # poll_interval: 1.0
720
+ # # max_poll_seconds: 300.0
721
+ # # http_timeout: 30.0
722
+ # yields:
723
+ # workflow_result: "object"
724
+
725
+ # ─── AutoGen ───
726
+ # autogen_team:
727
+ # name: "autogen_team"
728
+ # agent_type: "external"
729
+ # framework: "autogen"
730
+ # description: "Multi-agent conversation via external AutoGen Studio"
731
+ # connector_config:
732
+ # endpoint: "http://localhost:8081" # AutoGen Studio or custom API URL
733
+ # # api_key: "${AUTOGEN_API_KEY:}" # Bearer token (optional)
734
+ # # workflow_id: "" # Workflow/agent ID to execute
735
+ # # timeout: 120 # HTTP request timeout (seconds)
736
+ # # poll_interval: 2 # Seconds between status polls
737
+ # # max_poll_seconds: 300 # Max total polling time
738
+ # yields:
739
+ # team_result: "string"
740
+
741
+ # ─── A2A (Agent-to-Agent Protocol) ───
742
+ # a2a_partner:
743
+ # name: "a2a_partner"
744
+ # agent_type: "external"
745
+ # framework: "a2a"
746
+ # description: "Communicates with an A2A-compatible agent"
747
+ # connector_config:
748
+ # url: "${A2A_AGENT_URL:http://partner-agent:8080}" # Required (use 'url', not 'endpoint')
749
+ # auth_token: "${A2A_AUTH_TOKEN:}"
750
+ # # auth_scheme: "Bearer" # Authorization header scheme (default: "Bearer")
751
+ # # poll_interval: 2.0
752
+ # # max_poll_seconds: 300.0
753
+ # # http_timeout: 30.0
754
+ # yields:
755
+ # partner_response: "object"
756
+
757
+ # ─── MCP (Model Context Protocol) ─── http transport
758
+ # mcp_http_tool:
759
+ # name: "mcp_http_tool"
760
+ # agent_type: "external"
761
+ # framework: "mcp"
762
+ # description: "Access tools from an MCP server via HTTP"
763
+ # connector_config:
764
+ # tool_name: "my_tool" # Required: name of the tool to call
765
+ # transport: "http" # "http" or "stdio"
766
+ # url: "${MCP_ENDPOINT:http://localhost:5000}" # MCP server URL (use 'url', not 'endpoint')
767
+ # auth_token: "${MCP_API_KEY:}"
768
+ # # timeout: 60.0
769
+ # yields:
770
+ # tool_results: "object"
771
+
772
+ # ─── MCP (Model Context Protocol) ─── stdio transport
773
+ # mcp_stdio_tool:
774
+ # name: "mcp_stdio_tool"
775
+ # agent_type: "external"
776
+ # framework: "mcp"
777
+ # description: "Access tools from a local MCP server via stdio"
778
+ # connector_config:
779
+ # tool_name: "my_tool" # Required: name of the tool to call
780
+ # transport: "stdio"
781
+ # command: "npx" # Executable to launch
782
+ # args: ["-y", "@mcp/server-npm"] # Command arguments
783
+ # # env: # Environment variables for subprocess
784
+ # # MY_VAR: "value"
785
+ # # timeout: 60.0
786
+ # yields:
787
+ # tool_results: "object"
788
+
789
+ # ─── Zapier ───
790
+ # zapier_sheets:
791
+ # name: "zapier_sheets"
792
+ # agent_type: "external"
793
+ # framework: "zapier"
794
+ # description: "Trigger Zapier actions — MCP path (prefer_mcp=true) or REST fallback"
795
+ # connector_config:
796
+ # connection: "google_sheets" # App name (connection + action = tool name)
797
+ # action: "create_row" # Action to perform — workflow selector
798
+ # mcp_key: "${ZAPIER_MCP_KEY:}" # MCP path (preferred)
799
+ # api_key: "${ZAPIER_API_KEY:}" # REST fallback
800
+ # # prefer_mcp: true # Try MCP first, fall back to REST (default: true)
801
+ # # instructions: "" # Natural language instructions (REST path only)
802
+ # # timeout: 60.0
803
+ # yields:
804
+ # action_result: "object"
805
+
806
+ # ─── Composio ───
807
+ # composio_github:
808
+ # name: "composio_github"
809
+ # agent_type: "external"
810
+ # framework: "composio"
811
+ # description: "Access Composio-managed integrations"
812
+ # connector_config:
813
+ # action: "GITHUB_STAR_A_REPOSITORY" # Required: single Composio action — workflow selector
814
+ # entity_id: "default" # User/entity to act on behalf of
815
+ # api_key: "${COMPOSIO_API_KEY:}"
816
+ # # timeout: 60.0
817
+ # yields:
818
+ # integration_result: "object"
819
+
820
+ # ─── n8n ───
821
+ # n8n_workflow:
822
+ # name: "n8n_workflow"
823
+ # agent_type: "external"
824
+ # framework: "n8n"
825
+ # description: "Trigger n8n workflows via webhook"
826
+ # connector_config:
827
+ # webhook_url: "${N8N_WEBHOOK_URL:}" # Required — each workflow has its own URL
828
+ # auth_token: "${N8N_AUTH_TOKEN:}"
829
+ # # timeout: 60.0 # HTTP timeout (sync mode only)
830
+ # # mode: "sync" # "sync" (default) or "callback"
831
+ # # callback_timeout: 120.0 # Seconds to wait for callback (callback mode only)
832
+ # yields:
833
+ # workflow_result: "object"
834
+ #
835
+ # n8n + callback mode:
836
+ # Use mode: "callback" when n8n workflow uses "Respond Immediately".
837
+ # LeafMesh injects _leafmesh_callback_url + _leafmesh_session_id into payload.
838
+ # n8n workflow should end with HTTP Request node POSTing result back to that URL.
839
+ #
840
+ # n8n_async_workflow:
841
+ # name: "n8n_async_workflow"
842
+ # agent_type: "external"
843
+ # framework: "n8n"
844
+ # description: "Long-running n8n workflow with async callback"
845
+ # connector_config:
846
+ # webhook_url: "${N8N_WEBHOOK_URL:}"
847
+ # mode: "callback"
848
+ # callback_timeout: 300.0 # 5 min — workflow takes time to process
849
+ # yields:
850
+ # workflow_result: "object"
851
+
852
+ # ═══════════════════════════════════════════════════
853
+ # PROGRAMMATIC + INTEGRATION AGENTS
854
+ # Same connectors as external agents but paired with Python intelligence.
855
+ # SDK reads connector_config in the same way — pass connection details here.
856
+ # One agent = one specific action/workflow.
857
+ # ═══════════════════════════════════════════════════
858
+
859
+ # ─── Zapier (programmatic) ───
860
+ # zapier_sheets:
861
+ # name: "zapier_sheets"
862
+ # agent_type: "programmatic"
863
+ # description: "Adds a row to Google Sheets via Zapier"
864
+ # communication_type: "chain"
865
+ # integration: "zapier" # Options: zapier | composio | n8n | mcp
866
+ # connector_config:
867
+ # connection: "google_sheets" # Zapier app name ┐ combined into
868
+ # action: "create_row" # Zapier action ┘ google_sheets_create_row
869
+ # mcp_key: "${ZAPIER_MCP_KEY:}" # MCP path (preferred)
870
+ # api_key: "${ZAPIER_API_KEY:}" # REST fallback
871
+ # # prefer_mcp: true
872
+ # # instructions: ""
873
+ # # timeout: 60.0
874
+ # yields:
875
+ # result: "object"
876
+
877
+ # ─── Composio (programmatic) ───
878
+ # composio_github:
879
+ # name: "composio_github"
880
+ # agent_type: "programmatic"
881
+ # description: "Stars a GitHub repo via Composio"
882
+ # communication_type: "chain"
883
+ # integration: "composio"
884
+ # connector_config:
885
+ # action: "GITHUB_STAR_A_REPOSITORY" # Required: Composio action enum (UPPERCASE)
886
+ # entity_id: "default" # User/entity context
887
+ # api_key: "${COMPOSIO_API_KEY:}"
888
+ # # timeout: 60.0
889
+ # yields:
890
+ # result: "object"
891
+
892
+ # ─── n8n (programmatic) ───
893
+ # n8n_notify:
894
+ # name: "n8n_notify"
895
+ # agent_type: "programmatic"
896
+ # description: "Triggers an n8n workflow via webhook"
897
+ # communication_type: "chain"
898
+ # integration: "n8n"
899
+ # connector_config:
900
+ # webhook_url: "${N8N_WEBHOOK_URL:}" # Required — each workflow has its own URL
901
+ # auth_token: "${N8N_AUTH_TOKEN:}"
902
+ # # timeout: 60.0
903
+ # # mode: "callback" # Use callback for async/long-running workflows
904
+ # # callback_timeout: 120.0
905
+ # yields:
906
+ # result: "object"
907
+
908
+ # ─── MCP (programmatic) ─── http transport
909
+ # mcp_search:
910
+ # name: "mcp_search"
911
+ # agent_type: "programmatic"
912
+ # description: "Calls a specific tool on an MCP server"
913
+ # communication_type: "chain"
914
+ # integration: "mcp"
915
+ # connector_config:
916
+ # tool_name: "web_search" # Required: tool to invoke
917
+ # transport: "http" # "http" or "stdio"
918
+ # url: "${MCP_ENDPOINT:http://localhost:5000}" # MCP server URL
919
+ # auth_token: "${MCP_API_KEY:}"
920
+ # # timeout: 60.0
921
+ # yields:
922
+ # result: "object"
923
+
924
+ # ─── MCP (programmatic) ─── stdio transport
925
+ # mcp_local:
926
+ # name: "mcp_local"
927
+ # agent_type: "programmatic"
928
+ # description: "Calls a tool on a local MCP server via stdio"
929
+ # communication_type: "chain"
930
+ # integration: "mcp"
931
+ # connector_config:
932
+ # tool_name: "my_tool" # Required: tool to invoke
933
+ # transport: "stdio"
934
+ # command: "npx"
935
+ # args: ["-y", "@mcp/server-npm"]
936
+ # # env:
937
+ # # MY_VAR: "value"
938
+ # # timeout: 60.0
939
+ # yields:
940
+ # result: "object"
941
+
942
+ # ═══════════════════════════════════════════════════
943
+ # DATA STRUCTURES — Custom data type definitions (optional)
944
+ # Define shared schemas that agents can reference for validation
945
+ # ═══════════════════════════════════════════════════
946
+ # data_structures:
947
+ # customer_profile:
948
+ # type: "object"
949
+ # properties:
950
+ # name: { type: "string" }
951
+ # email: { type: "string" }
952
+ # tier: { type: "string" }
953
+ # required: ["name", "email"]
954
+ # validation_rules:
955
+ # email: "email_format"
956
+ # order_item:
957
+ # type: "object"
958
+ # properties:
959
+ # product_id: { type: "string" }
960
+ # quantity: { type: "number" }
961
+ # price: { type: "number" }
962
+ # required: ["product_id", "quantity"]
963
+
964
+ # Self-healing is always enabled (core safety feature, no config needed)
965
+
966
+ # ═══════════════════════════════════════════════════
967
+ # EVOLUTION — Genetic algorithm optimization
968
+ # Set enabled: true and provide test_scenarios to auto-run on start()
969
+ # Or call leafmesh.evolve_mesh_architecture(scenarios) at runtime
970
+ # ═══════════════════════════════════════════════════
971
+ # evolution:
972
+ # enabled: true
973
+ # strategy: "genetic"
974
+ # population_size: 10
975
+ # generations: 50
976
+ # mutation_rate: 0.1
977
+ # crossover_rate: 0.7
978
+ # elite_size: 2
979
+ # mutation_types:
980
+ # - "prompt_variation"
981
+ # - "temperature_adjustment"
982
+ # - "tool_selection"
983
+ # fitness_function: "task_completion_rate"
984
+ # selection_method: "tournament"
985
+ # test_scenarios: []
986
+
987
+ # ═══════════════════════════════════════════════════
988
+ # OBSERVABILITY
989
+ #
990
+ # Observability auto-enables when LEAFMESH_LICENSE_KEY is set in .env.
991
+ # No YAML config needed — traces, metrics, and logs flow automatically.
992
+ # Set LEAFMESH_ENV_TOKEN in .env to group telemetry by environment.
993
+ # ═══════════════════════════════════════════════════
994
+
995
+ # ═══════════════════════════════════════════════════
996
+ # API ENDPOINTS (built-in, no config needed)
997
+ #
998
+ # Trigger workflows:
999
+ # POST /api/mesh/request — trigger agent workflow via entry point
1000
+ # POST /api/mesh/stream — SSE stream of LLM response via entry point
1001
+ # GET /api/mesh/entry_points — list available entry points
1002
+ #
1003
+ # Webhooks (HITL + external integrations):
1004
+ # POST /webhook/{entry_point} — new task OR resume human HITL response
1005
+ # GET /api/webhook/secret — HMAC signing secret for webhook auth
1006
+ #
1007
+ # Sessions:
1008
+ # POST /api/sessions/{session_id}/agents/{agent_name}/rerun
1009
+ # — re-run an agent in an existing session
1010
+ # with optional feedback / new input
1011
+ # (used by ADK Studio "Rerun" button;
1012
+ # mirrors sdk.rerun_agent in Python)
1013
+ #
1014
+ # Native channel adapters (registered when channels: is configured on a human agent):
1015
+ # POST /channels/slack/{agent}/events — Slack Events API
1016
+ # POST /channels/telegram/{agent}/webhook — Telegram Bot updates
1017
+ # POST /channels/discord/{agent}/interactions — Discord interactions
1018
+ # GET /channels/whatsapp/{agent}/webhook — WhatsApp webhook verification
1019
+ # POST /channels/whatsapp/{agent}/webhook — WhatsApp messages
1020
+ # POST /channels/teams/{agent}/messages — Microsoft Teams activities
1021
+ #
1022
+ # Config validation:
1023
+ # POST /api/yaml/validate — validate a full config body (for editors)
1024
+ #
1025
+ # System:
1026
+ # GET /health — health check
1027
+ # GET /docs — interactive API docs (ReDoc)
1028
+ # ═══════════════════════════════════════════════════