@spendgraph/sdk 0.1.0 → 0.2.1

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.
Files changed (63) hide show
  1. package/dist/ai.js +0 -12
  2. package/dist/client.d.ts +37 -0
  3. package/dist/client.js +36 -0
  4. package/dist/core/client/client.d.ts +30 -0
  5. package/dist/core/client/client.js +128 -0
  6. package/dist/core/client/errors.d.ts +25 -0
  7. package/dist/core/client/errors.js +17 -0
  8. package/dist/core/client/index.d.ts +2 -0
  9. package/dist/core/client/index.js +2 -0
  10. package/dist/core/types.d.ts +28 -0
  11. package/dist/core/types.js +1 -0
  12. package/dist/index.d.ts +9 -124
  13. package/dist/index.js +5 -421
  14. package/dist/langchain.js +3 -17
  15. package/dist/resources/alerts.d.ts +18 -0
  16. package/dist/resources/alerts.js +9 -0
  17. package/dist/resources/credentials.d.ts +22 -0
  18. package/dist/resources/credentials.js +15 -0
  19. package/dist/resources/events.d.ts +41 -0
  20. package/dist/resources/events.js +18 -0
  21. package/dist/resources/index.d.ts +21 -0
  22. package/dist/resources/index.js +12 -0
  23. package/dist/resources/ingest.d.ts +42 -0
  24. package/dist/resources/ingest.js +27 -0
  25. package/dist/resources/keys.d.ts +34 -0
  26. package/dist/resources/keys.js +15 -0
  27. package/dist/resources/playground.d.ts +7 -0
  28. package/dist/resources/playground.js +9 -0
  29. package/dist/resources/pricing.d.ts +49 -0
  30. package/dist/resources/pricing.js +36 -0
  31. package/dist/resources/projects.d.ts +54 -0
  32. package/dist/resources/projects.js +49 -0
  33. package/dist/resources/prompts-admin.d.ts +23 -0
  34. package/dist/resources/prompts-admin.js +21 -0
  35. package/dist/resources/prompts.d.ts +124 -0
  36. package/dist/resources/prompts.js +49 -0
  37. package/dist/resources/stats.d.ts +65 -0
  38. package/dist/resources/stats.js +21 -0
  39. package/dist/resources/tools.d.ts +66 -0
  40. package/dist/resources/tools.js +21 -0
  41. package/dist/rollout/index.d.ts +1 -0
  42. package/dist/rollout/index.js +1 -0
  43. package/dist/rollout/rollout.d.ts +75 -0
  44. package/dist/rollout/rollout.js +1 -0
  45. package/dist/schema/index.d.ts +3 -0
  46. package/dist/schema/index.js +2 -0
  47. package/dist/schema/serialize/index.d.ts +1 -0
  48. package/dist/schema/serialize/index.js +1 -0
  49. package/dist/schema/serialize/serialize.d.ts +12 -0
  50. package/dist/schema/serialize/serialize.js +31 -0
  51. package/dist/schema/types/index.d.ts +1 -0
  52. package/dist/schema/types/index.js +1 -0
  53. package/dist/schema/types/types.d.ts +58 -0
  54. package/dist/schema/types/types.js +1 -0
  55. package/dist/schema/validate/index.d.ts +1 -0
  56. package/dist/schema/validate/index.js +1 -0
  57. package/dist/schema/validate/validate.d.ts +28 -0
  58. package/dist/schema/validate/validate.js +92 -0
  59. package/dist/track/index.d.ts +2 -0
  60. package/dist/track/index.js +1 -0
  61. package/dist/track/track.d.ts +209 -0
  62. package/dist/track/track.js +331 -0
  63. package/package.json +3 -2
