@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.
- package/CHANGELOG.md +42 -1
- package/README.md +299 -6
- package/dist/__tests__/clients.test.d.ts +1 -0
- package/dist/__tests__/clients.test.js +847 -0
- package/dist/clients/agent.d.ts +70 -0
- package/dist/clients/agent.js +127 -0
- package/dist/clients/approval.d.ts +67 -0
- package/dist/clients/approval.js +103 -0
- package/dist/clients/budget.d.ts +221 -0
- package/dist/clients/budget.js +181 -0
- package/dist/clients/checkpoint.d.ts +191 -0
- package/dist/clients/checkpoint.js +195 -0
- package/dist/clients/envelope.d.ts +73 -0
- package/dist/clients/envelope.js +95 -0
- package/dist/clients/eventstore.d.ts +87 -0
- package/dist/clients/eventstore.js +113 -0
- package/dist/clients/index.d.ts +15 -0
- package/dist/clients/index.js +35 -0
- package/dist/clients/metrics.d.ts +126 -0
- package/dist/clients/metrics.js +162 -0
- package/dist/clients/policy.d.ts +83 -0
- package/dist/clients/policy.js +102 -0
- package/dist/clients/tenant.d.ts +66 -0
- package/dist/clients/tenant.js +92 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +25 -3
- package/dist/instrumentation/__tests__/autoGovern.test.d.ts +6 -0
- package/dist/instrumentation/__tests__/autoGovern.test.js +416 -0
- package/dist/instrumentation/__tests__/evaluator.test.d.ts +6 -0
- package/dist/instrumentation/__tests__/evaluator.test.js +712 -0
- package/dist/instrumentation/autoGovern.d.ts +57 -0
- package/dist/instrumentation/autoGovern.js +319 -0
- package/dist/instrumentation/evaluator.d.ts +50 -0
- package/dist/instrumentation/evaluator.js +218 -0
- package/dist/instrumentation/index.d.ts +28 -0
- package/dist/instrumentation/index.js +34 -0
- package/dist/instrumentation/types.d.ts +105 -0
- package/dist/instrumentation/types.js +20 -0
- package/package.json +4 -4
- package/proto/fulcrum/agent/v1/agent_service.proto +170 -0
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* BudgetClient - REST-based client for budget management operations
|
|
4
|
+
*
|
|
5
|
+
* Works with the Fulcrum Dashboard REST API for managing budgets.
|
|
6
|
+
*/
|
|
7
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
+
exports.BudgetClientError = exports.BudgetClient = void 0;
|
|
9
|
+
class BudgetClient {
|
|
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 BudgetClientError(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 all budgets with optional filter
|
|
43
|
+
* Returns budgets and summary statistics
|
|
44
|
+
*/
|
|
45
|
+
async list(filter) {
|
|
46
|
+
const params = new URLSearchParams();
|
|
47
|
+
if (filter?.scope)
|
|
48
|
+
params.append('scope', filter.scope);
|
|
49
|
+
if (filter?.status)
|
|
50
|
+
params.append('status', filter.status);
|
|
51
|
+
const query = params.toString();
|
|
52
|
+
const path = query ? `/api/budgets?${query}` : '/api/budgets';
|
|
53
|
+
return this.request('GET', path);
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Get budgets only (without summary)
|
|
57
|
+
*/
|
|
58
|
+
async listBudgets(filter) {
|
|
59
|
+
const response = await this.list(filter);
|
|
60
|
+
return response.budgets;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Get budget summary only
|
|
64
|
+
*/
|
|
65
|
+
async getSummary() {
|
|
66
|
+
const response = await this.list();
|
|
67
|
+
return response.summary;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Get a single budget by ID
|
|
71
|
+
*/
|
|
72
|
+
async get(id) {
|
|
73
|
+
return this.request('GET', `/api/budgets/${id}`);
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Create a new budget
|
|
77
|
+
*/
|
|
78
|
+
async create(budget) {
|
|
79
|
+
const response = await this.request('POST', '/api/budgets', budget);
|
|
80
|
+
return response.budget;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Update an existing budget
|
|
84
|
+
*/
|
|
85
|
+
async update(id, updates) {
|
|
86
|
+
return this.request('PATCH', `/api/budgets/${id}`, updates);
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Delete a budget
|
|
90
|
+
*/
|
|
91
|
+
async delete(id) {
|
|
92
|
+
await this.request('DELETE', `/api/budgets/${id}`);
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Get budgets that have exceeded their limits
|
|
96
|
+
*/
|
|
97
|
+
async getExceeded() {
|
|
98
|
+
const response = await this.list({ status: 'exceeded' });
|
|
99
|
+
return response.budgets;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Get budgets in warning state
|
|
103
|
+
*/
|
|
104
|
+
async getWarnings() {
|
|
105
|
+
const response = await this.list({ status: 'warning' });
|
|
106
|
+
return response.budgets;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Calculate spending percentage for a budget
|
|
110
|
+
*/
|
|
111
|
+
calculatePercentage(budget) {
|
|
112
|
+
if (budget.limit_amount <= 0)
|
|
113
|
+
return 0;
|
|
114
|
+
return Math.round((budget.current_spend / budget.limit_amount) * 100);
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Check if budget is at or above a threshold
|
|
118
|
+
*/
|
|
119
|
+
isAtThreshold(budget, threshold) {
|
|
120
|
+
const percentage = this.calculatePercentage(budget);
|
|
121
|
+
return percentage >= threshold;
|
|
122
|
+
}
|
|
123
|
+
// ===== Cost Service Methods =====
|
|
124
|
+
/**
|
|
125
|
+
* Get cost summary for a specific execution envelope
|
|
126
|
+
*/
|
|
127
|
+
async getCostSummary(envelopeId) {
|
|
128
|
+
const response = await this.request('GET', `/v1/costs/${envelopeId}`);
|
|
129
|
+
return 'cost_summary' in response && response.cost_summary
|
|
130
|
+
? response.cost_summary
|
|
131
|
+
: response;
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Get aggregated spend summary with optional filtering and grouping
|
|
135
|
+
*/
|
|
136
|
+
async getSpendSummary(options) {
|
|
137
|
+
const params = new URLSearchParams();
|
|
138
|
+
if (options?.tenantId)
|
|
139
|
+
params.append('tenant_id', options.tenantId);
|
|
140
|
+
if (options?.workflowId)
|
|
141
|
+
params.append('workflow_id', options.workflowId);
|
|
142
|
+
if (options?.startTime)
|
|
143
|
+
params.append('start_time', options.startTime);
|
|
144
|
+
if (options?.endTime)
|
|
145
|
+
params.append('end_time', options.endTime);
|
|
146
|
+
if (options?.groupBy)
|
|
147
|
+
params.append('group_by', options.groupBy);
|
|
148
|
+
const query = params.toString();
|
|
149
|
+
const path = query ? `/v1/spend?${query}` : '/v1/spend';
|
|
150
|
+
return this.request('GET', path);
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Get detailed status for a budget including usage percentages
|
|
154
|
+
*/
|
|
155
|
+
async getBudgetStatus(budgetId) {
|
|
156
|
+
const response = await this.request('GET', `/v1/budgets/${budgetId}/status`);
|
|
157
|
+
if (response.status) {
|
|
158
|
+
return response.status;
|
|
159
|
+
}
|
|
160
|
+
// If response doesn't have status wrapper, treat response as the status itself
|
|
161
|
+
return response;
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Predict cost for a planned execution
|
|
165
|
+
*/
|
|
166
|
+
async predictCost(request) {
|
|
167
|
+
const response = await this.request('POST', '/v1/costs/predict', request);
|
|
168
|
+
return 'prediction' in response && response.prediction
|
|
169
|
+
? response.prediction
|
|
170
|
+
: response;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
exports.BudgetClient = BudgetClient;
|
|
174
|
+
class BudgetClientError extends Error {
|
|
175
|
+
constructor(message, statusCode) {
|
|
176
|
+
super(message);
|
|
177
|
+
this.statusCode = statusCode;
|
|
178
|
+
this.name = 'BudgetClientError';
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
exports.BudgetClientError = BudgetClientError;
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CheckpointClient - REST-based client for checkpoint management operations
|
|
3
|
+
*
|
|
4
|
+
* Works with the Fulcrum API for managing execution checkpoints and context.
|
|
5
|
+
*/
|
|
6
|
+
export type CheckpointType = 'UNSPECIFIED' | 'MANUAL' | 'AUTO' | 'PRE_TERMINATE' | 'ERROR' | 'MILESTONE';
|
|
7
|
+
export type ContextScope = 'UNSPECIFIED' | 'EXECUTION' | 'WORKFLOW' | 'TENANT';
|
|
8
|
+
export type MergeStrategy = 'UNSPECIFIED' | 'LAST_WRITE_WINS' | 'FAIL_ON_CONFLICT' | 'MERGE_RECURSIVE' | 'CUSTOM';
|
|
9
|
+
export interface CheckpointMetadata {
|
|
10
|
+
type: CheckpointType;
|
|
11
|
+
framework_type: string;
|
|
12
|
+
framework_version: string;
|
|
13
|
+
execution_status: string;
|
|
14
|
+
step_count: number;
|
|
15
|
+
current_node: string;
|
|
16
|
+
cost_snapshot_usd: number;
|
|
17
|
+
tokens_consumed: number;
|
|
18
|
+
tags: Record<string, string>;
|
|
19
|
+
description: string;
|
|
20
|
+
compressed: boolean;
|
|
21
|
+
compression_algorithm: string;
|
|
22
|
+
}
|
|
23
|
+
export interface Checkpoint {
|
|
24
|
+
checkpoint_id: string;
|
|
25
|
+
envelope_id: string;
|
|
26
|
+
execution_id: string;
|
|
27
|
+
tenant_id: string;
|
|
28
|
+
version: number;
|
|
29
|
+
parent_version: string;
|
|
30
|
+
metadata?: CheckpointMetadata;
|
|
31
|
+
data: Record<string, unknown>;
|
|
32
|
+
created_at: string;
|
|
33
|
+
expires_at?: string;
|
|
34
|
+
size_bytes: number;
|
|
35
|
+
save_duration_ms: number;
|
|
36
|
+
}
|
|
37
|
+
export interface CheckpointVersion {
|
|
38
|
+
checkpoint_id: string;
|
|
39
|
+
version: number;
|
|
40
|
+
parent_version: string;
|
|
41
|
+
created_at: string;
|
|
42
|
+
metadata?: CheckpointMetadata;
|
|
43
|
+
size_bytes: number;
|
|
44
|
+
}
|
|
45
|
+
export interface ExecutionContext {
|
|
46
|
+
execution_id: string;
|
|
47
|
+
tenant_id: string;
|
|
48
|
+
workflow_id: string;
|
|
49
|
+
scope: ContextScope;
|
|
50
|
+
data: Record<string, unknown>;
|
|
51
|
+
parent_execution_id: string;
|
|
52
|
+
inherited_keys: string[];
|
|
53
|
+
version: number;
|
|
54
|
+
updated_at: string;
|
|
55
|
+
}
|
|
56
|
+
export interface CheckpointData {
|
|
57
|
+
envelope_id: string;
|
|
58
|
+
execution_id: string;
|
|
59
|
+
tenant_id: string;
|
|
60
|
+
data: Record<string, unknown>;
|
|
61
|
+
metadata?: Partial<CheckpointMetadata>;
|
|
62
|
+
}
|
|
63
|
+
export interface SaveCheckpointRequest {
|
|
64
|
+
checkpoint: CheckpointData;
|
|
65
|
+
auto_version?: boolean;
|
|
66
|
+
max_versions?: number;
|
|
67
|
+
}
|
|
68
|
+
export interface SaveCheckpointResponse {
|
|
69
|
+
checkpoint_id: string;
|
|
70
|
+
version: number;
|
|
71
|
+
created_at: string;
|
|
72
|
+
}
|
|
73
|
+
export interface CheckpointQuery {
|
|
74
|
+
tenant_ids?: string[];
|
|
75
|
+
envelope_ids?: string[];
|
|
76
|
+
execution_ids?: string[];
|
|
77
|
+
types?: CheckpointType[];
|
|
78
|
+
created_after?: string;
|
|
79
|
+
created_before?: string;
|
|
80
|
+
framework_types?: string[];
|
|
81
|
+
tags?: Record<string, string>;
|
|
82
|
+
min_cost_usd?: number;
|
|
83
|
+
max_cost_usd?: number;
|
|
84
|
+
min_size_bytes?: number;
|
|
85
|
+
max_size_bytes?: number;
|
|
86
|
+
}
|
|
87
|
+
export interface ListCheckpointsOptions {
|
|
88
|
+
tenant_id?: string;
|
|
89
|
+
envelope_id?: string;
|
|
90
|
+
execution_id?: string;
|
|
91
|
+
page_size?: number;
|
|
92
|
+
page_token?: string;
|
|
93
|
+
order_by?: string;
|
|
94
|
+
}
|
|
95
|
+
export interface ListCheckpointsResponse {
|
|
96
|
+
checkpoints: Checkpoint[];
|
|
97
|
+
next_page_token: string;
|
|
98
|
+
total_count: number;
|
|
99
|
+
}
|
|
100
|
+
export interface ListVersionsResponse {
|
|
101
|
+
versions: CheckpointVersion[];
|
|
102
|
+
next_page_token: string;
|
|
103
|
+
total_count: number;
|
|
104
|
+
}
|
|
105
|
+
export interface UpdateContextRequest {
|
|
106
|
+
updates: Record<string, unknown>;
|
|
107
|
+
delete_keys?: string[];
|
|
108
|
+
expected_version?: number;
|
|
109
|
+
merge_strategy?: MergeStrategy;
|
|
110
|
+
}
|
|
111
|
+
export interface UpdateContextResponse {
|
|
112
|
+
context: ExecutionContext | null;
|
|
113
|
+
conflict_detected: boolean;
|
|
114
|
+
conflict_resolution: string;
|
|
115
|
+
}
|
|
116
|
+
export interface CheckpointClientOptions {
|
|
117
|
+
baseUrl: string;
|
|
118
|
+
apiKey?: string;
|
|
119
|
+
timeoutMs?: number;
|
|
120
|
+
}
|
|
121
|
+
export declare class CheckpointClient {
|
|
122
|
+
private baseUrl;
|
|
123
|
+
private apiKey?;
|
|
124
|
+
private timeoutMs;
|
|
125
|
+
constructor(options: CheckpointClientOptions);
|
|
126
|
+
private request;
|
|
127
|
+
/**
|
|
128
|
+
* Save a new checkpoint
|
|
129
|
+
*/
|
|
130
|
+
saveCheckpoint(request: SaveCheckpointRequest): Promise<SaveCheckpointResponse>;
|
|
131
|
+
/**
|
|
132
|
+
* Get a checkpoint by ID
|
|
133
|
+
*/
|
|
134
|
+
getCheckpoint(checkpointId: string, version?: number): Promise<Checkpoint>;
|
|
135
|
+
/**
|
|
136
|
+
* List checkpoints with optional filtering
|
|
137
|
+
*/
|
|
138
|
+
listCheckpoints(options?: ListCheckpointsOptions): Promise<ListCheckpointsResponse>;
|
|
139
|
+
/**
|
|
140
|
+
* Delete a checkpoint
|
|
141
|
+
*/
|
|
142
|
+
deleteCheckpoint(checkpointId: string, options?: {
|
|
143
|
+
softDelete?: boolean;
|
|
144
|
+
deleteAllVersions?: boolean;
|
|
145
|
+
}): Promise<{
|
|
146
|
+
success: boolean;
|
|
147
|
+
versions_deleted: number;
|
|
148
|
+
}>;
|
|
149
|
+
/**
|
|
150
|
+
* List all versions of checkpoints for an execution
|
|
151
|
+
*/
|
|
152
|
+
listCheckpointVersions(executionId: string, options?: {
|
|
153
|
+
pageSize?: number;
|
|
154
|
+
pageToken?: string;
|
|
155
|
+
}): Promise<ListVersionsResponse>;
|
|
156
|
+
/**
|
|
157
|
+
* Get a specific version of a checkpoint
|
|
158
|
+
*/
|
|
159
|
+
getCheckpointVersion(executionId: string, version: number): Promise<Checkpoint>;
|
|
160
|
+
/**
|
|
161
|
+
* Query checkpoints with advanced filtering
|
|
162
|
+
*/
|
|
163
|
+
queryCheckpoints(query: CheckpointQuery, options?: {
|
|
164
|
+
pageSize?: number;
|
|
165
|
+
pageToken?: string;
|
|
166
|
+
orderBy?: string;
|
|
167
|
+
}): Promise<ListCheckpointsResponse>;
|
|
168
|
+
/**
|
|
169
|
+
* Get execution context (shared state)
|
|
170
|
+
*/
|
|
171
|
+
getExecutionContext(executionId: string, options?: {
|
|
172
|
+
keys?: string[];
|
|
173
|
+
includeInherited?: boolean;
|
|
174
|
+
}): Promise<ExecutionContext>;
|
|
175
|
+
/**
|
|
176
|
+
* Update execution context with merge/conflict handling
|
|
177
|
+
*/
|
|
178
|
+
updateExecutionContext(executionId: string, request: UpdateContextRequest): Promise<UpdateContextResponse>;
|
|
179
|
+
/**
|
|
180
|
+
* Get the most recent checkpoint for an execution
|
|
181
|
+
*/
|
|
182
|
+
getLatestCheckpoint(executionId: string): Promise<Checkpoint | null>;
|
|
183
|
+
/**
|
|
184
|
+
* Check if any checkpoint exists for an execution
|
|
185
|
+
*/
|
|
186
|
+
checkpointExists(executionId: string): Promise<boolean>;
|
|
187
|
+
}
|
|
188
|
+
export declare class CheckpointClientError extends Error {
|
|
189
|
+
statusCode: number;
|
|
190
|
+
constructor(message: string, statusCode: number);
|
|
191
|
+
}
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* CheckpointClient - REST-based client for checkpoint management operations
|
|
4
|
+
*
|
|
5
|
+
* Works with the Fulcrum API for managing execution checkpoints and context.
|
|
6
|
+
*/
|
|
7
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
+
exports.CheckpointClientError = exports.CheckpointClient = void 0;
|
|
9
|
+
class CheckpointClient {
|
|
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 CheckpointClientError(errorData.error || `Request failed with status ${response.status}`, response.status);
|
|
34
|
+
}
|
|
35
|
+
const text = await response.text();
|
|
36
|
+
return text ? JSON.parse(text) : {};
|
|
37
|
+
}
|
|
38
|
+
finally {
|
|
39
|
+
clearTimeout(timeout);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Save a new checkpoint
|
|
44
|
+
*/
|
|
45
|
+
async saveCheckpoint(request) {
|
|
46
|
+
return this.request('POST', '/v1/checkpoints', request);
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Get a checkpoint by ID
|
|
50
|
+
*/
|
|
51
|
+
async getCheckpoint(checkpointId, version) {
|
|
52
|
+
const params = new URLSearchParams();
|
|
53
|
+
if (version !== undefined)
|
|
54
|
+
params.append('version', version.toString());
|
|
55
|
+
const query = params.toString();
|
|
56
|
+
const path = query
|
|
57
|
+
? `/v1/checkpoints/${checkpointId}?${query}`
|
|
58
|
+
: `/v1/checkpoints/${checkpointId}`;
|
|
59
|
+
const response = await this.request('GET', path);
|
|
60
|
+
return 'checkpoint' in response && response.checkpoint
|
|
61
|
+
? response.checkpoint
|
|
62
|
+
: response;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* List checkpoints with optional filtering
|
|
66
|
+
*/
|
|
67
|
+
async listCheckpoints(options) {
|
|
68
|
+
const params = new URLSearchParams();
|
|
69
|
+
if (options?.tenant_id)
|
|
70
|
+
params.append('tenant_id', options.tenant_id);
|
|
71
|
+
if (options?.envelope_id)
|
|
72
|
+
params.append('envelope_id', options.envelope_id);
|
|
73
|
+
if (options?.execution_id)
|
|
74
|
+
params.append('execution_id', options.execution_id);
|
|
75
|
+
if (options?.page_size)
|
|
76
|
+
params.append('page_size', options.page_size.toString());
|
|
77
|
+
if (options?.page_token)
|
|
78
|
+
params.append('page_token', options.page_token);
|
|
79
|
+
if (options?.order_by)
|
|
80
|
+
params.append('order_by', options.order_by);
|
|
81
|
+
const query = params.toString();
|
|
82
|
+
const path = query ? `/v1/checkpoints?${query}` : '/v1/checkpoints';
|
|
83
|
+
return this.request('GET', path);
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Delete a checkpoint
|
|
87
|
+
*/
|
|
88
|
+
async deleteCheckpoint(checkpointId, options) {
|
|
89
|
+
const params = new URLSearchParams();
|
|
90
|
+
if (options?.softDelete)
|
|
91
|
+
params.append('soft_delete', 'true');
|
|
92
|
+
if (options?.deleteAllVersions)
|
|
93
|
+
params.append('delete_all_versions', 'true');
|
|
94
|
+
const query = params.toString();
|
|
95
|
+
const path = query
|
|
96
|
+
? `/v1/checkpoints/${checkpointId}?${query}`
|
|
97
|
+
: `/v1/checkpoints/${checkpointId}`;
|
|
98
|
+
const response = await this.request('DELETE', path);
|
|
99
|
+
return {
|
|
100
|
+
success: response?.success ?? true,
|
|
101
|
+
versions_deleted: response?.versions_deleted ?? 1,
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* List all versions of checkpoints for an execution
|
|
106
|
+
*/
|
|
107
|
+
async listCheckpointVersions(executionId, options) {
|
|
108
|
+
const params = new URLSearchParams();
|
|
109
|
+
if (options?.pageSize)
|
|
110
|
+
params.append('page_size', options.pageSize.toString());
|
|
111
|
+
if (options?.pageToken)
|
|
112
|
+
params.append('page_token', options.pageToken);
|
|
113
|
+
const query = params.toString();
|
|
114
|
+
const path = query
|
|
115
|
+
? `/v1/checkpoints/${executionId}/versions?${query}`
|
|
116
|
+
: `/v1/checkpoints/${executionId}/versions`;
|
|
117
|
+
return this.request('GET', path);
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Get a specific version of a checkpoint
|
|
121
|
+
*/
|
|
122
|
+
async getCheckpointVersion(executionId, version) {
|
|
123
|
+
const response = await this.request('GET', `/v1/checkpoints/${executionId}/versions/${version}`);
|
|
124
|
+
return 'checkpoint' in response && response.checkpoint
|
|
125
|
+
? response.checkpoint
|
|
126
|
+
: response;
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Query checkpoints with advanced filtering
|
|
130
|
+
*/
|
|
131
|
+
async queryCheckpoints(query, options) {
|
|
132
|
+
const body = {
|
|
133
|
+
query,
|
|
134
|
+
page_size: options?.pageSize ?? 20,
|
|
135
|
+
page_token: options?.pageToken,
|
|
136
|
+
order_by: options?.orderBy,
|
|
137
|
+
};
|
|
138
|
+
return this.request('POST', '/v1/checkpoints:query', body);
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Get execution context (shared state)
|
|
142
|
+
*/
|
|
143
|
+
async getExecutionContext(executionId, options) {
|
|
144
|
+
const params = new URLSearchParams();
|
|
145
|
+
if (options?.keys?.length)
|
|
146
|
+
params.append('keys', options.keys.join(','));
|
|
147
|
+
if (options?.includeInherited)
|
|
148
|
+
params.append('include_inherited', 'true');
|
|
149
|
+
const query = params.toString();
|
|
150
|
+
const path = query
|
|
151
|
+
? `/v1/executions/${executionId}/context?${query}`
|
|
152
|
+
: `/v1/executions/${executionId}/context`;
|
|
153
|
+
const response = await this.request('GET', path);
|
|
154
|
+
return 'context' in response && response.context
|
|
155
|
+
? response.context
|
|
156
|
+
: response;
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Update execution context with merge/conflict handling
|
|
160
|
+
*/
|
|
161
|
+
async updateExecutionContext(executionId, request) {
|
|
162
|
+
return this.request('PATCH', `/v1/executions/${executionId}/context`, request);
|
|
163
|
+
}
|
|
164
|
+
// ===== Convenience Methods =====
|
|
165
|
+
/**
|
|
166
|
+
* Get the most recent checkpoint for an execution
|
|
167
|
+
*/
|
|
168
|
+
async getLatestCheckpoint(executionId) {
|
|
169
|
+
const response = await this.listCheckpoints({
|
|
170
|
+
execution_id: executionId,
|
|
171
|
+
page_size: 1,
|
|
172
|
+
order_by: 'created_at desc',
|
|
173
|
+
});
|
|
174
|
+
return response.checkpoints.length > 0 ? response.checkpoints[0] : null;
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Check if any checkpoint exists for an execution
|
|
178
|
+
*/
|
|
179
|
+
async checkpointExists(executionId) {
|
|
180
|
+
const response = await this.listCheckpoints({
|
|
181
|
+
execution_id: executionId,
|
|
182
|
+
page_size: 1,
|
|
183
|
+
});
|
|
184
|
+
return response.total_count > 0;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
exports.CheckpointClient = CheckpointClient;
|
|
188
|
+
class CheckpointClientError extends Error {
|
|
189
|
+
constructor(message, statusCode) {
|
|
190
|
+
super(message);
|
|
191
|
+
this.statusCode = statusCode;
|
|
192
|
+
this.name = 'CheckpointClientError';
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
exports.CheckpointClientError = CheckpointClientError;
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* EnvelopeClient - REST-based client for envelope management
|
|
3
|
+
*
|
|
4
|
+
* Works with the Fulcrum API for managing execution envelopes that wrap AI agent operations.
|
|
5
|
+
*/
|
|
6
|
+
export type EnvelopeStatus = 'PENDING' | 'RUNNING' | 'COMPLETED' | 'FAILED' | 'CANCELLED' | 'TIMEOUT';
|
|
7
|
+
export interface EnvelopeData {
|
|
8
|
+
envelope_id: string;
|
|
9
|
+
tenant_id: string;
|
|
10
|
+
budget_id?: string;
|
|
11
|
+
adapter_type: string;
|
|
12
|
+
workflow_id: string;
|
|
13
|
+
status: EnvelopeStatus;
|
|
14
|
+
metadata: Record<string, string>;
|
|
15
|
+
created_at: string;
|
|
16
|
+
updated_at: string;
|
|
17
|
+
completed_at?: string;
|
|
18
|
+
cost_usd: number;
|
|
19
|
+
token_count: number;
|
|
20
|
+
error_message?: string;
|
|
21
|
+
}
|
|
22
|
+
export interface CreateEnvelopeRequest {
|
|
23
|
+
tenant_id: string;
|
|
24
|
+
adapter_type: string;
|
|
25
|
+
workflow_id: string;
|
|
26
|
+
budget_id?: string;
|
|
27
|
+
metadata?: Record<string, string>;
|
|
28
|
+
}
|
|
29
|
+
export interface UpdateEnvelopeStatusRequest {
|
|
30
|
+
envelope_id: string;
|
|
31
|
+
status: EnvelopeStatus;
|
|
32
|
+
error_message?: string;
|
|
33
|
+
}
|
|
34
|
+
export interface ListEnvelopesRequest {
|
|
35
|
+
tenant_id?: string;
|
|
36
|
+
workflow_id?: string;
|
|
37
|
+
status?: EnvelopeStatus;
|
|
38
|
+
limit?: number;
|
|
39
|
+
offset?: number;
|
|
40
|
+
}
|
|
41
|
+
export declare class EnvelopeClientError extends Error {
|
|
42
|
+
statusCode?: number | undefined;
|
|
43
|
+
response?: unknown | undefined;
|
|
44
|
+
constructor(message: string, statusCode?: number | undefined, response?: unknown | undefined);
|
|
45
|
+
}
|
|
46
|
+
export interface EnvelopeClientOptions {
|
|
47
|
+
baseUrl: string;
|
|
48
|
+
apiKey: string;
|
|
49
|
+
timeout?: number;
|
|
50
|
+
}
|
|
51
|
+
export declare class EnvelopeClient {
|
|
52
|
+
private baseUrl;
|
|
53
|
+
private apiKey;
|
|
54
|
+
private timeout;
|
|
55
|
+
constructor(options: EnvelopeClientOptions);
|
|
56
|
+
private request;
|
|
57
|
+
/**
|
|
58
|
+
* Create a new execution envelope.
|
|
59
|
+
*/
|
|
60
|
+
create(request: CreateEnvelopeRequest): Promise<EnvelopeData>;
|
|
61
|
+
/**
|
|
62
|
+
* Get an envelope by ID.
|
|
63
|
+
*/
|
|
64
|
+
get(envelopeId: string): Promise<EnvelopeData>;
|
|
65
|
+
/**
|
|
66
|
+
* Update the status of an envelope.
|
|
67
|
+
*/
|
|
68
|
+
updateStatus(request: UpdateEnvelopeStatusRequest): Promise<EnvelopeData>;
|
|
69
|
+
/**
|
|
70
|
+
* List envelopes with optional filters.
|
|
71
|
+
*/
|
|
72
|
+
list(request?: ListEnvelopesRequest): Promise<EnvelopeData[]>;
|
|
73
|
+
}
|