1#[cfg(feature = "grpc")]
7mod grpc_convert {
8 use std::collections::HashMap;
9
10 use crate::agent_card::*;
11 use crate::proto::lf_a2a_v1 as pb;
12 use crate::push_notification::{AuthenticationInfo, TaskPushNotificationConfig};
13 use crate::task::{Task, TaskState, TaskStatus};
14 use crate::types::{Artifact, Message, Part, Role};
15
16 pub(crate) fn hashmap_to_struct(m: HashMap<String, serde_json::Value>) -> prost_types::Struct {
21 prost_types::Struct {
22 fields: m
23 .into_iter()
24 .map(|(k, v)| (k, json_to_prost_value(v)))
25 .collect(),
26 }
27 }
28
29 pub(crate) fn struct_to_hashmap(s: prost_types::Struct) -> HashMap<String, serde_json::Value> {
30 s.fields
31 .into_iter()
32 .map(|(k, v)| (k, prost_value_to_json(v)))
33 .collect()
34 }
35
36 fn json_to_prost_value(v: serde_json::Value) -> prost_types::Value {
37 use prost_types::value::Kind;
38 let kind = match v {
39 serde_json::Value::Null => Kind::NullValue(0),
40 serde_json::Value::Bool(b) => Kind::BoolValue(b),
41 serde_json::Value::Number(n) => Kind::NumberValue(n.as_f64().unwrap_or(0.0)),
42 serde_json::Value::String(s) => Kind::StringValue(s),
43 serde_json::Value::Array(arr) => Kind::ListValue(prost_types::ListValue {
44 values: arr.into_iter().map(json_to_prost_value).collect(),
45 }),
46 serde_json::Value::Object(obj) => Kind::StructValue(prost_types::Struct {
47 fields: obj
48 .into_iter()
49 .map(|(k, v)| (k, json_to_prost_value(v)))
50 .collect(),
51 }),
52 };
53 prost_types::Value { kind: Some(kind) }
54 }
55
56 fn prost_value_to_json(v: prost_types::Value) -> serde_json::Value {
57 use prost_types::value::Kind;
58 match v.kind {
59 Some(Kind::NullValue(_)) | None => serde_json::Value::Null,
60 Some(Kind::BoolValue(b)) => serde_json::Value::Bool(b),
61 Some(Kind::NumberValue(n)) => serde_json::Number::from_f64(n)
62 .map(serde_json::Value::Number)
63 .unwrap_or(serde_json::Value::Null),
64 Some(Kind::StringValue(s)) => serde_json::Value::String(s),
65 Some(Kind::ListValue(l)) => {
66 serde_json::Value::Array(l.values.into_iter().map(prost_value_to_json).collect())
67 }
68 Some(Kind::StructValue(s)) => {
69 let map: serde_json::Map<String, serde_json::Value> = s
70 .fields
71 .into_iter()
72 .map(|(k, v)| (k, prost_value_to_json(v)))
73 .collect();
74 serde_json::Value::Object(map)
75 }
76 }
77 }
78
79 fn opt_hashmap_to_struct(
80 m: Option<HashMap<String, serde_json::Value>>,
81 ) -> Option<prost_types::Struct> {
82 m.map(hashmap_to_struct)
83 }
84
85 fn opt_struct_to_hashmap(
86 s: Option<prost_types::Struct>,
87 ) -> Option<HashMap<String, serde_json::Value>> {
88 s.map(struct_to_hashmap)
89 }
90
91 fn opt_empty(s: &str) -> Option<String> {
92 if s.is_empty() {
93 None
94 } else {
95 Some(s.to_string())
96 }
97 }
98
99 impl From<Role> for i32 {
104 fn from(r: Role) -> i32 {
105 match r {
106 Role::User => pb::Role::User as i32,
107 Role::Agent => pb::Role::Agent as i32,
108 Role::Unspecified => pb::Role::Unspecified as i32,
109 }
110 }
111 }
112
113 impl From<i32> for Role {
114 fn from(v: i32) -> Self {
115 match v {
116 1 => Role::User,
117 2 => Role::Agent,
118 _ => Role::Unspecified,
119 }
120 }
121 }
122
123 impl From<TaskState> for i32 {
128 fn from(s: TaskState) -> i32 {
129 match s {
130 TaskState::Unspecified => 0,
131 TaskState::Submitted => 1,
132 TaskState::Working => 2,
133 TaskState::Completed => 3,
134 TaskState::Failed => 4,
135 TaskState::Canceled => 5,
136 TaskState::InputRequired => 6,
137 TaskState::Rejected => 7,
138 TaskState::AuthRequired => 8,
139 }
140 }
141 }
142
143 impl From<i32> for TaskState {
144 fn from(v: i32) -> Self {
145 match v {
146 1 => TaskState::Submitted,
147 2 => TaskState::Working,
148 3 => TaskState::Completed,
149 4 => TaskState::Failed,
150 5 => TaskState::Canceled,
151 6 => TaskState::InputRequired,
152 7 => TaskState::Rejected,
153 8 => TaskState::AuthRequired,
154 _ => TaskState::Unspecified,
155 }
156 }
157 }
158
159 impl From<Part> for pb::Part {
164 fn from(p: Part) -> pb::Part {
165 let content = if let Some(text) = p.text {
167 Some(pb::part::Content::Text(text))
168 } else if let Some(url) = p.url {
169 Some(pb::part::Content::Url(url))
170 } else if let Some(raw) = p.raw {
171 Some(pb::part::Content::Raw(raw.into_bytes()))
172 } else {
173 p.data
174 .map(|data| pb::part::Content::Data(json_to_prost_value(data)))
175 };
176
177 pb::Part {
178 content,
179 metadata: opt_hashmap_to_struct(p.metadata),
180 filename: p.filename.unwrap_or_default(),
181 media_type: p.media_type.unwrap_or_default(),
182 }
183 }
184 }
185
186 impl From<pb::Part> for Part {
187 fn from(p: pb::Part) -> Part {
188 let metadata = opt_struct_to_hashmap(p.metadata);
189 let media_type = opt_empty(&p.media_type);
190 let filename = opt_empty(&p.filename);
191
192 match p.content {
193 Some(pb::part::Content::Text(t)) => Part {
194 text: Some(t),
195 raw: None,
196 url: None,
197 data: None,
198 media_type,
199 filename,
200 metadata,
201 },
202 Some(pb::part::Content::Url(u)) => Part {
203 text: None,
204 raw: None,
205 url: Some(u),
206 data: None,
207 media_type,
208 filename,
209 metadata,
210 },
211 Some(pb::part::Content::Raw(b)) => Part {
212 text: None,
213 raw: Some(String::from_utf8_lossy(&b).to_string()),
214 url: None,
215 data: None,
216 media_type,
217 filename,
218 metadata,
219 },
220 Some(pb::part::Content::Data(v)) => Part {
221 text: None,
222 raw: None,
223 url: None,
224 data: Some(prost_value_to_json(v)),
225 media_type,
226 filename,
227 metadata,
228 },
229 None => Part {
230 text: Some(String::new()),
231 raw: None,
232 url: None,
233 data: None,
234 media_type,
235 filename,
236 metadata,
237 },
238 }
239 }
240 }
241
242 impl From<Message> for pb::Message {
247 fn from(m: Message) -> pb::Message {
248 pb::Message {
249 message_id: m.message_id,
250 context_id: m.context_id.unwrap_or_default(),
251 task_id: m.task_id.unwrap_or_default(),
252 role: i32::from(m.role),
253 parts: m.parts.into_iter().map(Into::into).collect(),
254 metadata: opt_hashmap_to_struct(m.metadata),
255 extensions: m.extensions.unwrap_or_default(),
256 reference_task_ids: m.reference_task_ids.unwrap_or_default(),
257 }
258 }
259 }
260
261 impl From<pb::Message> for Message {
262 fn from(m: pb::Message) -> Message {
263 Message {
264 message_id: m.message_id,
265 role: Role::from(m.role),
266 parts: m.parts.into_iter().map(Into::into).collect(),
267 context_id: opt_empty(&m.context_id),
268 task_id: opt_empty(&m.task_id),
269 reference_task_ids: if m.reference_task_ids.is_empty() {
270 None
271 } else {
272 Some(m.reference_task_ids)
273 },
274 metadata: opt_struct_to_hashmap(m.metadata),
275 extensions: if m.extensions.is_empty() {
276 None
277 } else {
278 Some(m.extensions)
279 },
280 }
281 }
282 }
283
284 impl From<Artifact> for pb::Artifact {
289 fn from(a: Artifact) -> pb::Artifact {
290 pb::Artifact {
291 artifact_id: a.artifact_id,
292 name: a.name.unwrap_or_default(),
293 description: a.description.unwrap_or_default(),
294 parts: a.parts.into_iter().map(Into::into).collect(),
295 metadata: opt_hashmap_to_struct(a.metadata),
296 extensions: a.extensions.unwrap_or_default(),
297 }
298 }
299 }
300
301 impl From<pb::Artifact> for Artifact {
302 fn from(a: pb::Artifact) -> Artifact {
303 Artifact {
304 artifact_id: a.artifact_id,
305 name: opt_empty(&a.name),
306 description: opt_empty(&a.description),
307 parts: a.parts.into_iter().map(Into::into).collect(),
308 metadata: opt_struct_to_hashmap(a.metadata),
309 extensions: if a.extensions.is_empty() {
310 None
311 } else {
312 Some(a.extensions)
313 },
314 }
315 }
316 }
317
318 impl From<TaskStatus> for pb::TaskStatus {
323 fn from(s: TaskStatus) -> pb::TaskStatus {
324 pb::TaskStatus {
325 state: i32::from(s.state),
326 message: s.message.map(Into::into),
327 timestamp: s.timestamp.and_then(|t| {
328 chrono::DateTime::parse_from_rfc3339(&t)
329 .ok()
330 .map(|dt| prost_types::Timestamp {
331 seconds: dt.timestamp(),
332 nanos: dt.timestamp_subsec_nanos() as i32,
333 })
334 }),
335 }
336 }
337 }
338
339 impl From<pb::TaskStatus> for TaskStatus {
340 fn from(s: pb::TaskStatus) -> TaskStatus {
341 TaskStatus {
342 state: TaskState::from(s.state),
343 message: s.message.map(Into::into),
344 timestamp: s.timestamp.and_then(|t| {
345 chrono::DateTime::from_timestamp(t.seconds, t.nanos as u32)
346 .map(|dt| dt.to_rfc3339())
347 }),
348 }
349 }
350 }
351
352 impl From<Task> for pb::Task {
357 fn from(t: Task) -> pb::Task {
358 pb::Task {
359 id: t.id,
360 context_id: t.context_id.unwrap_or_default(),
361 status: Some(t.status.into()),
362 artifacts: t
363 .artifacts
364 .unwrap_or_default()
365 .into_iter()
366 .map(Into::into)
367 .collect(),
368 history: t
369 .history
370 .unwrap_or_default()
371 .into_iter()
372 .map(Into::into)
373 .collect(),
374 metadata: opt_hashmap_to_struct(t.metadata),
375 }
376 }
377 }
378
379 impl From<pb::Task> for Task {
380 fn from(t: pb::Task) -> Task {
381 Task {
382 id: t.id,
383 context_id: opt_empty(&t.context_id),
384 status: t.status.map(Into::into).unwrap_or(TaskStatus {
385 state: TaskState::Unspecified,
386 message: None,
387 timestamp: None,
388 }),
389 artifacts: if t.artifacts.is_empty() {
390 None
391 } else {
392 Some(t.artifacts.into_iter().map(Into::into).collect())
393 },
394 history: if t.history.is_empty() {
395 None
396 } else {
397 Some(t.history.into_iter().map(Into::into).collect())
398 },
399 metadata: opt_struct_to_hashmap(t.metadata),
400 }
401 }
402 }
403
404 impl From<AuthenticationInfo> for pb::AuthenticationInfo {
409 fn from(a: AuthenticationInfo) -> pb::AuthenticationInfo {
410 pb::AuthenticationInfo {
411 scheme: a.scheme,
412 credentials: a.credentials.unwrap_or_default(),
413 }
414 }
415 }
416
417 impl From<pb::AuthenticationInfo> for AuthenticationInfo {
418 fn from(a: pb::AuthenticationInfo) -> AuthenticationInfo {
419 AuthenticationInfo {
420 scheme: a.scheme,
421 credentials: opt_empty(&a.credentials),
422 }
423 }
424 }
425
426 impl From<TaskPushNotificationConfig> for pb::TaskPushNotificationConfig {
431 fn from(c: TaskPushNotificationConfig) -> pb::TaskPushNotificationConfig {
432 pb::TaskPushNotificationConfig {
433 tenant: c.tenant.unwrap_or_default(),
434 id: c.config_id.unwrap_or_default(),
435 task_id: c.task_id,
436 url: c.url,
437 token: c.token.unwrap_or_default(),
438 authentication: c.authentication.map(Into::into),
439 }
440 }
441 }
442
443 impl From<pb::TaskPushNotificationConfig> for TaskPushNotificationConfig {
444 fn from(c: pb::TaskPushNotificationConfig) -> TaskPushNotificationConfig {
445 TaskPushNotificationConfig {
446 tenant: opt_empty(&c.tenant),
447 config_id: opt_empty(&c.id),
448 task_id: c.task_id,
449 url: c.url,
450 token: opt_empty(&c.token),
451 authentication: c.authentication.map(Into::into),
452 created_at: None,
453 }
454 }
455 }
456
457 impl From<AgentProvider> for pb::AgentProvider {
462 fn from(p: AgentProvider) -> pb::AgentProvider {
463 pb::AgentProvider {
464 url: p.url,
465 organization: p.organization,
466 }
467 }
468 }
469
470 impl From<pb::AgentProvider> for AgentProvider {
471 fn from(p: pb::AgentProvider) -> AgentProvider {
472 AgentProvider {
473 url: p.url,
474 organization: p.organization,
475 }
476 }
477 }
478
479 impl From<AgentExtension> for pb::AgentExtension {
484 fn from(e: AgentExtension) -> pb::AgentExtension {
485 pb::AgentExtension {
486 uri: e.uri,
487 description: e.description.unwrap_or_default(),
488 required: e.required,
489 params: e.params.map(hashmap_to_struct),
490 }
491 }
492 }
493
494 impl From<pb::AgentExtension> for AgentExtension {
495 fn from(e: pb::AgentExtension) -> AgentExtension {
496 AgentExtension {
497 uri: e.uri,
498 description: opt_empty(&e.description),
499 required: e.required,
500 params: e.params.map(struct_to_hashmap),
501 }
502 }
503 }
504
505 impl From<AgentCapabilities> for pb::AgentCapabilities {
510 fn from(c: AgentCapabilities) -> pb::AgentCapabilities {
511 pb::AgentCapabilities {
512 streaming: c.streaming,
513 push_notifications: c.push_notifications,
514 extended_agent_card: c.extended_agent_card,
515 extensions: c
516 .extensions
517 .unwrap_or_default()
518 .into_iter()
519 .map(Into::into)
520 .collect(),
521 }
522 }
523 }
524
525 impl From<pb::AgentCapabilities> for AgentCapabilities {
526 fn from(c: pb::AgentCapabilities) -> AgentCapabilities {
527 AgentCapabilities {
528 streaming: c.streaming,
529 push_notifications: c.push_notifications,
530 extended_agent_card: c.extended_agent_card,
531 extensions: if c.extensions.is_empty() {
532 None
533 } else {
534 Some(c.extensions.into_iter().map(Into::into).collect())
535 },
536 }
537 }
538 }
539
540 impl From<AgentSkill> for pb::AgentSkill {
545 fn from(s: AgentSkill) -> pb::AgentSkill {
546 pb::AgentSkill {
547 id: s.id,
548 name: s.name,
549 description: s.description,
550 tags: s.tags,
551 examples: s.examples.unwrap_or_default(),
552 input_modes: s.input_modes.unwrap_or_default(),
553 output_modes: s.output_modes.unwrap_or_default(),
554 security_requirements: s
555 .security_requirements
556 .unwrap_or_default()
557 .into_iter()
558 .map(Into::into)
559 .collect(),
560 }
561 }
562 }
563
564 impl From<pb::AgentSkill> for AgentSkill {
565 fn from(s: pb::AgentSkill) -> AgentSkill {
566 AgentSkill {
567 id: s.id,
568 name: s.name,
569 description: s.description,
570 tags: s.tags,
571 examples: if s.examples.is_empty() {
572 None
573 } else {
574 Some(s.examples)
575 },
576 input_modes: if s.input_modes.is_empty() {
577 None
578 } else {
579 Some(s.input_modes)
580 },
581 output_modes: if s.output_modes.is_empty() {
582 None
583 } else {
584 Some(s.output_modes)
585 },
586 security_requirements: if s.security_requirements.is_empty() {
587 None
588 } else {
589 Some(
590 s.security_requirements
591 .into_iter()
592 .map(Into::into)
593 .collect(),
594 )
595 },
596 }
597 }
598 }
599
600 impl From<AgentInterface> for pb::AgentInterface {
605 fn from(i: AgentInterface) -> pb::AgentInterface {
606 pb::AgentInterface {
607 url: i.url,
608 protocol_binding: i.protocol_binding,
609 tenant: i.tenant.unwrap_or_default(),
610 protocol_version: i.protocol_version,
611 }
612 }
613 }
614
615 impl From<pb::AgentInterface> for AgentInterface {
616 fn from(i: pb::AgentInterface) -> AgentInterface {
617 AgentInterface {
618 url: i.url,
619 protocol_binding: i.protocol_binding,
620 tenant: opt_empty(&i.tenant),
621 protocol_version: i.protocol_version,
622 }
623 }
624 }
625
626 impl From<AgentCardSignature> for pb::AgentCardSignature {
631 fn from(s: AgentCardSignature) -> pb::AgentCardSignature {
632 pb::AgentCardSignature {
633 protected: s.protected,
634 signature: s.signature,
635 header: s.header.map(hashmap_to_struct),
636 }
637 }
638 }
639
640 impl From<pb::AgentCardSignature> for AgentCardSignature {
641 fn from(s: pb::AgentCardSignature) -> AgentCardSignature {
642 AgentCardSignature {
643 protected: s.protected,
644 signature: s.signature,
645 header: s.header.map(struct_to_hashmap),
646 }
647 }
648 }
649
650 impl From<SecurityRequirement> for pb::SecurityRequirement {
655 fn from(r: SecurityRequirement) -> pb::SecurityRequirement {
656 pb::SecurityRequirement {
657 schemes: r
658 .schemes
659 .into_iter()
660 .map(|(k, v)| (k, pb::StringList { list: v }))
661 .collect(),
662 }
663 }
664 }
665
666 impl From<pb::SecurityRequirement> for SecurityRequirement {
667 fn from(r: pb::SecurityRequirement) -> SecurityRequirement {
668 SecurityRequirement {
669 schemes: r.schemes.into_iter().map(|(k, v)| (k, v.list)).collect(),
670 }
671 }
672 }
673
674 impl From<SecurityScheme> for pb::SecurityScheme {
679 fn from(s: SecurityScheme) -> pb::SecurityScheme {
680 let scheme = if let Some(api_key) = s.api_key {
681 Some(pb::security_scheme::Scheme::ApiKeySecurityScheme(
682 pb::ApiKeySecurityScheme {
683 description: api_key.description.unwrap_or_default(),
684 location: api_key.location,
685 name: api_key.name,
686 },
687 ))
688 } else if let Some(http_auth) = s.http_auth {
689 Some(pb::security_scheme::Scheme::HttpAuthSecurityScheme(
690 pb::HttpAuthSecurityScheme {
691 description: http_auth.description.unwrap_or_default(),
692 scheme: http_auth.scheme,
693 bearer_format: http_auth.bearer_format.unwrap_or_default(),
694 },
695 ))
696 } else if let Some(oauth2) = s.oauth2 {
697 Some(pb::security_scheme::Scheme::Oauth2SecurityScheme(
698 pb::OAuth2SecurityScheme {
699 description: oauth2.description.unwrap_or_default(),
700 flows: Some(oauth2.flows.into()),
701 oauth2_metadata_url: oauth2.oauth2_metadata_url.unwrap_or_default(),
702 },
703 ))
704 } else if let Some(oidc) = s.open_id_connect {
705 Some(pb::security_scheme::Scheme::OpenIdConnectSecurityScheme(
706 pb::OpenIdConnectSecurityScheme {
707 description: oidc.description.unwrap_or_default(),
708 open_id_connect_url: oidc.open_id_connect_url,
709 },
710 ))
711 } else if let Some(mtls) = s.mtls {
712 Some(pb::security_scheme::Scheme::MtlsSecurityScheme(
713 pb::MutualTlsSecurityScheme {
714 description: mtls.description.unwrap_or_default(),
715 },
716 ))
717 } else {
718 None
719 };
720 pb::SecurityScheme { scheme }
721 }
722 }
723
724 impl From<pb::SecurityScheme> for SecurityScheme {
725 fn from(s: pb::SecurityScheme) -> SecurityScheme {
726 match s.scheme {
727 Some(pb::security_scheme::Scheme::ApiKeySecurityScheme(a)) => SecurityScheme {
728 api_key: Some(ApiKeySecurityScheme {
729 name: a.name,
730 location: a.location,
731 description: opt_empty(&a.description),
732 }),
733 http_auth: None,
734 oauth2: None,
735 open_id_connect: None,
736 mtls: None,
737 },
738 Some(pb::security_scheme::Scheme::HttpAuthSecurityScheme(h)) => SecurityScheme {
739 api_key: None,
740 http_auth: Some(HttpAuthSecurityScheme {
741 scheme: h.scheme,
742 bearer_format: opt_empty(&h.bearer_format),
743 description: opt_empty(&h.description),
744 }),
745 oauth2: None,
746 open_id_connect: None,
747 mtls: None,
748 },
749 Some(pb::security_scheme::Scheme::Oauth2SecurityScheme(o)) => SecurityScheme {
750 api_key: None,
751 http_auth: None,
752 oauth2: Some(OAuth2SecurityScheme {
753 flows: o.flows.map(Into::into).unwrap_or(OAuthFlows {
754 authorization_code: None,
755 client_credentials: Some(ClientCredentialsOAuthFlow {
756 token_url: String::new(),
757 refresh_url: None,
758 scopes: HashMap::new(),
759 }),
760 implicit: None,
761 password: None,
762 device_code: None,
763 }),
764 description: opt_empty(&o.description),
765 oauth2_metadata_url: opt_empty(&o.oauth2_metadata_url),
766 }),
767 open_id_connect: None,
768 mtls: None,
769 },
770 Some(pb::security_scheme::Scheme::OpenIdConnectSecurityScheme(o)) => {
771 SecurityScheme {
772 api_key: None,
773 http_auth: None,
774 oauth2: None,
775 open_id_connect: Some(OpenIdConnectSecurityScheme {
776 open_id_connect_url: o.open_id_connect_url,
777 description: opt_empty(&o.description),
778 }),
779 mtls: None,
780 }
781 }
782 Some(pb::security_scheme::Scheme::MtlsSecurityScheme(m)) => SecurityScheme {
783 api_key: None,
784 http_auth: None,
785 oauth2: None,
786 open_id_connect: None,
787 mtls: Some(MutualTlsSecurityScheme {
788 description: opt_empty(&m.description),
789 }),
790 },
791 None => SecurityScheme {
792 api_key: None,
793 http_auth: None,
794 oauth2: None,
795 open_id_connect: None,
796 mtls: None,
797 },
798 }
799 }
800 }
801
802 impl From<OAuthFlows> for pb::OAuthFlows {
807 fn from(f: OAuthFlows) -> pb::OAuthFlows {
808 let flow = if let Some(ac) = f.authorization_code {
809 Some(pb::o_auth_flows::Flow::AuthorizationCode(
810 pb::AuthorizationCodeOAuthFlow {
811 authorization_url: ac.authorization_url,
812 token_url: ac.token_url,
813 refresh_url: ac.refresh_url.unwrap_or_default(),
814 scopes: ac.scopes,
815 pkce_required: ac.pkce_required.unwrap_or(false),
816 },
817 ))
818 } else if let Some(cc) = f.client_credentials {
819 Some(pb::o_auth_flows::Flow::ClientCredentials(
820 pb::ClientCredentialsOAuthFlow {
821 token_url: cc.token_url,
822 refresh_url: cc.refresh_url.unwrap_or_default(),
823 scopes: cc.scopes,
824 },
825 ))
826 } else if let Some(imp) = f.implicit {
827 Some(pb::o_auth_flows::Flow::Implicit(pb::ImplicitOAuthFlow {
828 authorization_url: imp.authorization_url.unwrap_or_default(),
829 refresh_url: imp.refresh_url.unwrap_or_default(),
830 scopes: imp.scopes,
831 }))
832 } else if let Some(pw) = f.password {
833 Some(pb::o_auth_flows::Flow::Password(pb::PasswordOAuthFlow {
834 token_url: pw.token_url.unwrap_or_default(),
835 refresh_url: pw.refresh_url.unwrap_or_default(),
836 scopes: pw.scopes,
837 }))
838 } else if let Some(dc) = f.device_code {
839 Some(pb::o_auth_flows::Flow::DeviceCode(
840 pb::DeviceCodeOAuthFlow {
841 device_authorization_url: dc.device_authorization_url,
842 token_url: dc.token_url,
843 refresh_url: dc.refresh_url.unwrap_or_default(),
844 scopes: dc.scopes,
845 },
846 ))
847 } else {
848 None
849 };
850 pb::OAuthFlows { flow }
851 }
852 }
853
854 impl From<pb::OAuthFlows> for OAuthFlows {
855 fn from(f: pb::OAuthFlows) -> OAuthFlows {
856 match f.flow {
857 Some(pb::o_auth_flows::Flow::AuthorizationCode(a)) => OAuthFlows {
858 authorization_code: Some(AuthorizationCodeOAuthFlow {
859 authorization_url: a.authorization_url,
860 token_url: a.token_url,
861 refresh_url: opt_empty(&a.refresh_url),
862 scopes: a.scopes,
863 pkce_required: Some(a.pkce_required),
864 }),
865 client_credentials: None,
866 implicit: None,
867 password: None,
868 device_code: None,
869 },
870 Some(pb::o_auth_flows::Flow::ClientCredentials(c)) => OAuthFlows {
871 authorization_code: None,
872 client_credentials: Some(ClientCredentialsOAuthFlow {
873 token_url: c.token_url,
874 refresh_url: opt_empty(&c.refresh_url),
875 scopes: c.scopes,
876 }),
877 implicit: None,
878 password: None,
879 device_code: None,
880 },
881 #[allow(deprecated)]
882 Some(pb::o_auth_flows::Flow::Implicit(i)) => OAuthFlows {
883 authorization_code: None,
884 client_credentials: None,
885 implicit: Some(ImplicitOAuthFlow {
886 authorization_url: opt_empty(&i.authorization_url),
887 refresh_url: opt_empty(&i.refresh_url),
888 scopes: i.scopes,
889 }),
890 password: None,
891 device_code: None,
892 },
893 #[allow(deprecated)]
894 Some(pb::o_auth_flows::Flow::Password(p)) => OAuthFlows {
895 authorization_code: None,
896 client_credentials: None,
897 implicit: None,
898 password: Some(PasswordOAuthFlow {
899 token_url: opt_empty(&p.token_url),
900 refresh_url: opt_empty(&p.refresh_url),
901 scopes: p.scopes,
902 }),
903 device_code: None,
904 },
905 Some(pb::o_auth_flows::Flow::DeviceCode(d)) => OAuthFlows {
906 authorization_code: None,
907 client_credentials: None,
908 implicit: None,
909 password: None,
910 device_code: Some(DeviceCodeOAuthFlow {
911 device_authorization_url: d.device_authorization_url,
912 token_url: d.token_url,
913 refresh_url: opt_empty(&d.refresh_url),
914 scopes: d.scopes,
915 }),
916 },
917 None => OAuthFlows {
918 authorization_code: None,
919 client_credentials: None,
920 implicit: None,
921 password: None,
922 device_code: None,
923 },
924 }
925 }
926 }
927
928 impl From<AgentCard> for pb::AgentCard {
933 fn from(c: AgentCard) -> pb::AgentCard {
934 pb::AgentCard {
935 name: c.name,
936 description: c.description,
937 version: c.version,
938 supported_interfaces: c.supported_interfaces.into_iter().map(Into::into).collect(),
939 provider: c.provider.map(Into::into),
940 capabilities: Some(c.capabilities.into()),
941 security_schemes: c
942 .security_schemes
943 .unwrap_or_default()
944 .into_iter()
945 .map(|(k, v)| (k, v.into()))
946 .collect(),
947 security_requirements: c
948 .security_requirements
949 .unwrap_or_default()
950 .into_iter()
951 .map(Into::into)
952 .collect(),
953 default_input_modes: c.default_input_modes,
954 default_output_modes: c.default_output_modes,
955 skills: c.skills.into_iter().map(Into::into).collect(),
956 signatures: c
957 .signatures
958 .unwrap_or_default()
959 .into_iter()
960 .map(Into::into)
961 .collect(),
962 documentation_url: c.documentation_url,
963 icon_url: c.icon_url,
964 }
965 }
966 }
967
968 impl From<pb::AgentCard> for AgentCard {
969 fn from(c: pb::AgentCard) -> AgentCard {
970 AgentCard {
971 name: c.name,
972 description: c.description,
973 version: c.version,
974 supported_interfaces: c.supported_interfaces.into_iter().map(Into::into).collect(),
975 provider: c.provider.map(Into::into),
976 capabilities: c.capabilities.map(Into::into).unwrap_or_default(),
977 security_schemes: {
978 let m: HashMap<String, SecurityScheme> = c
979 .security_schemes
980 .into_iter()
981 .map(|(k, v)| (k, v.into()))
982 .collect();
983 if m.is_empty() { None } else { Some(m) }
984 },
985 security_requirements: if c.security_requirements.is_empty() {
986 None
987 } else {
988 Some(
989 c.security_requirements
990 .into_iter()
991 .map(Into::into)
992 .collect(),
993 )
994 },
995 default_input_modes: c.default_input_modes,
996 default_output_modes: c.default_output_modes,
997 skills: c.skills.into_iter().map(Into::into).collect(),
998 signatures: if c.signatures.is_empty() {
999 None
1000 } else {
1001 Some(c.signatures.into_iter().map(Into::into).collect())
1002 },
1003 documentation_url: c.documentation_url,
1004 icon_url: c.icon_url,
1005 }
1006 }
1007 }
1008}