1use std::collections::HashMap;
2
3use chrono::{DateTime, Utc};
4use rmcp::model::Content;
5use serde::{Deserialize, Serialize};
6use serde_json::Value;
7use stakpak_shared::models::{
8 integrations::openai::{
9 AgentModel, ChatMessage, FunctionCall, MessageContent, Role, Tool, ToolCall,
10 },
11 llm::{LLMInput, LLMMessage, LLMMessageContent, LLMMessageTypedContent, LLMTokenUsage},
12};
13use uuid::Uuid;
14
15#[derive(Debug, Clone, Deserialize, Serialize)]
16pub enum ApiStreamError {
17 AgentInputInvalid(String),
18 AgentStateInvalid,
19 AgentNotSupported,
20 AgentExecutionLimitExceeded,
21 AgentInvalidResponseStream,
22 InvalidGeneratedCode,
23 CopilotError,
24 SaveError,
25 Unknown(String),
26}
27
28impl From<&str> for ApiStreamError {
29 fn from(error_str: &str) -> Self {
30 match error_str {
31 s if s.contains("Agent not supported") => ApiStreamError::AgentNotSupported,
32 s if s.contains("Agent state is not valid") => ApiStreamError::AgentStateInvalid,
33 s if s.contains("Agent thinking limit exceeded") => {
34 ApiStreamError::AgentExecutionLimitExceeded
35 }
36 s if s.contains("Invalid response stream") => {
37 ApiStreamError::AgentInvalidResponseStream
38 }
39 s if s.contains("Invalid generated code") => ApiStreamError::InvalidGeneratedCode,
40 s if s.contains(
41 "Our copilot is handling too many requests at this time, please try again later.",
42 ) =>
43 {
44 ApiStreamError::CopilotError
45 }
46 s if s
47 .contains("An error occurred while saving your data. Please try again later.") =>
48 {
49 ApiStreamError::SaveError
50 }
51 s if s.contains("Agent input is not valid: ") => {
52 ApiStreamError::AgentInputInvalid(s.replace("Agent input is not valid: ", ""))
53 }
54 _ => ApiStreamError::Unknown(error_str.to_string()),
55 }
56 }
57}
58
59impl From<String> for ApiStreamError {
60 fn from(error_str: String) -> Self {
61 ApiStreamError::from(error_str.as_str())
62 }
63}
64
65#[derive(Debug, Deserialize, Serialize, Clone)]
66pub struct AgentSession {
67 pub id: Uuid,
68 pub title: String,
69 pub agent_id: AgentID,
70 pub visibility: AgentSessionVisibility,
71 pub checkpoints: Vec<AgentCheckpointListItem>,
72 pub created_at: DateTime<Utc>,
73 pub updated_at: DateTime<Utc>,
74}
75
76#[derive(Debug, Deserialize, Serialize, Default, Clone, PartialEq)]
77pub enum AgentID {
78 #[default]
79 #[serde(rename = "pablo:v1")]
80 PabloV1,
81}
82
83impl std::str::FromStr for AgentID {
84 type Err = String;
85
86 fn from_str(s: &str) -> Result<Self, Self::Err> {
87 match s {
88 "pablo:v1" => Ok(AgentID::PabloV1),
89 _ => Err(format!("Invalid agent ID: {}", s)),
90 }
91 }
92}
93
94#[derive(Debug, Deserialize, Serialize, Clone)]
95pub enum AgentSessionVisibility {
96 #[serde(rename = "PRIVATE")]
97 Private,
98 #[serde(rename = "PUBLIC")]
99 Public,
100}
101
102impl std::fmt::Display for AgentSessionVisibility {
103 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
104 match self {
105 AgentSessionVisibility::Private => write!(f, "PRIVATE"),
106 AgentSessionVisibility::Public => write!(f, "PUBLIC"),
107 }
108 }
109}
110
111#[derive(Debug, Deserialize, Serialize, Clone)]
112pub struct AgentCheckpointListItem {
113 pub id: Uuid,
114 pub status: AgentStatus,
115 pub execution_depth: usize,
116 pub parent: Option<AgentParentCheckpoint>,
117 pub created_at: DateTime<Utc>,
118 pub updated_at: DateTime<Utc>,
119}
120
121#[derive(Debug, Deserialize, Serialize, Clone)]
122pub struct AgentSessionListItem {
123 pub id: Uuid,
124 pub agent_id: AgentID,
125 pub visibility: AgentSessionVisibility,
126 pub created_at: DateTime<Utc>,
127 pub updated_at: DateTime<Utc>,
128}
129
130impl From<AgentSession> for AgentSessionListItem {
131 fn from(item: AgentSession) -> Self {
132 Self {
133 id: item.id,
134 agent_id: item.agent_id,
135 visibility: item.visibility,
136 created_at: item.created_at,
137 updated_at: item.updated_at,
138 }
139 }
140}
141
142#[derive(Debug, Deserialize, Serialize, Clone)]
143pub struct AgentParentCheckpoint {
144 pub id: Uuid,
145}
146#[derive(Debug, Deserialize, Serialize, Clone, PartialEq)]
147pub enum AgentStatus {
148 #[serde(rename = "RUNNING")]
149 Running,
150 #[serde(rename = "COMPLETE")]
151 Complete,
152 #[serde(rename = "BLOCKED")]
153 Blocked,
154 #[serde(rename = "FAILED")]
155 Failed,
156}
157impl std::fmt::Display for AgentStatus {
158 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
159 match self {
160 AgentStatus::Running => write!(f, "RUNNING"),
161 AgentStatus::Complete => write!(f, "COMPLETE"),
162 AgentStatus::Blocked => write!(f, "BLOCKED"),
163 AgentStatus::Failed => write!(f, "FAILED"),
164 }
165 }
166}
167
168#[derive(Debug, Deserialize, Serialize, Clone)]
169pub struct RunAgentInput {
170 pub checkpoint_id: Uuid,
171 pub input: AgentInput,
172}
173
174impl PartialEq for RunAgentInput {
175 fn eq(&self, other: &Self) -> bool {
176 self.input == other.input
177 }
178}
179
180#[derive(Debug, Deserialize, Serialize, Clone)]
181pub struct RunAgentOutput {
182 pub checkpoint: AgentCheckpointListItem,
183 pub session: AgentSessionListItem,
184 pub output: AgentOutput,
185}
186
187#[derive(Debug, Deserialize, Serialize, Clone, PartialEq)]
188#[serde(tag = "agent_id")]
189pub enum AgentInput {
190 #[serde(rename = "pablo:v1")]
191 PabloV1 {
192 messages: Option<Vec<ChatMessage>>,
193 node_states: Option<serde_json::Value>,
194 },
195}
196
197impl AgentInput {
198 pub fn new(agent_id: &AgentID) -> Self {
199 match agent_id {
200 AgentID::PabloV1 => AgentInput::PabloV1 {
201 messages: None,
202 node_states: None,
203 },
204 }
205 }
206 pub fn set_user_prompt(&mut self, prompt: Option<String>) {
207 match self {
208 AgentInput::PabloV1 { messages, .. } => {
209 if let Some(prompt) = prompt {
210 *messages = Some(vec![ChatMessage {
211 role: Role::User,
212 content: Some(MessageContent::String(prompt)),
213 name: None,
214 tool_calls: None,
215 tool_call_id: None,
216 usage: None,
217 ..Default::default()
218 }]);
219 }
220 }
221 }
222 }
223 pub fn get_agent_id(&self) -> AgentID {
224 match self {
225 AgentInput::PabloV1 { .. } => AgentID::PabloV1,
226 }
227 }
228}
229#[derive(Debug, Deserialize, Serialize, Clone)]
230#[serde(tag = "agent_id")]
231pub enum AgentOutput {
232 #[serde(rename = "pablo:v1")]
233 PabloV1 {
234 messages: Vec<ChatMessage>,
235 node_states: serde_json::Value,
236 },
237}
238
239impl AgentOutput {
240 pub fn get_agent_id(&self) -> AgentID {
241 match self {
242 AgentOutput::PabloV1 { .. } => AgentID::PabloV1,
243 }
244 }
245 pub fn get_messages(&self) -> Vec<ChatMessage> {
246 match self {
247 AgentOutput::PabloV1 { messages, .. } => messages.clone(),
248 }
249 }
250 pub fn set_messages(&mut self, new_messages: Vec<ChatMessage>) {
251 match self {
252 AgentOutput::PabloV1 { messages, .. } => *messages = new_messages,
253 }
254 }
255}
256
257#[derive(Deserialize, Serialize, Debug)]
258pub struct Document {
259 pub content: String,
260 pub uri: String,
261 pub provisioner: ProvisionerType,
262}
263
264#[derive(Deserialize, Serialize, Debug)]
265pub struct SimpleDocument {
266 pub uri: String,
267 pub content: String,
268}
269
270#[derive(Deserialize, Serialize, Debug, Clone)]
271pub struct Block {
272 pub id: Uuid,
273 pub provider: String,
274 pub provisioner: ProvisionerType,
275 pub language: String,
276 pub key: String,
277 pub digest: u64,
278 pub references: Vec<Vec<Segment>>,
279 pub kind: String,
280 pub r#type: Option<String>,
281 pub name: Option<String>,
282 pub config: serde_json::Value,
283 pub document_uri: String,
284 pub code: String,
285 pub start_byte: usize,
286 pub end_byte: usize,
287 pub start_point: Point,
288 pub end_point: Point,
289 pub state: Option<serde_json::Value>,
290 pub updated_at: Option<DateTime<Utc>>,
291 pub created_at: Option<DateTime<Utc>>,
292 pub dependents: Vec<DependentBlock>,
293 pub dependencies: Vec<Dependency>,
294 pub api_group_version: Option<ApiGroupVersion>,
295
296 pub generated_summary: Option<String>,
297}
298
299impl Block {
300 pub fn get_uri(&self) -> String {
301 format!(
302 "{}#L{}-L{}",
303 self.document_uri, self.start_point.row, self.end_point.row
304 )
305 }
306}
307
308#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Hash, Clone)]
309pub enum ProvisionerType {
310 #[serde(rename = "Terraform")]
311 Terraform,
312 #[serde(rename = "Kubernetes")]
313 Kubernetes,
314 #[serde(rename = "Dockerfile")]
315 Dockerfile,
316 #[serde(rename = "GithubActions")]
317 GithubActions,
318 #[serde(rename = "None")]
319 None,
320}
321impl std::str::FromStr for ProvisionerType {
322 type Err = String;
323
324 fn from_str(s: &str) -> Result<Self, Self::Err> {
325 match s.to_lowercase().as_str() {
326 "terraform" => Ok(Self::Terraform),
327 "kubernetes" => Ok(Self::Kubernetes),
328 "dockerfile" => Ok(Self::Dockerfile),
329 "github-actions" => Ok(Self::GithubActions),
330 _ => Ok(Self::None),
331 }
332 }
333}
334impl std::fmt::Display for ProvisionerType {
335 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
336 match self {
337 ProvisionerType::Terraform => write!(f, "terraform"),
338 ProvisionerType::Kubernetes => write!(f, "kubernetes"),
339 ProvisionerType::Dockerfile => write!(f, "dockerfile"),
340 ProvisionerType::GithubActions => write!(f, "github-actions"),
341 ProvisionerType::None => write!(f, "none"),
342 }
343 }
344}
345
346#[derive(Serialize, Deserialize, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
347#[serde(untagged)]
348pub enum Segment {
349 Key(String),
350 Index(usize),
351}
352
353impl std::fmt::Display for Segment {
354 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
355 match self {
356 Segment::Key(key) => write!(f, "{}", key),
357 Segment::Index(index) => write!(f, "{}", index),
358 }
359 }
360}
361impl std::fmt::Debug for Segment {
362 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
363 match self {
364 Segment::Key(key) => write!(f, "{}", key),
365 Segment::Index(index) => write!(f, "{}", index),
366 }
367 }
368}
369
370#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq)]
371pub struct Point {
372 pub row: usize,
373 pub column: usize,
374}
375
376#[derive(Deserialize, Serialize, Debug, Clone)]
377pub struct DependentBlock {
378 pub key: String,
379}
380
381#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
382pub struct Dependency {
383 pub id: Option<Uuid>,
384 pub expression: Option<String>,
385 pub from_path: Option<Vec<Segment>>,
386 pub to_path: Option<Vec<Segment>>,
387 #[serde(default = "Vec::new")]
388 pub selectors: Vec<DependencySelector>,
389 #[serde(skip_serializing)]
390 pub key: Option<String>,
391 pub digest: Option<u64>,
392 #[serde(default = "Vec::new")]
393 pub from: Vec<Segment>,
394 pub from_field: Option<Vec<Segment>>,
395 pub to_field: Option<Vec<Segment>>,
396 pub start_byte: Option<usize>,
397 pub end_byte: Option<usize>,
398 pub start_point: Option<Point>,
399 pub end_point: Option<Point>,
400 pub satisfied: bool,
401}
402
403#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
404pub struct DependencySelector {
405 pub references: Vec<Vec<Segment>>,
406 pub operator: DependencySelectorOperator,
407}
408
409#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
410pub enum DependencySelectorOperator {
411 Equals,
412 NotEquals,
413 In,
414 NotIn,
415 Exists,
416 DoesNotExist,
417}
418
419#[derive(Serialize, Deserialize, Debug, Clone)]
420pub struct ApiGroupVersion {
421 pub alias: String,
422 pub group: String,
423 pub version: String,
424 pub provisioner: ProvisionerType,
425 pub status: APIGroupVersionStatus,
426}
427
428#[derive(Serialize, Deserialize, Debug, Clone)]
429pub enum APIGroupVersionStatus {
430 #[serde(rename = "UNAVAILABLE")]
431 Unavailable,
432 #[serde(rename = "PENDING")]
433 Pending,
434 #[serde(rename = "AVAILABLE")]
435 Available,
436}
437
438#[derive(Serialize, Deserialize, Debug)]
439pub struct BuildCodeIndexInput {
440 pub documents: Vec<SimpleDocument>,
441}
442
443#[derive(Serialize, Deserialize, Debug, Clone)]
444pub struct IndexError {
445 pub uri: String,
446 pub message: String,
447 pub details: Option<serde_json::Value>,
448}
449
450#[derive(Serialize, Deserialize, Debug, Clone)]
451pub struct BuildCodeIndexOutput {
452 pub blocks: Vec<Block>,
453 pub errors: Vec<IndexError>,
454 pub warnings: Vec<IndexError>,
455}
456
457#[derive(Serialize, Deserialize, Debug, Clone)]
458pub struct CodeIndex {
459 pub last_updated: DateTime<Utc>,
460 pub index: BuildCodeIndexOutput,
461}
462
463#[derive(Debug, Deserialize, Serialize, Clone, Default)]
464pub struct AgentSessionStats {
465 pub aborted_tool_calls: u32,
466 pub analysis_period: Option<String>,
467 pub failed_tool_calls: u32,
468 pub from_date: Option<String>,
469 pub sessions_with_activity: u32,
470 pub successful_tool_calls: u32,
471 pub to_date: Option<String>,
472 pub tools_usage: Vec<ToolUsageStats>,
473 pub total_sessions: u32,
474 pub total_time_saved_seconds: Option<u32>,
475 pub total_tool_calls: u32,
476}
477
478#[derive(Debug, Deserialize, Serialize, Clone)]
479pub struct ToolUsageStats {
480 pub display_name: String,
481 pub time_saved_per_call: Option<f64>,
482 pub time_saved_seconds: Option<u32>,
483 pub tool_name: String,
484 pub usage_counts: ToolUsageCounts,
485}
486
487#[derive(Debug, Deserialize, Serialize, Clone)]
488pub struct ToolUsageCounts {
489 pub aborted: u32,
490 pub failed: u32,
491 pub successful: u32,
492 pub total: u32,
493}
494
495#[derive(Serialize, Deserialize, Debug, Clone, Copy, Default)]
496#[serde(rename_all = "UPPERCASE")]
497pub enum RuleBookVisibility {
498 #[default]
499 Public,
500 Private,
501}
502
503#[derive(Serialize, Deserialize, Debug, Clone)]
504pub struct RuleBook {
505 pub id: String,
506 pub uri: String,
507 pub description: String,
508 pub content: String,
509 pub visibility: RuleBookVisibility,
510 pub tags: Vec<String>,
511 pub created_at: Option<DateTime<Utc>>,
512 pub updated_at: Option<DateTime<Utc>>,
513}
514
515#[derive(Serialize, Deserialize, Debug)]
516pub struct ToolsCallParams {
517 pub name: String,
518 pub arguments: Value,
519}
520
521#[derive(Serialize, Deserialize, Debug)]
522pub struct ToolsCallResponse {
523 pub content: Vec<Content>,
524}
525
526#[derive(Serialize, Deserialize, Debug, Clone)]
527pub struct APIKeyScope {
528 pub r#type: String,
529 pub name: String,
530}
531
532impl std::fmt::Display for APIKeyScope {
533 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
534 write!(f, "{} ({})", self.name, self.r#type)
535 }
536}
537
538#[derive(Serialize, Deserialize, Clone, Debug)]
539pub struct GetMyAccountResponse {
540 pub username: String,
541 pub id: String,
542 pub first_name: String,
543 pub last_name: String,
544 pub email: String,
545 pub scope: Option<APIKeyScope>,
546}
547
548impl GetMyAccountResponse {
549 pub fn to_text(&self) -> String {
550 format!(
551 "ID: {}\nUsername: {}\nName: {} {}\nEmail: {}",
552 self.id, self.username, self.first_name, self.last_name, self.email
553 )
554 }
555}
556
557#[derive(Serialize, Deserialize, Debug, Clone)]
558pub struct ListRuleBook {
559 pub id: String,
560 pub uri: String,
561 pub description: String,
562 pub visibility: RuleBookVisibility,
563 pub tags: Vec<String>,
564 pub created_at: Option<DateTime<Utc>>,
565 pub updated_at: Option<DateTime<Utc>>,
566}
567
568#[derive(Serialize, Deserialize, Debug)]
569pub struct ListRulebooksResponse {
570 pub results: Vec<ListRuleBook>,
571}
572
573#[derive(Serialize, Deserialize, Debug)]
574pub struct CreateRuleBookInput {
575 pub uri: String,
576 pub description: String,
577 pub content: String,
578 pub tags: Vec<String>,
579 #[serde(skip_serializing_if = "Option::is_none")]
580 pub visibility: Option<RuleBookVisibility>,
581}
582
583#[derive(Serialize, Deserialize, Debug)]
584pub struct CreateRuleBookResponse {
585 pub id: String,
586}
587
588impl ListRuleBook {
589 pub fn to_text(&self) -> String {
590 format!(
591 "URI: {}\nDescription: {}\nTags: {}\n",
592 self.uri,
593 self.description,
594 self.tags.join(", ")
595 )
596 }
597}
598
599#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
600pub struct SimpleLLMMessage {
601 #[serde(rename = "role")]
602 pub role: SimpleLLMRole,
603 pub content: String,
604}
605
606#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
607#[serde(rename_all = "lowercase")]
608pub enum SimpleLLMRole {
609 User,
610 Assistant,
611}
612
613impl std::fmt::Display for SimpleLLMRole {
614 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
615 match self {
616 SimpleLLMRole::User => write!(f, "user"),
617 SimpleLLMRole::Assistant => write!(f, "assistant"),
618 }
619 }
620}
621
622#[derive(Debug, Deserialize, Serialize)]
623pub struct SearchDocsRequest {
624 pub keywords: String,
625 pub exclude_keywords: Option<String>,
626 pub limit: Option<u32>,
627}
628
629#[derive(Debug, Deserialize, Serialize)]
630pub struct SearchMemoryRequest {
631 pub keywords: Vec<String>,
632 pub start_time: Option<DateTime<Utc>>,
633 pub end_time: Option<DateTime<Utc>>,
634}
635
636#[derive(Debug, Deserialize, Serialize)]
637pub struct SlackReadMessagesRequest {
638 pub channel: String,
639 pub limit: Option<u32>,
640}
641
642#[derive(Debug, Deserialize, Serialize)]
643pub struct SlackReadRepliesRequest {
644 pub channel: String,
645 pub ts: String,
646}
647
648#[derive(Debug, Deserialize, Serialize)]
649pub struct SlackSendMessageRequest {
650 pub channel: String,
651 pub mrkdwn_text: String,
652 pub thread_ts: Option<String>,
653}
654
655#[derive(Debug, Clone, Default, Serialize)]
656pub struct AgentState {
657 pub agent_model: AgentModel,
658 pub messages: Vec<ChatMessage>,
659 pub tools: Option<Vec<Tool>>,
660
661 pub llm_input: Option<LLMInput>,
662 pub llm_output: Option<LLMOutput>,
663
664 pub metadata: Option<HashMap<String, Value>>,
665}
666
667#[derive(Debug, Clone, Default, Serialize)]
668pub struct LLMOutput {
669 pub new_message: LLMMessage,
670 pub usage: LLMTokenUsage,
671}
672
673impl From<&LLMOutput> for ChatMessage {
674 fn from(value: &LLMOutput) -> Self {
675 let message_content = match &value.new_message.content {
676 LLMMessageContent::String(s) => s.clone(),
677 LLMMessageContent::List(l) => l
678 .iter()
679 .map(|c| match c {
680 LLMMessageTypedContent::Text { text } => text.clone(),
681 LLMMessageTypedContent::ToolCall { .. } => String::new(),
682 LLMMessageTypedContent::ToolResult { content, .. } => content.clone(),
683 LLMMessageTypedContent::Image { .. } => String::new(),
684 })
685 .collect::<Vec<_>>()
686 .join("\n"),
687 };
688 let tool_calls = if let LLMMessageContent::List(items) = &value.new_message.content {
689 let calls: Vec<ToolCall> = items
690 .iter()
691 .filter_map(|item| {
692 if let LLMMessageTypedContent::ToolCall { id, name, args } = item {
693 Some(ToolCall {
694 id: id.clone(),
695 r#type: "function".to_string(),
696 function: FunctionCall {
697 name: name.clone(),
698 arguments: args.to_string(),
699 },
700 })
701 } else {
702 None
703 }
704 })
705 .collect();
706
707 if calls.is_empty() { None } else { Some(calls) }
708 } else {
709 None
710 };
711 ChatMessage {
712 role: Role::Assistant,
713 content: Some(MessageContent::String(message_content)),
714 name: None,
715 tool_calls,
716 tool_call_id: None,
717 usage: Some(value.usage.clone()),
718 ..Default::default()
719 }
720 }
721}
722
723impl AgentState {
724 pub fn new(
725 agent_model: AgentModel,
726 messages: Vec<ChatMessage>,
727 tools: Option<Vec<Tool>>,
728 ) -> Self {
729 Self {
730 agent_model,
731 messages,
732 tools,
733 llm_input: None,
734 llm_output: None,
735 metadata: None,
736 }
737 }
738
739 pub fn set_messages(&mut self, messages: Vec<ChatMessage>) {
740 self.messages = messages;
741 }
742
743 pub fn set_tools(&mut self, tools: Option<Vec<Tool>>) {
744 self.tools = tools;
745 }
746
747 pub fn set_agent_model(&mut self, agent_model: AgentModel) {
748 self.agent_model = agent_model;
749 }
750
751 pub fn set_llm_input(&mut self, llm_input: Option<LLMInput>) {
752 self.llm_input = llm_input;
753 }
754
755 pub fn set_llm_output(&mut self, new_message: LLMMessage, new_usage: Option<LLMTokenUsage>) {
756 self.llm_output = Some(LLMOutput {
757 new_message,
758 usage: new_usage.unwrap_or_default(),
759 });
760 }
761
762 pub fn append_new_message(&mut self, new_message: ChatMessage) {
763 self.messages.push(new_message);
764 }
765}