arisa 5.1.24 → 5.1.49

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 (38) hide show
  1. package/package.json +2 -3
  2. package/src/core/agent/agent-manager.js +132 -70
  3. package/src/core/agent/pi-runtime.js +0 -8
  4. package/src/core/agent/system-shell-tool.js +13 -2
  5. package/src/core/artifacts/artifact-store.js +17 -18
  6. package/src/core/config/config-defaults.js +2 -2
  7. package/src/core/conversation/session-seed-store.js +85 -0
  8. package/src/core/tools/ipc-client.js +0 -2
  9. package/src/core/tools/tool-output-materializer.js +41 -0
  10. package/src/core/tools/tool-registry.js +96 -23
  11. package/src/official-tools.lock.json +145 -93
  12. package/src/runtime/doctor.js +1 -4
  13. package/src/runtime/headless-tool-executor.js +2 -32
  14. package/src/runtime/paths.js +7 -1
  15. package/src/runtime/restart-receipt.js +90 -0
  16. package/src/transport/telegram/bot.js +390 -1034
  17. package/src/transport/telegram/chat-queue.js +132 -0
  18. package/src/transport/telegram/media.js +2 -2
  19. package/src/transport/telegram/model-callback.js +211 -0
  20. package/src/transport/telegram/model-controls.js +164 -0
  21. package/src/transport/telegram/prompt-builders.js +372 -0
  22. package/src/transport/telegram/task-dispatcher.js +94 -0
  23. package/src/transport/telegram/update-command.js +1 -1
  24. package/src/transport/telegram/workspace-group.js +83 -0
  25. package/test/agent-tool-policy.test.js +7 -1
  26. package/test/context-and-task-bounds.test.js +9 -7
  27. package/test/doctor.test.js +2 -4
  28. package/test/model-selection.test.js +47 -1
  29. package/test/official-tool-dependencies.test.js +2 -0
  30. package/test/paths.test.js +4 -4
  31. package/test/restart-receipt.test.js +39 -0
  32. package/test/session-start-operational-notes.test.js +47 -0
  33. package/test/telegram-prompt-builders.test.js +33 -0
  34. package/test/telegram-task-dispatcher.test.js +102 -0
  35. package/test/telegram-workspace-group.test.js +76 -0
  36. package/test/tool-registry-run.test.js +62 -0
  37. package/test/topic-initialization.test.js +66 -0
  38. package/src/core/conversation/conversation-history-store.js +0 -142
@@ -1,142 +0,0 @@
1
- import crypto from "node:crypto";
2
- import { mkdir, open, readFile, writeFile } from "node:fs/promises";
3
- import path from "node:path";
4
- import { getChatConversationHistoryFile } from "../../runtime/paths.js";
5
-
6
- const utf8Bom = "\uFEFF";
7
-
8
- function normalizeText(value) {
9
- return String(value || "").trim();
10
- }
11
-
12
- function parseHistory(contents) {
13
- return String(contents || "")
14
- .replace(/^\uFEFF/, "")
15
- .split(/\r?\n/)
16
- .filter(Boolean)
17
- .map((line) => JSON.parse(line));
18
- }
19
-
20
- function serializeRecord(record) {
21
- return `${JSON.stringify(record)}\n`;
22
- }
23
-
24
- export function formatPortableConversation(records) {
25
- if (!records.length) return "";
26
- const sections = [
27
- "Portable Arisa conversation history.",
28
- "This portable history belongs to the same Telegram chat and is independent of the active agent harness.",
29
- "Use it as prior conversation context. Do not repeat it unless the user asks."
30
- ];
31
-
32
- for (const record of records) {
33
- if (record.kind === "seed") {
34
- sections.push(`Imported earlier conversation:\n${record.history}`);
35
- continue;
36
- }
37
- const parts = [];
38
- if (record.prompt) parts.push(`User or system request:\n${record.prompt}`);
39
- if (record.response) parts.push(`Assistant response:\n${record.response}`);
40
- if (parts.length) sections.push(parts.join("\n\n"));
41
- }
42
- return sections.join("\n\n---\n\n");
43
- }
44
-
45
- export class ConversationHistoryStore {
46
- constructor({ historyFile = getChatConversationHistoryFile } = {}) {
47
- this.locks = new Map();
48
- this.historyFile = historyFile;
49
- }
50
-
51
- async withChatLock(chatId, work) {
52
- const key = String(chatId);
53
- const previous = this.locks.get(key) || Promise.resolve();
54
- const current = previous.catch(() => {}).then(work);
55
- this.locks.set(key, current);
56
- try {
57
- return await current;
58
- } finally {
59
- if (this.locks.get(key) === current) this.locks.delete(key);
60
- }
61
- }
62
-
63
- async read(chatId) {
64
- try {
65
- return parseHistory(await readFile(this.historyFile(chatId), "utf8"));
66
- } catch (error) {
67
- if (error?.code === "ENOENT") return [];
68
- throw error;
69
- }
70
- }
71
-
72
- async hasEntries(chatId) {
73
- return (await this.read(chatId)).length > 0;
74
- }
75
-
76
- async appendRecord(chatId, record) {
77
- const file = this.historyFile(chatId);
78
- await mkdir(path.dirname(file), { recursive: true, mode: 0o700 });
79
- const handle = await open(file, "a+", 0o600);
80
- try {
81
- const stats = await handle.stat();
82
- if (stats.size === 0) await handle.write(utf8Bom);
83
- await handle.write(serializeRecord(record));
84
- } finally {
85
- await handle.close();
86
- }
87
- }
88
-
89
- async ensureSeed(chatId, { runtime, history }) {
90
- const normalizedHistory = normalizeText(history);
91
- if (!normalizedHistory) return false;
92
- return this.withChatLock(chatId, async () => {
93
- if ((await this.read(chatId)).length) return false;
94
- await this.appendRecord(chatId, {
95
- id: crypto.randomUUID(),
96
- kind: "seed",
97
- runtime,
98
- history: normalizedHistory,
99
- createdAt: new Date().toISOString()
100
- });
101
- return true;
102
- });
103
- }
104
-
105
- async appendTurn(chatId, { runtime, prompt, response }) {
106
- const normalizedPrompt = normalizeText(prompt);
107
- const normalizedResponse = normalizeText(response);
108
- if (!normalizedPrompt && !normalizedResponse) return null;
109
- const record = {
110
- id: crypto.randomUUID(),
111
- kind: "turn",
112
- runtime,
113
- prompt: normalizedPrompt,
114
- response: normalizedResponse,
115
- createdAt: new Date().toISOString()
116
- };
117
- await this.withChatLock(chatId, () => this.appendRecord(chatId, record));
118
- return record;
119
- }
120
-
121
- async reset(chatId, { runtime, history = "" } = {}) {
122
- return this.withChatLock(chatId, async () => {
123
- const file = this.historyFile(chatId);
124
- await mkdir(path.dirname(file), { recursive: true, mode: 0o700 });
125
- const normalizedHistory = normalizeText(history);
126
- const seed = normalizedHistory
127
- ? serializeRecord({
128
- id: crypto.randomUUID(),
129
- kind: "seed",
130
- runtime,
131
- history: normalizedHistory,
132
- createdAt: new Date().toISOString()
133
- })
134
- : "";
135
- await writeFile(file, `${utf8Bom}${seed}`, { encoding: "utf8", mode: 0o600 });
136
- });
137
- }
138
-
139
- async buildHandoff(chatId) {
140
- return formatPortableConversation(await this.read(chatId));
141
- }
142
- }