@@ -147,6 +147,179 @@ for await (const chunk of stream) {
147147
148148The workforce chat allows you to leverage multiple specialized agents working together to provide comprehensive responses to your queries.
149149
150+ ## Tracing
151+
152+ Send agent runs to AgentX so they show up in Observe / Live Traces. Nested spans link into a
153+ real tree (one row per LLM call, tool call and retrieval), so a multi-step run is inspectable
154+ step by step.
155+
156+ ``` typescript
157+ import { AgentX } from " @agentx-ai/agentx-js" ;
158+
159+ const client = new AgentX (); // reads AGENTX_API_KEY
160+
161+ const answer = await client .tracer .withSpan (
162+ " support-agent" ,
163+ { input: { query: question }, framework: " openai" },
164+ async (span ) => {
165+ // Retrievals and tool calls made inside the block attach to it automatically
166+ const docs = await client .tracer .traceRetrieval (" kb_search" , { query: question }, async (r ) => {
167+ r .docCount = 3 ;
168+ return knowledgeBase .search (question );
169+ });
170+
171+ const policy = await client .tracer .traceToolCall (" policy_lookup" , { input: { topic } }, async (t ) => {
172+ t .output = await lookupPolicy (topic );
173+ return t .output ;
174+ });
175+
176+ const reply = await callLlm (question , docs , policy );
177+ span .output = reply ;
178+ return reply ;
179+ }
180+ );
181+
182+ await client .tracer .flush (); // traces are queued in the background - flush before exiting
183+ ```
184+
185+ Need the trace id back (for example to attach it to an evaluation result)? Open the span with
186+ ` sync: true ` :
187+
188+ ``` typescript
189+ const span = client .tracer .trace (" support-agent" , { sync: true });
190+ span .output = await callLlm (question );
191+ const traceId = await span .end (); // the ingested trace's id
192+ ```
193+
194+ Other tracing entry points:
195+
196+ - ` client.tracer.wrap("name", fn) ` - wrap a function so every call is traced
197+ - ` client.tracer.useSpan(span, fn) ` - attach work started in another async context to a span
198+ - ` span.childSpan(name, { startTime, endTime, ... }) ` - emit a child row with your own timing
199+ - ` span.recordLlmCall({ durationMs, model, inputTokens, outputTokens }) ` - one LLM-call child row
200+ - ` client.tracer.evaluateTrace(traceId, datasetId) ` - score an ingested trace, agent not re-run
201+ - ` client.ping() ` - fail fast at startup on a bad key or base URL (trace delivery is silent)
202+
203+ ## Evaluations
204+
205+ Build a dataset, run your own agent against it, and get it scored and analysed.
206+
207+ ``` typescript
208+ const client = new AgentX ();
209+
210+ const dataset = await client .evaluations .datasets
211+ .builder (" Support QA" , { numberOfRequests: 3 , judgeModel: " gpt-5.5" })
212+ .addCase (" How do I reset my password?" , {
213+ expectedResults: " Point the user at Settings > Security." ,
214+ expectedTools: [" kb_search" ], // scored as a trajectory match against the linked trace
215+ })
216+ .addCase (" What are your support hours?" , { expectedResults: " 9-5 on weekdays." })
217+ .publish ();
218+
219+ const report = await client .evaluations
220+ .run ({
221+ datasetId: dataset .id ,
222+ subject: { displayName: " Support bot" , framework: " openai" , runtime: " local" },
223+ })
224+ .execute (async (evaluationCase ) => {
225+ const span = client .tracer .trace (" support-agent" , { sync: true });
226+ span .output = await myAgent (evaluationCase .query );
227+ const traceId = await span .end ();
228+ return { output: span .output , traceId }; // links the run's result to the full trace
229+ })
230+ .finalize ()
231+ .analyze ();
232+
233+ console .log (report .averageRating , report .recommendations );
234+ ```
235+
236+ Your ` execute ` function can return a plain string, an object
237+ (` { output, traceId, retrievalContext, metadata, inputTokens, outputTokens, error } ` ), or one of
238+ the bundled adapters:
239+
240+ ``` typescript
241+ import { HttpEndpointAdapter , PrecomputedAdapter } from " @agentx-ai/agentx-js" ;
242+
243+ // Call your own service for every case
244+ .execute (new HttpEndpointAdapter ({ url: " http://localhost:8080/eval" }))
245+
246+ // Or score answers you already have
247+ .execute (new PrecomputedAdapter ({ " case-0" : " Go to Settings > Security." }))
248+ ```
249+
250+ Live rating stats are available as soon as results are submitted, without waiting for
251+ ` .analyze() ` :
252+
253+ ``` typescript
254+ const run = await client .evaluations .run ({ datasetId , subject }).execute (myAgent ).finalize ();
255+ console .log (run .runId , run .averageRating , run .ratedCount );
256+ console .log (await run .fetchResults ()); // per-result rows: rating, justification, trace ids
257+ ```
258+
259+ Datasets can also be loaded from CSV (` query ` , ` expected_results ` , ` expected_capabilities ` ,
260+ ` expected_knowledge_base ` , ` expected_delegations ` ; list columns are semicolon-separated):
261+
262+ ``` typescript
263+ await client .evaluations .datasets .fromCsv (" ./cases.csv" , " Support QA" ).publish ();
264+ ```
265+
266+ Reusable grading configs live on ` client.evaluations.settings ` and can be pointed at any
267+ dataset:
268+
269+ ``` typescript
270+ const settings = await client .evaluations .settings
271+ .builder (" Strict grading" , { evaluationCriteria: " Answers must cite a policy." , judgeModel: " gpt-5.5" })
272+ .publish ();
273+
274+ await client .evaluations
275+ .run ({ datasetId , subject , evaluationSettingsId: settings .id })
276+ .execute (myAgent )
277+ .finalize ();
278+ ```
279+
280+ ## CI/CD gates
281+
282+ Block a merge when quality drops.
283+
284+ ``` typescript
285+ // Gate a run you just executed (or any finalized run by id)
286+ const gate = await client .evaluations
287+ .run ({ datasetId , subject })
288+ .execute (myAgent )
289+ .finalize ()
290+ .gate ({ failUnder: 7 , noRegression: true });
291+
292+ if (! gate .passed ) {
293+ process .exit (gate .exitCode );
294+ }
295+ ```
296+
297+ For CI-enabled datasets, the whole lifecycle is one call - it creates the run, asks your agent
298+ each question, submits the answers for scoring and returns the gate decision:
299+
300+ ``` typescript
301+ const result = await client .tracer .runEval (datasetId , (query ) => myAgent (query ), {
302+ agentName: " support-bot" ,
303+ concurrency: 4 ,
304+ failOnGate: true , // throws CIGateFailure when the gate fails
305+ gitContext: { branch: process .env .GITHUB_REF_NAME , commit_sha: process .env .GITHUB_SHA },
306+ });
307+
308+ console .log (result .gate , result .passRate , result .violations );
309+ ```
310+
311+ ## Self-hosted engines
312+
313+ Point the SDK at a self-hosted AgentX engine with ` baseUrl ` (or ` AGENTX_API_BASE_URL ` ):
314+
315+ ``` typescript
316+ const client = new AgentX (process .env .AGENTX_API_KEY , {
317+ baseUrl: " http://localhost:4700/api/v1" ,
318+ workspaceId: " optional-workspace-id" ,
319+ });
320+ await client .ping (); // verifies the URL and key before anything is traced
321+ ```
322+
150323## TypeScript Support
151324
152325This SDK is written in TypeScript and provides full type definitions. All classes, interfaces, and methods are properly typed for better development experience.
@@ -160,13 +333,45 @@ The main client class for interacting with the AgentX API.
160333#### Constructor
161334
162335- ` new AgentX(apiKey?: string) ` - Creates a new AgentX client instance
336+ - ` new AgentX(apiKey?: string, options?: AgentXOptions) ` - ` { baseUrl, workspaceId, flushTracesOnExit } `
337+ - ` AgentX.fromEnv(options?) ` - Creates a client from ` AGENTX_API_KEY ` / ` AGENTX_API_BASE_URL `
163338
164339#### Methods
165340
166341- ` getAgent(id: string): Promise<Agent> ` - Get a specific agent by ID
167342- ` listAgents(): Promise<Agent[]> ` - List all agents
168343- ` getProfile(): Promise<any> ` - Get the current user's profile
169- - ` static listWorkforces(): Promise<Workforce[]> ` - List all workforces
344+ - ` listWorkforces(): Promise<Workforce[]> ` - List all workforces
345+ - ` ping(): Promise<{ ok: true; baseUrl: string }> ` - Verify the base URL and API key
346+
347+ #### Properties
348+
349+ - ` tracer: Tracer ` - Tracing (see [ Tracing] ( #tracing ) )
350+ - ` evaluations: EvaluationsRunner ` - Evaluations (see [ Evaluations] ( #evaluations ) )
351+
352+ ### Tracer
353+
354+ - ` withSpan(name, options?, fn) ` - Run ` fn ` inside a span, closing it automatically
355+ - ` trace(name, options?): TraceSpan ` - Open a span you close yourself with ` span.end() `
356+ - ` wrap(name, fn, options?) ` - Wrap a function so every call is traced
357+ - ` useSpan(span, fn) ` - Attach work from another async context to a span
358+ - ` traceToolCall(name, options?, fn) ` / ` recordToolCall(name, options?) ` - Record a tool call
359+ - ` traceRetrieval(name, options?, fn) ` / ` recordRetrieval(name, options?) ` - Record a retrieval
360+ - ` flush(timeoutMs?) ` - Wait for queued traces to be delivered
361+ - ` evaluateTrace(traceId, datasetId, options?) ` - Score an ingested trace against a dataset
362+ - ` runEval(datasetId, agentFn, options?) ` - Full CI/CD evaluation lifecycle in one call
363+ - ` createCiRun ` / ` submitResult ` / ` finalizeCiRun ` / ` getCiRun ` - The CI lifecycle, step by step
364+
365+ ### EvaluationsRunner (` client.evaluations ` )
366+
367+ - ` run({ datasetId, subject, evaluationSettingsId? }) ` - Start a run; chain ` .execute(fn) ` ,
368+ ` .finalize() ` , ` .analyze() ` , ` .gate() `
369+ - ` datasets.builder(name, config?) ` / ` datasets.fromCsv(path, name, config?) ` /
370+ ` datasets.fromRows(rows, name, config?) ` / ` datasets.get(id) ` / ` datasets.list() `
371+ - ` settings.builder(name, config?) ` / ` settings.get(id) ` / ` settings.list() `
372+ - ` listModels(provider?) ` - Model ids valid for judges and portability comparisons
373+ - ` getRun(runId) ` / ` getReport(runId) ` / ` getAnalysisStatus(runId) ` / ` gateRun(runId, options?) `
374+ - ` listGates() ` / ` simulateConversation(options) ` - self-hosted engines
170375
171376### Agent
172377
@@ -233,6 +438,11 @@ The SDK throws descriptive errors for various failure scenarios:
233438- API errors (with status codes)
234439- Invalid data
235440
441+ Tracing and evaluations calls throw typed errors that all extend ` Error ` , so existing
442+ ` catch (error) ` blocks keep working: ` AgentXAuthError ` , ` AgentXConnectionError ` ,
443+ ` AgentXAPIError ` (carries ` statusCode ` ), ` AgentXValidationError ` , ` DatasetNotFound ` ,
444+ ` CINotEnabled ` and ` CIGateFailure ` .
445+
236446``` typescript
237447try {
238448 const agent = await client .getAgent (" invalid-id" );
@@ -244,6 +454,9 @@ try {
244454## Environment Variables
245455
246456- ` AGENTX_API_KEY ` - Your AgentX API key (optional if passed to constructor)
457+ - ` AGENTX_API_BASE_URL ` - API base URL, e.g. ` http://localhost:4700/api/v1 ` for a self-hosted
458+ engine (optional; defaults to ` https://api.agentx.so/api/v1 ` )
459+ - ` AGENTX_WORKSPACE_ID ` - Scope datasets, runs and traces to a workspace (optional)
247460
248461## Automated Publishing
249462
0 commit comments