@hivemagnus/ardent 0.0.0-stage → 1.0.2

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 (115) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +274 -2
  3. package/dist/a2a-client.d.ts +35 -0
  4. package/dist/a2a-client.js +172 -0
  5. package/dist/a2a-hermes-alias.d.ts +3 -0
  6. package/dist/a2a-hermes-alias.js +57 -0
  7. package/dist/a2a-idempotency.d.ts +13 -0
  8. package/dist/a2a-idempotency.js +86 -0
  9. package/dist/a2a-peers.d.ts +28 -0
  10. package/dist/a2a-peers.js +108 -0
  11. package/dist/a2a-push-inbox.d.ts +22 -0
  12. package/dist/a2a-push-inbox.js +84 -0
  13. package/dist/a2a-push.d.ts +27 -0
  14. package/dist/a2a-push.js +188 -0
  15. package/dist/a2a-server.d.ts +37 -0
  16. package/dist/a2a-server.js +186 -0
  17. package/dist/a2a-store.d.ts +10 -0
  18. package/dist/a2a-store.js +122 -0
  19. package/dist/a2a.d.ts +19 -0
  20. package/dist/a2a.js +466 -0
  21. package/dist/api.d.ts +6 -0
  22. package/dist/api.js +381 -0
  23. package/dist/artifacts.d.ts +15 -0
  24. package/dist/artifacts.js +41 -0
  25. package/dist/backend-events.d.ts +49 -0
  26. package/dist/backend-events.js +8 -0
  27. package/dist/channels.d.ts +52 -0
  28. package/dist/channels.js +184 -0
  29. package/dist/cli.d.ts +2 -0
  30. package/dist/cli.js +845 -0
  31. package/dist/codex-output-budget.d.ts +17 -0
  32. package/dist/codex-output-budget.js +31 -0
  33. package/dist/codex-output-budget.test.d.ts +1 -0
  34. package/dist/codex-output-budget.test.js +29 -0
  35. package/dist/codex.d.ts +82 -0
  36. package/dist/codex.js +431 -0
  37. package/dist/config.d.ts +171 -0
  38. package/dist/config.js +244 -0
  39. package/dist/context-checkpoints.d.ts +49 -0
  40. package/dist/context-checkpoints.js +248 -0
  41. package/dist/context.d.ts +16 -0
  42. package/dist/context.js +101 -0
  43. package/dist/gateway-lock.d.ts +18 -0
  44. package/dist/gateway-lock.js +104 -0
  45. package/dist/hermes-compat.d.ts +15 -0
  46. package/dist/hermes-compat.js +62 -0
  47. package/dist/identity.d.ts +15 -0
  48. package/dist/identity.js +52 -0
  49. package/dist/index.d.ts +9 -0
  50. package/dist/index.js +8 -0
  51. package/dist/job-engine.d.ts +222 -0
  52. package/dist/job-engine.js +497 -0
  53. package/dist/job-news-handlers.d.ts +54 -0
  54. package/dist/job-news-handlers.js +153 -0
  55. package/dist/job-ownership.d.ts +9 -0
  56. package/dist/job-ownership.js +17 -0
  57. package/dist/json-schema.d.ts +9 -0
  58. package/dist/json-schema.js +20 -0
  59. package/dist/llamacpp.d.ts +49 -0
  60. package/dist/llamacpp.js +216 -0
  61. package/dist/magnus-control.d.ts +3 -0
  62. package/dist/magnus-control.js +99 -0
  63. package/dist/magnus-node-dependency-impact.d.ts +1 -0
  64. package/dist/magnus-node-dependency-impact.js +126 -0
  65. package/dist/magnus-owner-reads.d.ts +4 -0
  66. package/dist/magnus-owner-reads.js +99 -0
  67. package/dist/magnus-readiness.d.ts +1 -0
  68. package/dist/magnus-readiness.js +108 -0
  69. package/dist/mattermost.d.ts +18 -0
  70. package/dist/mattermost.js +303 -0
  71. package/dist/memory-tools.d.ts +5 -0
  72. package/dist/memory-tools.js +49 -0
  73. package/dist/memory.d.ts +40 -0
  74. package/dist/memory.js +128 -0
  75. package/dist/model-policy.d.ts +64 -0
  76. package/dist/model-policy.js +56 -0
  77. package/dist/news.d.ts +10 -0
  78. package/dist/news.js +291 -0
  79. package/dist/owner-read.d.ts +32 -0
  80. package/dist/owner-read.js +130 -0
  81. package/dist/plugins.d.ts +74 -0
  82. package/dist/plugins.js +115 -0
  83. package/dist/research.d.ts +110 -0
  84. package/dist/research.js +164 -0
  85. package/dist/runtime.d.ts +33 -0
  86. package/dist/runtime.js +665 -0
  87. package/dist/skills.d.ts +13 -0
  88. package/dist/skills.js +87 -0
  89. package/dist/store.d.ts +142 -0
  90. package/dist/store.js +322 -0
  91. package/dist/team-artifacts.d.ts +138 -0
  92. package/dist/team-artifacts.js +241 -0
  93. package/dist/team-child.d.ts +21 -0
  94. package/dist/team-child.js +130 -0
  95. package/dist/team-contract.d.ts +116 -0
  96. package/dist/team-contract.js +84 -0
  97. package/dist/team-control.d.ts +8 -0
  98. package/dist/team-control.js +152 -0
  99. package/dist/telegram.d.ts +35 -0
  100. package/dist/telegram.js +284 -0
  101. package/dist/tools.d.ts +48 -0
  102. package/dist/tools.js +58 -0
  103. package/dist/version.d.ts +1 -0
  104. package/dist/version.js +5 -0
  105. package/model-policy.default.json +20 -0
  106. package/package.json +84 -4
  107. package/profiles/assistant/IDENTITY.md +9 -0
  108. package/profiles/assistant/SOUL.md +8 -0
  109. package/profiles/assistant/config.yaml +88 -0
  110. package/profiles/assistant/peers.yaml +12 -0
  111. package/profiles/assistant/skills/grounded-answers/SKILL.md +18 -0
  112. package/protocol/LICENSE-A2A.txt +202 -0
  113. package/protocol/README.md +12 -0
  114. package/protocol/a2a.proto +811 -0
  115. package/protocol/lock.json +9 -0
