@agent-ledger/sdk-ts 0.0.4 → 0.0.5

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.
package/README.md CHANGED
@@ -2,6 +2,8 @@
2
2
 
3
3
  Official TypeScript client for Agent Ledger. Use it to instrument any Node.js/Edge agent with structured telemetry, stream session events, and receive immediate feedback when budget guardrails block spending.
4
4
 
5
+ Portal: https://agent-ledger.thabo.xyz/
6
+
5
7
  ## Table of contents
6
8
 
7
9
  1. [Features](#features)
@@ -44,40 +46,53 @@ yarn add @agent-ledger/sdk-ts
44
46
  ## Getting started
45
47
 
46
48
  ```ts
47
- import { AgentLedgerClient, BudgetGuardrailError } from "@agent-ledger/sdk-ts";
49
+ import {
50
+ AgentLedgerClient,
51
+ BudgetGuardrailError,
52
+ withSession,
53
+ instrumentTool,
54
+ } from "@agent-ledger/sdk-ts";
48
55
 
49
56
  const ledger = new AgentLedgerClient({
50
57
  apiKey: process.env.AGENT_LEDGER_API_KEY!,
51
58
  });
52
59
 
53
60
  export async function runSupportAgent(prompt: string) {
54
- const sessionId = await ledger.startSession("support-bot");
55
-
56
- try {
57
- // 1. Run your own LLM/tool logic
58
- const response = await callModel(prompt);
59
-
60
- // 2. Log the LLM call (Agent Ledger auto-computes spend from provider/model/tokens)
61
- await ledger.logLLMCall(sessionId, {
62
- stepIndex: 0,
63
- provider: "openai",
64
- model: "gpt-4o-mini",
65
- prompt,
66
- response: response.text,
67
- tokensIn: response.usage.inputTokens,
68
- tokensOut: response.usage.outputTokens,
69
- latencyMs: response.latencyMs,
70
- });
71
-
72
- await ledger.endSession(sessionId, "success");
73
- return response.text;
74
- } catch (err) {
75
- if (err instanceof BudgetGuardrailError) {
76
- console.warn("Budget exceeded", err.details);
61
+ return withSession(ledger, "support-bot", async ({ sessionId, steps }) => {
62
+ try {
63
+ // 1. Run your own LLM logic
64
+ const response = await callModel(prompt);
65
+
66
+ // 2. Log the LLM call (Agent Ledger auto-computes spend from provider/model/tokens)
67
+ await ledger.logLLMCall(sessionId, {
68
+ stepIndex: steps.next(),
69
+ provider: "openai",
70
+ model: "gpt-4o-mini",
71
+ prompt,
72
+ response: response.text,
73
+ tokensIn: response.usage.inputTokens,
74
+ tokensOut: response.usage.outputTokens,
75
+ latencyMs: response.latencyMs,
76
+ });
77
+
78
+ // 3. Example tool wrapper (automatically logs tool_call + tool_result)
79
+ await instrumentTool({
80
+ ledger,
81
+ sessionId,
82
+ stepIndex: steps.next(),
83
+ toolName: "weather",
84
+ toolInput: { city: "Boston" },
85
+ run: async () => fetchWeather("Boston"),
86
+ });
87
+
88
+ return response.text;
89
+ } catch (err) {
90
+ if (err instanceof BudgetGuardrailError) {
91
+ console.warn("Budget exceeded", err.details);
92
+ }
93
+ throw err;
77
94
  }
78
- await ledger.endSession(sessionId, "error", { errorMessage: (err as Error).message });
79
- throw err;
80
- }
95
+ });
81
96
  }
82
97
  ```
83
98
 
package/dist/index.d.ts CHANGED
@@ -2,6 +2,8 @@ export type EventType = "llm_call" | "tool_call" | "tool_result" | "session_star
2
2
  export interface AgentLedgerClientOptions {
3
3
  apiKey: string;
4
4
  baseUrl?: string;
5
+ fetch?: typeof fetch;
6
+ defaultHeaders?: Record<string, string>;
5
7
  }
6
8
  export type BudgetGuardrailDetails = {
7
9
  agentName: string;
@@ -18,12 +20,14 @@ export declare class BudgetGuardrailError extends Error {
18
20
  export declare class AgentLedgerClient {
19
21
  private apiKey;
20
22
  private baseUrl;
23
+ private fetchImpl;
24
+ private defaultHeaders;
21
25
  constructor(opts: AgentLedgerClientOptions);
22
26
  startSession(agentName: string): Promise<string>;
23
27
  endSession(sessionId: string, status: "success" | "error", opts?: {
24
28
  errorMessage?: string;
25
29
  }): Promise<void>;
26
- logEvents(sessionId: string, events: any[]): Promise<void>;
30
+ logEvents(sessionId: string, events: AnyEvent[] | Array<Record<string, any>>): Promise<void>;
27
31
  logLLMCall(sessionId: string, e: Omit<LlmCallEvent, "type">): Promise<void>;
28
32
  logToolCall(sessionId: string, e: Omit<ToolCallEvent, "type">): Promise<void>;
29
33
  logToolResult(sessionId: string, e: Omit<ToolResultEvent, "type">): Promise<void>;
@@ -53,3 +57,22 @@ export type ToolResultEvent = {
53
57
  latencyMs: number;
54
58
  };
55
59
  export type AnyEvent = LlmCallEvent | ToolCallEvent | ToolResultEvent;
60
+ export type StepCounter = {
61
+ next: () => number;
62
+ peek: () => number;
63
+ reset: (value?: number) => void;
64
+ };
65
+ export declare function createStepCounter(startAt?: number): StepCounter;
66
+ export declare function withSession<T>(ledger: AgentLedgerClient, agentName: string, fn: (ctx: {
67
+ sessionId: string;
68
+ steps: StepCounter;
69
+ }) => Promise<T>): Promise<T>;
70
+ export declare function instrumentTool<TInput, TOutput>(opts: {
71
+ ledger: AgentLedgerClient;
72
+ sessionId: string;
73
+ stepIndex: number;
74
+ toolName: string;
75
+ toolInput: TInput;
76
+ run: () => Promise<TOutput> | TOutput;
77
+ captureLatencyMs?: boolean;
78
+ }): Promise<TOutput>;
package/dist/index.js CHANGED
@@ -18,16 +18,23 @@ export class BudgetGuardrailError extends Error {
18
18
  }
19
19
  export class AgentLedgerClient {
20
20
  constructor(opts) {
21
- this.apiKey = opts.apiKey;
21
+ const key = (opts.apiKey ?? "").trim();
22
+ if (!key) {
23
+ throw new Error("AgentLedgerClient: apiKey is required");
24
+ }
25
+ this.apiKey = key;
22
26
  const resolvedBaseUrl = resolveBaseUrl(opts.baseUrl).trim();
23
27
  this.baseUrl = resolvedBaseUrl.replace(/\/$/, "");
28
+ this.fetchImpl = opts.fetch ?? fetch;
29
+ this.defaultHeaders = { ...(opts.defaultHeaders ?? {}) };
24
30
  }
25
31
  async startSession(agentName) {
26
- const res = await fetch(`${this.baseUrl}/v1/sessions`, {
32
+ const res = await this.fetchImpl(`${this.baseUrl}/v1/sessions`, {
27
33
  method: "POST",
28
34
  headers: {
29
35
  "Content-Type": "application/json",
30
- "x-api-key": this.apiKey
36
+ "x-api-key": this.apiKey,
37
+ ...this.defaultHeaders,
31
38
  },
32
39
  body: JSON.stringify({ agentName })
33
40
  });
@@ -39,11 +46,12 @@ export class AgentLedgerClient {
39
46
  return data.id;
40
47
  }
41
48
  async endSession(sessionId, status, opts) {
42
- const res = await fetch(`${this.baseUrl}/v1/sessions/${sessionId}/end`, {
49
+ const res = await this.fetchImpl(`${this.baseUrl}/v1/sessions/${sessionId}/end`, {
43
50
  method: "POST",
44
51
  headers: {
45
52
  "Content-Type": "application/json",
46
- "x-api-key": this.apiKey
53
+ "x-api-key": this.apiKey,
54
+ ...this.defaultHeaders,
47
55
  },
48
56
  body: JSON.stringify({ status, errorMessage: opts?.errorMessage ?? null })
49
57
  });
@@ -53,11 +61,12 @@ export class AgentLedgerClient {
53
61
  }
54
62
  }
55
63
  async logEvents(sessionId, events) {
56
- const res = await fetch(`${this.baseUrl}/v1/events`, {
64
+ const res = await this.fetchImpl(`${this.baseUrl}/v1/events`, {
57
65
  method: "POST",
58
66
  headers: {
59
67
  "Content-Type": "application/json",
60
- "x-api-key": this.apiKey
68
+ "x-api-key": this.apiKey,
69
+ ...this.defaultHeaders,
61
70
  },
62
71
  body: JSON.stringify({ sessionId, events })
63
72
  });
@@ -90,4 +99,70 @@ export class AgentLedgerClient {
90
99
  return this.logEvents(sessionId, [event]);
91
100
  }
92
101
  }
102
+ export function createStepCounter(startAt = 0) {
103
+ let value = startAt;
104
+ return {
105
+ next: () => value++,
106
+ peek: () => value,
107
+ reset: (v = 0) => {
108
+ value = v;
109
+ },
110
+ };
111
+ }
112
+ export async function withSession(ledger, agentName, fn) {
113
+ const sessionId = await ledger.startSession(agentName);
114
+ const steps = createStepCounter(0);
115
+ try {
116
+ const result = await fn({ sessionId, steps });
117
+ await ledger.endSession(sessionId, "success");
118
+ return result;
119
+ }
120
+ catch (err) {
121
+ const message = err instanceof Error ? err.message : String(err);
122
+ try {
123
+ await ledger.endSession(sessionId, "error", { errorMessage: message });
124
+ }
125
+ catch {
126
+ // ignore telemetry failures on shutdown
127
+ }
128
+ throw err;
129
+ }
130
+ }
131
+ export async function instrumentTool(opts) {
132
+ await opts.ledger.logToolCall(opts.sessionId, {
133
+ stepIndex: opts.stepIndex,
134
+ toolName: opts.toolName,
135
+ toolInput: opts.toolInput,
136
+ });
137
+ const started = typeof performance !== "undefined" && performance.now ? performance.now() : Date.now();
138
+ try {
139
+ const output = await opts.run();
140
+ const ended = typeof performance !== "undefined" && performance.now ? performance.now() : Date.now();
141
+ const latencyMs = Math.max(0, Math.round(ended - started));
142
+ await opts.ledger.logToolResult(opts.sessionId, {
143
+ stepIndex: opts.stepIndex,
144
+ toolName: opts.toolName,
145
+ toolOutput: output,
146
+ latencyMs: opts.captureLatencyMs === false ? 0 : latencyMs,
147
+ });
148
+ return output;
149
+ }
150
+ catch (err) {
151
+ const ended = typeof performance !== "undefined" && performance.now ? performance.now() : Date.now();
152
+ const latencyMs = Math.max(0, Math.round(ended - started));
153
+ const message = err instanceof Error ? err.message : String(err);
154
+ try {
155
+ await opts.ledger.logToolResult(opts.sessionId, {
156
+ stepIndex: opts.stepIndex,
157
+ toolName: opts.toolName,
158
+ toolOutput: { error: message },
159
+ latencyMs: opts.captureLatencyMs === false ? 0 : latencyMs,
160
+ });
161
+ }
162
+ catch {
163
+ // ignore
164
+ }
165
+ throw err;
166
+ }
167
+ }
93
168
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAcA,MAAM,aAAa,GAAG,4CAA4C,CAAC;AACnE,MAAM,WAAW,GACf,OAAO,UAAU,KAAK,WAAW,IAAK,UAAkB,CAAC,OAAO,CAAC,CAAC,CAAE,UAAkB,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC;AAE7G,SAAS,cAAc,CAAC,QAAiB;IACvC,IAAI,QAAQ;QAAE,OAAO,QAAQ,CAAC;IAC9B,MAAM,OAAO,GAAG,WAAW,EAAE,GAAG,CAAC;IACjC,IAAI,OAAO,EAAE,qBAAqB,EAAE,CAAC;QACnC,OAAO,OAAO,CAAC,qBAAqB,CAAC;IACvC,CAAC;IACD,OAAO,aAAa,CAAC;AACvB,CAAC;AAWD,MAAM,OAAO,oBAAqB,SAAQ,KAAK;IAG7C,YAAY,OAAe,EAAE,OAA+B;QAC1D,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,sBAAsB,CAAC;QACnC,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;IACzB,CAAC;CACF;AAED,MAAM,OAAO,iBAAiB;IAM5B,YAAY,IAA8B;QACxC,MAAM,GAAG,GAAG,CAAC,IAAI,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;QACvC,IAAI,CAAC,GAAG,EAAE,CAAC;YACT,MAAM,IAAI,KAAK,CAAC,uCAAuC,CAAC,CAAC;QAC3D,CAAC;QACD,IAAI,CAAC,MAAM,GAAG,GAAG,CAAC;QAClB,MAAM,eAAe,GAAG,cAAc,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC;QAC5D,IAAI,CAAC,OAAO,GAAG,eAAe,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;QAElD,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC;QACrC,IAAI,CAAC,cAAc,GAAG,EAAE,GAAG,CAAC,IAAI,CAAC,cAAc,IAAI,EAAE,CAAC,EAAE,CAAC;IAC3D,CAAC;IAED,KAAK,CAAC,YAAY,CAAC,SAAiB;QAClC,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,GAAG,IAAI,CAAC,OAAO,cAAc,EAAE;YAC9D,MAAM,EAAE,MAAM;YACd,OAAO,EAAE;gBACP,cAAc,EAAE,kBAAkB;gBAClC,WAAW,EAAE,IAAI,CAAC,MAAM;gBACxB,GAAG,IAAI,CAAC,cAAc;aACvB;YACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,SAAS,EAAE,CAAC;SACpC,CAAC,CAAC;QAEH,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;YACZ,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC;YAC9B,MAAM,IAAI,KAAK,CAAC,IAAI,IAAI,4BAA4B,GAAG,CAAC,UAAU,EAAE,CAAC,CAAC;QACxE,CAAC;QAED,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC;QAC9B,OAAO,IAAI,CAAC,EAAY,CAAC;IAC3B,CAAC;IAED,KAAK,CAAC,UAAU,CACd,SAAiB,EACjB,MAA2B,EAC3B,IAAgC;QAEhC,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,GAAG,IAAI,CAAC,OAAO,gBAAgB,SAAS,MAAM,EAAE;YAC/E,MAAM,EAAE,MAAM;YACd,OAAO,EAAE;gBACP,cAAc,EAAE,kBAAkB;gBAClC,WAAW,EAAE,IAAI,CAAC,MAAM;gBACxB,GAAG,IAAI,CAAC,cAAc;aACvB;YACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,YAAY,EAAE,IAAI,EAAE,YAAY,IAAI,IAAI,EAAE,CAAC;SAC3E,CAAC,CAAC;QAEH,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;YACZ,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC;YAC9B,MAAM,IAAI,KAAK,CAAC,IAAI,IAAI,0BAA0B,GAAG,CAAC,UAAU,EAAE,CAAC,CAAC;QACtE,CAAC;IACH,CAAC;IAED,KAAK,CAAC,SAAS,CAAC,SAAiB,EAAE,MAA+C;QAChF,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,GAAG,IAAI,CAAC,OAAO,YAAY,EAAE;YAC5D,MAAM,EAAE,MAAM;YACd,OAAO,EAAE;gBACP,cAAc,EAAE,kBAAkB;gBAClC,WAAW,EAAE,IAAI,CAAC,MAAM;gBACxB,GAAG,IAAI,CAAC,cAAc;aACvB;YACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,SAAS,EAAE,MAAM,EAAE,CAAC;SAC5C,CAAC,CAAC;QAEH,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;YACZ,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC;YAC9B,IAAI,OAAO,GAAQ,IAAI,CAAC;YACxB,IAAI,CAAC;gBACH,OAAO,GAAG,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;YAC3C,CAAC;YAAC,MAAM,CAAC;gBACP,OAAO,GAAG,IAAI,CAAC;YACjB,CAAC;YAED,IAAI,GAAG,CAAC,MAAM,KAAK,GAAG,IAAI,OAAO,EAAE,OAAO,EAAE,CAAC;gBAC3C,MAAM,IAAI,oBAAoB,CAAC,OAAO,EAAE,KAAK,IAAI,uBAAuB,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC;YAC7F,CAAC;YAED,MAAM,OAAO,GAAG,OAAO,EAAE,KAAK,IAAI,IAAI,IAAI,sBAAsB,CAAC;YACjE,MAAM,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC;QAC3B,CAAC;IACH,CAAC;IAED,KAAK,CAAC,UAAU,CACd,SAAiB,EACjB,CAA6B;QAE7B,MAAM,KAAK,GAAiB,EAAE,IAAI,EAAE,UAAU,EAAE,GAAG,CAAC,EAAE,CAAC;QACvD,OAAO,IAAI,CAAC,SAAS,CAAC,SAAS,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC;IAC5C,CAAC;IAED,KAAK,CAAC,WAAW,CACf,SAAiB,EACjB,CAA8B;QAE9B,MAAM,KAAK,GAAkB,EAAE,IAAI,EAAE,WAAW,EAAE,GAAG,CAAC,EAAE,CAAC;QACzD,OAAO,IAAI,CAAC,SAAS,CAAC,SAAS,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC;IAC5C,CAAC;IAED,KAAK,CAAC,aAAa,CACjB,SAAiB,EACjB,CAAgC;QAEhC,MAAM,KAAK,GAAoB,EAAE,IAAI,EAAE,aAAa,EAAE,GAAG,CAAC,EAAE,CAAC;QAC7D,OAAO,IAAI,CAAC,SAAS,CAAC,SAAS,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC;IAC5C,CAAC;CACF;AAqCD,MAAM,UAAU,iBAAiB,CAAC,OAAO,GAAG,CAAC;IAC3C,IAAI,KAAK,GAAG,OAAO,CAAC;IACpB,OAAO;QACL,IAAI,EAAE,GAAG,EAAE,CAAC,KAAK,EAAE;QACnB,IAAI,EAAE,GAAG,EAAE,CAAC,KAAK;QACjB,KAAK,EAAE,CAAC,CAAC,GAAG,CAAC,EAAE,EAAE;YACf,KAAK,GAAG,CAAC,CAAC;QACZ,CAAC;KACF,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,MAAyB,EACzB,SAAiB,EACjB,EAAkE;IAElE,MAAM,SAAS,GAAG,MAAM,MAAM,CAAC,YAAY,CAAC,SAAS,CAAC,CAAC;IACvD,MAAM,KAAK,GAAG,iBAAiB,CAAC,CAAC,CAAC,CAAC;IACnC,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC,CAAC;QAC9C,MAAM,MAAM,CAAC,UAAU,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;QAC9C,OAAO,MAAM,CAAC;IAChB,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACjE,IAAI,CAAC;YACH,MAAM,MAAM,CAAC,UAAU,CAAC,SAAS,EAAE,OAAO,EAAE,EAAE,YAAY,EAAE,OAAO,EAAE,CAAC,CAAC;QACzE,CAAC;QAAC,MAAM,CAAC;YACP,wCAAwC;QAC1C,CAAC;QACD,MAAM,GAAG,CAAC;IACZ,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,cAAc,CAAkB,IAQrD;IACC,MAAM,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,SAAS,EAAE;QAC5C,SAAS,EAAE,IAAI,CAAC,SAAS;QACzB,QAAQ,EAAE,IAAI,CAAC,QAAQ;QACvB,SAAS,EAAE,IAAI,CAAC,SAAS;KAC1B,CAAC,CAAC;IAEH,MAAM,OAAO,GAAG,OAAO,WAAW,KAAK,WAAW,IAAI,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,WAAW,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC;IACvG,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,GAAG,EAAE,CAAC;QAChC,MAAM,KAAK,GAAG,OAAO,WAAW,KAAK,WAAW,IAAI,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,WAAW,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC;QACrG,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,OAAO,CAAC,CAAC,CAAC;QAE3D,MAAM,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,IAAI,CAAC,SAAS,EAAE;YAC9C,SAAS,EAAE,IAAI,CAAC,SAAS;YACzB,QAAQ,EAAE,IAAI,CAAC,QAAQ;YACvB,UAAU,EAAE,MAAM;YAClB,SAAS,EAAE,IAAI,CAAC,gBAAgB,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS;SAC3D,CAAC,CAAC;QAEH,OAAO,MAAM,CAAC;IAChB,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,KAAK,GAAG,OAAO,WAAW,KAAK,WAAW,IAAI,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,WAAW,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC;QACrG,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,OAAO,CAAC,CAAC,CAAC;QAC3D,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACjE,IAAI,CAAC;YACH,MAAM,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,IAAI,CAAC,SAAS,EAAE;gBAC9C,SAAS,EAAE,IAAI,CAAC,SAAS;gBACzB,QAAQ,EAAE,IAAI,CAAC,QAAQ;gBACvB,UAAU,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE;gBAC9B,SAAS,EAAE,IAAI,CAAC,gBAAgB,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS;aAC3D,CAAC,CAAC;QACL,CAAC;QAAC,MAAM,CAAC;YACP,SAAS;QACX,CAAC;QACD,MAAM,GAAG,CAAC;IACZ,CAAC;AACH,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agent-ledger/sdk-ts",
3
- "version": "0.0.4",
3
+ "version": "0.0.5",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
package/src/index.ts CHANGED
@@ -8,6 +8,8 @@ export type EventType =
8
8
  export interface AgentLedgerClientOptions {
9
9
  apiKey: string;
10
10
  baseUrl?: string;
11
+ fetch?: typeof fetch;
12
+ defaultHeaders?: Record<string, string>;
11
13
  }
12
14
 
13
15
  const PROD_BASE_URL = "https://agent-ledger-api.azurewebsites.net";
@@ -45,19 +47,29 @@ export class BudgetGuardrailError extends Error {
45
47
  export class AgentLedgerClient {
46
48
  private apiKey: string;
47
49
  private baseUrl: string;
50
+ private fetchImpl: typeof fetch;
51
+ private defaultHeaders: Record<string, string>;
48
52
 
49
53
  constructor(opts: AgentLedgerClientOptions) {
50
- this.apiKey = opts.apiKey;
54
+ const key = (opts.apiKey ?? "").trim();
55
+ if (!key) {
56
+ throw new Error("AgentLedgerClient: apiKey is required");
57
+ }
58
+ this.apiKey = key;
51
59
  const resolvedBaseUrl = resolveBaseUrl(opts.baseUrl).trim();
52
60
  this.baseUrl = resolvedBaseUrl.replace(/\/$/, "");
61
+
62
+ this.fetchImpl = opts.fetch ?? fetch;
63
+ this.defaultHeaders = { ...(opts.defaultHeaders ?? {}) };
53
64
  }
54
65
 
55
66
  async startSession(agentName: string): Promise<string> {
56
- const res = await fetch(`${this.baseUrl}/v1/sessions`, {
67
+ const res = await this.fetchImpl(`${this.baseUrl}/v1/sessions`, {
57
68
  method: "POST",
58
69
  headers: {
59
70
  "Content-Type": "application/json",
60
- "x-api-key": this.apiKey
71
+ "x-api-key": this.apiKey,
72
+ ...this.defaultHeaders,
61
73
  },
62
74
  body: JSON.stringify({ agentName })
63
75
  });
@@ -76,11 +88,12 @@ export class AgentLedgerClient {
76
88
  status: "success" | "error",
77
89
  opts?: { errorMessage?: string }
78
90
  ) {
79
- const res = await fetch(`${this.baseUrl}/v1/sessions/${sessionId}/end`, {
91
+ const res = await this.fetchImpl(`${this.baseUrl}/v1/sessions/${sessionId}/end`, {
80
92
  method: "POST",
81
93
  headers: {
82
94
  "Content-Type": "application/json",
83
- "x-api-key": this.apiKey
95
+ "x-api-key": this.apiKey,
96
+ ...this.defaultHeaders,
84
97
  },
85
98
  body: JSON.stringify({ status, errorMessage: opts?.errorMessage ?? null })
86
99
  });
@@ -91,12 +104,13 @@ export class AgentLedgerClient {
91
104
  }
92
105
  }
93
106
 
94
- async logEvents(sessionId: string, events: any[]) {
95
- const res = await fetch(`${this.baseUrl}/v1/events`, {
107
+ async logEvents(sessionId: string, events: AnyEvent[] | Array<Record<string, any>>) {
108
+ const res = await this.fetchImpl(`${this.baseUrl}/v1/events`, {
96
109
  method: "POST",
97
110
  headers: {
98
111
  "Content-Type": "application/json",
99
- "x-api-key": this.apiKey
112
+ "x-api-key": this.apiKey,
113
+ ...this.defaultHeaders,
100
114
  },
101
115
  body: JSON.stringify({ sessionId, events })
102
116
  });
@@ -171,4 +185,90 @@ export type ToolResultEvent = {
171
185
  latencyMs: number;
172
186
  };
173
187
 
174
- export type AnyEvent = LlmCallEvent | ToolCallEvent | ToolResultEvent;
188
+ export type AnyEvent = LlmCallEvent | ToolCallEvent | ToolResultEvent;
189
+
190
+ export type StepCounter = {
191
+ next: () => number;
192
+ peek: () => number;
193
+ reset: (value?: number) => void;
194
+ };
195
+
196
+ export function createStepCounter(startAt = 0): StepCounter {
197
+ let value = startAt;
198
+ return {
199
+ next: () => value++,
200
+ peek: () => value,
201
+ reset: (v = 0) => {
202
+ value = v;
203
+ },
204
+ };
205
+ }
206
+
207
+ export async function withSession<T>(
208
+ ledger: AgentLedgerClient,
209
+ agentName: string,
210
+ fn: (ctx: { sessionId: string; steps: StepCounter }) => Promise<T>
211
+ ): Promise<T> {
212
+ const sessionId = await ledger.startSession(agentName);
213
+ const steps = createStepCounter(0);
214
+ try {
215
+ const result = await fn({ sessionId, steps });
216
+ await ledger.endSession(sessionId, "success");
217
+ return result;
218
+ } catch (err) {
219
+ const message = err instanceof Error ? err.message : String(err);
220
+ try {
221
+ await ledger.endSession(sessionId, "error", { errorMessage: message });
222
+ } catch {
223
+ // ignore telemetry failures on shutdown
224
+ }
225
+ throw err;
226
+ }
227
+ }
228
+
229
+ export async function instrumentTool<TInput, TOutput>(opts: {
230
+ ledger: AgentLedgerClient;
231
+ sessionId: string;
232
+ stepIndex: number;
233
+ toolName: string;
234
+ toolInput: TInput;
235
+ run: () => Promise<TOutput> | TOutput;
236
+ captureLatencyMs?: boolean;
237
+ }): Promise<TOutput> {
238
+ await opts.ledger.logToolCall(opts.sessionId, {
239
+ stepIndex: opts.stepIndex,
240
+ toolName: opts.toolName,
241
+ toolInput: opts.toolInput,
242
+ });
243
+
244
+ const started = typeof performance !== "undefined" && performance.now ? performance.now() : Date.now();
245
+ try {
246
+ const output = await opts.run();
247
+ const ended = typeof performance !== "undefined" && performance.now ? performance.now() : Date.now();
248
+ const latencyMs = Math.max(0, Math.round(ended - started));
249
+
250
+ await opts.ledger.logToolResult(opts.sessionId, {
251
+ stepIndex: opts.stepIndex,
252
+ toolName: opts.toolName,
253
+ toolOutput: output,
254
+ latencyMs: opts.captureLatencyMs === false ? 0 : latencyMs,
255
+ });
256
+
257
+ return output;
258
+ } catch (err) {
259
+ const ended = typeof performance !== "undefined" && performance.now ? performance.now() : Date.now();
260
+ const latencyMs = Math.max(0, Math.round(ended - started));
261
+ const message = err instanceof Error ? err.message : String(err);
262
+ try {
263
+ await opts.ledger.logToolResult(opts.sessionId, {
264
+ stepIndex: opts.stepIndex,
265
+ toolName: opts.toolName,
266
+ toolOutput: { error: message },
267
+ latencyMs: opts.captureLatencyMs === false ? 0 : latencyMs,
268
+ });
269
+ } catch {
270
+ // ignore
271
+ }
272
+ throw err;
273
+ }
274
+ }