hive-am 1.4.0 → 1.6.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 (169) hide show
  1. package/CHANGELOG.md +52 -1
  2. package/README.md +6 -9
  3. package/bin/hive-am.mjs +242 -31
  4. package/bin/run.mjs +135 -0
  5. package/package.json +1 -1
  6. package/server/dist/connections/format.js +26 -0
  7. package/server/dist/connections/index.js +2 -0
  8. package/server/dist/connections/manager.js +18 -6
  9. package/server/dist/connections/router.js +43 -13
  10. package/server/dist/connections/secrets.js +9 -1
  11. package/server/dist/connections/slack.js +488 -0
  12. package/server/dist/connections/store.js +2 -0
  13. package/server/dist/db/migrations.js +80 -0
  14. package/server/dist/db.js +26 -13
  15. package/server/dist/dispatches.js +126 -0
  16. package/server/dist/efforts.js +105 -0
  17. package/server/dist/http/routes/agents.js +4 -3
  18. package/server/dist/http/routes/meta.js +12 -0
  19. package/server/dist/http/routes/notebook.js +10 -2
  20. package/server/dist/http/routes/orchestration.js +13 -2
  21. package/server/dist/http/routes/resources.js +3 -0
  22. package/server/dist/http/routes/types.js +18 -1
  23. package/server/dist/http/validate.js +27 -4
  24. package/server/dist/index.js +6 -1
  25. package/server/dist/instructions.js +11 -3
  26. package/server/dist/objects/agent-db.js +258 -0
  27. package/server/dist/objects/database.js +496 -34
  28. package/server/dist/objects/index.js +16 -8
  29. package/server/dist/providers/kiro.js +7 -1
  30. package/server/dist/providers/opencode-server.js +11 -1
  31. package/server/dist/providers/opencode.js +4 -3
  32. package/server/dist/providers/spawn.js +38 -4
  33. package/server/dist/retention.js +52 -0
  34. package/server/dist/runtime.js +69 -27
  35. package/server/dist/services/agents.js +53 -1
  36. package/server/dist/services/connections.js +18 -3
  37. package/server/dist/services/notebook.js +7 -3
  38. package/server/dist/skills/defaults.js +41 -5
  39. package/server/dist/skills/notebook.js +57 -13
  40. package/server/dist/watch.js +1 -1
  41. package/server/mcp/dispatch.mjs +116 -5
  42. package/web/.next/BUILD_ID +1 -1
  43. package/web/.next/app-build-manifest.json +98 -82
  44. package/web/.next/app-path-routes-manifest.json +7 -7
  45. package/web/.next/build-manifest.json +2 -2
  46. package/web/.next/prerender-manifest.json +51 -51
  47. package/web/.next/server/app/_not-found/page.js +2 -2
  48. package/web/.next/server/app/_not-found/page.js.nft.json +1 -1
  49. package/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  50. package/web/.next/server/app/_not-found.html +1 -1
  51. package/web/.next/server/app/_not-found.rsc +3 -3
  52. package/web/.next/server/app/agents/[id]/page.js +4 -4
  53. package/web/.next/server/app/agents/[id]/page.js.nft.json +1 -1
  54. package/web/.next/server/app/agents/[id]/page_client-reference-manifest.js +1 -1
  55. package/web/.next/server/app/agents/page.js +2 -2
  56. package/web/.next/server/app/agents/page.js.nft.json +1 -1
  57. package/web/.next/server/app/agents/page_client-reference-manifest.js +1 -1
  58. package/web/.next/server/app/agents.html +1 -1
  59. package/web/.next/server/app/agents.rsc +21 -18
  60. package/web/.next/server/app/chat/page.js +2 -2
  61. package/web/.next/server/app/chat/page.js.nft.json +1 -1
  62. package/web/.next/server/app/chat/page_client-reference-manifest.js +1 -1
  63. package/web/.next/server/app/chat.html +1 -1
  64. package/web/.next/server/app/chat.rsc +4 -4
  65. package/web/.next/server/app/connections/page.js +2 -2
  66. package/web/.next/server/app/connections/page.js.nft.json +1 -1
  67. package/web/.next/server/app/connections/page_client-reference-manifest.js +1 -1
  68. package/web/.next/server/app/connections.html +1 -1
  69. package/web/.next/server/app/connections.rsc +4 -4
  70. package/web/.next/server/app/index.html +1 -1
  71. package/web/.next/server/app/index.rsc +4 -4
  72. package/web/.next/server/app/page.js +2 -2
  73. package/web/.next/server/app/page.js.nft.json +1 -1
  74. package/web/.next/server/app/page_client-reference-manifest.js +1 -1
  75. package/web/.next/server/app/relations/page.js +2 -2
  76. package/web/.next/server/app/relations/page.js.nft.json +1 -1
  77. package/web/.next/server/app/relations/page_client-reference-manifest.js +1 -1
  78. package/web/.next/server/app/relations.html +1 -1
  79. package/web/.next/server/app/relations.rsc +4 -4
  80. package/web/.next/server/app/resources/[id]/page.js +2 -2
  81. package/web/.next/server/app/resources/[id]/page.js.nft.json +1 -1
  82. package/web/.next/server/app/resources/[id]/page_client-reference-manifest.js +1 -1
  83. package/web/.next/server/app/resources/page.js +2 -2
  84. package/web/.next/server/app/resources/page.js.nft.json +1 -1
  85. package/web/.next/server/app/resources/page_client-reference-manifest.js +1 -1
  86. package/web/.next/server/app/resources.html +1 -1
  87. package/web/.next/server/app/resources.rsc +4 -4
  88. package/web/.next/server/app/schedules/page.js +2 -2
  89. package/web/.next/server/app/schedules/page.js.nft.json +1 -1
  90. package/web/.next/server/app/schedules/page_client-reference-manifest.js +1 -1
  91. package/web/.next/server/app/schedules.html +1 -1
  92. package/web/.next/server/app/schedules.rsc +4 -4
  93. package/web/.next/server/app/sessions/page.js +2 -2
  94. package/web/.next/server/app/sessions/page.js.nft.json +1 -1
  95. package/web/.next/server/app/sessions/page_client-reference-manifest.js +1 -1
  96. package/web/.next/server/app/sessions.html +1 -1
  97. package/web/.next/server/app/sessions.rsc +4 -4
  98. package/web/.next/server/app/skills/page.js +2 -2
  99. package/web/.next/server/app/skills/page.js.nft.json +1 -1
  100. package/web/.next/server/app/skills/page_client-reference-manifest.js +1 -1
  101. package/web/.next/server/app/skills.html +1 -1
  102. package/web/.next/server/app/skills.rsc +4 -4
  103. package/web/.next/server/app/types/page.js +2 -2
  104. package/web/.next/server/app/types/page.js.nft.json +1 -1
  105. package/web/.next/server/app/types/page_client-reference-manifest.js +1 -1
  106. package/web/.next/server/app/types.html +1 -1
  107. package/web/.next/server/app/types.rsc +4 -4
  108. package/web/.next/server/app-paths-manifest.json +7 -7
  109. package/web/.next/server/chunks/{505.js → 111.js} +1 -1
  110. package/web/.next/server/chunks/143.js +1 -1
  111. package/web/.next/server/chunks/213.js +1 -1
  112. package/web/.next/server/chunks/368.js +1 -1
  113. package/web/.next/server/chunks/403.js +1 -1
  114. package/web/.next/server/chunks/612.js +1 -1
  115. package/web/.next/server/chunks/741.js +2 -0
  116. package/web/.next/server/chunks/837.js +1 -0
  117. package/web/.next/server/chunks/{435.js → 939.js} +3 -3
  118. package/web/.next/server/pages/404.html +1 -1
  119. package/web/.next/server/pages/500.html +1 -1
  120. package/web/.next/server/server-reference-manifest.json +1 -1
  121. package/web/.next/static/chunks/162-68ba190086f5ad39.js +1 -0
  122. package/web/.next/static/chunks/214-35b88db02113ae02.js +1 -0
  123. package/web/.next/static/chunks/281-4506bc98b7111729.js +1 -0
  124. package/web/.next/static/chunks/491-196bcb3dd11bb460.js +1 -0
  125. package/web/.next/static/chunks/517-8f2db464d10a4624.js +1 -0
  126. package/web/.next/static/chunks/{586-f7017d585a84738d.js → 586-4f67b823df060b46.js} +1 -1
  127. package/web/.next/static/chunks/587-3c53d91a1c4f99d6.js +1 -0
  128. package/web/.next/static/chunks/606-14fb5aaa4d0ff22d.js +1 -0
  129. package/web/.next/static/chunks/642-dc874c8caf203ee1.js +1 -0
  130. package/web/.next/static/chunks/{705-f81face97b1bb1af.js → 705-ce86175dea00e6a9.js} +1 -1
  131. package/web/.next/static/chunks/757-03361e7a97a605a2.js +1 -0
  132. package/web/.next/static/chunks/771-db19da9b1a24820c.js +1 -0
  133. package/web/.next/static/chunks/app/agents/[id]/page-803d53aedd10c8e5.js +1 -0
  134. package/web/.next/static/chunks/app/agents/layout-71dd98d696935e29.js +1 -0
  135. package/web/.next/static/chunks/app/agents/page-9da499db6d22731f.js +1 -0
  136. package/web/.next/static/chunks/app/chat/{page-5261b12b7d50f5d1.js → page-383bc24e72dab7fa.js} +1 -1
  137. package/web/.next/static/chunks/app/connections/page-b0ea2eae62cef74e.js +1 -0
  138. package/web/.next/static/chunks/app/layout-cb5af29b0742c513.js +1 -0
  139. package/web/.next/static/chunks/app/page-5e547e87de23d9fa.js +1 -0
  140. package/web/.next/static/chunks/app/relations/page-02710fe1f8a670a9.js +1 -0
  141. package/web/.next/static/chunks/app/resources/[id]/page-1e2afddcb1f04884.js +1 -0
  142. package/web/.next/static/chunks/app/resources/{page-61cccd8fdcc2f6c8.js → page-195b0af83b8ace0d.js} +1 -1
  143. package/web/.next/static/chunks/app/sessions/page-85638705fdc18174.js +1 -0
  144. package/web/.next/static/chunks/app/types/page-c4c2b2217c4667e8.js +1 -0
  145. package/web/.next/static/css/c7faf690373117bb.css +1 -0
  146. package/web/.next/trace +30 -30
  147. package/web/.next/types/routes.d.ts +2 -1
  148. package/web/.next/types/validator.ts +9 -0
  149. package/web/.next/server/chunks/274.js +0 -1
  150. package/web/.next/static/chunks/281-113274e705940a55.js +0 -1
  151. package/web/.next/static/chunks/316-26da9cc233ba7557.js +0 -1
  152. package/web/.next/static/chunks/391-18768499e741112e.js +0 -1
  153. package/web/.next/static/chunks/517-373a80c8ba432bdc.js +0 -1
  154. package/web/.next/static/chunks/562-7c2e33d838e869bf.js +0 -1
  155. package/web/.next/static/chunks/587-8e4d2be01ba7d48f.js +0 -1
  156. package/web/.next/static/chunks/606-c9a19918b02a98d0.js +0 -1
  157. package/web/.next/static/chunks/656-f537149fe28f79aa.js +0 -1
  158. package/web/.next/static/chunks/app/agents/[id]/page-6ed6edb3e74b0ebe.js +0 -1
  159. package/web/.next/static/chunks/app/agents/page-9bb8cba69776c719.js +0 -1
  160. package/web/.next/static/chunks/app/connections/page-eb11cfb1ffeab3ca.js +0 -1
  161. package/web/.next/static/chunks/app/layout-fad968a635f9a4b3.js +0 -1
  162. package/web/.next/static/chunks/app/page-99e0351e6ccaa384.js +0 -1
  163. package/web/.next/static/chunks/app/relations/page-a44fd515a3b0525e.js +0 -1
  164. package/web/.next/static/chunks/app/resources/[id]/page-fc494e85b01e8cb7.js +0 -1
  165. package/web/.next/static/chunks/app/sessions/page-a7534ebd90e982d6.js +0 -1
  166. package/web/.next/static/chunks/app/types/page-ebd37e220f77c1f3.js +0 -1
  167. package/web/.next/static/css/582723fcea1f9887.css +0 -1
  168. /package/web/.next/static/{YT6HM6qmegMJaBMX5QvuP → tdnUXVa01m25EjOobxVd1}/_buildManifest.js +0 -0
  169. /package/web/.next/static/{YT6HM6qmegMJaBMX5QvuP → tdnUXVa01m25EjOobxVd1}/_ssgManifest.js +0 -0
