telegram-agent-kit 0.4.0 → 0.5.0

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 CHANGED
@@ -157,9 +157,12 @@ You implement these; the kit drives them.
157
157
  | `Checkpointer` | `{ snapshot(threadId), rollback(threadId, id) }` | Per-thread snapshot/rollback for clean recovery on a failed turn. |
158
158
  | `ThreadStore` | `{ resolve(chatKey, now), touch(chatKey, now) }` | Maps `{ chatId, agentId }` to a thread id (so two bots over one chat id don't collide). |
159
159
 
160
- A `RenderEvent` is either `token` or `error`: `token` text is appended to the live draft,
161
- an `error` rolls the turn back, logs the message, and if you pass `errorNotice` tells
162
- the user in the chat instead of going silent.
160
+ A `RenderEvent` is one of `token`, `tool_start` or `error`. `token` text is appended to
161
+ the live draft *and* to the reply that gets sent. `tool_start` shows a transient
162
+ `🔧 \`name\`…` line under the draft so the user sees which tool is running instead of a
163
+ frozen draft — it is cleared by the next token and **never** becomes part of the sent
164
+ message. An `error` rolls the turn back, logs the message, and — if you pass
165
+ `errorNotice` — tells the user in the chat instead of going silent.
163
166
 
164
167
  ## API reference
165
168
 
@@ -189,6 +192,7 @@ the user in the chat instead of going silent.
189
192
  Pass `errorNotice` (plain text, your language) to have a failed turn say so in the chat —
190
193
  omit it and the user just sees the draft stop, which reads as being ignored.
191
194
  - `sendReply(client, chatId, reply, opts, signal?)` / `sendText(...)` — the send path on its own.
195
+ `opts` is `{ rich: boolean, log: Logger }`, with the same `rich` semantics as above.
192
196
  - Types: `BotClient`, `AgentStream`, `Checkpointer`, `ThreadStore`, `RenderEvent`, `ChatKey`, `Logger`.
193
197
 
194
198
  **Errors**
@@ -204,6 +208,10 @@ the user in the chat instead of going silent.
204
208
  `__pregel_*` LangGraph internal-execution key — are stripped so the kit retains full control over
205
209
  checkpoint routing and execution.
206
210
  - `streamAgent(agent, input, config, signal?)` — lower-level event stream if you need direct control.
211
+ Yields tokens from the **root** agent only: a delegated agent (a `subagents` entry, or the built-in
212
+ `task` tool) runs its own model node and LangChain replays its events into the parent stream, so
213
+ without this its monologue would interleave with the reply. Naming the root agent does not change
214
+ what streams.
207
215
 
208
216
  > `@langchain/core` and `deepagents` are **type-only, optional** peers. The built
209
217
  > `/deepagents` bundle contains no runtime import of either, so the core stays
@@ -1,4 +1,4 @@
1
- import { S as StreamInput, R as RenderEvent, A as AgentStream } from '../interfaces-DhF4n199.js';
1
+ import { S as StreamInput, R as RenderEvent, A as AgentStream } from '../interfaces-BluM8MeB.js';
2
2
  import { RunnableConfig } from '@langchain/core/runnables';
3
3
  import { createDeepAgent } from 'deepagents';
4
4
 
@@ -1,4 +1,7 @@
1
1
  // src/deepagents/stream-agent.ts
2
+ function isNested(ev) {
3
+ return ev.metadata?.checkpoint_ns?.includes("|") ?? false;
4
+ }
2
5
  function extractText(content) {
3
6
  if (typeof content === "string") return content;
4
7
  if (Array.isArray(content)) {
@@ -18,8 +21,12 @@ async function* streamAgent(agent, input, config, signal) {
18
21
  for await (const ev of iter) {
19
22
  if (ev.event === "on_chat_model_stream") {
20
23
  if (ev.metadata?.langgraph_node !== "model_request") continue;
24
+ if (isNested(ev)) continue;
21
25
  const text = extractText(ev.data?.chunk?.content);
22
26
  if (text) yield { type: "token", text };
27
+ } else if (ev.event === "on_tool_start") {
28
+ if (isNested(ev)) continue;
29
+ yield { type: "tool_start", name: ev.name ?? "unknown" };
23
30
  }
24
31
  }
25
32
  } catch (err) {
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { B as BotClient, L as Logger, C as ChatKey, A as AgentStream, a as Checkpointer, T as ThreadStore } from './interfaces-DhF4n199.js';
2
- export { b as AgentStreamContext, R as RenderEvent, S as StreamInput } from './interfaces-DhF4n199.js';
1
+ import { B as BotClient, L as Logger, C as ChatKey, A as AgentStream, a as Checkpointer, T as ThreadStore } from './interfaces-BluM8MeB.js';
2
+ export { b as AgentStreamContext, R as RenderEvent, S as StreamInput } from './interfaces-BluM8MeB.js';
3
3
 
4
4
  type SendOpts = {
5
5
  rich: boolean;
package/dist/index.js CHANGED
@@ -737,6 +737,7 @@ async function runTelegramTurn(opts) {
737
737
  });
738
738
  draft.start();
739
739
  let reply = "";
740
+ let status = "";
740
741
  let errorMessage;
741
742
  for await (const ev of opts.agentStream(
742
743
  { messages: [{ role: "user", content: opts.userText }] },
@@ -744,7 +745,13 @@ async function runTelegramTurn(opts) {
744
745
  )) {
745
746
  if (ev.type === "token") {
746
747
  reply += ev.text;
748
+ status = "";
747
749
  draft.push(reply);
750
+ } else if (ev.type === "tool_start") {
751
+ status = `\u{1F527} \`${ev.name}\`\u2026`;
752
+ draft.push(reply ? `${reply}
753
+
754
+ ${status}` : status);
748
755
  } else if (ev.type === "error") errorMessage = ev.message;
749
756
  }
750
757
  if (errorMessage !== void 0) {
@@ -771,6 +778,14 @@ async function runTelegramTurn(opts) {
771
778
  draftTornDown = true;
772
779
  await draft.finalize().catch(() => {
773
780
  });
781
+ if (status) {
782
+ await opts.client.sendMessageDraft(
783
+ { chatId: opts.chatKey.chatId, draftId: opts.draftId, text: reply },
784
+ opts.signal
785
+ ).catch(
786
+ (e) => log.warn("telegram draft status clear failed", { err: String(e) })
787
+ );
788
+ }
774
789
  turnCompleted = true;
775
790
  if (reply.trim().length > 0) {
776
791
  await sendReply(
@@ -43,6 +43,12 @@ type BotClient = {
43
43
  type RenderEvent = {
44
44
  type: 'token';
45
45
  text: string;
46
+ }
47
+ /** The agent started a tool call. Surfaced in the live draft as a transient
48
+ * status line and NEVER folded into the reply — see runTelegramTurn. */
49
+ | {
50
+ type: 'tool_start';
51
+ name: string;
46
52
  } | {
47
53
  type: 'error';
48
54
  message: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "telegram-agent-kit",
3
- "version": "0.4.0",
3
+ "version": "0.5.0",
4
4
  "description": "Render markdown to Telegram, stream agent replies into live drafts, and drive a snapshot/rollback turn-loop — runtime-agnostic.",
5
5
  "type": "module",
6
6
  "license": "MIT",