@geminilight/mindos 0.6.57 → 0.6.58

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 (222) hide show
  1. package/_standalone/.mindos-build-version +1 -1
  2. package/_standalone/.next/BUILD_ID +1 -1
  3. package/_standalone/.next/app-path-routes-manifest.json +21 -21
  4. package/_standalone/.next/build-manifest.json +2 -2
  5. package/_standalone/.next/cache/.previewinfo +1 -1
  6. package/_standalone/.next/cache/.rscinfo +1 -1
  7. package/_standalone/.next/cache/config.json +3 -3
  8. package/_standalone/.next/prerender-manifest.json +3 -3
  9. package/_standalone/.next/server/app/.well-known/agent-card.json/route_client-reference-manifest.js +1 -1
  10. package/_standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  11. package/_standalone/.next/server/app/_global-error.html +2 -2
  12. package/_standalone/.next/server/app/_global-error.rsc +1 -1
  13. package/_standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  14. package/_standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  15. package/_standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  16. package/_standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  17. package/_standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  18. package/_standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  19. package/_standalone/.next/server/app/_not-found/page.js +1 -1
  20. package/_standalone/.next/server/app/_not-found/page.js.nft.json +1 -1
  21. package/_standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  22. package/_standalone/.next/server/app/agents/[agentKey]/page.js +2 -2
  23. package/_standalone/.next/server/app/agents/[agentKey]/page.js.nft.json +1 -1
  24. package/_standalone/.next/server/app/agents/[agentKey]/page_client-reference-manifest.js +1 -1
  25. package/_standalone/.next/server/app/agents/page.js +1 -1
  26. package/_standalone/.next/server/app/agents/page.js.nft.json +1 -1
  27. package/_standalone/.next/server/app/agents/page_client-reference-manifest.js +1 -1
  28. package/_standalone/.next/server/app/api/a2a/agents/route_client-reference-manifest.js +1 -1
  29. package/_standalone/.next/server/app/api/a2a/delegations/route_client-reference-manifest.js +1 -1
  30. package/_standalone/.next/server/app/api/a2a/discover/route_client-reference-manifest.js +1 -1
  31. package/_standalone/.next/server/app/api/a2a/route_client-reference-manifest.js +1 -1
  32. package/_standalone/.next/server/app/api/acp/config/route.js +1 -1
  33. package/_standalone/.next/server/app/api/acp/config/route_client-reference-manifest.js +1 -1
  34. package/_standalone/.next/server/app/api/acp/detect/route.js +1 -1
  35. package/_standalone/.next/server/app/api/acp/detect/route_client-reference-manifest.js +1 -1
  36. package/_standalone/.next/server/app/api/acp/install/route_client-reference-manifest.js +1 -1
  37. package/_standalone/.next/server/app/api/acp/registry/route_client-reference-manifest.js +1 -1
  38. package/_standalone/.next/server/app/api/acp/session/route_client-reference-manifest.js +1 -1
  39. package/_standalone/.next/server/app/api/agent-activity/route_client-reference-manifest.js +1 -1
  40. package/_standalone/.next/server/app/api/agents/custom/detect/route.js +1 -1
  41. package/_standalone/.next/server/app/api/agents/custom/detect/route_client-reference-manifest.js +1 -1
  42. package/_standalone/.next/server/app/api/agents/custom/route.js +1 -1
  43. package/_standalone/.next/server/app/api/agents/custom/route_client-reference-manifest.js +1 -1
  44. package/_standalone/.next/server/app/api/ask/route.js +4 -4
  45. package/_standalone/.next/server/app/api/ask/route.js.nft.json +1 -1
  46. package/_standalone/.next/server/app/api/ask/route_client-reference-manifest.js +1 -1
  47. package/_standalone/.next/server/app/api/ask-sessions/route_client-reference-manifest.js +1 -1
  48. package/_standalone/.next/server/app/api/auth/route_client-reference-manifest.js +1 -1
  49. package/_standalone/.next/server/app/api/backlinks/route.js.nft.json +1 -1
  50. package/_standalone/.next/server/app/api/backlinks/route_client-reference-manifest.js +1 -1
  51. package/_standalone/.next/server/app/api/bootstrap/route.js.nft.json +1 -1
  52. package/_standalone/.next/server/app/api/bootstrap/route_client-reference-manifest.js +1 -1
  53. package/_standalone/.next/server/app/api/changes/route.js.nft.json +1 -1
  54. package/_standalone/.next/server/app/api/changes/route_client-reference-manifest.js +1 -1
  55. package/_standalone/.next/server/app/api/export/route.js.nft.json +1 -1
  56. package/_standalone/.next/server/app/api/export/route_client-reference-manifest.js +1 -1
  57. package/_standalone/.next/server/app/api/extract-pdf/route_client-reference-manifest.js +1 -1
  58. package/_standalone/.next/server/app/api/file/import/route.js.nft.json +1 -1
  59. package/_standalone/.next/server/app/api/file/import/route_client-reference-manifest.js +1 -1
  60. package/_standalone/.next/server/app/api/file/raw/route.js.nft.json +1 -1
  61. package/_standalone/.next/server/app/api/file/raw/route_client-reference-manifest.js +1 -1
  62. package/_standalone/.next/server/app/api/file/route.js.nft.json +1 -1
  63. package/_standalone/.next/server/app/api/file/route_client-reference-manifest.js +1 -1
  64. package/_standalone/.next/server/app/api/files/route.js.nft.json +1 -1
  65. package/_standalone/.next/server/app/api/files/route_client-reference-manifest.js +1 -1
  66. package/_standalone/.next/server/app/api/git/route.js.nft.json +1 -1
  67. package/_standalone/.next/server/app/api/git/route_client-reference-manifest.js +1 -1
  68. package/_standalone/.next/server/app/api/graph/route.js.nft.json +1 -1
  69. package/_standalone/.next/server/app/api/graph/route_client-reference-manifest.js +1 -1
  70. package/_standalone/.next/server/app/api/health/route_client-reference-manifest.js +1 -1
  71. package/_standalone/.next/server/app/api/inbox/route.js.nft.json +1 -1
  72. package/_standalone/.next/server/app/api/inbox/route_client-reference-manifest.js +1 -1
  73. package/_standalone/.next/server/app/api/init/route.js.nft.json +1 -1
  74. package/_standalone/.next/server/app/api/init/route_client-reference-manifest.js +1 -1
  75. package/_standalone/.next/server/app/api/mcp/agents/route.js +1 -1
  76. package/_standalone/.next/server/app/api/mcp/agents/route.js.nft.json +1 -1
  77. package/_standalone/.next/server/app/api/mcp/agents/route_client-reference-manifest.js +1 -1
  78. package/_standalone/.next/server/app/api/mcp/install/route.js +1 -1
  79. package/_standalone/.next/server/app/api/mcp/install/route_client-reference-manifest.js +1 -1
  80. package/_standalone/.next/server/app/api/mcp/install-skill/route_client-reference-manifest.js +1 -1
  81. package/_standalone/.next/server/app/api/mcp/restart/route_client-reference-manifest.js +1 -1
  82. package/_standalone/.next/server/app/api/mcp/status/route.js +1 -1
  83. package/_standalone/.next/server/app/api/mcp/status/route_client-reference-manifest.js +1 -1
  84. package/_standalone/.next/server/app/api/mcp/uninstall/route_client-reference-manifest.js +1 -1
  85. package/_standalone/.next/server/app/api/monitoring/route.js.nft.json +1 -1
  86. package/_standalone/.next/server/app/api/monitoring/route_client-reference-manifest.js +1 -1
  87. package/_standalone/.next/server/app/api/recent-files/route.js.nft.json +1 -1
  88. package/_standalone/.next/server/app/api/recent-files/route_client-reference-manifest.js +1 -1
  89. package/_standalone/.next/server/app/api/restart/route_client-reference-manifest.js +1 -1
  90. package/_standalone/.next/server/app/api/search/route.js.nft.json +1 -1
  91. package/_standalone/.next/server/app/api/search/route_client-reference-manifest.js +1 -1
  92. package/_standalone/.next/server/app/api/settings/list-models/route_client-reference-manifest.js +1 -1
  93. package/_standalone/.next/server/app/api/settings/reset-token/route.js +1 -1
  94. package/_standalone/.next/server/app/api/settings/reset-token/route_client-reference-manifest.js +1 -1
  95. package/_standalone/.next/server/app/api/settings/route.js +1 -1
  96. package/_standalone/.next/server/app/api/settings/route.js.nft.json +1 -1
  97. package/_standalone/.next/server/app/api/settings/route_client-reference-manifest.js +1 -1
  98. package/_standalone/.next/server/app/api/settings/test-key/route.js +1 -1
  99. package/_standalone/.next/server/app/api/settings/test-key/route_client-reference-manifest.js +1 -1
  100. package/_standalone/.next/server/app/api/setup/check-path/route_client-reference-manifest.js +1 -1
  101. package/_standalone/.next/server/app/api/setup/check-port/route_client-reference-manifest.js +1 -1
  102. package/_standalone/.next/server/app/api/setup/generate-token/route_client-reference-manifest.js +1 -1
  103. package/_standalone/.next/server/app/api/setup/ls/route_client-reference-manifest.js +1 -1
  104. package/_standalone/.next/server/app/api/setup/route.js +1 -1
  105. package/_standalone/.next/server/app/api/setup/route_client-reference-manifest.js +1 -1
  106. package/_standalone/.next/server/app/api/skills/route.js +1 -1
  107. package/_standalone/.next/server/app/api/skills/route_client-reference-manifest.js +1 -1
  108. package/_standalone/.next/server/app/api/sync/route_client-reference-manifest.js +1 -1
  109. package/_standalone/.next/server/app/api/tree-version/route.js.nft.json +1 -1
  110. package/_standalone/.next/server/app/api/tree-version/route_client-reference-manifest.js +1 -1
  111. package/_standalone/.next/server/app/api/uninstall/route_client-reference-manifest.js +1 -1
  112. package/_standalone/.next/server/app/api/update/route_client-reference-manifest.js +1 -1
  113. package/_standalone/.next/server/app/api/update-check/route_client-reference-manifest.js +1 -1
  114. package/_standalone/.next/server/app/api/update-status/route_client-reference-manifest.js +1 -1
  115. package/_standalone/.next/server/app/api/workflows/route.js.nft.json +1 -1
  116. package/_standalone/.next/server/app/api/workflows/route_client-reference-manifest.js +1 -1
  117. package/_standalone/.next/server/app/changes/page.js +2 -2
  118. package/_standalone/.next/server/app/changes/page.js.nft.json +1 -1
  119. package/_standalone/.next/server/app/changes/page_client-reference-manifest.js +1 -1
  120. package/_standalone/.next/server/app/echo/[segment]/page.js +1 -1
  121. package/_standalone/.next/server/app/echo/[segment]/page.js.nft.json +1 -1
  122. package/_standalone/.next/server/app/echo/[segment]/page_client-reference-manifest.js +1 -1
  123. package/_standalone/.next/server/app/echo/page.js +1 -1
  124. package/_standalone/.next/server/app/echo/page.js.nft.json +1 -1
  125. package/_standalone/.next/server/app/echo/page_client-reference-manifest.js +1 -1
  126. package/_standalone/.next/server/app/explore/page.js +2 -2
  127. package/_standalone/.next/server/app/explore/page.js.nft.json +1 -1
  128. package/_standalone/.next/server/app/explore/page_client-reference-manifest.js +1 -1
  129. package/_standalone/.next/server/app/help/page.js +2 -2
  130. package/_standalone/.next/server/app/help/page.js.nft.json +1 -1
  131. package/_standalone/.next/server/app/help/page_client-reference-manifest.js +1 -1
  132. package/_standalone/.next/server/app/inbox/history/page.js +1 -1
  133. package/_standalone/.next/server/app/inbox/history/page.js.nft.json +1 -1
  134. package/_standalone/.next/server/app/inbox/history/page_client-reference-manifest.js +1 -1
  135. package/_standalone/.next/server/app/login/page.js +1 -1
  136. package/_standalone/.next/server/app/login/page.js.nft.json +1 -1
  137. package/_standalone/.next/server/app/login/page_client-reference-manifest.js +1 -1
  138. package/_standalone/.next/server/app/page.js +1 -1
  139. package/_standalone/.next/server/app/page.js.nft.json +1 -1
  140. package/_standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  141. package/_standalone/.next/server/app/setup/page.js +2 -2
  142. package/_standalone/.next/server/app/setup/page.js.nft.json +1 -1
  143. package/_standalone/.next/server/app/setup/page_client-reference-manifest.js +1 -1
  144. package/_standalone/.next/server/app/trash/page.js +3 -3
  145. package/_standalone/.next/server/app/trash/page.js.nft.json +1 -1
  146. package/_standalone/.next/server/app/trash/page_client-reference-manifest.js +1 -1
  147. package/_standalone/.next/server/app/view/[...path]/page.js +3 -3
  148. package/_standalone/.next/server/app/view/[...path]/page.js.nft.json +1 -1
  149. package/_standalone/.next/server/app/view/[...path]/page_client-reference-manifest.js +1 -1
  150. package/_standalone/.next/server/app/wiki/page.js +1 -1
  151. package/_standalone/.next/server/app/wiki/page.js.nft.json +1 -1
  152. package/_standalone/.next/server/app/wiki/page_client-reference-manifest.js +1 -1
  153. package/_standalone/.next/server/app-paths-manifest.json +21 -21
  154. package/_standalone/.next/server/chunks/1550.js +1 -1
  155. package/_standalone/.next/server/chunks/1750.js +1 -1
  156. package/_standalone/.next/server/chunks/3484.js +1 -1
  157. package/_standalone/.next/server/chunks/530.js +23 -23
  158. package/_standalone/.next/server/chunks/6539.js +1 -1
  159. package/_standalone/.next/server/chunks/{2159.js → 6793.js} +2 -2
  160. package/_standalone/.next/server/pages/500.html +2 -2
  161. package/_standalone/.next/server/server-reference-manifest.js +1 -1
  162. package/_standalone/.next/server/server-reference-manifest.json +1 -1
  163. package/_standalone/.next/static/chunks/1053-fe009233cff06e72.js +29 -0
  164. package/_standalone/.next/static/chunks/7249-fa98ca10e9a10f39.js +11 -0
  165. package/_standalone/.next/static/chunks/app/{layout-b3919384ec2eb979.js → layout-7e02ddf4144b01f1.js} +11 -11
  166. package/_standalone/.next/static/chunks/app/page-6a6a12bd6d6812d0.js +7 -0
  167. package/_standalone/.next/static/chunks/app/trash/page-54cbd5c98d9de69b.js +1 -0
  168. package/_standalone/.next/static/chunks/app/view/[...path]/page-ca7bdcbf27f88a46.js +12 -0
  169. package/_standalone/.next/trace +64 -64
  170. package/_standalone/__tests__/api/mcp-install.test.ts +3 -2
  171. package/_standalone/__tests__/ask/non-streaming-api.test.ts +281 -0
  172. package/_standalone/__tests__/core/skill-install-logic.test.ts +1 -0
  173. package/_standalone/components/agents/CustomAgentModal.tsx +32 -8
  174. package/_standalone/data/skills/mindos/SKILL.md +14 -9
  175. package/_standalone/data/skills/mindos-zh/SKILL.md +13 -4
  176. package/_standalone/tsconfig.tsbuildinfo +1 -1
  177. package/app/app/api/agents/custom/route.ts +8 -0
  178. package/app/app/api/ask/route.ts +171 -10
  179. package/app/app/api/mcp/agents/route.ts +5 -3
  180. package/app/app/api/settings/route.ts +9 -0
  181. package/app/app/api/settings/test-key/route.ts +13 -1
  182. package/app/components/agents/CustomAgentModal.tsx +32 -8
  183. package/app/data/skills/mindos/SKILL.md +14 -9
  184. package/app/data/skills/mindos-zh/SKILL.md +13 -4
  185. package/app/lib/custom-agents.ts +45 -2
  186. package/app/lib/i18n/modules/panels.ts +10 -2
  187. package/app/lib/mcp-agents.ts +10 -0
  188. package/bin/lib/mcp-agents.js +10 -0
  189. package/package.json +1 -1
  190. package/skills/mindos/SKILL.md +10 -4
  191. package/skills/mindos-max/SKILL.md +191 -0
  192. package/skills/mindos-max-workspace/evals/evals.json +23 -0
  193. package/skills/mindos-max-workspace/iteration-1/capture-debugging-experience-en/eval_metadata.json +11 -0
  194. package/skills/mindos-max-workspace/iteration-1/capture-debugging-experience-en/old_skill/grading.json +28 -0
  195. package/skills/mindos-max-workspace/iteration-1/capture-debugging-experience-en/old_skill/outputs/transcript.md +203 -0
  196. package/skills/mindos-max-workspace/iteration-1/capture-debugging-experience-en/with_skill/grading.json +28 -0
  197. package/skills/mindos-max-workspace/iteration-1/capture-debugging-experience-en/with_skill/outputs/transcript.md +271 -0
  198. package/skills/mindos-max-workspace/iteration-1/save-meeting-decision-zh/eval_metadata.json +11 -0
  199. package/skills/mindos-max-workspace/iteration-1/save-meeting-decision-zh/old_skill/grading.json +28 -0
  200. package/skills/mindos-max-workspace/iteration-1/save-meeting-decision-zh/old_skill/outputs/transcript.md +121 -0
  201. package/skills/mindos-max-workspace/iteration-1/save-meeting-decision-zh/with_skill/grading.json +28 -0
  202. package/skills/mindos-max-workspace/iteration-1/save-meeting-decision-zh/with_skill/outputs/transcript.md +168 -0
  203. package/skills/mindos-max-workspace/iteration-1/search-past-decision-zh/eval_metadata.json +11 -0
  204. package/skills/mindos-max-workspace/iteration-1/search-past-decision-zh/old_skill/grading.json +28 -0
  205. package/skills/mindos-max-workspace/iteration-1/search-past-decision-zh/old_skill/outputs/transcript.md +143 -0
  206. package/skills/mindos-max-workspace/iteration-1/search-past-decision-zh/with_skill/grading.json +28 -0
  207. package/skills/mindos-max-workspace/iteration-1/search-past-decision-zh/with_skill/outputs/transcript.md +233 -0
  208. package/skills/mindos-max-workspace/skill-snapshot/mindos-original/SKILL.md +165 -0
  209. package/skills/mindos-max-workspace/skill-snapshot/mindos-original/references/README.md +12 -0
  210. package/skills/mindos-max-workspace/skill-snapshot/mindos-original/references/post-task-hooks.md +27 -0
  211. package/skills/mindos-max-workspace/skill-snapshot/mindos-original/references/preference-capture.md +41 -0
  212. package/skills/mindos-max-workspace/skill-snapshot/mindos-original/references/sop-template.md +74 -0
  213. package/skills/mindos-max-workspace/skill-snapshot/mindos-original/references/write-supplement.md +119 -0
  214. package/skills/mindos-max-zh/SKILL.md +192 -0
  215. package/skills/mindos-zh/SKILL.md +11 -3
  216. package/_standalone/.next/static/chunks/1053-5cb008a24930e271.js +0 -29
  217. package/_standalone/.next/static/chunks/7249-8cd568ad23656622.js +0 -11
  218. package/_standalone/.next/static/chunks/app/page-6436a99cda35132b.js +0 -7
  219. package/_standalone/.next/static/chunks/app/trash/page-8dc388695344fdd4.js +0 -1
  220. package/_standalone/.next/static/chunks/app/view/[...path]/page-b292b55305ecc021.js +0 -12
  221. /package/_standalone/.next/static/{zOaEtgJbdRMncnCBucULp → 2ksXveDzEcnCMRIElDkLq}/_buildManifest.js +0 -0
  222. /package/_standalone/.next/static/{zOaEtgJbdRMncnCBucULp → 2ksXveDzEcnCMRIElDkLq}/_ssgManifest.js +0 -0
