@fulcrum-governance/sdk 0.1.1 → 0.1.3

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 (40) hide show
  1. package/CHANGELOG.md +42 -1
  2. package/README.md +299 -6
  3. package/dist/__tests__/clients.test.d.ts +1 -0
  4. package/dist/__tests__/clients.test.js +847 -0
  5. package/dist/clients/agent.d.ts +70 -0
  6. package/dist/clients/agent.js +127 -0
  7. package/dist/clients/approval.d.ts +67 -0
  8. package/dist/clients/approval.js +103 -0
  9. package/dist/clients/budget.d.ts +221 -0
  10. package/dist/clients/budget.js +181 -0
  11. package/dist/clients/checkpoint.d.ts +191 -0
  12. package/dist/clients/checkpoint.js +195 -0
  13. package/dist/clients/envelope.d.ts +73 -0
  14. package/dist/clients/envelope.js +95 -0
  15. package/dist/clients/eventstore.d.ts +87 -0
  16. package/dist/clients/eventstore.js +113 -0
  17. package/dist/clients/index.d.ts +15 -0
  18. package/dist/clients/index.js +35 -0
  19. package/dist/clients/metrics.d.ts +126 -0
  20. package/dist/clients/metrics.js +162 -0
  21. package/dist/clients/policy.d.ts +83 -0
  22. package/dist/clients/policy.js +102 -0
  23. package/dist/clients/tenant.d.ts +66 -0
  24. package/dist/clients/tenant.js +92 -0
  25. package/dist/index.d.ts +1 -0
  26. package/dist/index.js +25 -3
  27. package/dist/instrumentation/__tests__/autoGovern.test.d.ts +6 -0
  28. package/dist/instrumentation/__tests__/autoGovern.test.js +416 -0
  29. package/dist/instrumentation/__tests__/evaluator.test.d.ts +6 -0
  30. package/dist/instrumentation/__tests__/evaluator.test.js +712 -0
  31. package/dist/instrumentation/autoGovern.d.ts +57 -0
  32. package/dist/instrumentation/autoGovern.js +319 -0
  33. package/dist/instrumentation/evaluator.d.ts +50 -0
  34. package/dist/instrumentation/evaluator.js +218 -0
  35. package/dist/instrumentation/index.d.ts +28 -0
  36. package/dist/instrumentation/index.js +34 -0
  37. package/dist/instrumentation/types.d.ts +105 -0
  38. package/dist/instrumentation/types.js +20 -0
  39. package/package.json +4 -4
  40. package/proto/fulcrum/agent/v1/agent_service.proto +170 -0
