foil-sdk 0.5.0__tar.gz

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.
Files changed (34) hide show
  1. foil_sdk-0.5.0/LICENSE +21 -0
  2. foil_sdk-0.5.0/PKG-INFO +665 -0
  3. foil_sdk-0.5.0/README.md +631 -0
  4. foil_sdk-0.5.0/examples/01_customer_support_bot.py +265 -0
  5. foil_sdk-0.5.0/examples/02_rag_pipeline.py +225 -0
  6. foil_sdk-0.5.0/examples/03_ecommerce_product_agent.py +245 -0
  7. foil_sdk-0.5.0/examples/04_knowledge_base_assistant.py +251 -0
  8. foil_sdk-0.5.0/examples/05_content_generation_agent.py +261 -0
  9. foil_sdk-0.5.0/examples/_demo_utils.py +179 -0
  10. foil_sdk-0.5.0/examples/custom_evaluations_example.py +380 -0
  11. foil_sdk-0.5.0/examples/customer_support_agent_example.py +563 -0
  12. foil_sdk-0.5.0/examples/multimodal_test.py +366 -0
  13. foil_sdk-0.5.0/examples/openai_agent_test.py +364 -0
  14. foil_sdk-0.5.0/examples/otel_example.py +110 -0
  15. foil_sdk-0.5.0/examples/semantic_search_example.py +176 -0
  16. foil_sdk-0.5.0/examples/signals_test.py +648 -0
  17. foil_sdk-0.5.0/examples/tracer_test.py +329 -0
  18. foil_sdk-0.5.0/examples/user_device_tracking_test.py +118 -0
  19. foil_sdk-0.5.0/foil/__init__.py +57 -0
  20. foil_sdk-0.5.0/foil/client.py +1447 -0
  21. foil_sdk-0.5.0/foil/integrations/__init__.py +10 -0
  22. foil_sdk-0.5.0/foil/integrations/langchain.py +539 -0
  23. foil_sdk-0.5.0/foil/otel.py +643 -0
  24. foil_sdk-0.5.0/foil/py.typed +0 -0
  25. foil_sdk-0.5.0/foil/tracer.py +790 -0
  26. foil_sdk-0.5.0/foil_sdk.egg-info/PKG-INFO +665 -0
  27. foil_sdk-0.5.0/foil_sdk.egg-info/SOURCES.txt +32 -0
  28. foil_sdk-0.5.0/foil_sdk.egg-info/dependency_links.txt +1 -0
  29. foil_sdk-0.5.0/foil_sdk.egg-info/requires.txt +14 -0
  30. foil_sdk-0.5.0/foil_sdk.egg-info/top_level.txt +4 -0
  31. foil_sdk-0.5.0/pyproject.toml +51 -0
  32. foil_sdk-0.5.0/setup.cfg +4 -0
  33. foil_sdk-0.5.0/tests/__init__.py +1 -0
  34. foil_sdk-0.5.0/tests/test_otel.py +463 -0
