@framers/agentos 0.1.6 → 0.1.7

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 (260) hide show
  1. package/README.md +19 -0
  2. package/dist/api/AgentOS.d.ts +12 -0
  3. package/dist/api/AgentOS.d.ts.map +1 -1
  4. package/dist/api/AgentOS.js +96 -2
  5. package/dist/api/AgentOS.js.map +1 -1
  6. package/dist/api/AgentOSOrchestrator.d.ts +45 -0
  7. package/dist/api/AgentOSOrchestrator.d.ts.map +1 -1
  8. package/dist/api/AgentOSOrchestrator.js +470 -6
  9. package/dist/api/AgentOSOrchestrator.js.map +1 -1
  10. package/dist/api/types/AgentOSInput.d.ts +8 -0
  11. package/dist/api/types/AgentOSInput.d.ts.map +1 -1
  12. package/dist/api/types/AgentOSResponse.d.ts +22 -2
  13. package/dist/api/types/AgentOSResponse.d.ts.map +1 -1
  14. package/dist/api/types/AgentOSResponse.js +1 -0
  15. package/dist/api/types/AgentOSResponse.js.map +1 -1
  16. package/dist/channels/ChannelRouter.d.ts +150 -0
  17. package/dist/channels/ChannelRouter.d.ts.map +1 -0
  18. package/dist/channels/ChannelRouter.js +309 -0
  19. package/dist/channels/ChannelRouter.js.map +1 -0
  20. package/dist/channels/IChannelAdapter.d.ts +113 -0
  21. package/dist/channels/IChannelAdapter.d.ts.map +1 -0
  22. package/dist/channels/IChannelAdapter.js +17 -0
  23. package/dist/channels/IChannelAdapter.js.map +1 -0
  24. package/dist/channels/index.d.ts +9 -0
  25. package/dist/channels/index.d.ts.map +1 -0
  26. package/dist/channels/index.js +7 -0
  27. package/dist/channels/index.js.map +1 -0
  28. package/dist/channels/types.d.ts +257 -0
  29. package/dist/channels/types.d.ts.map +1 -0
  30. package/dist/channels/types.js +12 -0
  31. package/dist/channels/types.js.map +1 -0
  32. package/dist/cognitive_substrate/GMI.d.ts +139 -0
  33. package/dist/cognitive_substrate/GMI.d.ts.map +1 -1
  34. package/dist/cognitive_substrate/GMI.js +680 -14
  35. package/dist/cognitive_substrate/GMI.js.map +1 -1
  36. package/dist/cognitive_substrate/GMIEvent.d.ts +151 -0
  37. package/dist/cognitive_substrate/GMIEvent.d.ts.map +1 -0
  38. package/dist/cognitive_substrate/GMIEvent.js +79 -0
  39. package/dist/cognitive_substrate/GMIEvent.js.map +1 -0
  40. package/dist/cognitive_substrate/IGMI.d.ts +22 -0
  41. package/dist/cognitive_substrate/IGMI.d.ts.map +1 -1
  42. package/dist/cognitive_substrate/IGMI.js.map +1 -1
  43. package/dist/cognitive_substrate/personas/IPersonaDefinition.d.ts +92 -0
  44. package/dist/cognitive_substrate/personas/IPersonaDefinition.d.ts.map +1 -1
  45. package/dist/cognitive_substrate/personas/PersonaLoader.d.ts.map +1 -1
  46. package/dist/cognitive_substrate/personas/PersonaLoader.js +21 -0
  47. package/dist/cognitive_substrate/personas/PersonaLoader.js.map +1 -1
  48. package/dist/cognitive_substrate/personas/metaprompt_presets.d.ts +86 -0
  49. package/dist/cognitive_substrate/personas/metaprompt_presets.d.ts.map +1 -0
  50. package/dist/cognitive_substrate/personas/metaprompt_presets.js +457 -0
  51. package/dist/cognitive_substrate/personas/metaprompt_presets.js.map +1 -0
  52. package/dist/config/RetrievalAugmentorConfiguration.d.ts +21 -0
  53. package/dist/config/RetrievalAugmentorConfiguration.d.ts.map +1 -1
  54. package/dist/config/RetrievalAugmentorConfiguration.js.map +1 -1
  55. package/dist/config/VectorStoreConfiguration.d.ts +2 -1
  56. package/dist/config/VectorStoreConfiguration.d.ts.map +1 -1
  57. package/dist/config/VectorStoreConfiguration.js.map +1 -1
  58. package/dist/config/extension-secrets.json +198 -0
  59. package/dist/core/agents/AgentCore.d.ts +8 -0
  60. package/dist/core/agents/AgentCore.d.ts.map +1 -1
  61. package/dist/core/agents/AgentCore.js.map +1 -1
  62. package/dist/core/conversation/ConversationManager.d.ts.map +1 -1
  63. package/dist/core/conversation/ConversationManager.js +2 -4
  64. package/dist/core/conversation/ConversationManager.js.map +1 -1
  65. package/dist/core/conversation/ILongTermMemoryRetriever.d.ts +30 -0
  66. package/dist/core/conversation/ILongTermMemoryRetriever.d.ts.map +1 -0
  67. package/dist/core/conversation/ILongTermMemoryRetriever.js +2 -0
  68. package/dist/core/conversation/ILongTermMemoryRetriever.js.map +1 -0
  69. package/dist/core/conversation/IRollingSummaryMemorySink.d.ts +44 -0
  70. package/dist/core/conversation/IRollingSummaryMemorySink.d.ts.map +1 -0
  71. package/dist/core/conversation/IRollingSummaryMemorySink.js +9 -0
  72. package/dist/core/conversation/IRollingSummaryMemorySink.js.map +1 -0
  73. package/dist/core/conversation/LongTermMemoryPolicy.d.ts +53 -0
  74. package/dist/core/conversation/LongTermMemoryPolicy.d.ts.map +1 -0
  75. package/dist/core/conversation/LongTermMemoryPolicy.js +84 -0
  76. package/dist/core/conversation/LongTermMemoryPolicy.js.map +1 -0
  77. package/dist/core/conversation/RollingSummaryCompactor.d.ts +61 -0
  78. package/dist/core/conversation/RollingSummaryCompactor.d.ts.map +1 -0
  79. package/dist/core/conversation/RollingSummaryCompactor.js +255 -0
  80. package/dist/core/conversation/RollingSummaryCompactor.js.map +1 -0
  81. package/dist/core/llm/PromptEngine.d.ts.map +1 -1
  82. package/dist/core/llm/PromptEngine.js +10 -1
  83. package/dist/core/llm/PromptEngine.js.map +1 -1
  84. package/dist/core/orchestration/AgentOrchestrator.d.ts +40 -0
  85. package/dist/core/orchestration/AgentOrchestrator.d.ts.map +1 -1
  86. package/dist/core/orchestration/AgentOrchestrator.js +324 -2
  87. package/dist/core/orchestration/AgentOrchestrator.js.map +1 -1
  88. package/dist/core/prompting/PromptProfileRouter.d.ts +74 -0
  89. package/dist/core/prompting/PromptProfileRouter.d.ts.map +1 -0
  90. package/dist/core/prompting/PromptProfileRouter.js +270 -0
  91. package/dist/core/prompting/PromptProfileRouter.js.map +1 -0
  92. package/dist/core/provenance/anchoring/AnchorManager.d.ts +86 -0
  93. package/dist/core/provenance/anchoring/AnchorManager.d.ts.map +1 -0
  94. package/dist/core/provenance/anchoring/AnchorManager.js +244 -0
  95. package/dist/core/provenance/anchoring/AnchorManager.js.map +1 -0
  96. package/dist/core/provenance/anchoring/providers/CompositeAnchorProvider.d.ts +20 -0
  97. package/dist/core/provenance/anchoring/providers/CompositeAnchorProvider.d.ts.map +1 -0
  98. package/dist/core/provenance/anchoring/providers/CompositeAnchorProvider.js +62 -0
  99. package/dist/core/provenance/anchoring/providers/CompositeAnchorProvider.js.map +1 -0
  100. package/dist/core/provenance/anchoring/providers/NoneProvider.d.ts +15 -0
  101. package/dist/core/provenance/anchoring/providers/NoneProvider.d.ts.map +1 -0
  102. package/dist/core/provenance/anchoring/providers/NoneProvider.js +21 -0
  103. package/dist/core/provenance/anchoring/providers/NoneProvider.js.map +1 -0
  104. package/dist/core/provenance/anchoring/providers/createAnchorProvider.d.ts +38 -0
  105. package/dist/core/provenance/anchoring/providers/createAnchorProvider.d.ts.map +1 -0
  106. package/dist/core/provenance/anchoring/providers/createAnchorProvider.js +67 -0
  107. package/dist/core/provenance/anchoring/providers/createAnchorProvider.js.map +1 -0
  108. package/dist/core/provenance/anchoring/providers/index.d.ts +12 -0
  109. package/dist/core/provenance/anchoring/providers/index.d.ts.map +1 -0
  110. package/dist/core/provenance/anchoring/providers/index.js +12 -0
  111. package/dist/core/provenance/anchoring/providers/index.js.map +1 -0
  112. package/dist/core/provenance/config/PolicyProfiles.d.ts +60 -0
  113. package/dist/core/provenance/config/PolicyProfiles.d.ts.map +1 -0
  114. package/dist/core/provenance/config/PolicyProfiles.js +144 -0
  115. package/dist/core/provenance/config/PolicyProfiles.js.map +1 -0
  116. package/dist/core/provenance/crypto/AgentKeyManager.d.ts +48 -0
  117. package/dist/core/provenance/crypto/AgentKeyManager.d.ts.map +1 -0
  118. package/dist/core/provenance/crypto/AgentKeyManager.js +162 -0
  119. package/dist/core/provenance/crypto/AgentKeyManager.js.map +1 -0
  120. package/dist/core/provenance/crypto/HashChain.d.ts +58 -0
  121. package/dist/core/provenance/crypto/HashChain.d.ts.map +1 -0
  122. package/dist/core/provenance/crypto/HashChain.js +86 -0
  123. package/dist/core/provenance/crypto/HashChain.js.map +1 -0
  124. package/dist/core/provenance/crypto/MerkleTree.d.ts +41 -0
  125. package/dist/core/provenance/crypto/MerkleTree.d.ts.map +1 -0
  126. package/dist/core/provenance/crypto/MerkleTree.js +86 -0
  127. package/dist/core/provenance/crypto/MerkleTree.js.map +1 -0
  128. package/dist/core/provenance/enforcement/AutonomyGuard.d.ts +37 -0
  129. package/dist/core/provenance/enforcement/AutonomyGuard.d.ts.map +1 -0
  130. package/dist/core/provenance/enforcement/AutonomyGuard.js +120 -0
  131. package/dist/core/provenance/enforcement/AutonomyGuard.js.map +1 -0
  132. package/dist/core/provenance/enforcement/ProvenanceStorageHooks.d.ts +43 -0
  133. package/dist/core/provenance/enforcement/ProvenanceStorageHooks.d.ts.map +1 -0
  134. package/dist/core/provenance/enforcement/ProvenanceStorageHooks.js +193 -0
  135. package/dist/core/provenance/enforcement/ProvenanceStorageHooks.js.map +1 -0
  136. package/dist/core/provenance/enforcement/RevisionManager.d.ts +41 -0
  137. package/dist/core/provenance/enforcement/RevisionManager.d.ts.map +1 -0
  138. package/dist/core/provenance/enforcement/RevisionManager.js +105 -0
  139. package/dist/core/provenance/enforcement/RevisionManager.js.map +1 -0
  140. package/dist/core/provenance/enforcement/TombstoneManager.d.ts +47 -0
  141. package/dist/core/provenance/enforcement/TombstoneManager.d.ts.map +1 -0
  142. package/dist/core/provenance/enforcement/TombstoneManager.js +121 -0
  143. package/dist/core/provenance/enforcement/TombstoneManager.js.map +1 -0
  144. package/dist/core/provenance/index.d.ts +34 -0
  145. package/dist/core/provenance/index.d.ts.map +1 -0
  146. package/dist/core/provenance/index.js +39 -0
  147. package/dist/core/provenance/index.js.map +1 -0
  148. package/dist/core/provenance/ledger/EventTypes.d.ts +123 -0
  149. package/dist/core/provenance/ledger/EventTypes.d.ts.map +1 -0
  150. package/dist/core/provenance/ledger/EventTypes.js +9 -0
  151. package/dist/core/provenance/ledger/EventTypes.js.map +1 -0
  152. package/dist/core/provenance/ledger/SignedEventLedger.d.ts +75 -0
  153. package/dist/core/provenance/ledger/SignedEventLedger.d.ts.map +1 -0
  154. package/dist/core/provenance/ledger/SignedEventLedger.js +210 -0
  155. package/dist/core/provenance/ledger/SignedEventLedger.js.map +1 -0
  156. package/dist/core/provenance/schema/provenance-schema.d.ts +17 -0
  157. package/dist/core/provenance/schema/provenance-schema.d.ts.map +1 -0
  158. package/dist/core/provenance/schema/provenance-schema.js +104 -0
  159. package/dist/core/provenance/schema/provenance-schema.js.map +1 -0
  160. package/dist/core/provenance/types.d.ts +261 -0
  161. package/dist/core/provenance/types.d.ts.map +1 -0
  162. package/dist/core/provenance/types.js +21 -0
  163. package/dist/core/provenance/types.js.map +1 -0
  164. package/dist/core/provenance/verification/BundleExporter.d.ts +50 -0
  165. package/dist/core/provenance/verification/BundleExporter.d.ts.map +1 -0
  166. package/dist/core/provenance/verification/BundleExporter.js +240 -0
  167. package/dist/core/provenance/verification/BundleExporter.js.map +1 -0
  168. package/dist/core/provenance/verification/ChainVerifier.d.ts +39 -0
  169. package/dist/core/provenance/verification/ChainVerifier.d.ts.map +1 -0
  170. package/dist/core/provenance/verification/ChainVerifier.js +204 -0
  171. package/dist/core/provenance/verification/ChainVerifier.js.map +1 -0
  172. package/dist/core/provenance/verification/ConversationVerifier.d.ts +56 -0
  173. package/dist/core/provenance/verification/ConversationVerifier.d.ts.map +1 -0
  174. package/dist/core/provenance/verification/ConversationVerifier.js +109 -0
  175. package/dist/core/provenance/verification/ConversationVerifier.js.map +1 -0
  176. package/dist/extensions/ExtensionManager.d.ts.map +1 -1
  177. package/dist/extensions/ExtensionManager.js +6 -1
  178. package/dist/extensions/ExtensionManager.js.map +1 -1
  179. package/dist/extensions/MessagingChannelPayload.d.ts +39 -0
  180. package/dist/extensions/MessagingChannelPayload.d.ts.map +1 -0
  181. package/dist/extensions/MessagingChannelPayload.js +12 -0
  182. package/dist/extensions/MessagingChannelPayload.js.map +1 -0
  183. package/dist/extensions/packs/provenance-pack.d.ts +66 -0
  184. package/dist/extensions/packs/provenance-pack.d.ts.map +1 -0
  185. package/dist/extensions/packs/provenance-pack.js +162 -0
  186. package/dist/extensions/packs/provenance-pack.js.map +1 -0
  187. package/dist/extensions/types.d.ts +11 -0
  188. package/dist/extensions/types.d.ts.map +1 -1
  189. package/dist/extensions/types.js +4 -0
  190. package/dist/extensions/types.js.map +1 -1
  191. package/dist/index.d.ts +7 -0
  192. package/dist/index.d.ts.map +1 -1
  193. package/dist/index.js +10 -0
  194. package/dist/index.js.map +1 -1
  195. package/dist/rag/IRetrievalAugmentor.d.ts +22 -1
  196. package/dist/rag/IRetrievalAugmentor.d.ts.map +1 -1
  197. package/dist/rag/RetrievalAugmentor.d.ts +37 -0
  198. package/dist/rag/RetrievalAugmentor.d.ts.map +1 -1
  199. package/dist/rag/RetrievalAugmentor.js +82 -6
  200. package/dist/rag/RetrievalAugmentor.js.map +1 -1
  201. package/dist/rag/VectorStoreManager.d.ts.map +1 -1
  202. package/dist/rag/VectorStoreManager.js +5 -0
  203. package/dist/rag/VectorStoreManager.js.map +1 -1
  204. package/dist/rag/graphrag/GraphRAGEngine.d.ts +100 -0
  205. package/dist/rag/graphrag/GraphRAGEngine.d.ts.map +1 -0
  206. package/dist/rag/graphrag/GraphRAGEngine.js +1146 -0
  207. package/dist/rag/graphrag/GraphRAGEngine.js.map +1 -0
  208. package/dist/rag/graphrag/IGraphRAG.d.ts +198 -0
  209. package/dist/rag/graphrag/IGraphRAG.d.ts.map +1 -0
  210. package/dist/rag/graphrag/IGraphRAG.js +11 -0
  211. package/dist/rag/graphrag/IGraphRAG.js.map +1 -0
  212. package/dist/rag/graphrag/index.d.ts +12 -0
  213. package/dist/rag/graphrag/index.d.ts.map +1 -0
  214. package/dist/rag/graphrag/index.js +11 -0
  215. package/dist/rag/graphrag/index.js.map +1 -0
  216. package/dist/rag/implementations/vector_stores/HnswlibVectorStore.d.ts +72 -0
  217. package/dist/rag/implementations/vector_stores/HnswlibVectorStore.d.ts.map +1 -0
  218. package/dist/rag/implementations/vector_stores/HnswlibVectorStore.js +463 -0
  219. package/dist/rag/implementations/vector_stores/HnswlibVectorStore.js.map +1 -0
  220. package/dist/rag/implementations/vector_stores/index.d.ts +1 -0
  221. package/dist/rag/implementations/vector_stores/index.d.ts.map +1 -1
  222. package/dist/rag/implementations/vector_stores/index.js +2 -0
  223. package/dist/rag/implementations/vector_stores/index.js.map +1 -1
  224. package/dist/rag/index.d.ts +3 -0
  225. package/dist/rag/index.d.ts.map +1 -1
  226. package/dist/rag/index.js +5 -0
  227. package/dist/rag/index.js.map +1 -1
  228. package/dist/rag/reranking/IRerankerService.d.ts +163 -0
  229. package/dist/rag/reranking/IRerankerService.d.ts.map +1 -0
  230. package/dist/rag/reranking/IRerankerService.js +9 -0
  231. package/dist/rag/reranking/IRerankerService.js.map +1 -0
  232. package/dist/rag/reranking/RerankerService.d.ts +107 -0
  233. package/dist/rag/reranking/RerankerService.d.ts.map +1 -0
  234. package/dist/rag/reranking/RerankerService.js +194 -0
  235. package/dist/rag/reranking/RerankerService.js.map +1 -0
  236. package/dist/rag/reranking/index.d.ts +55 -0
  237. package/dist/rag/reranking/index.d.ts.map +1 -0
  238. package/dist/rag/reranking/index.js +56 -0
  239. package/dist/rag/reranking/index.js.map +1 -0
  240. package/dist/rag/reranking/providers/CohereReranker.d.ts +66 -0
  241. package/dist/rag/reranking/providers/CohereReranker.d.ts.map +1 -0
  242. package/dist/rag/reranking/providers/CohereReranker.js +141 -0
  243. package/dist/rag/reranking/providers/CohereReranker.js.map +1 -0
  244. package/dist/rag/reranking/providers/LocalCrossEncoderReranker.d.ts +105 -0
  245. package/dist/rag/reranking/providers/LocalCrossEncoderReranker.d.ts.map +1 -0
  246. package/dist/rag/reranking/providers/LocalCrossEncoderReranker.js +214 -0
  247. package/dist/rag/reranking/providers/LocalCrossEncoderReranker.js.map +1 -0
  248. package/dist/rag/reranking/providers/index.d.ts +7 -0
  249. package/dist/rag/reranking/providers/index.d.ts.map +1 -0
  250. package/dist/rag/reranking/providers/index.js +7 -0
  251. package/dist/rag/reranking/providers/index.js.map +1 -0
  252. package/dist/rag/reranking/tests/index.d.ts +6 -0
  253. package/dist/rag/reranking/tests/index.d.ts.map +1 -0
  254. package/dist/rag/reranking/tests/index.js +11 -0
  255. package/dist/rag/reranking/tests/index.js.map +1 -0
  256. package/dist/types/optionalDependencies.d.ts +5 -0
  257. package/dist/types/optionalDependencies.d.ts.map +1 -0
  258. package/dist/types/optionalDependencies.js +4 -0
  259. package/dist/types/optionalDependencies.js.map +1 -0
  260. package/package.json +22 -6