@@ -0,0 +1,42 @@
1
+ import type { Client } from "../core/client/index.js";
2
+ import type { Tag } from "../core/types.js";
3
+ /** One call's consumption. The server prices it from the model id. */
4
+ export interface UsageEvent {
5
+ eventId?: string;
6
+ model: string;
7
+ inputTokens: number;
8
+ outputTokens: number;
9
+ cacheReadTokens?: number;
10
+ cacheWriteTokens?: number;
11
+ /** Billed on their own by search-grounded providers, not folded into output. */
12
+ citationTokens?: number;
13
+ reasoningTokens?: number;
14
+ timestamp?: string;
15
+ metadata?: Record<string, Tag>;
16
+ }
17
+ export interface IngestResult {
18
+ accepted: number;
19
+ rejected: number;
20
+ /** Ids nothing could price. Stored at $0 and counted, never rejected. */
21
+ unpricedModels: string[];
22
+ }
23
+ /** The route takes up to this many events per request. */
24
+ export declare const MAX_EVENTS = 100;
25
+ /**
26
+ * Anything that can deliver usage — this sender, a queue, a test double.
27
+ *
28
+ * `@spendgraph/llms` accepts this shape, so an `Ingest` from here can be handed
29
+ * straight to it without either package importing the other's transport.
30
+ */
31
+ export interface Sender {
32
+ send(events: UsageEvent[]): Promise<void>;
33
+ }
34
+ /** Posts usage straight through, chunked to what the route accepts. */
35
+ export declare class Ingest implements Sender {
36
+ private readonly client;
37
+ private readonly project?;
38
+ constructor(client: Client, project?: string | undefined);
39
+ send(events: UsageEvent[]): Promise<void>;
40
+ /** The same write, with the server's answer — which ids went unpriced. */
41
+ report(events: UsageEvent[]): Promise<IngestResult>;
42
+ }
@@ -0,0 +1,27 @@
1
+ export const MAX_EVENTS = 100;
2
+ export class Ingest {
3
+ client;
4
+ project;
5
+ constructor(client, project) {
6
+ this.client = client;
7
+ this.project = project;
8
+ }
9
+ async send(events) {
10
+ await this.report(events);
11
+ }
12
+ async report(events) {
13
+ const total = { accepted: 0, rejected: 0, unpricedModels: [] };
14
+ if (events.length === 0)
15
+ return total;
16
+ const unpriced = new Set();
17
+ for (let i = 0; i < events.length; i += MAX_EVENTS) {
18
+ const res = await this.client.post("/api/v1/ingest", { events: events.slice(i, i + MAX_EVENTS) }, { project: this.project });
19
+ total.accepted += res?.accepted ?? 0;
20
+ total.rejected += res?.rejected ?? 0;
21
+ for (const model of res?.unpricedModels ?? [])
22
+ unpriced.add(model);
23
+ }
24
+ total.unpricedModels = [...unpriced];
25
+ return total;
26
+ }
27
+ }
@@ -0,0 +1,34 @@
1
+ import type { Client } from "../core/client/index.js";
2
+ export interface ApiKeyRow {
3
+ id: string;
4
+ name: string;
5
+ projectId: string;
6
+ createdAt: string;
7
+ lastUsedAt: string | null;
8
+ revokedAt: string | null;
9
+ }
10
+ /**
11
+ * API keys. Dashboard session only, deliberately: a key that could mint keys
12
+ * would turn one leaked ingest credential into permanent access.
13
+ */
14
+ export declare class Keys {
15
+ private readonly client;
16
+ constructor(client: Client);
17
+ list(query?: {
18
+ project?: string;
19
+ }): Promise<{
20
+ keys: ApiKeyRow[];
21
+ }>;
22
+ /** The plaintext key is in this response and nowhere else, ever again. */
23
+ create(body: {
24
+ projectId: string;
25
+ name: string;
26
+ }): Promise<{
27
+ key: ApiKeyRow & {
28
+ plaintext: string;
29
+ };
30
+ }>;
31
+ revoke(keyId: string): Promise<{
32
+ revoked: boolean;
33
+ }>;
34
+ }
@@ -0,0 +1,15 @@
1
+ export class Keys {
2
+ client;
3
+ constructor(client) {
4
+ this.client = client;
5
+ }
6
+ list(query = {}) {
7
+ return this.client.get("/api/v1/keys", { ...query });
8
+ }
9
+ create(body) {
10
+ return this.client.post("/api/v1/keys", body);
11
+ }
12
+ revoke(keyId) {
13
+ return this.client.delete(`/api/v1/keys/${encodeURIComponent(keyId)}`);
14
+ }
15
+ }
@@ -0,0 +1,7 @@
1
+ import type { Client } from "../core/client/index.js";
2
+ /** Ad-hoc runs from the dashboard, streamed. Dashboard session only. */
3
+ export declare class Playground {
4
+ private readonly client;
5
+ constructor(client: Client);
6
+ run(body: Record<string, unknown>): Promise<Record<string, unknown>>;
7
+ }
@@ -0,0 +1,9 @@
1
+ export class Playground {
2
+ client;
3
+ constructor(client) {
4
+ this.client = client;
5
+ }
6
+ run(body) {
7
+ return this.client.post("/api/v1/playground/run", body);
8
+ }
9
+ }
@@ -0,0 +1,49 @@
1
+ import type { Client } from "../core/client/index.js";
2
+ export interface PricingRow {
3
+ model: string;
4
+ provider: string;
5
+ inputPerMtokMicros: number;
6
+ outputPerMtokMicros: number;
7
+ cacheReadPerMtokMicros: number | null;
8
+ cacheWritePerMtokMicros: number | null;
9
+ /** Flat charge per call — Perplexity bills one for the search behind Sonar. */
10
+ perRequestMicros: number | null;
11
+ }
12
+ /** The pricing catalogue. Dashboard session only. */
13
+ export declare class Pricing {
14
+ private readonly client;
15
+ constructor(client: Client);
16
+ list(): Promise<Record<string, unknown>>;
17
+ /** A manual override for one model, which outranks the synced rows. */
18
+ override(model: string, body: Record<string, unknown>): Promise<{
19
+ pricing: PricingRow;
20
+ }>;
21
+ /** Which models the catalogue can price, and which it cannot. */
22
+ coverage(): Promise<Record<string, unknown>>;
23
+ /** What legacy and offer-based pricing would each charge, side by side. */
24
+ readiness(): Promise<Record<string, unknown>>;
25
+ sync(body?: Record<string, unknown>): Promise<Record<string, unknown>>;
26
+ }
27
+ /** The model catalogue and the offers behind it. Dashboard session only. */
28
+ export declare class Models {
29
+ private readonly client;
30
+ constructor(client: Client);
31
+ list(query?: {
32
+ creator?: string;
33
+ limit?: number;
34
+ }): Promise<Record<string, unknown>>;
35
+ offers(query?: {
36
+ model?: string;
37
+ q?: string;
38
+ }): Promise<Record<string, unknown>>;
39
+ /** Prices one workload across models or serving providers. */
40
+ compare(query?: {
41
+ models?: string;
42
+ offers?: string;
43
+ baseline?: string;
44
+ benchmark?: string;
45
+ in?: number;
46
+ out?: number;
47
+ requests?: number;
48
+ }): Promise<Record<string, unknown>>;
49
+ }
@@ -0,0 +1,36 @@
1
+ export class Pricing {
2
+ client;
3
+ constructor(client) {
4
+ this.client = client;
5
+ }
6
+ list() {
7
+ return this.client.get("/api/v1/pricing");
8
+ }
9
+ override(model, body) {
10
+ return this.client.put(`/api/v1/pricing/${encodeURIComponent(model)}`, body);
11
+ }
12
+ coverage() {
13
+ return this.client.get("/api/v1/pricing/coverage");
14
+ }
15
+ readiness() {
16
+ return this.client.get("/api/v1/pricing/readiness");
17
+ }
18
+ sync(body = {}) {
19
+ return this.client.post("/api/v1/pricing/sync", body);
20
+ }
21
+ }
22
+ export class Models {
23
+ client;
24
+ constructor(client) {
25
+ this.client = client;
26
+ }
27
+ list(query = {}) {
28
+ return this.client.get("/api/v1/models", { ...query });
29
+ }
30
+ offers(query = {}) {
31
+ return this.client.get("/api/v1/offers", { ...query });
32
+ }
33
+ compare(query = {}) {
34
+ return this.client.get("/api/v1/compare", { ...query });
35
+ }
36
+ }
@@ -0,0 +1,54 @@
1
+ import type { Client } from "../core/client/index.js";
2
+ export interface ProjectRow {
3
+ id: string;
4
+ name: string;
5
+ createdAt: string;
6
+ }
7
+ export interface Budget {
8
+ monthlyLimitMicros: number | null;
9
+ alertThresholdPct: number | null;
10
+ }
11
+ /** Projects, their budgets, members and invites. Dashboard session only. */
12
+ export declare class Projects {
13
+ private readonly client;
14
+ constructor(client: Client);
15
+ list(): Promise<{
16
+ projects: ProjectRow[];
17
+ }>;
18
+ create(body: {
19
+ name: string;
20
+ }): Promise<{
21
+ project: ProjectRow;
22
+ }>;
23
+ budget(projectId: string): Promise<{
24
+ budget: Budget;
25
+ }>;
26
+ setBudget(projectId: string, body: Partial<Budget>): Promise<{
27
+ ok: boolean;
28
+ }>;
29
+ members(projectId: string): Promise<Record<string, unknown>>;
30
+ addMember(projectId: string, body: Record<string, unknown>): Promise<{
31
+ ok: boolean;
32
+ }>;
33
+ removeMember(projectId: string, userId: string): Promise<{
34
+ ok: boolean;
35
+ }>;
36
+ invite(projectId: string, body: Record<string, unknown>): Promise<{
37
+ ok: boolean;
38
+ added?: unknown;
39
+ }>;
40
+ revokeInvite(projectId: string, inviteId: string): Promise<{
41
+ ok: boolean;
42
+ }>;
43
+ }
44
+ /** Accepting an invite is the one project call that identifies a person, not a key. */
45
+ export declare class Invites {
46
+ private readonly client;
47
+ constructor(client: Client);
48
+ preview(token: string): Promise<{
49
+ project: ProjectRow;
50
+ }>;
51
+ accept(token: string): Promise<{
52
+ project: ProjectRow;
53
+ }>;
54
+ }
@@ -0,0 +1,49 @@
1
+ export class Projects {
2
+ client;
3
+ constructor(client) {
4
+ this.client = client;
5
+ }
6
+ list() {
7
+ return this.client.get("/api/v1/projects");
8
+ }
9
+ create(body) {
10
+ return this.client.post("/api/v1/projects", body);
11
+ }
12
+ budget(projectId) {
13
+ return this.client.get(`/api/v1/projects/${encodeURIComponent(projectId)}/budget`);
14
+ }
15
+ setBudget(projectId, body) {
16
+ return this.client.put(`/api/v1/projects/${encodeURIComponent(projectId)}/budget`, body);
17
+ }
18
+ members(projectId) {
19
+ return this.client.get(`/api/v1/projects/${encodeURIComponent(projectId)}/members`);
20
+ }
21
+ addMember(projectId, body) {
22
+ return this.client.post(`/api/v1/projects/${encodeURIComponent(projectId)}/members`, body);
23
+ }
24
+ removeMember(projectId, userId) {
25
+ return this.client.delete(`/api/v1/projects/${encodeURIComponent(projectId)}/members`, {
26
+ userId,
27
+ });
28
+ }
29
+ invite(projectId, body) {
30
+ return this.client.post(`/api/v1/projects/${encodeURIComponent(projectId)}/invites`, body);
31
+ }
32
+ revokeInvite(projectId, inviteId) {
33
+ return this.client.delete(`/api/v1/projects/${encodeURIComponent(projectId)}/invites`, {
34
+ inviteId,
35
+ });
36
+ }
37
+ }
38
+ export class Invites {
39
+ client;
40
+ constructor(client) {
41
+ this.client = client;
42
+ }
43
+ preview(token) {
44
+ return this.client.get("/api/v1/invites/accept", { token });
45
+ }
46
+ accept(token) {
47
+ return this.client.post("/api/v1/invites/accept", { token });
48
+ }
49
+ }
@@ -0,0 +1,23 @@
1
+ import type { Client } from "../core/client/index.js";
2
+ import type { Scoped } from "./prompts.js";
3
+ /**
4
+ * The prompt operations gated on a dashboard session — publishing a version,
5
+ * archiving a prompt, starting an optimization run, and reading run history.
6
+ */
7
+ export declare class PromptsAdmin {
8
+ private readonly client;
9
+ constructor(client: Client);
10
+ publish(promptId: string, body?: Record<string, unknown>): Promise<Record<string, unknown>>;
11
+ archive(promptId: string, query?: Scoped): Promise<Record<string, unknown>>;
12
+ /** Starts an optimization run. The budget is required, never defaulted. */
13
+ assay(promptId: string, body: Record<string, unknown>): Promise<Record<string, unknown>>;
14
+ runs(query?: {
15
+ project?: string;
16
+ limit?: number;
17
+ }): Promise<{
18
+ runs: unknown[];
19
+ }>;
20
+ run(runId: string): Promise<{
21
+ run: unknown;
22
+ }>;
23
+ }
@@ -0,0 +1,21 @@
1
+ export class PromptsAdmin {
2
+ client;
3
+ constructor(client) {
4
+ this.client = client;
5
+ }
6
+ publish(promptId, body = {}) {
7
+ return this.client.post(`/api/v1/prompts/${encodeURIComponent(promptId)}/publish`, body);
8
+ }
9
+ archive(promptId, query = {}) {
10
+ return this.client.post(`/api/v1/prompts/${encodeURIComponent(promptId)}/archive`, {}, { ...query });
11
+ }
12
+ assay(promptId, body) {
13
+ return this.client.post(`/api/v1/prompts/${encodeURIComponent(promptId)}/assay`, body);
14
+ }
15
+ runs(query = {}) {
16
+ return this.client.get("/api/v1/prompts/runs", { ...query });
17
+ }
18
+ run(runId) {
19
+ return this.client.get(`/api/v1/prompts/runs/${encodeURIComponent(runId)}`);
20
+ }
21
+ }
@@ -0,0 +1,124 @@
1
+ import type { Client } from "../core/client/index.js";
2
+ export type Role = "system" | "user" | "assistant";
3
+ export interface RenderedMessage {
4
+ role: Role;
5
+ content: string;
6
+ }
7
+ export interface PromptBlock {
8
+ title?: string;
9
+ body?: string;
10
+ }
11
+ export interface SavePromptInput {
12
+ projectId: string;
13
+ name: string;
14
+ blocks?: PromptBlock[];
15
+ variables?: Record<string, string>;
16
+ question?: string;
17
+ models?: string[];
18
+ temperature?: number;
19
+ maxTokens?: number;
20
+ }
21
+ export interface ReportRolloutInput {
22
+ /** Chosen by the caller so a retried report writes one row, not two. */
23
+ rolloutId: string;
24
+ versionId?: string | null;
25
+ model: string;
26
+ fields?: Record<string, string>;
27
+ rendered: RenderedMessage[];
28
+ output?: string;
29
+ status?: "completed" | "failed";
30
+ error?: string;
31
+ inputTokens?: number;
32
+ outputTokens?: number;
33
+ cacheReadTokens?: number;
34
+ cacheWriteTokens?: number;
35
+ citationTokens?: number;
36
+ reasoningTokens?: number;
37
+ latencyMs?: number;
38
+ caseId?: string;
39
+ /** Which repetition this is. pass^k needs it even when k is 1. */
40
+ seed?: number;
41
+ candidateId?: string;
42
+ parentId?: string;
43
+ generation?: number;
44
+ }
45
+ export interface RunPromptInput {
46
+ rolloutId: string;
47
+ [key: string]: unknown;
48
+ }
49
+ export interface DatasetCase {
50
+ caseId: string;
51
+ fieldValues?: Record<string, string>;
52
+ expected?: string | null;
53
+ split?: "feedback" | "held_out";
54
+ }
55
+ export interface Scoped {
56
+ project?: string;
57
+ }
58
+ /**
59
+ * Stored prompts, their versions, datasets and rollouts.
60
+ *
61
+ * This is the half of the API a job uses: every method here takes an API key.
62
+ * Publishing, archiving and optimizing are on the dashboard half — see
63
+ * `PromptsAdmin`.
64
+ */
65
+ export declare class Prompts {
66
+ private readonly client;
67
+ constructor(client: Client);
68
+ list(query?: Scoped & {
69
+ limit?: number;
70
+ cursor?: string;
71
+ archived?: boolean;
72
+ }): Promise<{
73
+ prompts: unknown[];
74
+ nextCursor?: string | null;
75
+ }>;
76
+ create(body: SavePromptInput): Promise<{
77
+ prompt: unknown;
78
+ }>;
79
+ /** One prompt with its current version. `runs` asks for its recent runs too. */
80
+ get<T = Record<string, unknown>>(promptId: string, query?: Scoped & {
81
+ runs?: number;
82
+ }): Promise<T>;
83
+ update(promptId: string, body: SavePromptInput, query?: Scoped): Promise<Record<string, unknown>>;
84
+ versions<T = Record<string, unknown>>(promptId: string, query?: Scoped & {
85
+ limit?: number;
86
+ origin?: string;
87
+ }): Promise<T>;
88
+ /** Promotes a stored version to current. Unchanged text is a no-op, not a fork. */
89
+ promote(promptId: string, versionId: string, query?: Scoped): Promise<{
90
+ promoted: string;
91
+ unchanged?: boolean;
92
+ }>;
93
+ cases<T = Record<string, unknown>>(promptId: string, query?: Scoped): Promise<T>;
94
+ /** Replaces the dataset. Splits are derived, so a case never moves between them. */
95
+ putCases<T = {
96
+ counts: unknown;
97
+ problem: unknown;
98
+ }>(promptId: string, cases: DatasetCase[], query?: Scoped): Promise<T>;
99
+ rollouts(promptId: string, query?: Scoped & {
100
+ limit?: number;
101
+ cursor?: string;
102
+ evaluation?: boolean;
103
+ }): Promise<Record<string, unknown>>;
104
+ /**
105
+ * Records a rollout the caller ran itself. Dedupes on `rolloutId`.
106
+ *
107
+ * `priced` is false where no pricing row covered the model. The stored cost
108
+ * is zero either way — the column is `notNull` — so this flag is the only
109
+ * thing telling a free call apart from an unpriced one.
110
+ */
111
+ report(promptId: string, body: ReportRolloutInput, query?: Scoped): Promise<{
112
+ rollout: unknown;
113
+ deduped?: boolean;
114
+ priced?: boolean;
115
+ }>;
116
+ /** Runs the prompt server-side, where the spec, rendering and pricing already live. */
117
+ run<T = {
118
+ rollout: unknown;
119
+ recorded?: boolean;
120
+ note?: string | null;
121
+ deduped?: boolean;
122
+ priced?: boolean;
123
+ }>(promptId: string, body: RunPromptInput, query?: Scoped): Promise<T>;
124
+ }
@@ -0,0 +1,49 @@
1
+ export class Prompts {
2
+ client;
3
+ constructor(client) {
4
+ this.client = client;
5
+ }
6
+ list(query = {}) {
7
+ return this.client.get("/api/v1/prompts", { ...query });
8
+ }
9
+ create(body) {
10
+ return this.client.post("/api/v1/prompts", body);
11
+ }
12
+ get(promptId, query = {}) {
13
+ return this.client.get(`/api/v1/prompts/${encodeURIComponent(promptId)}`, { ...query });
14
+ }
15
+ update(promptId, body, query = {}) {
16
+ return this.client.put(`/api/v1/prompts/${encodeURIComponent(promptId)}`, body, { ...query });
17
+ }
18
+ versions(promptId, query = {}) {
19
+ return this.client.get(`/api/v1/prompts/${encodeURIComponent(promptId)}/versions`, {
20
+ ...query,
21
+ });
22
+ }
23
+ promote(promptId, versionId, query = {}) {
24
+ return this.client.post(`/api/v1/prompts/${encodeURIComponent(promptId)}/versions`, { versionId }, { ...query });
25
+ }
26
+ cases(promptId, query = {}) {
27
+ return this.client.get(`/api/v1/prompts/${encodeURIComponent(promptId)}/cases`, {
28
+ ...query,
29
+ });
30
+ }
31
+ putCases(promptId, cases, query = {}) {
32
+ return this.client.put(`/api/v1/prompts/${encodeURIComponent(promptId)}/cases`, { cases }, { ...query });
33
+ }
34
+ rollouts(promptId, query = {}) {
35
+ return this.client.get(`/api/v1/prompts/${encodeURIComponent(promptId)}/rollouts`, {
36
+ ...query,
37
+ });
38
+ }
39
+ report(promptId, body, query = {}) {
40
+ return this.client.post(`/api/v1/prompts/${encodeURIComponent(promptId)}/rollouts`, body, {
41
+ ...query,
42
+ });
43
+ }
44
+ run(promptId, body, query = {}) {
45
+ return this.client.post(`/api/v1/prompts/${encodeURIComponent(promptId)}/run`, body, {
46
+ ...query,
47
+ });
48
+ }
49
+ }
@@ -0,0 +1,65 @@
1
+ import type { Client } from "../core/client/index.js";
2
+ /** Shared by every stats read. Defaults to the last 30 days, all visible projects. */
3
+ export interface RangeQuery {
4
+ /** ISO timestamp. Defaults to 30 days before `to`. */
5
+ from?: string;
6
+ /** ISO timestamp. Defaults to now. */
7
+ to?: string;
8
+ /** An API key is pinned to its own project and refuses any other. */
9
+ project?: string;
10
+ }
11
+ export interface Totals {
12
+ costMicros: number;
13
+ inputTokens: number;
14
+ outputTokens: number;
15
+ cacheReadTokens: number;
16
+ cacheWriteTokens: number;
17
+ requests: number;
18
+ }
19
+ export interface Summary {
20
+ current: Totals;
21
+ /** The window of the same length immediately before `from`. */
22
+ previous: Totals;
23
+ pricing: unknown;
24
+ }
25
+ export interface TimeseriesPoint {
26
+ day: string;
27
+ costMicros: number;
28
+ inputTokens: number;
29
+ outputTokens: number;
30
+ requests: number;
31
+ }
32
+ export interface Timeseries {
33
+ days: TimeseriesPoint[];
34
+ bucket: string;
35
+ }
36
+ export interface ModelRow {
37
+ model: string;
38
+ costMicros: number;
39
+ inputTokens: number;
40
+ outputTokens: number;
41
+ requests: number;
42
+ }
43
+ /**
44
+ * Spend, read back.
45
+ *
46
+ * Every method here takes an API key, so a job can check what it spent without
47
+ * a dashboard session.
48
+ */
49
+ export declare class Stats {
50
+ private readonly client;
51
+ constructor(client: Client);
52
+ /** Totals for the window, beside the window before it. */
53
+ summary(query?: RangeQuery): Promise<Summary>;
54
+ timeseries(query?: RangeQuery & {
55
+ bucket?: "day" | "hour";
56
+ }): Promise<Timeseries>;
57
+ byModel(query?: RangeQuery): Promise<{
58
+ models: ModelRow[];
59
+ }>;
60
+ byKey(query?: RangeQuery): Promise<Record<string, unknown>>;
61
+ /** Grouped by one metadata tag. `key` picks which tag. */
62
+ byTag(query?: RangeQuery & {
63
+ key?: string;
64
+ }): Promise<Record<string, unknown>>;
65
+ }
@@ -0,0 +1,21 @@
1
+ export class Stats {
2
+ client;
3
+ constructor(client) {
4
+ this.client = client;
5
+ }
6
+ summary(query = {}) {
7
+ return this.client.get("/api/v1/stats/summary", { ...query });
8
+ }
9
+ timeseries(query = {}) {
10
+ return this.client.get("/api/v1/stats/timeseries", { ...query });
11
+ }
12
+ byModel(query = {}) {
13
+ return this.client.get("/api/v1/stats/by-model", { ...query });
14
+ }
15
+ byKey(query = {}) {
16
+ return this.client.get("/api/v1/stats/by-key", { ...query });
17
+ }
18
+ byTag(query = {}) {
19
+ return this.client.get("/api/v1/stats/by-tag", { ...query });
20
+ }
21
+ }