@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 +42 -27
- package/dist/index.d.ts +24 -1
- package/dist/index.js +82 -7
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/index.ts +109 -9
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 {
|
|
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
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
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
|
-
|
|
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:
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
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":"
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
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
|
-
|
|
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
|
|
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
|
|
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:
|
|
95
|
-
const res = await
|
|
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
|
+
}
|