@bryti/agent 0.0.1 → 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 (228) hide show
  1. package/Dockerfile +27 -0
  2. package/README.md +77 -50
  3. package/config.example.yml +265 -0
  4. package/dist/active-hours.d.ts +23 -0
  5. package/dist/active-hours.d.ts.map +1 -0
  6. package/dist/active-hours.js +68 -0
  7. package/dist/active-hours.js.map +1 -0
  8. package/dist/agent.d.ts +84 -0
  9. package/dist/agent.d.ts.map +1 -0
  10. package/dist/agent.js +383 -0
  11. package/dist/agent.js.map +1 -0
  12. package/dist/channels/markdown/ir.d.ts +79 -0
  13. package/dist/channels/markdown/ir.d.ts.map +1 -0
  14. package/dist/channels/markdown/ir.js +824 -0
  15. package/dist/channels/markdown/ir.js.map +1 -0
  16. package/dist/channels/markdown/render.d.ts +35 -0
  17. package/dist/channels/markdown/render.d.ts.map +1 -0
  18. package/dist/channels/markdown/render.js +178 -0
  19. package/dist/channels/markdown/render.js.map +1 -0
  20. package/dist/channels/telegram-network-errors.d.ts +27 -0
  21. package/dist/channels/telegram-network-errors.d.ts.map +1 -0
  22. package/dist/channels/telegram-network-errors.js +156 -0
  23. package/dist/channels/telegram-network-errors.js.map +1 -0
  24. package/dist/channels/telegram.d.ts +76 -0
  25. package/dist/channels/telegram.d.ts.map +1 -0
  26. package/dist/channels/telegram.js +814 -0
  27. package/dist/channels/telegram.js.map +1 -0
  28. package/dist/channels/types.d.ts +59 -0
  29. package/dist/channels/types.d.ts.map +1 -0
  30. package/dist/channels/types.js +9 -0
  31. package/dist/channels/types.js.map +1 -0
  32. package/dist/channels/whatsapp.d.ts +45 -0
  33. package/dist/channels/whatsapp.d.ts.map +1 -0
  34. package/dist/channels/whatsapp.js +310 -0
  35. package/dist/channels/whatsapp.js.map +1 -0
  36. package/dist/cli.d.ts +13 -0
  37. package/dist/cli.d.ts.map +1 -0
  38. package/dist/cli.js +635 -0
  39. package/dist/cli.js.map +1 -0
  40. package/dist/commands.d.ts +35 -0
  41. package/dist/commands.d.ts.map +1 -0
  42. package/dist/commands.js +113 -0
  43. package/dist/commands.js.map +1 -0
  44. package/dist/compaction/history.d.ts +17 -0
  45. package/dist/compaction/history.d.ts.map +1 -0
  46. package/dist/compaction/history.js +35 -0
  47. package/dist/compaction/history.js.map +1 -0
  48. package/dist/compaction/index.d.ts +3 -0
  49. package/dist/compaction/index.d.ts.map +1 -0
  50. package/dist/compaction/index.js +3 -0
  51. package/dist/compaction/index.js.map +1 -0
  52. package/dist/compaction/proactive.d.ts +25 -0
  53. package/dist/compaction/proactive.d.ts.map +1 -0
  54. package/dist/compaction/proactive.js +87 -0
  55. package/dist/compaction/proactive.js.map +1 -0
  56. package/dist/compaction/transcript-repair.d.ts +55 -0
  57. package/dist/compaction/transcript-repair.d.ts.map +1 -0
  58. package/dist/compaction/transcript-repair.js +215 -0
  59. package/dist/compaction/transcript-repair.js.map +1 -0
  60. package/dist/config.d.ts +128 -0
  61. package/dist/config.d.ts.map +1 -0
  62. package/dist/config.js +317 -0
  63. package/dist/config.js.map +1 -0
  64. package/dist/crash-recovery.d.ts +23 -0
  65. package/dist/crash-recovery.d.ts.map +1 -0
  66. package/dist/crash-recovery.js +96 -0
  67. package/dist/crash-recovery.js.map +1 -0
  68. package/dist/defaults/extensions/EXTENSIONS.md +158 -0
  69. package/dist/defaults/extensions/documents-hedgedoc.ts +153 -0
  70. package/dist/history.d.ts +31 -0
  71. package/dist/history.d.ts.map +1 -0
  72. package/dist/history.js +49 -0
  73. package/dist/history.js.map +1 -0
  74. package/dist/index.d.ts +19 -0
  75. package/dist/index.d.ts.map +1 -0
  76. package/dist/index.js +673 -0
  77. package/dist/index.js.map +1 -0
  78. package/dist/logger.d.ts +39 -0
  79. package/dist/logger.d.ts.map +1 -0
  80. package/dist/logger.js +143 -0
  81. package/dist/logger.js.map +1 -0
  82. package/dist/memory/conversation-search.d.ts +15 -0
  83. package/dist/memory/conversation-search.d.ts.map +1 -0
  84. package/dist/memory/conversation-search.js +60 -0
  85. package/dist/memory/conversation-search.js.map +1 -0
  86. package/dist/memory/core-memory.d.ts +28 -0
  87. package/dist/memory/core-memory.d.ts.map +1 -0
  88. package/dist/memory/core-memory.js +102 -0
  89. package/dist/memory/core-memory.js.map +1 -0
  90. package/dist/memory/embeddings.d.ts +44 -0
  91. package/dist/memory/embeddings.d.ts.map +1 -0
  92. package/dist/memory/embeddings.js +139 -0
  93. package/dist/memory/embeddings.js.map +1 -0
  94. package/dist/memory/search.d.ts +49 -0
  95. package/dist/memory/search.d.ts.map +1 -0
  96. package/dist/memory/search.js +97 -0
  97. package/dist/memory/search.js.map +1 -0
  98. package/dist/memory/store.d.ts +32 -0
  99. package/dist/memory/store.d.ts.map +1 -0
  100. package/dist/memory/store.js +205 -0
  101. package/dist/memory/store.js.map +1 -0
  102. package/dist/message-queue.d.ts +73 -0
  103. package/dist/message-queue.d.ts.map +1 -0
  104. package/dist/message-queue.js +188 -0
  105. package/dist/message-queue.js.map +1 -0
  106. package/dist/model-infra.d.ts +64 -0
  107. package/dist/model-infra.d.ts.map +1 -0
  108. package/dist/model-infra.js +202 -0
  109. package/dist/model-infra.js.map +1 -0
  110. package/dist/projection/format.d.ts +10 -0
  111. package/dist/projection/format.d.ts.map +1 -0
  112. package/dist/projection/format.js +30 -0
  113. package/dist/projection/format.js.map +1 -0
  114. package/dist/projection/index.d.ts +11 -0
  115. package/dist/projection/index.d.ts.map +1 -0
  116. package/dist/projection/index.js +9 -0
  117. package/dist/projection/index.js.map +1 -0
  118. package/dist/projection/reflection.d.ts +94 -0
  119. package/dist/projection/reflection.d.ts.map +1 -0
  120. package/dist/projection/reflection.js +334 -0
  121. package/dist/projection/reflection.js.map +1 -0
  122. package/dist/projection/store.d.ts +144 -0
  123. package/dist/projection/store.d.ts.map +1 -0
  124. package/dist/projection/store.js +519 -0
  125. package/dist/projection/store.js.map +1 -0
  126. package/dist/projection/tools.d.ts +11 -0
  127. package/dist/projection/tools.d.ts.map +1 -0
  128. package/dist/projection/tools.js +237 -0
  129. package/dist/projection/tools.js.map +1 -0
  130. package/dist/scheduler.d.ts +36 -0
  131. package/dist/scheduler.d.ts.map +1 -0
  132. package/dist/scheduler.js +286 -0
  133. package/dist/scheduler.js.map +1 -0
  134. package/dist/system-prompt.d.ts +41 -0
  135. package/dist/system-prompt.d.ts.map +1 -0
  136. package/dist/system-prompt.js +162 -0
  137. package/dist/system-prompt.js.map +1 -0
  138. package/dist/time.d.ts +52 -0
  139. package/dist/time.d.ts.map +1 -0
  140. package/dist/time.js +138 -0
  141. package/dist/time.js.map +1 -0
  142. package/dist/tools/archival-memory-tool.d.ts +8 -0
  143. package/dist/tools/archival-memory-tool.d.ts.map +1 -0
  144. package/dist/tools/archival-memory-tool.js +68 -0
  145. package/dist/tools/archival-memory-tool.js.map +1 -0
  146. package/dist/tools/conversation-search-tool.d.ts +6 -0
  147. package/dist/tools/conversation-search-tool.d.ts.map +1 -0
  148. package/dist/tools/conversation-search-tool.js +28 -0
  149. package/dist/tools/conversation-search-tool.js.map +1 -0
  150. package/dist/tools/core-memory-tool.d.ts +7 -0
  151. package/dist/tools/core-memory-tool.d.ts.map +1 -0
  152. package/dist/tools/core-memory-tool.js +59 -0
  153. package/dist/tools/core-memory-tool.js.map +1 -0
  154. package/dist/tools/fetch-url.d.ts +15 -0
  155. package/dist/tools/fetch-url.d.ts.map +1 -0
  156. package/dist/tools/fetch-url.js +76 -0
  157. package/dist/tools/fetch-url.js.map +1 -0
  158. package/dist/tools/files.d.ts +10 -0
  159. package/dist/tools/files.d.ts.map +1 -0
  160. package/dist/tools/files.js +127 -0
  161. package/dist/tools/files.js.map +1 -0
  162. package/dist/tools/index.d.ts +17 -0
  163. package/dist/tools/index.d.ts.map +1 -0
  164. package/dist/tools/index.js +118 -0
  165. package/dist/tools/index.js.map +1 -0
  166. package/dist/tools/result.d.ts +21 -0
  167. package/dist/tools/result.d.ts.map +1 -0
  168. package/dist/tools/result.js +36 -0
  169. package/dist/tools/result.js.map +1 -0
  170. package/dist/tools/skill-install.d.ts +17 -0
  171. package/dist/tools/skill-install.d.ts.map +1 -0
  172. package/dist/tools/skill-install.js +148 -0
  173. package/dist/tools/skill-install.js.map +1 -0
  174. package/dist/tools/web-search.d.ts +42 -0
  175. package/dist/tools/web-search.d.ts.map +1 -0
  176. package/dist/tools/web-search.js +237 -0
  177. package/dist/tools/web-search.js.map +1 -0
  178. package/dist/trust/guardrail.d.ts +60 -0
  179. package/dist/trust/guardrail.d.ts.map +1 -0
  180. package/dist/trust/guardrail.js +171 -0
  181. package/dist/trust/guardrail.js.map +1 -0
  182. package/dist/trust/index.d.ts +12 -0
  183. package/dist/trust/index.d.ts.map +1 -0
  184. package/dist/trust/index.js +12 -0
  185. package/dist/trust/index.js.map +1 -0
  186. package/dist/trust/store.d.ts +118 -0
  187. package/dist/trust/store.d.ts.map +1 -0
  188. package/dist/trust/store.js +209 -0
  189. package/dist/trust/store.js.map +1 -0
  190. package/dist/trust/wrapper.d.ts +36 -0
  191. package/dist/trust/wrapper.d.ts.map +1 -0
  192. package/dist/trust/wrapper.js +142 -0
  193. package/dist/trust/wrapper.js.map +1 -0
  194. package/dist/usage.d.ts +53 -0
  195. package/dist/usage.d.ts.map +1 -0
  196. package/dist/usage.js +124 -0
  197. package/dist/usage.js.map +1 -0
  198. package/dist/util/math.d.ts +9 -0
  199. package/dist/util/math.d.ts.map +1 -0
  200. package/dist/util/math.js +22 -0
  201. package/dist/util/math.js.map +1 -0
  202. package/dist/util/ssrf.d.ts +21 -0
  203. package/dist/util/ssrf.d.ts.map +1 -0
  204. package/dist/util/ssrf.js +77 -0
  205. package/dist/util/ssrf.js.map +1 -0
  206. package/dist/workers/index.d.ts +8 -0
  207. package/dist/workers/index.d.ts.map +1 -0
  208. package/dist/workers/index.js +7 -0
  209. package/dist/workers/index.js.map +1 -0
  210. package/dist/workers/registry.d.ts +53 -0
  211. package/dist/workers/registry.d.ts.map +1 -0
  212. package/dist/workers/registry.js +38 -0
  213. package/dist/workers/registry.js.map +1 -0
  214. package/dist/workers/scoped-tools.d.ts +21 -0
  215. package/dist/workers/scoped-tools.d.ts.map +1 -0
  216. package/dist/workers/scoped-tools.js +111 -0
  217. package/dist/workers/scoped-tools.js.map +1 -0
  218. package/dist/workers/spawn.d.ts +62 -0
  219. package/dist/workers/spawn.d.ts.map +1 -0
  220. package/dist/workers/spawn.js +314 -0
  221. package/dist/workers/spawn.js.map +1 -0
  222. package/dist/workers/tools.d.ts +26 -0
  223. package/dist/workers/tools.d.ts.map +1 -0
  224. package/dist/workers/tools.js +380 -0
  225. package/dist/workers/tools.js.map +1 -0
  226. package/docker-compose.yml +72 -0
  227. package/package.json +16 -1
  228. package/run.sh +27 -0