@@ -1,11 +1,13 @@
1
+ import { randomUUID } from 'node:crypto';
1
2
  import { db } from '../db.js';
2
3
  import { DomainError } from '../errors.js';
3
4
  /**
4
- * An agent's notebook: Markdown it keeps for itself across conversations (see the «Notebook» default skill).
5
- * Lives in its own table so it never travels with the agent list. Every change bumps `version`; `seen` is the version the
6
- * agent's live conversation already contains, so the runtime knows when it must be re-sent (e.g. after the user edits it).
5
+ * A notebook: Markdown an agent keeps for itself across conversations (see the «Notebook» default skill). It is an object of its own with
6
+ * readers (`notebooks` and `notebook_readers`, created by db/migrations.ts): an agent and the clones made from it read and write the same one, and
7
+ * it goes away only with its last reader. It lives in its own table so it never travels with the agent list. Every change bumps `version`;
8
+ * `seen` belongs to the reader: it is the version that agent's live conversation already contains, so the runtime knows when the text must be
9
+ * re-sent to it (e.g. after the user, or another agent that shares the notebook, changed it).
7
10
  */
8
- // The table (agent_notebooks) is created by db/migrations.ts.
9
11
  /** It is prompt overhead on every turn, so it has a hard cap. */
10
12
  export const NOTEBOOK_MAX = 8000;
11
13
  const NOTE_MAX = 500;
@@ -37,19 +39,61 @@ const refuseSecret = (text) => {
37
39
  throw new NotebookError(`That looks like ${what}. Credentials are never stored in the notebook: leave it out (or describe where it lives, not its value).`);
38
40
  };
39
41
  const empty = () => ({ content: '', version: 0, seen: 0, updated_at: 0, updated_by: '' });
