@dhf-openclaw/grix 0.4.13 → 0.4.15
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/index.js +155 -2
- package/package.json +1 -1
- package/skills/grix-group/SKILL.md +8 -4
package/dist/index.js
CHANGED
|
@@ -3570,6 +3570,87 @@ async function deliverAibotPayload(params) {
|
|
|
3570
3570
|
return { sent, firstMessageId };
|
|
3571
3571
|
}
|
|
3572
3572
|
|
|
3573
|
+
// src/group-semantics.ts
|
|
3574
|
+
function normalizeEventType(value) {
|
|
3575
|
+
return String(value ?? "").trim().toLowerCase();
|
|
3576
|
+
}
|
|
3577
|
+
function normalizeMentionUserIds(value) {
|
|
3578
|
+
if (!Array.isArray(value)) {
|
|
3579
|
+
return [];
|
|
3580
|
+
}
|
|
3581
|
+
const deduped = /* @__PURE__ */ new Set();
|
|
3582
|
+
for (const entry of value) {
|
|
3583
|
+
const normalized = String(entry ?? "").trim();
|
|
3584
|
+
if (normalized) {
|
|
3585
|
+
deduped.add(normalized);
|
|
3586
|
+
}
|
|
3587
|
+
}
|
|
3588
|
+
return [...deduped];
|
|
3589
|
+
}
|
|
3590
|
+
function resolveGrixInboundSemantics(event) {
|
|
3591
|
+
const eventType = normalizeEventType(event.event_type);
|
|
3592
|
+
const isGroup = Number(event.session_type ?? 0) === 2 || eventType.startsWith("group_");
|
|
3593
|
+
const mentionUserIds = normalizeMentionUserIds(event.mention_user_ids);
|
|
3594
|
+
const hasAnyMention = mentionUserIds.length > 0;
|
|
3595
|
+
const wasMentioned = isGroup && eventType === "group_mention";
|
|
3596
|
+
const mentionsOther = isGroup && hasAnyMention && !wasMentioned;
|
|
3597
|
+
const mustReply = wasMentioned;
|
|
3598
|
+
const allowSilent = isGroup && !mustReply;
|
|
3599
|
+
const allowActions = !isGroup || mustReply;
|
|
3600
|
+
return {
|
|
3601
|
+
isGroup,
|
|
3602
|
+
eventType,
|
|
3603
|
+
wasMentioned,
|
|
3604
|
+
hasAnyMention,
|
|
3605
|
+
mentionsOther,
|
|
3606
|
+
mentionUserIds,
|
|
3607
|
+
mustReply,
|
|
3608
|
+
allowSilent,
|
|
3609
|
+
allowActions
|
|
3610
|
+
};
|
|
3611
|
+
}
|
|
3612
|
+
function buildGrixGroupSystemPrompt(semantics) {
|
|
3613
|
+
if (!semantics.isGroup) {
|
|
3614
|
+
return void 0;
|
|
3615
|
+
}
|
|
3616
|
+
if (semantics.wasMentioned) {
|
|
3617
|
+
return [
|
|
3618
|
+
"This group turn explicitly targeted you.",
|
|
3619
|
+
"You must reply or take the requested action when appropriate.",
|
|
3620
|
+
"Do not return NO_REPLY for this turn."
|
|
3621
|
+
].join(" ");
|
|
3622
|
+
}
|
|
3623
|
+
if (semantics.mentionsOther) {
|
|
3624
|
+
return [
|
|
3625
|
+
"This group turn explicitly targeted someone else, not you.",
|
|
3626
|
+
"You may reply only if you add clear value.",
|
|
3627
|
+
"Otherwise return NO_REPLY.",
|
|
3628
|
+
"Do not take action unless the task is clearly yours."
|
|
3629
|
+
].join(" ");
|
|
3630
|
+
}
|
|
3631
|
+
return [
|
|
3632
|
+
"This group turn is visible context, not an explicit mention for you.",
|
|
3633
|
+
"Reply only if it clearly helps the conversation.",
|
|
3634
|
+
"Otherwise return NO_REPLY.",
|
|
3635
|
+
"Do not take action unless the task is clearly yours."
|
|
3636
|
+
].join(" ");
|
|
3637
|
+
}
|
|
3638
|
+
function resolveGrixMentionFallbackText() {
|
|
3639
|
+
return "I'm here.";
|
|
3640
|
+
}
|
|
3641
|
+
function resolveGrixDispatchResolution(params) {
|
|
3642
|
+
if (params.visibleOutputSent || params.eventResultReported) {
|
|
3643
|
+
return {
|
|
3644
|
+
shouldCompleteSilently: false,
|
|
3645
|
+
shouldSendMentionFallback: false
|
|
3646
|
+
};
|
|
3647
|
+
}
|
|
3648
|
+
return {
|
|
3649
|
+
shouldCompleteSilently: params.semantics.allowSilent,
|
|
3650
|
+
shouldSendMentionFallback: params.semantics.mustReply
|
|
3651
|
+
};
|
|
3652
|
+
}
|
|
3653
|
+
|
|
3573
3654
|
// src/monitor.ts
|
|
3574
3655
|
var activeMonitorClients = /* @__PURE__ */ new Map();
|
|
3575
3656
|
function registerActiveMonitor(accountId, client) {
|
|
@@ -3847,8 +3928,10 @@ async function processEvent(params) {
|
|
|
3847
3928
|
const quotedMessageId = normalizeNumericMessageId(event.quoted_message_id);
|
|
3848
3929
|
const bodyForAgent = buildBodyWithQuotedReplyId(rawBody, quotedMessageId);
|
|
3849
3930
|
const senderId = toStringId2(event.sender_id);
|
|
3850
|
-
const
|
|
3931
|
+
const semantics = resolveGrixInboundSemantics(event);
|
|
3932
|
+
const isGroup = semantics.isGroup;
|
|
3851
3933
|
const chatType = isGroup ? "group" : "direct";
|
|
3934
|
+
const groupSystemPrompt = buildGrixGroupSystemPrompt(semantics);
|
|
3852
3935
|
const createdAt = toTimestampMs(event.created_at);
|
|
3853
3936
|
const baseLogContext = buildEventLogContext({
|
|
3854
3937
|
eventId,
|
|
@@ -3884,7 +3967,7 @@ async function processEvent(params) {
|
|
|
3884
3967
|
return;
|
|
3885
3968
|
}
|
|
3886
3969
|
runtime2.log(
|
|
3887
|
-
`[grix:${account.accountId}] inbound event ${baseLogContext} chatType=${chatType} bodyLen=${rawBody.length} quotedMessageId=${quotedMessageId || "-"}`
|
|
3970
|
+
`[grix:${account.accountId}] inbound event ${baseLogContext} chatType=${chatType} eventType=${semantics.eventType || "-"} wasMentioned=${semantics.wasMentioned ? "true" : "false"} mentionsOther=${semantics.mentionsOther ? "true" : "false"} bodyLen=${rawBody.length} quotedMessageId=${quotedMessageId || "-"}`
|
|
3888
3971
|
);
|
|
3889
3972
|
let inboundEventAccepted = false;
|
|
3890
3973
|
const commandOutcome = await handleExecApprovalCommand({
|
|
@@ -3994,6 +4077,7 @@ async function processEvent(params) {
|
|
|
3994
4077
|
SessionKey: route.sessionKey,
|
|
3995
4078
|
AccountId: route.accountId,
|
|
3996
4079
|
ChatType: chatType,
|
|
4080
|
+
GroupSystemPrompt: groupSystemPrompt,
|
|
3997
4081
|
ConversationLabel: fromLabel,
|
|
3998
4082
|
SenderName: senderId || void 0,
|
|
3999
4083
|
SenderId: senderId || void 0,
|
|
@@ -4004,6 +4088,7 @@ async function processEvent(params) {
|
|
|
4004
4088
|
// This field carries the inbound quoted message id from end user (event.quoted_message_id).
|
|
4005
4089
|
// It is not the outbound reply anchor used when plugin sends replies back to Aibot.
|
|
4006
4090
|
ReplyToMessageSid: quotedMessageId,
|
|
4091
|
+
WasMentioned: isGroup ? semantics.wasMentioned : void 0,
|
|
4007
4092
|
OriginatingChannel: "grix",
|
|
4008
4093
|
OriginatingTo: to
|
|
4009
4094
|
});
|
|
@@ -4357,6 +4442,49 @@ async function processEvent(params) {
|
|
|
4357
4442
|
markVisibleOutputSent();
|
|
4358
4443
|
}
|
|
4359
4444
|
}
|
|
4445
|
+
const dispatchResolution = resolveGrixDispatchResolution({
|
|
4446
|
+
semantics,
|
|
4447
|
+
visibleOutputSent,
|
|
4448
|
+
eventResultReported
|
|
4449
|
+
});
|
|
4450
|
+
if (dispatchResolution.shouldCompleteSilently) {
|
|
4451
|
+
runtime2.log(
|
|
4452
|
+
`[grix:${account.accountId}] group dispatch completed silently ${baseLogContext} attempt=${attemptLabel} wasMentioned=${semantics.wasMentioned ? "true" : "false"}`
|
|
4453
|
+
);
|
|
4454
|
+
reportEventResult("responded");
|
|
4455
|
+
}
|
|
4456
|
+
if (dispatchResolution.shouldSendMentionFallback) {
|
|
4457
|
+
outboundCounter++;
|
|
4458
|
+
const stableClientMsgId = `reply_${messageSid}_${outboundCounter}`;
|
|
4459
|
+
runtime2.log(
|
|
4460
|
+
`[grix:${account.accountId}] explicit mention fallback reply ${buildEventLogContext({
|
|
4461
|
+
eventId,
|
|
4462
|
+
sessionId,
|
|
4463
|
+
messageSid,
|
|
4464
|
+
clientMsgId: stableClientMsgId,
|
|
4465
|
+
outboundCounter
|
|
4466
|
+
})}`
|
|
4467
|
+
);
|
|
4468
|
+
const didSendFallback = await deliverAibotMessage({
|
|
4469
|
+
payload: {
|
|
4470
|
+
text: resolveGrixMentionFallbackText()
|
|
4471
|
+
},
|
|
4472
|
+
client,
|
|
4473
|
+
account,
|
|
4474
|
+
sessionId,
|
|
4475
|
+
abortSignal: runAbortController.signal,
|
|
4476
|
+
eventId,
|
|
4477
|
+
quotedMessageId: outboundQuotedMessageId,
|
|
4478
|
+
runtime: runtime2,
|
|
4479
|
+
statusSink,
|
|
4480
|
+
stableClientMsgId,
|
|
4481
|
+
tableMode
|
|
4482
|
+
});
|
|
4483
|
+
attemptHasOutbound = attemptHasOutbound || didSendFallback;
|
|
4484
|
+
if (didSendFallback) {
|
|
4485
|
+
markVisibleOutputSent();
|
|
4486
|
+
}
|
|
4487
|
+
}
|
|
4360
4488
|
break;
|
|
4361
4489
|
}
|
|
4362
4490
|
if (!visibleOutputSent && !eventResultReported) {
|
|
@@ -4579,6 +4707,26 @@ function applySetupAccountConfig(params) {
|
|
|
4579
4707
|
};
|
|
4580
4708
|
}
|
|
4581
4709
|
|
|
4710
|
+
// src/group-adapter.ts
|
|
4711
|
+
function resolveGrixGroupRequireMention() {
|
|
4712
|
+
return false;
|
|
4713
|
+
}
|
|
4714
|
+
function resolveGrixGroupIntroHint() {
|
|
4715
|
+
return [
|
|
4716
|
+
"All Grix group messages are visible to you.",
|
|
4717
|
+
"If WasMentioned is true, you are the primary addressee and should respond.",
|
|
4718
|
+
"If WasMentioned is false, reply only when you add clear value; otherwise use NO_REPLY."
|
|
4719
|
+
].join(" ");
|
|
4720
|
+
}
|
|
4721
|
+
|
|
4722
|
+
// src/group-tool-policy.ts
|
|
4723
|
+
var GROUP_DEFAULT_DENY = ["message"];
|
|
4724
|
+
function resolveGrixGroupToolPolicy() {
|
|
4725
|
+
return {
|
|
4726
|
+
deny: [...GROUP_DEFAULT_DENY]
|
|
4727
|
+
};
|
|
4728
|
+
}
|
|
4729
|
+
|
|
4582
4730
|
// src/channel.ts
|
|
4583
4731
|
var meta = {
|
|
4584
4732
|
id: "grix",
|
|
@@ -4795,6 +4943,11 @@ var aibotPlugin = {
|
|
|
4795
4943
|
hasRepliedRef
|
|
4796
4944
|
})
|
|
4797
4945
|
},
|
|
4946
|
+
groups: {
|
|
4947
|
+
resolveRequireMention: () => resolveGrixGroupRequireMention(),
|
|
4948
|
+
resolveGroupIntroHint: () => resolveGrixGroupIntroHint(),
|
|
4949
|
+
resolveToolPolicy: () => resolveGrixGroupToolPolicy()
|
|
4950
|
+
},
|
|
4798
4951
|
agentPrompt: {
|
|
4799
4952
|
messageToolHints: () => [
|
|
4800
4953
|
"- Grix `action=unsend` is a silent cleanup action: unsend the target `messageId`, unsend the recall command message when applicable, then end with `NO_REPLY` and do not send any confirmation text. Omit `sessionId`/`to` only when targeting the current Grix chat."
|
package/package.json
CHANGED
|
@@ -77,10 +77,13 @@ Required input:
|
|
|
77
77
|
|
|
78
78
|
Guardrails:
|
|
79
79
|
|
|
80
|
-
1.
|
|
81
|
-
2.
|
|
82
|
-
3.
|
|
83
|
-
4.
|
|
80
|
+
1. Only the current Agent owner can request this action.
|
|
81
|
+
2. If the requester is not the current Agent owner, reject the request directly and do not call `grix_group`.
|
|
82
|
+
3. This action is only for the current Agent leaving its own group membership.
|
|
83
|
+
4. Never translate a request to remove other members into `leave`; use `remove_members` for that.
|
|
84
|
+
5. Do not send `memberId`, `memberIds`, or `memberTypes` with this action.
|
|
85
|
+
6. This action does not require scope and should not be described as a scope-grant workflow.
|
|
86
|
+
7. Execute `leave` silently: do not send any pre-leave or farewell message to the group before leaving.
|
|
84
87
|
|
|
85
88
|
### remove_members
|
|
86
89
|
|
|
@@ -154,6 +157,7 @@ Required input:
|
|
|
154
157
|
2. Include key identifiers (`session_id`, member count, mute state) when successful.
|
|
155
158
|
3. Include exact remediation when failed.
|
|
156
159
|
4. Never hide scope or auth errors behind generic wording.
|
|
160
|
+
5. For `leave`, report result to the requester only; do not post extra messages into the group session.
|
|
157
161
|
|
|
158
162
|
## References
|
|
159
163
|
|