@fulcrum-governance/sdk 0.1.3 → 0.1.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/CHANGELOG.md +18 -4
- package/README.md +40 -51
- package/dist/__tests__/clients.test.js +127 -12
- package/dist/clients/agent.js +18 -12
- package/dist/clients/approval.js +15 -2
- package/dist/clients/budget.js +15 -2
- package/dist/clients/checkpoint.js +15 -2
- package/dist/clients/envelope.d.ts +5 -4
- package/dist/clients/envelope.js +39 -10
- package/dist/clients/eventstore.js +15 -2
- package/dist/clients/metrics.js +15 -2
- package/dist/clients/policy.d.ts +7 -2
- package/dist/clients/policy.js +55 -10
- package/dist/clients/tenant.js +15 -2
- package/dist/index.js +6 -2
- package/dist/instrumentation/__tests__/autoGovern.test.js +3 -2
- package/dist/instrumentation/__tests__/costReporter.test.d.ts +5 -0
- package/dist/instrumentation/__tests__/costReporter.test.js +137 -0
- package/dist/instrumentation/autoGovern.js +63 -1
- package/dist/instrumentation/costReporter.d.ts +27 -0
- package/dist/instrumentation/costReporter.js +69 -0
- package/dist/instrumentation/evaluator.d.ts +8 -0
- package/dist/instrumentation/evaluator.js +124 -11
- package/dist/instrumentation/index.d.ts +3 -1
- package/dist/instrumentation/index.js +3 -1
- package/dist/instrumentation/types.d.ts +13 -0
- package/package.json +11 -4
- package/proto/events.proto +1 -1
- package/proto/fulcrum/agent/v1/agent_service.proto +1 -1
- package/proto/fulcrum/bridge/v1/bridge.proto +1 -1
- package/proto/fulcrum/checkpoint/v1/checkpoint_service.proto +1 -1
- package/proto/fulcrum/cost/v1/cost_service.proto +1 -1
- package/proto/fulcrum/envelope/v1/envelope.proto +1 -1
- package/proto/fulcrum/envelope/v1/envelope_service.proto +1 -1
- package/proto/fulcrum/eventstore/v1/eventstore.proto +1 -1
- package/proto/fulcrum/policy/v1/policy_service.proto +1 -1
- package/proto/fulcrum/tenant/v1/tenant_service.proto +1 -1
|
@@ -21,6 +21,7 @@ class PolicyEvaluator {
|
|
|
21
21
|
this.syncInterval = null;
|
|
22
22
|
this.running = false;
|
|
23
23
|
this.config = { ...types_1.DEFAULT_CONFIG, ...config };
|
|
24
|
+
this.rawFetch = globalThis.fetch;
|
|
24
25
|
}
|
|
25
26
|
/**
|
|
26
27
|
* Start the background policy sync.
|
|
@@ -186,17 +187,114 @@ class PolicyEvaluator {
|
|
|
186
187
|
if (!this.config.apiKey || !this.config.tenantId) {
|
|
187
188
|
return;
|
|
188
189
|
}
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
190
|
+
try {
|
|
191
|
+
const url = `${this.config.serverUrl}/api/v1/policies`;
|
|
192
|
+
const response = await this.rawFetch(url, {
|
|
193
|
+
method: 'GET',
|
|
194
|
+
headers: {
|
|
195
|
+
'X-API-Key': this.config.apiKey,
|
|
196
|
+
'Accept': 'application/json',
|
|
197
|
+
},
|
|
198
|
+
signal: AbortSignal.timeout(10000),
|
|
199
|
+
});
|
|
200
|
+
if (!response.ok) {
|
|
201
|
+
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
202
|
+
}
|
|
203
|
+
const data = await response.json();
|
|
204
|
+
// Map server response to the Policy format the evaluator expects.
|
|
205
|
+
// The REST gateway returns a compact form; we normalise it here.
|
|
206
|
+
const policies = (data.policies ?? []).map((p) => ({
|
|
207
|
+
policyId: p.policy_id ?? '',
|
|
208
|
+
tenantId: this.config.tenantId,
|
|
209
|
+
priority: p.priority ?? 0,
|
|
210
|
+
status: mapStatus(p.status),
|
|
211
|
+
scope: p.scope
|
|
212
|
+
? {
|
|
213
|
+
applyToAll: p.scope.apply_to_all ?? false,
|
|
214
|
+
toolNames: p.scope.tool_names ?? [],
|
|
215
|
+
}
|
|
216
|
+
: undefined,
|
|
217
|
+
rules: (p.rules ?? []).map((r) => ({
|
|
218
|
+
ruleId: r.rule_id ?? '',
|
|
219
|
+
name: r.name ?? '',
|
|
220
|
+
enabled: r.enabled !== false,
|
|
221
|
+
priority: r.priority ?? 0,
|
|
222
|
+
conditions: (r.conditions ?? []).map((c) => ({
|
|
223
|
+
field: c.field ?? '',
|
|
224
|
+
operator: c.operator ?? 'equals',
|
|
225
|
+
value: c.value,
|
|
226
|
+
values: c.values,
|
|
227
|
+
})),
|
|
228
|
+
actions: (r.actions ?? []).map((a) => ({
|
|
229
|
+
actionType: a.action_type ?? 'allow',
|
|
230
|
+
})),
|
|
231
|
+
})),
|
|
232
|
+
}));
|
|
233
|
+
this.policies = policies;
|
|
234
|
+
this.lastSync = Date.now();
|
|
235
|
+
this.syncError = null;
|
|
236
|
+
console.debug(`[fulcrum] Synced ${policies.length} policies from server`);
|
|
237
|
+
}
|
|
238
|
+
catch (err) {
|
|
239
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
240
|
+
console.warn(`[fulcrum] Policy sync failed (will retry): ${message}`);
|
|
241
|
+
this.syncError = message;
|
|
242
|
+
// Still update timestamp to avoid tight retry loops
|
|
243
|
+
this.lastSync = Date.now();
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
/**
|
|
247
|
+
* Evaluate a request server-side via the REST gateway.
|
|
248
|
+
*
|
|
249
|
+
* Used as fallback when local cache is empty but credentials are configured.
|
|
250
|
+
* Returns null on any error so the caller can fall back to local evaluation.
|
|
251
|
+
*/
|
|
252
|
+
async evaluateServerSide(request) {
|
|
253
|
+
if (!this.config.apiKey || !this.config.tenantId) {
|
|
254
|
+
return null;
|
|
255
|
+
}
|
|
256
|
+
try {
|
|
257
|
+
const url = `${this.config.serverUrl}/api/v1/evaluate`;
|
|
258
|
+
const response = await this.rawFetch(url, {
|
|
259
|
+
method: 'POST',
|
|
260
|
+
headers: {
|
|
261
|
+
'X-API-Key': this.config.apiKey,
|
|
262
|
+
'Content-Type': 'application/json',
|
|
263
|
+
'Accept': 'application/json',
|
|
264
|
+
},
|
|
265
|
+
body: JSON.stringify({
|
|
266
|
+
tool_names: [request.toolName],
|
|
267
|
+
input: request.resource ?? request.toolName,
|
|
268
|
+
phase: request.actionType,
|
|
269
|
+
}),
|
|
270
|
+
signal: AbortSignal.timeout(5000),
|
|
271
|
+
});
|
|
272
|
+
if (!response.ok) {
|
|
273
|
+
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
274
|
+
}
|
|
275
|
+
const data = await response.json();
|
|
276
|
+
// Map server decision string to our Action type
|
|
277
|
+
const decisionStr = (data.decision ?? '').toLowerCase();
|
|
278
|
+
const actionMap = {
|
|
279
|
+
allow: 'allow',
|
|
280
|
+
'evaluation_decision_allow': 'allow',
|
|
281
|
+
deny: 'deny',
|
|
282
|
+
'evaluation_decision_deny': 'deny',
|
|
283
|
+
warn: 'warn',
|
|
284
|
+
'evaluation_decision_warn': 'warn',
|
|
285
|
+
escalate: 'escalate',
|
|
286
|
+
'evaluation_decision_escalate': 'escalate',
|
|
287
|
+
};
|
|
288
|
+
const action = actionMap[decisionStr] ?? 'allow';
|
|
289
|
+
return {
|
|
290
|
+
action,
|
|
291
|
+
reason: data.message ?? decisionStr,
|
|
292
|
+
};
|
|
293
|
+
}
|
|
294
|
+
catch (err) {
|
|
295
|
+
console.warn(`[fulcrum] Server-side evaluation failed (falling back to local): ${err instanceof Error ? err.message : err}`);
|
|
296
|
+
return null;
|
|
297
|
+
}
|
|
200
298
|
}
|
|
201
299
|
/**
|
|
202
300
|
* Manually update the policy cache (for testing).
|
|
@@ -216,3 +314,18 @@ class PolicyEvaluator {
|
|
|
216
314
|
}
|
|
217
315
|
}
|
|
218
316
|
exports.PolicyEvaluator = PolicyEvaluator;
|
|
317
|
+
/**
|
|
318
|
+
* Map a server status string to the Policy status type.
|
|
319
|
+
*/
|
|
320
|
+
function mapStatus(status) {
|
|
321
|
+
if (!status)
|
|
322
|
+
return 'active';
|
|
323
|
+
const s = status.toLowerCase().replace('policy_status_', '');
|
|
324
|
+
if (s === 'active')
|
|
325
|
+
return 'active';
|
|
326
|
+
if (s === 'inactive')
|
|
327
|
+
return 'inactive';
|
|
328
|
+
if (s === 'draft')
|
|
329
|
+
return 'draft';
|
|
330
|
+
return 'active';
|
|
331
|
+
}
|
|
@@ -25,4 +25,6 @@
|
|
|
25
25
|
*/
|
|
26
26
|
export { activate, deactivate, isActive } from './autoGovern';
|
|
27
27
|
export { PolicyEvaluator } from './evaluator';
|
|
28
|
-
export
|
|
28
|
+
export { CostReporter } from './costReporter';
|
|
29
|
+
export type { CostReporterConfig } from './costReporter';
|
|
30
|
+
export type { InstrumentationConfig, Decision, EvaluationRequest, Action, CostEvent } from './types';
|
|
@@ -25,10 +25,12 @@
|
|
|
25
25
|
* All patches are fail-safe: governance errors never crash your agent.
|
|
26
26
|
*/
|
|
27
27
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
28
|
-
exports.PolicyEvaluator = exports.isActive = exports.deactivate = exports.activate = void 0;
|
|
28
|
+
exports.CostReporter = exports.PolicyEvaluator = exports.isActive = exports.deactivate = exports.activate = void 0;
|
|
29
29
|
var autoGovern_1 = require("./autoGovern");
|
|
30
30
|
Object.defineProperty(exports, "activate", { enumerable: true, get: function () { return autoGovern_1.activate; } });
|
|
31
31
|
Object.defineProperty(exports, "deactivate", { enumerable: true, get: function () { return autoGovern_1.deactivate; } });
|
|
32
32
|
Object.defineProperty(exports, "isActive", { enumerable: true, get: function () { return autoGovern_1.isActive; } });
|
|
33
33
|
var evaluator_1 = require("./evaluator");
|
|
34
34
|
Object.defineProperty(exports, "PolicyEvaluator", { enumerable: true, get: function () { return evaluator_1.PolicyEvaluator; } });
|
|
35
|
+
var costReporter_1 = require("./costReporter");
|
|
36
|
+
Object.defineProperty(exports, "CostReporter", { enumerable: true, get: function () { return costReporter_1.CostReporter; } });
|
|
@@ -99,6 +99,19 @@ export interface Metrics {
|
|
|
99
99
|
allowedCalls: number;
|
|
100
100
|
patchFailures: number;
|
|
101
101
|
}
|
|
102
|
+
/**
|
|
103
|
+
* Cost event to report to the server.
|
|
104
|
+
*/
|
|
105
|
+
export interface CostEvent {
|
|
106
|
+
event_type: 'llm' | 'tool';
|
|
107
|
+
envelope_id?: string;
|
|
108
|
+
tool_name: string;
|
|
109
|
+
cost_usd: number;
|
|
110
|
+
tokens_in?: number;
|
|
111
|
+
tokens_out?: number;
|
|
112
|
+
model_id?: string;
|
|
113
|
+
workflow_id?: string;
|
|
114
|
+
}
|
|
102
115
|
/**
|
|
103
116
|
* Default configuration values.
|
|
104
117
|
*/
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fulcrum-governance/sdk",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.5",
|
|
4
4
|
"mcpName": "io.github.Dewars30/fulcrum",
|
|
5
5
|
"description": "TypeScript SDK for Fulcrum - Intelligent AI Governance Platform",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -11,18 +11,25 @@
|
|
|
11
11
|
"lint": "eslint src/",
|
|
12
12
|
"prepublishOnly": "npm run build"
|
|
13
13
|
},
|
|
14
|
-
"keywords": [
|
|
14
|
+
"keywords": [
|
|
15
|
+
"ai",
|
|
16
|
+
"governance",
|
|
17
|
+
"llm",
|
|
18
|
+
"agents",
|
|
19
|
+
"safety",
|
|
20
|
+
"grpc"
|
|
21
|
+
],
|
|
15
22
|
"author": "Fulcrum Team <hello@fulcrum.dev>",
|
|
16
23
|
"license": "Apache-2.0",
|
|
17
24
|
"repository": {
|
|
18
25
|
"type": "git",
|
|
19
|
-
"url": "https://github.com/
|
|
26
|
+
"url": "git+https://github.com/Fulcrum-Governance/fulcrum-io.git",
|
|
20
27
|
"directory": "sdk/typescript"
|
|
21
28
|
},
|
|
22
29
|
"dependencies": {
|
|
23
30
|
"@grpc/grpc-js": "^1.9.0",
|
|
24
31
|
"@grpc/proto-loader": "^0.7.0",
|
|
25
|
-
"uuid": "^
|
|
32
|
+
"uuid": "^14.0.0"
|
|
26
33
|
},
|
|
27
34
|
"devDependencies": {
|
|
28
35
|
"@types/node": "^20.0.0",
|
package/proto/events.proto
CHANGED
|
@@ -2,7 +2,7 @@ syntax = "proto3";
|
|
|
2
2
|
|
|
3
3
|
package fulcrum.events.v1;
|
|
4
4
|
|
|
5
|
-
option go_package = "github.com/fulcrum-io/
|
|
5
|
+
option go_package = "github.com/Fulcrum-Governance/fulcrum-io/pkg/events/v1";
|
|
6
6
|
|
|
7
7
|
import "google/protobuf/timestamp.proto";
|
|
8
8
|
import "google/protobuf/struct.proto";
|
|
@@ -12,7 +12,7 @@ package fulcrum.agent.v1;
|
|
|
12
12
|
import "google/protobuf/timestamp.proto";
|
|
13
13
|
import "google/protobuf/struct.proto";
|
|
14
14
|
|
|
15
|
-
option go_package = "github.com/fulcrum-io/
|
|
15
|
+
option go_package = "github.com/Fulcrum-Governance/fulcrum-io/pkg/agent/v1;agentv1";
|
|
16
16
|
|
|
17
17
|
service AgentService {
|
|
18
18
|
// CreateAgent creates a new agent for the authenticated tenant.
|
|
@@ -5,7 +5,7 @@ syntax = "proto3";
|
|
|
5
5
|
|
|
6
6
|
package fulcrum.bridge.v1;
|
|
7
7
|
|
|
8
|
-
option go_package = "github.com/fulcrum-io/
|
|
8
|
+
option go_package = "github.com/Fulcrum-Governance/fulcrum-io/pkg/bridge/v1";
|
|
9
9
|
|
|
10
10
|
// ExecutionRequest initiates a LangGraph StateGraph execution
|
|
11
11
|
message ExecutionRequest {
|
|
@@ -2,7 +2,7 @@ syntax = "proto3";
|
|
|
2
2
|
|
|
3
3
|
package fulcrum.checkpoint.v1;
|
|
4
4
|
|
|
5
|
-
option go_package = "github.com/fulcrum-io/
|
|
5
|
+
option go_package = "github.com/Fulcrum-Governance/fulcrum-io/pkg/checkpoint/v1";
|
|
6
6
|
|
|
7
7
|
import "google/api/annotations.proto";
|
|
8
8
|
import "google/protobuf/timestamp.proto";
|
|
@@ -2,7 +2,7 @@ syntax = "proto3";
|
|
|
2
2
|
|
|
3
3
|
package fulcrum.cost.v1;
|
|
4
4
|
|
|
5
|
-
option go_package = "github.com/fulcrum-io/
|
|
5
|
+
option go_package = "github.com/Fulcrum-Governance/fulcrum-io/pkg/cost/v1";
|
|
6
6
|
|
|
7
7
|
import "google/api/annotations.proto";
|
|
8
8
|
import "google/protobuf/timestamp.proto";
|
|
@@ -2,7 +2,7 @@ syntax = "proto3";
|
|
|
2
2
|
|
|
3
3
|
package fulcrum.envelope.v1;
|
|
4
4
|
|
|
5
|
-
option go_package = "github.com/fulcrum-io/
|
|
5
|
+
option go_package = "github.com/Fulcrum-Governance/fulcrum-io/pkg/envelope/v1";
|
|
6
6
|
|
|
7
7
|
import "google/protobuf/timestamp.proto";
|
|
8
8
|
import "google/protobuf/struct.proto";
|
|
@@ -2,7 +2,7 @@ syntax = "proto3";
|
|
|
2
2
|
|
|
3
3
|
package fulcrum.eventstore.v1;
|
|
4
4
|
|
|
5
|
-
option go_package = "github.com/fulcrum-io/
|
|
5
|
+
option go_package = "github.com/Fulcrum-Governance/fulcrum-io/pkg/eventstore/v1;eventstorev1";
|
|
6
6
|
|
|
7
7
|
import "google/protobuf/timestamp.proto";
|
|
8
8
|
import "google/protobuf/struct.proto";
|
|
@@ -2,7 +2,7 @@ syntax = "proto3";
|
|
|
2
2
|
|
|
3
3
|
package fulcrum.policy.v1;
|
|
4
4
|
|
|
5
|
-
option go_package = "github.com/fulcrum-io/
|
|
5
|
+
option go_package = "github.com/Fulcrum-Governance/fulcrum-io/pkg/policy/v1";
|
|
6
6
|
|
|
7
7
|
import "google/api/annotations.proto";
|
|
8
8
|
import "google/protobuf/timestamp.proto";
|
|
@@ -4,7 +4,7 @@ package fulcrum.tenant.v1;
|
|
|
4
4
|
|
|
5
5
|
import "google/protobuf/timestamp.proto";
|
|
6
6
|
|
|
7
|
-
option go_package = "github.com/fulcrum-io/
|
|
7
|
+
option go_package = "github.com/Fulcrum-Governance/fulcrum-io/pkg/tenant/v1;tenantv1";
|
|
8
8
|
|
|
9
9
|
service TenantService {
|
|
10
10
|
// CreateApiKey creates a new API key for the authenticated tenant.
|