Skip to main content

AgentUri

Struct AgentUri 

Source
pub struct AgentUri { /* private fields */ }
Expand description

A parsed and validated agent URI.

Agent URIs provide topology-independent identity for agents with capability-based discovery.

§Structure

agent://<trust-root>/<capability-path>/<agent-id>[?query][#fragment]

§Examples

use agent_uri::AgentUri;

let uri = AgentUri::parse("agent://anthropic.com/assistant/chat/llm_chat_01h455vb4pex5vsknk084sn02q").unwrap();
assert_eq!(uri.trust_root().host_str(), "anthropic.com");
assert_eq!(uri.capability_path().as_str(), "assistant/chat");
assert_eq!(uri.agent_id().prefix().as_str(), "llm_chat");

// With query and fragment
let uri = AgentUri::parse("agent://openai.com/tool/code/llm_01h455vb4pex5vsknk084sn02q?version=2.0#summarization").unwrap();
assert_eq!(uri.query().version(), Some("2.0"));
assert_eq!(uri.fragment().map(|f| f.as_str()), Some("summarization"));

§Identity

Two AgentUri values are equal when they name the same agent, which is a weaker condition than being the same string. Equality, ordering, and hashing compare the trust root, the capability path, and the agent ID — the canonical form. The query and the fragment are excluded: a query carries resolution hints and a fragment names a sub-capability, and neither changes which agent is being addressed. This is Section 5.2 of the specification, and it is what makes ?version=2.0 a request about an agent rather than a different agent.

A value that is not part of identity is still part of the string. Display, as_str, and serde all preserve the query and the fragment exactly as parsed. Only canonical drops them.

use agent_uri::AgentUri;

let plain = AgentUri::parse(
    "agent://acme.com/workflow/approval/rule_01h455vb4pex5vsknk084sn02q"
).unwrap();
let hinted = AgentUri::parse(
    "agent://acme.com/workflow/approval/rule_01h455vb4pex5vsknk084sn02q?ttl=300#invoice"
).unwrap();

// Equal as identities...
assert_eq!(plain, hinted);
assert_eq!(plain.canonical(), hinted.canonical());

// ...and not as strings.
assert_ne!(plain.as_str(), hinted.as_str());
assert_eq!(hinted.query().ttl(), Some(300));
assert_eq!(hinted.fragment().map(|f| f.as_str()), Some("invoice"));

§What this means for collections

A HashSet or HashMap keyed by AgentUri deduplicates by identity, so inserting a decorated URI where an undecorated one is already present keeps the first and discards the second — including its query and fragment. That is the intent for caches, registries, and DHT keys, where one agent must have one entry. It is a defect if the query is data you meant to keep, so key those by as_str instead.

use std::collections::HashSet;
use agent_uri::AgentUri;

let plain = AgentUri::parse(
    "agent://acme.com/workflow/approval/rule_01h455vb4pex5vsknk084sn02q"
).unwrap();
let hinted = AgentUri::parse(
    "agent://acme.com/workflow/approval/rule_01h455vb4pex5vsknk084sn02q?ttl=300"
).unwrap();

let mut agents = HashSet::new();
assert!(agents.insert(plain));
assert!(!agents.insert(hinted)); // same agent, so not a second entry
assert_eq!(agents.len(), 1);

Implementations§

Source§

impl AgentUri

Source

pub fn parse(input: &str) -> Result<Self, ParseError>

Parses an agent URI from a string.

§Case

Case is folded exactly where a standard makes a component case-insensitive: the scheme (RFC 3986 section 3.1) and the trust root’s DNS name (RFC 4343). The capability path and the agent ID are identity material that the grammar fixes as lowercase, so an uppercase letter in either is rejected rather than folded.

use agent_uri::AgentUri;

let uri = AgentUri::parse("AGENT://Anthropic.COM/chat/llm_01h455vb4pex5vsknk084sn02q").unwrap();
assert_eq!(
    uri.as_str(),
    "agent://anthropic.com/chat/llm_01h455vb4pex5vsknk084sn02q"
);

assert!(AgentUri::parse("agent://anthropic.com/Chat/llm_01h455vb4pex5vsknk084sn02q").is_err());
§Errors

Returns ParseError if:

  • The URI is empty
  • The URI exceeds 512 characters
  • The scheme is not “agent” (compared case-insensitively)
  • Any component (trust root, path, agent ID, query, fragment) is invalid
Source

pub fn new( trust_root: TrustRoot, capability_path: CapabilityPath, agent_id: AgentId, query: QueryParams, fragment: Option<Fragment>, ) -> Result<Self, ParseError>

