swarm repositories / source
aboutsummaryrefslogtreecommitdiff
path: root/crates/phone-opus/src/mcp/protocol.rs
blob: 2a029d07be825daac4d69b58b2e4810e2bcbaf27 (plain)
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
use std::path::PathBuf;

use libmcp::{Generation, HostSessionKernelSnapshot};
use serde::{Deserialize, Serialize};
use serde_json::Value;

use crate::mcp::telemetry::ServerTelemetry;

pub(crate) const PROTOCOL_VERSION: &str = "2025-11-25";
pub(crate) const SERVER_NAME: &str = "phone_opus";
pub(crate) const HOST_STATE_ENV: &str = "PHONE_OPUS_MCP_HOST_STATE";
pub(crate) const FORCE_ROLLOUT_ENV: &str = "PHONE_OPUS_MCP_TEST_FORCE_ROLLOUT_KEY";
pub(crate) const WORKER_CRASH_ONCE_ENV: &str = "PHONE_OPUS_MCP_TEST_WORKER_CRASH_ONCE_KEY";
pub(crate) const CLAUDE_BIN_ENV: &str = "PHONE_OPUS_CLAUDE_BIN";
pub(crate) const CLAUDE_CONSULT_PREFIX: &str = r"You are being invoked in a read-only consultation mode by another model. You cannot edit files or make changes; your role is to inspect, reason, and advise.

Take your time. Think deeply, check assumptions, and prefer a careful, high-signal analysis over a fast, shallow response.

Your job is to produce a report for the calling model, not for an end user. Make it actionable. Itemize your findings and prioritize them by importance and urgency. Focus on concrete issues, risks, design flaws, behavioral regressions, missing validations, and better alternatives when relevant.

When useful, distinguish clearly between:
- confirmed findings
- plausible risks or hypotheses
- open questions that would change the recommendation

Prefer specific recommendations over vague commentary. If there are no meaningful problems, say so plainly.

The real prompt follows.";
pub(crate) const CLAUDE_EFFORT: &str = "max";
pub(crate) const CLAUDE_MODEL: &str = "claude-opus-4-7";
pub(crate) const EMPTY_MCP_CONFIG: &str = "{\"mcpServers\":{}}";

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub(crate) enum ClaudeTool {
    Bash,
    Read,
    Grep,
    Glob,
    Ls,
    WebFetch,
}

impl ClaudeTool {
    const fn cli_name(self) -> &'static str {
        match self {
            Self::Bash => "Bash",
            Self::Read => "Read",
            Self::Grep => "Grep",
            Self::Glob => "Glob",
            Self::Ls => "LS",
            Self::WebFetch => "WebFetch",
        }
    }
}

pub(crate) const CLAUDE_TOOLSET: &[ClaudeTool] = &[
    ClaudeTool::Bash,
    ClaudeTool::Read,
    ClaudeTool::Grep,
    ClaudeTool::Glob,
    ClaudeTool::Ls,
    ClaudeTool::WebFetch,
];

pub(crate) fn render_claude_toolset(toolset: &[ClaudeTool]) -> String {
    toolset
        .iter()
        .map(|tool| tool.cli_name())
        .collect::<Vec<_>>()
        .join(",")
}

#[derive(Clone, Debug, Deserialize, Serialize)]
pub(crate) struct HostStateSeed {
    pub(crate) session_kernel: HostSessionKernelSnapshot,
    pub(crate) telemetry: ServerTelemetry,
    pub(crate) next_request_id: u64,
    pub(crate) worker_generation: Generation,
    pub(crate) worker_spawned: bool,
    pub(crate) force_rollout_consumed: bool,
    pub(crate) worker_crash_once_consumed: bool,
}

#[derive(Clone, Copy, Debug, Deserialize, Eq, Ord, PartialEq, PartialOrd, Serialize)]
#[serde(transparent)]
pub(crate) struct HostRequestId(pub(crate) u64);

#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(tag = "kind", rename_all = "snake_case")]
pub(crate) enum WorkerRequest {
    Execute {
        id: HostRequestId,
        operation: WorkerOperation,
    },
}

#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(tag = "kind", rename_all = "snake_case")]
pub(crate) enum WorkerOperation {
    CallTool { name: String, arguments: Value },
}

#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
pub(crate) struct WorkerResponse {
    pub(crate) id: HostRequestId,
    pub(crate) outcome: WorkerOutcome,
}

#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(tag = "status", rename_all = "snake_case")]
pub(crate) enum WorkerOutcome {
    Success {
        result: Value,
    },
    Fault {
        fault: crate::mcp::fault::FaultRecord,
    },
}

#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
pub(crate) struct BinaryFingerprint {
    pub(crate) length_bytes: u64,
    pub(crate) modified_unix_nanos: u128,
}

#[derive(Clone, Debug)]
pub(crate) struct WorkerSpawnConfig {
    pub(crate) executable: PathBuf,
}