@@ -0,0 +1,70 @@
1
+ import * as grpc from '@grpc/grpc-js';
2
+ export interface Agent {
3
+ id: string;
4
+ tenant_id: string;
5
+ name: string;
6
+ description?: string;
7
+ model: string;
8
+ status: 'active' | 'paused' | 'error' | 'deleted';
9
+ environment: string;
10
+ team: string;
11
+ config?: Record<string, any>;
12
+ created_at: Date;
13
+ updated_at: Date;
14
+ }
15
+ export interface CreateAgentRequest {
16
+ name: string;
17
+ description?: string;
18
+ model: string;
19
+ environment: string;
20
+ team: string;
21
+ config?: Record<string, any>;
22
+ }
23
+ export interface UpdateAgentRequest {
24
+ id: string;
25
+ name?: string;
26
+ description?: string;
27
+ status?: 'active' | 'paused' | 'error' | 'deleted';
28
+ config?: Record<string, any>;
29
+ }
30
+ export interface ListAgentsRequest {
31
+ page_size?: number;
32
+ page_token?: string;
33
+ status?: string;
34
+ environment?: string;
35
+ team?: string;
36
+ }
37
+ export interface ListAgentsResponse {
38
+ agents: Agent[];
39
+ next_page_token: string;
40
+ total_count: number;
41
+ }
42
+ export declare class AgentClient {
43
+ private client;
44
+ constructor(address: string, credentials?: grpc.ChannelCredentials);
45
+ /**
46
+ * Creates a new agent for the authenticated tenant.
47
+ */
48
+ createAgent(request: CreateAgentRequest, metadata?: grpc.Metadata): Promise<Agent>;
49
+ /**
50
+ * Retrieves an agent by ID.
51
+ */
52
+ getAgent(id: string, metadata?: grpc.Metadata): Promise<Agent>;
53
+ /**
54
+ * Lists all agents for the authenticated tenant.
55
+ */
56
+ listAgents(request?: ListAgentsRequest, metadata?: grpc.Metadata): Promise<ListAgentsResponse>;
57
+ /**
58
+ * Updates an existing agent.
59
+ */
60
+ updateAgent(request: UpdateAgentRequest, metadata?: grpc.Metadata): Promise<Agent>;
61
+ /**
62
+ * Deletes an agent by ID (soft delete).
63
+ */
64
+ deleteAgent(id: string, metadata?: grpc.Metadata): Promise<boolean>;
65
+ private transformAgent;
66
+ /**
67
+ * Closes the gRPC connection.
68
+ */
69
+ close(): void;
70
+ }
@@ -0,0 +1,127 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.AgentClient = void 0;
40
+ const grpc = __importStar(require("@grpc/grpc-js"));
41
+ const protoLoader = __importStar(require("@grpc/proto-loader"));
42
+ const util_1 = require("util");
43
+ const path_1 = __importDefault(require("path"));
44
+ const PROTO_PATH = path_1.default.join(__dirname, '../../proto/fulcrum/agent/v1/agent_service.proto');
45
+ const packageDefinition = protoLoader.loadSync(PROTO_PATH, {
46
+ keepCase: true,
47
+ longs: String,
48
+ enums: String,
49
+ defaults: true,
50
+ oneofs: true,
51
+ });
52
+ const protoDescriptor = grpc.loadPackageDefinition(packageDefinition);
53
+ const fulcrumPackage = protoDescriptor.fulcrum;
54
+ const agentPackage = fulcrumPackage.agent;
55
+ const agentV1 = agentPackage.v1;
56
+ class AgentClient {
57
+ constructor(address, credentials) {
58
+ const creds = credentials || grpc.credentials.createInsecure();
59
+ this.client = new agentV1.AgentService(address, creds);
60
+ }
61
+ /**
62
+ * Creates a new agent for the authenticated tenant.
63
+ */
64
+ async createAgent(request, metadata) {
65
+ const createAgentAsync = (0, util_1.promisify)(this.client.createAgent.bind(this.client));
66
+ const response = await createAgentAsync(request, metadata);
67
+ return this.transformAgent(response.agent);
68
+ }
69
+ /**
70
+ * Retrieves an agent by ID.
71
+ */
72
+ async getAgent(id, metadata) {
73
+ const getAgentAsync = (0, util_1.promisify)(this.client.getAgent.bind(this.client));
74
+ const response = await getAgentAsync({ id }, metadata);
75
+ return this.transformAgent(response.agent);
76
+ }
77
+ /**
78
+ * Lists all agents for the authenticated tenant.
79
+ */
80
+ async listAgents(request, metadata) {
81
+ const listAgentsAsync = (0, util_1.promisify)(this.client.listAgents.bind(this.client));
82
+ const response = await listAgentsAsync(request || {}, metadata);
83
+ return {
84
+ agents: response.agents.map((a) => this.transformAgent(a)),
85
+ next_page_token: response.next_page_token,
86
+ total_count: response.total_count,
87
+ };
88
+ }
89
+ /**
90
+ * Updates an existing agent.
91
+ */
92
+ async updateAgent(request, metadata) {
93
+ const updateAgentAsync = (0, util_1.promisify)(this.client.updateAgent.bind(this.client));
94
+ const response = await updateAgentAsync(request, metadata);
95
+ return this.transformAgent(response.agent);
96
+ }
97
+ /**
98
+ * Deletes an agent by ID (soft delete).
99
+ */
100
+ async deleteAgent(id, metadata) {
101
+ const deleteAgentAsync = (0, util_1.promisify)(this.client.deleteAgent.bind(this.client));
102
+ const response = await deleteAgentAsync({ id }, metadata);
103
+ return response.success;
104
+ }
105
+ transformAgent(agent) {
106
+ return {
107
+ id: agent.id,
108
+ tenant_id: agent.tenant_id,
109
+ name: agent.name,
110
+ description: agent.description,
111
+ model: agent.model,
112
+ status: agent.status,
113
+ environment: agent.environment,
114
+ team: agent.team,
115
+ config: agent.config,
116
+ created_at: new Date(agent.created_at),
117
+ updated_at: new Date(agent.updated_at),
118
+ };
119
+ }
120
+ /**
121
+ * Closes the gRPC connection.
122
+ */
123
+ close() {
124
+ this.client.close();
125
+ }
126
+ }
127
+ exports.AgentClient = AgentClient;
@@ -0,0 +1,67 @@
1
+ /**
2
+ * ApprovalClient - REST-based client for approval workflow operations
3
+ *
4
+ * Works with the Fulcrum Dashboard REST API for managing approval requests.
5
+ */
6
+ export interface Approval {
7
+ id: string;
8
+ envelope_id: string;
9
+ status: 'PENDING' | 'APPROVED' | 'DENIED';
10
+ reviewer_id?: string;
11
+ review_note?: string;
12
+ created_at?: string;
13
+ updated_at?: string;
14
+ policy_id?: string;
15
+ policy_name?: string;
16
+ action_type?: string;
17
+ request_data?: Record<string, unknown>;
18
+ }
19
+ export interface ApprovalFilter {
20
+ status?: 'PENDING' | 'APPROVED' | 'DENIED';
21
+ envelope_id?: string;
22
+ }
23
+ export interface ApprovalDecision {
24
+ approval_id: string;
25
+ decision: 'APPROVED' | 'DENIED';
26
+ comment?: string;
27
+ }
28
+ export interface ApprovalClientOptions {
29
+ baseUrl: string;
30
+ apiKey?: string;
31
+ timeoutMs?: number;
32
+ }
33
+ export declare class ApprovalClient {
34
+ private baseUrl;
35
+ private apiKey?;
36
+ private timeoutMs;
37
+ constructor(options: ApprovalClientOptions);
38
+ private request;
39
+ /**
40
+ * List approvals, optionally filtered by status
41
+ */
42
+ list(filter?: ApprovalFilter): Promise<Approval[]>;
43
+ /**
44
+ * List only pending approvals
45
+ */
46
+ listPending(): Promise<Approval[]>;
47
+ /**
48
+ * Get a single approval by ID
49
+ */
50
+ get(id: string): Promise<Approval>;
51
+ /**
52
+ * Submit an approval decision (approve or deny)
53
+ */
54
+ decide(decision: ApprovalDecision): Promise<Approval>;
55
+ /**
56
+ * Approve a pending action
57
+ */
58
+ approve(approvalId: string, comment?: string): Promise<Approval>;
59
+ /**
60
+ * Deny a pending action
61
+ */
62
+ deny(approvalId: string, comment: string): Promise<Approval>;
63
+ }
64
+ export declare class ApprovalClientError extends Error {
65
+ statusCode: number;
66
+ constructor(message: string, statusCode: number);
67
+ }
@@ -0,0 +1,103 @@
1
+ "use strict";
2
+ /**
3
+ * ApprovalClient - REST-based client for approval workflow operations
4
+ *
5
+ * Works with the Fulcrum Dashboard REST API for managing approval requests.
6
+ */
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ exports.ApprovalClientError = exports.ApprovalClient = void 0;
9
+ class ApprovalClient {
10
+ constructor(options) {
11
+ this.baseUrl = options.baseUrl.replace(/\/$/, '');
12
+ this.apiKey = options.apiKey;
13
+ this.timeoutMs = options.timeoutMs || 5000;
14
+ }
15
+ async request(method, path, body) {
16
+ const controller = new AbortController();
17
+ const timeout = setTimeout(() => controller.abort(), this.timeoutMs);
18
+ try {
19
+ const headers = {
20
+ 'Content-Type': 'application/json',
21
+ };
22
+ if (this.apiKey) {
23
+ headers['Authorization'] = `Bearer ${this.apiKey}`;
24
+ }
25
+ const response = await fetch(`${this.baseUrl}${path}`, {
26
+ method,
27
+ headers,
28
+ body: body ? JSON.stringify(body) : undefined,
29
+ signal: controller.signal,
30
+ });
31
+ if (!response.ok) {
32
+ const errorData = (await response.json().catch(() => ({})));
33
+ throw new ApprovalClientError(errorData.error || `Request failed with status ${response.status}`, response.status);
34
+ }
35
+ return (await response.json());
36
+ }
37
+ finally {
38
+ clearTimeout(timeout);
39
+ }
40
+ }
41
+ /**
42
+ * List approvals, optionally filtered by status
43
+ */
44
+ async list(filter) {
45
+ const params = new URLSearchParams();
46
+ if (filter?.status)
47
+ params.append('status', filter.status);
48
+ if (filter?.envelope_id)
49
+ params.append('envelope_id', filter.envelope_id);
50
+ const query = params.toString();
51
+ const path = query ? `/api/approvals?${query}` : '/api/approvals';
52
+ const response = await this.request('GET', path);
53
+ return response.approvals;
54
+ }
55
+ /**
56
+ * List only pending approvals
57
+ */
58
+ async listPending() {
59
+ return this.list({ status: 'PENDING' });
60
+ }
61
+ /**
62
+ * Get a single approval by ID
63
+ */
64
+ async get(id) {
65
+ return this.request('GET', `/api/approvals/${id}`);
66
+ }
67
+ /**
68
+ * Submit an approval decision (approve or deny)
69
+ */
70
+ async decide(decision) {
71
+ const response = await this.request('POST', '/api/approvals', decision);
72
+ return response.approval;
73
+ }
74
+ /**
75
+ * Approve a pending action
76
+ */
77
+ async approve(approvalId, comment) {
78
+ return this.decide({
79
+ approval_id: approvalId,
80
+ decision: 'APPROVED',
81
+ comment,
82
+ });
83
+ }
84
+ /**
85
+ * Deny a pending action
86
+ */
87
+ async deny(approvalId, comment) {
88
+ return this.decide({
89
+ approval_id: approvalId,
90
+ decision: 'DENIED',
91
+ comment,
92
+ });
93
+ }
94
+ }
95
+ exports.ApprovalClient = ApprovalClient;
96
+ class ApprovalClientError extends Error {
97
+ constructor(message, statusCode) {
98
+ super(message);
99
+ this.statusCode = statusCode;
100
+ this.name = 'ApprovalClientError';
101
+ }
102
+ }
103
+ exports.ApprovalClientError = ApprovalClientError;
@@ -0,0 +1,221 @@
1
+ /**
2
+ * BudgetClient - REST-based client for budget management operations
3
+ *
4
+ * Works with the Fulcrum Dashboard REST API for managing budgets.
5
+ */
6
+ export type BudgetScope = 'GLOBAL' | 'TENANT' | 'WORKFLOW' | 'MODEL';
7
+ export type BudgetPeriod = 'DAILY' | 'WEEKLY' | 'MONTHLY' | 'QUARTERLY';
8
+ export type BudgetAction = 'WARN' | 'SOFT_LIMIT' | 'HARD_LIMIT';
9
+ export type BudgetStatus = 'active' | 'warning' | 'exceeded' | 'disabled';
10
+ export interface Budget {
11
+ id: string;
12
+ org_id: string;
13
+ name: string;
14
+ scope: BudgetScope;
15
+ scope_id: string | null;
16
+ scope_name?: string;
17
+ limit_amount: number;
18
+ period: BudgetPeriod;
19
+ action: BudgetAction;
20
+ alert_thresholds: number[];
21
+ current_spend: number;
22
+ period_start: string;
23
+ created_by: string;
24
+ created_at: string;
25
+ updated_at: string;
26
+ last_alert_sent: string | null;
27
+ status: BudgetStatus;
28
+ percentage: number;
29
+ }
30
+ export interface BudgetSummary {
31
+ total: number;
32
+ active: number;
33
+ exceeded: number;
34
+ totalLimit: number;
35
+ totalSpend: number;
36
+ }
37
+ export interface BudgetsResponse {
38
+ budgets: Budget[];
39
+ summary: BudgetSummary;
40
+ }
41
+ export interface BudgetFilter {
42
+ scope?: BudgetScope;
43
+ status?: BudgetStatus;
44
+ }
45
+ export interface CreateBudgetRequest {
46
+ name: string;
47
+ scope: BudgetScope;
48
+ scope_id?: string;
49
+ scope_name?: string;
50
+ limit_amount: number;
51
+ period: BudgetPeriod;
52
+ action: BudgetAction;
53
+ alert_thresholds?: number[];
54
+ }
55
+ export interface UpdateBudgetRequest {
56
+ name?: string;
57
+ limit_amount?: number;
58
+ period?: BudgetPeriod;
59
+ action?: BudgetAction;
60
+ alert_thresholds?: number[];
61
+ }
62
+ export interface BudgetClientOptions {
63
+ baseUrl: string;
64
+ apiKey?: string;
65
+ timeoutMs?: number;
66
+ }
67
+ export declare class BudgetClient {
68
+ private baseUrl;
69
+ private apiKey?;
70
+ private timeoutMs;
71
+ constructor(options: BudgetClientOptions);
72
+ private request;
73
+ /**
74
+ * List all budgets with optional filter
75
+ * Returns budgets and summary statistics
76
+ */
77
+ list(filter?: BudgetFilter): Promise<BudgetsResponse>;
78
+ /**
79
+ * Get budgets only (without summary)
80
+ */
81
+ listBudgets(filter?: BudgetFilter): Promise<Budget[]>;
82
+ /**
83
+ * Get budget summary only
84
+ */
85
+ getSummary(): Promise<BudgetSummary>;
86
+ /**
87
+ * Get a single budget by ID
88
+ */
89
+ get(id: string): Promise<Budget>;
90
+ /**
91
+ * Create a new budget
92
+ */
93
+ create(budget: CreateBudgetRequest): Promise<Budget>;
94
+ /**
95
+ * Update an existing budget
96
+ */
97
+ update(id: string, updates: UpdateBudgetRequest): Promise<Budget>;
98
+ /**
99
+ * Delete a budget
100
+ */
101
+ delete(id: string): Promise<void>;
102
+ /**
103
+ * Get budgets that have exceeded their limits
104
+ */
105
+ getExceeded(): Promise<Budget[]>;
106
+ /**
107
+ * Get budgets in warning state
108
+ */
109
+ getWarnings(): Promise<Budget[]>;
110
+ /**
111
+ * Calculate spending percentage for a budget
112
+ */
113
+ calculatePercentage(budget: Budget): number;
114
+ /**
115
+ * Check if budget is at or above a threshold
116
+ */
117
+ isAtThreshold(budget: Budget, threshold: number): boolean;
118
+ /**
119
+ * Get cost summary for a specific execution envelope
120
+ */
121
+ getCostSummary(envelopeId: string): Promise<CostSummary>;
122
+ /**
123
+ * Get aggregated spend summary with optional filtering and grouping
124
+ */
125
+ getSpendSummary(options?: SpendSummaryOptions): Promise<SpendSummaryResponse>;
126
+ /**
127
+ * Get detailed status for a budget including usage percentages
128
+ */
129
+ getBudgetStatus(budgetId: string): Promise<BudgetStatusDetail>;
130
+ /**
131
+ * Predict cost for a planned execution
132
+ */
133
+ predictCost(request: PredictCostRequest): Promise<CostPrediction>;
134
+ }
135
+ export interface CostSummary {
136
+ total_tokens: number;
137
+ total_input_tokens: number;
138
+ total_output_tokens: number;
139
+ total_cost_usd: number;
140
+ total_llm_calls: number;
141
+ total_tool_calls: number;
142
+ }
143
+ export interface SpendSummary {
144
+ total_tokens: number;
145
+ total_input_tokens: number;
146
+ total_output_tokens: number;
147
+ total_cost_usd: number;
148
+ total_llm_calls: number;
149
+ total_tool_calls: number;
150
+ total_executions: number;
151
+ completed_executions: number;
152
+ failed_executions: number;
153
+ terminated_executions: number;
154
+ total_execution_time_seconds: number;
155
+ average_execution_time_seconds: number;
156
+ period_start?: string;
157
+ period_end?: string;
158
+ }
159
+ export type SpendGroupBy = 'MODEL' | 'DAY' | 'WEEK' | 'MONTH' | 'WORKFLOW';
160
+ export interface SpendSummaryOptions {
161
+ tenantId?: string;
162
+ workflowId?: string;
163
+ startTime?: string;
164
+ endTime?: string;
165
+ groupBy?: SpendGroupBy;
166
+ }
167
+ export interface GroupedSpendSummary {
168
+ group_key: string;
169
+ summary: SpendSummary;
170
+ }
171
+ export interface SpendSummaryResponse {
172
+ summary: SpendSummary;
173
+ grouped_summaries: GroupedSpendSummary[];
174
+ }
175
+ export interface BudgetStatusDetail {
176
+ budget_id: string;
177
+ status: string;
178
+ token_usage_percent: number;
179
+ cost_usage_percent: number;
180
+ llm_call_usage_percent: number;
181
+ tool_call_usage_percent: number;
182
+ remaining?: {
183
+ max_tokens?: number;
184
+ max_cost_usd?: number;
185
+ };
186
+ current_spend?: SpendSummary;
187
+ updated_at?: string;
188
+ }
189
+ export interface PredictCostRequest {
190
+ tenant_id?: string;
191
+ workflow_id?: string;
192
+ input_text?: string;
193
+ estimated_input_tokens?: number;
194
+ model_ids?: string[];
195
+ use_historical_data?: boolean;
196
+ lookback_days?: number;
197
+ }
198
+ export interface ModelCostPrediction {
199
+ model_id: string;
200
+ estimated_tokens: number;
201
+ estimated_cost_usd: number;
202
+ estimated_calls: number;
203
+ }
204
+ export interface CostPrediction {
205
+ estimated_input_tokens: number;
206
+ estimated_output_tokens: number;
207
+ estimated_total_tokens: number;
208
+ estimated_cost_usd: number;
209
+ estimated_cost_usd_min: number;
210
+ estimated_cost_usd_max: number;
211
+ confidence: number;
212
+ confidence_level: string;
213
+ estimated_duration_seconds: number;
214
+ model_predictions: ModelCostPrediction[];
215
+ historical_based: boolean;
216
+ sample_size: number;
217
+ }
218
+ export declare class BudgetClientError extends Error {
219
+ statusCode: number;
220
+ constructor(message: string, statusCode: number);
221
+ }