@better_openclaw/betterclaw 2.0.0 → 2.0.2

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 CHANGED
@@ -1,5 +1,5 @@
1
1
  <p align="center">
2
- <img src="docs/banner.png" alt="BetterClaw" width="100%" />
2
+ <img src="banner.png" alt="BetterClaw" width="100%" />
3
3
  </p>
4
4
 
5
5
  <p align="center">
@@ -17,9 +17,9 @@
17
17
 
18
18
  ## What is this?
19
19
 
20
- This is the server-side plugin for [BetterClaw](https://github.com/BetterClaw-app/BetterClaw-ios), an iOS app that connects your iPhone's sensors to your [OpenClaw](https://openclaw.dev) AI agent. The app streams device events (location, battery, health, geofences) to your gateway — this plugin decides what to do with them.
20
+ This is the server-side plugin for [BetterClaw](https://betterclaw.app), an iOS app that connects your iPhone's sensors to your [OpenClaw](https://openclaw.dev) AI agent. The app streams device events (location, battery, health, geofences) to your gateway — this plugin decides what to do with them.
21
21
 
22
- Without this plugin, raw events go straight to your agent. With it, they're filtered, triaged, and enriched before anything reaches your agent's conversation.
22
+ The plugin is the **sole event gateway** for all tiers. Smart mode controls filtering depth: OFF = passive context store, ON = full pipeline with rules, LLM triage, and proactive insights.
23
23
 
24
24
  ```
25
25
  BetterClaw iOS App This Plugin (on gateway) Agent
@@ -28,7 +28,7 @@ Without this plugin, raw events go straight to your agent. With it, they're filt
28
28
  battery ──────▶ ┌───────────────────┼───────────────────┐
29
29
  location ─────▶ │ Rules Engine │ Context Store │
30
30
  health ───────▶ │ LLM Triage │ Pattern Engine │ ──▶ filtered events
31
- geofence ─────▶ │ Budget Limiter │ Proactive Triggers│ + full context
31
+ geofence ─────▶ │ Daily Learner │ Proactive Triggers│ + full context
32
32
  └───────────────────┼───────────────────┘
33
33
 
34
34
  proactive insights
@@ -38,12 +38,15 @@ Without this plugin, raw events go straight to your agent. With it, they're filt
38
38
 
39
39
  ## Features
40
40
 
41
- - **Smart Filtering** — Per-source dedup, cooldown windows, and a daily push budget prevent event spam
42
- - **LLM Triage** — Ambiguous events get a cheap LLM call to decide push vs. suppress, keeping the expensive agent focused
43
- - **Device Context** — Rolling state snapshot: battery, GPS, zone occupancy, health metrics, activity classification
44
- - **Pattern Recognition** — Computes location routines, health trends (7d/30d baselines), and event stats every 6 hours
41
+ - **Tier-Aware Smart Mode** — Smart mode ON = full pipeline (rules → triage → push). Smart mode OFF = passive store (context updated, no filtering or pushing). Synced via periodic heartbeat from iOS.
42
+ - **Two-Layer LLM Triage** — Daily learner builds a personalized triage profile from OpenClaw memory summaries + event reactions. Per-event cheap LLM call with structured output for ambiguous events.
43
+ - **Smart Filtering** — Per-source dedup, cooldown windows, and a configurable daily push budget prevent event spam
44
+ - **Device Context** — Rolling state snapshot with per-field timestamps: battery, GPS, zone occupancy, health metrics, activity classification
45
+ - **Pattern Recognition** — Daily analysis computes location routines, health trends (7d/30d baselines), and event frequency stats
45
46
  - **Proactive Insights** — Combined-signal triggers: low battery away from home, unusual inactivity, sleep deficit, routine deviations, weekly digest
46
- - **Agent Tool** — `get_context` tool lets your agent read the full device snapshot on demand
47
+ - **Per-Device Config** — iOS app can override push budget and proactive settings at runtime via RPC
48
+ - **Agent Tool** — `get_context` tool lets your agent read the full device snapshot, tier, smart mode status, and triage profile on demand
49
+ - **CLI Setup** — `openclaw betterclaw setup` configures gateway allowedCommands automatically
47
50
 
48
51
  ## Requirements
49
52
 
@@ -54,6 +57,7 @@ Without this plugin, raw events go straight to your agent. With it, they're filt
54
57
 
55
58
  ```bash
56
59
  openclaw plugins install @betterclaw-app/betterclaw
60
+ openclaw betterclaw setup # configures gateway allowedCommands
57
61
  ```
58
62
 
59
63
  ## Configure
@@ -67,10 +71,11 @@ Add to your `openclaw.json`:
67
71
  "betterclaw": {
68
72
  "enabled": true,
69
73
  "config": {
70
- "llmModel": "openai/gpt-4o-mini",
74
+ "triageModel": "openai/gpt-4o-mini",
71
75
  "pushBudgetPerDay": 10,
72
76
  "patternWindowDays": 14,
73
- "proactiveEnabled": true
77
+ "proactiveEnabled": true,
78
+ "analysisHour": 5
74
79
  }
75
80
  }
76
81
  }
@@ -84,29 +89,41 @@ All config keys are optional — defaults are shown above.
84
89
 
85
90
  | Key | Default | Description |
86
91
  |-----|---------|-------------|
87
- | `llmModel` | `openai/gpt-4o-mini` | Model used for ambiguous event triage |
92
+ | `triageModel` | `openai/gpt-4o-mini` | Model for per-event triage (supports `provider/model` format) |
93
+ | `triageApiBase` | — | Optional base URL for OpenAI-compatible endpoint (e.g., Ollama) |
88
94
  | `pushBudgetPerDay` | `10` | Max events forwarded to the agent per day |
89
95
  | `patternWindowDays` | `14` | Days of event history used for pattern computation |
90
96
  | `proactiveEnabled` | `true` | Enable proactive combined-signal insights |
97
+ | `analysisHour` | `5` | Hour (0-23, system timezone) for daily pattern + learner analysis |
98
+
99
+ > **Migration:** `llmModel` still works as a deprecated alias for `triageModel`.
91
100
 
92
101
  ## How It Works
93
102
 
94
103
  ### Event Pipeline
95
104
 
96
- Every device event from the BetterClaw app goes through a multi-stage pipeline before reaching your agent:
105
+ Every device event from the BetterClaw app goes through the plugin:
97
106
 
98
- 1. **Rules Engine** — Checks dedup, cooldown timers, and daily budget. Obvious spam is dropped immediately.
99
- 2. **LLM Triage** — Events that aren't clearly push or suppress get a fast LLM call with device context for a judgment call.
100
- 3. **Context Update** — The device context store is updated with the latest sensor data regardless of whether the event is forwarded.
101
- 4. **Event Logging** — Every event and its decision (push/suppress/defer) is logged for pattern computation.
107
+ 1. **Context Update** — Device context store is always updated with the latest sensor data.
108
+ 2. **Smart Mode Check** — If smart mode is OFF, the event is stored and processing stops. If ON, continues.
109
+ 3. **Rules Engine** — Checks dedup, cooldown timers, and daily budget. Critical events (geofence, low battery) always push. Obvious spam is dropped.
110
+ 4. **LLM Triage** — Ambiguous events get a cheap LLM call with the personalized triage profile for a push/drop decision.
102
111
  5. **Agent Injection** — Events that pass are injected into the agent's main session with formatted context.
103
112
 
104
113
  ### Background Services
105
114
 
106
- Two engines run on a schedule in the background:
115
+ - **Pattern Engine + Daily Learner** (daily at `analysisHour`) — Computes location routines, health trends, event stats. Then runs a subagent turn to build a personalized triage profile from OpenClaw memory summaries and notification reaction data.
116
+ - **Proactive Engine** (hourly) — Evaluates combined-signal conditions and fires insights when thresholds are met.
117
+
118
+ ### Gateway RPCs
107
119
 
108
- - **Pattern Engine** (every 6h) Analyzes event history to compute location routines, health trends, and event frequency stats
109
- - **Proactive Engine** (every 30min) — Evaluates combined-signal conditions and fires insights when thresholds are met
120
+ | RPC | Direction | Purpose |
121
+ |-----|-----------|---------|
122
+ | `betterclaw.event` | iOS → plugin | Send a device event for processing |
123
+ | `betterclaw.ping` | iOS → plugin | Heartbeat: sync tier + smartMode, get budget info |
124
+ | `betterclaw.config` | iOS → plugin | Per-device settings override |
125
+ | `betterclaw.context` | iOS → plugin | Full context for iOS Context tab |
126
+ | `betterclaw.snapshot` | iOS → plugin | Bulk device state catch-up |
110
127
 
111
128
  ## Commands
112
129
 
@@ -118,7 +135,8 @@ Two engines run on a schedule in the background:
118
135
 
119
136
  | Plugin | BetterClaw iOS | OpenClaw |
120
137
  |--------|----------------|----------|
121
- | 1.x | 1.x+ | 2025.12+ |
138
+ | 2.x | 2.x+ | 2025.12+ |
139
+ | 1.x | 1.x | 2025.12+ |
122
140
 
123
141
  ## License
124
142
 
package/banner.png ADDED
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@better_openclaw/betterclaw",
3
- "version": "2.0.0",
3
+ "version": "2.0.2",
4
4
  "description": "Intelligent event filtering, context tracking, and proactive triggers for BetterClaw",
5
5
  "license": "AGPL-3.0-only",
6
6
  "repository": {
package/src/filter.ts CHANGED
@@ -1,21 +1,15 @@
1
1
  import type { DeviceContext, DeviceEvent, FilterDecision } from "./types.js";
2
2
 
3
- // Cooldowns in seconds
4
- const DEDUP_COOLDOWN: Record<string, number> = {
5
- "default.battery-low": 3600,
6
- "default.battery-critical": 1800,
7
- "default.daily-health": 82800, // 23 hours
8
- "default.geofence": 300,
9
- };
10
-
11
- const DEFAULT_COOLDOWN = 1800; // 30 minutes
12
-
13
3
  export class RulesEngine {
14
4
  private lastFired: Map<string, number> = new Map();
15
5
  private pushBudget: number;
6
+ private cooldowns: Record<string, number>;
7
+ private defaultCooldown: number;
16
8
 
17
- constructor(pushBudget: number = 10) {
9
+ constructor(pushBudget: number = 10, cooldowns: Record<string, number> = {}, defaultCooldown: number = 1800) {
18
10
  this.pushBudget = pushBudget;
11
+ this.cooldowns = cooldowns;
12
+ this.defaultCooldown = defaultCooldown;
19
13
  }
20
14
 
21
15
  evaluate(event: DeviceEvent, context: DeviceContext, budgetOverride?: number): FilterDecision {
@@ -26,7 +20,7 @@ export class RulesEngine {
26
20
 
27
21
  // Dedup check
28
22
  const lastFiredAt = this.lastFired.get(event.subscriptionId);
29
- const cooldown = DEDUP_COOLDOWN[event.subscriptionId] ?? DEFAULT_COOLDOWN;
23
+ const cooldown = this.cooldowns[event.subscriptionId] ?? this.defaultCooldown;
30
24
  if (lastFiredAt && event.firedAt - lastFiredAt < cooldown) {
31
25
  return {
32
26
  action: "drop",
package/src/index.ts CHANGED
@@ -16,6 +16,13 @@ import * as path from "node:path";
16
16
 
17
17
  export type { PluginConfig } from "./types.js";
18
18
 
19
+ const DEFAULT_COOLDOWNS: Record<string, number> = {
20
+ "default.battery-low": 3600,
21
+ "default.battery-critical": 1800,
22
+ "default.daily-health": 82800,
23
+ "default.geofence": 300,
24
+ };
25
+
19
26
  const DEFAULT_CONFIG: PluginConfig = {
20
27
  triageModel: "openai/gpt-4o-mini",
21
28
  triageApiBase: undefined,
@@ -23,6 +30,8 @@ const DEFAULT_CONFIG: PluginConfig = {
23
30
  patternWindowDays: 14,
24
31
  proactiveEnabled: true,
25
32
  analysisHour: 5,
33
+ deduplicationCooldowns: DEFAULT_COOLDOWNS,
34
+ defaultCooldown: 1800,
26
35
  };
27
36
 
28
37
  function resolveConfig(raw: Record<string, unknown> | undefined): PluginConfig {
@@ -34,6 +43,13 @@ function resolveConfig(raw: Record<string, unknown> | undefined): PluginConfig {
34
43
  patternWindowDays: typeof cfg.patternWindowDays === "number" && cfg.patternWindowDays > 0 ? cfg.patternWindowDays : 14,
35
44
  proactiveEnabled: typeof cfg.proactiveEnabled === "boolean" ? cfg.proactiveEnabled : true,
36
45
  analysisHour: typeof cfg.analysisHour === "number" ? Math.max(0, Math.min(23, cfg.analysisHour)) : 5,
46
+ deduplicationCooldowns: {
47
+ ...DEFAULT_COOLDOWNS,
48
+ ...(typeof cfg.deduplicationCooldowns === "object" && cfg.deduplicationCooldowns !== null
49
+ ? cfg.deduplicationCooldowns as Record<string, number>
50
+ : {}),
51
+ },
52
+ defaultCooldown: typeof cfg.defaultCooldown === "number" && cfg.defaultCooldown > 0 ? cfg.defaultCooldown : 1800,
37
53
  };
38
54
  }
39
55
 
@@ -52,7 +68,7 @@ export default {
52
68
 
53
69
  // Event log, rules engine, reaction tracker
54
70
  const eventLog = new EventLog(stateDir);
55
- const rules = new RulesEngine(config.pushBudgetPerDay);
71
+ const rules = new RulesEngine(config.pushBudgetPerDay, config.deduplicationCooldowns, config.defaultCooldown);
56
72
  const reactionTracker = new ReactionTracker(stateDir);
57
73
 
58
74
  // Pipeline dependencies
package/src/pipeline.ts CHANGED
@@ -134,7 +134,7 @@ async function pushToAgent(deps: PipelineDeps, event: DeviceEvent, reason: strin
134
134
  await deps.api.runtime.subagent.run({
135
135
  sessionKey: "main",
136
136
  message,
137
- deliver: true,
137
+ deliver: false,
138
138
  idempotencyKey,
139
139
  });
140
140
  deps.api.logger.info(`betterclaw: pushed event ${event.subscriptionId} to agent`);
package/src/types.ts CHANGED
@@ -127,6 +127,8 @@ export interface PluginConfig {
127
127
  patternWindowDays: number;
128
128
  proactiveEnabled: boolean;
129
129
  analysisHour: number;
130
+ deduplicationCooldowns: Record<string, number>;
131
+ defaultCooldown: number;
130
132
  }
131
133
 
132
134
  // Triage profile produced by daily learning agent