@prismer/runtime 2.0.3 → 2.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.cjs +2139 -295
- package/dist/cli.js +1978 -134
- package/dist/index.cjs +2107 -261
- package/dist/index.d.cts +533 -181
- package/dist/index.d.ts +533 -181
- package/dist/index.js +1992 -146
- package/package.json +2 -1
package/dist/index.d.cts
CHANGED
|
@@ -1,9 +1,404 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
-
import { EventEmitter } from 'node:events';
|
|
3
2
|
import Database from 'better-sqlite3';
|
|
3
|
+
import { EventEmitter } from 'node:events';
|
|
4
4
|
import { IncomingMessage, ServerResponse } from 'node:http';
|
|
5
5
|
import { Command } from 'commander';
|
|
6
6
|
|
|
7
|
+
type IMAgentStatus = 'online' | 'busy' | 'idle' | 'offline';
|
|
8
|
+
interface HostedAgentDeclaration {
|
|
9
|
+
imUserId: string;
|
|
10
|
+
name: string;
|
|
11
|
+
adapterName: string;
|
|
12
|
+
capabilities: string[];
|
|
13
|
+
profiles: Array<{
|
|
14
|
+
id: string;
|
|
15
|
+
version: number;
|
|
16
|
+
}>;
|
|
17
|
+
}
|
|
18
|
+
interface AgentHostDeclarePayload {
|
|
19
|
+
daemonId: string;
|
|
20
|
+
daemonVersion: string;
|
|
21
|
+
platform: 'darwin' | 'linux' | 'win32';
|
|
22
|
+
agents: HostedAgentDeclaration[];
|
|
23
|
+
}
|
|
24
|
+
interface HostAckedPayload {
|
|
25
|
+
workspaceId: string;
|
|
26
|
+
syncCursor: {
|
|
27
|
+
workspaces: number;
|
|
28
|
+
agent_profiles: number;
|
|
29
|
+
[key: string]: number;
|
|
30
|
+
};
|
|
31
|
+
profilesToSync: string[];
|
|
32
|
+
/** Profile IDs the daemon declared but that no longer exist on the cloud
|
|
33
|
+
* (soft-deleted). The daemon should remove these from its local store. */
|
|
34
|
+
profilesToDelete: string[];
|
|
35
|
+
}
|
|
36
|
+
interface AgentStatusChangedPayload {
|
|
37
|
+
agentImUserId: string;
|
|
38
|
+
status: IMAgentStatus;
|
|
39
|
+
activeProfileId?: string;
|
|
40
|
+
runningTaskIds?: string[];
|
|
41
|
+
}
|
|
42
|
+
interface TaskDispatchContextEntry {
|
|
43
|
+
sender: string;
|
|
44
|
+
senderRole: 'human' | 'agent' | 'admin' | 'system';
|
|
45
|
+
content: string;
|
|
46
|
+
createdAt: string;
|
|
47
|
+
/** Wave-8 W1: assets the human attached to THIS chat message. */
|
|
48
|
+
attachedAssetIds?: string[];
|
|
49
|
+
}
|
|
50
|
+
/** Wave-8 W1: hydrated asset reference attached to a dispatch. */
|
|
51
|
+
interface AssetRef {
|
|
52
|
+
assetId: string;
|
|
53
|
+
contentHash: string;
|
|
54
|
+
mime: string | null;
|
|
55
|
+
sizeBytes: number | null;
|
|
56
|
+
kind: string;
|
|
57
|
+
workspaceId: string;
|
|
58
|
+
role: 'attachment' | 'context';
|
|
59
|
+
/**
|
|
60
|
+
* 14b rev.3 §3.0.4 — cloud-hosted URL for this asset, when present.
|
|
61
|
+
* Adapters prefer this for image/file blocks (cheaper than base64) but
|
|
62
|
+
* fall back to `base64` when the URL is not reachable by the upstream
|
|
63
|
+
* LLM provider (D35 smart probing).
|
|
64
|
+
*/
|
|
65
|
+
cdnUrl?: string;
|
|
66
|
+
/**
|
|
67
|
+
* Optional human-readable filename. Surfaced to adapters that want to
|
|
68
|
+
* label `input_file` blocks (OpenClaw `/v1/responses`).
|
|
69
|
+
*/
|
|
70
|
+
filename?: string;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* 14b rev.3 §3.0.4 / §9 P3 — what `resolveAssetRefs` hands to an adapter for
|
|
74
|
+
* multimodal-aware dispatch. Extends AssetRef with:
|
|
75
|
+
* - `localPath` — daemon's local cache copy (still surfaced so file-based
|
|
76
|
+
* tools in legacy adapters keep working);
|
|
77
|
+
* - `base64` — populated when daemon decided cdnUrl was unreachable and
|
|
78
|
+
* inlined the bytes (D35 fallback);
|
|
79
|
+
* - `reachable` — cdnUrl reachability probe result for adapter introspection.
|
|
80
|
+
*/
|
|
81
|
+
interface ResolvedAssetRef extends AssetRef {
|
|
82
|
+
localPath?: string;
|
|
83
|
+
base64?: string;
|
|
84
|
+
reachable?: 'cdn' | 'base64' | 'unknown';
|
|
85
|
+
}
|
|
86
|
+
interface TaskDispatchRequestPayload {
|
|
87
|
+
taskId: string;
|
|
88
|
+
/** Agent target for runtimeRoute='agent'. Shell dispatches do not use this. */
|
|
89
|
+
agentImUserId?: string;
|
|
90
|
+
/** Runtime/device target for runtimeRoute='shell'. */
|
|
91
|
+
targetDaemonId?: string;
|
|
92
|
+
profileId: string;
|
|
93
|
+
capability: string;
|
|
94
|
+
prompt: string;
|
|
95
|
+
/** Execution surface. `shell` is daemon-local command execution. */
|
|
96
|
+
runtimeRoute?: 'agent' | 'sandbox' | 'shell';
|
|
97
|
+
metadata?: Record<string, unknown>;
|
|
98
|
+
timeoutMs?: number;
|
|
99
|
+
context?: TaskDispatchContextEntry[];
|
|
100
|
+
conversationId?: string;
|
|
101
|
+
/**
|
|
102
|
+
* Channel mode for the originating conversation. Optional and
|
|
103
|
+
* forward-compatible: when missing, daemon renders 'unknown' in the
|
|
104
|
+
* [Channel context] prompt block. See appendChannelContext in
|
|
105
|
+
* daemon/dispatch.ts.
|
|
106
|
+
* - `direct`: 1:1 DM (no @-mention needed in reply).
|
|
107
|
+
* - `group`: multi-party room (end reply with `@<recipient>` to
|
|
108
|
+
* continue the chain).
|
|
109
|
+
*/
|
|
110
|
+
conversationType?: 'direct' | 'group';
|
|
111
|
+
/**
|
|
112
|
+
* Active participants of the dispatch's conversation. Daemon injects this
|
|
113
|
+
* into [Channel context] so the agent knows the authoritative recipient list
|
|
114
|
+
* without hallucinating or having to call `prismer.conversation.listAgents`. Capped at 50
|
|
115
|
+
* entries server-side.
|
|
116
|
+
*/
|
|
117
|
+
participants?: Array<{
|
|
118
|
+
imUserId: string;
|
|
119
|
+
username: string;
|
|
120
|
+
displayName: string;
|
|
121
|
+
role: string;
|
|
122
|
+
agentType?: string | null;
|
|
123
|
+
}>;
|
|
124
|
+
/** Wave-8 W1: assets cloud wants daemon to fold into agent context. */
|
|
125
|
+
assetRefs?: AssetRef[];
|
|
126
|
+
}
|
|
127
|
+
interface TaskDispatchProgressPayload {
|
|
128
|
+
taskId: string;
|
|
129
|
+
progress: number;
|
|
130
|
+
message?: string;
|
|
131
|
+
detail?: Record<string, unknown>;
|
|
132
|
+
}
|
|
133
|
+
/** Wave-8 W1: how the daemon handled a single AssetRef. */
|
|
134
|
+
type AssetDispatchStrategy = 'inline-text' | 'inline-text-truncated' | 'uri-only' | 'fetched-https' | 'error';
|
|
135
|
+
interface AssetDispatchObservation {
|
|
136
|
+
/** AssetRef.assetId for cloud-attached refs; undefined for L5 https fetches. */
|
|
137
|
+
assetId?: string;
|
|
138
|
+
contentHash: string;
|
|
139
|
+
mime: string | null;
|
|
140
|
+
sizeBytes: number | null;
|
|
141
|
+
strategy: AssetDispatchStrategy;
|
|
142
|
+
inlinedBytes?: number;
|
|
143
|
+
error?: string;
|
|
144
|
+
/** L5: original URL the user wrote in the prompt. */
|
|
145
|
+
originalUrl?: string;
|
|
146
|
+
/** L5: post-redirect URL the body was actually downloaded from. */
|
|
147
|
+
finalUrl?: string;
|
|
148
|
+
/** L5: end-to-end fetch duration in ms (DNS + connect + body read). */
|
|
149
|
+
durationMs?: number;
|
|
150
|
+
}
|
|
151
|
+
interface TaskDispatchReplyPayload {
|
|
152
|
+
taskId: string;
|
|
153
|
+
ok: boolean;
|
|
154
|
+
output?: string;
|
|
155
|
+
error?: {
|
|
156
|
+
code: string;
|
|
157
|
+
message: string;
|
|
158
|
+
};
|
|
159
|
+
assetIds?: string[];
|
|
160
|
+
metrics?: {
|
|
161
|
+
tokensUsed?: number;
|
|
162
|
+
durationMs?: number;
|
|
163
|
+
};
|
|
164
|
+
/** Wave-8 W1: per-asset handling report. */
|
|
165
|
+
assetObservability?: AssetDispatchObservation[];
|
|
166
|
+
}
|
|
167
|
+
interface TaskCancelPayload {
|
|
168
|
+
taskId: string;
|
|
169
|
+
reason?: string;
|
|
170
|
+
}
|
|
171
|
+
interface IMWSMessage<T = unknown> {
|
|
172
|
+
type: string;
|
|
173
|
+
payload: T;
|
|
174
|
+
requestId?: string;
|
|
175
|
+
timestamp: number;
|
|
176
|
+
}
|
|
177
|
+
interface WorkspaceChangedPayload {
|
|
178
|
+
workspaceId: string;
|
|
179
|
+
/** ISO-8601 timestamp from im_workspaces.updatedAt. */
|
|
180
|
+
updatedAt: string;
|
|
181
|
+
}
|
|
182
|
+
interface AgentProfileChangedPayload {
|
|
183
|
+
profileId: string;
|
|
184
|
+
version: number;
|
|
185
|
+
}
|
|
186
|
+
interface AgentChangedPayload {
|
|
187
|
+
agentImUserId: string;
|
|
188
|
+
fields: {
|
|
189
|
+
displayName?: string;
|
|
190
|
+
capabilities?: string[];
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
interface WorkspaceFileChangedPayload {
|
|
194
|
+
workspaceId: string;
|
|
195
|
+
path: string;
|
|
196
|
+
operation: 'create' | 'update' | 'delete';
|
|
197
|
+
assetId?: string;
|
|
198
|
+
contentHash?: string;
|
|
199
|
+
version: number;
|
|
200
|
+
}
|
|
201
|
+
interface AssetChangedPayload {
|
|
202
|
+
workspaceId: string;
|
|
203
|
+
assetId: string;
|
|
204
|
+
operation: 'create' | 'update' | 'delete';
|
|
205
|
+
contentHash?: string;
|
|
206
|
+
assetIndexSeq?: number;
|
|
207
|
+
revision?: number;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
type MemoryPageType = 'hub' | 'leaf' | 'decision' | 'glossary' | 'archive';
|
|
211
|
+
type MemoryVisibility = {
|
|
212
|
+
kind: 'workspace';
|
|
213
|
+
} | {
|
|
214
|
+
kind: 'agent';
|
|
215
|
+
imUserId: string;
|
|
216
|
+
} | {
|
|
217
|
+
kind: 'private';
|
|
218
|
+
imUserId: string;
|
|
219
|
+
};
|
|
220
|
+
type ActorKind = 'human' | 'agent';
|
|
221
|
+
type MemorySyncStatus = 'local-only' | 'pending' | 'acked' | 'remote-conflict';
|
|
222
|
+
interface MemoryPage {
|
|
223
|
+
id: string;
|
|
224
|
+
workspaceId: string;
|
|
225
|
+
path: string;
|
|
226
|
+
title: string | null;
|
|
227
|
+
description: string | null;
|
|
228
|
+
contentHash: string;
|
|
229
|
+
version: number;
|
|
230
|
+
pageType: MemoryPageType;
|
|
231
|
+
visibility: MemoryVisibility;
|
|
232
|
+
encrypted: boolean;
|
|
233
|
+
stale: boolean;
|
|
234
|
+
archivedAt: number | null;
|
|
235
|
+
sourceAssetId: string | null;
|
|
236
|
+
sourceRefs: string[];
|
|
237
|
+
syncStatus: MemorySyncStatus;
|
|
238
|
+
createdAt: number;
|
|
239
|
+
updatedAt: number;
|
|
240
|
+
}
|
|
241
|
+
interface MemoryPageContent {
|
|
242
|
+
pageId: string;
|
|
243
|
+
version: number;
|
|
244
|
+
content: string;
|
|
245
|
+
}
|
|
246
|
+
interface MemoryLink {
|
|
247
|
+
sourceUri: string;
|
|
248
|
+
targetUri: string;
|
|
249
|
+
relation: string;
|
|
250
|
+
weight: number;
|
|
251
|
+
extractedFromPageId: string | null;
|
|
252
|
+
}
|
|
253
|
+
interface MemorySearchResult {
|
|
254
|
+
pageId: string;
|
|
255
|
+
path: string;
|
|
256
|
+
title: string | null;
|
|
257
|
+
snippet: string;
|
|
258
|
+
score: number;
|
|
259
|
+
tokenCount: number;
|
|
260
|
+
}
|
|
261
|
+
interface MemorySearchOptions {
|
|
262
|
+
topK?: number;
|
|
263
|
+
relevanceThreshold?: number;
|
|
264
|
+
maxBytes?: number;
|
|
265
|
+
pageType?: MemoryPageType[];
|
|
266
|
+
}
|
|
267
|
+
interface MemoryWriteInput {
|
|
268
|
+
workspaceId: string;
|
|
269
|
+
path: string;
|
|
270
|
+
content: string;
|
|
271
|
+
pageType?: MemoryPageType;
|
|
272
|
+
title?: string;
|
|
273
|
+
description?: string;
|
|
274
|
+
visibility?: MemoryVisibility;
|
|
275
|
+
sourceAssetId?: string;
|
|
276
|
+
sourceRefs?: string[];
|
|
277
|
+
stale?: boolean;
|
|
278
|
+
actorImUserId: string;
|
|
279
|
+
actorKind: ActorKind;
|
|
280
|
+
}
|
|
281
|
+
interface MemoryStats {
|
|
282
|
+
workspaceId: string | null;
|
|
283
|
+
pageCount: number;
|
|
284
|
+
pendingOutbox: number;
|
|
285
|
+
deadLetterCount: number;
|
|
286
|
+
lastSyncAt: number | null;
|
|
287
|
+
dbPath: string;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
interface MemoryStoreOptions {
|
|
291
|
+
/** Absolute path to the SQLite database file. Parent dir created with 0o700 if absent. */
|
|
292
|
+
dbPath: string;
|
|
293
|
+
/** Workspace this store belongs to. Reject ops referencing other workspaces. */
|
|
294
|
+
workspaceId: string;
|
|
295
|
+
/** Device identifier. Stamped onto version + outbox rows at write time. */
|
|
296
|
+
deviceId: string;
|
|
297
|
+
}
|
|
298
|
+
declare class MemoryStore {
|
|
299
|
+
private readonly opts;
|
|
300
|
+
private db;
|
|
301
|
+
constructor(opts: MemoryStoreOptions);
|
|
302
|
+
open(): void;
|
|
303
|
+
close(): void;
|
|
304
|
+
loadByPath(pagePath: string): MemoryPage | null;
|
|
305
|
+
loadById(pageId: string): MemoryPage | null;
|
|
306
|
+
loadContent(pageId: string, version?: number): MemoryPageContent | null;
|
|
307
|
+
list(options?: {
|
|
308
|
+
pageType?: MemoryPageType;
|
|
309
|
+
limit?: number;
|
|
310
|
+
}): MemoryPage[];
|
|
311
|
+
write(input: MemoryWriteInput): MemoryPage;
|
|
312
|
+
invalidate(pageIds: string[], _reason: string): void;
|
|
313
|
+
upsertLink(link: MemoryLink): void;
|
|
314
|
+
stats(): MemoryStats;
|
|
315
|
+
/**
|
|
316
|
+
* Record sync cursor for incremental sync. Used by cloud-sync.ts to
|
|
317
|
+
* persist the high-water mark for future cursor-based catch-up.
|
|
318
|
+
*/
|
|
319
|
+
recordCursor(workspaceId: string, cursor: string): void;
|
|
320
|
+
/**
|
|
321
|
+
* Internal accessor for outbox.ts — outbox writes its own table within the
|
|
322
|
+
* same DB. Returning the live Database handle keeps outbox transactions
|
|
323
|
+
* shareable with store transactions if ever needed.
|
|
324
|
+
*/
|
|
325
|
+
rawDb(): Database.Database;
|
|
326
|
+
/** Workspace this store is bound to (read-only). */
|
|
327
|
+
workspaceId(): string;
|
|
328
|
+
/** Device id stamped onto version + outbox rows. */
|
|
329
|
+
deviceId(): string;
|
|
330
|
+
private requireDb;
|
|
331
|
+
private rowToPage;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
type MemoryScope = 'workspace-shared' | 'agent-private';
|
|
335
|
+
interface ScopedMemoryStoreOptions {
|
|
336
|
+
/** Filesystem root, e.g. `~/.prismer/memory` (will create per-workspace dir under). */
|
|
337
|
+
rootDir: string;
|
|
338
|
+
/** Workspace identifier — used both as the cloud workspaceId and the dir slug. */
|
|
339
|
+
workspaceId: string;
|
|
340
|
+
/** Optional human-friendly slug for the dir; defaults to workspaceId. */
|
|
341
|
+
workspaceSlug?: string;
|
|
342
|
+
/** Device identifier, stamped onto outbox + version rows. */
|
|
343
|
+
deviceId: string;
|
|
344
|
+
}
|
|
345
|
+
interface ScopedWriteInput extends Omit<MemoryWriteInput, 'workspaceId'> {
|
|
346
|
+
scope: MemoryScope;
|
|
347
|
+
/** Required when scope='agent-private'; rejected when scope='workspace-shared'. */
|
|
348
|
+
agentImUserId?: string;
|
|
349
|
+
}
|
|
350
|
+
interface ScopedSearchInput {
|
|
351
|
+
query: string;
|
|
352
|
+
scope: MemoryScope;
|
|
353
|
+
/** Required when scope='agent-private' — search only this agent's bucket. */
|
|
354
|
+
agentImUserId?: string;
|
|
355
|
+
options?: MemorySearchOptions;
|
|
356
|
+
}
|
|
357
|
+
/**
|
|
358
|
+
* Per-workspace, per-bucket SQLite store with the same lifecycle semantics
|
|
359
|
+
* as the existing single-store MemoryStore class.
|
|
360
|
+
*/
|
|
361
|
+
declare class ScopedMemoryStore {
|
|
362
|
+
private readonly opts;
|
|
363
|
+
private sharedStore;
|
|
364
|
+
private agentStores;
|
|
365
|
+
private readonly workspaceDir;
|
|
366
|
+
constructor(opts: ScopedMemoryStoreOptions);
|
|
367
|
+
/** Resolve the shared store (lazy open). */
|
|
368
|
+
shared(): MemoryStore;
|
|
369
|
+
/** Resolve the per-agent store (lazy open). */
|
|
370
|
+
forAgent(agentImUserId: string): MemoryStore;
|
|
371
|
+
/** Resolve the right store for (scope, agentImUserId). */
|
|
372
|
+
resolve(scope: MemoryScope, agentImUserId?: string): MemoryStore;
|
|
373
|
+
/** Write a memory page into the correct bucket. */
|
|
374
|
+
write(input: ScopedWriteInput): {
|
|
375
|
+
pageId: string;
|
|
376
|
+
scope: MemoryScope;
|
|
377
|
+
agentImUserId?: string;
|
|
378
|
+
};
|
|
379
|
+
/**
|
|
380
|
+
* Search only the requested bucket. This is the daemon-first FTS5 path
|
|
381
|
+
* referenced by FF_MEMORY_SEARCH_DAEMON_FIRST.
|
|
382
|
+
*/
|
|
383
|
+
search(input: ScopedSearchInput): MemorySearchResult[];
|
|
384
|
+
/**
|
|
385
|
+
* Search across BOTH the shared bucket and the requesting agent's private
|
|
386
|
+
* bucket, merging results by descending score. Used by the recall-injector
|
|
387
|
+
* so the agent's prompt sees both shared knowledge and its own private notes.
|
|
388
|
+
*/
|
|
389
|
+
searchForAgent(query: string, agentImUserId: string, options?: MemorySearchOptions): MemorySearchResult[];
|
|
390
|
+
/** List which agent ids currently have a private DB on disk (for diagnostics). */
|
|
391
|
+
listAgentBuckets(): string[];
|
|
392
|
+
/** Total disk footprint (best-effort; sums each bucket's main DB file). */
|
|
393
|
+
diskBytes(): {
|
|
394
|
+
shared: number;
|
|
395
|
+
perAgent: Record<string, number>;
|
|
396
|
+
total: number;
|
|
397
|
+
};
|
|
398
|
+
/** Close all underlying stores. */
|
|
399
|
+
close(): void;
|
|
400
|
+
}
|
|
401
|
+
|
|
7
402
|
type AdapterKind = 'long-running' | 'interactive';
|
|
8
403
|
/**
|
|
9
404
|
* Adapter definition: how the daemon hosts one class of agent
|
|
@@ -70,6 +465,17 @@ interface AgentProfile {
|
|
|
70
465
|
*/
|
|
71
466
|
agentUsername?: string;
|
|
72
467
|
}
|
|
468
|
+
interface TaskHeartbeatHandle {
|
|
469
|
+
setPhase(phase: string): void;
|
|
470
|
+
touchStep(): void;
|
|
471
|
+
}
|
|
472
|
+
interface StepRecorderHandle {
|
|
473
|
+
recordPhaseChange(phase: string): void;
|
|
474
|
+
recordToolCall(toolName: string, input: unknown, toolCallId?: string): void;
|
|
475
|
+
recordToolResult(toolCallId: string, output: unknown): void;
|
|
476
|
+
recordReasoningChunk(text: string): void;
|
|
477
|
+
recordError(message: string, payload?: Record<string, unknown>): void;
|
|
478
|
+
}
|
|
73
479
|
interface TaskInput {
|
|
74
480
|
taskId: string;
|
|
75
481
|
prompt: string;
|
|
@@ -81,6 +487,59 @@ interface TaskInput {
|
|
|
81
487
|
detail?: Record<string, unknown>;
|
|
82
488
|
}) => void;
|
|
83
489
|
signal?: AbortSignal;
|
|
490
|
+
/**
|
|
491
|
+
* Wave-3 D2 observability handles. Optional — pre-Wave-3 adapters that
|
|
492
|
+
* don't read these still function (heartbeat keeps ticking with the
|
|
493
|
+
* adapter's last-set phase; no step timeline is emitted).
|
|
494
|
+
*
|
|
495
|
+
* `heartbeat`:
|
|
496
|
+
* - Adapter calls `heartbeat.setPhase('thinking' | 'tool_use' | ...)`
|
|
497
|
+
* when the lifecycle advances. The 15s timer is owned by dispatch.ts;
|
|
498
|
+
* adapters MUST NOT start/stop it themselves.
|
|
499
|
+
* - Adapter may call `heartbeat.touchStep()` around observable boundaries
|
|
500
|
+
* (tool call, token emission) so cloud's 45s "stuck" reaper can
|
|
501
|
+
* distinguish slow-but-alive from truly silent.
|
|
502
|
+
*
|
|
503
|
+
* `recorder`:
|
|
504
|
+
* - Per-task run step uploader. Adapter calls `recordToolCall`,
|
|
505
|
+
* `recordToolResult`, `recordReasoningChunk`, `recordPhaseChange`,
|
|
506
|
+
* `recordError` at the relevant moments. Implementation is throttled
|
|
507
|
+
* for reasoning_chunk (500ms batched).
|
|
508
|
+
* - Per §3.0.2 Gap C-⑤, short skill calls (<10s) may rely solely on
|
|
509
|
+
* the default 'tool_use' phase; long-running ones SHOULD self-report.
|
|
510
|
+
*
|
|
511
|
+
* See sdk/prismer-cloud/runtime/src/daemon/task-heartbeat.ts and
|
|
512
|
+
* sdk/prismer-cloud/runtime/src/daemon/step-recorder.ts.
|
|
513
|
+
*/
|
|
514
|
+
heartbeat?: TaskHeartbeatHandle;
|
|
515
|
+
recorder?: StepRecorderHandle;
|
|
516
|
+
/**
|
|
517
|
+
* 14b rev.3 §3.0.4 / §9 P3 — assets the daemon has resolved (cdnUrl
|
|
518
|
+
* reachability probed, base64 prefetched if necessary). Multimodal-aware
|
|
519
|
+
* adapters (Hermes `/v1/chat/completions`, OpenClaw `/v1/responses`) lift
|
|
520
|
+
* image/file blocks into their wire format; text-like inlining is still
|
|
521
|
+
* handled by `dispatch.ts:composePrompt` (it stays in the `prompt` string).
|
|
522
|
+
* Empty/undefined preserves the legacy text-only contract.
|
|
523
|
+
*/
|
|
524
|
+
assetRefs?: ResolvedAssetRef[];
|
|
525
|
+
/**
|
|
526
|
+
* v2.0 Wave 4-E6 (doc 14 §4.7 Track-F) — scoped daemon memory store.
|
|
527
|
+
*
|
|
528
|
+
* Optional handle the adapter may use to:
|
|
529
|
+
* - Search this agent's memory buckets (workspace-shared + agent-private)
|
|
530
|
+
* for daemon-first FTS5 lookup (0 round-trips to cloud)
|
|
531
|
+
* - Build a `[Relevant memory]` system block via the recall-injector for
|
|
532
|
+
* prompt enrichment before the LLM call
|
|
533
|
+
*
|
|
534
|
+
* When undefined, the adapter MUST NOT attempt local memory recall (legacy
|
|
535
|
+
* behaviour pre-Wave-4 — cloud `/memory/search` is the only path). When
|
|
536
|
+
* defined, FF_MEMORY_SEARCH_DAEMON_FIRST and operatingPrinciples drive
|
|
537
|
+
* whether the adapter actually injects.
|
|
538
|
+
*
|
|
539
|
+
* Wiring is owned by dispatch.ts (resolves per-agent slot → ScopedMemoryStore
|
|
540
|
+
* → passes here). Adapters never instantiate the store themselves.
|
|
541
|
+
*/
|
|
542
|
+
memoryStore?: ScopedMemoryStore;
|
|
84
543
|
}
|
|
85
544
|
interface TaskResult {
|
|
86
545
|
ok: boolean;
|
|
@@ -528,7 +987,7 @@ type LocalDb = Database.Database;
|
|
|
528
987
|
declare function openLocalDb(path: string): LocalDb;
|
|
529
988
|
declare function runMigrations(db: LocalDb): void;
|
|
530
989
|
declare function currentSchemaVersion(db: LocalDb): number;
|
|
531
|
-
declare const TARGET_SCHEMA_VERSION =
|
|
990
|
+
declare const TARGET_SCHEMA_VERSION = 4;
|
|
532
991
|
|
|
533
992
|
type SyncResourceType = 'workspace' | 'agent' | 'agent_profile';
|
|
534
993
|
type SyncOperation = 'create' | 'update' | 'delete';
|
|
@@ -1062,183 +1521,6 @@ declare class ParseClaimController {
|
|
|
1062
1521
|
}): HeartbeatHandle;
|
|
1063
1522
|
}
|
|
1064
1523
|
|
|
1065
|
-
type IMAgentStatus = 'online' | 'busy' | 'idle' | 'offline';
|
|
1066
|
-
interface HostedAgentDeclaration {
|
|
1067
|
-
imUserId: string;
|
|
1068
|
-
name: string;
|
|
1069
|
-
adapterName: string;
|
|
1070
|
-
capabilities: string[];
|
|
1071
|
-
profiles: Array<{
|
|
1072
|
-
id: string;
|
|
1073
|
-
version: number;
|
|
1074
|
-
}>;
|
|
1075
|
-
}
|
|
1076
|
-
interface AgentHostDeclarePayload {
|
|
1077
|
-
daemonId: string;
|
|
1078
|
-
daemonVersion: string;
|
|
1079
|
-
platform: 'darwin' | 'linux' | 'win32';
|
|
1080
|
-
agents: HostedAgentDeclaration[];
|
|
1081
|
-
}
|
|
1082
|
-
interface HostAckedPayload {
|
|
1083
|
-
workspaceId: string;
|
|
1084
|
-
syncCursor: {
|
|
1085
|
-
workspaces: number;
|
|
1086
|
-
agent_profiles: number;
|
|
1087
|
-
[key: string]: number;
|
|
1088
|
-
};
|
|
1089
|
-
profilesToSync: string[];
|
|
1090
|
-
/** Profile IDs the daemon declared but that no longer exist on the cloud
|
|
1091
|
-
* (soft-deleted). The daemon should remove these from its local store. */
|
|
1092
|
-
profilesToDelete: string[];
|
|
1093
|
-
}
|
|
1094
|
-
interface AgentStatusChangedPayload {
|
|
1095
|
-
agentImUserId: string;
|
|
1096
|
-
status: IMAgentStatus;
|
|
1097
|
-
activeProfileId?: string;
|
|
1098
|
-
runningTaskIds?: string[];
|
|
1099
|
-
}
|
|
1100
|
-
interface TaskDispatchContextEntry {
|
|
1101
|
-
sender: string;
|
|
1102
|
-
senderRole: 'human' | 'agent' | 'admin' | 'system';
|
|
1103
|
-
content: string;
|
|
1104
|
-
createdAt: string;
|
|
1105
|
-
/** Wave-8 W1: assets the human attached to THIS chat message. */
|
|
1106
|
-
attachedAssetIds?: string[];
|
|
1107
|
-
}
|
|
1108
|
-
/** Wave-8 W1: hydrated asset reference attached to a dispatch. */
|
|
1109
|
-
interface AssetRef {
|
|
1110
|
-
assetId: string;
|
|
1111
|
-
contentHash: string;
|
|
1112
|
-
mime: string | null;
|
|
1113
|
-
sizeBytes: number | null;
|
|
1114
|
-
kind: string;
|
|
1115
|
-
workspaceId: string;
|
|
1116
|
-
role: 'attachment' | 'context';
|
|
1117
|
-
}
|
|
1118
|
-
interface TaskDispatchRequestPayload {
|
|
1119
|
-
taskId: string;
|
|
1120
|
-
/** Agent target for runtimeRoute='agent'. Shell dispatches do not use this. */
|
|
1121
|
-
agentImUserId?: string;
|
|
1122
|
-
/** Runtime/device target for runtimeRoute='shell'. */
|
|
1123
|
-
targetDaemonId?: string;
|
|
1124
|
-
profileId: string;
|
|
1125
|
-
capability: string;
|
|
1126
|
-
prompt: string;
|
|
1127
|
-
/** Execution surface. `shell` is daemon-local command execution. */
|
|
1128
|
-
runtimeRoute?: 'agent' | 'sandbox' | 'shell';
|
|
1129
|
-
metadata?: Record<string, unknown>;
|
|
1130
|
-
timeoutMs?: number;
|
|
1131
|
-
context?: TaskDispatchContextEntry[];
|
|
1132
|
-
conversationId?: string;
|
|
1133
|
-
/**
|
|
1134
|
-
* Channel mode for the originating conversation. Optional and
|
|
1135
|
-
* forward-compatible: when missing, daemon renders 'unknown' in the
|
|
1136
|
-
* [Channel context] prompt block. See appendChannelContext in
|
|
1137
|
-
* daemon/dispatch.ts.
|
|
1138
|
-
* - `direct`: 1:1 DM (no @-mention needed in reply).
|
|
1139
|
-
* - `group`: multi-party room (end reply with `@<recipient>` to
|
|
1140
|
-
* continue the chain).
|
|
1141
|
-
*/
|
|
1142
|
-
conversationType?: 'direct' | 'group';
|
|
1143
|
-
/**
|
|
1144
|
-
* Active participants of the dispatch's conversation. Daemon injects this
|
|
1145
|
-
* into [Channel context] so the agent knows the authoritative recipient list
|
|
1146
|
-
* without hallucinating or having to call `prismer.conversation.listAgents`. Capped at 50
|
|
1147
|
-
* entries server-side.
|
|
1148
|
-
*/
|
|
1149
|
-
participants?: Array<{
|
|
1150
|
-
imUserId: string;
|
|
1151
|
-
username: string;
|
|
1152
|
-
displayName: string;
|
|
1153
|
-
role: string;
|
|
1154
|
-
agentType?: string | null;
|
|
1155
|
-
}>;
|
|
1156
|
-
/** Wave-8 W1: assets cloud wants daemon to fold into agent context. */
|
|
1157
|
-
assetRefs?: AssetRef[];
|
|
1158
|
-
}
|
|
1159
|
-
interface TaskDispatchProgressPayload {
|
|
1160
|
-
taskId: string;
|
|
1161
|
-
progress: number;
|
|
1162
|
-
message?: string;
|
|
1163
|
-
detail?: Record<string, unknown>;
|
|
1164
|
-
}
|
|
1165
|
-
/** Wave-8 W1: how the daemon handled a single AssetRef. */
|
|
1166
|
-
type AssetDispatchStrategy = 'inline-text' | 'inline-text-truncated' | 'uri-only' | 'fetched-https' | 'error';
|
|
1167
|
-
interface AssetDispatchObservation {
|
|
1168
|
-
/** AssetRef.assetId for cloud-attached refs; undefined for L5 https fetches. */
|
|
1169
|
-
assetId?: string;
|
|
1170
|
-
contentHash: string;
|
|
1171
|
-
mime: string | null;
|
|
1172
|
-
sizeBytes: number | null;
|
|
1173
|
-
strategy: AssetDispatchStrategy;
|
|
1174
|
-
inlinedBytes?: number;
|
|
1175
|
-
error?: string;
|
|
1176
|
-
/** L5: original URL the user wrote in the prompt. */
|
|
1177
|
-
originalUrl?: string;
|
|
1178
|
-
/** L5: post-redirect URL the body was actually downloaded from. */
|
|
1179
|
-
finalUrl?: string;
|
|
1180
|
-
/** L5: end-to-end fetch duration in ms (DNS + connect + body read). */
|
|
1181
|
-
durationMs?: number;
|
|
1182
|
-
}
|
|
1183
|
-
interface TaskDispatchReplyPayload {
|
|
1184
|
-
taskId: string;
|
|
1185
|
-
ok: boolean;
|
|
1186
|
-
output?: string;
|
|
1187
|
-
error?: {
|
|
1188
|
-
code: string;
|
|
1189
|
-
message: string;
|
|
1190
|
-
};
|
|
1191
|
-
assetIds?: string[];
|
|
1192
|
-
metrics?: {
|
|
1193
|
-
tokensUsed?: number;
|
|
1194
|
-
durationMs?: number;
|
|
1195
|
-
};
|
|
1196
|
-
/** Wave-8 W1: per-asset handling report. */
|
|
1197
|
-
assetObservability?: AssetDispatchObservation[];
|
|
1198
|
-
}
|
|
1199
|
-
interface TaskCancelPayload {
|
|
1200
|
-
taskId: string;
|
|
1201
|
-
reason?: string;
|
|
1202
|
-
}
|
|
1203
|
-
interface IMWSMessage<T = unknown> {
|
|
1204
|
-
type: string;
|
|
1205
|
-
payload: T;
|
|
1206
|
-
requestId?: string;
|
|
1207
|
-
timestamp: number;
|
|
1208
|
-
}
|
|
1209
|
-
interface WorkspaceChangedPayload {
|
|
1210
|
-
workspaceId: string;
|
|
1211
|
-
/** ISO-8601 timestamp from im_workspaces.updatedAt. */
|
|
1212
|
-
updatedAt: string;
|
|
1213
|
-
}
|
|
1214
|
-
interface AgentProfileChangedPayload {
|
|
1215
|
-
profileId: string;
|
|
1216
|
-
version: number;
|
|
1217
|
-
}
|
|
1218
|
-
interface AgentChangedPayload {
|
|
1219
|
-
agentImUserId: string;
|
|
1220
|
-
fields: {
|
|
1221
|
-
displayName?: string;
|
|
1222
|
-
capabilities?: string[];
|
|
1223
|
-
};
|
|
1224
|
-
}
|
|
1225
|
-
interface WorkspaceFileChangedPayload {
|
|
1226
|
-
workspaceId: string;
|
|
1227
|
-
path: string;
|
|
1228
|
-
operation: 'create' | 'update' | 'delete';
|
|
1229
|
-
assetId?: string;
|
|
1230
|
-
contentHash?: string;
|
|
1231
|
-
version: number;
|
|
1232
|
-
}
|
|
1233
|
-
interface AssetChangedPayload {
|
|
1234
|
-
workspaceId: string;
|
|
1235
|
-
assetId: string;
|
|
1236
|
-
operation: 'create' | 'update' | 'delete';
|
|
1237
|
-
contentHash?: string;
|
|
1238
|
-
assetIndexSeq?: number;
|
|
1239
|
-
revision?: number;
|
|
1240
|
-
}
|
|
1241
|
-
|
|
1242
1524
|
type PrismerUriType = 'asset' | 'file';
|
|
1243
1525
|
interface ParsedPrismerUri {
|
|
1244
1526
|
/** Original full URI string. */
|
|
@@ -1479,6 +1761,29 @@ declare class OutboxWatcher {
|
|
|
1479
1761
|
private currentScanDirs;
|
|
1480
1762
|
private tick;
|
|
1481
1763
|
private scanDir;
|
|
1764
|
+
/**
|
|
1765
|
+
* F2B — report an OUTBOX_MIME_MISMATCH task event to cloud so the task log
|
|
1766
|
+
* gains an auditable record of the rejection. Without this, the failure is
|
|
1767
|
+
* silent (file quarantined locally, agent unaware) and the next dispatch
|
|
1768
|
+
* loops on the same bad strategy.
|
|
1769
|
+
*
|
|
1770
|
+
* Best-effort: every catch site swallows errors. We never want this
|
|
1771
|
+
* upstream call to block local quarantine or trigger a retry loop, because
|
|
1772
|
+
* the reject decision is already final by the time we get here.
|
|
1773
|
+
*
|
|
1774
|
+
* Endpoint contract: POST /api/im/tasks/:id/event
|
|
1775
|
+
* { code: 'OUTBOX_MIME_MISMATCH', payload: { file, daemonError }, message }
|
|
1776
|
+
* Only callable when `task?.taskId` is known — pre-dispatch outbox files
|
|
1777
|
+
* (no active task) are quarantined silently as before.
|
|
1778
|
+
*/
|
|
1779
|
+
private reportMimeMismatchToCloud;
|
|
1780
|
+
/**
|
|
1781
|
+
* Move a file under `<dir>/_rejected/` so it stops being a scan candidate
|
|
1782
|
+
* (the loop skips the reserved subdir) and operators can find the
|
|
1783
|
+
* offending artifact. Filename collision is rare per task; on collision
|
|
1784
|
+
* we append a millisecond suffix to keep the original observable.
|
|
1785
|
+
*/
|
|
1786
|
+
private quarantine;
|
|
1482
1787
|
private upload;
|
|
1483
1788
|
}
|
|
1484
1789
|
|
|
@@ -1576,6 +1881,15 @@ interface DispatchDeps {
|
|
|
1576
1881
|
* Keyed by workspaceId. If absent, #ref resolution is skipped entirely.
|
|
1577
1882
|
*/
|
|
1578
1883
|
assetMetadataIndexes?: Map<string, AssetMetadataIndex>;
|
|
1884
|
+
/**
|
|
1885
|
+
* 14b D34=C — optional override for image vision-fallback. Enabled by
|
|
1886
|
+
* default when image assetRefs are present.
|
|
1887
|
+
*/
|
|
1888
|
+
visionAux?: {
|
|
1889
|
+
enabled?: boolean;
|
|
1890
|
+
cacheDir?: string;
|
|
1891
|
+
timeoutMs?: number;
|
|
1892
|
+
};
|
|
1579
1893
|
}
|
|
1580
1894
|
declare function handleDispatch(payload: TaskDispatchRequestPayload, requestId: string | undefined, deps: DispatchDeps): Promise<TaskDispatchReplyPayload>;
|
|
1581
1895
|
/**
|
|
@@ -1907,6 +2221,14 @@ declare class LocalServer {
|
|
|
1907
2221
|
* to `/api/sandboxes/:id/snapshot/manifest`.
|
|
1908
2222
|
*/
|
|
1909
2223
|
private handleSnapshot;
|
|
2224
|
+
/**
|
|
2225
|
+
* POST /v1/agents/:agentId/dump-state — agent-scoped daemon manifest.
|
|
2226
|
+
*
|
|
2227
|
+
* This is narrower than `/v1/snapshot`: it walks only the current agent's
|
|
2228
|
+
* profile/work dirs so cloud can attach the result to IMAgentSnapshot without
|
|
2229
|
+
* capturing unrelated agents hosted in the same daemon/container.
|
|
2230
|
+
*/
|
|
2231
|
+
private handleAgentDumpState;
|
|
1910
2232
|
/**
|
|
1911
2233
|
* POST /local/asset/write — agent-gen adapter RPC.
|
|
1912
2234
|
*
|
|
@@ -1991,6 +2313,8 @@ declare class Runner extends EventEmitter {
|
|
|
1991
2313
|
private taskReaperTimer?;
|
|
1992
2314
|
private skillResyncTimer?;
|
|
1993
2315
|
private skillSyncInFlight;
|
|
2316
|
+
private pendingReplyCache;
|
|
2317
|
+
private pendingReplyRecoveryDone;
|
|
1994
2318
|
constructor(opts?: RunnerOptions);
|
|
1995
2319
|
start(): Promise<void>;
|
|
1996
2320
|
/**
|
|
@@ -2076,11 +2400,39 @@ declare class Runner extends EventEmitter {
|
|
|
2076
2400
|
private wireWsHandlers;
|
|
2077
2401
|
private sendDeclare;
|
|
2078
2402
|
private handleIncoming;
|
|
2403
|
+
/**
|
|
2404
|
+
* v2.0 §4.8.1 — webhook dispatch over WS reverse channel.
|
|
2405
|
+
*
|
|
2406
|
+
* Acks via `webhook.dispatch.reply { _rpcId, ok, acceptedAt }` immediately
|
|
2407
|
+
* after `handleAgentMessageDispatch()` returns its synchronous response
|
|
2408
|
+
* — the actual reply (the agent's reply text/attachments) still flows
|
|
2409
|
+
* through `postMessageDispatchReply()` which posts to
|
|
2410
|
+
* `/api/im/dispatch/reply` after the adapter finishes. That mirrors the
|
|
2411
|
+
* HTTP /dispatch contract: ack first, asynchronous final reply via the
|
|
2412
|
+
* dispatch-reply REST endpoint.
|
|
2413
|
+
*
|
|
2414
|
+
* The `_rpcId` field is the only addition versus the HTTP path; we strip
|
|
2415
|
+
* it before passing the payload to the dispatch handler so existing
|
|
2416
|
+
* validation logic doesn't trip on an unknown field.
|
|
2417
|
+
*/
|
|
2418
|
+
private onWebhookDispatch;
|
|
2079
2419
|
private onHostAcked;
|
|
2080
2420
|
private onTaskDispatch;
|
|
2081
2421
|
private onTaskCancel;
|
|
2082
2422
|
private findMessageDispatchAgent;
|
|
2083
2423
|
private postMessageDispatchReply;
|
|
2424
|
+
/**
|
|
2425
|
+
* v2.0 §4.8.1 (Wave 4-E4) — submit the transport-probe report. Called
|
|
2426
|
+
* from `onHostAcked` so the daemon's container row exists in cloud
|
|
2427
|
+
* before we POST to /runtime/transport-report.
|
|
2428
|
+
*
|
|
2429
|
+
* The gatewayUrl reported here is `http://<local-ipv4>:<localPort>`
|
|
2430
|
+
* (typically `http://192.168.x.x:3210`). For a daemon without a local
|
|
2431
|
+
* HTTP server (startLocalServer=false in tests) we still post the
|
|
2432
|
+
* probe with `gatewayUrl=null` so cloud knows transport='ws' is the
|
|
2433
|
+
* only path.
|
|
2434
|
+
*/
|
|
2435
|
+
private reportTransport;
|
|
2084
2436
|
private onAgentChanged;
|
|
2085
2437
|
private onAgentProfileChanged;
|
|
2086
2438
|
private syncProfileFromCloud;
|
|
@@ -2268,17 +2620,17 @@ declare const CodexConfigSchema: z.ZodObject<{
|
|
|
2268
2620
|
*/
|
|
2269
2621
|
apiKeyEnv: z.ZodDefault<z.ZodString>;
|
|
2270
2622
|
}, "strip", z.ZodTypeAny, {
|
|
2623
|
+
sandbox: "read-only" | "workspace-write" | "danger-full-access";
|
|
2271
2624
|
model: string;
|
|
2272
2625
|
cwd: string;
|
|
2273
|
-
sandbox: "read-only" | "workspace-write" | "danger-full-access";
|
|
2274
2626
|
apiKeyEnv: string;
|
|
2275
2627
|
systemPrompt?: string | undefined;
|
|
2276
2628
|
envVars?: Record<string, string> | undefined;
|
|
2277
2629
|
}, {
|
|
2278
2630
|
cwd: string;
|
|
2631
|
+
sandbox?: "read-only" | "workspace-write" | "danger-full-access" | undefined;
|
|
2279
2632
|
model?: string | undefined;
|
|
2280
2633
|
systemPrompt?: string | undefined;
|
|
2281
|
-
sandbox?: "read-only" | "workspace-write" | "danger-full-access" | undefined;
|
|
2282
2634
|
envVars?: Record<string, string> | undefined;
|
|
2283
2635
|
apiKeyEnv?: string | undefined;
|
|
2284
2636
|
}>;
|