feat: chat improvements, file viewer, usage fixes, and agent filesystem awareness

This commit is contained in:
2026-04-16 13:42:06 +02:00
parent b6a5d169a9
commit a72eef4b82
10 changed files with 319 additions and 470 deletions

View File

@@ -31,7 +31,7 @@ _ANTHROPIC_MODEL_INFO = [
"context_length": 200000,
"description": "Anthropic's most powerful model. Best for complex reasoning, nuanced writing, and sophisticated analysis.",
"capabilities": {"vision": True, "tools": True, "online": False, "image_gen": False},
"pricing": {"prompt_per_1m": None, "completion_per_1m": None},
"pricing": {"prompt_per_1m": 15.00, "completion_per_1m": 75.00},
"architecture": {"tokenizer": "claude", "modality": "text+image->text"},
},
{
@@ -42,7 +42,7 @@ _ANTHROPIC_MODEL_INFO = [
"context_length": 200000,
"description": "Best balance of speed and intelligence. Ideal for most tasks requiring strong reasoning with faster response times.",
"capabilities": {"vision": True, "tools": True, "online": False, "image_gen": False},
"pricing": {"prompt_per_1m": None, "completion_per_1m": None},
"pricing": {"prompt_per_1m": 3.00, "completion_per_1m": 15.00},
"architecture": {"tokenizer": "claude", "modality": "text+image->text"},
},
{
@@ -53,7 +53,7 @@ _ANTHROPIC_MODEL_INFO = [
"context_length": 200000,
"description": "Fastest and most compact Claude model. Great for quick tasks, simple Q&A, and high-throughput workloads.",
"capabilities": {"vision": True, "tools": True, "online": False, "image_gen": False},
"pricing": {"prompt_per_1m": None, "completion_per_1m": None},
"pricing": {"prompt_per_1m": 0.80, "completion_per_1m": 4.00},
"architecture": {"tokenizer": "claude", "modality": "text+image->text"},
},
]
@@ -379,28 +379,34 @@ def get_model_pricing(model_id: str) -> tuple[float | None, float | None]:
Uses only in-memory data (hardcoded Anthropic/OpenAI + cached OpenRouter raw).
Returns (None, None) if pricing is unknown for this model.
model_id format: "anthropic:claude-sonnet-4-6", "openrouter:openai/gpt-4o", "openai:gpt-4o"
Handles multiple formats:
"anthropic:claude-sonnet-4-6" — prefixed (canonical)
"claude-sonnet-4-6" — bare Anthropic ID (stored by Anthropic provider)
"openrouter:openai/gpt-4o" — prefixed OpenRouter ID
"openai/gpt-4o" — bare OpenRouter ID (stored by some agents)
"openai:gpt-4o" — prefixed OpenAI ID
"""
# Anthropic — match on full prefixed id or bare_id
for m in _ANTHROPIC_MODEL_INFO:
if m["id"] == model_id:
if m["id"] == model_id or m["bare_id"] == model_id:
p = m["pricing"]
return p["prompt_per_1m"], p["completion_per_1m"]
# OpenAI — match on full prefixed id or bare_id
for m in _OPENAI_MODEL_INFO:
if m["id"] == model_id:
if m["id"] == model_id or m["bare_id"] == model_id:
p = m["pricing"]
return p["prompt_per_1m"], p["completion_per_1m"]
# OpenRouter: strip "openrouter:" prefix to get the bare OR model id
if model_id.startswith("openrouter:"):
bare = model_id[len("openrouter:"):]
for m in _or_raw:
if m.get("id", "") == bare and not _is_free_openrouter(m):
pricing = m.get("pricing", {})
try:
prompt = float(pricing.get("prompt", 0)) * 1_000_000
completion = float(pricing.get("completion", 0)) * 1_000_000
return prompt, completion
except (TypeError, ValueError):
return None, None
# OpenRouter: strip "openrouter:" prefix if present, then look up in cached raw list
or_bare = model_id[len("openrouter:"):] if model_id.startswith("openrouter:") else model_id
for m in _or_raw:
if m.get("id", "") == or_bare and not _is_free_openrouter(m):
pricing = m.get("pricing", {})
try:
prompt = float(pricing.get("prompt", 0)) * 1_000_000
completion = float(pricing.get("completion", 0)) * 1_000_000
return prompt, completion
except (TypeError, ValueError):
return None, None
return None, None