@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
@@ -0,0 +1,158 @@
1
+ # Writing Extensions for Bryti
2
+
3
+ Extensions add new tools to the agent. They are TypeScript files in
4
+ `data/files/extensions/`. The agent loads them on startup and the tools
5
+ become available immediately.
6
+
7
+ ## The one thing you need to know
8
+
9
+ Bryti runs headlessly — no terminal, no TUI. Extensions work through
10
+ `pi.registerTool()` only. Everything else in the pi extension API
11
+ (commands, UI, TUI components, session navigation) requires an interactive
12
+ terminal and does nothing here.
13
+
14
+ **Use:** `pi.registerTool()`
15
+ **Ignore:** `pi.registerCommand()`, `pi.registerShortcut()`, `ctx.ui.*`,
16
+ `ctx.sessionManager`, `pi.on()` events — these are no-ops or unavailable.
17
+
18
+ ## Minimal template
19
+
20
+ ```typescript
21
+ import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
22
+ import { Type } from "@sinclair/typebox";
23
+
24
+ export default function (pi: ExtensionAPI) {
25
+ pi.registerTool({
26
+ name: "tool_name", // snake_case, unique across all extensions
27
+ label: "tool_name", // same as name
28
+ description: "What this tool does and when to use it.",
29
+ parameters: Type.Object({
30
+ input: Type.String({ description: "What this parameter is" }),
31
+ }),
32
+ async execute(_toolCallId, { input }) {
33
+ // Do work here
34
+ return {
35
+ content: [{ type: "text", text: JSON.stringify({ result: input }) }],
36
+ };
37
+ },
38
+ });
39
+ }
40
+ ```
41
+
42
+ ## What you can do inside execute()
43
+
44
+ Anything Node.js supports:
45
+
46
+ - `fetch()` for HTTP requests
47
+ - `process.env.MY_VAR` for secrets and config (set in .env)
48
+ - `node:fs`, `node:path`, `node:child_process` for local system access
49
+ - Any npm package if you install it in `data/files/extensions/`
50
+
51
+ ## Returning results
52
+
53
+ Always return JSON-stringified text so the agent can parse the result:
54
+
55
+ ```typescript
56
+ // Success
57
+ return {
58
+ content: [{ type: "text", text: JSON.stringify({ key: "value" }) }],
59
+ };
60
+
61
+ // Error
62
+ return {
63
+ content: [{ type: "text", text: JSON.stringify({ error: "What went wrong" }) }],
64
+ };
65
+ ```
66
+
67
+ ## Using environment variables
68
+
69
+ Non-secret config (URLs, feature flags) goes in `config.yml` under `integrations`.
70
+ Secrets (API keys, tokens) go in `.env` and are referenced from config.yml via `${VAR}`.
71
+
72
+ Bryti injects `integrations.<name>.<key>` as `NAME_KEY` (uppercased) into `process.env`
73
+ at startup, so extensions read them the same way regardless of where they came from.
74
+
75
+ ```yaml
76
+ # config.yml
77
+ integrations:
78
+ my_service:
79
+ url: "https://api.example.com"
80
+ api_key: "${MY_SERVICE_API_KEY}" # secret stays in .env
81
+ ```
82
+
83
+ ```typescript
84
+ // extension reads it the same way either way
85
+ const url = process.env.MY_SERVICE_URL;
86
+ const apiKey = process.env.MY_SERVICE_API_KEY;
87
+
88
+ if (!url) {
89
+ return {
90
+ content: [{ type: "text", text: JSON.stringify({
91
+ error: "MY_SERVICE_URL not set. Add integrations.my_service.url to config.yml and restart."
92
+ })}],
93
+ };
94
+ }
95
+ ```
96
+
97
+ ## Optional tools (register only when configured)
98
+
99
+ If a tool requires env vars to work, check at registration time and skip
100
+ if they're missing. This keeps the tool list clean:
101
+
102
+ ```typescript
103
+ export default function (pi: ExtensionAPI) {
104
+ const apiKey = process.env.MY_SERVICE_API_KEY;
105
+ if (!apiKey) return; // Not configured — skip registration
106
+
107
+ pi.registerTool({ ... });
108
+ }
109
+ ```
110
+
111
+ ## Multiple tools in one file
112
+
113
+ Group related tools in a single file:
114
+
115
+ ```typescript
116
+ export default function (pi: ExtensionAPI) {
117
+ pi.registerTool({ name: "thing_get", ... });
118
+ pi.registerTool({ name: "thing_set", ... });
119
+ pi.registerTool({ name: "thing_list", ... });
120
+ }
121
+ ```
122
+
123
+ ## Parameter types
124
+
125
+ ```typescript
126
+ Type.String() // text
127
+ Type.Number() // number
128
+ Type.Boolean() // true/false
129
+ Type.Integer() // whole number
130
+ Type.Optional(Type.String()) // optional field
131
+ Type.Array(Type.String()) // list of strings
132
+ Type.Union([ // one of several string values
133
+ Type.Literal("option_a"),
134
+ Type.Literal("option_b"),
135
+ ])
136
+ ```
137
+
138
+ ## Disabling an extension
139
+
140
+ Write an empty file over it. An empty file is a permanent tombstone —
141
+ the extension will not be restored on restart, even if it was a default.
142
+
143
+ ```
144
+ file_write("extensions/some-extension.ts", "")
145
+ ```
146
+
147
+ Do not delete extension files. Always overwrite with empty content.
148
+
149
+ ## Real examples
150
+
151
+ Read the existing extensions in `data/files/extensions/` for patterns.
152
+ The bundled default:
153
+
154
+ - `extensions/documents-hedgedoc.ts` — optional tool (skips if env var missing), fetch API, multiple tools
155
+
156
+ The agent can also write its own extensions at runtime (shell access,
157
+ API integrations, etc.). Check `data/files/extensions/` for any that
158
+ already exist.
@@ -0,0 +1,153 @@
1
+ /**
2
+ * Document tools — HedgeDoc backend.
3
+ *
4
+ * Registers three tools: document_create, document_update, document_read.
5
+ *
6
+ * These tools are the stable interface for collaborative note editing.
7
+ * The tool NAMES are what the agent and users refer to. If you replace
8
+ * this backend (Notion, Google Docs, plain files, anything), keep the
9
+ * same tool names so the agent's behaviour and memory stay consistent.
10
+ *
11
+ * To replace this backend:
12
+ * 1. Rewrite this file (or write a new one and delete this)
13
+ * 2. Implement the same three tools against your preferred API
14
+ * 3. The agent will pick up the new tools on next restart
15
+ *
16
+ * Requirements for HedgeDoc:
17
+ * - HEDGEDOC_URL env var: internal URL pibot uses (e.g. http://hedgedoc:3000)
18
+ * - HEDGEDOC_PUBLIC_URL env var: user-facing URL for shared links (optional, defaults to HEDGEDOC_URL)
19
+ * - HedgeDoc must be started with CMD_ALLOW_FREEURL=true for document_update to work
20
+ * - See docker-compose.yml for the service definition
21
+ */
22
+
23
+ import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
24
+ import { Type } from "@sinclair/typebox";
25
+
26
+ export default function (pi: ExtensionAPI) {
27
+ const baseUrl = (process.env.HEDGEDOC_URL ?? "").replace(/\/$/, "");
28
+ const publicUrl = (process.env.HEDGEDOC_PUBLIC_URL ?? baseUrl).replace(/\/$/, "");
29
+
30
+ if (!baseUrl) {
31
+ // HedgeDoc not configured — tools are not registered.
32
+ // Set HEDGEDOC_URL in .env to activate document_create/update/read.
33
+ console.log("[documents-hedgedoc] HEDGEDOC_URL not set — document tools not registered");
34
+ return;
35
+ }
36
+
37
+ // ---------------------------------------------------------------------------
38
+ // Helpers
39
+ // ---------------------------------------------------------------------------
40
+
41
+ function extractNoteId(location: string): string {
42
+ const parts = location.split("/");
43
+ return parts[parts.length - 1];
44
+ }
45
+
46
+ function buildMarkdown(title: string, content: string): string {
47
+ const trimmed = content.trimStart();
48
+ if (trimmed.startsWith("# ")) return trimmed;
49
+ return `# ${title}\n\n${trimmed}`;
50
+ }
51
+
52
+ async function hedgedocPost(path: string, body: string): Promise<Response> {
53
+ const response = await fetch(`${baseUrl}${path}`, {
54
+ method: "POST",
55
+ headers: { "Content-Type": "text/markdown" },
56
+ body,
57
+ redirect: "manual", // capture 302 Location header ourselves
58
+ });
59
+ if (!response.ok && response.status !== 302) {
60
+ throw new Error(`HedgeDoc returned ${response.status} for ${path}`);
61
+ }
62
+ return response;
63
+ }
64
+
65
+ // ---------------------------------------------------------------------------
66
+ // document_create
67
+ // ---------------------------------------------------------------------------
68
+
69
+ pi.registerTool({
70
+ name: "document_create",
71
+ label: "document_create",
72
+ description:
73
+ "Create a new collaborative document and return a shareable link. " +
74
+ "Use this whenever the conversation produces content the user should be able to view, " +
75
+ "edit, or share: drafts, plans, research notes, code documents, etc. " +
76
+ "Send the returned url to the user so they can open it in their browser.",
77
+ parameters: Type.Object({
78
+ title: Type.String({ description: "Title for the document (written as the first H1 heading)" }),
79
+ content: Type.String({ description: "Initial markdown content of the document" }),
80
+ }),
81
+ async execute(_toolCallId, { title, content }) {
82
+ try {
83
+ const response = await hedgedocPost("/new", buildMarkdown(title, content));
84
+ const location = response.headers.get("location") ?? "";
85
+
86
+ if (!location) {
87
+ return { content: [{ type: "text", text: JSON.stringify({ error: "HedgeDoc did not return a note location" }) }] };
88
+ }
89
+
90
+ const noteId = extractNoteId(location);
91
+ const url = `${publicUrl}/${noteId}`;
92
+
93
+ return { content: [{ type: "text", text: JSON.stringify({ note_id: noteId, url, title }) }] };
94
+ } catch (error) {
95
+ return { content: [{ type: "text", text: JSON.stringify({ error: `Failed to create document: ${error instanceof Error ? error.message : String(error)}` }) }] };
96
+ }
97
+ },
98
+ });
99
+
100
+ // ---------------------------------------------------------------------------
101
+ // document_update
102
+ //
103
+ // Uses POST /new/<alias> which overwrites the note when CMD_ALLOW_FREEURL=true.
104
+ // ---------------------------------------------------------------------------
105
+
106
+ pi.registerTool({
107
+ name: "document_update",
108
+ label: "document_update",
109
+ description:
110
+ "Replace the full content of an existing document. " +
111
+ "Provide the complete new markdown — this is a full overwrite, not a patch. " +
112
+ "Read the document first with document_read if you need to preserve existing content.",
113
+ parameters: Type.Object({
114
+ note_id: Type.String({ description: "Note ID returned by document_create" }),
115
+ content: Type.String({ description: "Full new markdown content (replaces existing content)" }),
116
+ }),
117
+ async execute(_toolCallId, { note_id, content }) {
118
+ try {
119
+ await hedgedocPost(`/new/${note_id}`, content);
120
+ return { content: [{ type: "text", text: JSON.stringify({ note_id, updated: true }) }] };
121
+ } catch (error) {
122
+ return { content: [{ type: "text", text: JSON.stringify({ error: `Failed to update document: ${error instanceof Error ? error.message : String(error)}` }) }] };
123
+ }
124
+ },
125
+ });
126
+
127
+ // ---------------------------------------------------------------------------
128
+ // document_read
129
+ // ---------------------------------------------------------------------------
130
+
131
+ pi.registerTool({
132
+ name: "document_read",
133
+ label: "document_read",
134
+ description:
135
+ "Read the current markdown content of a document. " +
136
+ "Use this before updating so you can preserve content the user may have edited.",
137
+ parameters: Type.Object({
138
+ note_id: Type.String({ description: "Note ID returned by document_create" }),
139
+ }),
140
+ async execute(_toolCallId, { note_id }) {
141
+ try {
142
+ const response = await fetch(`${baseUrl}/${note_id}/download`);
143
+ if (!response.ok) {
144
+ throw new Error(`HedgeDoc returned ${response.status}`);
145
+ }
146
+ const content = await response.text();
147
+ return { content: [{ type: "text", text: JSON.stringify({ note_id, content }) }] };
148
+ } catch (error) {
149
+ return { content: [{ type: "text", text: JSON.stringify({ error: `Failed to read document: ${error instanceof Error ? error.message : String(error)}` }) }] };
150
+ }
151
+ },
152
+ });
153
+ }
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Conversation history as JSONL files, rotated by day. Used as an audit log;
3
+ * conversation_search reads these directly. Persistent pi sessions are the
4
+ * source of truth for agent context.
5
+ */
6
+ export interface ChatMessage {
7
+ role: "user" | "assistant" | "system" | "tool";
8
+ content: string;
9
+ tool_calls?: Array<{
10
+ id: string;
11
+ type: "function";
12
+ function: {
13
+ name: string;
14
+ arguments: string;
15
+ };
16
+ }>;
17
+ tool_call_id?: string;
18
+ name?: string;
19
+ timestamp: string;
20
+ }
21
+ export interface HistoryManager {
22
+ /** Append a message to today's history file. */
23
+ append(message: Omit<ChatMessage, "timestamp">): Promise<void>;
24
+ /** Clear all history. */
25
+ clear(): Promise<void>;
26
+ }
27
+ /**
28
+ * Create a file-based history manager.
29
+ */
30
+ export declare function createHistoryManager(dataDir: string): HistoryManager;
31
+ //# sourceMappingURL=history.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"history.d.ts","sourceRoot":"","sources":["../src/history.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAKH,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,GAAG,WAAW,GAAG,QAAQ,GAAG,MAAM,CAAC;IAC/C,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,KAAK,CAAC;QACjB,EAAE,EAAE,MAAM,CAAC;QACX,IAAI,EAAE,UAAU,CAAC;QACjB,QAAQ,EAAE;YACR,IAAI,EAAE,MAAM,CAAC;YACb,SAAS,EAAE,MAAM,CAAC;SACnB,CAAC;KACH,CAAC,CAAC;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,cAAc;IAC7B,gDAAgD;IAChD,MAAM,CAAC,OAAO,EAAE,IAAI,CAAC,WAAW,EAAE,WAAW,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAE/D,yBAAyB;IACzB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,GAAG,cAAc,CA2CpE"}
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Conversation history as JSONL files, rotated by day. Used as an audit log;
3
+ * conversation_search reads these directly. Persistent pi sessions are the
4
+ * source of truth for agent context.
5
+ */
6
+ import fs from "node:fs";
7
+ import path from "node:path";
8
+ /**
9
+ * Create a file-based history manager.
10
+ */
11
+ export function createHistoryManager(dataDir) {
12
+ const historyDir = path.join(dataDir, "history");
13
+ // Ensure directory exists
14
+ fs.mkdirSync(historyDir, { recursive: true });
15
+ function getTodayFilename() {
16
+ const today = new Date().toISOString().split("T")[0];
17
+ return `${today}.jsonl`;
18
+ }
19
+ function getHistoryFilePath(filename) {
20
+ return path.join(historyDir, filename);
21
+ }
22
+ function listHistoryFiles() {
23
+ if (!fs.existsSync(historyDir)) {
24
+ return [];
25
+ }
26
+ return fs.readdirSync(historyDir)
27
+ .filter((f) => f.endsWith(".jsonl"))
28
+ .sort()
29
+ .reverse(); // Most recent first
30
+ }
31
+ return {
32
+ async append(message) {
33
+ const fullMessage = {
34
+ ...message,
35
+ timestamp: new Date().toISOString(),
36
+ };
37
+ const filePath = getHistoryFilePath(getTodayFilename());
38
+ const line = JSON.stringify(fullMessage) + "\n";
39
+ fs.appendFileSync(filePath, line, "utf-8");
40
+ },
41
+ async clear() {
42
+ const files = listHistoryFiles();
43
+ for (const file of files) {
44
+ fs.unlinkSync(getHistoryFilePath(file));
45
+ }
46
+ },
47
+ };
48
+ }
49
+ //# sourceMappingURL=history.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"history.js","sourceRoot":"","sources":["../src/history.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AA0B7B;;GAEG;AACH,MAAM,UAAU,oBAAoB,CAAC,OAAe;IAClD,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;IAEjD,0BAA0B;IAC1B,EAAE,CAAC,SAAS,CAAC,UAAU,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAE9C,SAAS,gBAAgB;QACvB,MAAM,KAAK,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;QACrD,OAAO,GAAG,KAAK,QAAQ,CAAC;IAC1B,CAAC;IAED,SAAS,kBAAkB,CAAC,QAAgB;QAC1C,OAAO,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;IACzC,CAAC;IAED,SAAS,gBAAgB;QACvB,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;YAC/B,OAAO,EAAE,CAAC;QACZ,CAAC;QACD,OAAO,EAAE,CAAC,WAAW,CAAC,UAAU,CAAC;aAC9B,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;aACnC,IAAI,EAAE;aACN,OAAO,EAAE,CAAC,CAAC,oBAAoB;IACpC,CAAC;IAED,OAAO;QACL,KAAK,CAAC,MAAM,CAAC,OAAuC;YAClD,MAAM,WAAW,GAAgB;gBAC/B,GAAG,OAAO;gBACV,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;aACpC,CAAC;YACF,MAAM,QAAQ,GAAG,kBAAkB,CAAC,gBAAgB,EAAE,CAAC,CAAC;YACxD,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC,GAAG,IAAI,CAAC;YAChD,EAAE,CAAC,cAAc,CAAC,QAAQ,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;QAC7C,CAAC;QAED,KAAK,CAAC,KAAK;YACT,MAAM,KAAK,GAAG,gBAAgB,EAAE,CAAC;YACjC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;gBACzB,EAAE,CAAC,UAAU,CAAC,kBAAkB,CAAC,IAAI,CAAC,CAAC,CAAC;YAC1C,CAAC;QACH,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Bryti entry point.
3
+ *
4
+ * Wires config, persistent pi sessions (one per user), channel bridges
5
+ * (Telegram, WhatsApp), cron scheduler, and the message queue together.
6
+ *
7
+ * Startup: load config, ensure data dirs, warm up embedding model, start
8
+ * bridges, start scheduler, begin processing messages.
9
+ *
10
+ * Each message: load (or reuse) the user's persistent session, run
11
+ * transcript repair, prompt the model with fallback, persist the
12
+ * response to the JSONL audit log.
13
+ */
14
+ /**
15
+ * Exit code that signals an intentional restart to the run.sh supervisor loop.
16
+ * The loop checks for this code and restarts immediately without delay.
17
+ */
18
+ export declare const RESTART_EXIT_CODE = 42;
19
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AA+CH;;;GAGG;AACH,eAAO,MAAM,iBAAiB,KAAK,CAAC"}