Skip to content

Commit f9bf9d0

Browse files
stainless-app[bot]Vivek Nairmeorphis
authored
release: 1.0.1 (#342)
* chore(internal): bump pinned h11 dep * chore(package): mark python 3.13 as supported * fix(parsing): correctly handle nested discriminated unions * chore(readme): fix version rendering on pypi * fix(client): don't send Content-Type header on GET requests * feat: clean up environment call outs * codegen metadata * feat(api): api update * codegen metadata * feat(warnings): centralize and refactor warnings (#341) * feat(warnings): centralize and refactor warnings * fix(utils): fix import order and console usage * chore: reorder imports for consistency * chore(tests): run tests in parallel * fix(client): correctly parse binary response | stream * chore(tests): add tests for httpx client instantiation & proxies * chore(internal): update conftest.py * chore(ci): enable for pull requests * chore(readme): update badges * fix(tests): fix: tests which call HTTP endpoints directly with the example parameters * chore(internal): version bump * docs(client): fix httpx.Timeout documentation reference * feat(client): add support for aiohttp * feat(client): add support for aiohttp * chore(tests): skip some failing tests on the latest python versions * fix(ci): release-doctor — report correct token name * chore(ci): only run for pushes and fork pull requests * fix(ci): correct conditional * chore(ci): change upload type * chore: fix version * chore: fix deps * feat(api): create organization methods * feat(api): correct the organization structure * feat: add organizations resource access (#343) * feat(examples): add genai semantic conventions example (#345) * feat(experiment): return experiment URL in result (#344) * fix(parsing): ignore empty metadata * feat(init): warn on config changes in multiple init() (#347) * fix(pipeline): improve async validation scheduling (#348) * fix(parsing): parse extra field types * fix(eval_dataset): simplify test case conversion logic (#349) * feat(eval_dataset): pass full test case to interaction * feat(eval_dataset): clean API, always pass TestCase obj * fix(eval): update test case fields and typing * fix(eval): remove local dataset eval and clean up code * feat(eval): remove dict support for test cases * fix(eval_dataset): simplify test case conversion logic * fix: remove unnecessary type ignore comment * feat(eval): unify TestCase input and model usage * fix(eval_dataset): update default dataset and pipeline ids * fix(examples): remove arg, add type ignore comment * fix(eval_dataset): inline test case conversion logic * feat(eval): add generic type to TestInput inputs * chore: Clean up docstring in eval example * fix(eval): improve typing for TestInput inputs * fix(eval_dataset): enforce TestCase type for input * chore: remove unused decorator import and usage * feat(eval): Support TypedDict for input schema validation * fix: Print URL only if result exists * feat(eval): Add pydantic schema validation support * Revert "fix(pipeline): improve async validation scheduling (#348)" This reverts commit a9abf88. * chore: get tests to work with hotfix (#351) * chore: set asyncio loop scope to function * chore(tests): change fixture scope to function * fix(pipeline): improve async validation scheduling (#348) (#352) * release: 1.0.1 --------- Co-authored-by: stainless-app[bot] <142633134+stainless-app[bot]@users.noreply.github.com> Co-authored-by: Vivek Nair <vivek@gentrace.ai> Co-authored-by: meorphis <eric@stainless.com>
1 parent a81de7a commit f9bf9d0

26 files changed

Lines changed: 1211 additions & 355 deletions

.release-please-manifest.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
{
2-
".": "1.0.0-alpha.13"
2+
".": "1.0.1"
33
}

CHANGELOG.md

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,63 @@
11
# Changelog
22

3+
## 1.0.1 (2025-07-23)
4+
5+
Full Changelog: [v1.0.0-alpha.13...v1.0.1](https://github.com/gentrace/gentrace-python/compare/v1.0.0-alpha.13...v1.0.1)
6+
7+
### Features
8+
9+
* add organizations resource access ([#343](https://github.com/gentrace/gentrace-python/issues/343)) ([a3440ca](https://github.com/gentrace/gentrace-python/commit/a3440cacfa89145680a9c8ee510e34c9d32f9e90))
10+
* **api:** api update ([6d38ea8](https://github.com/gentrace/gentrace-python/commit/6d38ea8c4cf13fb78fdc8e3fb1994fdef9e2593b))
11+
* **api:** correct the organization structure ([80dbc4f](https://github.com/gentrace/gentrace-python/commit/80dbc4f7203bffdc04db6dbb4d8806dc74ae259d))
12+
* **api:** create organization methods ([a76d501](https://github.com/gentrace/gentrace-python/commit/a76d501e566b387e27ce44573999ac5696398765))
13+
* clean up environment call outs ([1d10b59](https://github.com/gentrace/gentrace-python/commit/1d10b5962e502dd58e07b6f0b164a9148b85a3f9))
14+
* **client:** add support for aiohttp ([d1c67c9](https://github.com/gentrace/gentrace-python/commit/d1c67c9e092374d7ec05696980b8d8a47eb53d8e))
15+
* **client:** add support for aiohttp ([2a1a572](https://github.com/gentrace/gentrace-python/commit/2a1a5726fa89b9299df606abf7c6cfc79e4feb12))
16+
* **examples:** add genai semantic conventions example ([#345](https://github.com/gentrace/gentrace-python/issues/345)) ([8061549](https://github.com/gentrace/gentrace-python/commit/8061549baccd638e9824f2403f9d06086a0c2e66))
17+
* **experiment:** return experiment URL in result ([#344](https://github.com/gentrace/gentrace-python/issues/344)) ([2c7950b](https://github.com/gentrace/gentrace-python/commit/2c7950b3012ae36d5d19d5bbcaea3330bb1d82bc))
18+
* **init:** warn on config changes in multiple init() ([#347](https://github.com/gentrace/gentrace-python/issues/347)) ([e5f66cb](https://github.com/gentrace/gentrace-python/commit/e5f66cb80896302acb9faa98a48831c698632630))
19+
* **interaction:** support default pipeline usage ([#346](https://github.com/gentrace/gentrace-python/issues/346)) ([a81de7a](https://github.com/gentrace/gentrace-python/commit/a81de7a8730a1da91e6f02acfce5a1a96b526192))
20+
* **warnings:** centralize and refactor warnings ([#341](https://github.com/gentrace/gentrace-python/issues/341)) ([eca923a](https://github.com/gentrace/gentrace-python/commit/eca923ab84f2693e8dd9845f345d309fc7951d32))
21+
22+
23+
### Bug Fixes
24+
25+
* **ci:** correct conditional ([7aeac82](https://github.com/gentrace/gentrace-python/commit/7aeac821ff1de2eabec960ef6c4293b5bd43fba0))
26+
* **ci:** release-doctor — report correct token name ([e5f4735](https://github.com/gentrace/gentrace-python/commit/e5f4735a859a0624ec303edfcab41b25363bf416))
27+
* **client:** correctly parse binary response | stream ([36e3af4](https://github.com/gentrace/gentrace-python/commit/36e3af4906699c892a054d574cdf9ec9778cfc72))
28+
* **client:** don't send Content-Type header on GET requests ([9a43359](https://github.com/gentrace/gentrace-python/commit/9a433594fca9ad6dc55d0961c0aff2616d47c08c))
29+
* **eval_dataset:** simplify test case conversion logic ([#349](https://github.com/gentrace/gentrace-python/issues/349)) ([7b7a451](https://github.com/gentrace/gentrace-python/commit/7b7a451e59b7323e901cb76b710e7598089b891b))
30+
* **parsing:** correctly handle nested discriminated unions ([e5b1210](https://github.com/gentrace/gentrace-python/commit/e5b1210ecb70f48b1a6fcb6c56c902eeb1da630d))
31+
* **parsing:** ignore empty metadata ([93edce5](https://github.com/gentrace/gentrace-python/commit/93edce534896516c663e0b5e1bae1562eb6646f6))
32+
* **parsing:** parse extra field types ([bb48320](https://github.com/gentrace/gentrace-python/commit/bb48320b8a174969e0a8e237f3724caeec54e90d))
33+
* **pipeline:** improve async validation scheduling ([#348](https://github.com/gentrace/gentrace-python/issues/348)) ([a9abf88](https://github.com/gentrace/gentrace-python/commit/a9abf88a3eea71cefbbea00a413a61f58020c29a))
34+
* **pipeline:** improve async validation scheduling ([#348](https://github.com/gentrace/gentrace-python/issues/348)) ([#352](https://github.com/gentrace/gentrace-python/issues/352)) ([26e6b2c](https://github.com/gentrace/gentrace-python/commit/26e6b2cecb246e0cee6006e13f9f4f3bd11c2929))
35+
* **tests:** fix: tests which call HTTP endpoints directly with the example parameters ([bbd629e](https://github.com/gentrace/gentrace-python/commit/bbd629e3aa5d8cd17bcbb5e204be5f192bd1349d))
36+
37+
38+
### Chores
39+
40+
* **ci:** change upload type ([9f4478a](https://github.com/gentrace/gentrace-python/commit/9f4478a61ef9bfa20e47d485b92c358d90c44b83))
41+
* **ci:** enable for pull requests ([40f97e3](https://github.com/gentrace/gentrace-python/commit/40f97e3771d078713024e471d8f520380729a32b))
42+
* **ci:** only run for pushes and fork pull requests ([4287211](https://github.com/gentrace/gentrace-python/commit/428721113ebd3dcbb9e98b9f7ddc94690c9c38f1))
43+
* fix deps ([0107e7a](https://github.com/gentrace/gentrace-python/commit/0107e7ab08751d51dd08775539b65a65bddf3f8f))
44+
* fix version ([4fa0928](https://github.com/gentrace/gentrace-python/commit/4fa0928bfee4b32a3bc55e5b0bb60f22a8e3ddf6))
45+
* get tests to work with hotfix ([#351](https://github.com/gentrace/gentrace-python/issues/351)) ([8f2e49e](https://github.com/gentrace/gentrace-python/commit/8f2e49eeb803867d26629df45a928eb096a1ca32))
46+
* **internal:** bump pinned h11 dep ([9d732a5](https://github.com/gentrace/gentrace-python/commit/9d732a5987d6b265bd3a33c77b3b1cae0c6078be))
47+
* **internal:** update conftest.py ([1ed8233](https://github.com/gentrace/gentrace-python/commit/1ed8233418094097f0c7be9869b36c7265492bdc))
48+
* **internal:** version bump ([3452596](https://github.com/gentrace/gentrace-python/commit/3452596693673801b642774cc2d6160768195839))
49+
* **package:** mark python 3.13 as supported ([59c5862](https://github.com/gentrace/gentrace-python/commit/59c5862b54bf7a394b1974777b524c07aea7e5dd))
50+
* **readme:** fix version rendering on pypi ([0bfd6e1](https://github.com/gentrace/gentrace-python/commit/0bfd6e1938a3d31a3dc9f3fa911cd883039ee300))
51+
* **readme:** update badges ([0df37ad](https://github.com/gentrace/gentrace-python/commit/0df37ad9cd044f19a27fd35fdcf81a20b6f50330))
52+
* **tests:** add tests for httpx client instantiation & proxies ([092a251](https://github.com/gentrace/gentrace-python/commit/092a251e699e18f328a994c67100b73750458d85))
53+
* **tests:** run tests in parallel ([a892e5b](https://github.com/gentrace/gentrace-python/commit/a892e5b80bdc19f2058fad7bae4935c051325cd1))
54+
* **tests:** skip some failing tests on the latest python versions ([bc643aa](https://github.com/gentrace/gentrace-python/commit/bc643aa42c733501dd174d748b4daff0d33d2e53))
55+
56+
57+
### Documentation
58+
59+
* **client:** fix httpx.Timeout documentation reference ([0ae37db](https://github.com/gentrace/gentrace-python/commit/0ae37db5b297ce830c9be70d9bb87d31b44d10d8))
60+
361
## 1.0.0-alpha.13 (2025-07-15)
462

563
Full Changelog: [v1.0.0-alpha.12...v1.0.0-alpha.13](https://github.com/gentrace/gentrace-python/compare/v1.0.0-alpha.12...v1.0.0-alpha.13)

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ The full API documentation can be found in [api.md](api.md).
1111

1212
```sh
1313
# install from PyPI
14-
pip install --pre gentrace-py
14+
pip install gentrace-py
1515
```
1616

1717
## Core Concepts
Lines changed: 46 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
1-
"""Simple dataset evaluation example with Gentrace."""
1+
"""Simple dataset evaluation example with Gentrace using local test cases."""
22

33
import os
44
import asyncio
5-
from typing import Any, Dict
5+
from typing import Optional
6+
from typing_extensions import TypedDict
67

78
from dotenv import load_dotenv
89
from openai import AsyncOpenAI
910

10-
from gentrace import TestInput, init, experiment, interaction, eval_dataset
11+
from gentrace import TestCase, TestInput, init, experiment, eval_dataset
1112

1213
load_dotenv()
1314

@@ -21,52 +22,62 @@
2122

2223
openai = AsyncOpenAI(api_key=os.getenv("OPENAI_API_KEY"))
2324

25+
class PromptInputs(TypedDict):
26+
prompt: str
2427

25-
async def process_ai_request(inputs: Dict[str, Any]) -> Dict[str, Any]:
26-
"""Process AI request using OpenAI."""
27-
# test_case.name # throwing exception
2828

29-
# Extract the prompt from inputs
30-
prompt = inputs.get("prompt", "Hey, how are you?")
3129

32-
# Call OpenAI
33-
response = await openai.chat.completions.create(
34-
model="gpt-4o-mini",
35-
messages=[{"role": "user", "content": prompt}],
36-
)
37-
38-
result = response.choices[0].message.content
30+
async def process_ai_request(test_case: TestCase) -> Optional[str]:
31+
print(f"Running test case: {test_case.name}")
3932

40-
return {
41-
"result": result,
42-
"metadata": {"model": response.model, "usage": response.usage.model_dump() if response.usage else None},
43-
}
33+
prompt = test_case.inputs.get("prompt")
4434

35+
response = await openai.chat.completions.create(
36+
model="gpt-4.1-nano",
37+
messages=[{"role": "user", "content": str(prompt)}],
38+
)
4539

46-
@interaction(pipeline_id=PIPELINE_ID, name="Process AI Request")
47-
async def traced_process_ai_request(inputs: Dict[str, Any]) -> Dict[str, Any]:
48-
"""Traced version of process_ai_request."""
49-
return await process_ai_request(inputs)
40+
return response.choices[0].message.content
5041

5142

5243
@experiment(pipeline_id=PIPELINE_ID)
5344
async def dataset_evaluation() -> None:
54-
"""Run evaluation on a dataset."""
55-
45+
"""Run evaluation on a dataset using type-safe TestInput objects with TypedDict."""
46+
47+
# Using TestInput with TypedDict for type safety
48+
test_cases = [
49+
TestInput[PromptInputs](
50+
name="greeting",
51+
inputs={"prompt": "Hello! How are you doing today?"}
52+
),
53+
TestInput[PromptInputs](
54+
name="factual_question",
55+
inputs={"prompt": "What is the capital of France?"}
56+
),
57+
TestInput[PromptInputs](
58+
name="math_problem",
59+
inputs={"prompt": "What is 25 * 4?"}
60+
),
61+
TestInput[PromptInputs](
62+
name="creative_writing",
63+
inputs={"prompt": "Write a haiku about artificial intelligence"}
64+
),
65+
TestInput[PromptInputs](
66+
inputs={"prompt": "Tell me a joke"}
67+
)
68+
]
69+
5670
await eval_dataset(
57-
data=[
58-
TestInput(name="greeting", inputs={"prompt": "Hello! How are you doing today?"}),
59-
TestInput(name="factual_question", inputs={"prompt": "What is the capital of France?"}),
60-
TestInput(name="math_problem", inputs={"prompt": "What is 25 * 4?"}),
61-
TestInput(name="creative_writing", inputs={"prompt": "Write a haiku about artificial intelligence"}),
62-
],
63-
interaction=traced_process_ai_request,
64-
max_concurrency=30,
71+
data=test_cases,
72+
schema=PromptInputs,
73+
interaction=process_ai_request,
6574
)
6675

6776
print("Dataset evaluation completed! Check your Gentrace dashboard for results.")
6877

6978

7079
if __name__ == "__main__":
71-
# Run the experiment
72-
asyncio.run(dataset_evaluation())
80+
result = asyncio.run(dataset_evaluation())
81+
82+
if result:
83+
print(f"Experiment URL: {result.url}")

examples/eval_dataset_simple.py

Lines changed: 20 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,13 @@
22

33
import os
44
import asyncio
5-
from typing import Any, Dict, List
5+
from typing import List, Optional
66

77
from dotenv import load_dotenv
88
from openai import AsyncOpenAI
9+
from pydantic import BaseModel
910

10-
from gentrace import TestCase, init, experiment, interaction, eval_dataset, test_cases_async
11+
from gentrace import TestCase, init, experiment, eval_dataset, test_cases_async
1112

1213
load_dotenv()
1314

@@ -21,32 +22,24 @@
2122

2223
openai = AsyncOpenAI(api_key=os.getenv("OPENAI_API_KEY"))
2324

25+
class QueryInputs(BaseModel):
26+
query: str
2427

25-
async def process_ai_request(inputs: Dict[str, Any]) -> Dict[str, Any]:
26-
"""Process AI request using OpenAI."""
27-
# test_case.name # throwing exception
2828

29-
# Extract the prompt from inputs
30-
prompt = inputs.get("prompt", "Hey, how are you?")
29+
async def process_ai_request(test_case: TestCase) -> Optional[str]:
30+
"""Process AI request using OpenAI."""
31+
# Print for each test case
32+
print(f"Processing test case: {test_case.name}")
33+
34+
query = test_case.inputs.get("query", "Hey, how are you?")
3135

3236
# Call OpenAI
3337
response = await openai.chat.completions.create(
34-
model="gpt-4o-mini",
35-
messages=[{"role": "user", "content": prompt}],
38+
model="gpt-4.1-nano",
39+
messages=[{"role": "user", "content": str(query)}],
3640
)
3741

38-
result = response.choices[0].message.content
39-
40-
return {
41-
"result": result,
42-
"metadata": {"model": response.model, "usage": response.usage.model_dump() if response.usage else None},
43-
}
44-
45-
46-
@interaction(pipeline_id=PIPELINE_ID, name="Process AI Request")
47-
async def traced_process_ai_request(inputs: Dict[str, Any]) -> Dict[str, Any]:
48-
"""Traced version of process_ai_request."""
49-
return await process_ai_request(inputs)
42+
return response.choices[0].message.content
5043

5144

5245
@experiment(pipeline_id=PIPELINE_ID)
@@ -60,13 +53,15 @@ async def fetch_test_cases() -> List[TestCase]:
6053

6154
await eval_dataset(
6255
data=fetch_test_cases,
63-
interaction=traced_process_ai_request,
64-
max_concurrency=30,
56+
schema=QueryInputs,
57+
interaction=process_ai_request,
6558
)
6659

6760
print("Dataset evaluation completed! Check your Gentrace dashboard for results.")
6861

6962

7063
if __name__ == "__main__":
71-
# Run the experiment
72-
asyncio.run(dataset_evaluation())
64+
result = asyncio.run(dataset_evaluation())
65+
66+
if result:
67+
print(f"Experiment URL: {result.url}")

examples/eval_simple.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,4 +44,5 @@ async def test_response_quality() -> Dict[str, Any]:
4444
if __name__ == "__main__":
4545
import asyncio
4646

47-
asyncio.run(test_response_quality())
47+
result = asyncio.run(test_response_quality())
48+
print(f"Experiment URL: {result.url}")

examples/genai-semantic-conventions.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ async def ask_question(question: str) -> str:
6060
# Set GenAI attributes according to semantic conventions
6161
span.set_attributes({
6262
"gen_ai.system": "openai",
63-
"gen_ai.request.model": "gpt-4o-mini",
63+
"gen_ai.request.model": "gpt-4.1-nano",
6464
"gen_ai.operation.name": "chat",
6565
"service.name": "genai-semantic-example",
6666
})
@@ -82,7 +82,7 @@ async def ask_question(question: str) -> str:
8282
print("Sending chat completion request...")
8383

8484
completion = await client.chat.completions.create(
85-
model="gpt-4o-mini",
85+
model="gpt-4.1-nano",
8686
messages=[
8787
{"role": "system", "content": system_message},
8888
{"role": "user", "content": question},
@@ -118,7 +118,7 @@ async def simulate_tool_call() -> str:
118118
try:
119119
span.set_attributes({
120120
"gen_ai.system": "openai",
121-
"gen_ai.request.model": "gpt-4o-mini",
121+
"gen_ai.request.model": "gpt-4.1-nano",
122122
"gen_ai.operation.name": "chat",
123123
"service.name": "genai-semantic-example",
124124
})
@@ -187,7 +187,7 @@ async def simulate_tool_call() -> str:
187187
]
188188

189189
completion = await client.chat.completions.create(
190-
model="gpt-4o-mini",
190+
model="gpt-4.1-nano",
191191
messages=[
192192
ChatCompletionUserMessageParam(role="user", content=user_question),
193193
ChatCompletionAssistantMessageParam(

examples/openai_simple.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323

2424
@interaction(name="chat_completion", pipeline_id=os.getenv("GENTRACE_PIPELINE_ID", ""))
2525
def chat_with_openai(prompt: str) -> str:
26-
response = client.chat.completions.create(model="gpt-4o-mini", messages=[{"role": "user", "content": prompt}])
26+
response = client.chat.completions.create(model="gpt-4.1-nano", messages=[{"role": "user", "content": prompt}])
2727
return response.choices[0].message.content or ""
2828

2929

examples/pydantic_ai_simple.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,14 +25,14 @@
2525

2626
# Create a simple Pydantic AI agent
2727
agent = Agent(
28-
OpenAIModel("gpt-4o-mini"),
28+
OpenAIModel("gpt-4.1-nano"),
2929
system_prompt="You are a helpful assistant that gives concise answers.",
3030
)
3131

3232

3333
@interaction(name="pydantic_ai_chat", pipeline_id=os.getenv("GENTRACE_PIPELINE_ID", ""))
3434
async def chat_with_agent(prompt: str) -> str:
35-
result = await agent.run(prompt)
35+
result = await agent.run(prompt) # type: ignore
3636
return result.output
3737

3838

pyproject.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "gentrace-py"
3-
version = "1.0.0-alpha.13"
3+
version = "1.0.1"
44
description = "The official Python library for the gentrace API"
55
dynamic = ["readme"]
66
license = "MIT"
@@ -157,7 +157,7 @@ testpaths = ["tests"]
157157
addopts = "--tb=short -n auto"
158158
xfail_strict = true
159159
asyncio_mode = "auto"
160-
asyncio_default_fixture_loop_scope = "session"
160+
asyncio_default_fixture_loop_scope = "function"
161161
filterwarnings = [
162162
"error"
163163
]

0 commit comments

Comments
 (0)