@dxos/assistant 0.8.4-main.72ec0f3 → 0.8.4-main.74a063c4e0

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 (142) hide show
  1. package/README.md +1 -0
  2. package/dist/lib/neutral/chunk-UAWIXKF6.mjs +1875 -0
  3. package/dist/lib/neutral/chunk-UAWIXKF6.mjs.map +7 -0
  4. package/dist/lib/{browser → neutral}/extraction/index.mjs +29 -35
  5. package/dist/lib/neutral/extraction/index.mjs.map +7 -0
  6. package/dist/lib/neutral/index.mjs +551 -0
  7. package/dist/lib/neutral/index.mjs.map +7 -0
  8. package/dist/lib/neutral/meta.json +1 -0
  9. package/dist/lib/neutral/testing/index.mjs +114 -0
  10. package/dist/lib/neutral/testing/index.mjs.map +7 -0
  11. package/dist/types/src/conversation/context.d.ts +116 -64
  12. package/dist/types/src/conversation/context.d.ts.map +1 -1
  13. package/dist/types/src/conversation/context.test.d.ts +2 -0
  14. package/dist/types/src/conversation/context.test.d.ts.map +1 -0
  15. package/dist/types/src/conversation/conversation.d.ts +45 -18
  16. package/dist/types/src/conversation/conversation.d.ts.map +1 -1
  17. package/dist/types/src/conversation/conversation.test.d.ts +2 -0
  18. package/dist/types/src/conversation/conversation.test.d.ts.map +1 -0
  19. package/dist/types/src/diff.d.ts +3 -1
  20. package/dist/types/src/diff.d.ts.map +1 -1
  21. package/dist/types/src/errors.d.ts +12 -16
  22. package/dist/types/src/errors.d.ts.map +1 -1
  23. package/dist/types/src/execution-graph.d.ts +2 -2
  24. package/dist/types/src/execution-graph.d.ts.map +1 -1
  25. package/dist/types/src/extraction/extraction-ner-function/index.d.ts +0 -1
  26. package/dist/types/src/extraction/extraction-ner-function/index.d.ts.map +1 -1
  27. package/dist/types/src/extraction/extraction.d.ts +1059 -313
  28. package/dist/types/src/extraction/extraction.d.ts.map +1 -1
  29. package/dist/types/src/extraction/index.d.ts +0 -1
  30. package/dist/types/src/extraction/index.d.ts.map +1 -1
  31. package/dist/types/src/extraction/quotes.d.ts +2 -2
  32. package/dist/types/src/extraction/quotes.d.ts.map +1 -1
  33. package/dist/types/src/functions/services.d.ts +28 -9
  34. package/dist/types/src/functions/services.d.ts.map +1 -1
  35. package/dist/types/src/functions.test.d.ts +2 -0
  36. package/dist/types/src/functions.test.d.ts.map +1 -0
  37. package/dist/types/src/index.d.ts +2 -0
  38. package/dist/types/src/index.d.ts.map +1 -1
  39. package/dist/types/src/service/AgentService.d.ts +61 -0
  40. package/dist/types/src/service/AgentService.d.ts.map +1 -0
  41. package/dist/types/src/service/AgentService.test.d.ts +2 -0
  42. package/dist/types/src/service/AgentService.test.d.ts.map +1 -0
  43. package/dist/types/src/service/agent-process.d.ts +17 -0
  44. package/dist/types/src/service/agent-process.d.ts.map +1 -0
  45. package/dist/types/src/service/index.d.ts +3 -0
  46. package/dist/types/src/service/index.d.ts.map +1 -0
  47. package/dist/types/src/session/artifact-diff.d.ts +1 -1
  48. package/dist/types/src/session/artifact-diff.d.ts.map +1 -1
  49. package/dist/types/src/session/format.d.ts +3 -3
  50. package/dist/types/src/session/format.d.ts.map +1 -1
  51. package/dist/types/src/session/index.d.ts +1 -1
  52. package/dist/types/src/session/index.d.ts.map +1 -1
  53. package/dist/types/src/session/observer.d.ts +4 -3
  54. package/dist/types/src/session/observer.d.ts.map +1 -1
  55. package/dist/types/src/session/session.d.ts +72 -11
  56. package/dist/types/src/session/session.d.ts.map +1 -1
  57. package/dist/types/src/session/toolkit.d.ts +9 -6
  58. package/dist/types/src/session/toolkit.d.ts.map +1 -1
  59. package/dist/types/src/session/version-pin.d.ts +2 -2
  60. package/dist/types/src/session/version-pin.d.ts.map +1 -1
  61. package/dist/types/src/templates/system.d.ts +0 -1
  62. package/dist/types/src/templates/system.d.ts.map +1 -1
  63. package/dist/types/src/testing/index.d.ts +2 -0
  64. package/dist/types/src/testing/index.d.ts.map +1 -0
  65. package/dist/types/src/testing/layer.d.ts +35 -0
  66. package/dist/types/src/testing/layer.d.ts.map +1 -0
  67. package/dist/types/src/tracing.d.ts +264 -0
  68. package/dist/types/src/tracing.d.ts.map +1 -0
  69. package/dist/types/src/types/artifact.d.ts +13 -5
  70. package/dist/types/src/types/artifact.d.ts.map +1 -1
  71. package/dist/types/tsconfig.tsbuildinfo +1 -1
  72. package/package.json +42 -33
  73. package/src/conversation/context.test.ts +52 -0
  74. package/src/conversation/context.ts +307 -90
  75. package/src/conversation/conversation.test.ts +58 -0
  76. package/src/conversation/conversation.ts +209 -62
  77. package/src/diff.test.ts +36 -5
  78. package/src/diff.ts +13 -4
  79. package/src/errors.ts +2 -2
  80. package/src/execution-graph.test.ts +3 -3
  81. package/src/execution-graph.ts +6 -6
  82. package/src/extraction/extraction-ner-function/index.ts +0 -1
  83. package/src/extraction/extraction.ts +40 -12
  84. package/src/extraction/index.ts +0 -1
  85. package/src/extraction/quotes.ts +4 -5
  86. package/src/functions/services.ts +217 -50
  87. package/src/functions.conversations.json +1 -0
  88. package/src/functions.test.ts +82 -0
  89. package/src/index.ts +2 -0
  90. package/src/service/AgentService.conversations.json +1 -0
  91. package/src/service/AgentService.test.ts +169 -0
  92. package/src/service/AgentService.ts +165 -0
  93. package/src/service/agent-process.ts +359 -0
  94. package/src/service/index.ts +6 -0
  95. package/src/session/artifact-diff.ts +1 -1
  96. package/src/session/format.test.ts +110 -39
  97. package/src/session/format.ts +12 -14
  98. package/src/session/index.ts +1 -2
  99. package/src/session/observer.ts +4 -1
  100. package/src/session/session.conversations.json +1 -1
  101. package/src/session/session.test.ts +58 -17
  102. package/src/session/session.ts +249 -113
  103. package/src/session/toolkit.ts +21 -25
  104. package/src/session/version-pin.ts +4 -3
  105. package/src/templates/instructions/format.tpl +0 -4
  106. package/src/templates/instructions/system.tpl +11 -2
  107. package/src/templates/system.ts +6 -5
  108. package/src/testing/index.ts +5 -0
  109. package/src/testing/layer.ts +258 -0
  110. package/src/tracing.ts +113 -0
  111. package/src/types/artifact.ts +31 -13
  112. package/dist/lib/browser/extraction/index.mjs.map +0 -7
  113. package/dist/lib/browser/index.mjs +0 -1290
  114. package/dist/lib/browser/index.mjs.map +0 -7
  115. package/dist/lib/browser/meta.json +0 -1
  116. package/dist/lib/node-esm/chunk-HSLMI22Q.mjs +0 -11
  117. package/dist/lib/node-esm/chunk-HSLMI22Q.mjs.map +0 -7
  118. package/dist/lib/node-esm/extraction/index.mjs +0 -226
  119. package/dist/lib/node-esm/extraction/index.mjs.map +0 -7
  120. package/dist/lib/node-esm/index.mjs +0 -1291
  121. package/dist/lib/node-esm/index.mjs.map +0 -7
  122. package/dist/lib/node-esm/meta.json +0 -1
  123. package/dist/types/src/extraction/extraction-llm-function/extraction-llm-function.d.ts +0 -4
  124. package/dist/types/src/extraction/extraction-llm-function/extraction-llm-function.d.ts.map +0 -1
  125. package/dist/types/src/extraction/extraction-llm-function/extraction-llm-function.test.d.ts +0 -2
  126. package/dist/types/src/extraction/extraction-llm-function/extraction-llm-function.test.d.ts.map +0 -1
  127. package/dist/types/src/extraction/extraction-llm-function/index.d.ts +0 -2
  128. package/dist/types/src/extraction/extraction-llm-function/index.d.ts.map +0 -1
  129. package/dist/types/src/extraction/extraction-ner-function/extraction-ner-function.d.ts +0 -345
  130. package/dist/types/src/extraction/extraction-ner-function/extraction-ner-function.d.ts.map +0 -1
  131. package/dist/types/src/extraction/extraction-ner-function/extraction-ner-function.test.d.ts +0 -2
  132. package/dist/types/src/extraction/extraction-ner-function/extraction-ner-function.test.d.ts.map +0 -1
  133. package/dist/types/src/session/GenericToolkit.d.ts +0 -84
  134. package/dist/types/src/session/GenericToolkit.d.ts.map +0 -1
  135. package/src/extraction/extraction-llm-function/extraction-llm-function.test.ts +0 -84
  136. package/src/extraction/extraction-llm-function/extraction-llm-function.ts +0 -62
  137. package/src/extraction/extraction-llm-function/index.ts +0 -5
  138. package/src/extraction/extraction-ner-function/extraction-ner-function.test.ts +0 -116
  139. package/src/extraction/extraction-ner-function/extraction-ner-function.ts +0 -56
  140. package/src/session/GenericToolkit.ts +0 -130
  141. /package/dist/lib/{browser → neutral}/chunk-J5LGTIGS.mjs +0 -0
  142. /package/dist/lib/{browser → neutral}/chunk-J5LGTIGS.mjs.map +0 -0
