Skip to main content

tap_agent/
agent.rs

1use crate::agent_key_manager::{AgentKeyManager, AgentKeyManagerBuilder};
2use crate::config::AgentConfig;
3#[cfg(all(not(target_arch = "wasm32"), test))]
4use crate::did::SyncDIDResolver; // Import SyncDIDResolver trait
5use crate::error::{Error, Result};
6use crate::key_manager::KeyManager; // Add KeyManager trait
7#[cfg(not(target_arch = "wasm32"))]
8use crate::message::SecurityMode;
9#[cfg(not(target_arch = "wasm32"))]
10use crate::message_packing::{PackOptions, Packable, UnpackOptions, Unpackable};
11#[cfg(not(target_arch = "wasm32"))]
12use async_trait::async_trait;
13#[cfg(feature = "native")]
14use reqwest::Client;
15#[cfg(target_arch = "wasm32")]
16use serde::de::DeserializeOwned;
17#[cfg(not(target_arch = "wasm32"))]
18use serde_json::Value;
19use std::path::PathBuf;
20use std::sync::Arc;
21#[cfg(feature = "native")]
22use std::time::Duration;
23#[cfg(not(target_arch = "wasm32"))]
24use tap_msg::didcomm::{PlainMessage, PlainMessageExt};
25use tap_msg::TapMessageBody;
26#[cfg(not(target_arch = "wasm32"))]
27use tracing::{debug, error, info, warn};
28
29/// Type alias for enhanced agent information: (DID, policies, metadata)
30pub type EnhancedAgentInfo = (
31    String,
32    Vec<String>,
33    std::collections::HashMap<String, String>,
34);
35
36/// Result of a message delivery attempt
37#[derive(Debug, Clone)]
38pub struct DeliveryResult {
39    /// The DID of the recipient
40    pub did: String,
41    /// The service endpoint URL that was used for delivery
42    pub endpoint: String,
43    /// HTTP status code if the delivery was successful
44    pub status: Option<u16>,
45    /// Error message if the delivery failed
46    pub error: Option<String>,
47}
48
49/// The Agent trait defines the interface for all TAP agents
50///
51/// This trait supports both standalone agent usage and integration with TAP Node.
52/// The different receive methods are designed for different usage patterns:
53///
54/// # Usage Patterns
55///
56/// ## Node Integration
57/// - [`receive_encrypted_message`]: Called by TAP Node for encrypted messages
58/// - [`receive_plain_message`]: Called by TAP Node for verified/decrypted messages
59///
60/// ## Standalone Usage
61/// - [`receive_message`]: Handles any message type (plain, signed, encrypted)
62///
63/// ## Message Sending
64/// - [`send_message`]: Sends messages to recipients with optional delivery
65///
66/// # Examples
67///
68/// ```rust,no_run
69/// use tap_agent::{Agent, TapAgent};
70/// use tap_msg::didcomm::PlainMessage;
71///
72/// async fn process_encrypted_message(agent: &TapAgent, jwe_json: &serde_json::Value) {
73///     // This would typically be called by TAP Node
74///     if let Err(e) = agent.receive_encrypted_message(jwe_json).await {
75///         tracing::error!("Failed to process encrypted message: {}", e);
76///     }
77/// }
78/// ```
79#[cfg(not(target_arch = "wasm32"))]
80#[async_trait]
81pub trait Agent {
82    /// Gets the agent's DID
83    fn get_agent_did(&self) -> &str;
84
85    /// Gets the service endpoint URL for a recipient
86    ///
87    /// This method resolves how to reach a given recipient, which could be:
88    /// - A direct URL if `to` is already a URL
89    /// - A DID resolution if `to` is a DID
90    async fn get_service_endpoint(&self, to: &str) -> Result<Option<String>>;
91
92    /// Sends a message to one or more recipients
93    ///
94    /// # Parameters
95    /// - `message`: The message to send (must implement TapMessageBody)
96    /// - `to`: List of recipient DIDs or URLs
97    /// - `deliver`: Whether to actually deliver the message or just pack it
98    ///
99    /// # Returns
100    /// - Packed message string
101    /// - Vector of delivery results (empty if deliver=false)
102    async fn send_message<
103        T: TapMessageBody + serde::Serialize + Send + Sync + std::fmt::Debug + 'static,
104    >(
105        &self,
106        message: &T,
107        to: Vec<&str>,
108        deliver: bool,
109    ) -> Result<(String, Vec<DeliveryResult>)>;
110
111    /// Receives an encrypted message (decrypt and process)
112    ///
113    /// This method is typically called by TAP Node when routing encrypted
114    /// messages to agents. The agent should:
115    /// 1. Parse the JWE from the JSON value
116    /// 2. Attempt to decrypt using its private keys
117    /// 3. Process the resulting PlainMessage
118    ///
119    /// # Parameters
120    /// - `jwe_value`: JSON representation of the encrypted message (JWE)
121    async fn receive_encrypted_message(&self, jwe_value: &Value) -> Result<()>;
122
123    /// Receives a plain message (already verified/decrypted)
124    ///
125    /// This method is called by TAP Node after signature verification
126    /// or by other agents after decryption. The message is ready for
127    /// business logic processing.
128    ///
129    /// # Parameters
130    /// - `message`: The verified/decrypted PlainMessage
131    async fn receive_plain_message(&self, message: PlainMessage) -> Result<()>;
132
133    /// Receives a raw message (for standalone usage - handles any message type)
134    ///
135    /// This method handles the complete message processing pipeline for
136    /// standalone agent usage. It can process:
137    /// - Plain messages (passed through)
138    /// - Signed messages (signature verified)
139    /// - Encrypted messages (decrypted)
140    ///
141    /// # Parameters
142    /// - `raw_message`: JSON string of any message type
143    ///
144    /// # Returns
145    /// - The processed PlainMessage
146    async fn receive_message(&self, raw_message: &str) -> Result<PlainMessage>;
147
148    /// Send a strongly-typed message
149    ///
150    /// # Parameters
151    /// - `message`: The typed message to send
152    /// - `deliver`: Whether to actually deliver the message
153    ///
154    /// # Returns
155    /// - Packed message string
156    /// - Vector of delivery results (empty if deliver=false)
157    async fn send_typed<T: TapMessageBody + Send + Sync + std::fmt::Debug + 'static>(
158        &self,
159        message: PlainMessage<T>,
160        deliver: bool,
161    ) -> Result<(String, Vec<DeliveryResult>)> {
162        // Convert to plain message and use existing send infrastructure
163        let plain_message = message.to_plain_message()?;
164        let to_vec: Vec<&str> = plain_message.to.iter().map(|s| s.as_str()).collect();
165
166        // Extract the body and send using the existing method
167        let body = serde_json::from_value::<T>(plain_message.body)?;
168        self.send_message(&body, to_vec, deliver).await
169    }
170
171    /// Send a message with MessageContext support for automatic routing
172    ///
173    /// This method uses MessageContext to automatically extract participants
174    /// and routing hints for improved message delivery.
175    ///
176    /// # Parameters
177    /// - `message`: The message body that implements both TapMessageBody and MessageContext
178    /// - `deliver`: Whether to actually deliver the message
179    ///
180    /// # Returns
181    /// - Packed message string
182    /// - Vector of delivery results (empty if deliver=false)
183    async fn send_with_context<T>(
184        &self,
185        message: &T,
186        deliver: bool,
187    ) -> Result<(String, Vec<DeliveryResult>)>
188    where
189        T: TapMessageBody
190            + tap_msg::message::MessageContext
191            + Send
192            + Sync
193            + std::fmt::Debug
194            + 'static,
195    {
196        // Extract participants using MessageContext
197        let participant_dids = message.participant_dids();
198        let recipients: Vec<&str> = participant_dids
199            .iter()
200            .map(|s| s.as_str())
201            .filter(|&did| did != self.get_agent_did()) // Don't send to self
202            .collect();
203
204        // Get routing hints for enhanced delivery
205        let _routing_hints = message.routing_hints();
206
207        // TODO: Use routing_hints to optimize delivery
208        // For now, just use the standard send_message method
209        self.send_message(message, recipients, deliver).await
210    }
211
212    /// Send a typed message with automatic context routing
213    ///
214    /// # Parameters
215    /// - `message`: The typed message with MessageContext support
216    /// - `deliver`: Whether to actually deliver the message
217    ///
218    /// # Returns
219    /// - Packed message string
220    /// - Vector of delivery results (empty if deliver=false)
221    async fn send_typed_with_context<T>(
222        &self,
223        message: PlainMessage<T>,
224        deliver: bool,
225    ) -> Result<(String, Vec<DeliveryResult>)>
226    where
227        T: TapMessageBody
228            + tap_msg::message::MessageContext
229            + Send
230            + Sync
231            + std::fmt::Debug
232            + 'static,
233    {
234        // Use the enhanced participant extraction
235        let participants = message.extract_participants_with_context();
236        let _recipients: Vec<&str> = participants
237            .iter()
238            .map(|s| s.as_str())
239            .filter(|&did| did != self.get_agent_did()) // Don't send to self
240            .collect();
241
242        // Get routing hints
243        let _routing_hints = message.routing_hints();
244
245        // Extract the body and send using the context-aware method
246        let body = message.body;
247        self.send_with_context(&body, deliver).await
248    }
249
250    /// Receive and parse a typed message
251    ///
252    /// # Parameters
253    /// - `raw_message`: The raw message string
254    ///
255    /// # Type Parameters
256    /// - `T`: The expected message body type
257    ///
258    /// # Returns
259    /// - The typed message if parsing succeeds
260    async fn receive_typed<T: TapMessageBody>(&self, raw_message: &str) -> Result<PlainMessage<T>> {
261        let plain_message = self.receive_message(raw_message).await?;
262        plain_message
263            .parse_as()
264            .map_err(|e| Error::Serialization(e.to_string()))
265    }
266
267    /// Create an Out-of-Band invitation for any TAP message
268    ///
269    /// # Parameters
270    /// - `message`: The message to include as a signed attachment
271    /// - `goal_code`: The goal code (e.g., "tap.payment", "tap.connect")
272    /// - `goal`: Human-readable goal description
273    /// - `service_url`: Base URL for the service
274    ///
275    /// # Returns
276    /// - The Out-of-Band invitation URL
277    async fn create_oob_invitation<T: TapMessageBody + serde::Serialize + Send + Sync>(
278        &self,
279        message: &T,
280        goal_code: &str,
281        goal: &str,
282        service_url: &str,
283    ) -> Result<String>;
284
285    /// Create a payment link from a Payment message
286    ///
287    /// # Parameters
288    /// - `payment`: The payment message to create a link for
289    /// - `config`: Optional configuration (uses defaults if None)
290    ///
291    /// # Returns
292    /// - The payment link URL
293    async fn create_payment_link(
294        &self,
295        payment: &tap_msg::message::Payment,
296        config: Option<crate::payment_link::PaymentLinkConfig>,
297    ) -> Result<String>;
298
299    /// Parse an Out-of-Band invitation from a URL
300    ///
301    /// # Parameters
302    /// - `url`: The OOB invitation URL
303    ///
304    /// # Returns
305    /// - The parsed Out-of-Band invitation
306    fn parse_oob_invitation(&self, url: &str) -> Result<crate::oob::OutOfBandInvitation>;
307
308    /// Process an Out-of-Band invitation and extract the attached message
309    ///
310    /// # Parameters
311    /// - `oob_invitation`: The Out-of-Band invitation to process
312    ///
313    /// # Returns
314    /// - The extracted and verified PlainMessage if successful
315    async fn process_oob_invitation(
316        &self,
317        oob_invitation: &crate::oob::OutOfBandInvitation,
318    ) -> Result<PlainMessage>;
319}
320
321/// A simplified Agent trait for WASM with relaxed bounds
322#[cfg(target_arch = "wasm32")]
323pub trait WasmAgent {
324    /// Gets the agent's DID
325    fn get_agent_did(&self) -> &str;
326
327    /// Pack a message for delivery
328    fn pack_message<T: TapMessageBody + serde::Serialize>(&self, message: &T) -> Result<String>;
329
330    /// Unpack a received message
331    fn unpack_message<T: TapMessageBody + DeserializeOwned>(
332        &self,
333        packed_message: &str,
334    ) -> Result<T>;
335}
336
337/// TapAgent implementation using the AgentKeyManager for cryptographic operations.
338#[derive(Debug, Clone)]
339pub struct TapAgent {
340    /// Configuration for the agent
341    pub config: AgentConfig,
342    /// Key Manager for cryptographic operations
343    key_manager: Arc<AgentKeyManager>,
344    /// DID Resolver for resolving DIDs to service endpoints
345    #[cfg(all(not(target_arch = "wasm32"), test))]
346    resolver: Option<Arc<dyn SyncDIDResolver>>,
347    /// HTTP client for sending requests
348    #[cfg(all(feature = "native", not(target_arch = "wasm32")))]
349    http_client: Option<Client>,
350}
351
352impl TapAgent {
353    /// Returns a reference to the agent's key manager
354    pub fn key_manager(&self) -> &Arc<AgentKeyManager> {
355        &self.key_manager
356    }
357
358    /// Creates a new TapAgent with the given configuration and AgentKeyManager
359    pub fn new(config: AgentConfig, key_manager: Arc<AgentKeyManager>) -> Self {
360        #[cfg(all(feature = "native", not(target_arch = "wasm32")))]
361        {
362            let timeout = Duration::from_secs(config.timeout_seconds.unwrap_or(30));
363            let client = Client::builder().timeout(timeout).build().ok();
364
365            #[cfg(test)]
366            let agent = TapAgent {
367                config,
368                key_manager,
369                resolver: None,
370                http_client: client,
371            };
372
373            #[cfg(not(test))]
374            let agent = TapAgent {
375                config,
376                key_manager,
377                http_client: client,
378            };
379
380            agent
381        }
382
383        #[cfg(not(all(feature = "native", not(target_arch = "wasm32"))))]
384        {
385            #[cfg(all(not(target_arch = "wasm32"), test))]
386            let agent = TapAgent {
387                config,
388                key_manager,
389                resolver: None,
390            };
391
392            #[cfg(all(not(target_arch = "wasm32"), not(test)))]
393            let agent = TapAgent {
394                config,
395                key_manager,
396            };
397
398            #[cfg(target_arch = "wasm32")]
399            let agent = TapAgent {
400                config,
401                key_manager,
402            };
403
404            agent
405        }
406    }
407
408    /// Creates a new TapAgent with the given configuration, key manager, and DID resolver
409    #[cfg(all(not(target_arch = "wasm32"), test))]
410    pub fn new_with_resolver(
411        config: AgentConfig,
412        key_manager: Arc<AgentKeyManager>,
413        resolver: Arc<dyn SyncDIDResolver>,
414    ) -> Self {
415        #[cfg(feature = "native")]
416        {
417            let timeout = Duration::from_secs(config.timeout_seconds.unwrap_or(30));
418            let client = Client::builder().timeout(timeout).build().ok();
419
420            TapAgent {
421                config,
422                key_manager,
423                resolver: Some(resolver),
424                http_client: client,
425            }
426        }
427
428        #[cfg(not(feature = "native"))]
429        {
430            TapAgent {
431                config,
432                key_manager,
433                resolver: Some(resolver),
434            }
435        }
436    }
437
438    /// Creates a new TapAgent with an ephemeral key
439    ///
440    /// This function generates a new DID key for temporary use.
441    /// The key is not persisted to storage and will be lost when the agent is dropped.
442    ///
443    /// # Returns
444    ///
445    /// A tuple containing the TapAgent and the DID that was generated
446    pub async fn from_ephemeral_key() -> crate::error::Result<(Self, String)> {
447        use crate::did::{DIDGenerationOptions, KeyType};
448
449        // Create a key manager
450        let key_manager = AgentKeyManager::new();
451
452        // Generate a key
453        let key = key_manager.generate_key(DIDGenerationOptions {
454            key_type: KeyType::Ed25519,
455        })?;
456
457        // Create a config with the new DID
458        let config = AgentConfig::new(key.did.clone()).with_debug(true);
459
460        // Create the agent
461        #[cfg(all(not(target_arch = "wasm32"), test))]
462        {
463            // Create a default resolver
464            let resolver = Arc::new(crate::did::MultiResolver::default());
465            let agent = Self::new_with_resolver(config, Arc::new(key_manager), resolver);
466            Ok((agent, key.did))
467        }
468
469        #[cfg(all(not(target_arch = "wasm32"), not(test)))]
470        {
471            let agent = Self::new(config, Arc::new(key_manager));
472            Ok((agent, key.did))
473        }
474
475        #[cfg(target_arch = "wasm32")]
476        {
477            let agent = Self::new(config, Arc::new(key_manager));
478            Ok((agent, key.did))
479        }
480    }
481
482    /// Creates a new TapAgent from stored keys
483    ///
484    /// This function uses the AgentKeyManagerBuilder to load keys from storage
485    ///
486    /// # Arguments
487    ///
488    /// * `did` - Optional DID to use. If None, the default DID from storage is used.
489    /// * `debug` - Whether to enable debug mode
490    ///
491    /// # Returns
492    ///
493    /// A Result containing either the created agent or an error if no keys are available
494    pub async fn from_stored_keys(did: Option<String>, debug: bool) -> Result<Self> {
495        use crate::storage::KeyStorage;
496
497        // Load keys from storage
498        let key_manager_builder = AgentKeyManagerBuilder::new().load_from_default_storage();
499        let key_manager = key_manager_builder.build()?;
500
501        // Get the DIDs available in the key manager
502        let dids = key_manager.list_keys()?;
503        if dids.is_empty() {
504            return Err(Error::Storage(
505                "No keys found in storage. Generate keys first with 'tap-agent-cli generate --save'".to_string(),
506            ));
507        }
508
509        // Get the DID to use
510        let agent_did = if let Some(specified_did) = did {
511            if !dids.contains(&specified_did) {
512                return Err(Error::Storage(format!(
513                    "Key with DID '{}' not found in storage",
514                    specified_did
515                )));
516            }
517            specified_did
518        } else {
519            // Try to get the default DID from storage
520            let storage = KeyStorage::load_default()?;
521            storage.default_did.unwrap_or_else(|| dids[0].clone())
522        };
523
524        // Create agent config
525        let config = AgentConfig::new(agent_did).with_debug(debug);
526
527        // Create the agent
528        #[cfg(all(not(target_arch = "wasm32"), test))]
529        {
530            // Create a default resolver
531            let resolver = Arc::new(crate::did::MultiResolver::default());
532            Ok(TapAgent::new_with_resolver(
533                config,
534                Arc::new(key_manager),
535                resolver,
536            ))
537        }
538
539        #[cfg(all(not(target_arch = "wasm32"), not(test)))]
540        {
541            Ok(TapAgent::new(config, Arc::new(key_manager)))
542        }
543
544        #[cfg(target_arch = "wasm32")]
545        {
546            Ok(TapAgent::new(config, Arc::new(key_manager)))
547        }
548    }
549
550    /// Creates a new TapAgent from a secret helper
551    ///
552    /// Invokes the secret helper to retrieve the private key for the given DID,
553    /// then creates a TapAgent using that key.
554    ///
555    /// # Arguments
556    ///
557    /// * `config` - The secret helper configuration
558    /// * `did` - The DID to fetch the key for
559    /// * `debug` - Whether to enable debug mode
560    #[cfg(not(target_arch = "wasm32"))]
561    pub async fn from_secret_helper(
562        config: &crate::secret_helper::SecretHelperConfig,
563        did: &str,
564        debug: bool,
565    ) -> Result<(Self, String)> {
566        let (private_key, key_type) = config.get_key(did)?;
567        Self::from_private_key(&private_key, key_type, debug).await
568    }
569
570    /// Creates a new TapAgent from an existing private key
571    ///
572    /// This function creates a new TapAgent using a provided private key,
573    /// which can be useful for integrating with external key management systems
574    /// or when keys are generated outside the TAP agent.
575    ///
576    /// # Arguments
577    ///
578    /// * `private_key` - The private key bytes
579    /// * `key_type` - The type of key (Ed25519, P256, or Secp256k1)
580    /// * `debug` - Whether to enable debug mode
581    ///
582    /// # Returns
583    ///
584    /// A Result containing either the created agent or an error
585    pub async fn from_private_key(
586        private_key: &[u8],
587        key_type: crate::did::KeyType,
588        debug: bool,
589    ) -> Result<(Self, String)> {
590        use crate::did::{DIDKeyGenerator, GeneratedKey};
591        use crate::did::{VerificationMaterial, VerificationMethod, VerificationMethodType};
592        #[cfg(feature = "crypto-ed25519")]
593        use curve25519_dalek::edwards::CompressedEdwardsY;
594        use multibase::{encode, Base};
595
596        // Create a key manager to hold our key
597        let key_manager = AgentKeyManager::new();
598
599        // Generate the appropriate key and DID based on the key type
600        let generated_key = match key_type {
601            #[cfg(feature = "crypto-ed25519")]
602            crate::did::KeyType::Ed25519 => {
603                if private_key.len() != 32 {
604                    return Err(Error::Validation(format!(
605                        "Invalid Ed25519 private key length: {}, expected 32 bytes",
606                        private_key.len()
607                    )));
608                }
609
610                // For Ed25519, we need to derive the public key from the private key
611                let mut private_key_bytes = [0u8; 32];
612                private_key_bytes.copy_from_slice(&private_key[0..32]);
613
614                let signing_key = ed25519_dalek::SigningKey::from_bytes(&private_key_bytes);
615
616                // Get the public key
617                let verifying_key = ed25519_dalek::VerifyingKey::from(&signing_key);
618                let public_key = verifying_key.to_bytes().to_vec();
619
620                // Create did:key identifier
621                // Multicodec prefix for Ed25519: 0xed01
622                let mut prefixed_key = vec![0xed, 0x01];
623                prefixed_key.extend_from_slice(&public_key);
624
625                // Encode the key with multibase (base58btc with 'z' prefix)
626                let multibase_encoded = encode(Base::Base58Btc, &prefixed_key);
627                let did = format!("did:key:{}", multibase_encoded);
628
629                // Create the verification method ID
630                let vm_id = format!("{}#{}", did, multibase_encoded);
631
632                // Create the verification method
633                let verification_method = VerificationMethod {
634                    id: vm_id.clone(),
635                    type_: VerificationMethodType::Ed25519VerificationKey2018,
636                    controller: did.clone(),
637                    verification_material: VerificationMaterial::Multibase {
638                        public_key_multibase: multibase_encoded.clone(),
639                    },
640                };
641
642                // Create X25519 key for key agreement - Implement the ed25519_to_x25519 conversion directly
643                let x25519_method_and_agreement = {
644                    // Only Ed25519 public keys must be exactly 32 bytes
645                    if public_key.len() != 32 {
646                        None
647                    } else {
648                        // Try to create a CompressedEdwardsY from the bytes
649                        let edwards_y = match CompressedEdwardsY::from_slice(&public_key) {
650                            Ok(point) => point,
651                            Err(_) => {
652                                return Err(Error::Cryptography(
653                                    "Failed to create Edwards point".to_string(),
654                                ))
655                            }
656                        };
657
658                        // Try to decompress to get the Edwards point
659                        let edwards_point = match edwards_y.decompress() {
660                            Some(point) => point,
661                            None => {
662                                return Err(Error::Cryptography(
663                                    "Failed to decompress Edwards point".to_string(),
664                                ))
665                            }
666                        };
667
668                        // Convert to Montgomery form
669                        let montgomery_point = edwards_point.to_montgomery();
670
671                        // Get the raw bytes representation of the X25519 key
672                        let x25519_key = montgomery_point.to_bytes();
673
674                        // Prefix for X25519: 0xEC01
675                        let mut x25519_prefixed = vec![0xEC, 0x01];
676                        x25519_prefixed.extend_from_slice(&x25519_key);
677
678                        // Encode the prefixed X25519 key with multibase
679                        let x25519_multibase = encode(Base::Base58Btc, &x25519_prefixed);
680
681                        // Create the X25519 verification method ID
682                        let x25519_vm_id = format!("{}#{}", did, x25519_multibase);
683
684                        // Create the X25519 verification method
685                        let x25519_verification_method = VerificationMethod {
686                            id: x25519_vm_id.clone(),
687                            type_: VerificationMethodType::X25519KeyAgreementKey2019,
688                            controller: did.clone(),
689                            verification_material: VerificationMaterial::Multibase {
690                                public_key_multibase: x25519_multibase,
691                            },
692                        };
693
694                        Some((x25519_verification_method, x25519_vm_id))
695                    }
696                };
697
698                // Build verification methods array
699                let mut verification_methods = vec![verification_method.clone()];
700                let mut key_agreement = Vec::new();
701
702                if let Some((x25519_vm, x25519_id)) = x25519_method_and_agreement {
703                    verification_methods.push(x25519_vm);
704                    key_agreement.push(x25519_id);
705                }
706
707                // Create the DID document
708                let did_doc = crate::did::DIDDoc {
709                    id: did.clone(),
710                    verification_method: verification_methods,
711                    authentication: vec![vm_id],
712                    key_agreement,
713                    assertion_method: Vec::new(),
714                    capability_invocation: Vec::new(),
715                    capability_delegation: Vec::new(),
716                    service: Vec::new(),
717                };
718
719                // Create a GeneratedKey with all necessary fields
720                GeneratedKey {
721                    key_type: crate::did::KeyType::Ed25519,
722                    did: did.clone(),
723                    public_key,
724                    private_key: private_key.to_vec(),
725                    did_doc,
726                }
727            }
728            #[cfg(feature = "crypto-p256")]
729            crate::did::KeyType::P256 => {
730                if private_key.len() != 32 {
731                    return Err(Error::Validation(format!(
732                        "Invalid P-256 private key length: {}, expected 32 bytes",
733                        private_key.len()
734                    )));
735                }
736
737                // For P-256, create a signing key from the private key
738                let signing_key = match p256::ecdsa::SigningKey::from_slice(private_key) {
739                    Ok(key) => key,
740                    Err(e) => {
741                        return Err(Error::Cryptography(format!(
742                            "Failed to create P-256 signing key: {:?}",
743                            e
744                        )))
745                    }
746                };
747
748                // Get the public key in uncompressed form
749                let public_key = signing_key
750                    .verifying_key()
751                    .to_encoded_point(false)
752                    .to_bytes()
753                    .to_vec();
754
755                // Create did:key identifier
756                // Multicodec prefix for P-256: 0x1200
757                let mut prefixed_key = vec![0x12, 0x00];
758                prefixed_key.extend_from_slice(&public_key);
759
760                // Encode the key with multibase (base58btc with 'z' prefix)
761                let multibase_encoded = encode(Base::Base58Btc, &prefixed_key);
762                let did = format!("did:key:{}", multibase_encoded);
763
764                // Create the verification method ID
765                let vm_id = format!("{}#{}", did, multibase_encoded);
766
767                // Create the verification method
768                let verification_method = VerificationMethod {
769                    id: vm_id.clone(),
770                    type_: VerificationMethodType::EcdsaSecp256k1VerificationKey2019, // Using the available type
771                    controller: did.clone(),
772                    verification_material: VerificationMaterial::Multibase {
773                        public_key_multibase: multibase_encoded.clone(),
774                    },
775                };
776
777                // Create the DID document
778                let did_doc = crate::did::DIDDoc {
779                    id: did.clone(),
780                    verification_method: vec![verification_method],
781                    authentication: vec![vm_id],
782                    key_agreement: Vec::new(),
783                    assertion_method: Vec::new(),
784                    capability_invocation: Vec::new(),
785                    capability_delegation: Vec::new(),
786                    service: Vec::new(),
787                };
788
789                // Create a GeneratedKey with all necessary fields
790                GeneratedKey {
791                    key_type: crate::did::KeyType::P256,
792                    did: did.clone(),
793                    public_key,
794                    private_key: private_key.to_vec(),
795                    did_doc,
796                }
797            }
798            #[cfg(feature = "crypto-secp256k1")]
799            crate::did::KeyType::Secp256k1 => {
800                if private_key.len() != 32 {
801                    return Err(Error::Validation(format!(
802                        "Invalid Secp256k1 private key length: {}, expected 32 bytes",
803                        private_key.len()
804                    )));
805                }
806
807                // For Secp256k1, create a signing key from the private key
808                let signing_key = match k256::ecdsa::SigningKey::from_slice(private_key) {
809                    Ok(key) => key,
810                    Err(e) => {
811                        return Err(Error::Cryptography(format!(
812                            "Failed to create Secp256k1 signing key: {:?}",
813                            e
814                        )))
815                    }
816                };
817
818                // Get the public key in uncompressed form
819                let public_key = signing_key
820                    .verifying_key()
821                    .to_encoded_point(false)
822                    .to_bytes()
823                    .to_vec();
824
825                // Create did:key identifier
826                // Multicodec prefix for Secp256k1: 0xe701
827                let mut prefixed_key = vec![0xe7, 0x01];
828                prefixed_key.extend_from_slice(&public_key);
829
830                // Encode the key with multibase (base58btc with 'z' prefix)
831                let multibase_encoded = encode(Base::Base58Btc, &prefixed_key);
832                let did = format!("did:key:{}", multibase_encoded);
833
834                // Create the verification method ID
835                let vm_id = format!("{}#{}", did, multibase_encoded);
836
837                // Create the verification method
838                let verification_method = VerificationMethod {
839                    id: vm_id.clone(),
840                    type_: VerificationMethodType::EcdsaSecp256k1VerificationKey2019,
841                    controller: did.clone(),
842                    verification_material: VerificationMaterial::Multibase {
843                        public_key_multibase: multibase_encoded.clone(),
844                    },
845                };
846
847                // Create the DID document
848                let did_doc = crate::did::DIDDoc {
849                    id: did.clone(),
850                    verification_method: vec![verification_method],
851                    authentication: vec![vm_id],
852                    key_agreement: Vec::new(),
853                    assertion_method: Vec::new(),
854                    capability_invocation: Vec::new(),
855                    capability_delegation: Vec::new(),
856                    service: Vec::new(),
857                };
858
859                // Create a GeneratedKey with all necessary fields
860                GeneratedKey {
861                    key_type: crate::did::KeyType::Secp256k1,
862                    did: did.clone(),
863                    public_key,
864                    private_key: private_key.to_vec(),
865                    did_doc,
866                }
867            }
868        };
869
870        // Create secret from the generated key and use it to add to the key manager
871        let did_generator = DIDKeyGenerator::new();
872        let _secret = did_generator.create_secret_from_key(&generated_key);
873
874        // Add the key to the key manager
875        key_manager.add_key(&generated_key)?;
876
877        // Create a config with the new DID
878        let config = AgentConfig::new(generated_key.did.clone()).with_debug(debug);
879
880        // Create the agent
881        #[cfg(all(not(target_arch = "wasm32"), test))]
882        {
883            // Create a default resolver
884            let resolver = Arc::new(crate::did::MultiResolver::default());
885            let agent = Self::new_with_resolver(config, Arc::new(key_manager), resolver);
886            Ok((agent, generated_key.did))
887        }
888
889        #[cfg(all(not(target_arch = "wasm32"), not(test)))]
890        {
891            let agent = Self::new(config, Arc::new(key_manager));
892            Ok((agent, generated_key.did))
893        }
894
895        #[cfg(target_arch = "wasm32")]
896        {
897            let agent = Self::new(config, Arc::new(key_manager));
898            Ok((agent, generated_key.did))
899        }
900    }
901
902    /// Determine the appropriate security mode for a message type
903    ///
904    /// This method implements TAP protocol rules for which security modes
905    /// should be used with different message types:
906    /// - Presentation messages use authenticated encryption (AuthCrypt)
907    /// - All other messages use digital signatures (Signed)
908    ///
909    /// If security_mode is specified in the agent config, that takes precedence.
910    ///
911    /// # Parameters
912    /// * `message_type` - The type of the message
913    ///
914    /// # Returns
915    /// The appropriate SecurityMode for the message type
916    #[cfg(not(target_arch = "wasm32"))]
917    fn determine_security_mode<T: TapMessageBody>(&self) -> SecurityMode {
918        // If security mode is explicitly configured, use that
919        if let Some(ref mode) = self.config.security_mode {
920            match mode.to_uppercase().as_str() {
921                "AUTHCRYPT" => return SecurityMode::AuthCrypt,
922                "ANONCRYPT" => return SecurityMode::AnonCrypt,
923                _ => return SecurityMode::Signed,
924            }
925        }
926
927        // Otherwise use type-based rules
928        let message_type = T::message_type();
929        if message_type == crate::message::PRESENTATION_MESSAGE_TYPE {
930            SecurityMode::AuthCrypt
931        } else {
932            SecurityMode::Signed
933        }
934    }
935
936    /// Get the signing key ID for this agent
937    ///
938    /// Resolves the DID document and returns the first authentication verification method ID
939    pub async fn get_signing_kid(&self) -> Result<String> {
940        let did = &self.config.agent_did;
941
942        // Try to get the DID document from our key manager first
943        if let Ok(agent_key) = self.key_manager.get_generated_key(did) {
944            // Get the first authentication method from the DID document
945            if let Some(auth_method_id) = agent_key.did_doc.authentication.first() {
946                return Ok(auth_method_id.clone());
947            }
948
949            // Fallback to first verification method
950            if let Some(vm) = agent_key.did_doc.verification_method.first() {
951                return Ok(vm.id.clone());
952            }
953        }
954
955        // Fallback to guessing based on DID method (for backward compatibility)
956        if did.starts_with("did:key:") {
957            let multibase = did.strip_prefix("did:key:").unwrap_or("");
958            Ok(format!("{}#{}", did, multibase))
959        } else if did.starts_with("did:web:") {
960            Ok(format!("{}#keys-1", did))
961        } else {
962            Ok(format!("{}#key-1", did))
963        }
964    }
965
966    /// Get the encryption key ID for a recipient
967    ///
968    /// Resolves the DID document and returns the appropriate key agreement method ID
969    pub async fn get_encryption_kid(&self, recipient_did: &str) -> Result<String> {
970        if recipient_did == self.config.agent_did {
971            // If asking for our own encryption key, get it from our DID document
972            if let Ok(agent_key) = self.key_manager.get_generated_key(recipient_did) {
973                // Look for key agreement methods first
974                if let Some(agreement_method_id) = agent_key.did_doc.key_agreement.first() {
975                    return Ok(agreement_method_id.clone());
976                }
977
978                // Fallback to authentication method (for keys that do both)
979                if let Some(auth_method_id) = agent_key.did_doc.authentication.first() {
980                    return Ok(auth_method_id.clone());
981                }
982
983                // Fallback to first verification method
984                if let Some(vm) = agent_key.did_doc.verification_method.first() {
985                    return Ok(vm.id.clone());
986                }
987            }
988
989            // Final fallback to signing key
990            return self.get_signing_kid().await;
991        }
992
993        // For external recipients, try to resolve their DID document
994        #[cfg(all(not(target_arch = "wasm32"), test))]
995        if let Some(resolver) = &self.resolver {
996            if let Ok(Some(did_doc)) = resolver.resolve(recipient_did).await {
997                // Look for key agreement methods first
998                if let Some(agreement_method_id) = did_doc.key_agreement.first() {
999                    return Ok(agreement_method_id.clone());
1000                }
1001
1002                // Fallback to authentication method
1003                if let Some(auth_method_id) = did_doc.authentication.first() {
1004                    return Ok(auth_method_id.clone());
1005                }
1006
1007                // Fallback to first verification method
1008                if let Some(vm) = did_doc.verification_method.first() {
1009                    return Ok(vm.id.clone());
1010                }
1011            }
1012        }
1013
1014        // Fallback to guessing based on DID method (for backward compatibility)
1015        if recipient_did.starts_with("did:key:") {
1016            let multibase = recipient_did.strip_prefix("did:key:").unwrap_or("");
1017            Ok(format!("{}#{}", recipient_did, multibase))
1018        } else if recipient_did.starts_with("did:web:") {
1019            Ok(format!("{}#keys-1", recipient_did))
1020        } else {
1021            Ok(format!("{}#key-1", recipient_did))
1022        }
1023    }
1024
1025    /// Send a message to a specific endpoint
1026    ///
1027    /// # Parameters
1028    /// * `packed_message` - The packed message to send
1029    /// * `endpoint` - The endpoint URL to send the message to
1030    ///
1031    /// # Returns
1032    /// The HTTP response status code, or error if the request failed
1033    #[cfg(all(feature = "native", not(target_arch = "wasm32")))]
1034    pub async fn send_to_endpoint(&self, packed_message: &str, endpoint: &str) -> Result<u16> {
1035        // Get HTTP client
1036        let client = self
1037            .http_client
1038            .as_ref()
1039            .ok_or_else(|| Error::Networking("HTTP client not available".to_string()))?;
1040
1041        // Send the message to the endpoint via HTTP POST
1042        let response = client
1043            .post(endpoint)
1044            .header("Content-Type", "application/didcomm-encrypted+json")
1045            .body(packed_message.to_string())
1046            .send()
1047            .await
1048            .map_err(|e| Error::Networking(format!("Failed to send message to endpoint: {}", e)))?;
1049
1050        // Get the status code
1051        let status = response.status().as_u16();
1052
1053        // Log the response status
1054        debug!("Message sent to endpoint {}, status: {}", endpoint, status);
1055
1056        Ok(status)
1057    }
1058
1059    #[cfg(any(not(feature = "native"), target_arch = "wasm32"))]
1060    pub async fn send_to_endpoint(&self, _packed_message: &str, _endpoint: &str) -> Result<u16> {
1061        // Feature not enabled or WASM doesn't have http_client
1062        Err(crate::error::Error::NotImplemented(
1063            "HTTP client not available".to_string(),
1064        ))
1065    }
1066
1067    /// Create an agent with enhanced configuration (policies and metadata)
1068    pub async fn create_enhanced_agent(
1069        agent_id: String,
1070        policies: Vec<String>,
1071        metadata: std::collections::HashMap<String, String>,
1072        save_to_storage: bool,
1073    ) -> Result<(Self, String)> {
1074        Self::create_enhanced_agent_with_path(agent_id, policies, metadata, save_to_storage, None)
1075            .await
1076    }
1077
1078    /// Create an agent with enhanced configuration (policies and metadata) with custom storage path
1079    pub async fn create_enhanced_agent_with_path(
1080        agent_id: String,
1081        policies: Vec<String>,
1082        metadata: std::collections::HashMap<String, String>,
1083        save_to_storage: bool,
1084        storage_path: Option<PathBuf>,
1085    ) -> Result<(Self, String)> {
1086        use crate::did::{DIDGenerationOptions, KeyType};
1087        use crate::storage::KeyStorage;
1088
1089        // Create a key manager and generate a key without saving to storage
1090        let key_manager = AgentKeyManager::new();
1091        let generated_key = key_manager.generate_key_without_save(DIDGenerationOptions {
1092            key_type: KeyType::Ed25519,
1093        })?;
1094
1095        // Create a config with the provided agent ID
1096        let config = AgentConfig::new(agent_id.clone()).with_debug(true);
1097
1098        // Add the generated key to the key manager with the custom DID
1099        // Use add_key_without_save to prevent automatic storage write
1100        let mut custom_generated_key = generated_key.clone();
1101        custom_generated_key.did = agent_id.clone();
1102        key_manager.add_key_without_save(&custom_generated_key)?;
1103
1104        // Create the agent
1105        #[cfg(all(not(target_arch = "wasm32"), test))]
1106        let agent = {
1107            let resolver = Arc::new(crate::did::MultiResolver::default());
1108            Self::new_with_resolver(config, Arc::new(key_manager), resolver)
1109        };
1110
1111        #[cfg(all(not(target_arch = "wasm32"), not(test)))]
1112        let agent = Self::new(config, Arc::new(key_manager));
1113
1114        #[cfg(target_arch = "wasm32")]
1115        let agent = Self::new(config, Arc::new(key_manager));
1116
1117        if save_to_storage {
1118            // Save to key storage
1119            let mut key_storage = if let Some(path) = &storage_path {
1120                KeyStorage::load_from_path(path)?
1121            } else {
1122                KeyStorage::load_default()?
1123            };
1124
1125            // Convert the generated key to a stored key
1126            let mut stored_key = KeyStorage::from_generated_key(&custom_generated_key);
1127            stored_key.label = format!(
1128                "agent-{}",
1129                agent_id.split(':').next_back().unwrap_or("agent")
1130            );
1131
1132            key_storage.add_key(stored_key);
1133
1134            if let Some(path) = &storage_path {
1135                key_storage.save_to_path(path)?;
1136            } else {
1137                key_storage.save_default()?;
1138            }
1139
1140            // Create agent directory with policies and metadata
1141            key_storage.create_agent_directory(&agent_id, &policies, &metadata)?;
1142        }
1143
1144        Ok((agent, agent_id))
1145    }
1146
1147    /// Load an enhanced agent from storage with policies and metadata
1148    pub async fn load_enhanced_agent(
1149        did: &str,
1150    ) -> Result<(Self, Vec<String>, std::collections::HashMap<String, String>)> {
1151        use crate::storage::KeyStorage;
1152
1153        // Load key storage
1154        let key_storage = KeyStorage::load_default()?;
1155
1156        // Check if the key exists in storage
1157        let agent = if key_storage.keys.contains_key(did) {
1158            // Load agent from stored keys
1159            Self::from_stored_keys(Some(did.to_string()), true).await?
1160        } else {
1161            // If key doesn't exist in storage, create an ephemeral agent
1162            // This is for test scenarios where agents are created but not persisted
1163            let (mut agent, _) = Self::from_ephemeral_key().await?;
1164            agent.config.agent_did = did.to_string();
1165            agent
1166        };
1167
1168        // Load policies and metadata from agent directory
1169        let policies = key_storage.load_agent_policies(did).unwrap_or_default();
1170        let metadata = key_storage.load_agent_metadata(did).unwrap_or_default();
1171
1172        Ok((agent, policies, metadata))
1173    }
1174
1175    /// List all enhanced agents with their policies and metadata
1176    pub fn list_enhanced_agents() -> Result<Vec<EnhancedAgentInfo>> {
1177        Self::list_enhanced_agents_with_path(None)
1178    }
1179
1180    /// List all enhanced agents with their policies and metadata with custom storage path
1181    pub fn list_enhanced_agents_with_path(
1182        storage_path: Option<PathBuf>,
1183    ) -> Result<Vec<EnhancedAgentInfo>> {
1184        use crate::storage::KeyStorage;
1185        use std::fs;
1186
1187        let key_storage = if let Some(path) = &storage_path {
1188            KeyStorage::load_from_path(path)?
1189        } else {
1190            KeyStorage::load_default()?
1191        };
1192        let mut agents = Vec::new();
1193
1194        // Get TAP directory
1195        let tap_dir = if let Some(path) = &storage_path {
1196            // For custom paths, the tap directory is the parent of the keys.json file
1197            path.parent()
1198                .ok_or_else(|| Error::Storage("Invalid storage path".to_string()))?
1199                .to_path_buf()
1200        } else {
1201            let home = dirs::home_dir()
1202                .ok_or_else(|| Error::Storage("Could not determine home directory".to_string()))?;
1203            home.join(crate::storage::DEFAULT_TAP_DIR)
1204        };
1205
1206        if !tap_dir.exists() {
1207            return Ok(agents);
1208        }
1209
1210        // Scan for agent directories
1211        for entry in fs::read_dir(&tap_dir)? {
1212            let entry = entry?;
1213            let path = entry.path();
1214
1215            if path.is_dir() {
1216                let dir_name = path.file_name().and_then(|n| n.to_str()).unwrap_or("");
1217
1218                // Skip known non-agent directories
1219                if dir_name == "keys.json" || dir_name.is_empty() {
1220                    continue;
1221                }
1222
1223                // Convert sanitized DID back to original format
1224                let did = dir_name.replace('_', ":");
1225
1226                // Try to load policies and metadata
1227                let policies = key_storage.load_agent_policies(&did).unwrap_or_default();
1228                let metadata = key_storage.load_agent_metadata(&did).unwrap_or_default();
1229
1230                // Only include if there are policies or metadata (indicating an enhanced agent)
1231                if !policies.is_empty() || !metadata.is_empty() {
1232                    agents.push((did, policies, metadata));
1233                }
1234            }
1235        }
1236
1237        Ok(agents)
1238    }
1239}
1240
1241#[async_trait]
1242#[cfg(not(target_arch = "wasm32"))]
1243impl crate::agent::Agent for TapAgent {
1244    fn get_agent_did(&self) -> &str {
1245        &self.config.agent_did
1246    }
1247
1248    async fn get_service_endpoint(&self, to: &str) -> Result<Option<String>> {
1249        // If it's a URL, return it directly
1250        if to.starts_with("http://") || to.starts_with("https://") {
1251            return Ok(Some(to.to_string()));
1252        }
1253
1254        // If it's a DID, try to find a service endpoint using the resolver
1255        if to.starts_with("did:") {
1256            // Use the DID resolver from the AgentKeyManager to get the service endpoints
1257            // For now, we'll use a simple approach that looks for DIDCommMessaging or Web service types
1258
1259            // For testing purposes, attempt to check if TapAgent has a resolver field
1260            #[cfg(test)]
1261            if let Some(resolver) = self.resolver.as_ref() {
1262                if let Ok(Some(did_doc)) = resolver.resolve(to).await {
1263                    // Look for services of type DIDCommMessaging first
1264                    if let Some(service) = did_doc
1265                        .service
1266                        .iter()
1267                        .find(|s| s.type_ == "DIDCommMessaging")
1268                    {
1269                        return Ok(Some(service.service_endpoint.clone()));
1270                    }
1271
1272                    // Then try Web type
1273                    if let Some(service) = did_doc.service.iter().find(|s| s.type_ == "Web") {
1274                        return Ok(Some(service.service_endpoint.clone()));
1275                    }
1276
1277                    // No matching service found in DID doc
1278                    if !did_doc.service.is_empty() {
1279                        // Use the first service as fallback
1280                        return Ok(Some(did_doc.service[0].service_endpoint.clone()));
1281                    }
1282                }
1283            }
1284
1285            // Fallback to a placeholder URL if no resolver is available or no service found
1286            return Ok(Some(format!(
1287                "https://example.com/did/{}",
1288                to.replace(":", "_")
1289            )));
1290        }
1291
1292        // No service endpoint found
1293        Ok(None)
1294    }
1295
1296    async fn send_message<
1297        T: TapMessageBody + serde::Serialize + Send + Sync + std::fmt::Debug + 'static,
1298    >(
1299        &self,
1300        message: &T,
1301        to: Vec<&str>,
1302        deliver: bool,
1303    ) -> Result<(String, Vec<DeliveryResult>)> {
1304        if to.is_empty() {
1305            return Err(Error::Validation("No recipients specified".to_string()));
1306        }
1307
1308        // Log the plaintext message
1309        debug!("\n==== SENDING TAP MESSAGE ====");
1310        debug!("Message Type: {}", T::message_type());
1311        debug!("Recipients: {:?}", to);
1312
1313        // Convert the TapMessageBody to a PlainMessage with explicit routing
1314        let plain_message =
1315            message.to_didcomm_with_route(self.get_agent_did(), to.iter().copied())?;
1316
1317        // Determine the appropriate security mode
1318        let security_mode = self.determine_security_mode::<T>();
1319        debug!("Security Mode: {:?}", security_mode);
1320
1321        // For each recipient, look up service endpoint before sending
1322        for recipient in &to {
1323            if let Ok(Some(endpoint)) = self.get_service_endpoint(recipient).await {
1324                debug!("Found service endpoint for {}: {}", recipient, endpoint);
1325            }
1326        }
1327
1328        // Get the appropriate key IDs
1329        let sender_kid = self.get_signing_kid().await?;
1330        let recipient_kid = if to.len() == 1
1331            && (security_mode == SecurityMode::AuthCrypt
1332                || security_mode == SecurityMode::AnonCrypt)
1333        {
1334            Some(self.get_encryption_kid(to[0]).await?)
1335        } else {
1336            None
1337        };
1338
1339        // Create pack options for the plaintext message
1340        let pack_options = PackOptions {
1341            security_mode,
1342            sender_kid: if security_mode == SecurityMode::AnonCrypt {
1343                None
1344            } else {
1345                Some(sender_kid)
1346            },
1347            recipient_kid,
1348        };
1349
1350        // Pack the plain message using the Packable trait
1351        let packed = plain_message.pack(&*self.key_manager, pack_options).await?;
1352
1353        // Log the packed message
1354        debug!("--- PACKED MESSAGE ---");
1355        debug!(
1356            "{}",
1357            serde_json::from_str::<serde_json::Value>(&packed)
1358                .map(|v| serde_json::to_string_pretty(&v).unwrap_or(packed.clone()))
1359                .unwrap_or(packed.clone())
1360        );
1361        debug!("=====================");
1362
1363        // If delivery is not requested, just return the packed message
1364        if !deliver {
1365            return Ok((packed, Vec::new()));
1366        }
1367
1368        // Try to deliver the message to each recipient's service endpoint
1369        let mut delivery_results = Vec::new();
1370
1371        for recipient in &to {
1372            match self.get_service_endpoint(recipient).await {
1373                Ok(Some(endpoint)) => {
1374                    debug!("Delivering message to {} at {}", recipient, endpoint);
1375
1376                    // Extract message ID for logging
1377                    let message_id = match serde_json::from_str::<Value>(&packed) {
1378                        Ok(json) => json
1379                            .get("id")
1380                            .and_then(|id| id.as_str())
1381                            .map(String::from)
1382                            .unwrap_or_else(|| "unknown".to_string()),
1383                        Err(_) => "unknown".to_string(),
1384                    };
1385
1386                    // Attempt to deliver the message
1387                    match self.send_to_endpoint(&packed, &endpoint).await {
1388                        Ok(status) => {
1389                            info!(
1390                                "✅ Delivered message {} to {} at {}",
1391                                message_id, recipient, endpoint
1392                            );
1393
1394                            delivery_results.push(DeliveryResult {
1395                                did: recipient.to_string(),
1396                                endpoint: endpoint.clone(),
1397                                status: Some(status),
1398                                error: None,
1399                            });
1400                        }
1401                        Err(e) => {
1402                            // Log error but don't fail
1403                            let error_msg = format!(
1404                                "Failed to deliver message {} to {} at {}: {}",
1405                                message_id, recipient, endpoint, e
1406                            );
1407                            error!("❌ {}", error_msg);
1408
1409                            delivery_results.push(DeliveryResult {
1410                                did: recipient.to_string(),
1411                                endpoint: endpoint.clone(),
1412                                status: None,
1413                                error: Some(error_msg),
1414                            });
1415                        }
1416                    }
1417                }
1418                Ok(None) => {
1419                    warn!(
1420                        "⚠️ No service endpoint found for {}, skipping delivery",
1421                        recipient
1422                    );
1423                }
1424                Err(e) => {
1425                    // Log error but don't fail
1426                    let error_msg = format!(
1427                        "Failed to resolve service endpoint for {}: {}",
1428                        recipient, e
1429                    );
1430                    error!("❌ {}", error_msg);
1431                }
1432            }
1433        }
1434
1435        Ok((packed, delivery_results))
1436    }
1437
1438    async fn receive_encrypted_message(&self, jwe_value: &Value) -> Result<()> {
1439        // Log the received encrypted message
1440        debug!("\n==== RECEIVING ENCRYPTED MESSAGE ====");
1441        debug!("Agent DID: {}", self.get_agent_did());
1442
1443        // Parse as JWE
1444        let jwe: crate::message::Jwe = serde_json::from_value(jwe_value.clone())
1445            .map_err(|e| Error::Serialization(format!("Failed to parse JWE: {}", e)))?;
1446
1447        // Get our encryption key ID
1448        let our_kid = self.get_signing_kid().await.ok();
1449
1450        // Create unpack options (accept both AuthCrypt and AnonCrypt)
1451        let unpack_options = UnpackOptions {
1452            expected_security_mode: SecurityMode::Any,
1453            expected_recipient_kid: our_kid,
1454            require_signature: false,
1455        };
1456
1457        // Decrypt the message
1458        let plain_message: PlainMessage<Value> =
1459            crate::message::Jwe::unpack(&jwe, &*self.key_manager, unpack_options).await?;
1460
1461        debug!(
1462            "Processed encrypted message: {} of type {}",
1463            plain_message.id, plain_message.type_
1464        );
1465        Ok(())
1466    }
1467
1468    async fn receive_plain_message(&self, message: PlainMessage) -> Result<()> {
1469        // Process already verified/decrypted message
1470        debug!("\n==== RECEIVING PLAIN MESSAGE ====");
1471        debug!("Message ID: {}", message.id);
1472        debug!("Message Type: {}", message.type_);
1473
1474        Ok(())
1475    }
1476
1477    async fn receive_message(&self, raw_message: &str) -> Result<PlainMessage> {
1478        // Log the received raw message
1479        debug!("\n==== RECEIVING RAW MESSAGE ====");
1480        debug!("Agent DID: {}", self.get_agent_did());
1481
1482        // First try to parse as JSON to determine message type
1483        let json_value: Value = serde_json::from_str(raw_message)
1484            .map_err(|e| Error::Serialization(format!("Failed to parse message as JSON: {}", e)))?;
1485
1486        // Check if it's an encrypted message (JWE) or signed message (JWS)
1487        let is_encrypted =
1488            json_value.get("protected").is_some() && json_value.get("recipients").is_some();
1489        let is_signed = json_value.get("payload").is_some()
1490            && (json_value.get("signatures").is_some() || json_value.get("signature").is_some());
1491
1492        debug!(
1493            "Message type detection: encrypted={}, signed={}",
1494            is_encrypted, is_signed
1495        );
1496
1497        if is_signed {
1498            debug!("Detected signed message");
1499            debug!("--- SIGNED MESSAGE ---");
1500            debug!(
1501                "{}",
1502                serde_json::to_string_pretty(&json_value).unwrap_or(raw_message.to_string())
1503            );
1504            debug!("---------------------");
1505
1506            // Parse as JWS
1507            let jws: crate::message::Jws = serde_json::from_value(json_value)
1508                .map_err(|e| Error::Serialization(format!("Failed to parse JWS: {}", e)))?;
1509
1510            // Verify using our resolver
1511            #[cfg(test)]
1512            let plain_message = if let Some(resolver) = &self.resolver {
1513                crate::verification::verify_jws(&jws, &**resolver).await?
1514            } else {
1515                // Fallback to unpacking with key manager for test compatibility
1516                let unpack_options = UnpackOptions {
1517                    expected_security_mode: SecurityMode::Signed,
1518                    expected_recipient_kid: None,
1519                    require_signature: true,
1520                };
1521                crate::message::Jws::unpack(&jws, &*self.key_manager, unpack_options).await?
1522            };
1523
1524            #[cfg(not(test))]
1525            let plain_message = {
1526                // In production, we need a resolver - for now use unpacking
1527                let unpack_options = UnpackOptions {
1528                    expected_security_mode: SecurityMode::Signed,
1529                    expected_recipient_kid: None,
1530                    require_signature: true,
1531                };
1532                crate::message::Jws::unpack(&jws, &*self.key_manager, unpack_options).await?
1533            };
1534
1535            // Log the unpacked message
1536            debug!("--- UNPACKED CONTENT ---");
1537            debug!(
1538                "{}",
1539                serde_json::to_string_pretty(&plain_message)
1540                    .unwrap_or_else(|_| format!("{:?}", plain_message))
1541            );
1542            debug!("------------------------");
1543
1544            Ok(plain_message)
1545        } else if is_encrypted {
1546            debug!("Detected encrypted message");
1547            debug!("--- ENCRYPTED MESSAGE ---");
1548            debug!(
1549                "{}",
1550                serde_json::to_string_pretty(&json_value).unwrap_or(raw_message.to_string())
1551            );
1552            debug!("---------------------");
1553
1554            // Get our encryption key ID
1555            let our_kid = self.get_signing_kid().await.ok();
1556
1557            // Create unpack options (accept both AuthCrypt and AnonCrypt for encrypted messages)
1558            let unpack_options = UnpackOptions {
1559                expected_security_mode: SecurityMode::Any,
1560                expected_recipient_kid: our_kid,
1561                require_signature: false,
1562            };
1563
1564            debug!("Unpacking with options: {:?}", unpack_options);
1565
1566            // Unpack the message
1567            let plain_message: PlainMessage =
1568                match String::unpack(&raw_message.to_string(), &*self.key_manager, unpack_options)
1569                    .await
1570                {
1571                    Ok(msg) => msg,
1572                    Err(e) => {
1573                        error!("Failed to unpack message: {}", e);
1574                        return Err(e);
1575                    }
1576                };
1577
1578            // Log the unpacked message
1579            debug!("--- UNPACKED CONTENT ---");
1580            debug!(
1581                "{}",
1582                serde_json::to_string_pretty(&plain_message)
1583                    .unwrap_or_else(|_| format!("{:?}", plain_message))
1584            );
1585            debug!("------------------------");
1586
1587            Ok(plain_message)
1588        } else {
1589            // It's already a plain message
1590            debug!("Detected plain message");
1591            debug!("--- PLAIN MESSAGE ---");
1592            debug!(
1593                "{}",
1594                serde_json::to_string_pretty(&json_value).unwrap_or(raw_message.to_string())
1595            );
1596            debug!("---------------------");
1597
1598            // Parse directly as PlainMessage
1599            serde_json::from_str::<PlainMessage>(raw_message)
1600                .map_err(|e| Error::Serialization(format!("Failed to parse PlainMessage: {}", e)))
1601        }
1602    }
1603
1604    async fn create_oob_invitation<T: TapMessageBody + serde::Serialize + Send + Sync>(
1605        &self,
1606        message: &T,
1607        goal_code: &str,
1608        goal: &str,
1609        service_url: &str,
1610    ) -> Result<String> {
1611        // Create the DIDComm PlainMessage for the message
1612        let plain_message = message.to_didcomm(self.get_agent_did())?;
1613
1614        // Serialize the plain message for signing (for debugging/logging purposes)
1615        let _message_json = serde_json::to_string(&plain_message)
1616            .map_err(|e| Error::Serialization(format!("Failed to serialize message: {}", e)))?;
1617
1618        // Sign the message using the pack method
1619        let sender_kid = self.get_signing_kid().await?;
1620        let pack_options = crate::message_packing::PackOptions::new().with_sign(&sender_kid);
1621        let signed_message = plain_message.pack(&*self.key_manager, pack_options).await?;
1622
1623        // Create the OOB invitation
1624        let oob_invitation =
1625            crate::oob::OutOfBandInvitation::builder(self.get_agent_did(), goal_code, goal)
1626                .add_signed_attachment("tap-message", &signed_message, Some("Signed TAP message"))
1627                .build();
1628
1629        // Generate the URL
1630        oob_invitation.to_url(service_url)
1631    }
1632
1633    async fn create_payment_link(
1634        &self,
1635        payment: &tap_msg::message::Payment,
1636        config: Option<crate::payment_link::PaymentLinkConfig>,
1637    ) -> Result<String> {
1638        let config = config.unwrap_or_default();
1639
1640        // Create a signing function that uses our pack method
1641        let key_manager = self.key_manager.clone();
1642        let agent_did = self.get_agent_did().to_string();
1643
1644        let sign_fn = move |message_json: String| {
1645            let key_manager = key_manager.clone();
1646            let agent_did = agent_did.clone();
1647
1648            async move {
1649                // Parse the message to get a PlainMessage
1650                let plain_message: PlainMessage =
1651                    serde_json::from_str(&message_json).map_err(|e| {
1652                        Error::Serialization(format!("Failed to parse message for signing: {}", e))
1653                    })?;
1654
1655                // Create a temporary agent to get the signing key ID
1656                let temp_config = AgentConfig::new(agent_did.clone());
1657                let temp_agent = TapAgent::new(temp_config, key_manager.clone());
1658                let sender_kid = temp_agent.get_signing_kid().await?;
1659
1660                let pack_options =
1661                    crate::message_packing::PackOptions::new().with_sign(&sender_kid);
1662                plain_message.pack(&*key_manager, pack_options).await
1663            }
1664        };
1665
1666        // Use the payment link builder with our signing function
1667        let payment_link =
1668            crate::payment_link::PaymentLink::builder(self.get_agent_did(), payment.clone())
1669                .with_config(config)
1670                .build_with_signer(sign_fn)
1671                .await?;
1672
1673        Ok(payment_link.url)
1674    }
1675
1676    fn parse_oob_invitation(&self, url: &str) -> Result<crate::oob::OutOfBandInvitation> {
1677        crate::oob::OutOfBandInvitation::from_url(url)
1678    }
1679
1680    async fn process_oob_invitation(
1681        &self,
1682        oob_invitation: &crate::oob::OutOfBandInvitation,
1683    ) -> Result<PlainMessage> {
1684        // Validate the invitation
1685        oob_invitation.validate()?;
1686
1687        // Get the signed attachment
1688        let attachment = oob_invitation.get_signed_attachment().ok_or_else(|| {
1689            Error::Validation("No signed attachment found in OOB invitation".to_string())
1690        })?;
1691
1692        // Extract the signed message JSON
1693        let signed_message_json = match &attachment.data {
1694            tap_msg::didcomm::AttachmentData::Json { value } => &value.json,
1695            _ => {
1696                return Err(Error::Validation(
1697                    "Attachment does not contain JSON data".to_string(),
1698                ))
1699            }
1700        };
1701
1702        // Convert to string for processing
1703        let signed_message_str = serde_json::to_string(signed_message_json).map_err(|e| {
1704            Error::Serialization(format!("Failed to serialize signed message: {}", e))
1705        })?;
1706
1707        // Process the signed message using our existing receive_message method
1708        self.receive_message(&signed_message_str).await
1709    }
1710}