openclaw-lark-multi-agent 1.6.0 → 1.8.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.
@@ -0,0 +1,10 @@
1
+ /** An authoritative terminal result of one generation-pinned, admitted executor run.
2
+ * Admission, terminal result and platform delivery receipts are separate facts. */
3
+ export type GoExecutorResult = {
4
+ sessionKey: string;
5
+ sessionId: string;
6
+ runId: string;
7
+ disposition: "visible" | "silent" | "empty" | "error";
8
+ text: string;
9
+ error?: string;
10
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,32 @@
1
+ /** Pure adapter contract. Independent queries are observations, not a global atomic snapshot. */
2
+ export type GoRuntimeSnapshot = {
3
+ sessionKey: string;
4
+ sessionId: string;
5
+ goalId: string;
6
+ goalRevision: number;
7
+ executorRunIds: string[];
8
+ checkerRunId: string;
9
+ complete: boolean;
10
+ archived: boolean;
11
+ independent?: boolean;
12
+ queryAvailable?: boolean;
13
+ running?: boolean;
14
+ atomicSnapshot?: boolean;
15
+ queuedInputs: number;
16
+ recoverableInputs: number;
17
+ pendingDeliveries: number;
18
+ tasks: Array<{
19
+ taskId: string;
20
+ runId: string;
21
+ parentTaskId: string | null;
22
+ state: string;
23
+ deliveryState: string;
24
+ }>;
25
+ };
26
+ export declare function goSnapshotBlocked(s: GoRuntimeSnapshot, expected: {
27
+ sessionKey: string;
28
+ sessionId: string;
29
+ goalId: string;
30
+ goalRevision: number;
31
+ executorRunIds: string[];
32
+ }): string | null;
@@ -0,0 +1,56 @@
1
+ export function goSnapshotBlocked(s, expected) {
2
+ if (!s.independent && (!s.checkerRunId || !expected.executorRunIds.length || expected.executorRunIds.some(id => !id)))
3
+ return "missing run identity";
4
+ if (s.independent ? !s.queryAvailable : !s.complete)
5
+ return "incomplete snapshot";
6
+ if (s.independent && s.queuedInputs !== 0)
7
+ return "pending or unknown input/delivery";
8
+ if (s.independent && s.running !== false)
9
+ return "active or unknown session";
10
+ if (s.archived || s.sessionKey !== expected.sessionKey || s.sessionId !== expected.sessionId || (!s.independent && (s.goalId !== expected.goalId || s.goalRevision !== expected.goalRevision)))
11
+ return "identity/version changed";
12
+ if (!s.independent && [s.queuedInputs, s.recoverableInputs, s.pendingDeliveries].some(n => !Number.isSafeInteger(n) || n !== 0))
13
+ return "pending or unknown input/delivery";
14
+ if (!s.independent && (new Set(s.executorRunIds).size !== s.executorRunIds.length || s.executorRunIds.length !== expected.executorRunIds.length || expected.executorRunIds.some(id => !s.executorRunIds.includes(id))))
15
+ return "run association changed";
16
+ const byId = new Map(s.tasks.map(t => [t.taskId, t]));
17
+ if (byId.size !== s.tasks.length)
18
+ return "duplicate task identity";
19
+ for (const task of s.tasks) {
20
+ const visited = new Set();
21
+ let cursor = task;
22
+ while (cursor) {
23
+ if (visited.has(cursor.taskId))
24
+ return "cyclic task ancestry";
25
+ visited.add(cursor.taskId);
26
+ cursor = cursor.parentTaskId ? byId.get(cursor.parentTaskId) : undefined;
27
+ }
28
+ }
29
+ const related = new Set(s.tasks.filter(t => expected.executorRunIds.includes(t.runId)).map(t => t.taskId));
30
+ // Fixed point, not ordering/prefix inference. Exclude no task just because its text says checker.
31
+ let changed = true;
32
+ while (changed) {
33
+ changed = false;
34
+ for (const t of s.tasks)
35
+ if (t.parentTaskId && related.has(t.parentTaskId) && !related.has(t.taskId)) {
36
+ related.add(t.taskId);
37
+ changed = true;
38
+ }
39
+ }
40
+ for (const t of s.tasks) {
41
+ if (t.parentTaskId && !byId.has(t.parentTaskId))
42
+ return "missing ancestor";
43
+ if (!related.has(t.taskId) && !s.independent)
44
+ continue;
45
+ if (t.runId === s.checkerRunId)
46
+ return "checker/executor association conflict";
47
+ if (!["completed", "failed", "cancelled"].includes(t.state))
48
+ return "active or unknown task";
49
+ if (!["delivered", "not_required"].includes(t.deliveryState))
50
+ return "pending or unknown task return";
51
+ }
52
+ // Each root run needs explicit terminal state evidence; absence is never idle.
53
+ if (!s.independent && expected.executorRunIds.some(id => !s.tasks.some(t => t.runId === id)))
54
+ return "missing root run";
55
+ return null;
56
+ }
@@ -103,6 +103,85 @@ export declare class MessageStore {
103
103
  constructor(dbPath?: string);
104
104
  /** Go / Go-Checker supervision state (design: artifacts/lma-go-checker-design-20260917 §10). */
105
105
  private initGoTables;
106
+ private ensureGoIntegrationSchema;
107
+ bindGoNativeIdentity(goId: number, identity: {
108
+ nativeGoalId?: string;
109
+ executorSessionId: string;
110
+ checkerSessionId: string;
111
+ checkerRunId?: string;
112
+ executorRunIds: string[];
113
+ goalUpdatedAt?: number;
114
+ goalRevision?: number | null;
115
+ }): void;
116
+ getGoNativeIdentity(goId: number): any;
117
+ setGoCriteria(goId: number, criteria: Array<{
118
+ id: string;
119
+ text: string;
120
+ }>): void;
121
+ getGoCriteria(goId: number): Array<{
122
+ id: string;
123
+ text: string;
124
+ }>;
125
+ getGoDeliveryOperation(goId: number, key: string): any;
126
+ recordGoDeliveryOperation(goId: number, key: string, state: "attempted" | "accepted" | "unknown" | "rejected", response?: unknown): void;
127
+ /** Durable initial-execution intent, separate from the at-most-once send ledger. */
128
+ createGoBootstrap(goId: number): void;
129
+ getGoBootstrap(goId: number): string | null;
130
+ finishGoBootstrap(goId: number, state: "done" | "superseded"): void;
131
+ isGoActionComplete(goId: number, actionKey: string): boolean;
132
+ listGoSends(goId: number): Array<{
133
+ actionKey: string;
134
+ idempotencyKey: string;
135
+ sessionKey: string;
136
+ sessionId: string;
137
+ }>;
138
+ recordGoRunResult(goId: number, actionKey: string, result: {
139
+ state: "complete" | "unknown";
140
+ text?: string;
141
+ runId: string;
142
+ executorResult?: import("./go-execution.js").GoExecutorResult;
143
+ }): void;
144
+ getGoRunResult(goId: number, actionKey: string): any;
145
+ listUnknownGoRunResults(goId: number): Array<{
146
+ actionKey: string;
147
+ runId: string;
148
+ sessionKey: string;
149
+ sessionId: string;
150
+ }>;
151
+ hasUnknownGoRunResults(goId: number): boolean;
152
+ associateGoAdmittedRun(goId: number, runId: string, executor: boolean): void;
153
+ /** Durable delivery ownership includes completed/stopped jobs, not only active ones. */
154
+ ownsGoExecutorRun(botName: string, chatId: string, sessionKey: string, sessionId: string, runId: string): boolean;
155
+ recordGoVisibleEvidence(goId: number, sourceKey: string, payload: {
156
+ sessionId: string;
157
+ runId: string;
158
+ kind: string;
159
+ text: string;
160
+ attachments: unknown[];
161
+ }): boolean;
162
+ recordGoDeliveryReceipt(goId: number, sourceKey: string, receipt: unknown): void;
163
+ listGoVisibleEvidence(goId: number): any[];
164
+ bindGoSendIdentity(goId: number, actionKey: string, identity: {
165
+ sessionKey: string;
166
+ sessionId: string;
167
+ }): void;
168
+ listUnresolvedGoSends(goId: number): Array<{
169
+ actionKey: string;
170
+ idempotencyKey: string;
171
+ sessionKey: string;
172
+ sessionId: string;
173
+ }>;
174
+ recordGoActionAttempt(goId: number, actionKey: string): {
175
+ state: string;
176
+ idempotency_key: string;
177
+ receipt_json: string;
178
+ } | undefined;
179
+ getGoActionLifecycle(goId: number, actionKey: string): {
180
+ state: string;
181
+ idempotency_key: string;
182
+ receipt_json: string;
183
+ } | undefined;
184
+ recordGoActionOutcome(goId: number, actionKey: string, state: 'accepted' | 'unknown', receipt?: unknown): void;
106
185
  observeRunError(botName: string, chatId: string, provenance: ErrorProvenance): PendingErrorNotice;
107
186
  getErrorNotice(botName: string, chatId: string, noticeId: string): PendingErrorNotice | undefined;
108
187
  saveErrorNotice(record: PendingErrorNotice): void;
@@ -245,6 +324,7 @@ export declare class MessageStore {
245
324
  executorSessionId: string;
246
325
  checkerSessionKey: string;
247
326
  checkerModel: string;
327
+ state?: "STARTING" | "WAITING_WORK";
248
328
  }): number;
249
329
  private rowToGoJob;
250
330
  getActiveGoJob(botName: string, chatId: string): GoJobRow | null;
@@ -266,8 +346,11 @@ export declare class MessageStore {
266
346
  finishGoCheck(goId: number, checkId: string, state: string, action: string, summary: string, raw: string): void;
267
347
  /** Idempotent action claim: returns true when newly claimed (caller performs the action), false when it already existed. */
268
348
  claimGoAction(goId: number, actionKey: string, kind: string, payload: string): boolean;
349
+ hasUnresolvedGoActions(goId: number): boolean;
269
350
  completeGoAction(goId: number, actionKey: string, receipt: string): void;
270
351
  setGoModelPref(botName: string, chatId: string, model: string | null): void;
271
352
  getGoModelPref(botName: string, chatId: string): string | null;
353
+ private closeObservers;
354
+ onClose(callback: () => void): () => boolean;
272
355
  close(): void;
273
356
  }
@@ -83,6 +83,136 @@ export class MessageStore {
83
83
  );
84
84
  `);
85
85
  }
86
+ ensureGoIntegrationSchema() {
87
+ this.db.exec(`CREATE TABLE IF NOT EXISTS go_native_bindings (
88
+ go_id INTEGER PRIMARY KEY, identity_json TEXT NOT NULL);
89
+ CREATE TABLE IF NOT EXISTS go_action_lifecycle (
90
+ go_id INTEGER NOT NULL, action_key TEXT NOT NULL, state TEXT NOT NULL,
91
+ idempotency_key TEXT NOT NULL, receipt_json TEXT NOT NULL DEFAULT '',
92
+ PRIMARY KEY(go_id, action_key));
93
+ CREATE TABLE IF NOT EXISTS go_visible_evidence (
94
+ go_id INTEGER NOT NULL, source_key TEXT NOT NULL, payload_json TEXT NOT NULL,
95
+ receipt_json TEXT NOT NULL DEFAULT '', PRIMARY KEY(go_id, source_key));`);
96
+ }
97
+ bindGoNativeIdentity(goId, identity) {
98
+ this.ensureGoIntegrationSchema();
99
+ this.db.prepare('INSERT INTO go_native_bindings VALUES (?, ?)').run(goId, JSON.stringify(identity));
100
+ }
101
+ getGoNativeIdentity(goId) {
102
+ this.ensureGoIntegrationSchema();
103
+ const row = this.db.prepare('SELECT identity_json FROM go_native_bindings WHERE go_id=?').get(goId);
104
+ return row ? JSON.parse(row.identity_json) : null;
105
+ }
106
+ setGoCriteria(goId, criteria) {
107
+ this.db.exec("CREATE TABLE IF NOT EXISTS go_criteria(go_id INTEGER PRIMARY KEY,criteria_json TEXT NOT NULL)");
108
+ this.db.prepare("INSERT OR REPLACE INTO go_criteria VALUES (?,?)").run(goId, JSON.stringify(criteria));
109
+ }
110
+ getGoCriteria(goId) {
111
+ this.db.exec("CREATE TABLE IF NOT EXISTS go_criteria(go_id INTEGER PRIMARY KEY,criteria_json TEXT NOT NULL)");
112
+ const row = this.db.prepare("SELECT criteria_json FROM go_criteria WHERE go_id=?").get(goId);
113
+ return row ? JSON.parse(row.criteria_json) : [];
114
+ }
115
+ getGoDeliveryOperation(goId, key) {
116
+ this.db.exec("CREATE TABLE IF NOT EXISTS go_delivery_operations(go_id INTEGER,operation_key TEXT,state TEXT,response_json TEXT,PRIMARY KEY(go_id,operation_key))");
117
+ return this.db.prepare("SELECT * FROM go_delivery_operations WHERE go_id=? AND operation_key=?").get(goId, key);
118
+ }
119
+ recordGoDeliveryOperation(goId, key, state, response) {
120
+ this.getGoDeliveryOperation(goId, key);
121
+ this.db.prepare("INSERT INTO go_delivery_operations VALUES (?,?,?,?) ON CONFLICT(go_id,operation_key) DO UPDATE SET state=excluded.state,response_json=excluded.response_json WHERE go_delivery_operations.state!='accepted'").run(goId, key, state, response === undefined ? "" : JSON.stringify(response));
122
+ }
123
+ /** Durable initial-execution intent, separate from the at-most-once send ledger. */
124
+ createGoBootstrap(goId) {
125
+ this.db.exec("CREATE TABLE IF NOT EXISTS go_bootstrap(go_id INTEGER PRIMARY KEY,state TEXT NOT NULL)");
126
+ this.db.prepare("INSERT OR IGNORE INTO go_bootstrap VALUES (?,'pending')").run(goId);
127
+ }
128
+ getGoBootstrap(goId) {
129
+ this.db.exec("CREATE TABLE IF NOT EXISTS go_bootstrap(go_id INTEGER PRIMARY KEY,state TEXT NOT NULL)");
130
+ return this.db.prepare("SELECT state FROM go_bootstrap WHERE go_id=?").get(goId)?.state ?? null;
131
+ }
132
+ finishGoBootstrap(goId, state) {
133
+ this.getGoBootstrap(goId);
134
+ this.db.prepare("UPDATE go_bootstrap SET state=? WHERE go_id=?").run(state, goId);
135
+ }
136
+ isGoActionComplete(goId, actionKey) {
137
+ return this.db.prepare("SELECT done FROM go_actions WHERE go_id=? AND action_key=?").get(goId, actionKey)?.done === 1;
138
+ }
139
+ listGoSends(goId) {
140
+ this.listUnresolvedGoSends(goId);
141
+ return this.db.prepare("SELECT s.*,l.idempotency_key FROM go_send_identities s JOIN go_action_lifecycle l ON s.go_id=l.go_id AND s.action_key=l.action_key WHERE s.go_id=?").all(goId)
142
+ .map(r => ({ actionKey: r.action_key, idempotencyKey: r.idempotency_key, ...JSON.parse(r.identity_json) }));
143
+ }
144
+ recordGoRunResult(goId, actionKey, result) {
145
+ this.db.exec("CREATE TABLE IF NOT EXISTS go_run_results(go_id INTEGER,action_key TEXT,result_json TEXT,PRIMARY KEY(go_id,action_key))");
146
+ this.db.prepare("INSERT OR REPLACE INTO go_run_results VALUES (?,?,?)").run(goId, actionKey, JSON.stringify(result));
147
+ }
148
+ getGoRunResult(goId, actionKey) {
149
+ this.db.exec("CREATE TABLE IF NOT EXISTS go_run_results(go_id INTEGER,action_key TEXT,result_json TEXT,PRIMARY KEY(go_id,action_key))");
150
+ const row = this.db.prepare("SELECT result_json FROM go_run_results WHERE go_id=? AND action_key=?").get(goId, actionKey);
151
+ return row ? JSON.parse(row.result_json) : null;
152
+ }
153
+ listUnknownGoRunResults(goId) {
154
+ this.getGoRunResult(goId, "");
155
+ this.listUnresolvedGoSends(goId);
156
+ return this.db.prepare("SELECT r.action_key,r.result_json,s.identity_json FROM go_run_results r JOIN go_send_identities s ON r.go_id=s.go_id AND r.action_key=s.action_key WHERE r.go_id=?").all(goId).flatMap(r => {
157
+ const result = JSON.parse(r.result_json);
158
+ return result.state === "unknown" ? [{ actionKey: r.action_key, runId: result.runId, ...JSON.parse(r.identity_json) }] : [];
159
+ });
160
+ }
161
+ hasUnknownGoRunResults(goId) {
162
+ this.getGoRunResult(goId, "");
163
+ return this.db.prepare("SELECT result_json FROM go_run_results WHERE go_id=?").all(goId).some(r => JSON.parse(r.result_json).state === "unknown");
164
+ }
165
+ associateGoAdmittedRun(goId, runId, executor) {
166
+ const identity = this.getGoNativeIdentity(goId);
167
+ if (!identity)
168
+ throw new Error("Missing independent identity");
169
+ if (executor)
170
+ identity.executorRunIds = [...new Set([...identity.executorRunIds, runId])];
171
+ else
172
+ identity.checkerRunId = runId;
173
+ this.db.prepare("UPDATE go_native_bindings SET identity_json=? WHERE go_id=?").run(JSON.stringify(identity), goId);
174
+ }
175
+ /** Durable delivery ownership includes completed/stopped jobs, not only active ones. */
176
+ ownsGoExecutorRun(botName, chatId, sessionKey, sessionId, runId) {
177
+ this.ensureGoIntegrationSchema();
178
+ return this.db.prepare("SELECT j.executor_session_key,j.executor_session_id,b.identity_json FROM go_jobs j JOIN go_native_bindings b ON j.id=b.go_id WHERE j.bot_name=? AND j.chat_id=? AND j.executor_session_id=?").all(botName, chatId, sessionId)
179
+ .some(row => [row.executor_session_key, `agent:main:${row.executor_session_key}`].includes(sessionKey) && JSON.parse(row.identity_json).executorRunIds.includes(runId));
180
+ }
181
+ recordGoVisibleEvidence(goId, sourceKey, payload) {
182
+ this.ensureGoIntegrationSchema();
183
+ return this.db.prepare('INSERT OR IGNORE INTO go_visible_evidence (go_id,source_key,payload_json) VALUES (?,?,?)').run(goId, sourceKey, JSON.stringify(payload)).changes === 1;
184
+ }
185
+ recordGoDeliveryReceipt(goId, sourceKey, receipt) {
186
+ this.ensureGoIntegrationSchema();
187
+ this.db.prepare('UPDATE go_visible_evidence SET receipt_json=? WHERE go_id=? AND source_key=?').run(JSON.stringify(receipt), goId, sourceKey);
188
+ }
189
+ listGoVisibleEvidence(goId) {
190
+ this.ensureGoIntegrationSchema();
191
+ return this.db.prepare('SELECT * FROM go_visible_evidence WHERE go_id=? ORDER BY rowid').all(goId)
192
+ .map(r => ({ sourceKey: r.source_key, ...JSON.parse(r.payload_json), receipt: r.receipt_json ? JSON.parse(r.receipt_json) : null }));
193
+ }
194
+ bindGoSendIdentity(goId, actionKey, identity) {
195
+ this.db.exec("CREATE TABLE IF NOT EXISTS go_send_identities(go_id INTEGER,action_key TEXT,identity_json TEXT,PRIMARY KEY(go_id,action_key))");
196
+ this.db.prepare("INSERT OR IGNORE INTO go_send_identities VALUES (?,?,?)").run(goId, actionKey, JSON.stringify(identity));
197
+ }
198
+ listUnresolvedGoSends(goId) {
199
+ this.db.exec("CREATE TABLE IF NOT EXISTS go_send_identities(go_id INTEGER,action_key TEXT,identity_json TEXT,PRIMARY KEY(go_id,action_key))");
200
+ return this.db.prepare("SELECT s.*,l.idempotency_key FROM go_send_identities s JOIN go_action_lifecycle l ON s.go_id=l.go_id AND s.action_key=l.action_key WHERE s.go_id=? AND l.state!='accepted'").all(goId).map(r => ({ actionKey: r.action_key, idempotencyKey: r.idempotency_key, ...JSON.parse(r.identity_json) }));
201
+ }
202
+ recordGoActionAttempt(goId, actionKey) {
203
+ this.ensureGoIntegrationSchema();
204
+ const idempotencyKey = `lma-go:${goId}:${actionKey}`;
205
+ this.db.prepare("INSERT OR IGNORE INTO go_action_lifecycle (go_id,action_key,state,idempotency_key) VALUES (?,?,'attempted',?)").run(goId, actionKey, idempotencyKey);
206
+ return this.getGoActionLifecycle(goId, actionKey);
207
+ }
208
+ getGoActionLifecycle(goId, actionKey) {
209
+ this.ensureGoIntegrationSchema();
210
+ return this.db.prepare('SELECT * FROM go_action_lifecycle WHERE go_id=? AND action_key=?').get(goId, actionKey);
211
+ }
212
+ recordGoActionOutcome(goId, actionKey, state, receipt) {
213
+ this.ensureGoIntegrationSchema();
214
+ this.db.prepare('UPDATE go_action_lifecycle SET state=?,receipt_json=? WHERE go_id=? AND action_key=? AND state!=?').run(state, receipt === undefined ? '' : JSON.stringify(receipt), goId, actionKey, 'accepted');
215
+ }
86
216
  observeRunError(botName, chatId, provenance) {
87
217
  const noticeId = errorIdentity(provenance.sessionKey, provenance.runId);
88
218
  const previous = this.getErrorNotice(botName, chatId, noticeId);
@@ -1199,8 +1329,8 @@ export class MessageStore {
1199
1329
  const now = Date.now();
1200
1330
  const r = this.db.prepare(`INSERT INTO go_jobs
1201
1331
  (bot_name, chat_id, goal, acceptance, state, executor_session_key, executor_session_id, checker_session_key, checker_model, revision, created_at, updated_at)
1202
- VALUES (?, ?, ?, ?, 'WAITING_WORK', ?, ?, ?, ?, 1, ?, ?)`)
1203
- .run(j.botName, j.chatId, j.goal, j.acceptance, j.executorSessionKey, j.executorSessionId, j.checkerSessionKey, j.checkerModel, now, now);
1332
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, 1, ?, ?)`)
1333
+ .run(j.botName, j.chatId, j.goal, j.acceptance, j.state || "WAITING_WORK", j.executorSessionKey, j.executorSessionId, j.checkerSessionKey, j.checkerModel, now, now);
1204
1334
  return Number(r.lastInsertRowid);
