@brantrusnak/openclaw-omadeus 1.0.1 → 1.0.2
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 +1 -1
- package/openclaw.plugin.json +144 -28
- package/package.json +3 -5
- package/src/api/auth.api.ts +0 -29
- package/src/api/channel.api.ts +29 -0
- package/src/api/nugget.api.ts +81 -10
- package/src/channel.ts +9 -9
- package/src/inbound-policy.ts +250 -0
- package/src/inbound.ts +20 -0
- package/src/member-resolve.ts +84 -0
- package/src/message-handler.ts +99 -53
- package/src/nugget-lookup.ts +67 -4
- package/src/onboarding.ts +242 -120
- package/src/types.ts +77 -7
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# OpenClaw Omadeus Plugin
|
|
2
2
|
|
|
3
|
-
Omadeus
|
|
3
|
+
[Omadeus](https://omadeus.com) plugin for [OpenClaw](https://www.npmjs.com/package/openclaw).
|
|
4
4
|
|
|
5
5
|
This plugin connects OpenClaw to Omadeus over WebSocket so OpenClaw can listen
|
|
6
6
|
for Omadeus messages and reply through the selected Omadeus channel.
|
package/openclaw.plugin.json
CHANGED
|
@@ -12,11 +12,77 @@
|
|
|
12
12
|
"password": { "type": "string" },
|
|
13
13
|
"organizationId": { "type": "number" },
|
|
14
14
|
"sessionToken": { "type": "string" },
|
|
15
|
-
"
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
15
|
+
"inbound": {
|
|
16
|
+
"type": "object",
|
|
17
|
+
"additionalProperties": false,
|
|
18
|
+
"properties": {
|
|
19
|
+
"version": { "type": "integer", "minimum": 1 },
|
|
20
|
+
"direct": {
|
|
21
|
+
"type": "object",
|
|
22
|
+
"additionalProperties": false,
|
|
23
|
+
"properties": {
|
|
24
|
+
"enabled": { "type": "boolean" },
|
|
25
|
+
"allowedSenderReferenceIds": {
|
|
26
|
+
"type": "array",
|
|
27
|
+
"items": { "type": "number" }
|
|
28
|
+
},
|
|
29
|
+
"requireMention": { "type": "string", "enum": ["never", "always"] }
|
|
30
|
+
},
|
|
31
|
+
"required": ["enabled"]
|
|
32
|
+
},
|
|
33
|
+
"channels": {
|
|
34
|
+
"type": "object",
|
|
35
|
+
"additionalProperties": false,
|
|
36
|
+
"properties": {
|
|
37
|
+
"enabled": { "type": "boolean" },
|
|
38
|
+
"allowedRoomIds": { "type": "array", "items": { "type": "number" } },
|
|
39
|
+
"allowedChannelViewIds": { "type": "array", "items": { "type": "number" } },
|
|
40
|
+
"allowedSenderReferenceIds": {
|
|
41
|
+
"type": "array",
|
|
42
|
+
"items": { "type": "number" }
|
|
43
|
+
},
|
|
44
|
+
"requireMention": {
|
|
45
|
+
"type": "string",
|
|
46
|
+
"enum": ["never", "always", "outsideAllowlist"]
|
|
47
|
+
}
|
|
48
|
+
},
|
|
49
|
+
"required": ["enabled"]
|
|
50
|
+
},
|
|
51
|
+
"entities": {
|
|
52
|
+
"type": "object",
|
|
53
|
+
"additionalProperties": false,
|
|
54
|
+
"properties": {
|
|
55
|
+
"enabled": { "type": "boolean" },
|
|
56
|
+
"allowedKinds": {
|
|
57
|
+
"type": "array",
|
|
58
|
+
"items": {
|
|
59
|
+
"type": "string",
|
|
60
|
+
"enum": [
|
|
61
|
+
"task",
|
|
62
|
+
"nugget",
|
|
63
|
+
"project",
|
|
64
|
+
"release",
|
|
65
|
+
"sprint",
|
|
66
|
+
"summary",
|
|
67
|
+
"client",
|
|
68
|
+
"folder"
|
|
69
|
+
]
|
|
70
|
+
}
|
|
71
|
+
},
|
|
72
|
+
"allowedRoomIds": { "type": "array", "items": { "type": "number" } },
|
|
73
|
+
"allowedSenderReferenceIds": {
|
|
74
|
+
"type": "array",
|
|
75
|
+
"items": { "type": "number" }
|
|
76
|
+
},
|
|
77
|
+
"requireMention": {
|
|
78
|
+
"type": "string",
|
|
79
|
+
"enum": ["never", "always", "outsideAllowlist"]
|
|
80
|
+
}
|
|
81
|
+
},
|
|
82
|
+
"required": ["enabled"]
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
20
86
|
}
|
|
21
87
|
},
|
|
22
88
|
"channelConfigs": {
|
|
@@ -32,11 +98,77 @@
|
|
|
32
98
|
"password": { "type": "string" },
|
|
33
99
|
"organizationId": { "type": "number" },
|
|
34
100
|
"sessionToken": { "type": "string" },
|
|
35
|
-
"
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
101
|
+
"inbound": {
|
|
102
|
+
"type": "object",
|
|
103
|
+
"additionalProperties": false,
|
|
104
|
+
"properties": {
|
|
105
|
+
"version": { "type": "integer", "minimum": 1 },
|
|
106
|
+
"direct": {
|
|
107
|
+
"type": "object",
|
|
108
|
+
"additionalProperties": false,
|
|
109
|
+
"properties": {
|
|
110
|
+
"enabled": { "type": "boolean" },
|
|
111
|
+
"allowedSenderReferenceIds": {
|
|
112
|
+
"type": "array",
|
|
113
|
+
"items": { "type": "number" }
|
|
114
|
+
},
|
|
115
|
+
"requireMention": { "type": "string", "enum": ["never", "always"] }
|
|
116
|
+
},
|
|
117
|
+
"required": ["enabled"]
|
|
118
|
+
},
|
|
119
|
+
"channels": {
|
|
120
|
+
"type": "object",
|
|
121
|
+
"additionalProperties": false,
|
|
122
|
+
"properties": {
|
|
123
|
+
"enabled": { "type": "boolean" },
|
|
124
|
+
"allowedRoomIds": { "type": "array", "items": { "type": "number" } },
|
|
125
|
+
"allowedChannelViewIds": { "type": "array", "items": { "type": "number" } },
|
|
126
|
+
"allowedSenderReferenceIds": {
|
|
127
|
+
"type": "array",
|
|
128
|
+
"items": { "type": "number" }
|
|
129
|
+
},
|
|
130
|
+
"requireMention": {
|
|
131
|
+
"type": "string",
|
|
132
|
+
"enum": ["never", "always", "outsideAllowlist"]
|
|
133
|
+
}
|
|
134
|
+
},
|
|
135
|
+
"required": ["enabled"]
|
|
136
|
+
},
|
|
137
|
+
"entities": {
|
|
138
|
+
"type": "object",
|
|
139
|
+
"additionalProperties": false,
|
|
140
|
+
"properties": {
|
|
141
|
+
"enabled": { "type": "boolean" },
|
|
142
|
+
"allowedKinds": {
|
|
143
|
+
"type": "array",
|
|
144
|
+
"items": {
|
|
145
|
+
"type": "string",
|
|
146
|
+
"enum": [
|
|
147
|
+
"task",
|
|
148
|
+
"nugget",
|
|
149
|
+
"project",
|
|
150
|
+
"release",
|
|
151
|
+
"sprint",
|
|
152
|
+
"summary",
|
|
153
|
+
"client",
|
|
154
|
+
"folder"
|
|
155
|
+
]
|
|
156
|
+
}
|
|
157
|
+
},
|
|
158
|
+
"allowedRoomIds": { "type": "array", "items": { "type": "number" } },
|
|
159
|
+
"allowedSenderReferenceIds": {
|
|
160
|
+
"type": "array",
|
|
161
|
+
"items": { "type": "number" }
|
|
162
|
+
},
|
|
163
|
+
"requireMention": {
|
|
164
|
+
"type": "string",
|
|
165
|
+
"enum": ["never", "always", "outsideAllowlist"]
|
|
166
|
+
}
|
|
167
|
+
},
|
|
168
|
+
"required": ["enabled"]
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
40
172
|
}
|
|
41
173
|
},
|
|
42
174
|
"uiHints": {
|
|
@@ -63,24 +195,8 @@
|
|
|
63
195
|
"sensitive": true,
|
|
64
196
|
"advanced": true
|
|
65
197
|
},
|
|
66
|
-
"
|
|
67
|
-
"label": "
|
|
68
|
-
"advanced": true
|
|
69
|
-
},
|
|
70
|
-
"selectedChannelViewId": {
|
|
71
|
-
"label": "Selected channel view ID",
|
|
72
|
-
"advanced": true
|
|
73
|
-
},
|
|
74
|
-
"selectedChannelTitle": {
|
|
75
|
-
"label": "Selected channel title",
|
|
76
|
-
"advanced": true
|
|
77
|
-
},
|
|
78
|
-
"selectedChannelPrivateRoomId": {
|
|
79
|
-
"label": "Selected private room ID",
|
|
80
|
-
"advanced": true
|
|
81
|
-
},
|
|
82
|
-
"selectedChannelPublicRoomId": {
|
|
83
|
-
"label": "Selected public room ID",
|
|
198
|
+
"inbound": {
|
|
199
|
+
"label": "Inbound policy (Jaguar chat)",
|
|
84
200
|
"advanced": true
|
|
85
201
|
}
|
|
86
202
|
},
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@brantrusnak/openclaw-omadeus",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "OpenClaw Omadeus project management channel plugin",
|
|
6
6
|
"homepage": "https://github.com/brantrusnak/openclaw-omadeus-plugin#readme",
|
|
@@ -54,10 +54,8 @@
|
|
|
54
54
|
"channel": {
|
|
55
55
|
"id": "omadeus",
|
|
56
56
|
"label": "Omadeus",
|
|
57
|
-
"selectionLabel": "Omadeus (WebSocket)",
|
|
58
|
-
"
|
|
59
|
-
"docsLabel": "omadeus",
|
|
60
|
-
"blurb": "Omadeus project management — tasks, chat rooms, and sprints.",
|
|
57
|
+
"selectionLabel": "Omadeus (API + WebSocket)",
|
|
58
|
+
"blurb": "AI-native project management that knows your role, speaks your language, and keeps your team in sync. No noise.",
|
|
61
59
|
"order": 70
|
|
62
60
|
},
|
|
63
61
|
"install": {
|
package/src/api/auth.api.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { getCasSession, setCasSession } from "../store.js";
|
|
2
2
|
import type {
|
|
3
3
|
CasAuthorizationCodeResponse,
|
|
4
|
-
OmadeusChannelView,
|
|
5
4
|
OmadeusOrganizationMember,
|
|
6
5
|
OmadeusOrganization,
|
|
7
6
|
OmadeusSessionTokenResponse,
|
|
@@ -139,34 +138,6 @@ export async function listOrganizations(params: {
|
|
|
139
138
|
return (await res.json()) as OmadeusOrganization[];
|
|
140
139
|
}
|
|
141
140
|
|
|
142
|
-
export async function listMemberChannelViews(params: {
|
|
143
|
-
maestroUrl: string;
|
|
144
|
-
sessionToken: string;
|
|
145
|
-
memberReferenceId: number;
|
|
146
|
-
skip?: number;
|
|
147
|
-
take?: number;
|
|
148
|
-
}): Promise<OmadeusChannelView[]> {
|
|
149
|
-
const { maestroUrl, sessionToken, memberReferenceId, skip = 0, take = 100 } = params;
|
|
150
|
-
const qs = new URLSearchParams({
|
|
151
|
-
skip: String(skip),
|
|
152
|
-
take: String(take),
|
|
153
|
-
sort: "-recentMessageAt",
|
|
154
|
-
});
|
|
155
|
-
const url = `${maestroUrl}/jaguar/apiv1/members/${memberReferenceId}/channelviews?${qs.toString()}`;
|
|
156
|
-
const res = await fetch(url, {
|
|
157
|
-
method: "LIST",
|
|
158
|
-
headers: {
|
|
159
|
-
Authorization: `Bearer ${sessionToken}`,
|
|
160
|
-
"Content-Type": "application/json;charset=UTF-8",
|
|
161
|
-
},
|
|
162
|
-
});
|
|
163
|
-
if (!res.ok) {
|
|
164
|
-
const text = await res.text().catch(() => "");
|
|
165
|
-
throw new Error(`Omadeus list channel views failed (${res.status}): ${text}`);
|
|
166
|
-
}
|
|
167
|
-
return (await res.json()) as OmadeusChannelView[];
|
|
168
|
-
}
|
|
169
|
-
|
|
170
141
|
export async function listOrganizationMembers(params: {
|
|
171
142
|
maestroUrl: string;
|
|
172
143
|
sessionToken: string;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { OmadeusChannelView } from "../types.js";
|
|
2
|
+
|
|
3
|
+
export async function listMemberChannelViews(params: {
|
|
4
|
+
maestroUrl: string;
|
|
5
|
+
sessionToken: string;
|
|
6
|
+
memberReferenceId: number;
|
|
7
|
+
skip?: number;
|
|
8
|
+
take?: number;
|
|
9
|
+
}): Promise<OmadeusChannelView[]> {
|
|
10
|
+
const { maestroUrl, sessionToken, memberReferenceId, skip = 0, take = 100 } = params;
|
|
11
|
+
const qs = new URLSearchParams({
|
|
12
|
+
skip: String(skip),
|
|
13
|
+
take: String(take),
|
|
14
|
+
sort: "-recentMessageAt",
|
|
15
|
+
});
|
|
16
|
+
const url = `${maestroUrl}/jaguar/apiv1/members/${memberReferenceId}/channelviews?${qs.toString()}`;
|
|
17
|
+
const res = await fetch(url, {
|
|
18
|
+
method: "LIST",
|
|
19
|
+
headers: {
|
|
20
|
+
Authorization: `Bearer ${sessionToken}`,
|
|
21
|
+
"Content-Type": "application/json;charset=UTF-8",
|
|
22
|
+
},
|
|
23
|
+
});
|
|
24
|
+
if (!res.ok) {
|
|
25
|
+
const text = await res.text().catch(() => "");
|
|
26
|
+
throw new Error(`Omadeus list channel views failed (${res.status}): ${text}`);
|
|
27
|
+
}
|
|
28
|
+
return (await res.json()) as OmadeusChannelView[];
|
|
29
|
+
}
|
package/src/api/nugget.api.ts
CHANGED
|
@@ -85,20 +85,23 @@ function extractRows(payload: unknown): Record<string, unknown>[] {
|
|
|
85
85
|
}
|
|
86
86
|
|
|
87
87
|
/**
|
|
88
|
-
* Dolphin SEARCH on nuggetviews
|
|
89
|
-
*
|
|
88
|
+
* Dolphin SEARCH on nuggetviews — arbitrary text query (e.g. N###, task title, or room id string).
|
|
89
|
+
* Prefer filtering results with `findNuggetRowByNumber` or `findNuggetRowByRoomId`.
|
|
90
90
|
*/
|
|
91
|
-
export async function
|
|
91
|
+
export async function searchNuggetRowsByTextQuery(
|
|
92
92
|
opts: OmadeusApiOptions,
|
|
93
|
-
params:
|
|
94
|
-
): Promise<Record<string, unknown>
|
|
95
|
-
const
|
|
93
|
+
params: { query: string; take?: number; signal?: AbortSignal },
|
|
94
|
+
): Promise<Record<string, unknown>[]> {
|
|
95
|
+
const take = params.take ?? 100;
|
|
96
|
+
const q = params.query.trim();
|
|
97
|
+
if (!q) {
|
|
98
|
+
return [];
|
|
99
|
+
}
|
|
96
100
|
const search = new URLSearchParams();
|
|
97
|
-
search.set("take",
|
|
98
|
-
|
|
101
|
+
search.set("take", String(take));
|
|
99
102
|
const res = await dolphinFetch(opts, `/nuggetviews?${search.toString()}`, {
|
|
100
103
|
method: "SEARCH",
|
|
101
|
-
body: JSON.stringify({ query }),
|
|
104
|
+
body: JSON.stringify({ query: q }),
|
|
102
105
|
signal: params.signal,
|
|
103
106
|
});
|
|
104
107
|
if (!res.ok) {
|
|
@@ -106,7 +109,75 @@ export async function searchNuggetByNumber(
|
|
|
106
109
|
throw new Error(`Omadeus nugget search failed (${res.status}): ${text.slice(0, 200)}`);
|
|
107
110
|
}
|
|
108
111
|
const payload = (await res.json()) as unknown;
|
|
109
|
-
|
|
112
|
+
return extractRows(payload);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Picks a row whose private/public/shared task room id matches a Jaguar `roomId`.
|
|
117
|
+
*/
|
|
118
|
+
export function findNuggetRowByRoomId(
|
|
119
|
+
rows: Record<string, unknown>[],
|
|
120
|
+
roomId: number,
|
|
121
|
+
): Record<string, unknown> | undefined {
|
|
122
|
+
for (const row of rows) {
|
|
123
|
+
for (const key of ["privateRoomId", "publicRoomId", "sharedRoomId"] as const) {
|
|
124
|
+
if (readNumberField(row, key) === roomId) {
|
|
125
|
+
return row;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
return undefined;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
export type FindNuggetByTaskRoomParams = {
|
|
133
|
+
roomId: number;
|
|
134
|
+
roomName?: string | null;
|
|
135
|
+
signal?: AbortSignal;
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Resolve the nugget/task row for a Jaguar Task or Nugget **chat room** by matching
|
|
140
|
+
* `privateRoomId` / `publicRoomId` / `sharedRoomId` to `roomId` in Dolphin `nuggetviews` search results.
|
|
141
|
+
* Tries search by `roomName` first (usually matches the task title), then by the numeric `roomId` as text.
|
|
142
|
+
*/
|
|
143
|
+
export async function findNuggetByTaskChannelRoom(
|
|
144
|
+
opts: OmadeusApiOptions,
|
|
145
|
+
params: FindNuggetByTaskRoomParams,
|
|
146
|
+
): Promise<Record<string, unknown> | null> {
|
|
147
|
+
const { roomId, roomName, signal } = params;
|
|
148
|
+
const tryQueries: string[] = [];
|
|
149
|
+
if (typeof roomName === "string" && roomName.trim()) {
|
|
150
|
+
tryQueries.push(roomName.trim());
|
|
151
|
+
}
|
|
152
|
+
tryQueries.push(String(roomId));
|
|
153
|
+
const tried = new Set<string>();
|
|
154
|
+
for (const query of tryQueries) {
|
|
155
|
+
if (tried.has(query)) {
|
|
156
|
+
continue;
|
|
157
|
+
}
|
|
158
|
+
tried.add(query);
|
|
159
|
+
const rows = await searchNuggetRowsByTextQuery(opts, { query, take: 100, signal });
|
|
160
|
+
const match = findNuggetRowByRoomId(rows, roomId);
|
|
161
|
+
if (match) {
|
|
162
|
+
return match;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
return null;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Dolphin SEARCH on nuggetviews returns an array of nugget/task rows.
|
|
170
|
+
* User-facing `N111` corresponds to `number: 111` on each row (not `id`).
|
|
171
|
+
*/
|
|
172
|
+
export async function searchNuggetByNumber(
|
|
173
|
+
opts: OmadeusApiOptions,
|
|
174
|
+
params: NuggetSearchParams,
|
|
175
|
+
): Promise<Record<string, unknown> | null> {
|
|
176
|
+
const rows = await searchNuggetRowsByTextQuery(opts, {
|
|
177
|
+
query: `N${params.nuggetNumber}`,
|
|
178
|
+
take: 100,
|
|
179
|
+
signal: params.signal,
|
|
180
|
+
});
|
|
110
181
|
const match = findNuggetRowByNumber(rows, params.nuggetNumber);
|
|
111
182
|
return match ?? null;
|
|
112
183
|
}
|
package/src/channel.ts
CHANGED
|
@@ -83,11 +83,7 @@ const omadeusConfigAdapter = createTopLevelChannelConfigAdapter<Account>({
|
|
|
83
83
|
"password",
|
|
84
84
|
"organizationId",
|
|
85
85
|
"sessionToken",
|
|
86
|
-
"
|
|
87
|
-
"selectedChannelViewId",
|
|
88
|
-
"selectedChannelTitle",
|
|
89
|
-
"selectedChannelPrivateRoomId",
|
|
90
|
-
"selectedChannelPublicRoomId",
|
|
86
|
+
"inbound",
|
|
91
87
|
],
|
|
92
88
|
// Keep adapter contract satisfied even though Omadeus no longer uses DM allowlists.
|
|
93
89
|
resolveAllowFrom: () => [],
|
|
@@ -188,10 +184,10 @@ export const omadeusPlugin: ChannelPlugin<Account> = {
|
|
|
188
184
|
meta: {
|
|
189
185
|
id: "omadeus",
|
|
190
186
|
label: "Omadeus",
|
|
191
|
-
selectionLabel: "Omadeus (WebSocket)",
|
|
192
|
-
docsPath: "
|
|
193
|
-
docsLabel: "
|
|
194
|
-
blurb: "
|
|
187
|
+
selectionLabel: "Omadeus (API + WebSocket)",
|
|
188
|
+
docsPath: "",
|
|
189
|
+
docsLabel: "",
|
|
190
|
+
blurb: "AI-native project management that knows your role, speaks your language, and keeps your team in sync. No noise.",
|
|
195
191
|
},
|
|
196
192
|
capabilities: {
|
|
197
193
|
chatTypes: ["direct", "group"],
|
|
@@ -205,6 +201,9 @@ export const omadeusPlugin: ChannelPlugin<Account> = {
|
|
|
205
201
|
messageToolHints: () => [
|
|
206
202
|
"- Omadeus routing: **send** uses **room id** (`to` / `target`, e.g. `room:117947` or `117947`). **edit**, **delete**, **react** use the Jaguar **message** `id` (`messageId`, or the current inbound message from context).",
|
|
207
203
|
"- Create Omadeus task/nugget: use `action=send` with params `{ op: \"create_task\"|\"create_nugget\", title, description, priority?, stage?, kind?, memberReferenceId?, clientId?, folderId? }`.",
|
|
204
|
+
"- Omadeus **Task** and **Nugget** are distinct product types (Jaguar `subscribableKind`). **Project**, **Sprint**, **Release**, **Folder**, **Client**, **Summary**, etc. also have entity chat rooms. User \"task\" / \"the task\" → map to **this room's** `subscribableKind` (Task vs Nugget vs other), not an OpenClaw background task.",
|
|
205
|
+
"- In Task or Nugget rooms, inbound may include **Dolphin nuggetviews** JSON for this chat's `roomId` — **summarize that** for status questions. The payload may include a **`people`** object (Omadeus member names). Use those for assignees; do not read `referenceId` numbers as names. Do not tell the user to go use the Omadeus app instead of answering from that data or the thread.",
|
|
206
|
+
"- `session_status` / SessionKey: **OpenClaw** gateway only. Use the inbound SessionKey, \"current\", or the hint in **entity** rooms — never a fake `task/<...>` string from a title.",
|
|
208
207
|
`- Reactions only allow these emojis (others are ignored): ${ALLOWED_OMADEUS_REACTION_EMOJI_LIST.join(" ")}`,
|
|
209
208
|
"- Reply in chat with plain text; use the message tool for proactive sends, edits, deletes, or reactions.",
|
|
210
209
|
],
|
|
@@ -711,6 +710,7 @@ export const omadeusPlugin: ChannelPlugin<Account> = {
|
|
|
711
710
|
runtime: ctx.runtime,
|
|
712
711
|
log,
|
|
713
712
|
outboundDeps,
|
|
713
|
+
selfReferenceId,
|
|
714
714
|
});
|
|
715
715
|
|
|
716
716
|
// Jaguar socket (chat — DMs, nugget/task/project rooms)
|