@segmentstream/agent 0.6.13 → 0.7.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.
Files changed (67) hide show
  1. package/README.md +41 -42
  2. package/dist/_chunks/{inbound-request-CysnjMdw.mjs → inbound-request-BwBvXk0A.mjs} +9 -2
  3. package/dist/extension/_manifest.json +2 -0
  4. package/dist/extension/channels/telegram.mjs +1 -0
  5. package/dist/extension/config.d.ts +17 -5
  6. package/dist/extension/config.mjs +26 -5
  7. package/dist/extension/connections/ontology.mjs +1 -1
  8. package/dist/extension/instructions.md +20 -0
  9. package/dist/extension/lib/attachment-formats.d.ts +1 -1
  10. package/dist/extension/lib/attachment-tables.d.ts +1 -1
  11. package/dist/extension/lib/confirmation-description.d.ts +5 -0
  12. package/dist/extension/lib/confirmation-description.mjs +7 -1
  13. package/dist/extension/lib/confirmation-outcome.d.ts +19 -0
  14. package/dist/extension/lib/confirmation-outcome.mjs +34 -0
  15. package/dist/extension/lib/confirmations.mjs +1 -1
  16. package/dist/extension/lib/connection-proxy.d.ts +2 -2
  17. package/dist/extension/lib/connection-proxy.mjs +6 -6
  18. package/dist/extension/lib/conversations.mjs +15 -1
  19. package/dist/extension/lib/customer-text-safety.mjs +2 -1
  20. package/dist/extension/lib/deferred-confirmations.d.ts +39 -0
  21. package/dist/extension/lib/deferred-confirmations.mjs +149 -0
  22. package/dist/extension/lib/ontology-tools.d.ts +2 -0
  23. package/dist/extension/lib/ontology-tools.mjs +5 -0
  24. package/dist/extension/lib/telegram/adapter.d.ts +6 -0
  25. package/dist/extension/lib/telegram/adapter.mjs +89 -14
  26. package/dist/extension/lib/telegram/attachment-description.d.ts +31 -0
  27. package/dist/extension/lib/telegram/attachment-description.mjs +82 -0
  28. package/dist/extension/lib/telegram/attachments-send.mjs +3 -3
  29. package/dist/extension/lib/telegram/audience.mjs +1 -1
  30. package/dist/extension/lib/telegram/bot.mjs +3 -1
  31. package/dist/extension/lib/telegram/chat-post-card.mjs +1 -1
  32. package/dist/extension/lib/telegram/confirmation-expiry.d.ts +4 -0
  33. package/dist/extension/lib/telegram/confirmation-expiry.mjs +50 -0
  34. package/dist/extension/lib/telegram/confirmations.d.ts +9 -1
  35. package/dist/extension/lib/telegram/confirmations.mjs +136 -15
  36. package/dist/extension/lib/telegram/conversations.d.ts +10 -1
  37. package/dist/extension/lib/telegram/conversations.mjs +177 -22
  38. package/dist/extension/lib/telegram/customer-text.mjs +1 -1
  39. package/dist/extension/lib/telegram/deferred-confirmations.d.ts +26 -0
  40. package/dist/extension/lib/telegram/deferred-confirmations.mjs +282 -0
  41. package/dist/extension/lib/telegram/files.mjs +20 -3
  42. package/dist/extension/lib/telegram/images.d.ts +1 -0
  43. package/dist/extension/lib/telegram/images.mjs +2 -1
  44. package/dist/extension/lib/telegram/inbound-request.d.ts +15 -1
  45. package/dist/extension/lib/telegram/inbound-request.mjs +1 -1
  46. package/dist/extension/lib/telegram/inbound.d.ts +12 -4
  47. package/dist/extension/lib/telegram/inbound.mjs +258 -74
  48. package/dist/extension/lib/telegram/media-policy.mjs +1 -1
  49. package/dist/extension/lib/telegram/observed.d.ts +45 -2
  50. package/dist/extension/lib/telegram/observed.mjs +62 -3
  51. package/dist/extension/lib/telegram/pdf-text.d.ts +5 -0
  52. package/dist/extension/lib/telegram/pdf-text.mjs +84 -0
  53. package/dist/extension/lib/telegram/router.d.ts +31 -7
  54. package/dist/extension/lib/telegram/router.mjs +152 -41
  55. package/dist/extension/lib/telegram/routing-context.d.ts +15 -3
  56. package/dist/extension/lib/telegram/routing-context.mjs +131 -6
  57. package/dist/extension/lib/telegram/silent.mjs +5 -3
  58. package/dist/extension/lib/telegram/turn-errors.mjs +1 -1
  59. package/dist/extension/lib/telegram/voice.d.ts +4 -0
  60. package/dist/extension/lib/telegram/voice.mjs +7 -6
  61. package/dist/extension/schedules/confirmations.d.ts +6 -0
  62. package/dist/extension/schedules/confirmations.mjs +33 -0
  63. package/dist/extension/tools/ontology.d.ts +4 -0
  64. package/dist/extension/tools/ontology.mjs +30 -0
  65. package/dist/tools/index.d.ts +1 -0
  66. package/dist/tools/index.mjs +2 -1
  67. package/package.json +7 -4
