Skip to content

Commit 332c643

Browse files
committed
feat(api): add OpenRouter API client with structured response handling
- Implemented data models for OpenRouter API response including OpenRouterModel, ModelPricing, and ProviderInfo. - Created a main function to fetch and parse models from the OpenRouter API. - Added error handling for JSON parsing and displayed model statistics (free vs paid). - Enhanced output with raw response length and first few model IDs.
1 parent 60094dc commit 332c643

File tree

9 files changed

+433
-783
lines changed

9 files changed

+433
-783
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
/target
2+
.DS_Store

.idea/agentic.iml

Lines changed: 12 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.idea/modules.xml

Lines changed: 8 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.idea/vcs.xml

Lines changed: 6 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.idea/workspace.xml

Lines changed: 45 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

api_test.rs

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
// Test our struct definitions against the real OpenRouter API
2+
use serde::{Deserialize, Serialize};
3+
4+
#[derive(Debug, Clone, Serialize, Deserialize)]
5+
pub struct OpenRouterModel {
6+
pub id: String,
7+
pub name: String,
8+
pub description: Option<String>,
9+
pub pricing: ModelPricing,
10+
pub context_length: u32,
11+
#[serde(skip_serializing_if = "Option::is_none")]
12+
pub architecture: Option<serde_json::Value>,
13+
#[serde(skip_serializing_if = "Option::is_none")]
14+
pub top_provider: Option<ProviderInfo>,
15+
}
16+
17+
#[derive(Debug, Clone, Serialize, Deserialize)]
18+
pub struct ModelPricing {
19+
pub prompt: String,
20+
pub completion: String,
21+
}
22+
23+
#[derive(Debug, Clone, Serialize, Deserialize)]
24+
pub struct ProviderInfo {
25+
pub context_length: Option<u32>,
26+
pub max_completion_tokens: Option<u32>,
27+
#[serde(skip_serializing_if = "Option::is_none")]
28+
pub is_moderated: Option<bool>,
29+
}
30+
31+
#[derive(Debug, Serialize, Deserialize)]
32+
pub struct OpenRouterResponse {
33+
pub data: Vec<OpenRouterModel>,
34+
}
35+
36+
#[tokio::main]
37+
async fn main() -> Result<(), Box<dyn std::error::Error>> {
38+
let client = reqwest::Client::new();
39+
let response = client
40+
.get("https://openrouter.ai/api/v1/models")
41+
.send()
42+
.await?;
43+
44+
let text = response.text().await?;
45+
46+
match serde_json::from_str::<OpenRouterResponse>(&text) {
47+
Ok(data) => {
48+
println!("✅ SUCCESS: Parsed {} models from OpenRouter API", data.data.len());
49+
println!("✅ Models range from '{}' to '{}'",
50+
data.data.first().map(|m| m.id.as_str()).unwrap_or("none"),
51+
data.data.last().map(|m| m.id.as_str()).unwrap_or("none"));
52+
},
53+
Err(e) => {
54+
println!("❌ FAILED: {}", e);
55+
return Err(e.into());
56+
}
57+
}
58+
59+
Ok(())
60+
}

src/events.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,10 @@ pub enum AppEvent {
2626
NavigateLeft,
2727
/// Navigate right (for theme switching)
2828
NavigateRight,
29+
/// Navigate to previous page
30+
PagePrevious,
31+
/// Navigate to next page
32+
PageNext,
2933
/// Select current item in settings modal
3034
Select,
3135
/// Start the AI orchestration application (Enter key)
@@ -78,6 +82,8 @@ impl EventHandler {
7882
KeyCode::Down | KeyCode::Char('j') => Ok(AppEvent::NavigateDown),
7983
KeyCode::Left | KeyCode::Char('h') => Ok(AppEvent::NavigateLeft),
8084
KeyCode::Right | KeyCode::Char('l') => Ok(AppEvent::NavigateRight),
85+
KeyCode::PageUp | KeyCode::Char('[') => Ok(AppEvent::PagePrevious),
86+
KeyCode::PageDown | KeyCode::Char(']') => Ok(AppEvent::PageNext),
8187
KeyCode::Enter => {
8288
// Enter can be either StartApplication or Select depending on context
8389
// We'll let the App decide which one to use based on state

0 commit comments

Comments
 (0)