usertrust-openclaw 1.1.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.
- package/dist/index.d.ts +46 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +148 -0
- package/dist/index.js.map +1 -0
- package/dist/stream-governor.d.ts +40 -0
- package/dist/stream-governor.d.ts.map +1 -0
- package/dist/stream-governor.js +94 -0
- package/dist/stream-governor.js.map +1 -0
- package/dist/token-extractor.d.ts +25 -0
- package/dist/token-extractor.d.ts.map +1 -0
- package/dist/token-extractor.js +53 -0
- package/dist/token-extractor.js.map +1 -0
- package/dist/types.d.ts +89 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +4 -0
- package/dist/types.js.map +1 -0
- package/openclaw.plugin.json +59 -0
- package/package.json +52 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import type { Governor } from "usertrust";
|
|
2
|
+
import type { OpenClawPluginApi, StreamFn, UsertrustPluginConfig } from "./types.js";
|
|
3
|
+
export { wrapStreamWithGovernance, wrapCompleteWithGovernance } from "./stream-governor.js";
|
|
4
|
+
export { createAccumulator, extractUsageFromEvent } from "./token-extractor.js";
|
|
5
|
+
export type { StreamEvent, StreamFn, StreamContext, StreamUsage, UsertrustPluginConfig, GovernedStreamMeta, } from "./types.js";
|
|
6
|
+
/**
|
|
7
|
+
* OpenClaw plugin entry point.
|
|
8
|
+
*
|
|
9
|
+
* Called by OpenClaw's plugin loader. Initializes the usertrust
|
|
10
|
+
* governance engine and registers the stream wrapper.
|
|
11
|
+
*/
|
|
12
|
+
export default function register(api: OpenClawPluginApi): void;
|
|
13
|
+
/**
|
|
14
|
+
* Programmatic API for non-OpenClaw usage.
|
|
15
|
+
*
|
|
16
|
+
* Use this when integrating usertrust governance into a custom
|
|
17
|
+
* pi-ai setup without the full OpenClaw plugin system.
|
|
18
|
+
*
|
|
19
|
+
* ```ts
|
|
20
|
+
* import { createGovernedStreamFn } from "@usertrust/openclaw";
|
|
21
|
+
*
|
|
22
|
+
* const governed = await createGovernedStreamFn(myStreamFn, {
|
|
23
|
+
* budget: 100_000,
|
|
24
|
+
* dryRun: true,
|
|
25
|
+
* });
|
|
26
|
+
*
|
|
27
|
+
* for await (const event of governed("claude-sonnet-4-6", context)) {
|
|
28
|
+
* // events flow through with governance applied
|
|
29
|
+
* }
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
32
|
+
export declare function createGovernedStreamFn(streamFn: StreamFn, config: UsertrustPluginConfig): Promise<{
|
|
33
|
+
governedStreamFn: StreamFn;
|
|
34
|
+
governor: Governor;
|
|
35
|
+
}>;
|
|
36
|
+
/**
|
|
37
|
+
* Get the active governor instance.
|
|
38
|
+
* Returns null if the plugin hasn't been initialized yet.
|
|
39
|
+
*/
|
|
40
|
+
export declare function getGovernor(): Governor | null;
|
|
41
|
+
/**
|
|
42
|
+
* Graceful shutdown — call this when OpenClaw exits.
|
|
43
|
+
* Voids all pending holds and flushes the audit chain.
|
|
44
|
+
*/
|
|
45
|
+
export declare function shutdown(): Promise<void>;
|
|
46
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAmCA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAE1C,OAAO,KAAK,EACX,iBAAiB,EAGjB,QAAQ,EACR,qBAAqB,EACrB,MAAM,YAAY,CAAC;AAGpB,OAAO,EAAE,wBAAwB,EAAE,0BAA0B,EAAE,MAAM,sBAAsB,CAAC;AAC5F,OAAO,EAAE,iBAAiB,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAChF,YAAY,EACX,WAAW,EACX,QAAQ,EACR,aAAa,EACb,WAAW,EACX,qBAAqB,EACrB,kBAAkB,GAClB,MAAM,YAAY,CAAC;AAKpB;;;;;GAKG;AACH,MAAM,CAAC,OAAO,UAAU,QAAQ,CAAC,GAAG,EAAE,iBAAiB,GAAG,IAAI,CA0B7D;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAsB,sBAAsB,CAC3C,QAAQ,EAAE,QAAQ,EAClB,MAAM,EAAE,qBAAqB,GAC3B,OAAO,CAAC;IAAE,gBAAgB,EAAE,QAAQ,CAAC;IAAC,QAAQ,EAAE,QAAQ,CAAA;CAAE,CAAC,CAI7D;AAED;;;GAGG;AACH,wBAAgB,WAAW,IAAI,QAAQ,GAAG,IAAI,CAE7C;AAED;;;GAGG;AACH,wBAAsB,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC,CAM9C"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
// Copyright 2026 Usertools, Inc.
|
|
3
|
+
/**
|
|
4
|
+
* @usertrust/openclaw — usertrust governance plugin for OpenClaw
|
|
5
|
+
*
|
|
6
|
+
* Adds budget enforcement, policy gates, and hash-chained audit trails
|
|
7
|
+
* to every LLM call in OpenClaw. Zero code changes required — install
|
|
8
|
+
* the plugin and every call is governed.
|
|
9
|
+
*
|
|
10
|
+
* Installation:
|
|
11
|
+
* openclaw plugins install @usertrust/openclaw
|
|
12
|
+
*
|
|
13
|
+
* Or manual setup in openclaw.json:
|
|
14
|
+
* {
|
|
15
|
+
* "plugins": {
|
|
16
|
+
* "entries": {
|
|
17
|
+
* "usertrust": {
|
|
18
|
+
* "enabled": true,
|
|
19
|
+
* "config": { "budget": 100000, "dryRun": true }
|
|
20
|
+
* }
|
|
21
|
+
* }
|
|
22
|
+
* }
|
|
23
|
+
* }
|
|
24
|
+
*
|
|
25
|
+
* How it works:
|
|
26
|
+
* User's LLM call → OpenClaw → wrapStreamFn (usertrust) →
|
|
27
|
+
* 1. Check budget (PENDING hold)
|
|
28
|
+
* 2. Forward to real stream
|
|
29
|
+
* 3. Accumulate token usage from stream
|
|
30
|
+
* 4. POST settle with actual cost
|
|
31
|
+
* 5. Return governed stream to OpenClaw
|
|
32
|
+
*/
|
|
33
|
+
import { createGovernor } from "usertrust";
|
|
34
|
+
import { wrapStreamWithGovernance } from "./stream-governor.js";
|
|
35
|
+
// Re-export for consumers
|
|
36
|
+
export { wrapStreamWithGovernance, wrapCompleteWithGovernance } from "./stream-governor.js";
|
|
37
|
+
export { createAccumulator, extractUsageFromEvent } from "./token-extractor.js";
|
|
38
|
+
/** Active governor instance — singleton per plugin lifecycle. */
|
|
39
|
+
let governor = null;
|
|
40
|
+
/**
|
|
41
|
+
* OpenClaw plugin entry point.
|
|
42
|
+
*
|
|
43
|
+
* Called by OpenClaw's plugin loader. Initializes the usertrust
|
|
44
|
+
* governance engine and registers the stream wrapper.
|
|
45
|
+
*/
|
|
46
|
+
export default function register(api) {
|
|
47
|
+
// Config is injected by OpenClaw from openclaw.json → plugins.entries.usertrust.config
|
|
48
|
+
// We register a hook that initializes on first use (lazy)
|
|
49
|
+
// since config isn't available at register time in all OpenClaw versions.
|
|
50
|
+
const plugin = {
|
|
51
|
+
id: "usertrust",
|
|
52
|
+
label: "usertrust Governance",
|
|
53
|
+
/**
|
|
54
|
+
* wrapStreamFn — the core integration point.
|
|
55
|
+
*
|
|
56
|
+
* OpenClaw calls this with the existing stream function.
|
|
57
|
+
* We return a wrapped version that adds governance.
|
|
58
|
+
*/
|
|
59
|
+
wrapStreamFn(originalStreamFn, config) {
|
|
60
|
+
// Lazy-initialize governor on first call
|
|
61
|
+
const getGovernor = lazyGovernor(config);
|
|
62
|
+
return (model, context, options) => {
|
|
63
|
+
return governedStreamLazy(getGovernor, originalStreamFn, model, context, options);
|
|
64
|
+
};
|
|
65
|
+
},
|
|
66
|
+
};
|
|
67
|
+
api.registerProvider(plugin);
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Programmatic API for non-OpenClaw usage.
|
|
71
|
+
*
|
|
72
|
+
* Use this when integrating usertrust governance into a custom
|
|
73
|
+
* pi-ai setup without the full OpenClaw plugin system.
|
|
74
|
+
*
|
|
75
|
+
* ```ts
|
|
76
|
+
* import { createGovernedStreamFn } from "@usertrust/openclaw";
|
|
77
|
+
*
|
|
78
|
+
* const governed = await createGovernedStreamFn(myStreamFn, {
|
|
79
|
+
* budget: 100_000,
|
|
80
|
+
* dryRun: true,
|
|
81
|
+
* });
|
|
82
|
+
*
|
|
83
|
+
* for await (const event of governed("claude-sonnet-4-6", context)) {
|
|
84
|
+
* // events flow through with governance applied
|
|
85
|
+
* }
|
|
86
|
+
* ```
|
|
87
|
+
*/
|
|
88
|
+
export async function createGovernedStreamFn(streamFn, config) {
|
|
89
|
+
const gov = await initGovernor(config);
|
|
90
|
+
const governedStreamFn = wrapStreamWithGovernance(streamFn, gov);
|
|
91
|
+
return { governedStreamFn, governor: gov };
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Get the active governor instance.
|
|
95
|
+
* Returns null if the plugin hasn't been initialized yet.
|
|
96
|
+
*/
|
|
97
|
+
export function getGovernor() {
|
|
98
|
+
return governor;
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Graceful shutdown — call this when OpenClaw exits.
|
|
102
|
+
* Voids all pending holds and flushes the audit chain.
|
|
103
|
+
*/
|
|
104
|
+
export async function shutdown() {
|
|
105
|
+
if (governor != null) {
|
|
106
|
+
await governor.destroy();
|
|
107
|
+
governor = null;
|
|
108
|
+
initPromise = null;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
// ── Internal ──
|
|
112
|
+
/** Module-level promise to prevent concurrent initialization race. */
|
|
113
|
+
let initPromise = null;
|
|
114
|
+
function initGovernor(config) {
|
|
115
|
+
if (governor != null) {
|
|
116
|
+
return Promise.resolve(governor);
|
|
117
|
+
}
|
|
118
|
+
// Memoize the init promise to prevent TOCTOU race — two concurrent
|
|
119
|
+
// callers both see governor == null but only one createGovernor runs.
|
|
120
|
+
if (initPromise == null) {
|
|
121
|
+
initPromise = createGovernor({
|
|
122
|
+
budget: config.budget,
|
|
123
|
+
...(config.dryRun != null ? { dryRun: config.dryRun } : {}),
|
|
124
|
+
...(config.configPath != null ? { configPath: config.configPath } : {}),
|
|
125
|
+
...(config.proxy != null ? { proxy: config.proxy } : {}),
|
|
126
|
+
...(config.proxyKey != null ? { key: config.proxyKey } : {}),
|
|
127
|
+
}).then((gov) => {
|
|
128
|
+
governor = gov;
|
|
129
|
+
return gov;
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
return initPromise;
|
|
133
|
+
}
|
|
134
|
+
function lazyGovernor(config) {
|
|
135
|
+
let promise = null;
|
|
136
|
+
return () => {
|
|
137
|
+
if (promise == null) {
|
|
138
|
+
promise = initGovernor(config);
|
|
139
|
+
}
|
|
140
|
+
return promise;
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
async function* governedStreamLazy(getGovernor, streamFn, model, context, options) {
|
|
144
|
+
const gov = await getGovernor();
|
|
145
|
+
const governed = wrapStreamWithGovernance(streamFn, gov);
|
|
146
|
+
yield* governed(model, context, options);
|
|
147
|
+
}
|
|
148
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* stream-governor.ts — Governed Stream Wrapper for pi-ai
|
|
3
|
+
*
|
|
4
|
+
* Wraps a pi-ai stream function with usertrust governance:
|
|
5
|
+
* 1. Before stream: authorize (budget check, PENDING hold)
|
|
6
|
+
* 2. During stream: forward events, accumulate token usage
|
|
7
|
+
* 3. After stream: settle with actual cost
|
|
8
|
+
* 4. On error: abort (VOID the hold)
|
|
9
|
+
*
|
|
10
|
+
* The wrapped function has the same signature as the original —
|
|
11
|
+
* it's a transparent middleware layer.
|
|
12
|
+
*/
|
|
13
|
+
import type { Governor } from "usertrust";
|
|
14
|
+
import type { StreamContext, StreamFn } from "./types.js";
|
|
15
|
+
/**
|
|
16
|
+
* Wrap a pi-ai stream function with usertrust governance.
|
|
17
|
+
*
|
|
18
|
+
* Returns a new stream function with the same signature. Every call:
|
|
19
|
+
* - Checks budget and creates a PENDING hold
|
|
20
|
+
* - Forwards all stream events unchanged
|
|
21
|
+
* - Settles with actual token usage on completion
|
|
22
|
+
* - Voids the hold on error
|
|
23
|
+
*
|
|
24
|
+
* The governance receipt is emitted as a custom `usertrust:receipt`
|
|
25
|
+
* property on the `done` event for consumers that want it.
|
|
26
|
+
*/
|
|
27
|
+
export declare function wrapStreamWithGovernance(streamFn: StreamFn, governor: Governor): StreamFn;
|
|
28
|
+
/**
|
|
29
|
+
* Wrap a non-streaming completion function with governance.
|
|
30
|
+
*
|
|
31
|
+
* For pi-ai's `completeSimple()` / `complete()` functions that
|
|
32
|
+
* return a Promise instead of an async iterable.
|
|
33
|
+
*/
|
|
34
|
+
export declare function wrapCompleteWithGovernance<T extends {
|
|
35
|
+
usage?: {
|
|
36
|
+
inputTokens: number;
|
|
37
|
+
outputTokens: number;
|
|
38
|
+
};
|
|
39
|
+
}>(completeFn: (model: string, context: StreamContext, options?: Record<string, unknown>) => Promise<T>, governor: Governor): (model: string, context: StreamContext, options?: Record<string, unknown>) => Promise<T>;
|
|
40
|
+
//# sourceMappingURL=stream-governor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stream-governor.d.ts","sourceRoot":"","sources":["../src/stream-governor.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAiB,QAAQ,EAAE,MAAM,WAAW,CAAC;AAEzD,OAAO,KAAK,EAAE,aAAa,EAAe,QAAQ,EAAE,MAAM,YAAY,CAAC;AAEvE;;;;;;;;;;;GAWG;AACH,wBAAgB,wBAAwB,CAAC,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,GAAG,QAAQ,CAQzF;AA+CD;;;;;GAKG;AACH,wBAAgB,0BAA0B,CACzC,CAAC,SAAS;IAAE,KAAK,CAAC,EAAE;QAAE,WAAW,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,EAEnE,UAAU,EAAE,CACX,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,aAAa,EACtB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAC7B,OAAO,CAAC,CAAC,CAAC,EACf,QAAQ,EAAE,QAAQ,GAChB,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,aAAa,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,OAAO,CAAC,CAAC,CAAC,CAsC1F"}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
// Copyright 2026 Usertools, Inc.
|
|
3
|
+
import { createAccumulator } from "./token-extractor.js";
|
|
4
|
+
/**
|
|
5
|
+
* Wrap a pi-ai stream function with usertrust governance.
|
|
6
|
+
*
|
|
7
|
+
* Returns a new stream function with the same signature. Every call:
|
|
8
|
+
* - Checks budget and creates a PENDING hold
|
|
9
|
+
* - Forwards all stream events unchanged
|
|
10
|
+
* - Settles with actual token usage on completion
|
|
11
|
+
* - Voids the hold on error
|
|
12
|
+
*
|
|
13
|
+
* The governance receipt is emitted as a custom `usertrust:receipt`
|
|
14
|
+
* property on the `done` event for consumers that want it.
|
|
15
|
+
*/
|
|
16
|
+
export function wrapStreamWithGovernance(streamFn, governor) {
|
|
17
|
+
return (model, context, options) => {
|
|
18
|
+
return governedStream(streamFn, governor, model, context, options);
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
async function* governedStream(streamFn, governor, model, context, options) {
|
|
22
|
+
// 1. Authorize — budget check, policy gate, PENDING hold
|
|
23
|
+
const auth = await governor.authorize({
|
|
24
|
+
model,
|
|
25
|
+
messages: context.messages,
|
|
26
|
+
...(context.maxTokens != null ? { maxOutputTokens: context.maxTokens } : {}),
|
|
27
|
+
params: {
|
|
28
|
+
...(context.temperature != null ? { temperature: context.temperature } : {}),
|
|
29
|
+
},
|
|
30
|
+
});
|
|
31
|
+
// 2. Stream with token accumulation
|
|
32
|
+
const accumulator = createAccumulator();
|
|
33
|
+
try {
|
|
34
|
+
const stream = streamFn(model, context, options);
|
|
35
|
+
for await (const event of stream) {
|
|
36
|
+
accumulator.update(event);
|
|
37
|
+
yield event;
|
|
38
|
+
}
|
|
39
|
+
// 3. Settle — POST actual cost
|
|
40
|
+
const usage = accumulator.result();
|
|
41
|
+
await governor.settle(auth, {
|
|
42
|
+
...(usage.usageReported
|
|
43
|
+
? { inputTokens: usage.inputTokens, outputTokens: usage.outputTokens }
|
|
44
|
+
: {}),
|
|
45
|
+
chunksDelivered: usage.chunksDelivered,
|
|
46
|
+
usageSource: usage.usageReported ? "provider" : "estimated",
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
catch (err) {
|
|
50
|
+
// 4. Abort — VOID the hold (catch abort errors to preserve original)
|
|
51
|
+
await governor.abort(auth, err).catch(() => { });
|
|
52
|
+
throw err;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Wrap a non-streaming completion function with governance.
|
|
57
|
+
*
|
|
58
|
+
* For pi-ai's `completeSimple()` / `complete()` functions that
|
|
59
|
+
* return a Promise instead of an async iterable.
|
|
60
|
+
*/
|
|
61
|
+
export function wrapCompleteWithGovernance(completeFn, governor) {
|
|
62
|
+
return async (model, context, options) => {
|
|
63
|
+
// 1. Authorize
|
|
64
|
+
const auth = await governor.authorize({
|
|
65
|
+
model,
|
|
66
|
+
messages: context.messages,
|
|
67
|
+
...(context.maxTokens != null ? { maxOutputTokens: context.maxTokens } : {}),
|
|
68
|
+
params: {
|
|
69
|
+
...(context.temperature != null ? { temperature: context.temperature } : {}),
|
|
70
|
+
},
|
|
71
|
+
});
|
|
72
|
+
try {
|
|
73
|
+
// 2. Execute
|
|
74
|
+
const result = await completeFn(model, context, options);
|
|
75
|
+
// 3. Settle with actual usage if available
|
|
76
|
+
await governor.settle(auth, {
|
|
77
|
+
...(result.usage != null
|
|
78
|
+
? {
|
|
79
|
+
inputTokens: result.usage.inputTokens,
|
|
80
|
+
outputTokens: result.usage.outputTokens,
|
|
81
|
+
usageSource: "provider",
|
|
82
|
+
}
|
|
83
|
+
: { usageSource: "estimated" }),
|
|
84
|
+
});
|
|
85
|
+
return result;
|
|
86
|
+
}
|
|
87
|
+
catch (err) {
|
|
88
|
+
// 4. Abort (catch abort errors to preserve original)
|
|
89
|
+
await governor.abort(auth, err).catch(() => { });
|
|
90
|
+
throw err;
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
//# sourceMappingURL=stream-governor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stream-governor.js","sourceRoot":"","sources":["../src/stream-governor.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* token-extractor.ts — pi-ai Stream Token Extraction
|
|
3
|
+
*
|
|
4
|
+
* Extracts token usage from pi-ai's normalized stream events.
|
|
5
|
+
* pi-ai reports usage on `done` and `error` events, unlike provider
|
|
6
|
+
* SDKs which scatter it across multiple event types.
|
|
7
|
+
*/
|
|
8
|
+
import type { StreamEvent, StreamUsage } from "./types.js";
|
|
9
|
+
/** Accumulated usage from a pi-ai stream. */
|
|
10
|
+
export interface AccumulatedUsage {
|
|
11
|
+
inputTokens: number;
|
|
12
|
+
outputTokens: number;
|
|
13
|
+
chunksDelivered: number;
|
|
14
|
+
usageReported: boolean;
|
|
15
|
+
}
|
|
16
|
+
export declare function extractUsageFromEvent(event: StreamEvent): StreamUsage | null;
|
|
17
|
+
/**
|
|
18
|
+
* Creates a token accumulator for tracking usage across a stream.
|
|
19
|
+
* Call `update()` for each event and `result()` when done.
|
|
20
|
+
*/
|
|
21
|
+
export declare function createAccumulator(): {
|
|
22
|
+
update(event: StreamEvent): void;
|
|
23
|
+
result(): AccumulatedUsage;
|
|
24
|
+
};
|
|
25
|
+
//# sourceMappingURL=token-extractor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"token-extractor.d.ts","sourceRoot":"","sources":["../src/token-extractor.ts"],"names":[],"mappings":"AAGA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE3D,6CAA6C;AAC7C,MAAM,WAAW,gBAAgB;IAChC,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,eAAe,EAAE,MAAM,CAAC;IACxB,aAAa,EAAE,OAAO,CAAC;CACvB;AAaD,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,WAAW,GAAG,WAAW,GAAG,IAAI,CAgB5E;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,IAAI;IACpC,MAAM,CAAC,KAAK,EAAE,WAAW,GAAG,IAAI,CAAC;IACjC,MAAM,IAAI,gBAAgB,CAAC;CAC3B,CAsBA"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
// Copyright 2026 Usertools, Inc.
|
|
3
|
+
/**
|
|
4
|
+
* Extract token usage from a pi-ai stream event.
|
|
5
|
+
* Returns non-zero usage only for `done` and `error` events.
|
|
6
|
+
*/
|
|
7
|
+
/** Max tokens to accept from a provider (prevents Infinity/overflow in cost math). */
|
|
8
|
+
const MAX_TOKENS = 2_000_000;
|
|
9
|
+
function clampTokens(n) {
|
|
10
|
+
return Math.min(Math.max(0, n), MAX_TOKENS);
|
|
11
|
+
}
|
|
12
|
+
export function extractUsageFromEvent(event) {
|
|
13
|
+
if (event.type === "done" && event.usage != null) {
|
|
14
|
+
return {
|
|
15
|
+
...event.usage,
|
|
16
|
+
inputTokens: clampTokens(event.usage.inputTokens),
|
|
17
|
+
outputTokens: clampTokens(event.usage.outputTokens),
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
if (event.type === "error" && event.usage != null) {
|
|
21
|
+
return {
|
|
22
|
+
...event.usage,
|
|
23
|
+
inputTokens: clampTokens(event.usage.inputTokens),
|
|
24
|
+
outputTokens: clampTokens(event.usage.outputTokens),
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
return null;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Creates a token accumulator for tracking usage across a stream.
|
|
31
|
+
* Call `update()` for each event and `result()` when done.
|
|
32
|
+
*/
|
|
33
|
+
export function createAccumulator() {
|
|
34
|
+
let inputTokens = 0;
|
|
35
|
+
let outputTokens = 0;
|
|
36
|
+
let chunksDelivered = 0;
|
|
37
|
+
let usageReported = false;
|
|
38
|
+
return {
|
|
39
|
+
update(event) {
|
|
40
|
+
chunksDelivered++;
|
|
41
|
+
const usage = extractUsageFromEvent(event);
|
|
42
|
+
if (usage != null) {
|
|
43
|
+
inputTokens = usage.inputTokens;
|
|
44
|
+
outputTokens = usage.outputTokens;
|
|
45
|
+
usageReported = true;
|
|
46
|
+
}
|
|
47
|
+
},
|
|
48
|
+
result() {
|
|
49
|
+
return { inputTokens, outputTokens, chunksDelivered, usageReported };
|
|
50
|
+
},
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=token-extractor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"token-extractor.js","sourceRoot":"","sources":["../src/token-extractor.ts"],"names":[],"mappings":"AAAA,sCAAsC;AACtC,iCAAiC;AAoBjC;;;GAGG;AACH,sFAAsF;AACtF,MAAM,UAAU,GAAG,SAAS,CAAC;AAE7B,SAAS,WAAW,CAAC,CAAS;IAC7B,OAAO,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC;AAC7C,CAAC;AAED,MAAM,UAAU,qBAAqB,CAAC,KAAkB;IACvD,IAAI,KAAK,CAAC,IAAI,KAAK,MAAM,IAAI,KAAK,CAAC,KAAK,IAAI,IAAI,EAAE,CAAC;QAClD,OAAO;YACN,GAAG,KAAK,CAAC,KAAK;YACd,WAAW,EAAE,WAAW,CAAC,KAAK,CAAC,KAAK,CAAC,WAAW,CAAC;YACjD,YAAY,EAAE,WAAW,CAAC,KAAK,CAAC,KAAK,CAAC,YAAY,CAAC;SACnD,CAAC;IACH,CAAC;IACD,IAAI,KAAK,CAAC,IAAI,KAAK,OAAO,IAAI,KAAK,CAAC,KAAK,IAAI,IAAI,EAAE,CAAC;QACnD,OAAO;YACN,GAAG,KAAK,CAAC,KAAK;YACd,WAAW,EAAE,WAAW,CAAC,KAAK,CAAC,KAAK,CAAC,WAAW,CAAC;YACjD,YAAY,EAAE,WAAW,CAAC,KAAK,CAAC,KAAK,CAAC,YAAY,CAAC;SACnD,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAC;AACb,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,iBAAiB;IAIhC,IAAI,WAAW,GAAG,CAAC,CAAC;IACpB,IAAI,YAAY,GAAG,CAAC,CAAC;IACrB,IAAI,eAAe,GAAG,CAAC,CAAC;IACxB,IAAI,aAAa,GAAG,KAAK,CAAC;IAE1B,OAAO;QACN,MAAM,CAAC,KAAkB;YACxB,eAAe,EAAE,CAAC;YAElB,MAAM,KAAK,GAAG,qBAAqB,CAAC,KAAK,CAAC,CAAC;YAC3C,IAAI,KAAK,IAAI,IAAI,EAAE,CAAC;gBACnB,WAAW,GAAG,KAAK,CAAC,WAAW,CAAC;gBAChC,YAAY,GAAG,KAAK,CAAC,YAAY,CAAC;gBAClC,aAAa,GAAG,IAAI,CAAC;YACtB,CAAC;QACF,CAAC;QAED,MAAM;YACL,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,eAAe,EAAE,aAAa,EAAE,CAAC;QACtE,CAAC;KACD,CAAC;AACH,CAAC"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* types.ts — OpenClaw Plugin API Types
|
|
3
|
+
*
|
|
4
|
+
* Type definitions for the OpenClaw plugin system and pi-ai streaming
|
|
5
|
+
* events. These mirror the OpenClaw/pi-ai interfaces without requiring
|
|
6
|
+
* the packages at compile time.
|
|
7
|
+
*/
|
|
8
|
+
export interface StreamUsage {
|
|
9
|
+
inputTokens: number;
|
|
10
|
+
outputTokens: number;
|
|
11
|
+
cacheReadTokens?: number;
|
|
12
|
+
cacheWriteTokens?: number;
|
|
13
|
+
}
|
|
14
|
+
export interface TextDeltaEvent {
|
|
15
|
+
type: "text_delta";
|
|
16
|
+
text: string;
|
|
17
|
+
}
|
|
18
|
+
export interface TextStartEvent {
|
|
19
|
+
type: "text_start";
|
|
20
|
+
}
|
|
21
|
+
export interface TextEndEvent {
|
|
22
|
+
type: "text_end";
|
|
23
|
+
}
|
|
24
|
+
export interface ThinkingDeltaEvent {
|
|
25
|
+
type: "thinking_delta";
|
|
26
|
+
text: string;
|
|
27
|
+
}
|
|
28
|
+
export interface ThinkingStartEvent {
|
|
29
|
+
type: "thinking_start";
|
|
30
|
+
}
|
|
31
|
+
export interface ThinkingEndEvent {
|
|
32
|
+
type: "thinking_end";
|
|
33
|
+
}
|
|
34
|
+
export interface ToolCallStartEvent {
|
|
35
|
+
type: "toolcall_start";
|
|
36
|
+
name: string;
|
|
37
|
+
id: string;
|
|
38
|
+
}
|
|
39
|
+
export interface ToolCallDeltaEvent {
|
|
40
|
+
type: "toolcall_delta";
|
|
41
|
+
args: string;
|
|
42
|
+
}
|
|
43
|
+
export interface ToolCallEndEvent {
|
|
44
|
+
type: "toolcall_end";
|
|
45
|
+
}
|
|
46
|
+
export interface StartEvent {
|
|
47
|
+
type: "start";
|
|
48
|
+
}
|
|
49
|
+
export interface DoneEvent {
|
|
50
|
+
type: "done";
|
|
51
|
+
stopReason: "stop" | "toolUse" | "length" | "error" | "aborted";
|
|
52
|
+
usage: StreamUsage;
|
|
53
|
+
}
|
|
54
|
+
export interface ErrorEvent {
|
|
55
|
+
type: "error";
|
|
56
|
+
error: unknown;
|
|
57
|
+
usage?: StreamUsage;
|
|
58
|
+
}
|
|
59
|
+
export type StreamEvent = StartEvent | TextStartEvent | TextDeltaEvent | TextEndEvent | ThinkingStartEvent | ThinkingDeltaEvent | ThinkingEndEvent | ToolCallStartEvent | ToolCallDeltaEvent | ToolCallEndEvent | DoneEvent | ErrorEvent;
|
|
60
|
+
export interface OpenClawPluginApi {
|
|
61
|
+
registerTool(tool: unknown): void;
|
|
62
|
+
registerProvider(provider: unknown): void;
|
|
63
|
+
registerChannel(channel: unknown): void;
|
|
64
|
+
registerHttpRoute(route: unknown): void;
|
|
65
|
+
}
|
|
66
|
+
/** Configuration passed to the plugin from openclaw.json. */
|
|
67
|
+
export interface UsertrustPluginConfig {
|
|
68
|
+
budget: number;
|
|
69
|
+
tier?: "free" | "mini" | "pro" | "mega" | "ultra";
|
|
70
|
+
dryRun?: boolean;
|
|
71
|
+
configPath?: string;
|
|
72
|
+
proxy?: string;
|
|
73
|
+
proxyKey?: string;
|
|
74
|
+
}
|
|
75
|
+
export interface StreamContext {
|
|
76
|
+
messages: unknown[];
|
|
77
|
+
model: string;
|
|
78
|
+
maxTokens?: number;
|
|
79
|
+
temperature?: number;
|
|
80
|
+
[key: string]: unknown;
|
|
81
|
+
}
|
|
82
|
+
export type StreamFn = (model: string, context: StreamContext, options?: Record<string, unknown>) => AsyncIterable<StreamEvent>;
|
|
83
|
+
/** Receipt attached to governed stream events. */
|
|
84
|
+
export interface GovernedStreamMeta {
|
|
85
|
+
transferId: string;
|
|
86
|
+
estimatedCost: number;
|
|
87
|
+
model: string;
|
|
88
|
+
}
|
|
89
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,sCAAsC;AACtC,iCAAiC"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "usertrust",
|
|
3
|
+
"name": "usertrust",
|
|
4
|
+
"description": "Financial governance for AI agents. Every LLM call becomes an immutable, auditable transaction with budget enforcement, policy gates, and hash-chained audit trails.",
|
|
5
|
+
"kind": "provider",
|
|
6
|
+
"configSchema": {
|
|
7
|
+
"type": "object",
|
|
8
|
+
"additionalProperties": false,
|
|
9
|
+
"properties": {
|
|
10
|
+
"budget": {
|
|
11
|
+
"type": "number",
|
|
12
|
+
"description": "Token budget in usertokens. 1 usertoken = $0.0001."
|
|
13
|
+
},
|
|
14
|
+
"tier": {
|
|
15
|
+
"type": "string",
|
|
16
|
+
"enum": ["free", "mini", "pro", "mega", "ultra"],
|
|
17
|
+
"description": "Budget tier for policy evaluation."
|
|
18
|
+
},
|
|
19
|
+
"dryRun": {
|
|
20
|
+
"type": "boolean",
|
|
21
|
+
"description": "Skip TigerBeetle ledger — audit-chain-only mode."
|
|
22
|
+
},
|
|
23
|
+
"configPath": {
|
|
24
|
+
"type": "string",
|
|
25
|
+
"description": "Path to usertrust.config.json. Defaults to .usertrust/usertrust.config.json."
|
|
26
|
+
},
|
|
27
|
+
"proxy": {
|
|
28
|
+
"type": "string",
|
|
29
|
+
"description": "Remote governance proxy URL."
|
|
30
|
+
},
|
|
31
|
+
"proxyKey": {
|
|
32
|
+
"type": "string",
|
|
33
|
+
"description": "API key for the governance proxy."
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
"required": ["budget"]
|
|
37
|
+
},
|
|
38
|
+
"uiHints": {
|
|
39
|
+
"budget": {
|
|
40
|
+
"label": "Token Budget",
|
|
41
|
+
"placeholder": "100000"
|
|
42
|
+
},
|
|
43
|
+
"tier": {
|
|
44
|
+
"label": "Budget Tier",
|
|
45
|
+
"placeholder": "pro"
|
|
46
|
+
},
|
|
47
|
+
"dryRun": {
|
|
48
|
+
"label": "Dry Run Mode"
|
|
49
|
+
},
|
|
50
|
+
"proxy": {
|
|
51
|
+
"label": "Proxy URL",
|
|
52
|
+
"placeholder": "https://proxy.usertools.ai"
|
|
53
|
+
},
|
|
54
|
+
"proxyKey": {
|
|
55
|
+
"label": "Proxy API Key",
|
|
56
|
+
"sensitive": true
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "usertrust-openclaw",
|
|
3
|
+
"version": "1.1.1",
|
|
4
|
+
"description": "usertrust governance plugin for OpenClaw. Budget enforcement, audit trails, and policy gates for every LLM call — zero code changes.",
|
|
5
|
+
"license": "Apache-2.0",
|
|
6
|
+
"author": "Usertools, Inc. <hello@usertools.ai> (https://usertrust.ai)",
|
|
7
|
+
"homepage": "https://usertrust.ai",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "git+https://github.com/usertools-ai/usertrust.git",
|
|
11
|
+
"directory": "packages/openclaw"
|
|
12
|
+
},
|
|
13
|
+
"bugs": "https://github.com/usertools-ai/usertrust/issues",
|
|
14
|
+
"keywords": [
|
|
15
|
+
"openclaw",
|
|
16
|
+
"usertrust",
|
|
17
|
+
"ai",
|
|
18
|
+
"governance",
|
|
19
|
+
"budget",
|
|
20
|
+
"audit",
|
|
21
|
+
"llm",
|
|
22
|
+
"plugin"
|
|
23
|
+
],
|
|
24
|
+
"type": "module",
|
|
25
|
+
"main": "dist/index.js",
|
|
26
|
+
"types": "dist/index.d.ts",
|
|
27
|
+
"exports": {
|
|
28
|
+
".": {
|
|
29
|
+
"import": "./dist/index.js",
|
|
30
|
+
"types": "./dist/index.d.ts"
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
"scripts": {
|
|
34
|
+
"build": "tsc",
|
|
35
|
+
"prepublishOnly": "tsc"
|
|
36
|
+
},
|
|
37
|
+
"files": [
|
|
38
|
+
"dist",
|
|
39
|
+
"openclaw.plugin.json"
|
|
40
|
+
],
|
|
41
|
+
"dependencies": {
|
|
42
|
+
"usertrust": "*"
|
|
43
|
+
},
|
|
44
|
+
"peerDependencies": {
|
|
45
|
+
"@mariozechner/pi-ai": ">=0.1.0"
|
|
46
|
+
},
|
|
47
|
+
"peerDependenciesMeta": {
|
|
48
|
+
"@mariozechner/pi-ai": {
|
|
49
|
+
"optional": true
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|