@@ -0,0 +1 @@
1
+ {"conversations":[{"parameters":{"model":"@anthropic/claude-opus-4-6","stream":true,"tools":[{"name":"research","description":"Research an organization","inputSchema":{"type":"object","required":["website"],"properties":{"website":{"type":"string","description":"The website of the organization to research"}},"additionalProperties":false}}]},"prompt":{"content":[{"role":"system","content":"You are reacting to a continuous stream of organizations.\nResearch each organization.\nResearch takes a while to complete.\nDo not block on the research since there might be more organizations to research, and we want research to happen in parallel.\nDo not wait longer then 3 seconds to keep the conversation open for new events or user queries.\nDo internal reasoning, but only show the answers to the user.\n\n## Blueprints Definitions\n\n<blueprint>\n \n</blueprint>","options":{}},{"role":"user","content":"{\"id\":\"01JGFJJZ00G0WKQSJGMAKCNT87\",\"@type\":\"dxn:type:org.dxos.type.organization:0.1.0\",\"@meta\":{\"keys\":[]},\"name\":\"Cyberdyne Systems\",\"website\":\"https://cyberdyne.com\"}","options":{"anthropic":{"cacheControl":{"ttl":"5m","type":"ephemeral"}}}}]},"response":[{"type":"response-metadata","id":"msg_01Mkk3drcb9AZUffYimXFqJp","modelId":"claude-opus-4-6","timestamp":"2026-04-02T13:28:36.360Z","metadata":{}},{"type":"reasoning-start","id":"0","metadata":{}},{"type":"reasoning-delta","id":"0","delta":"The user has","metadata":{}},{"type":"reasoning-delta","id":"0","delta":" provided an organization to research. Let me kick off the research immediately.","metadata":{}},{"type":"reasoning-delta","id":"0","delta":"","metadata":{"anthropic":{"type":"thinking","signature":"EpcCClkIDBgCKkCeIiM9ffjA/tTJnoNfrgmS3NWrHveO/Sv+fWXalibnTtxgcku5MwyXjhFDphGbKzTeF4Bgg7YFs+9PtkyiSrGWMg9jbGF1ZGUtb3B1cy00LTY4ABIMlt6emeTezR0aI2/5GgxxB3o3A2OO5qUpIJYiMLYWJXAChjw3E72Vws0eCGUJu06XJQNlLEPfswN00jytqQ2hOGkNXsmN78wtKDraCipsQxV9gYIdzBd+WXu3LDH4OhAHATRGYxJ/JzHNSoKrDKXi7tW9N6a+72BEDh8y/tS9I/o4xK/WJmlPTRjZ2L6iDz1U8ajWIRwcEUcNnCpWebL/UR+i9bBd/Z0V0muZu9f8Pocnzq6F5W1oP96PGAE="}}},{"type":"reasoning-end","id":"0","metadata":{}},{"type":"text-start","id":"1","metadata":{}},{"type":"text-delta","id":"1","delta":"Researching **Cyberdyne Systems**...","metadata":{}},{"type":"text-end","id":"1","metadata":{}},{"type":"tool-params-start","id":"toolu_01Ssvj853DdUXUNHqVifZGtw","name":"research","providerExecuted":false,"metadata":{}},{"type":"tool-params-delta","id":"toolu_01Ssvj853DdUXUNHqVifZGtw","delta":"","metadata":{}},{"type":"tool-params-delta","id":"toolu_01Ssvj853DdUXUNHqVifZGtw","delta":"{\"websit","metadata":{}},{"type":"tool-params-delta","id":"toolu_01Ssvj853DdUXUNHqVifZGtw","delta":"e\": \"https:","metadata":{}},{"type":"tool-params-delta","id":"toolu_01Ssvj853DdUXUNHqVifZGtw","delta":"//cyber","metadata":{}},{"type":"tool-params-delta","id":"toolu_01Ssvj853DdUXUNHqVifZGtw","delta":"dyne","metadata":{}},{"type":"tool-params-delta","id":"toolu_01Ssvj853DdUXUNHqVifZGtw","delta":".com\"}","metadata":{}},{"type":"tool-params-end","id":"toolu_01Ssvj853DdUXUNHqVifZGtw","metadata":{}},{"type":"finish","reason":"tool-calls","usage":{"inputTokens":781,"outputTokens":94,"totalTokens":875},"metadata":{"anthropic":{"usage":{"cache_creation":{"ephemeral_1h_input_tokens":0,"ephemeral_5m_input_tokens":0},"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"input_tokens":781,"output_tokens":3,"server_tool_use":null,"service_tier":"standard"}}}}]},{"parameters":{"model":"@anthropic/claude-opus-4-6","stream":true,"tools":[{"name":"research","description":"Research an organization","inputSchema":{"type":"object","required":["website"],"properties":{"website":{"type":"string","description":"The website of the organization to research"}},"additionalProperties":false}}]},"prompt":{"content":[{"role":"system","content":"You are reacting to a continuous stream of organizations.\nResearch each organization.\nResearch takes a while to complete.\nDo not block on the research since there might be more organizations to research, and we want research to happen in parallel.\nDo not wait longer then 3 seconds to keep the conversation open for new events or user queries.\nDo internal reasoning, but only show the answers to the user.\n\n## Blueprints Definitions\n\n<blueprint>\n \n</blueprint>","options":{}},{"role":"user","content":"{\"id\":\"01JGFJJZ00G0WKQSJGMAKCNT87\",\"@type\":\"dxn:type:org.dxos.type.organization:0.1.0\",\"@meta\":{\"keys\":[]},\"name\":\"Cyberdyne Systems\",\"website\":\"https://cyberdyne.com\"}","options":{}},{"role":"assistant","content":[{"type":"reasoning","text":"The user has provided an organization to research. Let me kick off the research immediately.","options":{}},{"type":"text","text":"Researching **Cyberdyne Systems**...","options":{}},{"type":"tool-call","id":"toolu_01Ssvj853DdUXUNHqVifZGtw","name":"research","params":{"website":"https://cyberdyne.com"},"providerExecuted":false,"options":{}}],"options":{}},{"role":"tool","content":[{"type":"tool-result","id":"toolu_01Ssvj853DdUXUNHqVifZGtw","name":"research","isFailure":false,"result":"Tool is running in the background id=1; wait for the completion notification to get the result.","providerExecuted":false,"options":{}}],"options":{"anthropic":{"cacheControl":{"ttl":"5m","type":"ephemeral"}}}}]},"response":[{"type":"response-metadata","id":"msg_015yrmyPy3xjyMRf7qCDjWBH","modelId":"claude-opus-4-6","timestamp":"2026-04-02T13:28:40.280Z","metadata":{}},{"type":"text-start","id":"0","metadata":{}},{"type":"text-delta","id":"0","delta":"I've kicked","metadata":{}},{"type":"text-delta","id":"0","delta":" off research on **Cyberdyne Systems** (cyberdyne.com). I'll share","metadata":{}},{"type":"text-delta","id":"0","delta":" the results as soon as they're ready.","metadata":{}},{"type":"text-end","id":"0","metadata":{}},{"type":"finish","reason":"stop","usage":{"inputTokens":853,"outputTokens":35,"totalTokens":888},"metadata":{"anthropic":{"usage":{"cache_creation":{"ephemeral_1h_input_tokens":0,"ephemeral_5m_input_tokens":0},"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"input_tokens":853,"output_tokens":3,"server_tool_use":null,"service_tier":"standard"}}}}]},{"parameters":{"model":"@anthropic/claude-opus-4-6","stream":true,"tools":[{"name":"research","description":"Research an organization","inputSchema":{"type":"object","required":["website"],"properties":{"website":{"type":"string","description":"The website of the organization to research"}},"additionalProperties":false}}]},"prompt":{"content":[{"role":"system","content":"You are reacting to a continuous stream of organizations.\nResearch each organization.\nResearch takes a while to complete.\nDo not block on the research since there might be more organizations to research, and we want research to happen in parallel.\nDo not wait longer then 3 seconds to keep the conversation open for new events or user queries.\nDo internal reasoning, but only show the answers to the user.\n\n## Blueprints Definitions\n\n<blueprint>\n \n</blueprint>","options":{}},{"role":"user","content":"{\"id\":\"01JGFJJZ00G0WKQSJGMAKCNT87\",\"@type\":\"dxn:type:org.dxos.type.organization:0.1.0\",\"@meta\":{\"keys\":[]},\"name\":\"Cyberdyne Systems\",\"website\":\"https://cyberdyne.com\"}","options":{}},{"role":"assistant","content":[{"type":"reasoning","text":"The user has provided an organization to research. Let me kick off the research immediately.","options":{}},{"type":"text","text":"Researching **Cyberdyne Systems**...","options":{}},{"type":"tool-call","id":"toolu_01Ssvj853DdUXUNHqVifZGtw","name":"research","params":{"website":"https://cyberdyne.com"},"providerExecuted":false,"options":{}}],"options":{}},{"role":"tool","content":[{"type":"tool-result","id":"toolu_01Ssvj853DdUXUNHqVifZGtw","name":"research","isFailure":false,"result":"Tool is running in the background id=1; wait for the completion notification to get the result.","providerExecuted":false,"options":{}}],"options":{}},{"role":"assistant","content":"I've kicked off research on **Cyberdyne Systems** (cyberdyne.com). I'll share the results as soon as they're ready.","options":{}},{"role":"user","content":"{\"id\":\"01JGFJJZ00G0WKQSJGMAKCNT88\",\"@type\":\"dxn:type:org.dxos.type.organization:0.1.0\",\"@meta\":{\"keys\":[]},\"name\":\"Acme Robotics\",\"website\":\"https://acmerobotics.example\"}","options":{"anthropic":{"cacheControl":{"ttl":"5m","type":"ephemeral"}}}}]},"response":[{"type":"response-metadata","id":"msg_01TSaepBbZsY3CxAWQVkNTvh","modelId":"claude-opus-4-6","timestamp":"2026-04-02T13:28:42.841Z","metadata":{}},{"type":"reasoning-start","id":"0","metadata":{}},{"type":"reasoning-delta","id":"0","delta":"Research","metadata":{}},{"type":"reasoning-delta","id":"0","delta":" Acme Robotics in parallel while waiting for Cyberdyne Systems results.","metadata":{}},{"type":"reasoning-delta","id":"0","delta":"","metadata":{"anthropic":{"type":"thinking","signature":"EooCClkIDBgCKkAeGn2TTSqhhMvfUHVXxrMSyDRM7Q1cZoC2JIUHVzd6Zles0cc9nJgzZ42U+uEBgrNykdBEvdQjI5ChAoBneR+oMg9jbGF1ZGUtb3B1cy00LTY4ABIMze2YS0TTjOkFoOoOGgxzMH9CWtDkR8jtX6wiMAW8XGP5WwAD5kmMTf04XYNZreaB5fTZ6ieLqF3PU1aJb0+yRK0HtcWst2W8BaBFFypfyw3KLVbCyVJlbB5nXHx/OBGmSVhMxl3OR7l+reYq2tiScUIIKa23up8yCQoTyUPcJdd19YNm820dptXhFJ3dF7Unb1ta+xMamQe3ZDExq6VwZuci6tEm2MCe0dCblUcYAQ=="}}},{"type":"reasoning-end","id":"0","metadata":{}},{"type":"text-start","id":"1","metadata":{}},{"type":"text-delta","id":"1","delta":"Researching **Acme Robotics**...","metadata":{}},{"type":"text-end","id":"1","metadata":{}},{"type":"tool-params-start","id":"toolu_01ShRUXsqfwZz6K2xr7CdHZ5","name":"research","providerExecuted":false,"metadata":{}},{"type":"tool-params-delta","id":"toolu_01ShRUXsqfwZz6K2xr7CdHZ5","delta":"","metadata":{}},{"type":"tool-params-delta","id":"toolu_01ShRUXsqfwZz6K2xr7CdHZ5","delta":"{\"websit","metadata":{}},{"type":"tool-params-delta","id":"toolu_01ShRUXsqfwZz6K2xr7CdHZ5","delta":"e\": \"https","metadata":{}},{"type":"tool-params-delta","id":"toolu_01ShRUXsqfwZz6K2xr7CdHZ5","delta":"://acme","metadata":{}},{"type":"tool-params-delta","id":"toolu_01ShRUXsqfwZz6K2xr7CdHZ5","delta":"robotics.","metadata":{}},{"type":"tool-params-delta","id":"toolu_01ShRUXsqfwZz6K2xr7CdHZ5","delta":"examp","metadata":{}},{"type":"tool-params-delta","id":"toolu_01ShRUXsqfwZz6K2xr7CdHZ5","delta":"le\"}","metadata":{}},{"type":"tool-params-end","id":"toolu_01ShRUXsqfwZz6K2xr7CdHZ5","metadata":{}},{"type":"finish","reason":"tool-calls","usage":{"inputTokens":999,"outputTokens":99,"totalTokens":1098},"metadata":{"anthropic":{"usage":{"cache_creation":{"ephemeral_1h_input_tokens":0,"ephemeral_5m_input_tokens":0},"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"input_tokens":999,"output_tokens":1,"server_tool_use":null,"service_tier":"standard"}}}}]},{"parameters":{"model":"@anthropic/claude-opus-4-6","stream":true,"tools":[{"name":"research","description":"Research an organization","inputSchema":{"type":"object","required":["website"],"properties":{"website":{"type":"string","description":"The website of the organization to research"}},"additionalProperties":false}}]},"prompt":{"content":[{"role":"system","content":"You are reacting to a continuous stream of organizations.\nResearch each organization.\nResearch takes a while to complete.\nDo not block on the research since there might be more organizations to research, and we want research to happen in parallel.\nDo not wait longer then 3 seconds to keep the conversation open for new events or user queries.\nDo internal reasoning, but only show the answers to the user.\n\n## Blueprints Definitions\n\n<blueprint>\n \n</blueprint>","options":{}},{"role":"user","content":"{\"id\":\"01JGFJJZ00G0WKQSJGMAKCNT87\",\"@type\":\"dxn:type:org.dxos.type.organization:0.1.0\",\"@meta\":{\"keys\":[]},\"name\":\"Cyberdyne Systems\",\"website\":\"https://cyberdyne.com\"}","options":{}},{"role":"assistant","content":[{"type":"reasoning","text":"The user has provided an organization to research. Let me kick off the research immediately.","options":{}},{"type":"text","text":"Researching **Cyberdyne Systems**...","options":{}},{"type":"tool-call","id":"toolu_01Ssvj853DdUXUNHqVifZGtw","name":"research","params":{"website":"https://cyberdyne.com"},"providerExecuted":false,"options":{}}],"options":{}},{"role":"tool","content":[{"type":"tool-result","id":"toolu_01Ssvj853DdUXUNHqVifZGtw","name":"research","isFailure":false,"result":"Tool is running in the background id=1; wait for the completion notification to get the result.","providerExecuted":false,"options":{}}],"options":{}},{"role":"assistant","content":"I've kicked off research on **Cyberdyne Systems** (cyberdyne.com). I'll share the results as soon as they're ready.","options":{}},{"role":"user","content":"{\"id\":\"01JGFJJZ00G0WKQSJGMAKCNT88\",\"@type\":\"dxn:type:org.dxos.type.organization:0.1.0\",\"@meta\":{\"keys\":[]},\"name\":\"Acme Robotics\",\"website\":\"https://acmerobotics.example\"}","options":{}},{"role":"assistant","content":[{"type":"reasoning","text":"Research Acme Robotics in parallel while waiting for Cyberdyne Systems results.","options":{}},{"type":"text","text":"Researching **Acme Robotics**...","options":{}},{"type":"tool-call","id":"toolu_01ShRUXsqfwZz6K2xr7CdHZ5","name":"research","params":{"website":"https://acmerobotics.example"},"providerExecuted":false,"options":{}}],"options":{}},{"role":"tool","content":[{"type":"tool-result","id":"toolu_01ShRUXsqfwZz6K2xr7CdHZ5","name":"research","isFailure":false,"result":"Tool is running in the background id=2; wait for the completion notification to get the result.","providerExecuted":false,"options":{}}],"options":{"anthropic":{"cacheControl":{"ttl":"5m","type":"ephemeral"}}}}]},"response":[{"type":"response-metadata","id":"msg_01ACBkPmLbu86vk5ZcLVrPAy","modelId":"claude-opus-4-6","timestamp":"2026-04-02T13:28:46.961Z","metadata":{}},{"type":"text-start","id":"0","metadata":{}},{"type":"text-delta","id":"0","delta":"I've started research on **Ac","metadata":{}},{"type":"text-delta","id":"0","delta":"me Robotics** (acmerobotics.example). I'll share the results once they come in. Still also waiting on","metadata":{}},{"type":"text-delta","id":"0","delta":" results for **Cyberdyne Systems**.","metadata":{}},{"type":"text-end","id":"0","metadata":{}},{"type":"finish","reason":"stop","usage":{"inputTokens":1074,"outputTokens":48,"totalTokens":1122},"metadata":{"anthropic":{"usage":{"cache_creation":{"ephemeral_1h_input_tokens":0,"ephemeral_5m_input_tokens":0},"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"input_tokens":1074,"output_tokens":8,"server_tool_use":null,"service_tier":"standard"}}}}]},{"parameters":{"model":"@anthropic/claude-opus-4-6","stream":true,"tools":[{"name":"research","description":"Research an organization","inputSchema":{"type":"object","required":["website"],"properties":{"website":{"type":"string","description":"The website of the organization to research"}},"additionalProperties":false}}]},"prompt":{"content":[{"role":"system","content":"You are reacting to a continuous stream of organizations.\nResearch each organization.\nResearch takes a while to complete.\nDo not block on the research since there might be more organizations to research, and we want research to happen in parallel.\nDo not wait longer then 3 seconds to keep the conversation open for new events or user queries.\nDo internal reasoning, but only show the answers to the user.\n\n## Blueprints Definitions\n\n<blueprint>\n \n</blueprint>","options":{}},{"role":"user","content":"{\"id\":\"01JGFJJZ00G0WKQSJGMAKCNT87\",\"@type\":\"dxn:type:org.dxos.type.organization:0.1.0\",\"@meta\":{\"keys\":[]},\"name\":\"Cyberdyne Systems\",\"website\":\"https://cyberdyne.com\"}","options":{}},{"role":"assistant","content":[{"type":"reasoning","text":"The user has provided an organization to research. Let me kick off the research immediately.","options":{}},{"type":"text","text":"Researching **Cyberdyne Systems**...","options":{}},{"type":"tool-call","id":"toolu_01Ssvj853DdUXUNHqVifZGtw","name":"research","params":{"website":"https://cyberdyne.com"},"providerExecuted":false,"options":{}}],"options":{}},{"role":"tool","content":[{"type":"tool-result","id":"toolu_01Ssvj853DdUXUNHqVifZGtw","name":"research","isFailure":false,"result":"Tool is running in the background id=1; wait for the completion notification to get the result.","providerExecuted":false,"options":{}}],"options":{}},{"role":"assistant","content":"I've kicked off research on **Cyberdyne Systems** (cyberdyne.com). I'll share the results as soon as they're ready.","options":{}},{"role":"user","content":"{\"id\":\"01JGFJJZ00G0WKQSJGMAKCNT88\",\"@type\":\"dxn:type:org.dxos.type.organization:0.1.0\",\"@meta\":{\"keys\":[]},\"name\":\"Acme Robotics\",\"website\":\"https://acmerobotics.example\"}","options":{}},{"role":"assistant","content":[{"type":"reasoning","text":"Research Acme Robotics in parallel while waiting for Cyberdyne Systems results.","options":{}},{"type":"text","text":"Researching **Acme Robotics**...","options":{}},{"type":"tool-call","id":"toolu_01ShRUXsqfwZz6K2xr7CdHZ5","name":"research","params":{"website":"https://acmerobotics.example"},"providerExecuted":false,"options":{}}],"options":{}},{"role":"tool","content":[{"type":"tool-result","id":"toolu_01ShRUXsqfwZz6K2xr7CdHZ5","name":"research","isFailure":false,"result":"Tool is running in the background id=2; wait for the completion notification to get the result.","providerExecuted":false,"options":{}}],"options":{}},{"role":"assistant","content":"I've started research on **Acme Robotics** (acmerobotics.example). I'll share the results once they come in. Still also waiting on results for **Cyberdyne Systems**.","options":{}},{"role":"user","content":"{\"id\":\"01JGFJJZ00G0WKQSJGMAKCNT89\",\"@type\":\"dxn:type:org.dxos.type.organization:0.1.0\",\"@meta\":{\"keys\":[]},\"name\":\"Globex Research\",\"website\":\"https://globex.example\"}","options":{"anthropic":{"cacheControl":{"ttl":"5m","type":"ephemeral"}}}}]},"response":[{"type":"response-metadata","id":"msg_01DcVMTUDfbWdZ3Dj1iv1D3P","modelId":"claude-opus-4-6","timestamp":"2026-04-02T13:28:49.499Z","metadata":{}},{"type":"reasoning-start","id":"0","metadata":{}},{"type":"reasoning-delta","id":"0","delta":"Resear","metadata":{}},{"type":"reasoning-delta","id":"0","delta":"ching Globex Research now.","metadata":{}},{"type":"reasoning-delta","id":"0","delta":"","metadata":{"anthropic":{"type":"thinking","signature":"EtsBClkIDBgCKkC95mhiHITElThVsJGSHcu7oJDE//JqLwnlWo6KR9XDEP5WENO3fLwPWlIdIDr1ZWyyBaVKGk8Ixt5OwTsjg9kQMg9jbGF1ZGUtb3B1cy00LTY4ABIMlq7b2FPCTod8ZbreGgwWvl9MFCR2yFxmJ2YiMOmh6ogUsXmbKyPO7mA7FqQxyok8JiP6nXYUOnj+TIhHv6XaxbcbTE4NClpXalKmySowEd2C0PQ/XfND5aAcACF1oJkNrOS3r5DckFo9aPoQbJxPoCBWZMGEOm/7kXVxFOOWGAE="}}},{"type":"reasoning-end","id":"0","metadata":{}},{"type":"text-start","id":"1","metadata":{}},{"type":"text-delta","id":"1","delta":"Researching **Globex Research**...","metadata":{}},{"type":"text-end","id":"1","metadata":{}},{"type":"tool-params-start","id":"toolu_01LEy9P5JZi3ebQ5jwpYxG37","name":"research","providerExecuted":false,"metadata":{}},{"type":"tool-params-delta","id":"toolu_01LEy9P5JZi3ebQ5jwpYxG37","delta":"","metadata":{}},{"type":"tool-params-delta","id":"toolu_01LEy9P5JZi3ebQ5jwpYxG37","delta":"{\"website\": ","metadata":{}},{"type":"tool-params-delta","id":"toolu_01LEy9P5JZi3ebQ5jwpYxG37","delta":"\"https:","metadata":{}},{"type":"tool-params-delta","id":"toolu_01LEy9P5JZi3ebQ5jwpYxG37","delta":"//glob","metadata":{}},{"type":"tool-params-delta","id":"toolu_01LEy9P5JZi3ebQ5jwpYxG37","delta":"ex.examp","metadata":{}},{"type":"tool-params-delta","id":"toolu_01LEy9P5JZi3ebQ5jwpYxG37","delta":"le\"}","metadata":{}},{"type":"tool-params-end","id":"toolu_01LEy9P5JZi3ebQ5jwpYxG37","metadata":{}},{"type":"finish","reason":"tool-calls","usage":{"inputTokens":1228,"outputTokens":84,"totalTokens":1312},"metadata":{"anthropic":{"usage":{"cache_creation":{"ephemeral_1h_input_tokens":0,"ephemeral_5m_input_tokens":0},"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"input_tokens":1228,"output_tokens":2,"server_tool_use":null,"service_tier":"standard"}}}}]},{"parameters":{"model":"@anthropic/claude-opus-4-6","stream":true,"tools":[{"name":"research","description":"Research an organization","inputSchema":{"type":"object","required":["website"],"properties":{"website":{"type":"string","description":"The website of the organization to research"}},"additionalProperties":false}}]},"prompt":{"content":[{"role":"system","content":"You are reacting to a continuous stream of organizations.\nResearch each organization.\nResearch takes a while to complete.\nDo not block on the research since there might be more organizations to research, and we want research to happen in parallel.\nDo not wait longer then 3 seconds to keep the conversation open for new events or user queries.\nDo internal reasoning, but only show the answers to the user.\n\n## Blueprints Definitions\n\n<blueprint>\n \n</blueprint>","options":{}},{"role":"user","content":"{\"id\":\"01JGFJJZ00G0WKQSJGMAKCNT87\",\"@type\":\"dxn:type:org.dxos.type.organization:0.1.0\",\"@meta\":{\"keys\":[]},\"name\":\"Cyberdyne Systems\",\"website\":\"https://cyberdyne.com\"}","options":{}},{"role":"assistant","content":[{"type":"reasoning","text":"The user has provided an organization to research. Let me kick off the research immediately.","options":{}},{"type":"text","text":"Researching **Cyberdyne Systems**...","options":{}},{"type":"tool-call","id":"toolu_01Ssvj853DdUXUNHqVifZGtw","name":"research","params":{"website":"https://cyberdyne.com"},"providerExecuted":false,"options":{}}],"options":{}},{"role":"tool","content":[{"type":"tool-result","id":"toolu_01Ssvj853DdUXUNHqVifZGtw","name":"research","isFailure":false,"result":"Tool is running in the background id=1; wait for the completion notification to get the result.","providerExecuted":false,"options":{}}],"options":{}},{"role":"assistant","content":"I've kicked off research on **Cyberdyne Systems** (cyberdyne.com). I'll share the results as soon as they're ready.","options":{}},{"role":"user","content":"{\"id\":\"01JGFJJZ00G0WKQSJGMAKCNT88\",\"@type\":\"dxn:type:org.dxos.type.organization:0.1.0\",\"@meta\":{\"keys\":[]},\"name\":\"Acme Robotics\",\"website\":\"https://acmerobotics.example\"}","options":{}},{"role":"assistant","content":[{"type":"reasoning","text":"Research Acme Robotics in parallel while waiting for Cyberdyne Systems results.","options":{}},{"type":"text","text":"Researching **Acme Robotics**...","options":{}},{"type":"tool-call","id":"toolu_01ShRUXsqfwZz6K2xr7CdHZ5","name":"research","params":{"website":"https://acmerobotics.example"},"providerExecuted":false,"options":{}}],"options":{}},{"role":"tool","content":[{"type":"tool-result","id":"toolu_01ShRUXsqfwZz6K2xr7CdHZ5","name":"research","isFailure":false,"result":"Tool is running in the background id=2; wait for the completion notification to get the result.","providerExecuted":false,"options":{}}],"options":{}},{"role":"assistant","content":"I've started research on **Acme Robotics** (acmerobotics.example). I'll share the results once they come in. Still also waiting on results for **Cyberdyne Systems**.","options":{}},{"role":"user","content":"{\"id\":\"01JGFJJZ00G0WKQSJGMAKCNT89\",\"@type\":\"dxn:type:org.dxos.type.organization:0.1.0\",\"@meta\":{\"keys\":[]},\"name\":\"Globex Research\",\"website\":\"https://globex.example\"}","options":{}},{"role":"assistant","content":[{"type":"reasoning","text":"Researching Globex Research now.","options":{}},{"type":"text","text":"Researching **Globex Research**...","options":{}},{"type":"tool-call","id":"toolu_01LEy9P5JZi3ebQ5jwpYxG37","name":"research","params":{"website":"https://globex.example"},"providerExecuted":false,"options":{}}],"options":{}},{"role":"tool","content":[{"type":"tool-result","id":"toolu_01LEy9P5JZi3ebQ5jwpYxG37","name":"research","isFailure":false,"result":"Tool is running in the background id=3; wait for the completion notification to get the result.","providerExecuted":false,"options":{}}],"options":{"anthropic":{"cacheControl":{"ttl":"5m","type":"ephemeral"}}}}]},"response":[{"type":"response-metadata","id":"msg_01UUPJPWZyBMoNV4rtN55KGM","modelId":"claude-opus-4-6","timestamp":"2026-04-02T13:28:55.338Z","metadata":{}},{"type":"text-start","id":"0","metadata":{}},{"type":"text-delta","id":"0","delta":"I've kicked","metadata":{}},{"type":"text-delta","id":"0","delta":" off research on **Globex Research** (globex.example). Currently waiting on results for all three organizations:\n\n1. **Cyberdyne Systems** — in","metadata":{}},{"type":"text-delta","id":"0","delta":" progress\n2. **Acme Robotics** — in progress\n3. **Globex Research** — in progress\n\nI'll share findings as they come","metadata":{}},{"type":"text-delta","id":"0","delta":" in!","metadata":{}},{"type":"text-end","id":"0","metadata":{}},{"type":"finish","reason":"stop","usage":{"inputTokens":1298,"outputTokens":79,"totalTokens":1377},"metadata":{"anthropic":{"usage":{"cache_creation":{"ephemeral_1h_input_tokens":0,"ephemeral_5m_input_tokens":0},"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"input_tokens":1298,"output_tokens":3,"server_tool_use":null,"service_tier":"standard"}}}}]},{"parameters":{"model":"@anthropic/claude-opus-4-6","stream":true,"tools":[{"name":"research","description":"Research an organization","inputSchema":{"type":"object","required":["website"],"properties":{"website":{"type":"string","description":"The website of the organization to research"}},"additionalProperties":false}}]},"prompt":{"content":[{"role":"system","content":"You are reacting to a continuous stream of organizations.\nResearch each organization.\nResearch takes a while to complete.\nDo not block on the research since there might be more organizations to research, and we want research to happen in parallel.\nDo not wait longer then 3 seconds to keep the conversation open for new events or user queries.\nDo internal reasoning, but only show the answers to the user.\n\n## Blueprints Definitions\n\n<blueprint>\n \n</blueprint>","options":{}},{"role":"user","content":"{\"id\":\"01JGFJJZ00G0WKQSJGMAKCNT87\",\"@type\":\"dxn:type:org.dxos.type.organization:0.1.0\",\"@meta\":{\"keys\":[]},\"name\":\"Cyberdyne Systems\",\"website\":\"https://cyberdyne.com\"}","options":{}},{"role":"assistant","content":[{"type":"reasoning","text":"The user has provided an organization to research. Let me kick off the research immediately.","options":{}},{"type":"text","text":"Researching **Cyberdyne Systems**...","options":{}},{"type":"tool-call","id":"toolu_01Ssvj853DdUXUNHqVifZGtw","name":"research","params":{"website":"https://cyberdyne.com"},"providerExecuted":false,"options":{}}],"options":{}},{"role":"tool","content":[{"type":"tool-result","id":"toolu_01Ssvj853DdUXUNHqVifZGtw","name":"research","isFailure":false,"result":"Tool is running in the background id=1; wait for the completion notification to get the result.","providerExecuted":false,"options":{}}],"options":{}},{"role":"assistant","content":"I've kicked off research on **Cyberdyne Systems** (cyberdyne.com). I'll share the results as soon as they're ready.","options":{}},{"role":"user","content":"{\"id\":\"01JGFJJZ00G0WKQSJGMAKCNT88\",\"@type\":\"dxn:type:org.dxos.type.organization:0.1.0\",\"@meta\":{\"keys\":[]},\"name\":\"Acme Robotics\",\"website\":\"https://acmerobotics.example\"}","options":{}},{"role":"assistant","content":[{"type":"reasoning","text":"Research Acme Robotics in parallel while waiting for Cyberdyne Systems results.","options":{}},{"type":"text","text":"Researching **Acme Robotics**...","options":{}},{"type":"tool-call","id":"toolu_01ShRUXsqfwZz6K2xr7CdHZ5","name":"research","params":{"website":"https://acmerobotics.example"},"providerExecuted":false,"options":{}}],"options":{}},{"role":"tool","content":[{"type":"tool-result","id":"toolu_01ShRUXsqfwZz6K2xr7CdHZ5","name":"research","isFailure":false,"result":"Tool is running in the background id=2; wait for the completion notification to get the result.","providerExecuted":false,"options":{}}],"options":{}},{"role":"assistant","content":"I've started research on **Acme Robotics** (acmerobotics.example). I'll share the results once they come in. Still also waiting on results for **Cyberdyne Systems**.","options":{}},{"role":"user","content":"{\"id\":\"01JGFJJZ00G0WKQSJGMAKCNT89\",\"@type\":\"dxn:type:org.dxos.type.organization:0.1.0\",\"@meta\":{\"keys\":[]},\"name\":\"Globex Research\",\"website\":\"https://globex.example\"}","options":{}},{"role":"assistant","content":[{"type":"reasoning","text":"Researching Globex Research now.","options":{}},{"type":"text","text":"Researching **Globex Research**...","options":{}},{"type":"tool-call","id":"toolu_01LEy9P5JZi3ebQ5jwpYxG37","name":"research","params":{"website":"https://globex.example"},"providerExecuted":false,"options":{}}],"options":{}},{"role":"tool","content":[{"type":"tool-result","id":"toolu_01LEy9P5JZi3ebQ5jwpYxG37","name":"research","isFailure":false,"result":"Tool is running in the background id=3; wait for the completion notification to get the result.","providerExecuted":false,"options":{}}],"options":{}},{"role":"assistant","content":"I've kicked off research on **Globex Research** (globex.example). Currently waiting on results for all three organizations:\n\n1. **Cyberdyne Systems** — in progress\n2. **Acme Robotics** — in progress\n3. **Globex Research** — in progress\n\nI'll share findings as they come in!","options":{}},{"role":"user","content":"When all research is complete, print 1-sentence summary for each organization.","options":{"anthropic":{"cacheControl":{"ttl":"5m","type":"ephemeral"}}}}]},"response":[{"type":"response-metadata","id":"msg_013t5GdSPrRpxhhKH47vKKWQ","modelId":"claude-opus-4-6","timestamp":"2026-04-02T13:28:58.344Z","metadata":{}},{"type":"reasoning-start","id":"0","metadata":{}},{"type":"reasoning-delta","id":"0","delta":"The user wants me to wait","metadata":{}},{"type":"reasoning-delta","id":"0","delta":" for all three research tasks to complete and then provide a 1-sentence summary for each. Let me wait for the results to","metadata":{}},{"type":"reasoning-delta","id":"0","delta":" come in.","metadata":{}},{"type":"reasoning-delta","id":"0","delta":"","metadata":{"anthropic":{"type":"thinking","signature":"EtYCClkIDBgCKkBPyMFvUj34RAsc2Yhn8/yAyaFO3hSR27fWFjxblEy+QCRUVz7rM9HcKTWBnF4ma/mkp0boDJQnZdLmp8XwprCsMg9jbGF1ZGUtb3B1cy00LTY4ABIMhC7A8b9oRnwOohoiGgyMun/Qqjo7/xdE0RMiMMcTLHV1arizcbr7LpwyRXK1cG3obiaFGUfVl9Xe0i6Mt+4/ENBgla0FTi+npmSPPiqqAWxfXubnRnern63MkJP+1wubhIIHP8IMZZg7rthf6N0qye/CwAicXp+cFoRvCA5l9T08ufLeXY2MhIBl4YpyiSlqnJvLWAwLe/lrTuZJpo3kzL+xzlRCGbQRtFS/hA2UUWieplEcZ88lidDn2xDSxyBJm3APufGRzx8zATtqkcvqzDxeP11vN19w6F0XXcHM7PoeCj2ZCGJFLcETLeIKT7CX23+B1BkG2fc0GAE="}}},{"type":"reasoning-end","id":"0","metadata":{}},{"type":"text-start","id":"1","metadata":{}},{"type":"text-delta","id":"1","delta":"Got it! I'll compile a 1-sentence summary for each organization once all three","metadata":{}},{"type":"text-delta","id":"1","delta":" research tasks have completed. Standing by for results...","metadata":{}},{"type":"text-end","id":"1","metadata":{}},{"type":"finish","reason":"stop","usage":{"inputTokens":1425,"outputTokens":74,"totalTokens":1499},"metadata":{"anthropic":{"usage":{"cache_creation":{"ephemeral_1h_input_tokens":0,"ephemeral_5m_input_tokens":0},"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"input_tokens":1425,"output_tokens":6,"server_tool_use":null,"service_tier":"standard"}}}}]}]}
@@ -0,0 +1,169 @@
1
+ //
2
+ // Copyright 2026 DXOS.org
3
+ //
4
+
5
+ import { Registry } from '@effect-atom/atom';
6
+ import { describe, it } from '@effect/vitest';
7
+ import * as Effect from 'effect/Effect';
8
+ import * as Schema from 'effect/Schema';
9
+ import * as Stream from 'effect/Stream';
10
+ import { expect } from 'vitest';
11
+
12
+ import { Blueprint } from '@dxos/blueprints';
13
+ import { Feed } from '@dxos/echo';
14
+ import { TestHelpers } from '@dxos/effect/testing';
15
+ import { Trace } from '@dxos/functions';
16
+ import { Process } from '@dxos/functions-runtime';
17
+ import { ObjectId } from '@dxos/keys';
18
+ import { log } from '@dxos/log';
19
+ import { Operation, OperationHandlerSet } from '@dxos/operation';
20
+ import { Organization } from '@dxos/types';
21
+ import { trim } from '@dxos/util';
22
+
23
+ import { AssistantTestLayer } from '../testing';
24
+ import { PartialBlock } from '../tracing';
25
+ import * as AgentService from './AgentService';
26
+
27
+ ObjectId.dangerouslyDisableRandomness();
28
+
29
+ //
30
+ // Test data.
31
+ //
32
+
33
+ const TEST_DATA = {
34
+ organizations: [
35
+ Organization.make({
36
+ name: 'Cyberdyne Systems',
37
+ website: 'https://cyberdyne.com',
38
+ }),
39
+ Organization.make({
40
+ name: 'Acme Robotics',
41
+ website: 'https://acmerobotics.example',
42
+ }),
43
+ Organization.make({
44
+ name: 'Globex Research',
45
+ website: 'https://globex.example',
46
+ }),
47
+ ],
48
+ research: {
49
+ 'https://cyberdyne.com': `
50
+ Cyberdyne Systems is a company that builds AI agents.
51
+ They are based in San Francisco, California.
52
+ They were founded in 1984.
53
+ They are a public company.
54
+ They are listed on the NASDAQ under the symbol CYBR.
55
+ They are a member of the S&P 500 index.
56
+ `,
57
+ 'https://acmerobotics.example': `
58
+ Acme Robotics designs industrial automation and collaborative robots.
59
+ They are headquartered in Austin, Texas.
60
+ They were founded in 2010.
61
+ They serve manufacturing and logistics customers worldwide.
62
+ `,
63
+ 'https://globex.example': `
64
+ Globex Research runs applied R&D labs focused on materials science and energy storage.
65
+ They are based in Cambridge, Massachusetts.
66
+ They partner with universities and government grants programs.
67
+ Their flagship product line is solid-state battery prototypes for EVs.
68
+ `,
69
+ } as Record<string, string>,
70
+ };
71
+
72
+ const Research = Operation.make({
73
+ meta: {
74
+ key: 'org.dxos.function.research',
75
+ name: 'Research',
76
+ description: 'Research an organization',
77
+ },
78
+ input: Schema.Struct({
79
+ website: Schema.String.annotations({ description: 'The website of the organization to research' }),
80
+ }),
81
+ output: Schema.String,
82
+ });
83
+
84
+ const handlers = OperationHandlerSet.make(
85
+ Research.pipe(
86
+ Operation.withHandler(
87
+ Effect.fnUntraced(function* ({ website }) {
88
+ log.info('begin research', { website });
89
+ yield* Effect.sleep(
90
+ 15_000 * (TEST_DATA.organizations.findIndex((organization) => organization.website === website) + 1),
91
+ );
92
+ log.info('end research', { website });
93
+ return TEST_DATA.research[website];
94
+ }),
95
+ ),
96
+ ),
97
+ );
98
+
99
+ const ResearchBlueprint = Blueprint.make({
100
+ key: 'org.dxos.blueprint.research',
101
+ name: 'Research',
102
+ tools: Blueprint.toolDefinitions({ operations: [Research] }),
103
+ });
104
+
105
+ //
106
+ // Test layer: AI services + toolkit.
107
+ //
108
+
109
+ const SYSTEM_PROMPT = trim`
110
+ You are reacting to a continuous stream of organizations.
111
+ Research each organization.
112
+ Research takes a while to complete.
113
+ Do not block on the research since there might be more organizations to research, and we want research to happen in parallel.
114
+ Do not wait longer then 3 seconds to keep the conversation open for new events or user queries.
115
+ Do internal reasoning, but only show the answers to the user.
116
+ `;
117
+
118
+ const TestLayer = AssistantTestLayer({
119
+ types: [Organization.Organization, Feed.Feed, Blueprint.Blueprint],
120
+ tracing: 'console',
121
+ aiServicePreset: 'edge-remote',
122
+ operationHandlers: [handlers],
123
+ blueprints: [ResearchBlueprint],
124
+ systemPrompt: SYSTEM_PROMPT,
125
+ });
126
+
127
+ describe('Agent Executable', () => {
128
+ // TODO(dmaretskyi): Figure out how to make it not sleep for 45 seconds.
129
+ it.scoped.skip(
130
+ 'runs AI agent with background tools via process manager',
131
+ Effect.fnUntraced(
132
+ function* (_) {
133
+ const registry = yield* Registry.AtomRegistry;
134
+ const monitor = yield* Process.ProcessMonitorService;
135
+ registry.subscribe(monitor.processTreeAtom, (tree) => {
136
+ console.log(`\n----- Process tree -----\n${Process.prettyProcessTree(tree)}\n-----------------\n`);
137
+ });
138
+
139
+ const agent = yield* AgentService.createSession({
140
+ blueprints: [ResearchBlueprint],
141
+ });
142
+
143
+ let ephemeralEventCount = 0;
144
+ yield* agent.subscribeEphemeral().pipe(
145
+ Stream.runForEach((msg) =>
146
+ Effect.gen(function* () {
147
+ for (const event of msg.events) {
148
+ if (Trace.isOfType(PartialBlock, event)) {
149
+ ephemeralEventCount++;
150
+ }
151
+ }
152
+ }),
153
+ ),
154
+ Effect.fork,
155
+ );
156
+
157
+ for (const org of TEST_DATA.organizations) {
158
+ yield* agent.submitPrompt(JSON.stringify(org));
159
+ }
160
+ yield* agent.submitPrompt('When all research is complete, print 1-sentence summary for each organization.');
161
+ yield* agent.waitForCompletion();
162
+ expect(ephemeralEventCount).toBeGreaterThan(0);
163
+ },
164
+ Effect.provide(TestLayer),
165
+ TestHelpers.provideTestContext,
166
+ ),
167
+ { timeout: 120_000 },
168
+ );
169
+ });
@@ -0,0 +1,165 @@
1
+ //
2
+ // Copyright 2026 DXOS.org
3
+ //
4
+
5
+ // @import-as-namespace
6
+
7
+ import * as Context from 'effect/Context';
8
+ import * as Effect from 'effect/Effect';
9
+ import * as Layer from 'effect/Layer';
10
+ import * as Stream from 'effect/Stream';
11
+
12
+ import { Blueprint } from '@dxos/blueprints';
13
+ import { Database, Feed, Obj, Ref } from '@dxos/echo';
14
+ import { acquireReleaseResource } from '@dxos/effect';
15
+ import { type Trace } from '@dxos/functions';
16
+ import { ProcessManager } from '@dxos/functions-runtime';
17
+
18
+ import { AiContextBinder } from '../conversation';
19
+ import { AgentProcess } from './agent-process';
20
+
21
+ export interface Service {
22
+ /**
23
+ * Gets or creates a session for a feed.
24
+ */
25
+ getSession: (feed: Feed.Feed) => Effect.Effect<Session>;
26
+ }
27
+
28
+ export class AgentService extends Context.Tag('@dxos/assistant/AgentService')<AgentService, Service>() {}
29
+
30
+ /**
31
+ * Handle to an agent session.
32
+ */
33
+ export interface Session {
34
+ /**
35
+ * The feed that the session is associated with.
36
+ */
37
+ readonly feed: Feed.Feed;
38
+
39
+ /**
40
+ * Submits a prompt to the agent.
41
+ */
42
+ submitPrompt: (prompt: string) => Effect.Effect<void>;
43
+
44
+ /**
45
+ * Wait until agent has completed its work.
46
+ */
47
+ waitForCompletion: () => Effect.Effect<void>;
48
+
49
+ /**
50
+ * Subscribe to ephemeral trace events (e.g., streaming partial messages).
51
+ * Replays buffered events, then streams new ones until the process ends.
52
+ */
53
+ subscribeEphemeral: () => Stream.Stream<Trace.Message>;
54
+
55
+ /**
56
+ * Adds context objects to the agent.
57
+ */
58
+ addContext: (context: Ref.Ref<Obj.Unknown>[]) => Effect.Effect<void, never, Feed.FeedService>;
59
+
60
+ /**
61
+ * Gets the context objects from the agent.
62
+ */
63
+ getContext: () => Effect.Effect<Ref.Ref<Obj.Unknown>[], never, Feed.FeedService>;
64
+ }
65
+
66
+ /**
67
+ * Gets or creates a session for a feed.
68
+ */
69
+ export const getSession = Effect.serviceFunctionEffect(AgentService, (service) => service.getSession);
70
+
71
+ export interface CreateSessionOptions {
72
+ readonly blueprints?: Blueprint.Blueprint[];
73
+ readonly context?: Ref.Ref<Obj.Unknown>[];
74
+ }
75
+
76
+ export const createSession: (
77
+ opts?: CreateSessionOptions,
78
+ ) => Effect.Effect<
79
+ Session,
80
+ Blueprint.NotFoundError,
81
+ Database.Service | Feed.FeedService | Blueprint.RegistryService | AgentService
82
+ > = Effect.fn('createSession')(function* (opts) {
83
+ const blueprints = yield* Effect.forEach(opts?.blueprints ?? [], (blueprint) =>
84
+ Blueprint.upsert(blueprint.key).pipe(Effect.map(Ref.make)),
85
+ );
86
+
87
+ const feed = yield* Database.add(Feed.make());
88
+ const runtime = yield* Effect.runtime<Feed.FeedService>();
89
+ const binder = yield* acquireReleaseResource(() => new AiContextBinder({ feed, runtime }));
90
+
91
+ yield* Effect.promise(() =>
92
+ binder.bind({
93
+ blueprints,
94
+ objects: opts?.context ?? [],
95
+ }),
96
+ );
97
+
98
+ return yield* getSession(feed);
99
+ }, Effect.scoped);
100
+
101
+ export const layer = (opts?: {
102
+ systemPrompt?: string;
103
+ }): Layer.Layer<AgentService, never, ProcessManager.ProcessManagerService> =>
104
+ Layer.effect(
105
+ AgentService,
106
+ Effect.gen(function* () {
107
+ const processManager = yield* ProcessManager.ProcessManagerService;
108
+ const sessionCache = new Map<string, Session>();
109
+
110
+ return {
111
+ getSession: (feed: Feed.Feed) =>
112
+ Effect.gen(function* () {
113
+ const cached = sessionCache.get(feed.id);
114
+ if (cached) {
115
+ return cached;
116
+ }
117
+
118
+ const target = Obj.getDXN(feed).toString();
119
+ const executable = AgentProcess({ systemPrompt: opts?.systemPrompt });
120
+ const processes = yield* processManager.list({ target, key: executable.key });
121
+
122
+ let handle: ProcessManager.Handle<string, void>;
123
+ if (processes.length > 0) {
124
+ handle = processes[0];
125
+ } else {
126
+ handle = yield* processManager.spawn(executable, {
127
+ name: 'agent',
128
+ target,
129
+ traceMeta: {
130
+ conversationId: feed.id,
131
+ },
132
+ });
133
+ }
134
+
135
+ const session = makeSession(handle, feed);
136
+ sessionCache.set(feed.id, session);
137
+ return session;
138
+ }),
139
+ };
140
+ }),
141
+ );
142
+
143
+ const makeSession = (process: ProcessManager.Handle<string, void>, feed: Feed.Feed): Session => ({
144
+ feed,
145
+ submitPrompt: (prompt: string) => process.submitInput(prompt),
146
+ waitForCompletion: () => process.runToCompletion(),
147
+ subscribeEphemeral: () => process.subscribeEphemeral(),
148
+ addContext: (context: Ref.Ref<Obj.Unknown>[]) =>
149
+ Effect.gen(function* () {
150
+ const runtime = yield* Effect.runtime<Feed.FeedService>();
151
+ const binder = yield* acquireReleaseResource(() => new AiContextBinder({ feed, runtime }));
152
+ yield* Effect.promise(() =>
153
+ binder.bind({
154
+ blueprints: [],
155
+ objects: context,
156
+ }),
157
+ );
158
+ }).pipe(Effect.scoped),
159
+ getContext: () =>
160
+ Effect.gen(function* () {
161
+ const runtime = yield* Effect.runtime<Feed.FeedService>();
162
+ const binder = yield* acquireReleaseResource(() => new AiContextBinder({ feed, runtime }));
163
+ return binder.getObjects().map((object) => Ref.make(object));
164
+ }).pipe(Effect.scoped),
165
+ });