@beeos-ai/device-agent 0.5.1 → 0.7.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/.pi/extensions/android-tools.ts +24 -3
- package/dist/adapters/agent-gateway-client.d.ts +25 -0
- package/dist/adapters/agent-gateway-client.js +49 -0
- package/dist/adapters/agent-gateway-client.js.map +1 -1
- package/dist/adapters/user-file-uploader.d.ts +74 -0
- package/dist/adapters/user-file-uploader.js +78 -0
- package/dist/adapters/user-file-uploader.js.map +1 -0
- package/dist/app/in-flight-turn.d.ts +120 -0
- package/dist/app/in-flight-turn.js +158 -0
- package/dist/app/in-flight-turn.js.map +1 -0
- package/dist/app/jsonl-store.d.ts +109 -0
- package/dist/app/jsonl-store.js +402 -0
- package/dist/app/jsonl-store.js.map +1 -0
- package/dist/app/message-store.d.ts +82 -31
- package/dist/app/message-store.js +109 -48
- package/dist/app/message-store.js.map +1 -1
- package/dist/app/plugin-commands/registry.d.ts +41 -0
- package/dist/app/plugin-commands/registry.js +62 -0
- package/dist/app/plugin-commands/registry.js.map +1 -0
- package/dist/app/plugin-commands/screenshot-command.d.ts +32 -0
- package/dist/app/plugin-commands/screenshot-command.js +44 -0
- package/dist/app/plugin-commands/screenshot-command.js.map +1 -0
- package/dist/app/plugin-commands/types.d.ts +63 -0
- package/dist/app/plugin-commands/types.js +26 -0
- package/dist/app/plugin-commands/types.js.map +1 -0
- package/dist/app/screenshot-service.d.ts +68 -0
- package/dist/app/screenshot-service.js +64 -0
- package/dist/app/screenshot-service.js.map +1 -0
- package/dist/app/session-manager.d.ts +150 -55
- package/dist/app/session-manager.js +385 -122
- package/dist/app/session-manager.js.map +1 -1
- package/dist/bootstrap.js +5 -1
- package/dist/bootstrap.js.map +1 -1
- package/dist/config/paths.d.ts +48 -0
- package/dist/config/paths.js +59 -0
- package/dist/config/paths.js.map +1 -0
- package/dist/inbound/acp/handlers/device.d.ts +9 -1
- package/dist/inbound/acp/handlers/device.js +9 -1
- package/dist/inbound/acp/handlers/device.js.map +1 -1
- package/dist/inbound/acp/handlers/initialize.d.ts +17 -5
- package/dist/inbound/acp/handlers/initialize.js +19 -7
- package/dist/inbound/acp/handlers/initialize.js.map +1 -1
- package/dist/inbound/acp/handlers/session.d.ts +0 -1
- package/dist/inbound/acp/handlers/skills.d.ts +24 -2
- package/dist/inbound/acp/handlers/skills.js +31 -2
- package/dist/inbound/acp/handlers/skills.js.map +1 -1
- package/dist/orchestrator-system-prompt.js +2 -2
- package/dist/plugins/acp/index.d.ts +26 -1
- package/dist/plugins/acp/index.js +86 -3
- package/dist/plugins/acp/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -6,18 +6,44 @@
|
|
|
6
6
|
* `session/update` envelopes are produced by translating `AgentEvent`s
|
|
7
7
|
* received from the host bus.
|
|
8
8
|
*
|
|
9
|
-
*
|
|
10
|
-
* speaks `AgentHost` only. The translation of host events into ACP
|
|
11
|
-
* envelopes lives here so swapping `IAgentCore` (single-layer / pi
|
|
12
|
-
* orchestrator / mock) doesn't change ACP semantics.
|
|
9
|
+
* Persistence model — turn-grained:
|
|
13
10
|
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
11
|
+
* - User prompts persist immediately on entry to `prompt()` (one
|
|
12
|
+
* `user_message` JSONL row).
|
|
13
|
+
* - Assistant chunks (`task:text`) and tool events (`task:tool`) are
|
|
14
|
+
* accumulated in an in-memory `InFlightTurnAggregator`; nothing is
|
|
15
|
+
* written until `task:end`, at which point a single
|
|
16
|
+
* `assistant_turn` JSONL row captures the entire turn (full text,
|
|
17
|
+
* every tool call in invocation order, stop reason, optional
|
|
18
|
+
* terminal error). This matches OpenClaw's "one line = one
|
|
19
|
+
* complete message" model and avoids the fragmented transcript
|
|
20
|
+
* produced by the legacy "one row per chunk" implementation.
|
|
21
|
+
*
|
|
22
|
+
* Single-session mode (`fixedSessionId`):
|
|
23
|
+
*
|
|
24
|
+
* When a fixedSessionId is supplied, every ACP session-management
|
|
25
|
+
* method (`new`/`load`/`list`/`rename`/`delete`) collapses onto that
|
|
26
|
+
* one sid. The mobile/web client receives `multipleSessions: false`
|
|
27
|
+
* in the initialize handshake so the UI hides session-switching
|
|
28
|
+
* affordances. This is the production configuration for device-agent
|
|
29
|
+
* — a single physical device serialises tasks anyway, and a fixed
|
|
30
|
+
* sid keeps the JSONL transcript stable across reconnects.
|
|
31
|
+
*
|
|
32
|
+
* Replay model — push-style:
|
|
33
|
+
*
|
|
34
|
+
* `session/load` does NOT return history in the RPC `result` (the
|
|
35
|
+
* web/mobile SDKs ignore that field). Instead, it pushes one
|
|
36
|
+
* `history_turn` envelope per persisted turn followed by an
|
|
37
|
+
* in-flight snapshot (streaming-style, WITHOUT `stream_complete`)
|
|
38
|
+
* when a task is mid-flight. This matches beeos-claw's
|
|
39
|
+
* `handleSessionLoad` exactly so the same chat-store reducer paths
|
|
40
|
+
* handle both agents.
|
|
16
41
|
*/
|
|
17
|
-
import { MessageStore
|
|
42
|
+
import { MessageStore } from "./message-store.js";
|
|
18
43
|
import type { AgentHost } from "../ports/agent-host.js";
|
|
44
|
+
import type { PluginCommandRegistry } from "./plugin-commands/registry.js";
|
|
19
45
|
export interface SessionUpdateNotifier {
|
|
20
|
-
/** Called for every step during `session/prompt
|
|
46
|
+
/** Called for every step during `session/prompt` (and during `session/load` replay). */
|
|
21
47
|
send(sessionId: string, update: Record<string, unknown>): void;
|
|
22
48
|
}
|
|
23
49
|
export interface SessionManagerOptions {
|
|
@@ -26,23 +52,42 @@ export interface SessionManagerOptions {
|
|
|
26
52
|
notifier?: SessionUpdateNotifier;
|
|
27
53
|
/**
|
|
28
54
|
* Called when the user asks to switch the underlying agent model.
|
|
29
|
-
* `provider` may be empty when the caller doesn't pin a specific
|
|
30
|
-
* (auto-detect from `model`).
|
|
55
|
+
* `provider` may be empty when the caller doesn't pin a specific
|
|
56
|
+
* adapter (auto-detect from `model`).
|
|
31
57
|
*/
|
|
32
58
|
onSetModel?: (provider: string, model: string) => Promise<void> | void;
|
|
59
|
+
/**
|
|
60
|
+
* If set, single-session mode is active: every session-management
|
|
61
|
+
* method aliases to this sid, `multipleSessions` should be advertised
|
|
62
|
+
* as `false` in `initialize`, and `delete` collapses to `clear`.
|
|
63
|
+
*/
|
|
64
|
+
fixedSessionId?: string;
|
|
33
65
|
maxSessions?: number;
|
|
34
66
|
sessionTtlMs?: number;
|
|
67
|
+
/**
|
|
68
|
+
* Optional plugin command registry. When set, `prompt()` does a
|
|
69
|
+
* prefix match against incoming text BEFORE dispatching to the
|
|
70
|
+
* AgentRunner — `/screenshot` and friends short-circuit straight
|
|
71
|
+
* to their handlers, bypassing the LLM entirely (mirrors OpenClaw
|
|
72
|
+
* `matchPluginCommand` semantics, see
|
|
73
|
+
* `openclaw/src/plugins/commands.ts`).
|
|
74
|
+
*/
|
|
75
|
+
pluginCommands?: PluginCommandRegistry;
|
|
35
76
|
}
|
|
36
77
|
export declare class SessionManager {
|
|
37
78
|
private readonly host;
|
|
38
79
|
private readonly store;
|
|
39
80
|
private readonly notifier;
|
|
40
81
|
private readonly onSetModel;
|
|
82
|
+
private readonly fixedSessionId;
|
|
41
83
|
private readonly maxSessions;
|
|
42
84
|
private readonly sessionTtlMs;
|
|
85
|
+
private readonly pluginCommands;
|
|
43
86
|
private readonly sessions;
|
|
44
87
|
/** taskId → sessionId for routing host events to the right ACP session. */
|
|
45
88
|
private readonly taskToSession;
|
|
89
|
+
/** Per-task in-flight aggregators. Keyed by taskId. */
|
|
90
|
+
private readonly inFlightByTask;
|
|
46
91
|
private activeSessionId;
|
|
47
92
|
private currentTask;
|
|
48
93
|
private unsubscribe;
|
|
@@ -52,9 +97,22 @@ export declare class SessionManager {
|
|
|
52
97
|
newSession(): {
|
|
53
98
|
sessionId: string;
|
|
54
99
|
};
|
|
100
|
+
/**
|
|
101
|
+
* Load a session.
|
|
102
|
+
*
|
|
103
|
+
* Push-replay model: emit one `history_turn` envelope per persisted
|
|
104
|
+
* turn so the chat-store sidecar resolver can reconstruct the bubble
|
|
105
|
+
* graph identically to a fresh streaming run. If a task is currently
|
|
106
|
+
* in-flight on this sid, additionally emit a streaming-style
|
|
107
|
+
* snapshot (`agent_message_chunk` + `tool_call` + `tool_call_update`)
|
|
108
|
+
* WITHOUT the closing `stream_complete` so the client knows the turn
|
|
109
|
+
* is still active.
|
|
110
|
+
*
|
|
111
|
+
* Returns `{ sessionId }` only — the legacy `history` field has been
|
|
112
|
+
* dropped because no client reads it (see explore audit).
|
|
113
|
+
*/
|
|
55
114
|
loadSession(sessionId: string): {
|
|
56
115
|
sessionId: string;
|
|
57
|
-
history: MessageHistoryEntry[];
|
|
58
116
|
};
|
|
59
117
|
listSessions(): {
|
|
60
118
|
sessions: {
|
|
@@ -67,6 +125,14 @@ export declare class SessionManager {
|
|
|
67
125
|
sessionId: string;
|
|
68
126
|
title: string;
|
|
69
127
|
};
|
|
128
|
+
/**
|
|
129
|
+
* Delete a session.
|
|
130
|
+
*
|
|
131
|
+
* In single-session mode, this collapses to `clearSession` because
|
|
132
|
+
* the one-and-only session can't be removed without losing the
|
|
133
|
+
* device's identity. Otherwise drops the in-memory + persisted state
|
|
134
|
+
* for `sessionId`.
|
|
135
|
+
*/
|
|
70
136
|
deleteSession(sessionId: string): {
|
|
71
137
|
deleted: boolean;
|
|
72
138
|
};
|
|
@@ -94,56 +160,85 @@ export declare class SessionManager {
|
|
|
94
160
|
/** Cancel the in-flight task for the active session, if any. */
|
|
95
161
|
cancel(): Promise<boolean>;
|
|
96
162
|
/**
|
|
97
|
-
*
|
|
163
|
+
* Dispatch a `/command` prompt to its registered handler, bypassing
|
|
164
|
+
* the AgentRunner / LLM. The wire shape stays compatible with the
|
|
165
|
+
* regular prompt path:
|
|
166
|
+
*
|
|
167
|
+
* 1. user message persisted (so reload sees the typed `/screenshot`)
|
|
168
|
+
* 2. `agent_status: running`
|
|
169
|
+
* 3. handler runs — typically emits its own `agent_message_chunk`
|
|
170
|
+
* with a `resource_link` (see `ScreenshotCommandHandler`)
|
|
171
|
+
* 4. `stream_complete` + `agent_status: idle`
|
|
98
172
|
*
|
|
99
|
-
*
|
|
100
|
-
*
|
|
101
|
-
* - `task:reasoning` — streaming "thinking" delta (agent_thought_chunk):
|
|
102
|
-
* planner plan/replan descriptions and per-step
|
|
103
|
-
* VLM rationale.
|
|
104
|
-
* - `task:tool` — start / update / end (tool_call / tool_call_update).
|
|
105
|
-
* `update` carries partial progress for long-running
|
|
106
|
-
* tools (large APK install, long shell streams,
|
|
107
|
-
* large screenshots) so the chat-store tool card
|
|
108
|
-
* can refresh in-place without waiting for `end`.
|
|
109
|
-
* Mirrors beeos-claw's tool_call_update in_progress
|
|
110
|
-
* semantics (see acp-gateway/tool-call-payload-builder.ts).
|
|
111
|
-
* - `task:notice` — out-of-band protocol notice. level=warn
|
|
112
|
-
* (transient retry hints) is dropped — noise
|
|
113
|
-
* the user can't act on. level=error (terminal
|
|
114
|
-
* failure) becomes a `system_message_chunk`
|
|
115
|
-
* with `metadata.kind = "agent_notice"`; the
|
|
116
|
-
* web client merges it into the matching
|
|
117
|
-
* assistant bubble's footer. NOT persisted.
|
|
118
|
-
* - `task:step` — structural step record (no ACP emission, kept
|
|
119
|
-
* for HTTP debug / future plugins).
|
|
120
|
-
* - `task:end` — terminal lifecycle event. We emit the canonical
|
|
121
|
-
* ACP `stream_complete` envelope here (BEFORE the
|
|
122
|
-
* `prompt()` finally block fires `agent_status:
|
|
123
|
-
* "idle"`). chat-store's `applyIncrementalUpdate`
|
|
124
|
-
* relies on `stream_complete` to (a) collapse
|
|
125
|
-
* streaming text part `state` from "streaming"
|
|
126
|
-
* back to "done" so the cursor caret stops
|
|
127
|
-
* rendering, and (b) trim `pendingMap` /
|
|
128
|
-
* `currentAsstId` so history-replay paths don't
|
|
129
|
-
* re-flag the just-finished turn as processing.
|
|
130
|
-
* Without it the bubble caret never collapses
|
|
131
|
-
* and reload paths see a stale `processing`
|
|
132
|
-
* pending — see plan
|
|
133
|
-
* `device-agent_stream_complete_对齐`.
|
|
173
|
+
* Errors from the handler are converted into a `system_message_chunk`
|
|
174
|
+
* notice (level=error) instead of crashing the whole session.
|
|
134
175
|
*
|
|
135
|
-
*
|
|
136
|
-
*
|
|
137
|
-
*
|
|
138
|
-
*
|
|
139
|
-
*
|
|
176
|
+
* NOTE: assistant turns produced by plugin commands are intentionally
|
|
177
|
+
* NOT persisted — slash command output is time-sensitive (a stale
|
|
178
|
+
* screenshot helps no one) and the user should re-issue the command
|
|
179
|
+
* on reconnect. The user-side `/screenshot` text IS persisted so the
|
|
180
|
+
* conversation log makes sense.
|
|
181
|
+
*/
|
|
182
|
+
private handlePluginCommand;
|
|
183
|
+
/**
|
|
184
|
+
* Translate host `AgentEvent`s into ACP `session/update` envelopes
|
|
185
|
+
* AND accumulate the assistant turn into the in-memory aggregator
|
|
186
|
+
* for this task. The aggregator is finalised on `task:end` and
|
|
187
|
+
* persisted as a single `assistant_turn` JSONL row — chunk-level
|
|
188
|
+
* persistence is intentionally NOT done (it produces fragmented
|
|
189
|
+
* transcripts that can't be reconstructed cleanly on reload).
|
|
140
190
|
*
|
|
141
|
-
*
|
|
142
|
-
*
|
|
143
|
-
*
|
|
191
|
+
* Source events:
|
|
192
|
+
* - `task:start` — allocate the in-flight aggregator.
|
|
193
|
+
* - `task:text` — append delta to in-flight + emit
|
|
194
|
+
* `agent_message_chunk`.
|
|
195
|
+
* - `task:reasoning` — emit `agent_thought_chunk` only (NOT
|
|
196
|
+
* persisted — bloats LLM context on resume).
|
|
197
|
+
* - `task:tool` — track in in-flight + emit
|
|
198
|
+
* `tool_call` / `tool_call_update`. Mid-flight
|
|
199
|
+
* progress is forwarded as `in_progress`.
|
|
200
|
+
* - `task:notice` — `warn` is dropped entirely; `error` becomes
|
|
201
|
+
* a `system_message_chunk` with
|
|
202
|
+
* `metadata.kind = "agent_notice"` AND is
|
|
203
|
+
* captured as the in-flight `error` field so
|
|
204
|
+
* the persisted turn carries the failure
|
|
205
|
+
* text.
|
|
206
|
+
* - `task:step` — structural; no ACP emission.
|
|
207
|
+
* - `task:end` — finalise the in-flight, persist a single
|
|
208
|
+
* `assistant_turn` row, emit `stream_complete`
|
|
209
|
+
* BEFORE the closing `agent_status: idle`
|
|
210
|
+
* (chat-store relies on this order).
|
|
144
211
|
*/
|
|
145
212
|
private handleHostEvent;
|
|
146
213
|
private resolveSession;
|
|
214
|
+
/** Map any sid the client passes onto the canonical sid in fixed mode. */
|
|
215
|
+
private aliasSessionId;
|
|
216
|
+
/** Materialise the fixed session in-memory + on disk if it isn't yet. */
|
|
217
|
+
private ensureFixedSession;
|
|
218
|
+
/**
|
|
219
|
+
* Lazily create an in-flight aggregator for events that arrive
|
|
220
|
+
* without a preceding `task:start` (defensive — agent-host always
|
|
221
|
+
* fires start, but tests + alternate adapters may not).
|
|
222
|
+
*/
|
|
223
|
+
private ensureInflight;
|
|
224
|
+
private findInflightForSession;
|
|
225
|
+
/**
|
|
226
|
+
* Emit a single persisted record as a `history_turn` envelope.
|
|
227
|
+
*
|
|
228
|
+
* Mirrors beeos-claw `bridge-core.replayAssistantTurnAsStream` —
|
|
229
|
+
* `history_turn` is a stamped-done snapshot of an entire turn that
|
|
230
|
+
* the chat-store reducer renders as a complete bubble (no streaming
|
|
231
|
+
* cursor). For assistant turns, we serialise tool calls into the
|
|
232
|
+
* shape `apply-update.buildToolCalls` accepts.
|
|
233
|
+
*/
|
|
234
|
+
private emitHistoryTurn;
|
|
235
|
+
/**
|
|
236
|
+
* Emit the current state of an in-flight turn as streaming-style
|
|
237
|
+
* envelopes WITHOUT the closing `stream_complete`. The client uses
|
|
238
|
+
* the absence of `stream_complete` to recognise the turn is still
|
|
239
|
+
* generating, matching beeos-claw's `emitCurrentStreamSnapshot`.
|
|
240
|
+
*/
|
|
241
|
+
private emitInflightSnapshot;
|
|
147
242
|
private notify;
|
|
148
243
|
private evictExpired;
|
|
149
244
|
}
|