zarz 0.3.4-alpha → 0.3.5-alpha

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/mcp/types.rs DELETED
@@ -1,170 +0,0 @@
1
- use serde::{Deserialize, Serialize};
2
- use serde_json::Value;
3
- use std::collections::HashMap;
4
-
5
- /// MCP JSON-RPC request
6
- #[derive(Debug, Clone, Serialize, Deserialize)]
7
- pub struct JsonRpcRequest {
8
- pub jsonrpc: String,
9
- pub id: u64,
10
- pub method: String,
11
- #[serde(skip_serializing_if = "Option::is_none")]
12
- pub params: Option<Value>,
13
- }
14
-
15
- /// MCP JSON-RPC response
16
- #[derive(Debug, Clone, Serialize, Deserialize)]
17
- pub struct JsonRpcResponse {
18
- pub jsonrpc: String,
19
- pub id: u64,
20
- #[serde(skip_serializing_if = "Option::is_none")]
21
- pub result: Option<Value>,
22
- #[serde(skip_serializing_if = "Option::is_none")]
23
- pub error: Option<JsonRpcError>,
24
- }
25
-
26
- /// MCP JSON-RPC error
27
- #[derive(Debug, Clone, Serialize, Deserialize)]
28
- pub struct JsonRpcError {
29
- pub code: i32,
30
- pub message: String,
31
- #[serde(skip_serializing_if = "Option::is_none")]
32
- pub data: Option<Value>,
33
- }
34
-
35
- /// MCP Tool definition
36
- #[derive(Debug, Clone, Serialize, Deserialize)]
37
- pub struct McpTool {
38
- pub name: String,
39
- pub description: Option<String>,
40
- #[serde(rename = "inputSchema")]
41
- pub input_schema: Value,
42
- }
43
-
44
- /// MCP Resource definition
45
- #[derive(Debug, Clone, Serialize, Deserialize)]
46
- #[allow(dead_code)]
47
- pub struct McpResource {
48
- pub uri: String,
49
- pub name: String,
50
- #[serde(skip_serializing_if = "Option::is_none")]
51
- pub description: Option<String>,
52
- #[serde(skip_serializing_if = "Option::is_none")]
53
- pub mime_type: Option<String>,
54
- }
55
-
56
- /// MCP Prompt definition
57
- #[derive(Debug, Clone, Serialize, Deserialize)]
58
- #[allow(dead_code)]
59
- pub struct McpPrompt {
60
- pub name: String,
61
- #[serde(skip_serializing_if = "Option::is_none")]
62
- pub description: Option<String>,
63
- #[serde(skip_serializing_if = "Option::is_none")]
64
- pub arguments: Option<Vec<PromptArgument>>,
65
- }
66
-
67
- #[derive(Debug, Clone, Serialize, Deserialize)]
68
- #[allow(dead_code)]
69
- pub struct PromptArgument {
70
- pub name: String,
71
- #[serde(skip_serializing_if = "Option::is_none")]
72
- pub description: Option<String>,
73
- pub required: bool,
74
- }
75
-
76
- /// MCP Initialize result
77
- #[derive(Debug, Clone, Serialize, Deserialize)]
78
- pub struct InitializeResult {
79
- #[serde(rename = "protocolVersion")]
80
- pub protocol_version: String,
81
- pub capabilities: ServerCapabilities,
82
- #[serde(rename = "serverInfo")]
83
- pub server_info: ServerInfo,
84
- }
85
-
86
- #[derive(Debug, Clone, Serialize, Deserialize)]
87
- pub struct ServerCapabilities {
88
- #[serde(skip_serializing_if = "Option::is_none")]
89
- pub tools: Option<ToolsCapability>,
90
- #[serde(skip_serializing_if = "Option::is_none")]
91
- pub resources: Option<ResourcesCapability>,
92
- #[serde(skip_serializing_if = "Option::is_none")]
93
- pub prompts: Option<PromptsCapability>,
94
- }
95
-
96
- #[derive(Debug, Clone, Serialize, Deserialize)]
97
- pub struct ToolsCapability {
98
- #[serde(skip_serializing_if = "Option::is_none")]
99
- pub list_changed: Option<bool>,
100
- }
101
-
102
- #[derive(Debug, Clone, Serialize, Deserialize)]
103
- pub struct ResourcesCapability {
104
- #[serde(skip_serializing_if = "Option::is_none")]
105
- pub subscribe: Option<bool>,
106
- #[serde(skip_serializing_if = "Option::is_none")]
107
- pub list_changed: Option<bool>,
108
- }
109
-
110
- #[derive(Debug, Clone, Serialize, Deserialize)]
111
- pub struct PromptsCapability {
112
- #[serde(skip_serializing_if = "Option::is_none")]
113
- pub list_changed: Option<bool>,
114
- }
115
-
116
- #[derive(Debug, Clone, Serialize, Deserialize)]
117
- pub struct ServerInfo {
118
- pub name: String,
119
- pub version: String,
120
- }
121
-
122
- /// Tools list response
123
- #[derive(Debug, Clone, Serialize, Deserialize)]
124
- pub struct ToolsListResult {
125
- pub tools: Vec<McpTool>,
126
- }
127
-
128
- /// Tool call request
129
- #[derive(Debug, Clone, Serialize, Deserialize)]
130
- #[allow(dead_code)]
131
- pub struct CallToolParams {
132
- pub name: String,
133
- #[serde(skip_serializing_if = "Option::is_none")]
134
- pub arguments: Option<HashMap<String, Value>>,
135
- }
136
-
137
- /// Tool call result
138
- #[derive(Debug, Clone, Serialize, Deserialize)]
139
- #[allow(dead_code)]
140
- pub struct CallToolResult {
141
- pub content: Vec<ToolContent>,
142
- #[serde(skip_serializing_if = "Option::is_none")]
143
- pub is_error: Option<bool>,
144
- }
145
-
146
- #[derive(Debug, Clone, Serialize, Deserialize)]
147
- #[serde(tag = "type")]
148
- #[allow(dead_code)]
149
- pub enum ToolContent {
150
- #[serde(rename = "text")]
151
- Text { text: String },
152
- #[serde(rename = "image")]
153
- Image { data: String, mime_type: String },
154
- #[serde(rename = "resource")]
155
- Resource { resource: McpResource },
156
- }
157
-
158
- /// Resources list response
159
- #[derive(Debug, Clone, Serialize, Deserialize)]
160
- #[allow(dead_code)]
161
- pub struct ResourcesListResult {
162
- pub resources: Vec<McpResource>,
163
- }
164
-
165
- /// Prompts list response
166
- #[derive(Debug, Clone, Serialize, Deserialize)]
167
- #[allow(dead_code)]
168
- pub struct PromptsListResult {
169
- pub prompts: Vec<McpPrompt>,
170
- }
@@ -1,242 +0,0 @@
1
- use anyhow::{Context, Result};
2
- use bytes::Bytes;
3
- use futures::stream::StreamExt;
4
- use reqwest::Client;
5
- use serde::Deserialize;
6
- use serde_json::json;
7
-
8
- use super::{CompletionRequest, CompletionResponse, CompletionStream};
9
-
10
- const DEFAULT_ENDPOINT: &str = "https://api.anthropic.com/v1/messages";
11
- const DEFAULT_VERSION: &str = "2023-06-01";
12
-
13
- pub struct AnthropicClient {
14
- http: Client,
15
- endpoint: String,
16
- api_key: String,
17
- version: String,
18
- }
19
-
20
- impl AnthropicClient {
21
- pub fn from_env(
22
- api_key_override: Option<String>,
23
- endpoint_override: Option<String>,
24
- timeout_override: Option<u64>,
25
- ) -> Result<Self> {
26
- let api_key = api_key_override
27
- .or_else(|| std::env::var("ANTHROPIC_API_KEY").ok())
28
- .ok_or_else(|| anyhow::anyhow!("ANTHROPIC_API_KEY is required. Please set it in ~/.zarz/config.toml or as an environment variable"))?;
29
- let endpoint = endpoint_override
30
- .or_else(|| std::env::var("ANTHROPIC_API_URL").ok())
31
- .unwrap_or_else(|| DEFAULT_ENDPOINT.to_string());
32
- let version = std::env::var("ANTHROPIC_API_VERSION")
33
- .ok()
34
- .filter(|v| !v.trim().is_empty())
35
- .unwrap_or_else(|| DEFAULT_VERSION.to_string());
36
-
37
- let timeout_secs = timeout_override
38
- .or_else(|| {
39
- std::env::var("ANTHROPIC_TIMEOUT_SECS")
40
- .ok()
41
- .and_then(|raw| raw.parse::<u64>().ok())
42
- })
43
- .unwrap_or(120);
44
-
45
- let http = Client::builder()
46
- .user_agent("zarz-cli/0.1")
47
- .timeout(std::time::Duration::from_secs(timeout_secs))
48
- .build()
49
- .context("Failed to build HTTP client for Anthropic")?;
50
-
51
- Ok(Self {
52
- http,
53
- endpoint,
54
- api_key,
55
- version,
56
- })
57
- }
58
-
59
- pub async fn complete(&self, request: &CompletionRequest) -> Result<CompletionResponse> {
60
- let mut payload = serde_json::Map::new();
61
- payload.insert("model".to_string(), serde_json::Value::String(request.model.clone()));
62
- payload.insert(
63
- "max_tokens".to_string(),
64
- serde_json::Value::Number(serde_json::Number::from(request.max_output_tokens)),
65
- );
66
- payload.insert("temperature".to_string(), json!(request.temperature));
67
- if let Some(system_prompt) = &request.system_prompt {
68
- payload.insert(
69
- "system".to_string(),
70
- serde_json::Value::String(system_prompt.clone()),
71
- );
72
- }
73
-
74
- if let Some(tools) = &request.tools {
75
- payload.insert("tools".to_string(), serde_json::Value::Array(tools.clone()));
76
- }
77
-
78
- if let Some(messages) = &request.messages {
79
- payload.insert("messages".to_string(), serde_json::Value::Array(messages.clone()));
80
- } else {
81
- payload.insert(
82
- "messages".to_string(),
83
- json!([{
84
- "role": "user",
85
- "content": [{
86
- "type": "text",
87
- "text": request.user_prompt
88
- }]
89
- }]),
90
- );
91
- }
92
-
93
- let response = self
94
- .http
95
- .post(&self.endpoint)
96
- .header("x-api-key", &self.api_key)
97
- .header("anthropic-version", &self.version)
98
- .json(&payload)
99
- .send()
100
- .await
101
- .context("Anthropic request failed")?;
102
-
103
- let response = response.error_for_status().context("Anthropic returned an error status")?;
104
- let parsed: AnthropicResponse = response
105
- .json()
106
- .await
107
- .context("Failed to decode Anthropic response")?;
108
-
109
- let mut text = String::new();
110
- let mut tool_calls = Vec::new();
111
-
112
- for block in parsed.content {
113
- match block {
114
- AnthropicResponseBlock::Text { text: t } => {
115
- text.push_str(&t);
116
- }
117
- AnthropicResponseBlock::ToolUse { id, name, input } => {
118
- tool_calls.push(super::ToolCall { id, name, input });
119
- }
120
- }
121
- }
122
-
123
- Ok(CompletionResponse {
124
- text,
125
- tool_calls,
126
- stop_reason: parsed.stop_reason,
127
- })
128
- }
129
-
130
- #[allow(dead_code)]
131
- pub async fn complete_stream(&self, request: &CompletionRequest) -> Result<CompletionStream> {
132
- let mut payload = serde_json::Map::new();
133
- payload.insert("model".to_string(), serde_json::Value::String(request.model.clone()));
134
- payload.insert(
135
- "max_tokens".to_string(),
136
- serde_json::Value::Number(serde_json::Number::from(request.max_output_tokens)),
137
- );
138
- payload.insert("temperature".to_string(), json!(request.temperature));
139
- payload.insert("stream".to_string(), json!(true));
140
-
141
- if let Some(system_prompt) = &request.system_prompt {
142
- payload.insert(
143
- "system".to_string(),
144
- serde_json::Value::String(system_prompt.clone()),
145
- );
146
- }
147
- payload.insert(
148
- "messages".to_string(),
149
- json!([{
150
- "role": "user",
151
- "content": [{
152
- "type": "text",
153
- "text": request.user_prompt
154
- }]
155
- }]),
156
- );
157
-
158
- let response = self
159
- .http
160
- .post(&self.endpoint)
161
- .header("x-api-key", &self.api_key)
162
- .header("anthropic-version", &self.version)
163
- .json(&payload)
164
- .send()
165
- .await
166
- .context("Anthropic streaming request failed")?;
167
-
168
- let response = response
169
- .error_for_status()
170
- .context("Anthropic returned an error status")?;
171
-
172
- let stream = response.bytes_stream();
173
- let text_stream = stream.map(|result| {
174
- let bytes = result?;
175
- parse_anthropic_sse_chunk(&bytes)
176
- });
177
-
178
- Ok(Box::pin(text_stream))
179
- }
180
- }
181
-
182
- #[allow(dead_code)]
183
- fn parse_anthropic_sse_chunk(bytes: &Bytes) -> Result<String> {
184
- let text = String::from_utf8_lossy(bytes);
185
- let mut result = String::new();
186
-
187
- for line in text.lines() {
188
- if let Some(data) = line.strip_prefix("data: ") {
189
- if data == "[DONE]" {
190
- break;
191
- }
192
-
193
- if let Ok(event) = serde_json::from_str::<StreamEvent>(data) {
194
- match event.event_type.as_str() {
195
- "content_block_delta" => {
196
- if let Some(delta) = event.delta {
197
- if let Some(text) = delta.text {
198
- result.push_str(&text);
199
- }
200
- }
201
- }
202
- _ => {}
203
- }
204
- }
205
- }
206
- }
207
-
208
- Ok(result)
209
- }
210
-
211
- #[allow(dead_code)]
212
- #[derive(Debug, Deserialize)]
213
- struct StreamEvent {
214
- #[serde(rename = "type")]
215
- event_type: String,
216
- delta: Option<StreamDelta>,
217
- }
218
-
219
- #[allow(dead_code)]
220
- #[derive(Debug, Deserialize)]
221
- struct StreamDelta {
222
- text: Option<String>,
223
- }
224
-
225
- #[derive(Debug, Deserialize)]
226
- struct AnthropicResponse {
227
- content: Vec<AnthropicResponseBlock>,
228
- stop_reason: Option<String>,
229
- }
230
-
231
- #[derive(Debug, Deserialize, Clone)]
232
- #[serde(tag = "type")]
233
- pub enum AnthropicResponseBlock {
234
- #[serde(rename = "text")]
235
- Text { text: String },
236
- #[serde(rename = "tool_use")]
237
- ToolUse {
238
- id: String,
239
- name: String,
240
- input: serde_json::Value,
241
- },
242
- }
@@ -1,259 +0,0 @@
1
- use anyhow::{anyhow, Context, Result};
2
- use bytes::Bytes;
3
- use futures::stream::StreamExt;
4
- use reqwest::Client;
5
- use serde::Deserialize;
6
- use serde_json::json;
7
-
8
- use super::{CompletionRequest, CompletionResponse, CompletionStream};
9
-
10
- // GLM Coding Plan endpoint (base URL only, no /chat/completions)
11
- const DEFAULT_ENDPOINT: &str = "https://api.z.ai/api/coding/paas/v4";
12
-
13
- pub struct GlmClient {
14
- http: Client,
15
- endpoint: String,
16
- api_key: String,
17
- }
18
-
19
- impl GlmClient {
20
- pub fn from_env(
21
- api_key_override: Option<String>,
22
- endpoint_override: Option<String>,
23
- timeout_override: Option<u64>,
24
- ) -> Result<Self> {
25
- let api_key = api_key_override
26
- .or_else(|| std::env::var("GLM_API_KEY").ok())
27
- .ok_or_else(|| anyhow::anyhow!("GLM_API_KEY is required. Please set it in ~/.zarz/config.toml or as an environment variable"))?;
28
- let endpoint = endpoint_override
29
- .or_else(|| std::env::var("GLM_API_URL").ok())
30
- .unwrap_or_else(|| DEFAULT_ENDPOINT.to_string());
31
-
32
- let timeout_secs = timeout_override
33
- .or_else(|| {
34
- std::env::var("GLM_TIMEOUT_SECS")
35
- .ok()
36
- .and_then(|raw| raw.parse::<u64>().ok())
37
- })
38
- .unwrap_or(120);
39
-
40
- let http = Client::builder()
41
- .user_agent("zarz-cli/0.1")
42
- .timeout(std::time::Duration::from_secs(timeout_secs))
43
- .build()
44
- .context("Failed to build HTTP client for GLM")?;
45
-
46
- Ok(Self {
47
- http,
48
- endpoint,
49
- api_key,
50
- })
51
- }
52
-
53
- pub async fn complete(&self, request: &CompletionRequest) -> Result<CompletionResponse> {
54
- let messages = if let Some(msgs) = &request.messages {
55
- msgs.clone()
56
- } else {
57
- let mut messages = Vec::new();
58
- if let Some(system) = &request.system_prompt {
59
- messages.push(json!({
60
- "role": "system",
61
- "content": system,
62
- }));
63
- }
64
- messages.push(json!({
65
- "role": "user",
66
- "content": request.user_prompt,
67
- }));
68
- messages
69
- };
70
-
71
- let mut payload = json!({
72
- "model": request.model,
73
- "max_tokens": request.max_output_tokens,
74
- "messages": messages,
75
- });
76
-
77
- if let Some(tools) = &request.tools {
78
- let glm_tools: Vec<_> = tools.iter().map(|tool| {
79
- json!({
80
- "type": "function",
81
- "function": {
82
- "name": tool["name"],
83
- "description": tool["description"],
84
- "parameters": tool["input_schema"]
85
- }
86
- })
87
- }).collect();
88
- payload["tools"] = json!(glm_tools);
89
- }
90
-
91
- // Construct full endpoint URL
92
- let full_url = format!("{}/chat/completions", self.endpoint);
93
-
94
- let response = self
95
- .http
96
- .post(&full_url)
97
- .bearer_auth(&self.api_key)
98
- .json(&payload)
99
- .send()
100
- .await
101
- .context("GLM request failed")?;
102
-
103
- // Check status and get error details if failed
104
- let status = response.status();
105
- if !status.is_success() {
106
- let error_body = response.text().await.unwrap_or_else(|_| "Unable to read error body".to_string());
107
- return Err(anyhow!("GLM API error ({}): {}", status, error_body));
108
- }
109
-
110
- let response = response;
111
-
112
- let parsed: GlmResponse = response
113
- .json()
114
- .await
115
- .context("Failed to decode GLM response")?;
116
-
117
- let first_choice = parsed.choices.into_iter().next()
118
- .ok_or_else(|| anyhow!("GLM response did not include any choices"))?;
119
-
120
- let text = first_choice.message.content.unwrap_or_default();
121
- let mut tool_calls = Vec::new();
122
-
123
- if let Some(calls) = first_choice.message.tool_calls {
124
- for call in calls {
125
- tool_calls.push(super::ToolCall {
126
- id: call.id,
127
- name: call.function.name,
128
- input: call.function.arguments,
129
- });
130
- }
131
- }
132
-
133
- Ok(CompletionResponse {
134
- text,
135
- tool_calls,
136
- stop_reason: first_choice.finish_reason,
137
- })
138
- }
139
-
140
- #[allow(dead_code)]
141
- pub async fn complete_stream(&self, request: &CompletionRequest) -> Result<CompletionStream> {
142
- let mut messages = Vec::new();
143
- if let Some(system) = &request.system_prompt {
144
- messages.push(json!({
145
- "role": "system",
146
- "content": system,
147
- }));
148
- }
149
- messages.push(json!({
150
- "role": "user",
151
- "content": request.user_prompt,
152
- }));
153
-
154
- let payload = json!({
155
- "model": request.model,
156
- "max_tokens": request.max_output_tokens,
157
- "messages": messages,
158
- "stream": true,
159
- });
160
-
161
- // Construct full endpoint URL
162
- let full_url = format!("{}/chat/completions", self.endpoint);
163
-
164
- let response = self
165
- .http
166
- .post(&full_url)
167
- .bearer_auth(&self.api_key)
168
- .json(&payload)
169
- .send()
170
- .await
171
- .context("GLM streaming request failed")?;
172
-
173
- let response = response
174
- .error_for_status()
175
- .context("GLM returned an error status")?;
176
-
177
- let stream = response.bytes_stream();
178
- let text_stream = stream.map(|result| {
179
- let bytes = result?;
180
- parse_glm_sse_chunk(&bytes)
181
- });
182
-
183
- Ok(Box::pin(text_stream))
184
- }
185
- }
186
-
187
- #[allow(dead_code)]
188
- fn parse_glm_sse_chunk(bytes: &Bytes) -> Result<String> {
189
- let text = String::from_utf8_lossy(bytes);
190
- let mut result = String::new();
191
-
192
- for line in text.lines() {
193
- if let Some(data) = line.strip_prefix("data: ") {
194
- if data == "[DONE]" {
195
- break;
196
- }
197
-
198
- if let Ok(chunk) = serde_json::from_str::<StreamChunk>(data) {
199
- if let Some(choice) = chunk.choices.first() {
200
- if let Some(content) = &choice.delta.content {
201
- result.push_str(content);
202
- }
203
- }
204
- }
205
- }
206
- }
207
-
208
- Ok(result)
209
- }
210
-
211
- #[allow(dead_code)]
212
- #[derive(Debug, Deserialize)]
213
- struct StreamChunk {
214
- choices: Vec<StreamChoice>,
215
- }
216
-
217
- #[allow(dead_code)]
218
- #[derive(Debug, Deserialize)]
219
- struct StreamChoice {
220
- delta: StreamDelta,
221
- }
222
-
223
- #[allow(dead_code)]
224
- #[derive(Debug, Deserialize)]
225
- struct StreamDelta {
226
- content: Option<String>,
227
- }
228
-
229
- #[derive(Debug, Deserialize)]
230
- struct GlmResponse {
231
- choices: Vec<GlmChoice>,
232
- }
233
-
234
- #[derive(Debug, Deserialize)]
235
- struct GlmChoice {
236
- message: GlmMessage,
237
- finish_reason: Option<String>,
238
- }
239
-
240
- #[derive(Debug, Deserialize)]
241
- struct GlmMessage {
242
- content: Option<String>,
243
- tool_calls: Option<Vec<GlmToolCall>>,
244
- }
245
-
246
- #[derive(Debug, Deserialize)]
247
- struct GlmToolCall {
248
- id: String,
249
- #[serde(rename = "type")]
250
- #[allow(dead_code)]
251
- call_type: String,
252
- function: GlmFunction,
253
- }
254
-
255
- #[derive(Debug, Deserialize)]
256
- struct GlmFunction {
257
- name: String,
258
- arguments: serde_json::Value,
259
- }