Skip to content

Commit 5f3093d

Browse files
authored
Pipeline maintainence (#451)
1 parent bfb94a8 commit 5f3093d

File tree

7 files changed

+141
-2
lines changed

7 files changed

+141
-2
lines changed

.github/workflows/tests.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,10 +57,13 @@ jobs:
5757
uses: pre-commit/action@v3.0.1
5858
- name: Check Python headers
5959
run: uv run --locked --no-sync scripts/check_headers.py
60+
if: matrix.setup == 'fast'
6061
- name: Run Black
6162
run: uv run --locked --no-sync black --check .
63+
if: matrix.setup != 'next'
6264
- name: Run isort
6365
run: uv run --locked --no-sync isort --check-only .
66+
if: matrix.setup != 'next'
6467
- name: Run pyright (fast)
6568
run: uv run --locked --no-sync pyright -p pyrightconfig.fast.json
6669
if: matrix.setup == 'fast'

agentlightning/emitter/annotation.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -246,7 +246,11 @@ def _record_auto_outputs(recording_ctx: SpanRecordingContext, result: Any) -> No
246246
flattened = flatten_attributes({LightningSpanAttributes.OPERATION_OUTPUT.value: result})
247247
recording_ctx.record_attributes(sanitize_attributes(flattened))
248248

249-
if asyncio.iscoroutinefunction(fn) or inspect.iscoroutinefunction(fn):
249+
if inspect.iscoroutinefunction(fn) or (
250+
# For backwards compatibility.
251+
hasattr(asyncio, "iscoroutinefunction")
252+
and asyncio.iscoroutinefunction(fn) # type: ignore
253+
):
250254

251255
@functools.wraps(fn)
252256
async def async_wrapper(*args: Any, **kwargs: Any) -> Any:

agentlightning/emitter/reward.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,11 @@ def wrap_result(result: Optional[float]) -> _RewardSpanData:
9292
return {"type": "reward", "value": float(result)}
9393

9494
# Check if the function is async
95-
is_async = asyncio.iscoroutinefunction(fn) or inspect.iscoroutinefunction(fn)
95+
is_async = inspect.iscoroutinefunction(fn) or (
96+
# For backwards compatibility.
97+
hasattr(asyncio, "iscoroutinefunction")
98+
and asyncio.iscoroutinefunction(fn) # type: ignore
99+
)
96100

97101
if is_async:
98102

agentlightning/instrumentation/weave.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -424,6 +424,29 @@ def score_list(self, req: tsi.ScoreListReq) -> Iterator[tsi.ScoreReadRes]:
424424
def score_delete(self, req: tsi.ScoreDeleteReq) -> tsi.ScoreDeleteRes:
425425
return tsi.ScoreDeleteRes(num_deleted=0)
426426

427+
# Experimental unstable APIs
428+
# We don't support these APIs yet.
429+
def annotation_queue_create(self, *args: Any, **kwargs: Any) -> Any:
430+
raise NotImplementedError()
431+
432+
def annotation_queues_query_stream(self, *args: Any, **kwargs: Any) -> Any:
433+
raise NotImplementedError()
434+
435+
def annotation_queue_read(self, *args: Any, **kwargs: Any) -> Any:
436+
raise NotImplementedError()
437+
438+
def annotation_queue_add_calls(self, *args: Any, **kwargs: Any) -> Any:
439+
raise NotImplementedError()
440+
441+
def annotation_queues_stats(self, *args: Any, **kwargs: Any) -> Any:
442+
raise NotImplementedError()
443+
444+
def annotation_queue_items_query(self, *args: Any, **kwargs: Any) -> Any:
445+
raise NotImplementedError()
446+
447+
def annotator_queue_items_progress_update(self, *args: Any, **kwargs: Any) -> Any:
448+
raise NotImplementedError()
449+
427450

428451
# Module-level storage for originals
429452
_original_init_weave_get_server: Callable[..., Any] | None = None

agentlightning/store/collection/mongo.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -663,6 +663,9 @@ async def upsert(self, items: Sequence[T_model], update_fields: Sequence[str] |
663663
return_document=ReturnDocument.AFTER,
664664
)
665665

666+
if result_doc is None: # pyright: ignore[reportUnnecessaryComparison]
667+
raise RuntimeError(f"Upsert resulted in no document for filter: {pk_filter}")
668+
666669
# Because upsert=True, result_doc is guaranteed to be not None
667670
new_item = self._model_validate_item(result_doc)
668671
upserted_items.append(new_item)

scripts/cleanup_aoai.py

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
# Copyright (c) Microsoft. All rights reserved.
2+
3+
import os
4+
5+
import requests
6+
from openai import OpenAI
7+
8+
# Most common Azure OpenAI setup:
9+
# AZURE_OPENAI_ENDPOINT="https://<resource>.openai.azure.com"
10+
# AZURE_OPENAI_API_KEY="..."
11+
# Optional (only if your endpoint requires it):
12+
# AZURE_OPENAI_API_VERSION="2025-xx-xx"
13+
#
14+
# This script treats "delete finetune job" as "cancel finetune job"
15+
# because fine-tune jobs are typically cancellable, not deletable.
16+
17+
18+
def _client() -> OpenAI:
19+
# This script assumes AZURE_OPENAI_ENDPOINT and AZURE_OPENAI_API_KEY are set in the environment.
20+
endpoint = os.environ["AZURE_OPENAI_ENDPOINT"]
21+
api_key = os.environ["AZURE_OPENAI_API_KEY"]
22+
return OpenAI(api_key=api_key, base_url=endpoint)
23+
24+
25+
def list_data_files():
26+
c = _client()
27+
return c.files.list(limit=100)
28+
29+
30+
def list_finetune_jobs():
31+
c = _client()
32+
return c.fine_tuning.jobs.list(limit=100)
33+
34+
35+
def delete_data_file(file_id: str):
36+
c = _client()
37+
return c.files.delete(file_id)
38+
39+
40+
def cancel_finetune_job(job_id: str):
41+
c = _client()
42+
return c.fine_tuning.jobs.cancel(job_id)
43+
44+
45+
def delete_finetune_job(job_id: str):
46+
# This script assumes AZURE_OPENAI_ENDPOINT and AZURE_OPENAI_API_KEY are set in the environment.
47+
endpoint = os.environ["AZURE_OPENAI_ENDPOINT"].rstrip("/")
48+
api_key = os.environ["AZURE_OPENAI_API_KEY"]
49+
root = endpoint.split("/openai")[0]
50+
51+
url = f"{root}/openai/fine_tuning/jobs/{job_id}"
52+
params = {"api-version": os.environ["AZURE_OPENAI_API_VERSION"]}
53+
54+
resp = requests.delete(url, headers={"api-key": api_key}, params=params, timeout=60)
55+
resp.raise_for_status()
56+
return resp.content
57+
58+
59+
if __name__ == "__main__":
60+
# Quick demo: print IDs you could delete
61+
jobs = list_finetune_jobs().data
62+
files = list_data_files().data
63+
64+
print("JOBS:")
65+
for j in jobs:
66+
print(f" {j.id} {getattr(j, 'status', '')} {getattr(j, 'model', '')}")
67+
68+
print("\nFILES:")
69+
for f in files:
70+
print(f" {f.id} {getattr(f, 'filename', '')} {getattr(f, 'status', '')}")
71+
72+
# Delete them all WITHOUT CONFIRMATION!
73+
for j in jobs:
74+
print(f"Deleting job {j.id}")
75+
try:
76+
if j.status == "running":
77+
cancel_finetune_job(j.id)
78+
delete_finetune_job(j.id)
79+
except Exception as exc:
80+
print(f" Error deleting job {j.id}: {exc}")
81+
82+
for f in files:
83+
print(f"Deleting file {f.id}")
84+
try:
85+
delete_data_file(f.id)
86+
except Exception as exc:
87+
print(f" Error deleting file {f.id}: {exc}")

0 commit comments

Comments
 (0)