@@ -0,0 +1,184 @@
1
+ import { z } from 'zod';
2
+ const Attachment = z.object({ name: z.string().max(128), media_type: z.string().max(100), bytes: z.instanceof(Uint8Array).refine(value => value.byteLength <= 2 * 1024 * 1024).optional(), external_id: z.string().max(256).optional() }).strict();
3
+ export const ChannelEvent = z.object({
4
+ platform: z.enum(['telegram', 'mattermost']), account: z.string().min(1).max(128),
5
+ channel_type: z.enum(['telegram_private', 'telegram_group', 'telegram_supergroup',
6
+ 'mattermost_dm', 'mattermost_channel']).optional(),
7
+ user: z.string().min(1).max(128), conversation: z.string().min(1).max(128),
8
+ thread: z.string().max(128).nullable(), update_id: z.string().min(1).max(256),
9
+ reply_to: z.string().max(128).nullable(), text: z.string().max(16000),
10
+ attachments: z.array(Attachment).max(5), authorized: z.literal(true), bot_message: z.boolean()
11
+ }).strict();
12
+ export class DeliveryRejectedError extends Error {
13
+ }
14
+ function eventScope(event) {
15
+ return { caller: `${event.platform}:${event.account}:${event.user}`, key: `${event.platform}:${event.account}:${event.conversation}:${event.thread ?? ''}` };
16
+ }
17
+ function sourceReply(runtime, caller) {
18
+ for (const task of runtime.store.listByCaller(caller, 20)) {
19
+ if (task.state !== 'completed')
20
+ continue;
21
+ const sources = new Map();
22
+ for (const event of runtime.store.events(task.id, 0, 500)) {
23
+ if (event.kind !== 'tool_result')
24
+ continue;
25
+ const result = z.object({ result: z.object({ ok: z.literal(true), value: z.unknown().optional() }) }).safeParse(event.detail);
26
+ if (!result.success)
27
+ continue;
28
+ const source = z.object({ source_id: z.string(), url: z.string().url().optional() }).passthrough();
29
+ const value = z.object({ results: z.array(source).optional(), search: z.object({ results: z.array(source) }).passthrough().optional() }).passthrough().safeParse(result.data.result.value);
30
+ if (!value.success)
31
+ continue;
32
+ for (const item of [...(value.data.results ?? []), ...(value.data.search?.results ?? [])])
33
+ if (!sources.has(item.source_id))
34
+ sources.set(item.source_id, item.url ?? 'URL unavailable');
35
+ }
36
+ if (sources.size)
37
+ return `Source IDs for task ${task.id}:\n${[...sources].slice(0, 20).map(([id, url]) => `${id} ${url}`).join('\n')}`;
38
+ }
39
+ return 'No completed task with recorded source IDs in this conversation.';
40
+ }
41
+ export class ChannelCore {
42
+ runtime;
43
+ env;
44
+ jobs;
45
+ #inflight = new Set();
46
+ constructor(runtime, env = process.env, jobs) {
47
+ this.runtime = runtime;
48
+ this.env = env;
49
+ this.jobs = jobs;
50
+ }
51
+ #replyFromTask(task) {
52
+ if (task.state !== 'completed' && task.state !== 'partial')
53
+ return { text: `Task ${task.id} ${task.state}: ${task.error ?? 'Result unavailable'}`, taskId: task.id, artifactIds: [] };
54
+ const artifact = this.runtime.store.events(task.id, 0, 500).find(item => item.kind === 'research_artifacts');
55
+ const recorded = z.object({ report: z.object({ id: z.string() }), markdown: z.object({ id: z.string() }) }).safeParse(artifact?.detail);
56
+ return { text: task.result ?? '', taskId: task.id, artifactIds: recorded.success ? [recorded.data.report.id, recorded.data.markdown.id] : [] };
57
+ }
58
+ async #send(event, reply, deliver, duplicate) {
59
+ const deliveryId = this.runtime.store.queueDelivery(event.platform, event.account, event.update_id, reply.taskId);
60
+ try {
61
+ const externalId = await deliver(reply);
62
+ this.runtime.store.setDelivery(deliveryId, 'sent', externalId);
63
+ return { duplicate, taskId: reply.taskId, delivery: 'sent' };
64
+ }
65
+ catch (error) {
66
+ const state = error instanceof DeliveryRejectedError ? 'failed' : 'unknown';
67
+ this.runtime.store.setDelivery(deliveryId, state, null, error instanceof Error ? error.message : 'Delivery uncertain');
68
+ return { duplicate, taskId: reply.taskId, delivery: state };
69
+ }
70
+ }
71
+ handle(raw, deliver) {
72
+ if (this.runtime.store.admissionFence())
73
+ throw new Error('Profile admission is fenced for rollback');
74
+ const event = ChannelEvent.parse(raw);
75
+ if (event.bot_message)
76
+ return Promise.resolve({ duplicate: false, taskId: null, delivery: null });
77
+ const key = `${event.platform}:${event.account}:${event.update_id}`;
78
+ if (this.#inflight.has(key))
79
+ return Promise.resolve({ duplicate: true, taskId: this.runtime.store.claimInbound(event.platform, event.account, event.update_id, event.channel_type ?? 'unknown').taskId, delivery: this.runtime.store.delivery(event.platform, event.account, event.update_id)?.state ?? null });
80
+ // Telegram acknowledges its update cursor after handle() returns. Claim
81
+ // inbound under the SQLite fence before returning any Promise to it.
82
+ const claimed = this.runtime.store.claimInbound(event.platform, event.account, event.update_id, event.channel_type ?? 'unknown');
83
+ this.#inflight.add(key);
84
+ return this.#handleAuthenticated(event, deliver, claimed).finally(() => this.#inflight.delete(key));
85
+ }
86
+ async #handleAuthenticated(event, deliver, claimed) {
87
+ const scope = eventScope(event);
88
+ if (!claimed.claimed) {
89
+ const existingDelivery = this.runtime.store.delivery(event.platform, event.account, event.update_id);
90
+ if (existingDelivery || !claimed.taskId)
91
+ return { duplicate: true, taskId: claimed.taskId, delivery: existingDelivery?.state ?? null };
92
+ let task = this.runtime.store.get(claimed.taskId);
93
+ if (!task || task.state === 'running')
94
+ return { duplicate: true, taskId: claimed.taskId, delivery: null };
95
+ if (task.state === 'queued') {
96
+ try {
97
+ await this.runtime.run(task.id, this.env);
98
+ }
99
+ catch { /* The task state below is authoritative. */ }
100
+ task = this.runtime.store.get(claimed.taskId);
101
+ }
102
+ if (!task)
103
+ return { duplicate: true, taskId: claimed.taskId, delivery: null };
104
+ return this.#send(event, this.#replyFromTask(task), deliver, true);
105
+ }
106
+ const session = this.runtime.store.session(scope.caller, 'direct', scope.key);
107
+ const command = /^\/(\w+)(?:@\S+)?(?:\s+(.*))?$/s.exec(event.text.trim());
108
+ let reply;
109
+ if (command) {
110
+ const name = command[1]?.toLowerCase();
111
+ const arg = command[2]?.trim() ?? '';
112
+ if (name === 'help' || name === 'commands')
113
+ reply = { text: '/help /commands /new /reset /status /jobs /model [llamacpp|codex] /stop /tasks /sources', taskId: null, artifactIds: [] };
114
+ else if (name === 'new' || name === 'reset') {
115
+ const next = this.runtime.store.resetSession(scope.caller, 'direct', scope.key);
116
+ reply = { text: `New conversation ${next.id}. Stored memory and credentials are unchanged.`, taskId: null, artifactIds: [] };
117
+ }
118
+ else if (name === 'status')
119
+ reply = { text: `${this.runtime.config.name} is running. Session: ${session.id}. Backend: ${this.runtime.store.channelBackend(scope.caller, scope.key) ?? this.runtime.config.execution.backend}.`, taskId: null, artifactIds: [] };
120
+ else if (name === 'model') {
121
+ if (arg && arg !== 'llamacpp' && arg !== 'codex')
122
+ reply = { text: 'Choose /model llamacpp or /model codex.', taskId: null, artifactIds: [] };
123
+ else {
124
+ if (arg === 'llamacpp' || arg === 'codex')
125
+ this.runtime.store.setChannelBackend(scope.caller, scope.key, arg);
126
+ reply = { text: `Backend for future tasks: ${this.runtime.store.channelBackend(scope.caller, scope.key) ?? this.runtime.config.execution.backend}.`, taskId: null, artifactIds: [] };
127
+ }
128
+ }
129
+ else if (name === 'stop') {
130
+ const latest = this.runtime.store.latestSessionTask(session.id, scope.caller);
131
+ if (latest && ['queued', 'running'].includes(latest.state)) {
132
+ this.runtime.cancel(latest.id);
133
+ reply = { text: `Cancellation requested for task ${latest.id}.`, taskId: latest.id, artifactIds: [] };
134
+ }
135
+ else
136
+ reply = { text: 'No active task in this conversation.', taskId: null, artifactIds: [] };
137
+ }
138
+ else if (name === 'tasks') {
139
+ const recent = this.runtime.store.listByCaller(scope.caller, 5);
140
+ reply = { text: recent.length ? recent.map(task => `${task.id} ${task.state}`).join('\n') : 'No tasks yet.', taskId: null, artifactIds: [] };
141
+ }
142
+ else if (name === 'jobs') {
143
+ try {
144
+ if (!this.jobs)
145
+ reply = { text: 'No scheduled job definitions are installed for this profile.', taskId: null, artifactIds: [] };
146
+ else {
147
+ const status = await this.jobs.status(10);
148
+ const lines = status.windows.map(window => `${window.job_id} ${window.local_key} ${window.state}`);
149
+ reply = { text: [`Job definitions revision ${status.active_revision ?? 'none'}${status.last_validation_error ? ` (invalid: ${status.last_validation_error})` : ''}.`,
150
+ ...(lines.length ? lines : ['No job windows recorded yet.'])].join('\n'), taskId: null, artifactIds: [] };
151
+ }
152
+ }
153
+ catch (error) {
154
+ reply = { text: error instanceof Error ? error.message : 'Schedule observation unavailable', taskId: null, artifactIds: [] };
155
+ }
156
+ }
157
+ else if (name === 'sources')
158
+ reply = { text: sourceReply(this.runtime, scope.caller), taskId: null, artifactIds: [] };
159
+ else
160
+ reply = { text: 'Unknown command. Use /help.', taskId: null, artifactIds: [] };
161
+ }
162
+ else {
163
+ const supported = event.attachments.filter(item => item.bytes && ['text/plain', 'text/markdown', 'application/json'].includes(item.media_type));
164
+ const unsupported = event.attachments.filter(item => !supported.includes(item));
165
+ const attachmentText = supported.map(item => `\n\nAttached ${item.name} (${item.media_type}):\n${new TextDecoder('utf-8').decode(item.bytes).slice(0, 8000)}`).join('');
166
+ const metadata = unsupported.map(item => `${item.name} (${item.media_type}${item.external_id ? `, id ${item.external_id}` : ''})`).join(', ');
167
+ const prompt = `${event.text}${attachmentText}${metadata ? `\n\nUnsupported attachments (metadata only): ${metadata}. Explain that their content was not read.` : ''}`.trim();
168
+ if (!prompt)
169
+ reply = { text: 'Send a message or use /help.', taskId: null, artifactIds: [] };
170
+ else {
171
+ const task = this.runtime.accept(prompt.slice(0, 16000), scope.caller, 'direct', `${event.platform}:${event.account}:${event.update_id}`.slice(0, 128), session.id, undefined, this.runtime.store.channelBackend(scope.caller, scope.key));
172
+ this.runtime.store.bindInboundTask(event.platform, event.account, event.update_id, task.id);
173
+ try {
174
+ await this.runtime.run(task.id, this.env);
175
+ reply = this.#replyFromTask(this.runtime.store.get(task.id) ?? task);
176
+ }
177
+ catch (error) {
178
+ reply = { text: `Task ${task.id} ${this.runtime.store.get(task.id)?.state ?? 'failed'}: ${error instanceof Error ? error.message : 'Execution failed'}`, taskId: task.id, artifactIds: [] };
179
+ }
180
+ }
181
+ }
182
+ return this.#send(event, reply, deliver, false);
183
+ }
184
+ }
package/dist/cli.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};