@yagr/agent 0.1.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 (215) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +257 -0
  3. package/dist/agent.d.ts +21 -0
  4. package/dist/agent.d.ts.map +1 -0
  5. package/dist/agent.js +47 -0
  6. package/dist/agent.js.map +1 -0
  7. package/dist/cli.d.ts +3 -0
  8. package/dist/cli.d.ts.map +1 -0
  9. package/dist/cli.js +293 -0
  10. package/dist/cli.js.map +1 -0
  11. package/dist/config/init-yagr-home.d.ts +2 -0
  12. package/dist/config/init-yagr-home.d.ts.map +1 -0
  13. package/dist/config/init-yagr-home.js +6 -0
  14. package/dist/config/init-yagr-home.js.map +1 -0
  15. package/dist/config/load-env.d.ts +2 -0
  16. package/dist/config/load-env.d.ts.map +1 -0
  17. package/dist/config/load-env.js +20 -0
  18. package/dist/config/load-env.js.map +1 -0
  19. package/dist/config/load-n8n-engine-config.d.ts +6 -0
  20. package/dist/config/load-n8n-engine-config.d.ts.map +1 -0
  21. package/dist/config/load-n8n-engine-config.js +39 -0
  22. package/dist/config/load-n8n-engine-config.js.map +1 -0
  23. package/dist/config/yagr-config-service.d.ts +51 -0
  24. package/dist/config/yagr-config-service.d.ts.map +1 -0
  25. package/dist/config/yagr-config-service.js +103 -0
  26. package/dist/config/yagr-config-service.js.map +1 -0
  27. package/dist/config/yagr-home.d.ts +4 -0
  28. package/dist/config/yagr-home.d.ts.map +1 -0
  29. package/dist/config/yagr-home.js +25 -0
  30. package/dist/config/yagr-home.js.map +1 -0
  31. package/dist/engine/engine.d.ts +15 -0
  32. package/dist/engine/engine.d.ts.map +1 -0
  33. package/dist/engine/engine.js +2 -0
  34. package/dist/engine/engine.js.map +1 -0
  35. package/dist/engine/n8n-engine.d.ts +26 -0
  36. package/dist/engine/n8n-engine.d.ts.map +1 -0
  37. package/dist/engine/n8n-engine.js +200 -0
  38. package/dist/engine/n8n-engine.js.map +1 -0
  39. package/dist/engine/yagr-engine.d.ts +17 -0
  40. package/dist/engine/yagr-engine.d.ts.map +1 -0
  41. package/dist/engine/yagr-engine.js +37 -0
  42. package/dist/engine/yagr-engine.js.map +1 -0
  43. package/dist/gateway/cli.d.ts +8 -0
  44. package/dist/gateway/cli.d.ts.map +1 -0
  45. package/dist/gateway/cli.js +50 -0
  46. package/dist/gateway/cli.js.map +1 -0
  47. package/dist/gateway/history-viewport.d.ts +14 -0
  48. package/dist/gateway/history-viewport.d.ts.map +1 -0
  49. package/dist/gateway/history-viewport.js +51 -0
  50. package/dist/gateway/history-viewport.js.map +1 -0
  51. package/dist/gateway/interactive-ui.d.ts +4 -0
  52. package/dist/gateway/interactive-ui.d.ts.map +1 -0
  53. package/dist/gateway/interactive-ui.js +430 -0
  54. package/dist/gateway/interactive-ui.js.map +1 -0
  55. package/dist/gateway/manager.d.ts +25 -0
  56. package/dist/gateway/manager.d.ts.map +1 -0
  57. package/dist/gateway/manager.js +204 -0
  58. package/dist/gateway/manager.js.map +1 -0
  59. package/dist/gateway/telegram.d.ts +30 -0
  60. package/dist/gateway/telegram.d.ts.map +1 -0
  61. package/dist/gateway/telegram.js +406 -0
  62. package/dist/gateway/telegram.js.map +1 -0
  63. package/dist/gateway/types.d.ts +19 -0
  64. package/dist/gateway/types.d.ts.map +1 -0
  65. package/dist/gateway/types.js +2 -0
  66. package/dist/gateway/types.js.map +1 -0
  67. package/dist/gateway/webui.d.ts +13 -0
  68. package/dist/gateway/webui.d.ts.map +1 -0
  69. package/dist/gateway/webui.js +663 -0
  70. package/dist/gateway/webui.js.map +1 -0
  71. package/dist/index.d.ts +23 -0
  72. package/dist/index.d.ts.map +1 -0
  73. package/dist/index.js +15 -0
  74. package/dist/index.js.map +1 -0
  75. package/dist/llm/create-language-model.d.ts +31 -0
  76. package/dist/llm/create-language-model.d.ts.map +1 -0
  77. package/dist/llm/create-language-model.js +129 -0
  78. package/dist/llm/create-language-model.js.map +1 -0
  79. package/dist/prompt/build-system-prompt.d.ts +3 -0
  80. package/dist/prompt/build-system-prompt.d.ts.map +1 -0
  81. package/dist/prompt/build-system-prompt.js +64 -0
  82. package/dist/prompt/build-system-prompt.js.map +1 -0
  83. package/dist/runtime/completion-gate.d.ts +21 -0
  84. package/dist/runtime/completion-gate.d.ts.map +1 -0
  85. package/dist/runtime/completion-gate.js +59 -0
  86. package/dist/runtime/completion-gate.js.map +1 -0
  87. package/dist/runtime/context-compaction.d.ts +25 -0
  88. package/dist/runtime/context-compaction.d.ts.map +1 -0
  89. package/dist/runtime/context-compaction.js +197 -0
  90. package/dist/runtime/context-compaction.js.map +1 -0
  91. package/dist/runtime/outcome.d.ts +23 -0
  92. package/dist/runtime/outcome.d.ts.map +1 -0
  93. package/dist/runtime/outcome.js +89 -0
  94. package/dist/runtime/outcome.js.map +1 -0
  95. package/dist/runtime/policy-hooks.d.ts +15 -0
  96. package/dist/runtime/policy-hooks.d.ts.map +1 -0
  97. package/dist/runtime/policy-hooks.js +54 -0
  98. package/dist/runtime/policy-hooks.js.map +1 -0
  99. package/dist/runtime/required-actions.d.ts +5 -0
  100. package/dist/runtime/required-actions.d.ts.map +1 -0
  101. package/dist/runtime/required-actions.js +77 -0
  102. package/dist/runtime/required-actions.js.map +1 -0
  103. package/dist/runtime/run-engine.d.ts +15 -0
  104. package/dist/runtime/run-engine.d.ts.map +1 -0
  105. package/dist/runtime/run-engine.js +624 -0
  106. package/dist/runtime/run-engine.js.map +1 -0
  107. package/dist/setup/setup-wizard.d.ts +52 -0
  108. package/dist/setup/setup-wizard.d.ts.map +1 -0
  109. package/dist/setup/setup-wizard.js +613 -0
  110. package/dist/setup/setup-wizard.js.map +1 -0
  111. package/dist/setup/start-launcher.d.ts +22 -0
  112. package/dist/setup/start-launcher.d.ts.map +1 -0
  113. package/dist/setup/start-launcher.js +76 -0
  114. package/dist/setup/start-launcher.js.map +1 -0
  115. package/dist/setup.d.ts +20 -0
  116. package/dist/setup.d.ts.map +1 -0
  117. package/dist/setup.js +247 -0
  118. package/dist/setup.js.map +1 -0
  119. package/dist/tools/build-tools.d.ts +608 -0
  120. package/dist/tools/build-tools.d.ts.map +1 -0
  121. package/dist/tools/build-tools.js +35 -0
  122. package/dist/tools/build-tools.js.map +1 -0
  123. package/dist/tools/delete-workspace-file.d.ts +38 -0
  124. package/dist/tools/delete-workspace-file.d.ts.map +1 -0
  125. package/dist/tools/delete-workspace-file.js +31 -0
  126. package/dist/tools/delete-workspace-file.js.map +1 -0
  127. package/dist/tools/deploy.d.ts +110 -0
  128. package/dist/tools/deploy.d.ts.map +1 -0
  129. package/dist/tools/deploy.js +28 -0
  130. package/dist/tools/deploy.js.map +1 -0
  131. package/dist/tools/generate-workflow.d.ts +180 -0
  132. package/dist/tools/generate-workflow.d.ts.map +1 -0
  133. package/dist/tools/generate-workflow.js +46 -0
  134. package/dist/tools/generate-workflow.js.map +1 -0
  135. package/dist/tools/index.d.ts +20 -0
  136. package/dist/tools/index.d.ts.map +1 -0
  137. package/dist/tools/index.js +20 -0
  138. package/dist/tools/index.js.map +1 -0
  139. package/dist/tools/list-directory.d.ts +48 -0
  140. package/dist/tools/list-directory.d.ts.map +1 -0
  141. package/dist/tools/list-directory.js +61 -0
  142. package/dist/tools/list-directory.js.map +1 -0
  143. package/dist/tools/list-workflows.d.ts +18 -0
  144. package/dist/tools/list-workflows.d.ts.map +1 -0
  145. package/dist/tools/list-workflows.js +17 -0
  146. package/dist/tools/list-workflows.js.map +1 -0
  147. package/dist/tools/manage-workflow.d.ts +42 -0
  148. package/dist/tools/manage-workflow.d.ts.map +1 -0
  149. package/dist/tools/manage-workflow.js +26 -0
  150. package/dist/tools/manage-workflow.js.map +1 -0
  151. package/dist/tools/move-workspace-file.d.ts +42 -0
  152. package/dist/tools/move-workspace-file.d.ts.map +1 -0
  153. package/dist/tools/move-workspace-file.js +45 -0
  154. package/dist/tools/move-workspace-file.js.map +1 -0
  155. package/dist/tools/n8nac.d.ts +144 -0
  156. package/dist/tools/n8nac.d.ts.map +1 -0
  157. package/dist/tools/n8nac.js +349 -0
  158. package/dist/tools/n8nac.js.map +1 -0
  159. package/dist/tools/node-info.d.ts +18 -0
  160. package/dist/tools/node-info.d.ts.map +1 -0
  161. package/dist/tools/node-info.js +15 -0
  162. package/dist/tools/node-info.js.map +1 -0
  163. package/dist/tools/observer.d.ts +32 -0
  164. package/dist/tools/observer.d.ts.map +1 -0
  165. package/dist/tools/observer.js +10 -0
  166. package/dist/tools/observer.js.map +1 -0
  167. package/dist/tools/read-workspace-file.d.ts +54 -0
  168. package/dist/tools/read-workspace-file.d.ts.map +1 -0
  169. package/dist/tools/read-workspace-file.js +49 -0
  170. package/dist/tools/read-workspace-file.js.map +1 -0
  171. package/dist/tools/replace-in-workspace-file.d.ts +62 -0
  172. package/dist/tools/replace-in-workspace-file.d.ts.map +1 -0
  173. package/dist/tools/replace-in-workspace-file.js +46 -0
  174. package/dist/tools/replace-in-workspace-file.js.map +1 -0
  175. package/dist/tools/report-progress.d.ts +20 -0
  176. package/dist/tools/report-progress.d.ts.map +1 -0
  177. package/dist/tools/report-progress.js +20 -0
  178. package/dist/tools/report-progress.js.map +1 -0
  179. package/dist/tools/request-required-action.d.ts +31 -0
  180. package/dist/tools/request-required-action.d.ts.map +1 -0
  181. package/dist/tools/request-required-action.js +33 -0
  182. package/dist/tools/request-required-action.js.map +1 -0
  183. package/dist/tools/search-nodes.d.ts +18 -0
  184. package/dist/tools/search-nodes.d.ts.map +1 -0
  185. package/dist/tools/search-nodes.js +15 -0
  186. package/dist/tools/search-nodes.js.map +1 -0
  187. package/dist/tools/search-templates.d.ts +18 -0
  188. package/dist/tools/search-templates.d.ts.map +1 -0
  189. package/dist/tools/search-templates.js +15 -0
  190. package/dist/tools/search-templates.js.map +1 -0
  191. package/dist/tools/search-workspace.d.ts +55 -0
  192. package/dist/tools/search-workspace.d.ts.map +1 -0
  193. package/dist/tools/search-workspace.js +86 -0
  194. package/dist/tools/search-workspace.js.map +1 -0
  195. package/dist/tools/validate.d.ts +110 -0
  196. package/dist/tools/validate.d.ts.map +1 -0
  197. package/dist/tools/validate.js +28 -0
  198. package/dist/tools/validate.js.map +1 -0
  199. package/dist/tools/workspace-utils.d.ts +10 -0
  200. package/dist/tools/workspace-utils.d.ts.map +1 -0
  201. package/dist/tools/workspace-utils.js +63 -0
  202. package/dist/tools/workspace-utils.js.map +1 -0
  203. package/dist/tools/write-workspace-file.d.ts +46 -0
  204. package/dist/tools/write-workspace-file.d.ts.map +1 -0
  205. package/dist/tools/write-workspace-file.js +39 -0
  206. package/dist/tools/write-workspace-file.js.map +1 -0
  207. package/dist/types.d.ts +243 -0
  208. package/dist/types.d.ts.map +1 -0
  209. package/dist/types.js +2 -0
  210. package/dist/types.js.map +1 -0
  211. package/dist/webui/app.js +26759 -0
  212. package/dist/webui/app.js.map +7 -0
  213. package/dist/webui/styles.css +740 -0
  214. package/dist/webui/styles.css.map +7 -0
  215. package/package.json +72 -0