1205
1335
  }
1206
1336
  rowToGoJob(row) {
@@ -1278,10 +1408,15 @@ export class MessageStore {
1278
1408
  }
1279
1409
  /** Idempotent action claim: returns true when newly claimed (caller performs the action), false when it already existed. */
1280
1410
  claimGoAction(goId, actionKey, kind, payload) {
1411
+ this.recordGoActionAttempt(goId, actionKey);
1281
1412
  return this.db.prepare(`INSERT OR IGNORE INTO go_actions (go_id, action_key, kind, payload, done, created_at) VALUES (?, ?, ?, ?, 0, ?)`)
1282
1413
  .run(goId, actionKey, kind, payload, Date.now()).changes === 1;
1283
1414
  }
1415
+ hasUnresolvedGoActions(goId) {
1416
+ return !!this.db.prepare(`SELECT 1 FROM go_actions WHERE go_id=? AND done=0 LIMIT 1`).get(goId) || this.listUnresolvedGoSends(goId).length > 0 || this.hasUnknownGoRunResults(goId);
1417
+ }
1284
1418
  completeGoAction(goId, actionKey, receipt) {
1419
+ this.recordGoActionOutcome(goId, actionKey, "accepted", receipt);
1285
1420
  this.db.prepare(`UPDATE go_actions SET done=1, receipt=? WHERE go_id=? AND action_key=?`).run(receipt.slice(0, 500), goId, actionKey);
1286
1421
  }
1287
1422
  setGoModelPref(botName, chatId, model) {
@@ -1293,7 +1428,12 @@ export class MessageStore {
1293
1428
  const r = this.db.prepare(`SELECT model FROM go_model_prefs WHERE bot_name=? AND chat_id=?`).get(botName, chatId);
1294
1429
  return r?.model ?? null;
1295
1430
  }
1431
+ closeObservers = new Set();
1432
+ onClose(callback) { this.closeObservers.add(callback); return () => this.closeObservers.delete(callback); }
1296
1433
  close() {
1434
+ for (const observer of this.closeObservers)
1435
+ observer();
1436
+ this.closeObservers.clear();
1297
1437
  this.db.close();
1298
1438
  }
1299
1439
  }
@@ -1,3 +1,4 @@
1
+ import type { GoExecutorResult } from "./go-execution.js";
1
2
  import { type ErrorProvenance, type ProactiveMessageMeta } from "./terminal-errors.js";
2
3
  import { SessionWaitPaused, type SessionRuntimeStatus } from "./session-status.js";
3
4
  import { OpenClawConfig } from "./config.js";
@@ -33,6 +34,12 @@ export declare const GATEWAY_PROTOCOL_MAX = 4;
33
34
  * Full agent pipeline — tools, memory, skills, context management by OpenClaw.
34
35
  */
35
36
  export declare class OpenClawClient {
37
+ private goEvidenceObservers;
38
+ /** Raw full event observer. Observation is NOT a Feishu delivery receipt. */
39
+ observeGoEvidence(callback: (event: {
40
+ channel: string;
41
+ payload: unknown;
42
+ }) => void): () => void;
36
43
  private config;
37
44
  private ws;
38
45
  private pending;
@@ -212,6 +219,16 @@ export declare class OpenClawClient {
212
219
  ensureModel(sessionKey: string, expectedModel: string): Promise<boolean>;
213
220
  deleteSession(key: string, deleteTranscript?: boolean): Promise<any>;
214
221
  resetSession(key: string): Promise<any>;
222
+ /** One-shot ToolTrim compaction: route the native semantic compaction
223
+ * through the lma-core plugin's lma-tooltrim provider (keep text, keep only
224
+ * the 10 most recent tool calls, drop the rest of the tool payload).
225
+ * Orchestration (validated E2E 2026-10-10): config.set {raw, baseHash} →
226
+ * sessions.compact → restore the original config (always). */
227
+ toolTrimCompact(key: string, keepRecentToolCalls?: number): Promise<any>;
228
+ /** Explicit LLM-summarize compaction (/compact semantic). Since lma-tooltrim
229
+ * is the persistent default provider, temporarily unset it so the built-in
230
+ * summarization pipeline runs, then restore the original config (always). */
231
+ semanticCompact(key: string): Promise<any>;
215
232
  compactSession(key: string, options?: {
216
233
  maxLines?: number;
217
234
  }): Promise<any>;
@@ -236,6 +253,113 @@ export declare class OpenClawClient {
236
253
  private releaseChatSendSlot;
237
254
  private acquireMaintenanceSlot;
238
255
  private releaseMaintenanceSlot;
256
+ /** Public native Goal protocol. Completion deliberately unavailable without host revision CAS. */
257
+ createGoNativeGoal(p: {
258
+ sessionKey: string;
259
+ sessionId: string;
260
+ objective: string;
261
+ operationId: string;
262
+ issuedAtMs: number;
263
+ }): Promise<any>;
264
+ readGoNativeGoal(sessionKey: string, sessionId: string): Promise<{
265
+ session: any;
266
+ goal: any;
267
+ revisionCAS: "unsupported";
268
+ }>;
269
+ updateGoNativeGoal(p: {
270
+ sessionKey: string;
271
+ sessionId: string;
272
+ goalId: string;
273
+ operationId: string;
274
+ issuedAtMs: number;
275
+ action: "edit" | "pause" | "resume" | "block";
276
+ objective?: string;
277
+ note?: string;
278
+ }): Promise<any>;
279
+ /** Admission receipt, not delivery. No restore, random retry key, or generation fallback. */
280
+ sendGoGuarded(p: {
281
+ sessionKey: string;
282
+ sessionId: string;
283
+ expectedLeafEntryId: string | null;
284
+ message: string;
285
+ idempotencyKey: string;
286
+ }): Promise<{
287
+ runId: any;
288
+ sessionId: string;
289
+ idempotencyKey: string;
290
+ raw: any;
291
+ }>;
292
+ /** Checker collection accepts only the admitted run, never a session-key fallback. */
293
+ collectGoRun(p: {
294
+ runId: string;
295
+ sessionKey: string;
296
+ sessionId?: string;
297
+ timeoutMs: number;
298
+ }): Promise<string>;
299
+ /** Public committed terminalReply is the authority, including explicit empty
300
+ * and terminal error. Stream prefaces, lifecycle end alone and timeout are not. */
301
+ readGoExecutorRunResult(p: {
302
+ sessionKey: string;
303
+ sessionId: string;
304
+ runId: string;
305
+ }, waitMs?: number): Promise<GoExecutorResult | null>;
306
+ collectGoExecutorRun(p: {
307
+ sessionKey: string;
308
+ sessionId: string;
309
+ runId: string;
310
+ timeoutMs: number;
311
+ }): Promise<GoExecutorResult>;
312
+ readGoRunResult(p: {
313
+ sessionKey: string;
314
+ sessionId: string;
315
+ runId: string;
316
+ }): Promise<string | null>;
317
+ /** Public generation-pinned original input receipts; absence is unknown, not permission to resend. */
318
+ reconcileGoSend(p: {
319
+ sessionKey: string;
320
+ sessionId: string;
321
+ idempotencyKey: string;
322
+ }): Promise<{
323
+ runId: any;
324
+ sessionId: string;
325
+ raw: any;
326
+ } | null>;
327
+ bindGoPolicy(binding: Record<string, string>): Promise<any>;
328
+ /** History publicly projects active leaf/run/recovery; describe alone does not. */
329
+ getGoSessionInfo(sessionKey: string): Promise<{
330
+ session: any;
331
+ }>;
332
+ verifyGoSafety(_executorKey: string): Promise<{
333
+ checkerToolsIsolated: boolean;
334
+ exactTaskAndDeliveryGate: boolean;
335
+ guardedSend: boolean;
336
+ }>;
337
+ initializeGoRuntime(p: {
338
+ goId: number;
339
+ goal: string;
340
+ executorSessionKey: string;
341
+ executorSessionId: string;
342
+ checkerSessionKey: string;
343
+ checkerSessionId: string;
344
+ }): Promise<{
345
+ executorSessionId: string;
346
+ checkerSessionId: string;
347
+ checkerRunId: string;
348
+ executorRunIds: never[];
349
+ }>;
350
+ readGoRuntimeSnapshot(sessionKey: string, sessionId: string): Promise<{
351
+ sessionKey: string;
352
+ sessionId: string;
353
+ archived: boolean;
354
+ complete: boolean;
355
+ independent: boolean;
356
+ atomicSnapshot: boolean;
357
+ queryAvailable: boolean;
358
+ running: any;
359
+ activeRunIds: any;
360
+ queuedInputs: any;
361
+ tasks: any;
362
+ }>;
239
363
  chatSend(params: {
240
364
  sessionKey: string;
241
365
  message: string;