42
+ /** The notebook an agent reads, with that agent's own `seen`. */
43
+ const readerRow = (agentId) => db.prepare(`SELECT n.id, n.content, n.version, r.seen, n.updated_at, n.updated_by FROM notebook_readers r JOIN notebooks n ON n.id = r.notebook_id WHERE r.agent_id = ?`).get(agentId);
44
+ /** The notebook the agent reads, created empty (version 0) when it has none yet. */
45
+ function ensure(agentId) {
46
+ let row = readerRow(agentId);
47
+ if (!row) {
48
+ const id = randomUUID();
49
+ db.prepare('INSERT INTO notebooks (id) VALUES (?)').run(id);
50
+ db.prepare('INSERT INTO notebook_readers (agent_id, notebook_id, seen) VALUES (?,?,0)').run(agentId, id);
51
+ row = readerRow(agentId);
52
+ }
53
+ return row;
54
+ }
40
55
  export const notebooks = {
41
- get: (agentId) => db.prepare('SELECT content,version,seen,updated_at,updated_by FROM agent_notebooks WHERE agent_id=?').get(agentId) ?? empty(),
56
+ get: (agentId) => { const r = readerRow(agentId); return r ? { content: r.content, version: r.version, seen: r.seen, updated_at: r.updated_at, updated_by: r.updated_by } : empty(); },
57
+ /** The other agents that read the same notebook (empty for an ordinary notebook). */
58
+ sharedWith(agentId) {
59
+ const r = readerRow(agentId);
60
+ if (!r)
61
+ return [];
62
+ return db.prepare('SELECT a.id, a.name FROM notebook_readers x JOIN agents a ON a.id = x.agent_id WHERE x.notebook_id = ? AND x.agent_id <> ? ORDER BY a.name').all(r.id, agentId);
63
+ },
42
64
  /** The agent (or the user) replaced the text. `live`: the change happened inside the conversation the agent is running now. */
43
- save(agentId, content, by, live) {
44
- const cur = notebooks.get(agentId), version = cur.version + 1, t = Date.now();
45
- const seen = live ? version : cur.seen;
46
- db.prepare(`INSERT INTO agent_notebooks (agent_id,content,version,seen,updated_at,updated_by) VALUES (?,?,?,?,?,?)
47
- ON CONFLICT(agent_id) DO UPDATE SET content=excluded.content, version=excluded.version, seen=excluded.seen, updated_at=excluded.updated_at, updated_by=excluded.updated_by`)
48
- .run(agentId, content, version, seen, t, by);
65
+ save: db.transaction((agentId, content, by, live) => {
66
+ const row = ensure(agentId); // an agent that never had one gets its own
67
+ const version = row.version + 1;
68
+ db.prepare('UPDATE notebooks SET content=?, version=?, updated_at=?, updated_by=? WHERE id=?').run(content, version, Date.now(), by, row.id);
69
+ // Only the writer's own conversation already contains what it just wrote; the other readers are sent it on their next turn.
70
+ if (live)
71
+ db.prepare('UPDATE notebook_readers SET seen=? WHERE agent_id=?').run(version, agentId);
49
72
  return notebooks.get(agentId);
50
- },
73
+ }),
51
74
  /** The runtime sent version `v` to the agent's conversation. */
52
- markSeen: (agentId, v) => { db.prepare('UPDATE agent_notebooks SET seen=MAX(seen, ?) WHERE agent_id=?').run(v, agentId); },
75
+ markSeen: (agentId, v) => { db.prepare('UPDATE notebook_readers SET seen=MAX(seen, ?) WHERE agent_id=?').run(v, agentId); },
76
+ /**
77
+ * `to` starts reading the notebook of `from` (a clone sharing its source's notes): `from` gets one if it had none, and what `to` read before
78
+ * is dropped with its last reader. Its `seen` starts at 0, so its first turn is sent the text.
79
+ */
80
+ share: db.transaction((fromId, toId) => {
81
+ if (fromId === toId)
82
+ return;
83
+ const nb = ensure(fromId);
84
+ db.prepare('INSERT INTO notebook_readers (agent_id, notebook_id, seen) VALUES (?,?,0) ON CONFLICT(agent_id) DO UPDATE SET notebook_id=excluded.notebook_id, seen=0').run(toId, nb.id);
85
+ db.prepare('DELETE FROM notebooks WHERE id NOT IN (SELECT notebook_id FROM notebook_readers)').run(); // what `to` read before, if nobody else does
86
+ }),
87
+ /** Gives the agent its own copy of the notebook it shares, and leaves the shared one with the others. Does nothing for an agent that shares nothing. */
88
+ separate: db.transaction((agentId) => {
89
+ const row = readerRow(agentId);
90
+ if (!row || !notebooks.sharedWith(agentId).length)
91
+ return notebooks.get(agentId);
92
+ const id = randomUUID();
93
+ db.prepare('INSERT INTO notebooks (id, content, version, updated_at, updated_by) VALUES (?,?,?,?,?)').run(id, row.content, row.version, row.updated_at, row.updated_by);
94
+ db.prepare('UPDATE notebook_readers SET notebook_id=? WHERE agent_id=?').run(id, agentId); // `seen` stays: it still describes what this agent's conversation holds
95
+ return notebooks.get(agentId);
96
+ }),
53
97
  /** Edit from the UI. `version` (when given) must be the one the user was looking at. */
54
98
  edit(agentId, content, version) {
55
99
  const text = content.replace(/\r\n/g, '\n').trimEnd();
@@ -134,7 +134,7 @@ async function noticeNow(w, reason) {
134
134
  ? (es ? `Apareció el archivo que esperabas (${dur}). Reviso el resultado…` : `The file you were waiting for appeared (${dur}). Checking the result…`)
135
135
  : (es ? `Terminó el proceso que esperabas (PID ${w.pid}, ${dur}). Reviso el resultado…` : `The process you were waiting for (PID ${w.pid}) has finished (${dur}). Checking the result…`);
136
136
  const msg = `🔔 ${who}${body}`;
137
- const { externalId } = await adapter.send(thread.target, msg);
137
+ const { externalId } = await adapter.send(adapter.proactive?.(thread.target) ?? thread.target, msg);
138
138
  threadMessages.record(thread.id, 'out', externalId, { name: agents.get(w.agent_id)?.name }, msg);
139
139
  }
140
140
  catch (e) {
@@ -1,15 +1,18 @@
1
1
  #!/usr/bin/env node
2
2
  // Minimal MCP stdio server for hive-am agents. Tool groups come from HIVE_CAPS:
3
- // dispatch → list_agents, dispatch (orchestrators with a team)
3
+ // dispatch → list_agents, dispatch, dispatch_status (orchestrators with a team)
4
4
  // channel → channel_reply, channel_send_file, channel_react, channel_mute (agents linked to Telegram/Slack)
5
5
  // wake → wake_me, wake_when_done, schedule_create, schedule_list, schedule_cancel (agents with the Wake-ups skill: to be woken later in the same place)
6
6
  // objects → object_list, object_logs, object_action (agents with the Colony objects skill: the servers and containers of their colony)
7
+ // databases → object_db_* (agents with the Database management skill: the database resources of their colony)
7
8
  // It only talks to the hive-am HTTP API; all rules (assignments, queueing) live there.
8
9
  import { createInterface } from 'node:readline';
9
10
 
10
11
  const API = process.env.HIVE_AM_API ?? 'http://127.0.0.1:4400';
11
12
  const FROM = process.env.HIVE_AGENT_ID;
12
13
  const CAPS = new Set((process.env.HIVE_CAPS ?? 'dispatch').split(',').filter(Boolean));
14
+ // A synchronous dispatch waits with dispatch_status calls of this many seconds each, so no request lasts long enough to hit a client timeout.
15
+ const POLL_S = Math.min(60, Math.max(1, Number(process.env.HIVE_AM_DISPATCH_POLL_S) || 25));
13
16
 
14
17
  const allTools = [
15
18
  {
@@ -21,17 +24,32 @@ const allTools = [
21
24
  {
22
25
  cap: 'dispatch',
23
26
  name: 'dispatch',
24
- description: 'Send a self-contained task to one of your subagents and wait for its final answer. Every delegation starts a fresh conversation for the subagent, so include all the context it needs.',
27
+ description: 'Send a self-contained task to one of your subagents. By default the call returns at once with a task id and the answer arrives later as a message to you (you can also ask with dispatch_status), so you can answer the person or delegate more meanwhile. Set background: false only for a very short task whose answer you need right now: the call then waits for the final answer. Every delegation starts a fresh conversation for the subagent, so include all the context it needs.',
25
28
  inputSchema: {
26
29
  type: 'object',
27
30
  properties: {
28
31
  agent: { type: 'string', description: 'Exact subagent name from list_agents' },
29
32
  task: { type: 'string', description: 'Full instructions for the subagent; include all context it needs.' },
33
+ background: { type: 'boolean', description: 'Return at once with a task id (default true). The result is sent to you as a message when the subagent finishes. Set false to wait for the final answer in this call.' },
30
34
  },
31
35
  required: ['agent', 'task'],
32
36
  additionalProperties: false,
33
37
  },
34
38
  },
39
+ {
40
+ cap: 'dispatch',
41
+ name: 'dispatch_status',
42
+ description: 'State of a task you delegated: queued, running, done, failed or interrupted, with the result once it has finished. With wait_seconds it waits up to that long for the end before answering.',
43
+ inputSchema: {
44
+ type: 'object',
45
+ properties: {
46
+ id: { type: 'string', description: 'The task id that dispatch returned' },
47
+ wait_seconds: { type: 'number', minimum: 0, maximum: 60, description: 'Wait up to this many seconds (0 to 60, default 0) for the task to finish.' },
48
+ },
49
+ required: ['id'],
50
+ additionalProperties: false,
51
+ },
52
+ },
35
53
  {
36
54
  cap: 'channel',
37
55
  name: 'channel_reply',
@@ -105,7 +123,7 @@ const allTools = [
105
123
  {
106
124
  cap: 'channel',
107
125
  name: 'channel_react',
108
- description: 'React with ONE emoji to the message you are handling (a thumbs-up to say "got it", a heart to say thanks). It is lighter than a reply and counts as your answer when nothing else needs saying. Each platform allows only some emoji (on Telegram a fixed list: 👍 👎 ❤ 🔥 👏 🎉 🙏 👌 👀 💯 🤔 😁 😢 ✍ 🫡 …); an emoji that is not allowed is refused and the error lists the ones you can use. Follow the "Chat channels" skill for when to react.',
126
+ description: 'React with ONE emoji to the message you are handling (a thumbs-up to say "got it", a heart to say thanks). It is lighter than a reply and counts as your answer when nothing else needs saying. Each platform allows only some emoji (on Telegram a fixed list: 👍 👎 ❤ 🔥 👏 🎉 🙏 👌 👀 💯 🤔 😁 😢 ✍ 🫡 …; on Slack a wider set, by emoji or as :name:); an emoji that is not allowed is refused and the error lists the ones you can use. Follow the "Chat channels" skill for when to react.',
109
127
  inputSchema: {
110
128
  type: 'object',
111
129
  properties: { emoji: { type: 'string', description: 'A single emoji, e.g. 👍.' } },
@@ -218,8 +236,78 @@ const allTools = [
218
236
  inputSchema: { type: 'object', properties: { id: { type: 'string', description: 'The schedule id.' } }, required: ['id'], additionalProperties: false },
219
237
  },
220
238
  ];
239
+
240
+ // ---- Database management (cap `databases`): one tool per operation, all answered by POST /api/agent-objects/db/<op> ----
241
+ const NAME = { type: 'string', description: 'The exact name of the database resource, as object_db_list shows it.' };
242
+ const DB = { type: 'string', description: 'Another database of the same server to use instead of the one the resource opens by default (see object_db_schema).' };
243
+ const SCHEMA = { type: 'string', description: 'The schema (PostgreSQL, SQL Server), the database (MySQL) or "main" (SQLite), as object_db_schema shows it.' };
244
+ const TABLE = { type: 'string', description: 'The table or view name.' };
245
+ const dbTool = (name, description, properties = {}, required = []) => ({ cap: 'databases', name: `object_db_${name}`, description, inputSchema: { type: 'object', properties, required, additionalProperties: false } });
246
+ const dbTools = [
247
+ dbTool('list', 'List the database resources you look after: name, engine, database and state. Use these exact names in the other object_db tools.'),
248
+ dbTool('schema', 'The structure of a database: the databases of the server, the current one and its tables and views (with a row estimate). Start here.', { name: NAME, database: DB }, ['name']),
249
+ dbTool('columns', 'The columns of a table or view: name, type, nullable, key and default.', { name: NAME, schema: SCHEMA, table: TABLE, database: DB }, ['name', 'schema', 'table']),
250
+ dbTool('describe', 'A table in full: columns, primary key, indexes, foreign keys and the number of rows.', { name: NAME, schema: SCHEMA, table: TABLE, database: DB }, ['name', 'schema', 'table']),
251
+ dbTool('search', 'Find tables, views and columns whose name contains some text, across everything the connection can see.', { name: NAME, query: { type: 'string', description: 'Part of a name.' }, database: DB }, ['name', 'query']),
252
+ dbTool('ddl', 'The CREATE statement of a table (with its indexes).', { name: NAME, schema: SCHEMA, table: TABLE, database: DB }, ['name', 'schema', 'table']),
253
+ dbTool('sample', 'The first rows of a table or view, without writing SQL.', { name: NAME, schema: SCHEMA, table: TABLE, limit: { type: 'number', description: 'How many rows (default 10).' }, database: DB }, ['name', 'schema', 'table']),
254
+ dbTool('query', 'Run ONE SQL statement: a read, or (not in read-only mode) a write or DDL. DROP and TRUNCATE need Full access. A result is cut at the resource\'s row limit and a query at its time limit. Writes are real and cannot be undone: say what you are about to change first. Results can contain secrets: never repeat them in a chat.', { name: NAME, sql: { type: 'string', description: 'One SQL statement.' }, database: DB }, ['name', 'sql']),
255
+ dbTool('exec', 'Run several SQL statements as ONE transaction: all are applied or none (a failure says which statement it was). Not in read-only mode; DROP and TRUNCATE need Full access and one of them refuses the whole script. MySQL commits by itself on CREATE, ALTER and DROP, so a DDL in the middle cannot be undone there.', { name: NAME, sql: { type: 'string', description: 'Statements separated by ;' }, database: DB }, ['name', 'sql']),
256
+ dbTool('explain', 'The execution plan of a statement, without running it.', { name: NAME, sql: { type: 'string', description: 'One SQL statement.' }, database: DB }, ['name', 'sql']),
257
+ dbTool('export', 'Write the result of a query to a CSV or JSON file inside your own working folder. It never writes outside it and never overwrites a file unless overwrite is true. Not in read-only mode.', { name: NAME, sql: { type: 'string', description: 'The query.' }, format: { type: 'string', enum: ['csv', 'json'] }, file: { type: 'string', description: 'The file, relative to your working folder.' }, overwrite: { type: 'boolean' }, database: DB }, ['name', 'sql', 'format', 'file']),
258
+ dbTool('saved', 'The named queries saved on a resource: list them, or add, update or remove one (not in read-only mode). A password in the text is replaced by ***.', { name: NAME, op: { type: 'string', enum: ['list', 'add', 'update', 'remove'] }, id: { type: 'string', description: 'The id of the saved query (update, remove).' }, query_name: { type: 'string', description: 'Its name (add, update).' }, sql: { type: 'string', description: 'Its text (add, update).' }, database: DB }, ['name', 'op']),
259
+ dbTool('history', 'The last 200 queries run on a resource (by people and by agents), or clear them (not in read-only mode).', { name: NAME, op: { type: 'string', enum: ['list', 'clear'] } }, ['name', 'op']),
260
+ dbTool('sessions', 'Who is connected to the server and what they are running (MySQL, PostgreSQL, SQL Server). Not in read-only mode.', { name: NAME }, ['name']),
261
+ dbTool('kill', 'Cancel what a session is running (MySQL, PostgreSQL) or end the session (SQL Server). Full access only. It can interrupt other people: look at object_db_sessions first and do it only when asked.', { name: NAME, id: { type: 'number', description: 'The session id from object_db_sessions.' } }, ['name', 'id']),
262
+ dbTool('config', 'How a resource connects: engine, host, port, user, database, SSL, driver properties and limits. The password is never shown: passwordSet says whether one exists.', { name: NAME }, ['name']),
263
+ dbTool('config_set', 'Change how a resource connects (Full access only). Give only the fields to change inside config; the engine cannot change. The new connection is tested first and nothing is saved if it fails. A password you give is stored and never shown again: do not repeat it anywhere. Can also rename it, move it to your colony or out of any, and choose the agent that looks after it.', { name: NAME, config: { type: 'object', description: 'Fields to change: host, port, user, password, database, file (SQLite), ssl, trustCert, props, readOnly, timeoutSec, maxRows.' }, new_name: { type: 'string' }, colony_id: { type: 'string', description: '"mine" (your colony) or "none".' }, manager_id: { type: 'string', description: 'An agent name or id, "me", or "none" to leave it to the colony.' } }, ['name']),
264
+ dbTool('test', 'Test a connection: a saved resource by name, or (Full access) a configuration that is not saved yet.', { name: { type: 'string', description: 'A saved resource to test.' }, config: { type: 'object', description: 'A draft configuration to test instead (Full access).' } }),
265
+ dbTool('create', 'Create a database resource (Full access only). The connection is tested first and nothing is created if it fails. It is created in your colony (or none) and you become the agent that looks after it. A password in config is stored and never shown again: do not repeat it anywhere.', { name: { type: 'string', description: 'The name of the new resource.' }, config: { type: 'object', description: 'engine (mysql, postgresql, sqlite, mssql) and host, port, user, password, database (or file for SQLite), ssl, trustCert, props, readOnly, timeoutSec, maxRows.' }, colony_id: { type: 'string', description: '"mine" (default) or "none".' } }, ['name', 'config']),
266
+ dbTool('delete', 'Delete a database resource (Full access only). The database itself is not touched: only hive-am forgets the connection, its saved queries and its history.', { name: NAME }, ['name']),
267
+ ];
268
+ allTools.push(...dbTools);
221
269
  const tools = allTools.filter((t) => CAPS.has(t.cap)).map(({ cap, ...t }) => t);
222
270
 
271
+ // ---- how a database answer is written for the model ----
272
+ const cellText = (v) => (v === null || v === undefined ? 'NULL' : String(v).replace(/\r?\n/g, '\\n'));
273
+ const table = (columns, rows) => [columns.map((c) => c.name ?? c).join('\t'), ...rows.map((r) => r.map(cellText).join('\t'))].join('\n');
274
+ const resultText = (r) => {
275
+ if (!r.columns?.length) return r.affected !== undefined ? `OK, ${r.affected} row${r.affected === 1 ? '' : 's'} affected (${r.ms ?? 0} ms).` : `OK (${r.ms ?? 0} ms).`;
276
+ return `${table(r.columns, r.rows)}\n${r.rows.length} row${r.rows.length === 1 ? '' : 's'}${r.truncated ? ' (cut at the resource\'s row limit: ask for fewer rows or columns)' : ''} in ${r.ms ?? 0} ms.`;
277
+ };
278
+ const dbAnswer = (op, j) => {
279
+ switch (op) {
280
+ case 'list': return j.databases.length ? j.databases.map((d) => `${d.name} · ${d.engine}${d.database ? ` · ${d.database}` : ''} · ${d.status}${d.detail ? ` (${d.detail})` : ''}`).join('\n') : 'You look after no database resources.';
281
+ case 'schema': return `${j.engine}, database ${j.database || '(none)'}${j.databases.length ? `. Databases on the server: ${j.databases.join(', ')}` : ''}.\n${j.tables.length ? j.tables.map((t) => `${t.schema}.${t.name} (${t.type}${t.rows !== undefined ? `, ~${t.rows} rows` : ''})`).join('\n') : 'No tables.'}`;
282
+ case 'columns': return j.columns.length ? j.columns.map((c) => `${c.name} ${c.type}${c.nullable ? '' : ' NOT NULL'}${c.key ? ` ${c.key}` : ''}${c.default !== undefined && c.default !== null ? ` DEFAULT ${c.default}` : ''}`).join('\n') : 'No columns: that table does not exist.';
283
+ case 'describe': return [`${j.schema}.${j.table}: ${j.rowCount ?? '?'} rows`, 'Columns:', ...j.columns.map((c) => ` ${c.name} ${c.type}${c.nullable ? '' : ' NOT NULL'}${c.key ? ` ${c.key}` : ''}`), `Primary key: ${j.primaryKey.join(', ') || '(none)'}`, 'Indexes:', ...(j.indexes.length ? j.indexes.map((i) => ` ${i.name}${i.unique ? ' UNIQUE' : ''} (${i.columns.join(', ')})`) : [' (none)']), 'Foreign keys:', ...(j.foreignKeys.length ? j.foreignKeys.map((f) => ` ${f.name}: (${f.columns.join(', ')}) -> ${f.refSchema ? `${f.refSchema}.` : ''}${f.refTable} (${f.refColumns.join(', ')})`) : [' (none)'])].join('\n');
284
+ case 'search': return j.matches.length ? j.matches.map((m) => (m.column ? `${m.schema}.${m.table}.${m.column} (column)` : `${m.schema}.${m.table} (${m.type})`)).join('\n') : 'Nothing matches.';
285
+ case 'ddl': return j.ddl;
286
+ case 'sample': case 'query': case 'explain': case 'sessions': return resultText(j);
287
+ case 'exec': return `${j.results.length} statement${j.results.length === 1 ? '' : 's'} applied in one transaction (${j.ms} ms).\n${j.results.map((r, n) => `${n + 1}. ${r.statement.replace(/\s+/g, ' ').slice(0, 80)}\n ${resultText(r).split('\n').join('\n ')}`).join('\n')}`;
288
+ case 'export': return `Wrote ${j.rows} row${j.rows === 1 ? '' : 's'} as ${j.format} to ${j.file} (${j.bytes} bytes)${j.truncated ? ', cut at the resource\'s row limit' : ''}.`;
289
+ case 'saved': return j.saved === undefined ? 'Done.' : Array.isArray(j.saved) ? (j.saved.length ? j.saved.map((q) => `${q.id} · ${q.name}${q.database ? ` (${q.database})` : ''}\n${q.sql}`).join('\n\n') : 'No saved queries.') : `Saved: ${j.saved.id} · ${j.saved.name}`;
290
+ case 'history': return j.cleared ? 'History cleared.' : j.history.length ? j.history.map((h) => `${new Date(h.at).toISOString().slice(0, 19)} ${h.ok ? 'ok' : 'FAILED'}${h.by ? ` (${h.by})` : ''} ${h.sql.replace(/\s+/g, ' ').slice(0, 160)}${h.error ? ` -> ${h.error}` : ''}`).join('\n') : 'No history.';
291
+ case 'kill': return j.text;
292
+ case 'config': return JSON.stringify({ name: j.name, ...j.config }, null, 2);
293
+ case 'test': return `Connection works: ${j.version} (${j.ms} ms).`;
294
+ case 'create': return `Created the database resource "${j.name}" (${j.engine}). You look after it now.`;
295
+ case 'config_set': return `Saved the connection of "${j.name}" after testing it.`;
296
+ case 'delete': return `Deleted the database resource "${j.deleted}".`;
297
+ default: return JSON.stringify(j);
298
+ }
299
+ };
300
+
301
+ async function taskStatus(id, waitSeconds) {
302
+ const r = await fetch(`${API}/api/dispatch/status`, {
303
+ method: 'POST', headers: { 'content-type': 'application/json' },
304
+ body: JSON.stringify({ from: FROM, id, wait_seconds: waitSeconds }),
305
+ });
306
+ const j = await r.json();
307
+ if (!r.ok) throw Object.assign(new Error(j.error ?? `dispatch_status failed (${r.status})`), { status: r.status });
308
+ return j;
309
+ }
310
+
223
311
  async function call(name, args) {
224
312
  if (!tools.some((t) => t.name === name)) throw new Error(`Unknown tool ${name}`);
225
313
  if (name === 'list_agents') {
@@ -227,13 +315,29 @@ async function call(name, args) {
227
315
  return JSON.stringify(await r.json(), null, 2);
228
316
  }
229
317
  if (name === 'dispatch') {
318
+ const background = args.background !== false;
230
319
  const r = await fetch(`${API}/api/dispatch`, {
231
320
  method: 'POST', headers: { 'content-type': 'application/json' },
232
- body: JSON.stringify({ from: FROM, agent: args.agent, task: args.task }),
321
+ body: JSON.stringify({ from: FROM, agent: args.agent, task: args.task, background, poll: !background }),
233
322
  });
234
323
  const j = await r.json();
235
324
  if (!r.ok) throw new Error(j.error ?? `dispatch failed (${r.status})`);
236
- return j.text || '(the subagent finished without a text answer)';
325
+ if (background) return `Task ${j.id} sent to ${j.agent} (${j.status}). You will be woken with the result when it finishes; you can also ask with dispatch_status.`;
326
+ // Wait for the end with short calls: the answer is read from the server's record, never from one long request.
327
+ for (let errors = 0; ;) {
328
+ let s;
329
+ try { s = await taskStatus(j.id, POLL_S); errors = 0; } catch (e) {
330
+ if (e.status || ++errors > 5) throw new Error(`${e.message}. The task ${j.id} goes on: ask for its result with dispatch_status.`);
331
+ await new Promise((ok) => setTimeout(ok, 2000));
332
+ continue;
333
+ }
334
+ if (s.status === 'done') return s.result;
335
+ if (s.status === 'failed' || s.status === 'interrupted') throw new Error(`${j.agent} did not finish the task (${s.status}): ${s.result}`);
336
+ }
337
+ }
338
+ if (name === 'dispatch_status') {
339
+ const s = await taskStatus(args.id, args.wait_seconds);
340
+ return `Task ${s.id} for ${s.agent}: ${s.status}.${s.note ? ` ${s.note}` : ''}${s.result !== undefined ? ` Result:\n${s.result}` : ' Not finished yet.'}`;
237
341
  }
238
342
  if (name === 'channel_reply') {
239
343
  const r = await fetch(`${API}/api/channel/reply`, {
@@ -293,6 +397,13 @@ async function call(name, args) {
293
397
  if (!r.ok) throw new Error(j.error ?? `channel_mute failed (${r.status})`);
294
398
  return j.muted ? `Muted in this thread (${j.place}). You will only be woken when someone mentions you or replies to you.` : `Unmuted in this thread (${j.place}).`;
295
399
  }
400
+ if (name.startsWith('object_db_')) {
401
+ const op = name.slice('object_db_'.length);
402
+ const r = await fetch(`${API}/api/agent-objects/db/${op}`, { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify({ from: FROM, ...args }) });
403
+ const j = await r.json();
404
+ if (!r.ok) throw new Error(j.error ?? `${name} failed (${r.status})`);
405
+ return dbAnswer(op, j);
406
+ }
296
407
  if (name === 'object_list' || name === 'object_logs' || name === 'object_action') {
297
408
  const r = await fetch(`${API}/api/agent-objects/${name.slice('object_'.length)}`, {
298
409
  method: 'POST', headers: { 'content-type': 'application/json' },
@@ -1 +1 @@
1
- YT6HM6qmegMJaBMX5QvuP
1
+ tdnUXVa01m25EjOobxVd1
@@ -13,30 +13,49 @@
13
13
  "static/chunks/89-b194fcffe5120c44.js",
14
14
  "static/chunks/main-app-6086068e5fb5eacd.js",
15
15
  "static/css/945795da867f5250.css",
16
- "static/css/582723fcea1f9887.css",
17
- "static/chunks/586-f7017d585a84738d.js",
18
- "static/chunks/281-113274e705940a55.js",
19
- "static/chunks/app/layout-fad968a635f9a4b3.js"
16
+ "static/css/c7faf690373117bb.css",
17
+ "static/chunks/586-4f67b823df060b46.js",
18
+ "static/chunks/281-4506bc98b7111729.js",
19
+ "static/chunks/app/layout-cb5af29b0742c513.js"
20
+ ],
21
+ "/chat/page": [
22
+ "static/chunks/webpack-ef515e41a83a16ac.js",
23
+ "static/chunks/0937d497-114a2a3de515565e.js",
24
+ "static/chunks/89-b194fcffe5120c44.js",
25
+ "static/chunks/main-app-6086068e5fb5eacd.js",
26
+ "static/chunks/586-4f67b823df060b46.js",
27
+ "static/chunks/706-fa2be0f10ffebe6a.js",
28
+ "static/chunks/281-4506bc98b7111729.js",
29
+ "static/chunks/517-8f2db464d10a4624.js",
30
+ "static/chunks/app/chat/page-383bc24e72dab7fa.js"
20
31
  ],
21
32
  "/connections/page": [
22
33
  "static/chunks/webpack-ef515e41a83a16ac.js",
23
34
  "static/chunks/0937d497-114a2a3de515565e.js",
24
35
  "static/chunks/89-b194fcffe5120c44.js",
25
36
  "static/chunks/main-app-6086068e5fb5eacd.js",
26
- "static/chunks/586-f7017d585a84738d.js",
27
- "static/chunks/281-113274e705940a55.js",
28
- "static/chunks/app/connections/page-eb11cfb1ffeab3ca.js"
37
+ "static/chunks/586-4f67b823df060b46.js",
38
+ "static/chunks/281-4506bc98b7111729.js",
39
+ "static/chunks/app/connections/page-b0ea2eae62cef74e.js"
29
40
  ],
30
- "/chat/page": [
41
+ "/resources/[id]/page": [
31
42
  "static/chunks/webpack-ef515e41a83a16ac.js",
32
43
  "static/chunks/0937d497-114a2a3de515565e.js",
33
44
  "static/chunks/89-b194fcffe5120c44.js",
34
45
  "static/chunks/main-app-6086068e5fb5eacd.js",
35
- "static/chunks/586-f7017d585a84738d.js",
46
+ "static/chunks/586-4f67b823df060b46.js",
36
47
  "static/chunks/706-fa2be0f10ffebe6a.js",
37
- "static/chunks/281-113274e705940a55.js",
38
- "static/chunks/517-373a80c8ba432bdc.js",
39
- "static/chunks/app/chat/page-5261b12b7d50f5d1.js"
48
+ "static/chunks/642-dc874c8caf203ee1.js",
49
+ "static/chunks/837-33c7480524f48577.js",
50
+ "static/chunks/771-db19da9b1a24820c.js",
51
+ "static/chunks/281-4506bc98b7111729.js",
52
+ "static/chunks/517-8f2db464d10a4624.js",
53
+ "static/chunks/350-0fe82e622e7a670f.js",
54
+ "static/chunks/606-14fb5aaa4d0ff22d.js",
55
+ "static/chunks/587-3c53d91a1c4f99d6.js",
56
+ "static/chunks/30-9adcbe92b15a6815.js",
57
+ "static/chunks/491-196bcb3dd11bb460.js",
58
+ "static/chunks/app/resources/[id]/page-1e2afddcb1f04884.js"
40
59
  ],
41
60
  "/relations/page": [
42
61
  "static/chunks/webpack-ef515e41a83a16ac.js",
@@ -45,133 +64,130 @@
45
64
  "static/chunks/main-app-6086068e5fb5eacd.js",
46
65
  "static/css/c4a545148b5320ec.css",
47
66
  "static/chunks/2b9ff8ee-969e65cc354b2150.js",
48
- "static/chunks/586-f7017d585a84738d.js",
49
- "static/chunks/562-7c2e33d838e869bf.js",
50
- "static/chunks/281-113274e705940a55.js",
51
- "static/chunks/app/relations/page-a44fd515a3b0525e.js"
67
+ "static/chunks/586-4f67b823df060b46.js",
68
+ "static/chunks/757-03361e7a97a605a2.js",
69
+ "static/chunks/281-4506bc98b7111729.js",
70
+ "static/chunks/app/relations/page-02710fe1f8a670a9.js"
52
71
  ],
53
- "/agents/[id]/page": [
72
+ "/resources/page": [
54
73
  "static/chunks/webpack-ef515e41a83a16ac.js",
55
74
  "static/chunks/0937d497-114a2a3de515565e.js",
56
75
  "static/chunks/89-b194fcffe5120c44.js",
57
76
  "static/chunks/main-app-6086068e5fb5eacd.js",
58
- "static/chunks/586-f7017d585a84738d.js",
77
+ "static/chunks/586-4f67b823df060b46.js",
59
78
  "static/chunks/706-fa2be0f10ffebe6a.js",
79
+ "static/chunks/642-dc874c8caf203ee1.js",
60
80
  "static/chunks/837-33c7480524f48577.js",
61
- "static/chunks/391-18768499e741112e.js",
62
- "static/chunks/316-26da9cc233ba7557.js",
63
- "static/chunks/281-113274e705940a55.js",
64
- "static/chunks/517-373a80c8ba432bdc.js",
81
+ "static/chunks/771-db19da9b1a24820c.js",
82
+ "static/chunks/281-4506bc98b7111729.js",
83
+ "static/chunks/517-8f2db464d10a4624.js",
65
84
  "static/chunks/350-0fe82e622e7a670f.js",
66
- "static/chunks/606-c9a19918b02a98d0.js",
85
+ "static/chunks/606-14fb5aaa4d0ff22d.js",
86
+ "static/chunks/587-3c53d91a1c4f99d6.js",
67
87
  "static/chunks/30-9adcbe92b15a6815.js",
68
- "static/chunks/705-f81face97b1bb1af.js",
69
- "static/chunks/app/agents/[id]/page-6ed6edb3e74b0ebe.js"
88
+ "static/chunks/491-196bcb3dd11bb460.js",
89
+ "static/chunks/app/resources/page-195b0af83b8ace0d.js"
70
90
  ],
71
- "/agents/page": [
91
+ "/page": [
72
92
  "static/chunks/webpack-ef515e41a83a16ac.js",
73
93
  "static/chunks/0937d497-114a2a3de515565e.js",
74
94
  "static/chunks/89-b194fcffe5120c44.js",
75
95
  "static/chunks/main-app-6086068e5fb5eacd.js",
76
- "static/chunks/586-f7017d585a84738d.js",
96
+ "static/chunks/586-4f67b823df060b46.js",
77
97
  "static/chunks/706-fa2be0f10ffebe6a.js",
78
- "static/chunks/281-113274e705940a55.js",
79
- "static/chunks/517-373a80c8ba432bdc.js",
80
- "static/chunks/app/agents/page-9bb8cba69776c719.js"
98
+ "static/chunks/642-dc874c8caf203ee1.js",
99
+ "static/chunks/162-68ba190086f5ad39.js",
100
+ "static/chunks/281-4506bc98b7111729.js",
101
+ "static/chunks/517-8f2db464d10a4624.js",
102
+ "static/chunks/350-0fe82e622e7a670f.js",
103
+ "static/chunks/606-14fb5aaa4d0ff22d.js",
104
+ "static/chunks/587-3c53d91a1c4f99d6.js",
105
+ "static/chunks/app/page-5e547e87de23d9fa.js"
81
106
  ],
82
- "/resources/[id]/page": [
107
+ "/schedules/page": [
83
108
  "static/chunks/webpack-ef515e41a83a16ac.js",
84
109
  "static/chunks/0937d497-114a2a3de515565e.js",
85
110
  "static/chunks/89-b194fcffe5120c44.js",
86
111
  "static/chunks/main-app-6086068e5fb5eacd.js",
87
- "static/chunks/586-f7017d585a84738d.js",
88
- "static/chunks/706-fa2be0f10ffebe6a.js",
89
- "static/chunks/837-33c7480524f48577.js",
90
- "static/chunks/391-18768499e741112e.js",
91
- "static/chunks/281-113274e705940a55.js",
92
- "static/chunks/517-373a80c8ba432bdc.js",
93
- "static/chunks/350-0fe82e622e7a670f.js",
94
- "static/chunks/606-c9a19918b02a98d0.js",
95
- "static/chunks/587-8e4d2be01ba7d48f.js",
96
- "static/chunks/30-9adcbe92b15a6815.js",
97
- "static/chunks/656-f537149fe28f79aa.js",
98
- "static/chunks/app/resources/[id]/page-fc494e85b01e8cb7.js"
112
+ "static/chunks/586-4f67b823df060b46.js",
113
+ "static/chunks/281-4506bc98b7111729.js",
114
+ "static/chunks/app/schedules/page-96976fff4ee23538.js"
99
115
  ],
100
- "/resources/page": [
116
+ "/sessions/page": [
101
117
  "static/chunks/webpack-ef515e41a83a16ac.js",
102
118
  "static/chunks/0937d497-114a2a3de515565e.js",
103
119
  "static/chunks/89-b194fcffe5120c44.js",
104
120
  "static/chunks/main-app-6086068e5fb5eacd.js",
105
- "static/chunks/586-f7017d585a84738d.js",
121
+ "static/chunks/586-4f67b823df060b46.js",
106
122
  "static/chunks/706-fa2be0f10ffebe6a.js",
107
- "static/chunks/837-33c7480524f48577.js",
108
- "static/chunks/391-18768499e741112e.js",
109
- "static/chunks/281-113274e705940a55.js",
110
- "static/chunks/517-373a80c8ba432bdc.js",
123
+ "static/chunks/654-92a63b3c4b412666.js",
124
+ "static/chunks/281-4506bc98b7111729.js",
111
125
  "static/chunks/350-0fe82e622e7a670f.js",
112
- "static/chunks/606-c9a19918b02a98d0.js",
113
- "static/chunks/587-8e4d2be01ba7d48f.js",
114
- "static/chunks/30-9adcbe92b15a6815.js",
115
- "static/chunks/656-f537149fe28f79aa.js",
116
- "static/chunks/app/resources/page-61cccd8fdcc2f6c8.js"
126
+ "static/chunks/705-ce86175dea00e6a9.js",
127
+ "static/chunks/app/sessions/page-85638705fdc18174.js"
117
128
  ],
118
- "/page": [
129
+ "/skills/page": [
119
130
  "static/chunks/webpack-ef515e41a83a16ac.js",
120
131
  "static/chunks/0937d497-114a2a3de515565e.js",
121
132
  "static/chunks/89-b194fcffe5120c44.js",
122
133
  "static/chunks/main-app-6086068e5fb5eacd.js",
123
- "static/chunks/586-f7017d585a84738d.js",
134
+ "static/chunks/586-4f67b823df060b46.js",
124
135
  "static/chunks/706-fa2be0f10ffebe6a.js",
125
- "static/chunks/391-18768499e741112e.js",
126
- "static/chunks/281-113274e705940a55.js",
127
- "static/chunks/517-373a80c8ba432bdc.js",
128
- "static/chunks/350-0fe82e622e7a670f.js",
129
- "static/chunks/606-c9a19918b02a98d0.js",
130
- "static/chunks/587-8e4d2be01ba7d48f.js",
131
- "static/chunks/app/page-99e0351e6ccaa384.js"
136
+ "static/chunks/281-4506bc98b7111729.js",
137
+ "static/chunks/app/skills/page-bc1acd0663f36129.js"
132
138
  ],
133
- "/schedules/page": [
139
+ "/types/page": [
134
140
  "static/chunks/webpack-ef515e41a83a16ac.js",
135
141
  "static/chunks/0937d497-114a2a3de515565e.js",
136
142
  "static/chunks/89-b194fcffe5120c44.js",
137
143
  "static/chunks/main-app-6086068e5fb5eacd.js",
138
- "static/chunks/586-f7017d585a84738d.js",
139
- "static/chunks/281-113274e705940a55.js",
140
- "static/chunks/app/schedules/page-96976fff4ee23538.js"
144
+ "static/chunks/586-4f67b823df060b46.js",
145
+ "static/chunks/706-fa2be0f10ffebe6a.js",
146
+ "static/chunks/281-4506bc98b7111729.js",
147
+ "static/chunks/517-8f2db464d10a4624.js",
148
+ "static/chunks/app/types/page-c4c2b2217c4667e8.js"
141
149
  ],
142
- "/sessions/page": [
150
+ "/agents/layout": [
143
151
  "static/chunks/webpack-ef515e41a83a16ac.js",
144
152
  "static/chunks/0937d497-114a2a3de515565e.js",
145
153
  "static/chunks/89-b194fcffe5120c44.js",
146
154
  "static/chunks/main-app-6086068e5fb5eacd.js",
147
- "static/chunks/586-f7017d585a84738d.js",
155
+ "static/chunks/586-4f67b823df060b46.js",
148
156
  "static/chunks/706-fa2be0f10ffebe6a.js",
149
- "static/chunks/654-92a63b3c4b412666.js",
150
- "static/chunks/281-113274e705940a55.js",
157
+ "static/chunks/642-dc874c8caf203ee1.js",
158
+ "static/chunks/281-4506bc98b7111729.js",
159
+ "static/chunks/517-8f2db464d10a4624.js",
151
160
  "static/chunks/350-0fe82e622e7a670f.js",
152
- "static/chunks/705-f81face97b1bb1af.js",
153
- "static/chunks/app/sessions/page-a7534ebd90e982d6.js"
161
+ "static/chunks/app/agents/layout-71dd98d696935e29.js"
154
162
  ],
155
- "/types/page": [
163
+ "/agents/page": [
156
164
  "static/chunks/webpack-ef515e41a83a16ac.js",
157
165
  "static/chunks/0937d497-114a2a3de515565e.js",
158
166
  "static/chunks/89-b194fcffe5120c44.js",
159
167
  "static/chunks/main-app-6086068e5fb5eacd.js",
160
- "static/chunks/586-f7017d585a84738d.js",
168
+ "static/chunks/586-4f67b823df060b46.js",
161
169
  "static/chunks/706-fa2be0f10ffebe6a.js",
162
- "static/chunks/281-113274e705940a55.js",
163
- "static/chunks/517-373a80c8ba432bdc.js",
164
- "static/chunks/app/types/page-ebd37e220f77c1f3.js"
170
+ "static/chunks/281-4506bc98b7111729.js",
171
+ "static/chunks/517-8f2db464d10a4624.js",
172
+ "static/chunks/app/agents/page-9da499db6d22731f.js"
165
173
  ],
166
- "/skills/page": [
174
+ "/agents/[id]/page": [
167
175
  "static/chunks/webpack-ef515e41a83a16ac.js",
168
176
  "static/chunks/0937d497-114a2a3de515565e.js",
169
177
  "static/chunks/89-b194fcffe5120c44.js",
170
178
  "static/chunks/main-app-6086068e5fb5eacd.js",
171
- "static/chunks/586-f7017d585a84738d.js",
179
+ "static/chunks/586-4f67b823df060b46.js",
172
180
  "static/chunks/706-fa2be0f10ffebe6a.js",
173
- "static/chunks/281-113274e705940a55.js",
174
- "static/chunks/app/skills/page-bc1acd0663f36129.js"
181
+ "static/chunks/642-dc874c8caf203ee1.js",
182
+ "static/chunks/837-33c7480524f48577.js",
183
+ "static/chunks/214-35b88db02113ae02.js",
184
+ "static/chunks/281-4506bc98b7111729.js",
185
+ "static/chunks/517-8f2db464d10a4624.js",
186
+ "static/chunks/350-0fe82e622e7a670f.js",
187
+ "static/chunks/606-14fb5aaa4d0ff22d.js",
188
+ "static/chunks/30-9adcbe92b15a6815.js",
189
+ "static/chunks/705-ce86175dea00e6a9.js",
190
+ "static/chunks/app/agents/[id]/page-803d53aedd10c8e5.js"
175
191
  ]
176
192
  }
177
193
  }
@@ -1,18 +1,18 @@
1
1
  {
2
2
  "/_not-found/page": "/_not-found",
3
- "/apple-icon.png/route": "/apple-icon.png",
4
- "/favicon.ico/route": "/favicon.ico",
5
3
  "/icon.png/route": "/icon.png",
6
- "/connections/page": "/connections",
4
+ "/favicon.ico/route": "/favicon.ico",
5
+ "/apple-icon.png/route": "/apple-icon.png",
7
6
  "/chat/page": "/chat",
8
- "/relations/page": "/relations",
9
- "/agents/[id]/page": "/agents/[id]",
10
- "/agents/page": "/agents",
7
+ "/connections/page": "/connections",
11
8
  "/resources/[id]/page": "/resources/[id]",
9
+ "/relations/page": "/relations",
12
10
  "/resources/page": "/resources",
13
11
  "/page": "/",
14
12
  "/schedules/page": "/schedules",
15
13
  "/sessions/page": "/sessions",
14
+ "/skills/page": "/skills",
16
15
  "/types/page": "/types",
17
- "/skills/page": "/skills"
16
+ "/agents/page": "/agents",
17
+ "/agents/[id]/page": "/agents/[id]"
18
18
  }
@@ -5,8 +5,8 @@
5
5
  "devFiles": [],
6
6
  "ampDevFiles": [],
7
7
  "lowPriorityFiles": [
8
- "static/YT6HM6qmegMJaBMX5QvuP/_buildManifest.js",
9
- "static/YT6HM6qmegMJaBMX5QvuP/_ssgManifest.js"
8
+ "static/tdnUXVa01m25EjOobxVd1/_buildManifest.js",
9
+ "static/tdnUXVa01m25EjOobxVd1/_ssgManifest.js"
10
10
  ],
11
11
  "rootMainFiles": [
12
12
  "static/chunks/webpack-ef515e41a83a16ac.js",