@ycodium-ai/plugin-im 0.2.2672 → 0.2.2690
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 +67 -31
- package/dist/index.js +5387 -2907
- package/locales/en.json +137 -43
- package/locales/zh-CN.json +139 -45
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,25 +1,43 @@
|
|
|
1
1
|
# @ycodium-ai/plugin-im
|
|
2
2
|
|
|
3
|
-
Talk to your agents from Telegram, WeCom, or Lark.
|
|
4
|
-
and it starts a turn on this machine; the conclusion comes back
|
|
5
|
-
and anything the agent needs approved lands there too.
|
|
3
|
+
Talk to your agents from Telegram, WeCom, or Lark. Message the bot (or mention
|
|
4
|
+
it in a group) and it starts a turn on this machine; the conclusion comes back
|
|
5
|
+
to the chat, and anything the agent needs approved lands there too.
|
|
6
6
|
|
|
7
7
|
## What it does
|
|
8
8
|
|
|
9
|
-
Each settings-card row is one
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
9
|
+
Each settings-card row is one bot (platform, credentials, who may use it); the
|
|
10
|
+
chats it talks in (private chats, groups) are not configured, they pick their own
|
|
11
|
+
project:
|
|
12
|
+
|
|
13
|
+
- **Allowed people** is an allow-list of that platform's user ids. Empty means
|
|
14
|
+
nobody can make the agent work. Someone who is not on it gets one reply with
|
|
15
|
+
their own user id and where to put it, at most once every ten minutes per
|
|
16
|
+
person (the table of who was told is bounded in memory).
|
|
17
|
+
- A chat with no project starts nothing. The first message from an allowed
|
|
18
|
+
person gets a project picker (a card on Lark, an inline keyboard on Telegram,
|
|
19
|
+
a numbered text list on WeCom, which has no buttons: reply with the number or
|
|
20
|
+
`/repo <number>`). The pick is written as a plugin fact and survives restarts.
|
|
21
|
+
`/repo` switches the project: the old thread is kept (still under that
|
|
22
|
+
project's `/sessions`), the chat forgets it, and a running turn blocks the
|
|
23
|
+
switch. The panel has a Pick project button.
|
|
24
|
+
- A chat only hears the project it picked: one conclusion per finished turn and
|
|
25
|
+
thread failures go to the chats that picked that project; a chat with no
|
|
26
|
+
project hears nothing.
|
|
27
|
+
- `/group <name>` (Lark only): the bot creates a group, adds the sender as owner
|
|
28
|
+
and posts the project picker in it. Telegram and WeCom bots cannot create
|
|
29
|
+
groups and answer so.
|
|
30
|
+
- **In groups, answer** (per bot): only when mentioned (default), every message,
|
|
31
|
+
or every message except ones aimed at someone else. WeCom only delivers
|
|
32
|
+
mentions, so it has no effect there. Under the default, a group that holds only the
|
|
33
|
+
sender and the bot needs no mention (`soloGroup.ts`; Lark `im.v1.chat.get`, Telegram
|
|
34
|
+
`getChatMemberCount`, answer cached five minutes; WeCom unsupported).
|
|
35
|
+
- Archived projects are read-only and are not offered by the picker. A message
|
|
36
|
+
to a chat whose project was archived or deleted gets a one-line reply that
|
|
37
|
+
says so and points at `/repo`, at most once every ten minutes per chat. Chat
|
|
38
|
+
commands such as help and status still work. Restore the project to resume.
|
|
19
39
|
- Secrets (bot tokens, app credentials) stay in the environment secret store.
|
|
20
40
|
The patch file keeps a reference, not the value.
|
|
21
|
-
- Who may command the bot is an allow-list of that platform's user ids. Empty
|
|
22
|
-
means anyone in the group can make the agent run things on this machine.
|
|
23
41
|
- A row can pick its own proxy. On a given machine one platform may be
|
|
24
42
|
unreachable while another is fine.
|
|
25
43
|
|
|
@@ -62,7 +80,7 @@ optional `choiceCards` surface (`ImChoiceCard`, `src/adapter.ts`): Lark patches
|
|
|
62
80
|
card, Telegram edits a message and its inline keyboard. A request is posted on
|
|
63
81
|
`thread.user-input-pending` (read with `listPendingUserInputs`), one card per
|
|
64
82
|
question, and answered with one `thread.user-input.respond` once every question
|
|
65
|
-
has an answer; a free-form answer is the next ordinary message in the
|
|
83
|
+
has an answer; a free-form answer is the next ordinary message in the chat, and
|
|
66
84
|
`thread.request-resolved` freezes the cards of a question answered elsewhere or
|
|
67
85
|
closed unanswered. WeCom has no buttons: it writes the options as numbers and the
|
|
68
86
|
reply is parsed in `src/questionCards.ts`. A message that lands behind a running
|
|
@@ -75,39 +93,41 @@ and `thread.turn-queue.resume`, and the card is the user's own action, so no
|
|
|
75
93
|
and withdrawing need buttons (resuming is the `/continue` command). Editing a queued message is not offered:
|
|
76
94
|
the host does not let a plugin dispatch `thread.turn-intent.edit`.
|
|
77
95
|
|
|
78
|
-
A
|
|
79
|
-
team it is pointed at, the model and plan mode set from the
|
|
80
|
-
this plugin has opened, and the approval, question and
|
|
81
|
-
waiting in the
|
|
96
|
+
A chat keeps its place across restarts. Which project a chat picked, which thread
|
|
97
|
+
it is talking in, the team it is pointed at, the model and plan mode set from the
|
|
98
|
+
chat, the threads this plugin has opened, and the approval, question and
|
|
99
|
+
queued-message buttons still waiting in the chat are
|
|
82
100
|
written as plugin facts (`ctx.events.append`) and folded back by a pure function
|
|
83
101
|
(`ctx.derivedState`, see `src/chatState.ts`). A saved thread that was deleted,
|
|
84
|
-
archived or
|
|
102
|
+
archived or no longer on the chat's project is dropped on the next message.
|
|
103
|
+
The chat key is `<bot row id>:<chat id>`: two bots in the same person's private chat share
|
|
104
|
+
the chat id, so the key has to carry the bot.
|
|
85
105
|
|
|
86
106
|
Inbound attachments. An adapter reports a message's resources as `resources`
|
|
87
107
|
(`ImInboundResource`, `src/adapter.ts`) and implements `fetchResource`, which must stop reading
|
|
88
108
|
at `maxBytes` (`readBodyLimited`, `src/attachments.ts`) and throw `ImResourceTooLargeError`.
|
|
89
109
|
An adapter whose platform caps bot downloads tighter than the host sets `downloadLimitBytes`
|
|
90
110
|
(Telegram: 20 MB); a size the platform reports up front is checked before any download. The
|
|
91
|
-
core (`collectResources` in `src/
|
|
111
|
+
core (`collectResources` in `src/inboundAttachments.ts`) cleans the name (`sanitizeAttachmentName`: the host
|
|
92
112
|
splices it into the `[Attached … "<name>" …]` line the agent reads, so newlines and double
|
|
93
113
|
quotes must not survive), takes the type from the bytes (`resolveMime`: platforms self-report,
|
|
94
114
|
Lark says PNG for every image), checks the host's limits (10 MiB image, 25 MiB other, 20 per
|
|
95
115
|
turn, mirrored from the host because a plugin cannot import it) and stores each one with
|
|
96
116
|
`ctx.attachments.store`; an image the host can inline reaches the agent as an image, anything
|
|
97
117
|
else as a path. A failed one is reported in the chat and left as a line in the turn text.
|
|
98
|
-
A message with attachments and no text starts no turn: the thread is created if the
|
|
118
|
+
A message with attachments and no text starts no turn: the thread is created if the chat has
|
|
99
119
|
none (attachments are stored per thread), the attachments wait in memory for that thread, and
|
|
100
|
-
the next message with text carries them. Waiting attachments are dropped when the
|
|
120
|
+
the next message with text carries them. Waiting attachments are dropped when the chat's
|
|
101
121
|
thread changes and are not persisted. Lark does not require a mention for a message that is only
|
|
102
122
|
a resource (`RESOURCE_MESSAGE_TYPES` in `src/larkInbound.ts`); the sender allow-list still
|
|
103
123
|
applies. Lark rich text is read by `src/larkPost.ts` (every image, `<image N>` placeholders in
|
|
104
124
|
order, the client's `md` field preferred). Known types we do not handle are reported with
|
|
105
|
-
`unsupportedType` and answered with one line, rate-limited per
|
|
125
|
+
`unsupportedType` and answered with one line, rate-limited per chat. A chat pointed at a team
|
|
106
126
|
cannot carry attachments. WeCom reports `image`, `file`, `video` and the images of `mixed` (a group "mention plus picture"; text items and `<image N>` placeholders keep their order, and a mixed with only images still has content, so it starts a turn) in `resources`, with the download URL and `aeskey` packed into the resource key. `fetchResource` (`src/wecomMedia.ts`) GETs the URL (valid five minutes) and decrypts: `aeskey` is base64 for a 32-byte key, the IV is its first 16 bytes, AES-256-CBC with auto padding off, then PKCS#7 removed with a **32-byte block** (pad value 1 to 32, every pad byte equal, else the media is rejected). Without an `aeskey` the bytes are used as they are. The ciphertext is capped at limit + 32, the plaintext at the limit, and the file name comes from `Content-Disposition` (`filename*=UTF-8''…` first, then `filename="…"`) through `ImFetchedResource`. A WeCom `voice` message is its transcript as text, not an attachment. `quote` is not read on any platform.
|
|
107
127
|
|
|
108
128
|
Outbound files. The plugin contributes one MCP tool, `im_send_file` (`src/sendFile.ts`;
|
|
109
129
|
`ctx.toolkit` name `im`), with `path` and an optional `description` (the caption). It sends only
|
|
110
|
-
to the
|
|
130
|
+
to the chat whose thread is the calling conversation (`chatOf(...).threadId`), never by
|
|
111
131
|
project, and fails with `not-in-chat` otherwise. The bytes come from `invocation.workspace`
|
|
112
132
|
(`workspace.read`: realpath-bounded to the thread's folders, regular files, 50 MiB cap) and must
|
|
113
133
|
be read before the handler returns, because every method rejects `invocation-ended` afterwards.
|
|
@@ -134,9 +154,10 @@ conversation and is left out when none has arrived since the plugin started, as
|
|
|
134
154
|
A picture goes as `image` only when it is PNG, JPEG or GIF within 10 MB (`imageMimeTypes`).
|
|
135
155
|
|
|
136
156
|
Chat commands: `/stop`, `/continue`, `/status`, `/new`, `/sessions`, `/resume`, `/model`,
|
|
137
|
-
`/plan`, `/team`, `/thread`, `/help`, `/panel`.
|
|
157
|
+
`/plan`, `/repo`, `/group`, `/team`, `/thread`, `/help`, `/panel`. In a chat with no project
|
|
158
|
+
`/sessions`, `/resume` and the team commands answer with the project picker. `/sessions` and `/resume` only list and
|
|
138
159
|
switch threads this plugin opened, since the host lets a plugin send only into
|
|
139
|
-
its own threads. `/continue` dispatches `thread.turn-queue.resume` for the
|
|
160
|
+
its own threads. `/continue` dispatches `thread.turn-queue.resume` for the chat's thread
|
|
140
161
|
when its queue is paused (a `/stop` or a failure pauses it), which is how WeCom, with
|
|
141
162
|
no buttons, resumes; it is not `/resume`, which already switches threads.
|
|
142
163
|
|
|
@@ -147,7 +168,7 @@ a short `pn:<version>:<index>` token (`callback_data` is capped at 64 bytes);
|
|
|
147
168
|
the action stays in memory and a tap on an older keyboard version counts as expired. Each card keeps its own view
|
|
148
169
|
stack in memory (`src/panelController.ts`), so after a restart an old card only
|
|
149
170
|
answers that it has expired. A tap runs the same handler as the typed command and
|
|
150
|
-
waits in the same per-
|
|
171
|
+
waits in the same per-chat queue as typed messages. Another platform opts in by
|
|
151
172
|
implementing the optional `panel` surface on its adapter (`src/adapter.ts`).
|
|
152
173
|
|
|
153
174
|
The **Reply language** setting (Chinese by default, or English) picks the
|
|
@@ -173,18 +194,33 @@ ycodium plugin add @ycodium-ai/plugin-im
|
|
|
173
194
|
The plugin ships enabled with Ycodium as `core.im`. Disabling it closes every
|
|
174
195
|
chat connection. Uninstalling it writes a removal onto the home patch, so a
|
|
175
196
|
restart or upgrade does not bring it back. Reinstalling the unversioned bundled
|
|
176
|
-
package restores the same entry without an npm fetch.
|
|
197
|
+
package restores the same entry without an npm fetch. Bot configuration and
|
|
177
198
|
secrets stay until you clear them.
|
|
178
199
|
|
|
179
200
|
## Surfaces
|
|
180
201
|
|
|
181
|
-
- **Web / Desktop** — Settings → Plugins → Chat. The
|
|
202
|
+
- **Web / Desktop** — Settings → Plugins → Chat. The bots table is the
|
|
182
203
|
settings card this package registers.
|
|
183
204
|
- **Mobile** — the same settings card, without platform option icons (mobile
|
|
184
205
|
has no plugin icon pipeline).
|
|
185
206
|
- Chat replies themselves go to Telegram, WeCom, or Lark, not into a Ycodium
|
|
186
207
|
page.
|
|
187
208
|
|
|
209
|
+
## Source layout
|
|
210
|
+
|
|
211
|
+
`src/index.ts` only assembles: it builds the adapters, registers the settings card, builds the
|
|
212
|
+
shared core and wires the feature modules together. Everything else is one module per
|
|
213
|
+
responsibility, each receiving a small `core` object (a few host capabilities, the reply
|
|
214
|
+
language, the saved-state mirror) plus an explicit `deps` object, never the whole `ctx`:
|
|
215
|
+
|
|
216
|
+
- `botConfig` (settings card, reading bots, chat keys, allow-list), `core` (state mirror and
|
|
217
|
+
persistence, delivery, bot and chat lookup), `connections` (one long connection per bot)
|
|
218
|
+
- `inbound` (per-bot message handlers), `chatQueue` (per-chat serial queue), `commands`,
|
|
219
|
+
`chatSetup` (picker, `/repo`, `/group`), `projectRows`/`projectList` (the project list),
|
|
220
|
+
`sessions`, `modelPlan`, `turns`, `inboundAttachments`, `teamRuns`
|
|
221
|
+
- `approvals`, `interactions` (question and queue cards, button routing), `replyCards`,
|
|
222
|
+
`notifications`, `acknowledgements`, `panelWiring` (with `panelController`)
|
|
223
|
+
|
|
188
224
|
## Developing
|
|
189
225
|
|
|
190
226
|
The package builds its own code and the Lark SDK into `dist/index.js`. The host
|