@@ -0,0 +1,204 @@
1
+ import qrcode from 'qrcode-terminal';
2
+ import { YagrConfigService } from '../config/yagr-config-service.js';
3
+ import { createTelegramGatewayRuntime, getTelegramGatewayStatus } from './telegram.js';
4
+ import { createWebUiGatewayRuntime, getWebUiGatewayStatus } from './webui.js';
5
+ function summarizeTelegramStatus(status) {
6
+ if (!status.configured || !status.botUsername) {
7
+ return 'Not configured';
8
+ }
9
+ const linkedCount = status.linkedChats.length;
10
+ const chatSummary = linkedCount === 1 ? '1 linked chat' : `${linkedCount} linked chats`;
11
+ return `@${status.botUsername}, ${chatSummary}`;
12
+ }
13
+ function summarizeWebUiStatus(status) {
14
+ if (!status.configured) {
15
+ return 'Not configured';
16
+ }
17
+ return status.url;
18
+ }
19
+ const GATEWAY_DESCRIPTORS = [
20
+ {
21
+ id: 'telegram',
22
+ label: 'Telegram',
23
+ getStatus: (configService, enabled) => {
24
+ const status = getTelegramGatewayStatus(configService);
25
+ return {
26
+ id: 'telegram',
27
+ label: 'Telegram',
28
+ enabled,
29
+ configured: status.configured,
30
+ implemented: true,
31
+ summary: summarizeTelegramStatus(status),
32
+ details: {
33
+ botUsername: status.botUsername,
34
+ linkedChats: status.linkedChats,
35
+ deepLink: status.deepLink,
36
+ },
37
+ };
38
+ },
39
+ createRuntime: async (engineResolver, options, configService) => createTelegramGatewayRuntime(engineResolver, options, configService),
40
+ },
41
+ {
42
+ id: 'webui',
43
+ label: 'Web UI',
44
+ getStatus: (configService, enabled) => {
45
+ const status = getWebUiGatewayStatus(configService);
46
+ return {
47
+ id: 'webui',
48
+ label: 'Web UI',
49
+ enabled,
50
+ configured: status.configured,
51
+ implemented: true,
52
+ summary: summarizeWebUiStatus(status),
53
+ details: {
54
+ url: status.url,
55
+ host: status.host,
56
+ port: status.port,
57
+ },
58
+ };
59
+ },
60
+ createRuntime: async (engineResolver, options, configService) => createWebUiGatewayRuntime(engineResolver, options, configService),
61
+ },
62
+ {
63
+ id: 'whatsapp',
64
+ label: 'WhatsApp',
65
+ getStatus: (_configService, enabled) => ({
66
+ id: 'whatsapp',
67
+ label: 'WhatsApp',
68
+ enabled,
69
+ configured: false,
70
+ implemented: false,
71
+ summary: 'Not implemented yet',
72
+ }),
73
+ },
74
+ ];
75
+ export function buildGatewaySupervisorStatus(surfaces) {
76
+ const normalizedSurfaces = surfaces.map((surface) => ({
77
+ ...surface,
78
+ startable: surface.enabled && surface.configured && surface.implemented,
79
+ }));
80
+ const warnings = normalizedSurfaces.flatMap((surface) => {
81
+ if (!surface.enabled) {
82
+ return [];
83
+ }
84
+ if (!surface.implemented) {
85
+ return [`${surface.label} is enabled but not implemented yet.`];
86
+ }
87
+ if (!surface.configured) {
88
+ return [`${surface.label} is enabled but not configured.`];
89
+ }
90
+ return [];
91
+ });
92
+ return {
93
+ enabledSurfaces: normalizedSurfaces.filter((surface) => surface.enabled).map((surface) => surface.id),
94
+ startableSurfaces: normalizedSurfaces.filter((surface) => surface.startable).map((surface) => surface.id),
95
+ surfaces: normalizedSurfaces,
96
+ warnings,
97
+ };
98
+ }
99
+ export function getGatewaySupervisorStatus(configService = new YagrConfigService()) {
100
+ const enabledSurfaces = configService.getEnabledGatewaySurfaces();
101
+ return buildGatewaySupervisorStatus(GATEWAY_DESCRIPTORS.map((descriptor) => descriptor.getStatus(configService, enabledSurfaces.includes(descriptor.id))));
102
+ }
103
+ async function stopRuntimeHandles(runtimes) {
104
+ await Promise.allSettled(runtimes.map(async (runtime) => {
105
+ await runtime.gateway.stop();
106
+ }));
107
+ }
108
+ export async function runGatewaySurfaces(surfaces, engineResolver, options = {}, configService = new YagrConfigService()) {
109
+ const requestedSurfaces = Array.from(new Set(surfaces));
110
+ if (requestedSurfaces.length === 0) {
111
+ throw new Error('No gateway surfaces were selected.');
112
+ }
113
+ const runtimes = [];
114
+ try {
115
+ for (const surface of requestedSurfaces) {
116
+ const descriptor = GATEWAY_DESCRIPTORS.find((entry) => entry.id === surface);
117
+ if (!descriptor || !descriptor.createRuntime) {
118
+ throw new Error(`${surface} is not implemented yet.`);
119
+ }
120
+ const status = descriptor.getStatus(configService, true);
121
+ if (!status.implemented) {
122
+ throw new Error(`${descriptor.label} is not implemented yet.`);
123
+ }
124
+ if (!status.configured) {
125
+ throw new Error(`${descriptor.label} is not configured.`);
126
+ }
127
+ const runtime = await descriptor.createRuntime(engineResolver, options, configService);
128
+ await runtime.gateway.start();
129
+ runtimes.push(runtime);
130
+ for (const line of runtime.startupMessages) {
131
+ process.stdout.write(`${line}\n`);
132
+ }
133
+ if (runtime.onboardingLink) {
134
+ process.stdout.write(`Onboarding link: ${runtime.onboardingLink}\n`);
135
+ qrcode.generate(runtime.onboardingLink, { small: true });
136
+ }
137
+ }
138
+ }
139
+ catch (error) {
140
+ await stopRuntimeHandles(runtimes);
141
+ throw error;
142
+ }
143
+ process.stdout.write(`Yagr gateway active. Surfaces: ${requestedSurfaces.join(', ')}.\n`);
144
+ await new Promise((resolve) => {
145
+ const stop = async () => {
146
+ await stopRuntimeHandles(runtimes);
147
+ resolve();
148
+ };
149
+ process.once('SIGINT', () => {
150
+ void stop();
151
+ });
152
+ process.once('SIGTERM', () => {
153
+ void stop();
154
+ });
155
+ });
156
+ }
157
+ export async function runGatewaySupervisor(engineResolver, options = {}, configService = new YagrConfigService()) {
158
+ const status = getGatewaySupervisorStatus(configService);
159
+ if (status.startableSurfaces.length === 0) {
160
+ const message = status.warnings[0] ?? 'No enabled and configured gateway surfaces are available.';
161
+ throw new Error(message);
162
+ }
163
+ const runtimes = [];
164
+ try {
165
+ for (const descriptor of GATEWAY_DESCRIPTORS) {
166
+ if (!status.startableSurfaces.includes(descriptor.id) || !descriptor.createRuntime) {
167
+ continue;
168
+ }
169
+ const runtime = await descriptor.createRuntime(engineResolver, options, configService);
170
+ await runtime.gateway.start();
171
+ runtimes.push(runtime);
172
+ for (const line of runtime.startupMessages) {
173
+ process.stdout.write(`${line}\n`);
174
+ }
175
+ if (runtime.onboardingLink) {
176
+ process.stdout.write(`Onboarding link: ${runtime.onboardingLink}\n`);
177
+ qrcode.generate(runtime.onboardingLink, { small: true });
178
+ }
179
+ }
180
+ }
181
+ catch (error) {
182
+ await stopRuntimeHandles(runtimes);
183
+ throw error;
184
+ }
185
+ process.stdout.write(`Yagr gateway supervisor active. Surfaces: ${status.startableSurfaces.join(', ')}.\n`);
186
+ if (status.warnings.length > 0) {
187
+ for (const warning of status.warnings) {
188
+ process.stdout.write(`Warning: ${warning}\n`);
189
+ }
190
+ }
191
+ await new Promise((resolve) => {
192
+ const stop = async () => {
193
+ await stopRuntimeHandles(runtimes);
194
+ resolve();
195
+ };
196
+ process.once('SIGINT', () => {
197
+ void stop();
198
+ });
199
+ process.once('SIGTERM', () => {
200
+ void stop();
201
+ });
202
+ });
203
+ }
204
+ //# sourceMappingURL=manager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manager.js","sourceRoot":"","sources":["../../src/gateway/manager.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,30 @@
1
+ import { YagrConfigService, type YagrTelegramLinkedChat } from '../config/yagr-config-service.js';
2
+ import type { Engine } from '../engine/engine.js';
3
+ import type { YagrRunOptions } from '../types.js';
4
+ import type { GatewayRuntimeHandle } from './types.js';
5
+ export declare function createOnboardingToken(): string;
6
+ export declare function buildTelegramDeepLink(botUsername: string, onboardingToken: string): string;
7
+ export declare function upsertLinkedChat(chats: YagrTelegramLinkedChat[], nextChat: YagrTelegramLinkedChat): YagrTelegramLinkedChat[];
8
+ export declare function removeLinkedChat(chats: YagrTelegramLinkedChat[], chatId: string): YagrTelegramLinkedChat[];
9
+ export declare function splitTelegramMessage(text: string, limit?: number): string[];
10
+ interface TelegramGatewayRuntimeOptions extends YagrRunOptions {
11
+ botToken?: string;
12
+ }
13
+ export interface TelegramGatewayStatus {
14
+ configured: boolean;
15
+ botUsername?: string;
16
+ linkedChats: YagrTelegramLinkedChat[];
17
+ deepLink?: string;
18
+ }
19
+ export declare function resolveTelegramBotIdentity(botToken: string): Promise<{
20
+ username: string;
21
+ firstName: string;
22
+ }>;
23
+ export declare function setupTelegramGateway(configService?: YagrConfigService): Promise<void>;
24
+ export declare function showTelegramOnboarding(configService?: YagrConfigService): void;
25
+ export declare function getTelegramGatewayStatus(configService?: YagrConfigService): TelegramGatewayStatus;
26
+ export declare function resetTelegramGateway(configService?: YagrConfigService): void;
27
+ export declare function createTelegramGatewayRuntime(engineResolver: () => Promise<Engine>, options?: TelegramGatewayRuntimeOptions, configService?: YagrConfigService): GatewayRuntimeHandle;
28
+ export declare function runTelegramGateway(engineResolver: () => Promise<Engine>, options?: TelegramGatewayRuntimeOptions, configService?: YagrConfigService): Promise<void>;
29
+ export {};
30
+ //# sourceMappingURL=telegram.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"telegram.d.ts","sourceRoot":"","sources":["../../src/gateway/telegram.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,iBAAiB,EAAE,KAAK,sBAAsB,EAAE,MAAM,kCAAkC,CAAC;AAClG,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,KAAK,EAAsB,cAAc,EAAE,MAAM,aAAa,CAAC;AACtE,OAAO,KAAK,EAAW,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAIhE,wBAAgB,qBAAqB,IAAI,MAAM,CAE9C;AAED,wBAAgB,qBAAqB,CAAC,WAAW,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,GAAG,MAAM,CAE1F;AAED,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,sBAAsB,EAAE,EAC/B,QAAQ,EAAE,sBAAsB,GAC/B,sBAAsB,EAAE,CAa1B;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,sBAAsB,EAAE,EAAE,MAAM,EAAE,MAAM,GAAG,sBAAsB,EAAE,CAE1G;AAED,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,SAAyB,GAAG,MAAM,EAAE,CAsB3F;AAED,UAAU,6BAA8B,SAAQ,cAAc;IAC5D,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,qBAAqB;IACpC,UAAU,EAAE,OAAO,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,sBAAsB,EAAE,CAAC;IACtC,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AA4BD,wBAAsB,0BAA0B,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAAC,CAWnH;AAED,wBAAsB,oBAAoB,CAAC,aAAa,oBAA0B,GAAG,OAAO,CAAC,IAAI,CAAC,CA+CjG;AAED,wBAAgB,sBAAsB,CAAC,aAAa,oBAA0B,GAAG,IAAI,CAmBpF;AAED,wBAAgB,wBAAwB,CAAC,aAAa,oBAA0B,GAAG,qBAAqB,CAevG;AAED,wBAAgB,oBAAoB,CAAC,aAAa,oBAA0B,GAAG,IAAI,CAQlF;AAED,wBAAgB,4BAA4B,CAC1C,cAAc,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,EACrC,OAAO,GAAE,6BAAkC,EAC3C,aAAa,oBAA0B,GACtC,oBAAoB,CAmBtB;AAwPD,wBAAsB,kBAAkB,CACtC,cAAc,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,EACrC,OAAO,GAAE,6BAAkC,EAC3C,aAAa,oBAA0B,GACtC,OAAO,CAAC,IAAI,CAAC,CA0Bf"}
@@ -0,0 +1,406 @@
1
+ import { randomBytes } from 'node:crypto';
2
+ import qrcode from 'qrcode-terminal';
3
+ import { Telegraf } from 'telegraf';
4
+ import { YagrAgent } from '../agent.js';
5
+ import { YagrConfigService } from '../config/yagr-config-service.js';
6
+ const TELEGRAM_MESSAGE_LIMIT = 4096;
7
+ export function createOnboardingToken() {
8
+ return randomBytes(18).toString('base64url');
9
+ }
10
+ export function buildTelegramDeepLink(botUsername, onboardingToken) {
11
+ return `https://t.me/${botUsername}?start=${onboardingToken}`;
12
+ }
13
+ export function upsertLinkedChat(chats, nextChat) {
14
+ const chatId = String(nextChat.chatId);
15
+ const existing = chats.find((entry) => String(entry.chatId) === chatId);
16
+ if (!existing) {
17
+ return [...chats, { ...nextChat, chatId }];
18
+ }
19
+ return chats.map((entry) => (String(entry.chatId) === chatId
20
+ ? { ...entry, ...nextChat, chatId }
21
+ : entry));
22
+ }
23
+ export function removeLinkedChat(chats, chatId) {
24
+ return chats.filter((entry) => String(entry.chatId) !== String(chatId));
25
+ }
26
+ export function splitTelegramMessage(text, limit = TELEGRAM_MESSAGE_LIMIT) {
27
+ const normalized = text.trim();
28
+ if (!normalized) {
29
+ return [];
30
+ }
31
+ const chunks = [];
32
+ let remaining = normalized;
33
+ while (remaining.length > limit) {
34
+ const candidate = remaining.slice(0, limit);
35
+ const splitAt = Math.max(candidate.lastIndexOf('\n\n'), candidate.lastIndexOf('\n'), candidate.lastIndexOf(' '));
36
+ const cut = splitAt > Math.floor(limit * 0.6) ? splitAt : limit;
37
+ chunks.push(remaining.slice(0, cut).trim());
38
+ remaining = remaining.slice(cut).trim();
39
+ }
40
+ if (remaining) {
41
+ chunks.push(remaining);
42
+ }
43
+ return chunks;
44
+ }
45
+ function buildTelegramTokenInstructions() {
46
+ return [
47
+ '1) Open Telegram and chat with @BotFather',
48
+ '2) Run /newbot (or /mybots)',
49
+ '3) Copy the token (looks like 123456:ABC...)',
50
+ 'Yagr stores this token during setup.',
51
+ 'Docs: https://core.telegram.org/bots#how-do-i-create-a-bot',
52
+ ].join('\n');
53
+ }
54
+ function formatLinkedChatCount(count) {
55
+ return count === 1 ? '1 chat lie' : `${count} chats lies`;
56
+ }
57
+ function formatRequiredActions(actions) {
58
+ if (actions.length === 0) {
59
+ return '';
60
+ }
61
+ return [
62
+ 'Actions requises :',
63
+ ...actions.map((action) => `- ${action.title}: ${action.message}`),
64
+ 'Utilise /approve pour reprendre si la demande est approuvable.',
65
+ ].join('\n');
66
+ }
67
+ export async function resolveTelegramBotIdentity(botToken) {
68
+ const bot = new Telegraf(botToken);
69
+ const me = await bot.telegram.getMe();
70
+ if (!me.username) {
71
+ throw new Error('Telegram bot username is missing. Configure the bot with BotFather first.');
72
+ }
73
+ return {
74
+ username: me.username,
75
+ firstName: me.first_name,
76
+ };
77
+ }
78
+ export async function setupTelegramGateway(configService = new YagrConfigService()) {
79
+ const currentToken = configService.getTelegramBotToken() ?? '';
80
+ if (!currentToken) {
81
+ process.stdout.write(`\nTo create a Telegram bot token:\n${buildTelegramTokenInstructions()}\n`);
82
+ }
83
+ const readline = await import('node:readline/promises');
84
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
85
+ let botToken;
86
+ try {
87
+ if (currentToken) {
88
+ const answer = await rl.question(`Reuse saved token? [Y/n] `);
89
+ botToken = answer.trim().toLowerCase() === 'n' ? await rl.question('Telegram bot token: ') : currentToken;
90
+ }
91
+ else {
92
+ botToken = await rl.question('Telegram bot token: ');
93
+ }
94
+ }
95
+ finally {
96
+ rl.close();
97
+ }
98
+ if (!botToken.includes(':'))
99
+ throw new Error('Invalid Telegram bot token format.');
100
+ process.stdout.write('Verifying token...\n');
101
+ const identity = await resolveTelegramBotIdentity(botToken);
102
+ configService.saveTelegramBotToken(botToken);
103
+ const nextConfig = configService.updateLocalConfig((localConfig) => ({
104
+ ...localConfig,
105
+ telegram: {
106
+ ...localConfig.telegram,
107
+ botUsername: identity.username,
108
+ onboardingToken: localConfig.telegram?.onboardingToken ?? createOnboardingToken(),
109
+ linkedChats: localConfig.telegram?.linkedChats ?? [],
110
+ },
111
+ }));
112
+ configService.enableGatewaySurface('telegram');
113
+ const deepLink = buildTelegramDeepLink(nextConfig.telegram?.botUsername ?? identity.username, nextConfig.telegram?.onboardingToken ?? createOnboardingToken());
114
+ process.stdout.write(`\nTelegram bot ready: @${identity.username}\nOnboarding link: ${deepLink}\n`);
115
+ qrcode.generate(deepLink, { small: true });
116
+ process.stdout.write('Gateway saved. Start with `yagr gateway start`.\n');
117
+ }
118
+ export function showTelegramOnboarding(configService = new YagrConfigService()) {
119
+ const status = getTelegramGatewayStatus(configService);
120
+ if (!status.configured || !status.botUsername || !status.deepLink) {
121
+ throw new Error('Telegram is not configured. Run `yagr telegram setup` first.');
122
+ }
123
+ process.stdout.write([
124
+ '',
125
+ `Bot: @${status.botUsername}`,
126
+ `Onboarding link: ${status.deepLink}`,
127
+ `Linked chats: ${formatLinkedChatCount(status.linkedChats.length)}`,
128
+ '',
129
+ 'Scan the QR or open the link, then press Start in Telegram.',
130
+ '',
131
+ ].join('\n'));
132
+ qrcode.generate(status.deepLink, { small: true });
133
+ }
134
+ export function getTelegramGatewayStatus(configService = new YagrConfigService()) {
135
+ const localConfig = configService.getLocalConfig();
136
+ const telegram = localConfig.telegram;
137
+ const botToken = configService.getTelegramBotToken();
138
+ const linkedChats = telegram?.linkedChats ?? [];
139
+ const deepLink = telegram?.botUsername && telegram.onboardingToken
140
+ ? buildTelegramDeepLink(telegram.botUsername, telegram.onboardingToken)
141
+ : undefined;
142
+ return {
143
+ configured: Boolean(botToken && telegram?.botUsername && telegram?.onboardingToken),
144
+ botUsername: telegram?.botUsername,
145
+ linkedChats,
146
+ deepLink,
147
+ };
148
+ }
149
+ export function resetTelegramGateway(configService = new YagrConfigService()) {
150
+ configService.clearTelegramBotToken();
151
+ configService.disableGatewaySurface('telegram');
152
+ configService.updateLocalConfig((localConfig) => {
153
+ const nextConfig = { ...localConfig };
154
+ delete nextConfig.telegram;
155
+ return nextConfig;
156
+ });
157
+ }
158
+ export function createTelegramGatewayRuntime(engineResolver, options = {}, configService = new YagrConfigService()) {
159
+ const status = getTelegramGatewayStatus(configService);
160
+ const botToken = options.botToken ?? configService.getTelegramBotToken();
161
+ const onboardingToken = configService.getLocalConfig().telegram?.onboardingToken;
162
+ if (!botToken || !status.botUsername || !onboardingToken) {
163
+ throw new Error('Telegram is not configured. Run `yagr telegram setup` first.');
164
+ }
165
+ const linkedCount = status.linkedChats.length;
166
+ return {
167
+ gateway: new TelegramGateway(engineResolver, options, configService, botToken, onboardingToken),
168
+ startupMessages: [
169
+ `Yagr Telegram gateway listening as @${status.botUsername}. ${formatLinkedChatCount(linkedCount)}.`,
170
+ 'Telegram transport is ready. The current orchestrator connection will be resolved on first message.',
171
+ ],
172
+ onboardingLink: status.deepLink && linkedCount === 0 ? status.deepLink : undefined,
173
+ };
174
+ }
175
+ class TelegramGateway {
176
+ engineResolver;
177
+ options;
178
+ configService;
179
+ onboardingToken;
180
+ bot;
181
+ agents = new Map();
182
+ runningChats = new Set();
183
+ pendingApprovals = new Map();
184
+ enginePromise;
185
+ stopped = false;
186
+ constructor(engineResolver, options, configService, botToken, onboardingToken) {
187
+ this.engineResolver = engineResolver;
188
+ this.options = options;
189
+ this.configService = configService;
190
+ this.onboardingToken = onboardingToken;
191
+ this.bot = new Telegraf(botToken);
192
+ }
193
+ async start() {
194
+ this.bot.start(async (ctx) => {
195
+ const payload = typeof ctx.payload === 'string' ? ctx.payload.trim() : '';
196
+ const chatId = String(ctx.chat.id);
197
+ if (payload !== this.onboardingToken) {
198
+ await ctx.reply('Ce bot n’est pas encore lie a cette conversation. Utilise le QR ou le lien genere par `yagr telegram setup`.');
199
+ return;
200
+ }
201
+ this.linkChat({
202
+ chatId,
203
+ userId: String(ctx.from?.id ?? ''),
204
+ username: ctx.from?.username,
205
+ firstName: ctx.from?.first_name,
206
+ linkedAt: new Date().toISOString(),
207
+ lastSeenAt: new Date().toISOString(),
208
+ });
209
+ await ctx.reply('Yagr est maintenant lie a ce chat. Tu peux me parler directement ici.');
210
+ });
211
+ this.bot.command('status', async (ctx) => {
212
+ const chatId = String(ctx.chat.id);
213
+ if (!this.isLinkedChat(chatId)) {
214
+ await ctx.reply('Chat non lie. Utilise le QR ou le lien d’onboarding d’abord.');
215
+ return;
216
+ }
217
+ const linkedChats = this.configService.getLocalConfig().telegram?.linkedChats ?? [];
218
+ await ctx.reply(`Gateway Telegram actif. ${formatLinkedChatCount(linkedChats.length)}.`);
219
+ });
220
+ this.bot.command('pending', async (ctx) => {
221
+ const chatId = String(ctx.chat.id);
222
+ const actions = this.pendingApprovals.get(chatId) ?? [];
223
+ if (actions.length === 0) {
224
+ await ctx.reply('Aucune action en attente.');
225
+ return;
226
+ }
227
+ await ctx.reply(formatRequiredActions(actions));
228
+ });
229
+ this.bot.command('approve', async (ctx) => {
230
+ const chatId = String(ctx.chat.id);
231
+ if (!this.isLinkedChat(chatId)) {
232
+ await ctx.reply('Chat non lie.');
233
+ return;
234
+ }
235
+ const actions = this.pendingApprovals.get(chatId) ?? [];
236
+ if (actions.length === 0) {
237
+ await ctx.reply('Aucune action approuvable en attente.');
238
+ return;
239
+ }
240
+ await this.executeRun(chatId, 'Permission granted. Continue the current task and execute the previously blocked step now.', actions, ctx.reply.bind(ctx));
241
+ });
242
+ this.bot.command('reset', async (ctx) => {
243
+ const chatId = String(ctx.chat.id);
244
+ this.agents.delete(chatId);
245
+ this.pendingApprovals.delete(chatId);
246
+ await ctx.reply('Conversation Yagr reinitialisee pour ce chat.');
247
+ });
248
+ this.bot.command('unlink', async (ctx) => {
249
+ const chatId = String(ctx.chat.id);
250
+ if (!this.isLinkedChat(chatId)) {
251
+ await ctx.reply('Ce chat n’est pas lie.');
252
+ return;
253
+ }
254
+ this.unlinkChat(chatId);
255
+ this.agents.delete(chatId);
256
+ this.pendingApprovals.delete(chatId);
257
+ await ctx.reply('Chat delie. Relance le lien/QR d’onboarding pour te reconnecter.');
258
+ });
259
+ this.bot.on('text', async (ctx) => {
260
+ const chatId = String(ctx.chat.id);
261
+ const text = ctx.message.text.trim();
262
+ if (!text || text.startsWith('/')) {
263
+ return;
264
+ }
265
+ if (ctx.chat.type !== 'private') {
266
+ await ctx.reply('Telegram supporte seulement les chats prives pour le moment.');
267
+ return;
268
+ }
269
+ if (!this.isLinkedChat(chatId)) {
270
+ await ctx.reply('Ce chat n’est pas encore lie. Utilise le QR ou le lien d’onboarding d’abord.');
271
+ return;
272
+ }
273
+ this.touchChat(chatId, ctx.from?.id, ctx.from?.username, ctx.from?.first_name);
274
+ await this.executeRun(chatId, text, [], ctx.reply.bind(ctx));
275
+ });
276
+ await this.bot.launch({ dropPendingUpdates: false });
277
+ }
278
+ async stop() {
279
+ if (this.stopped) {
280
+ return;
281
+ }
282
+ this.stopped = true;
283
+ this.bot.stop('Yagr Telegram gateway stopping');
284
+ }
285
+ async reply(chatId, message) {
286
+ const parts = splitTelegramMessage(message);
287
+ for (const part of parts) {
288
+ await this.bot.telegram.sendMessage(Number(chatId), part);
289
+ }
290
+ }
291
+ linkChat(chat) {
292
+ this.configService.updateLocalConfig((localConfig) => ({
293
+ ...localConfig,
294
+ telegram: {
295
+ ...localConfig.telegram,
296
+ linkedChats: upsertLinkedChat(localConfig.telegram?.linkedChats ?? [], chat),
297
+ },
298
+ }));
299
+ }
300
+ unlinkChat(chatId) {
301
+ this.configService.updateLocalConfig((localConfig) => ({
302
+ ...localConfig,
303
+ telegram: {
304
+ ...localConfig.telegram,
305
+ linkedChats: removeLinkedChat(localConfig.telegram?.linkedChats ?? [], chatId),
306
+ },
307
+ }));
308
+ }
309
+ touchChat(chatId, userId, username, firstName) {
310
+ const current = this.configService.getLocalConfig().telegram?.linkedChats ?? [];
311
+ const existing = current.find((entry) => String(entry.chatId) === String(chatId));
312
+ if (!existing) {
313
+ return;
314
+ }
315
+ this.linkChat({
316
+ ...existing,
317
+ chatId: String(chatId),
318
+ userId: userId ? String(userId) : existing.userId,
319
+ username: username ?? existing.username,
320
+ firstName: firstName ?? existing.firstName,
321
+ lastSeenAt: new Date().toISOString(),
322
+ });
323
+ }
324
+ isLinkedChat(chatId) {
325
+ const linkedChats = this.configService.getLocalConfig().telegram?.linkedChats ?? [];
326
+ return linkedChats.some((entry) => String(entry.chatId) === String(chatId));
327
+ }
328
+ async getEngine() {
329
+ this.enginePromise ??= this.engineResolver();
330
+ return await this.enginePromise;
331
+ }
332
+ async getAgent(chatId) {
333
+ const existing = this.agents.get(chatId);
334
+ if (existing) {
335
+ return existing;
336
+ }
337
+ const next = new YagrAgent(await this.getEngine());
338
+ this.agents.set(chatId, next);
339
+ return next;
340
+ }
341
+ async executeRun(chatId, prompt, satisfiedRequiredActions, reply) {
342
+ if (this.runningChats.has(chatId)) {
343
+ await reply('Un run est deja en cours pour ce chat. Attends sa fin avant d’envoyer une nouvelle demande.');
344
+ return;
345
+ }
346
+ this.runningChats.add(chatId);
347
+ try {
348
+ await reply('Yagr travaille...');
349
+ const result = await (await this.getAgent(chatId)).run(prompt, {
350
+ ...this.options,
351
+ display: undefined,
352
+ satisfiedRequiredActionIds: satisfiedRequiredActions.map((action) => action.id),
353
+ });
354
+ if (result.requiredActions.length > 0) {
355
+ this.pendingApprovals.set(chatId, result.requiredActions);
356
+ }
357
+ else {
358
+ this.pendingApprovals.delete(chatId);
359
+ }
360
+ const sections = [result.text.trim()];
361
+ const requiredActionsText = formatRequiredActions(result.requiredActions);
362
+ if (requiredActionsText) {
363
+ sections.push(requiredActionsText);
364
+ }
365
+ const message = sections.filter(Boolean).join('\n\n');
366
+ if (!message) {
367
+ await reply('Run termine, mais aucune reponse textuelle n’a ete produite.');
368
+ return;
369
+ }
370
+ for (const chunk of splitTelegramMessage(message)) {
371
+ await reply(chunk);
372
+ }
373
+ }
374
+ catch (error) {
375
+ const message = error instanceof Error ? error.message : String(error);
376
+ await reply(`Run echoue: ${message}`);
377
+ }
378
+ finally {
379
+ this.runningChats.delete(chatId);
380
+ }
381
+ }
382
+ }
383
+ export async function runTelegramGateway(engineResolver, options = {}, configService = new YagrConfigService()) {
384
+ const runtime = createTelegramGatewayRuntime(engineResolver, options, configService);
385
+ for (const line of runtime.startupMessages) {
386
+ process.stdout.write(`${line}\n`);
387
+ }
388
+ if (runtime.onboardingLink) {
389
+ process.stdout.write(`Onboarding link: ${runtime.onboardingLink}\n`);
390
+ qrcode.generate(runtime.onboardingLink, { small: true });
391
+ }
392
+ await runtime.gateway.start();
393
+ await new Promise((resolve) => {
394
+ const stop = async () => {
395
+ await runtime.gateway.stop();
396
+ resolve();
397
+ };
398
+ process.once('SIGINT', () => {
399
+ void stop();
400
+ });
401
+ process.once('SIGTERM', () => {
402
+ void stop();
403
+ });
404
+ });
405
+ }
406
+ //# sourceMappingURL=telegram.js.map