Foil SDK for monitoring and logging AI model invocations
Project description
Foil Python SDK
Python SDK for monitoring and logging AI agent invocations with Foil. Features distributed tracing, semantic search, multimodal content support (images, documents), signals/feedback, and OpenAI integration.
Installation
pip install foil-sdk
Or install from source:
pip install -e /path/to/foil-sdk
Quick Start
from foil import Foil, create_foil_tracer, SpanKind
# Create a tracer for your agent
tracer = create_foil_tracer(
api_key="your-api-key",
agent_name="my-agent",
base_url="https://api.getfoil.ai/api", # or your self-hosted URL
)
# Trace an agent execution
async def my_agent():
async with tracer.trace("weather-query", input="User asked about weather") as ctx:
# Create an LLM span
span = await ctx.start_span(SpanKind.LLM, "gpt-4", input="What is the weather?")
# ... call your LLM ...
await span.end(
output="The weather is sunny today!",
tokens={"prompt": 10, "completion": 8, "total": 18}
)
return "Agent completed"
Table of Contents
- Distributed Tracing
- Semantic Search
- Multimodal Content
- Signals & Feedback
- OpenAI Integration
- Experiments (A/B Testing)
- Low-Level API
- API Reference
- Examples
Distributed Tracing
Using the Tracer
from foil import create_foil_tracer, SpanKind
tracer = create_foil_tracer(
api_key="your-api-key",
agent_name="customer-support-agent",
)
async with tracer.trace("support-query", input=user_message, session_id=conversation_id) as ctx:
# LLM span for the main model call
span = await ctx.start_span(SpanKind.LLM, "gpt-4-turbo", input=messages)
response = await openai.chat.completions.create(
model="gpt-4-turbo",
messages=messages,
)
await span.end(
output=response.choices[0].message.content,
tokens={
"prompt": response.usage.prompt_tokens,
"completion": response.usage.completion_tokens,
"total": response.usage.total_tokens,
}
)
Span Kinds
from foil import SpanKind
SpanKind.AGENT # Root agent span
SpanKind.LLM # Language model calls
SpanKind.TOOL # Tool/function executions
SpanKind.CHAIN # Chain of operations
SpanKind.RETRIEVER # RAG retrieval operations
SpanKind.EMBEDDING # Embedding model calls
SpanKind.CUSTOM # Custom operation types
Nested Spans
async with tracer.trace("order-lookup") as ctx:
# LLM decides to use a tool
llm_span = await ctx.start_span(SpanKind.LLM, "gpt-4", input="Find order #12345")
# Tool execution (child of LLM span)
tool_span = await ctx.start_span(SpanKind.TOOL, "lookup_order", input={"order_id": "12345"})
result = await database.find_order("12345")
await tool_span.end(output=result)
await llm_span.end(output=f"Order found: {result}")
Semantic Search
Search through your traces using natural language queries. Foil automatically embeds your trace content and enables AI-powered semantic search.
Basic Search
from foil import Foil
foil = Foil(
api_key="your-api-key",
base_url="https://api.getfoil.ai/api",
)
# Search for conversations about a topic
results = foil.semantic_search("conversations about refund requests")
print(f"Found {len(results['results'])} matching traces")
for result in results["results"]:
print(f"Trace: {result['traceId']}, Similarity: {result['similarity'] * 100:.1f}%")
Search with Filters
results = foil.semantic_search(
"user asking about pricing",
agent_id="customer-support-agent", # Filter by specific agent
agent_name="support-bot", # Or filter by agent name
from_date="2024-01-01", # Start date (ISO format)
to_date="2024-12-31", # End date (ISO format)
limit=10, # Max results (default: 20)
offset=0, # Pagination offset
threshold=0.4, # Min similarity score 0-1 (default: 0.3)
)
Find Similar Traces
Find traces that are semantically similar to a specific trace:
# Find traces similar to a known trace
similar = foil.find_similar_traces(
"trace-abc-123",
limit=5,
threshold=0.4,
)
print(f"Found {len(similar['results'])} similar traces")
for result in similar["results"]:
print(f"{result['traceId']}: {result['similarity'] * 100:.1f}% similar")
Check Semantic Search Status
# Get overall embedding status
status = foil.get_semantic_search_status()
print(f"Embedded: {status['embeddedSpans']} / {status['totalSpans']} spans")
print(f"Coverage: {status['coveragePercent']}%")
print(f"Ready: {status['ready']}")
# Get status for specific agent
agent_status = foil.get_semantic_search_status("my-agent-id")
Multimodal Content
Foil supports multimodal input/output including images, documents, and other media types.
Media Categories
from foil import MediaCategory
MediaCategory.IMAGE # Images (png, jpg, gif, webp, etc.)
MediaCategory.DOCUMENT # Documents (pdf, doc, docx, etc.)
MediaCategory.SPREADSHEET # Spreadsheets (xlsx, csv, etc.)
MediaCategory.CODE # Code files
MediaCategory.AUDIO # Audio files
MediaCategory.VIDEO # Video files
MediaCategory.ARCHIVE # Archives (zip, tar, etc.)
MediaCategory.NOTEBOOK # Jupyter notebooks
MediaCategory.OTHER # Other file types
Uploading Media
from foil import Foil
foil = Foil(
api_key="your-api-key",
base_url="https://api.getfoil.ai/api",
)
# Upload from file path
result = foil.upload_media("/path/to/image.png")
print(result["mediaId"]) # 'media_abc123'
print(result["category"]) # 'image'
print(result["filename"]) # 'image.png'
print(result["mimeType"]) # 'image/png'
# Upload from bytes
with open("/path/to/document.pdf", "rb") as f:
content = f.read()
result = foil.upload_media(
content,
filename="document.pdf",
mime_type="application/pdf",
)
# Upload with trace/span association
result = foil.upload_media(
"/path/to/image.png",
trace_id="trace_123",
span_id="span_456",
direction="input", # or "output"
)
Content Blocks
Use content blocks to create multimodal input/output:
from foil import content, ContentBlock, MediaCategory
# Create multimodal content array
multimodal_input = content(
"Please analyze this image:",
ContentBlock.media(
upload_result["mediaId"],
category=MediaCategory.IMAGE,
filename="photo.jpg",
mime_type="image/jpeg",
),
"Focus on the composition and colors."
)
Media Retrieval
# Get media information
media_info = foil.get_media(media_id)
# Get presigned URL for download
url_info = foil.get_media_url(media_id, "original")
print(url_info["url"]) # Presigned S3 URL
# Get extracted content URL (for documents)
extracted_url = foil.get_media_url(media_id, "extracted")
# Batch get multiple media
batch_info = foil.batch_media_info([media_id1, media_id2, media_id3])
Signals & Feedback
Record user feedback and custom signals for your traces:
from foil import Foil
foil = Foil(api_key="your-api-key")
# Record a signal for a specific trace
foil.record_signal({
"traceId": "trace_123",
"signalName": "user_satisfaction",
"value": 4,
"signalType": "feedback",
"source": "user",
})
# Batch record signals
foil.record_signal_batch([
{"traceId": "trace_123", "signalName": "thumbs", "value": True, "source": "user"},
{"traceId": "trace_123", "signalName": "rating", "value": 5, "source": "user"},
])
# Get signals for a trace
signals = foil.get_trace_signals("trace_123")
OpenAI Integration
Automatic logging for OpenAI calls:
from openai import OpenAI
from foil import Foil
foil = Foil(api_key="your-foil-api-key")
client = foil.wrap_openai(OpenAI())
# All chat completion calls are now automatically logged
response = client.chat.completions.create(
model="gpt-4",
messages=[{"role": "user", "content": "Hello!"}]
)
Supports both streaming and non-streaming responses.
Experiments (A/B Testing)
Get variant assignments for experiments:
from foil import Foil
foil = Foil(api_key="your-api-key")
# Get assigned variant for a user
assignment = foil.get_experiment_variant("experiment_123", user_id)
if assignment["inExperiment"]:
print(assignment["variantName"]) # 'control' or 'treatment'
print(assignment["config"]) # {'model': 'gpt-4', 'temperature': 0.7}
Low-Level API
For more control, use the Foil client directly:
from foil import Foil
foil = Foil(
api_key="your-api-key",
base_url="https://api.getfoil.ai/api",
)
# Manual span management
trace_id = foil.create_trace_id()
span_id = foil.create_span_id()
foil.start_span({
"spanId": span_id,
"traceId": trace_id,
"name": "gpt-4",
"agentName": "my-agent",
"spanKind": "llm",
"input": messages,
})
# ... do work ...
foil.end_span({
"spanId": span_id,
"traceId": trace_id,
"agentName": "my-agent",
"output": response,
"tokens": {"prompt": 100, "completion": 50, "total": 150},
})
# Get trace data
trace = foil.get_trace(trace_id)
# List traces
traces = foil.list_traces(
agent_name="my-agent",
limit=10,
from_date="2024-01-01T00:00:00Z",
)
API Reference
Foil Client
Initialization
foil = Foil(api_key="your-api-key", base_url="https://api.getfoil.ai/api")
| Parameter | Type | Required | Description |
|---|---|---|---|
api_key |
str | Yes | Your Foil API key |
base_url |
str | No | API base URL (default: https://api.getfoil.ai/api) |
Semantic Search Methods
| Method | Description |
|---|---|
semantic_search(query, **options) |
Search spans using natural language |
find_similar_traces(trace_id, **options) |
Find traces similar to a given trace |
get_semantic_search_status(agent_id=None) |
Get embedding statistics |
Media Methods
| Method | Description |
|---|---|
upload_media(file, **options) |
Upload media for multimodal content |
get_media(media_id, content=None) |
Get media information |
get_media_url(media_id, content="original") |
Get presigned download URL |
batch_media_info(media_ids) |
Get info for multiple media |
Signal Methods
| Method | Description |
|---|---|
record_signal(data) |
Record a signal |
record_signal_batch(signals) |
Record multiple signals |
get_trace_signals(trace_id) |
Get signals for a trace |
Trace Methods
| Method | Description |
|---|---|
start_span(data) |
Start a span |
end_span(data) |
End a span |
get_trace(trace_id) |
Get trace with all spans |
list_traces(**options) |
List traces with filters |
Experiment Methods
| Method | Description |
|---|---|
get_experiment_variant(experiment_id, identifier) |
Get variant assignment |
Legacy Methods (Deprecated)
| Method | Replacement |
|---|---|
start_invocation(data) |
Use start_span(data) |
end_invocation(data) |
Use end_span(data) |
Examples
See the examples/ directory for complete working examples:
semantic_search_example.py- Semantic search usage
Run examples:
export FOIL_API_KEY=your-api-key
export FOIL_BASE_URL=https://api.getfoil.ai/api
export FOIL_AGENT_ID=your-agent-id
python examples/semantic_search_example.py
License
MIT
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file foil_sdk-0.6.3.tar.gz.
File metadata
- Download URL: foil_sdk-0.6.3.tar.gz
- Upload date:
- Size: 33.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.9.6
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6a3d61f268c346c9c3a75383343e612d621d79476bf4def0c6f7267fc6902938
|
|
| MD5 |
caed492eac8ffa0c7a801fa926599857
|
|
| BLAKE2b-256 |
eeab82d35d09c2290cce511ec981a499897781b579ace6ae8a804ef0fc2c4c82
|
File details
Details for the file foil_sdk-0.6.3-py3-none-any.whl.
File metadata
- Download URL: foil_sdk-0.6.3-py3-none-any.whl
- Upload date:
- Size: 27.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.9.6
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
239aedce1e327df9ad3ac71af14492194c3c9f05b9f5618ff11aa82046575555
|
|
| MD5 |
8afb5f7d9092b995626a78e410e1e552
|
|
| BLAKE2b-256 |
1c32eb5ac808bf407334dc5ab45e33669d77778c7ed5c04c8241ec55eb4970b4
|