@@ -11,9 +11,56 @@ import { AgentOSResponseChunkType, } from './types/AgentOSResponse.js';
11
11
  import { GMIInteractionType, // Added for GMITurnInput
12
12
  GMIOutputChunkType, // Added for comparisons
13
13
  } from '../cognitive_substrate/IGMI.js';
14
+ import { MessageRole } from '../core/conversation/ConversationMessage.js';
14
15
  import { uuidv4 } from '../utils/uuid.js';
15
16
  import { GMIError, GMIErrorCode } from '../utils/errors.js';
16
17
  import { normalizeUsage, snapshotPersonaDetails } from '../core/orchestration/helpers.js';
18
+ import { DEFAULT_PROMPT_PROFILE_CONFIG, selectPromptProfile, } from '../core/prompting/PromptProfileRouter.js';
19
+ import { DEFAULT_ROLLING_SUMMARY_COMPACTION_CONFIG, maybeCompactConversationMessages, } from '../core/conversation/RollingSummaryCompactor.js';
20
+ import { DEFAULT_LONG_TERM_MEMORY_POLICY, hasAnyLongTermMemoryScope, LONG_TERM_MEMORY_POLICY_METADATA_KEY, resolveLongTermMemoryPolicy, } from '../core/conversation/LongTermMemoryPolicy.js';
21
+ function normalizeMode(value) {
22
+ return (value || '').trim().toLowerCase();
23
+ }
24
+ function pickByMode(map, mode) {
25
+ if (!map || Object.keys(map).length === 0)
26
+ return null;
27
+ const modeNorm = normalizeMode(mode);
28
+ const exact = map[modeNorm];
29
+ if (exact)
30
+ return exact;
31
+ const patternMatch = Object.entries(map)
32
+ .map(([key, value]) => ({ key: normalizeMode(key), value }))
33
+ .filter(({ key }) => key && (modeNorm === key || modeNorm.startsWith(key) || modeNorm.includes(key)))
34
+ .sort((a, b) => b.key.length - a.key.length)[0];
35
+ return patternMatch?.value ?? null;
36
+ }
37
+ function renderPlainText(markdown) {
38
+ let text = String(markdown ?? '');
39
+ if (!text.trim())
40
+ return '';
41
+ text = text.replace(/\r\n/g, '\n');
42
+ // Fenced code blocks: keep inner content, drop fences.
43
+ text = text.replace(/```[a-zA-Z0-9_-]*\n([\s\S]*?)```/g, '$1');
44
+ // Inline code.
45
+ text = text.replace(/`([^`]+)`/g, '$1');
46
+ // Images + links.
47
+ text = text.replace(/!\[([^\]]*)\]\([^)]+\)/g, '$1');
48
+ text = text.replace(/\[([^\]]+)\]\([^)]+\)/g, '$1');
49
+ // Headings + blockquotes.
50
+ text = text.replace(/^\s{0,3}#{1,6}\s+/gm, '');
51
+ text = text.replace(/^\s{0,3}>\s?/gm, '');
52
+ // Emphasis / strike-through.
53
+ text = text.replace(/(\*\*|__)(.*?)\1/g, '$2');
54
+ text = text.replace(/(\*|_)(.*?)\1/g, '$2');
55
+ text = text.replace(/~~(.*?)~~/g, '$1');
56
+ // Horizontal rules.
57
+ text = text.replace(/^\s*(?:-{3,}|\*{3,}|_{3,})\s*$/gm, '');
58
+ // Basic HTML tags.
59
+ text = text.replace(/<\/?[^>]+>/g, '');
60
+ text = text.replace(/&nbsp;/g, ' ');
61
+ text = text.replace(/\n{3,}/g, '\n\n');
62
+ return text.trim();
63
+ }
17
64
  /**
18
65
  * @class AgentOSOrchestrator
19
66
  * @description
@@ -50,13 +97,22 @@ export class AgentOSOrchestrator {
50
97
  console.warn('AgentOSOrchestrator already initialized. Skipping re-initialization.');
51
98
  return;
52
99
  }
53
- if (!dependencies.gmiManager || !dependencies.toolOrchestrator || !dependencies.conversationManager || !dependencies.streamingManager) {
54
- throw new GMIError('AgentOSOrchestrator: Missing essential dependencies (gmiManager, toolOrchestrator, conversationManager, streamingManager).', GMIErrorCode.CONFIGURATION_ERROR);
100
+ if (!dependencies.gmiManager || !dependencies.toolOrchestrator || !dependencies.conversationManager || !dependencies.streamingManager || !dependencies.modelProviderManager) {
101
+ throw new GMIError('AgentOSOrchestrator: Missing essential dependencies (gmiManager, toolOrchestrator, conversationManager, streamingManager, modelProviderManager).', GMIErrorCode.CONFIGURATION_ERROR);
55
102
  }
56
103
  this.config = {
57
104
  maxToolCallIterations: config.maxToolCallIterations ?? 5,
58
105
  defaultAgentTurnTimeoutMs: config.defaultAgentTurnTimeoutMs ?? 120000,
59
106
  enableConversationalPersistence: config.enableConversationalPersistence ?? true,
107
+ promptProfileConfig: config.promptProfileConfig === null
108
+ ? null
109
+ : (config.promptProfileConfig ?? DEFAULT_PROMPT_PROFILE_CONFIG),
110
+ rollingSummaryCompactionConfig: config.rollingSummaryCompactionConfig === null
111
+ ? null
112
+ : { ...DEFAULT_ROLLING_SUMMARY_COMPACTION_CONFIG, ...(config.rollingSummaryCompactionConfig ?? {}) },
113
+ rollingSummaryCompactionProfilesConfig: config.rollingSummaryCompactionProfilesConfig ?? null,
114
+ rollingSummarySystemPrompt: config.rollingSummarySystemPrompt ?? '',
115
+ rollingSummaryStateKey: config.rollingSummaryStateKey ?? 'rollingSummaryState',
60
116
  };
61
117
  this.dependencies = dependencies;
62
118
  this.initialized = true;
@@ -156,6 +212,12 @@ export class AgentOSOrchestrator {
156
212
  workflow: data.workflow,
157
213
  };
158
214
  break;
215
+ case AgentOSResponseChunkType.METADATA_UPDATE:
216
+ chunk = {
217
+ ...baseChunk,
218
+ updates: data.updates,
219
+ };
220
+ break;
159
221
  default:
160
222
  console.error(`AgentOSOrchestrator: Unknown chunk type encountered in pushChunkToStream: ${type}`);
161
223
  chunk = {
@@ -255,6 +317,8 @@ export class AgentOSOrchestrator {
255
317
  let conversationContext;
256
318
  let currentPersonaId = input.selectedPersonaId;
257
319
  let gmiInstanceIdForChunks = 'gmi_pending_init';
320
+ let organizationIdForMemory;
321
+ let longTermMemoryPolicy = null;
258
322
  try {
259
323
  const gmiResult = await this.dependencies.gmiManager.getOrCreateGMIForSession(input.userId, input.sessionId, // This is AgentOS's session ID, GMI might have its own.
260
324
  input.selectedPersonaId, // Can be undefined, GMIManager handles default.
@@ -272,6 +336,346 @@ export class AgentOSOrchestrator {
272
336
  this.activeStreamContexts.set(agentOSStreamId, streamContext);
273
337
  await this.pushChunkToStream(agentOSStreamId, AgentOSResponseChunkType.SYSTEM_PROGRESS, gmiInstanceIdForChunks, currentPersonaId, false, { message: `Initializing persona ${currentPersonaId}... GMI: ${gmiInstanceIdForChunks}`, progressPercentage: 10 });
274
338
  const gmiInput = this.constructGMITurnInput(agentOSStreamId, input, streamContext);
339
+ // --- Org context + long-term memory policy (persisted per conversation) ---
340
+ if (conversationContext) {
341
+ const inboundOrg = typeof input.organizationId === 'string' ? input.organizationId.trim() : '';
342
+ // SECURITY NOTE: do not persist organizationId in conversation metadata. The org context
343
+ // should be asserted by the trusted caller each request (after membership checks).
344
+ organizationIdForMemory = inboundOrg || undefined;
345
+ const rawPrevPolicy = conversationContext.getMetadata(LONG_TERM_MEMORY_POLICY_METADATA_KEY);
346
+ const prevPolicy = rawPrevPolicy && typeof rawPrevPolicy === 'object'
347
+ ? rawPrevPolicy
348
+ : null;
349
+ const inputPolicy = input.memoryControl?.longTermMemory ?? null;
350
+ longTermMemoryPolicy = resolveLongTermMemoryPolicy({
351
+ previous: prevPolicy,
352
+ input: inputPolicy,
353
+ defaults: DEFAULT_LONG_TERM_MEMORY_POLICY,
354
+ });
355
+ // Only write back when the client supplies overrides or no prior policy exists.
356
+ if (inputPolicy || !prevPolicy) {
357
+ conversationContext.setMetadata(LONG_TERM_MEMORY_POLICY_METADATA_KEY, longTermMemoryPolicy);
358
+ }
359
+ }
360
+ else {
361
+ organizationIdForMemory =
362
+ typeof input.organizationId === 'string' ? input.organizationId.trim() : undefined;
363
+ longTermMemoryPolicy = resolveLongTermMemoryPolicy({
364
+ defaults: DEFAULT_LONG_TERM_MEMORY_POLICY,
365
+ });
366
+ }
367
+ (gmiInput.metadata ?? (gmiInput.metadata = {})).organizationId = organizationIdForMemory ?? null;
368
+ gmiInput.metadata.longTermMemoryPolicy = longTermMemoryPolicy;
369
+ // Persist inbound user/system message to ConversationContext BEFORE any LLM call so persona switches
370
+ // and restarts preserve memory, even if the LLM fails.
371
+ if (this.config.enableConversationalPersistence && conversationContext) {
372
+ try {
373
+ if (gmiInput.type === GMIInteractionType.TEXT && typeof gmiInput.content === 'string') {
374
+ conversationContext.addMessage({
375
+ role: MessageRole.USER,
376
+ content: gmiInput.content,
377
+ name: input.userId,
378
+ metadata: { agentPersonaId: currentPersonaId, source: 'agentos_input' },
379
+ });
380
+ }
381
+ else if (gmiInput.type === GMIInteractionType.MULTIMODAL_CONTENT) {
382
+ conversationContext.addMessage({
383
+ role: MessageRole.USER,
384
+ content: JSON.stringify(gmiInput.content),
385
+ name: input.userId,
386
+ metadata: { agentPersonaId: currentPersonaId, source: 'agentos_input_multimodal' },
387
+ });
388
+ }
389
+ else if (gmiInput.type === GMIInteractionType.SYSTEM_MESSAGE) {
390
+ conversationContext.addMessage({
391
+ role: MessageRole.SYSTEM,
392
+ content: typeof gmiInput.content === 'string' ? gmiInput.content : JSON.stringify(gmiInput.content),
393
+ metadata: { agentPersonaId: currentPersonaId, source: 'agentos_input_system' },
394
+ });
395
+ }
396
+ await this.dependencies.conversationManager.saveConversation(conversationContext);
397
+ }
398
+ catch (persistError) {
399
+ console.warn(`AgentOSOrchestrator: Failed to persist inbound message to ConversationContext for stream ${agentOSStreamId}.`, persistError);
400
+ }
401
+ }
402
+ // Build conversationHistoryForPrompt after compaction/routing so it can reflect rolling-summary trimming.
403
+ const modeForRouting = typeof input.options?.customFlags?.mode === 'string' && input.options.customFlags.mode.trim()
404
+ ? input.options.customFlags.mode.trim()
405
+ : currentPersonaId;
406
+ // --- Rolling summary compaction (text + JSON metadata) ---
407
+ let rollingSummaryResult = null;
408
+ let rollingSummaryProfileId = null;
409
+ let rollingSummaryConfigForTurn = this.config.rollingSummaryCompactionConfig;
410
+ let rollingSummarySystemPromptForTurn = this.config.rollingSummarySystemPrompt;
411
+ if (this.config.rollingSummaryCompactionProfilesConfig) {
412
+ const profilesConfig = this.config.rollingSummaryCompactionProfilesConfig;
413
+ const picked = pickByMode(profilesConfig.defaultProfileByMode, modeForRouting) ??
414
+ profilesConfig.defaultProfileId;
415
+ rollingSummaryProfileId = picked;
416
+ const profile = profilesConfig.profiles?.[picked];
417
+ if (profile?.config) {
418
+ rollingSummaryConfigForTurn = profile.config;
419
+ }
420
+ if (profile?.systemPrompt) {
421
+ rollingSummarySystemPromptForTurn = profile.systemPrompt;
422
+ }
423
+ }
424
+ if (conversationContext && rollingSummaryConfigForTurn) {
425
+ try {
426
+ const llmCaller = async (call) => {
427
+ const providerIdResolved = call.providerId ||
428
+ this.dependencies.modelProviderManager.getProviderForModel(call.modelId)?.providerId ||
429
+ this.dependencies.modelProviderManager.getDefaultProvider()?.providerId;
430
+ if (!providerIdResolved) {
431
+ throw new Error(`No provider resolved for rolling-summary model '${call.modelId}'.`);
432
+ }
433
+ const provider = this.dependencies.modelProviderManager.getProvider(providerIdResolved);
434
+ if (!provider) {
435
+ throw new Error(`Provider '${providerIdResolved}' not found for rolling-summary compaction.`);
436
+ }
437
+ const response = await provider.generateCompletion(call.modelId, call.messages, call.options);
438
+ const choice = response?.choices?.[0];
439
+ const responseContent = choice?.message?.content ?? choice?.text ?? '';
440
+ if (typeof responseContent === 'string')
441
+ return responseContent.trim();
442
+ if (Array.isArray(responseContent)) {
443
+ return responseContent
444
+ .map((part) => (typeof part?.text === 'string' ? part.text : ''))
445
+ .filter(Boolean)
446
+ .join('\n')
447
+ .trim();
448
+ }
449
+ return String(responseContent ?? '').trim();
450
+ };
451
+ const stateKey = this.config.rollingSummaryStateKey;
452
+ const compaction = await maybeCompactConversationMessages({
453
+ messages: conversationContext.getAllMessages(),
454
+ sessionMetadata: conversationContext.getAllMetadata(),
455
+ config: rollingSummaryConfigForTurn,
456
+ llmCaller: ({ providerId, modelId, messages, options }) => llmCaller({ providerId, modelId, messages, options }),
457
+ systemPrompt: rollingSummarySystemPromptForTurn,
458
+ stateKey,
459
+ });
460
+ rollingSummaryResult = compaction;
461
+ if (compaction.updatedSessionMetadata && Object.prototype.hasOwnProperty.call(compaction.updatedSessionMetadata, stateKey)) {
462
+ conversationContext.setMetadata(stateKey, compaction.updatedSessionMetadata[stateKey]);
463
+ }
464
+ }
465
+ catch (compactionError) {
466
+ console.warn(`AgentOSOrchestrator: Rolling summary compaction failed for stream ${agentOSStreamId} (continuing without it).`, compactionError);
467
+ }
468
+ }
469
+ if (!gmiInput.metadata) {
470
+ gmiInput.metadata = {};
471
+ }
472
+ const rollingSummaryEnabled = Boolean(rollingSummaryConfigForTurn?.enabled);
473
+ const rollingSummaryText = rollingSummaryEnabled && typeof rollingSummaryResult?.summaryText === 'string'
474
+ ? rollingSummaryResult.summaryText.trim()
475
+ : '';
476
+ gmiInput.metadata.rollingSummary =
477
+ rollingSummaryEnabled && rollingSummaryText
478
+ ? { text: rollingSummaryText, json: rollingSummaryResult?.summaryJson ?? undefined }
479
+ : null;
480
+ // --- Prompt-profile routing (concise/deep/planner/reviewer) ---
481
+ let promptProfileSelection = null;
482
+ if (conversationContext && this.config.promptProfileConfig) {
483
+ try {
484
+ const rawPrev = conversationContext.getMetadata('promptProfileState');
485
+ const previousState = rawPrev && typeof rawPrev === 'object' && typeof rawPrev.presetId === 'string'
486
+ ? rawPrev
487
+ : null;
488
+ const userMessageForRouting = gmiInput.type === GMIInteractionType.TEXT && typeof gmiInput.content === 'string'
489
+ ? gmiInput.content
490
+ : gmiInput.type === GMIInteractionType.MULTIMODAL_CONTENT
491
+ ? JSON.stringify(gmiInput.content)
492
+ : '';
493
+ const selection = selectPromptProfile(this.config.promptProfileConfig, {
494
+ conversationId: conversationContext.sessionId,
495
+ mode: modeForRouting,
496
+ userMessage: userMessageForRouting,
497
+ didCompact: Boolean(rollingSummaryResult?.didCompact),
498
+ }, previousState);
499
+ promptProfileSelection = selection.result;
500
+ conversationContext.setMetadata('promptProfileState', selection.nextState);
501
+ }
502
+ catch (routerError) {
503
+ console.warn(`AgentOSOrchestrator: Prompt-profile routing failed for stream ${agentOSStreamId} (continuing without it).`, routerError);
504
+ }
505
+ }
506
+ gmiInput.metadata.promptProfile = promptProfileSelection
507
+ ? {
508
+ id: promptProfileSelection.presetId,
509
+ systemInstructions: promptProfileSelection.systemInstructions,
510
+ reason: promptProfileSelection.reason,
511
+ }
512
+ : null;
513
+ // --- Long-term memory retrieval (user/persona/org) ---
514
+ let longTermMemoryContextText = null;
515
+ let longTermMemoryRetrievalDiagnostics;
516
+ if (conversationContext &&
517
+ this.dependencies.longTermMemoryRetriever &&
518
+ Boolean(longTermMemoryPolicy?.enabled) &&
519
+ (Boolean(longTermMemoryPolicy?.scopes?.user) ||
520
+ Boolean(longTermMemoryPolicy?.scopes?.persona) ||
521
+ Boolean(longTermMemoryPolicy?.scopes?.organization))) {
522
+ try {
523
+ const queryText = gmiInput.type === GMIInteractionType.TEXT && typeof gmiInput.content === 'string'
524
+ ? gmiInput.content.trim()
525
+ : gmiInput.type === GMIInteractionType.MULTIMODAL_CONTENT
526
+ ? JSON.stringify(gmiInput.content).trim()
527
+ : '';
528
+ const userTurnCount = conversationContext.getAllMessages().filter((m) => m?.role === MessageRole.USER).length;
529
+ const cadenceTurns = typeof this.config.promptProfileConfig?.routing?.reviewEveryNTurns === 'number'
530
+ ? Number(this.config.promptProfileConfig.routing.reviewEveryNTurns)
531
+ : 6;
532
+ const forceOnCompaction = typeof this.config.promptProfileConfig?.routing?.forceReviewOnCompaction === 'boolean'
533
+ ? Boolean(this.config.promptProfileConfig.routing.forceReviewOnCompaction)
534
+ : true;
535
+ const rawState = conversationContext.getMetadata('longTermMemoryRetrievalState');
536
+ const prevState = rawState &&
537
+ typeof rawState === 'object' &&
538
+ typeof rawState.lastReviewedUserTurn === 'number'
539
+ ? rawState
540
+ : null;
541
+ const shouldReview = !prevState ||
542
+ (cadenceTurns > 0 && userTurnCount - prevState.lastReviewedUserTurn >= cadenceTurns) ||
543
+ (forceOnCompaction && Boolean(rollingSummaryResult?.didCompact));
544
+ if (shouldReview && queryText.length > 0) {
545
+ const retrievalResult = await this.dependencies.longTermMemoryRetriever.retrieveLongTermMemory({
546
+ userId: streamContext.userId,
547
+ organizationId: organizationIdForMemory,
548
+ conversationId: streamContext.conversationId,
549
+ personaId: currentPersonaId,
550
+ mode: modeForRouting,
551
+ queryText,
552
+ memoryPolicy: longTermMemoryPolicy ?? DEFAULT_LONG_TERM_MEMORY_POLICY,
553
+ maxContextChars: 2800,
554
+ topKByScope: { user: 6, persona: 6, organization: 6 },
555
+ });
556
+ if (retrievalResult?.contextText && retrievalResult.contextText.trim()) {
557
+ longTermMemoryContextText = retrievalResult.contextText.trim();
558
+ longTermMemoryRetrievalDiagnostics = retrievalResult.diagnostics;
559
+ }
560
+ conversationContext.setMetadata('longTermMemoryRetrievalState', {
561
+ lastReviewedUserTurn: userTurnCount,
562
+ lastReviewedAt: Date.now(),
563
+ });
564
+ }
565
+ }
566
+ catch (retrievalError) {
567
+ console.warn(`AgentOSOrchestrator: Long-term memory retrieval failed for stream ${agentOSStreamId} (continuing without it).`, retrievalError);
568
+ }
569
+ }
570
+ gmiInput.metadata.longTermMemoryContext =
571
+ typeof longTermMemoryContextText === 'string' && longTermMemoryContextText.length > 0
572
+ ? longTermMemoryContextText
573
+ : null;
574
+ // Provide a durable history snapshot for prompt construction so persona switches share memory.
575
+ // When rolling-summary compaction is enabled and a summary exists, trim history to:
576
+ // - keep the configured head messages verbatim
577
+ // - keep only messages after `summaryUptoTimestamp` (unsummarized tail)
578
+ if (conversationContext) {
579
+ const excludeRoles = new Set([MessageRole.ERROR, MessageRole.THOUGHT]);
580
+ const useTrimmedHistory = rollingSummaryEnabled &&
581
+ typeof rollingSummaryResult?.summaryUptoTimestamp === 'number' &&
582
+ rollingSummaryText.length > 0;
583
+ const rawHistory = useTrimmedHistory
584
+ ? conversationContext.getAllMessages()
585
+ : conversationContext.getHistory(undefined, [MessageRole.ERROR, MessageRole.THOUGHT]);
586
+ let historyForPrompt = rawHistory.filter((m) => m && !excludeRoles.has(m.role));
587
+ const last = historyForPrompt[historyForPrompt.length - 1];
588
+ if (last?.role === MessageRole.USER) {
589
+ const content = typeof last.content === 'string' ? last.content.trim() : '';
590
+ const inbound = gmiInput.type === GMIInteractionType.TEXT && typeof gmiInput.content === 'string'
591
+ ? gmiInput.content.trim()
592
+ : gmiInput.type === GMIInteractionType.MULTIMODAL_CONTENT
593
+ ? JSON.stringify(gmiInput.content).trim()
594
+ : '';
595
+ if (content && inbound && content === inbound) {
596
+ historyForPrompt = historyForPrompt.slice(0, -1);
597
+ }
598
+ }
599
+ if (useTrimmedHistory) {
600
+ const headCount = Math.max(0, rollingSummaryConfigForTurn?.headMessagesToKeep ?? 0);
601
+ const head = historyForPrompt.slice(0, Math.min(headCount, historyForPrompt.length));
602
+ const afterSummary = historyForPrompt.filter((m) => m && m.timestamp > rollingSummaryResult.summaryUptoTimestamp);
603
+ const merged = [];
604
+ const seen = new Set();
605
+ for (const msg of [...head, ...afterSummary]) {
606
+ const id = typeof msg?.id === 'string' ? msg.id : '';
607
+ if (!id || seen.has(id))
608
+ continue;
609
+ seen.add(id);
610
+ merged.push(msg);
611
+ }
612
+ historyForPrompt = merged;
613
+ }
614
+ gmiInput.metadata.conversationHistoryForPrompt = historyForPrompt;
615
+ }
616
+ // Persist any compaction/router metadata updates prior to the main LLM call.
617
+ if (this.config.enableConversationalPersistence && conversationContext) {
618
+ try {
619
+ await this.dependencies.conversationManager.saveConversation(conversationContext);
620
+ }
621
+ catch (metadataPersistError) {
622
+ console.warn(`AgentOSOrchestrator: Failed to persist conversation metadata updates for stream ${agentOSStreamId}.`, metadataPersistError);
623
+ }
624
+ }
625
+ // Best-effort: persist structured rolling memory (`memory_json`) to an external store for retrieval.
626
+ if (rollingSummaryEnabled &&
627
+ rollingSummaryResult?.didCompact &&
628
+ typeof rollingSummaryResult.summaryText === 'string' &&
629
+ this.dependencies.rollingSummaryMemorySink &&
630
+ Boolean(longTermMemoryPolicy?.enabled) &&
631
+ hasAnyLongTermMemoryScope(longTermMemoryPolicy ?? DEFAULT_LONG_TERM_MEMORY_POLICY)) {
632
+ const update = {
633
+ userId: streamContext.userId,
634
+ organizationId: organizationIdForMemory,
635
+ sessionId: streamContext.sessionId,
636
+ conversationId: streamContext.conversationId,
637
+ personaId: currentPersonaId,
638
+ mode: modeForRouting,
639
+ profileId: rollingSummaryProfileId,
640
+ memoryPolicy: longTermMemoryPolicy ?? undefined,
641
+ summaryText: rollingSummaryResult.summaryText,
642
+ summaryJson: rollingSummaryResult.summaryJson ?? null,
643
+ summaryUptoTimestamp: rollingSummaryResult.summaryUptoTimestamp ?? null,
644
+ summaryUpdatedAt: rollingSummaryResult.summaryUpdatedAt ?? null,
645
+ };
646
+ void this.dependencies.rollingSummaryMemorySink
647
+ .upsertRollingSummaryMemory(update)
648
+ .catch((error) => {
649
+ console.warn(`AgentOSOrchestrator: Rolling summary sink failed for stream ${agentOSStreamId} (continuing).`, error);
650
+ });
651
+ }
652
+ // Emit routing + memory metadata as a first-class chunk for clients.
653
+ await this.pushChunkToStream(agentOSStreamId, AgentOSResponseChunkType.METADATA_UPDATE, gmiInstanceIdForChunks, currentPersonaId, false, {
654
+ updates: {
655
+ promptProfile: promptProfileSelection,
656
+ organizationId: organizationIdForMemory ?? null,
657
+ longTermMemoryPolicy,
658
+ longTermMemoryRetrieval: longTermMemoryContextText
659
+ ? {
660
+ didRetrieve: true,
661
+ contextChars: longTermMemoryContextText.length,
662
+ diagnostics: longTermMemoryRetrievalDiagnostics,
663
+ }
664
+ : { didRetrieve: false },
665
+ rollingSummary: rollingSummaryResult
666
+ ? {
667
+ profileId: rollingSummaryProfileId,
668
+ enabled: rollingSummaryResult.enabled,
669
+ didCompact: rollingSummaryResult.didCompact,
670
+ summaryText: rollingSummaryResult.summaryText,
671
+ summaryJson: rollingSummaryResult.summaryJson,
672
+ summaryUptoTimestamp: rollingSummaryResult.summaryUptoTimestamp,
673
+ summaryUpdatedAt: rollingSummaryResult.summaryUpdatedAt,
674
+ reason: rollingSummaryResult.reason,
675
+ }
676
+ : null,
677
+ },
678
+ });
275
679
  let currentToolCallIteration = 0;
276
680
  let continueProcessing = true;
277
681
  let lastGMIOutput; // To store the result from handleToolResult or final processTurnStream result
@@ -338,9 +742,6 @@ export class AgentOSOrchestrator {
338
742
  // This should use the true GMIOutput returned by GMI (either initial or after tool handling)
339
743
  // For now, this relies on the fact that the last interaction with GMI (processTurnStream or handleToolResult)
340
744
  // updated the conversation context, and we generate a final response summary.
341
- if (this.config.enableConversationalPersistence && conversationContext) {
342
- await this.dependencies.conversationManager.saveConversation(conversationContext);
343
- }
344
745
  // Send a final response chunk if not already implicitly sent by an error or final GMI chunk transform.
345
746
  // This part needs careful consideration of what `lastGMIOutput` represents here.
346
747
  // It should represent the *actual* TReturn from the GMI's processing.
@@ -349,8 +750,35 @@ export class AgentOSOrchestrator {
349
750
  isFinal: true,
350
751
  responseText: gmi ? 'Processing complete.' : 'Processing ended.',
351
752
  };
753
+ // Persist assistant output into ConversationContext for durable memory / prompt reconstruction.
754
+ if (this.config.enableConversationalPersistence && conversationContext) {
755
+ try {
756
+ if (typeof finalGMIStateForResponse.responseText === 'string' && finalGMIStateForResponse.responseText.trim()) {
757
+ conversationContext.addMessage({
758
+ role: MessageRole.ASSISTANT,
759
+ content: finalGMIStateForResponse.responseText,
760
+ metadata: { agentPersonaId: currentPersonaId, source: 'agentos_output' },
761
+ });
762
+ }
763
+ else if (finalGMIStateForResponse.toolCalls && finalGMIStateForResponse.toolCalls.length > 0) {
764
+ conversationContext.addMessage({
765
+ role: MessageRole.ASSISTANT,
766
+ content: null,
767
+ tool_calls: finalGMIStateForResponse.toolCalls,
768
+ metadata: { agentPersonaId: currentPersonaId, source: 'agentos_output_tool_calls' },
769
+ });
770
+ }
771
+ await this.dependencies.conversationManager.saveConversation(conversationContext);
772
+ }
773
+ catch (persistError) {
774
+ console.warn(`AgentOSOrchestrator: Failed to persist assistant output to ConversationContext for stream ${agentOSStreamId}.`, persistError);
775
+ }
776
+ }
352
777
  await this.pushChunkToStream(agentOSStreamId, AgentOSResponseChunkType.FINAL_RESPONSE, gmiInstanceIdForChunks, currentPersonaId, true, {
353
778
  finalResponseText: finalGMIStateForResponse.responseText ?? null,
779
+ finalResponseTextPlain: typeof finalGMIStateForResponse.responseText === 'string'
780
+ ? renderPlainText(finalGMIStateForResponse.responseText)
781
+ : null,
354
782
  finalToolCalls: finalGMIStateForResponse.toolCalls,
355
783
  finalUiCommands: finalGMIStateForResponse.uiCommands,
356
784
  audioOutput: finalGMIStateForResponse.audioOutput,
@@ -411,6 +839,22 @@ export class AgentOSOrchestrator {
411
839
  try {
412
840
  // Emit the tool result itself as a chunk
413
841
  await this.pushChunkToStream(agentOSStreamId, AgentOSResponseChunkType.TOOL_RESULT_EMISSION, gmiInstanceIdForChunks, personaId, false, { toolCallId, toolName, toolResult: toolOutput, isSuccess, errorMessage });
842
+ // Persist tool result into ConversationContext for durable memory / prompt reconstruction.
843
+ if (this.config.enableConversationalPersistence && conversationContext) {
844
+ try {
845
+ conversationContext.addMessage({
846
+ role: MessageRole.TOOL,
847
+ content: typeof toolOutput === 'string' ? toolOutput : JSON.stringify(toolOutput),
848
+ tool_call_id: toolCallId,
849
+ name: toolName,
850
+ metadata: { agentPersonaId: personaId, source: 'agentos_tool_result', isSuccess },
851
+ });
852
+ await this.dependencies.conversationManager.saveConversation(conversationContext);
853
+ }
854
+ catch (persistError) {
855
+ console.warn(`AgentOSOrchestrator: Failed to persist tool result to ConversationContext for stream ${agentOSStreamId}.`, persistError);
856
+ }
857
+ }
414
858
  // GMI processes the tool result and gives a *final output for that step*
415
859
  const gmiOutputAfterTool = await gmi.handleToolResult(toolCallId, toolName, toolResultPayload, userId, userApiKeys || {});
416
860
  // Process the GMIOutput (which is not a stream of chunks)
@@ -423,7 +867,27 @@ export class AgentOSOrchestrator {
423
867
  }
424
868
  else if (gmiOutputAfterTool.isFinal) {
425
869
  if (this.config.enableConversationalPersistence && conversationContext) {
426
- await this.dependencies.conversationManager.saveConversation(conversationContext);
870
+ try {
871
+ if (typeof gmiOutputAfterTool.responseText === 'string' && gmiOutputAfterTool.responseText.trim()) {
872
+ conversationContext.addMessage({
873
+ role: MessageRole.ASSISTANT,
874
+ content: gmiOutputAfterTool.responseText,
875
+ metadata: { agentPersonaId: personaId, source: 'agentos_output' },
876
+ });
877
+ }
878
+ else if (gmiOutputAfterTool.toolCalls && gmiOutputAfterTool.toolCalls.length > 0) {
879
+ conversationContext.addMessage({
880
+ role: MessageRole.ASSISTANT,
881
+ content: null,
882
+ tool_calls: gmiOutputAfterTool.toolCalls,
883
+ metadata: { agentPersonaId: personaId, source: 'agentos_output_tool_calls' },
884
+ });
885
+ }
886
+ await this.dependencies.conversationManager.saveConversation(conversationContext);
887
+ }
888
+ catch (persistError) {
889
+ console.warn(`AgentOSOrchestrator: Failed to persist assistant output after tool result for stream ${agentOSStreamId}.`, persistError);
890
+ }
427
891
  }
428
892
  // If it's final and no more tool calls, the interaction for this GMI processing cycle might be done.
429
893
  // Push a final response marker or the already pushed final data from processGMIOutput takes precedence.