package/dist/usage.js ADDED
@@ -0,0 +1,124 @@
1
+ /**
2
+ * Per-message token usage tracking.
3
+ *
4
+ * Records input tokens, output tokens, model, cost in USD, and latency for
5
+ * every agent response. Entries are appended to daily JSONL files under
6
+ * data/usage/. Used for cost monitoring and operator visibility into model
7
+ * spending over time.
8
+ */
9
+ import fs from "node:fs";
10
+ import path from "node:path";
11
+ function toDateString(date) {
12
+ return date.toISOString().split("T")[0];
13
+ }
14
+ // Round to 6 decimal places ($0.000001 precision). This prevents floating-point
15
+ // drift when accumulating many small cost values in running totals.
16
+ function roundUsd(value) {
17
+ return Math.round(value * 1_000_000) / 1_000_000;
18
+ }
19
+ export function calculateCostUsd(inputTokens, outputTokens, cost) {
20
+ if (!cost)
21
+ return 0;
22
+ // cost.input / cost.output are prices per million tokens; divide by 1,000,000
23
+ // to get the per-token rate before multiplying by the actual token count.
24
+ const input = (inputTokens * cost.input) / 1_000_000;
25
+ const output = (outputTokens * cost.output) / 1_000_000;
26
+ return roundUsd(input + output);
27
+ }
28
+ /**
29
+ * Look up a model's cost config using a three-step cascade.
30
+ *
31
+ * The model string returned by the SDK may differ from the config format in
32
+ * two ways: (1) it may carry an embedded "provider/model" prefix, or (2) the
33
+ * provider context may only be known separately. The cascade handles both:
34
+ *
35
+ * Step 1 — explicit provider + bare model id: use the provider hint (if any)
36
+ * and strip any embedded prefix from the model string.
37
+ * Step 2 — embedded provider prefix: parse "provider/model" from the model
38
+ * string itself and look up that pair.
39
+ * Step 3 — bare id across all providers: fall back to searching every
40
+ * configured provider for a model whose id matches the full model string.
41
+ */
42
+ export function resolveModelCost(config, provider, model) {
43
+ if (!model)
44
+ return undefined;
45
+ // Parse an optional "provider/model" prefix from the model string.
46
+ const slashIdx = model.indexOf("/");
47
+ const embeddedProvider = slashIdx !== -1 ? model.slice(0, slashIdx) : undefined;
48
+ const bareModel = slashIdx !== -1 ? model.slice(slashIdx + 1) : model;
49
+ // Candidate (providerName, modelId) pairs to try in order.
50
+ const candidates = [
51
+ [provider, bareModel],
52
+ [embeddedProvider, bareModel],
53
+ [undefined, model], // bare id across all providers
54
+ ];
55
+ for (const [providerName, modelId] of candidates) {
56
+ const providers = providerName
57
+ ? config.models.providers.filter((p) => p.name === providerName)
58
+ : config.models.providers;
59
+ for (const p of providers) {
60
+ const cost = p.models.find((m) => m.id === modelId)?.cost;
61
+ if (cost)
62
+ return cost;
63
+ }
64
+ }
65
+ return undefined;
66
+ }
67
+ export function createUsageTracker(dataDir) {
68
+ const usageDir = path.join(dataDir, "usage");
69
+ fs.mkdirSync(usageDir, { recursive: true });
70
+ function usageFilePath(date) {
71
+ return path.join(usageDir, `${date}.jsonl`);
72
+ }
73
+ return {
74
+ async append(entry) {
75
+ const timestamp = new Date().toISOString();
76
+ const date = toDateString(new Date());
77
+ const record = { timestamp, ...entry };
78
+ fs.appendFileSync(usageFilePath(date), `${JSON.stringify(record)}\n`, "utf-8");
79
+ },
80
+ async summarize(date) {
81
+ const day = date || toDateString(new Date());
82
+ const filePath = usageFilePath(day);
83
+ const summary = {
84
+ date: day,
85
+ total_messages: 0,
86
+ total_input_tokens: 0,
87
+ total_output_tokens: 0,
88
+ total_cost_usd: 0,
89
+ by_user: {},
90
+ };
91
+ if (!fs.existsSync(filePath)) {
92
+ return summary;
93
+ }
94
+ const lines = fs.readFileSync(filePath, "utf-8").split("\n");
95
+ for (const line of lines) {
96
+ if (!line.trim())
97
+ continue;
98
+ try {
99
+ const record = JSON.parse(line);
100
+ summary.total_messages += 1;
101
+ summary.total_input_tokens += record.input_tokens;
102
+ summary.total_output_tokens += record.output_tokens;
103
+ summary.total_cost_usd = roundUsd(summary.total_cost_usd + record.cost_usd);
104
+ const userSummary = summary.by_user[record.user_id] || {
105
+ messages: 0,
106
+ input_tokens: 0,
107
+ output_tokens: 0,
108
+ cost_usd: 0,
109
+ };
110
+ userSummary.messages += 1;
111
+ userSummary.input_tokens += record.input_tokens;
112
+ userSummary.output_tokens += record.output_tokens;
113
+ userSummary.cost_usd = roundUsd(userSummary.cost_usd + record.cost_usd);
114
+ summary.by_user[record.user_id] = userSummary;
115
+ }
116
+ catch {
117
+ // Skip malformed JSONL entries.
118
+ }
119
+ }
120
+ return summary;
121
+ },
122
+ };
123
+ }
124
+ //# sourceMappingURL=usage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"usage.js","sourceRoot":"","sources":["../src/usage.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Shared math utilities.
3
+ */
4
+ /**
5
+ * Compute cosine similarity between two vectors.
6
+ * Returns 0 if either vector has zero magnitude.
7
+ */
8
+ export declare function cosineSimilarity(a: number[], b: number[]): number;
9
+ //# sourceMappingURL=math.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"math.d.ts","sourceRoot":"","sources":["../../src/util/math.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,MAAM,EAAE,GAAG,MAAM,CAgBjE"}
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Shared math utilities.
3
+ */
4
+ /**
5
+ * Compute cosine similarity between two vectors.
6
+ * Returns 0 if either vector has zero magnitude.
7
+ */
8
+ export function cosineSimilarity(a, b) {
9
+ let dotProduct = 0;
10
+ let normA = 0;
11
+ let normB = 0;
12
+ for (let i = 0; i < a.length; i++) {
13
+ dotProduct += a[i] * b[i];
14
+ normA += a[i] * a[i];
15
+ normB += b[i] * b[i];
16
+ }
17
+ if (normA === 0 || normB === 0) {
18
+ return 0;
19
+ }
20
+ return dotProduct / (Math.sqrt(normA) * Math.sqrt(normB));
21
+ }
22
+ //# sourceMappingURL=math.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"math.js","sourceRoot":"","sources":["../../src/util/math.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH;;;GAGG;AACH,MAAM,UAAU,gBAAgB,CAAC,CAAW,EAAE,CAAW;IACvD,IAAI,UAAU,GAAG,CAAC,CAAC;IACnB,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,IAAI,KAAK,GAAG,CAAC,CAAC;IAEd,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QAClC,UAAU,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;QAC1B,KAAK,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;QACrB,KAAK,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IACvB,CAAC;IAED,IAAI,KAAK,KAAK,CAAC,IAAI,KAAK,KAAK,CAAC,EAAE,CAAC;QAC/B,OAAO,CAAC,CAAC;IACX,CAAC;IAED,OAAO,UAAU,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;AAC5D,CAAC"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Shared SSRF protection utilities.
3
+ *
4
+ * Used by fetch_url, skill_install, and anywhere else that fetches external URLs.
5
+ */
6
+ /**
7
+ * Check if a resolved IP address is private or reserved.
8
+ */
9
+ export declare function isPrivateIp(ip: string): boolean;
10
+ /**
11
+ * Check if a URL's hostname is obviously private (fast, pre-DNS check).
12
+ */
13
+ export declare function isPrivateHostname(url: string): boolean;
14
+ /**
15
+ * DNS lookup that rejects private IPs (SSRF protection against DNS rebinding).
16
+ * Use as the `lookup` option for axios or http.get.
17
+ *
18
+ * The callback signature matches dns.lookup with { all: false } (single result).
19
+ */
20
+ export declare function safeLookup(hostname: string, options: object, callback: (err: Error | null, address: string, family: number) => void): void;
21
+ //# sourceMappingURL=ssrf.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ssrf.d.ts","sourceRoot":"","sources":["../../src/util/ssrf.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH;;GAEG;AACH,wBAAgB,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CA2B/C;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAYtD;AAED;;;;;GAKG;AACH,wBAAgB,UAAU,CACxB,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,CAAC,GAAG,EAAE,KAAK,GAAG,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,KAAK,IAAI,GACrE,IAAI,CAaN"}
@@ -0,0 +1,77 @@
1
+ /**
2
+ * Shared SSRF protection utilities.
3
+ *
4
+ * Used by fetch_url, skill_install, and anywhere else that fetches external URLs.
5
+ */
6
+ import dns from "node:dns";
7
+ /**
8
+ * Check if a resolved IP address is private or reserved.
9
+ */
10
+ export function isPrivateIp(ip) {
11
+ // IPv4-mapped IPv6 (::ffff:x.x.x.x): extract the IPv4 part
12
+ const v4Mapped = ip.match(/^::ffff:(\d+\.\d+\.\d+\.\d+)$/i);
13
+ const addr = v4Mapped ? v4Mapped[1] : ip;
14
+ // Localhost
15
+ if (addr === "127.0.0.1" || addr === "::1" || addr.startsWith("127."))
16
+ return true;
17
+ // Private IPv4 ranges
18
+ if (addr.startsWith("10."))
19
+ return true;
20
+ if (addr.startsWith("192.168."))
21
+ return true;
22
+ if (addr.startsWith("172.")) {
23
+ const parts = addr.split(".");
24
+ if (parts.length >= 2) {
25
+ const second = parseInt(parts[1], 10);
26
+ if (second >= 16 && second <= 31)
27
+ return true;
28
+ }
29
+ }
30
+ // Link-local
31
+ if (addr.startsWith("169.254."))
32
+ return true;
33
+ // IPv6 private ranges
34
+ if (ip.startsWith("fc") || ip.startsWith("fd"))
35
+ return true; // ULA
36
+ if (ip.startsWith("fe80"))
37
+ return true; // link-local
38
+ return false;
39
+ }
40
+ /**
41
+ * Check if a URL's hostname is obviously private (fast, pre-DNS check).
42
+ */
43
+ export function isPrivateHostname(url) {
44
+ try {
45
+ const parsed = new URL(url);
46
+ const hostname = parsed.hostname;
47
+ if (hostname === "localhost")
48
+ return true;
49
+ // If hostname is an IP literal, check it directly
50
+ if (/^\d+\.\d+\.\d+\.\d+$/.test(hostname))
51
+ return isPrivateIp(hostname);
52
+ if (hostname.startsWith("["))
53
+ return isPrivateIp(hostname.slice(1, -1));
54
+ return false;
55
+ }
56
+ catch {
57
+ return true; // Invalid URLs are treated as private
58
+ }
59
+ }
60
+ /**
61
+ * DNS lookup that rejects private IPs (SSRF protection against DNS rebinding).
62
+ * Use as the `lookup` option for axios or http.get.
63
+ *
64
+ * The callback signature matches dns.lookup with { all: false } (single result).
65
+ */
66
+ export function safeLookup(hostname, options, callback) {
67
+ dns.lookup(hostname, { ...options, all: false }, (err, address, family) => {
68
+ if (err)
69
+ return callback(err, "", 0);
70
+ const addr = typeof address === "string" ? address : "";
71
+ if (isPrivateIp(addr)) {
72
+ return callback(Object.assign(new Error(`SSRF: ${hostname} resolved to private IP ${addr}`), { code: "ECONNREFUSED" }), "", 0);
73
+ }
74
+ callback(null, addr, family);
75
+ });
76
+ }
77
+ //# sourceMappingURL=ssrf.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ssrf.js","sourceRoot":"","sources":["../../src/util/ssrf.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Workers: background task execution for long-running jobs.
3
+ */
4
+ export { createWorkerRegistry } from "./registry.js";
5
+ export type { WorkerRegistry, WorkerEntry, WorkerStatus } from "./registry.js";
6
+ export { createWorkerTools } from "./tools.js";
7
+ export { createWorkerScopedTools } from "./scoped-tools.js";
8
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/workers/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;AACrD,YAAY,EAAE,cAAc,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAC/E,OAAO,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAC/C,OAAO,EAAE,uBAAuB,EAAE,MAAM,mBAAmB,CAAC"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Workers: background task execution for long-running jobs.
3
+ */
4
+ export { createWorkerRegistry } from "./registry.js";
5
+ export { createWorkerTools } from "./tools.js";
6
+ export { createWorkerScopedTools } from "./scoped-tools.js";
7
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/workers/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;AAErD,OAAO,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAC/C,OAAO,EAAE,uBAAuB,EAAE,MAAM,mBAAmB,CAAC"}
@@ -0,0 +1,53 @@
1
+ /**
2
+ * Worker registry: in-memory tracking of active and recently-completed workers.
3
+ * Each entry records status, timing, file paths, and the timeout handle.
4
+ */
5
+ export type WorkerStatus = "running" | "complete" | "failed" | "timeout" | "cancelled";
6
+ export interface WorkerEntry {
7
+ workerId: string;
8
+ status: WorkerStatus;
9
+ /** Short summary of what the worker is doing. */
10
+ task: string;
11
+ /** Absolute path to the worker's result file. */
12
+ resultPath: string;
13
+ /** Absolute path to the worker's directory. */
14
+ workerDir: string;
15
+ startedAt: Date;
16
+ completedAt: Date | null;
17
+ /** Error message if status is "failed" or "timeout". */
18
+ error: string | null;
19
+ /** Model used for this worker. */
20
+ model: string;
21
+ /**
22
+ * Abort the running session. Set asynchronously after session creation in
23
+ * spawnWorkerSession — it is null in the brief window between registry.register()
24
+ * and the session coming up. Always check for null before calling.
25
+ */
26
+ abort: (() => Promise<void>) | null;
27
+ /**
28
+ * Handle for the forced-termination timer set in spawnWorkerSession.
29
+ * Null when the worker has already finished (timer was cleared) or has not
30
+ * yet started. Stored here so worker_interrupt can cancel it.
31
+ */
32
+ timeoutHandle: ReturnType<typeof setTimeout> | null;
33
+ }
34
+ export interface WorkerRegistry {
35
+ /** Register a new worker. Returns the entry. */
36
+ register(entry: Omit<WorkerEntry, "completedAt">): WorkerEntry;
37
+ /** Get a worker by id. Returns null if not found. */
38
+ get(workerId: string): WorkerEntry | null;
39
+ /** Update mutable fields of a worker entry. */
40
+ update(workerId: string, updates: Partial<Pick<WorkerEntry, "status" | "completedAt" | "error" | "abort" | "timeoutHandle">>): void;
41
+ /**
42
+ * Count workers with status "running".
43
+ * Used by worker_dispatch in tools.ts to enforce the max_concurrent limit
44
+ * before spawning a new session.
45
+ */
46
+ runningCount(): number;
47
+ /** Remove a worker entry from the registry. */
48
+ remove(workerId: string): void;
49
+ /** List all entries (for worker_check). */
50
+ list(): WorkerEntry[];
51
+ }
52
+ export declare function createWorkerRegistry(): WorkerRegistry;
53
+ //# sourceMappingURL=registry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/workers/registry.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,MAAM,YAAY,GAAG,SAAS,GAAG,UAAU,GAAG,QAAQ,GAAG,SAAS,GAAG,WAAW,CAAC;AAEvF,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,YAAY,CAAC;IACrB,iDAAiD;IACjD,IAAI,EAAE,MAAM,CAAC;IACb,iDAAiD;IACjD,UAAU,EAAE,MAAM,CAAC;IACnB,+CAA+C;IAC/C,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,IAAI,CAAC;IAChB,WAAW,EAAE,IAAI,GAAG,IAAI,CAAC;IACzB,wDAAwD;IACxD,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,kCAAkC;IAClC,KAAK,EAAE,MAAM,CAAC;IACd;;;;OAIG;IACH,KAAK,EAAE,CAAC,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC,GAAG,IAAI,CAAC;IACpC;;;;OAIG;IACH,aAAa,EAAE,UAAU,CAAC,OAAO,UAAU,CAAC,GAAG,IAAI,CAAC;CACrD;AAED,MAAM,WAAW,cAAc;IAC7B,gDAAgD;IAChD,QAAQ,CAAC,KAAK,EAAE,IAAI,CAAC,WAAW,EAAE,aAAa,CAAC,GAAG,WAAW,CAAC;IAE/D,qDAAqD;IACrD,GAAG,CAAC,QAAQ,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI,CAAC;IAE1C,+CAA+C;IAC/C,MAAM,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,IAAI,CAAC,WAAW,EAAE,QAAQ,GAAG,aAAa,GAAG,OAAO,GAAG,OAAO,GAAG,eAAe,CAAC,CAAC,GAAG,IAAI,CAAC;IAEpI;;;;OAIG;IACH,YAAY,IAAI,MAAM,CAAC;IAEvB,+CAA+C;IAC/C,MAAM,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IAE/B,2CAA2C;IAC3C,IAAI,IAAI,WAAW,EAAE,CAAC;CACvB;AAED,wBAAgB,oBAAoB,IAAI,cAAc,CAoCrD"}
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Worker registry: in-memory tracking of active and recently-completed workers.
3
+ * Each entry records status, timing, file paths, and the timeout handle.
4
+ */
5
+ export function createWorkerRegistry() {
6
+ const entries = new Map();
7
+ return {
8
+ register(entry) {
9
+ const full = { ...entry, completedAt: null };
10
+ entries.set(entry.workerId, full);
11
+ return full;
12
+ },
13
+ get(workerId) {
14
+ return entries.get(workerId) ?? null;
15
+ },
16
+ update(workerId, updates) {
17
+ const entry = entries.get(workerId);
18
+ if (!entry)
19
+ return;
20
+ Object.assign(entry, updates);
21
+ },
22
+ runningCount() {
23
+ let count = 0;
24
+ for (const entry of entries.values()) {
25
+ if (entry.status === "running")
26
+ count++;
27
+ }
28
+ return count;
29
+ },
30
+ remove(workerId) {
31
+ entries.delete(workerId);
32
+ },
33
+ list() {
34
+ return Array.from(entries.values());
35
+ },
36
+ };
37
+ }
38
+ //# sourceMappingURL=registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/workers/registry.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAyDH,MAAM,UAAU,oBAAoB;IAClC,MAAM,OAAO,GAAG,IAAI,GAAG,EAAuB,CAAC;IAE/C,OAAO;QACL,QAAQ,CAAC,KAAK;YACZ,MAAM,IAAI,GAAgB,EAAE,GAAG,KAAK,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC;YAC1D,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;YAClC,OAAO,IAAI,CAAC;QACd,CAAC;QAED,GAAG,CAAC,QAAQ;YACV,OAAO,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,IAAI,CAAC;QACvC,CAAC;QAED,MAAM,CAAC,QAAQ,EAAE,OAAO;YACtB,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;YACpC,IAAI,CAAC,KAAK;gBAAE,OAAO;YACnB,MAAM,CAAC,MAAM,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;QAChC,CAAC;QAED,YAAY;YACV,IAAI,KAAK,GAAG,CAAC,CAAC;YACd,KAAK,MAAM,KAAK,IAAI,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC;gBACrC,IAAI,KAAK,CAAC,MAAM,KAAK,SAAS;oBAAE,KAAK,EAAE,CAAC;YAC1C,CAAC;YACD,OAAO,KAAK,CAAC;QACf,CAAC;QAED,MAAM,CAAC,QAAQ;YACb,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QAC3B,CAAC;QAED,IAAI;YACF,OAAO,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;QACtC,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Scoped tools for workers.
3
+ *
4
+ * Workers get a minimal tool set: read and write files in their own directory.
5
+ * No access to other directories, no shell, no memory. Which tools a worker
6
+ * gets will eventually be operator-configurable; for now it's hardcoded.
7
+ */
8
+ import type { AgentTool } from "@mariozechner/pi-agent-core";
9
+ /**
10
+ * Create scoped file tools (write_file, read_file) for a worker session.
11
+ *
12
+ * Isolation guarantees:
13
+ * - Workers can only write to their own workerDir (flat layout, no subdirectories).
14
+ * - Workers can only read files that live in the same workerDir, which means
15
+ * only files they wrote themselves plus task.md and steering.md. There is no
16
+ * cross-worker access and no parent-directory traversal.
17
+ * - Reserved filenames (status.json, task.md, steering.md) are blocked from
18
+ * writes so the runtime's control files cannot be corrupted.
19
+ */
20
+ export declare function createWorkerScopedTools(workerDir: string): AgentTool<any>[];
21
+ //# sourceMappingURL=scoped-tools.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scoped-tools.d.ts","sourceRoot":"","sources":["../../src/workers/scoped-tools.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,OAAO,KAAK,EAAE,SAAS,EAAmB,MAAM,6BAA6B,CAAC;AA8C9E;;;;;;;;;;GAUG;AACH,wBAAgB,uBAAuB,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,CAAC,GAAG,CAAC,EAAE,CAgE3E"}
@@ -0,0 +1,111 @@
1
+ /**
2
+ * Scoped tools for workers.
3
+ *
4
+ * Workers get a minimal tool set: read and write files in their own directory.
5
+ * No access to other directories, no shell, no memory. Which tools a worker
6
+ * gets will eventually be operator-configurable; for now it's hardcoded.
7
+ */
8
+ import fs from "node:fs";
9
+ import path from "node:path";
10
+ import { Type } from "@sinclair/typebox";
11
+ import { toolError, toolSuccess } from "../tools/result.js";
12
+ const MAX_FILE_SIZE = 100 * 1024; // 100KB — workers may write longer research docs
13
+ const writeResultSchema = Type.Object({
14
+ filename: Type.String({
15
+ description: 'Filename to write (e.g., "result.md", "sources.md"). No subdirectories allowed.',
16
+ }),
17
+ content: Type.String({ description: "Content to write to the file." }),
18
+ });
19
+ const readResultSchema = Type.Object({
20
+ filename: Type.String({
21
+ description: 'Filename to read (e.g., "result.md"). Must be a file the worker previously wrote.',
22
+ }),
23
+ });
24
+ /**
25
+ * Validate filename: no path separators, no traversal, no hidden files.
26
+ *
27
+ * Reserved filenames that workers must not overwrite:
28
+ * - status.json : written by spawn.ts to record worker status; read by
29
+ * worker_check to report progress back to the main agent.
30
+ * - task.md : the initial task brief written by worker_dispatch; treated
31
+ * as read-only so the worker always has access to its original
32
+ * instructions even if steering changes direction.
33
+ * - steering.md : the communication channel from the main agent to a running
34
+ * worker; written exclusively by worker_steer so the worker
35
+ * can safely poll it without racing against its own writes.
36
+ */
37
+ function isValidFilename(filename) {
38
+ if (!filename || filename.length > 255)
39
+ return false;
40
+ if (filename.includes("/") || filename.includes("\\"))
41
+ return false;
42
+ if (filename.startsWith("."))
43
+ return false;
44
+ if (filename === "status.json" || filename === "task.md" || filename === "steering.md")
45
+ return false; // reserved
46
+ return true;
47
+ }
48
+ /**
49
+ * Create scoped file tools (write_file, read_file) for a worker session.
50
+ *
51
+ * Isolation guarantees:
52
+ * - Workers can only write to their own workerDir (flat layout, no subdirectories).
53
+ * - Workers can only read files that live in the same workerDir, which means
54
+ * only files they wrote themselves plus task.md and steering.md. There is no
55
+ * cross-worker access and no parent-directory traversal.
56
+ * - Reserved filenames (status.json, task.md, steering.md) are blocked from
57
+ * writes so the runtime's control files cannot be corrupted.
58
+ */
59
+ export function createWorkerScopedTools(workerDir) {
60
+ const writeTool = {
61
+ name: "write_file",
62
+ label: "write_file",
63
+ description: "Write content to a file in your working directory. " +
64
+ "Use result.md for your main findings. You can also create additional files like sources.md or notes.md.",
65
+ parameters: writeResultSchema,
66
+ async execute(_toolCallId, { filename, content }) {
67
+ if (!isValidFilename(filename)) {
68
+ return toolError("Invalid filename. Use a simple name like 'result.md'. No paths, no hidden files.");
69
+ }
70
+ if (Buffer.byteLength(content, "utf-8") > MAX_FILE_SIZE) {
71
+ return toolError(`File too large. Maximum size is ${MAX_FILE_SIZE / 1024}KB.`);
72
+ }
73
+ try {
74
+ const filePath = path.join(workerDir, filename);
75
+ fs.writeFileSync(filePath, content, "utf-8");
76
+ return toolSuccess({
77
+ success: true,
78
+ filename,
79
+ bytes: Buffer.byteLength(content, "utf-8"),
80
+ });
81
+ }
82
+ catch (error) {
83
+ return toolError(error, "Failed to write file");
84
+ }
85
+ },
86
+ };
87
+ const readTool = {
88
+ name: "read_file",
89
+ label: "read_file",
90
+ description: "Read a file you previously wrote in your working directory.",
91
+ parameters: readResultSchema,
92
+ async execute(_toolCallId, { filename }) {
93
+ if (!isValidFilename(filename)) {
94
+ return toolError("Invalid filename.");
95
+ }
96
+ try {
97
+ const filePath = path.join(workerDir, filename);
98
+ if (!fs.existsSync(filePath)) {
99
+ return toolError(`File not found: ${filename}`);
100
+ }
101
+ const content = fs.readFileSync(filePath, "utf-8");
102
+ return toolSuccess({ filename, content });
103
+ }
104
+ catch (error) {
105
+ return toolError(error, "Failed to read file");
106
+ }
107
+ },
108
+ };
109
+ return [writeTool, readTool];
110
+ }
111
+ //# sourceMappingURL=scoped-tools.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scoped-tools.js","sourceRoot":"","sources":["../../src/workers/scoped-tools.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,62 @@
1
+ /**
2
+ * Worker session spawner and lifecycle management.
3
+ *
4
+ * Extracted from tools.ts to reduce file size and separate concerns:
5
+ * - tools.ts handles the tool definitions (public API)
6
+ * - spawn.ts handles session creation and lifecycle
7
+ */
8
+ import type { Config } from "../config.js";
9
+ import type { MemoryStore } from "../memory/store.js";
10
+ import type { WorkerRegistry } from "./registry.js";
11
+ import type { ProjectionStore } from "../projection/store.js";
12
+ export interface WorkerStatusFile {
13
+ worker_id: string;
14
+ status: "running" | "complete" | "failed" | "timeout" | "cancelled";
15
+ task: string;
16
+ started_at: string;
17
+ completed_at: string | null;
18
+ model: string;
19
+ error: string | null;
20
+ result_path: string;
21
+ }
22
+ /**
23
+ * Write (or overwrite) the status.json file in the worker directory.
24
+ *
25
+ * This is the primary way the main agent reads worker status via worker_check.
26
+ * worker_check first consults the in-memory registry; if the worker is no
27
+ * longer there (e.g. after a restart or 24-hour cleanup) it falls back to
28
+ * reading this file from disk. Writing is best-effort: failures are swallowed
29
+ * so they never abort a completion or timeout handler.
30
+ */
31
+ export declare function writeStatusFile(workerDir: string, data: WorkerStatusFile): void;
32
+ declare const ALLOWED_TOOLS: readonly ["web_search", "fetch_url"];
33
+ type AllowedTool = (typeof ALLOWED_TOOLS)[number];
34
+ /**
35
+ * Callback invoked when a worker's completion fact triggers projections.
36
+ * Injects an immediate message into the agent queue instead of waiting
37
+ * for the 5-minute cron tick.
38
+ */
39
+ export type WorkerTriggerCallback = (triggered: Array<{
40
+ id: string;
41
+ summary: string;
42
+ }>) => void;
43
+ export declare function spawnWorkerSession(opts: {
44
+ config: Config;
45
+ workerId: string;
46
+ workerDir: string;
47
+ task: string;
48
+ modelOverride: string | undefined;
49
+ toolNames: AllowedTool[];
50
+ memoryStore: MemoryStore;
51
+ projectionStore?: ProjectionStore;
52
+ registry: WorkerRegistry;
53
+ timeoutMs: number;
54
+ onTrigger?: WorkerTriggerCallback;
55
+ }): Promise<void>;
56
+ /**
57
+ * Remove the worker's registry entry after 24 hours. Result files stay on
58
+ * disk; only the in-memory tracking is cleared.
59
+ */
60
+ export declare function scheduleCleanup(registry: WorkerRegistry, workerId: string, _workerDir: string): void;
61
+ export {};
62
+ //# sourceMappingURL=spawn.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spawn.d.ts","sourceRoot":"","sources":["../../src/workers/spawn.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAWH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAC3C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAKtD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AACpD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AA0D9D,MAAM,WAAW,gBAAgB;IAC/B,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,SAAS,GAAG,UAAU,GAAG,QAAQ,GAAG,SAAS,GAAG,WAAW,CAAC;IACpE,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,gBAAgB,GAAG,IAAI,CAU/E;AAMD,QAAA,MAAM,aAAa,sCAAuC,CAAC;AAC3D,KAAK,WAAW,GAAG,CAAC,OAAO,aAAa,CAAC,CAAC,MAAM,CAAC,CAAC;AAElD;;;;GAIG;AACH,MAAM,MAAM,qBAAqB,GAAG,CAAC,SAAS,EAAE,KAAK,CAAC;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC,KAAK,IAAI,CAAC;AAMhG,wBAAsB,kBAAkB,CAAC,IAAI,EAAE;IAC7C,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,aAAa,EAAE,MAAM,GAAG,SAAS,CAAC;IAClC,SAAS,EAAE,WAAW,EAAE,CAAC;IACzB,WAAW,EAAE,WAAW,CAAC;IACzB,eAAe,CAAC,EAAE,eAAe,CAAC;IAClC,QAAQ,EAAE,cAAc,CAAC;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,qBAAqB,CAAC;CACnC,GAAG,OAAO,CAAC,IAAI,CAAC,CA+OhB;AAMD;;;GAGG;AACH,wBAAgB,eAAe,CAC7B,QAAQ,EAAE,cAAc,EACxB,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,GACjB,IAAI,CAMN"}