1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
//! This module defines an tk agent.

use std::borrow::Borrow;
use std::os::unix::thread;

use futures::FutureExt;
use log::info;
use yaaral::RuntimeInterface;

use crate::delegation::transport;
use crate::module::Module;
use crate::{
  decision, definitions, delegation, execution, knowledge_base, module, states, utils, Result,
};
use delegation::Task;

//     _                    _   ____        _
//    / \   __ _  ___ _ __ | |_|  _ \  __ _| |_ __ _
//   / _ \ / _` |/ _ \ '_ \| __| | | |/ _` | __/ _` |
//  / ___ | (_| |  __/ | | | |_| |_| | (_| | || (_| |
// /_/   \_\__, |\___|_| |_|\__|____/ \__,_|\__\__,_|
//         |___/

/// Data of an agent
#[derive(Clone)]
pub struct AgentData
{
  /// Uri of the agent
  pub agent_uri: String,
  /// Runtime for async (selected as a feature)
  pub async_runtime: yaaral::Runtime,
  /// Interface to the knowledge base of the agent
  pub knowledge_base: Box<dyn knowledge_base::KnowledgeBase>,
  /// Internal copy of the states of the agent
  pub states: states::SharedStates,
  /// Capabilities of the agent
  pub capabilities: definitions::agent::capabilities::Capabilities,
}

trait AgentDataTrait: Sync + Send {}

impl AgentDataTrait for AgentData {}

//                           _
//     /\                   | |
//    /  \   __ _  ___ _ __ | |_
//   / /\ \ / _` |/ _ \ '_ \| __|
//  / ____ \ (_| |  __/ | | | |_
// /_/    \_\__, |\___|_| |_|\__|
//           __/ |
//          |___/

/// This class represent a TK agent
pub struct Agent
{
  agent_data: AgentData,
  delegation_interface:
    module::ModuleInterface<delegation::InputMessage, delegation::OutputMessage>,
}

impl Agent
{
  /// Create a new agent with the given knowlege base and transport for the delegation
  pub fn new<TTransport, TDecision, TExecution, TKnowledgeBase>(
    agent_uri: String,
    async_runtime: yaaral::Runtime,
    knowledge_base: TKnowledgeBase,
    states: crate::states::States,
    capabilities: definitions::agent::capabilities::Capabilities,
    transport_options: TTransport::Options,
    decision_options: TDecision::Options,
    executor_options: TExecution::Options,
  ) -> Result<Self>
  where
    TKnowledgeBase: knowledge_base::KnowledgeBase,
    TTransport: delegation::transport::Module,
    TDecision: decision::Module,
    TExecution: execution::Module,
  {
    let agent_data = AgentData {
      agent_uri: agent_uri,
      async_runtime: async_runtime,
      knowledge_base: Box::new(knowledge_base),
      states: states::SharedStates::new(states),
      capabilities,
    };

    let transport_interfaces = TTransport::prepare_interfaces(20);
    let delegation_interfaces = delegation::Module::prepare_interfaces(20);
    let decision_interfaces = TDecision::prepare_interfaces(20);
    let executor_interfaces = TExecution::prepare_interfaces(20);

    let transport_interface = transport_interfaces.0.clone();
    let execution_interface = executor_interfaces.0.clone();
    let delegation_interface = delegation_interfaces.0.clone();
    let decision_interface = decision_interfaces.0.clone();

    // transport_interface.input_sender().

    let transport_module = TTransport::start(
      transport_interfaces,
      delegation_interfaces.0.clone(),
      transport_options,
    )?;
    let delegation_module = delegation::Module::start(
      agent_data.to_owned(),
      delegation_interfaces,
      transport_interface,
      decision_interface,
    );
    let decision_module = TDecision::start(
      agent_data.to_owned(),
      decision_interfaces,
      execution_interface,
      decision_options,
    );
    let execution_module =
      TExecution::start(agent_data.to_owned(), executor_interfaces, executor_options);
    agent_data.async_runtime.spawn_task(transport_module)?;
    agent_data.async_runtime.spawn_task(delegation_module)?;
    agent_data.async_runtime.spawn_task(decision_module)?;
    agent_data.async_runtime.spawn_task(execution_module)?;
    Ok(Self {
      agent_data,
      delegation_interface,
    })
  }
  /// Return a reference to the states of this agent
  pub fn states_ref(&self) -> &crate::states::SharedStates
  {
    &self.agent_data.states
  }
  /// Return a reference to the capabilities of this agent
  pub fn capabilities_ref(&self) -> &definitions::agent::capabilities::Capabilities
  {
    &self.agent_data.capabilities
  }
  /// Start the delegation of a task by this agent
  pub fn delegate_task(
    &self,
    task: definitions::task::Task,
  ) -> impl std::future::Future<Output = Result<()>>
  {
    log::info!("Start delegation of task {:?}", task.task_id());
    let agent_data = self.agent_data.clone();
    let delegation_input_sender = self.delegation_interface.input_sender();
    let mut delegation_output_recv = self.delegation_interface.output_receiver();
    async move {
      let task_uuid = task.task_id();
      let fut = delegation_input_sender
        .broadcast(delegation::InputMessage::create_start_delegation(
          agent_data.agent_uri.to_owned(),
          task,
          None,
        ))
        .await;
      while let Ok(msg) = delegation_output_recv.recv().await
      {
        match msg
        {
          delegation::OutputMessage::Status { uuid, status } =>
          {
            if uuid == task_uuid
            {
              info!("Delegation {:?} received status {:?}", uuid, status);
            }
          }
        }
      }
      Ok(())
    }
  }
}