@@ -254,11 +254,11 @@ describe('POST /api/mcp/install', () => {
254
254
  });
255
255
 
256
256
  describe('GET /api/mcp/agents', () => {
257
- it('returns all 20 agents (1 builtin + 19 registry)', async () => {
257
+ it('returns all 21 agents (1 builtin + 20 registry)', async () => {
258
258
  const { GET } = await importAgentsRoute();
259
259
  const res = await GET();
260
260
  const body = await res.json();
261
- expect(body.agents).toHaveLength(20);
261
+ expect(body.agents).toHaveLength(21);
262
262
  const keys = body.agents.map((a: { key: string }) => a.key);
263
263
  expect(keys).toContain('mindos');
264
264
  expect(keys).toContain('claude-code');
@@ -275,6 +275,7 @@ describe('GET /api/mcp/agents', () => {
275
275
  expect(keys).toContain('roo');
276
276
  expect(keys).toContain('github-copilot');
277
277
  expect(keys).toContain('codex');
278
+ expect(keys).toContain('antigravity');
278
279
  });
279
280
 
280
281
  it('detects installed agent from config file', async () => {
@@ -0,0 +1,281 @@
1
+ import { describe, it, expect } from 'vitest';
2
+
3
+ /**
4
+ * Tests for non-streaming API fallback.
5
+ * Verifies:
6
+ * 1. pi-ai → OpenAI message format conversion
7
+ * 2. SSE response reassembly (for proxies that ignore stream:false)
8
+ */
9
+
10
+ // ─────────────────────────────────────────────────
11
+ // Replicate helper functions from route.ts for unit testing
12
+ // ─────────────────────────────────────────────────
13
+
14
+ function piMessagesToOpenAI(piMessages: any[]): any[] {
15
+ return piMessages.map(msg => {
16
+ const role = msg.role;
17
+ if (role === 'system') return null;
18
+ if (role === 'user') {
19
+ return { role: 'user', content: typeof msg.content === 'string' ? msg.content : msg.content };
20
+ }
21
+ if (role === 'assistant') {
22
+ const content = msg.content;
23
+ let textContent = '';
24
+ const toolCalls: any[] = [];
25
+ if (Array.isArray(content)) {
26
+ for (const part of content) {
27
+ if (part.type === 'text' && part.text) {
28
+ textContent += part.text;
29
+ } else if (part.type === 'toolCall') {
30
+ toolCalls.push({
31
+ id: part.id ?? `call_fallback`,
32
+ type: 'function',
33
+ function: { name: part.name ?? 'unknown', arguments: JSON.stringify(part.arguments ?? {}) },
34
+ });
35
+ }
36
+ }
37
+ }
38
+ const result: any = { role: 'assistant' };
39
+ result.content = textContent || '';
40
+ if (toolCalls.length > 0) result.tool_calls = toolCalls;
41
+ return result;
42
+ }
43
+ if (role === 'toolResult') {
44
+ const contentText = Array.isArray(msg.content)
45
+ ? msg.content.filter((c: any) => c.type === 'text').map((c: any) => c.text ?? '').join('\n')
46
+ : String(msg.content ?? '');
47
+ return { role: 'tool', tool_call_id: msg.toolCallId ?? 'unknown', content: contentText };
48
+ }
49
+ return null;
50
+ }).filter(Boolean);
51
+ }
52
+
53
+ function reassembleSSE(sseText: string): any {
54
+ const lines = sseText.split('\n');
55
+ let content = '';
56
+ let role = 'assistant';
57
+ let finishReason = 'stop';
58
+ const toolCalls: Map<number, { id: string; type: string; function: { name: string; arguments: string } }> = new Map();
59
+
60
+ for (const line of lines) {
61
+ const trimmed = line.trim();
62
+ if (!trimmed.startsWith('data:')) continue;
63
+ const payload = trimmed.slice(5).trim();
64
+ if (payload === '[DONE]') break;
65
+ let chunk: any;
66
+ try { chunk = JSON.parse(payload); } catch { continue; }
67
+ const delta = chunk?.choices?.[0]?.delta;
68
+ if (!delta) continue;
69
+ if (delta.role) role = delta.role;
70
+ if (delta.content) content += delta.content;
71
+ if (chunk.choices[0].finish_reason) finishReason = chunk.choices[0].finish_reason;
72
+ if (delta.tool_calls) {
73
+ for (const tc of delta.tool_calls) {
74
+ const idx = tc.index ?? 0;
75
+ const existing = toolCalls.get(idx);
76
+ if (!existing) {
77
+ toolCalls.set(idx, {
78
+ id: tc.id ?? '',
79
+ type: tc.type ?? 'function',
80
+ function: { name: tc.function?.name ?? '', arguments: tc.function?.arguments ?? '' },
81
+ });
82
+ } else {
83
+ if (tc.id) existing.id = tc.id;
84
+ if (tc.function?.name) existing.function.name += tc.function.name;
85
+ if (tc.function?.arguments) existing.function.arguments += tc.function.arguments;
86
+ }
87
+ }
88
+ }
89
+ }
90
+
91
+ const message: any = { role, content: content || null };
92
+ if (toolCalls.size > 0) {
93
+ message.tool_calls = Array.from(toolCalls.values());
94
+ }
95
+ return { choices: [{ message, finish_reason: finishReason }] };
96
+ }
97
+
98
+ // ─────────────────────────────────────────────────
99
+ // piMessagesToOpenAI tests
100
+ // ─────────────────────────────────────────────────
101
+
102
+ describe('piMessagesToOpenAI', () => {
103
+ it('converts plain user message', () => {
104
+ expect(piMessagesToOpenAI([{ role: 'user', content: 'Hello!' }]))
105
+ .toEqual([{ role: 'user', content: 'Hello!' }]);
106
+ });
107
+
108
+ it('converts assistant text-only message', () => {
109
+ const result = piMessagesToOpenAI([{
110
+ role: 'assistant',
111
+ content: [{ type: 'text', text: 'Response' }],
112
+ }]);
113
+ expect(result).toEqual([{ role: 'assistant', content: 'Response' }]);
114
+ });
115
+
116
+ it('converts assistant message with tool calls', () => {
117
+ const result = piMessagesToOpenAI([{
118
+ role: 'assistant',
119
+ content: [
120
+ { type: 'text', text: 'Calling tool' },
121
+ { type: 'toolCall', id: 'call_1', name: 'read_file', arguments: { path: '/tmp' } },
122
+ ],
123
+ }]);
124
+ expect(result[0].content).toBe('Calling tool');
125
+ expect(result[0].tool_calls[0]).toMatchObject({
126
+ id: 'call_1', type: 'function',
127
+ function: { name: 'read_file', arguments: '{"path":"/tmp"}' },
128
+ });
129
+ });
130
+
131
+ it('converts tool result message', () => {
132
+ expect(piMessagesToOpenAI([{
133
+ role: 'toolResult', toolCallId: 'call_1',
134
+ content: [{ type: 'text', text: 'result data' }],
135
+ }])).toEqual([{ role: 'tool', tool_call_id: 'call_1', content: 'result data' }]);
136
+ });
137
+
138
+ it('skips system messages', () => {
139
+ const result = piMessagesToOpenAI([
140
+ { role: 'system', content: 'sys' },
141
+ { role: 'user', content: 'hi' },
142
+ ]);
143
+ expect(result).toHaveLength(1);
144
+ expect(result[0].role).toBe('user');
145
+ });
146
+
147
+ it('handles empty assistant content', () => {
148
+ const result = piMessagesToOpenAI([{ role: 'assistant', content: [] }]);
149
+ expect(result[0]).toEqual({ role: 'assistant', content: '' });
150
+ });
151
+
152
+ it('handles complex conversation history', () => {
153
+ const result = piMessagesToOpenAI([
154
+ { role: 'user', content: 'list files' },
155
+ { role: 'assistant', content: [
156
+ { type: 'text', text: 'checking' },
157
+ { type: 'toolCall', id: 'c1', name: 'ls', arguments: {} },
158
+ ]},
159
+ { role: 'toolResult', toolCallId: 'c1', content: [{ type: 'text', text: 'a.txt' }] },
160
+ { role: 'assistant', content: [{ type: 'text', text: 'Found a.txt' }] },
161
+ ]);
162
+ expect(result).toHaveLength(4);
163
+ expect(result[0].role).toBe('user');
164
+ expect(result[1].role).toBe('assistant');
165
+ expect(result[1].tool_calls).toHaveLength(1);
166
+ expect(result[2].role).toBe('tool');
167
+ expect(result[3]).toMatchObject({ role: 'assistant', content: 'Found a.txt' });
168
+ });
169
+ });
170
+
171
+ // ─────────────────────────────────────────────────
172
+ // reassembleSSE tests
173
+ // ─────────────────────────────────────────────────
174
+
175
+ describe('reassembleSSE', () => {
176
+ it('reassembles simple text SSE response', () => {
177
+ const sse = [
178
+ 'data: {"choices":[{"index":0,"delta":{"role":"assistant"},"finish_reason":null}]}',
179
+ 'data: {"choices":[{"index":0,"delta":{"content":"Hello"},"finish_reason":null}]}',
180
+ 'data: {"choices":[{"index":0,"delta":{"content":"!"},"finish_reason":null}]}',
181
+ 'data: {"choices":[{"index":0,"delta":{"content":""},"finish_reason":"stop"}]}',
182
+ 'data: [DONE]',
183
+ ].join('\n');
184
+
185
+ const result = reassembleSSE(sse);
186
+ expect(result.choices[0].message.content).toBe('Hello!');
187
+ expect(result.choices[0].message.role).toBe('assistant');
188
+ expect(result.choices[0].finish_reason).toBe('stop');
189
+ });
190
+
191
+ it('handles ikuncode-style empty response (proxy returns SSE with no content)', () => {
192
+ // This is the actual response from ikuncode when stream:false is sent
193
+ const sse = [
194
+ 'data: {"id":"","object":"chat.completion.chunk","created":0,"model":"gpt-5.4","choices":[],"usage":{"prompt_tokens":28,"completion_tokens":0,"total_tokens":28}}',
195
+ '',
196
+ 'data: [DONE]',
197
+ ].join('\n');
198
+
199
+ const result = reassembleSSE(sse);
200
+ // Should return empty content (no choices with delta)
201
+ expect(result.choices[0].message.content).toBeNull();
202
+ expect(result.choices[0].message.role).toBe('assistant');
203
+ });
204
+
205
+ it('reassembles SSE with tool calls', () => {
206
+ const sse = [
207
+ 'data: {"choices":[{"index":0,"delta":{"role":"assistant"},"finish_reason":null}]}',
208
+ 'data: {"choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"id":"call_abc","type":"function","function":{"name":"read_","arguments":""}}]},"finish_reason":null}]}',
209
+ 'data: {"choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"name":"file","arguments":"{\\"pa"}}]},"finish_reason":null}]}',
210
+ 'data: {"choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"th\\":\\"/tmp\\"}"}}]},"finish_reason":null}]}',
211
+ 'data: {"choices":[{"index":0,"delta":{"content":""},"finish_reason":"tool_calls"}]}',
212
+ 'data: [DONE]',
213
+ ].join('\n');
214
+
215
+ const result = reassembleSSE(sse);
216
+ const msg = result.choices[0].message;
217
+ expect(msg.tool_calls).toHaveLength(1);
218
+ expect(msg.tool_calls[0].id).toBe('call_abc');
219
+ expect(msg.tool_calls[0].function.name).toBe('read_file');
220
+ expect(msg.tool_calls[0].function.arguments).toBe('{"path":"/tmp"}');
221
+ expect(result.choices[0].finish_reason).toBe('tool_calls');
222
+ });
223
+
224
+ it('handles SSE with multiple tool calls', () => {
225
+ const sse = [
226
+ 'data: {"choices":[{"index":0,"delta":{"role":"assistant"},"finish_reason":null}]}',
227
+ 'data: {"choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"id":"c1","type":"function","function":{"name":"tool_a","arguments":"{}"}}]},"finish_reason":null}]}',
228
+ 'data: {"choices":[{"index":0,"delta":{"tool_calls":[{"index":1,"id":"c2","type":"function","function":{"name":"tool_b","arguments":"{}"}}]},"finish_reason":null}]}',
229
+ 'data: {"choices":[{"index":0,"delta":{"content":""},"finish_reason":"tool_calls"}]}',
230
+ 'data: [DONE]',
231
+ ].join('\n');
232
+
233
+ const result = reassembleSSE(sse);
234
+ expect(result.choices[0].message.tool_calls).toHaveLength(2);
235
+ expect(result.choices[0].message.tool_calls[0].id).toBe('c1');
236
+ expect(result.choices[0].message.tool_calls[1].id).toBe('c2');
237
+ });
238
+
239
+ it('handles SSE with text + tool calls mixed', () => {
240
+ const sse = [
241
+ 'data: {"choices":[{"index":0,"delta":{"role":"assistant"},"finish_reason":null}]}',
242
+ 'data: {"choices":[{"index":0,"delta":{"content":"Let me "},"finish_reason":null}]}',
243
+ 'data: {"choices":[{"index":0,"delta":{"content":"check."},"finish_reason":null}]}',
244
+ 'data: {"choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"id":"c1","type":"function","function":{"name":"search","arguments":"{\\"q\\":\\"test\\"}"}}]},"finish_reason":null}]}',
245
+ 'data: {"choices":[{"index":0,"delta":{"content":""},"finish_reason":"tool_calls"}]}',
246
+ 'data: [DONE]',
247
+ ].join('\n');
248
+
249
+ const result = reassembleSSE(sse);
250
+ expect(result.choices[0].message.content).toBe('Let me check.');
251
+ expect(result.choices[0].message.tool_calls).toHaveLength(1);
252
+ });
253
+
254
+ it('skips invalid SSE lines gracefully', () => {
255
+ const sse = [
256
+ 'data: {"choices":[{"index":0,"delta":{"content":"OK"},"finish_reason":null}]}',
257
+ 'data: INVALID_JSON',
258
+ '',
259
+ ':comment line',
260
+ 'data: {"choices":[{"index":0,"delta":{"content":""},"finish_reason":"stop"}]}',
261
+ 'data: [DONE]',
262
+ ].join('\n');
263
+
264
+ const result = reassembleSSE(sse);
265
+ expect(result.choices[0].message.content).toBe('OK');
266
+ });
267
+
268
+ it('handles SSE with usage chunk at end (no delta)', () => {
269
+ const sse = [
270
+ 'data: {"choices":[{"index":0,"delta":{"role":"assistant"},"finish_reason":null}]}',
271
+ 'data: {"choices":[{"index":0,"delta":{"content":"Hi"},"finish_reason":null}]}',
272
+ 'data: {"choices":[{"index":0,"delta":{"content":""},"finish_reason":"stop"}]}',
273
+ 'data: {"choices":[],"usage":{"prompt_tokens":10,"completion_tokens":5,"total_tokens":15}}',
274
+ 'data: [DONE]',
275
+ ].join('\n');
276
+
277
+ const result = reassembleSSE(sse);
278
+ expect(result.choices[0].message.content).toBe('Hi');
279
+ expect(result.choices[0].finish_reason).toBe('stop');
280
+ });
281
+ });
@@ -35,6 +35,7 @@ const SKILL_AGENT_REGISTRY: Record<string, { mode: 'universal' | 'additional' |
35
35
  'roo': { mode: 'additional', skillAgentName: 'roo' },
36
36
  'github-copilot': { mode: 'universal' },
37
37
  'codex': { mode: 'universal' },
38
+ 'antigravity': { mode: 'additional', skillAgentName: 'antigravity' },
38
39
  };
39
40
 
40
41
  /* ── Replicated logic from scripts/setup.js ──────────────────────── */
@@ -16,6 +16,9 @@ interface DetectResult {
16
16
  detectedFormat?: 'json' | 'toml';
17
17
  detectedConfigKey?: string;
18
18
  hasSkillsDir: boolean;
19
+ detectedSkillDir?: string;
20
+ skillCount?: number;
21
+ skillNames?: string[];
19
22
  suggestedName?: string;
20
23
  }
21
24
 
@@ -28,6 +31,7 @@ interface FormState {
28
31
  preferredTransport: 'stdio' | 'http';
29
32
  project: string;
30
33
  presenceCli: string;
34
+ skillDir: string;
31
35
  }
32
36
 
33
37
  interface CustomAgentModalProps {
@@ -85,6 +89,7 @@ export default function CustomAgentModal({
85
89
  preferredTransport: 'stdio',
86
90
  project: '',
87
91
  presenceCli: '',
92
+ skillDir: '',
88
93
  });
89
94
 
90
95
  // Reset state when modal opens/closes or editAgent changes
@@ -100,6 +105,7 @@ export default function CustomAgentModal({
100
105
  preferredTransport: editAgent.preferredTransport || 'stdio',
101
106
  project: editAgent.projectPath || '',
102
107
  presenceCli: '',
108
+ skillDir: editAgent.skillWorkspacePath || '',
103
109
  });
104
110
  setPhase('result');
105
111
  setCustomizeOpen(true);
@@ -115,6 +121,7 @@ export default function CustomAgentModal({
115
121
  preferredTransport: 'stdio',
116
122
  project: '',
117
123
  presenceCli: '',
124
+ skillDir: '',
118
125
  });
119
126
  setPhase('input');
120
127
  setCustomizeOpen(false);
@@ -182,7 +189,9 @@ export default function CustomAgentModal({
182
189
  // Detect API only scans ~/ paths for security; for other absolute paths,
183
190
  // skip detection and go straight to Phase B with sensible defaults.
184
191
  if (!dir.startsWith('~/')) {
185
- setField('global', (dir.endsWith('/') ? dir : dir + '/') + 'mcp.json');
192
+ const normalized = dir.endsWith('/') ? dir : dir + '/';
193
+ setField('global', normalized + 'mcp.json');
194
+ setField('skillDir', normalized + 'skills/');
186
195
  setDetectResult({ exists: false, hasSkillsDir: false });
187
196
  setPhase('result');
188
197
  setDetecting(false);
@@ -216,11 +225,14 @@ export default function CustomAgentModal({
216
225
  }
217
226
  if (data.detectedFormat) setField('format', data.detectedFormat);
218
227
  if (data.detectedConfigKey) setField('configKey', data.detectedConfigKey);
228
+ setField('skillDir', data.detectedSkillDir || (dir.endsWith('/') ? dir : dir + '/') + 'skills/');
219
229
 
220
230
  setPhase('result');
221
231
  } catch {
222
232
  clearTimeout(timeout);
223
- setField('global', (dir.endsWith('/') ? dir : dir + '/') + 'mcp.json');
233
+ const normalized = dir.endsWith('/') ? dir : dir + '/';
234
+ setField('global', normalized + 'mcp.json');
235
+ setField('skillDir', normalized + 'skills/');
224
236
  setDetectResult({ exists: false, hasSkillsDir: false });
225
237
  setDetectTimedOut(true);
226
238
  setPhase('result');
@@ -246,6 +258,7 @@ export default function CustomAgentModal({
246
258
  preferredTransport: form.preferredTransport,
247
259
  project: form.project.trim() || null,
248
260
  presenceCli: form.presenceCli.trim() || undefined,
261
+ skillDir: form.skillDir.trim() || undefined,
249
262
  }
250
263
  : {
251
264
  name: form.name.trim(),
@@ -256,6 +269,7 @@ export default function CustomAgentModal({
256
269
  preferredTransport: form.preferredTransport,
257
270
  project: form.project.trim() || null,
258
271
  presenceCli: form.presenceCli.trim() || undefined,
272
+ skillDir: form.skillDir.trim() || undefined,
259
273
  };
260
274
 
261
275
  try {
@@ -410,12 +424,12 @@ export default function CustomAgentModal({
410
424
  <span className="text-muted-foreground">{p.customAgentTransportLabel}</span>
411
425
  <span className="text-foreground">{form.preferredTransport}</span>
412
426
 
413
- {detectResult?.hasSkillsDir && (
414
- <>
415
- <span className="text-muted-foreground">{p.customAgentSkillsLabel}</span>
416
- <span className="text-foreground">{p.customAgentSkillsFound(0)}</span>
417
- </>
418
- )}
427
+ <span className="text-muted-foreground">{p.customAgentSkillsLabel}</span>
428
+ <span className="text-foreground">
429
+ {detectResult?.hasSkillsDir
430
+ ? p.customAgentSkillsFound(detectResult.skillCount ?? 0)
431
+ : p.customAgentSkillsNone ?? '—'}
432
+ </span>
419
433
  </div>
420
434
  </div>
421
435
 
@@ -490,6 +504,16 @@ export default function CustomAgentModal({
490
504
  </div>
491
505
  </Field>
492
506
 
507
+ {/* Skills Directory */}
508
+ <Field label={p.customAgentSkillDir} hint={p.customAgentSkillDirHint}>
509
+ <Input
510
+ value={form.skillDir}
511
+ onChange={(e) => setField('skillDir', e.target.value)}
512
+ placeholder={p.customAgentSkillDirPlaceholder}
513
+ autoComplete="off"
514
+ />
515
+ </Field>
516
+
493
517
  {/* Project Config */}
494
518
  <Field label={p.customAgentProjectConfig}>
495
519
  <Input
@@ -3,14 +3,19 @@ name: mindos
3
3
  description: >
4
4
  Operate a MindOS knowledge base: update notes, search, organize files, execute SOPs/workflows,
5
5
  retrospective, append CSV, cross-agent handoff, route unstructured input to the right files,
6
- distill experience, sync related docs. 更新笔记, 搜索知识库, 整理, 执行SOP, 复盘, 追加CSV, 交接, 路由到文件, 提炼经验.
7
- Use when the task targets files inside the user's MindOS KB (mindRoot).
6
+ distill experience, sync related docs.
7
+ 更新笔记, 搜索知识库, 整理文件, 执行SOP/工作流, 复盘, 追加CSV, 跨Agent交接,
8
+ 路由非结构化输入到对应文件, 提炼经验, 同步关联文档.
8
9
  NOT for editing app source, project docs, or paths outside the KB.
9
10
  Core concepts: Space, Instruction (INSTRUCTION.md), Skill (SKILL.md); notes can embody both.
10
- Trigger when user asks to: save or record a note, search their knowledge base, update or edit
11
- a file, organize notes, run a workflow or SOP, capture decisions from a session, append rows
12
- to a table or CSV, hand off context to another agent or says "帮我记下来" / "搜一下我的笔记" /
13
- "更新知识库" / "整理文件" / "执行工作流".
11
+ Trigger when user asks to: save or record anything, search for prior notes or context, update or
12
+ edit a file, organize notes, run a workflow or SOP, capture decisions from a session, append rows
13
+ to a table or CSV, hand off context to another agent, check if something was discussed before,
14
+ look up a past decision, distill lessons learned, prepare context for a meeting.
15
+ Also trigger on Chinese: 帮我记下来, 搜一下笔记, 更新知识库, 整理文件, 复盘, 提炼经验,
16
+ 保存, 记录, 交接, 查一下之前的, 有没有相关笔记, 把这个存起来.
17
+ When the user's question implies stored context may exist (past decisions, previous discussions,
18
+ meeting records), consider searching MindOS even if they don't explicitly mention it.
14
19
  ---
15
20
 
16
21
  # MindOS Skill
@@ -115,9 +120,9 @@ User request
115
120
  ## Judgment heuristics
116
121
 
117
122
  **Save intent boundary:**
118
- - "帮我记下来" / "保存" = write
119
- - "搜一下" / "总结" = read-only
120
- - "整理一下" → ask: display only, or write back?
123
+ - "save this" / "record" / "write down" = write
124
+ - "search" / "summarize" / "look up" = read-only
125
+ - "organize" → ask: display only, or write back?
121
126
 
122
127
  **File location uncertainty:**
123
128
  - Can't decide in 5 seconds → use nearest existing directory, inform user
@@ -1,11 +1,20 @@
1
1
  ---
2
2
  name: mindos-zh
3
3
  description: >
4
- 操作 MindOS 知识库:更新笔记, 搜索知识库, 整理文件, 执行SOP/工作流, 复盘, 追加CSV, 跨Agent交接,
5
- 路由非结构化输入到对应文件, 提炼经验, 同步关联文档. update notes, search knowledge base, organize,
6
- SOP, retrospective, CSV, handoff, route notes, distill experience.
7
- 仅 mindRoot 知识库内任务。不用于:改代码仓库/项目文档/KB 外路径。
4
+ MindOS 知识库操作:更新笔记、搜索知识库、整理文件、执行SOP/工作流、复盘、追加CSV、跨Agent交接、
5
+ 路由非结构化输入到对应文件、提炼经验、同步关联文档。
6
+ mindRoot 知识库内任务。不用于:改代码仓库、项目源码、KB 外路径。
8
7
  核心概念:空间、指令(INSTRUCTION.md)、技能(SKILL.md);笔记可承载指令与技能。
8
+ 触发场景:保存或记录任何内容、搜索历史笔记或上下文、更新或编辑文件、整理或重组文件结构、
9
+ 执行SOP或工作流、捕获对话中的决策、复盘或总结经验、追加表格或CSV数据、跨Agent交接上下文、
10
+ 提炼经验教训、同步关联文档、查找之前是否讨论过某事、查询历史决策、查找模板或SOP、
11
+ 为会议准备上下文。
12
+ 触发词:帮我记下来、搜一下我的笔记、更新知识库、整理文件、执行工作流、保存到知识库、
13
+ 记录一下、整理笔记、复盘、提炼经验、同步文档、查一下之前的记录、有没有相关的笔记、
14
+ 我之前写过什么、把这个存起来、总结一下保存、交接给其他Agent、追加到表格。
15
+ English triggers: save, record, search notes, organize, retrospective, handoff, lessons learned.
16
+ 当用户的问题暗示可能存在历史记录(过去的决策、之前的讨论、会议纪要)时,
17
+ 即使没有明确提到知识库,也应该考虑搜索 MindOS。
9
18
  ---
10
19
 
11
20
  # MindOS 技能