chrome-openclaw-sider 1.0.2 → 1.0.26
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 +11 -1
- package/README.zh_CN.md +8 -6
- package/dist/index.d.ts +12 -0
- package/{index.ts → dist/index.js} +24 -17
- package/dist/setup-entry.d.ts +18 -0
- package/dist/setup-entry.js +8 -0
- package/dist/src/account.d.ts +54 -0
- package/{src/account.ts → dist/src/account.js} +70 -160
- package/dist/src/auth.d.ts +30 -0
- package/{src/auth.ts → dist/src/auth.js} +61 -128
- package/dist/src/auto-title.d.ts +20 -0
- package/dist/src/auto-title.js +22 -0
- package/dist/src/channel-auto-title.d.ts +23 -0
- package/dist/src/channel-auto-title.js +77 -0
- package/dist/src/channel-builders.d.ts +105 -0
- package/dist/src/channel-builders.js +238 -0
- package/dist/src/channel-hooks.d.ts +30 -0
- package/dist/src/channel-hooks.js +331 -0
- package/dist/src/channel-monitor.d.ts +34 -0
- package/dist/src/channel-monitor.js +341 -0
- package/dist/src/channel-relay.d.ts +117 -0
- package/dist/src/channel-relay.js +573 -0
- package/dist/src/channel-runtime.d.ts +32 -0
- package/dist/src/channel-runtime.js +85 -0
- package/dist/src/channel-send-result.d.ts +19 -0
- package/dist/src/channel-send-result.js +126 -0
- package/dist/src/channel-session-model.d.ts +19 -0
- package/dist/src/channel-session-model.js +244 -0
- package/dist/src/channel-state.d.ts +92 -0
- package/dist/src/channel-state.js +471 -0
- package/dist/src/channel-streaming.d.ts +117 -0
- package/dist/src/channel-streaming.js +645 -0
- package/dist/src/channel-types.d.ts +207 -0
- package/dist/src/channel-types.js +40 -0
- package/dist/src/channel-typing.d.ts +17 -0
- package/dist/src/channel-typing.js +79 -0
- package/dist/src/channel-util.d.ts +78 -0
- package/dist/src/channel-util.js +524 -0
- package/dist/src/channel.d.ts +14 -0
- package/dist/src/channel.js +1023 -0
- package/dist/src/config.d.ts +18 -0
- package/dist/src/config.js +38 -0
- package/dist/src/inbound-media.d.ts +37 -0
- package/{src/inbound-media.ts → dist/src/inbound-media.js} +33 -81
- package/dist/src/media-upload.d.ts +86 -0
- package/dist/src/media-upload.js +1222 -0
- package/dist/src/setup-core.d.ts +72 -0
- package/{src/setup-core.ts → dist/src/setup-core.js} +106 -194
- package/dist/src/user-agent.d.ts +4 -0
- package/dist/src/user-agent.js +6 -0
- package/openclaw.plugin.json +86 -0
- package/package.json +9 -13
- package/setup-entry.ts +0 -6
- package/src/channel.ts +0 -3862
- package/src/config.ts +0 -29
- package/src/media-upload.ts +0 -983
- package/src/remote-browser-support.ts +0 -64
- package/src/user-agent.ts +0 -17
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
import {
|
|
2
|
+
hasFiniteNumber,
|
|
3
|
+
appendStructuredPayloadField,
|
|
4
|
+
extractToolResultMediaUrls,
|
|
5
|
+
extractToolResultText,
|
|
6
|
+
buildEventMeta,
|
|
7
|
+
toJsonSafeValue
|
|
8
|
+
} from "./channel-util.js";
|
|
9
|
+
const SOURCE_PATH_PREFIX_RE = /^(\/|\.\/|\.\.\/|~\/|[A-Za-z]:[\\/]|\\\\)/;
|
|
10
|
+
const SOURCE_SCHEME_RE = /^[a-zA-Z][a-zA-Z0-9+.-]*:/;
|
|
11
|
+
function isPathLikeSource(value) {
|
|
12
|
+
const trimmed = value.trim();
|
|
13
|
+
if (!trimmed) {
|
|
14
|
+
return false;
|
|
15
|
+
}
|
|
16
|
+
return SOURCE_PATH_PREFIX_RE.test(trimmed) || !SOURCE_SCHEME_RE.test(trimmed);
|
|
17
|
+
}
|
|
18
|
+
function buildSourceFields(source) {
|
|
19
|
+
const trimmed = source?.trim();
|
|
20
|
+
if (!trimmed) {
|
|
21
|
+
return {};
|
|
22
|
+
}
|
|
23
|
+
return {
|
|
24
|
+
media_url: trimmed,
|
|
25
|
+
...isPathLikeSource(trimmed) ? { source_path: trimmed } : { source_url: trimmed }
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
function buildThinkingPart(text) {
|
|
29
|
+
return {
|
|
30
|
+
type: "thinking",
|
|
31
|
+
spec_version: 1,
|
|
32
|
+
payload: { text }
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
function buildTextPart(text) {
|
|
36
|
+
return {
|
|
37
|
+
type: "core.text",
|
|
38
|
+
spec_version: 1,
|
|
39
|
+
payload: { text }
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
function buildToolCallPart(params) {
|
|
43
|
+
const payload = {
|
|
44
|
+
call_id: params.callId,
|
|
45
|
+
...params.toolName ? { tool_name: params.toolName } : {},
|
|
46
|
+
...params.toolCallId ? { tool_call_id: params.toolCallId } : {},
|
|
47
|
+
...params.runId ? { run_id: params.runId } : {}
|
|
48
|
+
};
|
|
49
|
+
appendStructuredPayloadField(payload, "tool_args", params.toolArgs);
|
|
50
|
+
return {
|
|
51
|
+
type: "tool.call",
|
|
52
|
+
spec_version: 1,
|
|
53
|
+
payload
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
function buildToolResultPart(params) {
|
|
57
|
+
const text = extractToolResultText(params.result);
|
|
58
|
+
const safeToolArgs = toJsonSafeValue(params.toolArgs);
|
|
59
|
+
const safeResult = toJsonSafeValue(params.result);
|
|
60
|
+
const payload = {
|
|
61
|
+
call_id: params.callId,
|
|
62
|
+
...params.toolName ? { tool_name: params.toolName } : {},
|
|
63
|
+
...params.toolCallId ? { tool_call_id: params.toolCallId } : {},
|
|
64
|
+
...params.runId ? { run_id: params.runId } : {},
|
|
65
|
+
...params.error ? { error: params.error } : {},
|
|
66
|
+
...hasFiniteNumber(params.durationMs) ? { duration_ms: params.durationMs } : {},
|
|
67
|
+
...text ? { text } : {},
|
|
68
|
+
...safeToolArgs !== void 0 ? { tool_args: safeToolArgs } : {},
|
|
69
|
+
...safeResult !== void 0 ? { result: safeResult } : {},
|
|
70
|
+
has_text: text.length > 0,
|
|
71
|
+
is_error: Boolean(params.error)
|
|
72
|
+
};
|
|
73
|
+
return {
|
|
74
|
+
type: "tool.result",
|
|
75
|
+
spec_version: 1,
|
|
76
|
+
payload
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
function buildTypingEvent(params) {
|
|
80
|
+
return {
|
|
81
|
+
eventType: "typing",
|
|
82
|
+
payload: {
|
|
83
|
+
on: params.state === "typing",
|
|
84
|
+
state: params.state,
|
|
85
|
+
session_id: params.sessionId,
|
|
86
|
+
ts: Date.now()
|
|
87
|
+
},
|
|
88
|
+
meta: buildEventMeta({ accountId: params.accountId })
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
function buildStreamingStartEvent(params) {
|
|
92
|
+
return {
|
|
93
|
+
eventType: "stream.start",
|
|
94
|
+
payload: {
|
|
95
|
+
session_id: params.sessionId,
|
|
96
|
+
stream_id: params.streamId,
|
|
97
|
+
ts: Date.now()
|
|
98
|
+
},
|
|
99
|
+
meta: buildEventMeta({ accountId: params.accountId })
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
function buildStreamingDeltaEvent(params) {
|
|
103
|
+
return {
|
|
104
|
+
eventType: "stream.delta",
|
|
105
|
+
payload: {
|
|
106
|
+
session_id: params.sessionId,
|
|
107
|
+
stream_id: params.streamId,
|
|
108
|
+
seq: params.seq,
|
|
109
|
+
delta: params.delta,
|
|
110
|
+
text: params.text,
|
|
111
|
+
done: false,
|
|
112
|
+
chunk_chars: params.delta.length,
|
|
113
|
+
ts: Date.now()
|
|
114
|
+
},
|
|
115
|
+
meta: buildEventMeta({ accountId: params.accountId })
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
function buildStreamingDoneEvent(params) {
|
|
119
|
+
return {
|
|
120
|
+
eventType: "stream.done",
|
|
121
|
+
payload: {
|
|
122
|
+
session_id: params.sessionId,
|
|
123
|
+
stream_id: params.streamId,
|
|
124
|
+
seq: params.seq,
|
|
125
|
+
done: true,
|
|
126
|
+
reason: params.reason,
|
|
127
|
+
ts: Date.now()
|
|
128
|
+
},
|
|
129
|
+
meta: buildEventMeta({ accountId: params.accountId })
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
function buildReasoningStartEvent(params) {
|
|
133
|
+
return {
|
|
134
|
+
eventType: "reasoning.start",
|
|
135
|
+
payload: {
|
|
136
|
+
session_id: params.sessionId,
|
|
137
|
+
stream_id: params.streamId,
|
|
138
|
+
ts: Date.now()
|
|
139
|
+
},
|
|
140
|
+
meta: buildEventMeta({ accountId: params.accountId })
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
function buildReasoningDeltaEvent(params) {
|
|
144
|
+
return {
|
|
145
|
+
eventType: "reasoning.delta",
|
|
146
|
+
payload: {
|
|
147
|
+
session_id: params.sessionId,
|
|
148
|
+
stream_id: params.streamId,
|
|
149
|
+
seq: params.seq,
|
|
150
|
+
delta: params.delta,
|
|
151
|
+
text: params.text,
|
|
152
|
+
done: false,
|
|
153
|
+
chunk_chars: params.delta.length,
|
|
154
|
+
ts: Date.now()
|
|
155
|
+
},
|
|
156
|
+
meta: buildEventMeta({ accountId: params.accountId })
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
function buildReasoningDoneEvent(params) {
|
|
160
|
+
return {
|
|
161
|
+
eventType: "reasoning.done",
|
|
162
|
+
payload: {
|
|
163
|
+
session_id: params.sessionId,
|
|
164
|
+
stream_id: params.streamId,
|
|
165
|
+
seq: params.seq,
|
|
166
|
+
done: true,
|
|
167
|
+
reason: params.reason,
|
|
168
|
+
ts: Date.now()
|
|
169
|
+
},
|
|
170
|
+
meta: buildEventMeta({ accountId: params.accountId })
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
function buildToolCallEvent(params) {
|
|
174
|
+
return {
|
|
175
|
+
eventType: "tool.call",
|
|
176
|
+
payload: {
|
|
177
|
+
session_id: params.sessionId,
|
|
178
|
+
seq: params.seq,
|
|
179
|
+
call_id: params.callId,
|
|
180
|
+
phase: params.phase,
|
|
181
|
+
tool_name: params.toolName,
|
|
182
|
+
tool_call_id: params.toolCallId,
|
|
183
|
+
run_id: params.runId,
|
|
184
|
+
session_key: params.sessionKey,
|
|
185
|
+
tool_args: params.toolArgs,
|
|
186
|
+
error: params.error,
|
|
187
|
+
duration_ms: params.durationMs,
|
|
188
|
+
ts: Date.now()
|
|
189
|
+
},
|
|
190
|
+
meta: buildEventMeta({ accountId: params.accountId })
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
function buildToolResultEvent(params) {
|
|
194
|
+
const text = extractToolResultText(params.result);
|
|
195
|
+
const mediaUrls = extractToolResultMediaUrls(params.result);
|
|
196
|
+
const safeResult = toJsonSafeValue(params.result);
|
|
197
|
+
const safeToolArgs = toJsonSafeValue(params.toolArgs);
|
|
198
|
+
return {
|
|
199
|
+
eventType: "tool.result",
|
|
200
|
+
payload: {
|
|
201
|
+
session_id: params.sessionId,
|
|
202
|
+
seq: params.seq,
|
|
203
|
+
call_id: params.callId,
|
|
204
|
+
tool_name: params.toolName,
|
|
205
|
+
tool_call_id: params.toolCallId,
|
|
206
|
+
run_id: params.runId,
|
|
207
|
+
session_key: params.sessionKey,
|
|
208
|
+
tool_args: safeToolArgs,
|
|
209
|
+
result: safeResult,
|
|
210
|
+
error: params.error,
|
|
211
|
+
duration_ms: params.durationMs,
|
|
212
|
+
text,
|
|
213
|
+
has_text: text.trim().length > 0,
|
|
214
|
+
media_urls: mediaUrls,
|
|
215
|
+
media_count: mediaUrls.length,
|
|
216
|
+
is_error: Boolean(params.error),
|
|
217
|
+
ts: Date.now()
|
|
218
|
+
},
|
|
219
|
+
meta: buildEventMeta({ accountId: params.accountId })
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
export {
|
|
223
|
+
buildReasoningDeltaEvent,
|
|
224
|
+
buildReasoningDoneEvent,
|
|
225
|
+
buildReasoningStartEvent,
|
|
226
|
+
buildSourceFields,
|
|
227
|
+
buildStreamingDeltaEvent,
|
|
228
|
+
buildStreamingDoneEvent,
|
|
229
|
+
buildStreamingStartEvent,
|
|
230
|
+
buildTextPart,
|
|
231
|
+
buildThinkingPart,
|
|
232
|
+
buildToolCallEvent,
|
|
233
|
+
buildToolCallPart,
|
|
234
|
+
buildToolResultEvent,
|
|
235
|
+
buildToolResultPart,
|
|
236
|
+
buildTypingEvent,
|
|
237
|
+
isPathLikeSource
|
|
238
|
+
};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { SiderToolHookPayload } from './channel-types.js';
|
|
2
|
+
import 'openclaw/plugin-sdk';
|
|
3
|
+
import './account.js';
|
|
4
|
+
import 'openclaw/plugin-sdk/setup';
|
|
5
|
+
import './auth.js';
|
|
6
|
+
import 'openclaw/plugin-sdk/plugin-entry';
|
|
7
|
+
import './auto-title.js';
|
|
8
|
+
import 'ws';
|
|
9
|
+
|
|
10
|
+
declare function recordSiderPersistedAgentMessage(params: {
|
|
11
|
+
sessionKey?: string;
|
|
12
|
+
message: unknown;
|
|
13
|
+
}): void;
|
|
14
|
+
declare function recordSiderAgentEnd(params: {
|
|
15
|
+
messages?: unknown[];
|
|
16
|
+
error?: string;
|
|
17
|
+
runId?: string;
|
|
18
|
+
success: boolean;
|
|
19
|
+
}): void;
|
|
20
|
+
declare function recordSiderLlmOutputUsage(params: {
|
|
21
|
+
sessionKey?: string;
|
|
22
|
+
runId?: string;
|
|
23
|
+
provider?: string;
|
|
24
|
+
model?: string;
|
|
25
|
+
usage?: unknown;
|
|
26
|
+
lastAssistant?: unknown;
|
|
27
|
+
}): void;
|
|
28
|
+
declare function emitSiderToolHookEvent(params: SiderToolHookPayload): Promise<void>;
|
|
29
|
+
|
|
30
|
+
export { emitSiderToolHookEvent, recordSiderAgentEnd, recordSiderLlmOutputUsage, recordSiderPersistedAgentMessage };
|
|
@@ -0,0 +1,331 @@
|
|
|
1
|
+
import { extractAssistantText } from "openclaw/plugin-sdk/agent-runtime";
|
|
2
|
+
import {
|
|
3
|
+
buildTextPart,
|
|
4
|
+
buildThinkingPart,
|
|
5
|
+
buildToolCallEvent,
|
|
6
|
+
buildToolCallPart,
|
|
7
|
+
buildToolResultEvent,
|
|
8
|
+
buildToolResultPart
|
|
9
|
+
} from "./channel-builders.js";
|
|
10
|
+
import { sendSiderEventBestEffort } from "./channel-relay.js";
|
|
11
|
+
import { logDebug, logWarn } from "./channel-runtime.js";
|
|
12
|
+
import {
|
|
13
|
+
clearRelayCallIdForToolEvent,
|
|
14
|
+
enqueueCompletedParts,
|
|
15
|
+
normalizeSessionBindingKey,
|
|
16
|
+
resolveRelayCallIdForToolEvent,
|
|
17
|
+
resolveSiderRunState,
|
|
18
|
+
resolveSiderSessionBinding,
|
|
19
|
+
scheduleQueuedPartFlush,
|
|
20
|
+
updateSiderRunStateContext
|
|
21
|
+
} from "./channel-state.js";
|
|
22
|
+
import {
|
|
23
|
+
addUsageTotals,
|
|
24
|
+
choosePreferredUsageTotals,
|
|
25
|
+
hasUsageTotals,
|
|
26
|
+
parseAssistantOutput,
|
|
27
|
+
parseUsageFromAssistantLike,
|
|
28
|
+
parseUsageTotals,
|
|
29
|
+
toRecord
|
|
30
|
+
} from "./channel-util.js";
|
|
31
|
+
function recordSiderPersistedAgentMessage(params) {
|
|
32
|
+
const binding = resolveSiderSessionBinding(params.sessionKey);
|
|
33
|
+
const runId = binding?.currentRunId;
|
|
34
|
+
if (!runId) {
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
const message = toRecord(params.message);
|
|
38
|
+
if (!message) {
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
const role = typeof message.role === "string" ? message.role.trim() : "";
|
|
42
|
+
if (role !== "assistant") {
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
const runState = updateSiderRunStateContext({
|
|
46
|
+
runId,
|
|
47
|
+
sessionKey: params.sessionKey,
|
|
48
|
+
sessionId: binding?.sessionId,
|
|
49
|
+
accountId: binding?.account.accountId,
|
|
50
|
+
provider: typeof message.provider === "string" ? message.provider : void 0,
|
|
51
|
+
model: typeof message.model === "string" ? message.model : void 0
|
|
52
|
+
});
|
|
53
|
+
const directUsage = parseUsageTotals(message.usage);
|
|
54
|
+
if (directUsage && hasUsageTotals(directUsage)) {
|
|
55
|
+
addUsageTotals(runState.usage, directUsage);
|
|
56
|
+
} else if (!hasUsageTotals(runState.usage)) {
|
|
57
|
+
const fallbackUsage = parseUsageFromAssistantLike(message);
|
|
58
|
+
if (fallbackUsage && hasUsageTotals(fallbackUsage)) {
|
|
59
|
+
runState.usage = fallbackUsage;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
const parsed = parseAssistantOutput(message);
|
|
63
|
+
if (!parsed) {
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
const assistantText = extractAssistantText(message).trim() || void 0;
|
|
67
|
+
const stopReason = parsed.stopReason?.trim();
|
|
68
|
+
const stopReasonLower = stopReason?.toLowerCase();
|
|
69
|
+
const shouldTreatAsToolUseMessage = stopReasonLower === "tooluse" || parsed.toolCalls.length > 0 && stopReasonLower !== "error" && stopReasonLower !== "aborted" && !assistantText;
|
|
70
|
+
if (shouldTreatAsToolUseMessage) {
|
|
71
|
+
const parts = [];
|
|
72
|
+
if (parsed.thinkingText) {
|
|
73
|
+
parts.push(buildThinkingPart(parsed.thinkingText));
|
|
74
|
+
}
|
|
75
|
+
if (assistantText) {
|
|
76
|
+
parts.push(buildTextPart(assistantText));
|
|
77
|
+
}
|
|
78
|
+
if (binding) {
|
|
79
|
+
for (const toolCall of parsed.toolCalls) {
|
|
80
|
+
const callId = resolveRelayCallIdForToolEvent({
|
|
81
|
+
binding,
|
|
82
|
+
phase: "start",
|
|
83
|
+
toolCallId: toolCall.toolCallId
|
|
84
|
+
});
|
|
85
|
+
parts.push(
|
|
86
|
+
buildToolCallPart({
|
|
87
|
+
callId,
|
|
88
|
+
toolName: toolCall.toolName,
|
|
89
|
+
toolCallId: toolCall.toolCallId,
|
|
90
|
+
runId,
|
|
91
|
+
toolArgs: toolCall.toolArgs
|
|
92
|
+
})
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
enqueueCompletedParts({
|
|
97
|
+
runId,
|
|
98
|
+
parts,
|
|
99
|
+
sessionKey: params.sessionKey,
|
|
100
|
+
sessionId: binding?.sessionId,
|
|
101
|
+
accountId: binding?.account.accountId,
|
|
102
|
+
provider: runState.provider,
|
|
103
|
+
model: runState.model
|
|
104
|
+
});
|
|
105
|
+
void scheduleQueuedPartFlush({
|
|
106
|
+
runId,
|
|
107
|
+
context: "before_message_write.tool_use"
|
|
108
|
+
});
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
if (parsed.toolCalls.length > 0) {
|
|
112
|
+
logDebug("treat assistant message with tool calls as final sider message", {
|
|
113
|
+
runId,
|
|
114
|
+
sessionKey: params.sessionKey,
|
|
115
|
+
stopReason: parsed.stopReason,
|
|
116
|
+
textLength: assistantText?.length ?? 0,
|
|
117
|
+
toolCallCount: parsed.toolCalls.length
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
runState.pendingFinalText = assistantText;
|
|
121
|
+
runState.pendingFinalThinking = parsed.thinkingText;
|
|
122
|
+
runState.pendingFinalStopReason = parsed.stopReason;
|
|
123
|
+
}
|
|
124
|
+
function recordSiderAgentEnd(params) {
|
|
125
|
+
if (params.success || !params.runId) {
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
logDebug("observed unsuccessful agent_end; final sider message remains enabled", {
|
|
129
|
+
runId: params.runId,
|
|
130
|
+
error: params.error?.trim() || void 0,
|
|
131
|
+
messageCount: params.messages?.length ?? 0
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
function recordSiderLlmOutputUsage(params) {
|
|
135
|
+
const binding = resolveSiderSessionBinding(params.sessionKey);
|
|
136
|
+
const runId = params.runId || binding?.currentRunId;
|
|
137
|
+
if (!runId) {
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
const existingRunState = resolveSiderRunState(runId);
|
|
141
|
+
if (!existingRunState && binding?.currentRunId !== runId) {
|
|
142
|
+
logDebug("skip llm_output sider usage update: run already cleaned up", {
|
|
143
|
+
runId,
|
|
144
|
+
sessionKey: params.sessionKey,
|
|
145
|
+
provider: params.provider,
|
|
146
|
+
model: params.model
|
|
147
|
+
});
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
const runState = existingRunState ?? updateSiderRunStateContext({
|
|
151
|
+
runId,
|
|
152
|
+
sessionKey: params.sessionKey,
|
|
153
|
+
sessionId: binding?.sessionId,
|
|
154
|
+
accountId: binding?.account.accountId
|
|
155
|
+
});
|
|
156
|
+
updateSiderRunStateContext({
|
|
157
|
+
runId,
|
|
158
|
+
sessionKey: params.sessionKey,
|
|
159
|
+
sessionId: binding?.sessionId,
|
|
160
|
+
accountId: binding?.account.accountId,
|
|
161
|
+
provider: params.provider,
|
|
162
|
+
model: params.model
|
|
163
|
+
});
|
|
164
|
+
const parsed = choosePreferredUsageTotals(
|
|
165
|
+
parseUsageTotals(params.usage),
|
|
166
|
+
parseUsageFromAssistantLike(params.lastAssistant)
|
|
167
|
+
);
|
|
168
|
+
if (parsed && hasUsageTotals(parsed)) {
|
|
169
|
+
runState.usage = parsed;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
async function emitSiderToolHookEvent(params) {
|
|
173
|
+
const binding = resolveSiderSessionBinding(params.sessionKey);
|
|
174
|
+
if (!binding) {
|
|
175
|
+
logDebug("skip sider tool hook event: session binding not found", {
|
|
176
|
+
sessionKey: params.sessionKey,
|
|
177
|
+
toolName: params.toolName,
|
|
178
|
+
toolCallId: params.toolCallId,
|
|
179
|
+
phase: params.phase
|
|
180
|
+
});
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
if (params.runId) {
|
|
184
|
+
binding.currentRunId = params.runId;
|
|
185
|
+
}
|
|
186
|
+
const normalizedToolName = (params.toolName ?? "").trim().toLowerCase();
|
|
187
|
+
const toolArgs = toRecord(params.params);
|
|
188
|
+
const currentSessionKey = normalizeSessionBindingKey(params.sessionKey);
|
|
189
|
+
const targetSessionKeyRaw = typeof toolArgs?.sessionKey === "string" ? toolArgs.sessionKey : void 0;
|
|
190
|
+
const targetSessionKey = normalizeSessionBindingKey(targetSessionKeyRaw);
|
|
191
|
+
const hasAttachmentLikeArgs = Boolean(
|
|
192
|
+
toolArgs && [
|
|
193
|
+
"attachments",
|
|
194
|
+
"attachment",
|
|
195
|
+
"media",
|
|
196
|
+
"mediaUrl",
|
|
197
|
+
"mediaUrls",
|
|
198
|
+
"file",
|
|
199
|
+
"files",
|
|
200
|
+
"buffer",
|
|
201
|
+
"content",
|
|
202
|
+
"contentBase64"
|
|
203
|
+
].some((field) => Object.prototype.hasOwnProperty.call(toolArgs, field))
|
|
204
|
+
);
|
|
205
|
+
if (normalizedToolName === "sessions_send" && params.phase === "start") {
|
|
206
|
+
if (hasAttachmentLikeArgs) {
|
|
207
|
+
logWarn("sider observed sessions_send with attachment-like args; sessions_send only forwards text/message args", {
|
|
208
|
+
accountId: binding.account.accountId,
|
|
209
|
+
sessionId: binding.sessionId,
|
|
210
|
+
runId: params.runId,
|
|
211
|
+
sessionKey: params.sessionKey,
|
|
212
|
+
targetSessionKey: targetSessionKeyRaw,
|
|
213
|
+
toolCallId: params.toolCallId
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
if (currentSessionKey && targetSessionKey && currentSessionKey === targetSessionKey) {
|
|
217
|
+
logWarn("sider observed sessions_send targeting current session; this often times out while current run is still active", {
|
|
218
|
+
accountId: binding.account.accountId,
|
|
219
|
+
sessionId: binding.sessionId,
|
|
220
|
+
runId: params.runId,
|
|
221
|
+
sessionKey: params.sessionKey,
|
|
222
|
+
targetSessionKey: targetSessionKeyRaw,
|
|
223
|
+
toolCallId: params.toolCallId
|
|
224
|
+
});
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
const callId = resolveRelayCallIdForToolEvent({
|
|
228
|
+
binding,
|
|
229
|
+
phase: params.phase,
|
|
230
|
+
toolCallId: params.toolCallId
|
|
231
|
+
});
|
|
232
|
+
if (params.phase === "start") {
|
|
233
|
+
binding.toolSeq += 1;
|
|
234
|
+
const toolCallEvent = buildToolCallEvent({
|
|
235
|
+
sessionId: binding.sessionId,
|
|
236
|
+
accountId: binding.account.accountId,
|
|
237
|
+
seq: binding.toolSeq,
|
|
238
|
+
callId,
|
|
239
|
+
phase: "start",
|
|
240
|
+
toolName: params.toolName,
|
|
241
|
+
toolCallId: params.toolCallId,
|
|
242
|
+
runId: params.runId,
|
|
243
|
+
sessionKey: params.sessionKey,
|
|
244
|
+
toolArgs: params.params,
|
|
245
|
+
error: params.error,
|
|
246
|
+
durationMs: params.durationMs
|
|
247
|
+
});
|
|
248
|
+
await sendSiderEventBestEffort({
|
|
249
|
+
account: binding.account,
|
|
250
|
+
sessionId: binding.sessionId,
|
|
251
|
+
event: toolCallEvent,
|
|
252
|
+
context: "tool.call.hook.start"
|
|
253
|
+
});
|
|
254
|
+
}
|
|
255
|
+
if (params.phase !== "start") {
|
|
256
|
+
if (normalizedToolName === "sessions_send") {
|
|
257
|
+
const resultRecord = toRecord(params.result);
|
|
258
|
+
const status = typeof resultRecord?.status === "string" ? resultRecord.status.trim().toLowerCase() : "";
|
|
259
|
+
if (status === "timeout") {
|
|
260
|
+
logWarn("sider observed sessions_send timeout", {
|
|
261
|
+
accountId: binding.account.accountId,
|
|
262
|
+
sessionId: binding.sessionId,
|
|
263
|
+
runId: params.runId,
|
|
264
|
+
sessionKey: params.sessionKey,
|
|
265
|
+
targetSessionKey: targetSessionKeyRaw,
|
|
266
|
+
toolCallId: params.toolCallId,
|
|
267
|
+
error: params.error,
|
|
268
|
+
durationMs: params.durationMs,
|
|
269
|
+
selfTargeted: Boolean(currentSessionKey && targetSessionKey && currentSessionKey === targetSessionKey),
|
|
270
|
+
hasAttachmentLikeArgs
|
|
271
|
+
});
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
binding.toolSeq += 1;
|
|
275
|
+
const toolResultEvent = buildToolResultEvent({
|
|
276
|
+
sessionId: binding.sessionId,
|
|
277
|
+
accountId: binding.account.accountId,
|
|
278
|
+
seq: binding.toolSeq,
|
|
279
|
+
callId,
|
|
280
|
+
toolName: params.toolName,
|
|
281
|
+
toolCallId: params.toolCallId,
|
|
282
|
+
runId: params.runId,
|
|
283
|
+
sessionKey: params.sessionKey,
|
|
284
|
+
toolArgs: params.params,
|
|
285
|
+
result: params.result,
|
|
286
|
+
error: params.error,
|
|
287
|
+
durationMs: params.durationMs
|
|
288
|
+
});
|
|
289
|
+
await sendSiderEventBestEffort({
|
|
290
|
+
account: binding.account,
|
|
291
|
+
sessionId: binding.sessionId,
|
|
292
|
+
event: toolResultEvent,
|
|
293
|
+
context: `tool.result.hook.${params.phase}`
|
|
294
|
+
});
|
|
295
|
+
if (params.runId) {
|
|
296
|
+
enqueueCompletedParts({
|
|
297
|
+
runId: params.runId,
|
|
298
|
+
parts: [
|
|
299
|
+
buildToolResultPart({
|
|
300
|
+
callId,
|
|
301
|
+
toolName: params.toolName,
|
|
302
|
+
toolCallId: params.toolCallId,
|
|
303
|
+
runId: params.runId,
|
|
304
|
+
toolArgs: params.params,
|
|
305
|
+
result: params.result,
|
|
306
|
+
error: params.error,
|
|
307
|
+
durationMs: params.durationMs
|
|
308
|
+
})
|
|
309
|
+
],
|
|
310
|
+
sessionKey: params.sessionKey,
|
|
311
|
+
sessionId: binding.sessionId,
|
|
312
|
+
accountId: binding.account.accountId
|
|
313
|
+
});
|
|
314
|
+
void scheduleQueuedPartFlush({
|
|
315
|
+
runId: params.runId,
|
|
316
|
+
context: `tool.result.hook.${params.phase}`
|
|
317
|
+
});
|
|
318
|
+
}
|
|
319
|
+
clearRelayCallIdForToolEvent({
|
|
320
|
+
binding,
|
|
321
|
+
callId,
|
|
322
|
+
toolCallId: params.toolCallId
|
|
323
|
+
});
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
export {
|
|
327
|
+
emitSiderToolHookEvent,
|
|
328
|
+
recordSiderAgentEnd,
|
|
329
|
+
recordSiderLlmOutputUsage,
|
|
330
|
+
recordSiderPersistedAgentMessage
|
|
331
|
+
};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { OpenClawConfig } from 'openclaw/plugin-sdk';
|
|
2
|
+
import { ResolvedSiderAccount } from './account.js';
|
|
3
|
+
import { SiderRelayMonitorRegistration, SiderMonitorLogger, SiderInboundRealtimeMessage } from './channel-types.js';
|
|
4
|
+
import 'openclaw/plugin-sdk/setup';
|
|
5
|
+
import './auth.js';
|
|
6
|
+
import 'openclaw/plugin-sdk/plugin-entry';
|
|
7
|
+
import './auto-title.js';
|
|
8
|
+
import 'ws';
|
|
9
|
+
|
|
10
|
+
declare function monitorSiderSession(params: {
|
|
11
|
+
cfg: OpenClawConfig;
|
|
12
|
+
account: ResolvedSiderAccount;
|
|
13
|
+
abortSignal: AbortSignal;
|
|
14
|
+
log?: SiderMonitorLogger;
|
|
15
|
+
onInboundMessage: (params: {
|
|
16
|
+
cfg: OpenClawConfig;
|
|
17
|
+
account: ResolvedSiderAccount;
|
|
18
|
+
event: SiderInboundRealtimeMessage;
|
|
19
|
+
}) => Promise<void>;
|
|
20
|
+
}): Promise<void>;
|
|
21
|
+
declare function launchManagedRelayMonitor(registration: SiderRelayMonitorRegistration): void;
|
|
22
|
+
declare function runManagedSiderRelayMonitor(params: {
|
|
23
|
+
cfg: OpenClawConfig;
|
|
24
|
+
account: ResolvedSiderAccount;
|
|
25
|
+
abortSignal: AbortSignal;
|
|
26
|
+
log?: SiderMonitorLogger;
|
|
27
|
+
onInboundMessage: (params: {
|
|
28
|
+
cfg: OpenClawConfig;
|
|
29
|
+
account: ResolvedSiderAccount;
|
|
30
|
+
event: SiderInboundRealtimeMessage;
|
|
31
|
+
}) => Promise<void>;
|
|
32
|
+
}): Promise<void>;
|
|
33
|
+
|
|
34
|
+
export { launchManagedRelayMonitor, monitorSiderSession, runManagedSiderRelayMonitor };
|