@@ -6,10 +6,10 @@ __eveDirname(__filename);
6
6
  __eveCreateRequire(import.meta.url);
7
7
  import "./principal.mjs";
8
8
  import { confirmationLocale } from "./confirmation-text.mjs";
9
- import { agentMessage, observedChatKey } from "./observed.mjs";
10
9
  import { splitTelegramText } from "./format.mjs";
11
10
  import { inTelegramSendQueue } from "./send-queue.mjs";
12
- import { a as TelegramDeliveryError, l as customerMessage, o as currentLocale, p as reportTelegramError } from "../../../_chunks/inbound-request-CysnjMdw.mjs";
11
+ import { a as TelegramDeliveryError, l as customerMessage, o as currentLocale, p as reportTelegramError } from "../../../_chunks/inbound-request-BwBvXk0A.mjs";
12
+ import { agentMessage, observedChatKey } from "./observed.mjs";
13
13
  const SILENT_MARKERS = new Set(["[silent]", "no_reply"]);
14
14
  function isSilentReply(text) {
15
15
  return SILENT_MARKERS.has(text.trim().toLowerCase());
@@ -24,7 +24,7 @@ function replyDelivery(observed, scope = () => "telegram") {
24
24
  return async (event, channel, context) => {
25
25
  if (completionKind(event.message, event.finishReason) !== "reply") return;
26
26
  const message = customerMessage(event.message, confirmationLocale(context.session?.auth.current ?? null, currentLocale()));
27
- await inTelegramSendQueue(scope(), channel.telegram.chatId, async () => {
27
+ const deliveredIds = await inTelegramSendQueue(scope(), channel.telegram.chatId, async () => {
28
28
  const messageIds = [];
29
29
  try {
30
30
  for (const part of splitTelegramText(message)) {
@@ -36,6 +36,7 @@ function replyDelivery(observed, scope = () => "telegram") {
36
36
  const reference = reportTelegramError("telegram_reply_delivery_failed", error, { messageIds });
37
37
  throw new TelegramDeliveryError(reference, error instanceof TelegramDeliveryError ? error.delivery : "unknown", messageIds);
38
38
  }
39
+ return messageIds;
39
40
  });
40
41
  const text = message.text;
41
42
  if (observed === void 0 || channel.telegram.chatType === "private") return;
@@ -56,6 +57,7 @@ function replyDelivery(observed, scope = () => "telegram") {
56
57
  observed.remember(chat, agentMessage({
57
58
  text,
58
59
  at: new Date().toISOString(),
60
+ messageId: String(deliveredIds.at(-1)),
59
61
  ...inReplyTo === void 0 ? {} : { inReplyTo }
60
62
  }));
61
63
  };
@@ -6,7 +6,7 @@ __eveDirname(__filename);
6
6
  __eveCreateRequire(import.meta.url);
7
7
  import { memberIdOf } from "./principal.mjs";
8
8
  import { confirmationLocale } from "./confirmation-text.mjs";
9
- import { c as customerCopy, d as failureText, o as currentLocale, p as reportTelegramError } from "../../../_chunks/inbound-request-CysnjMdw.mjs";
9
+ import { c as customerCopy, d as failureText, o as currentLocale, p as reportTelegramError } from "../../../_chunks/inbound-request-BwBvXk0A.mjs";
10
10
  const telegramFailureEvents = {
11
11
  async "turn.cancelled"(event, channel, context) {
12
12
  const errorId = reportTelegramError("turn_cancelled", event, {
@@ -20,6 +20,7 @@ export declare function voiceNote(voice: VoiceMessage, detail?: string): string;
20
20
  export type Transcriber = (input: {
21
21
  readonly audio: Uint8Array;
22
22
  readonly model: string;
23
+ readonly abortSignal?: AbortSignal;
23
24
  }) => Promise<string>;
24
25
  /**
25
26
  * Transcribes through AI Gateway. The Gateway provider authenticates with `AI_GATEWAY_API_KEY`
@@ -34,11 +35,14 @@ export declare class TelegramFileError extends Error {
34
35
  export declare function downloadTelegramFile(input: {
35
36
  readonly proxy: ConnectionProxy;
36
37
  readonly fileId: string;
38
+ readonly abortSignal?: AbortSignal;
39
+ readonly maxBytes?: number;
37
40
  }): Promise<Uint8Array>;
38
41
  /** What a voice message becomes: the text of the turn and the note that goes with it. */
39
42
  export interface VoiceText {
40
43
  readonly text: string;
41
44
  readonly note: string;
45
+ readonly processed?: boolean;
42
46
  }
43
47
  /**
44
48
  * Turns a voice message into text. When it cannot (transcription is off, the file exceeds what a
@@ -4,8 +4,8 @@ import { createRequire as __eveCreateRequire } from "node:module";
4
4
  const __filename = __eveFileURLToPath(import.meta.url);
5
5
  __eveDirname(__filename);
6
6
  __eveCreateRequire(import.meta.url);
7
+ import { p as reportTelegramError } from "../../../_chunks/inbound-request-BwBvXk0A.mjs";
7
8
  import "../connection-proxy.mjs";
8
- import { p as reportTelegramError } from "../../../_chunks/inbound-request-CysnjMdw.mjs";
9
9
  import { gateway, transcribe } from "ai";
10
10
  const LABELS = {
11
11
  voice: "voice message",
@@ -41,11 +41,11 @@ function voiceNote(voice, detail) {
41
41
  if (detail !== void 0) parts.push(detail);
42
42
  return `[${parts.join(", ")}]`;
43
43
  }
44
- const gatewayTranscriber = async ({ audio, model }) => {
44
+ const gatewayTranscriber = async ({ audio, model, abortSignal }) => {
45
45
  return (await transcribe({
46
46
  model: gateway.transcription(model),
47
47
  audio,
48
- abortSignal: AbortSignal.timeout(TRANSCRIPTION_TIMEOUT_MS)
48
+ abortSignal: abortSignal ?? AbortSignal.timeout(TRANSCRIPTION_TIMEOUT_MS)
49
49
  })).text.trim();
50
50
  };
51
51
  var TelegramFileError = class extends Error {
@@ -58,7 +58,7 @@ async function downloadTelegramFile(input) {
58
58
  path: "/getFile",
59
59
  headers: [["content-type", "application/json"]],
60
60
  body: new TextEncoder().encode(JSON.stringify({ file_id: input.fileId }))
61
- });
61
+ }, input.abortSignal);
62
62
  let filePath;
63
63
  let description = "";
64
64
  try {
@@ -75,7 +75,7 @@ async function downloadTelegramFile(input) {
75
75
  path: `/${filePath}`,
76
76
  headers: [],
77
77
  body: new Uint8Array()
78
- });
78
+ }, input.maxBytes, input.abortSignal);
79
79
  if (file.status !== 200) throw new TelegramFileError(`Telegram refused the file download with HTTP ${file.status}.`);
80
80
  return file.body;
81
81
  }
@@ -109,7 +109,8 @@ async function voiceText(input) {
109
109
  note
110
110
  } : {
111
111
  text: transcript,
112
- note
112
+ note,
113
+ processed: true
113
114
  };
114
115
  } catch (error) {
115
116
  return {
@@ -0,0 +1,6 @@
1
+ /** No model is invoked until an actual expiry outcome is delivered to its original chat. */
2
+ declare const _default: {
3
+ cron: string;
4
+ run({ to }: import("eve/schedules").ScheduleHandlerArgs): Promise<void>;
5
+ };
6
+ export default _default;
@@ -0,0 +1,33 @@
1
+ import { fileURLToPath as __eveFileURLToPath } from "node:url";
2
+ import { dirname as __eveDirname } from "node:path";
3
+ import { createRequire as __eveCreateRequire } from "node:module";
4
+ const __filename = __eveFileURLToPath(import.meta.url);
5
+ __eveDirname(__filename);
6
+ __eveCreateRequire(import.meta.url);
7
+ import { channelsEnabled } from "../lib/environment.mjs";
8
+ import segmentstream from "../extension.mjs";
9
+ import telegram_default from "../channels/telegram.mjs";
10
+ import { expireScheduledConfirmations } from "../lib/telegram/confirmation-expiry.mjs";
11
+ import { defineSchedule } from "eve/schedules";
12
+ var confirmations_default = defineSchedule({
13
+ cron: "* * * * *",
14
+ async run({ to }) {
15
+ const settings = segmentstream.config.channels.telegram;
16
+ if (!channelsEnabled(process.env) || !settings || segmentstream.config.confirmations.mode !== "deferred") return;
17
+ await expireScheduledConfirmations(settings.connection, async (record, result) => {
18
+ await to(telegram_default, {
19
+ chatId: record.data.chatId,
20
+ messageThreadId: record.data.threadId ? Number(record.data.threadId) : void 0,
21
+ confirmationAddress: record.data.address,
22
+ confirmationSessionId: record.data.sessionId
23
+ }).send(JSON.stringify({
24
+ type: "confirmation_result",
25
+ ...result
26
+ }), {
27
+ auth: null,
28
+ turnPolicy: "queue"
29
+ });
30
+ }, {}, settings);
31
+ }
32
+ });
33
+ export { confirmations_default as default };
@@ -0,0 +1,4 @@
1
+ declare const _default: import("eve").DynamicSentinel<{
2
+ [k: string]: import("eve/tools").ToolDefinition<Record<string, unknown>, Record<string, unknown>>;
3
+ } | null>;
4
+ export default _default;
@@ -0,0 +1,30 @@
1
+ import { fileURLToPath as __eveFileURLToPath } from "node:url";
2
+ import { dirname as __eveDirname } from "node:path";
3
+ import { createRequire as __eveCreateRequire } from "node:module";
4
+ const __filename = __eveFileURLToPath(import.meta.url);
5
+ __eveDirname(__filename);
6
+ __eveCreateRequire(import.meta.url);
7
+ import { memberIdOf } from "../lib/telegram/principal.mjs";
8
+ import segmentstream from "../extension.mjs";
9
+ import { ontologyTools } from "../lib/ontology-tools.mjs";
10
+ import { executeDeferredTool } from "../lib/deferred-confirmations.mjs";
11
+ import { defineDynamic, defineTool } from "eve/tools";
12
+ var ontology_default = defineDynamic({ events: { "turn.started": async (_event, context) => {
13
+ const memberId = memberIdOf(context.session.auth.current);
14
+ if (!segmentstream.config.ontology.connection || segmentstream.config.confirmations.mode !== "deferred" || memberId === void 0) return null;
15
+ return Object.fromEntries((await ontologyTools().list(memberId)).map((tool) => {
16
+ const action = String(tool.name);
17
+ const schema = tool.inputSchema;
18
+ const properties = Object.fromEntries(Object.entries(schema.properties ?? {}).filter(([key]) => key !== "_segmentstream"));
19
+ return [`ontology__${action}`, defineTool({
20
+ deferred: true,
21
+ description: String(tool.description ?? tool.title ?? action),
22
+ inputSchema: {
23
+ ...schema,
24
+ properties
25
+ },
26
+ execute: (input, ctx) => executeDeferredTool(memberId, action, input, ctx)
27
+ })];
28
+ }));
29
+ } } });
30
+ export { ontology_default as default };
@@ -6,4 +6,5 @@ export { default as attachments_promote } from "../extension/tools/attachments_p
6
6
  export { default as attachments_read } from "../extension/tools/attachments_read.js";
7
7
  export { default as attachments_send } from "../extension/tools/attachments_send.js";
8
8
  export { default as attachments_table } from "../extension/tools/attachments_table.js";
9
+ export { default as ontology } from "../extension/tools/ontology.js";
9
10
  export { default as questions_ask } from "../extension/tools/questions_ask.js";
@@ -10,5 +10,6 @@ import attachments_promote_default from "../extension/tools/attachments_promote.
10
10
  import attachments_read_default from "../extension/tools/attachments_read.mjs";
11
11
  import attachments_send_default from "../extension/tools/attachments_send.mjs";
12
12
  import attachments_table_default from "../extension/tools/attachments_table.mjs";
13
+ import ontology_default from "../extension/tools/ontology.mjs";
13
14
  import questions_ask_default from "../extension/tools/questions_ask.mjs";
14
- export { attachments_discard_default as attachments_discard, attachments_list_default as attachments_list, attachments_promote_default as attachments_promote, attachments_read_default as attachments_read, attachments_send_default as attachments_send, attachments_table_default as attachments_table, questions_ask_default as questions_ask };
15
+ export { attachments_discard_default as attachments_discard, attachments_list_default as attachments_list, attachments_promote_default as attachments_promote, attachments_read_default as attachments_read, attachments_send_default as attachments_send, attachments_table_default as attachments_table, ontology_default as ontology, questions_ask_default as questions_ask };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@segmentstream/agent",
3
- "version": "0.6.13",
3
+ "version": "0.7.0",
4
4
  "description": "Mount a SegmentStream workspace's agent on eve: the ontology as tools, acting as the member who writes, and Telegram through the workspace's connection.",
5
5
  "license": "Apache-2.0",
6
6
  "author": "SegmentStream",
@@ -57,11 +57,12 @@
57
57
  "typecheck": "tsc -p tsconfig.json --noEmit",
58
58
  "lint": "eslint src tests --config ../../eslint.config.mjs",
59
59
  "test": "vitest run",
60
- "prepack": "npm run build"
60
+ "prepack": "npm run build",
61
+ "eval:routing": "tsx tests/routing-eval/cli.ts"
61
62
  },
62
63
  "dependencies": {
63
64
  "@chat-adapter/telegram": "4.41.0",
64
- "@segmentstream-cloud/ontology": "0.31.5",
65
+ "@segmentstream-cloud/ontology": "0.32.0",
65
66
  "@vercel/oidc": "^3.8.4",
66
67
  "ai": "^7.0.128",
67
68
  "csv-parse": "^7.0.3",
@@ -72,6 +73,7 @@
72
73
  "mammoth": "^1.13.0",
73
74
  "marked": "15.0.12",
74
75
  "postal-mime": "^4.0.5",
76
+ "unpdf": "^1.9.0",
75
77
  "xlsx": "https://cdn.sheetjs.com/xlsx-0.20.3/xlsx-0.20.3.tgz"
76
78
  },
77
79
  "peerDependencies": {
@@ -81,7 +83,8 @@
81
83
  "@types/node": "^24",
82
84
  "eve": "0.76.3",
83
85
  "typescript": "^5.9",
84
- "vitest": "^4.1.11"
86
+ "vitest": "^4.1.11",
87
+ "tsx": "^4"
85
88
  },
86
89
  "publishConfig": {
87
90
  "access": "public"