@opengauge/openclaw-plugin 0.1.0

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/README.md ADDED
@@ -0,0 +1,65 @@
1
+ # @opengauge/openclaw-plugin
2
+
3
+ PromptOps observability for [OpenClaw](https://openclaw.ai) agents. Wraps every LLM provider call via `registerProvider` to give you per-call cost tracking, runaway loop detection, circuit breaker protection, and budget enforcement — without modifying your agent.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ openclaw plugins install @opengauge/openclaw-plugin
9
+ ```
10
+
11
+ Or manually:
12
+
13
+ ```bash
14
+ npm install @opengauge/openclaw-plugin
15
+ ```
16
+
17
+ ## What it does
18
+
19
+ Once installed, the plugin transparently wraps your OpenClaw agent's LLM provider:
20
+
21
+ - **Per-call cost tracking** — every API call logged to `~/.opengauge/data.db` with token counts, cost estimates, and latency
22
+ - **Runaway loop detection** — trigram Jaccard similarity detects when your agent is stuck making the same call repeatedly
23
+ - **Circuit breaker** — optionally blocks calls when runaway loops or budget thresholds are breached
24
+ - **Budget enforcement** — session, daily, and monthly spend limits
25
+ - **Fail-safe** — if anything in OpenGauge fails, your agent is unaffected. Errors are logged to `~/.opengauge/error.log`
26
+
27
+ ## Configuration
28
+
29
+ Create or edit `~/.opengauge/config.yml`:
30
+
31
+ ```yaml
32
+ openclaw:
33
+ circuit_breaker:
34
+ enabled: true
35
+ similarity_threshold: 0.8
36
+ max_similar_calls: 5
37
+ action: warn # warn | block
38
+ budget:
39
+ session_limit_usd: 5.00
40
+ daily_limit_usd: 20.00
41
+ monthly_limit_usd: 400.00
42
+ optimize: false
43
+ log_response_text: true
44
+ log_full_request: false
45
+ ```
46
+
47
+ ## View stats
48
+
49
+ From within OpenClaw:
50
+ ```
51
+ opengauge-stats
52
+ ```
53
+
54
+ Or from the terminal:
55
+ ```bash
56
+ npx opengauge stats --source=openclaw
57
+ ```
58
+
59
+ ## How it works
60
+
61
+ The plugin uses OpenClaw's `registerProvider` API to wrap the active LLM provider. Every individual LLM call — including multi-call tool-use loops within a single agent turn — is intercepted, logged, analyzed, and forwarded. The agent never knows OpenGauge is there.
62
+
63
+ ## License
64
+
65
+ MIT
@@ -0,0 +1,24 @@
1
+ export interface OpenClawCircuitBreakerConfig {
2
+ enabled: boolean;
3
+ similarity_threshold: number;
4
+ max_similar_calls: number;
5
+ escalation_check: boolean;
6
+ action: 'warn' | 'block';
7
+ }
8
+ export interface OpenClawBudgetConfig {
9
+ session_limit_usd: number;
10
+ daily_limit_usd: number;
11
+ monthly_limit_usd: number;
12
+ }
13
+ export interface OpenClawPluginConfig {
14
+ circuit_breaker: OpenClawCircuitBreakerConfig;
15
+ budget: OpenClawBudgetConfig;
16
+ optimize: boolean;
17
+ log_response_text: boolean;
18
+ log_full_request: boolean;
19
+ session_timeout_ms: number;
20
+ }
21
+ export declare function loadPluginConfig(): OpenClawPluginConfig;
22
+ export declare function getErrorLogPath(): string;
23
+ export declare function logError(error: unknown): void;
24
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,4BAA4B;IAC3C,OAAO,EAAE,OAAO,CAAC;IACjB,oBAAoB,EAAE,MAAM,CAAC;IAC7B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,gBAAgB,EAAE,OAAO,CAAC;IAC1B,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC;CAC1B;AAED,MAAM,WAAW,oBAAoB;IACnC,iBAAiB,EAAE,MAAM,CAAC;IAC1B,eAAe,EAAE,MAAM,CAAC;IACxB,iBAAiB,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,oBAAoB;IACnC,eAAe,EAAE,4BAA4B,CAAC;IAC9C,MAAM,EAAE,oBAAoB,CAAC;IAC7B,QAAQ,EAAE,OAAO,CAAC;IAClB,iBAAiB,EAAE,OAAO,CAAC;IAC3B,gBAAgB,EAAE,OAAO,CAAC;IAC1B,kBAAkB,EAAE,MAAM,CAAC;CAC5B;AAqBD,wBAAgB,gBAAgB,IAAI,oBAAoB,CAiCvD;AAED,wBAAgB,eAAe,IAAI,MAAM,CAExC;AAED,wBAAgB,QAAQ,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI,CAY7C"}
package/dist/config.js ADDED
@@ -0,0 +1,82 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.loadPluginConfig = loadPluginConfig;
7
+ exports.getErrorLogPath = getErrorLogPath;
8
+ exports.logError = logError;
9
+ const fs_1 = __importDefault(require("fs"));
10
+ const path_1 = __importDefault(require("path"));
11
+ const os_1 = __importDefault(require("os"));
12
+ const DEFAULT_CONFIG = {
13
+ circuit_breaker: {
14
+ enabled: true,
15
+ similarity_threshold: 0.8,
16
+ max_similar_calls: 5,
17
+ escalation_check: true,
18
+ action: 'warn',
19
+ },
20
+ budget: {
21
+ session_limit_usd: 5.00,
22
+ daily_limit_usd: 20.00,
23
+ monthly_limit_usd: 400.00,
24
+ },
25
+ optimize: false,
26
+ log_response_text: true,
27
+ log_full_request: false,
28
+ session_timeout_ms: 5 * 60 * 1000, // 5 minutes
29
+ };
30
+ function loadPluginConfig() {
31
+ const configPath = path_1.default.join(os_1.default.homedir(), '.opengauge', 'config.yml');
32
+ try {
33
+ if (!fs_1.default.existsSync(configPath))
34
+ return { ...DEFAULT_CONFIG };
35
+ const raw = fs_1.default.readFileSync(configPath, 'utf-8');
36
+ try {
37
+ const yaml = require('js-yaml');
38
+ const parsed = yaml.load(raw);
39
+ if (!parsed?.openclaw)
40
+ return { ...DEFAULT_CONFIG };
41
+ const oc = parsed.openclaw;
42
+ return {
43
+ circuit_breaker: {
44
+ ...DEFAULT_CONFIG.circuit_breaker,
45
+ ...oc.circuit_breaker,
46
+ },
47
+ budget: {
48
+ ...DEFAULT_CONFIG.budget,
49
+ ...oc.budget,
50
+ },
51
+ optimize: oc.optimize ?? DEFAULT_CONFIG.optimize,
52
+ log_response_text: oc.log_response_text ?? DEFAULT_CONFIG.log_response_text,
53
+ log_full_request: oc.log_full_request ?? DEFAULT_CONFIG.log_full_request,
54
+ session_timeout_ms: oc.session_timeout_ms ?? DEFAULT_CONFIG.session_timeout_ms,
55
+ };
56
+ }
57
+ catch {
58
+ return { ...DEFAULT_CONFIG };
59
+ }
60
+ }
61
+ catch {
62
+ return { ...DEFAULT_CONFIG };
63
+ }
64
+ }
65
+ function getErrorLogPath() {
66
+ return path_1.default.join(os_1.default.homedir(), '.opengauge', 'error.log');
67
+ }
68
+ function logError(error) {
69
+ try {
70
+ const logPath = getErrorLogPath();
71
+ const dir = path_1.default.dirname(logPath);
72
+ if (!fs_1.default.existsSync(dir))
73
+ fs_1.default.mkdirSync(dir, { recursive: true });
74
+ const timestamp = new Date().toISOString();
75
+ const message = error instanceof Error ? error.stack || error.message : String(error);
76
+ fs_1.default.appendFileSync(logPath, `[${timestamp}] ${message}\n`);
77
+ }
78
+ catch {
79
+ // If we can't even write error logs, silently fail
80
+ }
81
+ }
82
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,40 @@
1
+ /**
2
+ * @opengauge/openclaw-plugin
3
+ *
4
+ * OpenClaw plugin that wraps every LLM provider call via registerProvider,
5
+ * logging every individual API call to @opengauge/core's SQLite database.
6
+ *
7
+ * Features:
8
+ * - Per-call cost tracking
9
+ * - Runaway loop detection (circuit breaker)
10
+ * - Budget enforcement (session/daily/monthly)
11
+ * - Fail-safe: never crashes the agent
12
+ *
13
+ * Install: openclaw plugins install @opengauge/openclaw-plugin
14
+ */
15
+ import { type OpenClawProvider } from './wrapped-provider';
16
+ /**
17
+ * OpenClaw plugin API interface (minimal — matches registerProvider + registerCommand).
18
+ */
19
+ interface OpenClawPluginAPI {
20
+ registerProvider(provider: any): void;
21
+ registerCommand?(name: string, handler: (args: string[]) => Promise<string | void>): void;
22
+ getProvider?(): OpenClawProvider;
23
+ on?(event: string, handler: (...args: any[]) => void): void;
24
+ }
25
+ /**
26
+ * Plugin entry point — called by OpenClaw when the plugin is loaded.
27
+ */
28
+ export declare function register(api: OpenClawPluginAPI): void;
29
+ /**
30
+ * Plugin metadata for OpenClaw's plugin system.
31
+ */
32
+ export declare const metadata: {
33
+ name: string;
34
+ npm: string;
35
+ version: string;
36
+ description: string;
37
+ author: string;
38
+ };
39
+ export {};
40
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAGH,OAAO,EAAmB,KAAK,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAG5E;;GAEG;AACH,UAAU,iBAAiB;IACzB,gBAAgB,CAAC,QAAQ,EAAE,GAAG,GAAG,IAAI,CAAC;IACtC,eAAe,CAAC,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC;IAC1F,WAAW,CAAC,IAAI,gBAAgB,CAAC;IACjC,EAAE,CAAC,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,IAAI,GAAG,IAAI,CAAC;CAC7D;AAID;;GAEG;AACH,wBAAgB,QAAQ,CAAC,GAAG,EAAE,iBAAiB,GAAG,IAAI,CA8DrD;AAED;;GAEG;AACH,eAAO,MAAM,QAAQ;;;;;;CAMpB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,91 @@
1
+ "use strict";
2
+ /**
3
+ * @opengauge/openclaw-plugin
4
+ *
5
+ * OpenClaw plugin that wraps every LLM provider call via registerProvider,
6
+ * logging every individual API call to @opengauge/core's SQLite database.
7
+ *
8
+ * Features:
9
+ * - Per-call cost tracking
10
+ * - Runaway loop detection (circuit breaker)
11
+ * - Budget enforcement (session/daily/monthly)
12
+ * - Fail-safe: never crashes the agent
13
+ *
14
+ * Install: openclaw plugins install @opengauge/openclaw-plugin
15
+ */
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ exports.metadata = void 0;
18
+ exports.register = register;
19
+ const core_1 = require("opengauge/core");
20
+ const wrapped_provider_1 = require("./wrapped-provider");
21
+ const config_1 = require("./config");
22
+ let wrappedProvider = null;
23
+ /**
24
+ * Plugin entry point — called by OpenClaw when the plugin is loaded.
25
+ */
26
+ function register(api) {
27
+ try {
28
+ // Initialize database
29
+ const db = (0, core_1.getDb)();
30
+ (0, core_1.initSchema)(db);
31
+ const config = (0, config_1.loadPluginConfig)();
32
+ // Get the current provider and wrap it
33
+ const realProvider = api.getProvider?.();
34
+ if (!realProvider) {
35
+ (0, config_1.logError)(new Error('OpenGauge: Could not get current provider from OpenClaw API'));
36
+ return;
37
+ }
38
+ wrappedProvider = new wrapped_provider_1.WrappedProvider(realProvider, config);
39
+ // Register the wrapped provider
40
+ api.registerProvider(wrappedProvider);
41
+ // Register optional stats command
42
+ if (api.registerCommand) {
43
+ api.registerCommand('opengauge-stats', async (args) => {
44
+ try {
45
+ const queries = new core_1.SessionQueries((0, core_1.getDb)());
46
+ const summary = queries.getSpendSummary();
47
+ const alerts = queries.queryAlerts({ dismissed: false, limit: 5 });
48
+ const lines = [
49
+ '--- OpenGauge Stats ---',
50
+ `Sessions: ${summary.session_count}`,
51
+ `Total spend: $${summary.total_cost_usd.toFixed(4)}`,
52
+ `Tokens: ${summary.total_tokens_in.toLocaleString()} in / ${summary.total_tokens_out.toLocaleString()} out`,
53
+ `Tokens saved: ${summary.total_tokens_saved.toLocaleString()}`,
54
+ ];
55
+ if (alerts.length > 0) {
56
+ lines.push('', '--- Active Alerts ---');
57
+ for (const alert of alerts) {
58
+ lines.push(`[${alert.severity.toUpperCase()}] ${alert.alert_type}: ${alert.message}`);
59
+ }
60
+ }
61
+ return lines.join('\n');
62
+ }
63
+ catch (e) {
64
+ (0, config_1.logError)(e);
65
+ return 'OpenGauge: Failed to fetch stats. Check ~/.opengauge/error.log';
66
+ }
67
+ });
68
+ }
69
+ // Listen for shutdown to finalize session
70
+ if (api.on) {
71
+ api.on('gateway_stop', () => {
72
+ wrappedProvider?.shutdown();
73
+ });
74
+ }
75
+ }
76
+ catch (error) {
77
+ // Fail-safe: plugin must never crash OpenClaw
78
+ (0, config_1.logError)(error);
79
+ }
80
+ }
81
+ /**
82
+ * Plugin metadata for OpenClaw's plugin system.
83
+ */
84
+ exports.metadata = {
85
+ name: '@opengauge/openclaw-plugin',
86
+ npm: '@opengauge/openclaw-plugin',
87
+ version: '0.1.0',
88
+ description: 'Cost tracking, runaway loop detection, and budget enforcement for OpenClaw agents',
89
+ author: 'OpenGauge',
90
+ };
91
+ //# 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,66 @@
1
+ import { OpenClawPluginConfig } from './config';
2
+ /**
3
+ * OpenClaw provider interface (minimal — matches what registerProvider expects).
4
+ */
5
+ export interface OpenClawProviderRequest {
6
+ messages: Array<{
7
+ role: string;
8
+ content: string;
9
+ }>;
10
+ model?: string;
11
+ max_tokens?: number;
12
+ temperature?: number;
13
+ stream?: boolean;
14
+ [key: string]: any;
15
+ }
16
+ export interface OpenClawProviderResponse {
17
+ content: string;
18
+ model: string;
19
+ usage?: {
20
+ input_tokens?: number;
21
+ output_tokens?: number;
22
+ prompt_tokens?: number;
23
+ completion_tokens?: number;
24
+ };
25
+ [key: string]: any;
26
+ }
27
+ export interface OpenClawProvider {
28
+ name: string;
29
+ defaultModel?: string;
30
+ chat(request: OpenClawProviderRequest): Promise<OpenClawProviderResponse>;
31
+ chatStream?(request: OpenClawProviderRequest): AsyncIterable<any>;
32
+ }
33
+ export declare class WrappedProvider {
34
+ private realProvider;
35
+ private config;
36
+ private queries;
37
+ private session;
38
+ constructor(realProvider: OpenClawProvider, config: OpenClawPluginConfig);
39
+ get name(): string;
40
+ get defaultModel(): string | undefined;
41
+ /**
42
+ * Ensure we have an active session, creating one if needed or if timed out.
43
+ */
44
+ private ensureSession;
45
+ /**
46
+ * Run circuit breaker checks. Returns a block message if the call should be stopped.
47
+ */
48
+ private runCircuitBreaker;
49
+ /**
50
+ * Check budget thresholds. Returns a block message if budget is breached.
51
+ */
52
+ private checkBudget;
53
+ /**
54
+ * Main chat wrapper — intercepts every LLM call.
55
+ */
56
+ chat(request: OpenClawProviderRequest): Promise<OpenClawProviderResponse>;
57
+ /**
58
+ * Stream wrapper — logs the complete interaction after stream completes.
59
+ */
60
+ chatStream(request: OpenClawProviderRequest): AsyncIterable<any>;
61
+ /**
62
+ * Finalize the current session (called on plugin shutdown).
63
+ */
64
+ shutdown(): void;
65
+ }
66
+ //# sourceMappingURL=wrapped-provider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wrapped-provider.d.ts","sourceRoot":"","sources":["../src/wrapped-provider.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,oBAAoB,EAAY,MAAM,UAAU,CAAC;AAc1D;;GAEG;AACH,MAAM,WAAW,uBAAuB;IACtC,QAAQ,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACnD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;CACpB;AAED,MAAM,WAAW,wBAAwB;IACvC,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE;QACN,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,aAAa,CAAC,EAAE,MAAM,CAAC;QACvB,aAAa,CAAC,EAAE,MAAM,CAAC;QACvB,iBAAiB,CAAC,EAAE,MAAM,CAAC;KAC5B,CAAC;IACF,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;CACpB;AAED,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,IAAI,CAAC,OAAO,EAAE,uBAAuB,GAAG,OAAO,CAAC,wBAAwB,CAAC,CAAC;IAC1E,UAAU,CAAC,CAAC,OAAO,EAAE,uBAAuB,GAAG,aAAa,CAAC,GAAG,CAAC,CAAC;CACnE;AAED,qBAAa,eAAe;IAC1B,OAAO,CAAC,YAAY,CAAmB;IACvC,OAAO,CAAC,MAAM,CAAuB;IACrC,OAAO,CAAC,OAAO,CAAiB;IAChC,OAAO,CAAC,OAAO,CAA6B;gBAEhC,YAAY,EAAE,gBAAgB,EAAE,MAAM,EAAE,oBAAoB;IAMxE,IAAI,IAAI,IAAI,MAAM,CAEjB;IAED,IAAI,YAAY,IAAI,MAAM,GAAG,SAAS,CAErC;IAED;;OAEG;IACH,OAAO,CAAC,aAAa;IAyCrB;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAwCzB;;OAEG;IACH,OAAO,CAAC,WAAW;IA8BnB;;OAEG;IACG,IAAI,CAAC,OAAO,EAAE,uBAAuB,GAAG,OAAO,CAAC,wBAAwB,CAAC;IA4F/E;;OAEG;IACI,UAAU,CAAC,OAAO,EAAE,uBAAuB,GAAG,aAAa,CAAC,GAAG,CAAC;IA+EvE;;OAEG;IACH,QAAQ,IAAI,IAAI;CAQjB"}
@@ -0,0 +1,304 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.WrappedProvider = void 0;
4
+ const core_1 = require("opengauge/core");
5
+ const config_1 = require("./config");
6
+ class WrappedProvider {
7
+ realProvider;
8
+ config;
9
+ queries;
10
+ session = null;
11
+ constructor(realProvider, config) {
12
+ this.realProvider = realProvider;
13
+ this.config = config;
14
+ this.queries = new core_1.SessionQueries((0, core_1.getDb)());
15
+ }
16
+ get name() {
17
+ return this.realProvider.name;
18
+ }
19
+ get defaultModel() {
20
+ return this.realProvider.defaultModel;
21
+ }
22
+ /**
23
+ * Ensure we have an active session, creating one if needed or if timed out.
24
+ */
25
+ ensureSession(model) {
26
+ const now = Date.now();
27
+ if (this.session && (now - this.session.lastCallTimestamp) > this.config.session_timeout_ms) {
28
+ try {
29
+ this.queries.finalizeSession(this.session.sessionId);
30
+ }
31
+ catch (e) {
32
+ (0, config_1.logError)(e);
33
+ }
34
+ this.session = null;
35
+ }
36
+ if (!this.session) {
37
+ try {
38
+ const record = this.queries.createSession('openclaw', model, this.realProvider.name);
39
+ this.session = {
40
+ sessionId: record.id,
41
+ interactionCount: 0,
42
+ runningCostUsd: 0,
43
+ lastCallTimestamp: now,
44
+ recentInteractions: [],
45
+ contextDepthTokens: 0,
46
+ };
47
+ }
48
+ catch (e) {
49
+ (0, config_1.logError)(e);
50
+ this.session = {
51
+ sessionId: `fallback-${now}`,
52
+ interactionCount: 0,
53
+ runningCostUsd: 0,
54
+ lastCallTimestamp: now,
55
+ recentInteractions: [],
56
+ contextDepthTokens: 0,
57
+ };
58
+ }
59
+ }
60
+ return this.session;
61
+ }
62
+ /**
63
+ * Run circuit breaker checks. Returns a block message if the call should be stopped.
64
+ */
65
+ runCircuitBreaker(session) {
66
+ if (!this.config.circuit_breaker.enabled)
67
+ return null;
68
+ const verdict = (0, core_1.checkRunawayLoop)(session.recentInteractions, {
69
+ similarityThreshold: this.config.circuit_breaker.similarity_threshold,
70
+ tripPairCount: this.config.circuit_breaker.max_similar_calls,
71
+ warningPairCount: Math.max(2, this.config.circuit_breaker.max_similar_calls - 2),
72
+ });
73
+ if (verdict.verdict === 'trip') {
74
+ const msg = `OpenGauge circuit breaker: ${verdict.reason}. Session cost: $${session.runningCostUsd.toFixed(2)}. Stopping to prevent runaway spend.`;
75
+ try {
76
+ this.queries.writeAlert(session.sessionId, 'runaway_loop', 'critical', msg, { ...verdict, sessionCost: session.runningCostUsd });
77
+ }
78
+ catch (e) {
79
+ (0, config_1.logError)(e);
80
+ }
81
+ if (this.config.circuit_breaker.action === 'block') {
82
+ return msg;
83
+ }
84
+ }
85
+ else if (verdict.verdict === 'warning') {
86
+ try {
87
+ this.queries.writeAlert(session.sessionId, 'runaway_loop', 'warning', verdict.reason, verdict);
88
+ }
89
+ catch (e) {
90
+ (0, config_1.logError)(e);
91
+ }
92
+ }
93
+ return null;
94
+ }
95
+ /**
96
+ * Check budget thresholds. Returns a block message if budget is breached.
97
+ */
98
+ checkBudget(session) {
99
+ if (session.runningCostUsd >= this.config.budget.session_limit_usd) {
100
+ const msg = `OpenGauge budget: Session cost ($${session.runningCostUsd.toFixed(2)}) exceeds limit ($${this.config.budget.session_limit_usd.toFixed(2)}).`;
101
+ try {
102
+ this.queries.writeAlert(session.sessionId, 'budget_breach', 'critical', msg, {
103
+ sessionCost: session.runningCostUsd,
104
+ limit: this.config.budget.session_limit_usd,
105
+ });
106
+ }
107
+ catch (e) {
108
+ (0, config_1.logError)(e);
109
+ }
110
+ if (this.config.circuit_breaker.action === 'block')
111
+ return msg;
112
+ }
113
+ try {
114
+ const todayStart = new Date();
115
+ todayStart.setHours(0, 0, 0, 0);
116
+ const summary = this.queries.getSpendSummary(todayStart.getTime(), 'openclaw');
117
+ if (summary.total_cost_usd >= this.config.budget.daily_limit_usd) {
118
+ const msg = `OpenGauge budget: Daily spend ($${summary.total_cost_usd.toFixed(2)}) exceeds limit ($${this.config.budget.daily_limit_usd.toFixed(2)}).`;
119
+ this.queries.writeAlert(session.sessionId, 'budget_breach', 'critical', msg, {
120
+ dailyCost: summary.total_cost_usd,
121
+ limit: this.config.budget.daily_limit_usd,
122
+ });
123
+ if (this.config.circuit_breaker.action === 'block')
124
+ return msg;
125
+ }
126
+ }
127
+ catch (e) {
128
+ (0, config_1.logError)(e);
129
+ }
130
+ return null;
131
+ }
132
+ /**
133
+ * Main chat wrapper — intercepts every LLM call.
134
+ */
135
+ async chat(request) {
136
+ const model = request.model || this.realProvider.defaultModel || 'unknown';
137
+ const session = this.ensureSession(model);
138
+ const startTime = Date.now();
139
+ try {
140
+ const lastUserMsg = [...request.messages].reverse().find(m => m.role === 'user');
141
+ const originalPrompt = lastUserMsg?.content || '';
142
+ const blockMsg = this.runCircuitBreaker(session);
143
+ if (blockMsg) {
144
+ return {
145
+ content: blockMsg,
146
+ model,
147
+ usage: { input_tokens: 0, output_tokens: 0 },
148
+ };
149
+ }
150
+ const budgetMsg = this.checkBudget(session);
151
+ if (budgetMsg) {
152
+ return {
153
+ content: budgetMsg,
154
+ model,
155
+ usage: { input_tokens: 0, output_tokens: 0 },
156
+ };
157
+ }
158
+ const response = await this.realProvider.chat(request);
159
+ const latencyMs = Date.now() - startTime;
160
+ const tokensIn = response.usage?.input_tokens || response.usage?.prompt_tokens || 0;
161
+ const tokensOut = response.usage?.output_tokens || response.usage?.completion_tokens || 0;
162
+ const costEstimate = (0, core_1.calculateCost)(this.realProvider.name, model, tokensIn, tokensOut);
163
+ session.interactionCount++;
164
+ session.runningCostUsd += costEstimate.totalCost;
165
+ session.lastCallTimestamp = Date.now();
166
+ session.contextDepthTokens += tokensIn;
167
+ session.recentInteractions.push({
168
+ role: 'user',
169
+ content: originalPrompt,
170
+ timestamp: startTime,
171
+ });
172
+ session.recentInteractions.push({
173
+ role: 'assistant',
174
+ content: response.content,
175
+ timestamp: Date.now(),
176
+ });
177
+ if (session.recentInteractions.length > 40) {
178
+ session.recentInteractions = session.recentInteractions.slice(-40);
179
+ }
180
+ try {
181
+ this.queries.writeInteraction(session.sessionId, session.interactionCount, model, {
182
+ originalPrompt,
183
+ responseText: this.config.log_response_text ? response.content : undefined,
184
+ tokensIn,
185
+ tokensOut,
186
+ costUsd: costEstimate.totalCost,
187
+ latencyMs,
188
+ contextDepthTokens: session.contextDepthTokens,
189
+ metadata: this.config.log_full_request ? { messages: request.messages } : undefined,
190
+ });
191
+ }
192
+ catch (e) {
193
+ (0, config_1.logError)(e);
194
+ }
195
+ try {
196
+ this.queries.updateSessionAggregates(session.sessionId, tokensIn, tokensOut, costEstimate.totalCost);
197
+ }
198
+ catch (e) {
199
+ (0, config_1.logError)(e);
200
+ }
201
+ return response;
202
+ }
203
+ catch (error) {
204
+ (0, config_1.logError)(error);
205
+ try {
206
+ return await this.realProvider.chat(request);
207
+ }
208
+ catch (providerError) {
209
+ throw providerError;
210
+ }
211
+ }
212
+ }
213
+ /**
214
+ * Stream wrapper — logs the complete interaction after stream completes.
215
+ */
216
+ async *chatStream(request) {
217
+ if (!this.realProvider.chatStream) {
218
+ const response = await this.chat(request);
219
+ yield { content: response.content, done: true, ...response.usage };
220
+ return;
221
+ }
222
+ const model = request.model || this.realProvider.defaultModel || 'unknown';
223
+ const session = this.ensureSession(model);
224
+ const startTime = Date.now();
225
+ const lastUserMsg = [...request.messages].reverse().find(m => m.role === 'user');
226
+ const originalPrompt = lastUserMsg?.content || '';
227
+ try {
228
+ const blockMsg = this.runCircuitBreaker(session);
229
+ if (blockMsg) {
230
+ yield { content: blockMsg, done: true };
231
+ return;
232
+ }
233
+ const budgetMsg = this.checkBudget(session);
234
+ if (budgetMsg) {
235
+ yield { content: budgetMsg, done: true };
236
+ return;
237
+ }
238
+ }
239
+ catch (e) {
240
+ (0, config_1.logError)(e);
241
+ }
242
+ let fullContent = '';
243
+ let finalTokensIn = 0;
244
+ let finalTokensOut = 0;
245
+ try {
246
+ for await (const chunk of this.realProvider.chatStream(request)) {
247
+ if (chunk.content)
248
+ fullContent += chunk.content;
249
+ if (chunk.input_tokens || chunk.prompt_tokens) {
250
+ finalTokensIn = chunk.input_tokens || chunk.prompt_tokens || finalTokensIn;
251
+ }
252
+ if (chunk.output_tokens || chunk.completion_tokens) {
253
+ finalTokensOut = chunk.output_tokens || chunk.completion_tokens || finalTokensOut;
254
+ }
255
+ yield chunk;
256
+ }
257
+ }
258
+ catch (error) {
259
+ (0, config_1.logError)(error);
260
+ throw error;
261
+ }
262
+ try {
263
+ const latencyMs = Date.now() - startTime;
264
+ const costEstimate = (0, core_1.calculateCost)(this.realProvider.name, model, finalTokensIn, finalTokensOut);
265
+ session.interactionCount++;
266
+ session.runningCostUsd += costEstimate.totalCost;
267
+ session.lastCallTimestamp = Date.now();
268
+ session.contextDepthTokens += finalTokensIn;
269
+ session.recentInteractions.push({ role: 'user', content: originalPrompt, timestamp: startTime }, { role: 'assistant', content: fullContent, timestamp: Date.now() });
270
+ if (session.recentInteractions.length > 40) {
271
+ session.recentInteractions = session.recentInteractions.slice(-40);
272
+ }
273
+ this.queries.writeInteraction(session.sessionId, session.interactionCount, model, {
274
+ originalPrompt,
275
+ responseText: this.config.log_response_text ? fullContent : undefined,
276
+ tokensIn: finalTokensIn,
277
+ tokensOut: finalTokensOut,
278
+ costUsd: costEstimate.totalCost,
279
+ latencyMs,
280
+ contextDepthTokens: session.contextDepthTokens,
281
+ });
282
+ this.queries.updateSessionAggregates(session.sessionId, finalTokensIn, finalTokensOut, costEstimate.totalCost);
283
+ }
284
+ catch (e) {
285
+ (0, config_1.logError)(e);
286
+ }
287
+ }
288
+ /**
289
+ * Finalize the current session (called on plugin shutdown).
290
+ */
291
+ shutdown() {
292
+ if (this.session) {
293
+ try {
294
+ this.queries.finalizeSession(this.session.sessionId);
295
+ }
296
+ catch (e) {
297
+ (0, config_1.logError)(e);
298
+ }
299
+ this.session = null;
300
+ }
301
+ }
302
+ }
303
+ exports.WrappedProvider = WrappedProvider;
304
+ //# sourceMappingURL=wrapped-provider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wrapped-provider.js","sourceRoot":"","sources":["../src/wrapped-provider.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ {
2
+ "name": "@opengauge/openclaw-plugin",
3
+ "version": "0.1.0",
4
+ "description": "PromptOps observability for OpenClaw: per-call cost tracking, runaway loop detection, circuit breaker, and budget enforcement",
5
+ "author": "OpenGauge / Vega IoT",
6
+ "license": "MIT",
7
+ "entry": "dist/index.js",
8
+ "capabilities": ["registerProvider", "registerCommand"],
9
+ "config_schema": {
10
+ "circuit_breaker.enabled": { "type": "boolean", "default": true },
11
+ "circuit_breaker.similarity_threshold": { "type": "number", "default": 0.8 },
12
+ "circuit_breaker.max_similar_calls": { "type": "number", "default": 5 },
13
+ "circuit_breaker.action": { "type": "string", "enum": ["warn", "block"], "default": "warn" },
14
+ "budget.session_limit_usd": { "type": "number", "default": 5.0 },
15
+ "budget.daily_limit_usd": { "type": "number", "default": 20.0 },
16
+ "budget.monthly_limit_usd": { "type": "number", "default": 400.0 },
17
+ "optimize": { "type": "boolean", "default": false }
18
+ },
19
+ "keywords": ["observability", "cost-tracking", "circuit-breaker", "promptops"]
20
+ }
package/package.json ADDED
@@ -0,0 +1,45 @@
1
+ {
2
+ "name": "@opengauge/openclaw-plugin",
3
+ "version": "0.1.0",
4
+ "description": "PromptOps observability for OpenClaw: per-call cost tracking, runaway loop detection, circuit breaker, and budget enforcement",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "scripts": {
8
+ "build": "rm -rf dist && tsc",
9
+ "prepack": "npm run build"
10
+ },
11
+ "files": [
12
+ "dist",
13
+ "openclaw.plugin.json",
14
+ "README.md"
15
+ ],
16
+ "keywords": [
17
+ "openclaw",
18
+ "opengauge",
19
+ "promptops",
20
+ "observability",
21
+ "cost-tracking",
22
+ "circuit-breaker",
23
+ "llm",
24
+ "ai-agent"
25
+ ],
26
+ "author": "OpenGauge / Vega IoT",
27
+ "license": "MIT",
28
+ "repository": {
29
+ "type": "git",
30
+ "url": "https://github.com/applytorque/opengauge",
31
+ "directory": "packages/openclaw-plugin"
32
+ },
33
+ "dependencies": {
34
+ "js-yaml": "^4.1.0",
35
+ "opengauge": "^0.2.2"
36
+ },
37
+ "devDependencies": {
38
+ "@types/js-yaml": "^4.0.9",
39
+ "@types/node": "^22.13.0",
40
+ "typescript": "^5.7.0"
41
+ },
42
+ "engines": {
43
+ "node": ">=18"
44
+ }
45
+ }