Creates a new agent URI from its components.

§Errors

Returns ParseError if the resulting URI would exceed the maximum length.

Source

pub const fn trust_root(&self) -> &TrustRoot

Returns the trust root.

Source

pub const fn capability_path(&self) -> &CapabilityPath

Returns the capability path.

Source

pub const fn agent_id(&self) -> &AgentId

Returns the agent ID.

Source

pub const fn query(&self) -> &QueryParams

Returns the query parameters.

Source

pub const fn fragment(&self) -> Option<&Fragment>

Returns the fragment, if present.

Source

pub fn as_str(&self) -> &str

Returns the normalized URI string.

Source

pub fn canonical(&self) -> String

Returns the canonical URI (without query and fragment).

Source

pub fn is_localhost(&self) -> bool

Returns true if this URI references a localhost agent.

Source

pub fn with_query(&self, query: QueryParams) -> Result<Self, ParseError>

Returns a new URI with the given query parameters.

§Errors

Returns ParseError if the resulting URI would exceed the maximum length.

§Examples
use agent_uri::{AgentUri, QueryParams};

let uri = AgentUri::parse("agent://anthropic.com/chat/llm_01h455vb4pex5vsknk084sn02q").unwrap();
let query = QueryParams::parse("version=2.0").unwrap();
let updated = uri.with_query(query).unwrap();
assert_eq!(updated.query().version(), Some("2.0"));
Source

pub fn with_query_str(&self, s: &str) -> Result<Self, ParseError>

Returns a new URI with query parameters parsed from a string.

§Errors

Returns ParseError if the query string is invalid or the resulting URI would exceed the maximum length.

§Examples
use agent_uri::AgentUri;

let uri = AgentUri::parse("agent://anthropic.com/chat/llm_01h455vb4pex5vsknk084sn02q").unwrap();
let updated = uri.with_query_str("version=2.0&ttl=300").unwrap();
assert_eq!(updated.query().version(), Some("2.0"));
assert_eq!(updated.query().ttl(), Some(300));
Source

pub fn without_query(&self) -> Result<Self, ParseError>

Returns a new URI without query parameters.

§Errors

Returns ParseError if the resulting URI would exceed the maximum length. (This is unlikely but possible in edge cases.)

§Examples
use agent_uri::AgentUri;

let uri = AgentUri::parse("agent://anthropic.com/chat/llm_01h455vb4pex5vsknk084sn02q?version=2.0").unwrap();
let updated = uri.without_query().unwrap();
assert!(updated.query().is_empty());
Source

pub fn with_fragment(&self, fragment: Fragment) -> Result<Self, ParseError>

Returns a new URI with the given fragment.

§Errors

Returns ParseError if the resulting URI would exceed the maximum length.

§Examples
use agent_uri::{AgentUri, Fragment};

let uri = AgentUri::parse("agent://anthropic.com/chat/llm_01h455vb4pex5vsknk084sn02q").unwrap();
let fragment = Fragment::parse("summarization").unwrap();
let updated = uri.with_fragment(fragment).unwrap();
assert_eq!(updated.fragment().map(|f| f.as_str()), Some("summarization"));
Source

pub fn with_fragment_str(&self, s: &str) -> Result<Self, ParseError>

Returns a new URI with a fragment parsed from a string.

§Errors

Returns ParseError if the fragment is invalid or the resulting URI would exceed the maximum length.

§Examples
use agent_uri::AgentUri;

let uri = AgentUri::parse("agent://anthropic.com/chat/llm_01h455vb4pex5vsknk084sn02q").unwrap();
let updated = uri.with_fragment_str("summarization").unwrap();
assert_eq!(updated.fragment().map(|f| f.as_str()), Some("summarization"));
Source

pub fn without_fragment(&self) -> Result<Self, ParseError>

Returns a new URI without a fragment.

§Errors

Returns ParseError if the resulting URI would exceed the maximum length. (This is unlikely but possible in edge cases.)

§Examples
use agent_uri::AgentUri;

let uri = AgentUri::parse("agent://anthropic.com/chat/llm_01h455vb4pex5vsknk084sn02q#test").unwrap();
let updated = uri.without_fragment().unwrap();
assert!(updated.fragment().is_none());

Trait Implementations§

Source§

impl AsRef<str> for AgentUri

Source§

fn as_ref(&self) -> &str

Converts this type into a shared reference of the (usually inferred) input type.
Source§

impl Clone for AgentUri

Source§

