mirror of
https://github.com/tinyhumansai/openhuman.git
synced 2026-07-27 21:08:00 +00:00
This commit is contained in:
@@ -887,6 +887,21 @@ const CAPABILITIES: &[Capability] = &[
|
||||
status: CapabilityStatus::Beta,
|
||||
privacy: None,
|
||||
},
|
||||
Capability {
|
||||
id: "automation.crypto_agent",
|
||||
name: "Crypto Agent",
|
||||
domain: "automation",
|
||||
category: CapabilityCategory::Automation,
|
||||
description: "Dedicated wallet & market specialist sub-agent. The orchestrator \
|
||||
routes transfers, swaps, contract calls, balance lookups, and \
|
||||
exchange trading requests here. The agent enforces a read → \
|
||||
simulate → confirm → execute flow, refuses to fabricate chain ids \
|
||||
or token addresses, and gates every write call behind explicit \
|
||||
user confirmation.",
|
||||
how_to: "Automatic — invoked by the orchestrator when a crypto wallet or market action is requested. Connect a wallet via Settings > Recovery Phrase first.",
|
||||
status: CapabilityStatus::Beta,
|
||||
privacy: LOCAL_CREDENTIALS,
|
||||
},
|
||||
Capability {
|
||||
id: "automation.welcome_agent",
|
||||
name: "Welcome Message",
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
id = "crypto_agent"
|
||||
display_name = "Crypto Agent"
|
||||
delegate_name = "do_crypto"
|
||||
when_to_use = "Crypto wallet & market specialist — drives wallet balances, quotes, transfers, swaps, contract calls, and exchange trading workflows on the user's connected wallet identities. Use whenever a request is about on-chain balances, sending/receiving tokens, swapping or routing across chains, signing a contract call, or executing/inspecting market orders on a connected crypto exchange. Always read/simulate before signing; refuse to proceed on missing wallet setup, missing chain, missing liquidity, or unconfirmed intent."
|
||||
temperature = 0.2
|
||||
max_iterations = 8
|
||||
sandbox_mode = "none"
|
||||
|
||||
# Crypto agent has a tight single-purpose voice and gets its own safety
|
||||
# rules from the prompt body — the global identity/skills boilerplate
|
||||
# would dilute them, but the standard safety preamble stays on as a
|
||||
# belt-and-suspenders gate on financial-risk actions.
|
||||
omit_identity = true
|
||||
omit_memory_context = true
|
||||
omit_safety_preamble = false
|
||||
omit_skills_catalog = true
|
||||
|
||||
[model]
|
||||
hint = "agentic"
|
||||
|
||||
[tools]
|
||||
# Narrow allowlist. Wallet + market primitives only — no shell, no
|
||||
# file_write, no broad HTTP, no integration delegation. Names line up
|
||||
# with the wallet RPC controllers in `src/openhuman/wallet/schemas.rs`
|
||||
# (read: status/balances/supported_assets/chain_status; quote/prepare:
|
||||
# prepare_transfer/prepare_swap/prepare_contract_call; execute:
|
||||
# execute_prepared) and the financial-apis crypto/FX series exposed
|
||||
# via `stock_*`. Tools that aren't yet registered are silently dropped
|
||||
# by the tool filter at spawn time, so this list also describes the
|
||||
# agent's *intended* tool surface as wallet + exchange tools land.
|
||||
named = [
|
||||
# Read-only wallet inspection.
|
||||
"wallet_status",
|
||||
"wallet_balances",
|
||||
"wallet_supported_assets",
|
||||
"wallet_chain_status",
|
||||
# Quote / prepare. These MUST be called before any execute_prepared
|
||||
# — they return a deterministic transaction blob plus fee/slippage
|
||||
# estimates the agent shows the user for confirmation.
|
||||
"wallet_prepare_transfer",
|
||||
"wallet_prepare_swap",
|
||||
"wallet_prepare_contract_call",
|
||||
# Sign + broadcast a previously-prepared blob. Refuses to fabricate
|
||||
# parameters — only consumes a `prepared_id` returned by the
|
||||
# matching `wallet_prepare_*` call earlier in this turn.
|
||||
"wallet_execute_prepared",
|
||||
# Market data — crypto series, FX rates, commodities — for grounding
|
||||
# quote sanity checks and price questions before any execute step.
|
||||
"stock_quote",
|
||||
"stock_exchange_rate",
|
||||
"stock_crypto_series",
|
||||
# Memory recall lets the agent ground execution in the user's
|
||||
# previously-stated preferences (default chain, slippage tolerance,
|
||||
# named addresses) instead of re-asking every time.
|
||||
"memory_recall",
|
||||
# Confirmation gate — the agent MUST call this before any
|
||||
# wallet_execute_prepared / write-side exchange order. The runtime
|
||||
# routes the prompt to the user and blocks until they reply.
|
||||
"ask_user_clarification",
|
||||
# Time grounding for "as of <when>" framing and freshness checks on
|
||||
# quotes before execute.
|
||||
"current_time",
|
||||
]
|
||||
@@ -0,0 +1 @@
|
||||
pub mod prompt;
|
||||
@@ -0,0 +1,67 @@
|
||||
# Crypto Agent
|
||||
|
||||
You are the **Crypto Agent** — OpenHuman's specialist for wallet and market operations on the user's connected crypto identities. Every action you take moves real money, so your default posture is **read, simulate, confirm, then execute**.
|
||||
|
||||
## What you handle
|
||||
|
||||
- Reading balances, positions, supported chains and assets across the user's connected wallet identities (EVM, BTC, Solana, Tron, …).
|
||||
- Quoting transfers, swaps and contract calls; surfacing fees, slippage and the destination route.
|
||||
- Executing **only the exact blob** that was returned from a matching `wallet_prepare_*` call earlier in this turn — never a parameter set you invented.
|
||||
- Pulling crypto / FX market data to sanity-check a quote before signing.
|
||||
- Pointing the user back to **Settings → Connections** when a chain, exchange, or wallet identity isn't set up.
|
||||
|
||||
## What you do NOT handle
|
||||
|
||||
- Generic web research, news summaries, regulatory analysis — defer to the researcher.
|
||||
- Code writing, file edits, shell access, broad HTTP. You have no shell, no file_write, no curl.
|
||||
- Service integrations like Gmail / Notion / Slack — delegate via the orchestrator.
|
||||
- Autonomous background trading. You only act on an in-band user instruction with an explicit confirmation.
|
||||
|
||||
## Hard rules
|
||||
|
||||
1. **No fabrication.** Never invent chain ids, token contract addresses, market symbols, fee values, slippage numbers, exchange order ids, or tool names. If you don't have it from a tool result or the user, ask. If a tool isn't in your tool list, say so — do not pretend it exists.
|
||||
2. **Read before write.** Before any `wallet_prepare_*` call, confirm the relevant balance / chain status with `wallet_balances` / `wallet_chain_status` (or a recent earlier-in-turn result). Before any `wallet_execute_prepared`, confirm the freshness of the prepared blob with `current_time` — re-prepare if the quote is older than ~60s.
|
||||
3. **Quote before execute.** A `wallet_execute_prepared` call MUST be preceded by a matching `wallet_prepare_*` call **in this same turn**, and the `prepared_id` you pass MUST be the one that call returned. No exceptions.
|
||||
4. **Confirm before execute.** Before calling `wallet_execute_prepared` (or any write-side exchange order), call `ask_user_clarification` with a tight summary: `from → to`, asset + amount, chain, fee, slippage, and any non-obvious detail (bridging, approval first, etc.). Only proceed on an explicit yes.
|
||||
5. **Stop cleanly on missing setup.** If a wallet identity, chain, exchange connection, or required auth is missing, do not retry, do not guess. Say which thing is missing, point to **Settings → Connections** (or **Settings → Recovery Phrase** for wallet identities), and stop.
|
||||
6. **Stop cleanly on insufficient liquidity / balance.** If a quote fails for liquidity, slippage, or balance reasons, surface the reason verbatim, suggest the smallest viable adjustment (lower amount, different route), and wait for the user.
|
||||
7. **Never log secrets.** Do not echo private keys, seed phrases, mnemonics, exchange API secrets, or signed transaction payloads in your replies. Quote the public address and the prepared id, nothing more.
|
||||
|
||||
## Standard flow
|
||||
|
||||
1. **Frame the intent.** Restate the request in one short sentence: who pays, what asset, on which chain, to whom, why. If anything is ambiguous (chain, asset, recipient), ask once with `ask_user_clarification`.
|
||||
2. **Inspect.** `wallet_status` + `wallet_balances` (and `wallet_chain_status` for the target chain) to confirm the account exists, has the asset, and the chain is reachable. For market questions, `stock_crypto_series` / `stock_exchange_rate` to ground the answer.
|
||||
3. **Quote.** Call the right `wallet_prepare_*` once. Inspect fees, slippage, route. If anything is wildly off (slippage > a sensible bound, fee > a sensible fraction of the transfer, route involves unexpected hops), surface it as a concern, not a fait accompli.
|
||||
4. **Confirm.** Summarise the prepared transaction and call `ask_user_clarification`. Show: source identity (truncated address), destination (full address + label if known), asset + amount, native fee, slippage, est. landing time, prepared id.
|
||||
5. **Execute.** On explicit confirmation, call `wallet_execute_prepared` with the exact `prepared_id`. Report back the broadcast result (tx hash / order id), and the chain explorer URL only if the tool returned one — do not synthesise explorer links from the hash.
|
||||
6. **On failure.** Show a **sanitized** summary of the tool's error — never echo raw payloads, signed transaction blobs, full RPC responses, stack traces, request ids, or any field that could embed a secret. Redact long opaque tokens to a short prefix (e.g. `0xfee…dead`). Then name the likely cause in one line (e.g. "RPC rejected — nonce gap", "insufficient gas"), and stop. Do not auto-retry write operations.
|
||||
|
||||
## Output shape
|
||||
|
||||
Keep replies tight and grounded.
|
||||
|
||||
> checking balances on eth
|
||||
>
|
||||
> you've got 2.43 ETH on ethereum. quote for the 0.5 ETH transfer to `0xabc…123` is:
|
||||
>
|
||||
> - fee: ~0.0012 ETH (~$3)
|
||||
> - eta: ~12s
|
||||
> - prepared id: `tx_8f2…`
|
||||
>
|
||||
> ok to send?
|
||||
|
||||
After execution:
|
||||
|
||||
> sent. tx `0xfee…dead` — confirmed in block 19,422,118.
|
||||
|
||||
On a missing prerequisite:
|
||||
|
||||
> no solana identity set up yet — head to **Settings → Recovery Phrase** to derive one, then ping me back.
|
||||
|
||||
On a failed quote:
|
||||
|
||||
> swap quote failed: slippage would exceed 5% on this route. try a smaller amount or a different DEX route.
|
||||
|
||||
## Why this prompt exists
|
||||
|
||||
The orchestrator delegates crypto work here precisely because generic agents over-assume tool availability and under-confirm financial intent. **Your value is caution, not breadth.** When in doubt, stop and ask.
|
||||
@@ -0,0 +1,133 @@
|
||||
//! System prompt builder for the `crypto_agent` built-in agent.
|
||||
//!
|
||||
//! Crypto Agent is a narrow-scope, write-capable specialist. The body
|
||||
//! is the archetype's read/simulate/confirm/execute contract, followed
|
||||
//! by the standard tool + workspace blocks so the model sees the
|
||||
//! `wallet_*` / `stock_*` schemas the runtime injected. Identity,
|
||||
//! skills catalogue and global memory context are omitted — they would
|
||||
//! dilute the financial-safety voice the archetype establishes.
|
||||
|
||||
use crate::openhuman::context::prompt::{
|
||||
render_safety, render_tools, render_user_files, render_workspace, PromptContext,
|
||||
};
|
||||
use anyhow::Result;
|
||||
|
||||
const ARCHETYPE: &str = include_str!("prompt.md");
|
||||
|
||||
pub fn build(ctx: &PromptContext<'_>) -> Result<String> {
|
||||
tracing::debug!(
|
||||
agent_id = ctx.agent_id,
|
||||
model = ctx.model_name,
|
||||
tool_count = ctx.tools.len(),
|
||||
skill_count = ctx.skills.len(),
|
||||
"[agent_prompt][crypto_agent] build_start"
|
||||
);
|
||||
|
||||
let mut out = String::with_capacity(8192);
|
||||
out.push_str(ARCHETYPE.trim_end());
|
||||
out.push_str("\n\n");
|
||||
|
||||
let user_files = render_user_files(ctx)?;
|
||||
let user_files_present = !user_files.trim().is_empty();
|
||||
if user_files_present {
|
||||
out.push_str(user_files.trim_end());
|
||||
out.push_str("\n\n");
|
||||
}
|
||||
|
||||
let tools = render_tools(ctx)?;
|
||||
let tools_present = !tools.trim().is_empty();
|
||||
if tools_present {
|
||||
out.push_str(tools.trim_end());
|
||||
out.push_str("\n\n");
|
||||
}
|
||||
|
||||
let safety = render_safety();
|
||||
out.push_str(safety.trim_end());
|
||||
out.push_str("\n\n");
|
||||
|
||||
let workspace = render_workspace(ctx)?;
|
||||
let workspace_present = !workspace.trim().is_empty();
|
||||
if workspace_present {
|
||||
out.push_str(workspace.trim_end());
|
||||
out.push('\n');
|
||||
}
|
||||
|
||||
tracing::trace!(
|
||||
agent_id = ctx.agent_id,
|
||||
prompt_len = out.len(),
|
||||
user_files_present,
|
||||
tools_present,
|
||||
workspace_present,
|
||||
"[agent_prompt][crypto_agent] build_done"
|
||||
);
|
||||
Ok(out)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::openhuman::context::prompt::{LearnedContextData, ToolCallFormat};
|
||||
use std::collections::HashSet;
|
||||
|
||||
fn empty_ctx() -> PromptContext<'static> {
|
||||
use std::sync::OnceLock;
|
||||
static EMPTY_VISIBLE: OnceLock<HashSet<String>> = OnceLock::new();
|
||||
PromptContext {
|
||||
workspace_dir: std::path::Path::new("."),
|
||||
model_name: "test",
|
||||
agent_id: "crypto_agent",
|
||||
tools: &[],
|
||||
skills: &[],
|
||||
dispatcher_instructions: "",
|
||||
learned: LearnedContextData::default(),
|
||||
visible_tool_names: EMPTY_VISIBLE.get_or_init(HashSet::new),
|
||||
tool_call_format: ToolCallFormat::PFormat,
|
||||
connected_integrations: &[],
|
||||
connected_identities_md: String::new(),
|
||||
include_profile: false,
|
||||
include_memory_md: false,
|
||||
curated_snapshot: None,
|
||||
user_identity: None,
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn build_returns_nonempty_body() {
|
||||
let body = build(&empty_ctx()).unwrap();
|
||||
assert!(!body.is_empty());
|
||||
assert!(body.contains("Crypto Agent"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn build_enforces_read_simulate_confirm_execute() {
|
||||
let body = build(&empty_ctx()).unwrap();
|
||||
// The four phases must all be visible in the prompt — the agent's
|
||||
// entire safety story rests on them.
|
||||
assert!(
|
||||
body.contains("read, simulate, confirm, then execute")
|
||||
|| body.contains("read/simulate/confirm/execute"),
|
||||
"prompt must spell out the read→simulate→confirm→execute contract"
|
||||
);
|
||||
assert!(
|
||||
body.contains("ask_user_clarification"),
|
||||
"prompt must require explicit user confirmation before execute"
|
||||
);
|
||||
assert!(
|
||||
body.contains("prepared_id"),
|
||||
"execute step must consume a prepared_id, not fabricated parameters"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn build_forbids_fabrication_and_logging_secrets() {
|
||||
let body = build(&empty_ctx()).unwrap();
|
||||
assert!(
|
||||
body.contains("No fabrication"),
|
||||
"prompt must explicitly forbid fabricating chain/token/market params"
|
||||
);
|
||||
assert!(
|
||||
body.contains("Never log secrets") || body.contains("never log secrets"),
|
||||
"prompt must forbid echoing private keys / seed phrases"
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -77,6 +77,11 @@ pub const BUILTINS: &[BuiltinAgent] = &[
|
||||
toml: include_str!("integrations_agent/agent.toml"),
|
||||
prompt_fn: super::integrations_agent::prompt::build,
|
||||
},
|
||||
BuiltinAgent {
|
||||
id: "crypto_agent",
|
||||
toml: include_str!("crypto_agent/agent.toml"),
|
||||
prompt_fn: super::crypto_agent::prompt::build,
|
||||
},
|
||||
BuiltinAgent {
|
||||
id: "tools_agent",
|
||||
toml: include_str!("tools_agent/agent.toml"),
|
||||
@@ -177,7 +182,7 @@ mod tests {
|
||||
fn all_builtins_parse() {
|
||||
let defs = load_builtins().expect("built-in TOML must parse");
|
||||
assert_eq!(defs.len(), BUILTINS.len());
|
||||
assert_eq!(defs.len(), 15, "expected 15 built-in agents");
|
||||
assert_eq!(defs.len(), 16, "expected 16 built-in agents");
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -497,6 +502,135 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
/// Crypto Agent (#1397) is the dedicated specialist for wallet
|
||||
/// actions and market operations. It must have a *narrow* tool
|
||||
/// allowlist (no shell, no file_write, no broad HTTP), MUST keep
|
||||
/// the safety preamble on (financial-risk gate), and MUST require
|
||||
/// quote/confirm-before-execute via `ask_user_clarification`.
|
||||
#[test]
|
||||
fn crypto_agent_has_narrow_wallet_market_tools_and_safety_on() {
|
||||
let def = find("crypto_agent");
|
||||
// Hint must be agentic — the agent reasons about quotes vs.
|
||||
// executes across multiple tool calls per turn.
|
||||
assert!(matches!(def.model, ModelSpec::Hint(ref h) if h == "agentic"));
|
||||
assert_eq!(def.sandbox_mode, SandboxMode::None);
|
||||
// Financial-risk agent — global safety preamble stays ON.
|
||||
assert!(
|
||||
!def.omit_safety_preamble,
|
||||
"crypto_agent must keep the global safety preamble — financial-risk gate"
|
||||
);
|
||||
match &def.tools {
|
||||
ToolScope::Named(tools) => {
|
||||
// Wallet read surface.
|
||||
for required in [
|
||||
"wallet_status",
|
||||
"wallet_balances",
|
||||
"wallet_supported_assets",
|
||||
"wallet_chain_status",
|
||||
] {
|
||||
assert!(
|
||||
tools.iter().any(|t| t == required),
|
||||
"crypto_agent needs read tool `{required}`"
|
||||
);
|
||||
}
|
||||
// Quote / prepare surface.
|
||||
for required in [
|
||||
"wallet_prepare_transfer",
|
||||
"wallet_prepare_swap",
|
||||
"wallet_prepare_contract_call",
|
||||
] {
|
||||
assert!(
|
||||
tools.iter().any(|t| t == required),
|
||||
"crypto_agent needs prepare tool `{required}`"
|
||||
);
|
||||
}
|
||||
// Execute surface — gated by the prepared blob from a
|
||||
// matching prepare_* call in the same turn.
|
||||
assert!(
|
||||
tools.iter().any(|t| t == "wallet_execute_prepared"),
|
||||
"crypto_agent needs wallet_execute_prepared"
|
||||
);
|
||||
// Confirmation gate — MUST be present so the prompt's
|
||||
// "confirm before execute" rule is mechanically enforceable.
|
||||
assert!(
|
||||
tools.iter().any(|t| t == "ask_user_clarification"),
|
||||
"crypto_agent needs ask_user_clarification to gate write ops"
|
||||
);
|
||||
// Market grounding + context helpers. Pin the full set so a
|
||||
// TOML edit that silently drops `stock_quote`,
|
||||
// `stock_exchange_rate`, `memory_recall`, or `current_time`
|
||||
// gets caught here — the agent's quote-before-execute
|
||||
// discipline and "ground in user preferences before re-asking"
|
||||
// behaviour both depend on these being present.
|
||||
for required in [
|
||||
"stock_quote",
|
||||
"stock_exchange_rate",
|
||||
"stock_crypto_series",
|
||||
"memory_recall",
|
||||
"current_time",
|
||||
] {
|
||||
assert!(
|
||||
tools.iter().any(|t| t == required),
|
||||
"crypto_agent needs supporting tool `{required}`"
|
||||
);
|
||||
}
|
||||
// Hard exclusions — no broad-surface or write-anywhere tools.
|
||||
// Includes the orchestrator-level delegate_* tools so a future
|
||||
// TOML edit can't accidentally hand crypto writes to the
|
||||
// generic integrations or code-execution paths.
|
||||
for forbidden in [
|
||||
"shell",
|
||||
"file_write",
|
||||
"curl",
|
||||
"http_request",
|
||||
"composio_execute",
|
||||
"composio_list_tools",
|
||||
"spawn_subagent",
|
||||
"spawn_worker_thread",
|
||||
"delegate_to_integrations_agent",
|
||||
"delegate_run_code",
|
||||
"delegate_research",
|
||||
"delegate_plan",
|
||||
] {
|
||||
assert!(
|
||||
!tools.iter().any(|t| t == forbidden),
|
||||
"crypto_agent must NOT have `{forbidden}` — keeps blast radius bounded"
|
||||
);
|
||||
}
|
||||
}
|
||||
ToolScope::Wildcard => panic!("crypto_agent must have a Named tool scope"),
|
||||
}
|
||||
// Keep iteration cap tight — quote → confirm → execute is a
|
||||
// 3-step loop, not a research crawl.
|
||||
assert!(
|
||||
def.max_iterations <= 10,
|
||||
"crypto_agent max_iterations must stay tight (got {})",
|
||||
def.max_iterations
|
||||
);
|
||||
assert!(def.omit_identity);
|
||||
assert!(def.omit_memory_context);
|
||||
assert!(def.omit_skills_catalog);
|
||||
}
|
||||
|
||||
/// Routing: the orchestrator must list `crypto_agent` in its
|
||||
/// `subagents` so a `delegate_do_crypto` tool is synthesised at
|
||||
/// agent-build time. Without this entry the orchestrator can't
|
||||
/// route crypto-shaped requests to the specialist.
|
||||
#[test]
|
||||
fn orchestrator_subagents_include_crypto_agent() {
|
||||
use crate::openhuman::agent::harness::definition::SubagentEntry;
|
||||
let def = find("orchestrator");
|
||||
let listed = def.subagents.iter().any(|e| match e {
|
||||
SubagentEntry::AgentId(id) => id == "crypto_agent",
|
||||
_ => false,
|
||||
});
|
||||
assert!(
|
||||
listed,
|
||||
"orchestrator.subagents must list `crypto_agent` so the \
|
||||
routing layer can synthesise `delegate_do_crypto`"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn welcome_has_onboarding_and_memory_tools() {
|
||||
let def = find("welcome");
|
||||
|
||||
@@ -7,6 +7,7 @@ mod loader;
|
||||
pub mod archivist;
|
||||
pub mod code_executor;
|
||||
pub mod critic;
|
||||
pub mod crypto_agent;
|
||||
pub mod help;
|
||||
pub mod integrations_agent;
|
||||
pub mod morning_briefing;
|
||||
|
||||
@@ -44,6 +44,12 @@ subagents = [
|
||||
"tools_agent",
|
||||
"critic",
|
||||
"archivist",
|
||||
# Crypto wallet & market specialist (#1397). Synthesised into a
|
||||
# `delegate_do_crypto` tool at agent-build time. Route any wallet,
|
||||
# transfer, swap, contract-call, or exchange trading request here —
|
||||
# the agent enforces a strict read → simulate → confirm → execute
|
||||
# contract that the generic delegation surface does not.
|
||||
"crypto_agent",
|
||||
# NOTE: `summarizer` used to be listed here for the runtime-only
|
||||
# oversized-tool-result hook. That path is currently disabled
|
||||
# (`context.summarizer_payload_threshold_tokens = 0`) after recursive
|
||||
|
||||
@@ -26,6 +26,7 @@ Follow this sequence for every user message:
|
||||
- Yes: use direct tools (`current_time`, `cron_*`, `memory_*`, `composio_list_connections`, etc.).
|
||||
- No: continue.
|
||||
4. **Does this need other specialised execution?**
|
||||
- If the request is about a **crypto wallet or market action** — balances, transfers, swaps, contract calls, on-chain positions, or trading on a connected exchange — use `delegate_do_crypto`. It enforces read → simulate → confirm → execute and refuses to fabricate chain ids, token addresses, market symbols, or unsupported tools. **Do not** route crypto write operations through `delegate_to_integrations_agent` or `delegate_run_code`.
|
||||
- If code writing/execution/debugging is required, use `delegate_run_code`.
|
||||
- If web/doc crawling is required, use `delegate_researcher`.
|
||||
- If complex multi-step decomposition is required, use `delegate_plan`.
|
||||
|
||||
Reference in New Issue
Block a user