telegram-agent-kit 0.2.0 → 0.3.1

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
@@ -151,8 +151,9 @@ You implement these; the kit drives them.
151
151
  | `Checkpointer` | `{ snapshot(threadId), rollback(threadId, id) }` | Per-thread snapshot/rollback for clean recovery on a failed turn. |
152
152
  | `ThreadStore` | `{ resolve(chatKey, now), touch(chatKey, now) }` | Maps `{ chatId, agentId }` to a thread id (so two bots over one chat id don't collide). |
153
153
 
154
- A `RenderEvent` is one of `token`, `tool_start`, `tool_end`, or `error`. The kit
155
- appends `token` text to the live draft and treats an `error` event as a rollback.
154
+ A `RenderEvent` is either `token` or `error`: `token` text is appended to the live draft,
155
+ an `error` rolls the turn back, logs the message, and if you pass `errorNotice` tells
156
+ the user in the chat instead of going silent.
156
157
 
157
158
  ## API reference
158
159
 
@@ -177,6 +178,8 @@ appends `token` text to the live draft and treats an `error` event as a rollback
177
178
  - `runTelegramTurn(opts)` — orchestrate one turn. Never throws out; every failure is caught and logged.
178
179
  Accepts an optional `configurable` bag forwarded to your `AgentStream` as `context.configurable`,
179
180
  for passing per-turn data (e.g. `pendingImages`) to the agent without widening the core input type.
181
+ Pass `errorNotice` (plain text, your language) to have a failed turn say so in the chat —
182
+ omit it and the user just sees the draft stop, which reads as being ignored.
180
183
  - `sendReply(client, chatId, reply, opts, signal?)` / `sendText(...)` — the send path on its own.
181
184
  - Types: `BotClient`, `AgentStream`, `Checkpointer`, `ThreadStore`, `RenderEvent`, `ChatKey`, `Logger`.
182
185
 
@@ -1,15 +1,9 @@
1
- import { R as RenderEvent, A as AgentStream } from '../interfaces-FQIM1SDq.js';
1
+ import { S as StreamInput, R as RenderEvent, A as AgentStream } from '../interfaces-DhF4n199.js';
2
2
  import { RunnableConfig } from '@langchain/core/runnables';
3
3
  import { createDeepAgent } from 'deepagents';
4
4
 
5
5
  type Agent$1 = ReturnType<typeof createDeepAgent>;
6
- type StreamAgentInput = {
7
- messages: Array<{
8
- role: 'user';
9
- content: string;
10
- }>;
11
- };
12
- declare function streamAgent(agent: Agent$1, input: StreamAgentInput, config: RunnableConfig, signal?: AbortSignal): AsyncIterable<RenderEvent>;
6
+ declare function streamAgent(agent: Agent$1, input: StreamInput, config: RunnableConfig, signal?: AbortSignal): AsyncIterable<RenderEvent>;
13
7
 
14
8
  type Agent = Parameters<typeof streamAgent>[0];
15
9
  /** Adapt a deepagents agent to the kit's runtime-agnostic AgentStream: merge the
@@ -19,4 +13,4 @@ type Agent = Parameters<typeof streamAgent>[0];
19
13
  * the ONLY place the langgraph config shape lives. */
20
14
  declare function toAgentStream(agent: Agent): AgentStream;
21
15
 
22
- export { RenderEvent, type StreamAgentInput, streamAgent, toAgentStream };
16
+ export { RenderEvent, StreamInput, streamAgent, toAgentStream };
@@ -8,20 +8,7 @@ function extractText(content) {
8
8
  }
9
9
  return "";
10
10
  }
11
- function extractToolError(output) {
12
- if (typeof output !== "object" || output === null) return void 0;
13
- const o = output;
14
- if (o.status !== "error") return void 0;
15
- const c = o.content;
16
- if (typeof c === "string") return c;
17
- try {
18
- return JSON.stringify(c);
19
- } catch {
20
- return String(c);
21
- }
22
- }
23
11
  async function* streamAgent(agent, input, config, signal) {
24
- const toolStart = /* @__PURE__ */ new Map();
25
12
  const iter = agent.streamEvents(input, {
26
13
  ...config,
27
14
  signal,
@@ -33,24 +20,6 @@ async function* streamAgent(agent, input, config, signal) {
33
20
  if (ev.metadata?.langgraph_node !== "model_request") continue;
34
21
  const text = extractText(ev.data?.chunk?.content);
35
22
  if (text) yield { type: "token", text };
36
- } else if (ev.event === "on_tool_start") {
37
- toolStart.set(ev.run_id, Date.now());
38
- yield {
39
- type: "tool_start",
40
- id: ev.run_id,
41
- name: ev.name ?? "unknown",
42
- args: ev.data?.input
43
- };
44
- } else if (ev.event === "on_tool_end" || ev.event === "on_tool_error") {
45
- const startedAt = toolStart.get(ev.run_id) ?? Date.now();
46
- toolStart.delete(ev.run_id);
47
- const error = ev.event === "on_tool_error" ? ev.data?.error instanceof Error ? ev.data.error.message : String(ev.data?.error ?? "tool error") : extractToolError(ev.data?.output);
48
- yield {
49
- type: "tool_end",
50
- id: ev.run_id,
51
- durationMs: Date.now() - startedAt,
52
- ...error !== void 0 ? { error } : {}
53
- };
54
23
  }
55
24
  }
56
25
  } 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-FQIM1SDq.js';
2
- export { b as AgentStreamContext, R as RenderEvent, S as StreamInput } from './interfaces-FQIM1SDq.js';
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';
3
3
 
4
4
  type SendOpts = {
5
5
  rich: boolean;
@@ -76,9 +76,12 @@ type RunTelegramTurnOpts = {
76
76
  beforeTurn?: (ctx: TurnContext) => void | Promise<void>;
77
77
  afterTurn?: (ctx: TurnContext) => void | Promise<void>;
78
78
  };
79
- makeDraftStreamer?: (deps: DraftStreamerDeps) => DraftStreamer;
80
79
  draftConstants?: Partial<DraftConstants>;
81
80
  configurable?: Record<string, unknown>;
81
+ /** Plain-text line sent to the chat when the stream errors out (model chain
82
+ * exhausted, graph threw). Without it the turn returns silently and the user
83
+ * sees only a draft that stops moving — indistinguishable from being ignored. */
84
+ errorNotice?: string;
82
85
  };
83
86
  declare function runTelegramTurn(opts: RunTelegramTurnOpts): Promise<void>;
84
87
 
package/dist/index.js CHANGED
@@ -170,7 +170,7 @@ function renderLinks(text, autoClose) {
170
170
  rest = rest.slice(m.index + m.length);
171
171
  }
172
172
  }
