feat: Day 11 - landing page polish, SDK README, PyPI publish as vectry-agentlens
- Landing page: pip install snippet, How it Works section, dual code examples (decorator + OpenAI wrapper), Integrations section, Open Source badge - SDK README: quickstart, OpenAI/LangChain/Custom integrations, API reference, architecture diagram - Published vectry-agentlens v0.1.0 to PyPI (import as agentlens) - Fixed pyproject.toml: hatchling.build backend, wheel package mapping
This commit is contained in:
@@ -7,6 +7,14 @@ import {
|
|||||||
GitBranch,
|
GitBranch,
|
||||||
Cpu,
|
Cpu,
|
||||||
Zap,
|
Zap,
|
||||||
|
Terminal,
|
||||||
|
Code2,
|
||||||
|
Eye,
|
||||||
|
Package,
|
||||||
|
Link2,
|
||||||
|
Bot,
|
||||||
|
Star,
|
||||||
|
Clipboard,
|
||||||
} from "lucide-react";
|
} from "lucide-react";
|
||||||
|
|
||||||
export default function HomePage() {
|
export default function HomePage() {
|
||||||
@@ -16,13 +24,27 @@ export default function HomePage() {
|
|||||||
<section className="relative overflow-hidden border-b border-neutral-800/50">
|
<section className="relative overflow-hidden border-b border-neutral-800/50">
|
||||||
<div className="absolute inset-0 bg-gradient-to-b from-emerald-500/5 via-transparent to-transparent" />
|
<div className="absolute inset-0 bg-gradient-to-b from-emerald-500/5 via-transparent to-transparent" />
|
||||||
<div className="absolute inset-0 bg-[radial-gradient(ellipse_80%_50%_at_50%_-20%,rgba(16,185,129,0.1),transparent)]" />
|
<div className="absolute inset-0 bg-[radial-gradient(ellipse_80%_50%_at_50%_-20%,rgba(16,185,129,0.1),transparent)]" />
|
||||||
|
{/* Subtle grid pattern for depth */}
|
||||||
|
<div className="absolute inset-0 bg-[linear-gradient(rgba(255,255,255,0.012)_1px,transparent_1px),linear-gradient(90deg,rgba(255,255,255,0.012)_1px,transparent_1px)] bg-[size:64px_64px]" />
|
||||||
|
|
||||||
<div className="relative max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 pt-20 pb-24">
|
<div className="relative max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 pt-20 pb-24">
|
||||||
<div className="text-center">
|
<div className="text-center">
|
||||||
<div className="inline-flex items-center gap-2 px-4 py-2 rounded-full border border-emerald-500/20 bg-emerald-500/5 text-emerald-400 text-sm mb-8">
|
{/* Top badges row */}
|
||||||
|
<div className="flex flex-wrap items-center justify-center gap-3 mb-8">
|
||||||
|
<div className="inline-flex items-center gap-2 px-4 py-2 rounded-full border border-emerald-500/20 bg-emerald-500/5 text-emerald-400 text-sm">
|
||||||
<Zap className="w-4 h-4" />
|
<Zap className="w-4 h-4" />
|
||||||
<span>Agent Observability Platform</span>
|
<span>Agent Observability Platform</span>
|
||||||
</div>
|
</div>
|
||||||
|
<a
|
||||||
|
href="https://gitea.repi.fun/repi/agentlens"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
className="inline-flex items-center gap-2 px-4 py-2 rounded-full border border-neutral-700/50 bg-neutral-800/30 text-neutral-400 text-sm hover:border-neutral-600 hover:text-neutral-300 transition-all duration-200"
|
||||||
|
>
|
||||||
|
<Star className="w-3.5 h-3.5" />
|
||||||
|
<span>Open Source</span>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
<h1 className="text-6xl sm:text-7xl md:text-8xl font-bold tracking-tight mb-6">
|
<h1 className="text-6xl sm:text-7xl md:text-8xl font-bold tracking-tight mb-6">
|
||||||
<span className="bg-gradient-to-br from-emerald-400 via-emerald-300 to-emerald-500 bg-clip-text text-transparent">
|
<span className="bg-gradient-to-br from-emerald-400 via-emerald-300 to-emerald-500 bg-clip-text text-transparent">
|
||||||
@@ -30,16 +52,31 @@ export default function HomePage() {
|
|||||||
</span>
|
</span>
|
||||||
</h1>
|
</h1>
|
||||||
|
|
||||||
<p className="text-xl sm:text-2xl text-neutral-400 max-w-3xl mx-auto mb-10 leading-relaxed">
|
<p className="text-xl sm:text-2xl text-neutral-400 max-w-3xl mx-auto mb-8 leading-relaxed">
|
||||||
See why your AI agents make the decisions they make. <br className="hidden sm:block" />
|
See why your AI agents make the decisions they make. <br className="hidden sm:block" />
|
||||||
Complete observability for multi-agent systems.
|
Complete observability for multi-agent systems.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
{/* pip install snippet */}
|
||||||
|
<div className="flex justify-center mb-10">
|
||||||
|
<div className="inline-flex items-center gap-3 px-5 py-3 rounded-full bg-neutral-800/80 border border-neutral-700/50 backdrop-blur-sm">
|
||||||
|
<Terminal className="w-4 h-4 text-neutral-500 flex-shrink-0" />
|
||||||
|
<code className="text-sm sm:text-base font-mono text-emerald-400 tracking-wide select-all">
|
||||||
|
pip install vectry-agentlens
|
||||||
|
</code>
|
||||||
|
<div className="w-px h-5 bg-neutral-700" />
|
||||||
|
<Clipboard className="w-4 h-4 text-neutral-500 flex-shrink-0" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div className="flex flex-col sm:flex-row gap-4 justify-center items-center">
|
<div className="flex flex-col sm:flex-row gap-4 justify-center items-center">
|
||||||
<button className="group px-8 py-4 bg-emerald-500 hover:bg-emerald-400 text-neutral-950 font-semibold rounded-lg transition-all duration-200 flex items-center gap-2 shadow-lg shadow-emerald-500/25 hover:shadow-emerald-500/40">
|
<a
|
||||||
|
href="/dashboard"
|
||||||
|
className="group px-8 py-4 bg-emerald-500 hover:bg-emerald-400 text-neutral-950 font-semibold rounded-lg transition-all duration-200 flex items-center gap-2 shadow-lg shadow-emerald-500/25 hover:shadow-emerald-500/40"
|
||||||
|
>
|
||||||
Get Started
|
Get Started
|
||||||
<ArrowRight className="w-5 h-5 group-hover:translate-x-1 transition-transform" />
|
<ArrowRight className="w-5 h-5 group-hover:translate-x-1 transition-transform" />
|
||||||
</button>
|
</a>
|
||||||
<a
|
<a
|
||||||
href="https://gitea.repi.fun/repi/agentlens"
|
href="https://gitea.repi.fun/repi/agentlens"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
@@ -84,7 +121,7 @@ export default function HomePage() {
|
|||||||
</div>
|
</div>
|
||||||
<h3 className="text-xl font-semibold mb-3">Context Awareness</h3>
|
<h3 className="text-xl font-semibold mb-3">Context Awareness</h3>
|
||||||
<p className="text-neutral-400 leading-relaxed">
|
<p className="text-neutral-400 leading-relaxed">
|
||||||
Monitor context window utilization in real-time. Track what's being fed into your agents and what's being left behind.
|
Monitor context window utilization in real-time. Track what's being fed into your agents and what's being left behind.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -102,11 +139,102 @@ export default function HomePage() {
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
{/* How it Works Section */}
|
||||||
|
<section className="py-24 border-b border-neutral-800/50 relative">
|
||||||
|
<div className="absolute inset-0 bg-[radial-gradient(ellipse_60%_40%_at_50%_50%,rgba(16,185,129,0.04),transparent)]" />
|
||||||
|
<div className="relative max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||||
|
<div className="text-center mb-16">
|
||||||
|
<div className="inline-flex items-center gap-2 px-4 py-2 rounded-full border border-neutral-700 bg-neutral-800/30 text-neutral-400 text-sm mb-6">
|
||||||
|
<Zap className="w-4 h-4" />
|
||||||
|
<span>Quick Setup</span>
|
||||||
|
</div>
|
||||||
|
<h2 className="text-3xl sm:text-4xl font-bold mb-4">
|
||||||
|
Up and running in 3 steps
|
||||||
|
</h2>
|
||||||
|
<p className="text-lg text-neutral-400 max-w-2xl mx-auto">
|
||||||
|
Go from zero to full agent observability in under five minutes
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="grid md:grid-cols-3 gap-6 lg:gap-8">
|
||||||
|
{/* Step 1: Install */}
|
||||||
|
<div className="relative p-8 rounded-2xl border border-neutral-800/50 bg-neutral-900/30">
|
||||||
|
<div className="absolute -top-4 left-8">
|
||||||
|
<span className="inline-flex items-center justify-center w-8 h-8 rounded-full bg-emerald-500 text-neutral-950 text-sm font-bold shadow-lg shadow-emerald-500/25">
|
||||||
|
1
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div className="w-12 h-12 rounded-xl bg-emerald-500/10 flex items-center justify-center mb-5 mt-2">
|
||||||
|
<Package className="w-6 h-6 text-emerald-400" />
|
||||||
|
</div>
|
||||||
|
<h3 className="text-lg font-semibold mb-2">Install</h3>
|
||||||
|
<p className="text-neutral-400 text-sm mb-4">
|
||||||
|
One command to add AgentLens to your project.
|
||||||
|
</p>
|
||||||
|
<div className="px-4 py-2.5 rounded-lg bg-neutral-800/80 border border-neutral-700/50">
|
||||||
|
<code className="text-sm font-mono text-emerald-400">pip install vectry-agentlens</code>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Step 2: Instrument */}
|
||||||
|
<div className="relative p-8 rounded-2xl border border-neutral-800/50 bg-neutral-900/30">
|
||||||
|
<div className="absolute -top-4 left-8">
|
||||||
|
<span className="inline-flex items-center justify-center w-8 h-8 rounded-full bg-emerald-500 text-neutral-950 text-sm font-bold shadow-lg shadow-emerald-500/25">
|
||||||
|
2
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div className="w-12 h-12 rounded-xl bg-emerald-500/10 flex items-center justify-center mb-5 mt-2">
|
||||||
|
<Code2 className="w-6 h-6 text-emerald-400" />
|
||||||
|
</div>
|
||||||
|
<h3 className="text-lg font-semibold mb-2">Instrument</h3>
|
||||||
|
<p className="text-neutral-400 text-sm mb-4">
|
||||||
|
Add the <code className="text-emerald-400/80 font-mono text-xs bg-emerald-500/5 px-1.5 py-0.5 rounded">@trace</code> decorator or use <code className="text-emerald-400/80 font-mono text-xs bg-emerald-500/5 px-1.5 py-0.5 rounded">wrap_openai()</code>.
|
||||||
|
</p>
|
||||||
|
<div className="px-4 py-2.5 rounded-lg bg-neutral-800/80 border border-neutral-700/50">
|
||||||
|
<code className="text-sm font-mono text-emerald-400">@trace</code>
|
||||||
|
<span className="text-neutral-600 text-sm font-mono"> / </span>
|
||||||
|
<code className="text-sm font-mono text-emerald-400">wrap_openai()</code>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Step 3: Observe */}
|
||||||
|
<div className="relative p-8 rounded-2xl border border-neutral-800/50 bg-neutral-900/30">
|
||||||
|
<div className="absolute -top-4 left-8">
|
||||||
|
<span className="inline-flex items-center justify-center w-8 h-8 rounded-full bg-emerald-500 text-neutral-950 text-sm font-bold shadow-lg shadow-emerald-500/25">
|
||||||
|
3
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div className="w-12 h-12 rounded-xl bg-emerald-500/10 flex items-center justify-center mb-5 mt-2">
|
||||||
|
<Eye className="w-6 h-6 text-emerald-400" />
|
||||||
|
</div>
|
||||||
|
<h3 className="text-lg font-semibold mb-2">Observe</h3>
|
||||||
|
<p className="text-neutral-400 text-sm mb-4">
|
||||||
|
See every decision in the real-time dashboard.
|
||||||
|
</p>
|
||||||
|
<div className="px-4 py-2.5 rounded-lg bg-neutral-800/80 border border-neutral-700/50">
|
||||||
|
<code className="text-sm font-mono text-emerald-400">agentlens.vectry.tech</code>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Connecting arrows decoration */}
|
||||||
|
<div className="hidden md:flex items-center justify-center mt-10">
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<div className="w-16 h-px bg-gradient-to-r from-transparent to-emerald-500/30" />
|
||||||
|
<ArrowRight className="w-4 h-4 text-emerald-500/40" />
|
||||||
|
<div className="w-16 h-px bg-emerald-500/30" />
|
||||||
|
<ArrowRight className="w-4 h-4 text-emerald-500/40" />
|
||||||
|
<div className="w-16 h-px bg-gradient-to-l from-transparent to-emerald-500/30" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
{/* Code Example Section */}
|
{/* Code Example Section */}
|
||||||
<section className="py-24 border-b border-neutral-800/50">
|
<section className="py-24 border-b border-neutral-800/50">
|
||||||
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||||
<div className="grid lg:grid-cols-2 gap-12 items-center">
|
<div className="grid lg:grid-cols-2 gap-12 items-start">
|
||||||
<div>
|
<div className="lg:sticky lg:top-8">
|
||||||
<div className="inline-flex items-center gap-2 px-4 py-2 rounded-full border border-neutral-700 bg-neutral-800/30 text-neutral-400 text-sm mb-6">
|
<div className="inline-flex items-center gap-2 px-4 py-2 rounded-full border border-neutral-700 bg-neutral-800/30 text-neutral-400 text-sm mb-6">
|
||||||
<Cpu className="w-4 h-4" />
|
<Cpu className="w-4 h-4" />
|
||||||
<span>Python SDK</span>
|
<span>Python SDK</span>
|
||||||
@@ -136,45 +264,211 @@ export default function HomePage() {
|
|||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Code Block */}
|
{/* Code Blocks - Two patterns stacked */}
|
||||||
|
<div className="space-y-6">
|
||||||
|
{/* Decorator Pattern */}
|
||||||
<div className="rounded-xl overflow-hidden border border-neutral-800 bg-neutral-900/50 backdrop-blur-sm">
|
<div className="rounded-xl overflow-hidden border border-neutral-800 bg-neutral-900/50 backdrop-blur-sm">
|
||||||
<div className="px-4 py-3 border-b border-neutral-800 flex items-center gap-2">
|
<div className="px-4 py-3 border-b border-neutral-800 flex items-center justify-between">
|
||||||
<div className="flex gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<div className="w-3 h-3 rounded-full bg-neutral-600" />
|
<div className="flex gap-1.5">
|
||||||
<div className="w-3 h-3 rounded-full bg-neutral-600" />
|
<div className="w-3 h-3 rounded-full bg-neutral-700" />
|
||||||
<div className="w-3 h-3 rounded-full bg-neutral-600" />
|
<div className="w-3 h-3 rounded-full bg-neutral-700" />
|
||||||
|
<div className="w-3 h-3 rounded-full bg-neutral-700" />
|
||||||
</div>
|
</div>
|
||||||
<span className="ml-4 text-sm text-neutral-500">example.py</span>
|
<span className="ml-3 text-sm text-neutral-500">decorator_pattern.py</span>
|
||||||
</div>
|
</div>
|
||||||
<pre className="p-6 overflow-x-auto text-sm">
|
<span className="text-xs font-medium px-2.5 py-1 rounded-full bg-emerald-500/10 text-emerald-400 border border-emerald-500/20">
|
||||||
|
@trace
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<pre className="p-6 overflow-x-auto text-sm leading-relaxed">
|
||||||
<code className="text-neutral-300">
|
<code className="text-neutral-300">
|
||||||
<span className="text-purple-400">from</span> <span className="text-neutral-300">agentlens</span> <span className="text-purple-400">import</span> <span className="text-emerald-300">init</span><span className="text-neutral-300">,</span> <span className="text-emerald-300">trace</span>
|
<span className="text-purple-400">from</span>{" "}
|
||||||
<br />
|
<span className="text-neutral-300">agentlens</span>{" "}
|
||||||
<br />
|
<span className="text-purple-400">import</span>{" "}
|
||||||
|
<span className="text-emerald-300">init</span>
|
||||||
|
<span className="text-neutral-300">,</span>{" "}
|
||||||
|
<span className="text-emerald-300">trace</span>
|
||||||
|
{"\n"}
|
||||||
|
{"\n"}
|
||||||
<span className="text-neutral-500"># Initialize AgentLens</span>
|
<span className="text-neutral-500"># Initialize AgentLens</span>
|
||||||
<br />
|
{"\n"}
|
||||||
<span className="text-emerald-300">init</span><span className="text-neutral-300">(</span>
|
<span className="text-emerald-300">init</span>
|
||||||
<br />
|
<span className="text-neutral-300">(</span>
|
||||||
<span className="text-orange-300">api_key</span><span className="text-neutral-300">=</span><span className="text-emerald-300">"your-api-key"</span><span className="text-neutral-300">,</span>
|
{"\n"}
|
||||||
<br />
|
{" "}
|
||||||
<span className="text-orange-300">endpoint</span><span className="text-neutral-300">=</span><span className="text-emerald-300">"https://agentlens.vectry.tech"</span>
|
<span className="text-orange-300">api_key</span>
|
||||||
<br />
|
<span className="text-neutral-300">=</span>
|
||||||
|
<span className="text-emerald-300">"your-api-key"</span>
|
||||||
|
<span className="text-neutral-300">,</span>
|
||||||
|
{"\n"}
|
||||||
|
{" "}
|
||||||
|
<span className="text-orange-300">endpoint</span>
|
||||||
|
<span className="text-neutral-300">=</span>
|
||||||
|
<span className="text-emerald-300">"https://agentlens.vectry.tech"</span>
|
||||||
|
{"\n"}
|
||||||
<span className="text-neutral-300">)</span>
|
<span className="text-neutral-300">)</span>
|
||||||
<br />
|
{"\n"}
|
||||||
<br />
|
{"\n"}
|
||||||
<span className="text-neutral-500"># Trace your agent function</span>
|
<span className="text-neutral-500"># Trace your agent function</span>
|
||||||
<br />
|
{"\n"}
|
||||||
<span className="text-purple-400">@trace</span><span className="text-neutral-300">(</span><span className="text-orange-300">name</span><span className="text-neutral-300">=</span><span className="text-emerald-300">"research-agent"</span><span className="text-neutral-300">)</span>
|
<span className="text-purple-400">@trace</span>
|
||||||
<br />
|
<span className="text-neutral-300">(</span>
|
||||||
<span className="text-purple-400">async</span> <span className="text-purple-400">def</span> <span className="text-emerald-300">research</span><span className="text-neutral-300">(</span><span className="text-blue-300">topic</span><span className="text-neutral-300">:</span> <span className="text-blue-300">str</span><span className="text-neutral-300">):</span>
|
<span className="text-orange-300">name</span>
|
||||||
<br />
|
<span className="text-neutral-300">=</span>
|
||||||
<span className="text-neutral-500"># Your agent logic here</span>
|
<span className="text-emerald-300">"research-agent"</span>
|
||||||
<br />
|
<span className="text-neutral-300">)</span>
|
||||||
<span className="text-purple-400">return</span> <span className="text-emerald-300">f"Researching: {"{topic"}"</span>
|
{"\n"}
|
||||||
|
<span className="text-purple-400">async</span>{" "}
|
||||||
|
<span className="text-purple-400">def</span>{" "}
|
||||||
|
<span className="text-emerald-300">research</span>
|
||||||
|
<span className="text-neutral-300">(</span>
|
||||||
|
<span className="text-blue-300">topic</span>
|
||||||
|
<span className="text-neutral-300">:</span>{" "}
|
||||||
|
<span className="text-blue-300">str</span>
|
||||||
|
<span className="text-neutral-300">):</span>
|
||||||
|
{"\n"}
|
||||||
|
{" "}
|
||||||
|
<span className="text-neutral-500"># Your agent logic here</span>
|
||||||
|
{"\n"}
|
||||||
|
{" "}
|
||||||
|
<span className="text-purple-400">return</span>{" "}
|
||||||
|
<span className="text-emerald-300">f"Researching: {"{topic}"}"</span>
|
||||||
</code>
|
</code>
|
||||||
</pre>
|
</pre>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* OpenAI Wrapper Pattern */}
|
||||||
|
<div className="rounded-xl overflow-hidden border border-neutral-800 bg-neutral-900/50 backdrop-blur-sm">
|
||||||
|
<div className="px-4 py-3 border-b border-neutral-800 flex items-center justify-between">
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<div className="flex gap-1.5">
|
||||||
|
<div className="w-3 h-3 rounded-full bg-neutral-700" />
|
||||||
|
<div className="w-3 h-3 rounded-full bg-neutral-700" />
|
||||||
|
<div className="w-3 h-3 rounded-full bg-neutral-700" />
|
||||||
|
</div>
|
||||||
|
<span className="ml-3 text-sm text-neutral-500">openai_wrapper.py</span>
|
||||||
|
</div>
|
||||||
|
<span className="text-xs font-medium px-2.5 py-1 rounded-full bg-purple-500/10 text-purple-400 border border-purple-500/20">
|
||||||
|
wrap_openai
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<pre className="p-6 overflow-x-auto text-sm leading-relaxed">
|
||||||
|
<code className="text-neutral-300">
|
||||||
|
<span className="text-purple-400">from</span>{" "}
|
||||||
|
<span className="text-neutral-300">agentlens.integrations.openai</span>{" "}
|
||||||
|
<span className="text-purple-400">import</span>{" "}
|
||||||
|
<span className="text-emerald-300">wrap_openai</span>
|
||||||
|
{"\n"}
|
||||||
|
<span className="text-purple-400">import</span>{" "}
|
||||||
|
<span className="text-neutral-300">openai</span>
|
||||||
|
{"\n"}
|
||||||
|
{"\n"}
|
||||||
|
<span className="text-neutral-500"># Wrap the OpenAI client</span>
|
||||||
|
{"\n"}
|
||||||
|
<span className="text-neutral-300">client</span>{" "}
|
||||||
|
<span className="text-neutral-300">=</span>{" "}
|
||||||
|
<span className="text-neutral-300">openai.</span>
|
||||||
|
<span className="text-emerald-300">OpenAI</span>
|
||||||
|
<span className="text-neutral-300">()</span>
|
||||||
|
{"\n"}
|
||||||
|
<span className="text-neutral-300">client</span>{" "}
|
||||||
|
<span className="text-neutral-300">=</span>{" "}
|
||||||
|
<span className="text-emerald-300">wrap_openai</span>
|
||||||
|
<span className="text-neutral-300">(client)</span>
|
||||||
|
{"\n"}
|
||||||
|
{"\n"}
|
||||||
|
<span className="text-neutral-500"># Use as normal - traces automatically</span>
|
||||||
|
{"\n"}
|
||||||
|
<span className="text-neutral-300">response</span>{" "}
|
||||||
|
<span className="text-neutral-300">=</span>{" "}
|
||||||
|
<span className="text-neutral-300">client.chat.completions.</span>
|
||||||
|
<span className="text-emerald-300">create</span>
|
||||||
|
<span className="text-neutral-300">(</span>
|
||||||
|
{"\n"}
|
||||||
|
{" "}
|
||||||
|
<span className="text-orange-300">model</span>
|
||||||
|
<span className="text-neutral-300">=</span>
|
||||||
|
<span className="text-emerald-300">"gpt-4"</span>
|
||||||
|
<span className="text-neutral-300">,</span>
|
||||||
|
{"\n"}
|
||||||
|
{" "}
|
||||||
|
<span className="text-orange-300">messages</span>
|
||||||
|
<span className="text-neutral-300">=</span>
|
||||||
|
<span className="text-neutral-300">[</span>
|
||||||
|
<span className="text-neutral-300">{"{"}</span>
|
||||||
|
<span className="text-emerald-300">"role"</span>
|
||||||
|
<span className="text-neutral-300">:</span>{" "}
|
||||||
|
<span className="text-emerald-300">"user"</span>
|
||||||
|
<span className="text-neutral-300">,</span>{" "}
|
||||||
|
<span className="text-emerald-300">"content"</span>
|
||||||
|
<span className="text-neutral-300">:</span>{" "}
|
||||||
|
<span className="text-emerald-300">"Hello!"</span>
|
||||||
|
<span className="text-neutral-300">{"}"}</span>
|
||||||
|
<span className="text-neutral-300">]</span>
|
||||||
|
{"\n"}
|
||||||
|
<span className="text-neutral-300">)</span>
|
||||||
|
</code>
|
||||||
|
</pre>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
{/* Integrations Section */}
|
||||||
|
<section className="py-24 border-b border-neutral-800/50 relative">
|
||||||
|
<div className="absolute inset-0 bg-[radial-gradient(ellipse_50%_50%_at_50%_50%,rgba(16,185,129,0.03),transparent)]" />
|
||||||
|
<div className="relative max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||||
|
<div className="text-center mb-16">
|
||||||
|
<div className="inline-flex items-center gap-2 px-4 py-2 rounded-full border border-neutral-700 bg-neutral-800/30 text-neutral-400 text-sm mb-6">
|
||||||
|
<Link2 className="w-4 h-4" />
|
||||||
|
<span>Integrations</span>
|
||||||
|
</div>
|
||||||
|
<h2 className="text-3xl sm:text-4xl font-bold mb-4">
|
||||||
|
Works with your stack
|
||||||
|
</h2>
|
||||||
|
<p className="text-lg text-neutral-400 max-w-2xl mx-auto">
|
||||||
|
First-class support for the most popular AI frameworks. Drop in and start tracing.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="grid sm:grid-cols-3 gap-6 max-w-3xl mx-auto">
|
||||||
|
{/* OpenAI */}
|
||||||
|
<div className="group flex flex-col items-center p-8 rounded-2xl border border-neutral-800/50 bg-neutral-900/30 hover:border-emerald-500/20 transition-all duration-300">
|
||||||
|
<div className="w-16 h-16 rounded-2xl bg-neutral-800/80 border border-neutral-700/50 flex items-center justify-center mb-5 group-hover:border-emerald-500/30 transition-colors duration-300">
|
||||||
|
<Cpu className="w-8 h-8 text-neutral-300 group-hover:text-emerald-400 transition-colors duration-300" />
|
||||||
|
</div>
|
||||||
|
<h3 className="text-lg font-semibold mb-1">OpenAI</h3>
|
||||||
|
<p className="text-sm text-neutral-500">GPT-4, GPT-3.5, o1</p>
|
||||||
|
<span className="mt-3 text-xs font-medium px-3 py-1 rounded-full bg-emerald-500/10 text-emerald-400 border border-emerald-500/20">
|
||||||
|
wrap_openai()
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* LangChain */}
|
||||||
|
<div className="group flex flex-col items-center p-8 rounded-2xl border border-neutral-800/50 bg-neutral-900/30 hover:border-emerald-500/20 transition-all duration-300">
|
||||||
|
<div className="w-16 h-16 rounded-2xl bg-neutral-800/80 border border-neutral-700/50 flex items-center justify-center mb-5 group-hover:border-emerald-500/30 transition-colors duration-300">
|
||||||
|
<GitBranch className="w-8 h-8 text-neutral-300 group-hover:text-emerald-400 transition-colors duration-300" />
|
||||||
|
</div>
|
||||||
|
<h3 className="text-lg font-semibold mb-1">LangChain</h3>
|
||||||
|
<p className="text-sm text-neutral-500">Chains, Agents, Tools</p>
|
||||||
|
<span className="mt-3 text-xs font-medium px-3 py-1 rounded-full bg-emerald-500/10 text-emerald-400 border border-emerald-500/20">
|
||||||
|
Auto-instrumented
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Custom Agents */}
|
||||||
|
<div className="group flex flex-col items-center p-8 rounded-2xl border border-neutral-800/50 bg-neutral-900/30 hover:border-emerald-500/20 transition-all duration-300">
|
||||||
|
<div className="w-16 h-16 rounded-2xl bg-neutral-800/80 border border-neutral-700/50 flex items-center justify-center mb-5 group-hover:border-emerald-500/30 transition-colors duration-300">
|
||||||
|
<Bot className="w-8 h-8 text-neutral-300 group-hover:text-emerald-400 transition-colors duration-300" />
|
||||||
|
</div>
|
||||||
|
<h3 className="text-lg font-semibold mb-1">Custom Agents</h3>
|
||||||
|
<p className="text-sm text-neutral-500">Any Python agent</p>
|
||||||
|
<span className="mt-3 text-xs font-medium px-3 py-1 rounded-full bg-emerald-500/10 text-emerald-400 border border-emerald-500/20">
|
||||||
|
@trace decorator
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
@@ -203,7 +497,7 @@ export default function HomePage() {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="text-sm text-neutral-500">
|
<div className="text-sm text-neutral-500">
|
||||||
MIT License © 2026 Vectry
|
MIT License © 2026 Vectry
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
1
packages/sdk-python/.gitignore
vendored
Normal file
1
packages/sdk-python/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
dist/
|
||||||
@@ -1,38 +1,284 @@
|
|||||||
# AgentLens Python SDK
|
# AgentLens Python SDK
|
||||||
|
|
||||||
AgentLens provides observability for AI agents by tracing decisions, not just API calls.
|
[](https://pypi.org/project/vectry-agentlens/)
|
||||||
|
[](https://www.python.org/downloads/)
|
||||||
|
[](https://opensource.org/licenses/MIT)
|
||||||
|
|
||||||
## Installation
|
Agent observability that traces **decisions**, not just API calls.
|
||||||
|
|
||||||
```bash
|
## What is AgentLens?
|
||||||
pip install agentlens
|
|
||||||
```
|
AgentLens is an observability SDK for AI agents. Unlike generic LLM tracing tools that only capture request/response pairs, AgentLens captures the **decision points** your agent makes: which tool it chose, what alternatives it considered, and why. This gives you a decision tree view of agent behavior, not just a flat log of API calls.
|
||||||
|
|
||||||
## Quick Start
|
## Quick Start
|
||||||
|
|
||||||
```python
|
```bash
|
||||||
from agentlens import init, trace
|
pip install vectry-agentlens
|
||||||
|
|
||||||
# Initialize AgentLens
|
|
||||||
init(api_key="your-api-key", endpoint="https://agentlens.vectry.tech")
|
|
||||||
|
|
||||||
# Trace your agent functions
|
|
||||||
@trace(name="research-agent")
|
|
||||||
async def research(topic: str) -> str:
|
|
||||||
return f"Researching: {topic}"
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Features
|
```python
|
||||||
|
import agentlens
|
||||||
|
|
||||||
- **Decision Tracing**: Log and visualize agent decisions with alternatives
|
# Initialize once at startup
|
||||||
- **Context Awareness**: Monitor context window utilization
|
agentlens.init(api_key="your-api-key")
|
||||||
- **Cost Intelligence**: Track token usage and costs per operation
|
|
||||||
- **Integrations**: Native support for LangChain and OpenAI
|
|
||||||
|
|
||||||
## Documentation
|
# Trace any function with a decorator
|
||||||
|
@agentlens.trace(name="research-agent", tags=["research"])
|
||||||
|
def research(topic: str) -> str:
|
||||||
|
# Your agent logic here
|
||||||
|
return f"Results for: {topic}"
|
||||||
|
|
||||||
Full documentation available at [https://agentlens.vectry.tech/docs](https://agentlens.vectry.tech/docs)
|
research("quantum computing")
|
||||||
|
```
|
||||||
|
|
||||||
|
The `@trace` decorator works with both sync and async functions. Traces are batched and sent to the AgentLens API automatically.
|
||||||
|
|
||||||
|
You can also use `trace` as a context manager:
|
||||||
|
|
||||||
|
```python
|
||||||
|
with agentlens.trace(name="my-operation", session_id="user-123"):
|
||||||
|
# Everything inside is traced
|
||||||
|
result = do_work()
|
||||||
|
```
|
||||||
|
|
||||||
|
## Integrations
|
||||||
|
|
||||||
|
### OpenAI
|
||||||
|
|
||||||
|
Auto-capture every `chat.completions.create` call with token counts, cost estimation, and tool-call decisions.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pip install vectry-agentlens[openai]
|
||||||
|
```
|
||||||
|
|
||||||
|
```python
|
||||||
|
import openai
|
||||||
|
import agentlens
|
||||||
|
from agentlens.integrations.openai import wrap_openai
|
||||||
|
|
||||||
|
agentlens.init(api_key="your-api-key")
|
||||||
|
|
||||||
|
client = openai.OpenAI()
|
||||||
|
client = wrap_openai(client)
|
||||||
|
|
||||||
|
# All calls are now traced automatically
|
||||||
|
@agentlens.trace(name="assistant")
|
||||||
|
def ask(question: str) -> str:
|
||||||
|
response = client.chat.completions.create(
|
||||||
|
model="gpt-4o",
|
||||||
|
messages=[{"role": "user", "content": question}],
|
||||||
|
)
|
||||||
|
return response.choices[0].message.content
|
||||||
|
|
||||||
|
ask("What is the capital of France?")
|
||||||
|
```
|
||||||
|
|
||||||
|
`wrap_openai` instruments the client in-place. For each call it creates an LLM span with:
|
||||||
|
- Model name, temperature, and max_tokens
|
||||||
|
- Token usage (prompt, completion, total)
|
||||||
|
- Estimated cost in USD (built-in pricing for GPT-4, GPT-4o, GPT-3.5-turbo variants)
|
||||||
|
- Automatic `TOOL_SELECTION` decision points when the model invokes function/tool calls
|
||||||
|
|
||||||
|
Streaming is also supported transparently.
|
||||||
|
|
||||||
|
### LangChain
|
||||||
|
|
||||||
|
Drop in a callback handler to trace chains, agents, LLM calls, and tool invocations.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pip install vectry-agentlens[langchain]
|
||||||
|
```
|
||||||
|
|
||||||
|
```python
|
||||||
|
import agentlens
|
||||||
|
from agentlens.integrations.langchain import AgentLensCallbackHandler
|
||||||
|
|
||||||
|
agentlens.init(api_key="your-api-key")
|
||||||
|
|
||||||
|
handler = AgentLensCallbackHandler(
|
||||||
|
trace_name="langchain-agent",
|
||||||
|
tags=["production"],
|
||||||
|
session_id="user-456",
|
||||||
|
)
|
||||||
|
|
||||||
|
# Pass the handler to any LangChain chain or agent
|
||||||
|
result = chain.invoke(
|
||||||
|
{"input": "Summarize this document"},
|
||||||
|
config={"callbacks": [handler]},
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
The handler automatically creates spans for LLM calls, tool calls, and chain execution. Agent tool selections are logged as `TOOL_SELECTION` decision points.
|
||||||
|
|
||||||
|
It also works inside an existing trace context:
|
||||||
|
|
||||||
|
```python
|
||||||
|
@agentlens.trace(name="my-pipeline")
|
||||||
|
def run_pipeline(query: str):
|
||||||
|
handler = AgentLensCallbackHandler()
|
||||||
|
return chain.invoke({"input": query}, config={"callbacks": [handler]})
|
||||||
|
```
|
||||||
|
|
||||||
|
### Custom Agents
|
||||||
|
|
||||||
|
For any agent framework (or your own), use `log_decision()` to record decision points manually.
|
||||||
|
|
||||||
|
```python
|
||||||
|
import agentlens
|
||||||
|
from agentlens import log_decision
|
||||||
|
|
||||||
|
agentlens.init(api_key="your-api-key")
|
||||||
|
|
||||||
|
@agentlens.trace(name="routing-agent")
|
||||||
|
def route_request(query: str) -> str:
|
||||||
|
# Your routing logic
|
||||||
|
chosen_agent = "research-agent"
|
||||||
|
|
||||||
|
log_decision(
|
||||||
|
type="ROUTING",
|
||||||
|
chosen={"name": chosen_agent, "confidence": 0.92},
|
||||||
|
alternatives=[
|
||||||
|
{"name": "support-agent", "confidence": 0.45, "reason_rejected": "not a support query"},
|
||||||
|
{"name": "sales-agent", "confidence": 0.12, "reason_rejected": "no purchase intent"},
|
||||||
|
],
|
||||||
|
reasoning="Query contains research keywords",
|
||||||
|
context_snapshot={"tokens_used": 1200, "tokens_available": 6800},
|
||||||
|
cost_usd=0.003,
|
||||||
|
duration_ms=45,
|
||||||
|
)
|
||||||
|
|
||||||
|
return dispatch(chosen_agent, query)
|
||||||
|
```
|
||||||
|
|
||||||
|
Decision types include: `TOOL_SELECTION`, `ROUTING`, `RETRY`, `ESCALATION`, `MEMORY_RETRIEVAL`, `PLANNING`, and `CUSTOM`.
|
||||||
|
|
||||||
|
## API Reference
|
||||||
|
|
||||||
|
### `agentlens.init()`
|
||||||
|
|
||||||
|
Initialize the SDK. Call once at application startup.
|
||||||
|
|
||||||
|
```python
|
||||||
|
agentlens.init(
|
||||||
|
api_key="your-api-key", # Required. Your AgentLens API key.
|
||||||
|
endpoint="https://...", # API endpoint (default: https://agentlens.vectry.tech)
|
||||||
|
flush_interval=5.0, # Seconds between batch flushes (default: 5.0)
|
||||||
|
max_batch_size=10, # Traces per batch before auto-flush (default: 10)
|
||||||
|
enabled=True, # Set False to disable sending (e.g., in tests)
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
### `agentlens.trace()`
|
||||||
|
|
||||||
|
Decorator or context manager that creates a trace (or a nested span if already inside a trace).
|
||||||
|
|
||||||
|
```python
|
||||||
|
# As decorator
|
||||||
|
@agentlens.trace(name="my-agent", tags=["v2"], session_id="user-789", metadata={"env": "prod"})
|
||||||
|
def my_agent():
|
||||||
|
...
|
||||||
|
|
||||||
|
# As context manager
|
||||||
|
with agentlens.trace(name="sub-task") as ctx:
|
||||||
|
...
|
||||||
|
```
|
||||||
|
|
||||||
|
| Parameter | Type | Description |
|
||||||
|
|-------------|------------------|--------------------------------------|
|
||||||
|
| `name` | `str` | Name for the trace or span |
|
||||||
|
| `tags` | `list[str]` | Tags for filtering in the dashboard |
|
||||||
|
| `session_id`| `str` | Group traces by user session |
|
||||||
|
| `metadata` | `dict` | Arbitrary key-value metadata |
|
||||||
|
|
||||||
|
### `agentlens.log_decision()`
|
||||||
|
|
||||||
|
Record a decision point inside an active trace.
|
||||||
|
|
||||||
|
```python
|
||||||
|
agentlens.log_decision(
|
||||||
|
type="TOOL_SELECTION",
|
||||||
|
chosen={"name": "search", "confidence": 0.95},
|
||||||
|
alternatives=[{"name": "calculator", "confidence": 0.3}],
|
||||||
|
reasoning="User asked a factual question",
|
||||||
|
context_snapshot={"tokens_used": 500},
|
||||||
|
cost_usd=0.001,
|
||||||
|
duration_ms=23,
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
| Parameter | Type | Description |
|
||||||
|
|-------------------|--------------|------------------------------------------------|
|
||||||
|
| `type` | `str` | Decision type (see types above) |
|
||||||
|
| `chosen` | `dict` | The selected option (`name`, `confidence`, etc.) |
|
||||||
|
| `alternatives` | `list[dict]` | Rejected options with reasons |
|
||||||
|
| `reasoning` | `str` | Why this option was chosen |
|
||||||
|
| `context_snapshot`| `dict` | State at decision time (tokens, memory, etc.) |
|
||||||
|
| `cost_usd` | `float` | Cost of this decision in USD |
|
||||||
|
| `duration_ms` | `int` | Time taken to make the decision |
|
||||||
|
|
||||||
|
### `wrap_openai()`
|
||||||
|
|
||||||
|
Instrument an OpenAI client for automatic tracing.
|
||||||
|
|
||||||
|
```python
|
||||||
|
from agentlens.integrations.openai import wrap_openai
|
||||||
|
|
||||||
|
client = wrap_openai(openai.OpenAI())
|
||||||
|
```
|
||||||
|
|
||||||
|
Returns the same client instance with `chat.completions.create` wrapped. All calls automatically generate LLM spans and tool-call decision points.
|
||||||
|
|
||||||
|
### `AgentLensCallbackHandler`
|
||||||
|
|
||||||
|
LangChain callback handler for automatic tracing.
|
||||||
|
|
||||||
|
```python
|
||||||
|
from agentlens.integrations.langchain import AgentLensCallbackHandler
|
||||||
|
|
||||||
|
handler = AgentLensCallbackHandler(
|
||||||
|
trace_name="my-chain", # Trace name (if no active trace exists)
|
||||||
|
tags=["prod"], # Optional tags
|
||||||
|
session_id="user-123", # Optional session ID
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Architecture
|
||||||
|
|
||||||
|
```
|
||||||
|
Your Agent Code
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
AgentLens SDK ── @trace, log_decision(), wrap_openai()
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
Batched HTTP Transport ── Collects traces, flushes every 5s or 10 traces
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
AgentLens API ── https://agentlens.vectry.tech/api/traces
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
Dashboard ── Decision trees, analytics, real-time streaming
|
||||||
|
```
|
||||||
|
|
||||||
|
The SDK is lightweight and non-blocking. Traces are serialized and batched in a background thread, so your agent code is never slowed down by observability.
|
||||||
|
|
||||||
|
## Dashboard
|
||||||
|
|
||||||
|
View your traces at [agentlens.vectry.tech](https://agentlens.vectry.tech):
|
||||||
|
|
||||||
|
- **Decision Trees** - Visualize the full decision path of every agent run
|
||||||
|
- **Analytics** - Token usage, cost breakdowns, latency percentiles
|
||||||
|
- **Real-time Streaming** - Watch agent decisions as they happen
|
||||||
|
- **Session Grouping** - Track multi-turn conversations by session ID
|
||||||
|
|
||||||
|
## Development
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd packages/sdk-python
|
||||||
|
pip install -e ".[all]" # installs openai + langchain extras
|
||||||
|
python -m pytest tests/ -v
|
||||||
|
```
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
MIT © 2026 Vectry
|
MIT - Built by [Vectry](https://vectry.tech)
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
[build-system]
|
[build-system]
|
||||||
requires = ["hatchling"]
|
requires = ["hatchling"]
|
||||||
build-backend = "hatchling.backends"
|
build-backend = "hatchling.build"
|
||||||
|
|
||||||
[project]
|
[project]
|
||||||
name = "agentlens"
|
name = "vectry-agentlens"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
description = "Agent observability that traces decisions, not just API calls"
|
description = "Agent observability that traces decisions, not just API calls"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
@@ -25,7 +25,10 @@ dependencies = [
|
|||||||
[project.optional-dependencies]
|
[project.optional-dependencies]
|
||||||
langchain = ["langchain-core>=0.1.0"]
|
langchain = ["langchain-core>=0.1.0"]
|
||||||
openai = ["openai>=1.0.0"]
|
openai = ["openai>=1.0.0"]
|
||||||
all = ["agentlens[langchain,openai]"]
|
all = ["vectry-agentlens[langchain,openai]"]
|
||||||
|
|
||||||
|
[tool.hatch.build.targets.wheel]
|
||||||
|
packages = ["agentlens"]
|
||||||
|
|
||||||
[project.urls]
|
[project.urls]
|
||||||
Homepage = "https://agentlens.vectry.tech"
|
Homepage = "https://agentlens.vectry.tech"
|
||||||
|
|||||||
Reference in New Issue
Block a user