openclaw-openagent 1.0.13 → 1.0.14
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/src/messaging/executor.d.ts +2 -3
- package/dist/src/messaging/executor.js +4 -31
- package/dist/src/plugin-ui/assets/openagent-override.js +4 -5
- package/dist/src/runtime/update-checker.d.ts +1 -1
- package/dist/src/runtime/update-checker.js +9 -46
- package/package.json +1 -3
- package/src/app/channel-tools.ts +0 -249
- package/src/app/discovery-tools.ts +0 -273
- package/src/app/download-file-tool.ts +0 -133
- package/src/app/hooks.ts +0 -144
- package/src/app/index.ts +0 -84
- package/src/app/messaging-tools.ts +0 -79
- package/src/app/ops-tools.ts +0 -155
- package/src/app/remote-agent-tool.ts +0 -762
- package/src/app/types.ts +0 -68
- package/src/app/upload-file-tool.ts +0 -411
- package/src/app/verbose-preflight.ts +0 -190
- package/src/auth/config.ts +0 -266
- package/src/auth/credential-manager.ts +0 -146
- package/src/auth/index.ts +0 -24
- package/src/auth/verify.ts +0 -99
- package/src/channel.ts +0 -566
- package/src/compat.ts +0 -94
- package/src/config/config-schema.ts +0 -45
- package/src/messaging/aggregator.ts +0 -120
- package/src/messaging/collector.ts +0 -89
- package/src/messaging/executor.ts +0 -72
- package/src/messaging/inbound.ts +0 -150
- package/src/messaging/index.ts +0 -11
- package/src/messaging/mention-protocol.ts +0 -94
- package/src/messaging/process-c2c-request.ts +0 -564
- package/src/messaging/process-message.ts +0 -373
- package/src/messaging/scheduler.ts +0 -55
- package/src/messaging/types.ts +0 -38
- package/src/plugin-ui/adapters/oc-2026-04.js +0 -103
- package/src/plugin-ui/adapters/oc-2026-05.js +0 -125
- package/src/plugin-ui/adapters/oc-2026-06.js +0 -125
- package/src/plugin-ui/adapters/oc-unknown.js +0 -48
- package/src/plugin-ui/assets/agentbook-icon.svg +0 -5
- package/src/plugin-ui/assets/bg.png +0 -0
- package/src/plugin-ui/assets/icon.png +0 -0
- package/src/plugin-ui/assets/magic.svg +0 -5
- package/src/plugin-ui/assets/openagent-override.js +0 -11263
- package/src/plugin-ui/build.cjs +0 -463
- package/src/plugin-ui/index.ts +0 -18
- package/src/plugin-ui/modules/agent-book/panel/agent-book.js +0 -570
- package/src/plugin-ui/modules/agent-book/panel/agent-card.js +0 -170
- package/src/plugin-ui/modules/agent-book/panel/agent-data.js +0 -643
- package/src/plugin-ui/modules/agent-book/panel/inject-ui.js +0 -665
- package/src/plugin-ui/modules/agent-book/panel/mention-state.js +0 -206
- package/src/plugin-ui/modules/agent-book/panel/styles.js +0 -832
- package/src/plugin-ui/modules/agent-book/panel/theme-adapter.js +0 -86
- package/src/plugin-ui/modules/agent-book/remote-agent-tool/components-core.js +0 -295
- package/src/plugin-ui/modules/agent-book/remote-agent-tool/thought-chain-card.js +0 -211
- package/src/plugin-ui/modules/agent-book/scanner.js +0 -131
- package/src/plugin-ui/modules/agent-book/travelcard/travel-cards.js +0 -500
- package/src/plugin-ui/modules/agent-book/travelcard/travel-engine.js +0 -652
- package/src/plugin-ui/modules/agent-book/travelcard/travel-styles.js +0 -262
- package/src/plugin-ui/modules/loader/bootstrap.js +0 -133
- package/src/plugin-ui/modules/loader/shared-state.js +0 -838
- package/src/plugin-ui/modules/loader/ws-intercept.js +0 -199
- package/src/plugin-ui/modules/remote-agent/chunk-parser.js +0 -161
- package/src/plugin-ui/modules/remote-agent/execution-card.js +0 -530
- package/src/plugin-ui/modules/remote-agent/markdown-renderer.js +0 -256
- package/src/plugin-ui/modules/remote-agent/media-links.js +0 -151
- package/src/plugin-ui/modules/remote-agent/native-style-adapter.js +0 -134
- package/src/plugin-ui/modules/remote-agent/output-card.js +0 -342
- package/src/plugin-ui/modules/remote-agent/progress-store.js +0 -363
- package/src/plugin-ui/modules/remote-agent/render-hooks.js +0 -1700
- package/src/plugin-ui/modules/remote-agent/styles.js +0 -903
- package/src/plugin-ui/modules/remote-agent/tool-card-model.js +0 -130
- package/src/plugin-ui/postinstall-deploy.cjs +0 -52
- package/src/plugin-ui/ui-extension-loader/backup.ts +0 -92
- package/src/plugin-ui/ui-extension-loader/index.ts +0 -276
- package/src/plugin-ui/ui-extension-loader/locator.ts +0 -152
- package/src/plugin-ui/ui-extension-loader/manifest.ts +0 -57
- package/src/plugin-ui/ui-extension-loader/registry-regex.ts +0 -944
- package/src/plugin-ui/ui-extension-loader/removed-extensions.ts +0 -70
- package/src/plugin-ui/ui-extension-loader/types.ts +0 -72
- package/src/proxy/auth-proxy.ts +0 -414
- package/src/runtime/account.ts +0 -549
- package/src/runtime/index.ts +0 -7
- package/src/runtime/plugin-runtime.ts +0 -94
- package/src/runtime/registry.ts +0 -71
- package/src/runtime/update-checker.ts +0 -286
- package/src/sdk/CLASS_MAP.md +0 -143
- package/src/sdk/index.d.ts +0 -126
- package/src/sdk/index.js +0 -23990
- package/src/sdk/modules/cloud-search-module.js +0 -1117
- package/src/sdk/modules/follow-module.js +0 -1069
- package/src/sdk/modules/group-module.js +0 -7397
- package/src/sdk/modules/relationship-module.js +0 -2269
- package/src/sdk/modules/signaling-module.js +0 -1468
- package/src/sdk/modules/tim-upload-plugin.js +0 -730
- package/src/sdk/node-env/http-request.js +0 -90
- package/src/sdk/node-env/index.js +0 -57
- package/src/sdk/node-env/storage.js +0 -114
- package/src/sdk/package.json +0 -10
- package/src/sdk/tsconfig.json +0 -16
- package/src/state/pending-invocation-store.ts +0 -43
- package/src/state/store.ts +0 -756
- package/src/tim/c2c.ts +0 -451
- package/src/tim/channels.ts +0 -364
- package/src/tim/client.ts +0 -330
- package/src/tim/index.ts +0 -18
- package/src/tim/messages.ts +0 -166
- package/src/tim/sdk-logger-init.ts +0 -50
- package/src/tools.ts +0 -10
- package/src/transport/factory.ts +0 -95
- package/src/transport/oasn/index.ts +0 -17
- package/src/transport/oasn/oasn-agent-card.ts +0 -111
- package/src/transport/oasn/oasn-discovery.ts +0 -108
- package/src/transport/oasn/oasn-files.ts +0 -210
- package/src/transport/oasn/oasn-http.ts +0 -529
- package/src/transport/oasn/oasn-invocation.ts +0 -604
- package/src/transport/oasn/oasn-normalize.ts +0 -133
- package/src/transport/oasn/oasn-register.ts +0 -33
- package/src/transport/oasn/oasn-transport.ts +0 -318
- package/src/transport/oasn/oasn-types.ts +0 -404
- package/src/transport/tim/index.ts +0 -8
- package/src/transport/tim/tim-transport.ts +0 -515
- package/src/transport/types.ts +0 -538
- package/src/types/openclaw-plugin-sdk-media-store.d.ts +0 -9
- package/src/types/openclaw.d.ts +0 -97
- package/src/types/tencentcloud-chat.d.ts +0 -15
- package/src/util/http.ts +0 -113
- package/src/util/logger.ts +0 -131
- package/src/util/url-resolver.ts +0 -77
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* OpenAgent config schema — Zod-based runtime validation.
|
|
3
|
-
*
|
|
4
|
-
* This mirrors the JSON schema in openclaw.plugin.json but provides
|
|
5
|
-
* type-safe runtime parsing via Zod.
|
|
6
|
-
*
|
|
7
|
-
* Uses direct zod dependency (same pattern as openclaw-weixin v2.1.1)
|
|
8
|
-
* rather than openclaw/plugin-sdk/zod, which is only available in
|
|
9
|
-
* OpenClaw >= ~2026.3.28 and would break on earlier supported hosts.
|
|
10
|
-
*/
|
|
11
|
-
|
|
12
|
-
import { z } from 'zod';
|
|
13
|
-
|
|
14
|
-
// ---------------------------------------------------------------------------
|
|
15
|
-
// Zod config schema
|
|
16
|
-
// ---------------------------------------------------------------------------
|
|
17
|
-
|
|
18
|
-
const transportSchema = z.enum(['oasn', 'tim']).default('oasn');
|
|
19
|
-
const updatePolicySchema = z.enum(['notify', 'auto', 'off']).optional();
|
|
20
|
-
|
|
21
|
-
const openagentAccountSchema = z.object({
|
|
22
|
-
name: z.string().optional(),
|
|
23
|
-
enabled: z.boolean().optional(),
|
|
24
|
-
transport: transportSchema.optional(),
|
|
25
|
-
agent_id: z.string().optional(),
|
|
26
|
-
api_key: z.string().optional(),
|
|
27
|
-
api_base: z.string().optional(),
|
|
28
|
-
access_api_base: z.string().optional(),
|
|
29
|
-
claim_url: z.string().optional(),
|
|
30
|
-
status: z.enum(['unregistered', 'unclaimed', 'claim_pending', 'claimed', 'credential_expired', 'unknown']).optional(),
|
|
31
|
-
registered_at: z.string().optional(),
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
/** Top-level openagent config schema. */
|
|
35
|
-
export const OpenagentConfigSchema = openagentAccountSchema.extend({
|
|
36
|
-
transport: transportSchema.optional(),
|
|
37
|
-
api_base: z.string().optional(),
|
|
38
|
-
access_api_base: z.string().optional(),
|
|
39
|
-
update_policy: updatePolicySchema,
|
|
40
|
-
update_check: z.boolean().optional(),
|
|
41
|
-
auto_update: z.boolean().optional(),
|
|
42
|
-
update_channel: z.string().optional(),
|
|
43
|
-
update_dist_tag: z.string().optional(),
|
|
44
|
-
accounts: z.record(z.string(), openagentAccountSchema).optional(),
|
|
45
|
-
});
|
|
@@ -1,120 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* WindowAggregator — Message batching and ChannelDelta builder
|
|
3
|
-
*
|
|
4
|
-
* Buffers messages per channel with three flush triggers:
|
|
5
|
-
* 1. @mention → immediate flush
|
|
6
|
-
* 2. Buffer full → flush at maxBatchSize
|
|
7
|
-
* 3. Timer → flush after batchWindowMs
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
import { logger } from '../util/logger.js';
|
|
11
|
-
import type { RawMessage, ChannelDelta } from './types.js';
|
|
12
|
-
|
|
13
|
-
export interface AggregatorConfig {
|
|
14
|
-
batchWindowMs: number;
|
|
15
|
-
maxBatchSize: number;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
interface ChannelWindow {
|
|
19
|
-
channelId: string;
|
|
20
|
-
messages: RawMessage[];
|
|
21
|
-
timer: ReturnType<typeof setTimeout> | null;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export class WindowAggregator {
|
|
25
|
-
private windows = new Map<string, ChannelWindow>();
|
|
26
|
-
private config: AggregatorConfig;
|
|
27
|
-
public onDelta: ((delta: ChannelDelta) => void) | null = null;
|
|
28
|
-
|
|
29
|
-
constructor(config: Partial<AggregatorConfig> = {}) {
|
|
30
|
-
this.config = {
|
|
31
|
-
batchWindowMs: config.batchWindowMs || 60_000,
|
|
32
|
-
maxBatchSize: config.maxBatchSize || 20,
|
|
33
|
-
};
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
updateConfig(newConfig: Partial<AggregatorConfig>): void {
|
|
37
|
-
Object.assign(this.config, newConfig);
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
append(rawMessage: RawMessage): void {
|
|
41
|
-
const channelId = rawMessage.channelId;
|
|
42
|
-
const win = this._getOrCreate(channelId);
|
|
43
|
-
win.messages.push(rawMessage);
|
|
44
|
-
|
|
45
|
-
// Immediate flush on @mention
|
|
46
|
-
if (rawMessage.mentionsMe) {
|
|
47
|
-
this.flush(channelId, 'mention');
|
|
48
|
-
return;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
// Buffer full
|
|
52
|
-
if (win.messages.length >= this.config.maxBatchSize) {
|
|
53
|
-
this.flush(channelId, 'buffer_full');
|
|
54
|
-
return;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
// Start timer if not running
|
|
58
|
-
if (!win.timer) {
|
|
59
|
-
win.timer = setTimeout(
|
|
60
|
-
() => this.flush(channelId, 'timeout'),
|
|
61
|
-
this.config.batchWindowMs,
|
|
62
|
-
);
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
flush(channelId: string, reason: string): void {
|
|
67
|
-
const win = this.windows.get(channelId);
|
|
68
|
-
if (!win || win.messages.length === 0) return;
|
|
69
|
-
|
|
70
|
-
const messages = win.messages.splice(0);
|
|
71
|
-
if (win.timer) {
|
|
72
|
-
clearTimeout(win.timer);
|
|
73
|
-
win.timer = null;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
const hasMention = messages.some(m => m.mentionsMe);
|
|
77
|
-
const participants = [...new Set(messages.map(m => m.nick || m.from))];
|
|
78
|
-
const source = messages[0]?.source || 'push';
|
|
79
|
-
|
|
80
|
-
const delta: ChannelDelta = {
|
|
81
|
-
channelId,
|
|
82
|
-
channelName: channelId,
|
|
83
|
-
messageCount: messages.length,
|
|
84
|
-
participants,
|
|
85
|
-
hasMention,
|
|
86
|
-
urgency: hasMention ? 1.0 : Math.min(0.1 * messages.length, 0.9),
|
|
87
|
-
messages,
|
|
88
|
-
source,
|
|
89
|
-
flushReason: reason,
|
|
90
|
-
};
|
|
91
|
-
|
|
92
|
-
logger.debug(`[aggregator] FLUSH ch=${channelId} reason=${reason} msgs=${messages.length} mention=${hasMention}`);
|
|
93
|
-
|
|
94
|
-
if (this.onDelta) {
|
|
95
|
-
this.onDelta(delta);
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
flushAll(): void {
|
|
100
|
-
for (const channelId of this.windows.keys()) {
|
|
101
|
-
this.flush(channelId, 'shutdown');
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
stop(): void {
|
|
106
|
-
for (const win of this.windows.values()) {
|
|
107
|
-
if (win.timer) clearTimeout(win.timer);
|
|
108
|
-
}
|
|
109
|
-
this.windows.clear();
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
private _getOrCreate(channelId: string): ChannelWindow {
|
|
113
|
-
let win = this.windows.get(channelId);
|
|
114
|
-
if (!win) {
|
|
115
|
-
win = { channelId, messages: [], timer: null };
|
|
116
|
-
this.windows.set(channelId, win);
|
|
117
|
-
}
|
|
118
|
-
return win;
|
|
119
|
-
}
|
|
120
|
-
}
|
|
@@ -1,89 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Collector — Message deduplication and distribution
|
|
3
|
-
*
|
|
4
|
-
* Deduplicates incoming messages using StateStore (or in-memory fallback).
|
|
5
|
-
* Agent's own messages are marked seen but NOT forwarded to aggregator.
|
|
6
|
-
*
|
|
7
|
-
* Authoritative writer for StateStore fields:
|
|
8
|
-
* - last_visit: updated on ingest() success
|
|
9
|
-
* - last_msg_seq: updated on ingest() when msg has sequence
|
|
10
|
-
*/
|
|
11
|
-
|
|
12
|
-
import { logger } from '../util/logger.js';
|
|
13
|
-
import type { StateStore } from '../state/store.js';
|
|
14
|
-
import type { WindowAggregator } from './aggregator.js';
|
|
15
|
-
import type { RawMessage } from './types.js';
|
|
16
|
-
|
|
17
|
-
export class Collector {
|
|
18
|
-
private aggregator: WindowAggregator;
|
|
19
|
-
private store: StateStore | null;
|
|
20
|
-
private agentId: string;
|
|
21
|
-
private _memSeen = new Set<string>();
|
|
22
|
-
private _memCleanupTimer: ReturnType<typeof setInterval> | null = null;
|
|
23
|
-
|
|
24
|
-
constructor(aggregator: WindowAggregator, store: StateStore | null = null, agentId = '') {
|
|
25
|
-
this.aggregator = aggregator;
|
|
26
|
-
this.store = store;
|
|
27
|
-
this.agentId = agentId;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
ingest(rawMessage: RawMessage): void {
|
|
31
|
-
if (this._hasSeen(rawMessage.id)) {
|
|
32
|
-
logger.debug(`[collector] DEDUP skip id=${rawMessage.id}`);
|
|
33
|
-
return;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
// Mark as seen
|
|
37
|
-
this._markSeen(rawMessage.id, rawMessage.channelId);
|
|
38
|
-
|
|
39
|
-
// Update StateStore: last_visit + last_msg_seq
|
|
40
|
-
if (this.store) {
|
|
41
|
-
this.store.updateLastVisit(rawMessage.channelId);
|
|
42
|
-
if (rawMessage.seq != null) {
|
|
43
|
-
this.store.updateLastMsgSeq(rawMessage.channelId, rawMessage.seq);
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
// Agent's own messages: mark seen but don't trigger agent turns
|
|
48
|
-
if (this.agentId && rawMessage.from === this.agentId) {
|
|
49
|
-
logger.debug(`[collector] SELF msg id=${rawMessage.id} (marked seen, no turn)`);
|
|
50
|
-
return;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
logger.debug(`[collector] NEW msg id=${rawMessage.id} ch=${rawMessage.channelId} from=${rawMessage.nick}`);
|
|
54
|
-
this.aggregator.append(rawMessage);
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
ingestBatch(rawMessages: RawMessage[]): void {
|
|
58
|
-
for (const msg of rawMessages) {
|
|
59
|
-
this.ingest(msg);
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
private _hasSeen(messageId: string): boolean {
|
|
64
|
-
if (this.store) return this.store.hasSeen(messageId);
|
|
65
|
-
return this._memSeen.has(messageId);
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
private _markSeen(messageId: string, channelId: string): void {
|
|
69
|
-
if (this.store) {
|
|
70
|
-
this.store.markSeen(messageId, channelId);
|
|
71
|
-
} else {
|
|
72
|
-
this._memSeen.add(messageId);
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
startCleanup(intervalMs = 600_000): void {
|
|
77
|
-
if (this.store) return; // StateStore handles its own cleanup
|
|
78
|
-
this._memCleanupTimer = setInterval(() => {
|
|
79
|
-
this._memSeen.clear();
|
|
80
|
-
}, intervalMs);
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
stop(): void {
|
|
84
|
-
if (this._memCleanupTimer) {
|
|
85
|
-
clearInterval(this._memCleanupTimer);
|
|
86
|
-
this._memCleanupTimer = null;
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
}
|
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* ActionExecutor — Triggers OpenClaw agent turn via CLI
|
|
3
|
-
*
|
|
4
|
-
* Uses `openclaw agent` to inject inbound messages.
|
|
5
|
-
* Agent replies via openagent_send_message tool call.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import { execFile } from 'node:child_process';
|
|
9
|
-
import { promisify } from 'node:util';
|
|
10
|
-
|
|
11
|
-
import { logger } from '../util/logger.js';
|
|
12
|
-
import type { ChannelDelta } from './types.js';
|
|
13
|
-
|
|
14
|
-
const execFileAsync = promisify(execFile);
|
|
15
|
-
|
|
16
|
-
export class ActionExecutor {
|
|
17
|
-
private accountId = 'default';
|
|
18
|
-
private openclawBin = 'openclaw';
|
|
19
|
-
|
|
20
|
-
setAccountId(accountId: string): void {
|
|
21
|
-
this.accountId = accountId || 'default';
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
async handleDelta(delta: ChannelDelta): Promise<void> {
|
|
25
|
-
const text = this._formatDeltaText(delta);
|
|
26
|
-
|
|
27
|
-
logger.info(`[executor] INBOUND ch=${delta.channelId} msgs=${delta.messageCount} mention=${delta.hasMention}`);
|
|
28
|
-
|
|
29
|
-
try {
|
|
30
|
-
const args = [
|
|
31
|
-
'agent',
|
|
32
|
-
'--agent', 'main',
|
|
33
|
-
'--channel', 'openagent',
|
|
34
|
-
'--message', text,
|
|
35
|
-
'--session-id', `openagent:${delta.channelId}`,
|
|
36
|
-
'--json',
|
|
37
|
-
];
|
|
38
|
-
|
|
39
|
-
const { stdout, stderr } = await execFileAsync(this.openclawBin, args, {
|
|
40
|
-
timeout: 120_000,
|
|
41
|
-
env: { ...process.env },
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
if (stderr) {
|
|
45
|
-
logger.debug(`[executor] stderr: ${stderr.substring(0, 500)}`);
|
|
46
|
-
}
|
|
47
|
-
if (stdout) {
|
|
48
|
-
logger.info(`[executor] Agent turn completed for ch=${delta.channelId}`);
|
|
49
|
-
}
|
|
50
|
-
} catch (err) {
|
|
51
|
-
logger.error(`[executor] Agent turn failed: ${(err as Error).message}`);
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
private _formatDeltaText(delta: ChannelDelta): string {
|
|
56
|
-
const { channelId, messages, hasMention } = delta;
|
|
57
|
-
const mentionTag = hasMention ? ' ⚡ @mention' : '';
|
|
58
|
-
|
|
59
|
-
let messageSection: string;
|
|
60
|
-
if (messages.length === 1) {
|
|
61
|
-
const m = messages[0]!;
|
|
62
|
-
messageSection = `[Channel ${channelId}${mentionTag}] ${m.nick}: ${m.text}`;
|
|
63
|
-
} else {
|
|
64
|
-
const summary = messages.map(m => `[${m.nick}] ${m.text}`).join('\n');
|
|
65
|
-
messageSection = `📬 ${messages.length} new messages in channel ${channelId}${mentionTag}:\n${summary}`;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
const instruction = `[INSTRUCTION: Reply ONLY in channel ${channelId} using openagent_send_message. After calling the tool, respond with ONLY: NO_REPLY (this prevents your reply from leaking to the chat UI). Do NOT visit other channels. Do NOT send status reports. Just reply naturally to the conversation above, or stay silent if you have nothing to add.]`;
|
|
69
|
-
|
|
70
|
-
return `${messageSection}\n\n${instruction}`;
|
|
71
|
-
}
|
|
72
|
-
}
|
package/src/messaging/inbound.ts
DELETED
|
@@ -1,150 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Inbound — TIM push message → standard OpenClaw MsgContext conversion
|
|
3
|
-
*
|
|
4
|
-
* This module converts the TIM SDK's RawPushMessage into the standard
|
|
5
|
-
* MsgContext shape expected by channelRuntime.reply.dispatchReplyFromConfig().
|
|
6
|
-
*
|
|
7
|
-
* v3.4.0: Added BodyForAgent, InboundHistory, GroupSystemPrompt, GroupSubject,
|
|
8
|
-
* ConversationLabel, Surface, SenderId, RawBody, CommandBody to match
|
|
9
|
-
* the official plugin contract (Signal, LINE, Discord).
|
|
10
|
-
* See: docs/audit/008-inbound-context-gap.md
|
|
11
|
-
*
|
|
12
|
-
* Reference: docs/reference/plugins/openclaw-weixin/src/messaging/inbound.ts
|
|
13
|
-
*/
|
|
14
|
-
|
|
15
|
-
import type { RawPushMessage } from '../tim/client.js';
|
|
16
|
-
|
|
17
|
-
// ── Types ──
|
|
18
|
-
|
|
19
|
-
/** History entry for InboundHistory field. */
|
|
20
|
-
export interface InboundHistoryEntry {
|
|
21
|
-
sender: string;
|
|
22
|
-
body: string;
|
|
23
|
-
timestamp: number;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
/** Extra context not available from the raw TIM message alone. */
|
|
27
|
-
export interface InboundExtras {
|
|
28
|
-
/** Group display name (fetched from TIM group profile) */
|
|
29
|
-
groupName?: string;
|
|
30
|
-
/** Group-level system prompt (from channel skill / notification field) */
|
|
31
|
-
groupSystemPrompt?: string;
|
|
32
|
-
/** Recent message history for this channel */
|
|
33
|
-
inboundHistory?: InboundHistoryEntry[];
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* Standard inbound context for the OpenClaw pipeline.
|
|
38
|
-
* Field names MUST match the OpenClaw MsgContext contract.
|
|
39
|
-
*/
|
|
40
|
-
export interface OpenagentMsgContext {
|
|
41
|
-
/** Message text body (may include envelope in future) */
|
|
42
|
-
Body: string;
|
|
43
|
-
/** Current message original text — LLM prompt main body */
|
|
44
|
-
BodyForAgent: string;
|
|
45
|
-
/** Raw message body for command detection */
|
|
46
|
-
RawBody: string;
|
|
47
|
-
/** Command detection text */
|
|
48
|
-
CommandBody: string;
|
|
49
|
-
/** Sender user ID */
|
|
50
|
-
From: string;
|
|
51
|
-
/** Destination (channel ID for group chats) */
|
|
52
|
-
To: string;
|
|
53
|
-
/** Account ID this message belongs to */
|
|
54
|
-
AccountId: string;
|
|
55
|
-
/** Sender machine ID */
|
|
56
|
-
SenderId: string;
|
|
57
|
-
/** Sender display name */
|
|
58
|
-
SenderName: string;
|
|
59
|
-
/** Human-readable conversation label */
|
|
60
|
-
ConversationLabel: string;
|
|
61
|
-
/** Group name / subject */
|
|
62
|
-
GroupSubject: string;
|
|
63
|
-
/** Channel plugin identifier */
|
|
64
|
-
OriginatingChannel: 'openagent';
|
|
65
|
-
/** Original destination identifier */
|
|
66
|
-
OriginatingTo: string;
|
|
67
|
-
/** Unique message ID */
|
|
68
|
-
MessageSid: string;
|
|
69
|
-
/** Message timestamp (ms) */
|
|
70
|
-
Timestamp?: number;
|
|
71
|
-
/** Provider identifier */
|
|
72
|
-
Provider: 'openagent';
|
|
73
|
-
/** Platform surface identifier */
|
|
74
|
-
Surface: 'openagent';
|
|
75
|
-
/** Chat type: OpenAgent is group-only */
|
|
76
|
-
ChatType: 'group';
|
|
77
|
-
/** Whether the message @mentioned our agent */
|
|
78
|
-
WasMentioned?: boolean;
|
|
79
|
-
/** Session key override (set after resolveAgentRoute) */
|
|
80
|
-
SessionKey?: string;
|
|
81
|
-
/** Whether sender is authorized for slash commands */
|
|
82
|
-
CommandAuthorized?: boolean;
|
|
83
|
-
/** Group-level system prompt (channel skill / rules) */
|
|
84
|
-
GroupSystemPrompt?: string;
|
|
85
|
-
/** Recent message history for this channel */
|
|
86
|
-
InboundHistory?: InboundHistoryEntry[];
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
// ── Conversion ──
|
|
90
|
-
|
|
91
|
-
/**
|
|
92
|
-
* Convert a TIM RawPushMessage to the standard MsgContext.
|
|
93
|
-
*
|
|
94
|
-
* Mapping:
|
|
95
|
-
* raw.text → Body, BodyForAgent, RawBody, CommandBody
|
|
96
|
-
* raw.from → From, SenderId
|
|
97
|
-
* raw.channelId → To, OriginatingTo
|
|
98
|
-
* raw.nick → SenderName
|
|
99
|
-
* raw.id → MessageSid
|
|
100
|
-
* raw.time → Timestamp
|
|
101
|
-
* raw.mentionsMe → WasMentioned
|
|
102
|
-
* extras.groupName → GroupSubject, ConversationLabel
|
|
103
|
-
* extras.groupSystemPrompt → GroupSystemPrompt
|
|
104
|
-
* extras.inboundHistory → InboundHistory
|
|
105
|
-
*/
|
|
106
|
-
export function timMessageToMsgContext(
|
|
107
|
-
raw: RawPushMessage,
|
|
108
|
-
accountId: string,
|
|
109
|
-
extras?: InboundExtras,
|
|
110
|
-
): OpenagentMsgContext {
|
|
111
|
-
const senderName = raw.nick || raw.from;
|
|
112
|
-
const groupName = extras?.groupName || raw.channelId;
|
|
113
|
-
|
|
114
|
-
return {
|
|
115
|
-
// ── Message body (4 variants per official contract) ──
|
|
116
|
-
Body: raw.text,
|
|
117
|
-
BodyForAgent: raw.text,
|
|
118
|
-
RawBody: raw.text,
|
|
119
|
-
CommandBody: raw.text,
|
|
120
|
-
|
|
121
|
-
// ── Routing ──
|
|
122
|
-
From: raw.from,
|
|
123
|
-
To: raw.channelId,
|
|
124
|
-
AccountId: accountId,
|
|
125
|
-
|
|
126
|
-
// ── Sender info ──
|
|
127
|
-
SenderId: raw.from,
|
|
128
|
-
SenderName: senderName,
|
|
129
|
-
|
|
130
|
-
// ── Group info ──
|
|
131
|
-
ConversationLabel: groupName,
|
|
132
|
-
GroupSubject: groupName,
|
|
133
|
-
|
|
134
|
-
// ── Channel metadata ──
|
|
135
|
-
OriginatingChannel: 'openagent',
|
|
136
|
-
OriginatingTo: raw.channelId,
|
|
137
|
-
MessageSid: raw.id,
|
|
138
|
-
Timestamp: raw.time,
|
|
139
|
-
Provider: 'openagent',
|
|
140
|
-
Surface: 'openagent',
|
|
141
|
-
ChatType: 'group',
|
|
142
|
-
|
|
143
|
-
// ── Flags ──
|
|
144
|
-
WasMentioned: raw.mentionsMe,
|
|
145
|
-
|
|
146
|
-
// ── Enriched context (from extras) ──
|
|
147
|
-
GroupSystemPrompt: extras?.groupSystemPrompt || undefined,
|
|
148
|
-
InboundHistory: extras?.inboundHistory,
|
|
149
|
-
};
|
|
150
|
-
}
|
package/src/messaging/index.ts
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Messaging — Module barrel export
|
|
3
|
-
*
|
|
4
|
-
* v3.2.0: New channelRuntime-based pipeline (inbound + process-message).
|
|
5
|
-
* Legacy modules (collector, aggregator, scheduler, executor) are retained
|
|
6
|
-
* on disk but no longer exported or referenced.
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
export { timMessageToMsgContext, type OpenagentMsgContext } from './inbound.js';
|
|
10
|
-
export { processOneMessage, type ProcessMessageDeps } from './process-message.js';
|
|
11
|
-
export type { RawMessage, ChannelDelta, HistoryMessage } from './types.js';
|
|
@@ -1,94 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Mention Protocol — Bot-to-Bot communication in mention-only groups
|
|
3
|
-
*
|
|
4
|
-
* Pure function module — no side effects, no shared state.
|
|
5
|
-
*
|
|
6
|
-
* When a group has gm_req_mention=1, bots need to:
|
|
7
|
-
* 1. Know the group's "social rule" (must @-mention to trigger others)
|
|
8
|
-
* 2. Know who's in the group (member list)
|
|
9
|
-
* 3. Have their text-level @mentions translated to TIM protocol-level atUserList
|
|
10
|
-
*
|
|
11
|
-
* See: docs/audit/012-mention-mode-bot-to-bot-v3.4.4.md
|
|
12
|
-
*/
|
|
13
|
-
|
|
14
|
-
// ── Types ──
|
|
15
|
-
|
|
16
|
-
export interface MentionMember {
|
|
17
|
-
id: string;
|
|
18
|
-
nick: string;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
// ── Regex utility ──
|
|
22
|
-
|
|
23
|
-
function escapeRegex(s: string): string {
|
|
24
|
-
return s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
// ── Prompt injection ──
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* Build the mention protocol prompt to inject into GroupSystemPrompt.
|
|
31
|
-
* Tells the AI: this group is mention-only, here are the members,
|
|
32
|
-
* you must @mention them to communicate.
|
|
33
|
-
*
|
|
34
|
-
* Returns empty string if no other members exist.
|
|
35
|
-
*/
|
|
36
|
-
export function buildMentionPrompt(
|
|
37
|
-
members: MentionMember[],
|
|
38
|
-
selfId: string,
|
|
39
|
-
): string {
|
|
40
|
-
const others = members.filter(m => m.id !== selfId);
|
|
41
|
-
if (others.length === 0) return '';
|
|
42
|
-
|
|
43
|
-
const memberList = others
|
|
44
|
-
.map(m => `- ${m.nick} (mention as: @${m.nick})`)
|
|
45
|
-
.join('\n');
|
|
46
|
-
|
|
47
|
-
return [
|
|
48
|
-
'[GROUP COMMUNICATION PROTOCOL]',
|
|
49
|
-
'This group uses mention-only mode.',
|
|
50
|
-
'Your messages will ONLY be seen by members you @-mention.',
|
|
51
|
-
'To mention someone, write @their_name in your message.',
|
|
52
|
-
'',
|
|
53
|
-
'Group members:',
|
|
54
|
-
memberList,
|
|
55
|
-
'',
|
|
56
|
-
`Example: "@${others[0].nick} what do you think?"`,
|
|
57
|
-
'[/GROUP COMMUNICATION PROTOCOL]',
|
|
58
|
-
].join('\n');
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
// ── Text → atUserList extraction ──
|
|
62
|
-
|
|
63
|
-
/**
|
|
64
|
-
* Extract @-mention targets from AI output text.
|
|
65
|
-
*
|
|
66
|
-
* Strategy: iterate the known member list and search for each nick
|
|
67
|
-
* in the text. This is more robust than parsing @-tokens from text,
|
|
68
|
-
* because it handles:
|
|
69
|
-
* - Space after @: "@ 投资人Bot"
|
|
70
|
-
* - Case mismatch: "@投资人bot"
|
|
71
|
-
* - Trailing punct: "@投资人Bot,你好"
|
|
72
|
-
* - Multiple @: "@BotA @BotB hi"
|
|
73
|
-
*
|
|
74
|
-
* Only matches when @ prefix is present — mentioning a name without @
|
|
75
|
-
* (e.g. "投资人Bot说得对") does NOT trigger a match.
|
|
76
|
-
*
|
|
77
|
-
* Returns an array of userIDs suitable for TIM createTextAtMessage.
|
|
78
|
-
* Returns empty array if no matches found.
|
|
79
|
-
*/
|
|
80
|
-
export function extractAtTargets(
|
|
81
|
-
text: string,
|
|
82
|
-
members: MentionMember[],
|
|
83
|
-
selfId: string,
|
|
84
|
-
): string[] {
|
|
85
|
-
const results: string[] = [];
|
|
86
|
-
for (const member of members) {
|
|
87
|
-
if (member.id === selfId) continue;
|
|
88
|
-
const pattern = new RegExp(`@\\s*${escapeRegex(member.nick)}`, 'i');
|
|
89
|
-
if (pattern.test(text)) {
|
|
90
|
-
results.push(member.id);
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
return results;
|
|
94
|
-
}
|