173
- function renderCode(text, autoClose) {
173
+ function renderInline(text, autoClose) {
174
174
  let out = "";
175
175
  let rest = text;
176
176
  for (; ; ) {
@@ -193,9 +193,6 @@ function renderCode(text, autoClose) {
193
193
  rest = rest.slice(close + 1);
194
194
  }
195
195
  }
196
- function renderInline(line, autoClose) {
197
- return renderCode(line, autoClose);
198
- }
199
196
  var FENCE_OPEN_RE = /^(`{3,}|~{3,})\s*(.*)$/;
200
197
  var TICK_CLOSE_RE = /^`{3,}\s*$/;
201
198
  var TILDE_CLOSE_RE = /^~{3,}\s*$/;
@@ -691,7 +688,6 @@ var NOOP_LOG = { warn: () => {
691
688
  async function runTelegramTurn(opts) {
692
689
  const now = opts.now ?? (() => Date.now());
693
690
  const log = opts.log ?? NOOP_LOG;
694
- const makeDraftStreamer = opts.makeDraftStreamer ?? createDraftStreamer;
695
691
  const ctx = { chatKey: opts.chatKey, userText: opts.userText };
696
692
  let rollback = null;
697
693
  let turnCompleted = false;
@@ -718,7 +714,7 @@ async function runTelegramTurn(opts) {
718
714
  const threadId = await opts.threadStore.resolve(opts.chatKey, now());
719
715
  const checkpointId = await opts.checkpointer.snapshot(threadId);
720
716
  rollback = { threadId, checkpointId };
721
- draft = makeDraftStreamer({
717
+ draft = createDraftStreamer({
722
718
  client: opts.client,
723
719
  chatId: opts.chatKey.chatId,
724
720
  draftId: opts.draftId,
@@ -728,7 +724,7 @@ async function runTelegramTurn(opts) {
728
724
  });
729
725
  draft.start();
730
726
  let reply = "";
731
- let errored = false;
727
+ let errorMessage;
732
728
  for await (const ev of opts.agentStream(
733
729
  { messages: [{ role: "user", content: opts.userText }] },
734
730
  { threadId, signal: opts.signal, configurable: opts.configurable }
@@ -736,15 +732,27 @@ async function runTelegramTurn(opts) {
736
732
  if (ev.type === "token") {
737
733
  reply += ev.text;
738
734
  draft.push(reply);
739
- } else if (ev.type === "error") errored = true;
735
+ } else if (ev.type === "error") errorMessage = ev.message;
740
736
  }
741
- if (errored) {
737
+ if (errorMessage !== void 0) {
738
+ log.error("telegram turn errored", {
739
+ chatId: opts.chatKey.chatId,
740
+ err: errorMessage
741
+ });
742
742
  draftTornDown = true;
743
743
  await draft.abort().catch(() => {
744
744
  });
745
745
  await opts.checkpointer.rollback(rollback.threadId, rollback.checkpointId).catch(
746
746
  (e) => log.error("telegram rollback failed", { err: String(e) })
747
747
  );
748
+ if (opts.errorNotice && !opts.signal?.aborted) {
749
+ await opts.client.sendMessage(
750
+ { chatId: opts.chatKey.chatId, text: opts.errorNotice },
751
+ opts.signal
752
+ ).catch(
753
+ (e) => log.error("telegram error notice failed", { err: String(e) })
754
+ );
755
+ }
748
756
  return;
749
757
  }
750
758
  draftTornDown = true;
@@ -5,7 +5,6 @@ type ChatKey = {
5
5
  type Logger = {
6
6
  warn(msg: string, data?: unknown): void;
7
7
  error(msg: string, data?: unknown): void;
8
- info?(msg: string, data?: unknown): void;
9
8
  };
10
9
  /** Raw Bot API transport primitives — one HTTP call each, NO chunking /
11
10
  * rendering / fallback (the kit owns those). Each throws TelegramApiError
@@ -44,16 +43,6 @@ type BotClient = {
44
43
  type RenderEvent = {
45
44
  type: 'token';
46
45
  text: string;
47
- } | {
48
- type: 'tool_start';
49
- id: string;
50
- name: string;
51
- args: unknown;
52
- } | {
53
- type: 'tool_end';
54
- id: string;
55
- durationMs: number;
56
- error?: string;
57
46
  } | {
58
47
  type: 'error';
59
48
  message: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "telegram-agent-kit",
3
- "version": "0.2.0",
3
+ "version": "0.3.1",
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",