Repository navigation
Conversation
The Node OTLP exporter streams with Transfer-Encoding: chunked and sends no Content-Length. The Receiver read Content-Length only, so every Node export came back 400 with zero spans; two TH-8103 children had to put a de-chunking relay in front of it. Receiver now accepts both framings. It also records one entry per accepted export (path, lower-cased headers, flattened resource attributes) via requests(), so a contract test can assert X-Api-Key/X-Secret-Key and project_name through the shared harness instead of a private recorder. Verified: 6 harness tests pass, and the TanStack example's real Node exporter delivered 4 chunked exports (4 spans, collector path, both auth headers, project_name/project_type) with no relay. Refs: TH-8339, TH-8103
Add python/examples/baseten: trace Baseten Model APIs Chat Completions made with the official openai SDK (base_url https://inference.baseten.co/v1) by using the existing traceai-openai instrumentor. No Baseten package. - src/app.py: register() + OpenAIInstrumentor before the client; the Baseten key goes only to the OpenAI client, Future AGI keys only to the tracer. check_base_url() refuses the Anthropic-beta root (no /v1) and dedicated-deployment hosts (model-*.api.baseten.co); it never rewrites. - tests: loopback contract on the shared harness Receiver: request URL and bearer key at the documented host (MockTransport), one LLM span, model, usage (omitted when absent), provider label openai (D2), project resource and FI headers, no vendor key in any exported field, streaming, 401 error span, FI_HIDE_INPUTS/OUTPUTS with control, using_session, app subprocess under a socket guard, refused URLs exit 2 before tracing. - Pins current traceai-openai behaviour: streamed and failed calls have no model attribute; the default stream has no usage attributes. - README: install, configure, run, code, what you see, Baseten specifics, privacy, limits, tests and tested versions. approved: Nikhil 2026-10-03 blanket Refs: TH-8310
…EADME) From pr-reviewer t_6453b6cd (APPROVED, P3 follow-ups): - R1: check_base_url compares the host without an absolute-FQDN trailing dot, so https://inference.baseten.co. and model-*.api.baseten.co. are refused too (the URL is still returned/refused unchanged, never rewritten). Tests pin trailing-dot, upper-case, userinfo and port variants; the two trailing-dot cases failed before this change. - R2: test_hide_outputs gains a non-hidden control. - R3: README names gen_ai.request.model and notes the requested model stays in gen_ai.request.parameters on streamed and failed spans; tests pin it. - R4: requirements.txt comment no longer mentions a worktree. - R6: test_main_rejects_url_before_tracing replaces a vacuous fake-server check with a client-constructor spy. approved: Nikhil 2026-10-03 blanket Refs: TH-8310
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This PR adds a Baseten Model APIs recipe at
python/examples/baseten/(Linear TH-8310, parent TH-8103). Customers who call Baseten's OpenAI-compatible Chat Completions endpoint (https://inference.baseten.co/v1) with the officialopenaiSDK get traces through the existingtraceai-openaiinstrumentor. It adds no package and no instrumentor (decision D1), and changes nothing outsidepython/examples/baseten/.src/app.py: callsregister()and instruments withOpenAIInstrumentorbefore creating the client. The Baseten key goes only to the OpenAI client; the Future AGI keys go only to the tracer.check_base_url()refuses two Baseten URLs that need a different recipe and never rewrites a URL:https://inference.baseten.cowith no/v1;model-*.api.baseten.co.main()returns 2 before tracing or any network call when it refuses a URL.requirements.txt: the tested pinsopenai==3.24.0,traceAI-openai==0.1.10andfi-instrumentation-otel==1.1.0.README.md: install, configure (which key goes where), run, code, what you see in Future AGI, Baseten specifics (x-session-affinityis not a Future AGI session id;using_sessionis), privacy, limits, test command and tested versions.tests/: a loopback contract on the shared harnessReceiver(test(harness): shared OTLP harness for TH-8103 contract tests #203), plus a socket guard for subprocesses and a fake OpenAI server.What the tests pin
Every test runs offline. In-process tests use
httpx.MockTransportat the documented host, and subprocess tests use a fake on 127.0.0.1 under a guard that refuses non-loopback DNS and connects. The guard has a negative control.Request:
https://inference.baseten.co/v1/chat/completions;Authorization: Bearer <Baseten key>and no Future AGI header.Exported span:
ChatCompletionLLM span, exported to/tracer/v1/traceswithX-Api-Key/X-Secret-Key, theproject_nameresource andproject_type=observe;gen_ai.request.modelis the model id the response returns;gen_ai.provider.nameisopenai(D2). The instrumentor labels every non-OpenAI host this way, and the test pins it so that a later shared fix shows up;Behaviour:
FI_HIDE_INPUTS/FI_HIDE_OUTPUTSremove a unique marker from the export, and a control run without hiding finds it;using_session("s-1")setssession.id, andx-session-affinitydoes not;openai.AuthenticationError, a span with ERROR status and an exception event, with no key in the recorded text;--stream, with the guard log empty and a sentinel showing the guard was installed;ValueErrorwithout being rewritten;main()exits 2 before a client or tracer is created.Current
traceai-openaibehaviour, pinned and stated in the README (D-F5):gen_ai.request.model, because the instrumentor takes the model only from a non-streamed response. The requested model is still insidegen_ai.request.parameters;The shared fix is tracked separately (Linear TH-8402) and is not copied into this recipe.
Tests (exact head
34ed9de8daab7fde731450ac106859e7a5316d34, clean tree, actual exit codes + JUnit)openaitraceAI-openai==0.1.10+fi-instrumentation-otel==1.1.0(imported from site-packages, no repo source on the path)The command is in the README. No files outside
python/examples/baseten/changed, and the head did not move during the run. The first commit,0141574, had the same 6/6 matrix with 32 tests.Decisions (approved: Nikhil 2026-10-03 blanket)
traceai-openai, not atraceai-basetenpackage.openai. A host-to-provider mapping would be one shared change intraceai-openai, not a per-logo change.traceai-openai(TH-8402).BASETEN_API_KEYare unchanged.Not covered
Stacked on #203 (shared OTLP test harness,
3eaadc8), which must land first. Not for merge until review is complete.Review status
Review r1 (pr-reviewer
t_6453b6cd, claude-opus-5-5, at0141574): APPROVED, with no P1 or P2 findings. Six P3 items were raised. Fixed in34ed9de:test_hide_outputshad no non-hidden control.gen_ai.request.modeland notes the requested model stays ingen_ai.request.parameters.requirements.txtcomment mentioned a worktree.Kept as P3: R5, optional app hardening (FI key check, a
force_flush()result warning). The reviewer's context notes also stand: recipe tests are not wired into CI, andregister()'s signal handlers exit 0.Verification r1 (pr-verifier
t_dab442fa, claude-opus-5-5, at34ed9de): VERIFIED, with no blocking findings. R1–R4 and R6 are confirmed fixed, and R5 is accepted as P3. New P3 items, kept as follow-ups with no third fix round:check_base_urlis a best-effort guard. It compares the URL as urllib parses it, so dot-segment spellings (/v1/..,/.) and IDNA label separators can still reach a refused surface after httpx normalizes the URL. It is a guard, not a security boundary.gen_ai.request.parametersis dropped whenFI_HIDE_LLM_INVOCATION_PARAMETERS=true.Context notes from the verifier:
OPENAI_ORG_ID/OPENAI_PROJECT_ID/OPENAI_CUSTOM_HEADERSfrom the environment and would send them to Baseten;"usage": nullmay raise inside the shared accumulator (trigger unverified; noted on TH-8402);Video demo
A narrated CLI walkthrough, 6:21, recorded at the verified head
34ed9de(1080p H.264/AAC, burned captions, 10 embedded chapters). The video, captions, transcript, chapters, preview and both media-verification notes are private attachments on the Linear issue: TH-8310 (Future AGI workspace access required). Every command chapter runs./run_demo.sh <chapter>live in a real terminal and shows[exit 0]on screen.34ed9de, the six recipe files and the env variable namesFI_HIDE_INPUTS/FI_HIDE_OUTPUTSversus control; the provider still receives the promptNot shown: a live Baseten call, a running fi-collector, authentication, storage or the trace view. All runs use loopback fakes, and the narration says so. Static waits of 2 s or more were cut; nothing was sped up and no output was edited.