प्रबंधित एजेंट रनटाइम
स्थिरता: प्रयोगात्मक — यह सुविधा अतिरिक्त है और
managed-runtimeके पीछे फीचर-गेटेड है। सुविधा अक्षम होने पर यह मौजूदाRunner/LlmAgentAPIs को प्रभावित नहीं करती। भविष्य के रिलीज़ में API सतह बदल सकती है।
अवलोकन
प्रबंधित एजेंट रनटाइम (adk-managed) एक प्रदाता-निरपेक्ष, टिकाऊ और पुनःआरंभ योग्य
एजेंट निष्पादन इंजन है। यह एक घोषणात्मक ManagedAgentDef लेता है, चलाने योग्य एजेंट
बनाता है, और उसे चेकपॉइंट से पुनःआरंभ होने योग्य, इवेंट-स्ट्रीमिंग वाली
पृष्ठभूमि सत्र के रूप में संचालित करता है।
रनटाइम एक लाइब्रेरी है, सेवा नहीं। प्लेटफ़ॉर्म इसे होस्ट करता है। इसका अर्थ है:
- अलग से परीक्षण योग्य: शून्य HTTP/प्रमाणीकरण/बिलिंग निर्भरताएँ
- एम्बेड करने योग्य: स्व-होस्ट किए गए परिनियोजन सीधे उसी रनटाइम trait का उपयोग करते हैं
- बदला जा सकने वाला प्लेटफ़ॉर्म: अलग-अलग प्लेटफ़ॉर्म उसी रनटाइम को होस्ट कर सकते हैं
- प्रदाता-निरपेक्ष: मॉडल प्रदाता की परवाह किए बिना समान इवेंट अनुक्रम
त्वरित शुरुआत
अपने Cargo.toml में सुविधा जोड़ें:
[dependencies]
adk-rust = { version = "2.1.0", features = ["managed-runtime"] }
या सीधे adk-managed क्रेट का उपयोग करें:
[dependencies]
adk-managed = "2.1.0"
adk-session = "2.1.0"
न्यूनतम उदाहरण (ScriptedLlm — API कुंजी के बिना)
use std::sync::Arc;
use adk_managed::{
DefaultManagedAgentRuntime, ManagedAgentRuntime, ModelResolver,
ScriptedLlm, ScriptedTurn,
resolver::ResolverResult,
types::{ContentBlock, ManagedAgentDef, ModelRef, UserEvent},
};
use adk_session::InMemorySessionService;
use async_trait::async_trait;
use futures::StreamExt;
// A resolver that returns our scripted LLM
struct MockResolver { llm: Arc<dyn adk_core::Llm> }
#[async_trait]
impl ModelResolver for MockResolver {
async fn resolve(&self, _: &ModelRef) -> ResolverResult<Arc<dyn adk_core::Llm>> {
Ok(self.llm.clone())
}
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// 1. Create a scripted LLM (deterministic, offline, $0)
let llm = Arc::new(ScriptedLlm::new("test-model", vec![
ScriptedTurn { text: Some("Hello!".into()), tool_calls: vec![] },
]));
// 2. Build the runtime
let runtime = DefaultManagedAgentRuntime::new(
Arc::new(MockResolver { llm }),
Arc::new(InMemorySessionService::new()),
);
// 3. Create an agent
let def = ManagedAgentDef::new("my-agent", ModelRef::Shorthand("test-model".into()))
.with_system("You are helpful.");
let agent = runtime.create(def).await?;
// 4. Start a session
let session = runtime.start_session(&agent, None).await?;
// 5. Subscribe to events and send a message
let mut stream = runtime.stream_events(&session, None).await?;
runtime.send_event(&session, UserEvent::Message {
content: vec![ContentBlock::Text { text: "Hi!".into() }],
}).await?;
// 6. Collect events
while let Some(event) = stream.next().await {
println!("{event:?}");
}
Ok(())
}
आर्किटेक्चर
┌─────────────────────────────────────────────────────────────┐
│ Platform Layer (ep-* crates) │
│ HTTP Routes │ Auth │ Billing │ Multi-tenancy │
└──────────────────────────┬──────────────────────────────────┘
│ Rust trait calls (in-process)
▼
┌─────────────────────────────────────────────────────────────┐
│ Runtime Layer (adk-managed) │
│ │
│ ManagedAgentRuntime trait + DefaultManagedAgentRuntime │
│ ─────────────────────────────────────────────────── │
│ • Builds runnable agents from ManagedAgentDef │
│ • Runs supervised session loop (durable, resumable) │
│ • Emits provider-neutral SessionEvent stream │
│ • Manages custom tool parking, checkpoints, interrupts │
│ • Resolves ModelRef → Arc<dyn Llm> │
│ │
│ Composes existing crates: │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌────────────┐ │
│ │adk-runner│ │adk-session│ │adk-model │ │adk-tool │ │
│ └──────────┘ └──────────┘ └──────────┘ └────────────┘ │
└─────────────────────────────────────────────────────────────┘
मुख्य प्रकार
ManagedAgentRuntime trait
एजेंट के संपूर्ण जीवनचक्र को परिभाषित करने वाला केंद्रीय async trait:
| विधि | विवरण |
|---|---|
create(def) | एजेंट परिभाषा पंजीकृत करता है, AgentHandle लौटाता है |
start_session(agent, env?) | नया सत्र शुरू करता है, प्रारंभिक स्थिति Queued |
send_event(session, event) | सत्र को एक UserEvent भेजें |
stream_events(session, from_seq?) | SessionEvent स्ट्रीम की सदस्यता लें |
interrupt(session) | अगले सीमा-बिंदु पर रुकें, status.idle उत्सर्जित करें |
pause(session) | चेकपॉइंट बनाएं और प्रोसेसिंग रोकें |
resume(session) | विराम से फिर शुरू करें या पुनः प्रारंभ करें |
status(session) | वर्तमान SessionStatus की क्वेरी करें |
archive(session) | टर्मिनल स्थिति, डेटा सुरक्षित रखा गया |
delete_session(session) | सत्र डेटा हटाएँ |
ManagedAgentDef
बिल्डर API के साथ घोषणात्मक एजेंट परिभाषा:
let def = ManagedAgentDef::new("my-agent", ModelRef::Shorthand("gemini-3.7-flash".into()))
.with_system("You are a helpful assistant.")
.with_description("Research agent with web search")
.with_tools(vec![ToolConfig::BuiltIn(ManagedBuiltinTool::WebSearch)]);
SessionEvent
एकसमान क्रम संख्याओं वाली प्रदाता-निरपेक्ष इवेंट स्ट्रीम:
agent.message— सहायक टेक्स्ट सामग्रीagent.tool_use— अंतर्निहित टूल आह्वानagent.custom_tool_use— क्लाइंट द्वारा निष्पादित कस्टम टूल (लूप रुकता है)agent.mcp_tool_use— MCP टूल आह्वानstatus.running— टर्न शुरू हुआstatus.idle— टर्न पूरा हुआ (stop_reasonके साथ)error— निष्पादन त्रुटि
UserEvent
क्लाइंट-से-एजेंट इवेंट:
user.message— एजेंट को सामग्री भेजेंuser.interrupt— वर्तमान टर्न रोकेंuser.tool_confirmation— टूल निष्पादन की अनुमति दें/अस्वीकार करेंuser.custom_tool_result— कस्टम टूल परिणाम लौटाएँuser.tool_result— अंतर्निहित टूल परिणाम (केवल स्वयं-होस्टेड)user.define_outcome— सफलता मानदंड निर्धारित करें
ModelRef
सभी प्रदाताओं का समर्थन करने वाला प्रदाता-निरपेक्ष मॉडल संदर्भ:
// Shorthand (provider inferred from name)
ModelRef::Shorthand("gemini-3.7-flash".into())
ModelRef::Shorthand("gpt-5.6-terra".into())
ModelRef::Shorthand("claude-sonnet-5".into())
// Structured (explicit provider)
ModelRef::Structured {
provider: Provider::OpenaiCompatible,
model: ModelConfig::Compatible {
model: "my-model".into(),
base_url: "https://my-endpoint.com/v1".into(),
api_key: "sk-...".into(),
},
speed: None,
}
मुख्य विशेषताएँ
टिकाऊ सत्र
प्रत्येक इवेंट को परमाणु रूप से चेकपॉइंट किया जाता है। प्रक्रिया क्रैश होने पर, resume() बिना किसी इवेंट हानि के
अंतिम सुसंगत चेकपॉइंट से पुनर्स्थापित होता है:
// Before crash: events 0..5 committed
// After restart:
runtime.resume(&session).await?;
// Continues from seq=5, no gap, no duplicate
कस्टम टूल पार्किंग
जब एजेंट agent.custom_tool_use उत्सर्जित करता है, तो लूप तब तक रुकता है जब तक क्लाइंट
परिणाम नहीं लौटाता या कॉन्फ़िगर किया गया टाइमआउट समाप्त नहीं हो जाता:
// Agent emits: agent.custom_tool_use { custom_tool_use_id: "ct_1", name: "deploy" }
// Client executes the tool, then:
runtime.send_event(&session, UserEvent::CustomToolResult {
custom_tool_use_id: "ct_1".into(),
content: vec![ContentBlock::Text { text: "Deployed successfully".into() }],
}).await?;
इवेंट रीप्ले
क्रम-आधारित रीप्ले के माध्यम से SSE Last-Event-ID पुनः कनेक्शन का समर्थन:
// Reconnect from seq 42 — replays events 43, 44, ... then live tail
let stream = runtime.stream_events(&session, Some(42)).await?;
प्रदाता समानता
समान ManagedAgentDef, Gemini, OpenAI, Anthropic, Ollama, और OpenAI-संगत प्रदाताओं में बाइट-समरूप इवेंट प्रकार अनुक्रम उत्पन्न करता है (फिक्सचर F-8)।
ScriptedLlm के साथ परीक्षण
ScriptedLlm एक नियतात्मक LLM डबल है, जो पूर्ण रनटाइम पाइपलाइन का परीक्षण करता है। केवल प्रदाता API कॉल को प्रतिस्थापित किया जाता है:
use adk_managed::testing::{ScriptedLlm, ScriptedTurn, ScriptedToolCall};
use serde_json::json;
let llm = ScriptedLlm::new("test", vec![
ScriptedTurn {
text: Some("I'll search for that.".into()),
tool_calls: vec![ScriptedToolCall {
name: "web_search".into(),
input: json!({"query": "rust agents"}),
id: Some("tc_1".into()),
}],
},
ScriptedTurn {
text: Some("Here are the results...".into()),
tool_calls: vec![],
},
]);
API संदर्भ
पूर्ण API दस्तावेज़ docs.rs पर उपलब्ध है:
स्मोक टेस्ट उदाहरण
प्लेटफ़ॉर्म टीमों के लिए एक स्वतंत्र उदाहरण क्रेट प्रदान किया गया है:
cargo run --manifest-path examples/managed_runtime_hello/Cargo.toml
यह ScriptedLlm के साथ फ़िक्स्चर F-1 को आरंभ से अंत तक चलाता है (किसी API कुंजी की आवश्यकता नहीं है)।
प्रबंधित स्थिति की स्थायित्व
प्रबंधित सत्र स्थिति — इवेंट लॉग, अनुक्रम स्थिति, पार्क किए गए टूल कॉल और जीवनचक्र
स्थिति — एक ManagedStateStore में रहती है। स्टोर अपनी गारंटी स्वयं बताता है:
| स्थायित्व | अर्थ |
|---|---|
ProcessLocal | प्रक्रिया के चलते रहने तक पुनः चलाना और कार्य जारी रखना संभव है। क्रैश होने पर स्थिति खो जाती है, और कोई अन्य प्रक्रिया सत्र को फिर से जारी नहीं रख सकती। |
CrashDurable | लेखन की पुष्टि होने से पहले स्थिति को बैकिंग स्टोर में लिख दिया जाता है, इसलिए कोई अन्य प्रक्रिया सत्र का पुनर्निर्माण कर सकती है। |
केवल InMemoryManagedStateStore ही उपलब्ध कराया जाता है, और यह ProcessLocal है। गारंटी की जाँच करें, checkpointing की मौजूदगी से उसका अनुमान न लगाएँ:
use adk_managed::{Durability, InMemoryManagedStateStore, ManagedStateStore};
let store = InMemoryManagedStateStore::new();
assert_eq!(store.durability(), Durability::ProcessLocal);
assert!(!store.durability().survives_process_loss());
Checkpointing बनाम flushing
CheckpointManager::checkpoint किसी event और नई run state को एक साथ रिकॉर्ड करता है, इसलिए replay में उनमें से केवल एक कभी दिखाई नहीं देता। यह manager के अपने fields में किया गया लेखन है। flush snapshot को configured store में लिखता है, और restore उससे manager का पुनर्निर्माण करता है:
use adk_managed::{CheckpointManager, InMemoryManagedStateStore, ManagedStateStore};
use std::sync::Arc;
# async fn example() -> Result<(), adk_managed::types::RuntimeError> {
let store: Arc<dyn ManagedStateStore> = Arc::new(InMemoryManagedStateStore::new());
let manager = CheckpointManager::new("session-1".to_string()).with_store(Arc::clone(&store));
manager.flush().await?;
let restored = CheckpointManager::restore("session-1".to_string(), store).await?;
assert_eq!(restored.session_id(), "session-1");
# Ok(())
# }
स्थिति रिपोर्टिंग
ManagedAgentRuntime::status उसी handle को पढ़ता है जिस पर session loop लिखता है, इसलिए केवल control-plane transitions ही नहीं, बल्कि सामान्य transitions भी दिखाई देते हैं:
| संक्रमण | कारण |
|---|---|
Queued → Running | एक टर्न शुरू होता है |
Running → Idle | टर्न पूरा होता है और उपयोग दर्ज किया जाता है |
कोई भी → Paused | pause |
कोई भी → Archived | archive या delete_session |
नोट: पहले यह एक साझा हैंडल था,
statusपूरे सत्र के जीवनकाल के लिएQueuedरिपोर्ट करता था, जिसमें उसके टर्न निष्पादित होने के दौरान का समय भी शामिल था। कंट्रोल-प्लेन संक्रमण (रोकना, फिर से शुरू करना, संग्रहित करना) दिखाई देते थे क्योंकि वे सीधे हैंडल में लिखे जाते थे।
विलोपन का अर्थ
delete_session दोनों प्लेन हटाता है:
- सत्र को टर्मिनल स्थिति में सेट करता है और उसके लूप को रद्द करता है।
- रनटाइम हैंडल हटाता है।
- इंजेक्ट किए गए
SessionServiceके माध्यम से स्थायी रूप से संग्रहीत वार्तालाप को उसी पहचानstart_sessionके अंतर्गत हटाता है, जिससे उसे बनाया गया था।
यदि चरण 3 विफल होता है, तो delete_session उस ऐप, उपयोगकर्ता और सत्र का नाम बताते हुए एक त्रुटि लौटाता है जिनके पास अभी भी डेटा मौजूद है — उस समय तक हैंडल पहले ही हट चुका होता है, इसलिए कॉलर को यह बताना आवश्यक है कि मैन्युअल सफ़ाई में क्या करना है, न कि उसे सफलता मान लेने देना।
runtime.delete_session(&session).await?;
// The handle is gone and the conversation is no longer in the session backend.
महत्वपूर्ण: विलोपन उसके स्वामी के अंतर्गत सत्र के वार्तालाप को हटा देता है। सत्र स्वामित्व देखें।
सत्र स्वामित्व
start_session के लिए एक ManagedOwner आवश्यक है। सत्र उसी पहचान के अंतर्गत स्थायी रूप से संग्रहीत किया जाता है, और सत्र लूप द्वारा की जाने वाली प्रत्येक Runner कॉल इसका उपयोग करती है:
use adk_managed::{ManagedAgentRuntime, ManagedOwner};
# async fn start(runtime: &dyn ManagedAgentRuntime, agent: &adk_managed::AgentHandle)
# -> Result<(), adk_managed::RuntimeError> {
let owner = ManagedOwner::new("support-console", "user-42")?;
let session = runtime.start_session(agent, &owner, None).await?;
# Ok(())
# }
महत्वपूर्ण:
checkpointको "परमाणु रूप से स्थायी रूप से संग्रहीत करना" के रूप में दस्तावेज़ित किया गया था, इस गारंटी के साथ कि "किसी भी क्रैश के बाद पुनःचलाने पर एक सुसंगत दृश्य दिखाई देगा", और लोडिंग को "रीस्टार्ट के बाद सत्र को पुनर्निर्मित करने के लिए आवश्यक सब कुछ" लौटाने वाला बताया गया था। इनमें से कोई भी बात सही नहीं थी: दोनों ही किसी स्थायी स्टोर के विरुद्ध लेन-देन के बिना इन-मेमोरी फ़ील्ड पर काम करते थे। दिए गए स्टोर के साथ, नए प्रोसेस मेंrestoreको कुछ भी नहीं मिलता।
दोनों घटक आवश्यक हैं और रिक्त नहीं होने चाहिए। अलग-अलग स्वामियों से संबंधित सत्रों को अलग-अलग संबोधित किया जाता है, इसलिए लुकअप और विलोपन एक ही स्वामी के दायरे में होते हैं और किसी अन्य के डेटा तक नहीं पहुँच सकते।
नोट: प्रत्येक प्रबंधित सत्र को पहले
managed/managed_userकॉन्स्टेंट के अंतर्गत स्थायी रूप से संग्रहीत किया जाता था, इसलिए उन सभी ने एक ही तार्किक नेमस्पेस साझा किया: किसी भी चीज़ का दायरा कॉलर तक सीमित नहीं किया जा सकता था और किसी सत्र को किसी एक कॉलर से संबद्ध नहीं किया जा सकता था।
पर्यावरण कॉन्फ़िगरेशन
EnvironmentConfig में env_vars और working_dir शामिल हैं। यह रनटाइम ऐसे
कॉन्फ़िगरेशन को अस्वीकार करता है जो इनमें से किसी एक का अनुरोध करता है:
invalid request: EnvironmentConfig cannot be honoured by this runtime: sessions run
in-process, so per-session environment variables and working directories would have to mutate
process-global state shared with other sessions. Pass `None`, or configure a sandboxed runtime.
सत्र प्रक्रिया के भीतर चलते हैं, इसलिए प्रति-सत्र पर्यावरण वेरिएबल या कार्यशील डायरेक्टरी लागू करने से हर दूसरे सत्र के साथ साझा स्थिति बदल जाएगी। अस्वीकार करना ही ईमानदार परिणाम है; एक सैंडबॉक्सयुक्त निष्पादन सीमा ही इस अनुरोध को संतुष्ट करने योग्य बनाएगी।
नोट: आर्ग्युमेंट का नाम पहले
_envथा और उसे छोड़ दिया जाता था, इसलिए पर्यावरण कॉन्फ़िगरेशन देने वाले कॉलर को ऐसा सत्र मिलता था जो उसे चुपचाप अनदेखा कर देता था।