@mininglamp-oss/cc-channel-octo 1.0.3-dev.4ca07a0 → 1.0.3-dev.4edf363
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/config.bot.example.json +2 -1
- package/config.example.json +6 -1
- package/dist/agent-bridge.js +18 -6
- package/dist/agent-bridge.js.map +1 -1
- package/dist/config.d.ts +52 -0
- package/dist/config.js +6 -0
- package/dist/config.js.map +1 -1
- package/dist/group-context.d.ts +18 -0
- package/dist/group-context.js +77 -6
- package/dist/group-context.js.map +1 -1
- package/dist/group-md-cache.d.ts +50 -0
- package/dist/group-md-cache.js +79 -0
- package/dist/group-md-cache.js.map +1 -1
- package/dist/group-md-events.d.ts +36 -4
- package/dist/group-md-events.js +36 -5
- package/dist/group-md-events.js.map +1 -1
- package/dist/group-md-tool.d.ts +80 -0
- package/dist/group-md-tool.js +181 -0
- package/dist/group-md-tool.js.map +1 -0
- package/dist/group-md-writeback.d.ts +183 -0
- package/dist/group-md-writeback.js +223 -0
- package/dist/group-md-writeback.js.map +1 -0
- package/dist/group-md.d.ts +47 -24
- package/dist/group-md.js +112 -23
- package/dist/group-md.js.map +1 -1
- package/dist/index.d.ts +3 -2
- package/dist/index.js +112 -17
- package/dist/index.js.map +1 -1
- package/dist/octo/api.d.ts +59 -0
- package/dist/octo/api.js +53 -0
- package/dist/octo/api.js.map +1 -1
- package/dist/prompt-safety.d.ts +20 -0
- package/dist/prompt-safety.js +24 -0
- package/dist/prompt-safety.js.map +1 -1
- package/dist/session-router.d.ts +30 -2
- package/dist/session-router.js +72 -9
- package/dist/session-router.js.map +1 -1
- package/package.json +1 -1
package/dist/group-md-cache.js
CHANGED
|
@@ -90,4 +90,83 @@ export class GroupMdCache {
|
|
|
90
90
|
this.mem.delete(groupNo);
|
|
91
91
|
}
|
|
92
92
|
}
|
|
93
|
+
/**
|
|
94
|
+
* THREAD.md server cache (P3-1) — IN-MEMORY ONLY, with a TTL.
|
|
95
|
+
*
|
|
96
|
+
* The thread analogue of {@link GroupMdCache}. Holds server-fetched THREAD.md
|
|
97
|
+
* for a CommunityTopic thread. Same memory-only security model as the group
|
|
98
|
+
* cache (see the module SECURITY note): the resolved THREAD.md is injected as a
|
|
99
|
+
* trusted system-prompt block, so it must never touch disk — the only path
|
|
100
|
+
* content can enter the trusted channel is a live, authenticated `getThreadMd`
|
|
101
|
+
* over the bot token against the SSRF-validated `apiUrl`.
|
|
102
|
+
*
|
|
103
|
+
* Keying — COMPOSITE `<groupNo>::<shortId>`, NOT the bare shortId. Octo's
|
|
104
|
+
* current shortId is a globally unique 19-digit snowflake, so a bare shortId
|
|
105
|
+
* would not collide across groups today; the composite key is defensive
|
|
106
|
+
* double-insurance so that even if a future shortId scheme becomes a
|
|
107
|
+
* per-parent-group sequence, one group's THREAD.md can never be served for a
|
|
108
|
+
* same-shortId thread under a different parent group. `::` is intentionally
|
|
109
|
+
* outside the safe-id charset, so it can never appear inside a validated
|
|
110
|
+
* component and cannot be forged to cross a key boundary.
|
|
111
|
+
*
|
|
112
|
+
* Never throws.
|
|
113
|
+
*/
|
|
114
|
+
export class ThreadMdCache {
|
|
115
|
+
mem = new Map();
|
|
116
|
+
ttlMs;
|
|
117
|
+
now;
|
|
118
|
+
/**
|
|
119
|
+
* @param ttlMs staleness backstop in ms (entry expires this long after it was
|
|
120
|
+
* stored). Defaults to {@link DEFAULT_GROUP_MD_TTL_MS} — the thread cache
|
|
121
|
+
* shares the group cache's staleness policy. A non-positive value disables
|
|
122
|
+
* expiry (entries live until invalidate()).
|
|
123
|
+
* @param now injectable clock (testing); defaults to Date.now.
|
|
124
|
+
*/
|
|
125
|
+
constructor(ttlMs = DEFAULT_GROUP_MD_TTL_MS, now = () => Date.now()) {
|
|
126
|
+
this.ttlMs = ttlMs;
|
|
127
|
+
this.now = now;
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Build the composite Map key, or null if either component is unsafe. Both
|
|
131
|
+
* halves are validated with the same isSafeGroupNo rule the group cache uses,
|
|
132
|
+
* and neither can contain `::` (colon is outside the charset), so the
|
|
133
|
+
* separator is unambiguous.
|
|
134
|
+
*/
|
|
135
|
+
key(groupNo, shortId) {
|
|
136
|
+
if (!isSafeGroupNo(groupNo) || !isSafeGroupNo(shortId))
|
|
137
|
+
return null;
|
|
138
|
+
return `${groupNo}::${shortId}`;
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Read a cached entry from memory. Returns undefined on a miss, an expired
|
|
142
|
+
* entry (which is also evicted), or an unsafe groupNo/shortId.
|
|
143
|
+
*/
|
|
144
|
+
get(groupNo, shortId) {
|
|
145
|
+
const k = this.key(groupNo, shortId);
|
|
146
|
+
if (k === null)
|
|
147
|
+
return undefined;
|
|
148
|
+
const stored = this.mem.get(k);
|
|
149
|
+
if (!stored)
|
|
150
|
+
return undefined;
|
|
151
|
+
if (this.ttlMs > 0 && this.now() - stored.storedAt >= this.ttlMs) {
|
|
152
|
+
this.mem.delete(k);
|
|
153
|
+
return undefined;
|
|
154
|
+
}
|
|
155
|
+
return stored.entry;
|
|
156
|
+
}
|
|
157
|
+
/** Store an entry in memory, stamping it for TTL expiry. */
|
|
158
|
+
set(groupNo, shortId, entry) {
|
|
159
|
+
const k = this.key(groupNo, shortId);
|
|
160
|
+
if (k === null)
|
|
161
|
+
return;
|
|
162
|
+
this.mem.set(k, { entry, storedAt: this.now() });
|
|
163
|
+
}
|
|
164
|
+
/** Drop a cached entry (event-driven refresh hook, symmetric to GroupMdCache). */
|
|
165
|
+
invalidate(groupNo, shortId) {
|
|
166
|
+
const k = this.key(groupNo, shortId);
|
|
167
|
+
if (k === null)
|
|
168
|
+
return;
|
|
169
|
+
this.mem.delete(k);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
93
172
|
//# sourceMappingURL=group-md-cache.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"group-md-cache.js","sourceRoot":"","sources":["../src/group-md-cache.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AAUH,+EAA+E;AAC/E,MAAM,CAAC,MAAM,uBAAuB,GAAG,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,YAAY;AAElE;;;;GAIG;AACH,SAAS,aAAa,CAAC,OAAe;IACpC,OAAO,mBAAmB,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,OAAO,KAAK,GAAG,IAAI,OAAO,KAAK,IAAI,CAAC;AAClF,CAAC;AAOD,MAAM,OAAO,YAAY;IACN,GAAG,GAAG,IAAI,GAAG,EAAuB,CAAC;IACrC,KAAK,CAAS;IACd,GAAG,CAAe;IAEnC;;;;;OAKG;IACH,YAAY,QAAgB,uBAAuB,EAAE,MAAoB,GAAG,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE;QACvF,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACnB,IAAI,CAAC,GAAG,GAAG,GAAG,CAAC;IACjB,CAAC;IAED;;;OAGG;IACH,GAAG,CAAC,OAAe;QACjB,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC;YAAE,OAAO,SAAS,CAAC;QAC9C,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QACrC,IAAI,CAAC,MAAM;YAAE,OAAO,SAAS,CAAC;QAC9B,IAAI,IAAI,CAAC,KAAK,GAAG,CAAC,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,MAAM,CAAC,QAAQ,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YACjE,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;YACzB,OAAO,SAAS,CAAC;QACnB,CAAC;QACD,OAAO,MAAM,CAAC,KAAK,CAAC;IACtB,CAAC;IAED,4DAA4D;IAC5D,GAAG,CAAC,OAAe,EAAE,KAAmB;QACtC,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC;YAAE,OAAO;QACpC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;IACzD,CAAC;IAED;;;OAGG;IACH,UAAU,CAAC,OAAe;QACxB,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC;YAAE,OAAO;QACpC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAC3B,CAAC;CACF"}
|
|
1
|
+
{"version":3,"file":"group-md-cache.js","sourceRoot":"","sources":["../src/group-md-cache.ts"],"names":[],"mappings":"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"}
|
|
@@ -27,6 +27,11 @@
|
|
|
27
27
|
/**
|
|
28
28
|
* Provisional `event.type` literals treated as a GROUP.md change. PROVISIONAL —
|
|
29
29
|
* see the calibration note above. Overridable via `config.serverMdEventTypes`.
|
|
30
|
+
*
|
|
31
|
+
* Both an UPDATE and a DELETE of the server GROUP.md drive the same action —
|
|
32
|
+
* INVALIDATE the cached entry so the next turn re-fetches (an updated entry is
|
|
33
|
+
* re-read; a deleted one 404s and cleanly degrades to the local fallback), so
|
|
34
|
+
* `group_md_deleted` sits alongside `group_md_updated` here (P3-2 deleted tail).
|
|
30
35
|
*/
|
|
31
36
|
export declare const DEFAULT_GROUP_MD_EVENT_TYPES: readonly string[];
|
|
32
37
|
/** The `payload.event` shape (mirrors MessagePayload.event in octo/types.ts). */
|
|
@@ -35,9 +40,36 @@ export interface GroupMdEventLike {
|
|
|
35
40
|
group_no?: string;
|
|
36
41
|
}
|
|
37
42
|
/**
|
|
38
|
-
* True iff this event signals a GROUP.md change
|
|
39
|
-
* refresh. All other system events (group join/leave, etc.) return
|
|
40
|
-
* are dropped unchanged by the router. `eventTypes` lets the operator
|
|
41
|
-
* the provisional literal(s) without a code change.
|
|
43
|
+
* True iff this event signals a GROUP.md change (update or delete) and should
|
|
44
|
+
* drive a cache refresh. All other system events (group join/leave, etc.) return
|
|
45
|
+
* false and are dropped unchanged by the router. `eventTypes` lets the operator
|
|
46
|
+
* override the provisional literal(s) without a code change.
|
|
42
47
|
*/
|
|
43
48
|
export declare function isGroupMdUpdateEvent(event: GroupMdEventLike | undefined, eventTypes?: readonly string[]): boolean;
|
|
49
|
+
/**
|
|
50
|
+
* Provisional `event.type` literals treated as a THREAD.md change (P3-2). Same
|
|
51
|
+
* PROVISIONAL status as the group literals above — the exact wire literal is not
|
|
52
|
+
* yet confirmed from a captured event, so it is named after the design and is
|
|
53
|
+
* overridable via `config.threadMdEventTypes` without a code change. As on the
|
|
54
|
+
* group side, both update and delete map to the same invalidate action.
|
|
55
|
+
*/
|
|
56
|
+
export declare const DEFAULT_THREAD_MD_EVENT_TYPES: readonly string[];
|
|
57
|
+
/**
|
|
58
|
+
* The `payload.event` shape for a THREAD.md change — like {@link GroupMdEventLike}
|
|
59
|
+
* but also carrying `short_id`, which locates the subarea whose composite-keyed
|
|
60
|
+
* (`groupNo::shortId`) cache entry to invalidate. `short_id` is already part of
|
|
61
|
+
* MessagePayload.event (octo/types.ts).
|
|
62
|
+
*/
|
|
63
|
+
export interface ThreadMdEventLike {
|
|
64
|
+
type?: string;
|
|
65
|
+
group_no?: string;
|
|
66
|
+
short_id?: string;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* True iff this event signals a THREAD.md change (update or delete). The literal
|
|
70
|
+
* sets for group vs thread are DISJOINT (`group_md_*` vs `thread_md_*`), so a
|
|
71
|
+
* thread event never trips the group invalidation and vice versa — the two
|
|
72
|
+
* classifiers stay mutually exclusive, matching the read/write mutual-exclusion
|
|
73
|
+
* contract of #88 P3.
|
|
74
|
+
*/
|
|
75
|
+
export declare function isThreadMdUpdateEvent(event: ThreadMdEventLike | undefined, eventTypes?: readonly string[]): boolean;
|
package/dist/group-md-events.js
CHANGED
|
@@ -27,17 +27,48 @@
|
|
|
27
27
|
/**
|
|
28
28
|
* Provisional `event.type` literals treated as a GROUP.md change. PROVISIONAL —
|
|
29
29
|
* see the calibration note above. Overridable via `config.serverMdEventTypes`.
|
|
30
|
+
*
|
|
31
|
+
* Both an UPDATE and a DELETE of the server GROUP.md drive the same action —
|
|
32
|
+
* INVALIDATE the cached entry so the next turn re-fetches (an updated entry is
|
|
33
|
+
* re-read; a deleted one 404s and cleanly degrades to the local fallback), so
|
|
34
|
+
* `group_md_deleted` sits alongside `group_md_updated` here (P3-2 deleted tail).
|
|
30
35
|
*/
|
|
31
|
-
export const DEFAULT_GROUP_MD_EVENT_TYPES = [
|
|
36
|
+
export const DEFAULT_GROUP_MD_EVENT_TYPES = [
|
|
37
|
+
'group_md_updated',
|
|
38
|
+
'group_md_deleted',
|
|
39
|
+
];
|
|
32
40
|
/**
|
|
33
|
-
* True iff this event signals a GROUP.md change
|
|
34
|
-
* refresh. All other system events (group join/leave, etc.) return
|
|
35
|
-
* are dropped unchanged by the router. `eventTypes` lets the operator
|
|
36
|
-
* the provisional literal(s) without a code change.
|
|
41
|
+
* True iff this event signals a GROUP.md change (update or delete) and should
|
|
42
|
+
* drive a cache refresh. All other system events (group join/leave, etc.) return
|
|
43
|
+
* false and are dropped unchanged by the router. `eventTypes` lets the operator
|
|
44
|
+
* override the provisional literal(s) without a code change.
|
|
37
45
|
*/
|
|
38
46
|
export function isGroupMdUpdateEvent(event, eventTypes = DEFAULT_GROUP_MD_EVENT_TYPES) {
|
|
39
47
|
if (!event || typeof event.type !== 'string' || event.type === '')
|
|
40
48
|
return false;
|
|
41
49
|
return eventTypes.includes(event.type);
|
|
42
50
|
}
|
|
51
|
+
/**
|
|
52
|
+
* Provisional `event.type` literals treated as a THREAD.md change (P3-2). Same
|
|
53
|
+
* PROVISIONAL status as the group literals above — the exact wire literal is not
|
|
54
|
+
* yet confirmed from a captured event, so it is named after the design and is
|
|
55
|
+
* overridable via `config.threadMdEventTypes` without a code change. As on the
|
|
56
|
+
* group side, both update and delete map to the same invalidate action.
|
|
57
|
+
*/
|
|
58
|
+
export const DEFAULT_THREAD_MD_EVENT_TYPES = [
|
|
59
|
+
'thread_md_updated',
|
|
60
|
+
'thread_md_deleted',
|
|
61
|
+
];
|
|
62
|
+
/**
|
|
63
|
+
* True iff this event signals a THREAD.md change (update or delete). The literal
|
|
64
|
+
* sets for group vs thread are DISJOINT (`group_md_*` vs `thread_md_*`), so a
|
|
65
|
+
* thread event never trips the group invalidation and vice versa — the two
|
|
66
|
+
* classifiers stay mutually exclusive, matching the read/write mutual-exclusion
|
|
67
|
+
* contract of #88 P3.
|
|
68
|
+
*/
|
|
69
|
+
export function isThreadMdUpdateEvent(event, eventTypes = DEFAULT_THREAD_MD_EVENT_TYPES) {
|
|
70
|
+
if (!event || typeof event.type !== 'string' || event.type === '')
|
|
71
|
+
return false;
|
|
72
|
+
return eventTypes.includes(event.type);
|
|
73
|
+
}
|
|
43
74
|
//# sourceMappingURL=group-md-events.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"group-md-events.js","sourceRoot":"","sources":["../src/group-md-events.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH
|
|
1
|
+
{"version":3,"file":"group-md-events.js","sourceRoot":"","sources":["../src/group-md-events.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,4BAA4B,GAAsB;IAC7D,kBAAkB;IAClB,kBAAkB;CACnB,CAAC;AAQF;;;;;GAKG;AACH,MAAM,UAAU,oBAAoB,CAClC,KAAmC,EACnC,aAAgC,4BAA4B;IAE5D,IAAI,CAAC,KAAK,IAAI,OAAO,KAAK,CAAC,IAAI,KAAK,QAAQ,IAAI,KAAK,CAAC,IAAI,KAAK,EAAE;QAAE,OAAO,KAAK,CAAC;IAChF,OAAO,UAAU,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;AACzC,CAAC;AAED;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,6BAA6B,GAAsB;IAC9D,mBAAmB;IACnB,mBAAmB;CACpB,CAAC;AAcF;;;;;;GAMG;AACH,MAAM,UAAU,qBAAqB,CACnC,KAAoC,EACpC,aAAgC,6BAA6B;IAE7D,IAAI,CAAC,KAAK,IAAI,OAAO,KAAK,CAAC,IAAI,KAAK,QAAQ,IAAI,KAAK,CAAC,IAAI,KAAK,EAAE;QAAE,OAAO,KAAK,CAAC;IAChF,OAAO,UAAU,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;AACzC,CAAC"}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* P2-C: GROUP.md write-back tool — an in-process MCP server letting the agent
|
|
3
|
+
* persist an updated GROUP.md back to the server. The tool surfaces to the model
|
|
4
|
+
* as `mcp__group_md__update_group_md`.
|
|
5
|
+
*
|
|
6
|
+
* The server is built PER TURN (`createGroupMdToolServer`) with the current
|
|
7
|
+
* message's channel coords + the bot owner uid, so:
|
|
8
|
+
* - the write targets the PARENT group of the channel the agent is in
|
|
9
|
+
* (`extractParentGroupNo` — a thread shares its parent group's GROUP.md);
|
|
10
|
+
* - invocation is GATED to the bot owner (registerBot.owner_uid). The group's
|
|
11
|
+
* octo_tag token has server-side write permission, but the agent is driven by
|
|
12
|
+
* untrusted IM users, so this owner gate — not LLM judgment, and independent
|
|
13
|
+
* of the token's group-role permission — is what stops a prompt-injected
|
|
14
|
+
* agent from rewriting the operator's trusted GROUP.md from any chat.
|
|
15
|
+
*
|
|
16
|
+
* Concurrency, the byte ceiling, and the cache refresh are owned by the shared
|
|
17
|
+
* {@link GroupMdWriteback} coordinator (group-md-writeback.ts); this layer is
|
|
18
|
+
* only the owner-gate policy + the MCP surface.
|
|
19
|
+
*/
|
|
20
|
+
import { z } from 'zod';
|
|
21
|
+
import { type GroupMdWriteback, type ThreadMdWriteback } from './group-md-writeback.js';
|
|
22
|
+
/** MCP server name; the tool surfaces as `mcp__group_md__update_group_md`. */
|
|
23
|
+
export declare const GROUP_MD_TOOL_SERVER_NAME = "group_md";
|
|
24
|
+
/** MCP server name; the tool surfaces as `mcp__thread_md__update_thread_md`. */
|
|
25
|
+
export declare const THREAD_MD_TOOL_SERVER_NAME = "thread_md";
|
|
26
|
+
/** Raw coords of the session invoking the tool — gates the call + targets the group. */
|
|
27
|
+
export interface GroupMdSessionCoords {
|
|
28
|
+
/** Full channelId (may be a `<groupNo>____<shortId>` thread composite). */
|
|
29
|
+
channelId: string;
|
|
30
|
+
fromUid: string;
|
|
31
|
+
fromName?: string;
|
|
32
|
+
}
|
|
33
|
+
/** Shared deps the tool needs to perform a write-back. */
|
|
34
|
+
export interface GroupMdToolDeps {
|
|
35
|
+
writeback: GroupMdWriteback;
|
|
36
|
+
apiUrl: string;
|
|
37
|
+
botToken: string;
|
|
38
|
+
}
|
|
39
|
+
/** Shared deps the thread write-back tool needs. */
|
|
40
|
+
export interface ThreadMdToolDeps {
|
|
41
|
+
writeback: ThreadMdWriteback;
|
|
42
|
+
apiUrl: string;
|
|
43
|
+
botToken: string;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Build the GROUP.md tool DEFINITIONS for one agent turn. Exported separately
|
|
47
|
+
* from the server so tests can invoke the handler directly. `coords` targets the
|
|
48
|
+
* group + supplies the caller uid; `ownerUid` is the owner gate.
|
|
49
|
+
*/
|
|
50
|
+
export declare function buildGroupMdTools(deps: GroupMdToolDeps, coords: GroupMdSessionCoords, ownerUid: string): import("@anthropic-ai/claude-agent-sdk").SdkMcpToolDefinition<{
|
|
51
|
+
content: z.ZodString;
|
|
52
|
+
}>[];
|
|
53
|
+
/**
|
|
54
|
+
* Build the GROUP.md write-back MCP server for one agent turn. `coords` targets
|
|
55
|
+
* the group + supplies the caller uid; `ownerUid` is the owner gate.
|
|
56
|
+
*/
|
|
57
|
+
export declare function createGroupMdToolServer(deps: GroupMdToolDeps, coords: GroupMdSessionCoords, ownerUid: string): import("@anthropic-ai/claude-agent-sdk").McpSdkServerConfigWithInstance;
|
|
58
|
+
/**
|
|
59
|
+
* Build the THREAD.md tool DEFINITIONS for one agent turn (P3-2). The thread
|
|
60
|
+
* analogue of {@link buildGroupMdTools}: the tool surfaces as
|
|
61
|
+
* `mcp__thread_md__update_thread_md` and writes THIS thread's OWN THREAD.md
|
|
62
|
+
* (PUT /v1/bot/groups/{groupNo}/threads/{shortId}/md), NEVER the parent group's
|
|
63
|
+
* GROUP.md — the thread/group split is mutually exclusive (#88 P3).
|
|
64
|
+
* index.ts only ever wires the group tool OR this thread tool for a turn (chosen
|
|
65
|
+
* by channelId shape), so the two never co-exist in one session.
|
|
66
|
+
*
|
|
67
|
+
* `coords.channelId` MUST be a thread composite (`<groupNo>____<shortId>`); the
|
|
68
|
+
* caller (index.ts) guarantees this by routing on `isThreadChannelId`. The
|
|
69
|
+
* owner-gate is identical to the group tool (bot-owner-only, independent of the
|
|
70
|
+
* token's server-side thread permission).
|
|
71
|
+
*/
|
|
72
|
+
export declare function buildThreadMdTools(deps: ThreadMdToolDeps, coords: GroupMdSessionCoords, ownerUid: string): import("@anthropic-ai/claude-agent-sdk").SdkMcpToolDefinition<{
|
|
73
|
+
content: z.ZodString;
|
|
74
|
+
}>[];
|
|
75
|
+
/**
|
|
76
|
+
* Build the THREAD.md write-back MCP server for one agent turn. `coords` targets
|
|
77
|
+
* the thread (its composite channelId) + supplies the caller uid; `ownerUid` is
|
|
78
|
+
* the owner gate.
|
|
79
|
+
*/
|
|
80
|
+
export declare function createThreadMdToolServer(deps: ThreadMdToolDeps, coords: GroupMdSessionCoords, ownerUid: string): import("@anthropic-ai/claude-agent-sdk").McpSdkServerConfigWithInstance;
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* P2-C: GROUP.md write-back tool — an in-process MCP server letting the agent
|
|
3
|
+
* persist an updated GROUP.md back to the server. The tool surfaces to the model
|
|
4
|
+
* as `mcp__group_md__update_group_md`.
|
|
5
|
+
*
|
|
6
|
+
* The server is built PER TURN (`createGroupMdToolServer`) with the current
|
|
7
|
+
* message's channel coords + the bot owner uid, so:
|
|
8
|
+
* - the write targets the PARENT group of the channel the agent is in
|
|
9
|
+
* (`extractParentGroupNo` — a thread shares its parent group's GROUP.md);
|
|
10
|
+
* - invocation is GATED to the bot owner (registerBot.owner_uid). The group's
|
|
11
|
+
* octo_tag token has server-side write permission, but the agent is driven by
|
|
12
|
+
* untrusted IM users, so this owner gate — not LLM judgment, and independent
|
|
13
|
+
* of the token's group-role permission — is what stops a prompt-injected
|
|
14
|
+
* agent from rewriting the operator's trusted GROUP.md from any chat.
|
|
15
|
+
*
|
|
16
|
+
* Concurrency, the byte ceiling, and the cache refresh are owned by the shared
|
|
17
|
+
* {@link GroupMdWriteback} coordinator (group-md-writeback.ts); this layer is
|
|
18
|
+
* only the owner-gate policy + the MCP surface.
|
|
19
|
+
*/
|
|
20
|
+
import { z } from 'zod';
|
|
21
|
+
import { createSdkMcpServer, tool } from '@anthropic-ai/claude-agent-sdk';
|
|
22
|
+
import { extractParentGroupNo, extractThreadShortId, isThreadChannelId, } from './octo/channel-id.js';
|
|
23
|
+
import { GroupMdContentTooLargeError, MAX_GROUP_MD_CONTENT_BYTES, ThreadMdContentTooLargeError, MAX_THREAD_MD_CONTENT_BYTES, } from './group-md-writeback.js';
|
|
24
|
+
/** MCP server name; the tool surfaces as `mcp__group_md__update_group_md`. */
|
|
25
|
+
export const GROUP_MD_TOOL_SERVER_NAME = 'group_md';
|
|
26
|
+
/** MCP server name; the tool surfaces as `mcp__thread_md__update_thread_md`. */
|
|
27
|
+
export const THREAD_MD_TOOL_SERVER_NAME = 'thread_md';
|
|
28
|
+
function jsonResult(value) {
|
|
29
|
+
return { content: [{ type: 'text', text: JSON.stringify(value, null, 2) }] };
|
|
30
|
+
}
|
|
31
|
+
function errResult(msg) {
|
|
32
|
+
return { content: [{ type: 'text', text: `Error: ${msg}` }], isError: true };
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Build the GROUP.md tool DEFINITIONS for one agent turn. Exported separately
|
|
36
|
+
* from the server so tests can invoke the handler directly. `coords` targets the
|
|
37
|
+
* group + supplies the caller uid; `ownerUid` is the owner gate.
|
|
38
|
+
*/
|
|
39
|
+
export function buildGroupMdTools(deps, coords, ownerUid) {
|
|
40
|
+
const isOwner = coords.fromUid === ownerUid && ownerUid !== '';
|
|
41
|
+
return [
|
|
42
|
+
tool('update_group_md', 'Persist new GROUP.md content for THIS group on the server (it becomes the ' +
|
|
43
|
+
"group's trusted operator instructions on the next turn). `content` is the " +
|
|
44
|
+
'FULL replacement document, not a diff. Hard limit: 10240 bytes UTF-8. Only ' +
|
|
45
|
+
'the bot owner may call this; a non-owner request is rejected. Last write ' +
|
|
46
|
+
'wins server-side — compose the complete updated document, do not assume a ' +
|
|
47
|
+
'concurrent edit merged.', {
|
|
48
|
+
content: z
|
|
49
|
+
.string()
|
|
50
|
+
.describe('Full replacement GROUP.md document (≤10240 bytes UTF-8).'),
|
|
51
|
+
}, async (args) => {
|
|
52
|
+
try {
|
|
53
|
+
if (!isOwner) {
|
|
54
|
+
return errResult('Only the bot owner can update GROUP.md.');
|
|
55
|
+
}
|
|
56
|
+
const groupNo = extractParentGroupNo(coords.channelId);
|
|
57
|
+
if (!groupNo) {
|
|
58
|
+
return errResult('Could not resolve a group number from this channel.');
|
|
59
|
+
}
|
|
60
|
+
// Surface a friendly over-limit message before the coordinator throws
|
|
61
|
+
// (it re-checks as the authoritative boundary; this is just for UX).
|
|
62
|
+
const bytes = Buffer.byteLength(args.content, 'utf-8');
|
|
63
|
+
if (bytes > MAX_GROUP_MD_CONTENT_BYTES) {
|
|
64
|
+
return errResult(`content is ${bytes} bytes, over the ${MAX_GROUP_MD_CONTENT_BYTES}-byte ` +
|
|
65
|
+
`UTF-8 limit — trim it before writing (the server would reject it).`);
|
|
66
|
+
}
|
|
67
|
+
const res = await deps.writeback.writeBack({
|
|
68
|
+
apiUrl: deps.apiUrl,
|
|
69
|
+
botToken: deps.botToken,
|
|
70
|
+
groupNo,
|
|
71
|
+
content: args.content,
|
|
72
|
+
});
|
|
73
|
+
return jsonResult({
|
|
74
|
+
updated: { groupNo: res.groupNo, version: res.version, bytes: res.bytes },
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
catch (err) {
|
|
78
|
+
if (err instanceof GroupMdContentTooLargeError) {
|
|
79
|
+
return errResult(`content is ${err.bytes} bytes, over the ${MAX_GROUP_MD_CONTENT_BYTES}-byte UTF-8 limit.`);
|
|
80
|
+
}
|
|
81
|
+
return errResult(err instanceof Error ? err.message : String(err));
|
|
82
|
+
}
|
|
83
|
+
}),
|
|
84
|
+
];
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Build the GROUP.md write-back MCP server for one agent turn. `coords` targets
|
|
88
|
+
* the group + supplies the caller uid; `ownerUid` is the owner gate.
|
|
89
|
+
*/
|
|
90
|
+
export function createGroupMdToolServer(deps, coords, ownerUid) {
|
|
91
|
+
return createSdkMcpServer({
|
|
92
|
+
name: GROUP_MD_TOOL_SERVER_NAME,
|
|
93
|
+
version: '1.0.0',
|
|
94
|
+
tools: buildGroupMdTools(deps, coords, ownerUid),
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Build the THREAD.md tool DEFINITIONS for one agent turn (P3-2). The thread
|
|
99
|
+
* analogue of {@link buildGroupMdTools}: the tool surfaces as
|
|
100
|
+
* `mcp__thread_md__update_thread_md` and writes THIS thread's OWN THREAD.md
|
|
101
|
+
* (PUT /v1/bot/groups/{groupNo}/threads/{shortId}/md), NEVER the parent group's
|
|
102
|
+
* GROUP.md — the thread/group split is mutually exclusive (#88 P3).
|
|
103
|
+
* index.ts only ever wires the group tool OR this thread tool for a turn (chosen
|
|
104
|
+
* by channelId shape), so the two never co-exist in one session.
|
|
105
|
+
*
|
|
106
|
+
* `coords.channelId` MUST be a thread composite (`<groupNo>____<shortId>`); the
|
|
107
|
+
* caller (index.ts) guarantees this by routing on `isThreadChannelId`. The
|
|
108
|
+
* owner-gate is identical to the group tool (bot-owner-only, independent of the
|
|
109
|
+
* token's server-side thread permission).
|
|
110
|
+
*/
|
|
111
|
+
export function buildThreadMdTools(deps, coords, ownerUid) {
|
|
112
|
+
const isOwner = coords.fromUid === ownerUid && ownerUid !== '';
|
|
113
|
+
return [
|
|
114
|
+
tool('update_thread_md', 'Persist new THREAD.md content for THIS thread (subarea) on the server (it ' +
|
|
115
|
+
"becomes the thread's trusted operator instructions on the next turn). " +
|
|
116
|
+
'`content` is the FULL replacement document, not a diff. Hard limit: 10240 ' +
|
|
117
|
+
'bytes UTF-8. Only the bot owner may call this; a non-owner request is ' +
|
|
118
|
+
'rejected. This writes the thread\'s OWN THREAD.md, never the parent ' +
|
|
119
|
+
"group's GROUP.md. Last write wins server-side — compose the complete " +
|
|
120
|
+
'updated document, do not assume a concurrent edit merged.', {
|
|
121
|
+
content: z
|
|
122
|
+
.string()
|
|
123
|
+
.describe('Full replacement THREAD.md document (≤10240 bytes UTF-8).'),
|
|
124
|
+
}, async (args) => {
|
|
125
|
+
try {
|
|
126
|
+
if (!isOwner) {
|
|
127
|
+
return errResult('Only the bot owner can update THREAD.md.');
|
|
128
|
+
}
|
|
129
|
+
if (!isThreadChannelId(coords.channelId)) {
|
|
130
|
+
return errResult('This channel is not a thread — THREAD.md is only writable from a thread.');
|
|
131
|
+
}
|
|
132
|
+
const groupNo = extractParentGroupNo(coords.channelId);
|
|
133
|
+
const shortId = extractThreadShortId(coords.channelId);
|
|
134
|
+
if (!groupNo || !shortId) {
|
|
135
|
+
return errResult('Could not resolve a thread (groupNo/shortId) from this channel.');
|
|
136
|
+
}
|
|
137
|
+
// Friendly over-limit message before the coordinator throws (it re-checks
|
|
138
|
+
// as the authoritative boundary; this is just for UX).
|
|
139
|
+
const bytes = Buffer.byteLength(args.content, 'utf-8');
|
|
140
|
+
if (bytes > MAX_THREAD_MD_CONTENT_BYTES) {
|
|
141
|
+
return errResult(`content is ${bytes} bytes, over the ${MAX_THREAD_MD_CONTENT_BYTES}-byte ` +
|
|
142
|
+
`UTF-8 limit — trim it before writing (the server would reject it).`);
|
|
143
|
+
}
|
|
144
|
+
const res = await deps.writeback.writeBack({
|
|
145
|
+
apiUrl: deps.apiUrl,
|
|
146
|
+
botToken: deps.botToken,
|
|
147
|
+
groupNo,
|
|
148
|
+
shortId,
|
|
149
|
+
content: args.content,
|
|
150
|
+
});
|
|
151
|
+
return jsonResult({
|
|
152
|
+
updated: {
|
|
153
|
+
groupNo: res.groupNo,
|
|
154
|
+
shortId: res.shortId,
|
|
155
|
+
version: res.version,
|
|
156
|
+
bytes: res.bytes,
|
|
157
|
+
},
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
catch (err) {
|
|
161
|
+
if (err instanceof ThreadMdContentTooLargeError) {
|
|
162
|
+
return errResult(`content is ${err.bytes} bytes, over the ${MAX_THREAD_MD_CONTENT_BYTES}-byte UTF-8 limit.`);
|
|
163
|
+
}
|
|
164
|
+
return errResult(err instanceof Error ? err.message : String(err));
|
|
165
|
+
}
|
|
166
|
+
}),
|
|
167
|
+
];
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Build the THREAD.md write-back MCP server for one agent turn. `coords` targets
|
|
171
|
+
* the thread (its composite channelId) + supplies the caller uid; `ownerUid` is
|
|
172
|
+
* the owner gate.
|
|
173
|
+
*/
|
|
174
|
+
export function createThreadMdToolServer(deps, coords, ownerUid) {
|
|
175
|
+
return createSdkMcpServer({
|
|
176
|
+
name: THREAD_MD_TOOL_SERVER_NAME,
|
|
177
|
+
version: '1.0.0',
|
|
178
|
+
tools: buildThreadMdTools(deps, coords, ownerUid),
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
//# sourceMappingURL=group-md-tool.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"group-md-tool.js","sourceRoot":"","sources":["../src/group-md-tool.ts"],"names":[],"mappings":"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"}
|