openclaw-quiubo 2.6.42 → 2.6.44
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/MULTI_AGENT.md +9 -1
- package/README.md +63 -1
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +118 -0
- package/dist/index.js.map +4 -4
- package/dist/src/group-context-hook.d.ts +15 -0
- package/dist/src/group-context-hook.d.ts.map +1 -0
- package/openclaw.plugin.json +1 -1
- package/package.json +1 -1
package/MULTI_AGENT.md
CHANGED
|
@@ -201,7 +201,15 @@ Cron jobs are scoped per agent via the `agentId` field:
|
|
|
201
201
|
- **`delivery.channel`**: Must be `"quiubo"`.
|
|
202
202
|
- **`delivery.to`**: The raw group UUID (e.g. `eec8a4ce-d08d-483a-ba5d-90a43ce8f521`). Find it in the agent's welcome chat or via the API.
|
|
203
203
|
|
|
204
|
-
> **Multi-agent caveat:** The
|
|
204
|
+
> **Multi-agent caveat:** The announce delivery path does not reliably resolve targets for named agents ([openclaw/openclaw#32432](https://github.com/openclaw/openclaw/issues/32432)). Use `--no-deliver` so the agent sends messages itself:
|
|
205
|
+
>
|
|
206
|
+
> ```bash
|
|
207
|
+
> openclaw cron add --name "standup" --agent project-manager --every 24h \
|
|
208
|
+
> --no-deliver --to <group-uuid> \
|
|
209
|
+
> --message 'Post the daily standup to the group chat.'
|
|
210
|
+
> ```
|
|
211
|
+
>
|
|
212
|
+
> With `--no-deliver`, the agent uses its own channel binding to send messages, which correctly resolves identity and routing. See the [README cron section](./README.md#named-agent-crons) for details.
|
|
205
213
|
|
|
206
214
|
## Full Config Reference
|
|
207
215
|
|
package/README.md
CHANGED
|
@@ -34,6 +34,45 @@ The interactive wizard will:
|
|
|
34
34
|
| SDK API Key | Quiubo app > Settings > Developer > API Keys |
|
|
35
35
|
| Bot Identity | Created during setup wizard, or pre-create in Developer console |
|
|
36
36
|
|
|
37
|
+
## Quick Start: Talking to your agent
|
|
38
|
+
|
|
39
|
+
Once setup completes, your agent is ready to chat:
|
|
40
|
+
|
|
41
|
+
1. **Open Quiubo** — your agent appears as a contact with its own chat
|
|
42
|
+
2. **Send a message** — the agent receives it and responds automatically
|
|
43
|
+
3. **Add to groups** — invite the agent to any group, then @mention it to get its attention
|
|
44
|
+
|
|
45
|
+
### How agents receive messages
|
|
46
|
+
|
|
47
|
+
| Context | How to trigger the agent |
|
|
48
|
+
|---------|------------------------|
|
|
49
|
+
| 1:1 chat (agent channel) | Just send a message — the agent always responds |
|
|
50
|
+
| Group (agent is a member) | @mention the agent: `@BotName do something` |
|
|
51
|
+
| Group (agent-only) | Every message triggers all agents (auto-broadcast) |
|
|
52
|
+
| Group (directory agent) | @mention required — agents with `triggerMode: "mention"` only respond when mentioned |
|
|
53
|
+
|
|
54
|
+
### @team shortcut
|
|
55
|
+
|
|
56
|
+
In groups with 2+ agents, type `@Team` to mention all agents at once. The @Team mention expands to individual agent mentions before delivery.
|
|
57
|
+
|
|
58
|
+
### Scheduled messages
|
|
59
|
+
|
|
60
|
+
Agents can send messages on a schedule using cron jobs:
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
# Default agent — announce mode works
|
|
64
|
+
openclaw cron add --name "daily-report" --every 24h \
|
|
65
|
+
--channel quiubo --to <group-uuid> --announce \
|
|
66
|
+
--message "Generate and post the daily report."
|
|
67
|
+
|
|
68
|
+
# Named agent — use --no-deliver (agent sends the message itself)
|
|
69
|
+
openclaw cron add --name "standup" --agent my-agent --every 24h \
|
|
70
|
+
--no-deliver --to <group-uuid> \
|
|
71
|
+
--message "Post the daily standup to the group chat."
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
See [Cron delivery](#scheduled-messages--cron-delivery) for details on delivery modes.
|
|
75
|
+
|
|
37
76
|
## Configuration
|
|
38
77
|
|
|
39
78
|
```yaml
|
|
@@ -204,13 +243,36 @@ A typing indicator is sent immediately when processing begins, then repeated eve
|
|
|
204
243
|
Cron jobs that deliver to Quiubo groups **must** include `--to <groupId>`:
|
|
205
244
|
|
|
206
245
|
```bash
|
|
207
|
-
openclaw cron add --every 30m --channel quiubo --to 7868cc21-... "Check in with the team"
|
|
246
|
+
openclaw cron add --name "team-checkin" --every 30m --channel quiubo --to 7868cc21-... "Check in with the team"
|
|
208
247
|
```
|
|
209
248
|
|
|
210
249
|
Without `--to`, the extension cannot determine which group to deliver to. Unlike 1:1 sessions (which have a single bound chat), group sessions are multi-tenant — the target must be explicit.
|
|
211
250
|
|
|
212
251
|
> **Note:** The `--to` value is the Quiubo group UUID, visible in the group detail screen or conversation URL.
|
|
213
252
|
|
|
253
|
+
#### Named agent crons
|
|
254
|
+
|
|
255
|
+
The `--announce` delivery mode does not work reliably with `--agent <id>` (see [openclaw/openclaw#32432](https://github.com/openclaw/openclaw/issues/32432)). The workaround is `--no-deliver` — the agent sends the message itself using the message tool:
|
|
256
|
+
|
|
257
|
+
```bash
|
|
258
|
+
openclaw cron add --name "giskard-standup" --agent giskard --every 24h \
|
|
259
|
+
--no-deliver \
|
|
260
|
+
--to 7868cc21-... \
|
|
261
|
+
--message 'Post the daily standup summary to the Quiubo group chat.'
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
With `--no-deliver`, the cron skips the announce pipeline entirely. The agent receives the prompt and sends messages through its own account binding, which correctly resolves identity and group routing.
|
|
265
|
+
|
|
266
|
+
**Why this works:** Announce delivery resolves targets using a different code path that lacks proper account resolution for named agents. With `--no-deliver`, the agent uses the standard message tool path, which goes through the agent's own channel binding (`quiubo:accountId`).
|
|
267
|
+
|
|
268
|
+
#### Delivery mode comparison
|
|
269
|
+
|
|
270
|
+
| Mode | Flag | How it works | Named agent support |
|
|
271
|
+
|------|------|-------------|-------------------|
|
|
272
|
+
| Announce | `--announce` (default) | Cron delivers output via channel adapter | ❌ Fails for `--agent` |
|
|
273
|
+
| No deliver | `--no-deliver` | Agent sends messages itself via message tool | ✅ Works |
|
|
274
|
+
| Webhook | `--webhook --to <url>` | Cron POSTs to your endpoint | ✅ Works |
|
|
275
|
+
|
|
214
276
|
See [#84](https://github.com/bitlabs-com/quiubo/issues/84) for a planned improvement to auto-resolve the target from the session bound group.
|
|
215
277
|
|
|
216
278
|
## Managing Accounts
|
package/dist/index.d.ts
CHANGED
|
@@ -12,12 +12,17 @@ export { startWebhookServer, type WebhookHandlerOptions } from './src/webhook-ha
|
|
|
12
12
|
export type { QuiuboAccountConfig, QuiuboGroup, QuiuboMessage, QuiuboIdentity, QuiuboJoinToken, QuiuboAuthResponse, WebhookPayload, WebhookMessageData, WebhookJoinTokenRedeemedData, } from './src/types.js';
|
|
13
13
|
interface OpenClawPluginApi {
|
|
14
14
|
runtime: unknown;
|
|
15
|
+
config?: unknown;
|
|
15
16
|
registerChannel: (opts: {
|
|
16
17
|
plugin: any;
|
|
17
18
|
}) => void;
|
|
18
19
|
registerTool: (tool: any, opts?: {
|
|
19
20
|
name?: string;
|
|
20
21
|
}) => void;
|
|
22
|
+
registerHook: (events: string | string[], handler: (...args: any[]) => any, opts?: {
|
|
23
|
+
name?: string;
|
|
24
|
+
description?: string;
|
|
25
|
+
}) => void;
|
|
21
26
|
}
|
|
22
27
|
declare const plugin: {
|
|
23
28
|
id: string;
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAQH,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAChD,OAAO,EAAE,eAAe,EAAE,KAAK,aAAa,EAAE,KAAK,sBAAsB,EAAE,KAAK,cAAc,EAAE,KAAK,cAAc,EAAE,KAAK,SAAS,EAAE,MAAM,2BAA2B,CAAC;AACvK,OAAO,EAAE,cAAc,EAAE,KAAK,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;AACtF,OAAO,EAAE,kBAAkB,EAAE,KAAK,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;AAC1F,YAAY,EACV,mBAAmB,EACnB,WAAW,EACX,aAAa,EACb,cAAc,EACd,eAAe,EACf,kBAAkB,EAClB,cAAc,EACd,kBAAkB,EAClB,4BAA4B,GAC7B,MAAM,gBAAgB,CAAC;AAGxB,UAAU,iBAAiB;IACzB,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,OAAO,CAAC;IAEjB,eAAe,EAAE,CAAC,IAAI,EAAE;QAAE,MAAM,EAAE,GAAG,CAAA;KAAE,KAAK,IAAI,CAAC;IAEjD,YAAY,EAAE,CAAC,IAAI,EAAE,GAAG,EAAE,IAAI,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAC;IAE5D,YAAY,EAAE,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,EAAE,OAAO,EAAE,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,GAAG,EAAE,IAAI,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAC;CACrI;AAED,QAAA,MAAM,MAAM;;;;kBAII,iBAAiB;CAMhC,CAAC;AAEF,eAAe,MAAM,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -14818,6 +14818,123 @@ function createQuiuboPostToolFactory(ctx) {
|
|
|
14818
14818
|
};
|
|
14819
14819
|
}
|
|
14820
14820
|
|
|
14821
|
+
// src/group-context-hook.ts
|
|
14822
|
+
var CACHE_TTL_MS = 6e4;
|
|
14823
|
+
var cache = /* @__PURE__ */ new Map();
|
|
14824
|
+
function getCached(groupId) {
|
|
14825
|
+
const entry = cache.get(groupId);
|
|
14826
|
+
if (!entry) return void 0;
|
|
14827
|
+
if (Date.now() > entry.expiry) {
|
|
14828
|
+
cache.delete(groupId);
|
|
14829
|
+
return void 0;
|
|
14830
|
+
}
|
|
14831
|
+
return entry.data;
|
|
14832
|
+
}
|
|
14833
|
+
function setCache(groupId, data) {
|
|
14834
|
+
cache.set(groupId, { data, expiry: Date.now() + CACHE_TTL_MS });
|
|
14835
|
+
}
|
|
14836
|
+
function extractGroupIdFromSessionKey2(key) {
|
|
14837
|
+
if (!key) return void 0;
|
|
14838
|
+
const match = key.match(
|
|
14839
|
+
/quiubo:([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})$/i
|
|
14840
|
+
);
|
|
14841
|
+
return match?.[1];
|
|
14842
|
+
}
|
|
14843
|
+
function extractAgentIdFromSessionKey2(key) {
|
|
14844
|
+
if (!key) return "main";
|
|
14845
|
+
const match = key.match(/^agent:([^:]+):quiubo:/);
|
|
14846
|
+
return match?.[1] ?? "main";
|
|
14847
|
+
}
|
|
14848
|
+
function resolveAccountId2(config, agentId) {
|
|
14849
|
+
const bindings = config?.bindings ?? [];
|
|
14850
|
+
const matched = bindings.find(
|
|
14851
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
14852
|
+
(b) => b?.match?.channel === "quiubo" && b?.agentId === agentId
|
|
14853
|
+
);
|
|
14854
|
+
return matched?.match?.accountId ?? "default";
|
|
14855
|
+
}
|
|
14856
|
+
var DEFAULT_API_URL3 = "https://api.quiubo.chat/v1";
|
|
14857
|
+
async function fetchGroupContext(config, sessionKey) {
|
|
14858
|
+
const groupId = extractGroupIdFromSessionKey2(sessionKey);
|
|
14859
|
+
if (!groupId) return void 0;
|
|
14860
|
+
const cached = getCached(groupId);
|
|
14861
|
+
if (cached) return cached;
|
|
14862
|
+
const agentId = extractAgentIdFromSessionKey2(sessionKey);
|
|
14863
|
+
const accountId = resolveAccountId2(config, agentId);
|
|
14864
|
+
const quiuboConfig = config?.channels?.quiubo;
|
|
14865
|
+
const accountCfg = quiuboConfig?.accounts?.[accountId];
|
|
14866
|
+
if (!accountCfg?.apiKey) return void 0;
|
|
14867
|
+
const client = new QuiuboApiClient(
|
|
14868
|
+
accountCfg.apiUrl ?? DEFAULT_API_URL3,
|
|
14869
|
+
accountCfg.apiKey
|
|
14870
|
+
);
|
|
14871
|
+
const [group, { members }, { agents }] = await Promise.all([
|
|
14872
|
+
client.getGroup(groupId),
|
|
14873
|
+
client.listGroupMembers(groupId),
|
|
14874
|
+
client.listAgents()
|
|
14875
|
+
]);
|
|
14876
|
+
const botIdentityIds = new Set(agents.map((a) => a.identityId));
|
|
14877
|
+
const currentAgent = agents.find((a) => a.identityId === accountCfg.botIdentityId);
|
|
14878
|
+
const e2eeEnabled = currentAgent?.e2eeConfigured ?? false;
|
|
14879
|
+
let scopes = [];
|
|
14880
|
+
if (currentAgent) {
|
|
14881
|
+
try {
|
|
14882
|
+
const status = await client.getGroupAgent(currentAgent.id, groupId);
|
|
14883
|
+
scopes = status?.grantedScopes ?? [];
|
|
14884
|
+
} catch {
|
|
14885
|
+
}
|
|
14886
|
+
}
|
|
14887
|
+
const data = {
|
|
14888
|
+
groupId,
|
|
14889
|
+
groupName: group.name,
|
|
14890
|
+
groupType: group.groupType ?? "standard",
|
|
14891
|
+
e2ee: e2eeEnabled,
|
|
14892
|
+
members: members.map((m) => ({
|
|
14893
|
+
displayName: m.displayName ?? m.identityId,
|
|
14894
|
+
isBot: botIdentityIds.has(m.identityId),
|
|
14895
|
+
role: m.role
|
|
14896
|
+
})),
|
|
14897
|
+
scopes
|
|
14898
|
+
};
|
|
14899
|
+
setCache(groupId, data);
|
|
14900
|
+
return data;
|
|
14901
|
+
}
|
|
14902
|
+
function formatContextBlock(data) {
|
|
14903
|
+
const memberList = data.members.map((m) => `${m.displayName} (${m.isBot ? "bot" : "human"}${m.role === "owner" ? ", owner" : ""})`).join(", ");
|
|
14904
|
+
const lines = [
|
|
14905
|
+
"[Quiubo Group Context]",
|
|
14906
|
+
`Group: "${data.groupName}" (${data.groupId})`,
|
|
14907
|
+
`Type: ${data.groupType === "agent_channel" ? "agent channel" : data.groupType}`,
|
|
14908
|
+
`Members: ${memberList}`,
|
|
14909
|
+
`E2EE: ${data.e2ee ? "enabled" : "disabled"}`
|
|
14910
|
+
];
|
|
14911
|
+
if (data.scopes.length > 0) {
|
|
14912
|
+
lines.push(`Scopes: ${data.scopes.join(", ")}`);
|
|
14913
|
+
}
|
|
14914
|
+
return lines.join("\n");
|
|
14915
|
+
}
|
|
14916
|
+
function registerGroupContextHook(api) {
|
|
14917
|
+
api.registerHook(
|
|
14918
|
+
"before_prompt_build",
|
|
14919
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
14920
|
+
async (_event, ctx) => {
|
|
14921
|
+
if (ctx.channelId !== "quiubo") return;
|
|
14922
|
+
try {
|
|
14923
|
+
const config = api.runtime?.config ?? api.config;
|
|
14924
|
+
const data = await fetchGroupContext(config, ctx.sessionKey);
|
|
14925
|
+
if (!data) return;
|
|
14926
|
+
return {
|
|
14927
|
+
prependSystemContext: formatContextBlock(data)
|
|
14928
|
+
};
|
|
14929
|
+
} catch (err) {
|
|
14930
|
+
console.warn(`[quiubo] group-context-hook failed: ${err}`);
|
|
14931
|
+
return;
|
|
14932
|
+
}
|
|
14933
|
+
},
|
|
14934
|
+
{ name: "quiubo-group-context" }
|
|
14935
|
+
);
|
|
14936
|
+
}
|
|
14937
|
+
|
|
14821
14938
|
// src/polling-gateway.ts
|
|
14822
14939
|
var PollingGateway = class {
|
|
14823
14940
|
client;
|
|
@@ -14966,6 +15083,7 @@ var plugin = {
|
|
|
14966
15083
|
setQuiuboRuntime(api.runtime);
|
|
14967
15084
|
api.registerChannel({ plugin: quiuboPlugin });
|
|
14968
15085
|
api.registerTool(createQuiuboPostToolFactory, { name: "quiubo_create_post" });
|
|
15086
|
+
registerGroupContextHook(api);
|
|
14969
15087
|
}
|
|
14970
15088
|
};
|
|
14971
15089
|
var index_default = plugin;
|