@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.
- package/Dockerfile +27 -0
- package/README.md +77 -50
- package/config.example.yml +265 -0
- package/dist/active-hours.d.ts +23 -0
- package/dist/active-hours.d.ts.map +1 -0
- package/dist/active-hours.js +68 -0
- package/dist/active-hours.js.map +1 -0
- package/dist/agent.d.ts +84 -0
- package/dist/agent.d.ts.map +1 -0
- package/dist/agent.js +383 -0
- package/dist/agent.js.map +1 -0
- package/dist/channels/markdown/ir.d.ts +79 -0
- package/dist/channels/markdown/ir.d.ts.map +1 -0
- package/dist/channels/markdown/ir.js +824 -0
- package/dist/channels/markdown/ir.js.map +1 -0
- package/dist/channels/markdown/render.d.ts +35 -0
- package/dist/channels/markdown/render.d.ts.map +1 -0
- package/dist/channels/markdown/render.js +178 -0
- package/dist/channels/markdown/render.js.map +1 -0
- package/dist/channels/telegram-network-errors.d.ts +27 -0
- package/dist/channels/telegram-network-errors.d.ts.map +1 -0
- package/dist/channels/telegram-network-errors.js +156 -0
- package/dist/channels/telegram-network-errors.js.map +1 -0
- package/dist/channels/telegram.d.ts +76 -0
- package/dist/channels/telegram.d.ts.map +1 -0
- package/dist/channels/telegram.js +814 -0
- package/dist/channels/telegram.js.map +1 -0
- package/dist/channels/types.d.ts +59 -0
- package/dist/channels/types.d.ts.map +1 -0
- package/dist/channels/types.js +9 -0
- package/dist/channels/types.js.map +1 -0
- package/dist/channels/whatsapp.d.ts +45 -0
- package/dist/channels/whatsapp.d.ts.map +1 -0
- package/dist/channels/whatsapp.js +310 -0
- package/dist/channels/whatsapp.js.map +1 -0
- package/dist/cli.d.ts +13 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +635 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands.d.ts +35 -0
- package/dist/commands.d.ts.map +1 -0
- package/dist/commands.js +113 -0
- package/dist/commands.js.map +1 -0
- package/dist/compaction/history.d.ts +17 -0
- package/dist/compaction/history.d.ts.map +1 -0
- package/dist/compaction/history.js +35 -0
- package/dist/compaction/history.js.map +1 -0
- package/dist/compaction/index.d.ts +3 -0
- package/dist/compaction/index.d.ts.map +1 -0
- package/dist/compaction/index.js +3 -0
- package/dist/compaction/index.js.map +1 -0
- package/dist/compaction/proactive.d.ts +25 -0
- package/dist/compaction/proactive.d.ts.map +1 -0
- package/dist/compaction/proactive.js +87 -0
- package/dist/compaction/proactive.js.map +1 -0
- package/dist/compaction/transcript-repair.d.ts +55 -0
- package/dist/compaction/transcript-repair.d.ts.map +1 -0
- package/dist/compaction/transcript-repair.js +215 -0
- package/dist/compaction/transcript-repair.js.map +1 -0
- package/dist/config.d.ts +128 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +317 -0
- package/dist/config.js.map +1 -0
- package/dist/crash-recovery.d.ts +23 -0
- package/dist/crash-recovery.d.ts.map +1 -0
- package/dist/crash-recovery.js +96 -0
- package/dist/crash-recovery.js.map +1 -0
- package/dist/defaults/extensions/EXTENSIONS.md +158 -0
- package/dist/defaults/extensions/documents-hedgedoc.ts +153 -0
- package/dist/history.d.ts +31 -0
- package/dist/history.d.ts.map +1 -0
- package/dist/history.js +49 -0
- package/dist/history.js.map +1 -0
- package/dist/index.d.ts +19 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +673 -0
- package/dist/index.js.map +1 -0
- package/dist/logger.d.ts +39 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +143 -0
- package/dist/logger.js.map +1 -0
- package/dist/memory/conversation-search.d.ts +15 -0
- package/dist/memory/conversation-search.d.ts.map +1 -0
- package/dist/memory/conversation-search.js +60 -0
- package/dist/memory/conversation-search.js.map +1 -0
- package/dist/memory/core-memory.d.ts +28 -0
- package/dist/memory/core-memory.d.ts.map +1 -0
- package/dist/memory/core-memory.js +102 -0
- package/dist/memory/core-memory.js.map +1 -0
- package/dist/memory/embeddings.d.ts +44 -0
- package/dist/memory/embeddings.d.ts.map +1 -0
- package/dist/memory/embeddings.js +139 -0
- package/dist/memory/embeddings.js.map +1 -0
- package/dist/memory/search.d.ts +49 -0
- package/dist/memory/search.d.ts.map +1 -0
- package/dist/memory/search.js +97 -0
- package/dist/memory/search.js.map +1 -0
- package/dist/memory/store.d.ts +32 -0
- package/dist/memory/store.d.ts.map +1 -0
- package/dist/memory/store.js +205 -0
- package/dist/memory/store.js.map +1 -0
- package/dist/message-queue.d.ts +73 -0
- package/dist/message-queue.d.ts.map +1 -0
- package/dist/message-queue.js +188 -0
- package/dist/message-queue.js.map +1 -0
- package/dist/model-infra.d.ts +64 -0
- package/dist/model-infra.d.ts.map +1 -0
- package/dist/model-infra.js +202 -0
- package/dist/model-infra.js.map +1 -0
- package/dist/projection/format.d.ts +10 -0
- package/dist/projection/format.d.ts.map +1 -0
- package/dist/projection/format.js +30 -0
- package/dist/projection/format.js.map +1 -0
- package/dist/projection/index.d.ts +11 -0
- package/dist/projection/index.d.ts.map +1 -0
- package/dist/projection/index.js +9 -0
- package/dist/projection/index.js.map +1 -0
- package/dist/projection/reflection.d.ts +94 -0
- package/dist/projection/reflection.d.ts.map +1 -0
- package/dist/projection/reflection.js +334 -0
- package/dist/projection/reflection.js.map +1 -0
- package/dist/projection/store.d.ts +144 -0
- package/dist/projection/store.d.ts.map +1 -0
- package/dist/projection/store.js +519 -0
- package/dist/projection/store.js.map +1 -0
- package/dist/projection/tools.d.ts +11 -0
- package/dist/projection/tools.d.ts.map +1 -0
- package/dist/projection/tools.js +237 -0
- package/dist/projection/tools.js.map +1 -0
- package/dist/scheduler.d.ts +36 -0
- package/dist/scheduler.d.ts.map +1 -0
- package/dist/scheduler.js +286 -0
- package/dist/scheduler.js.map +1 -0
- package/dist/system-prompt.d.ts +41 -0
- package/dist/system-prompt.d.ts.map +1 -0
- package/dist/system-prompt.js +162 -0
- package/dist/system-prompt.js.map +1 -0
- package/dist/time.d.ts +52 -0
- package/dist/time.d.ts.map +1 -0
- package/dist/time.js +138 -0
- package/dist/time.js.map +1 -0
- package/dist/tools/archival-memory-tool.d.ts +8 -0
- package/dist/tools/archival-memory-tool.d.ts.map +1 -0
- package/dist/tools/archival-memory-tool.js +68 -0
- package/dist/tools/archival-memory-tool.js.map +1 -0
- package/dist/tools/conversation-search-tool.d.ts +6 -0
- package/dist/tools/conversation-search-tool.d.ts.map +1 -0
- package/dist/tools/conversation-search-tool.js +28 -0
- package/dist/tools/conversation-search-tool.js.map +1 -0
- package/dist/tools/core-memory-tool.d.ts +7 -0
- package/dist/tools/core-memory-tool.d.ts.map +1 -0
- package/dist/tools/core-memory-tool.js +59 -0
- package/dist/tools/core-memory-tool.js.map +1 -0
- package/dist/tools/fetch-url.d.ts +15 -0
- package/dist/tools/fetch-url.d.ts.map +1 -0
- package/dist/tools/fetch-url.js +76 -0
- package/dist/tools/fetch-url.js.map +1 -0
- package/dist/tools/files.d.ts +10 -0
- package/dist/tools/files.d.ts.map +1 -0
- package/dist/tools/files.js +127 -0
- package/dist/tools/files.js.map +1 -0
- package/dist/tools/index.d.ts +17 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +118 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/result.d.ts +21 -0
- package/dist/tools/result.d.ts.map +1 -0
- package/dist/tools/result.js +36 -0
- package/dist/tools/result.js.map +1 -0
- package/dist/tools/skill-install.d.ts +17 -0
- package/dist/tools/skill-install.d.ts.map +1 -0
- package/dist/tools/skill-install.js +148 -0
- package/dist/tools/skill-install.js.map +1 -0
- package/dist/tools/web-search.d.ts +42 -0
- package/dist/tools/web-search.d.ts.map +1 -0
- package/dist/tools/web-search.js +237 -0
- package/dist/tools/web-search.js.map +1 -0
- package/dist/trust/guardrail.d.ts +60 -0
- package/dist/trust/guardrail.d.ts.map +1 -0
- package/dist/trust/guardrail.js +171 -0
- package/dist/trust/guardrail.js.map +1 -0
- package/dist/trust/index.d.ts +12 -0
- package/dist/trust/index.d.ts.map +1 -0
- package/dist/trust/index.js +12 -0
- package/dist/trust/index.js.map +1 -0
- package/dist/trust/store.d.ts +118 -0
- package/dist/trust/store.d.ts.map +1 -0
- package/dist/trust/store.js +209 -0
- package/dist/trust/store.js.map +1 -0
- package/dist/trust/wrapper.d.ts +36 -0
- package/dist/trust/wrapper.d.ts.map +1 -0
- package/dist/trust/wrapper.js +142 -0
- package/dist/trust/wrapper.js.map +1 -0
- package/dist/usage.d.ts +53 -0
- package/dist/usage.d.ts.map +1 -0
- package/dist/usage.js +124 -0
- package/dist/usage.js.map +1 -0
- package/dist/util/math.d.ts +9 -0
- package/dist/util/math.d.ts.map +1 -0
- package/dist/util/math.js +22 -0
- package/dist/util/math.js.map +1 -0
- package/dist/util/ssrf.d.ts +21 -0
- package/dist/util/ssrf.d.ts.map +1 -0
- package/dist/util/ssrf.js +77 -0
- package/dist/util/ssrf.js.map +1 -0
- package/dist/workers/index.d.ts +8 -0
- package/dist/workers/index.d.ts.map +1 -0
- package/dist/workers/index.js +7 -0
- package/dist/workers/index.js.map +1 -0
- package/dist/workers/registry.d.ts +53 -0
- package/dist/workers/registry.d.ts.map +1 -0
- package/dist/workers/registry.js +38 -0
- package/dist/workers/registry.js.map +1 -0
- package/dist/workers/scoped-tools.d.ts +21 -0
- package/dist/workers/scoped-tools.d.ts.map +1 -0
- package/dist/workers/scoped-tools.js +111 -0
- package/dist/workers/scoped-tools.js.map +1 -0
- package/dist/workers/spawn.d.ts +62 -0
- package/dist/workers/spawn.d.ts.map +1 -0
- package/dist/workers/spawn.js +314 -0
- package/dist/workers/spawn.js.map +1 -0
- package/dist/workers/tools.d.ts +26 -0
- package/dist/workers/tools.d.ts.map +1 -0
- package/dist/workers/tools.js +380 -0
- package/dist/workers/tools.js.map +1 -0
- package/docker-compose.yml +72 -0
- package/package.json +16 -1
- 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"}
|
package/dist/history.js
ADDED
|
@@ -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"}
|
package/dist/index.d.ts
ADDED
|
@@ -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"}
|