foil_sdk-0.5.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 Foil
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,665 @@
1
+ Metadata-Version: 2.4
2
+ Name: foil-sdk
3
+ Version: 0.5.0
4
+ Summary: Foil SDK for monitoring and logging AI model invocations
5
+ Author: Foil
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://getfoil.ai
8
+ Project-URL: Documentation, https://docs.getfoil.ai
9
+ Project-URL: Repository, https://github.com/getfoil/foil
10
+ Keywords: ai,monitoring,logging,openai,llm,opentelemetry,tracing
11
+ Classifier: Development Status :: 3 - Alpha
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Programming Language :: Python :: 3.8
15
+ Classifier: Programming Language :: Python :: 3.9
16
+ Classifier: Programming Language :: Python :: 3.10
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Requires-Python: >=3.8
20
+ Description-Content-Type: text/markdown
21
+ License-File: LICENSE
22
+ Requires-Dist: requests>=2.25.0
23
+ Provides-Extra: dev
24
+ Requires-Dist: pytest>=7.0.0; extra == "dev"
25
+ Requires-Dist: pytest-cov>=4.0.0; extra == "dev"
26
+ Provides-Extra: otel
27
+ Requires-Dist: opentelemetry-api>=1.20.0; extra == "otel"
28
+ Requires-Dist: opentelemetry-sdk>=1.20.0; extra == "otel"
29
+ Provides-Extra: openllmetry
30
+ Requires-Dist: opentelemetry-api>=1.20.0; extra == "openllmetry"
31
+ Requires-Dist: opentelemetry-sdk>=1.20.0; extra == "openllmetry"
32
+ Requires-Dist: traceloop-sdk>=0.15.0; extra == "openllmetry"
33
+ Dynamic: license-file
34
+
35
+ # Foil Python SDK
36
+
37
+ Python SDK for monitoring and logging AI agent invocations with Foil. Features distributed tracing, semantic search, custom evaluations, multimodal content support (images, documents), signals/feedback, and OpenAI integration.
38
+
39
+ ## Installation
40
+
41
+ ```bash
42
+ pip install foil-sdk
43
+ ```
44
+
45
+ Or install from source:
46
+
47
+ ```bash
48
+ pip install -e /path/to/foil-sdk
49
+ ```
50
+
51
+ ## Quick Start
52
+
53
+ ```python
54
+ from foil import Foil, create_foil_tracer, SpanKind
55
+
56
+ # Create a tracer for your agent
57
+ tracer = create_foil_tracer(
58
+ api_key="your-api-key",
59
+ agent_name="my-agent",
60
+ base_url="https://api.foil.dev/api", # or your self-hosted URL
61
+ )
62
+
63
+ # Trace an agent execution
64
+ async def my_agent():
65
+ async with tracer.trace("weather-query", input="User asked about weather") as ctx:
66
+ # Create an LLM span
67
+ span = await ctx.start_span(SpanKind.LLM, "gpt-4", input="What is the weather?")
68
+
69
+ # ... call your LLM ...
70
+
71
+ await span.end(
72
+ output="The weather is sunny today!",
73
+ tokens={"prompt": 10, "completion": 8, "total": 18}
74
+ )
75
+
76
+ return "Agent completed"
77
+ ```
78
+
79
+ ## Table of Contents
80
+
81
+ - [Distributed Tracing](#distributed-tracing)
82
+ - [Semantic Search](#semantic-search)
83
+ - [Custom Evaluations](#custom-evaluations)
84
+ - [Multimodal Content](#multimodal-content)
85
+ - [Signals & Feedback](#signals--feedback)
86
+ - [OpenAI Integration](#openai-integration)
87
+ - [Experiments (A/B Testing)](#experiments-ab-testing)
88
+ - [Low-Level API](#low-level-api)
89
+ - [API Reference](#api-reference)
90
+ - [Examples](#examples)
91
+
92
+ ## Distributed Tracing
93
+
94
+ ### Using the Tracer
95
+
96
+ ```python
97
+ from foil import create_foil_tracer, SpanKind
98
+
99
+ tracer = create_foil_tracer(
100
+ api_key="your-api-key",
101
+ agent_name="customer-support-agent",
102
+ )
103
+
104
+ async with tracer.trace("support-query", input=user_message, session_id=conversation_id) as ctx:
105
+ # LLM span for the main model call
106
+ span = await ctx.start_span(SpanKind.LLM, "gpt-4-turbo", input=messages)
107
+
108
+ response = await openai.chat.completions.create(
109
+ model="gpt-4-turbo",
110
+ messages=messages,
111
+ )
112
+
113
+ await span.end(
114
+ output=response.choices[0].message.content,
115
+ tokens={
116
+ "prompt": response.usage.prompt_tokens,
117
+ "completion": response.usage.completion_tokens,
118
+ "total": response.usage.total_tokens,
119
+ }
120
+ )
121
+ ```
122
+
123
+ ### Span Kinds
124
+
125
+ ```python
126
+ from foil import SpanKind
127
+
128
+ SpanKind.AGENT # Root agent span
129
+ SpanKind.LLM # Language model calls
130
+ SpanKind.TOOL # Tool/function executions
131
+ SpanKind.CHAIN # Chain of operations
132
+ SpanKind.RETRIEVER # RAG retrieval operations
133
+ SpanKind.EMBEDDING # Embedding model calls
134
+ SpanKind.CUSTOM # Custom operation types
135
+ ```
136
+
137
+ ### Nested Spans
138
+
139
+ ```python
140
+ async with tracer.trace("order-lookup") as ctx:
141
+ # LLM decides to use a tool
142
+ llm_span = await ctx.start_span(SpanKind.LLM, "gpt-4", input="Find order #12345")
143
+
144
+ # Tool execution (child of LLM span)
145
+ tool_span = await ctx.start_span(SpanKind.TOOL, "lookup_order", input={"order_id": "12345"})
146
+ result = await database.find_order("12345")
147
+ await tool_span.end(output=result)
148
+
149
+ await llm_span.end(output=f"Order found: {result}")
150
+ ```
151
+
152
+ ## Semantic Search
153
+
154
+ Search through your traces using natural language queries. Foil automatically embeds your trace content and enables AI-powered semantic search.
155
+
156
+ ### Basic Search
157
+
158
+ ```python
159
+ from foil import Foil
160
+
161
+ foil = Foil(
162
+ api_key="your-api-key",
163
+ base_url="https://api.foil.dev/api",
164
+ )
165
+
166
+ # Search for conversations about a topic
167
+ results = foil.semantic_search("conversations about refund requests")
168
+
169
+ print(f"Found {len(results['results'])} matching traces")
170
+ for result in results["results"]:
171
+ print(f"Trace: {result['traceId']}, Similarity: {result['similarity'] * 100:.1f}%")
172
+ ```
173
+
174
+ ### Search with Filters
175
+
176
+ ```python
177
+ results = foil.semantic_search(
178
+ "user asking about pricing",
179
+ agent_id="customer-support-agent", # Filter by specific agent
180
+ agent_name="support-bot", # Or filter by agent name
181
+ from_date="2024-01-01", # Start date (ISO format)
182
+ to_date="2024-12-31", # End date (ISO format)
183
+ limit=10, # Max results (default: 20)
184
+ offset=0, # Pagination offset
185
+ threshold=0.4, # Min similarity score 0-1 (default: 0.3)
186
+ )
187
+ ```
188
+
189
+ ### Find Similar Traces
190
+
191
+ Find traces that are semantically similar to a specific trace:
192
+
193
+ ```python
194
+ # Find traces similar to a known trace
195
+ similar = foil.find_similar_traces(
196
+ "trace-abc-123",
197
+ limit=5,
198
+ threshold=0.4,
199
+ )
200
+
201
+ print(f"Found {len(similar['results'])} similar traces")
202
+ for result in similar["results"]:
203
+ print(f"{result['traceId']}: {result['similarity'] * 100:.1f}% similar")
204
+ ```
205
+
206
+ ### Check Semantic Search Status
207
+
208
+ ```python
209
+ # Get overall embedding status
210
+ status = foil.get_semantic_search_status()
211
+ print(f"Embedded: {status['embeddedSpans']} / {status['totalSpans']} spans")
212
+ print(f"Coverage: {status['coveragePercent']}%")
213
+ print(f"Ready: {status['ready']}")
214
+
215
+ # Get status for specific agent
216
+ agent_status = foil.get_semantic_search_status("my-agent-id")
217
+ ```
218
+
219
+ ## Custom Evaluations
220
+
221
+ Define custom evaluation criteria to analyze your agent's responses. Evaluations run automatically on new traces and can be boolean, score-based, or categorical.
222
+
223
+ ### Get Evaluation Templates
224
+
225
+ ```python
226
+ # List available pre-built evaluation templates
227
+ templates = foil.get_evaluation_templates()
228
+
229
+ for t in templates.get("templates", []):
230
+ print(f"{t['name']}: {t.get('description', 'N/A')}")
231
+ ```
232
+
233
+ ### Create a Boolean Evaluation
234
+
235
+ ```python
236
+ evaluation = foil.create_evaluation("agent-123", {
237
+ "name": "professional_tone",
238
+ "description": "Checks if the response maintains a professional tone",
239
+ "prompt": """Evaluate the assistant's response for professional tone.
240
+
241
+ Consider:
242
+ - Is the language respectful and courteous?
243
+ - Does it avoid slang or casual expressions?
244
+ - Is it helpful without being condescending?
245
+
246
+ Return true if professional, false otherwise.""",
247
+ "evaluationType": "boolean",
248
+ "enabled": True,
249
+ })
250
+
251
+ print(f"Created evaluation: {evaluation['evaluation']['name']}")
252
+ ```
253
+
254
+ ### Create a Score Evaluation (1-10)
255
+
256
+ ```python
257
+ evaluation = foil.create_evaluation("agent-123", {
258
+ "name": "helpfulness_score",
259
+ "description": "Rates response helpfulness on a scale of 1-10",
260
+ "prompt": """Rate the helpfulness of the response on a scale of 1-10.
261
+
262
+ Scoring:
263
+ - 1-3: Unhelpful
264
+ - 4-5: Somewhat helpful
265
+ - 6-7: Helpful
266
+ - 8-9: Very helpful
267
+ - 10: Exceptional
268
+
269
+ Return a single number from 1 to 10.""",
270
+ "evaluationType": "score",
271
+ "scoreMin": 1,
272
+ "scoreMax": 10,
273
+ "enabled": True,
274
+ })
275
+ ```
276
+
277
+ ### Create a Category Evaluation
278
+
279
+ ```python
280
+ evaluation = foil.create_evaluation("agent-123", {
281
+ "name": "response_intent",
282
+ "description": "Categorizes the type of response",
283
+ "prompt": """Classify the response into one category:
284
+
285
+ - informational: Provides facts or explanations
286
+ - action: Guides through a process
287
+ - clarification: Asks for more information
288
+ - escalation: Suggests human assistance
289
+ - closure: Wraps up the conversation
290
+
291
+ Return only the category name.""",
292
+ "evaluationType": "category",
293
+ "categories": ["informational", "action", "clarification", "escalation", "closure"],
294
+ "enabled": True,
295
+ })
296
+ ```
297
+
298
+ ### Test an Evaluation
299
+
300
+ Validate your evaluation prompt before enabling:
301
+
302
+ ```python
303
+ result = foil.test_evaluation("agent-123", evaluation_id, {
304
+ "input": "How do I reset my password?",
305
+ "output": "I'd be happy to help! Go to Settings > Security > Reset Password.",
306
+ })
307
+
308
+ print(f"Result: {result['result']}") # true/false, score, or category
309
+ print(f"Reasoning: {result['reasoning']}") # Explanation
310
+ ```
311
+
312
+ ### Add Few-Shot Examples
313
+
314
+ Improve evaluation accuracy with examples:
315
+
316
+ ```python
317
+ # Add a positive example
318
+ foil.add_evaluation_example("agent-123", evaluation_id, {
319
+ "input": "Why is my order late?",
320
+ "output": "I apologize for the delay. Let me check the status for you.",
321
+ "expectedResult": True,
322
+ "reasoning": "Professional and helpful response",
323
+ })
324
+
325
+ # Add a negative example
326
+ foil.add_evaluation_example("agent-123", evaluation_id, {
327
+ "input": "Why is my order late?",
328
+ "output": "idk check tracking yourself",
329
+ "expectedResult": False,
330
+ "reasoning": "Casual and unhelpful",
331
+ })
332
+ ```
333
+
334
+ ### Manage Evaluations
335
+
336
+ ```python
337
+ # List all evaluations for an agent
338
+ evaluations = foil.get_agent_evaluations("agent-123")
339
+
340
+ # Get specific evaluation details
341
+ evaluation = foil.get_evaluation("agent-123", evaluation_id)
342
+
343
+ # Update an evaluation
344
+ foil.update_evaluation("agent-123", evaluation_id, {
345
+ "description": "Updated description",
346
+ "enabled": False, # Disable temporarily
347
+ })
348
+
349
+ # Get evaluation analytics
350
+ analytics = foil.get_evaluation_analytics("agent-123", evaluation_id)
351
+ print(f"Total evaluations: {analytics.get('totalEvaluations', 0)}")
352
+ print(f"Distribution: {analytics.get('distribution')}")
353
+
354
+ # Clone a template
355
+ cloned = foil.clone_evaluation_template("agent-123", template_id)
356
+
357
+ # Remove an example
358
+ foil.remove_evaluation_example("agent-123", evaluation_id, example_id)
359
+
360
+ # Delete an evaluation
361
+ foil.delete_evaluation("agent-123", evaluation_id)
362
+ ```
363
+
364
+ ## Multimodal Content
365
+
366
+ Foil supports multimodal input/output including images, documents, and other media types.
367
+
368
+ ### Media Categories
369
+
370
+ ```python
371
+ from foil import MediaCategory
372
+
373
+ MediaCategory.IMAGE # Images (png, jpg, gif, webp, etc.)
374
+ MediaCategory.DOCUMENT # Documents (pdf, doc, docx, etc.)
375
+ MediaCategory.SPREADSHEET # Spreadsheets (xlsx, csv, etc.)
376
+ MediaCategory.CODE # Code files
377
+ MediaCategory.AUDIO # Audio files
378
+ MediaCategory.VIDEO # Video files
379
+ MediaCategory.ARCHIVE # Archives (zip, tar, etc.)
380
+ MediaCategory.NOTEBOOK # Jupyter notebooks
381
+ MediaCategory.OTHER # Other file types
382
+ ```
383
+
384
+ ### Uploading Media
385
+
386
+ ```python
387
+ from foil import Foil
388
+
389
+ foil = Foil(
390
+ api_key="your-api-key",
391
+ base_url="https://api.foil.dev/api",
392
+ )
393
+
394
+ # Upload from file path
395
+ result = foil.upload_media("/path/to/image.png")
396
+ print(result["mediaId"]) # 'media_abc123'
397
+ print(result["category"]) # 'image'
398
+ print(result["filename"]) # 'image.png'
399
+ print(result["mimeType"]) # 'image/png'
400
+
401
+ # Upload from bytes
402
+ with open("/path/to/document.pdf", "rb") as f:
403
+ content = f.read()
404
+ result = foil.upload_media(
405
+ content,
406
+ filename="document.pdf",
407
+ mime_type="application/pdf",
408
+ )
409
+
410
+ # Upload with trace/span association
411
+ result = foil.upload_media(
412
+ "/path/to/image.png",
413
+ trace_id="trace_123",
414
+ span_id="span_456",
415
+ direction="input", # or "output"
416
+ )
417
+ ```
418
+
419
+ ### Content Blocks
420
+
421
+ Use content blocks to create multimodal input/output:
422
+
423
+ ```python
424
+ from foil import content, ContentBlock, MediaCategory
425
+
426
+ # Create multimodal content array
427
+ multimodal_input = content(
428
+ "Please analyze this image:",
429
+ ContentBlock.media(
430
+ upload_result["mediaId"],
431
+ category=MediaCategory.IMAGE,
432
+ filename="photo.jpg",
433
+ mime_type="image/jpeg",
434
+ ),
435
+ "Focus on the composition and colors."
436
+ )
437
+ ```
438
+
439
+ ### Media Retrieval
440
+
441
+ ```python
442
+ # Get media information
443
+ media_info = foil.get_media(media_id)
444
+
445
+ # Get presigned URL for download
446
+ url_info = foil.get_media_url(media_id, "original")
447
+ print(url_info["url"]) # Presigned S3 URL
448
+
449
+ # Get extracted content URL (for documents)
450
+ extracted_url = foil.get_media_url(media_id, "extracted")
451
+
452
+ # Batch get multiple media
453
+ batch_info = foil.batch_media_info([media_id1, media_id2, media_id3])
454
+ ```
455
+
456
+ ## Signals & Feedback
457
+
458
+ Record user feedback and custom signals for your traces:
459
+
460
+ ```python
461
+ from foil import Foil
462
+
463
+ foil = Foil(api_key="your-api-key")
464
+
465
+ # Record a signal for a specific trace
466
+ foil.record_signal({
467
+ "traceId": "trace_123",
468
+ "signalName": "user_satisfaction",
469
+ "value": 4,
470
+ "signalType": "feedback",
471
+ "source": "user",
472
+ })
473
+
474
+ # Batch record signals
475
+ foil.record_signal_batch([
476
+ {"traceId": "trace_123", "signalName": "thumbs", "value": True, "source": "user"},
477
+ {"traceId": "trace_123", "signalName": "rating", "value": 5, "source": "user"},
478
+ ])
479
+
480
+ # Get signals for a trace
481
+ signals = foil.get_trace_signals("trace_123")
482
+ ```
483
+
484
+ ## OpenAI Integration
485
+
486
+ Automatic logging for OpenAI calls:
487
+
488
+ ```python
489
+ from openai import OpenAI
490
+ from foil import Foil
491
+
492
+ foil = Foil(api_key="your-foil-api-key")
493
+ client = foil.wrap_openai(OpenAI())
494
+
495
+ # All chat completion calls are now automatically logged
496
+ response = client.chat.completions.create(
497
+ model="gpt-4",
498
+ messages=[{"role": "user", "content": "Hello!"}]
499
+ )
500
+ ```
501
+
502
+ Supports both streaming and non-streaming responses.
503
+
504
+ ## Experiments (A/B Testing)
505
+
506
+ Get variant assignments for experiments:
507
+
508
+ ```python
509
+ from foil import Foil
510
+
511
+ foil = Foil(api_key="your-api-key")
512
+
513
+ # Get assigned variant for a user
514
+ assignment = foil.get_experiment_variant("experiment_123", user_id)
515
+
516
+ if assignment["inExperiment"]:
517
+ print(assignment["variantName"]) # 'control' or 'treatment'
518
+ print(assignment["config"]) # {'model': 'gpt-4', 'temperature': 0.7}
519
+ ```
520
+
521
+ ## Low-Level API
522
+
523
+ For more control, use the Foil client directly:
524
+
525
+ ```python
526
+ from foil import Foil
527
+
528
+ foil = Foil(
529
+ api_key="your-api-key",
530
+ base_url="https://api.foil.dev/api",
531
+ )
532
+
533
+ # Manual span management
534
+ trace_id = foil.create_trace_id()
535
+ span_id = foil.create_span_id()
536
+
537
+ foil.start_span({
538
+ "spanId": span_id,
539
+ "traceId": trace_id,
540
+ "name": "gpt-4",
541
+ "agentName": "my-agent",
542
+ "spanKind": "llm",
543
+ "input": messages,
544
+ })
545
+
546
+ # ... do work ...
547
+
548
+ foil.end_span({
549
+ "spanId": span_id,
550
+ "traceId": trace_id,
551
+ "agentName": "my-agent",
552
+ "output": response,
553
+ "tokens": {"prompt": 100, "completion": 50, "total": 150},
554
+ })
555
+
556
+ # Get trace data
557
+ trace = foil.get_trace(trace_id)
558
+
559
+ # List traces
560
+ traces = foil.list_traces(
561
+ agent_name="my-agent",
562
+ limit=10,
563
+ from_date="2024-01-01T00:00:00Z",
564
+ )
565
+ ```
566
+
567
+ ## API Reference
568
+
569
+ ### Foil Client
570
+
571
+ #### Initialization
572
+
573
+ ```python
574
+ foil = Foil(api_key="your-api-key", base_url="https://api.getfoil.ai/api")
575
+ ```
576
+
577
+ | Parameter | Type | Required | Description |
578
+ |-----------|------|----------|-------------|
579
+ | `api_key` | str | Yes | Your Foil API key |
580
+ | `base_url` | str | No | API base URL (default: https://api.getfoil.ai) |
581
+
582
+ ### Semantic Search Methods
583
+
584
+ | Method | Description |
585
+ |--------|-------------|
586
+ | `semantic_search(query, **options)` | Search spans using natural language |
587
+ | `find_similar_traces(trace_id, **options)` | Find traces similar to a given trace |
588
+ | `get_semantic_search_status(agent_id=None)` | Get embedding statistics |
589
+
590
+ ### Custom Evaluation Methods
591
+
592
+ | Method | Description |
593
+ |--------|-------------|
594
+ | `get_evaluation_templates()` | List available evaluation templates |
595
+ | `get_agent_evaluations(agent_id)` | List evaluations for an agent |
596
+ | `get_evaluation(agent_id, evaluation_id)` | Get evaluation details |
597
+ | `create_evaluation(agent_id, data)` | Create a custom evaluation |
598
+ | `update_evaluation(agent_id, evaluation_id, data)` | Update an evaluation |
599
+ | `delete_evaluation(agent_id, evaluation_id)` | Delete an evaluation |
600
+ | `test_evaluation(agent_id, evaluation_id, data)` | Test with sample data |
601
+ | `clone_evaluation_template(agent_id, template_id)` | Clone a template |
602
+ | `add_evaluation_example(agent_id, evaluation_id, data)` | Add few-shot example |
603
+ | `remove_evaluation_example(agent_id, evaluation_id, example_id)` | Remove example |
604
+ | `get_evaluation_analytics(agent_id, evaluation_id)` | Get evaluation metrics |
605
+
606
+ ### Media Methods
607
+
608
+ | Method | Description |
609
+ |--------|-------------|
610
+ | `upload_media(file, **options)` | Upload media for multimodal content |
611
+ | `get_media(media_id, content=None)` | Get media information |
612
+ | `get_media_url(media_id, content="original")` | Get presigned download URL |
613
+ | `batch_media_info(media_ids)` | Get info for multiple media |
614
+
615
+ ### Signal Methods
616
+
617
+ | Method | Description |
618
+ |--------|-------------|
619
+ | `record_signal(data)` | Record a signal |
620
+ | `record_signal_batch(signals)` | Record multiple signals |
621
+ | `get_trace_signals(trace_id)` | Get signals for a trace |
622
+
623
+ ### Trace Methods
624
+
625
+ | Method | Description |
626
+ |--------|-------------|
627
+ | `start_span(data)` | Start a span |
628
+ | `end_span(data)` | End a span |
629
+ | `get_trace(trace_id)` | Get trace with all spans |
630
+ | `list_traces(**options)` | List traces with filters |
631
+
632
+ ### Experiment Methods
633
+
634
+ | Method | Description |
635
+ |--------|-------------|
636
+ | `get_experiment_variant(experiment_id, identifier)` | Get variant assignment |
637
+
638
+ ### Legacy Methods (Deprecated)
639
+
640
+ | Method | Replacement |
641
+ |--------|-------------|
642
+ | `start_invocation(data)` | Use `start_span(data)` |
643
+ | `end_invocation(data)` | Use `end_span(data)` |
644
+
645
+ ## Examples
646
+
647
+ See the `examples/` directory for complete working examples:
648
+
649
+ - `semantic_search_example.py` - Semantic search usage
650
+ - `custom_evaluations_example.py` - Custom evaluations
651
+
652
+ Run examples:
653
+
654
+ ```bash
655
+ export FOIL_API_KEY=your-api-key
656
+ export FOIL_BASE_URL=https://api.getfoil.ai/api
657
+ export FOIL_AGENT_ID=your-agent-id
658
+
659
+ python examples/semantic_search_example.py
660
+ python examples/custom_evaluations_example.py
661
+ ```
662
+
663
+ ## License
664
+
665
+ MIT