fn clone(&self) -> Self

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for AgentUri

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl<'de> Deserialize<'de> for AgentUri

Available on crate feature serde only.
Source§

fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
Source§

impl Display for AgentUri

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Eq for AgentUri

Source§

impl FromStr for AgentUri

Source§

type Err = ParseError

The associated error which can be returned from parsing.
Source§

fn from_str(s: &str) -> Result<Self, Self::Err>

Parses a string s to return a value of this type. Read more
Source§

impl Hash for AgentUri

Hashes exactly what PartialEq compares, as the Hash/Eq contract requires: equal URIs hash equally, so a decorated URI and its plain form land in the same bucket rather than in two.

Source§

fn hash<H: Hasher>(&self, state: &mut H)

Feeds this value into the given Hasher. Read more
1.3.0 · Source§

fn hash_slice<H>(data: &[Self], state: &mut H)
where H: Hasher, Self: Sized,

Feeds a slice of this type into the given Hasher. Read more
Source§

impl Ord for AgentUri

Identity ordering: the same three fields PartialEq compares and Hash hashes, in the order they appear in a URI.

This used to render both sides with canonical and compare the strings, which allocated twice per comparison — a BTreeMap keyed by AgentUri paid that on every probe. The order is the same except where one component is a prefix of another, because the rendered form has a / between components and / sorts after . and after every letter: string order put acme.com.br before acme.com, and this puts acme.com first. Ordering by the components is the order the type’s own identity implies; the old one was an artifact of the separator.

Source§

fn cmp(&self, other: &Self) -> Ordering

This method returns an Ordering between self and other. Read more
1.21.0 (const: unstable) · Source§

fn max(self, other: Self) -> Self
where Self: Sized,

Compares and returns the maximum of two values. Read more
1.21.0 (const: unstable) · Source§

fn min(self, other: Self) -> Self
where Self: Sized,

Compares and returns the minimum of two values. Read more
1.50.0 (const: unstable) · Source§

fn clamp(self, min: Self, max: Self) -> Self
where Self: Sized,

Restrict a value to a certain interval. Read more
Source§

fn clamp_to<R>(self, range: R) -> Self
where Self: Sized, R: ClampBounds<Self>,

🔬This is a nightly-only experimental API. (clamp_to)
Restrict a value to a certain range. Read more
Source§

impl PartialEq for AgentUri

Identity equality: see the Identity section on AgentUri.

The three fields compared here are the three fields Hash hashes and the three fields Ord orders by. All three impls sit together so that a change to one is a visible omission in the others.

Source§

fn eq(&self, other: &Self) -> bool

Equality operator ==. Read more
1.0.0 (const: unstable) · Source§

fn ne(&self, other: &Rhs) -> bool

Inequality operator !=. Read more
Source§

impl PartialOrd for AgentUri

Source§

fn partial_cmp(&self, other: &Self) -> Option<Ordering>

This method returns an ordering between self and other values if one exists. Read more
1.0.0 (const: unstable) · Source§

fn lt(&self, other: &Rhs) -> bool

Tests less than (for self and other) and is used by the < operator. Read more
1.0.0 (const: unstable) · Source§

fn le(&self, other: &Rhs) -> bool

Tests less than or equal to (for self and other) and is used by the <= operator. Read more
1.0.0 (const: unstable) · Source§

fn gt(&self, other: &Rhs) -> bool

Tests greater than (for self and other) and is used by the > operator. Read more
1.0.0 (const: unstable) · Source§

fn ge(&self, other: &Rhs) -> bool

Tests greater than or equal to (for self and other) and is used by the >= operator. Read more
Source§

impl Serialize for AgentUri

Available on crate feature serde only.
Source§

fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where S: Serializer,

Serialize this value into the given Serde serializer. Read more
Source§

impl TryFrom<&str> for AgentUri

Source§

type Error = ParseError

The type returned in the event of a conversion error.
Source§

fn try_from(s: &str) -> Result<Self, Self::Error>

Performs the conversion.

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> DeserializeOwned for T
where T: for<'de> Deserialize<'de>,

Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> PrefixFactory for T
where T: AsRef<str>,

Source§

fn create_prefix_sanitized(&self) -> TypeIdPrefix

Sanitizes the input and creates a valid TypeIdPrefix. Read more
Source§

fn try_create_prefix(&self) -> Result<TypeIdPrefix, ValidationError>

Attempts to create a TypeIdPrefix from the input without modifying it. Read more
Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T> ToString for T
where T: Display + ?Sized,

Source§

fn to_string(&self) -> String

Converts the given value to a String. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.