@robota-sdk/agent-core 3.0.0-beta.8 → 3.0.0-beta.81
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.
- package/CHANGELOG.md +844 -0
- package/LICENSE +661 -21
- package/README.md +153 -26
- package/dist/browser/bounded-output-DpjpS98g.js +2 -0
- package/dist/browser/bounded-output-DpjpS98g.js.map +1 -0
- package/dist/browser/command-executor-cI7XJ374.js +2 -0
- package/dist/browser/command-executor-cI7XJ374.js.map +1 -0
- package/dist/browser/http-executor-CHy6UeBU.js +2 -0
- package/dist/browser/http-executor-CHy6UeBU.js.map +1 -0
- package/dist/browser/index.d.ts +6381 -3394
- package/dist/browser/index.d.ts.map +1 -0
- package/dist/browser/index.js +13 -5
- package/dist/browser/index.js.map +1 -0
- package/dist/browser/verdict-decoder-Dk_w2NG9.js +2 -0
- package/dist/browser/verdict-decoder-Dk_w2NG9.js.map +1 -0
- package/dist/node/bounded-output-DpjpS98g.js +2 -0
- package/dist/node/bounded-output-DpjpS98g.js.map +1 -0
- package/dist/node/command-executor-Aat_q7P2.cjs +1 -0
- package/dist/node/command-executor-DV-H2oD6.js +2 -0
- package/dist/node/command-executor-DV-H2oD6.js.map +1 -0
- package/dist/node/http-executor-71JiIdFP.cjs +1 -0
- package/dist/node/http-executor-cWzI2svn.js +2 -0
- package/dist/node/http-executor-cWzI2svn.js.map +1 -0
- package/dist/node/index-CiFlpr7-.d.cts +6893 -0
- package/dist/node/index-CiFlpr7-.d.cts.map +1 -0
- package/dist/node/index-DFlMw376.d.ts +6893 -0
- package/dist/node/index-DFlMw376.d.ts.map +1 -0
- package/dist/node/index.cjs +12 -5
- package/dist/node/index.d.cts +3 -4238
- package/dist/node/index.d.ts +3 -4238
- package/dist/node/index.js +13 -5
- package/dist/node/index.js.map +1 -0
- package/dist/node/node.cjs +1 -0
- package/dist/node/node.d.cts +236 -0
- package/dist/node/node.d.cts.map +1 -0
- package/dist/node/node.d.ts +236 -0
- package/dist/node/node.d.ts.map +1 -0
- package/dist/node/node.js +2 -0
- package/dist/node/node.js.map +1 -0
- package/dist/node/project-tool-schema-DrDjGKnH.cjs +1 -0
- package/dist/node/project-tool-schema-_UKfY7yO.js +2 -0
- package/dist/node/project-tool-schema-_UKfY7yO.js.map +1 -0
- package/dist/node/rolldown-runtime-DK3Fl9T5.js +1 -0
- package/dist/node/rolldown-runtime-DWNI8pZO.cjs +1 -0
- package/dist/node/testing/index.cjs +1 -0
- package/dist/node/testing/index.d.cts +96 -0
- package/dist/node/testing/index.d.cts.map +1 -0
- package/dist/node/testing/index.d.ts +96 -0
- package/dist/node/testing/index.d.ts.map +1 -0
- package/dist/node/testing/index.js +2 -0
- package/dist/node/testing/index.js.map +1 -0
- package/dist/node/types-gNrckgFE.d.cts +335 -0
- package/dist/node/types-gNrckgFE.d.cts.map +1 -0
- package/dist/node/types-gNrckgFE.d.ts +335 -0
- package/dist/node/types-gNrckgFE.d.ts.map +1 -0
- package/dist/node/verdict-decoder-Dk_w2NG9.js +2 -0
- package/dist/node/verdict-decoder-Dk_w2NG9.js.map +1 -0
- package/dist/node/verdict-decoder-Estx9MtY.cjs +1 -0
- package/package.json +89 -23
- package/dist/abstracts/abstract-agent.d.ts +0 -56
- package/dist/abstracts/abstract-agent.d.ts.map +0 -1
- package/dist/abstracts/abstract-agent.js +0 -55
- package/dist/abstracts/abstract-agent.js.map +0 -1
- package/dist/abstracts/abstract-ai-provider.d.ts +0 -187
- package/dist/abstracts/abstract-ai-provider.d.ts.map +0 -1
- package/dist/abstracts/abstract-ai-provider.js +0 -252
- package/dist/abstracts/abstract-ai-provider.js.map +0 -1
- package/dist/abstracts/abstract-executor.d.ts +0 -110
- package/dist/abstracts/abstract-executor.d.ts.map +0 -1
- package/dist/abstracts/abstract-executor.js +0 -156
- package/dist/abstracts/abstract-executor.js.map +0 -1
- package/dist/abstracts/abstract-manager.d.ts +0 -42
- package/dist/abstracts/abstract-manager.d.ts.map +0 -1
- package/dist/abstracts/abstract-manager.js +0 -49
- package/dist/abstracts/abstract-manager.js.map +0 -1
- package/dist/abstracts/abstract-module.d.ts +0 -365
- package/dist/abstracts/abstract-module.d.ts.map +0 -1
- package/dist/abstracts/abstract-module.js +0 -474
- package/dist/abstracts/abstract-module.js.map +0 -1
- package/dist/abstracts/abstract-plugin.d.ts +0 -369
- package/dist/abstracts/abstract-plugin.d.ts.map +0 -1
- package/dist/abstracts/abstract-plugin.js +0 -258
- package/dist/abstracts/abstract-plugin.js.map +0 -1
- package/dist/abstracts/abstract-tool.d.ts +0 -175
- package/dist/abstracts/abstract-tool.d.ts.map +0 -1
- package/dist/abstracts/abstract-tool.js +0 -140
- package/dist/abstracts/abstract-tool.js.map +0 -1
- package/dist/abstracts/abstract-workflow-converter.d.ts +0 -136
- package/dist/abstracts/abstract-workflow-converter.d.ts.map +0 -1
- package/dist/abstracts/abstract-workflow-converter.js +0 -252
- package/dist/abstracts/abstract-workflow-converter.js.map +0 -1
- package/dist/abstracts/abstract-workflow-validator.d.ts +0 -203
- package/dist/abstracts/abstract-workflow-validator.d.ts.map +0 -1
- package/dist/abstracts/abstract-workflow-validator.js +0 -447
- package/dist/abstracts/abstract-workflow-validator.js.map +0 -1
- package/dist/abstracts/index.d.ts +0 -6
- package/dist/abstracts/index.d.ts.map +0 -1
- package/dist/abstracts/index.js +0 -9
- package/dist/abstracts/index.js.map +0 -1
- package/dist/agents/constants.d.ts +0 -23
- package/dist/agents/constants.d.ts.map +0 -1
- package/dist/agents/constants.js +0 -22
- package/dist/agents/constants.js.map +0 -1
- package/dist/agents/index.d.ts +0 -1
- package/dist/agents/index.d.ts.map +0 -1
- package/dist/agents/index.js +0 -4
- package/dist/agents/index.js.map +0 -1
- package/dist/agents/robota.test.d.ts +0 -2
- package/dist/agents/robota.test.d.ts.map +0 -1
- package/dist/agents/robota.test.js +0 -416
- package/dist/agents/robota.test.js.map +0 -1
- package/dist/browser/builtin-templates.json +0 -107
- package/dist/core/robota.d.ts +0 -694
- package/dist/core/robota.d.ts.map +0 -1
- package/dist/core/robota.js +0 -1277
- package/dist/core/robota.js.map +0 -1
- package/dist/executors/local-executor.d.ts +0 -96
- package/dist/executors/local-executor.d.ts.map +0 -1
- package/dist/executors/local-executor.js +0 -197
- package/dist/executors/local-executor.js.map +0 -1
- package/dist/executors/local-executor.test.d.ts +0 -2
- package/dist/executors/local-executor.test.d.ts.map +0 -1
- package/dist/executors/local-executor.test.js +0 -192
- package/dist/executors/local-executor.test.js.map +0 -1
- package/dist/index.d.ts +0 -274
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js +0 -235
- package/dist/index.js.map +0 -1
- package/dist/interfaces/agent.d.ts +0 -198
- package/dist/interfaces/agent.d.ts.map +0 -1
- package/dist/interfaces/agent.js +0 -2
- package/dist/interfaces/agent.js.map +0 -1
- package/dist/interfaces/event-service.d.ts +0 -79
- package/dist/interfaces/event-service.d.ts.map +0 -1
- package/dist/interfaces/event-service.js +0 -2
- package/dist/interfaces/event-service.js.map +0 -1
- package/dist/interfaces/executor.d.ts +0 -128
- package/dist/interfaces/executor.d.ts.map +0 -1
- package/dist/interfaces/executor.js +0 -2
- package/dist/interfaces/executor.js.map +0 -1
- package/dist/interfaces/history-module.d.ts +0 -19
- package/dist/interfaces/history-module.d.ts.map +0 -1
- package/dist/interfaces/history-module.js +0 -2
- package/dist/interfaces/history-module.js.map +0 -1
- package/dist/interfaces/index.d.ts +0 -13
- package/dist/interfaces/index.d.ts.map +0 -1
- package/dist/interfaces/index.js +0 -4
- package/dist/interfaces/index.js.map +0 -1
- package/dist/interfaces/manager.d.ts +0 -142
- package/dist/interfaces/manager.d.ts.map +0 -1
- package/dist/interfaces/manager.js +0 -2
- package/dist/interfaces/manager.js.map +0 -1
- package/dist/interfaces/messages.d.ts +0 -75
- package/dist/interfaces/messages.d.ts.map +0 -1
- package/dist/interfaces/messages.js +0 -29
- package/dist/interfaces/messages.js.map +0 -1
- package/dist/interfaces/progress-reporting.d.ts +0 -86
- package/dist/interfaces/progress-reporting.d.ts.map +0 -1
- package/dist/interfaces/progress-reporting.js +0 -37
- package/dist/interfaces/progress-reporting.js.map +0 -1
- package/dist/interfaces/provider.d.ts +0 -217
- package/dist/interfaces/provider.d.ts.map +0 -1
- package/dist/interfaces/provider.js +0 -2
- package/dist/interfaces/provider.js.map +0 -1
- package/dist/interfaces/service.d.ts +0 -205
- package/dist/interfaces/service.d.ts.map +0 -1
- package/dist/interfaces/service.js +0 -6
- package/dist/interfaces/service.js.map +0 -1
- package/dist/interfaces/tool.d.ts +0 -248
- package/dist/interfaces/tool.d.ts.map +0 -1
- package/dist/interfaces/tool.js +0 -2
- package/dist/interfaces/tool.js.map +0 -1
- package/dist/interfaces/types.d.ts +0 -71
- package/dist/interfaces/types.d.ts.map +0 -1
- package/dist/interfaces/types.js +0 -33
- package/dist/interfaces/types.js.map +0 -1
- package/dist/interfaces/workflow-converter.d.ts +0 -193
- package/dist/interfaces/workflow-converter.d.ts.map +0 -1
- package/dist/interfaces/workflow-converter.js +0 -11
- package/dist/interfaces/workflow-converter.js.map +0 -1
- package/dist/interfaces/workflow-validator.d.ts +0 -209
- package/dist/interfaces/workflow-validator.d.ts.map +0 -1
- package/dist/interfaces/workflow-validator.js +0 -16
- package/dist/interfaces/workflow-validator.js.map +0 -1
- package/dist/managers/agent-factory.d.ts +0 -132
- package/dist/managers/agent-factory.d.ts.map +0 -1
- package/dist/managers/agent-factory.js +0 -284
- package/dist/managers/agent-factory.js.map +0 -1
- package/dist/managers/agent-factory.test.d.ts +0 -2
- package/dist/managers/agent-factory.test.d.ts.map +0 -1
- package/dist/managers/agent-factory.test.js +0 -249
- package/dist/managers/agent-factory.test.js.map +0 -1
- package/dist/managers/agent-templates.d.ts +0 -84
- package/dist/managers/agent-templates.d.ts.map +0 -1
- package/dist/managers/agent-templates.js +0 -159
- package/dist/managers/agent-templates.js.map +0 -1
- package/dist/managers/ai-provider-manager.d.ts +0 -80
- package/dist/managers/ai-provider-manager.d.ts.map +0 -1
- package/dist/managers/ai-provider-manager.js +0 -226
- package/dist/managers/ai-provider-manager.js.map +0 -1
- package/dist/managers/conversation-history-manager.d.ts +0 -455
- package/dist/managers/conversation-history-manager.d.ts.map +0 -1
- package/dist/managers/conversation-history-manager.js +0 -578
- package/dist/managers/conversation-history-manager.js.map +0 -1
- package/dist/managers/conversation-history-manager.test.d.ts +0 -2
- package/dist/managers/conversation-history-manager.test.d.ts.map +0 -1
- package/dist/managers/conversation-history-manager.test.js +0 -374
- package/dist/managers/conversation-history-manager.test.js.map +0 -1
- package/dist/managers/index.d.ts +0 -8
- package/dist/managers/index.d.ts.map +0 -1
- package/dist/managers/index.js +0 -8
- package/dist/managers/index.js.map +0 -1
- package/dist/managers/module-registry.d.ts +0 -161
- package/dist/managers/module-registry.d.ts.map +0 -1
- package/dist/managers/module-registry.js +0 -519
- package/dist/managers/module-registry.js.map +0 -1
- package/dist/managers/module-type-registry.d.ts +0 -113
- package/dist/managers/module-type-registry.d.ts.map +0 -1
- package/dist/managers/module-type-registry.js +0 -439
- package/dist/managers/module-type-registry.js.map +0 -1
- package/dist/managers/plugins.d.ts +0 -166
- package/dist/managers/plugins.d.ts.map +0 -1
- package/dist/managers/plugins.js +0 -339
- package/dist/managers/plugins.js.map +0 -1
- package/dist/managers/tool-manager.d.ts +0 -70
- package/dist/managers/tool-manager.d.ts.map +0 -1
- package/dist/managers/tool-manager.js +0 -138
- package/dist/managers/tool-manager.js.map +0 -1
- package/dist/managers/tool-manager.test.d.ts +0 -2
- package/dist/managers/tool-manager.test.d.ts.map +0 -1
- package/dist/managers/tool-manager.test.js +0 -186
- package/dist/managers/tool-manager.test.js.map +0 -1
- package/dist/node/builtin-templates.json +0 -107
- package/dist/plugins/conversation-history/conversation-history-plugin.d.ts +0 -67
- package/dist/plugins/conversation-history/conversation-history-plugin.d.ts.map +0 -1
- package/dist/plugins/conversation-history/conversation-history-plugin.js +0 -270
- package/dist/plugins/conversation-history/conversation-history-plugin.js.map +0 -1
- package/dist/plugins/conversation-history/index.d.ts +0 -3
- package/dist/plugins/conversation-history/index.d.ts.map +0 -1
- package/dist/plugins/conversation-history/index.js +0 -2
- package/dist/plugins/conversation-history/index.js.map +0 -1
- package/dist/plugins/conversation-history/storages/database-storage.d.ts +0 -19
- package/dist/plugins/conversation-history/storages/database-storage.d.ts.map +0 -1
- package/dist/plugins/conversation-history/storages/database-storage.js +0 -94
- package/dist/plugins/conversation-history/storages/database-storage.js.map +0 -1
- package/dist/plugins/conversation-history/storages/file-storage.d.ts +0 -15
- package/dist/plugins/conversation-history/storages/file-storage.d.ts.map +0 -1
- package/dist/plugins/conversation-history/storages/file-storage.js +0 -94
- package/dist/plugins/conversation-history/storages/file-storage.js.map +0 -1
- package/dist/plugins/conversation-history/storages/index.d.ts +0 -4
- package/dist/plugins/conversation-history/storages/index.d.ts.map +0 -1
- package/dist/plugins/conversation-history/storages/index.js +0 -4
- package/dist/plugins/conversation-history/storages/index.js.map +0 -1
- package/dist/plugins/conversation-history/storages/memory-storage.d.ts +0 -15
- package/dist/plugins/conversation-history/storages/memory-storage.d.ts.map +0 -1
- package/dist/plugins/conversation-history/storages/memory-storage.js +0 -33
- package/dist/plugins/conversation-history/storages/memory-storage.js.map +0 -1
- package/dist/plugins/conversation-history/types.d.ts +0 -61
- package/dist/plugins/conversation-history/types.d.ts.map +0 -1
- package/dist/plugins/conversation-history/types.js +0 -2
- package/dist/plugins/conversation-history/types.js.map +0 -1
- package/dist/plugins/error-handling/context-adapter.d.ts +0 -30
- package/dist/plugins/error-handling/context-adapter.d.ts.map +0 -1
- package/dist/plugins/error-handling/context-adapter.js +0 -41
- package/dist/plugins/error-handling/context-adapter.js.map +0 -1
- package/dist/plugins/error-handling/error-handling-plugin.d.ts +0 -49
- package/dist/plugins/error-handling/error-handling-plugin.d.ts.map +0 -1
- package/dist/plugins/error-handling/error-handling-plugin.js +0 -229
- package/dist/plugins/error-handling/error-handling-plugin.js.map +0 -1
- package/dist/plugins/error-handling/index.d.ts +0 -10
- package/dist/plugins/error-handling/index.d.ts.map +0 -1
- package/dist/plugins/error-handling/index.js +0 -10
- package/dist/plugins/error-handling/index.js.map +0 -1
- package/dist/plugins/error-handling/types.d.ts +0 -73
- package/dist/plugins/error-handling/types.d.ts.map +0 -1
- package/dist/plugins/error-handling/types.js +0 -14
- package/dist/plugins/error-handling/types.js.map +0 -1
- package/dist/plugins/event-emitter/metrics.d.ts +0 -17
- package/dist/plugins/event-emitter/metrics.d.ts.map +0 -1
- package/dist/plugins/event-emitter/metrics.js +0 -17
- package/dist/plugins/event-emitter/metrics.js.map +0 -1
- package/dist/plugins/event-emitter/types.d.ts +0 -112
- package/dist/plugins/event-emitter/types.d.ts.map +0 -1
- package/dist/plugins/event-emitter/types.js +0 -65
- package/dist/plugins/event-emitter/types.js.map +0 -1
- package/dist/plugins/event-emitter-plugin.d.ts +0 -222
- package/dist/plugins/event-emitter-plugin.d.ts.map +0 -1
- package/dist/plugins/event-emitter-plugin.js +0 -432
- package/dist/plugins/event-emitter-plugin.js.map +0 -1
- package/dist/plugins/event-emitter-plugin.test.d.ts +0 -2
- package/dist/plugins/event-emitter-plugin.test.d.ts.map +0 -1
- package/dist/plugins/event-emitter-plugin.test.js +0 -94
- package/dist/plugins/event-emitter-plugin.test.js.map +0 -1
- package/dist/plugins/execution/execution-analytics-plugin.d.ts +0 -129
- package/dist/plugins/execution/execution-analytics-plugin.d.ts.map +0 -1
- package/dist/plugins/execution/execution-analytics-plugin.js +0 -517
- package/dist/plugins/execution/execution-analytics-plugin.js.map +0 -1
- package/dist/plugins/execution/index.d.ts +0 -3
- package/dist/plugins/execution/index.d.ts.map +0 -1
- package/dist/plugins/execution/index.js +0 -2
- package/dist/plugins/execution/index.js.map +0 -1
- package/dist/plugins/execution/types.d.ts +0 -90
- package/dist/plugins/execution/types.d.ts.map +0 -1
- package/dist/plugins/execution/types.js +0 -2
- package/dist/plugins/execution/types.js.map +0 -1
- package/dist/plugins/index.d.ts +0 -10
- package/dist/plugins/index.d.ts.map +0 -1
- package/dist/plugins/index.js +0 -11
- package/dist/plugins/index.js.map +0 -1
- package/dist/plugins/limits/types.d.ts +0 -61
- package/dist/plugins/limits/types.d.ts.map +0 -1
- package/dist/plugins/limits/types.js +0 -2
- package/dist/plugins/limits/types.js.map +0 -1
- package/dist/plugins/limits-plugin.d.ts +0 -113
- package/dist/plugins/limits-plugin.d.ts.map +0 -1
- package/dist/plugins/limits-plugin.js +0 -380
- package/dist/plugins/limits-plugin.js.map +0 -1
- package/dist/plugins/logging/formatters.d.ts +0 -14
- package/dist/plugins/logging/formatters.d.ts.map +0 -1
- package/dist/plugins/logging/formatters.js +0 -24
- package/dist/plugins/logging/formatters.js.map +0 -1
- package/dist/plugins/logging/index.d.ts +0 -3
- package/dist/plugins/logging/index.d.ts.map +0 -1
- package/dist/plugins/logging/index.js +0 -2
- package/dist/plugins/logging/index.js.map +0 -1
- package/dist/plugins/logging/logging-plugin.d.ts +0 -91
- package/dist/plugins/logging/logging-plugin.d.ts.map +0 -1
- package/dist/plugins/logging/logging-plugin.js +0 -335
- package/dist/plugins/logging/logging-plugin.js.map +0 -1
- package/dist/plugins/logging/storages/console-storage.d.ts +0 -14
- package/dist/plugins/logging/storages/console-storage.d.ts.map +0 -1
- package/dist/plugins/logging/storages/console-storage.js +0 -38
- package/dist/plugins/logging/storages/console-storage.js.map +0 -1
- package/dist/plugins/logging/storages/file-storage.d.ts +0 -14
- package/dist/plugins/logging/storages/file-storage.d.ts.map +0 -1
- package/dist/plugins/logging/storages/file-storage.js +0 -41
- package/dist/plugins/logging/storages/file-storage.js.map +0 -1
- package/dist/plugins/logging/storages/index.d.ts +0 -5
- package/dist/plugins/logging/storages/index.d.ts.map +0 -1
- package/dist/plugins/logging/storages/index.js +0 -5
- package/dist/plugins/logging/storages/index.js.map +0 -1
- package/dist/plugins/logging/storages/remote-storage.d.ts +0 -20
- package/dist/plugins/logging/storages/remote-storage.d.ts.map +0 -1
- package/dist/plugins/logging/storages/remote-storage.js +0 -61
- package/dist/plugins/logging/storages/remote-storage.js.map +0 -1
- package/dist/plugins/logging/storages/silent-storage.d.ts +0 -10
- package/dist/plugins/logging/storages/silent-storage.d.ts.map +0 -1
- package/dist/plugins/logging/storages/silent-storage.js +0 -15
- package/dist/plugins/logging/storages/silent-storage.js.map +0 -1
- package/dist/plugins/logging/types.d.ts +0 -84
- package/dist/plugins/logging/types.d.ts.map +0 -1
- package/dist/plugins/logging/types.js +0 -2
- package/dist/plugins/logging/types.js.map +0 -1
- package/dist/plugins/performance/collectors/system-metrics-collector.d.ts +0 -12
- package/dist/plugins/performance/collectors/system-metrics-collector.d.ts.map +0 -1
- package/dist/plugins/performance/collectors/system-metrics-collector.js +0 -65
- package/dist/plugins/performance/collectors/system-metrics-collector.js.map +0 -1
- package/dist/plugins/performance/index.d.ts +0 -5
- package/dist/plugins/performance/index.d.ts.map +0 -1
- package/dist/plugins/performance/index.js +0 -4
- package/dist/plugins/performance/index.js.map +0 -1
- package/dist/plugins/performance/performance-plugin.d.ts +0 -49
- package/dist/plugins/performance/performance-plugin.d.ts.map +0 -1
- package/dist/plugins/performance/performance-plugin.js +0 -293
- package/dist/plugins/performance/performance-plugin.js.map +0 -1
- package/dist/plugins/performance/storages/index.d.ts +0 -2
- package/dist/plugins/performance/storages/index.d.ts.map +0 -1
- package/dist/plugins/performance/storages/index.js +0 -4
- package/dist/plugins/performance/storages/index.js.map +0 -1
- package/dist/plugins/performance/storages/memory-storage.d.ts +0 -19
- package/dist/plugins/performance/storages/memory-storage.d.ts.map +0 -1
- package/dist/plugins/performance/storages/memory-storage.js +0 -69
- package/dist/plugins/performance/storages/memory-storage.js.map +0 -1
- package/dist/plugins/performance/types.d.ts +0 -154
- package/dist/plugins/performance/types.d.ts.map +0 -1
- package/dist/plugins/performance/types.js +0 -2
- package/dist/plugins/performance/types.js.map +0 -1
- package/dist/plugins/usage/aggregate-usage-stats.d.ts +0 -12
- package/dist/plugins/usage/aggregate-usage-stats.d.ts.map +0 -1
- package/dist/plugins/usage/aggregate-usage-stats.js +0 -115
- package/dist/plugins/usage/aggregate-usage-stats.js.map +0 -1
- package/dist/plugins/usage/index.d.ts +0 -5
- package/dist/plugins/usage/index.d.ts.map +0 -1
- package/dist/plugins/usage/index.js +0 -4
- package/dist/plugins/usage/index.js.map +0 -1
- package/dist/plugins/usage/storages/file-storage.d.ts +0 -22
- package/dist/plugins/usage/storages/file-storage.d.ts.map +0 -1
- package/dist/plugins/usage/storages/file-storage.js +0 -111
- package/dist/plugins/usage/storages/file-storage.js.map +0 -1
- package/dist/plugins/usage/storages/index.d.ts +0 -5
- package/dist/plugins/usage/storages/index.d.ts.map +0 -1
- package/dist/plugins/usage/storages/index.js +0 -5
- package/dist/plugins/usage/storages/index.js.map +0 -1
- package/dist/plugins/usage/storages/memory-storage.d.ts +0 -22
- package/dist/plugins/usage/storages/memory-storage.d.ts.map +0 -1
- package/dist/plugins/usage/storages/memory-storage.js +0 -42
- package/dist/plugins/usage/storages/memory-storage.js.map +0 -1
- package/dist/plugins/usage/storages/remote-storage.d.ts +0 -26
- package/dist/plugins/usage/storages/remote-storage.d.ts.map +0 -1
- package/dist/plugins/usage/storages/remote-storage.js +0 -115
- package/dist/plugins/usage/storages/remote-storage.js.map +0 -1
- package/dist/plugins/usage/storages/silent-storage.d.ts +0 -19
- package/dist/plugins/usage/storages/silent-storage.d.ts.map +0 -1
- package/dist/plugins/usage/storages/silent-storage.js +0 -26
- package/dist/plugins/usage/storages/silent-storage.js.map +0 -1
- package/dist/plugins/usage/types.d.ts +0 -127
- package/dist/plugins/usage/types.d.ts.map +0 -1
- package/dist/plugins/usage/types.js +0 -2
- package/dist/plugins/usage/types.js.map +0 -1
- package/dist/plugins/usage/usage-plugin.d.ts +0 -67
- package/dist/plugins/usage/usage-plugin.d.ts.map +0 -1
- package/dist/plugins/usage/usage-plugin.js +0 -309
- package/dist/plugins/usage/usage-plugin.js.map +0 -1
- package/dist/plugins/webhook/http-client.d.ts +0 -30
- package/dist/plugins/webhook/http-client.d.ts.map +0 -1
- package/dist/plugins/webhook/http-client.js +0 -110
- package/dist/plugins/webhook/http-client.js.map +0 -1
- package/dist/plugins/webhook/index.d.ts +0 -9
- package/dist/plugins/webhook/index.d.ts.map +0 -1
- package/dist/plugins/webhook/index.js +0 -9
- package/dist/plugins/webhook/index.js.map +0 -1
- package/dist/plugins/webhook/transformer.d.ts +0 -63
- package/dist/plugins/webhook/transformer.d.ts.map +0 -1
- package/dist/plugins/webhook/transformer.js +0 -157
- package/dist/plugins/webhook/transformer.js.map +0 -1
- package/dist/plugins/webhook/types.d.ts +0 -183
- package/dist/plugins/webhook/types.d.ts.map +0 -1
- package/dist/plugins/webhook/types.js +0 -2
- package/dist/plugins/webhook/types.js.map +0 -1
- package/dist/plugins/webhook/webhook-plugin.d.ts +0 -92
- package/dist/plugins/webhook/webhook-plugin.d.ts.map +0 -1
- package/dist/plugins/webhook/webhook-plugin.js +0 -328
- package/dist/plugins/webhook/webhook-plugin.js.map +0 -1
- package/dist/schemas/agent-template-schema.d.ts +0 -137
- package/dist/schemas/agent-template-schema.d.ts.map +0 -1
- package/dist/schemas/agent-template-schema.js +0 -87
- package/dist/schemas/agent-template-schema.js.map +0 -1
- package/dist/services/conversation-service/index.d.ts +0 -88
- package/dist/services/conversation-service/index.d.ts.map +0 -1
- package/dist/services/conversation-service/index.js +0 -441
- package/dist/services/conversation-service/index.js.map +0 -1
- package/dist/services/conversation-service/types.d.ts +0 -32
- package/dist/services/conversation-service/types.d.ts.map +0 -1
- package/dist/services/conversation-service/types.js +0 -8
- package/dist/services/conversation-service/types.js.map +0 -1
- package/dist/services/event-service.d.ts +0 -61
- package/dist/services/event-service.d.ts.map +0 -1
- package/dist/services/event-service.js +0 -110
- package/dist/services/event-service.js.map +0 -1
- package/dist/services/event-service.test.d.ts +0 -2
- package/dist/services/event-service.test.d.ts.map +0 -1
- package/dist/services/event-service.test.js +0 -86
- package/dist/services/event-service.test.js.map +0 -1
- package/dist/services/execution-service.d.ts +0 -151
- package/dist/services/execution-service.d.ts.map +0 -1
- package/dist/services/execution-service.js +0 -1262
- package/dist/services/execution-service.js.map +0 -1
- package/dist/services/execution-service.test.d.ts +0 -2
- package/dist/services/execution-service.test.d.ts.map +0 -1
- package/dist/services/execution-service.test.js +0 -338
- package/dist/services/execution-service.test.js.map +0 -1
- package/dist/services/history-module.d.ts +0 -15
- package/dist/services/history-module.d.ts.map +0 -1
- package/dist/services/history-module.js +0 -42
- package/dist/services/history-module.js.map +0 -1
- package/dist/services/in-memory-history-store.d.ts +0 -12
- package/dist/services/in-memory-history-store.d.ts.map +0 -1
- package/dist/services/in-memory-history-store.js +0 -41
- package/dist/services/in-memory-history-store.js.map +0 -1
- package/dist/services/index.d.ts +0 -7
- package/dist/services/index.d.ts.map +0 -1
- package/dist/services/index.js +0 -13
- package/dist/services/index.js.map +0 -1
- package/dist/services/task-events.d.ts +0 -6
- package/dist/services/task-events.d.ts.map +0 -1
- package/dist/services/task-events.js +0 -6
- package/dist/services/task-events.js.map +0 -1
- package/dist/services/tool-execution-service.d.ts +0 -74
- package/dist/services/tool-execution-service.d.ts.map +0 -1
- package/dist/services/tool-execution-service.js +0 -189
- package/dist/services/tool-execution-service.js.map +0 -1
- package/dist/services/user-events.d.ts +0 -7
- package/dist/services/user-events.d.ts.map +0 -1
- package/dist/services/user-events.js +0 -6
- package/dist/services/user-events.js.map +0 -1
- package/dist/tools/implementations/function-tool/index.d.ts +0 -9
- package/dist/tools/implementations/function-tool/index.d.ts.map +0 -1
- package/dist/tools/implementations/function-tool/index.js +0 -13
- package/dist/tools/implementations/function-tool/index.js.map +0 -1
- package/dist/tools/implementations/function-tool/schema-converter.d.ts +0 -32
- package/dist/tools/implementations/function-tool/schema-converter.d.ts.map +0 -1
- package/dist/tools/implementations/function-tool/schema-converter.js +0 -164
- package/dist/tools/implementations/function-tool/schema-converter.js.map +0 -1
- package/dist/tools/implementations/function-tool/types.d.ts +0 -72
- package/dist/tools/implementations/function-tool/types.d.ts.map +0 -1
- package/dist/tools/implementations/function-tool/types.js +0 -14
- package/dist/tools/implementations/function-tool/types.js.map +0 -1
- package/dist/tools/implementations/function-tool.d.ts +0 -49
- package/dist/tools/implementations/function-tool.d.ts.map +0 -1
- package/dist/tools/implementations/function-tool.js +0 -223
- package/dist/tools/implementations/function-tool.js.map +0 -1
- package/dist/tools/implementations/index.d.ts +0 -4
- package/dist/tools/implementations/index.d.ts.map +0 -1
- package/dist/tools/implementations/index.js +0 -5
- package/dist/tools/implementations/index.js.map +0 -1
- package/dist/tools/implementations/mcp-tool.d.ts +0 -72
- package/dist/tools/implementations/mcp-tool.d.ts.map +0 -1
- package/dist/tools/implementations/mcp-tool.js +0 -246
- package/dist/tools/implementations/mcp-tool.js.map +0 -1
- package/dist/tools/implementations/openapi-tool.d.ts +0 -56
- package/dist/tools/implementations/openapi-tool.d.ts.map +0 -1
- package/dist/tools/implementations/openapi-tool.js +0 -324
- package/dist/tools/implementations/openapi-tool.js.map +0 -1
- package/dist/tools/implementations/relay-mcp-tool.d.ts +0 -38
- package/dist/tools/implementations/relay-mcp-tool.d.ts.map +0 -1
- package/dist/tools/implementations/relay-mcp-tool.js +0 -46
- package/dist/tools/implementations/relay-mcp-tool.js.map +0 -1
- package/dist/tools/index.d.ts +0 -3
- package/dist/tools/index.d.ts.map +0 -1
- package/dist/tools/index.js +0 -4
- package/dist/tools/index.js.map +0 -1
- package/dist/tools/registry/index.d.ts +0 -2
- package/dist/tools/registry/index.d.ts.map +0 -1
- package/dist/tools/registry/index.js +0 -3
- package/dist/tools/registry/index.js.map +0 -1
- package/dist/tools/registry/tool-registry.d.ts +0 -54
- package/dist/tools/registry/tool-registry.d.ts.map +0 -1
- package/dist/tools/registry/tool-registry.js +0 -146
- package/dist/tools/registry/tool-registry.js.map +0 -1
- package/dist/utils/errors.d.ts +0 -155
- package/dist/utils/errors.d.ts.map +0 -1
- package/dist/utils/errors.js +0 -203
- package/dist/utils/errors.js.map +0 -1
- package/dist/utils/execution-proxy.d.ts +0 -75
- package/dist/utils/execution-proxy.d.ts.map +0 -1
- package/dist/utils/execution-proxy.js +0 -230
- package/dist/utils/execution-proxy.js.map +0 -1
- package/dist/utils/index.d.ts +0 -11
- package/dist/utils/index.d.ts.map +0 -1
- package/dist/utils/index.js +0 -7
- package/dist/utils/index.js.map +0 -1
- package/dist/utils/logger.d.ts +0 -74
- package/dist/utils/logger.d.ts.map +0 -1
- package/dist/utils/logger.js +0 -143
- package/dist/utils/logger.js.map +0 -1
- package/dist/utils/message-converter.d.ts +0 -68
- package/dist/utils/message-converter.d.ts.map +0 -1
- package/dist/utils/message-converter.js +0 -87
- package/dist/utils/message-converter.js.map +0 -1
- package/dist/utils/periodic-task.d.ts +0 -14
- package/dist/utils/periodic-task.d.ts.map +0 -1
- package/dist/utils/periodic-task.js +0 -26
- package/dist/utils/periodic-task.js.map +0 -1
- package/dist/utils/validation.d.ts +0 -40
- package/dist/utils/validation.d.ts.map +0 -1
- package/dist/utils/validation.js +0 -162
- package/dist/utils/validation.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":["processEventHelper","ID_RADIX","validateAgentConfig","logger","ID_RADIX","ID_RANDOM_LENGTH","DEFAULT_MAX_EXECUTION_ROUNDS","UNLIMITED_EXECUTION_ROUNDS","executionUsage.createUsageObservationId","executionUsage.collectAssistantUsageMetadata","executeStreamFn","ID_RADIX","exhaustive"],"sources":["../../src/interfaces/types.ts","../../src/interfaces/provider-capabilities.ts","../../src/interfaces/model-effort-capability.ts","../../src/interfaces/provider.ts","../../src/interfaces/provider-definition.ts","../../src/interfaces/model-capability.ts","../../src/interfaces/media-provider.ts","../../src/interfaces/media-provider-definition.ts","../../src/interfaces/tool-search.ts","../../src/interfaces/interaction-builders.ts","../../src/interfaces/progress-reporting.ts","../../src/abstracts/abstract-agent.ts","../../src/abstracts/abstract-manager.ts","../../src/abstracts/ai-provider-helpers.ts","../../src/abstracts/abstract-ai-provider-executor-stream.ts","../../src/interfaces/messages.ts","../../src/abstracts/abstract-ai-provider-model-effort.ts","../../src/utils/logger.ts","../../src/abstracts/abstract-ai-provider.ts","../../src/abstracts/abstract-plugin-types.ts","../../src/agents/constants.ts","../../src/services/execution-constants.ts","../../src/services/tool-execution-constants.ts","../../src/plugins/event-emitter/types.ts","../../src/abstracts/abstract-plugin.ts","../../src/abstracts/abstract-executor.ts","../../src/abstracts/abstract-tool.ts","../../src/utils/abort-classification.ts","../../src/utils/message-converter.ts","../../src/utils/validation.ts","../../src/utils/error-utils.ts","../../src/utils/provider-failure.ts","../../src/utils/periodic-task.ts","../../src/schema/zod-schema-inspect.ts","../../src/schema/zod-to-json-schema.ts","../../src/schema/structured-output.ts","../../src/services/structured-output-transport.ts","../../src/utils/env-resolver.ts","../../src/providers/media-provider-factory.ts","../../src/utils/env-ref.ts","../../src/providers/provider-factory.ts","../../src/utils/random-id.ts","../../src/managers/conversation-message-factory.ts","../../src/managers/conversation-store-history.ts","../../src/managers/conversation-store.ts","../../src/managers/conversation-history-manager.ts","../../src/executors/local-executor-model-effort.ts","../../src/executors/local-executor.ts","../../src/utils/shell-argument.ts","../../src/plugins/event-emitter/metrics.ts","../../src/plugins/event-emitter-helpers.ts","../../src/plugins/event-emitter-plugin.ts","../../src/tool-registry/tool-registry.ts","../../src/tool-registry/output-validator.ts","../../src/tool-registry/parameter-validator.ts","../../src/event-service/event-service.ts","../../src/event-service/span-events.ts","../../src/tool-registry/function-tool.ts","../../src/tool-registry/tool-residency.ts","../../src/core/robota-base.ts","../../src/core/tool-result-value.ts","../../src/core/robota-config-manager.ts","../../src/managers/tool-manager.ts","../../src/context/token-usage.ts","../../src/context/estimation.ts","../../src/context/models.ts","../../src/services/tool-search-policy.ts","../../src/core/robota-construction.ts","../../src/core/robota-module-manager.ts","../../src/core/robota-plugin-manager.ts","../../src/core/robota-delegate-factory.ts","../../src/event-service/task-events.ts","../../src/event-service/user-events.ts","../../src/core/robota-events.ts","../../src/core/robota-execution.ts","../../src/core/robota-execution-structured.ts","../../src/core/robota-history.ts","../../src/managers/ai-provider-manager.ts","../../src/services/cache/cache-key-builder.ts","../../src/services/cache/memory-cache-storage.ts","../../src/services/cache/execution-cache-service.ts","../../src/services/execution-types.ts","../../src/services/execution-event-emitter-high-level.ts","../../src/services/tool-execution-batch.ts","../../src/services/tool-execution-service.ts","../../src/services/execution-event-helpers.ts","../../src/services/execution-event-emitter.ts","../../src/services/execution-failure.ts","../../src/services/execution-model-capability-guards.ts","../../src/services/execution-provider-call.ts","../../src/services/plugin-hook-dispatcher.ts","../../src/services/execution-service-helpers.ts","../../src/services/execution-structured-output-guard.ts","../../src/services/execution-model-route.ts","../../src/services/execution-trace-context.ts","../../src/services/execution-round-provider.ts","../../src/services/provider-call-usage.ts","../../src/services/message-origin.ts","../../src/services/execution-forced-summary.ts","../../src/services/execution-round-context.ts","../../src/services/execution-round-streaming.ts","../../src/services/execution-round-tool-results.ts","../../src/services/execution-round-tools.ts","../../src/services/execution-usage.ts","../../src/services/execution-round.ts","../../src/services/execution-pipeline.ts","../../src/services/execution-stream.ts","../../src/services/execution-user-message.ts","../../src/services/execution-service.ts","../../src/core/robota-initializer.ts","../../src/core/robota-lifecycle.ts","../../src/core/robota-run-queue.ts","../../src/managers/agent-factory-helpers.ts","../../src/managers/agent-templates.ts","../../src/managers/registry-transaction.ts","../../src/managers/agent-factory.ts","../../src/managers/module-registry-validation.ts","../../src/managers/module-type-registry-helpers.ts","../../src/managers/module-type-registry.ts","../../src/managers/module-registry.ts","../../src/core/robota.ts","../../src/core/tool-result-admission.ts","../../src/services/history-module.ts","../../src/orchestration/orchestration-events.ts","../../src/utils/execution-proxy-types.ts","../../src/utils/execution-proxy.ts","../../src/permissions/types.ts","../../src/permissions/command-segments.ts","../../src/permissions/argument-matchers.ts","../../src/permissions/permission-mode.ts","../../src/permissions/permission-safeguards.ts","../../src/permissions/read-only-commands.ts","../../src/permissions/permission-gate.ts","../../src/permissions/permission-policy.ts","../../src/permissions/pattern-validation.ts","../../src/permissions/tool-list-patterns.ts","../../src/permissions/auto-mode-rules.ts","../../src/context/model-pricing.ts","../../src/hooks/hook-matching.ts","../../src/hooks/hook-runner.ts","../../src/hooks/executors/guardrail-executor.ts","../../src/hooks/enforcement-policy.ts"],"sourcesContent":["/**\n * Agent-specific type definitions\n * Local types for agent functionality - not forced to use base types unless needed for cross-connections\n */\n\nexport type {\n TPrimitiveValue,\n TUniversalValue,\n TUniversalArrayValue,\n IUniversalObjectValue,\n} from './universal-value';\nimport type {\n TPrimitiveValue,\n TUniversalValue,\n TUniversalArrayValue,\n IUniversalObjectValue,\n} from './universal-value';\n\n/**\n * Metadata type - consistent across agent components\n */\nexport type TMetadataValue = TPrimitiveValue | TUniversalArrayValue | Date;\nexport type TMetadata = Record<string, TMetadataValue>;\n\n/**\n * Context data type - for execution contexts\n */\nexport type TContextData = Record<string, TUniversalValue>;\n\n/**\n * Logger data type - for logging contexts\n */\nexport type TLoggerData = Record<string, TUniversalValue | Date | Error>;\n\n/**\n * Configuration types - for agent configuration\n */\nexport type TComplexConfigValue = Record<\n string,\n TPrimitiveValue | TUniversalArrayValue | IUniversalObjectValue\n>;\nexport type TConfigValue =\n | TPrimitiveValue\n | TUniversalArrayValue\n | IUniversalObjectValue\n | Array<TComplexConfigValue>\n | Array<Record<string, TPrimitiveValue | TUniversalArrayValue | IUniversalObjectValue>>\n | Array<TComplexConfigValue>\n | TComplexConfigValue;\nexport type TConfigData = Record<string, TConfigValue>;\n\n/**\n * Tool parameter value type - specific for tool parameters\n */\nexport type TToolParameters = Record<string, TUniversalValue>;\n\n/**\n * Tool result data type - for tool execution results\n */\n// NOTE:\n// Tool result values are represented by the canonical TUniversalValue axis.\n\n// NOTE:\n// Provider config value types are owned by the provider axis (`interfaces/provider.ts`).\n// Avoid defining provider config interfaces in this value axis module.\n// Do not introduce duplicate provider config value types here.\n\n// NOTE:\n// `IPluginContext` moved to `../abstracts/abstract-plugin-types` (PLG-020 follow-up): it depends\n// on `IPluginExecutionResult`, which lives at the abstracts layer, and living here made this leaf\n// value-types module reach upward into abstracts — a module-level import cycle. Its only consumer\n// outside this file (`services/plugin-hook-dispatcher.ts`) now imports it from there directly.\n\n/**\n * Type utility functions for safe type checking and validation\n * @internal\n */\nexport const TypeUtils = {\n isPrimitive: (value: TUniversalValue): value is TPrimitiveValue => {\n return (\n value === null ||\n value === undefined ||\n typeof value === 'string' ||\n typeof value === 'number' ||\n typeof value === 'boolean'\n );\n },\n\n isArray: (value: TUniversalValue): value is TUniversalArrayValue => {\n return Array.isArray(value) && value.every((item) => TypeUtils.isUniversalValue(item));\n },\n\n isObject: (value: TUniversalValue): value is IUniversalObjectValue => {\n return (\n typeof value === 'object' &&\n value !== null &&\n !Array.isArray(value) &&\n !(value instanceof Date) &&\n Object.values(value).every((val) => TypeUtils.isUniversalValue(val))\n );\n },\n\n isUniversalValue: (value: TUniversalValue): value is TUniversalValue => {\n if (value instanceof Date) return true;\n return TypeUtils.isPrimitive(value) || TypeUtils.isArray(value) || TypeUtils.isObject(value);\n },\n};\n","export interface IProviderFunctionCallingCapability {\n supported: boolean;\n reason?: string;\n}\n\nexport interface IProviderNativeWebToolCapability {\n supported: boolean;\n enabled: boolean;\n source?: string;\n reason?: string;\n}\n\nexport interface IProviderNativeWebToolCapabilities {\n webSearch: IProviderNativeWebToolCapability;\n webFetch: IProviderNativeWebToolCapability;\n}\n\nexport interface IProviderCapabilities {\n functionCalling: IProviderFunctionCallingCapability;\n nativeWebTools: IProviderNativeWebToolCapabilities;\n}\n\n/**\n * Hosted web tools asked of one call: `true` requires the tool (a provider without it throws),\n * `false` withholds it from this call even when the provider is configured with it, and absent\n * leaves the provider's own configuration.\n */\nexport interface IProviderNativeWebToolRequest {\n webSearch?: boolean;\n webFetch?: boolean;\n}\n\nconst DEFAULT_NATIVE_WEB_SEARCH_REASON = 'Provider does not declare native web search support.';\nconst DEFAULT_NATIVE_WEB_FETCH_REASON = 'Provider does not declare native web fetch support.';\n\nexport function createDefaultProviderCapabilities(\n functionCallingSupported: boolean,\n): IProviderCapabilities {\n return {\n functionCalling: { supported: functionCallingSupported },\n nativeWebTools: {\n webSearch: {\n supported: false,\n enabled: false,\n reason: DEFAULT_NATIVE_WEB_SEARCH_REASON,\n },\n webFetch: {\n supported: false,\n enabled: false,\n reason: DEFAULT_NATIVE_WEB_FETCH_REASON,\n },\n },\n };\n}\n\n// NOTE:\n// `getProviderCapabilities` moved to `./provider.ts` (it takes an `IAIProvider`, and defining it\n// here required importing `./provider`, while `provider.ts` imports this module's types —\n// a module-level import cycle). Re-exported from `./provider` under the same name.\n\nexport function assertProviderNativeWebToolsAvailable(\n providerName: string,\n capabilities: IProviderCapabilities,\n request: IProviderNativeWebToolRequest | undefined,\n): void {\n if (request?.webSearch === true) {\n assertNativeWebToolAvailable(providerName, 'web search', capabilities.nativeWebTools.webSearch);\n }\n if (request?.webFetch === true) {\n assertNativeWebToolAvailable(providerName, 'web fetch', capabilities.nativeWebTools.webFetch);\n }\n}\n\nfunction assertNativeWebToolAvailable(\n providerName: string,\n label: string,\n capability: IProviderNativeWebToolCapability,\n): void {\n if (!capability.supported) {\n throw new Error(\n `Provider ${providerName} does not support native ${label}.${formatCapabilityReason(capability.reason)}`,\n );\n }\n if (!capability.enabled) {\n throw new Error(\n `Provider ${providerName} supports native ${label} but it is not enabled.${formatCapabilityReason(capability.reason)}`,\n );\n }\n}\n\nfunction formatCapabilityReason(reason: string | undefined): string {\n return reason ? ` ${reason}` : '';\n}\n","/** Provider-neutral native effort controls. `auto` is selection state, not a control. */\nexport type TModelEffort = 'none' | 'minimal' | 'low' | 'medium' | 'high' | 'xhigh' | 'max';\n\n/** Runtime boundary vocabulary for a concrete provider-native effort control. */\nexport const MODEL_EFFORT_VALUES = [\n 'none',\n 'minimal',\n 'low',\n 'medium',\n 'high',\n 'xhigh',\n 'max',\n] as const satisfies readonly TModelEffort[];\n\nexport function isModelEffort(value: TUniversalValue | undefined): value is TModelEffort {\n return typeof value === 'string' && MODEL_EFFORT_VALUES.includes(value as TModelEffort);\n}\n\n/** A caller can preserve provider-default selection without serializing a native control. */\nexport type TModelEffortSelection = TModelEffort | 'auto';\n\n/** The verified effort facts an adapter declares for one exact model identifier. */\nexport interface IModelEffortCapability {\n supportedEfforts: readonly TModelEffort[];\n defaultEffort: TModelEffort;\n /** Adapter-owned opaque identity for the verified native control. */\n nativeControlId: string;\n}\n\n/** Source-dated provider data. Core owns the shape but never provides the data. */\nexport interface IProviderModelEffortTable {\n verifiedAt: string;\n sourceUrl: string;\n models: Readonly<Record<string, IModelEffortCapability>>;\n}\n\nexport type TModelEffortDisposition = 'exact' | 'clamped' | 'model-default' | 'not-applied';\n\n/** Serializable output of resolving a selection against a verified provider table. */\nexport interface IModelEffortResolution {\n selection: TModelEffortSelection;\n effective: TModelEffort | null;\n disposition: TModelEffortDisposition;\n fingerprint: string;\n}\n\n/** Whether the adapter serialized a verified native effort control. */\nexport type TModelEffortNativeControl =\n | { readonly state: 'sent'; readonly id: string }\n | { readonly state: 'omitted'; readonly reason: string };\n\n/** Whether an endpoint dispatch occurred after the effort decision. */\nexport type TModelEffortProviderDispatch =\n { readonly state: 'sent' } | { readonly state: 'not-dispatched'; readonly reason: string };\n\n/** Serializable terminal result of one effort-bearing provider request. */\nexport interface IModelEffortOutcome {\n readonly resolution: IModelEffortResolution;\n readonly nativeControl: TModelEffortNativeControl;\n readonly providerDispatch: TModelEffortProviderDispatch;\n}\n\n/** Local observer for a request's one terminal provider effort outcome. */\nexport type TModelEffortOutcomeCallback = (outcome: IModelEffortOutcome) => void;\n\n/** Construct the three-fact terminal outcome without conflating its states. */\nexport function createModelEffortOutcome(\n resolution: IModelEffortResolution,\n outcome: Omit<IModelEffortOutcome, 'resolution'>,\n): IModelEffortOutcome {\n return { resolution, ...outcome };\n}\n\nconst EFFORT_ORDER = new Map(MODEL_EFFORT_VALUES.map((effort, index) => [effort, index]));\n\nfunction unresolved(selection: TModelEffortSelection, modelId: string): IModelEffortResolution {\n return {\n selection,\n effective: null,\n disposition: 'not-applied',\n fingerprint: `${modelId}|${selection}|not-applied`,\n };\n}\n\n/**\n * Resolve only adapter-declared facts. Missing provider/model data never becomes a guessed default.\n */\nexport function resolveModelEffort(\n table: IProviderModelEffortTable | undefined,\n modelId: string,\n selection: TModelEffortSelection,\n): IModelEffortResolution {\n const capability = table?.models[modelId];\n if (!capability) return unresolved(selection, modelId);\n\n const fingerprint = (effective: TModelEffort, disposition: TModelEffortDisposition): string =>\n `${modelId}|${selection}|${effective}|${disposition}|${capability.nativeControlId}|${table.verifiedAt}`;\n\n if (selection === 'auto') {\n if (!capability.supportedEfforts.includes(capability.defaultEffort)) {\n return unresolved(selection, modelId);\n }\n return {\n selection,\n effective: capability.defaultEffort,\n disposition: 'model-default',\n fingerprint: fingerprint(capability.defaultEffort, 'model-default'),\n };\n }\n\n if (capability.supportedEfforts.includes(selection)) {\n return {\n selection,\n effective: selection,\n disposition: 'exact',\n fingerprint: fingerprint(selection, 'exact'),\n };\n }\n\n const requestedOrder = EFFORT_ORDER.get(selection);\n const fallback = capability.supportedEfforts\n .filter(\n (effort) => (EFFORT_ORDER.get(effort) ?? Number.POSITIVE_INFINITY) < (requestedOrder ?? -1),\n )\n .at(-1);\n if (!fallback) return unresolved(selection, modelId);\n\n return {\n selection,\n effective: fallback,\n disposition: 'clamped',\n fingerprint: fingerprint(fallback, 'clamped'),\n };\n}\nimport type { TUniversalValue } from './types';\n","import type { TUniversalMessage, IToolCall } from './messages';\nimport type { IProviderCapabilityTable } from './model-capability';\nimport type { TModelFallbackCallback } from './model-fallback';\nimport type {\n IModelEffortResolution,\n IModelEffortOutcome,\n IProviderModelEffortTable,\n TModelEffortOutcomeCallback,\n TModelEffortSelection,\n} from './model-effort-capability';\nimport { createDefaultProviderCapabilities } from './provider-capabilities';\nimport type { IProviderCapabilities, IProviderNativeWebToolRequest } from './provider-capabilities';\nimport type { IProviderSpecificOptions } from './provider-specific-options';\nimport type { IToolSchema } from './tool-schema';\nimport type { IModelRef } from './role-model';\nimport type { IOutboundTraceContext } from './trace-context';\nimport type { TUniversalValue } from './universal-value';\n\nexport type {\n IProviderCapabilities,\n IProviderFunctionCallingCapability,\n IProviderNativeWebToolCapabilities,\n IProviderNativeWebToolCapability,\n IProviderNativeWebToolRequest,\n} from './provider-capabilities';\nexport {\n assertProviderNativeWebToolsAvailable,\n createDefaultProviderCapabilities,\n} from './provider-capabilities';\n\n/**\n * Reusable type definitions for provider layer\n */\n\n/**\n * Provider configuration value type\n * Used for storing provider-specific configuration values\n */\nexport type TProviderConfigValue = string | number | boolean;\n\nexport type { IProviderSpecificOptions } from './provider-specific-options';\nexport type { TModelEffort, TModelEffortSelection } from './model-effort-capability';\nexport { isModelEffort, MODEL_EFFORT_VALUES } from './model-effort-capability';\n\n// The universal JSON-schema subset moved to `./tool-schema` (CORE-039): it is its own concept,\n// reached by producers, validators and four provider adapters, and `provider.ts` was over its\n// frozen size baseline. Re-exported here so every existing `from './provider'` import resolves.\nexport type {\n IObjectParameterSchema,\n IParameterSchema,\n IToolSchema,\n TJSONSchemaEnum,\n TJSONSchemaKind,\n TParameterDefaultValue,\n} from './tool-schema';\n\n/**\n * Token usage statistics\n */\nexport interface ITokenUsage {\n promptTokens: number;\n completionTokens: number;\n totalTokens: number;\n}\n\n/**\n * Raw provider response interface\n */\nexport interface IRawProviderResponse {\n content: string | null;\n toolCalls?: IToolCall[];\n usage?: ITokenUsage;\n finishReason?: string;\n model?: string;\n metadata?: Record<string, TProviderConfigValue>;\n /** One terminal effort result for generic raw non-streaming calls or the explicit stream envelope. */\n modelEffortOutcome?: IModelEffortOutcome;\n}\n\n/**\n * Provider request payload\n */\nexport interface IProviderRequest {\n messages: TUniversalMessage[];\n model?: string;\n /** Caller selection retained until the adapter resolves its verified model table. */\n effort?: TModelEffortSelection;\n /** Immutable adapter-bound resolution handoff for this request. */\n effortResolution?: IModelEffortResolution;\n /** Local-only observer for the terminal serializable outcome. */\n onModelEffortOutcome?: TModelEffortOutcomeCallback;\n temperature?: number;\n maxTokens?: number;\n tools?: IToolSchema[];\n systemMessage?: string;\n metadata?: Record<string, string | number | boolean>;\n}\n\nexport type TTextDeltaCallback = (delta: string) => void;\n\nexport type TProviderNativeRawPayloadKind = 'request' | 'response' | 'stream_event';\n\nexport type TProviderNativeRawPayload = string | number | boolean | object | null | undefined;\n\nexport interface IProviderNativeRawPayloadEvent {\n provider: string;\n apiSurface?: string;\n payloadKind: TProviderNativeRawPayloadKind;\n payload: TProviderNativeRawPayload;\n sequence?: number;\n metadata?: Record<string, TProviderConfigValue>;\n}\n\nexport type TProviderNativeRawPayloadCallback = (event: IProviderNativeRawPayloadEvent) => void;\n\n/**\n * Tool-invocation directive threaded per model invocation (CORE-017).\n *\n * Canonical SSOT for the union. `'auto'` lets the model decide (provider default),\n * `'none'` suppresses tool calls for the invocation, `'required'` forces the model to call\n * some tool, and `{ tool: name }` forces a call to the named tool. Core validates that a\n * named tool exists in the invocation's tool list and that `'required'`/named forcing is\n * only used when tools are present — a violation throws instead of degrading silently.\n * Within a multi-round run, forcing directives apply to the FIRST model call only; rounds\n * after tool results revert to `'auto'` so the model can consume the results and finish.\n */\nexport type TToolChoice = 'auto' | 'none' | 'required' | { tool: string };\n\n/**\n * Options for AI provider chat requests\n */\nexport interface IChatOptions extends IProviderSpecificOptions {\n /** Tool schemas to provide to the AI provider */\n tools?: IToolSchema[];\n /** Maximum number of tokens to generate */\n maxTokens?: number;\n /** Temperature for response randomness (0-1) */\n temperature?: number;\n /**\n * Reasoning-effort dial for this invocation. Native-effort providers map it to their\n * request parameter; providers without native effort ignore it (documented no-op).\n * Threaded from session/model options; `auto` remains provider-default selection until resolution.\n */\n effort?: TModelEffortSelection;\n /** Immutable adapter-bound resolution handoff for this request. */\n effortResolution?: IModelEffortResolution;\n /** Local-only observer for this request's terminal model-effort outcome. */\n onModelEffortOutcome?: TModelEffortOutcomeCallback;\n /** Model to use for the request */\n model?: string;\n /** Callback for text deltas during streaming. When provided, the provider\n * should use streaming internally and call this for each text chunk,\n * while still returning the complete assembled message. */\n onTextDelta?: TTextDeltaCallback;\n /** Callback for provider-owned native SDK request/response/stream payload capture. */\n onProviderNativeRawPayload?: TProviderNativeRawPayloadCallback;\n /** AbortSignal for cancelling the provider call */\n signal?: AbortSignal;\n /**\n * Trusted trace context for THIS invoked call. Core sets it only on a call it actually hands to the\n * adapter, and only for a provider that answers `canPropagateTraceContext()` with true. An adapter\n * adds `traceparent` (via `traceHeadersFor`) to its per-request headers when its effective origin\n * is listed, after raw-payload capture, and never copies this into any captured payload.\n */\n outboundTraceContext?: IOutboundTraceContext;\n /**\n * Tool-invocation directive for this call. Adapters map it onto their wire format\n * (`tool_choice` / `functionCallingConfig`); omitted = provider default ('auto').\n */\n toolChoice?: TToolChoice;\n /** Provider-native hosted web tools requested for this call */\n nativeWebTools?: IProviderNativeWebToolRequest;\n /** Request structured output from the provider (CORE-015: `json_schema` carries the schema). */\n responseFormat?:\n | { type: 'text' | 'json_object' }\n | { type: 'json_schema'; name?: string; schema: Record<string, TUniversalValue> };\n /**\n * The run this call belongs to: the same for every call of one run and different for the next.\n * A provider that can answer on another model keys its per-run choice on it; a call without one\n * belongs to no run and starts from the requested model.\n */\n executionId?: string;\n /** Told when this request moved to another model, so the caller can attribute the answer. */\n onModelFallback?: TModelFallbackCallback;\n /**\n * Any other model this request moves to must offer at least the requested model's context\n * window; a model whose window is unknown counts as smaller. Set by compaction, whose input was\n * sized to the requested model.\n */\n preserveContextWindow?: boolean;\n}\n\n/**\n * Provider-agnostic AI Provider interface\n * This interface uses only TUniversalMessage types and avoids provider-specific types\n */\nexport interface IAIProvider {\n /** Provider identifier */\n readonly name: string;\n /** Provider version */\n readonly version: string;\n\n /**\n * Generate response from AI model using TUniversalMessage\n * @param messages - Array of TUniversalMessage from conversation history\n * @param options - Chat options including tools, model settings, etc.\n * @returns Promise resolving to a TUniversalMessage response\n */\n chat(messages: TUniversalMessage[], options?: IChatOptions): Promise<TUniversalMessage>;\n\n /**\n * Generate streaming response from AI model using TUniversalMessage\n * @param messages - Array of TUniversalMessage from conversation history\n * @param options - Chat options including tools, model settings, etc.\n * @returns AsyncIterable of TUniversalMessage chunks\n */\n chatStream?(\n messages: TUniversalMessage[],\n options?: IChatOptions,\n ): AsyncIterable<TUniversalMessage>;\n\n /**\n * Generate response from AI model (raw provider response)\n * @param payload - Provider request payload\n * @returns Promise resolving to raw provider response\n */\n generateResponse(payload: IProviderRequest): Promise<IRawProviderResponse>;\n\n /**\n * Generate streaming response from AI model (raw provider response)\n * @param payload - Provider request payload\n * @returns AsyncIterable of raw provider response chunks\n */\n generateStreamingResponse?(payload: IProviderRequest): AsyncIterable<IRawProviderResponse>;\n\n /**\n * Check if the provider supports tool calling\n * @returns true if tool calling is supported\n */\n supportsTools(): boolean;\n\n /**\n * Report provider-neutral capability state.\n * Providers without native web support can omit this and use default capability helpers.\n */\n getCapabilities?(): IProviderCapabilities;\n\n /**\n * What this provider's models can do (PROV-006/PROV-008).\n *\n * `supportsTools()` answers for the vendor, which is the wrong granularity when models differ.\n * This is the per-MODEL answer, declared by the package that ships the adapter and reachable from\n * the instance — the catalog on `IProviderDefinition` is discovery, which the instance never\n * holds. Optional, and silence is NOT denial: see `interfaces/model-capability.ts`.\n */\n capabilityTable?(): IProviderCapabilityTable | undefined;\n\n /**\n * Source-dated effort data for exact models this adapter can verify. Optional: a missing table is\n * a visible `not-applied` result, never a vendor-wide inferred default.\n */\n effortTable?(): IProviderModelEffortTable | undefined;\n\n /**\n * Whether this provider instance is pointed at its vendor's own endpoint. CORE-043.\n *\n * A provider configured with a custom `baseURL` still speaks the vendor's protocol, but the\n * vendor's guarantees are no longer the ones in force — a gateway can accept a structured-output\n * parameter and forward a request that ignores it, so the runtime would claim enforcement the\n * endpoint does not provide.\n *\n * Separate from `capabilityTable()` deliberately. Endpoint identity and capability declaration are\n * independent facts, and coupling them would force a provider with no verified table to invent one\n * in order to report its endpoint. Silence means the provider did not say, which is not a claim\n * that the endpoint is the vendor's.\n */\n endpointIsVendorDefault?(): boolean;\n\n /**\n * Whether this instance can put a trusted `traceparent` on its own HTTP requests: it knows its\n * effective origin and sends through a transport it controls. Optional, and silence means it\n * cannot — core then sends it no trace context and tells the host which provider could not.\n */\n canPropagateTraceContext?(): boolean;\n\n /**\n * Where a request for `model` in the run `executionId` will go first. Only a provider that can\n * answer on another model implements it; absent, the request goes to this provider and `model`.\n */\n resolveModelRoute?(model: string, executionId?: string): IModelRef;\n\n /**\n * Optional generic hook for enabling provider-native hosted web behavior.\n */\n configureNativeWebTools?(request: IProviderNativeWebToolRequest): IProviderCapabilities;\n\n /**\n * Validate provider configuration\n * @returns true if configuration is valid\n */\n validateConfig(): boolean;\n\n /**\n * Clean up resources when provider is no longer needed\n */\n dispose?(): Promise<void>;\n\n /**\n * Close provider connections and cleanup resources\n */\n close?(): Promise<void>;\n}\n\n/**\n * Resolve provider-neutral capability state for a provider instance.\n *\n * Defined here (not in `./provider-capabilities`) because it takes an `IAIProvider`, which is\n * declared in this module; `./provider-capabilities` has no dependency back on `./provider`.\n */\nexport function getProviderCapabilities(provider: IAIProvider): IProviderCapabilities {\n const supportsTools =\n typeof provider.supportsTools === 'function' ? provider.supportsTools() : false;\n return provider.getCapabilities?.() ?? createDefaultProviderCapabilities(supportsTools);\n}\n\n/**\n * Provider options interface\n */\nexport interface IProviderOptions {\n apiKey?: string;\n baseURL?: string;\n timeout?: number;\n retries?: number;\n maxConcurrentRequests?: number;\n defaultModel?: string;\n organization?: string;\n project?: string;\n /** Additional provider-specific configuration */\n extra?: Record<string, TProviderConfigValue>;\n}\n\n/**\n * Base union for provider option values.\n *\n * Purpose:\n * - Enable provider packages to compose their own option value unions without redefining the primitives.\n * - Keep the shared axis in @robota-sdk/agent-core (SSOT).\n *\n * Note:\n * - Provider packages may extend this with provider-specific runtime objects (e.g., OpenAI/Anthropic clients).\n */\nexport type TProviderOptionValueBase =\n | string\n | number\n | boolean\n | undefined\n | null\n | TProviderOptionValueBase[]\n | { [key: string]: TProviderOptionValueBase };\n","import type { IAIProvider } from './provider';\nimport type { TUniversalValue } from './types';\n\nexport interface IProviderDefinitionConfig {\n name: string;\n model: string;\n apiKey?: string;\n /**\n * Name of the environment variable `apiKey` was resolved FROM, when the stored settings value\n * was a `$ENV:` reference (SEC-009). Config loading resolves such a reference into the secret\n * itself, which is correct for an in-process provider and wrong for anything that has to\n * SERIALIZE the config — the resolved value then crosses a boundary the credential's owner\n * never opted into. Keeping the variable name lets a serializing caller carry the reference and\n * leave the secret behind; `ISerializableProviderProfile` already declares the same field, and\n * `resolveProfileApiKey` already reads it.\n *\n * Distinct from `sourceEnvVar`, which is set only for a synthesized `'env-default'` config.\n */\n apiKeyEnv?: string;\n baseURL?: string;\n timeout?: number;\n options?: Record<string, TUniversalValue>;\n /**\n * Resolution origin. `'env-default'` means no settings profile existed and the config\n * was synthesized from a provider definition's defaults because its `$ENV:` apiKey\n * reference resolved — callers surface a startup notice for this case.\n */\n source?: 'env-default';\n /**\n * Name of the environment variable the env-default key was resolved from\n * (set only when `source` is `'env-default'`) — lets callers name the variable in the\n * startup notice without exposing the key value.\n */\n sourceEnvVar?: string;\n}\n\nexport interface IProviderProfileDefaults {\n model?: string;\n apiKey?: string;\n baseURL?: string;\n timeout?: number;\n options?: Record<string, TUniversalValue>;\n}\n\nexport interface IProviderProfileConfig {\n type?: string;\n model?: string;\n apiKey?: string;\n baseURL?: string;\n timeout?: number;\n options?: Record<string, TUniversalValue>;\n}\n\nexport interface IProviderProbeResult {\n ok: boolean;\n message: string;\n models?: string[];\n}\n\nexport type TProviderCredentialField = 'apiKey';\nexport type TProviderSetupField = 'baseURL' | 'model' | TProviderCredentialField;\nexport type TProviderSetupHelpLinkKind = 'api-key' | 'console' | 'official';\n\nexport interface IProviderCredentialRequirement {\n anyOf: readonly TProviderCredentialField[];\n}\n\nexport interface IProviderSetupHelpLink {\n kind: TProviderSetupHelpLinkKind;\n label: string;\n url: string;\n sourceUrl?: string;\n lastVerifiedAt?: string;\n}\n\nexport type TProviderModelCatalogStatus = 'live' | 'generated' | 'fallback' | 'unavailable';\nexport type TProviderModelLifecycle = 'active' | 'preview' | 'deprecated' | 'unavailable';\n\nexport type { TProviderModelCapability } from './provider-model-capability-kind';\nimport type { TProviderModelCapability } from './provider-model-capability-kind';\n\nexport interface IProviderModelCatalogEntry {\n id: string;\n displayName: string;\n aliases?: readonly string[];\n contextWindow?: number;\n capabilities?: readonly TProviderModelCapability[];\n lifecycle?: TProviderModelLifecycle;\n lastVerifiedAt?: string;\n sourceUrl?: string;\n /**\n * Per-model USD cost per input/output token (ARCH-PROVIDER-003). This is the correct SSOT home for\n * cost — it is a per-**model** attribute, not per-provider — consumed by cost-estimating nodes/commands\n * so pricing is not hardcoded in the execution layer. Both optional; absent means cost is unknown for\n * this model and estimators must degrade explicitly rather than assume a default price.\n */\n costPerInputToken?: number;\n costPerOutputToken?: number;\n}\n\nexport interface IProviderModelCatalog {\n status: TProviderModelCatalogStatus;\n entries?: readonly IProviderModelCatalogEntry[];\n lastVerifiedAt?: string;\n sourceUrl?: string;\n message?: string;\n}\n\nexport interface IProviderSetupStepDefinition {\n key: TProviderSetupField;\n title: string;\n defaultValue?: string;\n required?: boolean;\n masked?: boolean;\n}\n\nexport type TProviderCategory = 'cloud-paid' | 'cloud-free' | 'local-free';\n\n/**\n * Passive reachability declaration for diagnostics (OBSERVABILITY-1991).\n *\n * The host and port a pre-session doctor may TCP-probe when a profile declares no `baseURL` and the\n * definition declares no `defaults.baseURL` — the case for vendors whose SDK embeds its endpoint. It\n * is deliberately not a URL and not part of `defaults`: nothing in setup, persistence or provider\n * construction reads it, so declaring it cannot switch an API surface or persist a base URL. It is\n * distinct from `probeProfile`, which is an active HTTP probe.\n */\nexport interface IProviderEndpoint {\n readonly host: string;\n readonly port: number;\n}\n\nexport interface IProviderDefinition {\n type: string;\n aliases?: readonly string[];\n displayName?: string;\n description?: string;\n /** Billing/hosting category shown as a badge in provider selection UI. */\n category?: TProviderCategory;\n defaults?: IProviderProfileDefaults;\n /**\n * Optional enforced model allowlist (ARCH-PROVIDER-003). Distinct from {@link modelCatalog}: the catalog\n * is the *descriptive* model inventory (often `status:'unavailable'` with no entries), whereas\n * `allowedModels` is the *enforced* execution allowlist — a node rejects a requested model outside it.\n * When present it should be a subset/override consistent with `modelCatalog.entries[].id`, not a second\n * drifting inventory. Absent means no allowlist enforcement (any model the provider accepts is allowed).\n */\n allowedModels?: readonly string[];\n /**\n * INTERIM provider-level cost per token in USD (ARCH-PROVIDER-003), migrated verbatim from the per-vendor\n * LLM nodes' single `COST_PER_TOKEN_USD` scalar. The correct long-term home is the per-model\n * {@link IProviderModelCatalogEntry.costPerInputToken}/`costPerOutputToken`; this flat scalar is a\n * fidelity-preserving interim used only while model catalogs are `status:'unavailable'` (no per-model\n * entries to attach cost to). Consumed by the collapsed `llm-text` node's `maxCostUsd` estimation. Absent\n * means cost is unknown for this provider and estimators must degrade explicitly.\n */\n costPerTokenUsd?: number;\n modelCatalog?: IProviderModelCatalog;\n setupHelpLinks?: readonly IProviderSetupHelpLink[];\n setupSteps?: readonly IProviderSetupStepDefinition[];\n credentialRequirement?: IProviderCredentialRequirement;\n requiresApiKey?: boolean;\n /**\n * The environment variables this provider's client reads to decide where it connects or which\n * credential it sends, beyond its configuration (for example a base-URL variable the SDK falls\n * back to). A process that builds this provider from another process's configuration must see\n * the same values, or the credential goes somewhere its owner did not choose.\n */\n destinationEnvironment?: readonly string[];\n createProvider: (config: IProviderDefinitionConfig) => IAIProvider;\n probeProfile?: (profile: IProviderProfileConfig) => Promise<IProviderProbeResult>;\n /** Diagnostic-only reachability declaration; read by no setup, persistence or runtime path. */\n endpoint?: IProviderEndpoint;\n}\n\nexport function findProviderDefinition(\n definitions: readonly IProviderDefinition[],\n type: string,\n): IProviderDefinition | undefined {\n return definitions.find(\n (definition) => definition.type === type || definition.aliases?.includes(type) === true,\n );\n}\n\nexport function formatSupportedProviderTypes(definitions: readonly IProviderDefinition[]): string {\n return definitions\n .map((definition) => {\n if (!definition.aliases || definition.aliases.length === 0) {\n return definition.type;\n }\n const aliasLabel = definition.aliases.length === 1 ? 'alias' : 'aliases';\n return `${definition.type} (${aliasLabel}: ${definition.aliases.join(', ')})`;\n })\n .join(', ');\n}\n\nexport function getProviderCredentialRequirement(\n definition: IProviderDefinition | undefined,\n): IProviderCredentialRequirement | undefined {\n if (definition?.credentialRequirement !== undefined) {\n return definition.credentialRequirement;\n }\n if (definition?.requiresApiKey === true) {\n return { anyOf: ['apiKey'] };\n }\n return undefined;\n}\n","/**\n * What a model can do, and where that answer lives. PROV-006 / PROV-008.\n *\n * PROV-006 made the per-model capability vocabulary readable: `tools`, `vision`, `json_schema`,\n * `reasoning`, `native_web`, `streaming`. PROV-008 moved it out of the struct it was sharing.\n *\n * `IProviderModelCatalogEntry` carried three payloads with nothing in common — which models EXIST\n * (dynamic, per-account, refreshable), what a model CAN DO (static, versioned with the adapter), and\n * what a model COSTS (static, versioned with vendor pricing) — hanging off `IProviderDefinition`, a\n * registry artifact the provider instance never holds. So nothing at runtime could read any of it,\n * and the live-refresh path could not have populated the static halves anyway: it builds entries from\n * a models-list endpoint that returns ids and nothing else.\n *\n * Capability is therefore its own thing, declared by the package that ships the adapter and reachable\n * from the provider INSTANCE. Discovery stays where it belongs, on the definition.\n *\n * Two rules this file exists to hold:\n *\n * 1. **A capability table states the VENDOR DEFAULT plus verified deviations** — not an enumeration\n * of every model. An enumeration is a per-model × six-flag matrix nobody maintains and that\n * silently rots; a deviation list is short, and each entry is something somebody checked.\n * 2. **A miss resolves to the vendor default, never to a negative.** A model absent from the\n * deviation list is an ordinary model, not a crippled one. A provider with no table at all has\n * said NOTHING — different again from saying no, and what `undefined` means below.\n */\n\nimport type { TProviderModelCapability } from './provider-model-capability-kind.js';\n\n/** One model that verifiably differs from its vendor's default, and when that was checked. */\nexport interface IModelCapabilityDeviation {\n /** The complete capability set for this model — not a delta against the default. */\n capabilities: readonly TProviderModelCapability[];\n /** ISO date this deviation was verified against the vendor's documentation. */\n verifiedAt: string;\n sourceUrl?: string;\n}\n\n/**\n * What a provider package declares about its own models.\n *\n * A package with no verified source for its vendor's baseline declares NO TABLE rather than an empty\n * one: an empty default would resolve every capability to \"false\", which is the silence-read-as-denial\n * inversion this contract exists to forbid.\n */\nexport interface IProviderCapabilityTable {\n /** What this vendor's models can do unless a model below says otherwise. */\n vendorDefault: readonly TProviderModelCapability[];\n /** Only models that verifiably differ. Absent means none do. */\n deviations?: Readonly<Record<string, IModelCapabilityDeviation>>;\n /** ISO date the vendor default was verified. */\n verifiedAt: string;\n sourceUrl?: string;\n}\n\n/**\n * The capability set that applies to a model, or `undefined` when nothing has been declared.\n *\n * A model with no deviation gets the vendor default — the rule that makes a short table safe.\n */\nexport function resolveModelCapabilities(\n table: IProviderCapabilityTable | undefined,\n modelId: string,\n): readonly TProviderModelCapability[] | undefined {\n if (!table) return undefined;\n return table.deviations?.[modelId]?.capabilities ?? table.vendorDefault;\n}\n\n/**\n * Whether a model declares a capability.\n *\n * Returns `undefined` when nothing has said — no table, or a table with no answer for this model.\n */\nexport function modelDeclaresCapability(\n table: IProviderCapabilityTable | undefined,\n modelId: string,\n capability: TProviderModelCapability,\n): boolean | undefined {\n const capabilities = resolveModelCapabilities(table, modelId);\n // An EMPTY list is silence, not a blanket denial. A presence check alone lets `[]` through, and\n // `[].includes(x)` answers `false` — so a table whose author had not filled the list in yet would\n // read as a model that can do nothing, stripping its tools. That is the exact inversion this\n // module's contract forbids, in the one shape a presence check does not catch.\n if (!capabilities || capabilities.length === 0) return undefined;\n return capabilities.includes(capability);\n}\n\n/**\n * Resolve a capability question with an explicit answer for silence.\n *\n * The shape every consumer wants: \"can this model do X, and if nothing has said, what do I assume?\"\n * Writing the assumption at the call site is the point — an assumption nobody states is the reason\n * this vocabulary went unread for as long as it did.\n */\nexport function resolveModelCapability(\n table: IProviderCapabilityTable | undefined,\n modelId: string,\n capability: TProviderModelCapability,\n whenNothingIsDeclared: boolean,\n): boolean {\n return modelDeclaresCapability(table, modelId, capability) ?? whenNothingIsDeclared;\n}\n","import type { TUniversalValue } from './types';\n\n/**\n * Provider-agnostic media output reference.\n * Providers must not return raw binary payloads in this contract.\n */\nexport interface IMediaOutputRef {\n kind: 'asset' | 'uri';\n assetId?: string;\n uri?: string;\n mimeType?: string;\n bytes?: number;\n}\n\nexport interface IProviderMediaError {\n code:\n | 'PROVIDER_AUTH_ERROR'\n | 'PROVIDER_RATE_LIMITED'\n | 'PROVIDER_TIMEOUT'\n | 'PROVIDER_INVALID_REQUEST'\n | 'PROVIDER_UPSTREAM_ERROR'\n | 'PROVIDER_JOB_NOT_FOUND'\n | 'PROVIDER_JOB_NOT_CANCELLABLE';\n message: string;\n details?: Record<string, TUniversalValue>;\n /** The vendor's HTTP status, when the failure was an HTTP response. */\n status?: number;\n}\n\nexport type TProviderMediaResult<TValue> =\n { ok: true; value: TValue } | { ok: false; error: IProviderMediaError };\n\nexport interface IInlineImageInputSource {\n kind: 'inline';\n mimeType: string;\n data: string;\n}\n\nexport interface IUriImageInputSource {\n kind: 'uri';\n uri: string;\n mimeType?: string;\n}\n\nexport type TImageInputSource = IInlineImageInputSource | IUriImageInputSource;\n\nexport interface IImageGenerationRequest {\n prompt: string;\n model: string;\n}\n\nexport interface IImageEditRequest {\n image: TImageInputSource;\n prompt: string;\n model: string;\n}\n\nexport interface IImageComposeRequest {\n images: TImageInputSource[];\n prompt: string;\n model: string;\n}\n\nexport interface IImageGenerationResult {\n outputs: IMediaOutputRef[];\n model: string;\n}\n\nexport interface IImageGenerationProvider {\n generateImage(\n request: IImageGenerationRequest,\n ): Promise<TProviderMediaResult<IImageGenerationResult>>;\n editImage?(request: IImageEditRequest): Promise<TProviderMediaResult<IImageGenerationResult>>;\n composeImage?(\n request: IImageComposeRequest,\n ): Promise<TProviderMediaResult<IImageGenerationResult>>;\n}\n\nexport interface IVideoGenerationRequest {\n prompt: string;\n model: string;\n durationSeconds?: number;\n aspectRatio?: string;\n seed?: number;\n inputImages?: TImageInputSource[];\n}\n\nexport interface IVideoJobAccepted {\n jobId: string;\n status: 'queued' | 'running';\n createdAt: string;\n}\n\nexport interface IVideoJobSnapshot {\n jobId: string;\n status: 'queued' | 'running' | 'succeeded' | 'failed' | 'cancelled';\n output?: IMediaOutputRef;\n error?: IProviderMediaError;\n updatedAt: string;\n}\n\nexport interface IVideoGenerationProvider {\n createVideo(request: IVideoGenerationRequest): Promise<TProviderMediaResult<IVideoJobAccepted>>;\n getVideoJob(jobId: string): Promise<TProviderMediaResult<IVideoJobSnapshot>>;\n cancelVideoJob(jobId: string): Promise<TProviderMediaResult<IVideoJobSnapshot>>;\n}\n\nexport function isImageGenerationProvider(provider: object): provider is IImageGenerationProvider {\n return (\n 'generateImage' in provider &&\n typeof (\n provider as {\n generateImage?: (...args: never[]) => Promise<TProviderMediaResult<IImageGenerationResult>>;\n }\n ).generateImage === 'function'\n );\n}\n\nexport function isVideoGenerationProvider(provider: object): provider is IVideoGenerationProvider {\n return (\n 'createVideo' in provider &&\n 'getVideoJob' in provider &&\n 'cancelVideoJob' in provider &&\n typeof (\n provider as {\n createVideo?: (...args: never[]) => Promise<TProviderMediaResult<IVideoJobAccepted>>;\n }\n ).createVideo === 'function' &&\n typeof (\n provider as {\n getVideoJob?: (...args: never[]) => Promise<TProviderMediaResult<IVideoJobSnapshot>>;\n }\n ).getVideoJob === 'function' &&\n typeof (\n provider as {\n cancelVideoJob?: (...args: never[]) => Promise<TProviderMediaResult<IVideoJobSnapshot>>;\n }\n ).cancelVideoJob === 'function'\n );\n}\n","import type { IImageGenerationProvider, IVideoGenerationProvider } from './media-provider.js';\n\n/** Values resolved by a media provider factory at execution time. */\nexport interface IMediaProviderConfig {\n readonly credential?: string;\n readonly baseUrl?: string;\n /** The node's resolved model allowlist, passed to image-capable provider factories. */\n readonly imageCapableModels?: readonly string[];\n}\n\n/** Environment-variable names used to resolve a media provider's credential and endpoint. */\nexport interface IMediaProviderCredentialRequirement {\n readonly credentialEnvVars: readonly string[];\n readonly baseUrlEnvVars?: readonly string[];\n readonly requiresBaseUrl?: boolean;\n}\n\n/**\n * A late-bound media provider definition. DAG nodes receive this definition and create a provider\n * during execution, preserving credential-free node discovery and typed missing-credential errors.\n */\nexport interface IMediaProviderDefinition {\n readonly type: string;\n readonly displayName?: string;\n readonly credentialRequirement?: IMediaProviderCredentialRequirement;\n readonly defaults?: {\n readonly model?: string;\n readonly allowedModels?: readonly string[];\n readonly baseUrl?: string;\n };\n readonly createImageProvider?: (config: IMediaProviderConfig) => IImageGenerationProvider;\n readonly createVideoProvider?: (config: IMediaProviderConfig) => IVideoGenerationProvider;\n}\n\nexport function isMediaProviderDefinition(value: unknown): value is IMediaProviderDefinition {\n if (typeof value !== 'object' || value === null) return false;\n const candidate = value as Partial<IMediaProviderDefinition>;\n return (\n typeof candidate.type === 'string' &&\n candidate.type.length > 0 &&\n (typeof candidate.createImageProvider === 'function' ||\n typeof candidate.createVideoProvider === 'function')\n );\n}\n\nexport function findMediaProviderDefinition(\n definitions: readonly IMediaProviderDefinition[],\n type: string,\n): IMediaProviderDefinition | undefined {\n return definitions.find((definition) => definition.type === type);\n}\n","/**\n * Tool search vocabulary (CLI-1990) — the client-side residency contract.\n *\n * A tool schema may declare `deferLoading` (`IToolSchema`); when the policy engages, such a schema\n * is WITHHELD from the request entirely until it is loaded — by the model calling the search tool,\n * or by a `toolChoice` that forces the tool. This is stronger than the vendor feature it is named\n * after: `defer_loading` keeps a definition out of the context window while the request still\n * carries it, whereas here the schema leaves the request. Every provider gets the same behaviour,\n * because the model-visible artifact is an ordinary function tool and the catalog is ours.\n *\n * The full contract is agent-core `docs/SPEC.md` § Tool Residency and Tool Search.\n */\n\nimport type { IToolSchema } from './tool-schema';\n\n/**\n * The registered name of the model-facing search tool.\n *\n * Owned here rather than in the package that ships the tool because the execution layer names it in\n * the unknown-tool remedy — the message that tells a model which tool loads the one it just called.\n * agent-tools registers its builtin under this name.\n */\nexport const TOOL_SEARCH_TOOL_NAME = 'ToolSearch';\n\n/**\n * `IAgentConfig.toolSearch`. `'auto'` (the default) engages deferral by threshold —\n * `resolveToolSearchMode` — so ten resident tools cost nothing; `'on'` / `'off'` force the answer.\n */\nexport type TToolSearchSetting = 'auto' | 'on' | 'off';\n\n/** The resolved answer: whether deferred schemas are withheld from the model's tool list. */\nexport type TToolSearchMode = 'on' | 'off';\n\n/**\n * The catalog a search tool loads through — the port `IToolExecutionContext.deferredTools` carries.\n *\n * Narrow on purpose: a tool that can list and load must not be able to register, remove or execute.\n */\nexport interface IDeferredToolCatalog {\n /**\n * Deferred tools not yet loaded — the population a search can still discover. Empty while\n * deferral is not engaged, because nothing is withheld then.\n */\n listDeferredTools(): IToolSchema[];\n /**\n * Mark the named deferred tools loaded for the rest of the session and return their schemas. A\n * resident name is returned as it is (it was never withheld); an unknown name throws, naming the\n * entry, and then nothing is loaded — the check runs over every name before the first load.\n */\n loadDeferredTools(names: readonly string[]): IToolSchema[];\n}\n","/**\n * Ergonomic constructors for {@link IActionRequest} plus the {@link isConfirmed} response helper\n * (CMD-004). The contract stays a single shape; these keep call sites readable so producers do not\n * hand-assemble the field combinations for confirm / single / multi / text.\n */\n\nimport type { IActionDefault, IActionOption, IActionRequest, TActionResponse } from './interaction';\n\n/** Option value for the affirmative choice of a confirmation. */\nexport const CONFIRM_YES = 'yes';\n/** Option value for the negative choice of a confirmation. */\nexport const CONFIRM_NO = 'no';\n\nconst CONFIRM_OPTIONS: readonly IActionOption[] = [\n { value: CONFIRM_YES, label: 'Yes' },\n { value: CONFIRM_NO, label: 'No' },\n];\n\n/** Build a yes/no confirmation action (two options, single selection). */\nexport function confirmAction(\n id: string,\n message: string,\n extra?: { description?: string; defaultYes?: boolean },\n): IActionRequest {\n return {\n id,\n title: message,\n description: extra?.description,\n options: CONFIRM_OPTIONS,\n maxSelect: 1,\n default:\n extra?.defaultYes === undefined\n ? undefined\n : { values: [extra.defaultYes ? CONFIRM_YES : CONFIRM_NO] },\n };\n}\n\n/** Build a single-select action (optionally allowing a typed custom answer). */\nexport function selectAction(\n id: string,\n title: string,\n options: readonly IActionOption[],\n extra?: {\n description?: string;\n allowFreeText?: boolean;\n maxVisible?: number;\n default?: IActionDefault;\n },\n): IActionRequest {\n return {\n id,\n title,\n options,\n maxSelect: 1,\n description: extra?.description,\n allowFreeText: extra?.allowFreeText,\n maxVisible: extra?.maxVisible,\n default: extra?.default,\n };\n}\n\n/** Build a multi-select action (min/max selections; defaults: min 1, max = number of options). */\nexport function multiSelectAction(\n id: string,\n title: string,\n options: readonly IActionOption[],\n extra?: {\n description?: string;\n minSelect?: number;\n maxSelect?: number;\n maxVisible?: number;\n default?: IActionDefault;\n },\n): IActionRequest {\n return {\n id,\n title,\n options,\n minSelect: extra?.minSelect ?? 1,\n maxSelect: extra?.maxSelect ?? options.length,\n description: extra?.description,\n maxVisible: extra?.maxVisible,\n default: extra?.default,\n };\n}\n\n/** Build a free-text action (optionally masked for secret entry such as an API key). */\nexport function textAction(\n id: string,\n title: string,\n extra?: {\n description?: string;\n masked?: boolean;\n allowEmpty?: boolean;\n placeholder?: string;\n default?: IActionDefault;\n },\n): IActionRequest {\n return {\n id,\n title,\n allowFreeText: true,\n description: extra?.description,\n masked: extra?.masked,\n allowEmpty: extra?.allowEmpty,\n placeholder: extra?.placeholder,\n default: extra?.default,\n };\n}\n\n/** True when the user answered a {@link confirmAction} affirmatively (selected \"Yes\"). */\nexport function isConfirmed(response: TActionResponse): boolean {\n return response.type === 'answer' && response.values.includes(CONFIRM_YES);\n}\n","import type { ITool, TToolParameters } from './tool';\n\n/**\n * Execution step definition for tools that support step-by-step progress reporting\n */\nexport interface IToolExecutionStep {\n /** Unique identifier for this step */\n id: string;\n\n /** Human-readable name of the step */\n name: string;\n\n /** Tool-provided estimated duration for this step in milliseconds */\n estimatedDuration: number;\n\n /** Optional description of what this step does */\n description?: string;\n}\n\n/**\n * Progress callback function type for real-time progress updates\n */\nexport type TToolProgressCallback = (step: string, progress: number) => void;\n\n/**\n * 🆕 IProgressReportingTool - Optional interface for tools that can provide their own progress information\n *\n * This interface extends the standard ITool to allow tools to optionally provide:\n * - Estimated execution duration\n * - Step-by-step execution plans\n * - Real-time progress callbacks\n *\n * Benefits:\n * - Tools can provide accurate progress information based on their internal knowledge\n * - No simulation or fake progress - only real tool-provided estimates\n * - Completely optional - existing tools work unchanged\n * - Tools can self-report progress for better user experience\n */\nexport interface IProgressReportingTool extends ITool {\n /**\n * Get estimated execution duration for given parameters (optional)\n *\n * Tools can implement this to provide accurate time estimates based on:\n * - Parameter complexity (e.g., search query length, file size)\n * - Historical execution data\n * - Internal optimization knowledge\n *\n * @param parameters - The parameters that will be passed to execute()\n * @returns Estimated duration in milliseconds, or undefined if not available\n */\n getEstimatedDuration?(parameters: TToolParameters): number;\n\n /**\n * Get execution steps for given parameters (optional)\n *\n * Tools can implement this to provide step-by-step execution plans:\n * - webSearch: [query processing, API call, result parsing, filtering]\n * - fileSearch: [file scanning, content reading, pattern matching, result formatting]\n * - github-mcp: [authentication, API request, response processing, data transformation]\n *\n * @param parameters - The parameters that will be passed to execute()\n * @returns Array of execution steps, or undefined if not available\n */\n getExecutionSteps?(parameters: TToolParameters): IToolExecutionStep[];\n\n /**\n * Set progress callback for real-time updates (optional)\n *\n * Tools can implement this to provide real-time progress updates during execution:\n * - Called when each step starts/completes\n * - Progress value between 0-100 representing completion percentage\n * - Step name helps users understand what's currently happening\n *\n * @param callback - Function to call with progress updates\n */\n setProgressCallback?(callback: TToolProgressCallback): void;\n}\n\n/**\n * Type guard to check if a tool implements progress reporting\n */\nexport function isProgressReportingTool(tool: ITool): tool is IProgressReportingTool {\n return (\n 'getEstimatedDuration' in tool || 'getExecutionSteps' in tool || 'setProgressCallback' in tool\n );\n}\n\n/**\n * Helper function to safely get estimated duration from any tool\n */\nexport function getToolEstimatedDuration(\n tool: ITool,\n parameters: TToolParameters,\n): number | undefined {\n if (isProgressReportingTool(tool) && tool.getEstimatedDuration) {\n return tool.getEstimatedDuration(parameters);\n }\n return undefined;\n}\n\n/**\n * Helper function to safely get execution steps from any tool\n */\nexport function getToolExecutionSteps(\n tool: ITool,\n parameters: TToolParameters,\n): IToolExecutionStep[] | undefined {\n if (isProgressReportingTool(tool) && tool.getExecutionSteps) {\n return tool.getExecutionSteps(parameters);\n }\n return undefined;\n}\n\n/**\n * Helper function to safely set progress callback on any tool\n */\nexport function setToolProgressCallback(tool: ITool, callback: TToolProgressCallback): boolean {\n if (isProgressReportingTool(tool) && tool.setProgressCallback) {\n tool.setProgressCallback(callback);\n return true;\n }\n return false;\n}\n","/**\n * @fileoverview Abstract Agent Base Class\n *\n * 🎯 ABSTRACT CLASS - DO NOT DEPEND ON CONCRETE IMPLEMENTATIONS\n *\n * This class defines the foundational lifecycle for agent implementations.\n * Subclasses provide provider/tool-specific behavior while inheriting the\n * shared guarantees around initialization, history, and disposal.\n */\nimport type { IAgent, IAgentConfig, TUniversalMessage, IRunOptions } from '../interfaces/agent';\n\nexport abstract class AbstractAgent<\n TConfig = IAgentConfig,\n TContext = IRunOptions,\n TMessage = TUniversalMessage,\n> implements IAgent<TConfig, TContext, TMessage> {\n protected history: TMessage[] = [];\n protected isInitialized = false;\n protected config?: TConfig;\n\n /**\n * Initialize the agent (subclass responsibility)\n */\n protected abstract initialize(): Promise<void>;\n\n /**\n * Configure the agent with type-safe configuration\n */\n async configure(config: TConfig): Promise<void> {\n this.config = config;\n await this.ensureInitialized();\n }\n\n /**\n * Run agent with user input and type-safe context\n */\n abstract run(input: string, context?: TContext): Promise<string>;\n\n /**\n * Run agent with streaming response and type-safe context\n */\n abstract runStream(input: string, context?: TContext): AsyncGenerator<string, string, never>;\n\n /**\n * Get conversation history with type-safe messages\n */\n getHistory(): TMessage[] {\n return [...this.history];\n }\n\n /**\n * Clear conversation history\n */\n clearHistory(): void {\n this.history = [];\n }\n\n /**\n * Add message to history\n */\n protected addMessage(message: TMessage): void {\n this.history.push(message);\n }\n\n /**\n * Validate user input\n */\n protected validateInput(input: string): void {\n if (!input || typeof input !== 'string') {\n throw new Error('Input must be a non-empty string');\n }\n }\n\n /**\n * Ensure agent is initialized before running\n */\n protected async ensureInitialized(): Promise<void> {\n if (!this.isInitialized) {\n await this.initialize();\n this.isInitialized = true;\n }\n }\n\n /**\n * Cleanup resources\n */\n async dispose(): Promise<void> {\n this.clearHistory();\n this.isInitialized = false;\n }\n}\n","/**\n * @fileoverview Abstract Manager Base Class\n *\n * 🎯 ABSTRACT CLASS - DO NOT IMPORT CONCRETE IMPLEMENTATIONS\n *\n * This class defines the common lifecycle contract for all manager implementations.\n * It enforces explicit initialization/disposal semantics so that subclasses can\n * provide their own resource management logic while sharing guard rails.\n *\n * Architectural rules:\n * - Depends only on abstractions (no concrete manager implementations)\n * - Provides finalize hooks (`doInitialize`, `doDispose`) for subclasses\n * - Guards public APIs via `ensureInitialized`\n */\n\n/** Construction-time lifecycle declaration for a manager. */\nexport interface IManagerLifecycleOptions {\n /**\n * Declare that this manager needs no asynchronous setup, so its API works from construction.\n *\n * CORE-045: a manager whose `doInitialize` does nothing still refused every guarded call until\n * something awaited `initialize()`. That turned a public API into a trap — `registerTool` and\n * `swapDefaultProvider` threw on every freshly constructed agent — while protecting nothing,\n * because there was no asynchronous state for a caller to race. Declare this only when\n * `doInitialize` genuinely has no work to wait for; the guard remains meaningful either way,\n * since disposal returns the manager to a refusing state.\n */\n readyOnConstruction?: boolean;\n}\n\nexport abstract class AbstractManager {\n protected initialized = false;\n private disposed = false;\n\n protected constructor(options: IManagerLifecycleOptions = {}) {\n this.initialized = options.readyOnConstruction === true;\n }\n\n /**\n * Initialize the manager (idempotent)\n */\n async initialize(): Promise<void> {\n if (this.initialized) {\n return;\n }\n await this.doInitialize();\n this.initialized = true;\n // Disposal is reversible by an explicit re-initialize, which is the contract this class has\n // always had (both hooks are documented idempotent). What must not happen is a disposed manager\n // silently answering as though nothing happened -- hence the flag, not a permanent tombstone.\n this.disposed = false;\n }\n\n /**\n * Subclass-specific initialization logic\n */\n protected abstract doInitialize(): Promise<void>;\n\n /**\n * Dispose manager resources (idempotent)\n */\n async dispose(): Promise<void> {\n await this.doDispose();\n this.initialized = false;\n this.disposed = true;\n }\n\n /**\n * Subclass-specific disposal logic\n */\n protected abstract doDispose(): Promise<void>;\n\n /**\n * Whether the manager completed initialization\n */\n isInitialized(): boolean {\n return this.initialized;\n }\n\n /**\n * Ensure manager is usable before performing operations.\n *\n * The two refusing states are reported separately because they describe different situations: an\n * uninitialized manager is waiting for its owner to call `initialize()`, while a disposed one has\n * been torn down and its resources released. Reporting both as \"not initialized\" sent CORE-045's\n * investigation looking for a missing await that did not exist.\n */\n protected ensureInitialized(): void {\n if (this.disposed) {\n throw new Error(\n `${this.constructor.name} was disposed — re-initialize it before use, or build a new one`,\n );\n }\n if (!this.initialized) {\n throw new Error(`${this.constructor.name} is not initialized`);\n }\n }\n}\n","/**\n * Helper functions for AbstractAIProvider.\n *\n * Extracted from abstracts/abstract-ai-provider.ts to keep that file under 300 lines.\n * Contains message/tool validation and executor delegation utilities.\n */\nimport type { IExecutor, IExecutorChatResult, TExecutorStreamEvent } from '../interfaces/executor';\nimport type { TUniversalMessage } from '../interfaces/messages';\nimport type { IToolSchema, IChatOptions } from '../interfaces/provider';\n\n/**\n * Validate that messages is a non-empty array of messages with valid roles.\n * Throws if validation fails.\n */\nexport function validateProviderMessages(messages: TUniversalMessage[]): void {\n if (!Array.isArray(messages)) {\n throw new Error('Messages must be an array');\n }\n if (messages.length === 0) {\n throw new Error('Messages array cannot be empty');\n }\n for (const message of messages) {\n if (!message.role || !['user', 'assistant', 'system', 'tool'].includes(message.role)) {\n throw new Error(`Invalid message role: ${message.role}`);\n }\n }\n}\n\n/**\n * Validate that tools is an array of tool schemas with name, description, and parameters.\n * No-ops if tools is undefined.\n */\nexport function validateProviderTools(tools?: IToolSchema[]): void {\n if (!tools) return;\n if (!Array.isArray(tools)) {\n throw new Error('Tools must be an array');\n }\n for (const tool of tools) {\n if (!tool.name || typeof tool.name !== 'string') {\n throw new Error('Tool must have a valid name');\n }\n if (!tool.description || typeof tool.description !== 'string') {\n throw new Error('Tool must have a valid description');\n }\n if (\n !tool.parameters ||\n typeof tool.parameters !== 'object' ||\n tool.parameters === null ||\n Array.isArray(tool.parameters)\n ) {\n throw new Error('Tool must have valid parameters');\n }\n }\n}\n\n/**\n * Execute a chat request via an injected executor (non-streaming).\n * Throws if executor or model is missing.\n */\nexport async function executeChatViaExecutor(\n executor: IExecutor | undefined,\n providerName: string,\n messages: TUniversalMessage[],\n options?: IChatOptions,\n): Promise<IExecutorChatResult> {\n if (!executor) {\n throw new Error(\n `Executor is required for ${providerName} provider. Configure an executor or use direct execution path.`,\n );\n }\n if (!options?.model) {\n throw new Error(`Model is required for executor execution in ${providerName} provider.`);\n }\n const result = await executor.executeChat({\n messages,\n options,\n provider: providerName,\n model: options.model,\n ...(options.tools && { tools: options.tools }),\n });\n return result;\n}\n\n/**\n * Execute a streaming chat request via an injected executor.\n * Throws if executor or model is missing.\n */\nexport async function* executeChatStreamViaExecutor(\n executor: IExecutor | undefined,\n providerName: string,\n messages: TUniversalMessage[],\n options?: IChatOptions,\n): AsyncIterable<TExecutorStreamEvent> {\n if (!executor || !executor.executeChatStream) {\n throw new Error(`Streaming executor is required for ${providerName} provider.`);\n }\n if (!options?.model) {\n throw new Error(`Model is required for executor streaming in ${providerName} provider.`);\n }\n const stream = executor.executeChatStream({\n messages,\n options,\n provider: providerName,\n model: options.model,\n stream: true,\n ...(options.tools && { tools: options.tools }),\n });\n let terminalSeen = false;\n for await (const event of stream) {\n if (event.kind === 'terminal') {\n if (terminalSeen) {\n throw new Error(`Executor \"${providerName}\" emitted more than one stream terminal result.`);\n }\n terminalSeen = true;\n }\n yield event;\n }\n if (!terminalSeen) {\n throw new Error(`Executor \"${providerName}\" ended a stream without a terminal result.`);\n }\n}\n","import { executeChatStreamViaExecutor } from './ai-provider-helpers';\n\nimport type { IExecutor, TExecutorStreamEvent } from '../interfaces/executor';\nimport type { TUniversalMessage } from '../interfaces/messages';\nimport type { IChatOptions, IToolSchema } from '../interfaces/provider';\nimport type { ILogger } from '../utils/logger';\n\n/** Log and delegate a provider streaming call through its configured executor. */\nexport async function* executeProviderStreamViaExecutor(\n logger: ILogger,\n executor: IExecutor | undefined,\n providerName: string,\n messages: TUniversalMessage[],\n options?: IChatOptions,\n): AsyncIterable<TExecutorStreamEvent> {\n logger.debug?.(\n '🔍 [TOOL-FLOW] AbstractAIProvider.executeStreamViaExecutorOrDirect() - Executor request',\n {\n provider: providerName,\n model: options?.model,\n hasTools: !!options?.tools,\n toolsCount: options?.tools?.length || 0,\n toolNames: options?.tools?.map((tool: IToolSchema) => tool.name) || [],\n },\n );\n yield* executeChatStreamViaExecutor(executor, providerName, messages, options);\n}\n","/**\n * Message Contracts (Single Source of Truth)\n *\n * IMPORTANT:\n * - This module is owned by the `interfaces` layer.\n * - All message types used across the SDK must be defined here to avoid drift.\n * - Runtime values (variables/classes/objects) and compile-time types can share the same name in TypeScript.\n * Prefixing type aliases (`T*`) and interfaces (`I*`) reduces value/type name collision risk and review overhead.\n */\n\n/**\n * Universal message role type - provider-independent neutral role.\n */\nexport type TUniversalMessageRole = 'user' | 'assistant' | 'system' | 'tool';\n\n/**\n * Message metadata used across conversation history and provider adapters.\n */\nexport type TUniversalMessageMetadata = Record<\n string,\n string | number | boolean | Date | string[] | number[] | Record<string, number>\n>;\n\n/**\n * Universal multimodal message part contracts.\n */\nexport interface ITextMessagePart {\n type: 'text';\n text: string;\n}\n\nexport interface IInlineImageMessagePart {\n type: 'image_inline';\n mimeType: string;\n data: string;\n}\n\nexport interface IUriImageMessagePart {\n type: 'image_uri';\n uri: string;\n mimeType?: string;\n}\n\nexport type TUniversalMessagePart =\n ITextMessagePart | IInlineImageMessagePart | IUriImageMessagePart;\n\n/**\n * Tool call (OpenAI tool calling format).\n */\nexport interface IToolCall {\n id: string;\n type: 'function';\n function: {\n name: string;\n arguments: string;\n };\n}\n\n/** State of a message in conversation history */\nexport type TMessageState = 'complete' | 'interrupted';\n\n/**\n * Base message contract shared by all message variants.\n */\nexport interface IBaseMessage {\n /** Unique message identifier */\n id: string;\n /** Message creation timestamp */\n timestamp: Date;\n /** Whether this message is complete or was interrupted */\n state: TMessageState;\n /** Additional metadata */\n metadata?: TUniversalMessageMetadata;\n}\n\nexport interface IUserMessage extends IBaseMessage {\n role: 'user';\n content: string;\n parts?: TUniversalMessagePart[];\n name?: string;\n}\n\nexport interface IAssistantMessage extends IBaseMessage {\n role: 'assistant';\n /** Assistant response content (can be null when making tool calls) */\n content: string | null;\n parts?: TUniversalMessagePart[];\n toolCalls?: IToolCall[];\n}\n\nexport interface ISystemMessage extends IBaseMessage {\n role: 'system';\n content: string;\n parts?: TUniversalMessagePart[];\n name?: string;\n}\n\nexport interface IToolMessage extends IBaseMessage {\n role: 'tool';\n content: string;\n parts?: TUniversalMessagePart[];\n toolCallId: string;\n name?: string;\n}\n\n/**\n * Universal message union used across the SDK as the canonical contract.\n * Used for AI provider communication. Extracted from IHistoryEntry[] via filtering.\n */\nexport type TUniversalMessage = IUserMessage | IAssistantMessage | ISystemMessage | IToolMessage;\n\n/**\n * Universal history entry — the base type for all records in conversation history.\n *\n * History is a universal timeline that records everything: AI chat messages,\n * system events, skill invocations, permission decisions, etc.\n * AI provider receives only chat entries (filtered and converted to TUniversalMessage).\n * TUI can render any range of entries.\n *\n * - append-only, read-only\n * - category + type for classification (free-form strings, no pre-defined enum)\n * - data holds type-specific structured content\n */\nexport interface IHistoryEntry<T = unknown> {\n /** Unique entry identifier */\n id: string;\n /** Entry creation timestamp */\n timestamp: Date;\n /** Top-level classification: 'chat', 'event', etc. */\n category: string;\n /** Sub-classification within category. Free-form, not pre-defined. */\n type: string;\n /** Type-specific structured data */\n data?: T;\n}\n\n/** Check if a history entry is a chat message (for AI provider filtering). */\nexport function isChatEntry(entry: IHistoryEntry): boolean {\n return entry.category === 'chat';\n}\n\n/**\n * Convert a chat history entry to TUniversalMessage for AI provider consumption.\n * Only call on entries where isChatEntry() returns true.\n */\nexport function chatEntryToMessage(entry: IHistoryEntry): TUniversalMessage {\n // data contains the full original message — just restore id/timestamp from entry\n const data = entry.data as Record<string, unknown>;\n if (!data) {\n throw new Error(`Chat entry ${entry.id} has no data`);\n }\n return {\n ...data,\n id: entry.id,\n timestamp: entry.timestamp,\n } as TUniversalMessage;\n}\n\n/**\n * Convert a TUniversalMessage to an IHistoryEntry for storage.\n */\nexport function messageToHistoryEntry(message: TUniversalMessage): IHistoryEntry {\n return {\n id: message.id,\n timestamp: message.timestamp,\n category: 'chat',\n type: message.role,\n data: { ...message },\n };\n}\n\n/**\n * Filter history entries and convert chat entries to TUniversalMessage[].\n * Used when passing conversation to AI provider.\n */\nexport function getMessagesForAPI(history: IHistoryEntry[]): TUniversalMessage[] {\n return history.filter(isChatEntry).map(chatEntryToMessage);\n}\n\n/**\n * Type guards for the canonical TUniversalMessage union.\n *\n * NOTE:\n * - These guards are owned by the `interfaces` layer and must not depend on managers/services.\n * - Call sites should use these guards instead of importing from manager layers.\n */\nexport function isUserMessage(message: TUniversalMessage): message is IUserMessage {\n return message.role === 'user';\n}\n\nexport function isAssistantMessage(message: TUniversalMessage): message is IAssistantMessage {\n return message.role === 'assistant';\n}\n\nexport function isSystemMessage(message: TUniversalMessage): message is ISystemMessage {\n return message.role === 'system';\n}\n\nexport function isToolMessage(message: TUniversalMessage): message is IToolMessage {\n return message.role === 'tool';\n}\n","/** Generic raw-provider model-effort outcome assembly, separate from provider lifecycle code. */\n\nimport { isAssistantMessage } from '../interfaces/messages';\nimport {\n createModelEffortOutcome,\n resolveModelEffort,\n} from '../interfaces/model-effort-capability';\n\nimport type { TUniversalMessage } from '../interfaces/messages';\nimport type {\n IModelEffortOutcome,\n IProviderModelEffortTable,\n} from '../interfaces/model-effort-capability';\nimport type { IChatOptions, IProviderRequest } from '../interfaces/provider';\nimport type { IRawProviderResponse } from '../interfaces/provider';\nimport type { ILogger } from '../utils/logger';\n\ninterface IGenericRawResponseProvider {\n readonly name: string;\n chat(messages: TUniversalMessage[], options?: IChatOptions): Promise<TUniversalMessage>;\n chatStream?(\n messages: TUniversalMessage[],\n options?: IChatOptions,\n ): AsyncIterable<TUniversalMessage>;\n effortTable?(): IProviderModelEffortTable | undefined;\n}\n\nfunction createGenericChatOptions(\n payload: IProviderRequest,\n effortTable: (() => IProviderModelEffortTable | undefined) | undefined,\n logger: ILogger,\n captureTerminalOutcome: (outcome: IModelEffortOutcome) => void,\n): IChatOptions {\n const shouldCaptureTerminalOutcome =\n payload.effort !== undefined || payload.effortResolution !== undefined;\n const observer = payload.onModelEffortOutcome;\n const onModelEffortOutcome = !shouldCaptureTerminalOutcome\n ? observer\n : (outcome: IModelEffortOutcome): void => {\n captureTerminalOutcome(outcome);\n if (observer === undefined) return;\n try {\n observer(outcome);\n } catch (error) {\n logger.warn('Model-effort outcome observer failed', {\n error: error instanceof Error ? error.message : String(error),\n });\n }\n };\n const options: IChatOptions = {\n ...(payload.model !== undefined && { model: payload.model }),\n ...(payload.effort !== undefined && { effort: payload.effort }),\n ...(payload.effortResolution !== undefined && { effortResolution: payload.effortResolution }),\n ...(onModelEffortOutcome !== undefined && { onModelEffortOutcome }),\n ...(payload.temperature !== undefined && { temperature: payload.temperature }),\n ...(payload.maxTokens !== undefined && { maxTokens: payload.maxTokens }),\n ...(payload.tools !== undefined && { tools: payload.tools }),\n };\n if (\n options.effort === undefined ||\n options.effortResolution !== undefined ||\n options.model === undefined\n ) {\n return options;\n }\n return {\n ...options,\n effortResolution: resolveModelEffort(effortTable?.(), options.model, options.effort),\n };\n}\n\nfunction publishGenericNoTableOutcome(\n options: IChatOptions,\n hasEffortTableAccessor: boolean,\n logger: ILogger,\n): IModelEffortOutcome | undefined {\n if (hasEffortTableAccessor) return undefined;\n const resolution = options.effortResolution;\n const observer = options.onModelEffortOutcome;\n if (resolution === undefined || observer === undefined) return undefined;\n const outcome = createModelEffortOutcome(resolution, {\n nativeControl: { state: 'omitted', reason: 'model-effort-not-applied' },\n providerDispatch: { state: 'sent' },\n });\n try {\n observer(outcome);\n } catch (error) {\n logger.warn('Model-effort outcome observer failed', {\n error: error instanceof Error ? error.message : String(error),\n });\n }\n return outcome;\n}\n\nfunction requireGenericTerminalOutcome(\n providerName: string,\n options: IChatOptions,\n terminalOutcome: IModelEffortOutcome | undefined,\n): void {\n if (options.effort !== undefined && terminalOutcome === undefined) {\n throw new Error(\n `Provider \"${providerName}\" did not emit a model-effort terminal outcome for a selected generic request.`,\n );\n }\n}\n\n/** Adapt the common chat contract to one terminal raw response envelope. */\nexport async function generateGenericResponse(\n provider: IGenericRawResponseProvider,\n logger: ILogger,\n payload: IProviderRequest,\n): Promise<IRawProviderResponse> {\n let terminalOutcome: IModelEffortOutcome | undefined;\n const options = createGenericChatOptions(\n payload,\n provider.effortTable?.bind(provider),\n logger,\n (outcome) => {\n terminalOutcome = outcome;\n },\n );\n const response = await provider.chat(payload.messages, options);\n terminalOutcome ??= publishGenericNoTableOutcome(\n options,\n provider.effortTable !== undefined,\n logger,\n );\n requireGenericTerminalOutcome(provider.name, options, terminalOutcome);\n\n return {\n content: response.content ?? null,\n toolCalls: isAssistantMessage(response) ? response.toolCalls : undefined,\n model: payload.model,\n metadata: payload.metadata,\n ...(terminalOutcome !== undefined && { modelEffortOutcome: terminalOutcome }),\n };\n}\n\n/** Adapt a common chat stream to message envelopes followed by one terminal raw envelope. */\nexport async function* generateGenericStreamingResponse(\n provider: IGenericRawResponseProvider,\n logger: ILogger,\n payload: IProviderRequest,\n): AsyncIterable<IRawProviderResponse> {\n if (!provider.chatStream) {\n throw new Error(`[AI-PROVIDER] Streaming is not supported by provider \"${provider.name}\"`);\n }\n\n let terminalOutcome: IModelEffortOutcome | undefined;\n const options = createGenericChatOptions(\n payload,\n provider.effortTable?.bind(provider),\n logger,\n (outcome) => {\n terminalOutcome = outcome;\n },\n );\n for await (const chunk of provider.chatStream(payload.messages, options)) {\n yield {\n content: chunk.content ?? null,\n toolCalls: isAssistantMessage(chunk) ? chunk.toolCalls : undefined,\n model: payload.model,\n metadata: payload.metadata,\n };\n }\n terminalOutcome ??= publishGenericNoTableOutcome(\n options,\n provider.effortTable !== undefined,\n logger,\n );\n requireGenericTerminalOutcome(provider.name, options, terminalOutcome);\n if (terminalOutcome !== undefined) {\n yield {\n content: null,\n model: payload.model,\n metadata: payload.metadata,\n modelEffortOutcome: terminalOutcome,\n };\n }\n}\n","import type { TLoggerData, TUniversalValue } from '../interfaces/types';\n\n/**\n * Reusable type definitions for logger utility\n */\n\n/**\n * Log levels for the logger\n */\nexport type TUtilLogLevel = 'debug' | 'info' | 'warn' | 'error' | 'silent';\n\n/**\n * Log entry structure\n */\nexport interface IUtilLogEntry {\n timestamp: string;\n level: TUtilLogLevel;\n message: string;\n context?: TLoggerData;\n packageName?: string;\n}\n\n/**\n * Logger interface\n */\nexport interface ILogger {\n debug(...args: Array<TUniversalValue | TLoggerData | Error>): void;\n info(...args: Array<TUniversalValue | TLoggerData | Error>): void;\n warn(...args: Array<TUniversalValue | TLoggerData | Error>): void;\n error(...args: Array<TUniversalValue | TLoggerData | Error>): void;\n log(...args: Array<TUniversalValue | TLoggerData | Error>): void;\n group?(label?: string): void;\n groupEnd?(): void;\n}\n\n/**\n * Silent logger that does nothing (Null Object Pattern)\n *\n * IMPORTANT:\n * - This library must not write to stdio by default.\n * - Inject a real logger explicitly if you want output.\n */\nexport const SilentLogger: ILogger = {\n debug: () => {},\n info: () => {},\n warn: () => {},\n error: () => {},\n log: () => {},\n group: () => {},\n groupEnd: () => {},\n};\n\n/**\n * Global logger configuration\n */\nclass LoggerConfig {\n private static instance: LoggerConfig;\n private globalLevel: TUtilLogLevel;\n private globalSink: ILogger | undefined;\n\n private constructor() {\n // Set default level (environment variables no longer used for browser compatibility)\n this.globalLevel = 'warn';\n }\n\n static getInstance(): LoggerConfig {\n if (!LoggerConfig.instance) {\n LoggerConfig.instance = new LoggerConfig();\n }\n return LoggerConfig.instance;\n }\n\n getGlobalLevel(): TUtilLogLevel {\n return this.globalLevel;\n }\n\n setGlobalLevel(level: TUtilLogLevel): void {\n this.globalLevel = level;\n }\n\n getGlobalSink(): ILogger | undefined {\n return this.globalSink;\n }\n\n setGlobalSink(sink: ILogger | undefined): void {\n this.globalSink = sink;\n }\n}\n\n/** How one logger differs from the process-wide defaults. */\nexport interface ILoggerOptions {\n /** Write to this sink instead of the process-wide one. */\n sink?: ILogger;\n /**\n * This logger's own threshold, so a component can be quieter or louder than the process.\n *\n * Without it the only knob was `setGlobalLogLevel`, which is why a per-agent `logging` config\n * ended up silencing the whole process (CORE-029).\n */\n level?: TUtilLogLevel;\n}\n\n/**\n * Console logger implementation\n * @internal\n */\nexport class ConsoleLogger implements ILogger {\n /**\n * This logger's own threshold. `undefined` means \"follow the process-wide level\".\n *\n * CORE-029: the field existed and nothing ever set it, so the only way to change a level was\n * `setGlobalLogLevel` — and `Robota`'s constructor called it from `config.logging`, which meant one\n * agent's per-agent setting silenced every other agent AND every other package in the process.\n * A per-agent option has to reach a per-agent logger.\n */\n private level?: TUtilLogLevel;\n private packageName: string;\n private explicitSink: ILogger | undefined;\n\n /**\n * CORE-029: the sink is resolved PER CALL, not frozen at construction.\n *\n * It used to be `logger || SilentLogger`, decided once in the constructor. No call site in the\n * repository ever passed one and there was no way to set one afterwards, so every diagnostic this\n * package emits — 157 `logger.*` calls, including \"Robota initialization failed\" and every\n * catch-and-log-only path — went to `SilentLogger` by construction. Not \"was not configured\":\n * could not be.\n *\n * Resolving late is what makes a host able to turn logging on at all, and it is also why a logger\n * created during module initialisation still honours a sink installed afterwards.\n */\n constructor(packageName: string, options: ILoggerOptions = {}) {\n this.packageName = packageName;\n this.explicitSink = options.sink;\n this.level = options.level;\n }\n\n private get sinkLogger(): ILogger {\n return this.explicitSink ?? LoggerConfig.getInstance().getGlobalSink() ?? SilentLogger;\n }\n\n debug(...args: Array<TUniversalValue | TLoggerData | Error>): void {\n if (this.shouldLog('debug')) {\n const [message, context] = args;\n this.forward('debug', String(message ?? ''), isLoggerContext(context) ? context : undefined);\n }\n }\n\n info(...args: Array<TUniversalValue | TLoggerData | Error>): void {\n if (this.shouldLog('info')) {\n const [message, context] = args;\n this.forward('info', String(message ?? ''), isLoggerContext(context) ? context : undefined);\n }\n }\n\n warn(...args: Array<TUniversalValue | TLoggerData | Error>): void {\n if (this.shouldLog('warn')) {\n const [message, context] = args;\n this.forward('warn', String(message ?? ''), isLoggerContext(context) ? context : undefined);\n }\n }\n\n error(...args: Array<TUniversalValue | TLoggerData | Error>): void {\n if (this.shouldLog('error')) {\n const [message, context] = args;\n this.forward('error', String(message ?? ''), isLoggerContext(context) ? context : undefined);\n }\n }\n\n log(...args: Array<TUniversalValue | TLoggerData | Error>): void {\n // Alias for info-level output (when enabled).\n this.info(...args);\n }\n\n private getLevel(): TUtilLogLevel {\n return this.level || LoggerConfig.getInstance().getGlobalLevel();\n }\n\n private shouldLog(level: TUtilLogLevel): boolean {\n const currentLevel = this.getLevel();\n if (currentLevel === 'silent') return false;\n\n const levels: TUtilLogLevel[] = ['debug', 'info', 'warn', 'error', 'silent'];\n return levels.indexOf(level) >= levels.indexOf(currentLevel);\n }\n\n private forward(level: TUtilLogLevel, message: string, context?: TLoggerData): void {\n const entry: IUtilLogEntry = {\n timestamp: new Date().toISOString(),\n level,\n message,\n ...(context && { context }),\n packageName: this.packageName,\n };\n\n const formattedMessage = `[${entry.timestamp}] [${entry.level.toUpperCase()}] [${entry.packageName}] ${entry.message}`;\n switch (level) {\n case 'debug':\n this.sinkLogger.debug(formattedMessage, context ?? {});\n return;\n case 'info':\n this.sinkLogger.info(formattedMessage, context ?? {});\n return;\n case 'warn':\n this.sinkLogger.warn(formattedMessage, context ?? {});\n return;\n case 'error':\n this.sinkLogger.error(formattedMessage, context ?? {});\n return;\n case 'silent':\n return;\n }\n }\n}\n\nfunction isLoggerContext(value: unknown): value is TLoggerData {\n return (\n typeof value === 'object' &&\n value !== null &&\n !(value instanceof Error) &&\n !(value instanceof Date) &&\n !Array.isArray(value)\n );\n}\n\n/**\n * Create a named logger instance for a package or module.\n * Use this to create loggers with a specific name prefix for easy log filtering.\n */\nexport function createLogger(packageName: string, options: ILoggerOptions = {}): ILogger {\n return new ConsoleLogger(packageName, options);\n}\n\n/**\n * Set global log level for all loggers\n */\nexport function setGlobalLogLevel(level: TUtilLogLevel): void {\n LoggerConfig.getInstance().setGlobalLevel(level);\n}\n\n/**\n * Get global log level\n */\nexport function getGlobalLogLevel(): TUtilLogLevel {\n return LoggerConfig.getInstance().getGlobalLevel();\n}\n\n/**\n * Install the process-wide sink every logger writes to. CORE-029.\n *\n * Without this there was no way to receive anything this package logs: `createLogger`'s optional\n * sink parameter had no caller anywhere in the repository, and nothing could supply one later, so\n * `SilentLogger` was not a default — it was the only reachable outcome.\n *\n * The default stays SILENT. A library that starts writing to `console` because it was imported is a\n * different defect, so turning diagnostics on remains something a host does deliberately. Pass\n * `undefined` to go back to silence.\n */\nexport function setGlobalLoggerSink(sink: ILogger | undefined): void {\n LoggerConfig.getInstance().setGlobalSink(sink);\n}\n\n/** The installed process-wide sink, or `undefined` when diagnostics are going nowhere. */\nexport function getGlobalLoggerSink(): ILogger | undefined {\n return LoggerConfig.getInstance().getGlobalSink();\n}\n\n/**\n * Default logger for the agents package\n */\nexport const logger = createLogger('agents');\n","/**\n * @fileoverview Abstract AI Provider Base Class\n *\n * 🎯 ABSTRACT CLASS - DO NOT DEPEND ON CONCRETE IMPLEMENTATIONS\n *\n * Defines the shared contract and helper utilities for all AI provider implementations.\n * Concrete providers should extend this class and inject their own dependencies.\n */\nimport { executeProviderStreamViaExecutor } from './abstract-ai-provider-executor-stream';\nimport {\n generateGenericResponse,\n generateGenericStreamingResponse,\n} from './abstract-ai-provider-model-effort';\nimport {\n validateProviderMessages,\n validateProviderTools,\n executeChatViaExecutor,\n} from './ai-provider-helpers';\nimport {\n assertProviderNativeWebToolsAvailable,\n createDefaultProviderCapabilities,\n} from '../interfaces/provider-capabilities';\nimport { hashToolSchema, projectToolSchema } from '../schema/project-tool-schema';\nimport { createLogger, SilentLogger } from '../utils/logger';\n\nimport type { IExecutor, IExecutorChatResult, TExecutorStreamEvent } from '../interfaces/executor';\nimport type { TUniversalMessage } from '../interfaces/messages';\nimport type { IProviderModelEffortTable } from '../interfaces/model-effort-capability';\nimport type {\n IAIProvider,\n IToolSchema,\n IChatOptions,\n IProviderRequest,\n IRawProviderResponse,\n} from '../interfaces/provider';\nimport type {\n IProviderCapabilities,\n IProviderNativeWebToolRequest,\n} from '../interfaces/provider-capabilities';\nimport type { IToolSchemaProjectionProfile } from '../schema/project-tool-schema';\nimport type { ILogger } from '../utils/logger';\n\n/**\n * MCP-005: the global-sink logger every `projectTools` quarantine line goes through.\n *\n * `AnthropicProvider` and `GeminiProvider` construct with no logger, so `this.logger` is\n * `SilentLogger` (`:89` below) — a quarantine reported only there would be silent on two of four\n * providers. `createLogger('ToolSchemaProjection')` is the CORE-040 precedent\n * (`agent-mcp/src/third-party-schema.ts`, `createLogger('ThirdPartySchema')`): audible without an\n * injected logger, because it writes to the process-wide sink a host installs with\n * `setGlobalLoggerSink`.\n */\nconst toolSchemaProjectionLogger: ILogger = createLogger('ToolSchemaProjection');\n\n/**\n * Provider logging data type\n * Used for storing logging information in provider operations\n */\nexport type TProviderLoggingData = Record<string, string | number | boolean | Date | string[]>;\n\n/**\n * Provider configuration base interface\n */\nexport interface IProviderRuntimeConfig {\n apiKey?: string;\n baseUrl?: string;\n timeout?: number;\n [key: string]: string | number | boolean | undefined;\n}\n\n/**\n * Enhanced provider configuration that supports executor injection\n */\nexport interface IExecutorAwareProviderConfig {\n apiKey?: string;\n baseUrl?: string;\n timeout?: number;\n /**\n * Optional executor for handling AI requests\n * When provided, the provider will delegate all chat operations to this executor\n * instead of making direct API calls. This enables remote execution capabilities.\n */\n executor?: IExecutor;\n [key: string]: string | number | boolean | IExecutor | undefined;\n}\n\n/**\n * Base AI provider implementation with proper type constraints.\n * All AI providers should extend this class.\n *\n * Subclasses MUST: extend this class, use override keyword, call super() in constructor,\n * not redefine types that exist in agent-core, handle null message content correctly.\n *\n * @template TConfig - Provider configuration type\n */\nexport abstract class AbstractAIProvider<TConfig = IProviderRuntimeConfig> implements IAIProvider {\n abstract readonly name: string;\n abstract readonly version: string;\n protected config?: TConfig;\n protected executor?: IExecutor;\n protected readonly logger: ILogger;\n\n /**\n * MCP-005 per-tool quarantine memo — instance-scoped (never a module singleton), so one provider\n * instance's cache cannot silence another's, and a re-registered tool with a CHANGED schema is\n * judged and reported again while an unchanged one is not re-reported on every turn. Keyed by\n * `provider.name` + `model` + `tool.name` + `hashToolSchema(tool.parameters)`.\n */\n private readonly quarantinedToolSchemas = new Map<string, true>();\n\n constructor(logger: ILogger = SilentLogger) {\n this.logger = logger;\n }\n\n /**\n * Configure the provider with type-safe configuration\n */\n async configure(config: TConfig): Promise<void> {\n this.config = config;\n\n // Check if config includes executor and set it\n if (this.hasExecutor(config) && config.executor) {\n this.executor = config.executor;\n }\n\n // Subclasses can override for additional setup\n }\n\n private hasExecutor(config: TConfig): config is TConfig & { executor?: IExecutor } {\n return typeof config === 'object' && config !== null && 'executor' in config;\n }\n\n /**\n * Each provider must implement chat using their own native SDK types internally\n * @param messages - Array of messages from conversation history\n * @param options - Chat options including tools, model settings, etc.\n * @returns Promise resolving to a response\n */\n abstract chat(messages: TUniversalMessage[], options?: IChatOptions): Promise<TUniversalMessage>;\n\n /**\n * Wrap an async iterable to yield to the macrotask queue periodically.\n * Providers MUST use this when iterating over streaming events to ensure\n * the main thread event loop stays responsive (ESC abort, Ctrl+C, etc.).\n *\n * Usage in provider:\n * for await (const event of this.streamWithAbort(stream, signal)) { ... }\n */\n protected async *streamWithAbort<T>(\n source: AsyncIterable<T>,\n signal?: AbortSignal,\n ): AsyncGenerator<T> {\n const iterator = source[Symbol.asyncIterator]();\n try {\n while (!signal?.aborted) {\n const item = await nextStreamItem(iterator, signal);\n if (item.done) break;\n await yieldToMacrotask(signal);\n if (signal?.aborted) break;\n yield item.value;\n }\n } finally {\n if (signal?.aborted) {\n await iterator.return?.();\n }\n }\n }\n\n /**\n * Each provider must implement streaming chat using their own native SDK types internally\n * @param messages - Array of messages from conversation history\n * @param options - Chat options including tools, model settings, etc.\n * @returns AsyncIterable of response chunks\n */\n chatStream?(\n messages: TUniversalMessage[],\n options?: IChatOptions,\n ): AsyncIterable<TUniversalMessage>;\n\n /** Optional adapter-owned effort capability data. */\n effortTable?(): IProviderModelEffortTable | undefined;\n\n /**\n * Provider-agnostic raw response API.\n *\n * This is the canonical \"raw payload\" entrypoint required by the AIProvider contract.\n * The default implementation delegates to `chat()` and adapts the result into a\n * RawProviderResponse shape.\n */\n async generateResponse(payload: IProviderRequest): Promise<IRawProviderResponse> {\n return generateGenericResponse(this, this.logger, payload);\n }\n\n /**\n * Provider-agnostic raw streaming API.\n *\n * If a provider does not implement chatStream, it does not support streaming.\n */\n async *generateStreamingResponse(payload: IProviderRequest): AsyncIterable<IRawProviderResponse> {\n yield* generateGenericStreamingResponse(this, this.logger, payload);\n }\n\n /**\n * Default implementation - most modern providers support tools\n * @returns true if tool calling is supported\n */\n supportsTools(): boolean {\n return true;\n }\n\n getCapabilities(): IProviderCapabilities {\n return createDefaultProviderCapabilities(this.supportsTools());\n }\n\n /**\n * Default implementation - providers can override for specific validation\n * @returns true if configuration is valid\n */\n validateConfig(): boolean {\n return true;\n }\n\n /** Validate that messages is a non-empty array with valid roles. */\n protected validateMessages(messages: TUniversalMessage[]): void {\n validateProviderMessages(messages);\n }\n\n /** Validate tool schemas. No-ops if tools is undefined. */\n protected validateTools(tools?: IToolSchema[]): void {\n validateProviderTools(tools);\n }\n\n /**\n * MCP-005: this provider's tool-schema wire constraints, as data. `undefined` (the default) means\n * \"adopt every tool unchanged, no diagnostics\" — today's behaviour, kept for `agent-provider-replay`\n * and any embedding provider that overrides nothing.\n */\n protected projectionProfile(): IToolSchemaProjectionProfile | undefined {\n return undefined;\n }\n\n /**\n * Project `tools` through `projectionProfile()` before handing them to a converter. A helper, not\n * an automatic seam: `chat`/`chatStream` are abstract, so the base runs nothing itself — each\n * concrete provider calls this at its own request-building site(s), after `validateTools` and\n * before its converter.\n *\n * No profile: returns `tools` unchanged (same array, no diagnostics). With a profile: adopted and\n * adapted tools are returned in a NEW array (an adapted tool is a projected COPY; `tools` itself and\n * every original tool object are never mutated); a rejected tool is omitted from the returned array\n * and reported ONCE per cache identity via the global-sink `ToolSchemaProjection` logger.\n */\n protected projectTools(\n tools: IToolSchema[] | undefined,\n model: string,\n ): IToolSchema[] | undefined {\n const profile = this.projectionProfile();\n if (!profile || !tools) {\n return tools;\n }\n\n const kept: IToolSchema[] = [];\n for (const tool of tools) {\n const projection = projectToolSchema(tool, profile);\n if (projection.outcome !== 'rejected') {\n kept.push(projection.tool);\n continue;\n }\n\n const identity = `${this.name}\u0000${model}\u0000${tool.name}\u0000${hashToolSchema(tool.parameters)}`;\n if (this.quarantinedToolSchemas.has(identity)) {\n continue;\n }\n this.quarantinedToolSchemas.set(identity, true);\n\n const { path, keyword, reason } = projection.rejection ?? {\n path: '',\n keyword: '',\n reason: 'rejected',\n };\n toolSchemaProjectionLogger.warn(\n `tool_schema_quarantined provider=${this.name} model=${model} tool=${tool.name} path=${path} keyword=${keyword} reason=${reason}`,\n );\n }\n return kept;\n }\n\n protected validateNativeWebTools(request?: IProviderNativeWebToolRequest): void {\n assertProviderNativeWebToolsAvailable(this.name, this.getCapabilities(), request);\n }\n\n /**\n * Execute chat via executor.\n * Subclasses should call this only when an executor is configured.\n */\n protected async executeViaExecutorOrDirect(\n messages: TUniversalMessage[],\n options?: IChatOptions,\n ): Promise<IExecutorChatResult> {\n return executeChatViaExecutor(this.executor, this.name, messages, options);\n }\n\n /**\n * Execute streaming chat via executor.\n * Subclasses should call this only when an executor is configured.\n */\n protected async *executeStreamViaExecutorOrDirect(\n messages: TUniversalMessage[],\n options?: IChatOptions,\n ): AsyncIterable<TExecutorStreamEvent> {\n yield* executeProviderStreamViaExecutor(\n this.logger,\n this.executor,\n this.name,\n messages,\n options,\n );\n }\n\n /**\n * Clean up resources when provider is no longer needed\n * Override this method in subclasses for additional cleanup\n */\n async dispose(): Promise<void> {\n // Clean up executor if present\n if (this.executor?.dispose) {\n await this.executor.dispose();\n }\n\n // Subclasses can override for additional cleanup\n }\n}\n\nasync function nextStreamItem<T>(\n iterator: AsyncIterator<T>,\n signal?: AbortSignal,\n): Promise<IteratorResult<T>> {\n if (!signal) return iterator.next();\n if (signal.aborted) return { done: true, value: undefined as T };\n\n let abortListener: (() => void) | undefined;\n const aborted = new Promise<IteratorResult<T>>((resolve) => {\n abortListener = (): void => resolve({ done: true, value: undefined as T });\n signal.addEventListener('abort', abortListener, { once: true });\n });\n\n try {\n return await Promise.race([iterator.next(), aborted]);\n } finally {\n if (abortListener) signal.removeEventListener('abort', abortListener);\n }\n}\n\nasync function yieldToMacrotask(signal?: AbortSignal): Promise<void> {\n if (signal?.aborted) return;\n await new Promise<void>((resolve) => setTimeout(resolve, 0));\n}\n","/**\n * Type definitions for AbstractPlugin.\n *\n * Extracted from abstract-plugin.ts to keep each file under 300 lines.\n */\nimport type { IRunOptions } from '../interfaces/run-options';\nimport type { TUniversalMessage } from '../interfaces/messages';\nimport type { ITokenUsage } from '../interfaces/provider';\nimport type {\n TToolParameters,\n IToolExecutionResult,\n IToolExecutionContext,\n} from '../interfaces/tool';\nimport type { TContextData, TMetadata } from '../interfaces/types';\nimport type {\n IEventEmitterEventData,\n IEventEmitterPlugin,\n TEventName,\n} from '../plugins/event-emitter/types';\n\n/** Plugin categories for classification */\nexport enum PluginCategory {\n MONITORING = 'monitoring',\n LOGGING = 'logging',\n STORAGE = 'storage',\n NOTIFICATION = 'notification',\n SECURITY = 'security',\n PERFORMANCE = 'performance',\n ERROR_HANDLING = 'error_handling',\n LIMITS = 'limits',\n EVENT_PROCESSING = 'event_processing',\n CUSTOM = 'custom',\n}\n\nconst PRIORITY_CRITICAL = 1000;\nconst PRIORITY_HIGH = 800;\nconst PRIORITY_NORMAL = 500;\nconst PRIORITY_LOW = 200;\nconst PRIORITY_MINIMAL = 100;\n\n/** Plugin priority levels */\nexport enum PluginPriority {\n CRITICAL = PRIORITY_CRITICAL,\n HIGH = PRIORITY_HIGH,\n NORMAL = PRIORITY_NORMAL,\n LOW = PRIORITY_LOW,\n MINIMAL = PRIORITY_MINIMAL,\n}\n\n/** Plugin execution context for all plugins */\nexport interface IPluginExecutionContext {\n executionId?: string;\n sessionId?: string;\n userId?: string;\n messages?: TUniversalMessage[];\n config?: Record<string, string | number | boolean>;\n metadata?: Record<string, string | number | boolean | Date>;\n [key: string]:\n | string\n | number\n | boolean\n | Date\n | string[]\n | number[]\n | boolean[]\n | TUniversalMessage[]\n | Record<string, string | number | boolean>\n | Record<string, string | number | boolean | Date>\n | undefined;\n}\n\n/** Plugin execution result for all plugins */\nexport interface IPluginExecutionResult {\n response?: string;\n content?: string;\n duration?: number;\n tokensUsed?: number;\n toolsExecuted?: number;\n success?: boolean;\n usage?: Partial<ITokenUsage>;\n toolCalls?: Array<{\n id?: string;\n name?: string;\n arguments?: Record<string, string | number | boolean>;\n result?: string | number | boolean | null;\n }>;\n results?: Array<{\n id?: string;\n type?: string;\n data?: string | number | boolean | null;\n success?: boolean;\n }>;\n error?: Error;\n metadata?: Record<string, string | number | boolean | Date>;\n}\n\n/**\n * Plugin context type - for plugin execution contexts\n *\n * Moved from `interfaces/types.ts` (PLG-020 follow-up): it depends on `IPluginExecutionResult`\n * above, which lives at this abstracts layer.\n */\nexport interface IPluginContext {\n input?: string;\n response?: string;\n messages?: TUniversalMessage[];\n responseMessage?: TUniversalMessage;\n metadata?: TMetadata;\n error?: Error;\n executionContext?: TContextData;\n /** PLG-020 (issue #2460): the run's result, for `afterExecution` / `afterConversation` / `afterToolExecution`. */\n executionResult?: IPluginExecutionResult;\n /** PLG-020 (issue #2460): the message just appended to the conversation, for `onMessageAdded`. */\n message?: TUniversalMessage;\n}\n\n/** Error context for plugin error handling */\nexport interface IPluginErrorContext {\n action: string;\n tool?: string;\n parameters?: TToolParameters;\n result?: IToolExecutionResult;\n error?: Error;\n executionId?: string;\n sessionId?: string;\n userId?: string;\n timestamp?: Date;\n attempt?: number;\n stack?: string;\n metadata?: Record<string, string | number | boolean>;\n}\n\n/** Plugin configuration interface */\nexport interface IPluginConfig extends IPluginOptions {\n options?: Record<string, string | number | boolean>;\n}\n\n/** Plugin options that all plugin options should extend */\nexport interface IPluginOptions {\n enabled?: boolean;\n category?: PluginCategory;\n priority?: PluginPriority | number;\n moduleEvents?: TEventName[];\n subscribeToAllModuleEvents?: boolean;\n}\n\n/** Plugin data interface */\nexport interface IPluginData {\n name: string;\n version: string;\n enabled: boolean;\n category: PluginCategory;\n priority: number;\n subscribedEvents: TEventName[];\n metadata?: Record<string, string | number | boolean>;\n}\n\n/** Type-safe plugin interface with specific type parameters */\nexport interface IPluginContract<\n TOptions extends IPluginOptions = IPluginOptions,\n TStats = IPluginStats,\n> {\n name: string;\n version: string;\n enabled: boolean;\n category: PluginCategory;\n priority: number;\n initialize(options?: TOptions): Promise<void>;\n /**\n * CORE-022: the single component-level disposal entry point. The base implementation\n * unsubscribes module events; overrides release owned resources (timers, sockets,\n * storage) — always calling `super.dispose()`. Driven by `Robota.destroy()`.\n */\n dispose(): Promise<void>;\n cleanup?(): Promise<void>;\n getData?(): IPluginData;\n getStats?(): TStats;\n subscribeToModuleEvents?(eventEmitter: IEventEmitterPlugin): Promise<void>;\n unsubscribeFromModuleEvents?(eventEmitter: IEventEmitterPlugin): Promise<void>;\n onModuleEvent?(eventName: TEventName, eventData: IEventEmitterEventData): Promise<void> | void;\n}\n\n/** Plugin statistics base interface with common metrics */\nexport interface IPluginStats {\n enabled: boolean;\n calls: number;\n errors: number;\n lastActivity?: Date;\n moduleEventsReceived?: number;\n [key: string]:\n | string\n | number\n | boolean\n | Date\n | string[]\n | number[]\n | boolean[]\n | Record<string, string | number | boolean | Date>\n | undefined;\n}\n\n/** Plugin interface extending IPluginContract */\nexport interface IPlugin extends IPluginContract<IPluginConfig, IPluginStats> {}\n\n/** Plugin lifecycle hooks */\nexport interface IPluginHooks {\n beforeRun?(input: string, options?: IRunOptions): Promise<void> | void;\n afterRun?(input: string, response: string, options?: IRunOptions): Promise<void> | void;\n beforeExecution?(context: IPluginExecutionContext): Promise<void> | void;\n afterExecution?(\n context: IPluginExecutionContext,\n result: IPluginExecutionResult,\n ): Promise<void> | void;\n beforeConversation?(context: IPluginExecutionContext): Promise<void> | void;\n afterConversation?(\n context: IPluginExecutionContext,\n result: IPluginExecutionResult,\n ): Promise<void> | void;\n beforeToolCall?(toolName: string, parameters: TToolParameters): Promise<void> | void;\n beforeToolExecution?(\n context: IPluginExecutionContext,\n toolData: IToolExecutionContext,\n ): Promise<void> | void;\n afterToolCall?(\n toolName: string,\n parameters: TToolParameters,\n result: IToolExecutionResult,\n ): Promise<void> | void;\n afterToolExecution?(\n context: IPluginExecutionContext,\n toolResults: IPluginExecutionResult,\n ): Promise<void> | void;\n beforeProviderCall?(messages: TUniversalMessage[]): Promise<void> | void;\n afterProviderCall?(\n messages: TUniversalMessage[],\n response: TUniversalMessage,\n ): Promise<void> | void;\n onStreamingChunk?(chunk: TUniversalMessage): Promise<void> | void;\n onError?(error: Error, context?: IPluginErrorContext): Promise<void> | void;\n onMessageAdded?(message: TUniversalMessage): Promise<void> | void;\n onModuleEvent?(eventName: TEventName, eventData: IEventEmitterEventData): Promise<void> | void;\n}\n","/**\n * Agent event constants\n *\n * Events emitted by Agent instances themselves.\n * Event names are local (no dots) and must be used via constants (no string literals).\n */\nexport const AGENT_EVENTS = {\n /** Agent instance has been created and initialized */\n CREATED: 'created',\n /** Agent execution lifecycle - start */\n EXECUTION_START: 'execution_start',\n /** Agent execution lifecycle - complete */\n EXECUTION_COMPLETE: 'execution_complete',\n /** Agent execution lifecycle - error */\n EXECUTION_ERROR: 'execution_error',\n /** Agent aggregation process completed */\n AGGREGATION_COMPLETE: 'aggregation_complete',\n /** Agent configuration (e.g., tools) has been updated by the agent */\n CONFIG_UPDATED: 'config_updated',\n} as const;\n\nexport const AGENT_EVENT_PREFIX = 'agent' as const;\n\nexport type TAgentEvent = (typeof AGENT_EVENTS)[keyof typeof AGENT_EVENTS];\n","/**\n * ExecutionService owned events.\n * Local event names only (no dots). Full names are composed at emit time.\n */\nexport const EXECUTION_EVENTS = {\n START: 'start',\n COMPLETE: 'complete',\n ERROR: 'error',\n ASSISTANT_MESSAGE_START: 'assistant_message_start',\n ASSISTANT_MESSAGE_COMPLETE: 'assistant_message_complete',\n USER_MESSAGE: 'user_message',\n TOOL_RESULTS_TO_LLM: 'tool_results_to_llm',\n TOOL_RESULTS_READY: 'tool_results_ready',\n} as const;\n\nexport const EXECUTION_EVENT_PREFIX = 'execution' as const;\n","/**\n * ToolExecutionService owned events.\n * Local event names only (no dots). Full names are composed at emit time.\n *\n * Extracted from `tool-execution-service.ts` into a leaf module: `plugins/event-emitter/types.ts`\n * needs only these constants, not the rest of the service module (which imports plugin/manager\n * interfaces) — importing the whole module there created a module-level import cycle.\n * `tool-execution-service.ts` re-exports these names, so existing imports are unaffected.\n */\nexport const TOOL_EVENTS = {\n CALL_START: 'call_start',\n CALL_COMPLETE: 'call_complete',\n CALL_ERROR: 'call_error',\n CALL_RESPONSE_READY: 'call_response_ready',\n} as const;\n\nexport const TOOL_EVENT_PREFIX = 'tool' as const;\n\nexport const UNKNOWN_TOOL_ERROR_CODE = 'unknown_tool' as const;\n\n/**\n * A tool call's arguments failed to decode to a JSON object (invalid JSON, or a non-object root).\n * Marks a per-call batch outcome the same way `UNKNOWN_TOOL_ERROR_CODE` marks a tool the call named\n * that was never invoked — the request is refused before reaching the tool, and the batch's other\n * requests are unaffected.\n */\nexport const ARGUMENT_DECODE_ERROR_CODE = 'argument_decode_error' as const;\n","import { AGENT_EVENTS, AGENT_EVENT_PREFIX } from '../../agents/constants';\nimport { EXECUTION_EVENTS, EXECUTION_EVENT_PREFIX } from '../../services/execution-constants';\nimport { TOOL_EVENTS, TOOL_EVENT_PREFIX } from '../../services/tool-execution-constants';\n\nconst buildEventName = <TPrefix extends string, TLocal extends string>(\n prefix: TPrefix,\n localName: TLocal,\n): `${TPrefix}.${TLocal}` => `${prefix}.${localName}`;\n\nconst EXECUTION_EVENT_NAMES = {\n START: buildEventName(EXECUTION_EVENT_PREFIX, EXECUTION_EVENTS.START),\n COMPLETE: buildEventName(EXECUTION_EVENT_PREFIX, EXECUTION_EVENTS.COMPLETE),\n ERROR: buildEventName(EXECUTION_EVENT_PREFIX, EXECUTION_EVENTS.ERROR),\n} as const;\n\nconst TOOL_EVENT_NAMES = {\n CALL_START: buildEventName(TOOL_EVENT_PREFIX, TOOL_EVENTS.CALL_START),\n CALL_COMPLETE: buildEventName(TOOL_EVENT_PREFIX, TOOL_EVENTS.CALL_COMPLETE),\n CALL_ERROR: buildEventName(TOOL_EVENT_PREFIX, TOOL_EVENTS.CALL_ERROR),\n} as const;\n\nconst AGENT_EVENT_NAMES = {\n EXECUTION_START: buildEventName(AGENT_EVENT_PREFIX, AGENT_EVENTS.EXECUTION_START),\n EXECUTION_COMPLETE: buildEventName(AGENT_EVENT_PREFIX, AGENT_EVENTS.EXECUTION_COMPLETE),\n EXECUTION_ERROR: buildEventName(AGENT_EVENT_PREFIX, AGENT_EVENTS.EXECUTION_ERROR),\n CREATED: buildEventName(AGENT_EVENT_PREFIX, AGENT_EVENTS.CREATED),\n} as const;\n\nexport type TExecutionEventName =\n (typeof EXECUTION_EVENT_NAMES)[keyof typeof EXECUTION_EVENT_NAMES];\ntype TToolEventName = (typeof TOOL_EVENT_NAMES)[keyof typeof TOOL_EVENT_NAMES];\ntype TAgentEventName = (typeof AGENT_EVENT_NAMES)[keyof typeof AGENT_EVENT_NAMES];\n\n/**\n * Event types that can be emitted.\n *\n * IMPORTANT:\n * - Do not use string literals for event names outside this module.\n * - Import and use EVENT_EMITTER_EVENTS instead.\n */\nexport const EVENT_EMITTER_EVENTS = {\n EXECUTION_START: EXECUTION_EVENT_NAMES.START,\n EXECUTION_COMPLETE: EXECUTION_EVENT_NAMES.COMPLETE,\n EXECUTION_ERROR: EXECUTION_EVENT_NAMES.ERROR,\n TOOL_BEFORE_EXECUTE: 'tool.beforeExecute',\n TOOL_AFTER_EXECUTE: 'tool.afterExecute',\n TOOL_SUCCESS: 'tool.success',\n TOOL_ERROR: TOOL_EVENT_NAMES.CALL_ERROR,\n CONVERSATION_START: 'conversation.start',\n CONVERSATION_COMPLETE: 'conversation.complete',\n CONVERSATION_ERROR: 'conversation.error',\n AGENT_EXECUTION_START: AGENT_EVENT_NAMES.EXECUTION_START,\n AGENT_EXECUTION_COMPLETE: AGENT_EVENT_NAMES.EXECUTION_COMPLETE,\n AGENT_EXECUTION_ERROR: AGENT_EVENT_NAMES.EXECUTION_ERROR,\n AGENT_CREATED: AGENT_EVENT_NAMES.CREATED,\n AGENT_DESTROYED: 'agent.destroyed',\n PLUGIN_LOADED: 'plugin.loaded',\n PLUGIN_UNLOADED: 'plugin.unloaded',\n PLUGIN_ERROR: 'plugin.error',\n ERROR_OCCURRED: 'error.occurred',\n WARNING_OCCURRED: 'warning.occurred',\n MODULE_INITIALIZE_START: 'module.initialize.start',\n MODULE_INITIALIZE_COMPLETE: 'module.initialize.complete',\n MODULE_INITIALIZE_ERROR: 'module.initialize.error',\n MODULE_EXECUTION_START: 'module.execution.start',\n MODULE_EXECUTION_COMPLETE: 'module.execution.complete',\n MODULE_EXECUTION_ERROR: 'module.execution.error',\n MODULE_DISPOSE_START: 'module.dispose.start',\n MODULE_DISPOSE_COMPLETE: 'module.dispose.complete',\n MODULE_DISPOSE_ERROR: 'module.dispose.error',\n MODULE_REGISTERED: 'module.registered',\n MODULE_UNREGISTERED: 'module.unregistered',\n EXECUTION_HIERARCHY: 'execution.hierarchy',\n EXECUTION_REALTIME: 'execution.realtime',\n TOOL_REALTIME: 'tool.realtime',\n CUSTOM: 'custom',\n} as const;\n\nexport type TEventName =\n | TExecutionEventName\n | TToolEventName\n | TAgentEventName\n | 'tool.beforeExecute'\n | 'tool.afterExecute'\n | 'tool.success'\n | 'conversation.start'\n | 'conversation.complete'\n | 'conversation.error'\n | 'agent.destroyed'\n | 'plugin.loaded'\n | 'plugin.unloaded'\n | 'plugin.error'\n | 'error.occurred'\n | 'warning.occurred'\n | 'module.initialize.start'\n | 'module.initialize.complete'\n | 'module.initialize.error'\n | 'module.execution.start'\n | 'module.execution.complete'\n | 'module.execution.error'\n | 'module.dispose.start'\n | 'module.dispose.complete'\n | 'module.dispose.error'\n | 'module.registered'\n | 'module.unregistered'\n | 'execution.hierarchy'\n | 'execution.realtime'\n | 'tool.realtime'\n | 'custom';\n\n/**\n * Valid event data value types\n */\nexport type TEventDataValue =\n | string\n | number\n | boolean\n | Date\n | null\n | undefined\n | TEventDataValue[]\n | { [key: string]: TEventDataValue };\n\n/**\n * Event data structure\n */\nexport interface IEventEmitterEventData {\n type: TEventName;\n timestamp: Date;\n executionId?: string;\n sessionId?: string;\n userId?: string;\n data?: Record<string, TEventDataValue>;\n error?: Error;\n metadata?: Record<string, TEventDataValue>;\n}\n\n/**\n * Event listener function\n */\nexport type TEventEmitterListener = (event: IEventEmitterEventData) => void | Promise<void>;\n\n/**\n * Console-like interface for the EventEmitterPlugin.\n *\n * Use this interface for typing instead of the concrete EventEmitterPlugin class.\n */\nexport interface IEventEmitterPlugin {\n on(\n eventType: TEventName,\n listener: TEventEmitterListener,\n options?: {\n once?: boolean;\n filter?: (event: IEventEmitterEventData) => boolean;\n },\n ): string;\n once(\n eventType: TEventName,\n listener: TEventEmitterListener,\n filter?: (event: IEventEmitterEventData) => boolean,\n ): string;\n off(eventType: TEventName, handlerIdOrListener: string | TEventEmitterListener): boolean;\n emit(eventType: TEventName, eventData?: Partial<IEventEmitterEventData>): Promise<void>;\n}\n\n/**\n * Event handler with metadata\n */\nexport interface IEventEmitterHandler {\n id: string;\n listener: TEventEmitterListener;\n once: boolean;\n filter?: (event: IEventEmitterEventData) => boolean;\n}\n","/**\n * Abstract class for all plugins with type parameter support.\n *\n * Type definitions live in ./abstract-plugin-types.ts.\n */\nimport { PluginCategory, PluginPriority } from './abstract-plugin-types';\nimport { EVENT_EMITTER_EVENTS } from '../plugins/event-emitter/types';\nimport { createLogger, type ILogger } from '../utils/logger';\n\nimport type {\n IPluginOptions,\n IPluginStats,\n IPluginConfig,\n IPluginData,\n IPluginContract,\n IPluginHooks,\n IPluginExecutionContext,\n IPluginExecutionResult,\n IPluginErrorContext,\n} from './abstract-plugin-types';\nimport type { IRunOptions } from '../interfaces/agent';\nimport type { TUniversalMessage } from '../interfaces/messages';\nimport type {\n TToolParameters,\n IToolExecutionResult,\n IToolExecutionContext,\n} from '../interfaces/tool';\nimport type {\n IEventEmitterEventData,\n IEventEmitterPlugin,\n TEventName,\n} from '../plugins/event-emitter/types';\n\n// Re-export all types for backward compatibility\nexport type {\n IPluginOptions,\n IPluginStats,\n IPluginConfig,\n IPluginData,\n IPluginContract,\n IPluginHooks,\n IPluginExecutionContext,\n IPluginExecutionResult,\n IPluginErrorContext,\n};\nexport type { IPlugin, IPluginContext } from './abstract-plugin-types';\nexport { PluginCategory, PluginPriority };\n\n/**\n * Abstract class for all plugins with type parameter support.\n * Provides plugin lifecycle management and common functionality.\n * @template TOptions - Plugin options type that extends IPluginOptions\n * @template TStats - Plugin statistics type\n */\nexport abstract class AbstractPlugin<\n TOptions extends IPluginOptions = IPluginOptions,\n TStats extends IPluginStats = IPluginStats,\n>\n implements IPluginContract<TOptions, TStats>, IPluginHooks\n{\n abstract readonly name: string;\n abstract readonly version: string;\n public enabled = true;\n public category: PluginCategory = PluginCategory.CUSTOM;\n public priority: number = PluginPriority.NORMAL;\n protected options: TOptions | undefined;\n protected eventEmitter: IEventEmitterPlugin | undefined;\n protected subscribedEvents: TEventName[] = [];\n protected eventHandlers = new Map<TEventName, string[]>();\n protected readonly pluginLogger: ILogger = createLogger('AbstractPlugin');\n protected stats = {\n calls: 0,\n errors: 0,\n moduleEventsReceived: 0,\n lastActivity: undefined as Date | undefined,\n };\n\n async initialize(options?: TOptions): Promise<void> {\n this.options = options;\n if (options && 'enabled' in options && typeof options.enabled === 'boolean')\n this.enabled = options.enabled;\n else this.enabled = true;\n if (options?.category) this.category = options.category;\n if (options?.priority !== undefined)\n this.priority = typeof options.priority === 'number' ? options.priority : options.priority;\n }\n\n async subscribeToModuleEvents(eventEmitter: IEventEmitterPlugin): Promise<void> {\n this.eventEmitter = eventEmitter;\n if (!this.options) return;\n const eventsToSubscribe: TEventName[] = [];\n if (this.options.subscribeToAllModuleEvents) {\n eventsToSubscribe.push(\n EVENT_EMITTER_EVENTS.MODULE_INITIALIZE_START,\n EVENT_EMITTER_EVENTS.MODULE_INITIALIZE_COMPLETE,\n EVENT_EMITTER_EVENTS.MODULE_INITIALIZE_ERROR,\n EVENT_EMITTER_EVENTS.MODULE_EXECUTION_START,\n EVENT_EMITTER_EVENTS.MODULE_EXECUTION_COMPLETE,\n EVENT_EMITTER_EVENTS.MODULE_EXECUTION_ERROR,\n EVENT_EMITTER_EVENTS.MODULE_DISPOSE_START,\n EVENT_EMITTER_EVENTS.MODULE_DISPOSE_COMPLETE,\n EVENT_EMITTER_EVENTS.MODULE_DISPOSE_ERROR,\n );\n }\n if (this.options.moduleEvents) eventsToSubscribe.push(...this.options.moduleEvents);\n for (const eventType of eventsToSubscribe) {\n const handlerId = this.eventEmitter.on(\n eventType,\n async (eventData: IEventEmitterEventData) => {\n try {\n this.stats.moduleEventsReceived++;\n this.stats.lastActivity = new Date();\n await this.onModuleEvent?.(eventType, eventData);\n } catch (error) {\n this.stats.errors++;\n const safeError = error instanceof Error ? error : new Error(String(error));\n this.pluginLogger.error(\n `Plugin \"${this.name}\" failed to handle module event \"${String(eventType)}\"`,\n { plugin: this.name, eventType: String(eventType), error: safeError.message },\n );\n }\n },\n );\n const existing = this.eventHandlers.get(eventType);\n if (existing) existing.push(handlerId);\n else this.eventHandlers.set(eventType, [handlerId]);\n this.subscribedEvents.push(eventType);\n }\n }\n\n async unsubscribeFromModuleEvents(eventEmitter: IEventEmitterPlugin): Promise<void> {\n for (const [eventType, handlerIds] of this.eventHandlers.entries()) {\n for (const handlerId of handlerIds) eventEmitter.off(eventType, handlerId);\n }\n this.eventHandlers.clear();\n this.subscribedEvents = [];\n this.eventEmitter = undefined;\n }\n\n async dispose(): Promise<void> {\n if (this.eventEmitter) await this.unsubscribeFromModuleEvents(this.eventEmitter);\n }\n enable(): void {\n this.enabled = true;\n }\n disable(): void {\n this.enabled = false;\n }\n isEnabled(): boolean {\n return this.enabled;\n }\n getConfig(): IPluginConfig {\n return {};\n }\n updateConfig(_config: IPluginConfig): void {\n /* override in subclass */\n }\n\n getData(): IPluginData {\n return {\n name: this.name,\n version: this.version,\n enabled: this.enabled,\n category: this.category,\n priority: this.priority,\n subscribedEvents: [...this.subscribedEvents],\n metadata: {\n moduleEventsReceived: this.stats.moduleEventsReceived,\n totalCalls: this.stats.calls,\n totalErrors: this.stats.errors,\n },\n };\n }\n\n clearData?(): void;\n\n getStatus(): {\n name: string;\n version: string;\n enabled: boolean;\n initialized: boolean;\n category: PluginCategory;\n priority: number;\n subscribedEventsCount: number;\n hasEventEmitter: boolean;\n } {\n return {\n name: this.name,\n version: this.version,\n enabled: this.enabled,\n initialized: true,\n category: this.category,\n priority: this.priority,\n subscribedEventsCount: this.subscribedEvents.length,\n hasEventEmitter: !!this.eventEmitter,\n };\n }\n\n getStats(): TStats {\n const baseStats: IPluginStats = {\n enabled: this.enabled,\n calls: this.stats.calls,\n errors: this.stats.errors,\n moduleEventsReceived: this.stats.moduleEventsReceived,\n ...(this.stats.lastActivity && { lastActivity: this.stats.lastActivity }),\n };\n return baseStats as TStats;\n }\n\n protected updateCallStats(): void {\n this.stats.calls++;\n this.stats.lastActivity = new Date();\n }\n protected updateErrorStats(): void {\n this.stats.errors++;\n this.stats.lastActivity = new Date();\n }\n\n // Optional lifecycle hooks - plugins can override these\n async beforeRun?(input: string, options?: IRunOptions): Promise<void>;\n async afterRun?(input: string, response: string, options?: IRunOptions): Promise<void>;\n async beforeExecution?(context: IPluginExecutionContext): Promise<void>;\n async afterExecution?(\n context: IPluginExecutionContext,\n result: IPluginExecutionResult,\n ): Promise<void>;\n async beforeConversation?(context: IPluginExecutionContext): Promise<void>;\n async afterConversation?(\n context: IPluginExecutionContext,\n result: IPluginExecutionResult,\n ): Promise<void>;\n async beforeToolCall?(toolName: string, parameters: TToolParameters): Promise<void>;\n async beforeToolExecution?(\n context: IPluginExecutionContext,\n toolData: IToolExecutionContext,\n ): Promise<void>;\n async afterToolCall?(\n toolName: string,\n parameters: TToolParameters,\n result: IToolExecutionResult,\n ): Promise<void>;\n async afterToolExecution?(\n context: IPluginExecutionContext,\n toolResults: IPluginExecutionResult,\n ): Promise<void>;\n async beforeProviderCall?(messages: TUniversalMessage[]): Promise<void>;\n async afterProviderCall?(\n messages: TUniversalMessage[],\n response: TUniversalMessage,\n ): Promise<void>;\n async onStreamingChunk?(chunk: TUniversalMessage): Promise<void>;\n async onError?(error: Error, context?: IPluginErrorContext): Promise<void>;\n async onMessageAdded?(message: TUniversalMessage): Promise<void>;\n async onModuleEvent?(eventName: TEventName, eventData: IEventEmitterEventData): Promise<void>;\n}\n","import { SilentLogger } from '../utils/logger';\n\nimport type {\n IExecutor,\n IChatExecutionRequest,\n IStreamExecutionRequest,\n IExecutorChatResult,\n TExecutorStreamEvent,\n} from '../interfaces/executor';\nimport type { TUniversalMessage, IAssistantMessage } from '../interfaces/messages';\nimport type { TLoggerData } from '../interfaces/types';\nimport type { ILogger } from '../utils/logger';\n\n/**\n * @fileoverview Abstract Executor Base Class\n *\n * 🎯 ABSTRACT CLASS - DO NOT DEPEND ON CONCRETE IMPLEMENTATIONS\n *\n * Provides shared execution helpers (retry, timeout, validation, logging) for all\n * executor implementations. Concrete executors should extend this class and inject\n * their own logger implementation if they need custom logging behavior.\n *\n * @example\n * ```typescript\n * export class MyCustomExecutor extends AbstractExecutor {\n * async executeChat(request: IChatExecutionRequest): Promise<AssistantMessage> {\n * return this.withRetry(() => this.performChat(request));\n * }\n * }\n * ```\n */\nexport abstract class AbstractExecutor implements IExecutor {\n /**\n * Logger injected via constructor (defaults to abstract logger)\n */\n protected readonly logger: ILogger;\n\n constructor(logger: ILogger = SilentLogger) {\n this.logger = logger;\n }\n\n abstract readonly name: string;\n abstract readonly version: string;\n\n /**\n * Execute a chat completion request\n * Must be implemented by concrete executor classes\n */\n abstract executeChat(request: IChatExecutionRequest): Promise<IExecutorChatResult>;\n\n /**\n * Execute a streaming chat completion request\n * Optional - can be implemented by concrete executor classes\n */\n abstract executeChatStream?(\n request: IStreamExecutionRequest,\n ): AsyncIterable<TExecutorStreamEvent>;\n\n /**\n * Check if the executor supports tool calling\n * Default implementation returns false, can be overridden\n */\n supportsTools(): boolean {\n return false;\n }\n\n /**\n * Validate executor configuration\n * Default implementation returns true, can be overridden\n */\n validateConfig(): boolean {\n return true;\n }\n\n /**\n * Clean up resources when executor is no longer needed\n * Default implementation does nothing, can be overridden\n */\n async dispose?(): Promise<void> {\n // Default: no cleanup needed\n }\n\n /**\n * Execute function with retry logic\n *\n * @param fn - Function to execute with retries\n * @param maxRetries - Maximum number of retry attempts (default: 3)\n * @param retryDelay - Delay between retries in milliseconds (default: 1000)\n * @returns Promise resolving to function result\n */\n protected async withRetry<T>(\n fn: () => Promise<T>,\n maxRetries: number = 3,\n retryDelay: number = 1000,\n ): Promise<T> {\n let lastError: Error;\n\n for (let attempt = 0; attempt <= maxRetries; attempt++) {\n try {\n return await fn();\n } catch (error) {\n lastError = error instanceof Error ? error : new Error(String(error));\n\n if (attempt < maxRetries) {\n this.logger.warn?.(\n `[${this.name}] Attempt ${attempt + 1} failed, retrying in ${retryDelay}ms`,\n {\n error: lastError.message,\n attempt: attempt + 1,\n maxRetries,\n },\n );\n await this.delay(retryDelay);\n }\n }\n }\n\n throw lastError!;\n }\n\n /**\n * Execute function with timeout\n *\n * @param promise - Promise to execute with timeout\n * @param timeoutMs - Timeout in milliseconds\n * @returns Promise resolving to function result\n */\n protected withTimeout<T>(promise: Promise<T>, timeoutMs: number): Promise<T> {\n let timerId: ReturnType<typeof setTimeout>;\n return Promise.race([\n promise.then((result) => {\n clearTimeout(timerId);\n return result;\n }),\n new Promise<never>((_, reject) => {\n timerId = setTimeout(\n () => reject(new Error(`Operation timed out after ${timeoutMs}ms`)),\n timeoutMs,\n );\n }),\n ]);\n }\n\n /**\n * Delay execution for specified milliseconds\n *\n * @param ms - Milliseconds to delay\n * @returns Promise that resolves after the delay\n */\n protected delay(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n }\n\n /**\n * Log debug information (only if logging is enabled)\n *\n * @param message - Log message\n * @param data - Optional data to log\n */\n protected logDebug(message: string, data?: TLoggerData): void {\n this.logger.debug?.(`[${this.name}] ${message}`, data);\n }\n\n /**\n * Log error information\n *\n * @param message - Log message\n * @param error - Error object\n * @param data - Optional additional data\n */\n protected logError(message: string, error: Error, data?: TLoggerData): void {\n this.logger.error?.(`[${this.name}] ${message}`, {\n error: error.message,\n stack: error.stack,\n ...data,\n });\n }\n\n /**\n * Validate that request has required fields\n *\n * @param request - Chat execution request to validate\n * @throws Error if validation fails\n */\n protected validateRequest(request: IChatExecutionRequest): void {\n if (!request.messages || request.messages.length === 0) {\n throw new Error('Request must include at least one message');\n }\n\n if (!request.provider) {\n throw new Error('Request must specify a provider');\n }\n\n if (!request.model) {\n throw new Error('Request must specify a model');\n }\n }\n\n /**\n * Validate that response is properly formatted\n *\n * @param response - Response to validate\n * @throws Error if validation fails\n */\n protected validateResponse(response: TUniversalMessage): void {\n if (!response.role) {\n throw new Error('Response must have a role');\n }\n\n const hasToolCalls =\n response.role === 'assistant' &&\n 'toolCalls' in response &&\n Array.isArray((response as IAssistantMessage).toolCalls) &&\n (response as IAssistantMessage).toolCalls!.length > 0;\n if (!response.content && !hasToolCalls) {\n throw new Error('Response must have content or tool calls');\n }\n }\n}\n","/**\n * @fileoverview Abstract Tool Base Class\n *\n * 🎯 ABSTRACT CLASS - DO NOT DEPEND ON CONCRETE IMPLEMENTATIONS\n *\n * This is a pure abstract base class that defines the interface and common behavior\n * for all tools. It follows strict architectural principles:\n *\n * - Depends ONLY on interfaces (EventService interface, not concrete implementations)\n * - Does NOT import concrete classes\n * - Uses Dependency Injection for all dependencies\n * - Handles undefined dependencies gracefully (Null Object Pattern)\n *\n * Concrete implementations should be handled\n * by the caller who creates the tool instance, not by this abstract class.\n *\n * @example\n * ```typescript\n * // ✅ CORRECT: Caller prepares an owner-bound EventService and injects it\n * // (Example: bind to the current tool call identity and ownerPath.)\n * const toolEventService = bindWithOwnerPath(baseEventService, {\n * ownerType: 'tool',\n * ownerId: toolCallId,\n * ownerPath,\n * });\n * const tool = new MyTool({ eventService: toolEventService });\n *\n * // ❌ WRONG: AbstractTool creates concrete EventService\n * // This violates Dependency Inversion Principle\n * ```\n */\n\nimport { SilentLogger } from '../utils/logger';\n\nimport type { IBaseEventData, IEventService } from '../interfaces/event-service';\nimport type { IToolSchema } from '../interfaces/provider';\nimport type {\n IToolResult,\n IToolExecutionContext,\n IParameterValidationResult,\n TToolParameters,\n} from '../interfaces/tool';\nimport type { ILogger } from '../utils/logger';\n\nexport type {\n IAbstractToolOptions,\n TToolExecutionFunction,\n IAbstractTool,\n IToolContract,\n IToolWithEventService,\n} from './abstract-tool-types';\nimport type { IAbstractToolOptions, IToolWithEventService } from './abstract-tool-types';\n\n/**\n * Abstract base class for tools with type parameter support\n * Provides type-safe parameter handling and result processing\n *\n * 🎯 ARCHITECTURAL PRINCIPLES:\n * - Pure abstract class - depends only on interfaces\n * - No concrete class dependencies (EventService interface only)\n * - Dependency Injection for all external dependencies\n * - Graceful degradation (undefined dependencies = silent operation)\n *\n * @template TParameters - Tool parameters type (defaults to TToolParameters)\n * @template TResult - Tool result type (defaults to ToolResult for backward compatibility)\n */\nexport abstract class AbstractTool<\n TParameters = TToolParameters,\n TResult = IToolResult,\n> implements IToolWithEventService<TParameters, TResult> {\n abstract readonly schema: IToolSchema;\n\n /**\n * Logger for tool operations\n */\n protected readonly logger: ILogger;\n\n /**\n * EventService for direct event emission (optional)\n * If undefined, tool operates silently without emitting events\n */\n private eventService: IEventService | undefined;\n\n /**\n * Constructor with simplified options\n *\n * 🎯 DEPENDENCY INJECTION:\n * All dependencies are injected via options parameter\n * No concrete classes are instantiated within this constructor\n *\n * @param options - Configuration options for the tool\n */\n constructor(options: IAbstractToolOptions = {}) {\n // Accept eventService as-is (no wrapping, no transformation)\n // Caller is responsible for providing properly configured EventService\n this.eventService = options.eventService;\n this.logger = options.logger ?? SilentLogger;\n }\n\n /**\n * Set EventService for post-construction injection\n *\n * 🎯 DEPENDENCY INJECTION:\n * Accepts EventService as-is without transformation\n * Caller is responsible for providing properly configured EventService\n *\n * @param eventService - EventService instance to use for event emission (or undefined for silent operation)\n */\n setEventService(eventService: IEventService | undefined): void {\n this.eventService = eventService;\n }\n\n /**\n * Get current EventService (for testing/inspection)\n */\n protected getEventService(): IEventService | undefined {\n return this.eventService;\n }\n\n /**\n * Emit event through EventService (if available)\n * If EventService is not available, silently ignores the event (Null Object Pattern)\n *\n * @param eventType - Type of event to emit\n * @param data - Event data\n */\n protected emitEvent(eventType: string, data: IBaseEventData): void {\n if (!this.eventService) {\n // Silent operation - no EventService available\n return;\n }\n this.eventService.emit(eventType, data);\n }\n\n /**\n * Execute tool with simplified lifecycle\n * @param parameters - Tool parameters\n * @param context - Optional execution context\n * @returns Promise resolving to tool result\n */\n async execute(parameters: TParameters, context: IToolExecutionContext): Promise<TResult> {\n return await this.executeImpl(parameters, context);\n }\n\n /**\n * Concrete implementation of tool execution\n * This method should be implemented by subclasses to provide actual tool logic\n *\n * @param parameters - Tool parameters\n * @param context - Optional execution context\n * @returns Promise resolving to tool result\n */\n protected abstract executeImpl(\n parameters: TParameters,\n context: IToolExecutionContext,\n ): Promise<TResult>;\n\n validate(parameters: TParameters): boolean {\n const required = this.schema.parameters.required || [];\n return required.every(\n (field) => field in (parameters as Record<string, string | number | boolean>),\n );\n }\n\n /**\n * Validate tool parameters with detailed result (default implementation)\n */\n validateParameters(parameters: TParameters): IParameterValidationResult {\n const required = this.schema.parameters.required || [];\n const errors: string[] = [];\n const paramObj = parameters as Record<string, string | number | boolean>;\n\n for (const field of required) {\n if (!(field in paramObj)) {\n errors.push(`Missing required parameter: ${field}`);\n }\n }\n\n return {\n isValid: errors.length === 0,\n errors,\n };\n }\n\n getDescription(): string {\n return this.schema.description;\n }\n\n getName(): string {\n return this.schema.name;\n }\n}\n","/**\n * CORE-027 — was this failure an ABORT, or did it merely say so?\n *\n * Three call sites classified it the same wrong way:\n *\n * error.name === 'AbortError' || error.message.includes('aborted') || error.message.includes('abort')\n *\n * The substring test is a guess about prose. A provider failure whose message happens to contain\n * those letters — \"the upstream aborted the stream after a policy check\", \"AbortController is not\n * supported by this runtime\", a remote 5xx body quoting the word — was classified as a user\n * interruption, and `execution-service.ts` then returned `success: true, interrupted: true` for it.\n * A real failure reported as a successful interrupted run is the sharpest kind of silent wrong\n * answer: nothing downstream, including the print-mode exit code, has any way to tell.\n *\n * The authoritative signal is the one the caller already holds. An abort happens because SOMETHING\n * ABORTED — the `AbortSignal` that was passed in says so, and the platform's own abort errors carry\n * `name === 'AbortError'`. Neither is a guess about wording, and both are things the abort mechanism\n * actually produces.\n *\n * `DOMException` with `name === 'AbortError'` is covered by the name test; `undici` and `node:fetch`\n * both raise it that way, as does `AbortSignal.throwIfAborted()`.\n */\n/**\n * Whether a value is error-SHAPED, without asking which realm or prototype chain it came from.\n *\n * `instanceof Error` is not a safe test here for two independent reasons, and only one of them was\n * raised in review:\n *\n * - **Cross-realm.** An error thrown in a worker, a `vm` context, or a different iframe fails\n * `instanceof` against this realm's `Error` even when it is a perfectly ordinary error.\n * - **`DOMException`.** Review claimed it does not extend `Error`. On this runtime it does —\n * measured on Node 22.14: `new DOMException('x','AbortError') instanceof Error === true`, and\n * WebIDL has put `Error.prototype` in its chain since 2021. So the claim does not hold here. But\n * `agent-core` ships a BROWSER build too, and nothing is gained by depending on that being true\n * everywhere when the structural test costs a line.\n *\n * A bare `{ name: 'AbortError' }` is still not an abort: an error carries a message.\n */\nfunction isErrorShaped(\n value: unknown,\n): value is { name: string; message: string; cause?: unknown } {\n return (\n typeof value === 'object' &&\n value !== null &&\n typeof (value as { name?: unknown }).name === 'string' &&\n typeof (value as { message?: unknown }).message === 'string'\n );\n}\n\nexport function isAbortFailure(error: unknown, signal?: AbortSignal): boolean {\n // The caller's own signal is the fact. If it is aborted, the round ended because of that,\n // whatever the provider's error text says.\n if (signal?.aborted === true) return true;\n if (!isErrorShaped(error)) return false;\n // What the platform raises for an abort. Checked on the ERROR OBJECT, never on its prose.\n if (error.name === 'AbortError') return true;\n // A wrapped abort keeps the original as its cause; one level is enough for the wrappers here.\n const cause: unknown = error.cause;\n return isErrorShaped(cause) && cause.name === 'AbortError';\n}\n","import type { TUniversalMessage } from '../interfaces/messages';\nimport type { IUniversalObjectValue } from '../interfaces/types';\n\n/**\n * Provider message format type.\n *\n * Provider packages own concrete message shapes. Core only carries the generic\n * conversion hook and never branches on provider names.\n */\nexport type TProviderMessage = TUniversalMessage | IUniversalObjectValue;\n\nexport type TMessageFormatConverter<TMessage extends TProviderMessage = TProviderMessage> = (\n messages: readonly TUniversalMessage[],\n) => TMessage[];\n\nexport type TMessageConverterRegistry = Readonly<Record<string, TMessageFormatConverter>>;\n\n/**\n * Universal message converter utility\n *\n * The converter is registry-based so provider-specific message conversion is\n * injected by provider packages or callers instead of being hardcoded in core.\n */\nexport class MessageConverter {\n /**\n * Convert messages using an injected converter or converter registry.\n */\n static toProviderFormat(\n messages: TUniversalMessage[],\n converter?: TMessageFormatConverter | string,\n registry: TMessageConverterRegistry = {},\n ): TProviderMessage[] {\n if (typeof converter === 'function') {\n return converter(messages);\n }\n\n if (typeof converter === 'string') {\n const registeredConverter = registry[converter];\n if (registeredConverter !== undefined) {\n return registeredConverter(messages);\n }\n }\n\n return this.toUniversalFormat(messages);\n }\n\n /**\n * Convert to universal format (no conversion)\n */\n private static toUniversalFormat(messages: TUniversalMessage[]): TUniversalMessage[] {\n return messages;\n }\n\n /**\n * Extract system message from messages\n */\n static extractSystemMessage(messages: TUniversalMessage[]): string | undefined {\n const systemMsg = messages.find((msg) => msg.role === 'system');\n return systemMsg?.content;\n }\n\n /**\n * Filter non-system messages\n */\n static filterNonSystemMessages(messages: TUniversalMessage[]): TUniversalMessage[] {\n return messages.filter((msg) => msg.role !== 'system');\n }\n}\n","import type { IAgentConfig } from '../interfaces/agent';\n\nconst MAX_SYSTEM_MESSAGE_LENGTH = 1000;\nconst MAX_TOOLS_WARNING_THRESHOLD = 20;\nconst MAX_INPUT_LENGTH = 10000;\nconst MIN_API_KEY_LENGTH = 10;\n\n/**\n * Validation result interface\n */\nexport interface ISimpleValidationResult {\n isValid: boolean;\n errors: string[];\n warnings?: string[];\n}\n\n/**\n * Validation utility class\n */\nexport class Validator {\n /**\n * Validate agent configuration\n */\n static validateAgentConfig(config: Partial<IAgentConfig>): ISimpleValidationResult {\n const errors: string[] = [];\n const warnings: string[] = [];\n\n // Required fields validation for new API\n if (!config.name) {\n errors.push('name is required');\n }\n\n if (!config.aiProviders || config.aiProviders.length === 0) {\n errors.push('aiProviders array is required and must have at least one provider');\n }\n\n if (!config.defaultModel) {\n errors.push('defaultModel is required');\n } else {\n if (!config.defaultModel.provider) {\n errors.push('defaultModel.provider is required');\n }\n if (!config.defaultModel.model) {\n errors.push('defaultModel.model is required');\n }\n }\n\n // Provider validation\n if (config.aiProviders && config.defaultModel?.provider) {\n const providerNames = config.aiProviders.map((p) => p.name);\n if (!providerNames.includes(config.defaultModel.provider)) {\n errors.push(\n `defaultModel.provider \"${config.defaultModel.provider}\" is not found in aiProviders list`,\n );\n }\n }\n\n // Optional field validation for defaultModel\n if (config.defaultModel?.temperature !== undefined) {\n if (\n typeof config.defaultModel.temperature !== 'number' ||\n config.defaultModel.temperature < 0 ||\n config.defaultModel.temperature > 2\n ) {\n errors.push('defaultModel.temperature must be a number between 0 and 2');\n }\n }\n\n if (config.defaultModel?.maxTokens !== undefined) {\n if (typeof config.defaultModel.maxTokens !== 'number' || config.defaultModel.maxTokens <= 0) {\n errors.push('defaultModel.maxTokens must be a positive number');\n }\n }\n\n // Warnings for best practices\n if (config.systemMessage && config.systemMessage.length > MAX_SYSTEM_MESSAGE_LENGTH) {\n warnings.push(\n 'systemMessage is quite long, consider keeping it concise for better performance',\n );\n }\n\n if (config.tools && config.tools.length > MAX_TOOLS_WARNING_THRESHOLD) {\n warnings.push(\n 'Large number of tools may impact performance, consider grouping related tools',\n );\n }\n\n return {\n isValid: errors.length === 0,\n errors,\n warnings,\n };\n }\n\n /**\n * Validate user input string\n */\n static validateUserInput(input: string): ISimpleValidationResult {\n const errors: string[] = [];\n const warnings: string[] = [];\n\n if (!input || typeof input !== 'string') {\n errors.push('Input must be a non-empty string');\n } else {\n if (input.trim().length === 0) {\n errors.push('Input cannot be only whitespace');\n }\n\n if (input.length > MAX_INPUT_LENGTH) {\n warnings.push('Very long input may be truncated by AI providers');\n }\n }\n\n return {\n isValid: errors.length === 0,\n errors,\n warnings,\n };\n }\n\n /**\n * Validate provider name\n */\n static validateProviderName(name: string): ISimpleValidationResult {\n const errors: string[] = [];\n\n if (!name || typeof name !== 'string') {\n errors.push('Provider name must be a non-empty string');\n } else {\n if (!/^[a-zA-Z][a-zA-Z0-9_-]*$/.test(name)) {\n errors.push(\n 'Provider name must start with a letter and contain only letters, numbers, underscores, and hyphens',\n );\n }\n }\n\n return {\n isValid: errors.length === 0,\n errors,\n };\n }\n\n /**\n * Validate model name\n */\n static validateModelName(name: string): ISimpleValidationResult {\n const errors: string[] = [];\n\n if (!name || typeof name !== 'string') {\n errors.push('Model name must be a non-empty string');\n } else {\n if (name.trim().length === 0) {\n errors.push('Model name cannot be only whitespace');\n }\n }\n\n return {\n isValid: errors.length === 0,\n errors,\n };\n }\n\n /**\n * Validate API key format (basic check)\n */\n static validateApiKey(apiKey: string): ISimpleValidationResult {\n const errors: string[] = [];\n const warnings: string[] = [];\n\n if (!apiKey || typeof apiKey !== 'string') {\n errors.push('API key must be a non-empty string');\n return { isValid: false, errors };\n }\n\n // General security checks\n if (apiKey.length < MIN_API_KEY_LENGTH) {\n errors.push('API key appears to be too short');\n }\n\n if (/\\s/.test(apiKey)) {\n errors.push('API key should not contain whitespace');\n }\n\n return {\n isValid: errors.length === 0,\n errors,\n warnings,\n };\n }\n}\n\n// Standalone validation functions for convenience\nexport const validateAgentConfig = Validator.validateAgentConfig;\nexport const validateUserInput = Validator.validateUserInput;\nexport const validateProviderName = Validator.validateProviderName;\nexport const validateModelName = Validator.validateModelName;\nexport const validateApiKey = Validator.validateApiKey;\n","/**\n * Helpers over the error taxonomy — CORE-035.\n *\n * Split out of `errors.ts`, which owns the CLASSES. Two responsibilities lived in one file: what the\n * errors ARE, and what a caller does with an arbitrary one. Keeping them together pushed the\n * taxonomy file past the size ceiling the moment a class was added to it, which is the wrong thing\n * for a ceiling to be blocking.\n */\n\nimport { ConfigurationError, ProviderError, RobotaError } from './errors';\n\nimport type { TErrorExternalInput } from './errors';\n\n/**\n * Error utility functions\n */\nexport class ErrorUtils {\n /**\n * Check if error is recoverable\n */\n static isRecoverable(error: Error): boolean {\n if (error instanceof RobotaError) {\n return error.recoverable;\n }\n return false;\n }\n\n /**\n * Extract error code from any error\n */\n static getErrorCode(error: Error): string {\n if (error instanceof RobotaError) {\n return error.code;\n }\n return 'UNKNOWN_ERROR';\n }\n\n /**\n * Create error from unknown value\n */\n static fromUnknown(\n error: TErrorExternalInput,\n defaultMessage = 'An unknown error occurred',\n ): RobotaError {\n if (error instanceof RobotaError) {\n return error;\n }\n\n if (error instanceof Error) {\n return new ConfigurationError(error.message || defaultMessage);\n }\n\n const message = typeof error === 'string' ? error : defaultMessage;\n return new ConfigurationError(message);\n }\n\n /**\n * Wrap external errors\n */\n static wrapProviderError(\n error: TErrorExternalInput,\n provider: string,\n operation: string,\n ): ProviderError {\n const originalError = error instanceof Error ? error : new Error(String(error));\n return new ProviderError(`Failed to ${operation}`, provider, originalError, { operation });\n }\n}\n","/**\n * Provider failures, read from what the vendor reported rather than from message prose.\n *\n * `toProviderError` is what an adapter's catch block uses so the HTTP status and the vendor's\n * error type survive the adapter boundary. `classifyProviderFailure` answers one question from\n * those facts: could the same request plausibly succeed on a different model?\n */\n\nimport { isAbortFailure } from './abort-classification';\nimport {\n AuthenticationError,\n ModelNotAvailableError,\n NetworkError,\n ProviderError,\n RateLimitError,\n RobotaError,\n} from './errors';\n\nimport type { IProviderFailureDetails } from './errors';\n\nconst HTTP_BAD_REQUEST = 400;\nconst HTTP_UNAUTHORIZED = 401;\nconst HTTP_PAYMENT_REQUIRED = 402;\nconst HTTP_FORBIDDEN = 403;\nconst HTTP_NOT_FOUND = 404;\nconst HTTP_PAYLOAD_TOO_LARGE = 413;\nconst HTTP_TOO_MANY_REQUESTS = 429;\nconst HTTP_INTERNAL_SERVER_ERROR = 500;\nconst HTTP_BAD_GATEWAY = 502;\nconst HTTP_SERVICE_UNAVAILABLE = 503;\nconst HTTP_GATEWAY_TIMEOUT = 504;\nconst HTTP_OVERLOADED = 529;\n\nconst RATE_LIMIT_TYPES: ReadonlySet<string> = new Set(['rate_limit_error']);\nconst OVERLOADED_TYPES: ReadonlySet<string> = new Set(['overloaded_error']);\nconst AUTH_TYPES: ReadonlySet<string> = new Set(['authentication_error', 'permission_error']);\nconst MODEL_UNAVAILABLE_CODES: ReadonlySet<string> = new Set(['model_not_found']);\nconst NETWORK_ERROR_CODES: ReadonlySet<string> = new Set([\n 'ECONNRESET',\n 'ECONNREFUSED',\n 'ENOTFOUND',\n 'ETIMEDOUT',\n 'EPIPE',\n 'EAI_AGAIN',\n 'UND_ERR_SOCKET',\n 'UND_ERR_CONNECT_TIMEOUT',\n]);\nconst SDK_ABORT_CLASS = 'APIUserAbortError';\nconst MAX_WRAP_DEPTH = 8;\nconst NETWORK_ERROR_CLASSES: ReadonlySet<string> = new Set([\n 'APIConnectionError',\n 'APIConnectionTimeoutError',\n]);\n\n/** Why a provider call failed, as far as switching models is concerned. */\nexport type TProviderFailureReason =\n | 'overloaded'\n | 'service-unavailable'\n | 'server-error'\n | 'model-unavailable'\n | 'authentication'\n | 'billing'\n | 'rate-limit'\n | 'invalid-request'\n | 'network'\n | 'aborted'\n | 'unknown';\n\nexport interface IProviderFailureClassification {\n /** True when another model could plausibly serve the same request. */\n switchable: boolean;\n reason: TProviderFailureReason;\n}\n\ntype TErrorRecord = Record<string, unknown>;\n\nfunction asRecord(value: unknown): TErrorRecord | undefined {\n return typeof value === 'object' && value !== null ? (value as TErrorRecord) : undefined;\n}\n\nfunction stringField(record: TErrorRecord | undefined, key: string): string | undefined {\n const value = record?.[key];\n return typeof value === 'string' && value.length > 0 ? value : undefined;\n}\n\n/**\n * Read the HTTP status and vendor error type off an SDK error.\n *\n * The SDKs disagree on where the type lives: `error.type` (Anthropic, OpenAI), the parsed body at\n * `error.error.type` (OpenAI) or `error.error.error.type` (Anthropic, whose body is\n * `{ type: 'error', error: { type } }`). On an HTTP error with no type, a `code` such as OpenAI's\n * `model_not_found` stands in for it.\n */\nexport function readProviderFailureDetails(error: unknown): IProviderFailureDetails {\n const record = asRecord(error);\n if (record === undefined) return {};\n const status = typeof record['status'] === 'number' ? record['status'] : undefined;\n const body = asRecord(record['error']);\n const nested = asRecord(body?.['error']);\n const bodyType = stringField(body, 'type');\n const type =\n stringField(record, 'type') ??\n stringField(nested, 'type') ??\n (bodyType === 'error' ? undefined : bodyType) ??\n (status !== undefined && !(error instanceof RobotaError)\n ? stringField(record, 'code')\n : undefined);\n return {\n ...(status !== undefined && { status }),\n ...(type !== undefined && { type }),\n };\n}\n\n/**\n * The name of the class that built this value. The Stainless SDKs (OpenAI, Anthropic) never set\n * `name` on their error classes, so `name` reads `'Error'`; the constructor name is what tells an\n * `APIUserAbortError` or an `APIConnectionError` apart. Checked by name, not `instanceof`, because\n * this package depends on no vendor SDK and each provider may load its own copy of one.\n */\nfunction className(value: unknown): string | undefined {\n const ctor = asRecord(value)?.['constructor'];\n if (typeof ctor !== 'function') return undefined;\n const name = (ctor as { name?: unknown }).name;\n return typeof name === 'string' && name.length > 0 ? name : undefined;\n}\n\n/** An abort, including the SDKs' own `APIUserAbortError`, whose `name` is not `'AbortError'`. */\nfunction isAbort(value: unknown): boolean {\n return isAbortFailure(value) || className(value) === SDK_ABORT_CLASS;\n}\n\n/**\n * Turn whatever an adapter caught into a typed provider failure.\n *\n * Aborts and errors already in the taxonomy pass through unchanged, a rate limit becomes a\n * `RateLimitError`, and anything else becomes a `ProviderError` carrying the status and type the\n * vendor reported, with the original kept as `originalError`.\n */\nexport function toProviderError(error: unknown, provider: string, operation: string): Error {\n if (error instanceof RobotaError || isAbort(error)) return error as Error;\n const originalError =\n error instanceof Error ? error : new Error(typeof error === 'string' ? error : '');\n const details = readProviderFailureDetails(error);\n if (\n details.status === HTTP_TOO_MANY_REQUESTS ||\n (details.type !== undefined && RATE_LIMIT_TYPES.has(details.type))\n ) {\n return new RateLimitError(\n originalError.message || `${provider} rate limit exceeded.`,\n undefined,\n provider,\n );\n }\n const reason = originalError.message || 'request failed';\n return new ProviderError(`${operation}: ${reason}`, provider, originalError, undefined, details);\n}\n\nfunction isNetworkFailure(error: unknown): boolean {\n if (error instanceof NetworkError) return true;\n const record = asRecord(error);\n if (record === undefined) return false;\n const code = stringField(record, 'code');\n if (code !== undefined && NETWORK_ERROR_CODES.has(code)) return true;\n const ctorName = className(error);\n if (ctorName !== undefined && NETWORK_ERROR_CLASSES.has(ctorName)) return true;\n const name = stringField(record, 'name');\n if (name !== undefined && NETWORK_ERROR_CLASSES.has(name)) return true;\n // undici's fetch rejects a transport failure as `TypeError: fetch failed`.\n return name === 'TypeError' && stringField(record, 'message') === 'fetch failed';\n}\n\n/**\n * The error and everything it wraps, outermost first: `originalError` (the taxonomy's wrappers) and\n * `cause` (the platform's and the SDKs'), followed to a small depth and never twice.\n */\nfunction layersOf(error: unknown): unknown[] {\n const layers: unknown[] = [];\n const seen = new Set<unknown>();\n let frontier: unknown[] = [error];\n for (let depth = 0; depth <= MAX_WRAP_DEPTH && frontier.length > 0; depth++) {\n const next: unknown[] = [];\n for (const layer of frontier) {\n if (layer === undefined || layer === null || seen.has(layer)) continue;\n seen.add(layer);\n layers.push(layer);\n const record = asRecord(layer);\n if (record !== undefined) next.push(record['originalError'], record['cause']);\n }\n frontier = next;\n }\n return layers;\n}\n\ntype TLayerVerdict =\n | { kind: 'definitive'; classification: IProviderFailureClassification }\n /** A bare 400/404: a deeper `model_not_found` code may still say more precisely what failed. */\n | { kind: 'tentative'; classification: IProviderFailureClassification }\n | { kind: 'none' };\n\nconst definitive = (switchable: boolean, reason: TProviderFailureReason): TLayerVerdict => ({\n kind: 'definitive',\n classification: { switchable, reason },\n});\n\nfunction detailsOf(layer: unknown): IProviderFailureDetails {\n if (!(layer instanceof ProviderError)) return readProviderFailureDetails(layer);\n return {\n ...(layer.status !== undefined && { status: layer.status }),\n ...(layer.type !== undefined && { type: layer.type }),\n };\n}\n\nfunction hasModelUnavailableCode(layer: unknown): boolean {\n if (layer instanceof RobotaError) return false;\n const code = stringField(asRecord(layer), 'code');\n return code !== undefined && MODEL_UNAVAILABLE_CODES.has(code);\n}\n\n/**\n * What one layer says on its own. The order is the precedence: what the error IS, then the\n * failures no other model fixes (auth, rate limit, billing), then a model the vendor names as\n * unknown, then a transport failure, then the remaining statuses.\n */\nfunction classifyLayer(layer: unknown): TLayerVerdict {\n if (layer instanceof RateLimitError) return definitive(false, 'rate-limit');\n if (layer instanceof AuthenticationError) return definitive(false, 'authentication');\n if (layer instanceof ModelNotAvailableError) return definitive(true, 'model-unavailable');\n\n const { status, type } = detailsOf(layer);\n if (status === HTTP_TOO_MANY_REQUESTS || (type !== undefined && RATE_LIMIT_TYPES.has(type))) {\n return definitive(false, 'rate-limit');\n }\n if (\n status === HTTP_UNAUTHORIZED ||\n status === HTTP_FORBIDDEN ||\n (type !== undefined && AUTH_TYPES.has(type))\n ) {\n return definitive(false, 'authentication');\n }\n if (status === HTTP_PAYMENT_REQUIRED) return definitive(false, 'billing');\n\n // OpenAI-compatible vendors send `code: 'model_not_found'` beside `type: 'invalid_request_error'`\n // on a 400, so the code outranks a bare 400/404 — and nothing else.\n const bareStatus =\n status === undefined || status === HTTP_BAD_REQUEST || status === HTTP_NOT_FOUND;\n if (\n bareStatus &&\n (hasModelUnavailableCode(layer) || (type !== undefined && MODEL_UNAVAILABLE_CODES.has(type)))\n ) {\n return definitive(true, 'model-unavailable');\n }\n\n if (isNetworkFailure(layer)) return definitive(false, 'network');\n\n if (status === HTTP_OVERLOADED || (type !== undefined && OVERLOADED_TYPES.has(type))) {\n return definitive(true, 'overloaded');\n }\n if (status === HTTP_SERVICE_UNAVAILABLE) return definitive(true, 'service-unavailable');\n if (\n status === HTTP_INTERNAL_SERVER_ERROR ||\n status === HTTP_BAD_GATEWAY ||\n status === HTTP_GATEWAY_TIMEOUT\n ) {\n return definitive(true, 'server-error');\n }\n // A chat endpoint's only addressable resource is the model, so its 404 means the model.\n if (status === HTTP_NOT_FOUND) {\n return { kind: 'tentative', classification: { switchable: true, reason: 'model-unavailable' } };\n }\n if (status === HTTP_BAD_REQUEST || status === HTTP_PAYLOAD_TOO_LARGE) {\n return { kind: 'tentative', classification: { switchable: false, reason: 'invalid-request' } };\n }\n return { kind: 'none' };\n}\n\n/**\n * Decide whether a failed provider call is worth retrying on a different model.\n *\n * Switchable: overload, 503, 500/502/504, and a model the provider does not serve — failures of\n * this model or this vendor's capacity. Not switchable: auth, billing, rate limit, a request the\n * vendor rejected as malformed or too large, a transport failure, an abort, and anything\n * unrecognized — another model would fail the same way, the caller asked to stop, or nobody knows.\n *\n * An abort anywhere wins, because the caller asked to stop. Otherwise the outermost layer that says\n * something decides, so a wrapper's own verdict (a rate limit, a dropped connection) is never\n * overridden by a switchable status buried underneath it; a wrapper that says nothing lets the\n * layers underneath speak.\n */\nexport function classifyProviderFailure(\n error: unknown,\n signal?: AbortSignal,\n): IProviderFailureClassification {\n const layers = layersOf(error);\n if (signal?.aborted === true || layers.some((layer) => isAbort(layer))) {\n return { switchable: false, reason: 'aborted' };\n }\n let tentative: IProviderFailureClassification | undefined;\n for (const layer of layers) {\n const verdict = classifyLayer(layer);\n if (verdict.kind === 'none') continue;\n if (tentative === undefined && verdict.kind === 'definitive') return verdict.classification;\n if (tentative === undefined) {\n tentative = verdict.classification;\n continue;\n }\n // Under a bare 400/404/413, the first deeper layer that decides settles it: only a precise\n // \"no such model\" refines the verdict; any other decision keeps it.\n if (verdict.kind === 'definitive') {\n return verdict.classification.reason === 'model-unavailable'\n ? verdict.classification\n : tentative;\n }\n }\n return tentative ?? { switchable: false, reason: 'unknown' };\n}\n","import type { TTimerId } from './timer-types';\nimport type { ILogger } from './logger';\n\ninterface IPeriodicTaskOptions {\n name: string;\n intervalMs: number;\n}\n\n/**\n * Start a periodic async task with consistent error logging.\n * SSOT helper to avoid duplicating setInterval(async () => ...) patterns.\n */\nexport function startPeriodicTask(\n logger: ILogger,\n options: IPeriodicTaskOptions,\n task: () => Promise<void>,\n): TTimerId {\n const timer: TTimerId = setInterval(() => {\n void (async () => {\n try {\n await task();\n } catch (error) {\n logger.error('Periodic task failed', {\n task: options.name,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n })();\n }, options.intervalMs);\n\n return timer;\n}\n\nexport function stopPeriodicTask(timer: TTimerId | undefined): void {\n if (!timer) return;\n clearInterval(timer);\n}\n","/**\n * Reading a Zod schema's `_def` — the inspection half of the converter (CORE-039).\n *\n * Split from `zod-to-json-schema.ts` by responsibility: everything here ANSWERS QUESTIONS about a\n * Zod schema (what does it wrap, is this field required, what unknown-key mode is it in), while the\n * sibling module decides what subset node to emit. The dependency runs one way, conversion →\n * inspection, so the mutual recursion between the object walk and the node walk stays in one file.\n */\n\nimport type { IZodSchema, IZodSchemaDef } from './zod-schema-types';\nimport type { TJSONSchemaKind } from '../interfaces/provider';\nimport type { TUniversalValue } from '../interfaces/types';\n\n/** Guard for the structural stand-in: real Zod wrapper chains are nowhere near this deep. */\nexport const MAX_WRAPPER_DEPTH = 64;\n\n/**\n * Map Zod's three unknown-key modes onto the subset, which previously saw only two.\n *\n * `strip` is Zod's DEFAULT and means \"extra keys are accepted at the boundary, then dropped\" — so it\n * is `true`, not omitted. Emitting omitted (which the subset reads as CLOSED) told every consumer to\n * reject payloads the author's own schema accepts. `strict` is the mode that actually rejects.\n */\nexport function resolveAdditionalProperties(\n objectDef: IZodSchemaDef,\n allowAdditionalProperties?: boolean,\n): boolean | undefined {\n if (allowAdditionalProperties) {\n return true;\n }\n switch (objectDef.unknownKeys) {\n case 'passthrough':\n case 'strip':\n return true;\n case 'strict':\n return false;\n default:\n // Not a Zod object with a declared mode — leave it to the subset's omitted-means-closed default.\n return undefined;\n }\n}\n\n/** Unwrap transparent wrappers until an object definition is reached; undefined if it never is. */\nexport function unwrapToObjectDef(typeDef: IZodSchemaDef): IZodSchemaDef | undefined {\n const resolved = unwrapTransparent(typeDef);\n return resolved.typeName === 'ZodObject' ? resolved : undefined;\n}\n\n/**\n * Strip wrappers that do not change the emitted JSON schema: `ZodEffects` (`.refine()`,\n * `.transform()`), `ZodOptional`, `ZodNullable`, `ZodDefault`. Optionality is carried by\n * `isRequiredField`, not by the property's own shape.\n */\nexport function unwrapTransparent(typeDef: IZodSchemaDef): IZodSchemaDef {\n let current = typeDef;\n // Real Zod builds wrapper chains acyclically, but `IZodSchema` is a structural stand-in and\n // `zodToJsonSchema` is exported — so this loop is reachable with a hand-built `_def` whose\n // `innerType` points at itself. The cap turns that into the file's usual loud failure instead of\n // a hang.\n for (let depth = 0; depth <= MAX_WRAPPER_DEPTH; depth += 1) {\n const inner =\n current.typeName === 'ZodEffects'\n ? current.schema\n : current.typeName === 'ZodOptional' ||\n current.typeName === 'ZodNullable' ||\n current.typeName === 'ZodDefault'\n ? current.innerType\n : undefined;\n if (!inner) {\n return current;\n }\n current = requireDef(inner, `${String(current.typeName)} inner type`);\n }\n throw new Error(\n `Zod wrapper chain exceeds ${MAX_WRAPPER_DEPTH} levels; refusing to unwrap further (cyclic schema?).`,\n );\n}\n\nexport function requireDef(schema: IZodSchema, label: string): IZodSchemaDef {\n const def = schema._def;\n if (!def) {\n throw new Error(`${label} is missing _def; cannot convert to JSON schema.`);\n }\n return def;\n}\n\nexport function literalKind(value: TUniversalValue | undefined): TJSONSchemaKind | undefined {\n if (typeof value === 'string') return 'string';\n if (typeof value === 'number') return 'number';\n if (typeof value === 'boolean') return 'boolean';\n if (value === null) return 'null';\n return undefined;\n}\n\n/**\n * Check if a Zod field is required (not optional, nullable, or defaulted), looking through\n * `ZodEffects` so `.optional().refine(…)` is not reported as required.\n */\nexport function isRequiredField(typeObj: IZodSchema): boolean {\n const typeDef = typeObj._def;\n if (!typeDef) {\n throw new Error('Zod schema is missing _def; cannot determine required fields.');\n }\n\n // Loop, do not peel one level: `.optional().refine(f).refine(f)` is two ZodEffects deep, and a\n // single unwrap reported that field as required -- the model then being told an optional field is\n // mandatory. A partial copy of the unwrap is the same divergence this file exists to remove.\n let resolved = typeDef;\n for (\n let depth = 0;\n resolved.typeName === 'ZodEffects' && depth <= MAX_WRAPPER_DEPTH;\n depth += 1\n ) {\n if (!resolved.schema) break;\n resolved = requireDef(resolved.schema, 'ZodEffects inner type');\n }\n\n return (\n resolved.typeName !== 'ZodOptional' &&\n resolved.typeName !== 'ZodNullable' &&\n resolved.typeName !== 'ZodDefault'\n );\n}\n\n/**\n * Safely extract enum values from Zod schema\n */\nexport function extractEnumValues(schema: IZodSchema): TUniversalValue[] {\n const typeDef = requireDef(schema, 'Zod schema');\n if (!typeDef.values || !Array.isArray(typeDef.values)) {\n throw new Error('ZodEnum schema is missing enum values; cannot extract enum values.');\n }\n return typeDef.values;\n}\n\n/**\n * Check if schema has validation constraints\n */\nexport function hasValidationConstraints(schema: IZodSchema): boolean {\n const typeDef = requireDef(schema, 'Zod schema');\n return !!(typeDef.checks && typeDef.checks.length > 0);\n}\n\n/**\n * Safe schema type name extraction\n */\nexport function getSchemaTypeName(schema: IZodSchema): string {\n const typeDef = requireDef(schema, 'Zod schema');\n if (!typeDef.typeName) {\n throw new Error('Zod schema has empty typeName; cannot determine schema type name.');\n }\n return typeDef.typeName;\n}\n","/**\n * Zod → JSON Schema conversion (SSOT).\n *\n * Owned by agent-core (CORE-015): the structured-output run pipeline and the\n * tools package both convert Zod schemas to the universal JSON-schema subset\n * (`IParameterSchema`), so the single converter lives at the bottom of the\n * dependency graph. The tools package imports these functions from core.\n *\n * CORE-039: the object shape walk is written ONCE and used by both the root and\n * every nested object. Two copies is how the two levels came to disagree — the\n * root named its fields while a nested object was emitted as a bare\n * `{ type: 'object' }`, so a model was told \"this is an object\" and nothing else.\n */\n\nimport {\n isRequiredField,\n requireDef,\n literalKind,\n resolveAdditionalProperties,\n unwrapToObjectDef,\n} from './zod-schema-inspect';\n\nimport type { IZodSchema, IZodSchemaDef, ISchemaConversionOptions } from './zod-schema-types';\nimport type {\n IObjectParameterSchema,\n IParameterSchema,\n TJSONSchemaEnum,\n} from '../interfaces/provider';\nimport type { TUniversalValue } from '../interfaces/types';\n\n/**\n * Convert a Zod schema to the universal JSON-schema subset.\n *\n * The root must resolve to an object; `.refine()`/`.transform()`/`.optional()`/`.default()`\n * wrappers around one are unwrapped first. A root that is not an object throws rather than\n * silently returning an empty schema — an empty schema reaches the model as \"an object, contents\n * unspecified\", which is the failure this converter exists to prevent.\n */\nexport function zodToJsonSchema(\n schema: IZodSchema,\n options: ISchemaConversionOptions = {},\n): IObjectParameterSchema {\n const schemaDef = requireDef(schema, 'Zod schema');\n const objectDef = unwrapToObjectDef(schemaDef);\n if (!objectDef) {\n throw new Error(\n `Zod schema root must be an object; got ${String(schemaDef.typeName)}. ` +\n 'Wrap the fields in z.object({ … }) before converting.',\n );\n }\n return convertObjectShape(objectDef, options.allowAdditionalProperties);\n}\n\n/**\n * The one object walk: shape → `properties` + `required` + `additionalProperties`.\n * Used by the root and by every nested `ZodObject`.\n */\nfunction convertObjectShape(\n objectDef: IZodSchemaDef,\n allowAdditionalProperties?: boolean,\n): IObjectParameterSchema {\n const properties: Record<string, IParameterSchema> = {};\n const required: string[] = [];\n\n // Zod v3's `_def.shape` is a FUNCTION (the property form is the `ZodObject.shape` getter);\n // structural stand-ins supply it directly. Accept both.\n const shape = typeof objectDef.shape === 'function' ? objectDef.shape() : objectDef.shape;\n\n for (const [key, typeObj] of Object.entries(shape ?? {})) {\n properties[key] = convertZodTypeToProperty(typeObj, allowAdditionalProperties);\n if (isRequiredField(typeObj)) {\n required.push(key);\n }\n }\n\n const additionalProperties = resolveAdditionalProperties(objectDef, allowAdditionalProperties);\n return {\n type: 'object',\n properties,\n required,\n ...(additionalProperties !== undefined && { additionalProperties }),\n };\n}\n\n/**\n * Convert an individual Zod type to a subset node.\n */\nfunction convertZodTypeToProperty(\n typeObj: IZodSchema,\n allowAdditionalProperties?: boolean,\n): IParameterSchema {\n const typeDef = requireDef(typeObj, 'Zod type');\n\n const base: Partial<IParameterSchema> = {};\n if (typeDef.description) {\n base.description = typeDef.description;\n }\n\n switch (typeDef.typeName) {\n case 'ZodString':\n return { type: 'string', ...base };\n\n case 'ZodNumber':\n return { type: 'number', ...base };\n\n case 'ZodBoolean':\n return { type: 'boolean', ...base };\n\n case 'ZodArray': {\n if (!typeDef.type) {\n throw new Error('ZodArray is missing item type; cannot convert to JSON schema.');\n }\n return {\n type: 'array',\n items: convertZodTypeToProperty(typeDef.type, allowAdditionalProperties),\n ...base,\n };\n }\n\n case 'ZodObject':\n // The nested case delegates to the SAME walk the root uses, so the two cannot drift again.\n return { ...convertObjectShape(typeDef, allowAdditionalProperties), ...base };\n\n case 'ZodEnum': {\n const enumValues = typeDef.values;\n if (!enumValues || !Array.isArray(enumValues)) {\n throw new Error('ZodEnum is missing enum values; cannot convert to JSON schema.');\n }\n return { type: 'string', enum: enumValues as TJSONSchemaEnum, ...base };\n }\n\n case 'ZodNativeEnum': {\n // CORE-041: `_def.values` is the enum OBJECT here, not the array `ZodEnum` carries.\n return { ...convertNativeEnum(typeDef.values), ...base };\n }\n\n case 'ZodDate':\n // CORE-041: JSON has no date type, so a string is what the provider receives either way —\n // this is the faithful description of the payload, not a lossy stand-in. `format` carries the\n // intent to a provider that reads it, and `validateAgainstJsonSchema` checks the type.\n return { type: 'string', format: 'date-time', ...base };\n\n case 'ZodLiteral':\n return { ...convertLiteral(typeDef.value), ...base };\n\n case 'ZodUnion':\n case 'ZodDiscriminatedUnion': {\n const members = typeDef.options;\n if (!members || !Array.isArray(members) || members.length === 0) {\n throw new Error(\n `${String(typeDef.typeName)} is missing options; cannot convert to JSON schema.`,\n );\n }\n // A union node carries `anyOf` INSTEAD of `type` — emitting both is invalid JSON Schema.\n return {\n anyOf: members.map((member) => convertZodTypeToProperty(member, allowAdditionalProperties)),\n ...base,\n };\n }\n\n case 'ZodEffects': {\n if (!typeDef.schema) {\n throw new Error('ZodEffects is missing schema; cannot convert to JSON schema.');\n }\n return { ...convertZodTypeToProperty(typeDef.schema, allowAdditionalProperties), ...base };\n }\n\n case 'ZodNullable': {\n if (!typeDef.innerType) {\n throw new Error('ZodNullable is missing innerType; cannot convert to JSON schema.');\n }\n // The null branch is part of what the field accepts, so it has to survive into the schema.\n // Dropping it was harmless only while nested nodes were opaque; now that depth is enforced,\n // an advertised `{type:'string'}` would reject a `null` the author's own Zod schema accepts.\n return {\n anyOf: [\n convertZodTypeToProperty(typeDef.innerType, allowAdditionalProperties),\n { type: 'null' },\n ],\n ...base,\n };\n }\n\n case 'ZodOptional':\n case 'ZodDefault': {\n if (!typeDef.innerType) {\n throw new Error(\n `${String(typeDef.typeName)} is missing innerType; cannot convert to JSON schema.`,\n );\n }\n return { ...convertZodTypeToProperty(typeDef.innerType, allowAdditionalProperties), ...base };\n }\n\n case 'ZodRecord':\n if (typeDef.valueType) {\n return {\n type: 'object',\n additionalProperties: convertZodTypeToProperty(\n typeDef.valueType,\n allowAdditionalProperties,\n ),\n ...base,\n };\n }\n return { type: 'object', additionalProperties: { type: 'string' }, ...base };\n\n default:\n throw new Error(unsupportedConstructMessage(String(typeDef.typeName)));\n }\n}\n\n/** A literal is a one-value enum of its own primitive type. */\nfunction convertLiteral(value: TUniversalValue | undefined): IParameterSchema {\n const kind = literalKind(value);\n if (!kind) {\n throw new Error(\n `ZodLiteral value ${String(value)} is not a JSON primitive; cannot convert to JSON schema.`,\n );\n }\n // `TJSONSchemaEnum` has no null member, and a null literal needs none: `type: 'null'` already\n // admits exactly one value.\n return kind === 'null' ? { type: 'null' } : { type: kind, enum: [value] as TJSONSchemaEnum };\n}\n\n/**\n * Convert a `ZodNativeEnum`'s value set — CORE-041.\n *\n * A NUMERIC TypeScript enum compiles to an object with a reverse mapping, so `Object.values` on\n * `enum Level { Low, High }` yields `['Low', 'High', 0, 1]`. Emitting that would advertise `\"Low\"` as\n * an acceptable value for a field that accepts `0`, which is a wrong contract rather than a wide one.\n * When any numeric value is present, the numeric half IS the value set and the names are the\n * compiler's bookkeeping.\n */\nfunction convertNativeEnum(values: IZodSchemaDef['values']): IParameterSchema {\n if (!values || typeof values !== 'object') {\n throw new Error('ZodNativeEnum is missing enum values; cannot convert to JSON schema.');\n }\n const all = Array.isArray(values) ? values : Object.values(values);\n const numeric = all.filter((entry): entry is number => typeof entry === 'number');\n const members = numeric.length > 0 ? numeric : all;\n if (members.length === 0) {\n throw new Error('ZodNativeEnum declares no members; cannot convert to JSON schema.');\n }\n return {\n type: numeric.length > 0 ? 'number' : 'string',\n enum: members as TJSONSchemaEnum,\n };\n}\n\n/**\n * The boundary between Zod and the universal JSON-schema subset, stated where a consumer hits it —\n * CORE-041.\n *\n * The old message was `Unsupported Zod type: ZodTuple`: the name of the consumer's own construct,\n * and nothing they could act on. The boundary is real and staying — these constructs need\n * positional `items`, `allOf` or `$ref`, none of which the subset carries, and none of which the\n * field-enumerated provider mappers would forward if it did. That is also why adopting\n * `zod-to-json-schema` does not dissolve this: the difficulty was never PARSING Zod, it is that the\n * target language cannot say these things, and a library emitting a richer document widens the gap.\n *\n * Mapping them lossily was the other option and is worse than throwing: a tuple flattened to an\n * array of `anyOf` members would tell the model that any order and any length are acceptable — a\n * contract the author did not write. A loud boundary a consumer can route around beats a quiet one\n * that misdescribes their schema.\n */\nconst CONSTRUCT_GUIDANCE: Record<string, string> = {\n ZodTuple:\n 'a tuple needs positional `items`, and the subset models `items` as ONE schema — use `z.object({...})` for a fixed-shape record, or `z.array(z.union([...]))` if order genuinely does not matter',\n ZodIntersection:\n 'an intersection needs `allOf` — merge the two object schemas yourself with `.merge()`, which produces a single object node the subset can carry',\n ZodLazy:\n 'a recursive schema needs `$ref` — flatten the recursion to a fixed depth, or model the nested level as `z.record(...)`',\n ZodDate: 'use `z.string()` (optionally with `.datetime()`), which is what a provider receives',\n};\n\nfunction unsupportedConstructMessage(typeName: string): string {\n const guidance = CONSTRUCT_GUIDANCE[typeName];\n const why = guidance ?? 'it has no representation in the subset';\n return (\n `${typeName} cannot be carried by the universal JSON-schema subset: ${why}. ` +\n 'The subset is the one language every provider mapper forwards intact; a construct outside it ' +\n 'would be advertised to the model and enforced by nothing.'\n );\n}\n","/**\n * Structured output normalization and validation (CORE-015).\n *\n * `run(input, { output })` accepts either a Zod schema or an explicit JSON-schema\n * wrapper. Both normalize to one internal representation (`IStructuredOutputSpec`)\n * that carries the JSON schema for the provider's native structured-output surface\n * and a validate function for the core-side enforcement loop. The enforcement loop\n * is the universal contract: providers with a native surface enforce early, and for\n * providers without one the bounded validate-and-retry loop still guarantees the\n * returned object matches the schema.\n */\n\nimport { zodToJsonSchema } from './zod-to-json-schema';\n\nimport type { IZodSchema } from './zod-schema-types';\nimport type { IToolSchema, IParameterSchema } from '../interfaces/provider';\n\n/** Explicit raw-JSON-schema form of `IRunOptions.output`. */\nexport interface IJsonSchemaOutput {\n /** JSON Schema (object root, universal subset) the response must match. */\n jsonSchema: IToolSchema['parameters'];\n /** Optional schema name forwarded to provider native surfaces. */\n name?: string;\n}\n\n/** Accepted `IRunOptions.output` values: a Zod schema or an explicit JSON-schema wrapper. */\nexport type TStructuredOutputSchema = IZodSchema | IJsonSchemaOutput;\n\nexport type TStructuredOutputValidation =\n { success: true; value: unknown } | { success: false; issues: string[] };\n\n/** Internal SSOT representation every `output` value normalizes to. */\nexport interface IStructuredOutputSpec {\n name: string;\n jsonSchema: IToolSchema['parameters'];\n validate(value: unknown): TStructuredOutputValidation;\n}\n\nfunction isZodSchema(output: TStructuredOutputSchema): output is IZodSchema {\n return (\n typeof (output as IZodSchema).safeParse === 'function' &&\n typeof (output as IZodSchema).parse === 'function'\n );\n}\n\nfunction formatZodError(error: unknown): string[] {\n if (error && typeof error === 'object' && 'issues' in error) {\n const issues = (error as { issues: unknown }).issues;\n if (Array.isArray(issues)) {\n return issues.map((issue) => {\n if (issue && typeof issue === 'object' && 'message' in issue) {\n const path = Array.isArray((issue as { path?: unknown[] }).path)\n ? (issue as { path: unknown[] }).path.join('.')\n : '';\n const message = String((issue as { message: unknown }).message);\n return path ? `${path}: ${message}` : message;\n }\n return String(issue);\n });\n }\n }\n return [String(error)];\n}\n\n/** Normalize an accepted `output` value into the internal spec. */\nexport function normalizeStructuredOutput(output: TStructuredOutputSchema): IStructuredOutputSpec {\n if (isZodSchema(output)) {\n return {\n name: 'structured_output',\n jsonSchema: zodToJsonSchema(output),\n validate: (value) => {\n const result = output.safeParse(value);\n if (result.success) {\n return { success: true, value: result.data };\n }\n return { success: false, issues: formatZodError(result.error) };\n },\n };\n }\n const { jsonSchema, name } = output;\n return {\n name: name ?? 'structured_output',\n jsonSchema,\n validate: (value) => {\n const issues = validateAgainstJsonSchema(jsonSchema, value, '$');\n return issues.length === 0 ? { success: true, value } : { success: false, issues };\n },\n };\n}\n\n/**\n * Validate a value against the universal JSON-schema subset (`IParameterSchema`). Covers type,\n * required, enum, items, nested properties, unions and numeric bounds — the full expressible\n * surface of the subset, at every level.\n *\n * CORE-039: this is the ONE complete walk. `parameter-validator` delegates its depth here rather\n * than keeping a second, shallower copy, and the two must therefore agree by construction.\n */\nexport function validateAgainstJsonSchema(\n schema: IParameterSchema,\n value: unknown,\n path: string,\n): string[] {\n const issues: string[] = [];\n const kind = schema.type;\n\n // A union node carries `anyOf` instead of `type`, so it is answered before the type switch.\n if (schema.anyOf) {\n return validateAnyOf(schema.anyOf, value, path);\n }\n\n switch (kind) {\n case 'object': {\n if (typeof value !== 'object' || value === null || Array.isArray(value)) {\n return [`${path}: expected object, got ${describeType(value)}`];\n }\n const record = value as Record<string, unknown>;\n const required = schema.required ?? [];\n for (const key of required) {\n if (!(key in record)) {\n issues.push(`${path}.${key}: required property missing`);\n }\n }\n const properties = schema.properties ?? {};\n for (const [key, propertySchema] of Object.entries(properties)) {\n if (key in record) {\n issues.push(...validateAgainstJsonSchema(propertySchema, record[key], `${path}.${key}`));\n }\n }\n const additional = schema.additionalProperties;\n if (isClosed(schema)) {\n for (const key of Object.keys(record)) {\n if (!(key in properties)) {\n issues.push(`${path}.${key}: unexpected additional property`);\n }\n }\n } else if (typeof additional === 'object') {\n for (const [key, entry] of Object.entries(record)) {\n if (!(key in properties)) {\n issues.push(...validateAgainstJsonSchema(additional, entry, `${path}.${key}`));\n }\n }\n }\n return issues;\n }\n\n case 'array': {\n if (!Array.isArray(value)) {\n return [`${path}: expected array, got ${describeType(value)}`];\n }\n const items = schema.items;\n if (items) {\n value.forEach((entry, index) => {\n issues.push(...validateAgainstJsonSchema(items, entry, `${path}[${index}]`));\n });\n }\n return issues;\n }\n\n case 'string': {\n if (typeof value !== 'string') {\n return [`${path}: expected string, got ${describeType(value)}`];\n }\n if (schema.enum && !schema.enum.some((entry) => entry === value)) {\n issues.push(\n `${path}: value ${JSON.stringify(value)} is not one of the allowed enum values`,\n );\n }\n if (schema.pattern && !new RegExp(schema.pattern).test(value)) {\n issues.push(`${path}: value does not match pattern ${schema.pattern}`);\n }\n return issues;\n }\n\n case 'number':\n case 'integer': {\n if (typeof value !== 'number' || Number.isNaN(value)) {\n return [`${path}: expected number, got ${describeType(value)}`];\n }\n if (kind === 'integer' && !Number.isInteger(value)) {\n issues.push(`${path}: expected integer, got non-integer number`);\n }\n if (schema.minimum !== undefined && value < schema.minimum) {\n issues.push(`${path}: value ${value} is below minimum ${schema.minimum}`);\n }\n if (schema.maximum !== undefined && value > schema.maximum) {\n issues.push(`${path}: value ${value} is above maximum ${schema.maximum}`);\n }\n if (schema.enum && !schema.enum.some((entry) => entry === value)) {\n issues.push(`${path}: value ${value} is not one of the allowed enum values`);\n }\n return issues;\n }\n\n case 'boolean': {\n if (typeof value !== 'boolean') {\n return [`${path}: expected boolean, got ${describeType(value)}`];\n }\n return issues;\n }\n\n case 'null': {\n if (value !== null) {\n return [`${path}: expected null, got ${describeType(value)}`];\n }\n return issues;\n }\n\n default:\n return kind === undefined\n ? [`${path}: schema node declares neither a type nor anyOf`]\n : [`${path}: unsupported schema type ${String(kind)}`];\n }\n}\n\n/**\n * Whether an object node is closed to properties it does not declare.\n *\n * `additionalProperties` declares closure **relative to a declared `properties` set**. A node that\n * declares no `properties` declares no closure and permits any properties, exactly as JSON Schema\n * says — and exactly as every provider reads the document we forward them. A node that DOES declare\n * `properties`, including an empty `properties: {}`, is closed unless `additionalProperties` says\n * otherwise.\n *\n * This is the convention's definition at a position it was never written for, not an exception to\n * it. The rule was authored for a tool's `parameters` root, where `properties` is structurally\n * always present, so \"omitted rejects extras\" could only ever mean \"nothing beyond the declared\n * set\". A nested node can omit `properties` entirely; carrying the root's phrasing there unchanged\n * would give omitted `additionalProperties` a second meaning — \"the empty object only\" — that no\n * producer intends, that contradicts the schema we ship to the provider, and that is the same\n * root-versus-nested divergence this item exists to remove.\n *\n * An explicit `additionalProperties: false` closes the node either way; that is a producer saying so.\n */\nfunction isClosed(schema: IParameterSchema): boolean {\n const additional = schema.additionalProperties;\n if (additional === false) {\n return true;\n }\n return additional === undefined && schema.properties !== undefined;\n}\n\n/**\n * A union node is satisfied by ANY member. Reporting every member's complaint would bury the real\n * one, so a failure reports the branch count and each branch's issues under its own index.\n */\nfunction validateAnyOf(members: IParameterSchema[], value: unknown, path: string): string[] {\n if (members.length === 0) {\n return [`${path}: anyOf declares no members`];\n }\n const perMember = members.map((member, index) =>\n validateAgainstJsonSchema(member, value, `${path}|anyOf[${index}]`),\n );\n if (perMember.some((memberIssues) => memberIssues.length === 0)) {\n return [];\n }\n return [\n `${path}: value matches none of the ${members.length} allowed shapes`,\n ...perMember.flat(),\n ];\n}\n\nfunction describeType(value: unknown): string {\n if (value === null) return 'null';\n if (Array.isArray(value)) return 'array';\n return typeof value;\n}\n\n/**\n * Parse the model's final text into a JSON value. Tolerates a fenced\n * ```json code block wrapper (providers without native enforcement commonly\n * emit one); the parsed value is still strictly schema-validated afterwards.\n */\nexport function parseStructuredResponseText(\n text: string,\n): { success: true; value: unknown } | { success: false; issue: string } {\n const trimmed = text.trim();\n // `[^\\S\\n]*\\n` — not `\\s*\\n`: `\\s` also matches `\\n`, so the two overlap and an unterminated\n // fence costs O(n^2) to reject. Restricting the run to horizontal whitespace makes the newline\n // split point unique. `text` here is raw model output, so it is not trusted to be well-formed.\n const fenced = /^```(?:json)?[^\\S\\n]*\\n([\\s\\S]*?)\\n?```$/.exec(trimmed);\n const candidate = fenced ? fenced[1] : trimmed;\n try {\n return { success: true, value: JSON.parse(candidate) };\n } catch (error) {\n // allow-fallback: converts JSON.parse failure into a typed failure result feeding the bounded retry loop\n return {\n success: false,\n issue: `response is not valid JSON: ${error instanceof Error ? error.message : String(error)}`,\n };\n }\n}\n","/**\n * Deciding — before the first model call — which transport can carry a schema. CORE-043.\n *\n * `robotaRunStructured` wrapped an ordinary run in a validate-and-retry loop and asked the provider\n * for `responseFormat: 'json_schema'` unconditionally. A provider whose surface cannot express that\n * accepted the option and ignored it, so the schema never reached the model; the loop then spent its\n * full retry budget rediscovering that, and reported \"failed schema validation after 3 attempts\" —\n * a description of the symptom, on a fact that was knowable before anything was sent.\n *\n * The decision lives HERE, at the seam that builds the wire option, rather than in\n * `robotaRunStructured`. That function has no provider — it composes a run out of the public API and\n * never sees which model will serve it, so a decision made there would have to guess at exactly the\n * thing being decided. `buildChatResponseFormat` is the one place every structured request passes\n * through with the resolved provider in hand.\n */\n\nimport { modelDeclaresCapability } from '../interfaces/model-capability.js';\n\nimport type { IProviderCapabilityTable } from '../interfaces/model-capability.js';\nimport type {\n IProviderStructuredOutputCapability,\n TStructuredOutputMechanism,\n} from '../interfaces/structured-output-capability.js';\n\nexport interface IStructuredOutputResolutionInput {\n /** The provider's own declaration, or `undefined` when it declares nothing. */\n table: IProviderCapabilityTable | undefined;\n /**\n * Which model will serve the request. Required, not optional.\n *\n * Capability is a property of a (provider, model) pair — `deepseek-chat` and `deepseek-reasoner`\n * differ — so an optional model argument would let a caller ask a question that has no answer and\n * receive a confident one.\n */\n model: string;\n /**\n * Whether the provider is pointed at its vendor's own endpoint (CORE-043).\n *\n * Deliberately NOT a field on the capability table. Endpoint identity and capability declaration\n * are independent facts: a provider that declines to declare a table — because it has no verified\n * source for one — must still be able to say it is pointed at a gateway. Coupling them would force\n * that provider to invent a table in order to report an endpoint, which is exactly the fabricated\n * claim PROV-006 refused to make. `undefined` means the provider did not say.\n */\n endpointIsVendorDefault?: boolean | undefined;\n}\n\n/** Which transport the declared capabilities imply, most capable first. */\nfunction mechanismFor(\n table: IProviderCapabilityTable | undefined,\n model: string,\n): TStructuredOutputMechanism {\n if (modelDeclaresCapability(table, model, 'json_schema') === true) {\n return 'response_schema';\n }\n if (modelDeclaresCapability(table, model, 'json_object') === true) {\n return 'json_object';\n }\n return 'none';\n}\n\n/**\n * What this model can be asked for, and how confident that answer is.\n *\n * A model absent from a table's deviations resolves to the vendor default — that is the table's own\n * miss policy (PROV-006), not a guess made here. What this function adds is the record of WHICH of\n * those routes produced the answer, because a caller told \"no schema transport\" deserves to know\n * whether that was declared for this model or inherited from a baseline.\n */\nexport function resolveStructuredOutputCapability(\n input: IStructuredOutputResolutionInput,\n): IProviderStructuredOutputCapability {\n const { table, model, endpointIsVendorDefault } = input;\n\n if (!table) {\n // Silence is not denial (PROV-006). A provider that declares nothing has said nothing, and\n // resolving that to `'none'` would strip a working `json_schema` from every provider that simply\n // has no verified table yet — reading a gap in our own records as a limitation of the vendor.\n // The request goes out as asked; `provenance` is what carries the uncertainty.\n if (endpointIsVendorDefault === false) {\n return {\n mechanism: 'response_schema',\n provenance: 'unverified-endpoint',\n reason:\n 'a custom baseURL is configured and the provider declares no capability table, so nothing here can claim the endpoint enforces the schema',\n };\n }\n return {\n mechanism: 'response_schema',\n provenance: 'undeclared',\n reason:\n 'the provider declares no capability table, so the request is sent as asked — silence is not a denial',\n };\n }\n\n const mechanism = mechanismFor(table, model);\n const declaredForThisModel = table.deviations?.[model] !== undefined;\n\n if (endpointIsVendorDefault === false) {\n return {\n mechanism,\n provenance: 'unverified-endpoint',\n reason:\n 'a custom baseURL is configured, so the vendor capability table describes the protocol but not necessarily the endpoint serving it',\n };\n }\n\n return {\n mechanism,\n provenance: declaredForThisModel ? 'catalog' : 'vendor-default',\n ...(mechanism === 'none' && {\n reason: `${model} declares no schema transport, so the schema travels in the prompt and is enforced by validation`,\n }),\n ...(mechanism === 'json_object' && {\n reason: `${model} guarantees JSON but not its shape, so the schema travels in the prompt and is enforced by validation`,\n }),\n };\n}\n","/**\n * The injected environment resolver (#2347 / #2051).\n *\n * Provider normalization must be deterministic from its arguments and a resolver it is HANDED —\n * never from ambient `process.env`. This module is the ONE place in the normalization path that is\n * allowed to touch `process.env`: it defines the default resolver a composition root injects when it\n * wants the host environment. Every normalization module (`env-ref.ts`, both `provider-factory.ts`)\n * takes a `TEnvResolver` parameter and is forbidden `process.env` by the\n * `provider-env-resolution` scan.\n */\n\n/** Resolve an environment variable NAME (not a `$ENV:` reference) to its value, or `undefined`. */\nexport type TEnvResolver = (name: string) => string | undefined;\n\n/** The host process environment. Injected by composition roots; a test injects a map instead. */\nexport const processEnvResolver: TEnvResolver = (name) => process.env[name];\n\n/** Build a resolver over a fixed record — what a unit test injects instead of mutating `process.env`. */\nexport function createRecordEnvResolver(record: Readonly<Record<string, string>>): TEnvResolver {\n return (name) => record[name];\n}\n","import {\n isImageGenerationProvider,\n isVideoGenerationProvider,\n type IImageGenerationProvider,\n type IVideoGenerationProvider,\n} from '../interfaces/media-provider.js';\nimport { processEnvResolver, type TEnvResolver } from '../utils/env-resolver.js';\n\nimport type {\n IMediaProviderConfig,\n IMediaProviderDefinition,\n} from '../interfaces/media-provider-definition.js';\n\nexport type TMediaCredentialResolution =\n | { readonly ok: true; readonly config: IMediaProviderConfig }\n | { readonly ok: false; readonly missing: readonly string[] };\n\nexport interface IMediaProviderOverrides {\n readonly imageCapableModels?: readonly string[];\n readonly baseUrl?: string;\n}\n\nfunction firstResolved(\n names: readonly string[] | undefined,\n resolve: TEnvResolver,\n): string | undefined {\n for (const name of names ?? []) {\n const value = resolve(name);\n if (typeof value === 'string' && value.trim().length > 0) return value.trim();\n }\n return undefined;\n}\n\nexport function resolveMediaProviderConfig(\n definition: IMediaProviderDefinition,\n overrides: IMediaProviderOverrides = {},\n resolve: TEnvResolver = processEnvResolver,\n): TMediaCredentialResolution {\n const requirement = definition.credentialRequirement;\n const baseUrl =\n overrides.baseUrl ??\n firstResolved(requirement?.baseUrlEnvVars, resolve) ??\n definition.defaults?.baseUrl;\n\n if (requirement === undefined) {\n return {\n ok: true,\n config: {\n ...(baseUrl !== undefined ? { baseUrl } : {}),\n ...(overrides.imageCapableModels !== undefined\n ? { imageCapableModels: overrides.imageCapableModels }\n : {}),\n },\n };\n }\n\n const credential = firstResolved(requirement.credentialEnvVars, resolve);\n const missing: string[] = [];\n if (credential === undefined) missing.push(...requirement.credentialEnvVars);\n if (requirement.requiresBaseUrl === true && baseUrl === undefined) {\n missing.push(...(requirement.baseUrlEnvVars ?? []));\n }\n if (missing.length > 0) return { ok: false, missing };\n\n return {\n ok: true,\n config: {\n ...(credential !== undefined ? { credential } : {}),\n ...(baseUrl !== undefined ? { baseUrl } : {}),\n ...(overrides.imageCapableModels !== undefined\n ? { imageCapableModels: overrides.imageCapableModels }\n : {}),\n },\n };\n}\n\nexport function createImageProviderFromDefinition(\n definition: IMediaProviderDefinition,\n overrides: IMediaProviderOverrides = {},\n resolve: TEnvResolver = processEnvResolver,\n): IImageGenerationProvider | undefined {\n if (definition.createImageProvider === undefined) return undefined;\n const resolved = resolveMediaProviderConfig(definition, overrides, resolve);\n if (!resolved.ok) return undefined;\n try {\n const provider = definition.createImageProvider(resolved.config);\n return isImageGenerationProvider(provider) ? provider : undefined;\n } catch {\n // allow-fallback: an unavailable credential or provider SDK is reported by the owning node's typed validation error\n return undefined;\n }\n}\n\nexport function createVideoProviderFromDefinition(\n definition: IMediaProviderDefinition,\n overrides: IMediaProviderOverrides = {},\n resolve: TEnvResolver = processEnvResolver,\n): IVideoGenerationProvider | undefined {\n if (definition.createVideoProvider === undefined) return undefined;\n const resolved = resolveMediaProviderConfig(definition, overrides, resolve);\n if (!resolved.ok) return undefined;\n try {\n const provider = definition.createVideoProvider(resolved.config);\n return isVideoGenerationProvider(provider) ? provider : undefined;\n } catch {\n // allow-fallback: an unavailable credential or provider SDK is reported by the owning node's typed validation error\n return undefined;\n }\n}\n","import { processEnvResolver, type TEnvResolver } from './env-resolver.js';\n\nexport const ENV_REFERENCE_PREFIX = '$ENV:';\n\nexport function isEnvReference(value: string): boolean {\n return value.startsWith(ENV_REFERENCE_PREFIX);\n}\n\nexport function formatEnvReference(name: string): string {\n return `${ENV_REFERENCE_PREFIX}${name}`;\n}\n\n/**\n * Resolve a `$ENV:<name>` reference through `resolve` (#2347): a non-reference is returned as-is; an\n * empty name is `undefined`. The resolver defaults to the host environment so existing call sites keep\n * their meaning, but this function itself never reads `process.env`.\n */\nexport function resolveEnvReference(\n value: string,\n resolve: TEnvResolver = processEnvResolver,\n): string | undefined {\n if (!isEnvReference(value)) {\n return value;\n }\n const envName = value.slice(ENV_REFERENCE_PREFIX.length).trim();\n if (envName.length === 0) {\n return undefined;\n }\n return resolve(envName);\n}\n\nexport function hasUsableSecretReference(\n value: string | undefined,\n resolve: TEnvResolver = processEnvResolver,\n): boolean {\n if (value === undefined || value.length === 0) {\n return false;\n }\n return resolveEnvReference(value, resolve) !== undefined;\n}\n","import {\n findProviderDefinition,\n formatSupportedProviderTypes,\n getProviderCredentialRequirement,\n} from '../interfaces/provider-definition.js';\nimport { resolveEnvReference } from '../utils/env-ref.js';\nimport { processEnvResolver, type TEnvResolver } from '../utils/env-resolver.js';\n\nimport type {\n IProviderDefinition,\n IProviderDefinitionConfig,\n IProviderCredentialRequirement,\n TProviderCredentialField,\n} from '../interfaces/provider-definition.js';\nimport type { IAIProvider } from '../interfaces/provider.js';\nimport type { TUniversalValue } from '../interfaces/types.js';\n\n/**\n * Normalize loose provider settings into a fully-resolved {@link IProviderDefinitionConfig}.\n *\n * The default model comes from the provider definition's `defaults.model` (the single SSOT for a\n * provider's default model — never a second field); `apiKey` `$ENV:` references are resolved here via\n * {@link resolveEnvReference}. This resolver lives in `agent-core` (it imports only `agent-core` symbols)\n * so any consumer — including the `dag-node-llm-text` leaf, which depends on `agent-core` alone — reuses\n * the one credential-resolution path instead of re-reading `process.env` (ARCH-PROVIDER-003).\n *\n * #2347: the environment is INJECTED as `resolve`. This function is deterministic from its arguments\n * and that resolver; it never reads `process.env` itself (guarded by the `provider-env-resolution`\n * scan). The default is the host environment so composition roots need not pass one.\n */\nexport function normalizeProviderConfig(\n settings: {\n name: string;\n model?: string;\n apiKey?: string;\n baseURL?: string;\n timeout?: number;\n options?: Record<string, TUniversalValue>;\n },\n providerDefinitions: readonly IProviderDefinition[],\n resolve: TEnvResolver = processEnvResolver,\n): IProviderDefinitionConfig {\n const defaults = findProviderDefinition(providerDefinitions, settings.name)?.defaults ?? {};\n const model = settings.model ?? defaults.model;\n if (!model) {\n throw new Error(`Provider ${settings.name} requires model`);\n }\n const apiKeyReference = settings.apiKey ?? defaults.apiKey;\n const options = settings.options ?? defaults.options;\n return {\n name: settings.name,\n model,\n apiKey:\n apiKeyReference !== undefined ? resolveEnvReference(apiKeyReference, resolve) : undefined,\n baseURL: settings.baseURL ?? defaults.baseURL,\n timeout: settings.timeout,\n ...(options !== undefined && { options }),\n };\n}\n\n/**\n * Construct an {@link IAIProvider} from a resolved config against the injected provider-definition\n * registry, enforcing the definition's credential requirement. Throws a typed error naming the supported\n * provider types when the requested provider is not in the registry.\n */\nexport function createProviderFromConfig(\n settings: IProviderDefinitionConfig,\n providerDefinitions: readonly IProviderDefinition[],\n): IAIProvider {\n const definition = findProviderDefinition(providerDefinitions, settings.name);\n if (definition === undefined) {\n throw new Error(\n `Unknown provider: ${settings.name}. Currently supported: ${formatSupportedProviderTypes(providerDefinitions)}`,\n );\n }\n const credentialRequirement = getProviderCredentialRequirement(definition);\n if (\n credentialRequirement !== undefined &&\n !hasRequiredProviderCredential(settings, credentialRequirement)\n ) {\n throw new Error(\n `Provider ${settings.name} requires ${formatCredentialRequirement(credentialRequirement)}`,\n );\n }\n return definition.createProvider(settings);\n}\n\n/** Whether `settings` satisfies at least one of the credential fields the requirement allows. */\nfunction hasRequiredProviderCredential(\n settings: IProviderDefinitionConfig,\n requirement: IProviderCredentialRequirement,\n): boolean {\n return requirement.anyOf.some((field) => hasProviderCredentialValue(settings, field));\n}\n\nfunction hasProviderCredentialValue(\n settings: IProviderDefinitionConfig,\n field: TProviderCredentialField,\n): boolean {\n const value = settings[field];\n return value !== undefined && value.length > 0;\n}\n\nfunction formatCredentialRequirement(requirement: IProviderCredentialRequirement): string {\n return requirement.anyOf\n .map((field) => (field === 'apiKey' ? 'apiKey (API key)' : field))\n .join(' or ');\n}\n","/**\n * A random identifier, from the platform rather than from Node. CORE-028.\n *\n * Five modules in this package imported `randomUUID` from `node:crypto`, and this package ships a\n * `browser` export condition — so the first line of the browser bundle was\n * `import{randomUUID}from\"node:crypto\"`. `apps/agent-web` carries webpack aliases and two\n * hand-written stub modules that exist only to patch around that.\n *\n * `globalThis.crypto.randomUUID()` is the same function in both places: Web Crypto in the browser,\n * and a global in Node since 19 (verified on 22.14). Nothing is lost by asking the platform.\n *\n * The fallback is NOT a silent one. `crypto.randomUUID` requires a SECURE CONTEXT in browsers, so a\n * page served over plain HTTP has `crypto` but not the method — and an id generator that throws\n * there would take the whole session with it. The replacement is a v4 UUID built from\n * `getRandomValues`, which needs no secure context and is the same quality of randomness; only if\n * even that is missing does this throw, because at that point there is no randomness to be had and\n * inventing some with `Math.random` would be worse than failing.\n */\nexport function randomId(): string {\n const platformCrypto = globalThis.crypto as Crypto | undefined;\n if (typeof platformCrypto?.randomUUID === 'function') {\n return platformCrypto.randomUUID();\n }\n if (typeof platformCrypto?.getRandomValues === 'function') {\n const bytes = platformCrypto.getRandomValues(new Uint8Array(16));\n // RFC 4122 §4.4: set the version (4) and variant (10xx) bits.\n bytes[6] = ((bytes[6] ?? 0) & 0x0f) | 0x40;\n bytes[8] = ((bytes[8] ?? 0) & 0x3f) | 0x80;\n const hex = Array.from(bytes, (b) => b.toString(16).padStart(2, '0')).join('');\n return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;\n }\n throw new Error(\n 'No cryptographic randomness is available on this platform (globalThis.crypto is missing both ' +\n 'randomUUID and getRandomValues), so a unique identifier cannot be generated. This is not ' +\n 'something to substitute Math.random for.',\n );\n}\n","/**\n * Message factory functions for conversation messages.\n *\n * Extracted from conversation-history-manager.ts.\n *\n * Note: Type guards live in interfaces/messages.ts (SSOT) and are NOT duplicated here.\n */\nimport { randomId } from '../utils/random-id.js';\n\nimport type {\n IAssistantMessage,\n TUniversalMessageMetadata,\n ISystemMessage,\n IToolCall,\n IToolMessage,\n IUserMessage,\n TUniversalMessagePart,\n TMessageState,\n} from '../interfaces/messages';\n\n/** Create a user message. */\nexport function createUserMessage(\n content: string,\n options?: {\n name?: string;\n metadata?: TUniversalMessageMetadata;\n parts?: TUniversalMessagePart[];\n },\n): IUserMessage {\n const message: IUserMessage = {\n id: randomId(),\n role: 'user',\n content,\n state: 'complete',\n timestamp: new Date(),\n };\n if (options?.name) message.name = options.name;\n if (options?.metadata) message.metadata = options.metadata;\n if (options?.parts) message.parts = options.parts;\n return message;\n}\n\n/** Create an assistant message. */\nexport function createAssistantMessage(\n content: string | null,\n options?: {\n toolCalls?: IToolCall[];\n metadata?: TUniversalMessageMetadata;\n parts?: TUniversalMessagePart[];\n state?: TMessageState;\n },\n): IAssistantMessage {\n const message: IAssistantMessage = {\n id: randomId(),\n role: 'assistant',\n content,\n state: options?.state ?? 'complete',\n timestamp: new Date(),\n };\n if (options?.toolCalls) message.toolCalls = options.toolCalls;\n if (options?.metadata) message.metadata = options.metadata;\n if (options?.parts) message.parts = options.parts;\n return message;\n}\n\n/** Create a system message. */\nexport function createSystemMessage(\n content: string,\n options?: {\n name?: string;\n metadata?: TUniversalMessageMetadata;\n parts?: TUniversalMessagePart[];\n },\n): ISystemMessage {\n const message: ISystemMessage = {\n id: randomId(),\n role: 'system',\n content,\n state: 'complete',\n timestamp: new Date(),\n };\n if (options?.name) message.name = options.name;\n if (options?.metadata) message.metadata = options.metadata;\n if (options?.parts) message.parts = options.parts;\n return message;\n}\n\n/** Create a tool message. */\nexport function createToolMessage(\n content: string,\n options: {\n toolCallId: string;\n name?: string;\n metadata?: TUniversalMessageMetadata;\n parts?: TUniversalMessagePart[];\n },\n): IToolMessage {\n const message: IToolMessage = {\n id: randomId(),\n role: 'tool',\n content,\n toolCallId: options.toolCallId,\n state: 'complete',\n timestamp: new Date(),\n };\n if (options.name) message.name = options.name;\n if (options.metadata) message.metadata = options.metadata;\n if (options.parts) message.parts = options.parts;\n return message;\n}\n","/**\n * In-memory conversation history implementations.\n *\n * SimpleConversationHistory and PersistentSystemConversationHistory.\n */\nimport {\n createUserMessage,\n createAssistantMessage,\n createSystemMessage,\n createToolMessage,\n} from './conversation-message-factory';\nimport {\n isSystemMessage,\n messageToHistoryEntry,\n chatEntryToMessage,\n isChatEntry,\n} from '../interfaces/messages';\n\nimport type { IConversationHistory } from './conversation-history-types';\nimport type {\n TUniversalMessageMetadata,\n TUniversalMessageRole,\n IToolCall,\n TUniversalMessage,\n TUniversalMessagePart,\n IHistoryEntry,\n} from '../interfaces/messages';\n\n/**\n * Default conversation history implementation.\n * In-memory storage with optional message count limiting.\n * @public\n */\nexport class SimpleConversationHistory implements IConversationHistory {\n protected readonly maxMessages: number;\n private entries: IHistoryEntry[] = [];\n\n constructor(options?: { maxMessages?: number }) {\n this.maxMessages = options?.maxMessages || 0;\n }\n\n /** Add a chat message (converted to IHistoryEntry internally) */\n addMessage(message: TUniversalMessage): void {\n this.entries.push(messageToHistoryEntry(message));\n this.applyMessageLimit();\n }\n\n /** Add a raw history entry (for events, etc.) */\n addEntry(entry: IHistoryEntry): void {\n this.entries.push(entry);\n }\n\n /** Get all history entries (universal timeline) */\n getHistory(): IHistoryEntry[] {\n return [...this.entries];\n }\n\n addUserMessage(\n content: string,\n metadata?: TUniversalMessageMetadata,\n parts?: TUniversalMessagePart[],\n ): void {\n this.addMessage(\n createUserMessage(content, { ...(metadata && { metadata }), ...(parts && { parts }) }),\n );\n }\n\n addAssistantMessage(\n content: string | null,\n toolCalls?: IToolCall[],\n metadata?: TUniversalMessageMetadata,\n parts?: TUniversalMessagePart[],\n ): void {\n this.addMessage(\n createAssistantMessage(content, {\n ...(toolCalls && { toolCalls }),\n ...(metadata && { metadata }),\n ...(parts && { parts }),\n }),\n );\n }\n\n addSystemMessage(\n content: string,\n metadata?: TUniversalMessageMetadata,\n parts?: TUniversalMessagePart[],\n ): void {\n this.addMessage(\n createSystemMessage(content, { ...(metadata && { metadata }), ...(parts && { parts }) }),\n );\n }\n\n /**\n * Set the single head system prompt (the agent's live instruction state).\n *\n * The system prompt is not append-only conversation content: it is replaceable agent config. This\n * enforces exactly one system message, AT THE HEAD, replacing any existing one(s). It is injected\n * once per session and updated in place only when the prompt actually changes (persona, etc.); it\n * is not called per turn, so a fast path is unnecessary.\n */\n setSystemPrompt(\n content: string,\n metadata?: TUniversalMessageMetadata,\n parts?: TUniversalMessagePart[],\n ): void {\n const isSystemChatEntry = (entry: IHistoryEntry): boolean =>\n isChatEntry(entry) && isSystemMessage(chatEntryToMessage(entry));\n // Drop every existing system message, then place exactly one at the head.\n const withoutSystem = this.entries.filter((entry) => !isSystemChatEntry(entry));\n const entry = messageToHistoryEntry(\n createSystemMessage(content, { ...(metadata && { metadata }), ...(parts && { parts }) }),\n );\n withoutSystem.unshift(entry);\n this.entries = withoutSystem;\n }\n\n addToolMessageWithId(\n content: string,\n toolCallId: string,\n toolName: string,\n metadata?: TUniversalMessageMetadata,\n parts?: TUniversalMessagePart[],\n ): void {\n this.addMessage(\n createToolMessage(content, {\n toolCallId,\n name: toolName,\n ...(metadata && { metadata }),\n ...(parts && { parts }),\n }),\n );\n }\n\n /** Get chat messages only (backward compatible) */\n getMessages(): TUniversalMessage[] {\n return this.entries.filter(isChatEntry).map(chatEntryToMessage);\n }\n getMessagesByRole(role: TUniversalMessageRole): TUniversalMessage[] {\n return this.getMessages().filter((m) => m.role === role);\n }\n getRecentMessages(count: number): TUniversalMessage[] {\n return this.getMessages().slice(-count);\n }\n getMessageCount(): number {\n return this.entries.filter(isChatEntry).length;\n }\n clear(): void {\n this.entries = [];\n }\n\n /** @internal — limits chat entries only, preserves event entries */\n protected applyMessageLimit(): void {\n if (this.maxMessages <= 0) return;\n const chatEntries = this.entries.filter(isChatEntry);\n if (chatEntries.length <= this.maxMessages) return;\n\n const chatMessages = chatEntries.map(chatEntryToMessage);\n const systemMessages = chatMessages.filter(isSystemMessage);\n const nonSystem = chatMessages.filter((msg) => !isSystemMessage(msg));\n const available = Math.max(0, this.maxMessages - systemMessages.length);\n const keepMessages = [...systemMessages, ...nonSystem.slice(-available)];\n const keepIds = new Set(keepMessages.map((m) => m.id));\n\n // Keep all event entries + kept chat entries\n this.entries = this.entries.filter((e) => !isChatEntry(e) || keepIds.has(e.id));\n }\n}\n\n/**\n * Conversation history with persistent system prompt.\n * @public\n */\nexport class PersistentSystemConversationHistory implements IConversationHistory {\n private readonly history: SimpleConversationHistory;\n private systemPrompt: string;\n\n constructor(systemPrompt: string, options?: { maxMessages?: number }) {\n this.systemPrompt = systemPrompt;\n this.history = new SimpleConversationHistory(options);\n this.history.addSystemMessage(this.systemPrompt);\n }\n\n addMessage(message: TUniversalMessage): void {\n this.history.addMessage(message);\n }\n addUserMessage(\n content: string,\n metadata?: TUniversalMessageMetadata,\n parts?: TUniversalMessagePart[],\n ): void {\n this.history.addUserMessage(content, metadata, parts);\n }\n addAssistantMessage(\n content: string | null,\n toolCalls?: IToolCall[],\n metadata?: TUniversalMessageMetadata,\n parts?: TUniversalMessagePart[],\n ): void {\n this.history.addAssistantMessage(content, toolCalls, metadata, parts);\n }\n addSystemMessage(\n content: string,\n metadata?: TUniversalMessageMetadata,\n parts?: TUniversalMessagePart[],\n ): void {\n this.history.addSystemMessage(content, metadata, parts);\n }\n addToolMessageWithId(\n content: string,\n toolCallId: string,\n toolName: string,\n metadata?: TUniversalMessageMetadata,\n parts?: TUniversalMessagePart[],\n ): void {\n this.history.addToolMessageWithId(content, toolCallId, toolName, metadata, parts);\n }\n addEntry(entry: IHistoryEntry): void {\n this.history.addEntry(entry);\n }\n getHistory(): IHistoryEntry[] {\n return this.history.getHistory();\n }\n getMessages(): TUniversalMessage[] {\n return this.history.getMessages();\n }\n getMessagesByRole(role: TUniversalMessageRole): TUniversalMessage[] {\n return this.history.getMessagesByRole(role);\n }\n getRecentMessages(count: number): TUniversalMessage[] {\n return this.history.getRecentMessages(count);\n }\n getMessageCount(): number {\n return this.history.getMessageCount();\n }\n\n clear(): void {\n this.history.clear();\n this.history.addSystemMessage(this.systemPrompt);\n }\n\n updateSystemPrompt(systemPrompt: string): void {\n this.systemPrompt = systemPrompt;\n const nonSystem = this.history.getMessages().filter((msg) => !isSystemMessage(msg));\n this.history.clear();\n this.history.addSystemMessage(this.systemPrompt);\n nonSystem.forEach((message) => this.history.addMessage(message));\n }\n\n getSystemPrompt(): string {\n return this.systemPrompt;\n }\n}\n","/**\n * ConversationStore — streaming state management and API format conversion.\n *\n * In-memory history classes live in ./conversation-store-history.ts.\n */\n\nimport { SimpleConversationHistory } from './conversation-store-history';\nimport { isAssistantMessage, isToolMessage } from '../interfaces/messages';\nimport { randomId } from '../utils/random-id.js';\n\nimport type { IConversationHistory } from './conversation-history-types';\nimport type {\n TUniversalMessageMetadata,\n TUniversalMessageRole,\n IToolCall,\n TUniversalMessage,\n TUniversalMessagePart,\n IAssistantMessage,\n IHistoryEntry,\n TMessageState,\n} from '../interfaces/messages';\n\n/** API message format for provider consumption */\nexport interface IProviderApiMessage {\n role: string;\n content: string | null;\n tool_calls?: Array<{\n id: string;\n type: 'function';\n function: { name: string; arguments: string };\n }>;\n tool_call_id?: string;\n}\n\n/** State of an in-progress assistant response being streamed */\ninterface IStreamingState {\n id: string;\n content: string;\n toolCalls: IToolCall[];\n}\n\n/**\n * Conversation store with duplicate prevention and API format conversion.\n * @public\n */\nexport class ConversationStore implements IConversationHistory {\n private history: SimpleConversationHistory;\n private pendingAssistant: IStreamingState | null = null;\n\n // `maxMessages` defaults to 0 = unbounded (append-only). History records everything; context size\n // is managed by size-based compaction, never by count-based truncation. A positive value is an\n // explicit opt-in for a bounded buffer only.\n constructor(maxMessages: number = 0) {\n this.history = new SimpleConversationHistory({ maxMessages });\n }\n\n addMessage(message: TUniversalMessage): void {\n this.history.addMessage(message);\n }\n addUserMessage(\n content: string,\n metadata?: TUniversalMessageMetadata,\n parts?: TUniversalMessagePart[],\n ): void {\n this.history.addUserMessage(content, metadata, parts);\n }\n addAssistantMessage(\n content: string | null,\n toolCalls?: IToolCall[],\n metadata?: TUniversalMessageMetadata,\n parts?: TUniversalMessagePart[],\n ): void {\n this.history.addAssistantMessage(content, toolCalls, metadata, parts);\n }\n addSystemMessage(\n content: string,\n metadata?: TUniversalMessageMetadata,\n parts?: TUniversalMessagePart[],\n ): void {\n this.history.addSystemMessage(content, metadata, parts);\n }\n\n /**\n * Set the single head system prompt (live instruction state). Replaces any existing system\n * message in place; idempotent and never appends. See agent-core SPEC → System Prompt (SSOT).\n */\n setSystemPrompt(\n content: string,\n metadata?: TUniversalMessageMetadata,\n parts?: TUniversalMessagePart[],\n ): void {\n this.history.setSystemPrompt(content, metadata, parts);\n }\n\n addToolMessage(\n content: string,\n toolCallId: string,\n toolName?: string,\n metadata?: TUniversalMessageMetadata,\n parts?: TUniversalMessagePart[],\n ): void {\n this.history.addToolMessageWithId(content, toolCallId, toolName || 'unknown', metadata, parts);\n }\n\n addToolMessageWithId(\n content: string,\n toolCallId: string,\n toolName: string,\n metadata?: TUniversalMessageMetadata,\n parts?: TUniversalMessagePart[],\n ): void {\n this.history.addToolMessageWithId(content, toolCallId, toolName, metadata, parts);\n }\n\n /** Add a raw history entry (events, etc.) */\n addEntry(entry: IHistoryEntry): void {\n this.history.addEntry(entry);\n }\n\n /** Get all history entries (universal timeline) */\n getHistory(): IHistoryEntry[] {\n return this.history.getHistory();\n }\n\n getMessages(): TUniversalMessage[] {\n return this.history.getMessages();\n }\n getMessagesByRole(role: TUniversalMessageRole): TUniversalMessage[] {\n return this.history.getMessagesByRole(role);\n }\n getRecentMessages(count: number): TUniversalMessage[] {\n return this.history.getRecentMessages(count);\n }\n getMessageCount(): number {\n return this.history.getMessageCount();\n }\n\n /** Begin a new assistant response. Must be called before provider call.\n * Ensures pendingAssistant exists so commitAssistant always has data to save. */\n beginAssistant(): void {\n if (!this.pendingAssistant) {\n this.pendingAssistant = {\n id: randomId(),\n content: '',\n toolCalls: [],\n };\n }\n }\n\n /** Append streaming text delta to pending assistant response */\n appendStreaming(delta: string): void {\n if (!this.pendingAssistant) {\n this.pendingAssistant = {\n id: randomId(),\n content: '',\n toolCalls: [],\n };\n }\n this.pendingAssistant.content += delta;\n }\n\n /** Append a tool call to pending assistant response (deduplicates by id) */\n appendToolCall(toolCall: IToolCall): void {\n if (!this.pendingAssistant) {\n this.pendingAssistant = {\n id: randomId(),\n content: '',\n toolCalls: [],\n };\n }\n if (!this.pendingAssistant.toolCalls.some((tc) => tc.id === toolCall.id)) {\n this.pendingAssistant.toolCalls.push(toolCall);\n }\n }\n\n /**\n * Commit pending assistant response to history.\n * Precondition: beginAssistant() must have been called before the provider call.\n * History is append-only — this always adds a message.\n */\n commitAssistant(state: TMessageState, metadata?: TUniversalMessageMetadata): void {\n if (!this.pendingAssistant) return; // No pending state — error paths use addAssistantMessage directly\n const pending = this.pendingAssistant;\n const hasToolCalls = pending.toolCalls.length > 0;\n // History records everything — text is always preserved.\n // Context savings is compaction's responsibility, not history's.\n const content = pending.content;\n const message: IAssistantMessage = {\n id: pending.id,\n role: 'assistant',\n content,\n state,\n timestamp: new Date(),\n ...(hasToolCalls && { toolCalls: pending.toolCalls }),\n ...(metadata && { metadata }),\n };\n this.history.addMessage(message);\n this.pendingAssistant = null;\n }\n\n /** Discard pending assistant response without saving */\n discardPending(): void {\n this.pendingAssistant = null;\n }\n\n /** Returns true if there is accumulated pending assistant state (streaming or tool calls) */\n hasPendingAssistant(): boolean {\n return this.pendingAssistant !== null;\n }\n\n /** Get pending assistant content (empty string if no content streamed yet) */\n getPendingContent(): string {\n return this.pendingAssistant?.content ?? '';\n }\n\n getMessagesForAPI(): IProviderApiMessage[] {\n return this.history.getMessages().map((msg) => {\n const apiMsg: IProviderApiMessage = { role: msg.role, content: msg.content };\n // Annotate interrupted assistant messages for model awareness\n if (isAssistantMessage(msg) && msg.state === 'interrupted') {\n apiMsg.content = (apiMsg.content || '') + '\\n\\n[This response was interrupted by the user]';\n }\n if (isAssistantMessage(msg) && msg.toolCalls) {\n apiMsg.tool_calls = msg.toolCalls;\n }\n if (isToolMessage(msg)) {\n apiMsg.tool_call_id = msg.toolCallId;\n }\n return apiMsg;\n });\n }\n\n clear(): void {\n this.history.clear();\n }\n}\n","/**\n * Multi-session conversation history manager.\n *\n * Message factories live in ./conversation-message-factory.ts.\n * Store implementations live in ./conversation-store.ts.\n */\nimport { ConversationStore } from './conversation-store';\nimport { createLogger, type ILogger } from '../utils/logger';\n\n// Re-export type guards from interfaces (SSOT)\nexport {\n isUserMessage,\n isAssistantMessage,\n isSystemMessage,\n isToolMessage,\n} from '../interfaces/messages';\n\n// Re-export factory functions from conversation-message-factory\nexport {\n createUserMessage,\n createAssistantMessage,\n createSystemMessage,\n createToolMessage,\n} from './conversation-message-factory';\n\nexport {\n SimpleConversationHistory,\n PersistentSystemConversationHistory,\n} from './conversation-store-history';\n\nexport { ConversationStore } from './conversation-store';\n\nexport type { IProviderApiMessage } from './conversation-store';\n\nexport type { IConversationHistory } from './conversation-history-types';\n\n/**\n * 0 = unbounded (append-only). Conversation history must preserve every message; context size is\n * managed by size-based compaction (which summarizes), never by count-based truncation. A positive\n * value is an explicit opt-in for a bounded buffer only.\n */\nconst DEFAULT_MAX_MESSAGES_PER_CONVERSATION = 0;\nconst DEFAULT_MAX_CONVERSATIONS = 50;\n\n/** Configuration options for ConversationHistory manager */\nexport interface IConversationHistoryOptions {\n maxMessagesPerConversation?: number;\n maxConversations?: number;\n}\n\n/** Multi-session conversation history manager. @public */\nexport class ConversationHistory {\n private conversations = new Map<string, ConversationStore>();\n private logger: ILogger;\n private readonly maxMessagesPerConversation: number;\n private readonly maxConversations: number;\n\n constructor(options: IConversationHistoryOptions = {}) {\n this.maxMessagesPerConversation =\n options.maxMessagesPerConversation || DEFAULT_MAX_MESSAGES_PER_CONVERSATION;\n this.maxConversations = options.maxConversations || DEFAULT_MAX_CONVERSATIONS;\n this.logger = createLogger('ConversationHistory');\n }\n\n getConversationStore(conversationId: string): ConversationStore {\n if (!this.conversations.has(conversationId)) {\n if (this.conversations.size >= this.maxConversations) this.cleanupOldConversations();\n this.conversations.set(\n conversationId,\n new ConversationStore(this.maxMessagesPerConversation),\n );\n }\n return this.conversations.get(conversationId)!;\n }\n\n hasConversation(conversationId: string): boolean {\n return this.conversations.has(conversationId);\n }\n\n removeConversation(conversationId: string): boolean {\n const removed = this.conversations.delete(conversationId);\n if (removed) this.logger.debug('Removed conversation', { conversationId });\n return removed;\n }\n\n clearAll(): void {\n const count = this.conversations.size;\n this.conversations.clear();\n this.logger.debug('Cleared all conversations', { removedCount: count });\n }\n\n getStats(): { totalConversations: number; conversationIds: string[]; totalMessages: number } {\n const conversationIds = Array.from(this.conversations.keys());\n const totalMessages = Array.from(this.conversations.values()).reduce(\n (sum, s) => sum + s.getMessageCount(),\n 0,\n );\n return { totalConversations: this.conversations.size, conversationIds, totalMessages };\n }\n\n /** @internal */\n private cleanupOldConversations(): void {\n if (this.conversations.size === 0) return;\n const firstKey = this.conversations.keys().next().value;\n if (firstKey) this.conversations.delete(firstKey);\n }\n}\n","import type { IModelEffortOutcome } from '../interfaces/model-effort-capability';\nimport type { IChatOptions } from '../interfaces/provider';\n\ninterface IModelEffortOutcomeCollector {\n observe(outcome: IModelEffortOutcome): void;\n terminal(providerName: string): IModelEffortOutcome | undefined;\n}\n\n/** Collect exactly one adapter-owned terminal outcome per executor request. */\nexport function createModelEffortOutcomeCollector(): IModelEffortOutcomeCollector {\n let outcome: IModelEffortOutcome | undefined;\n let count = 0;\n\n return {\n observe(nextOutcome): void {\n count += 1;\n if (count === 1) outcome = nextOutcome;\n },\n terminal(providerName): IModelEffortOutcome | undefined {\n if (count > 1) {\n throw new Error(`Provider \"${providerName}\" emitted ${count} model-effort outcomes`);\n }\n return outcome;\n },\n };\n}\n\n/** Invoke the caller callback only after the executor has a terminal outcome. */\nexport function notifyModelEffortOutcome(\n logger: { warn(message: string, data: Record<string, string>): void },\n options: IChatOptions | undefined,\n outcome: IModelEffortOutcome | undefined,\n): void {\n if (outcome === undefined || options?.onModelEffortOutcome === undefined) return;\n try {\n options.onModelEffortOutcome(outcome);\n } catch (error) {\n logger.warn('Model-effort outcome observer failed', {\n error: error instanceof Error ? error.message : String(error),\n });\n }\n}\n","import {\n createModelEffortOutcomeCollector,\n notifyModelEffortOutcome,\n} from './local-executor-model-effort';\nimport { AbstractExecutor } from '../abstracts/abstract-executor';\n\nimport type {\n IChatExecutionRequest,\n IStreamExecutionRequest,\n ILocalExecutorConfig,\n IExecutorChatResult,\n TExecutorStreamEvent,\n} from '../interfaces/executor';\nimport type { TUniversalMessage, IAssistantMessage } from '../interfaces/messages';\nimport type { IChatOptions } from '../interfaces/provider';\n\n/**\n * Local executor that directly delegates to AI provider instances\n *\n * This executor maintains a registry of AI provider instances and delegates\n * chat execution requests to the appropriate provider based on the provider\n * name in the request. This is the \"traditional\" execution mode where\n * API calls are made directly from the client.\n *\n * @example\n * ```typescript\n * import { LocalExecutor } from '@robota-sdk/agent-core';\n * import { OpenAIProvider } from '@robota-sdk/agent-provider/openai';\n *\n * const executor = new LocalExecutor();\n * executor.registerProvider('openai', new OpenAIProvider({ apiKey: 'sk-...' }));\n *\n * const response = await executor.executeChat({\n * messages: [{ role: 'user', content: 'Hello!' }],\n * provider: 'openai',\n * model: 'gpt-4'\n * });\n * ```\n */\nexport class LocalExecutor extends AbstractExecutor {\n readonly name = 'local';\n readonly version = '1.0.0';\n\n private providers = new Map<string, IAIProviderInstance>();\n private config: Required<ILocalExecutorConfig>;\n\n constructor(config: ILocalExecutorConfig = {}) {\n super();\n this.config = {\n timeout: 30000,\n maxRetries: 3,\n retryDelay: 1000,\n enableLogging: false,\n ...config,\n };\n }\n\n /**\n * Register an AI provider instance for use with this executor\n *\n * @param name - Provider name (e.g., 'openai', 'anthropic', 'google')\n * @param provider - Provider instance that implements the required chat methods\n */\n registerProvider(name: string, provider: IAIProviderInstance): void {\n this.providers.set(name, provider);\n }\n\n /**\n * Unregister an AI provider\n *\n * @param name - Provider name to remove\n */\n unregisterProvider(name: string): void {\n this.providers.delete(name);\n }\n\n /**\n * Get registered provider instance\n *\n * @param name - Provider name\n * @returns Provider instance or undefined if not registered\n */\n getProvider(name: string): IAIProviderInstance | undefined {\n return this.providers.get(name);\n }\n\n /**\n * Execute a chat completion request by delegating to the appropriate provider\n */\n async executeChat(request: IChatExecutionRequest): Promise<IExecutorChatResult> {\n this.validateRequest(request);\n const provider = this.requireChatProvider(request);\n\n if (this.config.enableLogging) {\n this.logDebug(`Executing chat with provider: ${request.provider}, model: ${request.model}`);\n }\n\n try {\n let outcomes = createModelEffortOutcomeCollector();\n // Delegate to provider's chat method with retry logic\n const response = await this.withRetry(\n async () => {\n outcomes = createModelEffortOutcomeCollector();\n return await this.withTimeout(\n provider.chat(request.messages, {\n ...request.options,\n model: request.model,\n tools: request.tools,\n onModelEffortOutcome: (outcome) => {\n outcomes.observe(outcome);\n },\n }),\n this.config.timeout,\n );\n },\n this.config.maxRetries,\n this.config.retryDelay,\n );\n\n // Ensure response is properly typed as AssistantMessage\n if (response.role !== 'assistant') {\n throw new Error(`Expected assistant message, got ${response.role}`);\n }\n const modelEffortOutcome = outcomes.terminal(request.provider);\n\n this.validateResponse(response);\n notifyModelEffortOutcome(this.logger, request.options, modelEffortOutcome);\n return {\n message: response as IAssistantMessage,\n ...(modelEffortOutcome !== undefined && { modelEffortOutcome }),\n };\n } catch (error) {\n const err = error instanceof Error ? error : new Error(String(error));\n this.logError('Chat execution failed', err, {\n provider: request.provider,\n model: request.model,\n });\n throw err;\n }\n }\n\n /**\n * Execute a streaming chat completion request\n */\n async *executeChatStream(request: IStreamExecutionRequest): AsyncIterable<TExecutorStreamEvent> {\n this.validateRequest(request);\n\n const provider = this.providers.get(request.provider);\n if (!provider) {\n throw new Error(`Provider \"${request.provider}\" not registered with LocalExecutor`);\n }\n\n if (!provider.chatStream) {\n throw new Error(`Provider \"${request.provider}\" does not implement chatStream method`);\n }\n\n if (this.config.enableLogging) {\n this.logDebug(\n `Executing streaming chat with provider: ${request.provider}, model: ${request.model}`,\n );\n }\n\n try {\n const outcomes = createModelEffortOutcomeCollector();\n // Delegate to provider's chatStream method\n const stream = provider.chatStream(request.messages, {\n ...request.options,\n model: request.model,\n tools: request.tools,\n onModelEffortOutcome: (outcome) => {\n outcomes.observe(outcome);\n },\n });\n\n for await (const chunk of stream) {\n this.validateResponse(chunk);\n yield { kind: 'message', message: chunk };\n }\n const modelEffortOutcome = outcomes.terminal(request.provider);\n notifyModelEffortOutcome(this.logger, request.options, modelEffortOutcome);\n yield { kind: 'terminal', ...(modelEffortOutcome !== undefined && { modelEffortOutcome }) };\n } catch (error) {\n const err = error instanceof Error ? error : new Error(String(error));\n this.logError('Streaming chat execution failed', err, {\n provider: request.provider,\n model: request.model,\n });\n throw err;\n }\n }\n\n /**\n * Check if any registered providers support tools\n */\n override supportsTools(): boolean {\n for (const provider of this.providers.values()) {\n if (provider.supportsTools && provider.supportsTools()) {\n return true;\n }\n }\n return false;\n }\n\n /**\n * Validate executor configuration and all registered providers\n */\n override validateConfig(): boolean {\n try {\n // Validate executor config\n if (this.config.timeout <= 0) {\n return false;\n }\n if (this.config.maxRetries < 0) {\n return false;\n }\n if (this.config.retryDelay < 0) {\n return false;\n }\n\n // Validate all registered providers\n for (const provider of this.providers.values()) {\n if (provider.validateConfig && !provider.validateConfig()) {\n return false;\n }\n }\n\n return true;\n } catch {\n // allow-fallback: a provider validateConfig that throws means the config is unusable → not runnable\n return false;\n }\n }\n\n /**\n * Clean up all registered providers\n */\n override async dispose(): Promise<void> {\n if (this.config.enableLogging) {\n this.logDebug(`Disposing ${this.providers.size} providers`);\n }\n\n const disposePromises: Promise<void>[] = [];\n\n for (const provider of this.providers.values()) {\n if (provider.dispose) {\n disposePromises.push(provider.dispose());\n }\n }\n\n await Promise.all(disposePromises);\n this.providers.clear();\n }\n\n private requireChatProvider(\n request: IChatExecutionRequest,\n ): IAIProviderInstance & { chat: NonNullable<IAIProviderInstance['chat']> } {\n const provider = this.providers.get(request.provider);\n if (!provider) {\n throw new Error(`Provider \"${request.provider}\" not registered with LocalExecutor`);\n }\n if (!provider.chat) {\n throw new Error(`Provider \"${request.provider}\" does not implement chat method`);\n }\n return provider as IAIProviderInstance & { chat: NonNullable<IAIProviderInstance['chat']> };\n }\n}\n\n/**\n * Interface that AI provider instances must implement to work with LocalExecutor\n *\n * This interface represents the subset of AI provider methods that LocalExecutor\n * needs to delegate to. It's designed to be compatible with existing BaseAIProvider\n * implementations from @robota-sdk packages.\n */\nexport interface IAIProviderInstance {\n /** Provider name */\n readonly name?: string;\n\n /** Chat completion method */\n chat?(messages: TUniversalMessage[], options?: IChatOptions): Promise<TUniversalMessage>;\n\n /** Streaming chat completion method */\n chatStream?(\n messages: TUniversalMessage[],\n options?: IChatOptions,\n ): AsyncIterable<TUniversalMessage>;\n\n /** Check if provider supports tools */\n supportsTools?(): boolean;\n\n /** Validate provider configuration */\n validateConfig?(): boolean;\n\n /** Clean up provider resources */\n dispose?(): Promise<void>;\n}\n","/**\n * One argument of a command the user is told to paste into a shell, when it comes from text someone\n * else controls — a server name from a repository's settings, say.\n *\n * It is shown only when it is a plain token that reads the same in every shell and cannot be taken\n * for an option or an assignment. Nothing is quoted: quoting rules differ between shells (in fish a\n * backslash escapes inside single quotes), so a quoted name safe in one shell runs a command in\n * another. Anything else is not shown, and the caller names the argument generically instead.\n */\n\nconst PLAIN_ARGUMENT = /^[A-Za-z0-9_@%+:,./][A-Za-z0-9_@%+=:,./-]*$/;\n\n/** The argument as it is safe to paste, or `undefined` when it is not. */\nexport function shellArgumentForDisplay(value: string): string | undefined {\n return PLAIN_ARGUMENT.test(value) ? value : undefined;\n}\n","export interface IEventEmitterMetricsSnapshot {\n totalEmitted: number;\n totalErrors: number;\n}\n\nexport interface IEventEmitterMetrics {\n incrementEmitted(): void;\n incrementErrors(): void;\n getSnapshot(): IEventEmitterMetricsSnapshot;\n}\n\nexport class InMemoryEventEmitterMetrics implements IEventEmitterMetrics {\n private totalEmitted = 0;\n private totalErrors = 0;\n\n incrementEmitted(): void {\n this.totalEmitted += 1;\n }\n\n incrementErrors(): void {\n this.totalErrors += 1;\n }\n\n getSnapshot(): IEventEmitterMetricsSnapshot {\n return {\n totalEmitted: this.totalEmitted,\n totalErrors: this.totalErrors,\n };\n }\n}\n","/**\n * Helper functions for EventEmitterPlugin.\n *\n * Extracted from plugins/event-emitter-plugin.ts to keep that file under 300 lines.\n * Contains validation logic, event processing, and stats computation.\n */\nimport { PluginError } from '../utils/errors';\n\nimport type { ILogger } from '../utils/logger';\nimport type { IEventEmitterMetrics } from './event-emitter/metrics';\nimport type {\n IEventEmitterHandlerRegistration,\n IEventEmitterPluginOptions,\n IEventEmitterPluginStats,\n} from './event-emitter/plugin-types';\nimport type {\n IEventEmitterEventData,\n TEventDataValue,\n TEventName,\n TEventEmitterListener,\n} from './event-emitter/types';\n\n/**\n * Validate EventEmitterPlugin constructor options.\n * Throws PluginError if any value is out of range.\n */\nexport function validateEventEmitterOptions(\n options: IEventEmitterPluginOptions,\n pluginName: string,\n): void {\n if (options.maxListeners !== undefined && options.maxListeners < 0)\n throw new PluginError(\n `Invalid maxListeners option: ${options.maxListeners}. Must be a non-negative number.`,\n pluginName,\n { maxListeners: options.maxListeners },\n );\n if (\n options.buffer !== undefined &&\n options.buffer.maxSize !== undefined &&\n options.buffer.maxSize < 0\n )\n throw new PluginError(\n `Invalid buffer.maxSize option: ${options.buffer.maxSize}. Must be a non-negative number.`,\n pluginName,\n { bufferMaxSize: options.buffer.maxSize },\n );\n if (\n options.buffer !== undefined &&\n options.buffer.flushInterval !== undefined &&\n options.buffer.flushInterval < 0\n )\n throw new PluginError(\n `Invalid buffer.flushInterval option: ${options.buffer.flushInterval}. Must be a non-negative number.`,\n pluginName,\n { bufferFlushInterval: options.buffer.flushInterval },\n );\n}\n\n/**\n * Execute a single registered event handler, catching errors via metrics.\n *\n * CORE-021 (SPEC § EventEmitterPlugin Error Containment): with catchErrors enabled\n * (the default) a throwing handler is recorded and structured-logged, then SWALLOWED —\n * rethrowing here turned every handler bug into an unhandled rejection through the\n * buffered flush timer. catchErrors: false rethrows to the emitter caller.\n */\nexport async function executeEventHandler(\n handler: IEventEmitterHandlerRegistration,\n event: IEventEmitterEventData,\n metrics: IEventEmitterMetrics,\n catchErrors: boolean,\n logger: ILogger,\n): Promise<void> {\n try {\n await handler.listener(event);\n } catch (error) {\n metrics.incrementErrors();\n if (!catchErrors) {\n throw error instanceof Error ? error : new Error(String(error));\n }\n logger.error('Event handler error', {\n eventType: event.type,\n handlerId: handler.id,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n}\n\n/**\n * Process a single event by dispatching it to matching registered handlers.\n * Handles once-only removal and async vs sequential dispatch.\n */\nexport async function processEvent(\n event: IEventEmitterEventData,\n handlers: Map<TEventName, IEventEmitterHandlerRegistration[]>,\n asyncMode: boolean,\n offFn: (eventType: TEventName, id: string) => void,\n execHandler: (\n handler: IEventEmitterHandlerRegistration,\n event: IEventEmitterEventData,\n ) => Promise<void>,\n): Promise<void> {\n const eventHandlers = handlers.get(event.type);\n if (!eventHandlers || eventHandlers.length === 0) return;\n const handlersToCall = eventHandlers.filter((h) => !h.filter || h.filter(event));\n if (handlersToCall.length === 0) return;\n for (const h of handlersToCall.filter((h) => h.once)) offFn(event.type, h.id);\n if (asyncMode) {\n await Promise.all(handlersToCall.map((h) => execHandler(h, event)));\n return;\n }\n for (const h of handlersToCall) await execHandler(h, event);\n}\n\n/**\n * Compute the listener-count stats portion of EventEmitterPlugin.getStats().\n */\nfunction computeListenerStats(handlers: Map<TEventName, IEventEmitterHandlerRegistration[]>): {\n listenerCounts: Partial<Record<TEventName, number>>;\n totalListeners: number;\n} {\n const listenerCounts: Partial<Record<TEventName, number>> = {};\n let totalListeners = 0;\n for (const [eventType, hs] of handlers) {\n listenerCounts[eventType] = hs.length;\n totalListeners += hs.length;\n }\n return { listenerCounts, totalListeners };\n}\n\n/**\n * Build the full IEventEmitterPluginStats object.\n */\nexport function buildEventEmitterStats(\n base: Omit<\n IEventEmitterPluginStats,\n | 'eventTypes'\n | 'listenerCounts'\n | 'totalListeners'\n | 'bufferedEvents'\n | 'totalEmitted'\n | 'totalErrors'\n >,\n handlers: Map<TEventName, IEventEmitterHandlerRegistration[]>,\n bufferedEvents: number,\n metrics: IEventEmitterMetrics,\n): IEventEmitterPluginStats {\n const { listenerCounts, totalListeners } = computeListenerStats(handlers);\n const metricsSnapshot = metrics.getSnapshot();\n const enabled = base.enabled as boolean;\n const calls = base.calls as number;\n const errors = base.errors as number;\n return {\n enabled,\n calls,\n errors,\n eventTypes: Array.from(handlers.keys()),\n listenerCounts,\n totalListeners,\n bufferedEvents,\n totalEmitted: metricsSnapshot.totalEmitted,\n totalErrors: metricsSnapshot.totalErrors,\n };\n}\n\n/** Register a handler in the handlers map, enforcing max listeners. */\nexport function registerHandler(\n handlers: Map<TEventName, IEventEmitterHandlerRegistration[]>,\n eventType: TEventName,\n handlerId: string,\n listener: TEventEmitterListener,\n options: { once?: boolean; filter?: (event: IEventEmitterEventData) => boolean } | undefined,\n maxListeners: number,\n pluginName: string,\n): void {\n if (!handlers.has(eventType)) handlers.set(eventType, []);\n const hs = handlers.get(eventType)!;\n if (hs.length >= maxListeners) {\n throw new PluginError(\n `Maximum listeners (${maxListeners}) exceeded for event type: ${eventType}`,\n pluginName,\n { eventType, currentListeners: hs.length },\n );\n }\n hs.push({\n id: handlerId,\n listener,\n once: options?.once ?? false,\n ...(options?.filter && { filter: options.filter }),\n });\n}\n\n/** Remove a handler by id or listener reference. Returns true if removed. */\nexport function unregisterHandler(\n handlers: Map<TEventName, IEventEmitterHandlerRegistration[]>,\n eventType: TEventName,\n handlerIdOrListener: string | TEventEmitterListener,\n): boolean {\n const hs = handlers.get(eventType);\n if (!hs) return false;\n const index =\n typeof handlerIdOrListener === 'string'\n ? hs.findIndex((h) => h.id === handlerIdOrListener)\n : hs.findIndex((h) => h.listener === handlerIdOrListener);\n if (index !== -1) {\n hs.splice(index, 1);\n return true;\n }\n return false;\n}\n\nexport function buildToolCallEmitData(\n context: { executionId?: string; sessionId?: string; userId?: string },\n toolCall: { name?: string; id?: string; result?: string | number | boolean | null },\n duration: number | undefined,\n): Partial<IEventEmitterEventData> {\n const hasResult = toolCall.result !== null && toolCall.result !== undefined;\n return {\n executionId: context.executionId,\n sessionId: context.sessionId,\n userId: context.userId,\n data: {\n toolName: toolCall.name || '',\n toolId: toolCall.id || '',\n toolResult: hasResult ? String(toolCall.result) : undefined,\n duration: duration as TEventDataValue,\n success: hasResult,\n },\n };\n}\n","import {\n AbstractPlugin,\n type IPluginExecutionContext,\n type IPluginExecutionResult,\n type IPluginErrorContext,\n PluginCategory,\n PluginPriority,\n} from '../abstracts/abstract-plugin';\nimport { createLogger, type ILogger } from '../utils/logger';\nimport { InMemoryEventEmitterMetrics, type IEventEmitterMetrics } from './event-emitter/metrics';\nimport {\n EVENT_EMITTER_EVENTS,\n type IEventEmitterEventData,\n type TEventDataValue,\n type TEventName,\n type TEventEmitterListener,\n} from './event-emitter/types';\nimport {\n validateEventEmitterOptions,\n executeEventHandler,\n processEvent as processEventHelper,\n buildEventEmitterStats,\n registerHandler,\n unregisterHandler,\n buildToolCallEmitData,\n} from './event-emitter-helpers';\n\nimport type { IToolExecutionContext } from '../interfaces/tool';\nimport type { TTimerId } from '../utils';\nimport type {\n IEventEmitterHandlerRegistration,\n IEventEmitterPluginOptions,\n IEventEmitterPluginStats,\n} from './event-emitter/plugin-types';\n\n// Re-export types that were originally exported from this file\nexport type { TEventName };\nexport type {\n TEventExecutionValue,\n IEventExecutionContextData,\n TEventEmitterMetadata,\n IEventEmitterPluginExecutionContext,\n IEventEmitterPluginExecutionResult,\n IEventEmitterHierarchicalEventData,\n IEventEmitterPluginOptions,\n IEventEmitterPluginStats,\n} from './event-emitter/plugin-types';\nexport type { IEventEmitterEventData, TEventEmitterListener };\n\nconst DEFAULT_MAX_LISTENERS = 100;\n\n/** Provides pub/sub event coordination during the agent execution lifecycle. */\nexport class EventEmitterPlugin extends AbstractPlugin<\n IEventEmitterPluginOptions,\n IEventEmitterPluginStats\n> {\n name = 'EventEmitterPlugin';\n version = '1.0.0';\n\n private pluginOptions: Required<Omit<IEventEmitterPluginOptions, 'metrics'>>;\n private logger: ILogger;\n private handlers = new Map<TEventName, IEventEmitterHandlerRegistration[]>();\n private eventBuffer: IEventEmitterEventData[] = [];\n private nextHandlerId = 1;\n private bufferTimer?: TTimerId;\n private metrics: IEventEmitterMetrics;\n\n constructor(options: IEventEmitterPluginOptions = {}) {\n super();\n this.logger = createLogger('EventEmitterPlugin');\n this.metrics = options.metrics ?? new InMemoryEventEmitterMetrics();\n validateEventEmitterOptions(options, this.name);\n\n this.pluginOptions = {\n enabled: options.enabled ?? true,\n events: options.events ?? [\n EVENT_EMITTER_EVENTS.AGENT_EXECUTION_START,\n EVENT_EMITTER_EVENTS.AGENT_EXECUTION_COMPLETE,\n EVENT_EMITTER_EVENTS.AGENT_EXECUTION_ERROR,\n EVENT_EMITTER_EVENTS.TOOL_BEFORE_EXECUTE,\n EVENT_EMITTER_EVENTS.TOOL_AFTER_EXECUTE,\n EVENT_EMITTER_EVENTS.TOOL_SUCCESS,\n EVENT_EMITTER_EVENTS.TOOL_ERROR,\n ],\n maxListeners: options.maxListeners ?? DEFAULT_MAX_LISTENERS,\n async: options.async ?? true,\n catchErrors: options.catchErrors ?? true,\n filters:\n options.filters ?? ({} as Record<TEventName, (event: IEventEmitterEventData) => boolean>),\n buffer: options.buffer ?? { enabled: false, maxSize: 1000, flushInterval: 5000 },\n category: options.category ?? PluginCategory.EVENT_PROCESSING,\n priority: options.priority ?? PluginPriority.HIGH,\n moduleEvents: options.moduleEvents ?? [],\n subscribeToAllModuleEvents: options.subscribeToAllModuleEvents ?? false,\n };\n\n if (this.pluginOptions.buffer.enabled) {\n // CORE-021: the scheduled flush must never float — with catchErrors: false a\n // handler error rejects flushBuffer(), and an unhandled rejection kills the\n // process on Node 20+. The timer is a last-resort surface: log, never rethrow.\n this.bufferTimer = setInterval(() => {\n this.flushBuffer().catch((error: unknown) => {\n this.logger.error('Buffered flush failed', {\n error: error instanceof Error ? error.message : String(error),\n });\n });\n }, this.pluginOptions.buffer.flushInterval);\n }\n }\n\n override async beforeExecution(context: IPluginExecutionContext): Promise<void> {\n await this.emit(EVENT_EMITTER_EVENTS.AGENT_EXECUTION_START, {\n executionId: context.executionId,\n sessionId: context.sessionId,\n userId: context.userId,\n data: {\n messageCount: context.messages?.length || 0,\n ...(context.config && { config: context.config }),\n },\n });\n }\n\n override async afterExecution(\n context: IPluginExecutionContext,\n result: IPluginExecutionResult,\n ): Promise<void> {\n await this.emit(EVENT_EMITTER_EVENTS.AGENT_EXECUTION_COMPLETE, {\n executionId: context.executionId,\n sessionId: context.sessionId,\n userId: context.userId,\n data: {\n duration: result?.duration,\n tokensUsed: result?.tokensUsed,\n toolsExecuted: result?.toolsExecuted,\n },\n });\n }\n\n override async beforeConversation(context: IPluginExecutionContext): Promise<void> {\n await this.emit(EVENT_EMITTER_EVENTS.CONVERSATION_START, {\n executionId: context.executionId,\n sessionId: context.sessionId,\n userId: context.userId,\n data: {\n messages: context.messages?.map((msg) => ({\n role: msg.role,\n content: msg.content || '',\n timestamp: msg.timestamp ? msg.timestamp.toISOString() : new Date().toISOString(),\n })),\n config: context.config as Record<string, TEventDataValue>,\n },\n });\n }\n\n override async afterConversation(\n context: IPluginExecutionContext,\n result: IPluginExecutionResult,\n ): Promise<void> {\n await this.emit(EVENT_EMITTER_EVENTS.CONVERSATION_COMPLETE, {\n executionId: context.executionId,\n sessionId: context.sessionId,\n userId: context.userId,\n data: {\n response: result.content || result.response,\n tokensUsed: result.usage?.totalTokens || result.tokensUsed,\n toolCalls: result.toolCalls?.map((call) => ({\n id: call.id || '',\n name: call.name || '',\n arguments: JSON.stringify(call.arguments || {}),\n result: String(call.result || ''),\n })),\n },\n });\n }\n\n override async beforeToolExecution(\n context: IPluginExecutionContext,\n toolData: IToolExecutionContext,\n ): Promise<void> {\n if (!toolData) return;\n await this.emit(EVENT_EMITTER_EVENTS.TOOL_BEFORE_EXECUTE, {\n executionId: context.executionId,\n sessionId: context.sessionId,\n userId: context.userId,\n data: {\n toolName: toolData.toolName,\n toolId: toolData.executionId,\n arguments: JSON.stringify(toolData.parameters ?? {}),\n },\n });\n }\n\n override async afterToolExecution(\n context: IPluginExecutionContext,\n toolResults: IPluginExecutionResult,\n ): Promise<void> {\n if (!toolResults.toolCalls || toolResults.toolCalls.length === 0) return;\n for (const toolCall of toolResults.toolCalls) {\n const eventType =\n toolCall.result === null\n ? EVENT_EMITTER_EVENTS.TOOL_ERROR\n : EVENT_EMITTER_EVENTS.TOOL_SUCCESS;\n const baseData = buildToolCallEmitData(context, toolCall, toolResults.duration);\n await this.emit(eventType, baseData);\n await this.emit(EVENT_EMITTER_EVENTS.TOOL_AFTER_EXECUTE, {\n ...baseData,\n data: { ...baseData.data, toolResult: String(toolCall.result || '') },\n });\n }\n }\n\n override async onError(error: Error, context?: IPluginErrorContext): Promise<void> {\n await this.emit(EVENT_EMITTER_EVENTS.AGENT_EXECUTION_ERROR, {\n executionId: context?.executionId,\n sessionId: context?.sessionId,\n userId: context?.userId,\n error: error instanceof Error ? error : new Error(String(error)),\n data: { action: context?.action, tool: context?.tool, attempt: context?.attempt },\n });\n }\n\n on(\n eventType: TEventName,\n listener: TEventEmitterListener,\n options?: { once?: boolean; filter?: (event: IEventEmitterEventData) => boolean },\n ): string {\n const handlerId = `handler_${this.nextHandlerId++}`;\n registerHandler(\n this.handlers,\n eventType,\n handlerId,\n listener,\n options,\n this.pluginOptions.maxListeners,\n this.name,\n );\n return handlerId;\n }\n\n once(\n eventType: TEventName,\n listener: TEventEmitterListener,\n filter?: (event: IEventEmitterEventData) => boolean,\n ): string {\n return this.on(eventType, listener, { once: true, ...(filter && { filter }) });\n }\n\n off(eventType: TEventName, handlerIdOrListener: string | TEventEmitterListener): boolean {\n return unregisterHandler(this.handlers, eventType, handlerIdOrListener);\n }\n\n async emit(\n eventType: TEventName,\n eventData: Partial<IEventEmitterEventData> = {},\n ): Promise<void> {\n if (!this.pluginOptions.events.includes(eventType)) return;\n const event: IEventEmitterEventData = { type: eventType, timestamp: new Date(), ...eventData };\n const globalFilter = this.pluginOptions.filters[eventType];\n if (globalFilter && !globalFilter(event)) return;\n this.metrics.incrementEmitted();\n if (this.pluginOptions.buffer.enabled) {\n this.eventBuffer.push(event);\n // CORE-021: overflow flush is awaited — emit() is async and its caller owns the\n // rejection path (a floating call here was the second unhandled-rejection source).\n if (this.eventBuffer.length >= this.pluginOptions.buffer.maxSize) await this.flushBuffer();\n return;\n }\n await this.processEvent(event);\n }\n\n private async processEvent(event: IEventEmitterEventData): Promise<void> {\n await processEventHelper(\n event,\n this.handlers,\n this.pluginOptions.async,\n (t, id) => this.off(t, id),\n (h, e) =>\n executeEventHandler(h, e, this.metrics, this.pluginOptions.catchErrors, this.logger),\n );\n }\n\n async flushBuffer(): Promise<void> {\n if (this.eventBuffer.length === 0) return;\n const events = [...this.eventBuffer];\n this.eventBuffer = [];\n for (const event of events) await this.processEvent(event);\n }\n\n override getStats(): IEventEmitterPluginStats {\n return buildEventEmitterStats(\n super.getStats(),\n this.handlers,\n this.eventBuffer.length,\n this.metrics,\n );\n }\n\n clearAllListeners(): void {\n this.handlers.clear();\n }\n\n /** CORE-022: dispose() is the single disposal entry point — releases the flush timer. */\n override async dispose(): Promise<void> {\n if (this.bufferTimer) clearInterval(this.bufferTimer);\n await this.flushBuffer();\n this.clearAllListeners();\n await super.dispose();\n }\n}\n","import { ValidationError } from '../utils/errors';\nimport { logger } from '../utils/logger';\n\nimport type { IParameterSchema, IToolSchema, TJSONSchemaKind } from '../interfaces/provider';\nimport type { ITool, IToolRegistry } from '../interfaces/tool';\n\n/**\n * The parameter kinds a registered tool may declare — every member of `TJSONSchemaKind`.\n *\n * CORE-039: this list previously omitted `integer` and `null`, so a tool declaring an `integer`\n * parameter was refused at registration by a type the subset itself defines. Derived from the union\n * rather than re-listed, so a new kind cannot be added to the subset and forgotten here.\n */\nconst VALID_PARAMETER_TYPES: readonly TJSONSchemaKind[] = [\n 'string',\n 'number',\n 'integer',\n 'boolean',\n 'array',\n 'object',\n 'null',\n];\n\n/**\n * Tool registry implementation\n * Manages tool registration, validation, and retrieval\n */\nexport class ToolRegistry implements IToolRegistry {\n private tools = new Map<string, ITool>();\n\n /**\n * Register a tool\n */\n register(tool: ITool): void {\n if (!tool.schema?.name) {\n throw new ValidationError('Tool must have a valid schema with name');\n }\n\n const toolName = tool.schema.name;\n\n // Validate tool schema\n this.validateToolSchema(tool.schema);\n\n // Check for duplicate registration\n if (this.tools.has(toolName)) {\n logger.warn(`Tool \"${toolName}\" is already registered, overriding`, {\n toolName,\n existingTool: this.tools.get(toolName)?.constructor.name,\n });\n }\n\n this.tools.set(toolName, tool);\n logger.debug(`Tool \"${toolName}\" registered successfully`, {\n toolName,\n toolType: tool.constructor.name,\n parameters: Object.keys(tool.schema.parameters?.properties || {}),\n });\n }\n\n /**\n * Unregister a tool\n */\n unregister(name: string): void {\n if (!this.tools.has(name)) {\n logger.warn(`Attempted to unregister non-existent tool \"${name}\"`);\n return;\n }\n\n this.tools.delete(name);\n logger.debug(`Tool \"${name}\" unregistered successfully`);\n }\n\n /**\n * Get tool by name\n */\n get(name: string): ITool | undefined {\n return this.tools.get(name);\n }\n\n /**\n * Get all registered tools\n */\n getAll(): ITool[] {\n return Array.from(this.tools.values());\n }\n\n /**\n * Get tool schemas\n */\n getSchemas(): IToolSchema[] {\n const tools = this.getAll();\n\n logger.debug('[TOOL-FLOW] ToolRegistry.getSchemas() - Tools before schema extraction', {\n count: tools.length,\n tools: tools.map((t) => ({\n name: t.schema?.name ?? 'unnamed',\n hasSchema: !!t.schema,\n schemaType: typeof t.schema,\n toolType: t.constructor?.name || 'unknown',\n })),\n });\n\n return this.getAll().map((tool) => tool.schema);\n }\n\n /**\n * Check if tool exists\n */\n has(name: string): boolean {\n return this.tools.has(name);\n }\n\n /**\n * Clear all tools\n */\n clear(): void {\n const toolCount = this.tools.size;\n this.tools.clear();\n logger.debug(`Cleared ${toolCount} tools from registry`);\n }\n\n /**\n * Get tool names\n */\n getToolNames(): string[] {\n return Array.from(this.tools.keys());\n }\n\n /**\n * Get tools by pattern\n */\n getToolsByPattern(pattern: string | RegExp): ITool[] {\n const regex = typeof pattern === 'string' ? new RegExp(pattern) : pattern;\n return this.getAll().filter((tool) => regex.test(tool.schema.name));\n }\n\n /**\n * Get tool count\n */\n size(): number {\n return this.tools.size;\n }\n\n /**\n * Validate tool schema\n */\n private validateToolSchema(schema: IToolSchema): void {\n if (!schema.name || typeof schema.name !== 'string') {\n throw new ValidationError('Tool schema must have a valid name');\n }\n\n if (!schema.description || typeof schema.description !== 'string') {\n throw new ValidationError('Tool schema must have a description');\n }\n\n if (\n !schema.parameters ||\n typeof schema.parameters !== 'object' ||\n schema.parameters === null ||\n Array.isArray(schema.parameters)\n ) {\n throw new ValidationError('Tool schema must have parameters object');\n }\n\n if (schema.parameters.type !== 'object') {\n throw new ValidationError('Tool parameters type must be \"object\"');\n }\n\n // Validate parameter properties, at every depth. Checking only the top level let a nested node\n // declaring neither `type` nor `anyOf` register cleanly and then fail on EVERY invocation --\n // newly constructible once `type` became optional (CORE-039).\n if (schema.parameters.properties) {\n for (const [propName, propSchema] of Object.entries(schema.parameters.properties)) {\n assertParameterNodeValid(propName, propSchema);\n }\n }\n\n // Validate required fields exist in properties\n if (schema.parameters.required) {\n const properties = schema.parameters.properties || {};\n for (const requiredField of schema.parameters.required) {\n if (!properties[requiredField]) {\n throw new ValidationError(\n `Required parameter \"${requiredField}\" is not defined in properties`,\n );\n }\n }\n }\n }\n}\n\n/**\n * Assert one subset node is one this runtime can act on, recursively.\n *\n * A node declares EITHER a `type` from the subset's kinds OR an `anyOf` of alternatives. Both walks\n * that read it at run time refuse anything else, so accepting it at registration only moves the\n * failure to every later invocation.\n */\nfunction assertParameterNodeValid(path: string, node: IParameterSchema | undefined): void {\n // CORE-039: a union node carries `anyOf` INSTEAD of `type`, so demanding a type here would reject\n // every tool with a union-typed argument at registration -- the converter would emit it correctly\n // and this check would throw on it.\n if (node?.anyOf) {\n if (node.anyOf.length === 0) {\n throw new ValidationError(`Parameter \"${path}\" declares an empty anyOf`);\n }\n node.anyOf.forEach((member, index) =>\n assertParameterNodeValid(`${path}|anyOf[${index}]`, member),\n );\n return;\n }\n\n if (!node?.type) {\n throw new ValidationError(`Parameter \"${path}\" must declare a type or anyOf`);\n }\n\n if (!VALID_PARAMETER_TYPES.includes(node.type)) {\n throw new ValidationError(`Parameter \"${path}\" has invalid type \"${node.type}\"`);\n }\n\n if (node.properties) {\n for (const [key, child] of Object.entries(node.properties)) {\n assertParameterNodeValid(`${path}.${key}`, child);\n }\n }\n if (node.items) {\n assertParameterNodeValid(`${path}[]`, node.items);\n }\n}\n","/**\n * SELFHOST-005 — tool OUTPUT schema validation.\n *\n * The counterpart to the tool-INPUT `parameter-validator`: when a tool declares an `outputSchema`,\n * its returned value is validated against it right after the tool function runs, in the SAME layer\n * (`FunctionTool.execute`). A mismatch throws `ToolExecutionError` before the result returns, so the\n * execution round propagates it exactly like any other tool failure. Reuses the CORE-015\n * `validateAgainstJsonSchema` machinery. (Model-output structured validation is separate — CORE-015.)\n */\n\nimport { validateAgainstJsonSchema } from '../schema/structured-output.js';\nimport { ToolExecutionError } from '../utils/errors.js';\n\nimport type { IToolSchema } from '../interfaces/provider.js';\nimport type { TUniversalValue } from '../interfaces/types.js';\n\n/** The declared output schema — the object-root shape or a bare parameter schema (see `IToolSchema`). */\ntype TOutputSchema = NonNullable<IToolSchema['outputSchema']>;\n\n/**\n * Validate a tool's output value against its declared `outputSchema`. Throws `ToolExecutionError`\n * (which the execution round already propagates) when the value does not conform.\n */\nexport function validateToolOutput(\n toolName: string,\n output: TUniversalValue,\n schema: TOutputSchema,\n): void {\n const issues = validateAgainstJsonSchema(schema, output, '$');\n if (issues.length > 0) {\n throw new ToolExecutionError(\n `output does not match the declared outputSchema: ${issues.join('; ')}`,\n toolName,\n undefined,\n { outputSchemaIssues: issues },\n );\n }\n}\n","import { validateAgainstJsonSchema } from '../schema/structured-output.js';\n\nimport type { IParameterSchema } from '../interfaces/provider';\nimport type { IParameterValidationResult, TToolParameters } from '../interfaces/tool';\nimport type { TUniversalValue } from '../interfaces/types';\n\n/**\n * Validate one parameter against its schema node. Returns the issues found; empty means valid.\n *\n * CORE-039: exactly ONE thing lives here — the leaf TYPE mismatch and its caller-facing wording\n * (`Parameter \"x\" must be a string`), which callers depend on. Everything else — enum, numeric\n * bounds, pattern, a nested object's own properties and requirements, a union's branches — is\n * `validateAgainstJsonSchema`'s, the single complete walk over the subset.\n *\n * The split is by CONCERN, not by kind. Delegating only some kinds is what made constraint\n * enforcement depend on where a node sat: a `minimum` was checked inside a nested object and\n * ignored at the top level, and two message dialects appeared at the same position depending on the\n * declared type. That is the divergence this item exists to remove, so the boundary is drawn once\n * and applies to every node.\n */\nfunction validateParameterType(\n key: string,\n value: TUniversalValue,\n schema: IParameterSchema,\n): string[] {\n const mismatch = leafTypeMismatch(key, value, schema);\n if (mismatch) {\n // Return rather than fall through: the deep walk would otherwise report the same defect a\n // second time in its own dialect, inside one ValidationError message.\n return [mismatch];\n }\n return validateAgainstJsonSchema(schema, value, `Parameter \"${key}\"`);\n}\n\n/**\n * The caller-facing type check. `undefined` means \"no leaf mismatch to report\" — either the value\n * matches the declared kind, or the node is one the deep walk answers on its own (a union, or a\n * kind with no caller-facing wording of its own).\n */\nfunction leafTypeMismatch(\n key: string,\n value: TUniversalValue,\n schema: IParameterSchema,\n): string | undefined {\n if (schema.anyOf) {\n // A union node carries `anyOf` instead of `type`; deciding which branch matched is precisely\n // what the deep walk does, and no single leaf message can describe the failure.\n return undefined;\n }\n\n const expectedType = schema['type'];\n switch (expectedType) {\n case 'string':\n return typeof value === 'string'\n ? undefined\n : `Parameter \"${key}\" must be a string, got ${describeValue(value)}`;\n\n case 'number':\n case 'integer':\n return typeof value === 'number' && !isNaN(value)\n ? undefined\n : `Parameter \"${key}\" must be a number, got ${describeValue(value)}`;\n\n case 'boolean':\n return typeof value === 'boolean'\n ? undefined\n : `Parameter \"${key}\" must be a boolean, got ${describeValue(value)}`;\n\n case 'array':\n return Array.isArray(value)\n ? undefined\n : `Parameter \"${key}\" must be an array, got ${describeValue(value)}`;\n\n case 'object':\n return typeof value === 'object' && value !== null && !Array.isArray(value)\n ? undefined\n : `Parameter \"${key}\" must be an object, got ${describeValue(value)}`;\n\n case 'null':\n // No caller-facing wording of its own; the deep walk reports it.\n return undefined;\n\n case undefined:\n // Reachable since `type` became optional for union nodes. A node with neither is not a valid\n // subset node, and accepting it silently is the failure class this item removes.\n return `Parameter \"${key}\" declares neither a type nor anyOf`;\n\n default:\n return `Parameter \"${key}\" has unsupported schema type \"${String(expectedType)}\"`;\n }\n}\n\n/** `typeof null` is `'object'`, which makes the leaf message actively misleading for a null. */\nfunction describeValue(value: TUniversalValue): string {\n if (value === null) return 'null';\n if (Array.isArray(value)) return 'array';\n return typeof value;\n}\n\n/**\n * Collect all validation errors for the given parameters against a schema.\n */\nexport function getValidationErrors(\n parameters: TToolParameters,\n schemaRequired: string[],\n schemaProperties: Record<string, IParameterSchema>,\n additionalProperties?: boolean | IParameterSchema,\n): string[] {\n const errors: string[] = [];\n\n // Check required parameters\n for (const field of schemaRequired) {\n if (!(field in parameters)) {\n errors.push(`Missing required parameter: ${field}`);\n }\n }\n\n // Check parameter types and constraints\n for (const [key, value] of Object.entries(parameters)) {\n const paramSchema = schemaProperties[key];\n if (!paramSchema) {\n if (additionalProperties === true) {\n continue;\n }\n if (additionalProperties && typeof additionalProperties === 'object') {\n errors.push(...validateParameterType(key, value, additionalProperties));\n continue;\n }\n errors.push(`Unknown parameter: ${key}`);\n continue;\n }\n\n errors.push(...validateParameterType(key, value, paramSchema));\n }\n\n return errors;\n}\n\n/**\n * Validate parameters and return a structured result.\n */\nexport function validateToolParameters(\n parameters: TToolParameters,\n schemaRequired: string[],\n schemaProperties: Record<string, IParameterSchema>,\n additionalProperties?: boolean | IParameterSchema,\n): IParameterValidationResult {\n const errors = getValidationErrors(\n parameters,\n schemaRequired,\n schemaProperties,\n additionalProperties,\n );\n return {\n isValid: errors.length === 0,\n errors,\n };\n}\n","export type {\n IAgentEventData,\n IBaseEventData,\n IExecutionEventData,\n IEventContext,\n IEventService,\n IEventServiceOwnerBinding,\n IOwnerPathSegment,\n IToolEventData,\n TEventListener,\n} from './interfaces';\n\nimport type {\n IBaseEventData,\n IEventContext,\n IEventService,\n IEventServiceOwnerBinding,\n TEventListener,\n} from './interfaces';\n\n/**\n * Abstract base for event services.\n * Concrete implementations decide how events are delivered.\n */\nexport abstract class AbstractEventService implements IEventService {\n private listeners = new Set<TEventListener>();\n\n abstract emit(eventType: string, data: IBaseEventData, context?: IEventContext): void;\n\n subscribe(listener: TEventListener): void {\n this.listeners.add(listener);\n }\n\n unsubscribe(listener: TEventListener): void {\n this.listeners.delete(listener);\n }\n\n protected notifyListeners(\n eventType: string,\n data: IBaseEventData,\n context?: IEventContext,\n ): void {\n for (const listener of this.listeners) {\n listener(eventType, data, context);\n }\n }\n}\n\n/**\n * Default no-op event service (production-safe).\n * When injected, emit() intentionally does nothing.\n */\nexport class DefaultEventService extends AbstractEventService {\n emit(_eventType: string, _data: IBaseEventData, _context?: IEventContext): void {\n // Intentionally empty: no-op event service.\n }\n}\n\n/**\n * Singleton default event service instance.\n */\nexport const DEFAULT_ABSTRACT_EVENT_SERVICE: IEventService = new DefaultEventService();\n\n/**\n * Check if a given service is the default no-op implementation.\n */\nexport function isDefaultEventService(service: IEventService): boolean {\n return service === DEFAULT_ABSTRACT_EVENT_SERVICE || service instanceof DefaultEventService;\n}\n\n/**\n * Compose a full event name from owner prefix and local name.\n * Local names must not contain dots.\n */\nexport function composeEventName(ownerType: string, localName: string): string {\n if (!ownerType || ownerType.trim().length === 0) {\n throw new Error('[EVENTS] ownerType is required to compose event names.');\n }\n if (ownerType.includes('.')) {\n throw new Error(`[EVENTS] ownerType must not contain '.': \"${ownerType}\"`);\n }\n if (!localName || localName.trim().length === 0) {\n throw new Error('[EVENTS] local event name is required.');\n }\n if (localName.includes('.')) {\n throw new Error(`[EVENTS] Local event name must not contain '.': \"${localName}\"`);\n }\n return `${ownerType}.${localName}`;\n}\n\nconst ID_RADIX = 36;\nconst SPAN_ID_SUBSTR_END = 10;\n\n/**\n * Generate a unique span ID for distributed tracing correlation. Exported so a per-operation timing\n * source (SELFHOST-004) can mint a span id it puts on BOTH the event payload and the event context.\n */\nexport function generateSpanId(): string {\n return `span_${Date.now().toString(ID_RADIX)}_${Math.random().toString(ID_RADIX).slice(2, SPAN_ID_SUBSTR_END)}`;\n}\n\n/**\n * A scoped event service that always emits with an owner binding applied.\n */\nexport class StructuredEventService extends AbstractEventService {\n private readonly base: IEventService;\n private readonly binding: IEventServiceOwnerBinding;\n\n constructor(base: IEventService, binding: IEventServiceOwnerBinding) {\n super();\n this.base = base;\n this.binding = binding;\n }\n\n emit(eventType: string, data: IBaseEventData, context?: IEventContext): void {\n if (eventType.includes('.')) {\n throw new Error(`[EVENTS] Local event name must not contain '.': \"${eventType}\"`);\n }\n const merged: IEventContext = {\n ...context,\n ownerType: this.binding.ownerType,\n ownerId: this.binding.ownerId,\n ownerPath: this.binding.ownerPath,\n depth: this.binding.ownerPath.length,\n spanId: context?.spanId ?? generateSpanId(),\n };\n const fullEventName = composeEventName(this.binding.ownerType, eventType);\n this.base.emit(fullEventName, data, merged);\n }\n\n override subscribe(listener: TEventListener): void {\n this.base.subscribe(listener);\n }\n\n override unsubscribe(listener: TEventListener): void {\n this.base.unsubscribe(listener);\n }\n}\n\n/**\n * Bind an EventService to an explicit owner path.\n * This is the standard entry point for scoped emission (path-only architecture).\n */\nexport function bindWithOwnerPath(\n base: IEventService,\n binding: IEventServiceOwnerBinding,\n): IEventService {\n return new StructuredEventService(base, binding);\n}\n\n/**\n * Alias for bindWithOwnerPath for historical call sites.\n * Intentionally forwards to the single authoritative implementation.\n */\nexport function bindEventServiceOwner(\n base: IEventService,\n binding: IEventServiceOwnerBinding,\n): IEventService {\n return bindWithOwnerPath(base, binding);\n}\n\n/**\n * Observable EventService that notifies subscribed listeners.\n */\nexport class ObservableEventService extends AbstractEventService {\n emit(eventType: string, data: IBaseEventData, context?: IEventContext): void {\n this.notifyListeners(eventType, data, context);\n }\n}\n","import type { IBaseEventData } from './interfaces.js';\nimport type { IModelFallbackNotice } from '../interfaces/model-fallback';\n\n/**\n * SELFHOST-004: per-operation span lifecycle event names. Mirrors the `TASK_EVENTS`/`USER_EVENTS`\n * pattern (a const name set + a prefix). The local name is distinctive (`span_completed`, not a bare\n * `completed`) so a consumer can identify a span-completion regardless of the emitting owner's prefix.\n */\nexport const SPAN_EVENTS = {\n COMPLETED: 'span_completed',\n} as const;\n\n/** Content-free completion of one provider round, separate from legacy tool timing events. */\nexport const PROVIDER_CALL_EVENTS = {\n COMPLETED: 'provider_call_completed',\n} as const;\n\n/** A provider request moved to another model after the one it was on failed. */\nexport const PROVIDER_FALLBACK_EVENTS = {\n SWITCHED: 'provider_fallback',\n} as const;\n\n/** The notice a `provider_fallback` event carries, or `undefined` when the payload is malformed. */\nexport function readModelFallbackNotice(\n data: Readonly<Record<string, unknown>>,\n): IModelFallbackNotice | undefined {\n const { fromProvider, fromModel, toProvider, toModel, reason } = data;\n if (\n typeof fromProvider !== 'string' ||\n typeof fromModel !== 'string' ||\n typeof toProvider !== 'string' ||\n typeof toModel !== 'string' ||\n typeof reason !== 'string'\n ) {\n return undefined;\n }\n return {\n from: { provider: fromProvider, model: fromModel },\n to: { provider: toProvider, model: toModel },\n reason: reason as IModelFallbackNotice['reason'],\n };\n}\n\n/** Content-free completion of the body actually awaited by one permitted tool call. */\nexport const TOOL_BODY_EVENTS = {\n COMPLETED: 'tool_body_completed',\n} as const;\n\n/** Content-free decision reached for one tool call before any body runs. */\nexport const TOOL_PERMISSION_EVENTS = {\n DECIDED: 'tool_permission_decided',\n} as const;\n\nexport const SPAN_EVENT_PREFIX = 'span' as const;\n\nexport type TSpanEvent = (typeof SPAN_EVENTS)[keyof typeof SPAN_EVENTS];\n\n/**\n * SELFHOST-004: span-completion event payload — JOINS the span id with its measured duration and the\n * operation name (raw scalars ONLY; references no transport type). Emitted by the per-operation timing\n * source (e.g. `FunctionTool`) so a consuming layer (`agent-framework`) can build a record span entry\n * WITHOUT `agent-core` depending on `agent-interface-transport` (no cycle). The payload `spanId` is the\n * AUTHORITATIVE id a consumer reads; owner/turn correlation is applied by the event service's binding\n * (`ownerPath` on the emitted `IEventContext`). Note the context's own auto-minted `spanId` is a\n * separate scope tag and need not equal this payload id — always read the payload id for the span.\n */\nexport interface ISpanCompletionEventData extends IBaseEventData {\n /** The span id (equals the emitted event's context `spanId`). */\n spanId: string;\n /** Measured wall-clock duration of the operation, in milliseconds. */\n durationMs: number;\n /** The operation name (e.g. the tool name). */\n op: string;\n}\n","import { validateToolOutput } from './output-validator';\nimport { getValidationErrors, validateToolParameters } from './parameter-validator';\nimport { generateSpanId } from '../event-service/event-service';\nimport { SPAN_EVENTS } from '../event-service/span-events';\nimport { ToolExecutionError, ValidationError } from '../utils/errors';\n\nimport type { ISpanCompletionEventData } from '../event-service/span-events';\nimport type { IToolSchema } from '../interfaces/provider';\nimport type {\n IFunctionTool,\n IToolResult,\n IToolExecutionContext,\n IParameterValidationResult,\n TToolExecutor,\n TToolParameters,\n IEventService,\n} from '../interfaces/tool';\nimport type { TUniversalValue } from '../interfaces/types';\n\n/**\n * Function tool implementation\n * Wraps a JavaScript function as a tool with schema validation\n *\n * Implements IFunctionTool without extending AbstractTool to avoid\n * circular runtime dependency (tools -> agents -> tools).\n */\nexport class FunctionTool implements IFunctionTool {\n readonly schema: IToolSchema;\n readonly fn: TToolExecutor;\n private eventService: IEventService | undefined;\n\n constructor(schema: IToolSchema, fn: TToolExecutor) {\n this.schema = schema;\n this.fn = fn;\n this.validateConstructorInputs();\n }\n\n /**\n * Get tool name\n */\n getName(): string {\n return this.schema.name;\n }\n\n /**\n * Set EventService for post-construction injection.\n * Accepts EventService as-is without transformation.\n * Caller is responsible for providing properly configured EventService.\n */\n setEventService(eventService: IEventService | undefined): void {\n this.eventService = eventService;\n }\n\n /**\n * Execute the function tool\n */\n async execute(\n parameters: TToolParameters,\n context?: IToolExecutionContext,\n ): Promise<IToolResult> {\n const toolName = this.schema.name;\n\n // Validate parameters before execution\n if (!this.validate(parameters)) {\n const errors = getValidationErrors(\n parameters,\n this.schema.parameters.required || [],\n this.schema.parameters.properties || {},\n this.schema.parameters.additionalProperties,\n );\n throw new ValidationError(`Invalid parameters for tool \"${toolName}\": ${errors.join(', ')}`);\n }\n\n // Execute the function\n const startTime = Date.now();\n let result: TUniversalValue;\n try {\n result = await this.fn(parameters, context);\n } catch (error) {\n if (error instanceof ToolExecutionError || error instanceof ValidationError) {\n throw error;\n }\n\n throw new ToolExecutionError(\n `Function tool execution failed: ${error instanceof Error ? error.message : String(error)}`,\n toolName,\n error instanceof Error ? error : new Error(String(error)),\n {\n parameterCount: Object.keys(parameters || {}).length,\n hasContext: !!context,\n },\n );\n }\n\n // SELFHOST-004: capture the pure fn() duration BEFORE output validation so the span timing is not\n // inflated by validation work.\n const executionTime = Date.now() - startTime;\n\n // SELFHOST-005: validate the tool OUTPUT against its declared schema (beside the tool-input\n // validation above), throwing before the result returns — same layer as the input validator.\n if (this.schema.outputSchema) {\n validateToolOutput(toolName, result, this.schema.outputSchema);\n }\n\n // SELFHOST-004: surface per-operation timing as a span-completion event whose PAYLOAD JOINS the\n // span id with the measured duration + op name (raw scalars). A consumer (agent-framework) turns\n // this into a record span entry; agent-core builds NO transport entry (it depends on neither\n // transport nor plugin — no cycle). Owner correlation (to the turn) is applied by the event\n // service's binding (`ownerPath`); the authoritative span id lives on the payload.\n if (this.eventService) {\n const spanEvent: ISpanCompletionEventData = {\n timestamp: new Date(),\n spanId: generateSpanId(),\n durationMs: executionTime,\n op: toolName,\n };\n this.eventService.emit(SPAN_EVENTS.COMPLETED, spanEvent);\n }\n\n return {\n success: true,\n data: result,\n metadata: {\n executionTime,\n toolName,\n parameters,\n },\n };\n }\n\n /**\n * Validate parameters (simple boolean result)\n */\n validate(parameters: TToolParameters): boolean {\n return (\n getValidationErrors(\n parameters,\n this.schema.parameters.required || [],\n this.schema.parameters.properties || {},\n this.schema.parameters.additionalProperties,\n ).length === 0\n );\n }\n\n /**\n * Validate tool parameters with detailed result\n */\n validateParameters(parameters: TToolParameters): IParameterValidationResult {\n return validateToolParameters(\n parameters,\n this.schema.parameters.required || [],\n this.schema.parameters.properties || {},\n this.schema.parameters.additionalProperties,\n );\n }\n\n /**\n * Get tool description\n */\n getDescription(): string {\n return this.schema.description;\n }\n\n /**\n * Validate constructor inputs\n */\n private validateConstructorInputs(): void {\n if (!this.schema) {\n throw new ValidationError('Tool schema is required');\n }\n\n if (!this.fn || typeof this.fn !== 'function') {\n throw new ValidationError('Tool function is required and must be a function');\n }\n\n if (!this.schema.name) {\n throw new ValidationError('Tool schema must have a name');\n }\n }\n}\n","/**\n * Tool residency (CLI-1990): which registered schemas the model is offered.\n *\n * Three words, used consistently across the layers that read this module:\n *\n * - **resident** — a schema that does not declare `deferLoading`; always offered.\n * - **deferred** — declares `deferLoading: true`; withheld while deferral is engaged, until loaded.\n * - **offered** — what the next request carries: every registered tool while deferral is off, the\n * resident ones plus the loaded deferred ones once it is on.\n *\n * Pure functions over schemas, beside the registry they describe. The STATE (which deferred tools\n * are loaded) belongs to the tool manager; the POLICY (whether deferral is engaged) belongs to the\n * agent, through `resolveToolSearchMode`. Neither is decided here.\n */\n\nimport { TOOL_SEARCH_TOOL_NAME } from '../interfaces/tool-search';\n\nimport type { IToolSchema } from '../interfaces/tool-schema';\nimport type { TToolSearchMode } from '../interfaces/tool-search';\n\n/**\n * The vendor's own invariant, as a Robota-level error: a request in which every tool is withheld\n * offers the model nothing to call and nothing to search with.\n */\nexport const ALL_TOOLS_DEFERRED_MESSAGE =\n 'at least one tool must stay resident; all tools cannot be deferred';\n\n/**\n * The second half of the same invariant: a withheld schema the model has no way to load is not\n * deferred, it is unreachable. Session assembly adds the loader whenever a declared tool is deferred;\n * an SDK-direct configuration that defers tools must register it itself. Refused, never repaired\n * silently (No Fallback Policy).\n */\nexport const DEFERRED_WITHOUT_LOADER_MESSAGE =\n `a tool schema was withheld but no ${TOOL_SEARCH_TOOL_NAME} tool is offered; ` +\n 'register the loader or turn tool search off';\n\n/** Whether a schema declares itself deferred. Omission means resident. */\nexport function isDeferredTool(schema: IToolSchema): boolean {\n return schema.deferLoading === true;\n}\n\n/**\n * The schemas a request carries. With deferral off this is the identity — the projection every\n * existing tool set takes, since nothing in today's tree declares `deferLoading`. With it on, a\n * non-empty set that projects to nothing is refused rather than sent: see the message above.\n */\nexport function projectOfferedTools(\n schemas: readonly IToolSchema[],\n loaded: ReadonlySet<string>,\n mode: TToolSearchMode,\n): IToolSchema[] {\n if (mode === 'off') return [...schemas];\n const offered = schemas.filter((schema) => !isDeferredTool(schema) || loaded.has(schema.name));\n if (schemas.length > 0 && offered.length === 0) {\n throw new Error(ALL_TOOLS_DEFERRED_MESSAGE);\n }\n const withheld = offered.length < schemas.length;\n if (withheld && !offered.some((schema) => schema.name === TOOL_SEARCH_TOOL_NAME)) {\n throw new Error(DEFERRED_WITHOUT_LOADER_MESSAGE);\n }\n return offered;\n}\n\n/**\n * The same invariant at DECLARATION time, for an assembly that wants to fail at startup rather than\n * at the first request: a non-empty set in which every tool declares `deferLoading` is refused.\n */\nexport function assertResidentToolRemains(schemas: readonly IToolSchema[]): void {\n if (schemas.length > 0 && schemas.every(isDeferredTool)) {\n throw new Error(ALL_TOOLS_DEFERRED_MESSAGE);\n }\n}\n","import { AbstractAgent } from '../abstracts/abstract-agent';\n\nimport type {\n TModuleStats,\n TRegisterModuleOptions,\n TExecuteModuleContext,\n TExecuteModuleResult,\n} from './robota-types';\nimport type { IModule } from '../abstracts/abstract-module';\nimport type {\n IPluginContract,\n IPluginHooks,\n IPluginOptions,\n IPluginStats,\n} from '../abstracts/abstract-plugin';\nimport type { IAgentConfig, IRunOptions, TUniversalMessage } from '../interfaces/agent';\n\nexport type TPlugin = IPluginContract<IPluginOptions, IPluginStats> & IPluginHooks;\n\ninterface IModuleManagerProxy {\n registerModule(module: IModule, options?: TRegisterModuleOptions): Promise<void>;\n unregisterModule(moduleName: string): Promise<boolean>;\n getModule(moduleName: string): IModule | undefined;\n getModulesByType(moduleType: string): IModule[];\n getModules(): IModule[];\n getModuleNames(): string[];\n hasModule(moduleName: string): boolean;\n executeModule(moduleName: string, context: TExecuteModuleContext): Promise<TExecuteModuleResult>;\n getModuleStats(moduleName: string): TModuleStats;\n}\n\ninterface IPluginManagerProxy {\n addPlugin(plugin: TPlugin): void;\n removePlugin(pluginName: string): boolean;\n getPlugin(pluginName: string): TPlugin | undefined;\n getPlugins(): TPlugin[];\n getPluginNames(): string[];\n}\n\nexport abstract class RobotaBase extends AbstractAgent<\n IAgentConfig,\n IRunOptions,\n TUniversalMessage\n> {\n protected moduleManager!: IModuleManagerProxy;\n protected pluginManager!: IPluginManagerProxy;\n /**\n * Narrowed from `AbstractAgent`'s optional `config`: a Robota agent always has one, assigned in the\n * constructor. Declared HERE so `name` below can read it without a fallback that would lie.\n */\n declare protected config: IAgentConfig;\n\n /**\n * The agent's identity label, read THROUGH `config` rather than copied at construction.\n *\n * ARCH-040 (issue #1820): a preset carries `agentName`, and it reached the agent only when the\n * agent was built — so starting with a preset set the name while switching to the SAME preset\n * mid-session left the old one. One preset with two answers, decided by when it was chosen.\n *\n * Reading through `config` makes `updateConfiguration({ name })` the rename, so there is one way\n * to change it and `getConfig()`, `getStats()` and `getName()` cannot disagree about what this\n * agent is called. It lives on the BASE because `config` does; the subclass keeps no copy to\n * forget to update.\n */\n get name(): string {\n return this.config.name;\n }\n\n addPlugin(plugin: TPlugin): void {\n this.pluginManager.addPlugin(plugin);\n }\n removePlugin(pluginName: string): boolean {\n return this.pluginManager.removePlugin(pluginName);\n }\n getPlugin(pluginName: string): TPlugin | undefined {\n return this.pluginManager.getPlugin(pluginName);\n }\n getPlugins(): TPlugin[] {\n return this.pluginManager.getPlugins();\n }\n getPluginNames(): string[] {\n return this.pluginManager.getPluginNames();\n }\n\n async registerModule(module: IModule, options?: TRegisterModuleOptions): Promise<void> {\n return this.moduleManager.registerModule(module, options);\n }\n async unregisterModule(moduleName: string): Promise<boolean> {\n return this.moduleManager.unregisterModule(moduleName);\n }\n getModule(moduleName: string): IModule | undefined {\n return this.moduleManager.getModule(moduleName);\n }\n getModulesByType(moduleType: string): IModule[] {\n return this.moduleManager.getModulesByType(moduleType);\n }\n getModules(): IModule[] {\n return this.moduleManager.getModules();\n }\n getModuleNames(): string[] {\n return this.moduleManager.getModuleNames();\n }\n hasModule(moduleName: string): boolean {\n return this.moduleManager.hasModule(moduleName);\n }\n async executeModule(\n moduleName: string,\n context: TExecuteModuleContext,\n ): Promise<TExecuteModuleResult> {\n return this.moduleManager.executeModule(moduleName, context);\n }\n getModuleStats(moduleName: string): TModuleStats {\n return this.moduleManager.getModuleStats(moduleName);\n }\n}\n","import { ToolExecutionError } from '../utils/errors';\n\nimport type { IToolResult } from '../interfaces/tool';\nimport type { TUniversalValue } from '../interfaces/types';\n\n/** Adapt a tool envelope to the executor value contract without turning failures into success. */\nexport function toolResultValue(name: string, result: IToolResult): TUniversalValue {\n if (!result.success) {\n const detail =\n result.data === undefined\n ? ''\n : `; data: ${typeof result.data === 'string' ? result.data : JSON.stringify(result.data)}`;\n throw new ToolExecutionError(`${result.error ?? 'Tool execution failed'}${detail}`, name);\n }\n if (result.data === undefined)\n throw new ToolExecutionError('Tool execution succeeded but returned no data', name);\n return result.data;\n}\n","import { toolResultValue } from './tool-result-value';\n/**\n * Configuration and tool management delegate for the Robota agent.\n *\n * Extracted from robota.ts to keep the main class under 300 lines.\n */\nimport { AGENT_EVENTS } from '../agents/constants';\nimport { ConfigurationError } from '../utils/errors';\n\nimport type { IToolWithEventService } from '../abstracts/abstract-tool';\nimport type { AbstractTool } from '../abstracts/abstract-tool';\nimport type { IAgentConfig } from '../interfaces/agent';\nimport type { IEventService } from '../interfaces/event-service';\nimport type { TModelEffortSelection } from '../interfaces/provider';\nimport type { IToolExecutionContext, TToolParameters } from '../interfaces/tool';\nimport type { TUniversalValue } from '../interfaces/types';\nimport type { AIProviders } from '../managers/ai-provider-manager';\nimport type { Tools } from '../managers/tool-manager';\nimport type { ILogger } from '../utils/logger';\n\n/** Agent statistics metadata type */\nexport type TAgentStatsMetadata = Record<string, string | number | boolean | Date | string[]>;\n\n/**\n * Validates the agent configuration format.\n * @internal\n */\nexport function validateAgentConfig(config: IAgentConfig): void {\n if (!config.name) {\n throw new ConfigurationError('Agent name is required', { component: 'Robota' });\n }\n\n if (!config.aiProviders || config.aiProviders.length === 0) {\n throw new ConfigurationError('At least one AI provider is required', { component: 'Robota' });\n }\n\n if (!config.defaultModel) {\n throw new ConfigurationError('Default model configuration is required', {\n component: 'Robota',\n });\n }\n\n if (!config.defaultModel.provider || !config.defaultModel.model) {\n throw new ConfigurationError('Default model must specify both provider and model', {\n component: 'Robota',\n });\n }\n\n const providerNames = config.aiProviders.map((p) => p.name);\n const duplicates = providerNames.filter((name, index) => providerNames.indexOf(name) !== index);\n if (duplicates.length > 0) {\n throw new ConfigurationError(`Duplicate AI provider names: ${duplicates.join(', ')}`, {\n component: 'Robota',\n duplicates,\n });\n }\n\n if (!providerNames.includes(config.defaultModel.provider)) {\n throw new ConfigurationError(\n `Default provider '${config.defaultModel.provider}' not found in AI providers list. Available: ${providerNames.join(', ')}`,\n {\n component: 'Robota',\n defaultProvider: config.defaultModel.provider,\n availableProviders: providerNames,\n },\n );\n }\n}\n\n/**\n * Manages model/tool/config updates on behalf of a Robota instance.\n * @internal\n */\nexport class RobotaConfigManager {\n constructor(\n private readonly logger: ILogger,\n private readonly getAIProviders: () => AIProviders,\n private readonly getTools: () => Tools,\n private readonly getEventService: () => IEventService | undefined,\n private readonly ensureReady: () => Promise<void>,\n private readonly getConfig: () => IAgentConfig,\n private readonly setConfig: (c: IAgentConfig) => void,\n private readonly getConfigVersion: () => number,\n private readonly bumpConfigVersion: () => number,\n private readonly getConfigUpdatedAt: () => number,\n private readonly setConfigUpdatedAt: (t: number) => void,\n private readonly emitAgentEvent: (eventType: string, data: Record<string, unknown>) => void,\n ) {}\n\n /** Update tools for this agent instance. */\n async updateTools(next: Array<IToolWithEventService>): Promise<{ version: number }> {\n await this.ensureReady();\n\n if (!Array.isArray(next)) {\n throw new ConfigurationError('updateTools: next must be an array of tools');\n }\n\n const registry = this.getTools().getRegistry();\n registry.clear();\n\n const toolNames: string[] = [];\n const eventService = this.getEventService();\n for (const tool of next) {\n if (eventService) {\n tool.setEventService(eventService);\n }\n const toolExecutor = async (\n parameters: TToolParameters,\n context?: IToolExecutionContext,\n ): Promise<TUniversalValue> => {\n if (!context) {\n throw new Error('[ROBOTA] Missing ToolExecutionContext for tool execution');\n }\n const result = await tool.execute(parameters, context);\n return toolResultValue(tool.schema.name, result);\n };\n this.getTools().addTool(tool.schema, toolExecutor);\n const nm = tool.schema.name;\n if (typeof nm === 'string' && nm.length > 0) toolNames.push(nm);\n }\n\n const config = this.getConfig();\n config.tools = next;\n this.setConfig(config);\n const version = this.bumpConfigVersion();\n this.setConfigUpdatedAt(Date.now());\n\n this.emitAgentEvent(AGENT_EVENTS.CONFIG_UPDATED, {\n parameters: {\n tools: toolNames,\n systemMessage: config.systemMessage,\n provider: config.defaultModel.provider,\n model: config.defaultModel.model,\n temperature: config.defaultModel.temperature,\n maxTokens: config.defaultModel.maxTokens,\n },\n metadata: { version },\n });\n\n return { version };\n }\n\n /**\n * Update configuration partially — `tools` and `name`. ARCH-040 added `name`: `RobotaBase.name`\n * reads through `config`, so writing it here IS the rename, with no second copy to forget.\n */\n async updateConfiguration(patch: Partial<IAgentConfig>): Promise<{ version: number }> {\n if (patch.tools) {\n return this.updateTools(patch.tools);\n }\n if (patch.name !== undefined) {\n this.setConfig({ ...this.getConfig(), name: patch.name });\n const version = this.bumpConfigVersion();\n this.setConfigUpdatedAt(Date.now());\n return { version };\n }\n throw new ConfigurationError('updateConfiguration: only `tools` and `name` are supported');\n }\n\n /** Read-only configuration overview for UI. */\n async getConfiguration(): Promise<{\n version: number;\n tools: Array<{ name: string; parameters?: string[] }>;\n updatedAt: number;\n metadata?: TAgentStatsMetadata;\n }> {\n await this.ensureReady();\n const schemas = this.getTools().getTools();\n const tools = schemas.map((s) => ({\n name: s.name,\n parameters: (() => {\n const params = s.parameters as { properties?: Record<string, object> } | undefined;\n const props = params?.properties;\n return props && typeof props === 'object' ? Object.keys(props) : undefined;\n })(),\n }));\n return {\n version: this.getConfigVersion(),\n tools,\n updatedAt: this.getConfigUpdatedAt(),\n metadata: undefined,\n };\n }\n\n /** Set the current model configuration (complete replacement). */\n setModel(modelConfig: {\n provider: string;\n model: string;\n temperature?: number;\n maxTokens?: number;\n topP?: number;\n effort?: TModelEffortSelection;\n }): void {\n if (!modelConfig.provider || !modelConfig.model) {\n throw new ConfigurationError('Both provider and model are required', { component: 'Robota' });\n }\n\n // CORE-047: no readiness guard, and no `isReady` dependency to hold one. The provider registry\n // and the current (provider, model) pair are established by the `Robota` CONSTRUCTOR\n // (`createConfiguredProviders`), so there is no asynchronous state left for this to protect. A\n // destroyed agent is still refused — by the provider manager's own disposal check, which says\n // \"disposed\" rather than misreporting teardown as \"not initialized\".\n const aiProviders = this.getAIProviders();\n const availableProviders = aiProviders.getProviderNames();\n if (!availableProviders.includes(modelConfig.provider)) {\n throw new ConfigurationError(\n `AI Provider '${modelConfig.provider}' not found. Available: ${availableProviders.join(', ')}`,\n { component: 'Robota', provider: modelConfig.provider, availableProviders },\n );\n }\n\n aiProviders.setCurrentProvider(modelConfig.provider, modelConfig.model);\n\n const config = this.getConfig();\n this.setConfig({\n ...config,\n defaultModel: {\n ...config.defaultModel,\n provider: modelConfig.provider,\n model: modelConfig.model,\n ...(modelConfig.temperature !== undefined && { temperature: modelConfig.temperature }),\n ...(modelConfig.maxTokens !== undefined && { maxTokens: modelConfig.maxTokens }),\n ...(modelConfig.topP !== undefined && { topP: modelConfig.topP }),\n ...(modelConfig.effort !== undefined && { effort: modelConfig.effort }),\n },\n });\n\n this.logger.debug('Model configuration updated', modelConfig);\n }\n\n /** Get the current model configuration. */\n getModel(): {\n provider: string;\n model: string;\n temperature?: number;\n maxTokens?: number;\n topP?: number;\n effort?: TModelEffortSelection;\n } {\n // CORE-047: no readiness guard — see `setModel`.\n const currentProviderInfo = this.getAIProviders().getCurrentProvider();\n if (!currentProviderInfo) {\n throw new ConfigurationError('No provider is currently set', { component: 'Robota' });\n }\n\n const config = this.getConfig();\n return {\n provider: currentProviderInfo.provider,\n model: currentProviderInfo.model,\n ...(config.defaultModel.temperature !== undefined && {\n temperature: config.defaultModel.temperature,\n }),\n ...(config.defaultModel.maxTokens !== undefined && {\n maxTokens: config.defaultModel.maxTokens,\n }),\n ...(config.defaultModel.topP !== undefined && { topP: config.defaultModel.topP }),\n ...(config.defaultModel.effort !== undefined && { effort: config.defaultModel.effort }),\n };\n }\n\n /**\n * Live system-prompt update (SSOT). Sets the top-level `config.systemMessage` — the single source\n * of the system prompt. The conversation store head is updated separately by `Robota`; together\n * they ensure the next provider request carries the change. The system prompt is an agent-level\n * concern, not model config, so it is intentionally not part of `setModel`.\n */\n setSystemMessage(content: string): void {\n const config = this.getConfig();\n config.systemMessage = content;\n this.setConfig(config);\n this.setConfigUpdatedAt(Date.now());\n }\n\n /** Current live system prompt (top-level `config.systemMessage`). */\n getSystemMessage(): string | undefined {\n return this.getConfig().systemMessage;\n }\n\n /** Register a new tool for function calling. */\n registerTool(tool: AbstractTool, tools: Tools): void {\n if (tools.hasTool(tool.schema.name)) {\n throw new Error(\n `[STRICT-POLICY][EMITTER-CONTRACT] Duplicate tool registration attempted: ${tool.schema.name}. ` +\n `Tool registration flow must provide a single authoritative registration path.`,\n );\n }\n\n const toolExecutor = async (\n parameters: TToolParameters,\n context?: IToolExecutionContext,\n ): Promise<TUniversalValue> => {\n if (!context) {\n throw new Error('[ROBOTA] Missing ToolExecutionContext for tool execution');\n }\n const result = await tool.execute(parameters, context);\n return toolResultValue(tool.schema.name, result);\n };\n tools.addTool(tool.schema, toolExecutor);\n this.logger.debug('Tool registered', { toolName: tool.schema.name });\n }\n}\n","import { AbstractManager } from '../abstracts/abstract-manager';\nimport { ToolRegistry, FunctionTool, isDeferredTool, projectOfferedTools } from '../tool-registry';\nimport { ToolExecutionError } from '../utils/errors';\nimport { logger } from '../utils/logger';\n\nimport type { IToolManager } from '../interfaces/manager';\nimport type { IToolSchema } from '../interfaces/provider';\nimport type {\n ITool,\n TToolExecutor,\n TToolParameters,\n IToolExecutionContext,\n} from '../interfaces/tool';\nimport type { TToolSearchMode } from '../interfaces/tool-search';\nimport type { TUniversalValue } from '../interfaces/types';\n\n/**\n * What a tool manager is constructed with (CLI-1990).\n *\n * The manager owns the residency STATE — which deferred tools have been loaded — but not the policy\n * that decides whether deferral is engaged: that is a function of the agent's config, its model and\n * the registered set, all of which the agent owns. The policy is read through this resolver on\n * every projection and never cached, so a config or model change is reflected by the next read.\n */\nexport interface IToolManagerOptions {\n resolveToolSearchMode: () => TToolSearchMode;\n /** Whether a registered tool is shown to the model. Read on every call; absent → all are. */\n isToolVisible?: (toolName: string) => boolean;\n}\n\n/**\n * Tool Manager - manages tool registration and execution\n * Manages tool registration and execution using Tool Registry\n * Instance-based for isolated tool management\n * @internal\n */\nexport class Tools extends AbstractManager implements IToolManager {\n private registry: ToolRegistry;\n private allowedTools?: string[];\n private readonly resolveToolSearchMode: () => TToolSearchMode;\n private readonly isToolVisible: (toolName: string) => boolean;\n /** Deferred tools loaded so far this session — by the search tool, or by a forcing `toolChoice`. */\n private readonly loadedDeferredTools = new Set<string>();\n\n constructor(options: IToolManagerOptions) {\n // CORE-045: `doInitialize` below only logs, so this registry is usable the moment it exists.\n // Without this declaration `Robota.registerTool()` threw on every freshly constructed agent,\n // because the only thing that awaited `initialize()` was the first run.\n super({ readyOnConstruction: true });\n this.registry = new ToolRegistry();\n this.resolveToolSearchMode = options.resolveToolSearchMode;\n this.isToolVisible = options.isToolVisible ?? (() => true);\n }\n\n /**\n * Initialize the manager\n */\n protected async doInitialize(): Promise<void> {\n logger.debug('Tools initialized');\n }\n\n /**\n * Cleanup manager resources\n */\n protected async doDispose(): Promise<void> {\n this.registry.clear();\n this.loadedDeferredTools.clear();\n delete this.allowedTools;\n logger.debug('Tools disposed');\n }\n\n /**\n * Register a tool with schema and executor function\n */\n addTool(schema: IToolSchema, executor: TToolExecutor): void {\n this.ensureInitialized();\n\n const tool = new FunctionTool(schema, executor);\n this.registry.register(tool);\n\n logger.debug(`Tool \"${schema.name}\" registered successfully`);\n }\n\n /**\n * Remove a tool by name\n */\n removeTool(name: string): void {\n this.ensureInitialized();\n this.registry.unregister(name);\n }\n\n /**\n * Get tool interface by name\n */\n getTool(name: string): ITool | undefined {\n this.ensureInitialized();\n return this.registry.get(name);\n }\n\n /**\n * Get tool schema by name\n */\n getToolSchema(name: string): IToolSchema | undefined {\n this.ensureInitialized();\n const tool = this.registry.get(name);\n return tool?.schema;\n }\n\n /**\n * Get all registered tool schemas\n */\n getTools(): IToolSchema[] {\n this.ensureInitialized();\n\n const schemas = this.registry\n .getSchemas()\n .filter((schema) => this.isToolVisible(schema.name));\n\n // Filter by allowed tools if set\n if (this.allowedTools) {\n return schemas.filter((schema) => this.allowedTools!.includes(schema.name));\n }\n\n return schemas;\n }\n\n /**\n * The schemas the model is offered at the next request (CLI-1990): every registered tool while\n * deferral is not engaged; the resident ones plus the loaded deferred ones once it is. Read per\n * round by the execution loop — never a snapshot — and refused, not sent, when it would be empty\n * over a non-empty registry (`projectOfferedTools`).\n */\n getOfferedTools(): IToolSchema[] {\n return projectOfferedTools(\n this.getTools(),\n this.loadedDeferredTools,\n this.resolveToolSearchMode(),\n );\n }\n\n /** Whether a call to this tool would execute now: registered, and offered by the projection. */\n isToolOffered(name: string): boolean {\n return this.getOfferedTools().some((schema) => schema.name === name);\n }\n\n /** Deferred tools not yet loaded — the population a search discovers. Empty while deferral is off. */\n listDeferredTools(): IToolSchema[] {\n if (this.resolveToolSearchMode() === 'off') return [];\n return this.getTools().filter(\n (schema) => isDeferredTool(schema) && !this.loadedDeferredTools.has(schema.name),\n );\n }\n\n /**\n * Mark deferred tools loaded for the rest of the session. Every name is resolved before any is\n * loaded, so an unknown entry — thrown naming it — loads nothing; a resident name is returned as\n * it is, already offered.\n */\n loadDeferredTools(names: readonly string[]): IToolSchema[] {\n this.ensureInitialized();\n const schemas = names.map((name) => {\n // A tool hidden from the model is not loadable by name either (issue #3081).\n const schema = this.isToolVisible(name) ? this.registry.get(name)?.schema : undefined;\n if (!schema) {\n throw new ToolExecutionError(\n `Tool \"${name}\" is not registered, so it cannot be loaded`,\n name,\n );\n }\n return schema;\n });\n for (const schema of schemas) {\n if (isDeferredTool(schema)) this.loadedDeferredTools.add(schema.name);\n }\n return schemas;\n }\n\n /**\n * Execute a tool with parameters\n */\n async executeTool(\n name: string,\n parameters: TToolParameters,\n context?: IToolExecutionContext,\n ): Promise<TUniversalValue> {\n this.ensureInitialized();\n\n // Check if tool is allowed\n if (this.allowedTools && !this.allowedTools.includes(name)) {\n throw new ToolExecutionError(`Tool \"${name}\" is not in the allowed tools list`, name);\n }\n\n const tool = this.registry.get(name);\n if (!tool) {\n throw new ToolExecutionError(`Tool \"${name}\" is not registered`, name);\n }\n\n let result;\n try {\n result = await tool.execute(parameters, context);\n } catch (error) {\n // Re-wrap errors thrown by tools to ensure instanceof checks work\n // when tools are loaded from dist packages\n if (error instanceof Error) {\n throw new ToolExecutionError(error.message, name, error);\n }\n throw new ToolExecutionError(String(error), name);\n }\n\n if (!result.success) {\n throw new ToolExecutionError(result.error || 'Tool execution failed', name, undefined, {\n parameters: JSON.stringify(parameters),\n result: JSON.stringify(result),\n });\n }\n\n if (typeof result.data === 'undefined') {\n throw new ToolExecutionError('Tool execution succeeded but returned no data', name);\n }\n return result.data;\n }\n\n /**\n * Check if tool exists\n */\n hasTool(name: string): boolean {\n this.ensureInitialized();\n return this.registry.has(name);\n }\n\n /**\n * Set allowed tools for filtering\n */\n setAllowedTools(tools: string[]): void {\n this.ensureInitialized();\n this.allowedTools = [...tools];\n logger.debug(`Set allowed tools: ${tools.join(', ')}`);\n }\n\n /**\n * Get allowed tools\n */\n getAllowedTools(): string[] | undefined {\n this.ensureInitialized();\n return this.allowedTools ? [...this.allowedTools] : undefined;\n }\n\n /**\n * Get tool registry instance (for advanced operations)\n */\n getRegistry(): ToolRegistry {\n this.ensureInitialized();\n return this.registry;\n }\n\n /**\n * Get tool count\n */\n getToolCount(): number {\n this.ensureInitialized();\n return this.registry.size();\n }\n}\n","import type { TUniversalMessage, TUniversalMessageMetadata } from '../interfaces/messages.js';\n\nexport interface IMessageTokenUsage {\n readonly inputTokens: number;\n readonly outputTokens: number;\n readonly totalTokens?: number;\n}\n\ninterface IProviderUsageLike {\n readonly promptTokens?: number;\n readonly completionTokens?: number;\n readonly totalTokens?: number;\n readonly inputTokens?: number;\n readonly outputTokens?: number;\n}\n\ntype TMessageWithProviderUsage = TUniversalMessage & {\n readonly usage?: IProviderUsageLike;\n};\n\n/** Read normalized provider usage from a universal message when present. */\nexport function readTokenUsageFromMessage(\n message: TUniversalMessage,\n): IMessageTokenUsage | undefined {\n const metadataUsage = readTokenUsageFromMetadata(message.metadata);\n const topLevelUsage = readTokenUsageFromProviderUsage(\n (message as TMessageWithProviderUsage).usage,\n );\n return metadataUsage ?? topLevelUsage;\n}\n\nexport function readTokenUsageFromMetadata(\n metadata: TUniversalMessageMetadata | undefined,\n): IMessageTokenUsage | undefined {\n if (!metadata) return undefined;\n\n const direct = readTokenUsageFromProviderUsage({\n inputTokens: numberFromMetadata(metadata, 'inputTokens'),\n outputTokens: numberFromMetadata(metadata, 'outputTokens'),\n promptTokens: numberFromMetadata(metadata, 'promptTokens'),\n completionTokens: numberFromMetadata(metadata, 'completionTokens'),\n totalTokens: numberFromMetadata(metadata, 'totalTokens'),\n });\n if (direct) return direct;\n\n const nested = metadata['usage'];\n if (typeof nested === 'string') {\n return readTokenUsageFromJson(nested);\n }\n if (isNumberRecord(nested)) {\n return readTokenUsageFromProviderUsage(nested);\n }\n return undefined;\n}\n\nfunction readTokenUsageFromJson(value: string): IMessageTokenUsage | undefined {\n try {\n const parsed = JSON.parse(value) as IProviderUsageLike;\n return readTokenUsageFromProviderUsage(parsed);\n } catch {\n // allow-fallback: malformed provider-usage JSON yields no token-usage snapshot (advisory metric)\n return undefined;\n }\n}\n\nfunction readTokenUsageFromProviderUsage(\n usage: IProviderUsageLike | undefined,\n): IMessageTokenUsage | undefined {\n if (!usage) return undefined;\n const inputTokens = firstFiniteNumber(usage.inputTokens, usage.promptTokens);\n const outputTokens = firstFiniteNumber(usage.outputTokens, usage.completionTokens);\n if (inputTokens === undefined || outputTokens === undefined) return undefined;\n const totalTokens = firstFiniteNumber(usage.totalTokens);\n return {\n inputTokens,\n outputTokens,\n ...(totalTokens !== undefined && { totalTokens }),\n };\n}\n\nfunction numberFromMetadata(metadata: TUniversalMessageMetadata, key: string): number | undefined {\n const value = metadata[key];\n return typeof value === 'number' && Number.isFinite(value) ? value : undefined;\n}\n\nfunction firstFiniteNumber(...values: Array<number | undefined>): number | undefined {\n return values.find(\n (value): value is number => typeof value === 'number' && Number.isFinite(value),\n );\n}\n\nfunction isNumberRecord(\n value: TUniversalMessageMetadata[string] | undefined,\n): value is Record<string, number> {\n return (\n typeof value === 'object' &&\n value !== null &&\n !Array.isArray(value) &&\n Object.values(value).every((item) => typeof item === 'number' && Number.isFinite(item))\n );\n}\n","import { readTokenUsageFromMessage } from './token-usage.js';\n\nimport type { TUniversalMessage } from '../interfaces/messages.js';\nimport type { IToolSchema } from '../interfaces/tool-schema.js';\n\nexport const CONTEXT_ESTIMATE_CHARS_PER_TOKEN = 4;\n\nexport interface IContextTokenEstimateOptions {\n readonly usageFloorTokens?: number;\n}\n\nexport interface IContextTokenEstimate {\n readonly usedTokens: number;\n readonly serializedTokens: number;\n readonly providerTokens?: number;\n readonly usageFloorTokens?: number;\n}\n\nexport function estimateSerializedContextTokens(messages: readonly TUniversalMessage[]): number {\n return Math.ceil(JSON.stringify(messages).length / CONTEXT_ESTIMATE_CHARS_PER_TOKEN);\n}\n\n/**\n * CLI-1990: what a set of tool schemas costs on every request, by the same chars-per-token heuristic\n * the message estimate uses — a serialised schema is what the adapters put on the wire. An empty set\n * costs nothing, stated rather than left to the two-character `[]`.\n */\nexport function estimateToolSchemaTokens(schemas: readonly IToolSchema[]): number {\n if (schemas.length === 0) return 0;\n return Math.ceil(JSON.stringify(schemas).length / CONTEXT_ESTIMATE_CHARS_PER_TOKEN);\n}\n\nexport function estimateContextTokensFromMessages(\n messages: readonly TUniversalMessage[],\n options: IContextTokenEstimateOptions = {},\n): IContextTokenEstimate {\n const serializedTokens = estimateSerializedContextTokens(messages);\n const providerEstimate = readLatestProviderTokens(messages);\n const providerTokens = providerEstimate?.tokens;\n const usageFloorTokens = normalizeUsageFloorTokens(options.usageFloorTokens);\n const providerUsageIsTerminal = providerEstimate?.index === messages.length - 1;\n const usedTokens = providerUsageIsTerminal\n ? Math.max(providerTokens ?? 0, usageFloorTokens ?? 0)\n : Math.max(serializedTokens, providerTokens ?? 0, usageFloorTokens ?? 0);\n\n return {\n usedTokens,\n serializedTokens,\n ...(providerTokens !== undefined && { providerTokens }),\n ...(usageFloorTokens !== undefined && { usageFloorTokens }),\n };\n}\n\nfunction readLatestProviderTokens(\n messages: readonly TUniversalMessage[],\n): { tokens: number; index: number } | undefined {\n for (let index = messages.length - 1; index >= 0; index--) {\n const usage = readTokenUsageFromMessage(messages[index]);\n if (usage) {\n return {\n tokens: usage.totalTokens ?? usage.inputTokens + usage.outputTokens,\n index,\n };\n }\n }\n return undefined;\n}\n\nfunction normalizeUsageFloorTokens(value: number | undefined): number | undefined {\n if (value === undefined || !Number.isFinite(value) || value <= 0) {\n return undefined;\n }\n return Math.ceil(value);\n}\n","/**\n * Claude model definitions — SSOT for model metadata.\n * Source: https://platform.claude.com/docs/en/about-claude/models/overview\n */\n\nimport { createLogger } from '../utils/logger';\n\nconst logger = createLogger('agent-core:models');\n\n/**\n * One line per unknown model, not one per call. `getModelContextWindow` runs on every round, and a\n * warning repeated a thousand times is a warning nobody reads.\n */\nconst warnedModels = new Set<string>();\n\nfunction warnUnknownModel(modelId: string, what: string, fallback: number): void {\n const key = `${modelId}:${what}`;\n if (warnedModels.has(key)) return;\n warnedModels.add(key);\n logger.warn(\n `No metadata registered for model \"${modelId}\"; using the default ${what} of ${fallback}. ` +\n \"This number belongs to a different vendor's models — register the model through \" +\n 'registerModelMetadata() from the package that owns it. (NEUT-010)',\n );\n}\n\nexport interface IModelDefinition {\n /** Human-readable model name */\n name: string;\n /** API model identifier */\n id: string;\n /** Context window size in tokens */\n contextWindow: number;\n /** Maximum output tokens */\n maxOutput: number;\n}\n\n/**\n * Known Claude models (4.5+).\n * Keyed by API model ID for fast lookup.\n */\nexport const DEFAULT_CONTEXT_WINDOW = 200_000;\n\n/**\n * Model metadata contributed by a provider package. NEUT-010.\n *\n * This package used to carry a CLAUDE table, against its own SPEC (\"must not branch on concrete\n * provider or model names\") — and `agent-provider-anthropic` imported it back out. The table now\n * lives with the package that owns those models, and every provider contributes the same way.\n *\n * The registry is the ONLY source. A model nobody registered is a model nobody owns, which is a\n * different answer from \"here is a number\", and the callers below say so.\n */\nconst registeredModels = new Map<string, IModelDefinition>();\n\n/**\n * Contribute model metadata from the package that owns the model.\n *\n * The last registration wins, which is what lets a host correct a provider. A CONFLICTING one is\n * announced first: two packages claiming the same model id with different numbers means one of them\n * is wrong, and replacing a value in silence is the failure mode this whole change is against.\n * Re-registering identical values — which happens whenever a module is loaded twice — says nothing.\n */\nexport function registerModelMetadata(...definitions: IModelDefinition[]): void {\n for (const definition of definitions) {\n const existing = registeredModels.get(definition.id);\n if (existing && !sameDefinition(existing, definition)) {\n logger.warn(\n `Model \"${definition.id}\" was already registered with different metadata ` +\n `(context window ${existing.contextWindow} -> ${definition.contextWindow}, ` +\n `max output ${existing.maxOutput} -> ${definition.maxOutput}). The later registration ` +\n 'wins; one of the two owners is wrong. (NEUT-010)',\n );\n }\n registeredModels.set(definition.id, definition);\n }\n}\n\nfunction sameDefinition(a: IModelDefinition, b: IModelDefinition): boolean {\n return a.name === b.name && a.contextWindow === b.contextWindow && a.maxOutput === b.maxOutput;\n}\n\n/** Forget contributed metadata. Exposed for tests and for hosts that rebuild a registry. */\nexport function clearRegisteredModelMetadata(): void {\n registeredModels.clear();\n}\n\n/** The metadata known for a model ID, or `undefined` when nothing owns it. */\nexport function findModelDefinition(modelId: string): IModelDefinition | undefined {\n return registeredModels.get(modelId);\n}\n\n/**\n * Get context window size for a model ID.\n *\n * NEUT-010: an unknown model used to receive `DEFAULT_CONTEXT_WINDOW` — 200 000, which is CLAUDE's\n * window — with no signal at all. Every non-Claude session was therefore sized against a number\n * belonging to a different vendor's models, and the two consumers that act on it\n * (`execution-round-context.ts`, `execution-round-tools.ts`, and `agent-session`'s context-window\n * tracker) had no way to know they were working from a guess.\n *\n * The fallback remains, because these call sites need a number to plan a round with. What changes is\n * that it is no longer SILENT: falling back now says which model it could not identify. A guess that\n * announces itself can be found; one that does not is indistinguishable from knowledge.\n */\nexport function getModelContextWindow(modelId: string): number {\n const known = findModelDefinition(modelId)?.contextWindow;\n if (known !== undefined) return known;\n warnUnknownModel(modelId, 'context window', DEFAULT_CONTEXT_WINDOW);\n return DEFAULT_CONTEXT_WINDOW;\n}\n\nexport const DEFAULT_MAX_OUTPUT = 16_384;\n\n/** Get max output tokens for a model ID. Falls back to DEFAULT_MAX_OUTPUT, and says so. */\nexport function getModelMaxOutput(modelId: string): number {\n const known = findModelDefinition(modelId)?.maxOutput;\n if (known !== undefined) return known;\n warnUnknownModel(modelId, 'max output', DEFAULT_MAX_OUTPUT);\n return DEFAULT_MAX_OUTPUT;\n}\n\n/**\n * Get human-readable model name for a model ID. Falls back to the ID itself.\n *\n * No warning here: the ID is a CORRECT answer to \"what should I call this model\", not a guess about\n * the model's capabilities. Warning on it would train the reader to ignore the ones that matter.\n */\nexport function getModelName(modelId: string): string {\n return findModelDefinition(modelId)?.name ?? modelId;\n}\n\n/** Format token count as human-readable (e.g., 200K, 1M, 1.2M). Minimum unit is K. */\nexport function formatTokenCount(tokens: number): string {\n if (tokens >= 1_000_000) {\n const m = tokens / 1_000_000;\n return Number.isInteger(m) ? `${m}M` : `${parseFloat(m.toFixed(1))}M`;\n }\n // Minimum unit is K — values below 1000 show as \"<1K\" or \"0K\"\n if (tokens <= 0) return '0K';\n if (tokens < 1_000) return '<1K';\n const k = tokens / 1_000;\n return Number.isInteger(k) ? `${k}K` : `${parseFloat(k.toFixed(1))}K`;\n}\n","/**\n * The threshold policy that decides whether deferral engages (CLI-1990 § Solution 3).\n *\n * \"On by default\" means default-on as a THRESHOLD policy, never unconditional deferral. Anthropic's\n * own guidance is that standard tool calling is the better fit under ten tools, and its SDK engages\n * search when the deferrable definitions reach a tenth of the model's context window; OpenAI and\n * Gemini document comparable bands. So at the ten resident built-ins of today's tree the answer is\n * `'off'` and nothing regresses, and when a tool set crosses the band — MCP servers arriving, say —\n * it switches itself on with no flag day. An explicit setting wins over both.\n *\n * Only DEFERRABLE schemas are measured against the window: deferral cannot save what is resident,\n * so counting it would engage the mechanism for a saving it cannot make.\n */\n\nimport { estimateToolSchemaTokens } from '../context/estimation';\nimport { getModelContextWindow } from '../context/models';\nimport { isDeferredTool } from '../tool-registry/tool-residency';\n\nimport type { IToolSchema } from '../interfaces/tool-schema';\nimport type { TToolSearchMode, TToolSearchSetting } from '../interfaces/tool-search';\n\n/** Deferral engages when MORE than this many deferrable tools are registered. */\nexport const TOOL_SEARCH_DEFERRABLE_COUNT_THRESHOLD = 15;\n\n/** …or when the deferrable schemas' estimated tokens reach this share of the model's context window. */\nexport const TOOL_SEARCH_CONTEXT_WINDOW_SHARE = 0.1;\n\n/** What the policy reads from an agent config — `IAgentConfig` satisfies it. */\nexport interface IToolSearchPolicyConfig {\n readonly toolSearch?: TToolSearchSetting;\n}\n\n/**\n * Whether deferred schemas are withheld from the model's tool list.\n *\n * Evaluated per read, never cached: the inputs are the config, the model and the registered set,\n * and each of them can change between rounds through the agent's own seams.\n */\nexport function resolveToolSearchMode(\n config: IToolSearchPolicyConfig,\n modelId: string,\n tools: readonly IToolSchema[],\n): TToolSearchMode {\n const setting = config.toolSearch ?? 'auto';\n if (setting !== 'auto') return setting;\n const deferrable = tools.filter(isDeferredTool);\n // Decided before any window lookup, so a tree with nothing deferrable never asks about a model it\n // may not have registered metadata for.\n if (deferrable.length === 0) return 'off';\n if (deferrable.length > TOOL_SEARCH_DEFERRABLE_COUNT_THRESHOLD) return 'on';\n const share = estimateToolSchemaTokens(deferrable) / getModelContextWindow(modelId);\n return share >= TOOL_SEARCH_CONTEXT_WINDOW_SHARE ? 'on' : 'off';\n}\n","/**\n * What `Robota`'s constructor builds that is more than a `new` — kept beside `robota-initializer`\n * for the reason that file exists: the class file sits at its size ceiling.\n */\n\nimport { Tools } from '../managers/tool-manager';\nimport { resolveToolSearchMode } from '../services/tool-search-policy';\nimport { TOOL_SEARCH_TOOL_NAME } from '../interfaces/tool-search';\n\nimport type { IAgentConfig } from '../interfaces/agent';\n\nconst ID_RADIX = 36;\nconst ID_RANDOM_LENGTH = 9;\n\n/** The conversation this agent owns: the configured id, or a fresh one. */\nexport function createConversationId(config: IAgentConfig): string {\n return (\n config.conversationId ||\n `conv_${Date.now()}_${Math.random().toString(ID_RADIX).substr(2, ID_RANDOM_LENGTH)}`\n );\n}\n\n/**\n * The tool manager, given the ONE policy source it needs (CLI-1990).\n *\n * The manager owns the residency state — which deferred tools are loaded — and asks this resolver\n * whether deferral is engaged on every projection. `readConfig` is read each time rather than\n * captured once, so `updateConfiguration` and `setModel` are reflected by the next round without\n * re-wiring; the deferrable set is the manager's own registry, which is why the closure closes over\n * the instance it is building.\n */\nexport function createConfiguredTools(readConfig: () => IAgentConfig): Tools {\n const tools: Tools = new Tools({\n resolveToolSearchMode: () => {\n const config = readConfig();\n // Issue #3081: with the loader hidden by a deny rule, nothing could load a withheld schema,\n // so deferral is off and every visible tool is offered resident.\n if (config.isToolVisible?.(TOOL_SEARCH_TOOL_NAME) === false) return 'off';\n return resolveToolSearchMode(config, config.defaultModel.model, tools.getTools());\n },\n isToolVisible: (toolName) => readConfig().isToolVisible?.(toolName) ?? true,\n });\n return tools;\n}\n","/**\n * Module management delegate for the Robota agent.\n *\n * Extracted from robota.ts to keep the main class under 300 lines.\n * All public method signatures are preserved via delegation.\n */\nimport type { IModule } from '../abstracts/abstract-module';\nimport type { IModuleResultData, IModuleExecutionContext } from '../abstracts/abstract-module';\nimport type { ModuleRegistry } from '../managers/module-registry';\nimport type { ILogger } from '../utils/logger';\n\n/**\n * Manages module lifecycle on behalf of a Robota instance.\n * @internal\n */\nexport class RobotaModuleManager {\n constructor(\n private readonly agentName: string,\n private readonly moduleRegistry: ModuleRegistry,\n private readonly logger: ILogger,\n private readonly isReady: () => boolean,\n private readonly ensureReady: () => Promise<void>,\n ) {}\n\n /**\n * Register a new module with the agent\n */\n async registerModule(\n module: IModule,\n options?: { autoInitialize?: boolean; validateDependencies?: boolean },\n ): Promise<void> {\n await this.ensureReady();\n\n await this.moduleRegistry.registerModule(module, {\n autoInitialize: options?.autoInitialize ?? true,\n validateDependencies: options?.validateDependencies ?? true,\n });\n\n this.logger.info('Module registered', {\n moduleName: module.name,\n moduleType: module.getModuleType().type,\n });\n }\n\n /**\n * Unregister a module from the agent\n */\n async unregisterModule(moduleName: string): Promise<boolean> {\n if (!this.isReady()) {\n return false;\n }\n\n const result = await this.moduleRegistry.unregisterModule(moduleName);\n\n if (result) {\n this.logger.info('Module unregistered', { moduleName });\n }\n\n return result;\n }\n\n /**\n * Get a module by name\n */\n getModule(moduleName: string): IModule | undefined {\n if (!this.isReady()) {\n return undefined;\n }\n return this.moduleRegistry.getModule(moduleName);\n }\n\n /**\n * Get modules by type\n */\n getModulesByType(moduleType: string): IModule[] {\n if (!this.isReady()) {\n return [];\n }\n return this.moduleRegistry.getModulesByType(moduleType);\n }\n\n /**\n * Get all registered modules\n */\n getModules(): IModule[] {\n if (!this.isReady()) {\n return [];\n }\n return this.moduleRegistry.getAllModules();\n }\n\n /**\n * Get all registered module names\n */\n getModuleNames(): string[] {\n if (!this.isReady()) {\n return [];\n }\n return this.moduleRegistry.getModuleNames();\n }\n\n /**\n * Check if a module is registered\n */\n hasModule(moduleName: string): boolean {\n if (!this.isReady()) {\n return false;\n }\n return this.moduleRegistry.hasModule(moduleName);\n }\n\n /**\n * Execute a module by name\n */\n async executeModule(\n moduleName: string,\n context: {\n executionId?: string;\n sessionId?: string;\n userId?: string;\n metadata?: Record<string, string | number | boolean | Date>;\n },\n ): Promise<{ success: boolean; data?: IModuleResultData; error?: Error; duration?: number }> {\n await this.ensureReady();\n\n const executionContext: IModuleExecutionContext = {\n agentName: this.agentName,\n ...(context.executionId && { executionId: context.executionId }),\n ...(context.sessionId && { sessionId: context.sessionId }),\n ...(context.userId && { userId: context.userId }),\n ...(context.metadata && { metadata: context.metadata }),\n };\n\n return await this.moduleRegistry.executeModule(moduleName, executionContext);\n }\n\n /**\n * Get module execution statistics\n */\n getModuleStats(moduleName: string):\n | {\n totalExecutions: number;\n successfulExecutions: number;\n failedExecutions: number;\n averageExecutionTime: number;\n lastExecutionTime?: Date;\n }\n | undefined {\n if (!this.isReady()) {\n return undefined;\n }\n return this.moduleRegistry.getModuleStats(moduleName);\n }\n}\n","/**\n * Plugin management delegate for the Robota agent.\n *\n * Extracted from robota.ts to keep the main class under 300 lines.\n * All public method signatures are preserved via delegation.\n */\nimport { ConfigurationError } from '../utils/errors';\n\nimport type {\n IPluginContract,\n IPluginHooks,\n IPluginOptions,\n IPluginStats,\n} from '../abstracts/abstract-plugin';\nimport type { ExecutionService } from '../services/execution-service';\nimport type { ILogger } from '../utils/logger';\n\n/**\n * Manages plugin lifecycle on behalf of a Robota instance.\n * @internal\n */\nexport class RobotaPluginManager {\n constructor(\n private readonly logger: ILogger,\n private readonly isReady: () => boolean,\n private readonly getExecutionService: () => ExecutionService | undefined,\n ) {}\n\n /**\n * Add a plugin to the agent at runtime.\n */\n addPlugin(plugin: IPluginContract<IPluginOptions, IPluginStats> & IPluginHooks): void {\n const executionService = this.getExecutionService();\n if (!this.isReady() || !executionService) {\n throw new ConfigurationError(\n 'Cannot add plugin before agent is fully initialized. Await an operation like run() first, or pass plugins via the constructor config.',\n { pluginName: plugin.name },\n );\n }\n executionService.registerPlugin(plugin);\n this.logger.debug('Plugin added', { pluginName: plugin.name });\n }\n\n /**\n * Remove a plugin from the agent by name.\n */\n removePlugin(pluginName: string): boolean {\n const executionService = this.getExecutionService();\n if (!executionService) {\n return false;\n }\n const removed = executionService.removePlugin(pluginName);\n if (removed) {\n this.logger.debug('Plugin removed', { pluginName });\n }\n return removed;\n }\n\n /**\n * Get a specific plugin by name.\n */\n getPlugin(\n pluginName: string,\n ): (IPluginContract<IPluginOptions, IPluginStats> & IPluginHooks) | undefined {\n const executionService = this.getExecutionService();\n if (!executionService) {\n return undefined;\n }\n return executionService.getPlugin(pluginName);\n }\n\n /**\n * Get all registered plugins.\n */\n getPlugins(): Array<IPluginContract<IPluginOptions, IPluginStats> & IPluginHooks> {\n const executionService = this.getExecutionService();\n if (!executionService) {\n return [];\n }\n return executionService.getPlugins();\n }\n\n /**\n * Get all registered plugin names.\n */\n getPluginNames(): string[] {\n const executionService = this.getExecutionService();\n if (!this.isReady() || !executionService) {\n return [];\n }\n return executionService.getPlugins().map((plugin) => plugin.name);\n }\n}\n","/**\n * Factory functions for creating the Robota delegate managers.\n *\n * Extracted from core/robota.ts to keep that file under 300 lines.\n * Creates RobotaModuleManager, RobotaPluginManager, and RobotaConfigManager\n * with all required closures bound to the Robota instance state.\n */\nimport { RobotaConfigManager } from './robota-config-manager';\nimport { RobotaModuleManager } from './robota-module-manager';\nimport { RobotaPluginManager } from './robota-plugin-manager';\n\nimport type { IAgentConfig } from '../interfaces/agent';\nimport type { IAgentEventData } from '../interfaces/event-service';\nimport type { IEventService } from '../interfaces/event-service';\nimport type { AIProviders } from '../managers/ai-provider-manager';\nimport type { ModuleRegistry } from '../managers/module-registry';\nimport type { Tools } from '../managers/tool-manager';\nimport type { ExecutionService } from '../services/execution-service';\nimport type { ILogger } from '../utils/logger';\n\n/**\n * Mutable state references for the Robota instance.\n * All fields are accessed via getters/setters to allow live binding.\n */\nexport interface IRobotaDelegateState {\n getName: () => string;\n getModuleRegistry: () => ModuleRegistry;\n getLogger: () => ILogger;\n getIsFullyInitialized: () => boolean;\n ensureFullyInitialized: () => Promise<void>;\n getExecutionService: () => ExecutionService;\n getAiProviders: () => AIProviders;\n getTools: () => Tools;\n getEventService: () => IEventService;\n getConfig: () => IAgentConfig;\n setConfig: (c: IAgentConfig) => void;\n getConfigVersion: () => number;\n incrementConfigVersion: () => number;\n getConfigUpdatedAt: () => number;\n setConfigUpdatedAt: (t: number) => void;\n emitAgentEvent: (eventType: string, data: Record<string, unknown>) => void;\n}\n\n/**\n * Create all three delegate managers for a Robota instance.\n */\nexport function createRobotaDelegates(state: IRobotaDelegateState): {\n moduleManager: RobotaModuleManager;\n pluginManager: RobotaPluginManager;\n configManager: RobotaConfigManager;\n} {\n const moduleManager = new RobotaModuleManager(\n state.getName(),\n state.getModuleRegistry(),\n state.getLogger(),\n state.getIsFullyInitialized,\n state.ensureFullyInitialized,\n );\n\n const pluginManager = new RobotaPluginManager(\n state.getLogger(),\n state.getIsFullyInitialized,\n state.getExecutionService,\n );\n\n const configManager = new RobotaConfigManager(\n state.getLogger(),\n state.getAiProviders,\n state.getTools,\n state.getEventService,\n state.ensureFullyInitialized,\n state.getConfig,\n (c: IAgentConfig) => state.setConfig(c),\n state.getConfigVersion,\n state.incrementConfigVersion,\n state.getConfigUpdatedAt,\n (t: number) => state.setConfigUpdatedAt(t),\n (eventType: string, data: Record<string, unknown>) =>\n state.emitAgentEvent(eventType, data as Omit<IAgentEventData, 'timestamp'>),\n );\n\n return { moduleManager, pluginManager, configManager };\n}\n","export const TASK_EVENTS = {\n ASSIGNED: 'assigned',\n COMPLETED: 'completed',\n} as const;\n\nexport const TASK_EVENT_PREFIX = 'task' as const;\n","export const USER_EVENTS = {\n MESSAGE: 'message',\n INPUT: 'input',\n} as const;\n\nexport const USER_EVENT_PREFIX = 'user' as const;\n\nexport type TUserEvent = (typeof USER_EVENTS)[keyof typeof USER_EVENTS];\n","/**\n * Event-related helpers for the Robota agent class.\n *\n * Extracted from core/robota.ts to keep that file under 300 lines.\n * Handles agent event emission and owner path construction.\n */\nimport { AGENT_EVENTS, AGENT_EVENT_PREFIX } from '../agents/constants';\nimport { isDefaultEventService } from '../event-service/index';\nimport { EVENT_EMITTER_EVENTS } from '../plugins/event-emitter/types';\nimport { EventEmitterPlugin } from '../plugins/event-emitter-plugin';\n\nimport type { IAgentConfig, IExecutionContextInjection } from '../interfaces/agent';\nimport type {\n IEventService,\n IOwnerPathSegment,\n IAgentEventData,\n} from '../interfaces/event-service';\n\n/**\n * Emit the AGENT_EVENTS.CREATED event with tool and model parameters.\n */\nexport function emitCreatedEvent(\n config: IAgentConfig,\n emitFn: (eventType: string, data: Omit<IAgentEventData, 'timestamp'>) => void,\n): void {\n const toolNames: string[] = Array.isArray(config.tools)\n ? config.tools\n .map((t) => {\n const sn = t?.schema?.name;\n if (typeof sn === 'string' && sn.length > 0) return sn;\n const nm = (t as { name?: string } | undefined)?.name;\n if (typeof nm === 'string' && nm.length > 0) return nm;\n return '';\n })\n .filter((n): n is string => typeof n === 'string' && n.length > 0)\n : [];\n emitFn(AGENT_EVENTS.CREATED, {\n parameters: {\n tools: toolNames,\n systemMessage: config.systemMessage,\n provider: config.defaultModel.provider,\n model: config.defaultModel.model,\n temperature: config.defaultModel.temperature,\n maxTokens: config.defaultModel.maxTokens,\n },\n });\n}\n\n/**\n * Emit an agent event via the agentEventService.\n * No-ops when the service is the default (no-op) implementation.\n */\nexport function emitAgentEvent(\n agentEventService: IEventService,\n conversationId: string,\n executionContext: IExecutionContextInjection | undefined,\n eventType: string,\n data: Omit<IAgentEventData, 'timestamp'>,\n): void {\n if (isDefaultEventService(agentEventService)) return;\n agentEventService.emit(\n eventType,\n { timestamp: new Date(), ...data },\n {\n ownerType: AGENT_EVENT_PREFIX,\n ownerId: conversationId,\n ownerPath: buildOwnerPath(conversationId, executionContext),\n },\n );\n}\n\n/**\n * Create an EventEmitterPlugin configured for module lifecycle events.\n * Used by the Robota constructor to avoid a 14-line inline EventEmitterPlugin instantiation.\n */\nexport function createModuleEventEmitter(): EventEmitterPlugin {\n return new EventEmitterPlugin({\n enabled: true,\n events: [\n EVENT_EMITTER_EVENTS.MODULE_INITIALIZE_START,\n EVENT_EMITTER_EVENTS.MODULE_INITIALIZE_COMPLETE,\n EVENT_EMITTER_EVENTS.MODULE_INITIALIZE_ERROR,\n EVENT_EMITTER_EVENTS.MODULE_EXECUTION_START,\n EVENT_EMITTER_EVENTS.MODULE_EXECUTION_COMPLETE,\n EVENT_EMITTER_EVENTS.MODULE_EXECUTION_ERROR,\n EVENT_EMITTER_EVENTS.MODULE_DISPOSE_START,\n EVENT_EMITTER_EVENTS.MODULE_DISPOSE_COMPLETE,\n EVENT_EMITTER_EVENTS.MODULE_DISPOSE_ERROR,\n ],\n });\n}\n\n/**\n * Build the owner path segment array for an agent.\n */\nexport function buildOwnerPath(\n conversationId: string,\n executionContext?: IExecutionContextInjection,\n): IOwnerPathSegment[] {\n const base = executionContext?.ownerPath?.length\n ? executionContext.ownerPath.map((segment) => ({ ...segment }))\n : [];\n return [...base, { type: 'agent', id: conversationId }];\n}\n","/**\n * Execution methods (run, runStream) for the Robota agent.\n *\n * Extracted from robota.ts to keep the main class under 300 lines.\n */\nimport { AGENT_EVENTS } from '../agents/constants';\n\nimport type { TUniversalMessage, IAgentConfig, IRunOptions } from '../interfaces/agent';\nimport type { IAgentEventData } from '../interfaces/event-service';\nimport type { ExecutionService } from '../services/execution-service';\nimport type { IExecutionContext } from '../services/execution-types';\nimport type { ILogger } from '../utils/logger';\n\n/** Dependencies required by the execution helpers. @internal */\nexport interface IRobotaExecutionDeps {\n readonly conversationId: string;\n readonly config: IAgentConfig;\n readonly logger: ILogger;\n getHistory(): TUniversalMessage[];\n getExecutionService(): ExecutionService;\n emitAgentEvent(eventType: string, data: Omit<IAgentEventData, 'timestamp'>): void;\n}\n\nfunction buildRunContext(\n deps: IRobotaExecutionDeps,\n options: IRunOptions,\n): Partial<IExecutionContext> {\n return {\n conversationId: deps.conversationId,\n ...(options.sessionId && { sessionId: options.sessionId }),\n ...(options.userId && { userId: options.userId }),\n ...(options.driverId && { driverId: options.driverId }),\n ...(options.metadata && { metadata: options.metadata }),\n ...(options.signal && { signal: options.signal }),\n awaitProviderSettlement: options.awaitProviderSettlement,\n ...(options.onTextDelta && { onTextDelta: options.onTextDelta }),\n ...(options.onExecutionEvent && { onExecutionEvent: options.onExecutionEvent }),\n ...(options.maxExecutionRounds !== undefined && {\n maxExecutionRounds: options.maxExecutionRounds,\n }),\n ...(options.maxSameToolInputs !== undefined && {\n maxSameToolInputs: options.maxSameToolInputs,\n }),\n ...(options.allowToolOnlyCompletion !== undefined && {\n allowToolOnlyCompletion: options.allowToolOnlyCompletion,\n }),\n ...(options.maxTokens !== undefined && { maxTokens: options.maxTokens }),\n ...(options.temperature !== undefined && { temperature: options.temperature }),\n ...(options.toolChoice !== undefined && { toolChoice: options.toolChoice }),\n ...(options.withholdHostedTools === true && { withholdHostedTools: true }),\n ...(options.ephemeralSystemContext !== undefined && {\n ephemeralSystemContext: options.ephemeralSystemContext,\n }),\n ...(options.traceContext !== undefined && { traceContext: options.traceContext }),\n };\n}\n\n/** Execute a single conversation turn. @internal */\nexport async function robotaRun(\n deps: IRobotaExecutionDeps,\n input: string,\n options: IRunOptions = {},\n configOverrides?: Partial<IAgentConfig>,\n): Promise<string> {\n try {\n deps.emitAgentEvent(AGENT_EVENTS.EXECUTION_START, {});\n\n deps.logger.debug('Starting Robota execution', {\n inputLength: input.length,\n conversationId: deps.conversationId,\n sessionId: options.sessionId || 'none',\n userId: options.userId || 'none',\n hasMetadata: !!options.metadata,\n });\n\n const messages = deps.getHistory();\n const executionConfig: IAgentConfig = { ...deps.config, ...configOverrides };\n\n const result = await deps\n .getExecutionService()\n .execute(input, messages, executionConfig, buildRunContext(deps, options));\n\n deps.logger.debug('Robota execution completed', {\n success: result.success,\n duration: result.duration,\n tokensUsed: result.tokensUsed,\n toolsExecuted: result.toolsExecuted,\n interrupted: result.interrupted,\n });\n\n if (result.interrupted) {\n deps.emitAgentEvent(AGENT_EVENTS.EXECUTION_COMPLETE, {});\n return result.response;\n }\n\n if (!result.success) {\n // CORE-020: every failed result must carry its error (SPEC invariant); a missing\n // error here is a contract violation, not a reason to fall through to the response.\n throw (\n result.error ??\n new Error(\n '[STRICT-POLICY] Failed execution result missing error field — every success:false result must carry error',\n )\n );\n }\n\n deps.emitAgentEvent(AGENT_EVENTS.EXECUTION_COMPLETE, {});\n return result.response;\n } catch (error) {\n deps.logger.error('Robota execution failed', {\n error: error instanceof Error ? error.message : String(error),\n conversationId: deps.conversationId,\n });\n deps.emitAgentEvent(AGENT_EVENTS.EXECUTION_ERROR, {\n error: error instanceof Error ? error.message : String(error),\n });\n throw error;\n }\n}\n\n/** Execute a streaming conversation turn. @internal */\nexport async function* robotaRunStream(\n deps: IRobotaExecutionDeps,\n input: string,\n options: IRunOptions = {},\n configOverrides?: Partial<IAgentConfig>,\n): AsyncGenerator<string, string, undefined> {\n try {\n deps.emitAgentEvent(AGENT_EVENTS.EXECUTION_START, {});\n\n deps.logger.debug('Starting Robota streaming execution', {\n inputLength: input.length,\n conversationId: deps.conversationId,\n sessionId: options.sessionId || 'none',\n userId: options.userId || 'none',\n hasMetadata: !!options.metadata,\n });\n\n const messages = deps.getHistory();\n const executionConfig: IAgentConfig = { ...deps.config, ...configOverrides };\n\n // CORE-018: the streaming context is built by the SAME buildRunContext as the round\n // path — the historical inline construction dropped signal/onTextDelta/onExecutionEvent\n // (and every run option added after it), making the public streaming API uncancellable.\n const stream = deps\n .getExecutionService()\n .executeStream(input, messages, executionConfig, buildRunContext(deps, options));\n\n // CORE-042: `yield*` rather than a manual loop -- it forwards `.return()` to the delegated\n // generator, which is what makes the adapter's abort-on-abandonment fire when a consumer breaks\n // out. It also carries the turn's final assistant text out as this generator's return value, so\n // `runStream` answers what `run` answers instead of making every caller re-accumulate deltas.\n const result = yield* stream;\n\n if (!result.success) {\n // CORE-020, and CORE-042 makes it the SAME rule on both entry points: `execute` reports a\n // failed turn by resolving with `success: false` and an error, and the caller throws it. The\n // streaming path used to reject from inside its own engine instead, which is how the two\n // could disagree about what a failed run looks like.\n throw (\n result.error ??\n new Error(\n '[STRICT-POLICY] Failed execution result missing error field — every success:false result must carry error',\n )\n );\n }\n return result.response;\n } catch (error) {\n deps.logger.error('Robota streaming execution failed', {\n error: error instanceof Error ? error.message : String(error),\n conversationId: deps.conversationId,\n });\n deps.emitAgentEvent(AGENT_EVENTS.EXECUTION_ERROR, {\n error: error instanceof Error ? error.message : String(error),\n });\n throw error;\n } finally {\n deps.emitAgentEvent(AGENT_EVENTS.EXECUTION_COMPLETE, {});\n }\n}\n","/**\n * Structured-output execution (CORE-015) for the Robota agent.\n *\n * Split from robota-execution.ts to keep each file under 300 lines: the plain turn and the\n * schema-enforced retry loop are separate responsibilities that happen to share an entry object.\n */\nimport { robotaRun, robotaRunStream } from './robota-execution';\nimport { parseStructuredResponseText } from '../schema/structured-output';\nimport { StructuredOutputError } from '../utils/errors';\n\nimport type { IRobotaExecutionDeps } from './robota-execution';\nimport type { IAgentConfig, IRunOptions } from '../interfaces/agent';\nimport type { TConfigValue } from '../interfaces/types';\nimport type { IStructuredOutputSpec } from '../schema/structured-output';\n\n/** Config override that routes the structured-output schema to the provider surface. */\nfunction structuredConfigOverrides(spec: IStructuredOutputSpec): Partial<IAgentConfig> {\n return {\n responseFormat: {\n type: 'json_schema',\n // The universal JSON-schema subset is plain JSON data; the interface merely\n // lacks an index signature, hence the widening cast.\n schema: spec.jsonSchema as unknown as Record<string, TConfigValue>,\n name: spec.name,\n },\n };\n}\n\nfunction buildRetryFeedbackInput(spec: IStructuredOutputSpec, issues: string[]): string {\n return [\n 'Your previous response did not match the required JSON schema.',\n 'Validation issues:',\n ...issues.map((issue) => `- ${issue}`),\n '',\n 'Respond with ONLY a JSON object (no prose, no code fences) matching this JSON schema:',\n JSON.stringify(spec.jsonSchema),\n ].join('\\n');\n}\n\n/**\n * Execute a schema-enforced structured turn (CORE-015). Each attempt is a full\n * conversation turn (history stays append-only); a validation failure feeds the\n * issues back as the next attempt's input, bounded by `outputRetries`.\n * @internal\n */\nexport async function robotaRunStructured(\n deps: IRobotaExecutionDeps,\n input: string,\n options: IRunOptions,\n spec: IStructuredOutputSpec,\n): Promise<unknown> {\n const maxAttempts = (options.outputRetries ?? 2) + 1;\n const overrides = structuredConfigOverrides(spec);\n let attemptInput = input;\n let lastIssues: string[] = [];\n\n for (let attempt = 1; attempt <= maxAttempts; attempt++) {\n const responseText = await robotaRun(deps, attemptInput, options, overrides);\n const outcome = validateStructuredText(spec, responseText);\n if (outcome.success) {\n return outcome.value;\n }\n lastIssues = outcome.issues;\n deps.logger.debug('Structured output validation failed', {\n attempt,\n maxAttempts,\n issues: lastIssues,\n });\n if (attempt < maxAttempts) {\n attemptInput = buildRetryFeedbackInput(spec, lastIssues);\n }\n }\n\n throw new StructuredOutputError(\n `response failed schema validation after ${maxAttempts} attempt(s)`,\n lastIssues,\n maxAttempts,\n );\n}\n\n/**\n * Streaming variant of the structured turn: text deltas stream as usual (retried\n * attempts stream too) and the validated object is the generator's return value.\n * @internal\n */\nexport async function* robotaRunStreamStructured(\n deps: IRobotaExecutionDeps,\n input: string,\n options: IRunOptions,\n spec: IStructuredOutputSpec,\n): AsyncGenerator<string, unknown, undefined> {\n const maxAttempts = (options.outputRetries ?? 2) + 1;\n const overrides = structuredConfigOverrides(spec);\n let attemptInput = input;\n let lastIssues: string[] = [];\n\n for (let attempt = 1; attempt <= maxAttempts; attempt++) {\n // CORE-042: validate the turn's FINAL assistant text, which `robotaRunStream` now returns --\n // not the concatenation of every yielded chunk. The concatenation carries round-1 prose and the\n // inter-round separator, so a tool-using structured turn could never parse. `yield*` is required\n // rather than a manual loop: it forwards `.return()`, without which a consumer breaking out of a\n // structured stream would leave the turn running.\n const finalText = yield* robotaRunStream(deps, attemptInput, options, overrides);\n const outcome = validateStructuredText(spec, finalText);\n if (outcome.success) {\n return outcome.value;\n }\n lastIssues = outcome.issues;\n deps.logger.debug('Structured output validation failed (stream)', {\n attempt,\n maxAttempts,\n issues: lastIssues,\n });\n if (attempt < maxAttempts) {\n attemptInput = buildRetryFeedbackInput(spec, lastIssues);\n }\n }\n\n throw new StructuredOutputError(\n `response failed schema validation after ${maxAttempts} attempt(s)`,\n lastIssues,\n maxAttempts,\n );\n}\n\nfunction validateStructuredText(\n spec: IStructuredOutputSpec,\n responseText: string,\n): { success: true; value: unknown } | { success: false; issues: string[] } {\n const parsed = parseStructuredResponseText(responseText);\n if (!parsed.success) {\n return { success: false, issues: [parsed.issue] };\n }\n const validated = spec.validate(parsed.value);\n if (validated.success) {\n return { success: true, value: validated.value };\n }\n return { success: false, issues: validated.issues };\n}\n","/**\n * History helper functions for the Robota agent.\n *\n * These standalone functions operate on ConversationHistory + a conversationId,\n * extracted from core/robota.ts to keep that file under 300 lines.\n */\nimport type { TUniversalMessage } from '../interfaces/agent';\nimport type { IHistoryEntry } from '../interfaces/messages';\nimport type { ConversationHistory } from '../managers/conversation-history-manager';\n\n/**\n * Return the current conversation messages as TUniversalMessage[].\n */\nexport function getHistory(\n conversationHistory: ConversationHistory,\n conversationId: string,\n): TUniversalMessage[] {\n const session = conversationHistory.getConversationStore(conversationId);\n return session.getMessages().map((msg) => ({\n id: msg.id,\n role: msg.role,\n content: msg.content,\n state: msg.state,\n timestamp: msg.timestamp,\n metadata: msg.metadata,\n ...(msg.role === 'assistant' && 'toolCalls' in msg ? { toolCalls: msg.toolCalls } : {}),\n ...(msg.role === 'tool' && 'toolCallId' in msg\n ? { toolCallId: (msg as { toolCallId: string }).toolCallId }\n : {}),\n ...(msg.role === 'tool' && 'name' in msg ? { name: (msg as { name: string }).name } : {}),\n })) as TUniversalMessage[];\n}\n\n/**\n * Return the full history timeline (IHistoryEntry[]) including events.\n */\nexport function getFullHistory(\n conversationHistory: ConversationHistory,\n conversationId: string,\n): IHistoryEntry[] {\n const store = conversationHistory.getConversationStore(conversationId);\n return store.getHistory();\n}\n\n/**\n * Add an event entry to history.\n */\nexport function addHistoryEntry(\n conversationHistory: ConversationHistory,\n conversationId: string,\n entry: IHistoryEntry,\n): void {\n const store = conversationHistory.getConversationStore(conversationId);\n store.addEntry(entry);\n}\n\n/**\n * Clear all messages in the conversation.\n */\nexport function clearHistory(\n conversationHistory: ConversationHistory,\n conversationId: string,\n): void {\n conversationHistory.getConversationStore(conversationId).clear();\n}\n\n/**\n * Inject a message into conversation history without triggering execution.\n */\nexport function injectMessage(\n conversationHistory: ConversationHistory,\n conversationId: string,\n role: 'user' | 'assistant' | 'system' | 'tool',\n content: string,\n options?: { toolCallId?: string; name?: string },\n): void {\n const session = conversationHistory.getConversationStore(conversationId);\n if (role === 'tool' && options?.toolCallId) {\n session.addToolMessageWithId(content, options.toolCallId, options.name ?? 'unknown');\n } else if (role === 'assistant') {\n session.addAssistantMessage(content, []);\n } else if (role === 'system') {\n session.addSystemMessage(content);\n } else {\n session.addUserMessage(content);\n }\n}\n\n/**\n * Inject a full TUniversalMessage into conversation history preserving all fields\n * (toolCalls, toolCallId, content=null, etc.) without triggering execution.\n * Used for session restore to correctly reconstruct tool_use+tool_result pairs.\n */\nexport function injectRawMessage(\n conversationHistory: ConversationHistory,\n conversationId: string,\n msg: TUniversalMessage,\n): void {\n conversationHistory.getConversationStore(conversationId).addMessage(msg);\n}\n","import { AbstractManager } from '../abstracts/abstract-manager';\nimport { ConfigurationError, ValidationError } from '../utils/errors';\nimport { logger } from '../utils/logger';\nimport { Validator } from '../utils/validation';\n\nimport type { IAIProviderManager } from '../interfaces/manager';\nimport type { IAIProvider } from '../interfaces/provider';\n\n/**\n * AI Provider Manager - manages AI provider instances\n * Manages registration, selection, and state of AI providers\n * Instance-based for isolated provider management\n * @internal\n */\nexport class AIProviders extends AbstractManager implements IAIProviderManager {\n private providers = new Map<string, IAIProvider>();\n private currentProvider: string | undefined;\n private currentModel: string | undefined;\n\n constructor() {\n // CORE-045: same as the tool registry — `doInitialize` only logs, so there is no asynchronous\n // state a caller could race, and refusing until the first run made `swapDefaultProvider()`\n // throw on every freshly constructed agent.\n super({ readyOnConstruction: true });\n }\n\n /**\n * Initialize the manager\n */\n protected async doInitialize(): Promise<void> {\n logger.debug('AIProviders initialized');\n }\n\n /**\n * Cleanup manager resources\n */\n protected async doDispose(): Promise<void> {\n // Close all providers\n for (const [name, provider] of this.providers) {\n try {\n if (provider.close) {\n await provider.close();\n }\n logger.debug(`Closed AI provider: ${name}`);\n } catch (error) {\n logger.warn(`Failed to close AI provider ${name}`, {\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n this.providers.clear();\n this.currentProvider = undefined;\n this.currentModel = undefined;\n\n logger.debug('AIProviders disposed');\n }\n\n /**\n * Register an AI provider\n */\n addProvider(name: string, provider: IAIProvider): void {\n this.ensureInitialized();\n\n // Validate provider name\n const nameValidation = Validator.validateProviderName(name);\n if (!nameValidation.isValid) {\n throw new ValidationError(`Invalid provider name: ${nameValidation.errors.join(', ')}`);\n }\n\n // Validate provider\n if (!provider || typeof provider !== 'object' || provider === null || Array.isArray(provider)) {\n throw new ValidationError('Provider must be a valid object instance');\n }\n\n if (!provider.name || typeof provider.name !== 'string') {\n throw new ValidationError('Provider must have a valid name');\n }\n\n if (typeof provider.chat !== 'function') {\n throw new ValidationError('Provider must have a chat method');\n }\n\n // Check for duplicate registration\n if (this.providers.has(name)) {\n logger.warn(`Provider \"${name}\" is already registered, overriding`, {\n providerName: name,\n existingProvider: this.providers.get(name)?.name,\n });\n }\n\n this.providers.set(name, provider);\n logger.debug(`AI provider \"${name}\" registered successfully`, {\n providerName: name,\n version: provider.version,\n supportsStreaming: typeof provider.chatStream === 'function',\n });\n }\n\n /**\n * Remove an AI provider\n */\n removeProvider(name: string): void {\n this.ensureInitialized();\n\n if (!this.providers.has(name)) {\n logger.warn(`Attempted to remove non-existent provider \"${name}\"`);\n return;\n }\n\n // Close provider if it has close method\n const provider = this.providers.get(name);\n if (provider?.close) {\n provider.close().catch((error: Error) => {\n logger.warn(`Failed to close provider ${name}`, {\n error: error.message,\n });\n });\n }\n\n this.providers.delete(name);\n\n // Clear current selection if this was the current provider\n if (this.currentProvider === name) {\n this.currentProvider = undefined;\n this.currentModel = undefined;\n logger.debug(`Cleared current provider selection after removing \"${name}\"`);\n }\n\n logger.debug(`AI provider \"${name}\" removed successfully`);\n }\n\n /**\n * Get registered provider by name\n */\n getProvider(name: string): IAIProvider | undefined {\n this.ensureInitialized();\n return this.providers.get(name);\n }\n\n /**\n * Get all registered providers\n */\n getProviders(): Record<string, IAIProvider> {\n this.ensureInitialized();\n return Object.fromEntries(this.providers);\n }\n\n /**\n * Set current provider and model\n */\n setCurrentProvider(name: string, model: string): void {\n this.ensureInitialized();\n\n // Validate provider exists\n const provider = this.providers.get(name);\n if (!provider) {\n throw new ConfigurationError(`Provider \"${name}\" is not registered`);\n }\n\n // Note: Model validation is now handled at runtime in ChatOptions\n // No pre-validation needed since models are provider-specific\n\n this.currentProvider = name;\n this.currentModel = model;\n\n logger.debug(`Current AI provider set to \"${name}\" with model \"${model}\"`);\n }\n\n /**\n * Get current provider and model\n */\n getCurrentProvider(): { provider: string; model: string } | undefined {\n this.ensureInitialized();\n\n if (!this.currentProvider || !this.currentModel) {\n return undefined;\n }\n\n return {\n provider: this.currentProvider,\n model: this.currentModel,\n };\n }\n\n /**\n * Check if provider is configured\n */\n isConfigured(): boolean {\n this.ensureInitialized();\n return !!(\n this.currentProvider &&\n this.currentModel &&\n this.providers.has(this.currentProvider)\n );\n }\n\n /**\n * Get current provider instance\n */\n getCurrentProviderInstance(): IAIProvider | undefined {\n if (!this.isConfigured() || !this.currentProvider) {\n return undefined;\n }\n\n return this.providers.get(this.currentProvider);\n }\n\n /**\n * Get provider names\n */\n getProviderNames(): string[] {\n this.ensureInitialized();\n return Array.from(this.providers.keys());\n }\n\n /**\n * Get providers by pattern\n */\n getProvidersByPattern(pattern: string | RegExp): Record<string, IAIProvider> {\n this.ensureInitialized();\n\n const regex = typeof pattern === 'string' ? new RegExp(pattern) : pattern;\n const result: Record<string, IAIProvider> = {};\n\n for (const [name, provider] of this.providers) {\n if (regex.test(name)) {\n result[name] = provider;\n }\n }\n\n return result;\n }\n\n /**\n * Check if provider supports streaming\n */\n supportsStreaming(providerName?: string): boolean {\n this.ensureInitialized();\n\n const name = providerName || this.currentProvider;\n if (!name) {\n return false;\n }\n\n const provider = this.providers.get(name);\n return !!(provider && typeof provider.chatStream === 'function');\n }\n\n /**\n * Get provider count\n */\n getProviderCount(): number {\n this.ensureInitialized();\n return this.providers.size;\n }\n}\n","import jsSHA from 'jssha';\n\nimport type { ICacheKey } from '../../interfaces/cache';\nimport type { TModelEffortSelection } from '../../interfaces/model-effort-capability';\nimport type { TUniversalMessage } from '../../interfaces/messages';\n\ninterface ICacheKeyOptions {\n temperature?: number;\n maxTokens?: number;\n /**\n * DATA-007/API-001: the SESSION's effort selection (e.g. `'low'`, `'high'`, `'auto'`) — never a\n * locally resolved effective value. The selection is the single source of truth for this key: two\n * requests with different selections never share an entry, and two with the same selection always\n * do, independent of what any particular provider or executor would resolve it to. `null`/\n * `undefined` both mean \"no selection was distinguished\" and hash identically; the caller normalizes\n * an absent selection to `'auto'` before passing it in.\n */\n effortCacheIdentity?: TModelEffortSelection | null;\n}\n\nexport class CacheKeyBuilder {\n build(\n messages: TUniversalMessage[],\n model: string,\n provider: string,\n options?: ICacheKeyOptions,\n ): ICacheKey {\n const serializable = messages.map((m) => ({\n role: m.role,\n content: m.content,\n }));\n\n const payload = JSON.stringify({\n messages: serializable,\n model,\n provider,\n temperature: options?.temperature,\n maxTokens: options?.maxTokens,\n effortCacheIdentity: options?.effortCacheIdentity ?? null,\n });\n\n return {\n hash: this.sha256(payload),\n model,\n provider,\n };\n }\n\n computeIntegrityHash(content: string): string {\n return this.sha256(content);\n }\n\n private sha256(input: string): string {\n const shaObj = new jsSHA('SHA-256', 'TEXT');\n shaObj.update(input);\n return shaObj.getHash('HEX');\n }\n}\n","import { CacheKeyBuilder } from './cache-key-builder';\nimport { CacheIntegrityError } from '../../utils/errors';\n\nimport type { ICacheEntry, ICacheStorage, ICacheStats } from '../../interfaces/cache';\n\ninterface IMemoryCacheStorageOptions {\n maxEntries: number;\n ttlMs: number;\n}\n\nexport class MemoryCacheStorage implements ICacheStorage {\n private readonly cache = new Map<string, ICacheEntry>();\n private readonly accessOrder: string[] = [];\n private readonly maxEntries: number;\n private readonly ttlMs: number;\n private readonly keyBuilder = new CacheKeyBuilder();\n private hits = 0;\n private misses = 0;\n\n constructor(options: IMemoryCacheStorageOptions) {\n this.maxEntries = options.maxEntries;\n this.ttlMs = options.ttlMs;\n }\n\n get(hash: string): ICacheEntry | undefined {\n const entry = this.cache.get(hash);\n\n if (!entry) {\n this.misses++;\n return undefined;\n }\n\n if (Date.now() - entry.timestamp > this.ttlMs) {\n this.cache.delete(hash);\n this.removeFromAccessOrder(hash);\n this.misses++;\n return undefined;\n }\n\n const expectedHash = this.keyBuilder.computeIntegrityHash(entry.response);\n if (entry.integrityHash !== expectedHash) {\n this.cache.delete(hash);\n this.removeFromAccessOrder(hash);\n throw new CacheIntegrityError(`Integrity check failed for cache entry ${hash}`, {\n hash,\n expected: expectedHash,\n actual: entry.integrityHash,\n });\n }\n\n this.touchAccessOrder(hash);\n this.hits++;\n return entry;\n }\n\n set(entry: ICacheEntry): void {\n const hash = entry.key.hash;\n\n if (!this.cache.has(hash) && this.cache.size >= this.maxEntries) {\n this.evictLRU();\n }\n\n this.cache.set(hash, entry);\n this.touchAccessOrder(hash);\n }\n\n delete(hash: string): boolean {\n if (this.cache.has(hash)) {\n this.cache.delete(hash);\n this.removeFromAccessOrder(hash);\n return true;\n }\n return false;\n }\n\n clear(): void {\n this.cache.clear();\n this.accessOrder.length = 0;\n this.hits = 0;\n this.misses = 0;\n }\n\n getStats(): ICacheStats {\n const total = this.hits + this.misses;\n return {\n hits: this.hits,\n misses: this.misses,\n entries: this.cache.size,\n hitRate: total === 0 ? 0 : this.hits / total,\n };\n }\n\n private touchAccessOrder(hash: string): void {\n this.removeFromAccessOrder(hash);\n this.accessOrder.push(hash);\n }\n\n private removeFromAccessOrder(hash: string): void {\n const idx = this.accessOrder.indexOf(hash);\n if (idx !== -1) {\n this.accessOrder.splice(idx, 1);\n }\n }\n\n private evictLRU(): void {\n const lruHash = this.accessOrder.shift();\n if (lruHash) {\n this.cache.delete(lruHash);\n }\n }\n}\n","import type { CacheKeyBuilder } from './cache-key-builder';\nimport type { ICacheStorage, ICacheStats } from '../../interfaces/cache';\nimport type { TModelEffortSelection } from '../../interfaces/model-effort-capability';\nimport type { TUniversalMessage } from '../../interfaces/messages';\n\n/**\n * DATA-007/API-001: `effortCacheIdentity` is the session's raw effort SELECTION (see\n * `CacheKeyBuilder`'s own doc for why it is the selection and not a resolved value). `lookup` and\n * `store` both funnel through the SAME `keyBuilder.build` call below, so they can never drift into\n * separate identity rules for the same request.\n */\ninterface IExecutionCacheOptions {\n temperature?: number;\n maxTokens?: number;\n effortCacheIdentity?: TModelEffortSelection | null;\n}\n\nexport class ExecutionCacheService {\n constructor(\n private readonly storage: ICacheStorage,\n private readonly keyBuilder: CacheKeyBuilder,\n ) {}\n\n lookup(\n messages: TUniversalMessage[],\n model: string,\n provider: string,\n options?: IExecutionCacheOptions,\n ): string | undefined {\n const key = this.keyBuilder.build(messages, model, provider, options);\n const entry = this.storage.get(key.hash);\n return entry ? entry.response : undefined;\n }\n\n store(\n messages: TUniversalMessage[],\n model: string,\n provider: string,\n response: string,\n options?: IExecutionCacheOptions,\n ): void {\n const key = this.keyBuilder.build(messages, model, provider, options);\n this.storage.set({\n key,\n response,\n timestamp: Date.now(),\n integrityHash: this.keyBuilder.computeIntegrityHash(response),\n });\n }\n\n getStats(): ICacheStats {\n return this.storage.getStats();\n }\n}\n","import type { IAgentConfig, IAssistantMessage, TExecutionEventCallback } from '../interfaces/agent';\nimport type { TUniversalMessage } from '../interfaces/messages';\nimport type { IProviderCapabilityTable } from '../interfaces/model-capability';\nimport type { IModelRef } from '../interfaces/role-model';\nimport type {\n IChatOptions,\n IToolSchema,\n TTextDeltaCallback,\n TToolChoice,\n} from '../interfaces/provider';\nimport type { IDeferredToolCatalog } from '../interfaces/tool-search';\nimport type { IRunTraceContext } from '../interfaces/trace-context';\nimport type { TMetadata } from '../interfaces/types';\n\n/** Preview length for general content truncation */\nexport const PREVIEW_LENGTH = 100;\n\n/** Preview length for content previews in event data */\nexport const CONTENT_PREVIEW_LENGTH = 200;\n\n/** Preview length for short previews in debug logs */\nexport const SHORT_PREVIEW_LENGTH = 50;\n\n/** Average words per minute for reading time estimation */\nexport const WORDS_PER_MINUTE = 200;\n\n/** Threshold for high complexity response length */\nexport const HIGH_COMPLEXITY_THRESHOLD = 1000;\n\n/** Threshold for medium complexity response length */\nexport const MEDIUM_COMPLEXITY_THRESHOLD = 300;\n\n/** Threshold for high input complexity character count */\nexport const HIGH_INPUT_COMPLEXITY_THRESHOLD = 200;\n\n/** Threshold for medium input complexity character count */\nexport const MEDIUM_INPUT_COMPLEXITY_THRESHOLD = 50;\n\n/** Number of recent messages to show in debug logs */\nexport const LAST_MESSAGES_SLICE = -5;\n\n/** Radix for random ID generation */\nexport const ID_RADIX = 36;\n\n/** Length of random portion of generated IDs */\nexport const ID_RANDOM_LENGTH = 9;\n\n/**\n * Provider and tools information resolved at the start of execution\n */\nexport interface IResolvedProviderInfo {\n provider: {\n chat: (messages: TUniversalMessage[], options: IChatOptions) => Promise<TUniversalMessage>;\n /**\n * PROV-006/PROV-008: what this provider's models can do, so the turn can ask whether THIS model\n * can do what the request needs. Structurally typed like `chat` above — this seam names what it\n * uses rather than depending on the whole provider interface.\n */\n capabilityTable?: () => IProviderCapabilityTable | undefined;\n /**\n * CORE-043: whether this provider is pointed at its vendor's own endpoint. Separate from the\n * table on purpose — a provider with no verified capability table must still be able to say it\n * is behind a gateway.\n */\n endpointIsVendorDefault?: () => boolean;\n /** Whether this provider can carry a trusted `traceparent`. See `IAIProvider`. */\n canPropagateTraceContext?: () => boolean;\n /** Where a request for a model goes first in a run. See `IAIProvider`. */\n resolveModelRoute?: (model: string, executionId?: string) => IModelRef;\n };\n currentInfo: { provider: string };\n aiProviderInfo: {\n providerName: string;\n model: string;\n temperature: number | undefined;\n maxTokens: number | undefined;\n };\n toolsInfo: Array<{\n name: string;\n description: string;\n parameters: string[];\n }>;\n /**\n * CLI-1990: the tools the model is offered, read PER ROUND — never a per-run snapshot. A deferred\n * tool loaded by a round-N tool call is on the wire in round N+1, which is what a search tool\n * needs and what the snapshot this replaced made impossible.\n */\n readAvailableTools: () => IToolSchema[];\n /** The catalog a forcing `toolChoice` loads through before the request is asserted (CLI-1990). */\n deferredTools: IDeferredToolCatalog;\n}\n\n/** Consecutive model rounds with an unavailable tool call before the loop force-summarizes. */\nexport const MAX_CONSECUTIVE_UNKNOWN_TOOL_FAILURE_ROUNDS = 2;\n\n/**\n * Mutable state tracked across execution rounds\n */\nexport interface IExecutionRoundState {\n toolsExecuted: string[];\n currentRound: number;\n runningAssistantCount: number;\n lastTrackedAssistantMessage: IAssistantMessage | undefined;\n /** Cumulative input tokens from API responses (authoritative, not estimated) */\n cumulativeInputTokens: number;\n /** Consecutive model rounds that produced at least one unavailable tool call. */\n consecutiveUnknownToolFailureRounds: number;\n /** Optional instruction used when forcing a final response after loop guard trips. */\n forcedSummaryInstruction?: string;\n /** Tracks how many times each (toolName, inputHash) pair has been called this turn. */\n sameToolInputCounts: Map<string, number>;\n /**\n * The ORIGINAL value a provider call threw, when a round ended in a provider failure.\n *\n * CORE-027: the failure used to survive only as `Request failed: ${message}` prose in the\n * conversation store, and the final result's `error` was rebuilt from that display string —\n * class, `code`, `category`, `recoverable`, stack and `cause` all destroyed by the round trip.\n * Carrying the thrown value itself is the only representation that loses nothing.\n */\n providerFailure?: unknown;\n}\n\n/**\n * Error with optional execution-specific properties\n */\nexport interface IExecutionError extends Error {\n executionId?: string;\n toolName?: string;\n error?: Error;\n}\n\n/**\n * Type guard to check if error has execution properties\n */\nexport function isExecutionError(error: Error): error is IExecutionError {\n return 'executionId' in error || 'toolName' in error;\n}\n\n/**\n * Execution context for service operations.\n * Applies Type Deduplication Rule: Use standardized metadata type\n */\nexport interface IExecutionContext {\n /**\n * PEER-007 (issue #1915): display attribution, stored on the user message so a transcript reader\n * can tell a peer's turn from the operator's. Never an authorization input (issue #1809).\n */\n driverId?: string;\n conversationId?: string;\n sessionId?: string;\n userId?: string;\n messages: TUniversalMessage[];\n config: IAgentConfig;\n metadata?: TMetadata;\n startTime: Date;\n executionId: string;\n /** AbortSignal for cancelling execution */\n signal?: AbortSignal;\n /** Join an aborted/timed-out provider call before completing; an uncooperative call may remain pending. */\n awaitProviderSettlement?: boolean;\n /** Per-run streaming text callback. */\n onTextDelta?: TTextDeltaCallback;\n /** Per-run replay event callback for provider/tool execution boundaries. */\n onExecutionEvent?: TExecutionEventCallback;\n /** Per-run model/tool round limit. Use 0 for no core round cap. */\n maxExecutionRounds?: number;\n /** Max times the same tool may be called with identical input before aborting. Unset = no limit. */\n maxSameToolInputs?: number;\n /** Tool-only turn ending counts as completion — skip the forced summary call (CORE-011). */\n allowToolOnlyCompletion?: boolean;\n /** Run-scoped max output tokens override — wins over `defaultModel.maxTokens` (CORE-016). */\n maxTokens?: number;\n /** Run-scoped temperature override — wins over `defaultModel.temperature` (CORE-016). */\n temperature?: number;\n /** Run-scoped tool-invocation directive — wins over `defaultModel.toolChoice` (CORE-017). */\n toolChoice?: TToolChoice;\n /** Leave provider-hosted tools out of this run's requests. See `IRunOptions`. */\n withholdHostedTools?: boolean;\n /**\n * Run-scoped EPHEMERAL system context (SELFHOST-008 P3) — a transient system-role block added to the\n * provider request for this run only, NEVER written to the conversation store. See `IRunOptions`.\n */\n ephemeralSystemContext?: string;\n /** Run-scoped trusted trace context for invoked provider calls. See `IRunOptions`. */\n traceContext?: IRunTraceContext;\n}\n\n/**\n * Execution result containing the response and execution metadata\n */\nexport interface ICoreExecutionResult {\n response: string;\n messages: TUniversalMessage[];\n executionId: string;\n duration: number;\n tokensUsed?: number;\n toolsExecuted: string[];\n success: boolean;\n error?: Error;\n /** Whether execution was interrupted by abort */\n interrupted?: boolean;\n}\n\n/**\n * History statistics type returned by ConversationHistory.getStats()\n */\nexport interface IHistoryStats {\n totalConversations: number;\n conversationIds: string[];\n totalMessages: number;\n}\n\n/**\n * Plugin statistics type - using a simpler structure\n */\nexport interface IExecutionServicePluginStats {\n pluginCount: number;\n pluginNames: string[];\n historyStats: IHistoryStats;\n}\n\n/**\n * Count words in text without allocating an intermediate array.\n * Avoids the cost of split(/\\s+/) in hot paths.\n */\nexport function countWords(text: string): number {\n let count = 0;\n let inWord = false;\n for (let i = 0; i < text.length; i++) {\n const isSpace = text[i] === ' ' || text[i] === '\\t' || text[i] === '\\n' || text[i] === '\\r';\n if (!isSpace && !inWord) {\n count++;\n inWord = true;\n } else if (isSpace) {\n inWord = false;\n }\n }\n return count;\n}\n","import { EXECUTION_EVENTS } from './execution-constants';\nimport {\n countWords,\n PREVIEW_LENGTH,\n CONTENT_PREVIEW_LENGTH,\n WORDS_PER_MINUTE,\n HIGH_COMPLEXITY_THRESHOLD,\n MEDIUM_COMPLEXITY_THRESHOLD,\n HIGH_INPUT_COMPLEXITY_THRESHOLD,\n MEDIUM_INPUT_COMPLEXITY_THRESHOLD,\n} from './execution-types';\nimport { bindWithOwnerPath } from '../event-service/index';\n\nimport type { IExecutionEventEmitterSurface } from './execution-event-emitter-surface';\nimport type { IResolvedProviderInfo } from './execution-types';\nimport type { IAgentConfig } from '../interfaces/agent';\nimport type { IEventService, IEventContext } from '../interfaces/event-service';\nimport type { TUniversalMessage } from '../interfaces/messages';\n\n/**\n * Emit the EXECUTION START event.\n * Extracted from ExecutionEventEmitter to reduce file size.\n */\nexport function emitExecutionStartEvent(\n emitter: IExecutionEventEmitterSurface,\n input: string,\n config: IAgentConfig,\n messages: TUniversalMessage[],\n resolved: IResolvedProviderInfo,\n conversationId: string,\n executionId: string,\n): void {\n emitter.emitExecution(\n EXECUTION_EVENTS.START,\n {\n parameters: {\n input,\n agentConfiguration: resolved.aiProviderInfo,\n availableTools: resolved.toolsInfo,\n toolCount: resolved.toolsInfo.length,\n hasTools: resolved.toolsInfo.length > 0,\n systemMessage: config.systemMessage,\n provider: config.defaultModel.provider,\n model: config.defaultModel.model,\n temperature: config.defaultModel.temperature,\n maxTokens: config.defaultModel.maxTokens,\n },\n metadata: {\n method: 'execute',\n inputLength: input.length,\n messageCount: messages.length,\n aiProvider: resolved.aiProviderInfo.providerName,\n model: resolved.aiProviderInfo.model,\n toolsAvailable: resolved.toolsInfo.map((t) => t.name),\n agentCapabilities: {\n canUseTools: resolved.toolsInfo.length > 0,\n supportedActions: resolved.toolsInfo.map((t) => t.name),\n },\n },\n },\n conversationId,\n executionId,\n );\n}\n\n/**\n * Emit the USER_MESSAGE event.\n * Extracted from ExecutionEventEmitter to reduce file size.\n */\nexport function emitUserMessageEvent(\n emitter: IExecutionEventEmitterSurface,\n input: string,\n conversationId: string,\n executionId: string,\n): void {\n emitter.emitExecution(\n EXECUTION_EVENTS.USER_MESSAGE,\n {\n parameters: {\n input,\n userPrompt: input,\n userMessageContent: input,\n messageLength: input.length,\n wordCount: countWords(input),\n characterCount: input.length,\n },\n metadata: {\n messageRole: 'user',\n inputLength: input.length,\n messageType: 'user_message',\n hasQuestions: input.includes('?'),\n containsUrgency: /urgent|asap|critical|emergency/i.test(input),\n estimatedComplexity:\n input.length > HIGH_INPUT_COMPLEXITY_THRESHOLD\n ? 'high'\n : input.length > MEDIUM_INPUT_COMPLEXITY_THRESHOLD\n ? 'medium'\n : 'low',\n },\n },\n conversationId,\n executionId,\n );\n}\n\n/**\n * Emit the ASSISTANT_MESSAGE_COMPLETE event.\n * Extracted from ExecutionEventEmitter to reduce file size.\n */\nexport function emitAssistantMessageComplete(\n emitter: IExecutionEventEmitterSurface,\n baseEventService: IEventService,\n assistantResponse: { content?: string | null; timestamp?: Date },\n executionId: string,\n currentRound: number,\n conversationId: string,\n thinkingNodeId: string,\n previousThinkingNodeId: string | undefined,\n): void {\n if (typeof assistantResponse.content !== 'string' || assistantResponse.content.length === 0) {\n throw new Error('[EXECUTION] assistant response must have content or tool calls');\n }\n if (!(assistantResponse.timestamp instanceof Date)) {\n throw new Error('[EXECUTION] assistant response timestamp is required');\n }\n const responseContent = assistantResponse.content;\n const responseStartTime = assistantResponse.timestamp;\n const responseDuration = new Date().getTime() - responseStartTime.getTime();\n\n emitter.emitWithContext(\n EXECUTION_EVENTS.ASSISTANT_MESSAGE_COMPLETE,\n {\n parameters: {\n assistantMessage: responseContent,\n responseLength: responseContent.length,\n wordCount: countWords(responseContent),\n responseTime: responseDuration,\n contentPreview:\n responseContent.length > CONTENT_PREVIEW_LENGTH\n ? responseContent.substring(0, CONTENT_PREVIEW_LENGTH) + '...'\n : responseContent,\n },\n result: {\n success: true,\n data: responseContent.substring(0, PREVIEW_LENGTH) + '...',\n fullResponse: responseContent,\n responseMetrics: {\n length: responseContent.length,\n estimatedReadTime: Math.ceil(countWords(responseContent) / WORDS_PER_MINUTE),\n hasCodeBlocks: /```/.test(responseContent),\n hasLinks: /https?:\\/\\//.test(responseContent),\n complexity:\n responseContent.length > HIGH_COMPLEXITY_THRESHOLD\n ? 'high'\n : responseContent.length > MEDIUM_COMPLEXITY_THRESHOLD\n ? 'medium'\n : 'low',\n },\n },\n metadata: {\n executionId,\n round: currentRound,\n completed: true,\n reason: 'no_tool_calls',\n responseCharacteristics: {\n hasQuestions: responseContent.includes('?'),\n isError: /error|fail|wrong/i.test(responseContent),\n isComplete: /complete|done|finish/i.test(responseContent),\n containsNumbers: /\\d/.test(responseContent),\n },\n },\n },\n () =>\n emitter.buildResponseOwnerContext(\n conversationId,\n executionId,\n thinkingNodeId,\n previousThinkingNodeId,\n ),\n (ctx) => {\n if (!ctx.ownerType || !ctx.ownerId) {\n throw new Error('[EXECUTION] Missing owner context for response event');\n }\n return bindWithOwnerPath(baseEventService, {\n ownerType: ctx.ownerType,\n ownerId: ctx.ownerId,\n ownerPath: ctx.ownerPath,\n });\n },\n );\n}\n\n/**\n * Emit TOOL_RESULTS_READY and TOOL_RESULTS_TO_LLM events.\n * Extracted from ExecutionEventEmitter to reduce file size.\n */\nexport function emitToolResultsEvents(\n emitter: IExecutionEventEmitterSurface,\n baseEventService: IEventService,\n assistantToolCalls: Array<{ id?: string }>,\n toolSummary: { results: Array<{ toolName?: string }> },\n toolsExecuted: string[],\n conversationId: string,\n executionId: string,\n currentRound: number,\n thinkingNodeId: string,\n previousThinkingNodeId: string | undefined,\n): void {\n const toolCallIds = assistantToolCalls.map((toolCall) => {\n if (!toolCall.id || toolCall.id.length === 0) {\n throw new Error('[EXECUTION] Tool call missing id for tool results ready payload');\n }\n return toolCall.id;\n });\n if (toolCallIds.length === 0) {\n throw new Error('[EXECUTION] Tool results ready requires toolCallIds');\n }\n\n const buildCtx = (): IEventContext =>\n emitter.buildThinkingOwnerContext(\n conversationId,\n executionId,\n thinkingNodeId,\n previousThinkingNodeId,\n );\n const resolveService = (ctx: IEventContext): IEventService => {\n if (!ctx.ownerType || !ctx.ownerId) {\n throw new Error('[EXECUTION] Missing owner context for tool results event');\n }\n return bindWithOwnerPath(baseEventService, {\n ownerType: ctx.ownerType,\n ownerId: ctx.ownerId,\n ownerPath: ctx.ownerPath,\n });\n };\n\n emitter.emitWithContext(\n EXECUTION_EVENTS.TOOL_RESULTS_READY,\n {\n parameters: { toolCallIds, round: currentRound },\n metadata: { round: currentRound },\n },\n buildCtx,\n resolveService,\n );\n\n emitter.emitWithContext(\n EXECUTION_EVENTS.TOOL_RESULTS_TO_LLM,\n {\n parameters: {\n toolsExecuted: toolsExecuted.length,\n round: currentRound,\n },\n metadata: {\n toolsExecuted: toolSummary.results.map((r) => {\n if (!r.toolName || (r.toolName as string).length === 0) {\n throw new Error('[EXECUTION] Tool result missing toolName');\n }\n return r.toolName;\n }),\n round: currentRound,\n },\n },\n buildCtx,\n resolveService,\n );\n}\n","import { ValidationError } from '../utils/errors';\nimport { randomId } from '../utils/random-id.js';\nimport { spanIdFromMintedId, toolTraceContextFor, traceEnvFor } from '../utils/trace-context';\n\nimport { ARGUMENT_DECODE_ERROR_CODE, TOOL_EVENTS } from './tool-execution-constants';\n\nimport type { IToolExecutionBatchContext } from './tool-execution-batch-types';\nimport type { IToolEventData } from '../interfaces/event-service';\nimport type { IToolExecutionRequest } from '../interfaces/service';\nimport type {\n IToolExecutionResult,\n IToolExecutionContext,\n TToolParameters,\n} from '../interfaces/tool';\nimport type { ILogger } from '../utils/logger';\n\nconst MIN_PARALLEL_CONCURRENCY = 1;\n\n/**\n * Shared interface for the minimal ToolExecutionService surface needed by batch helpers.\n */\nexport interface IToolExecutor {\n executeTool(\n toolName: string,\n parameters: TToolParameters,\n context?: IToolExecutionContext,\n ): Promise<IToolExecutionResult>;\n}\n\ninterface IParallelExecutionState {\n resultsByIndex: Array<IToolExecutionResult | undefined>;\n errorsByIndex: Array<Error | undefined>;\n nextRequestIndex: number;\n}\n\nfunction requireExecutionRequestFields(request: {\n executionId?: string;\n ownerType?: string;\n ownerId?: string;\n}): { executionId: string; ownerType: string; ownerId: string } {\n if (!request.executionId) {\n throw new ValidationError(\n '[STRICT-POLICY][EMITTER-CONTRACT] Tool execution request missing executionId',\n );\n }\n if (!request.ownerType) {\n throw new ValidationError(\n `[STRICT-POLICY][EMITTER-CONTRACT] Tool execution request missing ownerType: executionId=${request.executionId}`,\n );\n }\n if (!request.ownerId) {\n throw new ValidationError(\n `[STRICT-POLICY][EMITTER-CONTRACT] Tool execution request missing ownerId: executionId=${request.executionId}`,\n );\n }\n return {\n executionId: request.executionId,\n ownerType: request.ownerType,\n ownerId: request.ownerId,\n };\n}\n\nfunction createExecutionContext(\n request: IToolExecutionRequest,\n signal?: AbortSignal,\n): IToolExecutionContext {\n const required = requireExecutionRequestFields(request);\n // Minted per body, never taken from the vendor's tool call ID, which may repeat and is not hex.\n const toolBodyId = randomId();\n const outboundTraceContext = request.traceContext\n ? toolTraceContextFor(request.traceContext, toolBodyId)\n : undefined;\n const shellTraceEnv = traceEnvFor('shell', request.traceContext, spanIdFromMintedId(toolBodyId));\n const hookTraceEnv = request.traceContext\n ? traceEnvFor('hooks', request.traceContext, request.traceContext.parentSpanId)\n : undefined;\n return {\n toolName: request.toolName,\n parameters: request.parameters,\n ...(signal ? { signal } : {}),\n executionId: required.executionId,\n ownerType: required.ownerType,\n ownerId: required.ownerId,\n ownerPath: request.ownerPath,\n metadata: request.metadata,\n eventService: request.eventService,\n baseEventService: request.baseEventService,\n ...(request.ask ? { ask: request.ask } : {}),\n ...(request.deferredTools ? { deferredTools: request.deferredTools } : {}),\n toolBodyId,\n ...(outboundTraceContext ? { outboundTraceContext } : {}),\n ...(shellTraceEnv ? { shellTraceEnv } : {}),\n ...(hookTraceEnv ? { hookTraceEnv } : {}),\n };\n}\n\nfunction createInterruptedResult(request: IToolExecutionRequest): IToolExecutionResult {\n return {\n toolName: request.toolName,\n executionId: request.executionId ?? '',\n success: false,\n error: 'Execution interrupted by user',\n result: null,\n };\n}\n\nfunction createErrorResult(request: IToolExecutionRequest, error: Error): IToolExecutionResult {\n return {\n toolName: request.toolName,\n result: null,\n success: false,\n error: error.message,\n executionId: request.executionId,\n };\n}\n\n/**\n * Issue #2875 (follow-up to #2078): a request whose arguments failed to decode is refused HERE,\n * the same way an unknown tool name is refused inside `ToolExecutionService.executeTool` — as a\n * normal failed result for this one request, never as a thrown error that would abort the batch.\n * `executor.executeTool` is never called, so the tool never sees the placeholder `parameters`.\n *\n * Emits `TOOL_EVENTS.CALL_ERROR` on the request's own event service, the same way the unknown-tool\n * path does — a listener watching per-call events must see EVERY call fail or succeed exactly once,\n * decode failures included, not just the ones that reached the tool.\n */\nfunction createArgumentDecodeErrorResult(request: IToolExecutionRequest): IToolExecutionResult {\n const error = request.argumentDecodeError;\n if (request.eventService && error !== undefined) {\n const errorEvent: IToolEventData = {\n timestamp: new Date(),\n toolName: request.toolName,\n error,\n };\n request.eventService.emit(TOOL_EVENTS.CALL_ERROR, errorEvent);\n }\n return {\n toolName: request.toolName,\n result: null,\n success: false,\n error,\n executionId: request.executionId,\n metadata: { errorCode: ARGUMENT_DECODE_ERROR_CODE, requestedTool: request.toolName },\n };\n}\n\nfunction createToolFailureError(result: IToolExecutionResult): Error {\n return new Error(\n `Tool execution failed: toolName=${String(result.toolName)} executionId=${String(result.executionId)} error=${String(result.error || 'Unknown error')}`,\n );\n}\n\nfunction isDefinedResult(result: IToolExecutionResult | undefined): result is IToolExecutionResult {\n return result !== undefined;\n}\n\nfunction isDefinedError(error: Error | undefined): error is Error {\n return error !== undefined;\n}\n\nfunction resolveMaxConcurrency(requestCount: number, maxConcurrency?: number): number {\n if (requestCount === 0) {\n return 0;\n }\n if (maxConcurrency === undefined || !Number.isFinite(maxConcurrency)) {\n return requestCount;\n }\n\n const normalized = Math.floor(maxConcurrency);\n if (normalized < MIN_PARALLEL_CONCURRENCY) {\n return MIN_PARALLEL_CONCURRENCY;\n }\n\n return Math.min(normalized, requestCount);\n}\n\nasync function executeParallelRequest(\n batchContext: IToolExecutionBatchContext,\n executor: IToolExecutor,\n state: IParallelExecutionState,\n index: number,\n): Promise<void> {\n const request = batchContext.requests[index];\n if (!request) {\n return;\n }\n\n try {\n const result = batchContext.signal?.aborted\n ? createInterruptedResult(request)\n : request.argumentDecodeError !== undefined\n ? createArgumentDecodeErrorResult(request)\n : await executor.executeTool(\n request.toolName,\n request.parameters,\n createExecutionContext(request, batchContext.signal),\n );\n state.resultsByIndex[index] = result;\n if (!result.success) {\n state.errorsByIndex[index] = createToolFailureError(result);\n }\n } catch (error) {\n const err = error instanceof Error ? error : new Error(String(error));\n state.errorsByIndex[index] = err;\n state.resultsByIndex[index] = createErrorResult(request, err);\n }\n}\n\nasync function runParallelWorker(\n batchContext: IToolExecutionBatchContext,\n executor: IToolExecutor,\n state: IParallelExecutionState,\n): Promise<void> {\n while (state.nextRequestIndex < batchContext.requests.length) {\n const currentIndex = state.nextRequestIndex;\n state.nextRequestIndex += 1;\n await executeParallelRequest(batchContext, executor, state, currentIndex);\n }\n}\n\n/**\n * Execute tool requests in parallel with a bounded worker pool.\n * Preserves a result entry for every request (SSOT for toolCallId → result mapping).\n */\nasync function executeParallel(\n batchContext: IToolExecutionBatchContext,\n executor: IToolExecutor,\n): Promise<{ results: IToolExecutionResult[]; errors: Error[] }> {\n const state: IParallelExecutionState = {\n resultsByIndex: new Array(batchContext.requests.length),\n errorsByIndex: new Array(batchContext.requests.length),\n nextRequestIndex: 0,\n };\n const concurrency = resolveMaxConcurrency(\n batchContext.requests.length,\n batchContext.maxConcurrency,\n );\n\n const workers = Array.from({ length: concurrency }, () =>\n runParallelWorker(batchContext, executor, state),\n );\n await Promise.all(workers);\n\n const results = state.resultsByIndex.filter(isDefinedResult);\n const errors = state.errorsByIndex.filter(isDefinedError);\n\n if (errors.length > 0 && !batchContext.continueOnError) {\n throw errors[0];\n }\n\n return { results, errors };\n}\n\n/**\n * Execute tool requests sequentially, stopping on first error unless continueOnError is set.\n */\nasync function executeSequential(\n batchContext: IToolExecutionBatchContext,\n executor: IToolExecutor,\n): Promise<{ results: IToolExecutionResult[]; errors: Error[] }> {\n const results: IToolExecutionResult[] = [];\n const errors: Error[] = [];\n\n for (const request of batchContext.requests) {\n try {\n const result = batchContext.signal?.aborted\n ? createInterruptedResult(request)\n : request.argumentDecodeError !== undefined\n ? createArgumentDecodeErrorResult(request)\n : await executor.executeTool(\n request.toolName,\n request.parameters,\n createExecutionContext(request, batchContext.signal),\n );\n results.push(result);\n if (!result.success) {\n errors.push(createToolFailureError(result));\n }\n if (!result.success && !batchContext.continueOnError) {\n break;\n }\n } catch (error) {\n const err = error instanceof Error ? error : new Error(String(error));\n errors.push(err);\n if (!batchContext.continueOnError) {\n break;\n }\n }\n }\n\n return { results, errors };\n}\n\n/**\n * Execute a batch of tool requests, dispatching to parallel or sequential strategy.\n */\nexport async function executeBatch(\n batchContext: IToolExecutionBatchContext,\n executor: IToolExecutor,\n logger: ILogger,\n): Promise<{ results: IToolExecutionResult[]; errors: Error[] }> {\n logger.debug(`Executing ${batchContext.requests.length} tools in ${batchContext.mode} mode`);\n\n if (batchContext.mode === 'parallel') {\n return executeParallel(batchContext, executor);\n }\n return executeSequential(batchContext, executor);\n}\n","import { executeBatch } from './tool-execution-batch';\nimport { TOOL_SEARCH_TOOL_NAME } from '../interfaces/tool-search';\nimport { ValidationError } from '../utils/errors';\nimport { SilentLogger, type ILogger } from '../utils/logger';\n\nimport type { IOwnerPathSegment, IToolEventData } from '../interfaces/event-service';\nimport type { IUserInteraction } from '../interfaces/interaction';\nimport type { IToolManager } from '../interfaces/manager';\nimport type { IToolExecutionRequest } from '../interfaces/service';\nimport type {\n IToolExecutionContext,\n IToolExecutionResult,\n TToolParameters,\n TToolMetadata,\n} from '../interfaces/tool';\nimport type { IDeferredToolCatalog } from '../interfaces/tool-search';\n\nexport type { IToolExecutionBatchContext } from './tool-execution-batch-types';\nimport type { IToolExecutionBatchContext } from './tool-execution-batch-types';\n\nexport {\n TOOL_EVENTS,\n TOOL_EVENT_PREFIX,\n UNKNOWN_TOOL_ERROR_CODE,\n ARGUMENT_DECODE_ERROR_CODE,\n} from './tool-execution-constants';\nimport { TOOL_EVENTS, UNKNOWN_TOOL_ERROR_CODE } from './tool-execution-constants';\n\n/**\n * Simplified ToolExecutionService\n * Focuses only on core tool execution without complex hierarchy tracking\n */\nexport class ToolExecutionService {\n private tools: IToolManager;\n private logger: ILogger;\n private askHandler?: IUserInteraction['ask'];\n /** CLI-1990: the narrow port a search tool loads through — no tool ever holds the manager. */\n private readonly deferredToolCatalog: IDeferredToolCatalog;\n\n constructor(tools: IToolManager, logger: ILogger = SilentLogger) {\n this.tools = tools;\n this.logger = logger;\n this.deferredToolCatalog = {\n listDeferredTools: () => this.tools.listDeferredTools(),\n loadDeferredTools: (names) => this.tools.loadDeferredTools(names),\n };\n }\n\n /**\n * Session-scoped \"ask the user\" port (CMD-005). When set, every execution request built by\n * `createExecutionRequestsWithContext` carries it into the tool's `IToolExecutionContext.ask`.\n */\n setAskHandler(ask: IUserInteraction['ask'] | undefined): void {\n this.askHandler = ask;\n }\n\n /**\n * Execute a single tool\n * @param toolName - Name of the tool to execute\n * @param parameters - Tool parameters\n * @param context - Optional execution context\n * @returns Promise resolving to tool execution result\n */\n async executeTool(\n toolName: string,\n parameters: TToolParameters,\n context?: IToolExecutionContext,\n catalog: 'offered' | 'registered' = 'offered',\n ): Promise<IToolExecutionResult> {\n this.logger.debug(`Executing tool: ${toolName}`);\n\n try {\n if (!context?.executionId) {\n throw new ValidationError(\n 'ToolExecutionService requires executionId (toolCallId) in ToolExecutionContext',\n );\n }\n\n // CLI-1990: a deferred tool the model has not loaded is refused like an unknown one — the model\n // was never shown its schema — and the remedy names the tool that loads it, so the two rounds\n // before the unknown-tool loop guard force-summarises are recoverable rather than fatal.\n context.signal?.throwIfAborted();\n const withheld =\n catalog === 'offered' &&\n this.tools.getToolSchema(toolName)?.deferLoading === true &&\n !this.tools.isToolOffered(toolName);\n if (!this.tools.hasTool(toolName) || withheld) {\n const availableTools = (\n catalog === 'registered' ? this.tools.getTools() : this.tools.getOfferedTools()\n )\n .map((tool) => tool.name)\n .sort();\n const error = formatUnknownToolError(toolName, availableTools, withheld);\n const eventService = context.eventService;\n if (eventService) {\n const errorEvent: IToolEventData = {\n timestamp: new Date(),\n toolName,\n error,\n };\n eventService.emit(TOOL_EVENTS.CALL_ERROR, errorEvent);\n }\n this.logger.warn('Tool call skipped because requested tool is not registered', {\n toolName,\n availableTools,\n });\n return {\n success: false,\n error,\n toolName,\n executionId: context.executionId,\n metadata: {\n errorCode: UNKNOWN_TOOL_ERROR_CODE,\n requestedTool: toolName,\n availableTools,\n },\n };\n }\n\n const eventService = context.eventService;\n if (eventService) {\n const startEvent: IToolEventData = {\n timestamp: new Date(),\n toolName,\n parameters,\n };\n eventService.emit(TOOL_EVENTS.CALL_START, startEvent);\n }\n\n // Normalize execution context without duplicating keys from the spread.\n const { toolName: _toolName, parameters: _parameters, ...restContext } = context;\n void _toolName;\n void _parameters;\n\n const executionContext: IToolExecutionContext = {\n ...restContext,\n deferredTools: this.deferredToolCatalog,\n toolName,\n parameters,\n executionId: context.executionId,\n };\n\n // Execute the tool with full context\n // Context already contains all necessary information including tool call ID\n const result = await this.tools.executeTool(toolName, parameters, executionContext);\n\n this.logger.debug(`Tool execution completed: ${toolName}`);\n\n if (eventService) {\n const completeEvent: IToolEventData = {\n timestamp: new Date(),\n toolName,\n result,\n };\n eventService.emit(TOOL_EVENTS.CALL_COMPLETE, completeEvent);\n eventService.emit(TOOL_EVENTS.CALL_RESPONSE_READY, completeEvent);\n }\n\n return {\n success: true,\n result,\n toolName,\n executionId: executionContext.executionId!,\n };\n } catch (error) {\n this.logger.error(`Tool execution failed: ${toolName}`);\n\n const toolError = error instanceof Error ? error : new Error(String(error));\n\n const eventService = context?.eventService;\n if (eventService && context?.executionId) {\n const errorEvent: IToolEventData = {\n timestamp: new Date(),\n toolName,\n error: toolError.message,\n };\n eventService.emit(TOOL_EVENTS.CALL_ERROR, errorEvent);\n }\n\n return {\n success: false,\n error: toolError.message,\n toolName,\n executionId: context?.executionId,\n };\n }\n }\n\n /**\n * Create execution requests with context (for ExecutionService compatibility)\n * @param toolCalls - Array of tool calls from AI provider\n * @param context - Execution context\n * @returns Array of tool execution requests\n */\n createExecutionRequestsWithContext(\n toolCalls: Array<{ id: string; function: { name: string; arguments: string } }>,\n context: {\n ownerPathBase: IOwnerPathSegment[];\n metadataFactory?: (toolCall: {\n id: string;\n function: { name: string; arguments: string };\n }) => TToolMetadata | undefined;\n },\n ): IToolExecutionRequest[] {\n return toolCalls.map((toolCall) => {\n const decoded = decodeToolCallArguments(\n toolCall.id,\n toolCall.function.name,\n toolCall.function.arguments,\n );\n return {\n toolName: toolCall.function.name,\n // Issue #2875 (follow-up to #2078): a decode failure carries a placeholder here — the\n // batch executor checks `argumentDecodeError` and returns a failed result WITHOUT ever\n // passing `parameters` to the tool.\n parameters: decoded.ok ? decoded.parameters : ({} as TToolParameters),\n executionId: toolCall.id,\n ownerType: 'tool',\n ownerId: toolCall.id,\n ownerPath: [...context.ownerPathBase, { type: 'tool', id: toolCall.id }],\n metadata: context.metadataFactory ? context.metadataFactory(toolCall) : undefined,\n ...(this.askHandler ? { ask: this.askHandler } : {}),\n deferredTools: this.deferredToolCatalog,\n ...(decoded.ok ? {} : { argumentDecodeError: decoded.error }),\n };\n });\n }\n\n /**\n * Execute tools from batch context (for ExecutionService compatibility)\n * @param batchContext - Batch execution context\n * @returns Promise resolving to tool execution summary\n */\n async executeTools(\n batchContext: IToolExecutionBatchContext,\n ): Promise<{ results: IToolExecutionResult[]; errors: Error[] }> {\n return executeBatch(batchContext, this, this.logger);\n }\n}\n\ntype TDecodedToolCallArguments =\n | { ok: true; parameters: TToolParameters }\n | { ok: false; error: string };\n\n/**\n * Issue #2078: `TToolParameters` is a record contract, so a syntactically valid JSON body whose root\n * is `null`, a scalar, or an array is refused HERE. The parameter validator downstream enumerates\n * fields with `in` and assumes a non-null object; a bare cast would let those roots reach it.\n *\n * Issue #2875 (follow-up to #2078): this returns a result instead of throwing. One provider batch\n * can name several tool calls; a malformed call is THIS call's failure, not a reason to abort request\n * construction for the rest of the batch — the caller turns a decode failure into the same per-call\n * failed outcome an unknown tool name already gets, so every call still gets a result.\n */\nfunction decodeToolCallArguments(\n callId: string,\n toolName: string,\n raw: string,\n): TDecodedToolCallArguments {\n let decoded: unknown;\n try {\n decoded = JSON.parse(raw);\n } catch {\n return {\n ok: false,\n error: `Failed to parse arguments for tool \"${toolName}\" (call ${callId}): invalid JSON`,\n };\n }\n if (decoded === null || typeof decoded !== 'object' || Array.isArray(decoded)) {\n const root =\n decoded === null ? 'null' : Array.isArray(decoded) ? 'an array' : `a ${typeof decoded}`;\n return {\n ok: false,\n error: `Failed to parse arguments for tool \"${toolName}\" (call ${callId}): expected a JSON object at the root, got ${root}`,\n };\n }\n return { ok: true, parameters: decoded as TToolParameters };\n}\n\nfunction formatUnknownToolError(\n toolName: string,\n availableTools: string[],\n withheld: boolean,\n): string {\n const available =\n availableTools.length > 0 ? availableTools.join(', ') : 'no registered tools are available';\n if (withheld) {\n return (\n `Tool \"${toolName}\" is registered but deferred and not yet loaded, so the tool call was not executed. ` +\n `Call ${TOOL_SEARCH_TOOL_NAME} with names: [\"${toolName}\"] to load it, then call it again. ` +\n `Available tools: ${available}.`\n );\n }\n return `Tool \"${toolName}\" is not registered, so the tool call was not executed. Available tools: ${available}.`;\n}\n","import { EXECUTION_EVENT_PREFIX } from './execution-constants';\nimport { TOOL_EVENT_PREFIX } from './tool-execution-service';\n\nimport type { TExecutionEventCallback, TExecutionEventData } from '../interfaces/agent';\nimport type { IEventContext, IOwnerPathSegment } from '../interfaces/event-service';\nimport type { TUniversalMessage } from '../interfaces/messages';\n\n/**\n * Build the owner path from an optional IExecutionContextInjection.\n */\nexport function buildBaseOwnerPath(executionContext?: {\n ownerPath?: IOwnerPathSegment[];\n}): IOwnerPathSegment[] {\n if (!executionContext?.ownerPath?.length) {\n return [];\n }\n return executionContext.ownerPath.map((segment) => ({ ...segment }));\n}\n\n/**\n * Build the IEventContext for an execution-level event.\n */\nexport function buildExecutionOwnerContext(\n agentOwnerPathBase: IOwnerPathSegment[],\n ownerPathBase: IOwnerPathSegment[],\n rootId: string,\n executionId: string,\n): IEventContext {\n if (!rootId || rootId.length === 0) {\n throw new Error('[EXECUTION] Missing rootId for execution owner context');\n }\n if (!executionId || executionId.length === 0) {\n throw new Error('[EXECUTION] Missing executionId for execution owner context');\n }\n const basePath = agentOwnerPathBase.length ? agentOwnerPathBase : ownerPathBase;\n const path: IOwnerPathSegment[] = [...basePath];\n if (rootId && !path.some((segment) => segment.type === 'agent' && segment.id === rootId)) {\n path.push({ type: 'agent', id: rootId });\n }\n path.push({ type: 'execution', id: executionId });\n return {\n ownerType: EXECUTION_EVENT_PREFIX,\n ownerId: executionId,\n ownerPath: path,\n };\n}\n\n/**\n * Build the IEventContext for a thinking-level event.\n */\nexport function buildThinkingOwnerContext(\n agentOwnerPathBase: IOwnerPathSegment[],\n ownerPathBase: IOwnerPathSegment[],\n rootId: string,\n executionId: string,\n thinkingNodeId: string,\n previousThinkingNodeId?: string,\n): IEventContext {\n if (!thinkingNodeId || thinkingNodeId.length === 0) {\n throw new Error('[EXECUTION] Missing thinkingNodeId for thinking owner context');\n }\n const base = buildExecutionOwnerContext(\n agentOwnerPathBase,\n ownerPathBase,\n rootId,\n executionId,\n ).ownerPath;\n const path: IOwnerPathSegment[] = [...base];\n if (previousThinkingNodeId) {\n path.push({ type: 'thinking', id: previousThinkingNodeId });\n path.push({\n type: 'tool_result',\n id: `tool_result_${previousThinkingNodeId}`,\n });\n }\n path.push({ type: 'thinking', id: thinkingNodeId });\n return {\n ownerType: EXECUTION_EVENT_PREFIX,\n ownerId: executionId,\n ownerPath: path,\n };\n}\n\n/**\n * Build the IEventContext for a tool-level event.\n */\nexport function buildToolOwnerContext(\n agentOwnerPathBase: IOwnerPathSegment[],\n ownerPathBase: IOwnerPathSegment[],\n rootId: string,\n executionId: string,\n toolCallId: string,\n): IEventContext {\n if (!toolCallId || toolCallId.length === 0) {\n throw new Error('[EXECUTION] Missing toolCallId for tool owner context');\n }\n const base = buildExecutionOwnerContext(\n agentOwnerPathBase,\n ownerPathBase,\n rootId,\n executionId,\n ).ownerPath;\n const path = [...base, { type: 'tool', id: toolCallId }];\n return {\n ownerType: TOOL_EVENT_PREFIX,\n ownerId: toolCallId,\n ownerPath: path,\n };\n}\n\n/**\n * Build the IEventContext for a response-level event.\n */\nexport function buildResponseOwnerContext(\n agentOwnerPathBase: IOwnerPathSegment[],\n ownerPathBase: IOwnerPathSegment[],\n rootId: string,\n executionId: string,\n thinkingNodeId: string,\n previousThinkingNodeId?: string,\n): IEventContext {\n const thinkingPath = buildThinkingOwnerContext(\n agentOwnerPathBase,\n ownerPathBase,\n rootId,\n executionId,\n thinkingNodeId,\n previousThinkingNodeId,\n ).ownerPath;\n const responseNodeId = `response_${thinkingNodeId}`;\n const path: IOwnerPathSegment[] = [...thinkingPath, { type: 'response', id: responseNodeId }];\n return {\n ownerType: EXECUTION_EVENT_PREFIX,\n ownerId: executionId,\n ownerPath: path,\n };\n}\n\n/**\n * Announce the message just appended to the conversation store — CORE-033.\n *\n * `history_mutation` is a REQUIRED family (`agent-core/docs/SPEC.md`), and `agent-session` builds\n * its session log from it: a consumer replays the appends to reconstruct the conversation. Three\n * sites appended without announcing — the forced summary, the hard-capacity diagnostic, and the\n * provider-failure record — so a replay diverged from the store at exactly the abnormal moments a\n * reader most needs it to agree.\n *\n * It reads the appended message back out of the store rather than taking it as an argument, because\n * the store is what a replay must reproduce: an event built from what the CALLER meant to append\n * could disagree with what the store holds, which is the class of defect this exists to close.\n */\nexport function announceAppend(\n store: { getMessages(): TUniversalMessage[] },\n context: { onExecutionEvent?: TExecutionEventCallback },\n executionId: string,\n // `string | undefined`, matching every sibling emit in this engine: a turn without one emits the\n // field absent rather than as a fabricated empty string, which a consumer would read as an id.\n conversationId: string | undefined,\n extra: TExecutionEventData = {},\n): void {\n if (context.onExecutionEvent === undefined) return;\n const messages = store.getMessages();\n const appended = messages.at(-1);\n if (appended === undefined) return;\n context.onExecutionEvent('history_mutation', {\n executionId,\n conversationId,\n ...extra,\n mutation: 'append_message',\n index: messages.length - 1,\n message: appended,\n } as TExecutionEventData);\n}\n","import {\n emitAssistantMessageComplete as emitAssistantMessageCompleteHelper,\n emitToolResultsEvents as emitToolResultsEventsHelper,\n emitExecutionStartEvent as emitExecutionStartEventHelper,\n emitUserMessageEvent as emitUserMessageEventHelper,\n} from './execution-event-emitter-high-level';\nimport {\n buildBaseOwnerPath,\n buildExecutionOwnerContext,\n buildThinkingOwnerContext,\n buildToolOwnerContext,\n buildResponseOwnerContext,\n} from './execution-event-helpers';\nimport { TOOL_EVENT_PREFIX } from './tool-execution-constants';\nimport { isDefaultEventService, bindWithOwnerPath } from '../event-service/index';\n\nimport type { IResolvedProviderInfo } from './execution-types';\nimport type { IExecutionContextInjection } from '../interfaces/agent';\nimport type { IAgentConfig } from '../interfaces/agent';\nimport type {\n IEventService,\n IEventContext,\n IOwnerPathSegment,\n IExecutionEventData,\n IToolEventData,\n IBaseEventData,\n} from '../interfaces/event-service';\nimport type { TUniversalMessage } from '../interfaces/messages';\nimport type { ILogger } from '../utils/logger';\n\n/**\n * Encapsulates all event emission logic for ExecutionService.\n * Manages owner path construction and event service scoping.\n */\nexport class ExecutionEventEmitter {\n private readonly baseEventService: IEventService;\n private readonly logger: ILogger;\n private readonly ownerPathBase: IOwnerPathSegment[];\n private readonly toolEventServices: Map<string, IEventService>;\n private agentOwnerPathBase: IOwnerPathSegment[];\n\n constructor(\n baseEventService: IEventService,\n logger: ILogger,\n executionContext?: IExecutionContextInjection,\n ) {\n this.baseEventService = baseEventService;\n this.logger = logger;\n this.ownerPathBase = buildBaseOwnerPath(executionContext);\n this.toolEventServices = new Map();\n this.agentOwnerPathBase = [];\n }\n\n /**\n * Prepare owner path bases for a conversation\n */\n prepareOwnerPathBases(conversationId: string): void {\n this.toolEventServices.clear();\n const ownerPath = [...this.ownerPathBase, { type: 'agent', id: conversationId }];\n this.agentOwnerPathBase = ownerPath;\n }\n\n /**\n * Reset owner path bases after execution\n */\n resetOwnerPathBases(): void {\n this.toolEventServices.clear();\n this.agentOwnerPathBase = [];\n }\n\n /**\n * Ensure a scoped event service exists for a tool\n */\n ensureToolEventService(\n ownerId: string | undefined,\n ownerPath: IOwnerPathSegment[] | undefined,\n ): IEventService {\n if (isDefaultEventService(this.baseEventService)) {\n return this.baseEventService;\n }\n if (!ownerId) {\n throw new Error('[EVENT-SERVICE] Missing ownerId for tool event context');\n }\n if (!ownerPath || ownerPath.length === 0) {\n throw new Error('[EVENT-SERVICE] Missing ownerPath for tool event context');\n }\n if (this.toolEventServices.has(ownerId)) {\n return this.toolEventServices.get(ownerId)!;\n }\n const scoped = bindWithOwnerPath(this.baseEventService, {\n ownerType: TOOL_EVENT_PREFIX,\n ownerId,\n ownerPath: ownerPath.map((segment) => ({ ...segment })),\n });\n this.toolEventServices.set(ownerId, scoped);\n return scoped;\n }\n\n /**\n * Clear tool event services (e.g., between rounds)\n */\n clearToolEventServices(): void {\n this.toolEventServices.clear();\n }\n\n /**\n * Get the base event service\n */\n getBaseEventService(): IEventService {\n return this.baseEventService;\n }\n\n // --- Owner context builders (delegating to pure helpers) ---\n\n buildExecutionOwnerContext(rootId: string, executionId: string): IEventContext {\n return buildExecutionOwnerContext(\n this.agentOwnerPathBase,\n this.ownerPathBase,\n rootId,\n executionId,\n );\n }\n\n buildThinkingOwnerContext(\n rootId: string,\n executionId: string,\n thinkingNodeId: string,\n previousThinkingNodeId?: string,\n ): IEventContext {\n return buildThinkingOwnerContext(\n this.agentOwnerPathBase,\n this.ownerPathBase,\n rootId,\n executionId,\n thinkingNodeId,\n previousThinkingNodeId,\n );\n }\n\n buildToolOwnerContext(rootId: string, executionId: string, toolCallId: string): IEventContext {\n return buildToolOwnerContext(\n this.agentOwnerPathBase,\n this.ownerPathBase,\n rootId,\n executionId,\n toolCallId,\n );\n }\n\n buildResponseOwnerContext(\n rootId: string,\n executionId: string,\n thinkingNodeId: string,\n previousThinkingNodeId?: string,\n ): IEventContext {\n return buildResponseOwnerContext(\n this.agentOwnerPathBase,\n this.ownerPathBase,\n rootId,\n executionId,\n thinkingNodeId,\n previousThinkingNodeId,\n );\n }\n\n // --- Emit helpers ---\n\n emitExecution(\n eventType: string,\n data: Omit<IExecutionEventData, 'timestamp'>,\n rootId: string,\n executionId: string,\n ): void {\n this.emitWithContext(\n eventType,\n data,\n () => this.buildExecutionOwnerContext(rootId, executionId),\n (context) => {\n if (!context.ownerType || !context.ownerId) {\n throw new Error('[EXECUTION] Missing owner context for execution event');\n }\n return bindWithOwnerPath(this.baseEventService, {\n ownerType: context.ownerType,\n ownerId: context.ownerId,\n ownerPath: context.ownerPath,\n });\n },\n );\n }\n\n emitTool(\n eventType: string,\n data: Omit<IToolEventData, 'timestamp'>,\n rootId: string,\n executionId: string,\n toolCallId: string,\n ): void {\n this.emitWithContext(\n eventType,\n data,\n () => this.buildToolOwnerContext(rootId, executionId, toolCallId),\n (context) => this.ensureToolEventService(context.ownerId, context.ownerPath),\n );\n }\n\n emitWithContext<TEvent extends IBaseEventData>(\n eventType: string,\n data: Omit<TEvent, 'timestamp'>,\n buildContext: () => IEventContext,\n resolveService: (context: IEventContext) => IEventService,\n ): void {\n if (isDefaultEventService(this.baseEventService)) {\n return;\n }\n const context = buildContext();\n const service = resolveService(context);\n const payload: TEvent = {\n timestamp: new Date(),\n ...(data as Omit<TEvent, 'timestamp'>),\n } as TEvent;\n service.emit(eventType, payload, context);\n }\n\n // --- High-level event emitters ---\n\n emitExecutionStartEvent(\n input: string,\n config: IAgentConfig,\n messages: TUniversalMessage[],\n resolved: IResolvedProviderInfo,\n conversationId: string,\n executionId: string,\n ): void {\n emitExecutionStartEventHelper(\n this,\n input,\n config,\n messages,\n resolved,\n conversationId,\n executionId,\n );\n }\n\n emitUserMessageEvent(input: string, conversationId: string, executionId: string): void {\n emitUserMessageEventHelper(this, input, conversationId, executionId);\n }\n\n emitAssistantMessageComplete(\n assistantResponse: { content?: string | null; timestamp?: Date },\n executionId: string,\n currentRound: number,\n conversationId: string,\n thinkingNodeId: string,\n previousThinkingNodeId: string | undefined,\n ): void {\n emitAssistantMessageCompleteHelper(\n this,\n this.baseEventService,\n assistantResponse,\n executionId,\n currentRound,\n conversationId,\n thinkingNodeId,\n previousThinkingNodeId,\n );\n }\n\n emitToolResultsEvents(\n assistantToolCalls: Array<{ id?: string }>,\n toolSummary: { results: Array<{ toolName?: string }> },\n toolsExecuted: string[],\n conversationId: string,\n executionId: string,\n currentRound: number,\n thinkingNodeId: string,\n previousThinkingNodeId: string | undefined,\n ): void {\n emitToolResultsEventsHelper(\n this,\n this.baseEventService,\n assistantToolCalls,\n toolSummary,\n toolsExecuted,\n conversationId,\n executionId,\n currentRound,\n thinkingNodeId,\n previousThinkingNodeId,\n );\n }\n}\n","/**\n * CORE-027 — the failure a result carries is the failure that happened.\n *\n * A round that ends in a provider failure records a `Request failed: …` assistant message for the\n * READER; the failure's representation is the thrown value itself, carried out of the round on\n * `IExecutionRoundState.providerFailure`. Rebuilding the error from the display prose was the\n * round trip that destroyed its class, `code`, `category`, `recoverable` flag, stack and `cause`.\n */\n\nimport type { ICoreExecutionResult } from './execution-types';\nimport type { TUniversalMessage } from '../interfaces/messages';\nimport type { ConversationStore } from '../managers/conversation-history-manager';\n\n/**\n * The `error` a failed result carries: the ORIGINAL thrown value by identity when it was carried,\n * a wrapper for a non-Error thrown value, and a reconstruction from the display message ONLY for\n * a restored store whose failure round predates the carried value (an older session).\n */\nfunction resolveProviderFailureError(providerFailure: unknown, response: string): Error {\n if (providerFailure instanceof Error) return providerFailure;\n if (providerFailure !== undefined) return new Error(String(providerFailure));\n return new Error(response);\n}\n\n/**\n * Build the final ICoreExecutionResult from the completed conversation store.\n */\nexport function buildFinalResult(\n conversationStore: ConversationStore,\n executionId: string,\n startTime: Date,\n toolsExecuted: string[],\n providerFailure?: unknown,\n): ICoreExecutionResult {\n const finalMessages = conversationStore.getMessages();\n // Find last assistant message with actual content (skip stripped tool-round messages)\n const lastAssistantMessage = finalMessages\n .filter(\n (msg) =>\n msg.role === 'assistant' && typeof msg.content === 'string' && msg.content.length > 0,\n )\n .pop();\n const response: string = lastAssistantMessage\n ? (lastAssistantMessage.content as string)\n : 'No response received. The context window may be full.';\n // A round that ended in a provider failure records the error as an assistant message\n // with providerError metadata — that message must not count as a successful response,\n // or the failure is masked as exit 0 downstream.\n const endedWithProviderError = lastAssistantMessage?.metadata?.['providerError'] === true;\n const duration = Date.now() - startTime.getTime();\n return {\n response,\n messages: finalMessages.map((msg) => {\n if (typeof msg.content !== 'string')\n throw new Error('[EXECUTION] Message content is required');\n return {\n role: msg.role,\n content: msg.content,\n timestamp: msg.timestamp,\n metadata: msg.metadata,\n ...(msg.role === 'assistant' && 'toolCalls' in msg ? { toolCalls: msg.toolCalls } : {}),\n ...(msg.role === 'tool' && 'toolCallId' in msg ? { toolCallId: msg.toolCallId } : {}),\n };\n }) as TUniversalMessage[],\n executionId,\n duration,\n tokensUsed: finalMessages\n .filter((msg) => msg.metadata?.['usage'])\n .reduce((sum, msg) => {\n const usage = msg.metadata?.['usage'];\n if (usage && typeof usage === 'object' && 'totalTokens' in usage) {\n const totalTokens = Number(usage.totalTokens);\n if (Number.isNaN(totalTokens))\n throw new Error('[EXECUTION] totalTokens must be a number');\n return sum + totalTokens;\n }\n return sum;\n }, 0),\n toolsExecuted,\n success: !!lastAssistantMessage && !endedWithProviderError,\n // CORE-027: the ORIGINAL thrown value, by identity — see resolveProviderFailureError.\n ...(endedWithProviderError\n ? { error: resolveProviderFailureError(providerFailure, response) }\n : {}),\n };\n}\n","/**\n * What THIS model can be asked to do. PROV-006.\n *\n * The provider catalog carries a per-model capability vocabulary — `tools`, `vision`,\n * `json_schema`, `reasoning`, `native_web`, `streaming` — and nothing read it. Tool gating asked a\n * per-PROVIDER boolean, so a model whose own entry declares no `tools` was handed the whole toolset.\n *\n * Split out of `execution-round-provider.ts` to keep it under the size ceiling, and because \"may\n * this model be asked this?\" is a question of its own — separate from assembling the request.\n *\n * The rule: only a POPULATED capability list that omits the capability is a denial. A catalog silent\n * about a model has said nothing, and reading silence as refusal would cripple every model no\n * catalog happens to list.\n *\n * `vision` is deliberately NOT gated here — see PROV-010. A first attempt refused any turn whose\n * outgoing messages carried an image part, which is correct about what is sent and wrong about what\n * to do: `setModel()` preserves the conversation, so switching to a non-vision model left every\n * later text-only turn permanently refused because an old image was still in the history.\n */\n\nimport { resolveModelCapability } from '../interfaces/model-capability.js';\n\nimport type { IResolvedProviderInfo } from './execution-types';\nimport type { IChatOptions } from '../interfaces/provider';\n\n/**\n * Withhold tools from a model that declares none.\n *\n * Mutates the options rather than rebuilding them: the tool list is assembled once for the turn, and\n * a second assembly path is how the two capability answers drifted apart in the first place.\n */\nexport function applyModelToolCapability(\n chatOptions: IChatOptions,\n model: string,\n resolved: IResolvedProviderInfo,\n): void {\n if (chatOptions.tools === undefined) return;\n if (resolveModelCapability(resolved.provider.capabilityTable?.(), model, 'tools', true)) return;\n delete chatOptions.tools;\n delete chatOptions.toolChoice;\n}\n","/**\n * One provider call, honouring the run's cancellation signal and the configured idle timeout.\n *\n * Split out of `execution-round-provider.ts`, which had grown two responsibilities: ASSEMBLING a\n * request (what options, which transport, which tools this model may have) and MAKING one safely\n * (abort propagation, idle detection, listener cleanup). They change for different reasons.\n *\n * Exported so every provider call in the execution turn goes through one implementation — CORE-042:\n * the forced-summary call was the last one built by hand, and it silently had neither guard.\n */\n\nimport type { TUniversalMessage } from '../interfaces/messages';\nimport type { IChatOptions } from '../interfaces/provider';\n\ntype TProviderChat = (\n messages: TUniversalMessage[],\n options: IChatOptions,\n) => Promise<TUniversalMessage>;\n\n/**\n * Call a provider honouring the run's cancellation signal and the configured idle timeout.\n *\n * Exported so that every provider call in the execution turn goes through one implementation --\n * CORE-042: the forced-summary call was the last one built by hand, and it silently had neither.\n */\nexport async function callProviderWithIdleTimeout(\n chat: TProviderChat,\n messages: TUniversalMessage[],\n options: IChatOptions,\n timeoutMs: number | undefined,\n awaitProviderSettlement = false,\n): Promise<TUniversalMessage> {\n const normalizedTimeoutMs = normalizeTimeoutMs(timeoutMs);\n const upstreamSignal = options.signal;\n if (normalizedTimeoutMs === undefined && upstreamSignal === undefined) {\n return chat(messages, options);\n }\n if (upstreamSignal?.aborted) {\n throw createAbortError();\n }\n\n const controller = new AbortController();\n let idleTimer: ReturnType<typeof setTimeout> | undefined;\n let settled = false;\n let providerCall: Promise<TUniversalMessage> | undefined;\n let rejectGuard: ((reason: Error) => void) | undefined;\n\n const clearIdleTimer = (): void => {\n if (idleTimer !== undefined) {\n clearTimeout(idleTimer);\n idleTimer = undefined;\n }\n };\n\n const failWith = (error: Error): void => {\n if (settled) return;\n settled = true;\n rejectGuard?.(error);\n controller.abort(error);\n };\n\n const resetIdleTimer = (): void => {\n if (normalizedTimeoutMs === undefined || settled) return;\n clearIdleTimer();\n idleTimer = setTimeout(() => {\n failWith(new Error(`Provider call idle timeout after ${normalizedTimeoutMs}ms`));\n }, normalizedTimeoutMs);\n };\n\n const handleUpstreamAbort = (): void => {\n failWith(createAbortError());\n };\n upstreamSignal?.addEventListener('abort', handleUpstreamAbort, { once: true });\n\n const originalOnTextDelta = options.onTextDelta;\n const guardedOptions: IChatOptions = {\n ...options,\n signal: controller.signal,\n ...(originalOnTextDelta !== undefined\n ? {\n onTextDelta: (delta: string): void => {\n resetIdleTimer();\n originalOnTextDelta(delta);\n },\n }\n : {}),\n };\n\n resetIdleTimer();\n\n try {\n const guard = new Promise<never>((_, reject) => { rejectGuard = reject; });\n // Install the guard before entering provider code, which can synchronously abort.\n providerCall = (async () => chat(messages, guardedOptions))();\n return await Promise.race([providerCall, guard]);\n } finally {\n settled = true;\n clearIdleTimer();\n upstreamSignal?.removeEventListener('abort', handleUpstreamAbort);\n // Preserve the guard outcome even if the provider later succeeds or rejects.\n if (awaitProviderSettlement && providerCall) await providerCall.then(() => {}, () => {});\n }\n}\n\nfunction normalizeTimeoutMs(timeoutMs: number | undefined): number | undefined {\n if (timeoutMs === undefined || !Number.isFinite(timeoutMs) || timeoutMs <= 0) {\n return undefined;\n }\n return timeoutMs;\n}\n\nfunction createAbortError(): Error {\n const error = new Error('aborted');\n error.name = 'AbortError';\n return error;\n}\n","import { EXECUTION_EVENT_PREFIX, EXECUTION_EVENTS } from './execution-constants';\n\nimport type {\n IPluginContract,\n IPluginHooks,\n IPluginOptions,\n IPluginStats,\n IPluginErrorContext,\n} from '../abstracts/abstract-plugin';\nimport type { IPluginExecutionContext, IPluginContext } from '../abstracts/abstract-plugin-types';\nimport type { ILogger } from '../utils/logger';\n\n/** Combined plugin type used throughout the execution service */\nexport type TPluginWithHooks = IPluginContract<IPluginOptions, IPluginStats> & IPluginHooks;\n\n/** Handler for a single plugin hook invocation */\ntype TPluginHookHandler = (plugin: TPluginWithHooks, context: IPluginContext) => Promise<void>;\n\n/**\n * PLG-020 (issue #2460): the execution-level context the official plugins consume. Built from the\n * dispatcher's `executionContext` (string ids) plus the conversation messages, so `LimitsPlugin`,\n * `WebhookPlugin` and friends are reached by the production dispatcher rather than only by tests.\n */\nfunction toExecutionContext(context: IPluginContext): IPluginExecutionContext {\n const execution: IPluginExecutionContext = {};\n for (const key of ['executionId', 'sessionId', 'userId'] as const) {\n const value = context.executionContext?.[key];\n if (typeof value === 'string' && value.length > 0) execution[key] = value;\n }\n if (context.messages) execution.messages = context.messages;\n return execution;\n}\n\n/** Map from hook name to its handler function */\nconst HOOK_HANDLERS: Record<string, TPluginHookHandler> = {\n // PLG-020 (issue #2460): the four execution-level hooks the official plugins implement, and the\n // message hook the history plugin implements, were declared on `IPluginHooks` and dispatched by\n // nothing. They are dispatched here, at the same sites as their run-level siblings.\n beforeExecution: async (plugin, context) => {\n if (plugin.beforeExecution) await plugin.beforeExecution(toExecutionContext(context));\n },\n afterExecution: async (plugin, context) => {\n if (plugin.afterExecution && context.executionResult) {\n await plugin.afterExecution(toExecutionContext(context), context.executionResult);\n }\n },\n afterConversation: async (plugin, context) => {\n if (plugin.afterConversation && context.executionResult) {\n await plugin.afterConversation(toExecutionContext(context), context.executionResult);\n }\n },\n afterToolExecution: async (plugin, context) => {\n if (plugin.afterToolExecution && context.executionResult?.toolCalls?.length) {\n await plugin.afterToolExecution(toExecutionContext(context), context.executionResult);\n }\n },\n onMessageAdded: async (plugin, context) => {\n if (plugin.onMessageAdded && context.message) await plugin.onMessageAdded(context.message);\n },\n beforeRun: async (plugin, context) => {\n if (plugin.beforeRun && context.input) {\n await plugin.beforeRun(context.input, context.metadata);\n }\n },\n afterRun: async (plugin, context) => {\n if (plugin.afterRun && context.input && context.response) {\n await plugin.afterRun(context.input, context.response, context.metadata);\n }\n },\n beforeProviderCall: async (plugin, context) => {\n if (plugin.beforeProviderCall && context.messages) {\n await plugin.beforeProviderCall(context.messages);\n }\n },\n afterProviderCall: async (plugin, context) => {\n if (plugin.afterProviderCall && context.messages && context.responseMessage) {\n await plugin.afterProviderCall(context.messages, context.responseMessage);\n }\n },\n onError: async (plugin, context) => {\n if (plugin.onError && context.error) {\n const errorContext: IPluginErrorContext = {\n action: `${EXECUTION_EVENT_PREFIX}.${EXECUTION_EVENTS.ERROR}`,\n metadata: {},\n };\n\n const executionIdValue = context.executionContext?.['executionId'];\n if (typeof executionIdValue === 'string' && executionIdValue.length > 0) {\n errorContext.executionId = executionIdValue;\n }\n const sessionIdValue = context.executionContext?.['sessionId'];\n if (typeof sessionIdValue === 'string' && sessionIdValue.length > 0) {\n errorContext.sessionId = sessionIdValue;\n }\n const userIdValue = context.executionContext?.['userId'];\n if (typeof userIdValue === 'string' && userIdValue.length > 0) {\n errorContext.userId = userIdValue;\n }\n\n await plugin.onError(context.error, errorContext);\n }\n },\n};\n\n/**\n * Dispatch a hook call to all plugins that implement it.\n * Uses a handler map instead of a switch for lower cyclomatic complexity.\n */\nexport async function callPluginHook(\n plugins: ReadonlyArray<TPluginWithHooks>,\n hookName: string,\n context: IPluginContext,\n logger: ILogger,\n): Promise<void> {\n const handler = HOOK_HANDLERS[hookName];\n if (!handler) {\n return;\n }\n\n for (const plugin of plugins) {\n try {\n await handler(plugin, context);\n } catch (error) {\n logger.warn('Plugin hook failed', {\n pluginName: plugin.name,\n hookName,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n}\n","import { EXECUTION_EVENTS } from './execution-constants';\nimport {\n type IResolvedProviderInfo,\n type IExecutionContext,\n ID_RADIX,\n ID_RANDOM_LENGTH,\n} from './execution-types';\nimport { callPluginHook } from './plugin-hook-dispatcher';\nimport { type ConversationStore } from '../managers/conversation-history-manager';\n\nimport type { ExecutionEventEmitter } from './execution-event-emitter';\nimport type { TPluginWithHooks } from './plugin-hook-dispatcher';\nimport type { IAgentConfig, IAssistantMessage, IToolMessage } from '../interfaces/agent';\nimport type { IAIProviderManager } from '../interfaces/manager';\nimport type { IToolManager } from '../interfaces/manager';\nimport type { TUniversalMessage } from '../interfaces/messages';\nimport type { IChatOptions, IToolSchema, TToolChoice } from '../interfaces/provider';\nimport type { IResponseFormatConfig } from '../interfaces/response-format';\nimport type { ILogger } from '../utils/logger';\n\n/**\n * Map the config-level response format onto provider chat options (CORE-015:\n * `json_schema` requires the schema payload; `text`/`json_object` carry type only).\n */\nexport function buildChatResponseFormat(\n responseFormat: IResponseFormatConfig | undefined,\n): IChatOptions['responseFormat'] | undefined {\n if (!responseFormat?.type) {\n return undefined;\n }\n if (responseFormat.type === 'json_schema') {\n if (!responseFormat.schema) {\n throw new Error(\"responseFormat.schema is required when type is 'json_schema'.\");\n }\n return {\n type: 'json_schema',\n schema: responseFormat.schema,\n ...(responseFormat.name && { name: responseFormat.name }),\n };\n }\n return { type: responseFormat.type };\n}\n\n/**\n * Resolve the effective tool-invocation directive for a given execution round (CORE-017).\n * Forcing directives (`'required'` / `{ tool }`) apply to the run's FIRST model call only;\n * follow-up rounds (after tool results) revert to `'auto'` so the model can consume the\n * results and finish — a persistent force would re-trigger the tool every round and the run\n * could never produce a final answer. `'auto'`/`'none'` persist across rounds.\n */\nexport function resolveToolChoiceForRound(\n toolChoice: TToolChoice | undefined,\n round: number,\n): TToolChoice | undefined {\n if (toolChoice === undefined || round <= 1) {\n return toolChoice;\n }\n if (toolChoice === 'required' || typeof toolChoice === 'object') {\n return 'auto';\n }\n return toolChoice;\n}\n\n/**\n * Validate a tool-invocation directive against the invocation's tool list (CORE-017).\n * Forcing semantics (`'required'` / `{ tool: name }`) demand tools to force — a missing\n * tool list or an unknown name is a caller contract violation and throws immediately.\n */\nexport function assertToolChoiceValid(\n toolChoice: TToolChoice | undefined,\n tools: IToolSchema[] | undefined,\n): void {\n if (toolChoice === undefined || toolChoice === 'auto' || toolChoice === 'none') {\n return;\n }\n const names = (tools ?? []).map((tool) => tool.name);\n if (toolChoice === 'required') {\n if (names.length === 0) {\n throw new Error(\"toolChoice 'required' needs at least one tool, but the run has none.\");\n }\n return;\n }\n if (!names.includes(toolChoice.tool)) {\n throw new Error(\n `toolChoice requests tool \"${toolChoice.tool}\" which is not available for this run. ` +\n `Available tools: ${names.length > 0 ? names.join(', ') : '(none)'}`,\n );\n }\n}\n\n/**\n * Resolve the current AI provider and available tools from managers.\n * Pure function — no class instance needed.\n */\nexport function resolveProviderAndTools(\n aiProviders: IAIProviderManager,\n tools: IToolManager,\n config: IAgentConfig,\n): IResolvedProviderInfo {\n const currentInfo = aiProviders.getCurrentProvider();\n const provider = currentInfo ? aiProviders.getProvider(currentInfo.provider) : null;\n if (!currentInfo || !currentInfo.provider || !provider) {\n throw new Error('[EXECUTION] Provider is required');\n }\n const registeredTools = tools.getTools();\n const aiProviderInfo = {\n providerName: currentInfo.provider,\n model: config.defaultModel.model,\n temperature: config.defaultModel.temperature,\n maxTokens: config.defaultModel.maxTokens,\n };\n const toolsInfo = registeredTools.map((tool) => {\n if (!tool.description || tool.description.length === 0) {\n throw new Error(`[EXECUTION] Tool \"${tool.name}\" is missing description`);\n }\n return {\n name: tool.name,\n description: tool.description,\n parameters: Object.keys(tool.parameters.properties ?? {}),\n };\n });\n const readAvailableTools = (): IToolSchema[] => tools.getOfferedTools();\n const deferredTools = tools;\n return { provider, currentInfo, aiProviderInfo, toolsInfo, readAvailableTools, deferredTools };\n}\n\n/**\n * Validate that the resolved provider is usable.\n */\nexport function validateProvider(resolved: IResolvedProviderInfo): void {\n if (!resolved.currentInfo) throw new Error('No AI provider configured');\n if (!resolved.provider)\n throw new Error(`AI provider '${resolved.currentInfo.provider}' not found`);\n if (typeof resolved.provider.chat !== 'function') {\n throw new Error('Provider must have chat method to support execution');\n }\n}\n\n/**\n * Initialize or restore a conversation store for the given conversation.\n */\nexport function initializeConversationStore(\n conversationHistory: { getConversationStore: (id: string) => ConversationStore },\n conversationId: string,\n messages: TUniversalMessage[],\n config: IAgentConfig,\n executionId: string,\n): ConversationStore {\n const session = conversationHistory.getConversationStore(conversationId);\n // Restore prior CONVERSATION content (user/assistant/tool) when this store has none yet. Keying off\n // conversation content (not getMessageCount) lets a system prompt injected before the first run\n // coexist with restore (CORE-008). Persisted `system` messages are intentionally NOT restored: the\n // system prompt is injected fresh from config.systemMessage below, which is a resume-time staleness\n // refresh (the rebuilt prompt reflects the current cwd/AGENTS.md/CLAUDE.md and tools — CORE-009).\n const hasConversationContent = session.getMessages().some((m) => m.role !== 'system');\n if (!hasConversationContent && messages.length > 0) {\n for (const msg of messages) {\n if (msg.role === 'user') {\n session.addUserMessage(msg.content, msg.metadata, msg.parts);\n } else if (msg.role === 'assistant') {\n session.addAssistantMessage(\n msg.content,\n (msg as IAssistantMessage).toolCalls,\n msg.metadata,\n msg.parts,\n );\n } else if (msg.role === 'tool') {\n const toolName = msg.metadata?.['toolName'];\n if (typeof toolName !== 'string' || toolName.length === 0) {\n throw new Error('[EXECUTION] Tool message missing toolName metadata');\n }\n session.addToolMessageWithId(\n msg.content,\n (msg as IToolMessage).toolCallId,\n toolName,\n msg.metadata,\n msg.parts,\n );\n }\n // `system` messages are skipped — the system prompt is established below from config, not the\n // restored log (CORE-009/CORE-010).\n }\n }\n // Inject the system prompt into the session log ONCE — only when the log has no system message yet\n // (session start, or the first turn after resume). Thereafter the log is reused as-is; the prompt\n // is never re-attached per turn. Live changes (persona, self-verification, AGENTS.md/CLAUDE.md\n // staleness refresh) update the head in place via Robota.updateSystemPrompt, which keeps\n // config.systemMessage and the log head in sync (CORE-010; see agent-core SPEC → System Prompt).\n const hasSystemMessage = session.getMessages().some((m) => m.role === 'system');\n if (config.systemMessage && !hasSystemMessage) {\n session.setSystemPrompt(config.systemMessage, { executionId });\n }\n return session;\n}\n\n/**\n * Handle a non-abort error from the execution pipeline:\n * fires onError plugin hook and emits the error event.\n */\nexport async function handleExecutionError(\n error: unknown,\n fullContext: IExecutionContext,\n startTime: Date,\n conversationId: string,\n executionId: string,\n plugins: TPluginWithHooks[],\n logger: ILogger,\n eventEmitter: ExecutionEventEmitter,\n): Promise<void> {\n const duration = Date.now() - startTime.getTime();\n const normalizedError = error instanceof Error ? error : new Error(String(error));\n await callPluginHook(\n plugins,\n 'onError',\n {\n error: normalizedError,\n executionContext: convertExecutionContextToPluginFormat(fullContext),\n },\n logger,\n );\n logger.error('Execution pipeline failed', {\n executionId,\n conversationId,\n duration,\n error: error instanceof Error ? error.message : String(error),\n });\n eventEmitter.emitExecution(\n EXECUTION_EVENTS.ERROR,\n {\n error: error instanceof Error ? error.message : String(error),\n metadata: { method: 'execute', success: false, duration },\n },\n conversationId,\n executionId,\n );\n}\n\n/**\n * Generate a unique execution ID.\n */\nexport function generateExecutionId(): string {\n return `exec_${Date.now()}_${Math.random().toString(ID_RADIX).substr(2, ID_RANDOM_LENGTH)}`;\n}\n\n/**\n * Assert that a conversationId is present and non-empty, throwing with context label.\n */\nexport function requireConversationId(\n context: { conversationId?: string } | undefined,\n label: string,\n): string {\n if (!context?.conversationId || context.conversationId.length === 0) {\n throw new Error(`[EXECUTION] conversationId is required for ${label}`);\n }\n return context.conversationId;\n}\n\nexport function buildFullExecutionContext(\n messages: TUniversalMessage[],\n config: IAgentConfig,\n startTime: Date,\n executionId: string,\n conversationId: string,\n context?: Partial<IExecutionContext>,\n): IExecutionContext {\n return {\n messages,\n config,\n startTime,\n executionId,\n conversationId,\n ...(context?.sessionId && { sessionId: context.sessionId }),\n ...(context?.userId && { userId: context.userId }),\n ...(context?.metadata && { metadata: context.metadata }),\n ...(context?.signal && { signal: context.signal }),\n awaitProviderSettlement: context?.awaitProviderSettlement,\n ...(context?.onTextDelta && { onTextDelta: context.onTextDelta }),\n ...(context?.onExecutionEvent && { onExecutionEvent: context.onExecutionEvent }),\n ...(context?.maxExecutionRounds !== undefined && {\n maxExecutionRounds: context.maxExecutionRounds,\n }),\n ...(context?.maxSameToolInputs !== undefined && {\n maxSameToolInputs: context.maxSameToolInputs,\n }),\n ...(context?.allowToolOnlyCompletion !== undefined && {\n allowToolOnlyCompletion: context.allowToolOnlyCompletion,\n }),\n ...(context?.maxTokens !== undefined && { maxTokens: context.maxTokens }),\n ...(context?.temperature !== undefined && { temperature: context.temperature }),\n ...(context?.toolChoice !== undefined && { toolChoice: context.toolChoice }),\n ...(context?.withholdHostedTools === true && { withholdHostedTools: true }),\n ...(context?.ephemeralSystemContext !== undefined && {\n ephemeralSystemContext: context.ephemeralSystemContext,\n }),\n ...(context?.traceContext !== undefined && { traceContext: context.traceContext }),\n };\n}\n\n/**\n * Convert an IExecutionContext to the flat record format expected by plugin hooks.\n */\nfunction convertExecutionContextToPluginFormat(\n context: IExecutionContext,\n): Record<string, string | number | boolean> {\n const conversationId = requireConversationId(context, 'plugin-context');\n const payload: Record<string, string | number | boolean> = {\n conversationId,\n executionId: context.executionId,\n startTime: context.startTime.toISOString(),\n messageCount: context.messages.length,\n };\n if (context.sessionId) payload.sessionId = context.sessionId;\n if (context.userId) payload.userId = context.userId;\n return payload;\n}\n","/**\n * Making a structured request survive a provider that cannot carry the schema. CORE-043.\n *\n * Two defects, one seam. The turn asked every provider for `responseFormat: 'json_schema'`; a\n * provider whose surface cannot express that accepted the option and dropped it. And the only place\n * the schema was ever stated in words is `buildRetryFeedbackInput` — which runs on ATTEMPT TWO. So\n * for a provider without a schema parameter, attempt one was sent with nothing describing the shape\n * at all, and was therefore guaranteed to fail. The advertised \"3 attempts\" were really two, and the\n * first was spent discovering something the capability table already knew.\n *\n * Both are fixed where the request is assembled, because that is the only point that holds the\n * resolved provider AND the outgoing messages at once. `robotaRunStructured` holds neither: it\n * composes a turn out of the public API and never learns which model will serve it.\n */\n\nimport { resolveStructuredOutputCapability } from './structured-output-transport.js';\nimport { randomId } from '../utils/random-id.js';\n\nimport type { IResolvedProviderInfo } from './execution-types';\nimport type { ISystemMessage, TUniversalMessage } from '../interfaces/messages';\nimport type { IChatOptions } from '../interfaces/provider';\nimport type { IProviderStructuredOutputCapability } from '../interfaces/structured-output-capability';\n\n/**\n * What actually happened to a structured request.\n *\n * Reports the OUTCOME, not the resolution. \"This provider declares json_schema\" is a fact about a\n * table; \"the schema was sent as a parameter and no prompt statement was needed\" is a fact about the\n * request that was made, and only the second one explains a result the caller is holding.\n */\nexport interface IStructuredOutputTransportOutcome {\n capability: IProviderStructuredOutputCapability;\n /** What was ultimately put on the wire — `'omitted'` when no response-format option was sent. */\n sent: 'json_schema' | 'json_object' | 'omitted';\n /** Whether the schema was stated in the prompt because the wire could not carry it. */\n schemaInPrompt: boolean;\n}\n\n/** The aligned request: what to send, and the record of why it looks that way. */\nexport interface IStructuredOutputTransportPlan {\n /**\n * The messages to send. A NEW array when an instruction was added — never the caller's own.\n * `conversationMessages` is conversation history; appending a per-request instruction to it would\n * persist a transport workaround into the conversation and repeat it every following round.\n */\n messages: TUniversalMessage[];\n outcome: IStructuredOutputTransportOutcome | undefined;\n}\n\n/**\n * State the schema in words, for a model that will not receive it as a parameter.\n *\n * Deliberately the same instruction the retry path already uses, rather than a second phrasing: a\n * model that fails and retries should not be told the requirement in two different ways.\n */\nfunction schemaInstruction(schema: Record<string, unknown>): string {\n return [\n 'Respond with ONLY a JSON object (no prose, no code fences) matching this JSON schema:',\n JSON.stringify(schema),\n ].join('\\n');\n}\n\n/**\n * Align a structured request with what the provider can actually honour.\n *\n * Mutates `chatOptions` and appends to `messages` in place, matching `applyModelToolCapability`\n * alongside it — the request is assembled once per turn, and a second assembly path is how the\n * capability answers drifted apart before.\n *\n * Returns the outcome, or `undefined` when the request was not structured at all.\n */\nexport function applyStructuredOutputTransport(\n chatOptions: IChatOptions,\n messages: TUniversalMessage[],\n model: string,\n resolved: IResolvedProviderInfo,\n): IStructuredOutputTransportPlan {\n const requested = chatOptions.responseFormat;\n if (requested?.type !== 'json_schema') return { messages, outcome: undefined };\n\n const capability = resolveStructuredOutputCapability({\n table: resolved.provider.capabilityTable?.(),\n model,\n endpointIsVendorDefault: resolved.provider.endpointIsVendorDefault?.(),\n });\n\n if (capability.mechanism === 'response_schema') {\n return { messages, outcome: { capability, sent: 'json_schema', schemaInPrompt: false } };\n }\n\n // The shape cannot ride on the wire, so it rides in the prompt — on the FIRST attempt, which is\n // the attempt that previously had no statement of the requirement at all.\n const instruction: ISystemMessage = {\n role: 'system',\n content: schemaInstruction(requested.schema),\n id: randomId(),\n timestamp: new Date(),\n state: 'complete',\n };\n const outgoing = [...messages, instruction];\n\n if (capability.mechanism === 'json_object') {\n // Still worth sending: it does not enforce the shape, but it does remove the prose and the code\n // fences that are the most common reason the parse step fails before validation is even reached.\n chatOptions.responseFormat = { type: 'json_object' };\n return {\n messages: outgoing,\n outcome: { capability, sent: 'json_object', schemaInPrompt: true },\n };\n }\n\n // `'none'` and any undeclared provider: sending an option the endpoint ignores tells the caller\n // nothing and risks a hard rejection from a strict gateway. Omit it and rely on the prompt.\n delete chatOptions.responseFormat;\n return { messages: outgoing, outcome: { capability, sent: 'omitted', schemaInPrompt: true } };\n}\n","/**\n * Which provider and model a run's request is actually on.\n *\n * A provider that can answer on another model decides the move itself; this only keeps the loop's\n * records honest about it. Without such a provider the route stays empty and every record keeps\n * naming the configured provider and model, exactly as before.\n */\n\nimport type { IResolvedProviderInfo } from './execution-types';\nimport type { IModelFallbackNotice } from '../interfaces/model-fallback';\nimport type { IModelRef } from '../interfaces/role-model';\n\nexport interface IModelRoute {\n /** Where the request is now; absent while it is on the configured provider and model. */\n current?: IModelRef;\n}\n\n/** Ask the provider where this run's request for `model` goes first. */\nexport function openModelRoute(\n resolved: IResolvedProviderInfo,\n model: string,\n executionId: string,\n): IModelRoute {\n const first = resolved.provider.resolveModelRoute?.(model, executionId);\n if (first === undefined) return {};\n if (first.provider === resolved.currentInfo.provider && first.model === model) return {};\n return { current: first };\n}\n\n/** The provider the request is on, falling back to the configured one. */\nexport function routeProvider(route: IModelRoute, resolved: IResolvedProviderInfo): string {\n return route.current?.provider ?? resolved.currentInfo.provider;\n}\n\n/** The model the request is on, falling back to `configured`. */\nexport function routeModel(route: IModelRoute, configured: string): string {\n return route.current?.model ?? configured;\n}\n\n/** Record a move the provider reported. */\nexport function moveModelRoute(route: IModelRoute, notice: IModelFallbackNotice): void {\n route.current = { provider: notice.to.provider, model: notice.to.model };\n}\n","/**\n * Which trace context, if any, one invoked provider call carries.\n *\n * Resolved at the invocation boundary rather than while assembling the request, so a cache hit or a\n * preflight refusal never resolves one and the replay channel's `provider_request` is recorded from\n * options that do not contain it.\n */\nimport { outboundTraceContextFor } from '../utils/trace-context';\n\nimport type { IResolvedProviderInfo } from './execution-types';\nimport type { IChatOptions } from '../interfaces/provider';\nimport type { IOutboundTraceContext, IRunTraceContext } from '../interfaces/trace-context';\n\nexport function resolveProviderCallTraceContext(\n traceContext: IRunTraceContext | undefined,\n provider: IResolvedProviderInfo['provider'],\n providerId: string,\n callId: string,\n): IOutboundTraceContext | undefined {\n // No origin listed: nothing could be sent, so there is nothing to probe or report.\n if (traceContext === undefined || traceContext.allowedOrigins.length === 0) return undefined;\n let capable = false;\n try {\n capable = provider.canPropagateTraceContext?.() === true;\n } catch {\n // allow-fallback: a capability probe that throws is a provider that cannot propagate.\n capable = false;\n }\n if (!capable) {\n try {\n traceContext.onPropagationUnavailable?.(providerId);\n } catch {\n // A host diagnostic must never fail the provider call it describes.\n }\n return undefined;\n }\n return outboundTraceContextFor(traceContext, callId);\n}\n\n/** The options handed to the adapter: unchanged when there is nothing to propagate. */\nexport function withOutboundTraceContext(\n options: IChatOptions,\n outbound: IOutboundTraceContext | undefined,\n): IChatOptions {\n return outbound === undefined ? options : { ...options, outboundTraceContext: outbound };\n}\n","/**\n * Provider call helpers for execution rounds.\n * Extracted from execution-round.ts for single-responsibility.\n */\n\nimport { applyModelToolCapability } from './execution-model-capability-guards.js';\nimport { callProviderWithIdleTimeout } from './execution-provider-call.js';\nimport { assertToolChoiceValid, buildChatResponseFormat } from './execution-service-helpers';\nimport { applyStructuredOutputTransport } from './execution-structured-output-guard.js';\nimport { routeModel } from './execution-model-route.js';\nimport { withOutboundTraceContext } from './execution-trace-context.js';\nimport { randomId } from '../utils/random-id.js';\n\nimport type { IModelRoute } from './execution-model-route';\nimport type { IStructuredOutputTransportOutcome } from './execution-structured-output-guard';\nimport type { IResolvedProviderInfo, IExecutionRoundState } from './execution-types';\nimport type { IAgentConfig, IAssistantMessage } from '../interfaces/agent';\nimport type { IToolCall, TUniversalMessage } from '../interfaces/messages';\nimport type { IChatOptions, TToolChoice } from '../interfaces/provider';\nimport type { IDeferredToolCatalog } from '../interfaces/tool-search';\nimport type { IOutboundTraceContext } from '../interfaces/trace-context';\nimport type { ILogger } from '../utils/logger';\nimport type { ExecutionCacheService } from './cache/execution-cache-service';\n\ntype TProviderChat = (\n messages: TUniversalMessage[],\n options: IChatOptions,\n) => Promise<TUniversalMessage>;\n\n/**\n * A provider request as it will actually be sent — after every capability guard has adjusted it.\n *\n * `messages` is NOT necessarily the array the caller passed in: the structured-output guard adds a\n * system instruction when the wire cannot carry the schema. Reporting the caller's array instead\n * would put a `provider_request` in the session log that no replay could reproduce.\n */\nexport interface IAssembledProviderRequest {\n messages: TUniversalMessage[];\n options: IChatOptions;\n structuredOutput?: IStructuredOutputTransportOutcome;\n}\n\n/** Compute thinking context IDs for event tracking */\nexport function computeRoundThinkingContext(\n conversationId: string,\n roundState: IExecutionRoundState,\n): { thinkingNodeId: string; previousThinkingNodeId: string | undefined } {\n const shouldChainFromPreviousToolResult =\n Array.isArray(roundState.lastTrackedAssistantMessage?.toolCalls) &&\n roundState.lastTrackedAssistantMessage.toolCalls.length > 0;\n const thinkingNodeId = `thinking_${conversationId}_round${roundState.runningAssistantCount + 1}`;\n const previousThinkingNodeId = shouldChainFromPreviousToolResult\n ? `thinking_${conversationId}_round${roundState.runningAssistantCount}`\n : undefined;\n return { thinkingNodeId, previousThinkingNodeId };\n}\n\n/**\n * CLI-1990: a forcing directive that names a deferred tool loads it before the round assembles, so\n * `toolChoice: { tool }` fetches the schema rather than failing `assertToolChoiceValid` against a\n * list the tool is withheld from. A resident or already-loaded name is not in the catalog and\n * nothing happens; an unknown name is left for the assertion to report as it always has.\n */\nfunction loadForcedDeferredTool(\n toolChoice: TToolChoice | undefined,\n catalog: IDeferredToolCatalog,\n): void {\n if (toolChoice === undefined || typeof toolChoice !== 'object') return;\n if (catalog.listDeferredTools().some((schema) => schema.name === toolChoice.tool)) {\n catalog.loadDeferredTools([toolChoice.tool]);\n }\n}\n\n/** Assemble the wire options for one round, before any capability guard has adjusted them. */\nfunction buildRoundChatOptions(\n model: string,\n config: IAgentConfig,\n resolved: IResolvedProviderInfo,\n overrides: Partial<IChatOptions> | undefined,\n): IChatOptions {\n const responseFormat = buildChatResponseFormat(config.responseFormat);\n // CLI-1990: read PER ROUND. The tool list used to be a per-run snapshot spread here each round, so\n // a tool loaded by round N's ToolSearch call was invisible to round N+1 — the one property a\n // search tool needs. The manager applies the residency projection inside this read.\n const effectiveToolChoice = overrides?.toolChoice ?? config.defaultModel?.toolChoice;\n const tools = effectiveToolChoice === 'none' ? [] : resolved.readAvailableTools();\n return {\n model,\n // Preserve provider-default selection until the adapter resolves its verified model table.\n effort: config.defaultModel?.effort ?? 'auto',\n ...(config.defaultModel?.maxTokens !== undefined && {\n maxTokens: config.defaultModel.maxTokens,\n }),\n ...(config.defaultModel?.temperature !== undefined && {\n temperature: config.defaultModel.temperature,\n }),\n ...(config.defaultModel?.toolChoice !== undefined && {\n toolChoice: config.defaultModel.toolChoice,\n }),\n ...(tools.length > 0 && { tools }),\n ...(responseFormat ? { responseFormat } : {}),\n ...overrides,\n };\n}\n\n/** Call the AI provider with optional cache lookup/store */\nexport async function callProviderWithCache(\n conversationMessages: TUniversalMessage[],\n config: IAgentConfig,\n resolved: IResolvedProviderInfo,\n cacheService?: ExecutionCacheService,\n overrides?: Partial<IChatOptions>,\n /**\n * CORE-043: fires once, with the request as it will actually be sent.\n *\n * A callback rather than a field on `IResolvedProviderInfo`, because this describes THIS request,\n * not the provider. The caller closes over the run's event emitter, so the replay channel records\n * the assembled request rather than the inputs it was assembled from — the transport guard can add\n * a system instruction the caller's own array does not contain, and a log of the array the caller\n * passed in would not reconstruct what the model was actually asked.\n */\n onRequestAssembled?: (request: IAssembledProviderRequest) => void,\n awaitProviderSettlement?: boolean,\n onDispatch?: (disposition: 'invoked' | 'cache-hit', model: string) => void,\n /** Asked only when the adapter is actually invoked, after the request was announced. */\n resolveOutboundTraceContext?: () => IOutboundTraceContext | undefined,\n /**\n * Where the request actually goes. The cache is keyed on the model that is asked, and a reply is\n * stored under the model that gave it, so a substitute model's answer is never served as the\n * requested model's, nor the other way round.\n */\n route: IModelRoute = {},\n): Promise<TUniversalMessage> {\n if (!config.defaultModel?.model) {\n throw new Error('Model is required in defaultModel configuration. Please specify a model.');\n }\n if (typeof config.defaultModel.model !== 'string' || config.defaultModel.model.trim() === '') {\n throw new Error('Model must be a non-empty string in defaultModel configuration.');\n }\n\n const model = config.defaultModel.model;\n // The directive this round will carry: the round override, else the config default (CORE-017).\n loadForcedDeferredTool(\n overrides?.toolChoice ?? config.defaultModel.toolChoice,\n resolved.deferredTools,\n );\n const chatOptions = buildRoundChatOptions(model, config, resolved, overrides);\n assertToolChoiceValid(chatOptions.toolChoice, chatOptions.tools);\n // PROV-006: what this MODEL can be asked to do, as opposed to what its vendor can.\n applyModelToolCapability(chatOptions, model, resolved);\n // CORE-043: which transport can carry the schema — decided before the call rather than discovered\n // by spending the retry budget. `outgoing` may carry a prompt statement of the schema, so every\n // use below (cache key included) reads it rather than the caller's history array.\n const { messages: outgoing, outcome: structuredOutcome } = applyStructuredOutputTransport(\n chatOptions,\n conversationMessages,\n model,\n resolved,\n );\n onRequestAssembled?.({\n messages: outgoing,\n options: chatOptions,\n ...(structuredOutcome !== undefined && { structuredOutput: structuredOutcome }),\n });\n const providerChat = resolved.provider.chat.bind(resolved.provider) as TProviderChat;\n const observedChat: TProviderChat = (messages, options) => {\n // Invocation of the provider SDK adapter, not proof of a network attempt within that adapter.\n onDispatch?.('invoked', options.model ?? model);\n return providerChat(messages, withOutboundTraceContext(options, resolveOutboundTraceContext?.()));\n };\n // DATA-007/API-001: the SESSION's effort selection is the cache identity — never a locally resolved\n // effective value. An earlier version of this fix resolved the effort against\n // `resolved.provider.effortTable()` before touching the cache, but that table is only ever\n // populated for a NATIVE provider verified in-process; a `SimpleRemoteExecutor`-backed provider\n // never has one (the server resolves against its OWN table and never serializes the resolution\n // back — see `agent-remote-client/.../wire-chat-options.ts`), and a local table can simply be\n // missing an entry for this exact model (version skew, a `baseURL`/API-surface variant). Both cases\n // report the same \"not applied\" outcome regardless of the actual selection, which would let\n // different selections collide. Keying on the raw selection sidesteps that entirely: it is known\n // upfront, is identical across every executor shape, and is exactly what the caller asked for.\n // `undefined` normalizes to `'auto'`, matching `buildRoundChatOptions`'s own default. This replaces\n // the former API-001 bypass (which unconditionally skipped the cache for any explicit selection\n // because the key could not tell efforts apart) — the cache is now always consulted.\n const effortCacheIdentity = chatOptions.effort ?? 'auto';\n\n if (cacheService) {\n const cachedResponse = cacheService.lookup(\n outgoing,\n routeModel(route, config.defaultModel.model),\n route.current?.provider ?? config.defaultModel.provider,\n {\n temperature: config.defaultModel.temperature,\n maxTokens: config.defaultModel.maxTokens,\n effortCacheIdentity,\n },\n );\n if (cachedResponse) {\n onDispatch?.('cache-hit', chatOptions.model ?? model);\n return {\n role: 'assistant',\n content: cachedResponse,\n timestamp: new Date(),\n id: randomId(),\n state: 'complete' as const,\n };\n }\n const response = await callProviderWithIdleTimeout(\n observedChat,\n outgoing,\n chatOptions,\n config.timeout,\n awaitProviderSettlement,\n );\n if (typeof response.content === 'string') {\n cacheService.store(\n outgoing,\n routeModel(route, config.defaultModel.model),\n route.current?.provider ?? config.defaultModel.provider,\n response.content,\n {\n temperature: config.defaultModel.temperature,\n maxTokens: config.defaultModel.maxTokens,\n effortCacheIdentity,\n },\n );\n }\n return response;\n }\n\n return callProviderWithIdleTimeout(observedChat, outgoing, chatOptions, config.timeout, awaitProviderSettlement);\n}\n\n/** Validate and normalize the provider response */\nexport function validateAndExtractResponse(\n response: TUniversalMessage,\n executionId: string,\n conversationId: string | undefined,\n currentRound: number,\n logger: ILogger,\n): { assistantResponse: IAssistantMessage; assistantToolCalls: IToolCall[] } {\n const assistantToolCallsFromResponse =\n response.role === 'assistant' ? (response as IAssistantMessage).toolCalls : undefined;\n\n const hasToolCalls =\n Array.isArray(assistantToolCallsFromResponse) && assistantToolCallsFromResponse.length > 0;\n if (typeof response.content !== 'string' && !hasToolCalls) {\n throw new Error('[EXECUTION] Provider response must have content or tool calls');\n }\n if (assistantToolCallsFromResponse && !Array.isArray(assistantToolCallsFromResponse)) {\n throw new Error('[EXECUTION] assistant toolCalls must be an array');\n }\n const responseContent = response.content ?? '';\n logger.debug(`[ROUND-${currentRound}] Provider response completed`, {\n executionId,\n conversationId,\n round: currentRound,\n responseLength: responseContent.length,\n hasToolCalls:\n Array.isArray(assistantToolCallsFromResponse) && assistantToolCallsFromResponse.length > 0,\n toolCallsCount: Array.isArray(assistantToolCallsFromResponse)\n ? assistantToolCallsFromResponse.length\n : 0,\n });\n\n if (response.role !== 'assistant') {\n throw new Error(`Unexpected response role: ${response.role}`);\n }\n\n const assistantResponse = response as IAssistantMessage;\n const assistantToolCalls = assistantResponse.toolCalls ?? [];\n if (!Array.isArray(assistantToolCalls)) {\n throw new Error('[EXECUTION] assistantResponse.toolCalls must be an array');\n }\n\n return { assistantResponse, assistantToolCalls };\n}\n\n// Re-exported from its own module (see execution-provider-call.ts) so existing importers of this\n// file keep one import path for \"make a provider call safely\".\nexport { callProviderWithIdleTimeout } from './execution-provider-call.js';\n","import type { TUniversalMessage } from '../interfaces/messages';\n\nexport type TProviderUsageProvenance = 'complete' | 'partial' | 'absent';\n\nexport interface IVerifiedProviderCallUsage {\n readonly provenance: TProviderUsageProvenance;\n readonly promptTokens?: number;\n readonly completionTokens?: number;\n readonly totalTokens?: number;\n}\n\n/** Keep billing/telemetry stricter than context-window heuristics: only adapter-attested totals count. */\nexport function verifiedProviderCallUsage(message: TUniversalMessage | undefined): IVerifiedProviderCallUsage {\n const marker = message?.metadata?.['usageProvenance'];\n if (marker === 'partial') return { provenance: 'partial' };\n if (marker !== 'complete') return { provenance: 'absent' };\n\n const topLevel = (message as TUniversalMessage & {\n usage?: { promptTokens?: unknown; completionTokens?: unknown; totalTokens?: unknown };\n }).usage;\n const metadata = message?.metadata;\n const promptTokens = topLevel?.promptTokens ?? metadata?.['promptTokens'] ?? metadata?.['inputTokens'];\n const completionTokens = topLevel?.completionTokens ?? metadata?.['completionTokens'] ?? metadata?.['outputTokens'];\n const totalTokens = topLevel?.totalTokens ?? metadata?.['totalTokens'];\n if (\n typeof promptTokens !== 'number' || !Number.isSafeInteger(promptTokens) || promptTokens < 0 ||\n typeof completionTokens !== 'number' || !Number.isSafeInteger(completionTokens) || completionTokens < 0 ||\n !Number.isSafeInteger(promptTokens + completionTokens) ||\n (totalTokens !== undefined && totalTokens !== promptTokens + completionTokens)\n ) return { provenance: 'absent' };\n\n return {\n provenance: 'complete',\n promptTokens,\n completionTokens,\n totalTokens: promptTokens + completionTokens,\n };\n}\n","/**\n * How a message's origin is shown to the MODEL.\n *\n * A peer session's message is stored with the peer's driver id in its metadata (display attribution,\n * never an authorization input). The transcript shows it; the provider request did not, so the model\n * read a peer's words as its own operator's. This module is the one place the outgoing request marks\n * them: a user message whose driver id starts with `peer:` is wrapped in `<peer_message from=\"…\">`.\n *\n * The wrapper is generated from metadata only, and wrapper-shaped text inside any message body is\n * escaped first, so no text — operator's, peer's, or a tool's output — can forge or close one. It is\n * applied to the derived request array, never to the stored history, so the transcript keeps what was\n * sent and every later request (including after resume) derives the same marking again.\n */\n\nimport type { TUniversalMessage, TUniversalMessagePart } from '../interfaces/messages';\n\nconst PEER_DRIVER_PREFIX = 'peer:';\n/** A peer id is printed only when it is a plain identifier; anything else is not echoed. */\nconst PRINTABLE_PEER_ID = /^peer:[A-Za-z0-9._:-]{1,128}$/;\nconst WRAPPER_MARKUP = /<(\\/?)(peer_message)/gi;\n\n/** Neutralize `<peer_message` / `</peer_message` so text can neither open nor close a wrapper. */\nexport function escapeOriginMarkup(text: string): string {\n return text.replace(WRAPPER_MARKUP, '<$1$2');\n}\n\n/** The peer driver id a message is attributed to, or undefined for the operator's own. */\nexport function peerDriverOf(message: TUniversalMessage): string | undefined {\n if (message.role !== 'user') return undefined;\n const driverId = message.metadata?.driverId;\n return typeof driverId === 'string' && driverId.startsWith(PEER_DRIVER_PREFIX) ? driverId : undefined;\n}\n\n/** A peer driver id safe to print: the id itself when it is a plain identifier, otherwise a fixed marker. */\nexport function printablePeerDriver(driverId: string): string {\n return PRINTABLE_PEER_ID.test(driverId) ? driverId : 'peer:unverified';\n}\n\n/** Escape text parts, keeping each unchanged part's identity so callers can tell nothing changed. */\nfunction escapeParts(parts: TUniversalMessagePart[]): TUniversalMessagePart[] {\n return parts.map((part) => {\n if (part.type !== 'text') return part;\n const text = escapeOriginMarkup(part.text);\n return text === part.text ? part : { ...part, text };\n });\n}\n\nfunction presentOne(message: TUniversalMessage): TUniversalMessage {\n if (message.role === 'tool') {\n const content = escapeOriginMarkup(message.content);\n const parts = message.parts ? escapeParts(message.parts) : undefined;\n const partsChanged = parts?.some((part, i) => part !== message.parts?.[i]) ?? false;\n if (content === message.content && !partsChanged) return message;\n return { ...message, content, ...(parts ? { parts } : {}) };\n }\n if (message.role !== 'user') return message;\n const peer = peerDriverOf(message);\n const body = escapeOriginMarkup(message.content);\n const parts = message.parts ? escapeParts(message.parts) : undefined;\n if (!peer) {\n const partsChanged = parts?.some((part, i) => part !== message.parts?.[i]) ?? false;\n if (body === message.content && !partsChanged) return message;\n return { ...message, content: body, ...(parts ? { parts } : {}) };\n }\n const open = `<peer_message from=\"${printablePeerDriver(peer)}\">`;\n const close = '</peer_message>';\n return {\n ...message,\n content: `${open}\\n${body}\\n${close}`,\n ...(parts\n ? {\n parts: [\n { type: 'text' as const, text: open },\n ...parts,\n { type: 'text' as const, text: close },\n ],\n }\n : {}),\n };\n}\n\n/** The request-side view of a conversation: peer messages wrapped, wrapper-shaped text escaped. */\nexport function presentMessageOrigins(messages: readonly TUniversalMessage[]): TUniversalMessage[] {\n return messages.map(presentOne);\n}\n","import { announceAppend } from './execution-event-helpers';\nimport { callProviderWithIdleTimeout } from './execution-round-provider';\nimport { PROVIDER_CALL_EVENTS, PROVIDER_FALLBACK_EVENTS } from '../event-service/span-events';\nimport { moveModelRoute, openModelRoute, routeModel, routeProvider } from './execution-model-route';\nimport { isAbortFailure } from '../utils/abort-classification';\nimport { randomId } from '../utils/random-id.js';\nimport { verifiedProviderCallUsage } from './provider-call-usage';\nimport { presentMessageOrigins } from './message-origin';\nimport { resolveProviderCallTraceContext, withOutboundTraceContext } from './execution-trace-context';\n\nimport type {\n IExecutionContext,\n IExecutionRoundState,\n IResolvedProviderInfo,\n} from './execution-types';\nimport type { IAgentConfig, TExecutionEventData } from '../interfaces/agent';\nimport type { IChatOptions } from '../interfaces/provider';\nimport type { TUniversalMessage } from '../interfaces/messages';\nimport type { ConversationStore } from '../managers/conversation-history-manager';\nimport type { ILogger } from '../utils/logger';\n\nconst DEFAULT_MAX_EXECUTION_ROUNDS = 10;\nconst UNLIMITED_EXECUTION_ROUNDS = 0;\n\n/**\n * When max rounds are exhausted without a text response, force one final provider call\n * to generate a summary.\n *\n * Its own file (CORE-033): the loop that decides WHETHER to force a summary and the call that\n * PERFORMS one are separate responsibilities, and this one grew a request assembly, a transport\n * option set and three replay-event emissions of its own — enough that keeping it beside the loop\n * pushed `execution-pipeline.ts` past the file ceiling.\n */\nexport async function forceSummaryCall(\n conversationStore: ConversationStore,\n resolved: IResolvedProviderInfo,\n config: IAgentConfig,\n executionId: string,\n roundState: IExecutionRoundState,\n conversationId: string,\n fullContext: IExecutionContext,\n logger: ILogger,\n maxRounds: number = DEFAULT_MAX_EXECUTION_ROUNDS,\n): Promise<void> {\n logger.warn('No final text response — forcing summary call', {\n maxRounds: maxRounds === UNLIMITED_EXECUTION_ROUNDS ? 'unlimited' : maxRounds,\n currentRound: roundState.currentRound,\n conversationId,\n });\n try {\n const syntheticMsg =\n roundState.forcedSummaryInstruction ??\n 'Tool round limit reached. Provide your response based on the information gathered so far. If results are incomplete, let the user know what was covered and what remains — the user can request additional analysis in a follow-up message.';\n // CORE-033: the instruction is a per-call prompt artifact, not conversation. It used to be\n // APPENDED to the store, sent, then taken back out with `clear()` + re-add — a non-append\n // rewrite of an append-only history that no event described, so a replay driven from the\n // session log could not reconstruct the store even in principle. It now only ever exists in the\n // OUTGOING array, the same shape `applyStructuredOutputTransport` uses for the schema\n // instruction (CORE-043). Nothing is added, so nothing has to be removed.\n const summaryMessages = [\n ...presentMessageOrigins(conversationStore.getMessages()),\n {\n id: randomId(),\n role: 'user' as const,\n content: syntheticMsg,\n state: 'complete' as const,\n timestamp: new Date(),\n },\n ];\n const systemMsg = config.systemMessage ?? '';\n\n const hasSystemMsg = summaryMessages.some(\n (m) => m.role === 'system' && m.content === systemMsg,\n );\n const messagesForProvider =\n systemMsg && !hasSystemMsg\n ? [\n {\n id: randomId(),\n role: 'system' as const,\n content: systemMsg,\n state: 'complete' as const,\n timestamp: new Date(),\n },\n ...summaryMessages,\n ]\n : summaryMessages;\n\n // CORE-042: this was the one provider call in the turn built by hand -- `{ model, onTextDelta }`,\n // carrying no `signal`, no `effort` and no idle timeout. That was survivable while the streaming\n // path had its own engine; now that the streaming entry awaits the turn when its consumer walks\n // away, an unabortable call here is a hang on the public streaming API. It goes through the same\n // helper every round call goes through, so there is one implementation of \"call the provider\".\n // Tools stay deliberately absent: this call exists to END the tool loop, not to extend it.\n const route = openModelRoute(resolved, resolved.aiProviderInfo.model, executionId);\n const chatOptions: IChatOptions = {\n model: resolved.aiProviderInfo.model,\n effort: config.defaultModel?.effort ?? 'auto',\n // Provider-hosted tools can be enabled by adapter configuration even when no local\n // schemas are passed. A forced summary must remain a text-only terminal call.\n toolChoice: 'none',\n ...(config.defaultModel?.maxTokens !== undefined && {\n maxTokens: config.defaultModel.maxTokens,\n }),\n ...(config.defaultModel?.temperature !== undefined && {\n temperature: config.defaultModel.temperature,\n }),\n ...(fullContext.signal && { signal: fullContext.signal }),\n ...(fullContext.onTextDelta && { onTextDelta: fullContext.onTextDelta }),\n executionId,\n onModelFallback: (notice) => {\n moveModelRoute(route, notice);\n fullContext.onExecutionEvent?.(PROVIDER_FALLBACK_EVENTS.SWITCHED, {\n executionId,\n conversationId,\n round: roundState.currentRound,\n fromProvider: notice.from.provider,\n fromModel: notice.from.model,\n toProvider: notice.to.provider,\n toModel: notice.to.model,\n reason: notice.reason,\n } as TExecutionEventData);\n announceRequest();\n },\n };\n\n // CORE-033: this is a provider call like any other, so it announces itself like one. The SPEC\n // declares `provider_request` REQUIRED, and a replay that cannot see the call the summary came\n // from cannot explain the summary. Emitted with the ASSEMBLED array, for the reason\n // `execution-round-streaming` gives: the request the model received, not the caller's history.\n const announceRequest = (): void => {\n fullContext.onExecutionEvent?.('provider_request', {\n executionId,\n conversationId,\n round: roundState.currentRound,\n provider: routeProvider(route, resolved),\n model: routeModel(route, resolved.aiProviderInfo.model),\n messages: messagesForProvider,\n forcedSummary: true,\n } as TExecutionEventData);\n };\n announceRequest();\n\n const startedAtMs = Date.now();\n const callId = randomId();\n const dispatch: { invoked: boolean; startedAtMs?: number } = { invoked: false };\n let providerOutcome: 'success' | 'failure' | 'interrupted' = 'failure';\n let forceResponse: TUniversalMessage | undefined;\n try {\n forceResponse = await callProviderWithIdleTimeout(\n (messages, options) => {\n // The same adapter-invocation boundary as normal rounds; internal retries stay opaque.\n dispatch.invoked = true;\n dispatch.startedAtMs = Date.now();\n const outbound = resolveProviderCallTraceContext(\n fullContext.traceContext,\n resolved.provider,\n resolved.currentInfo.provider,\n callId,\n );\n return resolved.provider.chat(messages, withOutboundTraceContext(options, outbound));\n },\n messagesForProvider,\n chatOptions,\n config.timeout,\n fullContext.awaitProviderSettlement,\n );\n providerOutcome = 'success';\n } catch (error) {\n if (isAbortFailure(error, fullContext.signal)) providerOutcome = 'interrupted';\n throw error;\n } finally {\n const usage = dispatch.invoked ? verifiedProviderCallUsage(forceResponse) : { provenance: 'absent' as const };\n fullContext.onExecutionEvent?.(PROVIDER_CALL_EVENTS.COMPLETED, {\n executionId,\n conversationId,\n round: roundState.currentRound,\n startedAt: new Date(dispatch.startedAtMs ?? startedAtMs).toISOString(),\n endedAt: new Date(Math.max(Date.now(), dispatch.startedAtMs ?? startedAtMs)).toISOString(),\n outcome: providerOutcome,\n callId,\n disposition: dispatch.invoked ? 'invoked' : 'preflight-refused',\n ...(dispatch.invoked && {\n providerId: routeProvider(route, resolved),\n modelId: routeModel(route, resolved.aiProviderInfo.model),\n ...(typeof forceResponse?.metadata?.['providerRequestId'] === 'string' && {\n providerRequestId: forceResponse.metadata['providerRequestId'],\n }),\n }),\n usageProvenance: usage.provenance,\n ...('promptTokens' in usage && usage.promptTokens !== undefined && {\n promptTokens: usage.promptTokens,\n completionTokens: usage.completionTokens,\n totalTokens: usage.totalTokens,\n }),\n } as TExecutionEventData);\n }\n\n if (!forceResponse) throw new Error('Forced summary provider returned no response.');\n\n const responseText = typeof forceResponse.content === 'string' ? forceResponse.content : '';\n const committedText =\n responseText || 'Maximum rounds reached. Partial results available in conversation history.';\n const verifiedUsage = verifiedProviderCallUsage(forceResponse);\n const summaryMetadata = {\n ...(forceResponse.metadata ?? {}),\n round: roundState.currentRound,\n providerId: routeProvider(route, resolved),\n modelId: routeModel(route, resolved.aiProviderInfo.model),\n usageProvenance: verifiedUsage.provenance,\n ...(verifiedUsage.provenance === 'complete' && {\n inputTokens: verifiedUsage.promptTokens,\n outputTokens: verifiedUsage.completionTokens,\n totalTokens: verifiedUsage.totalTokens,\n }),\n };\n conversationStore.addAssistantMessage(committedText, [], summaryMetadata);\n // CORE-033: the summary is the turn's answer; committing it silently left the last thing the\n // user reads absent from every replay of the conversation.\n fullContext.onExecutionEvent?.('assistant_message_committed', {\n executionId,\n conversationId,\n round: roundState.currentRound,\n message: committedText,\n } as TExecutionEventData);\n announceAppend(conversationStore, fullContext, executionId, conversationId, {\n round: roundState.currentRound,\n });\n } catch (forceErr) {\n logger.warn('Forced summary call failed', {\n error: forceErr instanceof Error ? forceErr.message : String(forceErr),\n });\n }\n}\n","import { announceAppend } from './execution-event-helpers';\nimport { estimateContextTokensFromMessages } from '../context/estimation';\nimport { getModelContextWindow } from '../context/models';\n\nimport type { IExecutionContext, IExecutionRoundState } from './execution-types';\nimport type { IAgentConfig } from '../interfaces/agent';\nimport type { TUniversalMessage } from '../interfaces/messages';\nimport type { ConversationStore } from '../managers/conversation-history-manager';\nimport type { ILogger } from '../utils/logger';\n\nexport const CONTEXT_HARD_BLOCK_THRESHOLD = 0.95;\n\n/**\n * Product-neutral default remediation hint for the hard-capacity notice. This zero-dependency\n * core layer must not emit product vocabulary (e.g. slash commands); a surface tier that has a\n * concrete remediation command injects its own hint via `IAgentConfig.contextCapacityHint`.\n */\nexport const DEFAULT_CONTEXT_CAPACITY_HINT =\n 'Reduce the conversation history (for example, compact or summarize it) and retry.';\n\nexport interface IContextCapacityDecision {\n readonly shouldBlock: boolean;\n readonly estimatedTokens: number;\n readonly contextLimit: number;\n readonly thresholdTokens: number;\n readonly thresholdPercentage: number;\n readonly usedPercentage: number;\n readonly serializedTokens: number;\n readonly providerTokens?: number;\n readonly usageFloorTokens?: number;\n}\n\nexport function getContextCapacityDecision(\n messages: readonly TUniversalMessage[],\n model: string,\n usageFloorTokens: number,\n): IContextCapacityDecision {\n const estimate = estimateContextTokensFromMessages(messages, { usageFloorTokens });\n const contextLimit = getModelContextWindow(model);\n const thresholdTokens = contextLimit * CONTEXT_HARD_BLOCK_THRESHOLD;\n const usedPercentage =\n contextLimit > 0 ? Math.round((estimate.usedTokens / contextLimit) * 10_000) / 100 : 100;\n\n return {\n shouldBlock: estimate.usedTokens > thresholdTokens,\n estimatedTokens: estimate.usedTokens,\n contextLimit,\n thresholdTokens,\n thresholdPercentage: CONTEXT_HARD_BLOCK_THRESHOLD * 100,\n usedPercentage,\n serializedTokens: estimate.serializedTokens,\n ...(estimate.providerTokens !== undefined && { providerTokens: estimate.providerTokens }),\n ...(estimate.usageFloorTokens !== undefined && {\n usageFloorTokens: estimate.usageFloorTokens,\n }),\n };\n}\n\n/** Check context capacity; if near limit, add a hard-block message and return true. */\nexport function handleContextCapacityBlock(\n conversationMessages: readonly TUniversalMessage[],\n config: IAgentConfig,\n roundState: IExecutionRoundState,\n conversationStore: ConversationStore,\n logger: ILogger,\n // CORE-033: the block appends a message, and every append announces itself. Threaded in rather\n // than reached for globally, so this stays a pure function of what it was given — grouped into one\n // argument because three more positionals on a six-positional function is a signature nobody can\n // read at the call site.\n announce: { fullContext: IExecutionContext; executionId: string; conversationId: string },\n): boolean {\n // The round number was also passed in, alongside the `roundState` it is read from — one value\n // arriving twice is one value that can disagree with itself.\n const currentRound = roundState.currentRound;\n const contextDecision = getContextCapacityDecision(\n conversationMessages,\n config.defaultModel.model,\n roundState.cumulativeInputTokens,\n );\n if (!contextDecision.shouldBlock) return false;\n\n logger.warn('[ROUND] Context hard-capacity prevention before provider call', {\n estimatedTokens: contextDecision.estimatedTokens,\n contextLimit: contextDecision.contextLimit,\n thresholdTokens: contextDecision.thresholdTokens,\n thresholdPercentage: contextDecision.thresholdPercentage,\n serializedTokens: contextDecision.serializedTokens,\n providerTokens: contextDecision.providerTokens ?? 0,\n usageFloorTokens: contextDecision.usageFloorTokens ?? 0,\n round: currentRound,\n });\n const capacityHint = config.contextCapacityHint ?? DEFAULT_CONTEXT_CAPACITY_HINT;\n conversationStore.addAssistantMessage(\n `Context window is near capacity. Cannot process further in this round. Estimated ${contextDecision.estimatedTokens.toLocaleString()} / ${contextDecision.contextLimit.toLocaleString()} tokens (${Math.round(contextDecision.usedPercentage)}%) exceeds the hard-block threshold ${Math.round(contextDecision.thresholdPercentage)}%. ${capacityHint}`,\n [],\n {\n round: currentRound,\n contextOverflow: true,\n estimatedTokens: contextDecision.estimatedTokens,\n contextLimit: contextDecision.contextLimit,\n thresholdTokens: contextDecision.thresholdTokens,\n thresholdPercentage: contextDecision.thresholdPercentage,\n serializedTokens: contextDecision.serializedTokens,\n providerTokens: contextDecision.providerTokens ?? 0,\n usageFloorTokens: contextDecision.usageFloorTokens ?? 0,\n usedPercentage: contextDecision.usedPercentage,\n },\n );\n // CORE-033: the block ENDS the round, and this diagnostic is the only thing the user sees for it.\n // Appending it without a `history_mutation` left a replay of the session log short exactly one\n // message — and the one explaining why the turn stopped.\n announceAppend(\n conversationStore,\n announce.fullContext,\n announce.executionId,\n announce.conversationId,\n { round: currentRound, contextOverflow: true },\n );\n return true;\n}\n","import { announceAppend } from './execution-event-helpers';\nimport { callProviderWithCache } from './execution-round-provider';\nimport { resolveToolChoiceForRound } from './execution-service-helpers';\nimport { isAbortFailure } from '../utils/abort-classification';\nimport { randomId } from '../utils/random-id';\nimport { verifiedProviderCallUsage } from './provider-call-usage';\nimport { resolveProviderCallTraceContext } from './execution-trace-context';\nimport { PROVIDER_CALL_EVENTS, PROVIDER_FALLBACK_EVENTS } from '../event-service/span-events';\nimport { moveModelRoute, openModelRoute, routeModel, routeProvider } from './execution-model-route';\n\nimport type { IAssembledProviderRequest } from './execution-round-provider';\nimport type { IModelRoute } from './execution-model-route';\n\nimport type { IExecutionContext, IResolvedProviderInfo } from './execution-types';\nimport type { IAgentConfig, TExecutionEventData } from '../interfaces/agent';\nimport type { TUniversalMessage } from '../interfaces/messages';\nimport type { TProviderNativeRawPayloadCallback } from '../interfaces/provider';\nimport type { ConversationStore } from '../managers/conversation-history-manager';\nimport type { ExecutionCacheService } from './cache/execution-cache-service';\nimport type { ILogger } from '../utils/logger';\n\nexport interface IRoundStreamingCallbacks {\n wrappedOnTextDelta: (delta: string) => void;\n wrappedOnProviderNativeRawPayload: TProviderNativeRawPayloadCallback;\n}\n\nexport function createRoundStreamingCallbacks(\n fullContext: IExecutionContext,\n conversationStore: ConversationStore,\n executionId: string,\n currentRound: number,\n): IRoundStreamingCallbacks {\n let streamDeltaSequence = 0;\n let providerNativeRawPayloadSequence = 0;\n\n const wrappedOnTextDelta = (delta: string): void => {\n fullContext.onExecutionEvent?.('provider_stream_raw_delta', {\n executionId,\n conversationId: fullContext.conversationId,\n round: currentRound,\n sequence: streamDeltaSequence,\n delta,\n } as TExecutionEventData);\n streamDeltaSequence++;\n conversationStore.appendStreaming(delta);\n fullContext.onTextDelta?.(delta);\n };\n\n const wrappedOnProviderNativeRawPayload: TProviderNativeRawPayloadCallback = (event): void => {\n const sequence = event.sequence ?? providerNativeRawPayloadSequence;\n providerNativeRawPayloadSequence = Math.max(providerNativeRawPayloadSequence, sequence + 1);\n fullContext.onExecutionEvent?.('provider_native_raw_payload', {\n executionId,\n conversationId: fullContext.conversationId,\n round: currentRound,\n ...event,\n sequence,\n } as TExecutionEventData);\n };\n\n return { wrappedOnTextDelta, wrappedOnProviderNativeRawPayload };\n}\n\n/** Call the provider with event emissions. Returns null if round should break; throws on abort. */\nexport async function callRoundProviderWithEvents(\n conversationMessages: TUniversalMessage[],\n config: IAgentConfig,\n resolved: IResolvedProviderInfo,\n cacheService: ExecutionCacheService | undefined,\n fullContext: IExecutionContext,\n conversationStore: ConversationStore,\n currentRound: number,\n executionId: string,\n usageObservationId: string,\n logger: ILogger,\n wrappedOnTextDelta: (delta: string) => void,\n wrappedOnProviderNativeRawPayload: TProviderNativeRawPayloadCallback,\n onProviderFailure?: (error: unknown) => void,\n /** Where the request is actually answered; read by the caller to attribute the committed reply. */\n route: IModelRoute = openModelRoute(resolved, config.defaultModel.model, executionId),\n): Promise<TUniversalMessage | null> {\n const startedAtMs = Date.now();\n const callId = randomId();\n const dispatch: { disposition: 'invoked' | 'cache-hit' | 'preflight-refused'; model?: string; startedAtMs?: number } = {\n disposition: 'preflight-refused',\n };\n let providerResponse: TUniversalMessage | undefined;\n let outcome: 'success' | 'failure' | 'interrupted' = 'failure';\n let assembled: IAssembledProviderRequest | undefined;\n const announceRequest = (request: IAssembledProviderRequest): void => {\n fullContext.onExecutionEvent?.('provider_request', {\n executionId,\n conversationId: fullContext.conversationId,\n round: currentRound,\n provider: routeProvider(route, resolved),\n model: routeModel(route, config.defaultModel.model),\n effort: request.options.effort,\n messages: request.messages,\n tools: request.options.tools,\n } as TExecutionEventData);\n };\n try {\n const response = await callProviderWithCache(\n conversationMessages,\n config,\n resolved,\n cacheService,\n {\n signal: fullContext.signal,\n onTextDelta: wrappedOnTextDelta,\n onProviderNativeRawPayload: wrappedOnProviderNativeRawPayload,\n // CORE-016/017: run-scoped model option overrides win over defaultModel.\n ...(fullContext.maxTokens !== undefined && { maxTokens: fullContext.maxTokens }),\n ...(fullContext.temperature !== undefined && { temperature: fullContext.temperature }),\n ...(fullContext.withholdHostedTools === true && {\n nativeWebTools: { webSearch: false, webFetch: false },\n }),\n executionId,\n // The same request, now sent to another model: it is announced again under that model's\n // name, so the replay channel and every usage record name the model that answered.\n onModelFallback: (notice) => {\n moveModelRoute(route, notice);\n dispatch.model = notice.to.model;\n fullContext.onExecutionEvent?.(PROVIDER_FALLBACK_EVENTS.SWITCHED, {\n executionId,\n conversationId: fullContext.conversationId,\n round: currentRound,\n fromProvider: notice.from.provider,\n fromModel: notice.from.model,\n toProvider: notice.to.provider,\n toModel: notice.to.model,\n reason: notice.reason,\n } as TExecutionEventData);\n if (assembled !== undefined) announceRequest(assembled);\n },\n // Forcing directives apply to round 1 only — later rounds revert to 'auto' so the\n // model can consume tool results and finish (resolved against run-then-default).\n ...(() => {\n const effectiveToolChoice = resolveToolChoiceForRound(\n fullContext.toolChoice ?? config.defaultModel.toolChoice,\n currentRound,\n );\n return effectiveToolChoice !== undefined ? { toolChoice: effectiveToolChoice } : {};\n })(),\n },\n // Emitted from here, not before the call, so the replay channel records the request as\n // ASSEMBLED. The structured-output guard can add a system instruction that\n // `conversationMessages` does not contain, and a `provider_request` logging the caller's own\n // array would describe a request that was never sent — `agent-session/docs/SPEC.md` promises\n // this event carries the request envelope, and a replay has to be able to reproduce it.\n // The same rule holds for `tools` (CLI-1990): the wire carries the residency projection and\n // whatever the model-capability guard removed, so the envelope logs the options as sent, not\n // the registry the round was assembled from.\n (request) => {\n assembled = request;\n announceRequest(request);\n // CORE-043: which transport actually carried the schema. The OUTCOME, not the resolution —\n // \"the table declares json_schema\" describes a catalog, while \"the schema was sent as a\n // parameter, so no prompt statement was needed\" explains the result the caller is holding.\n const structured = request.structuredOutput;\n if (structured !== undefined) {\n fullContext.onExecutionEvent?.('structured_output_transport', {\n executionId,\n conversationId: fullContext.conversationId,\n round: currentRound,\n provider: resolved.currentInfo.provider,\n model: config.defaultModel.model,\n mechanism: structured.capability.mechanism,\n provenance: structured.capability.provenance,\n sent: structured.sent,\n schemaInPrompt: structured.schemaInPrompt,\n ...(structured.capability.reason !== undefined && {\n reason: structured.capability.reason,\n }),\n } as TExecutionEventData);\n }\n },\n fullContext.awaitProviderSettlement,\n (actualDisposition, model) => {\n dispatch.disposition = actualDisposition;\n dispatch.model = routeModel(route, model);\n if (actualDisposition === 'invoked') dispatch.startedAtMs = Date.now();\n },\n () => resolveProviderCallTraceContext(\n fullContext.traceContext,\n resolved.provider,\n resolved.currentInfo.provider,\n callId,\n ),\n route,\n );\n providerResponse = response;\n // CORE-042: a provider that returned assembled text without streaming any of it still owes the\n // caller its deltas — `IChatOptions.onTextDelta`'s contract is what such a provider is violating,\n // and `run(onTextDelta)` against one emitted nothing at all before this. Routing the assembled\n // text through the SAME wrapper means both entry points get it, rather than the streaming entry\n // special-casing it and becoming a second implementation on day one.\n //\n // Emitted BEFORE the response events on purpose: every real streaming round delivers its deltas\n // ahead of the normalized response, and a replay consumer folding deltas until that arrives would\n // otherwise attribute this one to the next round.\n //\n // Stated as the TAIL rather than as \"emitted nothing\", because history commits the delta buffer\n // and not the returned message: a provider whose deltas stop short of its own assembled text\n // truncates the committed assistant message, silently. The no-delta case is that same bug with\n // an empty buffer. When the buffer is not a prefix of the assembled text the provider has\n // contradicted itself; that is not repaired here by guessing, but it is not passed over in\n // silence either.\n if (typeof response.content === 'string' && response.content.length > 0) {\n const streamed = conversationStore.getPendingContent();\n if (response.content.startsWith(streamed)) {\n const tail = response.content.slice(streamed.length);\n if (tail.length > 0) {\n wrappedOnTextDelta(tail);\n }\n } else {\n logger.warn(\n 'Provider deltas are not a prefix of its assembled message — committing the streamed text',\n {\n conversationId: fullContext.conversationId,\n round: currentRound,\n streamedLength: streamed.length,\n assembledLength: response.content.length,\n },\n );\n }\n }\n fullContext.onExecutionEvent?.('provider_response_raw', {\n executionId,\n conversationId: fullContext.conversationId,\n round: currentRound,\n effort: config.defaultModel?.effort ?? 'high',\n response,\n responseKind: 'provider-normalized-message',\n } as TExecutionEventData);\n fullContext.onExecutionEvent?.('provider_response_normalized', {\n executionId,\n conversationId: fullContext.conversationId,\n round: currentRound,\n response,\n toolCallsCount:\n response.role === 'assistant' && Array.isArray(response.toolCalls)\n ? response.toolCalls.length\n : 0,\n } as TExecutionEventData);\n outcome = 'success';\n return response;\n } catch (providerError) {\n // allow-fallback: provider errors terminate the round, not the process\n //\n // CORE-027: classified from the SIGNAL this round was given and from the error's own name, never\n // from its prose. The substring test that stood here committed the round as `interrupted` for\n // any provider failure whose message happened to contain \"abort\".\n if (isAbortFailure(providerError, fullContext.signal)) {\n outcome = 'interrupted';\n conversationStore.commitAssistant('interrupted', {\n round: currentRound,\n usageObservationId,\n executionId,\n providerId: routeProvider(route, resolved),\n modelId: routeModel(route, resolved.aiProviderInfo.model),\n });\n throw providerError;\n }\n conversationStore.discardPending();\n // CORE-027: the message below is DISPLAY, not the failure's representation. The thrown value\n // itself is handed out so the final result can carry it with class, code, category, stack and\n // cause intact — rebuilding it from this prose is the round trip that destroyed all of them.\n onProviderFailure?.(providerError);\n const errMsg = providerError instanceof Error ? providerError.message : String(providerError);\n logger.error('[ROUND] Provider call failed', { error: errMsg, round: currentRound });\n conversationStore.addAssistantMessage(`Request failed: ${errMsg}`, [], {\n round: currentRound,\n usageObservationId,\n executionId,\n providerId: routeProvider(route, resolved),\n modelId: routeModel(route, resolved.aiProviderInfo.model),\n providerError: true,\n });\n // CORE-033: announced like every other append. A failed turn is precisely when a reader goes to\n // the session log, and this record was the one message the log never contained.\n announceAppend(conversationStore, fullContext, executionId, fullContext.conversationId, {\n round: currentRound,\n usageObservationId,\n executionId,\n providerId: routeProvider(route, resolved),\n modelId: routeModel(route, resolved.aiProviderInfo.model),\n providerError: true,\n });\n return null;\n } finally {\n const usage = dispatch.disposition === 'invoked'\n ? verifiedProviderCallUsage(providerResponse)\n : { provenance: 'absent' as const };\n // A single content-free lifecycle observation per attempted provider round. This is emitted\n // even when the provider fails or the turn is interrupted; it contains no request/response.\n fullContext.onExecutionEvent?.(PROVIDER_CALL_EVENTS.COMPLETED, {\n executionId,\n conversationId: fullContext.conversationId,\n round: currentRound,\n startedAt: new Date(dispatch.startedAtMs ?? startedAtMs).toISOString(),\n endedAt: new Date(Math.max(Date.now(), dispatch.startedAtMs ?? startedAtMs)).toISOString(),\n outcome,\n callId,\n disposition: dispatch.disposition,\n ...(dispatch.disposition === 'invoked' && {\n providerId: routeProvider(route, resolved),\n ...(dispatch.model !== undefined && { modelId: dispatch.model }),\n ...(typeof providerResponse?.metadata?.['providerRequestId'] === 'string' && {\n providerRequestId: providerResponse.metadata['providerRequestId'],\n }),\n }),\n usageProvenance: usage.provenance,\n ...('promptTokens' in usage && usage.promptTokens !== undefined && {\n promptTokens: usage.promptTokens,\n completionTokens: usage.completionTokens,\n totalTokens: usage.totalTokens,\n }),\n } as TExecutionEventData);\n }\n}\n","import { isExecutionError, PREVIEW_LENGTH } from './execution-types';\nimport { ARGUMENT_DECODE_ERROR_CODE, UNKNOWN_TOOL_ERROR_CODE } from './tool-execution-service';\nimport { estimateContextTokensFromMessages } from '../context/estimation';\n\nimport type { IToolCall, TUniversalMessageMetadata } from '../interfaces/messages';\nimport type { TToolMetadata } from '../interfaces/tool';\nimport type { ConversationStore } from '../managers/conversation-history-manager';\nimport type { ILogger } from '../utils/logger';\n\n/** Result of addToolResultsToHistory indicating whether context overflow occurred */\nexport interface IToolResultsOutcome {\n contextOverflowed: boolean;\n addedCount: number;\n skippedCount: number;\n unknownToolFailureCount: number;\n unknownToolNames: string[];\n}\n\nconst CONTEXT_OVERFLOW_TOOL_SKIP_MESSAGE =\n 'Error: Context window near capacity. Tool execution result skipped. Respond with available results and re-request skipped tools if needed.';\n\nexport function isUnknownToolExecutionResult(result: {\n success: boolean;\n metadata?: { errorCode?: string };\n}): boolean {\n return !result.success && result.metadata?.errorCode === UNKNOWN_TOOL_ERROR_CODE;\n}\n\n/** Issue #2875 (follow-up to #2078): a call whose arguments failed to decode never reached the tool. */\nexport function isArgumentDecodeErrorResult(result: {\n success: boolean;\n metadata?: { errorCode?: string };\n}): boolean {\n return !result.success && result.metadata?.errorCode === ARGUMENT_DECODE_ERROR_CODE;\n}\n\n/** Add tool execution results to conversation history in call order */\nexport function addToolResultsToHistory(\n assistantToolCalls: IToolCall[],\n toolSummary: {\n results: Array<{\n executionId?: string;\n toolName?: string;\n success: boolean;\n result?: unknown;\n error?: string;\n metadata?: TToolMetadata;\n }>;\n errors: Error[];\n },\n conversationStore: ConversationStore,\n currentRound: number,\n logger: ILogger,\n contextBudget?: { contextLimit: number; cumulativeInputTokens: number },\n): IToolResultsOutcome {\n const TOOL_RESULT_OVERFLOW_THRESHOLD = 0.8;\n let contextOverflowed = false;\n let addedCount = 0;\n let skippedCount = 0;\n\n for (const toolCall of assistantToolCalls) {\n if (!toolCall.id) {\n throw new Error(`Tool call missing ID: ${JSON.stringify(toolCall)}`);\n }\n const toolCallName = toolCall.function?.name;\n if (!toolCallName || toolCallName.length === 0) {\n throw new Error(`[EXECUTION] Tool call \"${toolCall.id}\" missing function name`);\n }\n\n if (contextOverflowed) {\n logger.warn('[ROUND] Skipping tool result due to context overflow', {\n toolCallId: toolCall.id,\n toolName: toolCallName,\n round: currentRound,\n });\n conversationStore.addToolMessageWithId(\n CONTEXT_OVERFLOW_TOOL_SKIP_MESSAGE,\n toolCall.id,\n toolCallName,\n { round: currentRound, success: false, error: 'context_overflow', toolName: toolCallName },\n );\n skippedCount++;\n continue;\n }\n\n const result = toolSummary.results.find((r) => r.executionId === toolCall.id);\n const error = toolSummary.errors.find(\n (e) => isExecutionError(e) && e.executionId === toolCall.id,\n );\n\n let content: string;\n const metadata: TUniversalMessageMetadata = { round: currentRound };\n\n if (result && result.success) {\n if (typeof result.result === 'undefined') {\n throw new Error('[EXECUTION] Tool result missing result payload');\n }\n content = typeof result.result === 'string' ? result.result : JSON.stringify(result.result);\n metadata['success'] = true;\n if (result.toolName) metadata['toolName'] = result.toolName;\n } else if (result && !result.success) {\n if (!result.error || result.error.length === 0) {\n throw new Error('[EXECUTION] Tool result missing error message');\n }\n content = `Error: ${result.error}`;\n metadata['success'] = false;\n metadata['error'] = result.error;\n if (result.toolName) metadata['toolName'] = result.toolName;\n if (result.metadata?.errorCode === UNKNOWN_TOOL_ERROR_CODE) {\n metadata['errorCode'] = UNKNOWN_TOOL_ERROR_CODE;\n if (typeof result.metadata.requestedTool === 'string') {\n metadata['requestedTool'] = result.metadata.requestedTool;\n }\n if (Array.isArray(result.metadata.availableTools)) {\n metadata['availableTools'] = result.metadata.availableTools.filter(\n (toolName): toolName is string => typeof toolName === 'string',\n );\n }\n }\n if (result.metadata?.errorCode === ARGUMENT_DECODE_ERROR_CODE) {\n metadata['errorCode'] = ARGUMENT_DECODE_ERROR_CODE;\n if (typeof result.metadata.requestedTool === 'string') {\n metadata['requestedTool'] = result.metadata.requestedTool;\n }\n }\n } else if (error) {\n const execError = error as { error?: Error; message: string; toolName?: string };\n const execMessage = (() => {\n if (execError.error?.message) return execError.error.message;\n if (execError.message) return execError.message;\n return '';\n })();\n if (!execMessage || execMessage.length === 0) {\n throw new Error('[EXECUTION] Tool execution error missing message');\n }\n content = `Error: ${execMessage}`;\n metadata['success'] = false;\n metadata['error'] = execMessage;\n if (execError.toolName) metadata['toolName'] = execError.toolName;\n } else {\n throw new Error(`No execution result found for tool call ID: ${toolCall.id}`);\n }\n\n logger.debug('Adding tool result to conversation', {\n toolCallId: toolCall.id,\n toolName: toolCallName,\n content: content.substring(0, PREVIEW_LENGTH),\n round: currentRound,\n currentHistoryLength: conversationStore.getMessages().length,\n });\n\n conversationStore.addToolMessageWithId(content, toolCall.id, toolCallName, metadata);\n\n if (contextBudget) {\n const estimate = estimateContextTokensFromMessages(conversationStore.getMessages(), {\n usageFloorTokens: contextBudget.cumulativeInputTokens,\n });\n const estimatedTokens = estimate.usedTokens;\n if (estimatedTokens > contextBudget.contextLimit * TOOL_RESULT_OVERFLOW_THRESHOLD) {\n logger.warn(\n '[ROUND] Context budget exceeded after tool result — skipping remaining tools',\n {\n estimatedTokens,\n contextLimit: contextBudget.contextLimit,\n toolCallId: toolCall.id,\n round: currentRound,\n },\n );\n contextOverflowed = true;\n }\n }\n\n addedCount++;\n\n logger.debug('Tool result added to history', {\n toolCallId: toolCall.id,\n newHistoryLength: conversationStore.getMessages().length,\n round: currentRound,\n });\n }\n\n return {\n contextOverflowed,\n addedCount,\n skippedCount,\n unknownToolFailureCount: 0,\n unknownToolNames: [],\n };\n}\n","import {\n type IToolResultsOutcome,\n addToolResultsToHistory,\n isArgumentDecodeErrorResult,\n isUnknownToolExecutionResult,\n} from './execution-round-tool-results';\nimport { type IExecutionRoundState } from './execution-types';\nimport { getModelContextWindow } from '../context/models';\nimport { SameToolInputLoopError } from '../utils/errors';\n\nimport type { IRoundDependencies } from './execution-round-types';\nimport type { IToolExecutionBatchContext } from './tool-execution-service';\nimport type {\n IAgentConfig,\n TExecutionEventCallback,\n TExecutionEventData,\n} from '../interfaces/agent';\nimport type { IToolCall } from '../interfaces/messages';\nimport type { IRunTraceContext } from '../interfaces/trace-context';\nimport type { ConversationStore } from '../managers/conversation-history-manager';\n\nexport type { IToolResultsOutcome } from './execution-round-tool-results';\n\n/** @internal exported for unit testing */\nexport function checkSameToolInputLimit(\n assistantToolCalls: IToolCall[],\n roundState: IExecutionRoundState,\n maxSameToolInputs: number,\n): void {\n for (const toolCall of assistantToolCalls) {\n const name = toolCall.function?.name ?? 'unknown';\n const args =\n typeof toolCall.function?.arguments === 'string'\n ? toolCall.function.arguments\n : JSON.stringify(toolCall.function?.arguments ?? {});\n const key = `${name}::${args}`;\n const count = (roundState.sameToolInputCounts.get(key) ?? 0) + 1;\n roundState.sameToolInputCounts.set(key, count);\n // CORE-035: `maxSameToolInputs` names a MAXIMUM, so the Nth identical call is allowed and the\n // N+1th trips. The SPEC used to say \"N or more times\", contradicting its own option name.\n if (count > maxSameToolInputs) {\n throw new SameToolInputLoopError(name, count, maxSameToolInputs);\n }\n }\n}\n\n/** Execute tools from assistant tool calls and add results to conversation history */\nexport async function executeAndRecordToolCalls(\n assistantToolCalls: IToolCall[],\n conversationStore: ConversationStore,\n conversationId: string,\n executionId: string,\n currentRound: number,\n thinkingNodeId: string,\n previousThinkingNodeId: string | undefined,\n roundState: IExecutionRoundState,\n deps: IRoundDependencies,\n config?: IAgentConfig,\n signal?: AbortSignal,\n onExecutionEvent?: TExecutionEventCallback,\n maxSameToolInputs?: number,\n traceContext?: IRunTraceContext,\n): Promise<IToolResultsOutcome> {\n const { toolExecutionService, logger, eventEmitter } = deps;\n\n const resolvedMaxSameToolInputs = maxSameToolInputs ?? config?.maxSameToolInputs;\n if (resolvedMaxSameToolInputs !== undefined) {\n checkSameToolInputLimit(assistantToolCalls, roundState, resolvedMaxSameToolInputs);\n }\n\n logger.debug('Tool calls detected, executing tools', {\n toolCallCount: assistantToolCalls.length,\n round: currentRound,\n toolCalls: assistantToolCalls.map((tc: IToolCall) => ({ id: tc.id, name: tc.function?.name })),\n });\n\n const toolOwnerPathBase = eventEmitter.buildThinkingOwnerContext(\n conversationId,\n executionId,\n thinkingNodeId,\n previousThinkingNodeId,\n ).ownerPath;\n const expectedCountForBatch = assistantToolCalls.length;\n const batchId = `${thinkingNodeId}`;\n const toolRequestsBase = toolExecutionService.createExecutionRequestsWithContext(\n assistantToolCalls,\n {\n ownerPathBase: toolOwnerPathBase,\n metadataFactory: (toolCall) => ({\n conversationId,\n round: currentRound,\n directParentId: thinkingNodeId,\n batchId,\n expectedCount: expectedCountForBatch,\n toolCallId: toolCall.id,\n }),\n },\n );\n const toolRequests = toolRequestsBase.map((request) => {\n if (!request.ownerId) {\n throw new Error('[EXECUTION] Tool request missing ownerId');\n }\n return {\n ...request,\n eventService: eventEmitter.ensureToolEventService(request.ownerId, request.ownerPath),\n baseEventService: eventEmitter.getBaseEventService(),\n ...(traceContext ? { traceContext } : {}),\n };\n });\n const toolContext: IToolExecutionBatchContext = {\n requests: toolRequests,\n mode: 'parallel',\n maxConcurrency: 5,\n continueOnError: true,\n signal,\n };\n\n onExecutionEvent?.('tool_batch_started', {\n executionId,\n conversationId,\n round: currentRound,\n batchId,\n mode: toolContext.mode,\n maxConcurrency: toolContext.maxConcurrency,\n requestCount: toolRequests.length,\n tools: toolRequests.map((request) => request.toolName),\n } as TExecutionEventData);\n toolRequests.forEach((request, index) => {\n onExecutionEvent?.('tool_execution_request', {\n executionId,\n conversationId,\n round: currentRound,\n batchId,\n index,\n toolName: request.toolName,\n toolCallId: request.executionId,\n // Issue #2875: `request.parameters` is a placeholder ({}) when the call's arguments failed to\n // decode — reporting it unchanged would misrepresent a malformed call as one that ran with no\n // arguments. Report the decode error instead; the field stays a record either way.\n parameters:\n request.argumentDecodeError !== undefined\n ? { argumentDecodeError: request.argumentDecodeError }\n : request.parameters,\n ownerPath: request.ownerPath,\n } as TExecutionEventData);\n });\n\n const toolSummary = await toolExecutionService.executeTools(toolContext);\n const unknownToolNames = toolSummary.results\n .filter(isUnknownToolExecutionResult)\n .map((result) => result.toolName)\n .filter((toolName): toolName is string => typeof toolName === 'string' && toolName.length > 0);\n\n toolSummary.results.forEach((result, index) => {\n onExecutionEvent?.('tool_execution_result', {\n executionId,\n conversationId,\n round: currentRound,\n batchId,\n index,\n toolName: result.toolName,\n toolCallId: result.executionId,\n success: result.success,\n result: result.result,\n error: result.error,\n metadata: result.metadata,\n } as TExecutionEventData);\n });\n\n roundState.toolsExecuted.push(\n ...toolSummary.results\n .filter((result) => !isUnknownToolExecutionResult(result) && !isArgumentDecodeErrorResult(result))\n .map((r) => {\n if (!r.toolName || r.toolName.length === 0) {\n throw new Error('[EXECUTION] Tool result missing toolName');\n }\n return r.toolName;\n }),\n );\n\n const contextLimit = getModelContextWindow(config?.defaultModel?.model ?? '');\n const messageCountBeforeToolResults = conversationStore.getMessages().length;\n const toolResultsOutcome = addToolResultsToHistory(\n assistantToolCalls,\n toolSummary,\n conversationStore,\n currentRound,\n logger,\n { contextLimit, cumulativeInputTokens: roundState.cumulativeInputTokens },\n );\n const addedToolMessages = conversationStore.getMessages().slice(messageCountBeforeToolResults);\n addedToolMessages.forEach((message, offset) => {\n onExecutionEvent?.('tool_message_committed', {\n executionId,\n conversationId,\n round: currentRound,\n batchId,\n index: offset,\n message,\n } as TExecutionEventData);\n onExecutionEvent?.('history_mutation', {\n executionId,\n conversationId,\n round: currentRound,\n batchId,\n mutation: 'append_message',\n index: messageCountBeforeToolResults + offset,\n message,\n } as TExecutionEventData);\n });\n\n eventEmitter.emitToolResultsEvents(\n assistantToolCalls,\n toolSummary,\n roundState.toolsExecuted,\n conversationId,\n executionId,\n currentRound,\n thinkingNodeId,\n previousThinkingNodeId,\n );\n\n eventEmitter.clearToolEventServices();\n\n return {\n ...toolResultsOutcome,\n unknownToolFailureCount: unknownToolNames.length,\n unknownToolNames,\n };\n}\n","import { readTokenUsageFromMessage } from '../context/token-usage';\nimport { chatEntryToMessage, isChatEntry } from '../interfaces/messages';\nimport { randomId } from '../utils/random-id';\n\nimport type { IHistoryEntry, TUniversalMessage } from '../interfaces/messages';\nimport type { ITokenUsage } from '../interfaces/provider';\n\n/**\n * Aggregate token totals over a whole session/sub-session history.\n *\n * TYPE-003: alias of the usage-triple SSOT ({@link ITokenUsage}) — the aggregate shape is the\n * same triple by definition, so it is derived rather than re-declared.\n */\nexport type ISessionUsageTotals = ITokenUsage;\n\n/**\n * ANALYTICS-001 (Phase 2): sum assistant token usage across a history timeline — used to capture a\n * subagent / background task's total usage so it can be attributed to its source in the parent log.\n * Returns undefined when no usage was reported (so callers can skip recording an empty entry).\n */\nexport function sumHistoryUsage(\n history: readonly IHistoryEntry[],\n): ISessionUsageTotals | undefined {\n let promptTokens = 0;\n let completionTokens = 0;\n let found = false;\n for (const entry of history) {\n if (!isChatEntry(entry) || entry.data === undefined) continue;\n const message = chatEntryToMessage(entry);\n if (message.role !== 'assistant') continue;\n const usage = collectAssistantUsageMetadata(message);\n if (!usage) continue;\n found = true;\n promptTokens += usage.inputTokens;\n completionTokens += usage.outputTokens;\n }\n if (!found) return undefined;\n return { promptTokens, completionTokens, totalTokens: promptTokens + completionTokens };\n}\n\nexport interface IAssistantUsageMetadata {\n inputTokens: number;\n outputTokens: number;\n usage: {\n totalTokens: number;\n inputTokens: number;\n outputTokens: number;\n };\n}\n\nexport function createUsageObservationId(): string {\n return randomId();\n}\n\nexport function collectAssistantUsageMetadata(\n message: TUniversalMessage,\n): IAssistantUsageMetadata | undefined {\n const usage = readTokenUsageFromMessage(message);\n if (!usage) return undefined;\n\n const totalTokens = usage.totalTokens ?? usage.inputTokens + usage.outputTokens;\n return {\n inputTokens: usage.inputTokens,\n outputTokens: usage.outputTokens,\n usage: {\n totalTokens,\n inputTokens: usage.inputTokens,\n outputTokens: usage.outputTokens,\n },\n };\n}\n","import { EXECUTION_EVENTS } from './execution-constants';\nimport { handleContextCapacityBlock } from './execution-round-context';\nimport {\n computeRoundThinkingContext,\n validateAndExtractResponse,\n} from './execution-round-provider';\nimport {\n createRoundStreamingCallbacks,\n callRoundProviderWithEvents,\n} from './execution-round-streaming';\nimport { executeAndRecordToolCalls } from './execution-round-tools';\nimport { openModelRoute, routeModel, routeProvider } from './execution-model-route';\nimport {\n type IResolvedProviderInfo,\n type IExecutionRoundState,\n type IExecutionContext,\n SHORT_PREVIEW_LENGTH,\n LAST_MESSAGES_SLICE,\n MAX_CONSECUTIVE_UNKNOWN_TOOL_FAILURE_ROUNDS,\n} from './execution-types';\nimport * as executionUsage from './execution-usage';\nimport { callPluginHook } from './plugin-hook-dispatcher';\nimport { presentMessageOrigins } from './message-origin';\nimport { bindWithOwnerPath } from '../event-service/index';\nimport { createSystemMessage } from '../managers/conversation-message-factory';\n\nimport type { IAgentConfig, TExecutionEventData } from '../interfaces/agent';\nimport type { TMessageState } from '../interfaces/messages';\nimport type { ConversationStore } from '../managers/conversation-history-manager';\n\nexport type { IToolResultsOutcome } from './execution-round-tools';\nexport {\n computeRoundThinkingContext,\n callProviderWithCache,\n validateAndExtractResponse,\n} from './execution-round-provider';\nexport { executeAndRecordToolCalls } from './execution-round-tools';\nexport { addToolResultsToHistory } from './execution-round-tool-results';\nexport {\n CONTEXT_HARD_BLOCK_THRESHOLD,\n type IContextCapacityDecision,\n getContextCapacityDecision,\n} from './execution-round-context';\n\nexport type { IRoundDependencies } from './execution-round-types';\nimport type { IRoundDependencies } from './execution-round-types';\n\nexport async function executeRound(\n roundState: IExecutionRoundState,\n maxRounds: number,\n conversationStore: ConversationStore,\n conversationId: string,\n executionId: string,\n fullContext: IExecutionContext,\n config: IAgentConfig,\n resolved: IResolvedProviderInfo,\n deps: IRoundDependencies,\n): Promise<boolean> {\n const { plugins, logger, eventEmitter, cacheService } = deps;\n const currentRound = roundState.currentRound;\n logger.debug(`[ROUND-${currentRound}] Starting execution round ${currentRound}`, {\n executionId,\n conversationId: fullContext.conversationId,\n round: currentRound,\n maxRounds,\n });\n const conversationMessages = conversationStore.getMessages();\n // The request marks each peer-driven message as a peer's; the stored history is left as sent.\n const requestMessages = presentMessageOrigins(conversationMessages);\n // SELFHOST-008 P3: an EPHEMERAL per-run system block (e.g. per-turn recalled memory) is appended to a\n // DERIVED provider-message array only — it is sent to the model for this call but never written to the\n // conversation store, so it does not persist to history nor rebuild the cached static system prompt.\n const ephemeralSystemContext = fullContext.ephemeralSystemContext;\n const providerMessages =\n ephemeralSystemContext && ephemeralSystemContext.trim().length > 0\n ? [...requestMessages, createSystemMessage(ephemeralSystemContext)]\n : requestMessages;\n const { thinkingNodeId, previousThinkingNodeId } = computeRoundThinkingContext(\n conversationId,\n roundState,\n );\n\n await callPluginHook(plugins, 'beforeProviderCall', { messages: conversationMessages }, logger);\n logger.debug('Sending messages to AI provider', {\n round: currentRound,\n messageCount: conversationMessages.length,\n lastFewMessages: conversationMessages.slice(LAST_MESSAGES_SLICE).map((m) => ({\n role: m.role,\n content: m.content?.substring(0, SHORT_PREVIEW_LENGTH),\n hasToolCalls: 'toolCalls' in m ? !!m.toolCalls?.length : false,\n toolCallId: 'toolCallId' in m ? m.toolCallId : undefined,\n })),\n });\n\n eventEmitter.emitWithContext(\n EXECUTION_EVENTS.ASSISTANT_MESSAGE_START,\n {\n parameters: { round: currentRound, messageCount: conversationMessages.length },\n metadata: { round: currentRound, thinkingNodeId },\n },\n () =>\n eventEmitter.buildThinkingOwnerContext(\n conversationId,\n executionId,\n thinkingNodeId,\n previousThinkingNodeId,\n ),\n (ctx) => {\n if (!ctx.ownerType || !ctx.ownerId) {\n throw new Error('[EXECUTION] Missing owner context for thinking event');\n }\n return bindWithOwnerPath(eventEmitter.getBaseEventService(), {\n ownerType: ctx.ownerType,\n ownerId: ctx.ownerId,\n ownerPath: ctx.ownerPath,\n });\n },\n );\n\n // Pre-send hard-capacity check. Routine compaction is owned by agent-sessions; this guard is\n // only a last safety stop when the effective context estimate is already near the model limit.\n if (\n handleContextCapacityBlock(\n conversationMessages,\n config,\n roundState,\n conversationStore,\n logger,\n { fullContext, executionId, conversationId },\n )\n ) {\n return true;\n }\n\n if (currentRound > 1) {\n fullContext.onTextDelta?.('\\n\\n');\n }\n\n conversationStore.beginAssistant();\n const usageObservationId = executionUsage.createUsageObservationId();\n\n const { wrappedOnTextDelta, wrappedOnProviderNativeRawPayload } = createRoundStreamingCallbacks(\n fullContext,\n conversationStore,\n executionId,\n currentRound,\n );\n\n const route = openModelRoute(resolved, config.defaultModel.model, executionId);\n const response = await callRoundProviderWithEvents(\n providerMessages,\n config,\n resolved,\n cacheService,\n fullContext,\n conversationStore,\n currentRound,\n executionId,\n usageObservationId,\n logger,\n wrappedOnTextDelta,\n wrappedOnProviderNativeRawPayload,\n (error) => void (roundState.providerFailure = error),\n route,\n );\n if (response === null) return true;\n\n const { assistantResponse, assistantToolCalls } = validateAndExtractResponse(\n response,\n executionId,\n fullContext.conversationId,\n currentRound,\n logger,\n );\n if (\n assistantToolCalls.length > 0 &&\n (fullContext.toolChoice ?? config.defaultModel?.toolChoice) === 'none'\n ) {\n throw new Error(\n 'Provider returned tool calls despite toolChoice none; no tools were executed.',\n );\n }\n\n await callPluginHook(\n plugins,\n 'afterProviderCall',\n { messages: conversationMessages, responseMessage: response },\n logger,\n );\n // PLG-020 (issue #2460): the assistant message is observable as it lands, like the user's.\n await callPluginHook(plugins, 'onMessageAdded', { message: response }, logger);\n\n const responseHasText =\n typeof assistantResponse.content === 'string' && assistantResponse.content.trim().length > 0;\n if (assistantToolCalls.length === 0 && !responseHasText) {\n logger.warn('[ROUND] Provider returned empty assistant response without tool calls', {\n executionId,\n conversationId: fullContext.conversationId,\n round: currentRound,\n });\n conversationStore.discardPending();\n return true;\n }\n\n const usageMetadata = executionUsage.collectAssistantUsageMetadata(assistantResponse);\n const inputTokens = usageMetadata?.inputTokens ?? 0;\n\n if (inputTokens > 0) {\n roundState.cumulativeInputTokens = inputTokens;\n }\n\n for (const tc of assistantToolCalls) {\n conversationStore.appendToolCall(tc);\n }\n\n const messageState: TMessageState = fullContext.signal?.aborted ? 'interrupted' : 'complete';\n conversationStore.commitAssistant(messageState, {\n round: currentRound,\n usageObservationId,\n executionId,\n providerId: routeProvider(route, resolved),\n modelId: routeModel(route, resolved.aiProviderInfo.model),\n ...(usageMetadata ?? {}),\n });\n const committedAssistantMessage = conversationStore.getMessages().at(-1);\n fullContext.onExecutionEvent?.('assistant_message_committed', {\n executionId,\n conversationId: fullContext.conversationId,\n round: currentRound,\n message: assistantResponse,\n } as TExecutionEventData);\n if (committedAssistantMessage) {\n fullContext.onExecutionEvent?.('history_mutation', {\n executionId,\n conversationId: fullContext.conversationId,\n round: currentRound,\n mutation: 'append_message',\n index: conversationStore.getMessages().length - 1,\n message: committedAssistantMessage,\n } as TExecutionEventData);\n }\n roundState.runningAssistantCount++;\n roundState.lastTrackedAssistantMessage = assistantResponse;\n\n if (assistantToolCalls.length === 0) {\n logger.debug(\n `[AGENT-FLOW-CONTROL] Round ${currentRound} completed - no tool calls, execution finished for agent ${fullContext.conversationId}`,\n );\n eventEmitter.emitAssistantMessageComplete(\n assistantResponse,\n executionId,\n currentRound,\n conversationId,\n thinkingNodeId,\n previousThinkingNodeId,\n );\n return true;\n }\n\n const toolOutcome = await executeAndRecordToolCalls(\n assistantToolCalls,\n conversationStore,\n conversationId,\n executionId,\n currentRound,\n thinkingNodeId,\n previousThinkingNodeId,\n roundState,\n deps,\n config,\n fullContext.signal,\n fullContext.onExecutionEvent,\n fullContext.maxSameToolInputs ?? config.maxSameToolInputs,\n fullContext.traceContext,\n );\n\n if (toolOutcome.contextOverflowed) {\n logger.warn(\n '[ROUND] Tool results partially skipped due to context overflow — continuing to let AI respond',\n { added: toolOutcome.addedCount, skipped: toolOutcome.skippedCount, round: currentRound },\n );\n }\n\n if (toolOutcome.unknownToolFailureCount > 0) {\n roundState.consecutiveUnknownToolFailureRounds += 1;\n } else {\n roundState.consecutiveUnknownToolFailureRounds = 0;\n }\n\n if (\n roundState.consecutiveUnknownToolFailureRounds >= MAX_CONSECUTIVE_UNKNOWN_TOOL_FAILURE_ROUNDS\n ) {\n const unavailableTools = [...new Set(toolOutcome.unknownToolNames)].sort();\n roundState.forcedSummaryInstruction = [\n `The model repeatedly requested unavailable tool(s): ${unavailableTools.join(', ')}.`,\n 'Those tool calls were not executed because they are not registered tools.',\n 'Respond to the user now with that reason and use the available tool results already in the conversation history.',\n ].join(' ');\n logger.warn('[ROUND] Stopping repeated unavailable tool-call loop', {\n unavailableTools,\n consecutiveRounds: roundState.consecutiveUnknownToolFailureRounds,\n round: currentRound,\n });\n return true;\n }\n\n logger.debug(`Round ${currentRound} completed for agent ${fullContext.conversationId}`);\n return false;\n}\n","import { EXECUTION_EVENTS } from './execution-constants';\nimport { buildFinalResult } from './execution-failure';\nimport { forceSummaryCall } from './execution-forced-summary';\nimport { executeRound } from './execution-round';\nimport {\n type IResolvedProviderInfo,\n type IExecutionContext,\n type ICoreExecutionResult,\n type IExecutionRoundState,\n PREVIEW_LENGTH,\n} from './execution-types';\nimport { callPluginHook } from './plugin-hook-dispatcher';\n\nimport type { ExecutionEventEmitter } from './execution-event-emitter';\nimport type { TPluginWithHooks } from './plugin-hook-dispatcher';\nimport type { ToolExecutionService } from './tool-execution-service';\nimport type { IAgentConfig } from '../interfaces/agent';\nimport type { TMetadata } from '../interfaces/types';\nimport type { ConversationStore } from '../managers/conversation-history-manager';\nimport type { ILogger } from '../utils/logger';\nimport type { ExecutionCacheService } from './cache/execution-cache-service';\n\nconst DEFAULT_MAX_EXECUTION_ROUNDS = 10;\nconst UNLIMITED_EXECUTION_ROUNDS = 0;\n\nfunction resolveMaxExecutionRounds(config: IAgentConfig, context: IExecutionContext): number {\n const configured = context.maxExecutionRounds ?? config.maxExecutionRounds;\n if (configured === undefined) {\n return DEFAULT_MAX_EXECUTION_ROUNDS;\n }\n if (!Number.isInteger(configured) || configured < 0) {\n throw new Error('[EXECUTION] maxExecutionRounds must be a non-negative integer');\n }\n return configured;\n}\n\nfunction hasRoundCapacity(currentRound: number, maxRounds: number): boolean {\n return maxRounds === UNLIMITED_EXECUTION_ROUNDS || currentRound < maxRounds;\n}\n\n/** Dependencies for running the execution round loop */\nexport interface IExecutionRoundDeps {\n toolExecutionService: ToolExecutionService;\n plugins: TPluginWithHooks[];\n logger: ILogger;\n eventEmitter: ExecutionEventEmitter;\n cacheService?: ExecutionCacheService;\n}\n\n/**\n * Run the execution round loop and (if needed) force a summary call at the end.\n * Mutates roundState.\n */\nexport async function runExecutionLoop(\n conversationStore: ConversationStore,\n conversationId: string,\n executionId: string,\n fullContext: IExecutionContext,\n config: IAgentConfig,\n resolved: IResolvedProviderInfo,\n roundState: IExecutionRoundState,\n signal: AbortSignal | undefined,\n deps: IExecutionRoundDeps,\n): Promise<void> {\n const maxRounds = resolveMaxExecutionRounds(config, fullContext);\n\n while (hasRoundCapacity(roundState.currentRound, maxRounds)) {\n if (signal?.aborted) break;\n roundState.currentRound++;\n const shouldBreak = await executeRound(\n roundState,\n maxRounds,\n conversationStore,\n conversationId,\n executionId,\n fullContext,\n config,\n resolved,\n deps,\n );\n if (shouldBreak) break;\n if (signal?.aborted) break;\n }\n\n // If loop ended without a final text response (e.g., maxRounds reached while\n // AI was still issuing tool calls), make one more provider call so the AI\n // can generate a summary from the results collected so far.\n const allMsgs = conversationStore.getMessages();\n const lastMsg = allMsgs.length > 0 ? allMsgs[allMsgs.length - 1] : undefined;\n const hasTextResponse =\n lastMsg?.role === 'assistant' &&\n typeof lastMsg.content === 'string' &&\n lastMsg.content.length > 0 &&\n (!('toolCalls' in lastMsg) || (lastMsg.toolCalls as unknown[]).length === 0);\n\n // CORE-011: a caller that already extracted its tool outcome can abort away the summary call,\n // and a decision-agent run can declare tool-only endings valid completions outright.\n if (signal?.aborted) return;\n if (fullContext.allowToolOnlyCompletion === true) return;\n\n if (!hasTextResponse) {\n await forceSummaryCall(\n conversationStore,\n resolved,\n config,\n executionId,\n roundState,\n conversationId,\n fullContext,\n deps.logger,\n maxRounds,\n );\n }\n}\n\n/**\n * Finalize the execution after all rounds complete:\n * calls afterRun hooks, logs success, emits COMPLETE event, and returns the result.\n */\nexport async function finalizeExecution(\n input: string,\n conversationStore: ConversationStore,\n executionId: string,\n startTime: Date,\n roundState: IExecutionRoundState,\n conversationId: string,\n interrupted: boolean,\n context: Partial<IExecutionContext> | undefined,\n plugins: TPluginWithHooks[],\n logger: ILogger,\n eventEmitter: ExecutionEventEmitter,\n): Promise<ICoreExecutionResult> {\n const result = {\n ...buildFinalResult(\n conversationStore,\n executionId,\n startTime,\n roundState.toolsExecuted,\n roundState.providerFailure,\n ),\n interrupted,\n };\n\n await callPluginHook(\n plugins,\n 'afterRun',\n {\n input,\n response: result.response,\n metadata: context?.metadata as TMetadata,\n },\n logger,\n );\n // PLG-020 (issue #2460): the execution-level hooks, carrying the run's result. `afterToolExecution`\n // fires only when a tool ran (the dispatcher checks `toolCalls`).\n const pluginContext = {\n messages: result.messages,\n executionContext: { executionId, conversationId },\n executionResult: {\n response: result.response,\n duration: result.duration,\n ...(result.tokensUsed !== undefined ? { tokensUsed: result.tokensUsed } : {}),\n toolsExecuted: result.toolsExecuted.length,\n success: result.success,\n toolCalls: result.toolsExecuted.map((name) => ({ name })),\n },\n };\n for (const hookName of ['afterExecution', 'afterConversation', 'afterToolExecution'] as const) {\n await callPluginHook(plugins, hookName, pluginContext, logger);\n }\n\n logger.debug('Execution pipeline completed successfully', {\n executionId,\n conversationId,\n duration: result.duration,\n tokensUsed: result.tokensUsed,\n toolsExecuted: result.toolsExecuted.length,\n rounds: roundState.currentRound,\n });\n\n eventEmitter.emitExecution(\n EXECUTION_EVENTS.COMPLETE,\n {\n result: {\n success: true,\n data: result.response.substring(0, PREVIEW_LENGTH) + '...',\n },\n metadata: {\n method: 'execute',\n success: true,\n duration: result.duration,\n tokensUsed: result.tokensUsed,\n toolsExecuted: result.toolsExecuted,\n },\n },\n conversationId,\n executionId,\n );\n\n return result;\n}\n","/**\n * Streaming ENTRY into the one execution turn (CORE-042).\n *\n * This file used to be a second execution engine: it re-derived store setup, provider resolution,\n * chat options, provider-message derivation, tool execution, validation, commit and error\n * classification inline, and owned none of them. Every turn capability therefore had to be built\n * twice, and the forgotten copy failed silently — six commits in a row were the identical\n * \"the streaming path dropped X, copy X in\" patch, two of them found by users after publish.\n *\n * There is no second engine now. `runStream` runs the SAME `execute()` the round path runs, with a\n * queue-feeding `onTextDelta`, and yields the deltas as they arrive. Rounds, the post-tool model\n * call, the round cap, abort state, plugin hooks, replay events, caching and the capacity guard are\n * not re-implemented here — they are simply what the turn does.\n *\n * That the round path streams at all is not incidental: `IChatOptions.onTextDelta` is contractual\n * (\"the provider should use streaming internally and call this for each text chunk, while still\n * returning the complete assembled message\"), and it is the mechanism the shipped product already\n * renders from — the TUI, headless mode, the ws transport and agent-server all consume deltas fed\n * through `run()`, not through this entry point.\n */\n\nimport type { ICoreExecutionResult, IExecutionContext } from './execution-types';\nimport type { IAgentConfig } from '../interfaces/agent';\nimport type { TUniversalMessage } from '../interfaces/messages';\n\n/** The turn this entry point streams. Injected so the seam stays one-directional and testable. */\nexport type TRunExecute = (\n input: string,\n messages: TUniversalMessage[],\n config: IAgentConfig,\n context: Partial<IExecutionContext>,\n) => Promise<ICoreExecutionResult>;\n\n/**\n * Run one turn, yield its text deltas, and return the turn's result.\n *\n * The RESULT is returned, not the response string, because `execute()` reports failure by resolving\n * with `success: false` and an `error` rather than by rejecting (CORE-020). Throwing that here would\n * put the failure rule in two layers; the caller applies the same check `robotaRun` applies, so one\n * rule lives in one place.\n *\n * The generator OWNS cancellation, not merely draining. A consumer that stops iterating (`break`,\n * `return`, an exception) must not leave the turn running: `execute()` is an in-flight promise here,\n * and an abandoned turn would keep writing to the conversation store after `Robota.runStream`'s\n * `finally` has already released the CORE-012 run slot and reset ephemeral history — interleaving a\n * dead turn's writes into the next run. So the `finally` aborts the turn and awaits it to settlement\n * before returning.\n */\nexport async function* executeStream(\n input: string,\n messages: TUniversalMessage[],\n config: IAgentConfig,\n context: Partial<IExecutionContext> | undefined,\n runExecute: TRunExecute,\n): AsyncGenerator<string, ICoreExecutionResult> {\n const pending: string[] = [];\n let wake: (() => void) | null = null;\n let finished = false;\n let failure: unknown = null;\n // Boxed rather than a bare `let`: the assignment happens inside a callback, and TypeScript's\n // control-flow analysis narrows a captured `let` to its initializer at the read site.\n const settled: { result: ICoreExecutionResult | null } = { result: null };\n\n const abandon = new AbortController();\n const callerSignal = context?.signal;\n const signal = callerSignal ? AbortSignal.any([callerSignal, abandon.signal]) : abandon.signal;\n\n const callerOnTextDelta = context?.onTextDelta;\n const onTextDelta = (delta: string): void => {\n pending.push(delta);\n // The caller's own callback still fires: `IRunOptions.onTextDelta` reaches this context, and\n // swallowing it here would be a new instance of the drop this file exists to end.\n callerOnTextDelta?.(delta);\n wake?.();\n };\n\n const turn = runExecute(input, messages, config, { ...context, signal, onTextDelta })\n .then(\n (value) => {\n settled.result = value;\n },\n (error: unknown) => {\n failure = error;\n },\n )\n .finally(() => {\n finished = true;\n wake?.();\n });\n\n try {\n for (;;) {\n while (pending.length > 0) {\n yield pending.shift() as string;\n }\n if (finished) break;\n await new Promise<void>((resolve) => {\n wake = (): void => {\n wake = null;\n resolve();\n };\n });\n }\n if (failure !== null) {\n throw failure;\n }\n if (settled.result === null) {\n throw new Error('[EXECUTION] streaming turn settled without a result');\n }\n return settled.result;\n } finally {\n abandon.abort();\n await turn;\n }\n}\n","/**\n * Metadata for the stored user message.\n *\n * PEER-007 (issue #1915): the driver id rides on the MESSAGE, not just the turn, because the\n * transcript is what a reader has once the turn ends — without it a peer session's message is\n * indistinguishable from the operator's own. Display attribution only, never an authorization input\n * (issue #1809). Absent when the turn has no attributed driver, which every surface reads as the\n * operator's own.\n */\nexport function userMessageMetadata(\n executionId: string,\n driverId?: string,\n): { executionId: string; driverId?: string } {\n return { executionId, ...(driverId !== undefined ? { driverId } : {}) };\n}\n","import { ExecutionEventEmitter } from './execution-event-emitter';\nimport { runExecutionLoop, finalizeExecution } from './execution-pipeline';\nimport {\n resolveProviderAndTools,\n validateProvider,\n initializeConversationStore,\n handleExecutionError,\n generateExecutionId,\n requireConversationId,\n buildFullExecutionContext,\n} from './execution-service-helpers';\nimport { executeStream as executeStreamFn } from './execution-stream';\nimport {\n type IExecutionRoundState,\n type IExecutionContext,\n type ICoreExecutionResult,\n type IExecutionServicePluginStats,\n} from './execution-types';\nimport { userMessageMetadata } from './execution-user-message';\nimport { callPluginHook, type TPluginWithHooks } from './plugin-hook-dispatcher';\nimport { ToolExecutionService } from './tool-execution-service';\nimport { isAbortFailure } from '../utils/abort-classification';\nimport { createLogger, type ILogger } from '../utils/logger';\n\nimport type {\n IAgentConfig,\n IAssistantMessage,\n IExecutionContextInjection,\n} from '../interfaces/agent';\nimport type { IEventService } from '../interfaces/event-service';\nimport type { IAIProviderManager, IToolManager } from '../interfaces/manager';\nimport type { TUniversalMessage } from '../interfaces/messages';\nimport type {\n IToolExecutionContext,\n IToolExecutionResult,\n TToolParameters,\n} from '../interfaces/tool';\nimport type { TMetadata } from '../interfaces/types';\nimport type { ConversationHistory } from '../managers/conversation-history-manager';\nimport type { ExecutionCacheService } from './cache/execution-cache-service';\n\n// Re-export constants for public API compatibility\nexport { EXECUTION_EVENTS, EXECUTION_EVENT_PREFIX } from './execution-constants';\n\n/** Orchestrates the execution pipeline: AI provider, tool execution, and plugin lifecycle. */\nexport class ExecutionService {\n private toolExecutionService: ToolExecutionService;\n private aiProviders: IAIProviderManager;\n private tools: IToolManager;\n private conversationHistory: ConversationHistory;\n private plugins: TPluginWithHooks[] = [];\n private logger: ILogger;\n private eventEmitter: ExecutionEventEmitter;\n private cacheService?: ExecutionCacheService;\n\n constructor(\n aiProviders: IAIProviderManager,\n tools: IToolManager,\n conversationHistory: ConversationHistory,\n eventService?: IEventService,\n executionContext?: IExecutionContextInjection,\n cacheService?: ExecutionCacheService,\n ) {\n this.toolExecutionService = new ToolExecutionService(tools);\n this.aiProviders = aiProviders;\n this.tools = tools;\n this.conversationHistory = conversationHistory;\n this.plugins = [];\n this.logger = createLogger('ExecutionService');\n if (!eventService) {\n throw new Error('[EXECUTION] EventService is required');\n }\n this.eventEmitter = new ExecutionEventEmitter(eventService, this.logger, executionContext);\n this.cacheService = cacheService;\n }\n\n /**\n * Session-scoped \"ask the user\" port (CMD-005) — delegates to the tool execution layer so every\n * tool call's context carries `ask` when an interactive user is attached.\n */\n setAskHandler(ask: Parameters<ToolExecutionService['setAskHandler']>[0]): void {\n this.toolExecutionService.setAskHandler(ask);\n }\n\n /** A direct catalog call uses the existing executor, without a provider/history round. */\n invokeRuntimeTool(\n name: string,\n parameters: TToolParameters,\n context: IToolExecutionContext,\n ): Promise<IToolExecutionResult> {\n return this.toolExecutionService.executeTool(name, parameters, context, 'registered');\n }\n\n /** Register a plugin */\n registerPlugin(plugin: TPluginWithHooks): void {\n const pluginPriority = plugin.priority ?? 0;\n const insertIndex = this.plugins.findIndex((p) => (p.priority ?? 0) < pluginPriority);\n if (insertIndex === -1) {\n this.plugins.push(plugin);\n } else {\n this.plugins.splice(insertIndex, 0, plugin);\n }\n this.logger.debug('Plugin registered', { pluginName: plugin.name, priority: pluginPriority });\n }\n\n /** Remove a plugin */\n removePlugin(pluginName: string): boolean {\n const index = this.plugins.findIndex((p) => p.name === pluginName);\n if (index !== -1) {\n this.plugins.splice(index, 1);\n this.logger.debug('Plugin removed', { pluginName });\n return true;\n }\n return false;\n }\n\n /** Get a plugin by name */\n getPlugin(pluginName: string): TPluginWithHooks | undefined {\n return this.plugins.find((p) => p.name === pluginName);\n }\n\n /** Get all registered plugins */\n getPlugins(): TPluginWithHooks[] {\n return [...this.plugins];\n }\n\n /** Execute the full pipeline with centralized history management */\n async execute(\n input: string,\n messages: TUniversalMessage[],\n config: IAgentConfig,\n context?: Partial<IExecutionContext>,\n ): Promise<ICoreExecutionResult> {\n const executionId = generateExecutionId();\n const startTime = new Date();\n const conversationId = requireConversationId(context, 'execute');\n\n const fullContext = buildFullExecutionContext(\n messages,\n config,\n startTime,\n executionId,\n conversationId,\n context,\n );\n\n this.eventEmitter.prepareOwnerPathBases(conversationId);\n\n this.logger.debug('Starting execution pipeline', {\n executionId,\n conversationId,\n messageCount: messages.length,\n hasContext: !!context,\n });\n\n const resolved = resolveProviderAndTools(this.aiProviders, this.tools, config);\n this.eventEmitter.emitExecutionStartEvent(\n input,\n config,\n messages,\n resolved,\n conversationId,\n executionId,\n );\n\n const conversationStore = initializeConversationStore(\n this.conversationHistory,\n conversationId,\n messages,\n config,\n executionId,\n );\n\n try {\n const messageCountBeforeUser = conversationStore.getMessages().length;\n conversationStore.addUserMessage(input, userMessageMetadata(executionId, context?.driverId));\n const userMessage = conversationStore.getMessages()[messageCountBeforeUser];\n if (userMessage) {\n fullContext.onExecutionEvent?.('history_mutation', {\n executionId,\n conversationId,\n mutation: 'append_message',\n index: messageCountBeforeUser,\n message: userMessage,\n });\n }\n this.eventEmitter.emitUserMessageEvent(input, conversationId, executionId);\n\n await callPluginHook(\n this.plugins,\n 'beforeRun',\n {\n input,\n ...(context?.metadata ? { metadata: context.metadata as TMetadata } : {}),\n },\n this.logger,\n );\n // PLG-020 (issue #2460): the execution-level hook, with the ids and the conversation so far.\n const pluginExecutionContext = { executionId, conversationId };\n if (userMessage) {\n await callPluginHook(\n this.plugins,\n 'onMessageAdded',\n { message: userMessage, executionContext: pluginExecutionContext },\n this.logger,\n );\n }\n await callPluginHook(\n this.plugins,\n 'beforeExecution',\n { messages: conversationStore.getMessages(), executionContext: pluginExecutionContext },\n this.logger,\n );\n\n validateProvider(resolved);\n\n const roundState: IExecutionRoundState = {\n toolsExecuted: [],\n currentRound: 0,\n runningAssistantCount: 0,\n lastTrackedAssistantMessage: undefined,\n cumulativeInputTokens: 0,\n consecutiveUnknownToolFailureRounds: 0,\n sameToolInputCounts: new Map(),\n };\n\n for (const msg of conversationStore.getMessages()) {\n if (msg.role === 'assistant') {\n roundState.runningAssistantCount++;\n roundState.lastTrackedAssistantMessage = msg as IAssistantMessage;\n }\n }\n\n await runExecutionLoop(\n conversationStore,\n conversationId,\n executionId,\n fullContext,\n config,\n resolved,\n roundState,\n context?.signal,\n {\n toolExecutionService: this.toolExecutionService,\n plugins: this.plugins,\n logger: this.logger,\n eventEmitter: this.eventEmitter,\n cacheService: this.cacheService,\n },\n );\n\n return finalizeExecution(\n input,\n conversationStore,\n executionId,\n startTime,\n roundState,\n conversationId,\n context?.signal?.aborted ?? false,\n context,\n this.plugins,\n this.logger,\n this.eventEmitter,\n );\n } catch (error) {\n // CORE-027: classified from the SIGNAL and the error's own name, never from its prose. The\n // substring test that stood here returned `success: true, interrupted: true` for any provider\n // failure whose message happened to contain \"abort\".\n if (isAbortFailure(error, context?.signal)) {\n return {\n response: '',\n messages: conversationStore.getMessages(),\n executionId,\n duration: Date.now() - startTime.getTime(),\n toolsExecuted: [],\n success: true,\n interrupted: true,\n };\n }\n await handleExecutionError(\n error,\n fullContext,\n startTime,\n conversationId,\n executionId,\n this.plugins,\n this.logger,\n this.eventEmitter,\n );\n // CORE-020: a failed result carries the error itself — never error text disguised\n // as a response. robotaRun throws result.error so callers receive a rejection.\n return {\n response: '',\n messages: [],\n tokensUsed: 0,\n toolsExecuted: [],\n duration: Date.now() - startTime.getTime(),\n executionId,\n success: false,\n error: error instanceof Error ? error : new Error(String(error)),\n };\n } finally {\n this.eventEmitter.resetOwnerPathBases();\n }\n }\n\n /** Execute with streaming response */\n async *executeStream(\n input: string,\n messages: TUniversalMessage[],\n config: IAgentConfig,\n context?: Partial<IExecutionContext>,\n ): AsyncGenerator<string, ICoreExecutionResult> {\n // CORE-042: a streaming ENTRY into `execute`, not a second engine. Everything the turn does is\n // the turn's; this hands it a delta sink and yields what arrives.\n return yield* executeStreamFn(input, messages, config, context, this.execute.bind(this));\n }\n\n /** Get execution statistics from plugins */\n async getStats(): Promise<IExecutionServicePluginStats> {\n return {\n pluginCount: this.plugins.length,\n pluginNames: this.plugins.map((p) => p.name),\n historyStats: this.conversationHistory.getStats(),\n };\n }\n\n /** Clear all plugins */\n clearPlugins(): void {\n this.plugins = [];\n this.logger.debug('All plugins cleared');\n }\n}\n","import { toolResultValue } from './tool-result-value';\n/**\n * Async initialization logic for the Robota agent.\n *\n * Extracted from robota.ts to keep the main class under 300 lines.\n */\nimport { AbstractTool } from '../abstracts/abstract-tool';\nimport { AIProviders } from '../managers/ai-provider-manager';\nimport { CacheKeyBuilder, MemoryCacheStorage, ExecutionCacheService } from '../services/cache';\nimport { ExecutionService } from '../services/execution-service';\n\nimport type { IAgentConfig } from '../interfaces/agent';\nimport type { IEventService } from '../interfaces/event-service';\nimport type { IToolExecutionContext, TToolParameters } from '../interfaces/tool';\nimport type { TUniversalValue } from '../interfaces/types';\nimport type { AgentFactory } from '../managers/agent-factory';\nimport type { ConversationHistory } from '../managers/conversation-history-manager';\nimport type { ModuleRegistry } from '../managers/module-registry';\nimport type { Tools } from '../managers/tool-manager';\nimport type { EventEmitterPlugin } from '../plugins/event-emitter-plugin';\nimport type { ILogger } from '../utils/logger';\n\n/**\n * Context required for async initialization.\n * @internal\n */\nexport interface IRobotaInitContext {\n config: IAgentConfig;\n aiProviders: AIProviders;\n tools: Tools;\n agentFactory: AgentFactory;\n conversationHistory: ConversationHistory;\n moduleRegistry: ModuleRegistry;\n eventEmitter: EventEmitterPlugin;\n eventService: IEventService;\n logger: ILogger;\n}\n\n/**\n * Build the provider registry an agent's config describes, with its current model already selected\n * — CORE-047.\n *\n * Registration and selection are synchronous and derived entirely from config the constructor has\n * already passed through `validateAgentConfig`. They lived inside `performAsyncInitialization` only\n * because they were written next to work that genuinely is async (modules, plugins, the execution\n * service), and the cost of that placement was that `getModel()` / `setModel()` /\n * `swapDefaultProvider()` had to refuse until the agent had run a turn — you could not ask which\n * model you were using without first asking the model a question.\n *\n * Constructing and configuring in one function is the point: there is no intermediate state in which\n * an `AIProviders` exists without the config's providers in it, so \"an agent knows which model it is\n * configured for from the moment it exists\" is true by construction rather than by a flag a caller\n * has to reach. `Robota` calls it exactly once, from its CONSTRUCTOR;\n * `performAsyncInitialization` must not repeat the work, or a `setModel()` made before the first run\n * would be silently reverted to `config.defaultModel` when the run initializes.\n *\n * @internal\n */\nexport function createConfiguredProviders(config: IAgentConfig): AIProviders {\n const aiProviders = new AIProviders();\n if (config.aiProviders) {\n for (const provider of config.aiProviders) {\n aiProviders.addProvider(provider.name, provider);\n }\n }\n if (config.defaultModel) {\n aiProviders.setCurrentProvider(config.defaultModel.provider, config.defaultModel.model);\n }\n return aiProviders;\n}\n\n/**\n * Performs the full async initialization of a Robota instance.\n * Returns the created ExecutionService.\n * @internal\n */\nasync function performAsyncInitialization(ctx: IRobotaInitContext): Promise<ExecutionService> {\n const {\n config,\n aiProviders,\n tools,\n agentFactory,\n conversationHistory,\n moduleRegistry,\n eventEmitter,\n eventService,\n logger,\n } = ctx;\n\n logger.debug('Starting Robota initialization with independent managers');\n\n // Initialize all instance-specific managers\n await Promise.all([aiProviders.initialize(), tools.initialize(), agentFactory.initialize()]);\n\n // CORE-047: provider registration and current-model selection are NOT repeated here. The\n // constructor did them (`createConfiguredProviders`), and repeating them would revert a\n // `setModel()` made before the first run back to `config.defaultModel` at run time.\n\n // Register modules if provided\n if (config.modules) {\n for (const module of config.modules) {\n await moduleRegistry.registerModule(module, {\n autoInitialize: true,\n validateDependencies: true,\n });\n }\n logger.debug('Modules registered and initialized', {\n moduleCount: config.modules.length,\n moduleNames: config.modules.map((m) => m.name),\n });\n }\n\n // Register tools\n if (config.tools) {\n for (const tool of config.tools) {\n if (tool instanceof AbstractTool && eventService) {\n tool.setEventService(eventService);\n }\n const toolExecutor = async (\n parameters: TToolParameters,\n context?: IToolExecutionContext,\n ): Promise<TUniversalValue> => {\n if (!context) {\n throw new Error('[ROBOTA] Missing ToolExecutionContext for tool execution');\n }\n const result = await tool.execute(parameters, context);\n return toolResultValue(tool.schema.name, result);\n };\n tools.addTool(tool.schema, toolExecutor);\n logger.debug('Tool registered during initialization', { toolName: tool.schema.name });\n }\n }\n\n // Build cache service if cache config is provided\n let cacheService: ExecutionCacheService | undefined;\n if (config.cache?.enabled) {\n const cacheStorage = new MemoryCacheStorage({\n maxEntries: config.cache.maxEntries,\n ttlMs: config.cache.ttlMs,\n });\n cacheService = new ExecutionCacheService(cacheStorage, new CacheKeyBuilder());\n }\n\n const executionService = new ExecutionService(\n aiProviders,\n tools,\n conversationHistory,\n eventService,\n config.executionContext,\n cacheService,\n );\n\n // CMD-005: forward the injected \"ask the user\" port into tool execution contexts.\n if (config.ask) {\n executionService.setAskHandler(config.ask);\n }\n\n // Register plugins with ExecutionService\n if (config.plugins) {\n for (const plugin of config.plugins) {\n executionService.registerPlugin(plugin);\n if (plugin.subscribeToModuleEvents) {\n await plugin.subscribeToModuleEvents(eventEmitter);\n logger.debug('Plugin subscribed to module events', { pluginName: plugin.name });\n }\n }\n }\n\n logger.debug('Robota initialization completed successfully with independent managers');\n return executionService;\n}\n\n/**\n * Mutable init state passed to performDoAsyncInit.\n */\nexport interface IRobotaInitState {\n ctx: IRobotaInitContext;\n setExecutionService: (svc: ExecutionService) => void;\n setFullyInitialized: (v: boolean) => void;\n}\n\n/**\n * Wraps performAsyncInitialization with the standard error handling pattern\n * from the Robota class, setting executionService and isFullyInitialized on success.\n */\nexport async function performDoAsyncInit(state: IRobotaInitState): Promise<void> {\n try {\n const svc = await performAsyncInitialization(state.ctx);\n state.setExecutionService(svc);\n state.setFullyInitialized(true);\n } catch (error) {\n state.ctx.logger.error('Robota initialization failed', {\n error: error instanceof Error ? error.message : String(error),\n });\n throw error;\n }\n}\n","/**\n * Lifecycle and stats helpers for the Robota agent.\n *\n * Extracted from robota.ts to keep the main class under 300 lines.\n */\nimport type { TAgentStatsMetadata } from './robota-config-manager';\nimport type { TUniversalMessage } from '../interfaces/agent';\nimport type { AIProviders } from '../managers/ai-provider-manager';\nimport type { ModuleRegistry } from '../managers/module-registry';\nimport type { Tools } from '../managers/tool-manager';\nimport type { EventEmitterPlugin } from '../plugins/event-emitter-plugin';\nimport type { ExecutionService } from '../services/execution-service';\nimport type { ILogger } from '../utils/logger';\n\n/** Dependencies required by getStats. @internal */\nexport interface IRobotaStatsDeps {\n readonly name: string;\n readonly version: string;\n readonly conversationId: string;\n readonly startTime: number;\n readonly isFullyInitialized: boolean;\n aiProviders: AIProviders;\n tools: Tools;\n getPluginNames(): string[];\n getModuleNames(): string[];\n getHistory(): TUniversalMessage[];\n}\n\n/** Build comprehensive agent statistics. @internal */\nexport function buildAgentStats(deps: IRobotaStatsDeps): {\n name: string;\n version: string;\n conversationId: string;\n providers: string[];\n currentProvider: string | null;\n tools: string[];\n plugins: string[];\n modules: string[];\n historyLength: number;\n historyStats: TAgentStatsMetadata;\n uptime: number;\n} {\n const providers = deps.isFullyInitialized ? deps.aiProviders.getProviderNames() : [];\n const currentProviderInfo = deps.isFullyInitialized\n ? deps.aiProviders.getCurrentProvider()\n : null;\n const currentProvider = currentProviderInfo ? currentProviderInfo.provider : null;\n const tools = deps.isFullyInitialized ? deps.tools.getTools().map((tool) => tool.name) : [];\n const plugins = deps.getPluginNames();\n const modules = deps.getModuleNames();\n const history = deps.getHistory();\n const uptime = Date.now() - deps.startTime;\n\n const roleCounts = { user: 0, assistant: 0, system: 0, tool: 0 };\n for (const msg of history) {\n if (msg.role in roleCounts) {\n roleCounts[msg.role as keyof typeof roleCounts]++;\n }\n }\n\n return {\n name: deps.name,\n version: deps.version,\n conversationId: deps.conversationId,\n providers,\n currentProvider,\n tools,\n plugins,\n modules,\n historyLength: history.length,\n historyStats: {\n userMessages: roleCounts.user,\n assistantMessages: roleCounts.assistant,\n systemMessages: roleCounts.system,\n toolMessages: roleCounts.tool,\n },\n uptime,\n };\n}\n\n/** Dependencies required by destroy. @internal */\nexport interface IRobotaDestroyDeps {\n readonly name: string;\n readonly isFullyInitialized: boolean;\n moduleRegistry: ModuleRegistry;\n eventEmitter: EventEmitterPlugin;\n executionService: ExecutionService | undefined;\n /**\n * The lifecycle-managed collaborators the agent owns.\n *\n * CORE-045: the disposal chain reached modules, plugins, the module registry and the event\n * emitter but never these two, so a destroyed agent still held its tool registry and its provider\n * instances — and still ACCEPTED `registerTool`, because the flag that would have refused it was\n * never flipped. Disposal is what the flag genuinely marks; leaving them out made that untrue.\n */\n tools: Tools;\n aiProviders: AIProviders;\n logger: ILogger;\n resetState(): void;\n}\n\n/** Result of a best-effort destroy: cleanup failures are collected, never thrown (CORE-013). */\nexport interface IDestroyResult {\n errors: Error[];\n}\n\n/**\n * Destroy and clean up the agent instance — **best-effort** (CORE-013).\n *\n * Disposal must be safe to fire-and-forget (`void agent.destroy()`): a rejection here becomes an\n * unhandled rejection that kills the host process on Node 20+. Every cleanup step therefore runs\n * regardless of earlier failures; each failure is logged and collected into the returned\n * `IDestroyResult.errors` instead of being thrown. State is always reset.\n * @internal\n */\nexport async function destroyAgent(deps: IRobotaDestroyDeps): Promise<IDestroyResult> {\n deps.logger.debug('Destroying Robota instance', { name: deps.name });\n const errors: Error[] = [];\n\n const step = async (label: string, run: () => Promise<void> | void): Promise<void> => {\n try {\n await run();\n deps.logger.debug(label);\n } catch (error) {\n // allow-fallback: best-effort disposal IS the contract — failure is logged, collected into the returned result, and remaining steps still run (CORE-013)\n const wrapped = error instanceof Error ? error : new Error(String(error));\n errors.push(wrapped);\n deps.logger.error('Error during Robota destruction step', {\n step: label,\n error: wrapped.message,\n });\n }\n };\n\n if (deps.isFullyInitialized && deps.moduleRegistry) {\n await step('All modules disposed', () => deps.moduleRegistry.disposeAllModules());\n }\n\n if (deps.executionService) {\n const plugins = deps.executionService.getPlugins();\n for (const plugin of plugins) {\n // CORE-022 (SPEC § Disposal Chain Contract): dispose() is the SINGLE component-level\n // entry point — the base implementation unsubscribes module events, and overrides\n // release owned resources (timers/sockets/storage). Without this a plugin's resources\n // outlive the agent and keep the process event loop alive (RUNTIME-09).\n await step(`Plugin disposed: ${plugin.name}`, () => plugin.dispose());\n }\n deps.logger.debug('ExecutionService plugins cleaned up');\n }\n\n if (deps.moduleRegistry) {\n await step('ModuleRegistry cleared', () => deps.moduleRegistry.clearAllModules());\n }\n\n if (deps.eventEmitter) {\n await step('EventEmitter disposed', () => deps.eventEmitter.dispose());\n }\n\n await step('Tools disposed', () => deps.tools.dispose());\n await step('AIProviders disposed', () => deps.aiProviders.dispose());\n\n deps.resetState();\n if (errors.length === 0) {\n deps.logger.info('Robota instance destroyed successfully', { name: deps.name });\n } else {\n deps.logger.warn('Robota instance destroyed with cleanup failures', {\n name: deps.name,\n failureCount: errors.length,\n });\n }\n return { errors };\n}\n","/**\n * The per-instance run queue (CORE-012).\n *\n * Split out of `robota.ts`, which is long past the file-size ceiling: serializing runs is a\n * self-contained responsibility with its own invariant, and it is the one part of the agent whose\n * correctness is about ordering rather than about conversation.\n *\n * The invariant: **one run at a time, per agent instance.** A second `run()` (or `runStream()`)\n * waits for the first to settle rather than interleaving with it, because both write to the same\n * conversation store — concurrent turns would produce a history that never happened.\n */\n\n/** Serializes runs on one agent instance and lets a caller wait for the queue to drain. */\nexport class RunQueue {\n private tail: Promise<void> = Promise.resolve();\n\n /**\n * Wait for the previous run to settle, then hold the slot until the returned function is called.\n *\n * The slot is claimed BEFORE awaiting the predecessor, so callers queue in the order they\n * arrived rather than racing to claim it once the predecessor finishes.\n */\n async acquire(signal: AbortSignal | undefined): Promise<() => void> {\n const previous = this.tail;\n let release: () => void = () => {};\n this.tail = new Promise<void>((resolve) => {\n release = resolve;\n });\n await previous;\n if (signal?.aborted) {\n // Aborting while queued must not consume the turn: release first so the queue keeps moving,\n // then report. Throwing while still holding the slot would deadlock every later run.\n release();\n throw new Error('Run aborted while queued behind another run on this instance');\n }\n return release;\n }\n\n /** Run `task` in the slot, releasing it however the task settles. */\n async run<T>(signal: AbortSignal | undefined, task: () => Promise<T>): Promise<T> {\n const release = await this.acquire(signal);\n try {\n return await task();\n } finally {\n release();\n }\n }\n\n /**\n * Resolves once every run queued so far has settled.\n *\n * Disposal awaits this so an in-flight turn is not torn out from under itself (CORE-022).\n */\n get drained(): Promise<void> {\n return this.tail;\n }\n}\n","import { ConfigurationError } from '../utils/errors';\n\nimport type { IAgent, IAgentConfig } from '../interfaces/agent';\n\nconst MAX_CONCURRENT_AGENTS = 100;\nconst DEFAULT_TEMPERATURE = 0.7;\nconst ID_RADIX = 36;\nconst AGENT_ID_SUBSTR_END = 8;\n\n/**\n * Configuration options for AgentFactory\n */\nexport interface IAgentFactoryOptions {\n /** Default model to use if not specified in config */\n defaultModel?: string;\n /** Default provider to use if not specified in config */\n defaultProvider?: string;\n /** Maximum number of concurrent agents */\n maxConcurrentAgents?: number;\n /**\n * Default system message for agents created without one. Defaults to the EMPTY string —\n * this foundation layer never injects persona text; any default persona is an upper-tier\n * (application/preset) decision. Empty string is an expressible, respected value.\n */\n defaultSystemMessage?: string;\n /** Enable strict configuration validation */\n strictValidation?: boolean;\n /**\n * ARCH-055: the agent-id source. Injected so a test can drive a deterministic collision corpus;\n * the factory retries a colliding id, so the source need not be unique on its own.\n */\n idFactory?: () => string;\n}\n\n/**\n * Agent creation statistics\n */\nexport interface IAgentCreationStats {\n /** Total number of agents created */\n totalCreated: number;\n /** Number of currently active agents */\n activeCount: number;\n /** Number of agents created from templates */\n fromTemplates: number;\n /** Number of custom configured agents */\n customConfigured: number;\n /** Template vs custom creation ratio (fromTemplates / totalCreated) */\n templateUsageRatio: number;\n}\n\n/**\n * Agent lifecycle events\n */\nexport interface IAgentLifecycleEvents {\n /** Called before agent creation */\n beforeCreate?: (config: IAgentConfig) => Promise<void> | void;\n /** Called after successful agent creation */\n afterCreate?: (agent: IAgent<IAgentConfig>, config: IAgentConfig) => Promise<void> | void;\n /** Called when agent creation fails */\n onCreateError?: (error: Error, config: IAgentConfig) => Promise<void> | void;\n /** Called when agent is destroyed */\n onDestroy?: (agentId: string) => Promise<void> | void;\n}\n\n/**\n * Resolved factory options.\n * The infrastructure fields are always populated; `defaultModel`/`defaultProvider` stay exactly as\n * the caller supplied them — no vendor model/provider default is injected at this foundation layer.\n */\nexport type TResolvedFactoryOptions = Required<\n Pick<\n IAgentFactoryOptions,\n 'maxConcurrentAgents' | 'defaultSystemMessage' | 'strictValidation' | 'idFactory'\n >\n> &\n Pick<IAgentFactoryOptions, 'defaultModel' | 'defaultProvider'>;\n\n/**\n * Build resolved factory options from partial user input.\n *\n * Only vendor-neutral infrastructure defaults are applied here. A model/provider is never\n * defaulted to a hardcoded vendor name; resolution happens later in {@link applyAgentDefaults}\n * from the caller's config, and an unresolvable model/provider fails loudly rather than silently\n * substituting one.\n */\nexport function resolveFactoryOptions(options: IAgentFactoryOptions): TResolvedFactoryOptions {\n return {\n maxConcurrentAgents: options.maxConcurrentAgents || MAX_CONCURRENT_AGENTS,\n // Neutral default: no baked-in persona prompt at this layer (`??` keeps '' expressible).\n defaultSystemMessage: options.defaultSystemMessage ?? '',\n strictValidation: options.strictValidation ?? true,\n idFactory: options.idFactory ?? generateAgentId,\n ...(options.defaultModel !== undefined && { defaultModel: options.defaultModel }),\n ...(options.defaultProvider !== undefined && { defaultProvider: options.defaultProvider }),\n };\n}\n\n/**\n * Apply default configuration values to a partial agent config.\n */\nexport function applyAgentDefaults(\n config: Partial<IAgentConfig>,\n options: TResolvedFactoryOptions,\n): IAgentConfig {\n if (!config.aiProviders || config.aiProviders.length === 0) {\n throw new ConfigurationError('At least one AI provider must be specified in aiProviders array');\n }\n\n const baseModel = config.defaultModel;\n\n // Resolve the model without falling back to a hardcoded vendor model. A missing model is a\n // configuration error to surface, not something to paper over.\n const resolvedModel = baseModel?.model ?? options.defaultModel;\n if (!resolvedModel) {\n throw new ConfigurationError(\n 'No model specified: set config.defaultModel.model or the AgentFactory defaultModel option',\n );\n }\n\n // Provider resolves from the explicit config, then the first configured provider, then the\n // factory option — never a hardcoded vendor name.\n const resolvedProvider =\n baseModel?.provider ?? config.aiProviders[0]?.name ?? options.defaultProvider;\n if (!resolvedProvider) {\n throw new ConfigurationError(\n 'No provider specified: set config.defaultModel.provider, an aiProviders entry, or the AgentFactory defaultProvider option',\n );\n }\n\n return {\n id: config.id || generateAgentId(),\n name: config.name || 'Unnamed Agent',\n aiProviders: config.aiProviders,\n defaultModel: {\n provider: resolvedProvider,\n model: resolvedModel,\n temperature: baseModel?.temperature ?? DEFAULT_TEMPERATURE,\n ...(baseModel?.maxTokens !== undefined && { maxTokens: baseModel.maxTokens }),\n ...(baseModel?.topP !== undefined && { topP: baseModel.topP }),\n },\n // System prompt is agent-level (single source of truth), not model config.\n // `??` so an explicit empty system message is respected rather than replaced.\n systemMessage: config.systemMessage ?? options.defaultSystemMessage,\n tools: config.tools || [],\n plugins: config.plugins || [],\n metadata: config.metadata || {},\n ...(config.logging && { logging: config.logging }),\n ...(config.conversationId && { conversationId: config.conversationId }),\n ...config,\n };\n}\n\n/**\n * Generate a unique agent ID.\n */\nfunction generateAgentId(): string {\n const timestamp = Date.now();\n const random = Math.random().toString(ID_RADIX).substring(2, AGENT_ID_SUBSTR_END);\n return `agent_${timestamp}_${random}`;\n}\n\n/**\n * Update creation statistics in-place and return the updated object.\n */\nexport function updateCreationStats(\n stats: IAgentCreationStats,\n fromTemplate: boolean,\n): IAgentCreationStats {\n stats.totalCreated++;\n stats.activeCount++;\n\n if (fromTemplate) {\n stats.fromTemplates++;\n } else {\n stats.customConfigured++;\n }\n\n stats.templateUsageRatio = stats.totalCreated > 0 ? stats.fromTemplates / stats.totalCreated : 0;\n\n return stats;\n}\n\n// Re-export constant so consumers can use it if needed\n","import { createLogger, type ILogger } from '../utils/logger';\n\nimport type { IAgentTemplate, IAgentConfig } from '../interfaces/agent';\n\n/**\n * Reusable type definitions for agent templates\n */\n\n/**\n * Agent template configuration data type\n * Used for storing template configuration values\n */\nexport type TAgentTemplateConfigurationData = Record<\n string,\n string | number | boolean | string[] | number[] | boolean[]\n>;\n\n/**\n * Template application result\n */\nexport interface ITemplateApplicationResult {\n /** Applied configuration */\n config: IAgentConfig;\n /** Template that was applied */\n template: IAgentTemplate;\n /** Any warnings during application */\n warnings: string[];\n /** Whether config was modified during application */\n modified: boolean;\n}\n\n/**\n * Agent Templates implementation\n * Manages agent templates for AgentFactory\n * Instance-based for isolated template management\n */\nexport class AgentTemplates {\n private templates = new Map<string, IAgentTemplate>();\n private logger: ILogger;\n\n constructor() {\n this.logger = createLogger('AgentTemplates');\n this.logger.info('AgentTemplates initialized');\n }\n\n /**\n * Register a template\n */\n registerTemplate(template: IAgentTemplate): void {\n if (!template.id) {\n throw new Error('Template must have an ID');\n }\n\n if (this.templates.has(template.id)) {\n this.logger.warn(`Template \"${template.id}\" is already registered, overriding`);\n }\n\n this.templates.set(template.id, template);\n this.logger.info(`Template \"${template.id}\" registered successfully`, {\n templateId: template.id,\n category: template.category,\n tags: template.tags,\n });\n }\n\n /**\n * Unregister a template\n */\n unregisterTemplate(templateId: string): boolean {\n const removed = this.templates.delete(templateId);\n if (removed) {\n this.logger.info(`Template \"${templateId}\" unregistered`);\n } else {\n this.logger.warn(`Attempted to unregister non-existent template \"${templateId}\"`);\n }\n return removed;\n }\n\n /**\n * Get all templates\n */\n getTemplates(): IAgentTemplate[] {\n return Array.from(this.templates.values());\n }\n\n /**\n * Get template by ID\n */\n getTemplate(templateId: string): IAgentTemplate | undefined {\n return this.templates.get(templateId);\n }\n\n /**\n * Find templates by criteria\n */\n findTemplates(criteria: {\n category?: string;\n tags?: string[];\n provider?: string;\n model?: string;\n }): IAgentTemplate[] {\n return this.getTemplates().filter((template) => {\n // Check category\n if (criteria.category && template.category !== criteria.category) {\n return false;\n }\n\n // Check tags\n if (criteria.tags && criteria.tags.length > 0) {\n const hasAnyTag = criteria.tags.some((tag) => template.tags?.includes(tag));\n if (!hasAnyTag) {\n return false;\n }\n }\n\n // Check provider\n if (criteria.provider && template.config.defaultModel?.provider !== criteria.provider) {\n return false;\n }\n\n // Check model\n if (criteria.model && template.config.defaultModel?.model !== criteria.model) {\n return false;\n }\n\n return true;\n });\n }\n\n /**\n * Apply template to configuration\n */\n applyTemplate(\n template: IAgentTemplate,\n overrides: Partial<IAgentConfig> = {},\n ): ITemplateApplicationResult {\n const warnings: string[] = [];\n let modified = false;\n\n // Start with template configuration\n const config: IAgentConfig = { ...template.config };\n\n // Apply overrides with type-safe approach\n const mergedConfig: IAgentConfig = { ...config, ...overrides };\n\n // Check for modifications by comparing specific known fields\n const checkField = (fieldName: keyof IAgentConfig): void => {\n if (fieldName in overrides && config[fieldName] !== overrides[fieldName]) {\n modified = true;\n if (config[fieldName] !== undefined) {\n warnings.push(\n `Override: ${fieldName} changed from \"${String(config[fieldName])}\" to \"${String(overrides[fieldName])}\"`,\n );\n }\n }\n };\n\n // Check common override fields\n if (overrides.name !== undefined) checkField('name');\n if (overrides.systemMessage !== undefined) checkField('systemMessage');\n\n // Use the merged config\n const finalConfig = mergedConfig;\n\n this.logger.debug('Template applied', {\n templateId: template.id,\n overridesCount: Object.keys(overrides).length,\n warningsCount: warnings.length,\n modified,\n });\n\n return {\n config: finalConfig,\n template,\n warnings,\n modified,\n };\n }\n\n /**\n * Check if template exists\n */\n hasTemplate(templateId: string): boolean {\n return this.templates.has(templateId);\n }\n\n /**\n * Get template count\n */\n getTemplateCount(): number {\n return this.templates.size;\n }\n\n /**\n * Clear all templates\n */\n clearAll(): void {\n this.templates.clear();\n this.logger.info('All templates cleared');\n }\n\n /**\n * Get template statistics\n */\n getStats(): {\n totalTemplates: number;\n categories: string[];\n tags: string[];\n providers: string[];\n models: string[];\n } {\n const templates = this.getTemplates();\n const categories = [\n ...new Set(\n templates\n .map((t) => t.category)\n .filter(\n (category): category is string => typeof category === 'string' && category.length > 0,\n ),\n ),\n ];\n const tags = [...new Set(templates.flatMap((t) => t.tags || []))];\n const providers = [\n ...new Set(\n templates\n .map((t) => t.config.defaultModel?.provider)\n .filter(\n (provider): provider is string => typeof provider === 'string' && provider.length > 0,\n ),\n ),\n ];\n const models = [\n ...new Set(\n templates\n .map((t) => t.config.defaultModel?.model)\n .filter((model): model is string => typeof model === 'string' && model.length > 0),\n ),\n ];\n\n return {\n totalTemplates: templates.length,\n categories,\n tags,\n providers,\n models,\n };\n }\n}\n","/**\n * ARCH-055 (#2159): the transactional lifecycle contract for registry-owned instances.\n *\n * A registry (agent factory, module registry, plugin set) mutates its state around asynchronous\n * initialization. Without one contract, a failure part-way leaves partial registration, wrong\n * statistics, or an initialized resource with no disposal path — and `TransportRegistry` had grown\n * its own serialized-startup-with-reverse-rollback while the agent/module/plugin family repeated the\n * partial-registration shape. This module names the contract once:\n *\n * - **Lifecycle identity.** An instance a registry owns declares its lifecycle through\n * {@link IRegistryOwnedLifecycle}; {@link lifecycleOf} is the one type guard — no more per-registry\n * `typeof x.cleanup === 'function'` duck-typing.\n * - **Commit timing.** Steps run in order; the registry's authoritative state changes only in the\n * step that commits it, after every step that can fail has succeeded.\n * - **Reverse rollback.** When a step throws, the `undo` of every COMPLETED step runs in reverse\n * order, always — a throwing `undo` does not stop the remaining ones.\n * - **Primary-error preservation.** The caller receives the step's error. Rollback failures are\n * attached as {@link IRegistryTransactionError.rollbackErrors}, never substituted for it.\n */\n\nexport interface IRegistryOwnedLifecycle {\n initialize?(): Promise<void>;\n cleanup?(): Promise<void>;\n}\n\n/** The declared lifecycle of `instance`, or `undefined` when it declares none. */\nexport function lifecycleOf(instance: object): IRegistryOwnedLifecycle | undefined {\n const candidate = instance as Partial<Record<'initialize' | 'cleanup', unknown>>;\n const initialize = typeof candidate.initialize === 'function' ? candidate.initialize : undefined;\n const cleanup = typeof candidate.cleanup === 'function' ? candidate.cleanup : undefined;\n if (initialize === undefined && cleanup === undefined) return undefined;\n return {\n ...(initialize ? { initialize: () => (initialize as () => Promise<void>).call(instance) } : {}),\n ...(cleanup ? { cleanup: () => (cleanup as () => Promise<void>).call(instance) } : {}),\n };\n}\n\nexport interface IRegistryTransactionStep {\n readonly name: string;\n run(): Promise<void> | void;\n /** Reverses `run`. Called only if `run` completed and a LATER step failed. */\n undo?(): Promise<void> | void;\n}\n\nexport interface IRegistryTransactionError extends Error {\n readonly failedStep: string;\n /** Errors thrown by `undo` handlers during rollback, in execution (reverse) order. */\n readonly rollbackErrors: readonly { step: string; error: unknown }[];\n}\n\nexport function isRegistryTransactionError(error: unknown): error is IRegistryTransactionError {\n return error instanceof Error && 'failedStep' in error && 'rollbackErrors' in error;\n}\n\n/**\n * Run `steps` in order with reverse rollback on failure. Throws the FAILING step's error, decorated\n * with `failedStep` and `rollbackErrors` (the original error object is thrown, so `instanceof` on\n * the caller's own error classes keeps working).\n */\nexport async function runRegistryTransaction(\n steps: readonly IRegistryTransactionStep[],\n): Promise<void> {\n const completed: IRegistryTransactionStep[] = [];\n for (const step of steps) {\n try {\n await step.run();\n } catch (error) {\n // allow-fallback: this IS the rollback contract — the primary error is rethrown below after\n // every completed step has been reversed; nothing is swallowed.\n const rollbackErrors: { step: string; error: unknown }[] = [];\n for (const done of completed.reverse()) {\n if (done.undo === undefined) continue;\n try {\n await done.undo();\n } catch (undoError) {\n // allow-fallback: a failing undo must not stop the remaining undos; it is RECORDED on the\n // primary error, which the caller receives.\n rollbackErrors.push({ step: done.name, error: undoError });\n }\n }\n throw decorate(error, step.name, rollbackErrors);\n }\n completed.push(step);\n }\n}\n\nfunction decorate(\n error: unknown,\n failedStep: string,\n rollbackErrors: readonly { step: string; error: unknown }[],\n): IRegistryTransactionError {\n const primary = error instanceof Error ? error : new Error(String(error));\n return Object.assign(primary, { failedStep, rollbackErrors });\n}\n","import {\n applyAgentDefaults,\n resolveFactoryOptions,\n updateCreationStats,\n type IAgentFactoryOptions,\n type IAgentCreationStats,\n type IAgentLifecycleEvents,\n type TResolvedFactoryOptions,\n} from './agent-factory-helpers';\nimport { AgentTemplates, type ITemplateApplicationResult } from './agent-templates';\nimport { lifecycleOf, runRegistryTransaction } from './registry-transaction';\nimport { ConfigurationError, ValidationError } from '../utils/errors';\nimport { createLogger, type ILogger } from '../utils/logger';\nimport { validateAgentConfig } from '../utils/validation';\n\nimport type { IAgent, IAgentConfig, IAgentTemplate } from '../interfaces/agent';\nimport type { TConfigData } from '../interfaces/types';\n\nexport type {\n IAgentFactoryOptions,\n IAgentCreationStats,\n IAgentLifecycleEvents,\n} from './agent-factory-helpers';\n\nconst MAX_ID_COLLISION_RETRIES = 16;\n\n/**\n * Agent Factory for creating and managing agents\n * Instance-based for isolated agent factory management\n */\nexport class AgentFactory {\n private agentTemplates: AgentTemplates;\n private initialized = false;\n private logger: ILogger;\n private options: TResolvedFactoryOptions;\n private activeAgents: Map<string, IAgent<IAgentConfig>>;\n /**\n * ARCH-055 admission: ids reserved by a `createAgent` that has not yet committed. Pending plus\n * active count toward `maxConcurrentAgents`, so concurrent creates cannot exceed the limit, and a\n * reserved id cannot be handed to a second create while the first is still initializing.\n */\n private readonly pendingAgents = new Set<string>();\n private creationStats: IAgentCreationStats;\n private lifecycleEvents: IAgentLifecycleEvents;\n\n constructor(options: IAgentFactoryOptions = {}, lifecycleEvents: IAgentLifecycleEvents = {}) {\n this.agentTemplates = new AgentTemplates();\n this.logger = createLogger('AgentFactory');\n this.options = resolveFactoryOptions(options);\n this.activeAgents = new Map();\n this.creationStats = {\n totalCreated: 0,\n activeCount: 0,\n fromTemplates: 0,\n customConfigured: 0,\n templateUsageRatio: 0,\n };\n this.lifecycleEvents = lifecycleEvents;\n\n this.logger.debug('AgentFactory initialized', {\n maxConcurrentAgents: this.options.maxConcurrentAgents,\n strictValidation: this.options.strictValidation,\n hasDefaultModel: !!this.options.defaultModel,\n hasDefaultProvider: !!this.options.defaultProvider,\n hasLifecycleEvents: this.lifecycleEvents !== null,\n });\n }\n\n /**\n * Initialize the factory\n */\n async initialize(): Promise<void> {\n if (this.initialized) {\n return;\n }\n\n this.logger.debug('Initializing AgentFactory');\n this.initialized = true;\n this.logger.debug('AgentFactory initialization completed');\n }\n\n /**\n * Create a new agent instance.\n *\n * ARCH-055 (#2159): one transaction. Admission — the limit check and a collision-safe id with a\n * pending slot — happens BEFORE the first `await`, so concurrent creates cannot overshoot\n * `maxConcurrentAgents` or overwrite each other. Then `beforeCreate` → construct → `initialize` →\n * commit (pending → active, statistics) → `afterCreate`, each with its reverse step: a failure\n * anywhere rolls back every completed step in reverse (an initialized agent is `cleanup`ed, a\n * committed one is unregistered and its statistics reversed), releases the slot, and rethrows the\n * PRIMARY error with any rollback errors attached.\n */\n async createAgent(\n AgentClass: new (config: IAgentConfig) => IAgent<IAgentConfig>,\n config: Partial<IAgentConfig>,\n fromTemplate: boolean = false,\n ): Promise<IAgent<IAgentConfig>> {\n // Apply defaults before try so fullConfig is available in catch\n let fullConfig: IAgentConfig | undefined;\n const agentId = this.admit();\n try {\n // Apply default configuration\n fullConfig = applyAgentDefaults(config, this.options);\n const resolvedConfig = fullConfig;\n\n // Validate configuration\n if (this.options.strictValidation) {\n const validation = validateAgentConfig(fullConfig);\n if (!validation.isValid) {\n throw new ValidationError(`Invalid agent configuration: ${validation.errors.join(', ')}`);\n }\n }\n\n let agent: IAgent<IAgentConfig> | undefined;\n await runRegistryTransaction([\n {\n name: 'beforeCreate',\n run: () => this.lifecycleEvents.beforeCreate?.(resolvedConfig),\n },\n {\n name: 'construct',\n run: () => {\n agent = new AgentClass(resolvedConfig);\n },\n },\n {\n name: 'initialize',\n run: () => (agent ? lifecycleOf(agent)?.initialize?.() : undefined),\n undo: () => (agent ? lifecycleOf(agent)?.cleanup?.() : undefined),\n },\n {\n name: 'commit',\n run: () => {\n if (!agent) throw new ConfigurationError('Agent was not constructed');\n this.activeAgents.set(agentId, agent);\n updateCreationStats(this.creationStats, fromTemplate);\n },\n undo: () => {\n this.activeAgents.delete(agentId);\n this.creationStats.activeCount--;\n this.creationStats.totalCreated--;\n if (fromTemplate) this.creationStats.fromTemplates--;\n else this.creationStats.customConfigured--;\n },\n },\n {\n name: 'afterCreate',\n run: () =>\n agent ? this.lifecycleEvents.afterCreate?.(agent, resolvedConfig) : undefined,\n },\n ]);\n this.pendingAgents.delete(agentId);\n if (!agent) throw new ConfigurationError('Agent was not constructed');\n\n this.logger.info('Agent created successfully', {\n agentId,\n model: fullConfig.defaultModel.model,\n provider: fullConfig.defaultModel.provider,\n });\n\n return agent;\n } catch (error) {\n this.pendingAgents.delete(agentId);\n // Call error lifecycle event\n const normalizedError = error instanceof Error ? error : new Error(String(error));\n if (this.lifecycleEvents.onCreateError && fullConfig) {\n await this.lifecycleEvents.onCreateError(normalizedError, fullConfig);\n }\n\n this.logger.error('Failed to create agent', {\n error: normalizedError.message,\n model: config.defaultModel?.model,\n provider: config.defaultModel?.provider,\n hasTools: !!config.tools?.length,\n });\n throw normalizedError;\n }\n }\n\n /**\n * ARCH-055 admission: reserve a collision-safe id and a pending slot synchronously. Pending and\n * active instances both count toward the limit.\n */\n private admit(): string {\n if (this.activeAgents.size + this.pendingAgents.size >= this.options.maxConcurrentAgents) {\n throw new ConfigurationError(\n `Maximum concurrent agents limit reached: ${this.options.maxConcurrentAgents}`,\n );\n }\n let agentId = this.options.idFactory();\n let attempts = 0;\n while (this.activeAgents.has(agentId) || this.pendingAgents.has(agentId)) {\n attempts += 1;\n if (attempts > MAX_ID_COLLISION_RETRIES) {\n throw new ConfigurationError(\n 'Agent id factory keeps returning ids that are already in use',\n );\n }\n agentId = this.options.idFactory();\n }\n this.pendingAgents.add(agentId);\n return agentId;\n }\n\n /**\n * Create agent from template\n */\n async createFromTemplate(\n AgentClass: new (config: IAgentConfig) => IAgent<IAgentConfig>,\n templateId: string,\n overrides: Partial<IAgentConfig> = {},\n ): Promise<IAgent<IAgentConfig>> {\n const template = this.agentTemplates.getTemplate(templateId);\n if (!template) {\n throw new ConfigurationError(`Template not found: ${templateId}`);\n }\n\n // Apply template to configuration\n const templateResult = this.applyTemplate(template, overrides);\n\n if (templateResult.warnings.length > 0) {\n this.logger.warn('Template application warnings', {\n templateId,\n warnings: templateResult.warnings,\n });\n }\n\n // Create agent with template configuration\n const agent = await this.createAgent(AgentClass, templateResult.config, true);\n\n this.logger.info('Agent created from template', {\n templateId,\n modified: templateResult.modified,\n warnings: templateResult.warnings.length,\n });\n\n return agent;\n }\n\n /**\n * Register a template\n */\n registerTemplate(template: IAgentTemplate): void {\n this.agentTemplates.registerTemplate(template);\n }\n\n /**\n * Unregister a template\n */\n unregisterTemplate(templateId: string): boolean {\n return this.agentTemplates.unregisterTemplate(templateId);\n }\n\n /**\n * Get all templates\n */\n getTemplates(): IAgentTemplate[] {\n return this.agentTemplates.getTemplates();\n }\n\n /**\n * Get template by ID\n */\n getTemplate(templateId: string): IAgentTemplate | undefined {\n return this.agentTemplates.getTemplate(templateId);\n }\n\n /**\n * Find templates by criteria\n */\n findTemplates(criteria: {\n category?: string;\n tags?: string[];\n provider?: string;\n model?: string;\n }): IAgentTemplate[] {\n return this.agentTemplates.findTemplates(criteria);\n }\n\n /**\n * Apply template to configuration\n */\n applyTemplate(\n template: IAgentTemplate,\n overrides: Partial<IAgentConfig> = {},\n ): ITemplateApplicationResult {\n return this.agentTemplates.applyTemplate(template, overrides as TConfigData);\n }\n\n /**\n * Destroy an agent\n */\n async destroyAgent(agentId: string): Promise<boolean> {\n const agent = this.activeAgents.get(agentId);\n if (!agent) {\n return false;\n }\n\n try {\n // ARCH-055: the declared lifecycle, through the one type guard — not per-site duck typing.\n await lifecycleOf(agent)?.cleanup?.();\n\n // Remove from tracking\n this.activeAgents.delete(agentId);\n this.creationStats.activeCount--;\n\n // Call destroy lifecycle event\n if (this.lifecycleEvents.onDestroy) {\n await this.lifecycleEvents.onDestroy(agentId);\n }\n\n this.logger.info('Agent destroyed', { agentId });\n return true;\n } catch (error) {\n this.logger.error('Error destroying agent', {\n agentId,\n error: error instanceof Error ? error.message : String(error),\n });\n throw error;\n }\n }\n\n /**\n * Get creation statistics\n */\n getCreationStats(): IAgentCreationStats {\n return { ...this.creationStats };\n }\n\n /**\n * Get all active agents\n */\n getActiveAgents(): Map<string, IAgent<IAgentConfig>> {\n return new Map(this.activeAgents);\n }\n\n /**\n * Validate agent configuration\n */\n validateConfiguration(config: Partial<IAgentConfig>): { isValid: boolean; errors: string[] } {\n return validateAgentConfig(config);\n }\n}\n","/**\n * Module validation helpers for ModuleRegistry.\n *\n * Extracted from module-registry.ts to keep each file under 300 lines.\n * @internal\n */\nimport { ConfigurationError } from '../utils/errors';\n\nimport type { ModuleDescriptorRegistry } from './module-type-registry';\nimport type { IModule } from '../abstracts/abstract-module';\nimport type { ILogger } from '../utils/logger';\n\n/** Validate a module before registration. @internal */\nexport function validateModule(\n module: IModule,\n typeRegistry: ModuleDescriptorRegistry,\n logger: ILogger,\n): void {\n if (!module.name || module.name.trim() === '') {\n throw new ConfigurationError('Module name is required');\n }\n if (!module.version || module.version.trim() === '') {\n throw new ConfigurationError('Module version is required');\n }\n const moduleType = module.getModuleType();\n const validation = typeRegistry.validateTypeDescriptor(moduleType);\n if (!validation.valid) {\n throw new ConfigurationError(`Invalid module type: ${validation.errors.join(', ')}`, {\n moduleName: module.name,\n errors: validation.errors,\n });\n }\n if (validation.warnings.length > 0) {\n logger.warn('Module type validation warnings', {\n moduleName: module.name,\n warnings: validation.warnings,\n });\n }\n}\n\n/** Validate module dependencies against the type registry and registered modules. @internal */\nexport async function validateModuleDependencies(\n module: IModule,\n typeRegistry: ModuleDescriptorRegistry,\n registeredModules: Map<string, IModule>,\n logger: ILogger,\n): Promise<void> {\n const moduleType = module.getModuleType();\n if (!moduleType.dependencies || moduleType.dependencies.length === 0) return;\n\n for (const depType of moduleType.dependencies) {\n if (!typeRegistry.hasType(depType)) {\n throw new ConfigurationError(\n `Module '${module.name}' depends on unregistered type '${depType}'`,\n { moduleName: module.name, dependencyType: depType },\n );\n }\n }\n\n const availableTypes = new Set<string>();\n for (const registeredModule of registeredModules.values()) {\n availableTypes.add(registeredModule.getModuleType().type);\n }\n const missing: string[] = [];\n for (const depType of moduleType.dependencies) {\n if (!availableTypes.has(depType)) missing.push(depType);\n }\n if (missing.length > 0) {\n logger.warn('Module has unmet dependencies', {\n moduleName: module.name,\n missingDependencies: missing,\n });\n }\n}\n\n/** Find modules that depend on the given module. @internal */\nexport function findDependentModules(moduleName: string, modules: Map<string, IModule>): string[] {\n const targetModule = modules.get(moduleName);\n if (!targetModule) return [];\n const targetType = targetModule.getModuleType().type;\n const dependents: string[] = [];\n for (const [name, module] of modules.entries()) {\n if (name === moduleName) continue;\n if (module.getModuleType().dependencies?.includes(targetType)) dependents.push(name);\n }\n return dependents;\n}\n\n/** Compute registry-wide statistics. @internal */\nexport interface IModuleRegistryStats {\n totalModules: number;\n initializedModules: number;\n enabledModules: number;\n modulesByType: Record<string, number>;\n totalExecutions: number;\n totalSuccessfulExecutions: number;\n totalFailedExecutions: number;\n averageExecutionTime: number;\n}\n\n/** @internal */\nexport interface IModuleExecutionStats {\n totalExecutions: number;\n successfulExecutions: number;\n failedExecutions: number;\n averageExecutionTime: number;\n lastExecutionTime?: Date;\n totalExecutionTime: number;\n}\n\n/** Build registry stats. @internal */\nexport function buildRegistryStats(\n modules: Map<string, IModule>,\n moduleStats: Map<string, IModuleExecutionStats>,\n): IModuleRegistryStats {\n const modulesByType: Record<string, number> = {};\n let initializedModules = 0;\n let enabledModules = 0;\n let totalExecutions = 0;\n let totalSuccessfulExecutions = 0;\n let totalFailedExecutions = 0;\n let totalExecutionTime = 0;\n\n for (const module of modules.values()) {\n const type = module.getModuleType().type;\n modulesByType[type] = (modulesByType[type] || 0) + 1;\n if (module.isInitialized()) initializedModules++;\n if (module.isEnabled()) enabledModules++;\n }\n for (const stats of moduleStats.values()) {\n totalExecutions += stats.totalExecutions;\n totalSuccessfulExecutions += stats.successfulExecutions;\n totalFailedExecutions += stats.failedExecutions;\n totalExecutionTime += stats.totalExecutionTime;\n }\n\n return {\n totalModules: modules.size,\n initializedModules,\n enabledModules,\n modulesByType,\n totalExecutions,\n totalSuccessfulExecutions,\n totalFailedExecutions,\n averageExecutionTime: totalExecutions > 0 ? totalExecutionTime / totalExecutions : 0,\n };\n}\n","/**\n * Builtin type registrations and helper logic for ModuleDescriptorRegistry.\n *\n * Extracted from module-type-registry.ts to keep each file under 300 lines.\n * @internal\n */\nimport { ModuleCategory, ModuleLayer } from '../abstracts/abstract-module';\n\nimport type {\n IModuleDescriptorValidationResult,\n IModuleDependencyResolution,\n} from './module-type-registry-types';\nimport type { IModuleDescriptor } from '../abstracts/abstract-module';\n\n/** @internal */\nexport function getBuiltinTypeDescriptors(): IModuleDescriptor[] {\n return [\n {\n type: 'storage',\n category: ModuleCategory.STORAGE,\n layer: ModuleLayer.INFRASTRUCTURE,\n capabilities: ['data-persistence', 'data-retrieval'],\n },\n {\n type: 'memory-storage',\n category: ModuleCategory.STORAGE,\n layer: ModuleLayer.INFRASTRUCTURE,\n dependencies: ['storage'],\n capabilities: ['in-memory-storage', 'fast-access'],\n },\n {\n type: 'file-storage',\n category: ModuleCategory.STORAGE,\n layer: ModuleLayer.INFRASTRUCTURE,\n dependencies: ['storage'],\n capabilities: ['persistent-storage', 'file-system-access'],\n },\n {\n type: 'text-processing',\n category: ModuleCategory.PROCESSING,\n layer: ModuleLayer.APPLICATION,\n capabilities: ['text-analysis', 'content-transformation'],\n },\n {\n type: 'file-processing',\n category: ModuleCategory.PROCESSING,\n layer: ModuleLayer.APPLICATION,\n dependencies: ['storage'],\n capabilities: ['file-parsing', 'content-extraction'],\n },\n {\n type: 'api-integration',\n category: ModuleCategory.INTEGRATION,\n layer: ModuleLayer.APPLICATION,\n capabilities: ['external-api-access', 'data-synchronization'],\n },\n {\n type: 'database-integration',\n category: ModuleCategory.INTEGRATION,\n layer: ModuleLayer.INFRASTRUCTURE,\n dependencies: ['storage'],\n capabilities: ['database-access', 'query-execution'],\n },\n {\n type: 'rag',\n category: ModuleCategory.CAPABILITY,\n layer: ModuleLayer.DOMAIN,\n dependencies: ['storage', 'text-processing'],\n capabilities: ['document-search', 'context-retrieval', 'semantic-search'],\n },\n {\n type: 'speech-processing',\n category: ModuleCategory.CAPABILITY,\n layer: ModuleLayer.DOMAIN,\n capabilities: ['speech-to-text', 'text-to-speech', 'audio-processing'],\n },\n {\n type: 'image-analysis',\n category: ModuleCategory.CAPABILITY,\n layer: ModuleLayer.DOMAIN,\n capabilities: ['image-recognition', 'visual-analysis', 'content-extraction'],\n },\n ];\n}\n\n/** Validate a module type descriptor. @internal */\nexport function validateTypeDescriptor(\n typeDescriptor: IModuleDescriptor,\n getType: (type: string) => IModuleDescriptor | undefined,\n): IModuleDescriptorValidationResult {\n const errors: string[] = [];\n const warnings: string[] = [];\n if (!typeDescriptor.type || typeDescriptor.type.trim() === '')\n errors.push('Module type is required and cannot be empty');\n if (!typeDescriptor.category) errors.push('Module category is required');\n if (!typeDescriptor.layer) errors.push('Module layer is required');\n if (typeDescriptor.type && !/^[a-zA-Z][a-zA-Z0-9-_]*$/.test(typeDescriptor.type))\n errors.push(\n 'Module type must start with a letter and contain only letters, numbers, hyphens, and underscores',\n );\n if (typeDescriptor.dependencies) {\n for (const dep of typeDescriptor.dependencies) {\n if (!dep || dep.trim() === '') errors.push('Dependencies cannot be empty');\n }\n if (typeDescriptor.dependencies.includes(typeDescriptor.type))\n errors.push('Module cannot depend on itself');\n }\n if (typeDescriptor.capabilities) {\n for (const cap of typeDescriptor.capabilities) {\n if (!cap || cap.trim() === '') errors.push('Capabilities cannot be empty');\n }\n }\n if (typeDescriptor.dependencies) {\n const layerOrder = [\n ModuleLayer.INFRASTRUCTURE,\n ModuleLayer.CORE,\n ModuleLayer.APPLICATION,\n ModuleLayer.DOMAIN,\n ModuleLayer.PRESENTATION,\n ];\n const currentIdx = layerOrder.indexOf(typeDescriptor.layer);\n for (const depType of typeDescriptor.dependencies) {\n const depDesc = getType(depType);\n if (depDesc) {\n const depIdx = layerOrder.indexOf(depDesc.layer);\n if (depIdx > currentIdx)\n warnings.push(\n `Module '${typeDescriptor.type}' (${typeDescriptor.layer}) depends on '${depType}' (${depDesc.layer}) which is in a higher layer`,\n );\n }\n }\n }\n return { valid: errors.length === 0, errors, warnings };\n}\n\n/** Resolve module dependencies via topological sort. @internal */\nexport function resolveDependenciesHelper(\n moduleTypes: string[],\n getType: (type: string) => IModuleDescriptor | undefined,\n hasType: (type: string) => boolean,\n): IModuleDependencyResolution {\n const visited = new Set<string>();\n const visiting = new Set<string>();\n const order: string[] = [];\n const circularDependencies: string[][] = [];\n const missingDependencies: string[] = [];\n for (const moduleType of moduleTypes) {\n const descriptor = getType(moduleType);\n if (!descriptor) {\n missingDependencies.push(moduleType);\n continue;\n }\n if (descriptor.dependencies) {\n for (const dep of descriptor.dependencies) {\n if (!hasType(dep) && !missingDependencies.includes(dep)) missingDependencies.push(dep);\n }\n }\n }\n const visit = (moduleType: string, path: string[] = []): void => {\n if (visiting.has(moduleType)) {\n const cycleStart = path.indexOf(moduleType);\n circularDependencies.push(path.slice(cycleStart).concat([moduleType]));\n return;\n }\n if (visited.has(moduleType)) return;\n const descriptor = getType(moduleType);\n if (!descriptor) return;\n visiting.add(moduleType);\n const newPath = [...path, moduleType];\n if (descriptor.dependencies) {\n for (const dep of descriptor.dependencies) {\n if (moduleTypes.includes(dep) || hasType(dep)) visit(dep, newPath);\n }\n }\n visiting.delete(moduleType);\n visited.add(moduleType);\n order.push(moduleType);\n };\n for (const moduleType of moduleTypes) {\n if (!visited.has(moduleType)) visit(moduleType);\n }\n return {\n resolved: missingDependencies.length === 0 && circularDependencies.length === 0,\n order,\n circularDependencies,\n missingDependencies,\n };\n}\n\n/** Check compatibility between module types. @internal */\nexport function checkCompatibilityHelper(\n moduleTypes: string[],\n getType: (type: string) => IModuleDescriptor | undefined,\n): {\n compatible: boolean;\n conflicts: Array<{ module1: string; module2: string; reason: string }>;\n suggestions: string[];\n} {\n const conflicts: Array<{ module1: string; module2: string; reason: string }> = [];\n const suggestions: string[] = [];\n const modulesByLayer = new Map<ModuleLayer, string[]>();\n for (const moduleType of moduleTypes) {\n const descriptor = getType(moduleType);\n if (descriptor) {\n if (!modulesByLayer.has(descriptor.layer)) modulesByLayer.set(descriptor.layer, []);\n modulesByLayer.get(descriptor.layer)!.push(moduleType);\n }\n }\n const capabilityProviders = new Map<string, string[]>();\n for (const moduleType of moduleTypes) {\n const descriptor = getType(moduleType);\n if (descriptor?.capabilities) {\n for (const cap of descriptor.capabilities) {\n if (!capabilityProviders.has(cap)) capabilityProviders.set(cap, []);\n capabilityProviders.get(cap)!.push(moduleType);\n }\n }\n }\n for (const [capability, providers] of Array.from(capabilityProviders.entries())) {\n if (providers.length > 1) {\n for (let i = 0; i < providers.length; i++) {\n for (let j = i + 1; j < providers.length; j++) {\n const m1 = providers[i];\n const m2 = providers[j];\n if (m1 && m2)\n conflicts.push({\n module1: m1,\n module2: m2,\n reason: `Both modules provide capability '${capability}'`,\n });\n }\n }\n }\n }\n if (conflicts.length > 0) {\n suggestions.push('Consider using only one module per capability');\n suggestions.push('Check if modules can be configured to avoid conflicts');\n }\n if (!modulesByLayer.has(ModuleLayer.INFRASTRUCTURE) && moduleTypes.length > 1)\n suggestions.push('Consider adding infrastructure modules for better foundation');\n return { compatible: conflicts.length === 0, conflicts, suggestions };\n}\n\n/** Build registry stats. @internal */\nexport function buildTypeRegistryStats(registeredTypes: Map<string, IModuleDescriptor>): {\n totalTypes: number;\n typesByCategory: Record<ModuleCategory, number>;\n typesByLayer: Record<ModuleLayer, number>;\n typesWithDependencies: number;\n typesWithCapabilities: number;\n} {\n const typesByCategory: Record<ModuleCategory, number> = {\n [ModuleCategory.CORE]: 0,\n [ModuleCategory.STORAGE]: 0,\n [ModuleCategory.PROCESSING]: 0,\n [ModuleCategory.INTEGRATION]: 0,\n [ModuleCategory.INTERFACE]: 0,\n [ModuleCategory.CAPABILITY]: 0,\n };\n const typesByLayer: Record<ModuleLayer, number> = {\n [ModuleLayer.INFRASTRUCTURE]: 0,\n [ModuleLayer.CORE]: 0,\n [ModuleLayer.APPLICATION]: 0,\n [ModuleLayer.DOMAIN]: 0,\n [ModuleLayer.PRESENTATION]: 0,\n };\n let typesWithDependencies = 0;\n let typesWithCapabilities = 0;\n for (const descriptor of registeredTypes.values()) {\n typesByCategory[descriptor.category]++;\n typesByLayer[descriptor.layer]++;\n if (descriptor.dependencies && descriptor.dependencies.length > 0) typesWithDependencies++;\n if (descriptor.capabilities && descriptor.capabilities.length > 0) typesWithCapabilities++;\n }\n return {\n totalTypes: registeredTypes.size,\n typesByCategory,\n typesByLayer,\n typesWithDependencies,\n typesWithCapabilities,\n };\n}\n","/**\n * Registry for managing module types dynamically.\n *\n * Builtin registrations and helpers live in ./module-type-registry-helpers.ts.\n */\nimport {\n getBuiltinTypeDescriptors,\n validateTypeDescriptor,\n resolveDependenciesHelper,\n checkCompatibilityHelper,\n buildTypeRegistryStats,\n} from './module-type-registry-helpers';\nimport { type IModuleDescriptor } from '../abstracts/abstract-module';\nimport { ConfigurationError } from '../utils/errors';\nimport { createLogger, type ILogger } from '../utils/logger';\n\nimport type { ModuleCategory, ModuleLayer } from '../abstracts/abstract-module';\n\nexport type {\n IModuleDescriptorValidationResult,\n IModuleDependencyResolution,\n} from './module-type-registry-types';\nimport type {\n IModuleDescriptorValidationResult,\n IModuleDependencyResolution,\n} from './module-type-registry-types';\n\n/** Module compatibility check result */\nexport interface IModuleCompatibilityResult {\n compatible: boolean;\n conflicts: Array<{ module1: string; module2: string; reason: string }>;\n suggestions: string[];\n}\n\n/**\n * Registry for managing module types dynamically.\n * Provides type validation, dependency resolution, and compatibility checking.\n */\nexport class ModuleDescriptorRegistry {\n private registeredTypes = new Map<string, IModuleDescriptor>();\n private logger: ILogger;\n\n constructor() {\n this.logger = createLogger('ModuleDescriptorRegistry');\n this.registerBuiltinTypes();\n }\n\n registerType(typeDescriptor: IModuleDescriptor): void {\n const validation = this.validateTypeDescriptor(typeDescriptor);\n if (!validation.valid)\n throw new ConfigurationError(\n `Invalid module type descriptor: ${validation.errors.join(', ')}`,\n { type: typeDescriptor.type, errors: validation.errors },\n );\n if (this.registeredTypes.has(typeDescriptor.type)) {\n const existing = this.registeredTypes.get(typeDescriptor.type);\n this.logger.warn('Overriding existing module type', {\n type: typeDescriptor.type,\n previousCategory: existing?.category || 'unknown',\n newCategory: typeDescriptor.category,\n });\n }\n this.registeredTypes.set(typeDescriptor.type, typeDescriptor);\n this.logger.info('Module type registered', {\n type: typeDescriptor.type,\n category: typeDescriptor.category,\n layer: typeDescriptor.layer,\n dependencies: typeDescriptor.dependencies?.length || 0,\n capabilities: typeDescriptor.capabilities?.length || 0,\n });\n }\n\n unregisterType(type: string): boolean {\n if (!this.registeredTypes.has(type)) return false;\n const dependentTypes = this.findDependentTypes(type);\n if (dependentTypes.length > 0)\n throw new ConfigurationError(\n `Cannot unregister module type '${type}' - it is required by: ${dependentTypes.join(', ')}`,\n { type, dependentTypes },\n );\n this.registeredTypes.delete(type);\n this.logger.info('Module type unregistered', { type });\n return true;\n }\n\n getType(type: string): IModuleDescriptor | undefined {\n return this.registeredTypes.get(type);\n }\n getAllTypes(): IModuleDescriptor[] {\n return Array.from(this.registeredTypes.values());\n }\n getTypesByCategory(category: ModuleCategory): IModuleDescriptor[] {\n return Array.from(this.registeredTypes.values()).filter((t) => t.category === category);\n }\n getTypesByLayer(layer: ModuleLayer): IModuleDescriptor[] {\n return Array.from(this.registeredTypes.values()).filter((t) => t.layer === layer);\n }\n hasType(type: string): boolean {\n return this.registeredTypes.has(type);\n }\n\n validateTypeDescriptor(typeDescriptor: IModuleDescriptor): IModuleDescriptorValidationResult {\n return validateTypeDescriptor(typeDescriptor, (t) => this.getType(t));\n }\n\n resolveDependencies(moduleTypes: string[]): IModuleDependencyResolution {\n return resolveDependenciesHelper(\n moduleTypes,\n (t) => this.getType(t),\n (t) => this.hasType(t),\n );\n }\n\n checkCompatibility(moduleTypes: string[]): IModuleCompatibilityResult {\n return checkCompatibilityHelper(moduleTypes, (t) => this.getType(t));\n }\n\n private findDependentTypes(type: string): string[] {\n const deps: string[] = [];\n for (const [rt, desc] of this.registeredTypes) {\n if (desc.dependencies?.includes(type)) deps.push(rt);\n }\n return deps;\n }\n\n private registerBuiltinTypes(): void {\n for (const desc of getBuiltinTypeDescriptors()) this.registerType(desc);\n this.logger.info('Built-in module types registered', { totalTypes: this.registeredTypes.size });\n }\n\n clearAllTypes(): void {\n this.registeredTypes.clear();\n this.logger.info('All module types cleared');\n }\n\n getStats(): {\n totalTypes: number;\n typesByCategory: Record<ModuleCategory, number>;\n typesByLayer: Record<ModuleLayer, number>;\n typesWithDependencies: number;\n typesWithCapabilities: number;\n } {\n return buildTypeRegistryStats(this.registeredTypes);\n }\n}\n","/**\n * Registry for managing module instances.\n *\n * Validation helpers live in ./module-registry-validation.ts.\n */\nimport {\n validateModule,\n validateModuleDependencies,\n findDependentModules,\n buildRegistryStats,\n} from './module-registry-validation';\nimport { ModuleDescriptorRegistry } from './module-type-registry';\nimport { ConfigurationError } from '../utils/errors';\nimport { createLogger, type ILogger } from '../utils/logger';\n\nimport type { IModuleExecutionStats, IModuleRegistryStats } from './module-registry-validation';\nimport type {\n IBaseModuleOptions,\n IModule,\n IModuleExecutionContext,\n IModuleExecutionResult,\n} from '../abstracts/abstract-module';\nimport type { IEventEmitterPlugin } from '../plugins/event-emitter/types';\n\nexport type { IModuleExecutionStats };\n\nconst MODULE_REGISTRY_EVENTS = {\n REGISTERED: 'module.registered',\n UNREGISTERED: 'module.unregistered',\n} as const;\n\nexport interface IModuleRegistrationOptions {\n autoInitialize?: boolean;\n initOptions?: IBaseModuleOptions;\n validateDependencies?: boolean;\n initTimeout?: number;\n}\n\nexport interface IModuleStatus {\n name: string;\n type: string;\n enabled: boolean;\n initialized: boolean;\n hasEventEmitter: boolean;\n registrationTime: Date;\n initializationTime?: Date;\n lastActivity?: Date;\n dependencies: string[];\n dependents: string[];\n}\n\nexport class ModuleRegistry {\n private modules = new Map<string, IModule>();\n private moduleOptions = new Map<string, IBaseModuleOptions>();\n private moduleStatuses = new Map<string, IModuleStatus>();\n private moduleStats = new Map<string, IModuleExecutionStats>();\n private registrationOrder: string[] = [];\n private initializationOrder: string[] = [];\n private typeRegistry: ModuleDescriptorRegistry;\n private eventEmitter: IEventEmitterPlugin | undefined;\n private logger: ILogger;\n private isDisposing = false;\n\n constructor(eventEmitter?: IEventEmitterPlugin, typeRegistry?: ModuleDescriptorRegistry) {\n this.eventEmitter = eventEmitter;\n this.typeRegistry = typeRegistry ?? new ModuleDescriptorRegistry();\n this.logger = createLogger('ModuleRegistry');\n }\n\n async registerModule(module: IModule, options: IModuleRegistrationOptions = {}): Promise<void> {\n if (this.isDisposing) throw new ConfigurationError('Cannot register modules during disposal');\n validateModule(module, this.typeRegistry, this.logger);\n if (this.modules.has(module.name))\n throw new ConfigurationError(`Module with name '${module.name}' is already registered`, {\n moduleName: module.name,\n });\n if (options.validateDependencies !== false)\n await validateModuleDependencies(module, this.typeRegistry, this.modules, this.logger);\n\n this.modules.set(module.name, module);\n this.moduleOptions.set(module.name, options.initOptions || {});\n this.registrationOrder.push(module.name);\n const moduleType = module.getModuleType();\n this.moduleStatuses.set(module.name, {\n name: module.name,\n type: moduleType.type,\n enabled: module.isEnabled(),\n initialized: false,\n hasEventEmitter: !!this.eventEmitter,\n registrationTime: new Date(),\n dependencies: moduleType.dependencies || [],\n dependents: [],\n });\n this.moduleStats.set(module.name, {\n totalExecutions: 0,\n successfulExecutions: 0,\n failedExecutions: 0,\n averageExecutionTime: 0,\n totalExecutionTime: 0,\n });\n\n if (options.autoInitialize) await this.initializeModule(module.name, options.initTimeout);\n if (this.eventEmitter)\n await this.eventEmitter.emit(MODULE_REGISTRY_EVENTS.REGISTERED, {\n data: { moduleName: module.name, moduleType: moduleType.type },\n timestamp: new Date(),\n });\n }\n\n async unregisterModule(moduleName: string): Promise<boolean> {\n const module = this.modules.get(moduleName);\n if (!module) return false;\n const dependents = findDependentModules(moduleName, this.modules);\n if (dependents.length > 0)\n throw new ConfigurationError(\n `Cannot unregister module '${moduleName}' - it is required by: ${dependents.join(', ')}`,\n { moduleName, dependents },\n );\n if (module.isInitialized() && module.dispose) await module.dispose();\n this.modules.delete(moduleName);\n this.moduleOptions.delete(moduleName);\n this.moduleStatuses.delete(moduleName);\n this.moduleStats.delete(moduleName);\n const ri = this.registrationOrder.indexOf(moduleName);\n if (ri !== -1) this.registrationOrder.splice(ri, 1);\n const ii = this.initializationOrder.indexOf(moduleName);\n if (ii !== -1) this.initializationOrder.splice(ii, 1);\n if (this.eventEmitter)\n await this.eventEmitter.emit(MODULE_REGISTRY_EVENTS.UNREGISTERED, {\n data: { moduleName },\n timestamp: new Date(),\n });\n return true;\n }\n\n async initializeModule(moduleName: string, timeout?: number): Promise<void> {\n const module = this.modules.get(moduleName);\n if (!module) throw new ConfigurationError(`Module '${moduleName}' not found`);\n if (module.isInitialized()) return;\n const options = this.moduleOptions.get(moduleName);\n const initPromise = module.initialize(options, this.eventEmitter);\n if (timeout && timeout > 0) {\n let timerId: ReturnType<typeof setTimeout>;\n const timeoutPromise = new Promise<never>((_, reject) => {\n timerId = setTimeout(() => {\n reject(new Error(`Module '${moduleName}' initialization timed out after ${timeout}ms`));\n }, timeout);\n });\n await Promise.race([\n initPromise.then((result) => {\n clearTimeout(timerId);\n return result;\n }),\n timeoutPromise,\n ]);\n } else {\n await initPromise;\n }\n const status = this.moduleStatuses.get(moduleName);\n if (status) {\n status.initialized = true;\n status.initializationTime = new Date();\n }\n if (!this.initializationOrder.includes(moduleName)) this.initializationOrder.push(moduleName);\n }\n\n async initializeAllModules(timeout?: number): Promise<void> {\n const moduleNames = Array.from(this.modules.keys());\n if (moduleNames.length === 0) return;\n const moduleTypes = moduleNames.map((name) => this.modules.get(name)!.getModuleType().type);\n const resolution = this.typeRegistry.resolveDependencies(moduleTypes);\n if (!resolution.resolved) {\n const errors: string[] = [];\n if (resolution.missingDependencies.length > 0)\n errors.push(`Missing dependencies: ${resolution.missingDependencies.join(', ')}`);\n if (resolution.circularDependencies.length > 0)\n errors.push(\n `Circular dependencies: ${resolution.circularDependencies.map((c) => c.join(' -> ')).join('; ')}`,\n );\n throw new ConfigurationError(`Cannot initialize modules: ${errors.join('; ')}`, {\n missingDependencies: resolution.missingDependencies,\n circularDependencies: resolution.circularDependencies.map((c) => c.join(' -> ')),\n });\n }\n for (const moduleType of resolution.order) {\n const mn = moduleNames.find(\n (name) => this.modules.get(name)!.getModuleType().type === moduleType,\n );\n if (mn) await this.initializeModule(mn, timeout);\n }\n }\n\n async executeModule(\n moduleName: string,\n context: IModuleExecutionContext,\n ): Promise<IModuleExecutionResult> {\n const module = this.modules.get(moduleName);\n if (!module) throw new ConfigurationError(`Module '${moduleName}' not found`);\n if (!module.isInitialized())\n throw new ConfigurationError(`Module '${moduleName}' is not initialized`);\n if (!module.isEnabled()) throw new ConfigurationError(`Module '${moduleName}' is disabled`);\n const stats = this.moduleStats.get(moduleName)!;\n const startTime = Date.now();\n try {\n if (!module.execute)\n throw new ConfigurationError(`Module '${moduleName}' does not support execute()`);\n const result = await module.execute(context);\n const duration = Date.now() - startTime;\n stats.totalExecutions++;\n stats.successfulExecutions++;\n stats.totalExecutionTime += duration;\n stats.averageExecutionTime = stats.totalExecutionTime / stats.totalExecutions;\n stats.lastExecutionTime = new Date();\n const status = this.moduleStatuses.get(moduleName);\n if (status) status.lastActivity = new Date();\n return result;\n } catch (error) {\n const duration = Date.now() - startTime;\n stats.totalExecutions++;\n stats.failedExecutions++;\n stats.totalExecutionTime += duration;\n stats.averageExecutionTime = stats.totalExecutionTime / stats.totalExecutions;\n stats.lastExecutionTime = new Date();\n throw error;\n }\n }\n\n getModule(moduleName: string): IModule | undefined {\n return this.modules.get(moduleName);\n }\n getModulesByType(moduleType: string): IModule[] {\n return Array.from(this.modules.values()).filter((m) => m.getModuleType().type === moduleType);\n }\n getAllModules(): IModule[] {\n return Array.from(this.modules.values());\n }\n getModuleNames(): string[] {\n return Array.from(this.modules.keys());\n }\n hasModule(moduleName: string): boolean {\n return this.modules.has(moduleName);\n }\n getModuleStatus(moduleName: string): IModuleStatus | undefined {\n return this.moduleStatuses.get(moduleName);\n }\n getAllModuleStatuses(): IModuleStatus[] {\n return Array.from(this.moduleStatuses.values());\n }\n getModuleStats(moduleName: string): IModuleExecutionStats | undefined {\n return this.moduleStats.get(moduleName);\n }\n getAllModuleStats(): Record<string, IModuleExecutionStats> {\n const s: Record<string, IModuleExecutionStats> = {};\n for (const [n, ms] of this.moduleStats.entries()) s[n] = { ...ms };\n return s;\n }\n\n async disposeAllModules(): Promise<void> {\n this.isDisposing = true;\n const reverseOrder = [...this.initializationOrder].reverse();\n for (const moduleName of reverseOrder) {\n const module = this.modules.get(moduleName);\n if (module && module.isInitialized()) {\n try {\n if (module.dispose) await module.dispose();\n const s = this.moduleStatuses.get(moduleName);\n if (s) s.initialized = false;\n } catch (error) {\n this.logger.error('Failed to dispose module', {\n name: moduleName,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n }\n this.initializationOrder = [];\n this.isDisposing = false;\n }\n\n clearAllModules(): void {\n this.modules.clear();\n this.moduleOptions.clear();\n this.moduleStatuses.clear();\n this.moduleStats.clear();\n this.registrationOrder = [];\n this.initializationOrder = [];\n this.isDisposing = false;\n }\n\n getRegistryStats(): IModuleRegistryStats {\n return buildRegistryStats(this.modules, this.moduleStats);\n }\n}\n","import { RobotaBase } from './robota-base';\nimport { validateAgentConfig } from './robota-config-manager';\nimport { createConfiguredTools, createConversationId } from './robota-construction';\nimport { createRobotaDelegates } from './robota-delegate-factory';\nimport {\n emitCreatedEvent,\n emitAgentEvent,\n buildOwnerPath,\n createModuleEventEmitter,\n} from './robota-events';\nimport { robotaRun, robotaRunStream, type IRobotaExecutionDeps } from './robota-execution';\nimport { robotaRunStructured, robotaRunStreamStructured } from './robota-execution-structured';\nimport {\n getHistory,\n getFullHistory,\n addHistoryEntry,\n clearHistory,\n injectMessage,\n injectRawMessage,\n} from './robota-history';\nimport { createConfiguredProviders, performDoAsyncInit } from './robota-initializer';\nimport { buildAgentStats, destroyAgent, type IDestroyResult } from './robota-lifecycle';\nimport { RunQueue } from './robota-run-queue';\nimport { DEFAULT_ABSTRACT_EVENT_SERVICE, bindWithOwnerPath } from '../event-service/index';\nimport { AgentFactory } from '../managers/agent-factory';\nimport { ConversationHistory } from '../managers/conversation-history-manager';\nimport { ModuleRegistry } from '../managers/module-registry';\nimport { normalizeStructuredOutput } from '../schema/structured-output';\nimport { createLogger, type ILogger } from '../utils/logger';\n\nimport type { RobotaConfigManager } from './robota-config-manager';\nimport type { IModelConfig, IConfigurationSnapshot } from './robota-types';\nimport type { AbstractTool, IToolWithEventService } from '../abstracts/abstract-tool';\nimport type {\n TUniversalMessage,\n IAgentConfig,\n IRunOptions,\n IAgent,\n TRunOptionsWithOutput,\n} from '../interfaces/agent';\nimport type { IEventService, IAgentEventData } from '../interfaces/event-service';\nimport type { IHistoryEntry } from '../interfaces/messages';\nimport type { IAIProvider, IToolSchema } from '../interfaces/provider';\nimport type {\n IToolExecutionContext,\n IToolExecutionResult,\n TToolParameters,\n} from '../interfaces/tool';\nimport type { AIProviders } from '../managers/ai-provider-manager';\nimport type { Tools } from '../managers/tool-manager';\nimport type { EventEmitterPlugin } from '../plugins/event-emitter-plugin';\nimport type { IJsonSchemaOutput } from '../schema/structured-output';\nimport type { ExecutionService } from '../services/execution-service';\nimport type { ZodType, TypeOf } from 'zod';\n\nexport type { TAgentStatsMetadata } from './robota-config-manager';\n\n/** @public */\nexport class Robota\n extends RobotaBase\n implements IAgent<IAgentConfig, IRunOptions, TUniversalMessage>\n{\n public readonly version: string = '1.0.0';\n\n private aiProviders: AIProviders;\n private tools: Tools;\n private agentFactory: AgentFactory;\n private conversationHistory: ConversationHistory;\n private moduleRegistry: ModuleRegistry;\n private eventEmitter: EventEmitterPlugin;\n private executionService!: ExecutionService;\n private eventService: IEventService;\n private agentEventService: IEventService;\n private conversationId: string;\n private logger: ILogger;\n private initializationPromise?: Promise<void> | undefined;\n /** Terminal state (CORE-022): once destroyed, run/runStream reject and re-init is impossible. */\n private destroyed = false;\n private isFullyInitialized = false;\n private startTime: number;\n private configVersion: number = 1;\n private configUpdatedAt: number = Date.now();\n private configManager!: RobotaConfigManager;\n\n constructor(config: IAgentConfig) {\n super();\n this.config = config;\n this.conversationId = createConversationId(config);\n // CORE-029: `config.logging` is PER-AGENT and used to be applied with `setGlobalLogLevel`,\n // which is process-wide — so one agent built with `{ enabled: false }` silenced every other\n // agent, and every other package, from a constructor. The level belongs to this agent's logger.\n const logLevel =\n config.logging?.enabled === false ? ('silent' as const) : config.logging?.level;\n this.logger = createLogger('Robota', logLevel ? { level: logLevel } : {});\n this.startTime = Date.now();\n\n validateAgentConfig(config);\n\n this.aiProviders = createConfiguredProviders(config); // CORE-047 — see its docblock for why here\n this.tools = createConfiguredTools(() => this.config);\n this.agentFactory = new AgentFactory();\n this.conversationHistory = new ConversationHistory();\n this.eventEmitter = createModuleEventEmitter();\n this.moduleRegistry = new ModuleRegistry(this.eventEmitter);\n\n this.eventService = config.eventService || DEFAULT_ABSTRACT_EVENT_SERVICE;\n this.agentEventService = bindWithOwnerPath(this.eventService, {\n ownerType: 'agent',\n ownerId: this.conversationId,\n ownerPath: buildOwnerPath(this.conversationId, this.config.executionContext),\n });\n\n const delegates = createRobotaDelegates({\n getName: () => this.name,\n getModuleRegistry: () => this.moduleRegistry,\n getLogger: () => this.logger,\n getIsFullyInitialized: () => this.isFullyInitialized,\n ensureFullyInitialized: () => this.ensureFullyInitialized(),\n getExecutionService: () => this.executionService,\n getAiProviders: () => this.aiProviders,\n getTools: () => this.tools,\n getEventService: () => this.eventService,\n getConfig: () => this.config,\n setConfig: (c) => {\n this.config = c;\n },\n getConfigVersion: () => this.configVersion,\n incrementConfigVersion: () => ++this.configVersion,\n getConfigUpdatedAt: () => this.configUpdatedAt,\n setConfigUpdatedAt: (t) => {\n this.configUpdatedAt = t;\n },\n emitAgentEvent: (t, d) => this.emitAgentEvent(t, d as Omit<IAgentEventData, 'timestamp'>),\n });\n this.moduleManager = delegates.moduleManager;\n this.pluginManager = delegates.pluginManager;\n this.configManager = delegates.configManager;\n emitCreatedEvent(this.config, (t, d) => this.emitAgentEvent(t, d));\n }\n\n /**\n * Build the asynchronous half — modules, plugins, the execution service — WITHOUT running a turn.\n * Idempotent. The provider registry and current model are NOT part of it: they are established by\n * the constructor (CORE-047), so reading or changing the model never needs this first.\n */\n async ensureReady(): Promise<void> {\n await this.ensureFullyInitialized();\n }\n\n /** The live registered catalog, including tools deferred from model discovery. */\n async listRuntimeTools(): Promise<IToolSchema[]> {\n await this.ensureReady();\n return this.tools.getTools();\n }\n\n /** Explicit tool invocation through the same executor used by model turns. */\n async invokeRuntimeTool(\n name: string,\n parameters: TToolParameters,\n context: IToolExecutionContext,\n ): Promise<IToolExecutionResult> {\n await this.ensureReady();\n const ownerPath = [\n ...buildOwnerPath(this.conversationId, this.config.executionContext),\n { type: 'tool', id: context.executionId ?? name },\n ];\n return this.executionService.invokeRuntimeTool(name, parameters, {\n ...context,\n baseEventService: this.eventService,\n eventService: bindWithOwnerPath(this.eventService, {\n ownerPath,\n ownerType: 'tool',\n ownerId: context.executionId ?? name,\n }),\n ownerPath,\n ownerType: 'tool',\n ownerId: context.executionId,\n });\n }\n\n /**\n * Concurrency contract (CORE-012): a Robota instance owns ONE conversation history, so\n * concurrent `run`/`runStream` calls on the same instance are serialized on an internal queue —\n * a call issued while another is in flight waits its turn (its `signal` is honored while queued).\n * Interleaved histories are therefore impossible by construction.\n *\n * Structured output (CORE-015): with `options.output` set the promise resolves to the validated\n * object (typed `z.infer<S>` for a Zod schema) instead of a string. Note the structured typing\n * is visible on `Robota` directly; through the generic `IAgent` interface the return type stays\n * `Promise<string>`.\n */\n run<S extends ZodType>(input: string, options: TRunOptionsWithOutput<S>): Promise<TypeOf<S>>;\n run(input: string, options: TRunOptionsWithOutput<IJsonSchemaOutput>): Promise<unknown>;\n run(input: string, options?: IRunOptions): Promise<string>;\n async run(input: string, options: IRunOptions = {}): Promise<unknown> {\n this.assertNotDestroyed();\n return this.runQueue.run(options.signal, async () => {\n await this.ensureFullyInitialized();\n try {\n if (options.output) {\n const spec = normalizeStructuredOutput(options.output);\n return await robotaRunStructured(this.executionDeps(), input, options, spec);\n }\n return await robotaRun(this.executionDeps(), input, options);\n } finally {\n this.resetEphemeralHistory();\n }\n });\n }\n\n runStream<S extends ZodType>(\n input: string,\n options: TRunOptionsWithOutput<S>,\n ): AsyncGenerator<string, TypeOf<S>, undefined>;\n runStream(\n input: string,\n options: TRunOptionsWithOutput<IJsonSchemaOutput>,\n ): AsyncGenerator<string, unknown, undefined>;\n runStream(input: string, options?: IRunOptions): AsyncGenerator<string, string, undefined>;\n async *runStream(\n input: string,\n options: IRunOptions = {},\n ): AsyncGenerator<string, unknown, undefined> {\n this.assertNotDestroyed();\n // Serialized like run(): the queue slot is held until the stream is fully consumed\n // (return or throw), because the conversation history is being written throughout.\n const release = await this.runQueue.acquire(options.signal);\n try {\n await this.ensureFullyInitialized();\n if (options.output) {\n const spec = normalizeStructuredOutput(options.output);\n // The validated object is the generator's return value (CORE-015).\n return yield* robotaRunStreamStructured(this.executionDeps(), input, options, spec);\n }\n return yield* robotaRunStream(this.executionDeps(), input, options);\n } finally {\n this.resetEphemeralHistory();\n release();\n }\n }\n\n /**\n * Run-isolated mode (CORE-014): with `retainHistory: false` the conversation store is\n * ephemeral per run — reset after every run settles (success, abort, or error) so nothing\n * accumulates across runs. The system prompt re-applies on the next run (CORE-010).\n */\n private resetEphemeralHistory(): void {\n if (this.config.retainHistory === false) {\n this.clearHistory();\n }\n }\n\n /** One run at a time, per instance (CORE-012). */\n private readonly runQueue = new RunQueue();\n\n private executionDeps(): IRobotaExecutionDeps {\n return {\n conversationId: this.conversationId,\n config: this.config,\n logger: this.logger,\n getHistory: () => this.getHistory(),\n getExecutionService: () => this.executionService,\n emitAgentEvent: (t, d) => this.emitAgentEvent(t, d),\n };\n }\n\n override getHistory(): TUniversalMessage[] {\n return getHistory(this.conversationHistory, this.conversationId);\n }\n getFullHistory(): IHistoryEntry[] {\n return getFullHistory(this.conversationHistory, this.conversationId);\n }\n addHistoryEntry(entry: IHistoryEntry): void {\n addHistoryEntry(this.conversationHistory, this.conversationId, entry);\n }\n override clearHistory(): void {\n clearHistory(this.conversationHistory, this.conversationId);\n }\n injectMessage(\n role: 'user' | 'assistant' | 'system' | 'tool',\n content: string,\n options?: { toolCallId?: string; name?: string },\n ): void {\n injectMessage(this.conversationHistory, this.conversationId, role, content, options);\n }\n injectRawMessage(msg: TUniversalMessage): void {\n injectRawMessage(this.conversationHistory, this.conversationId, msg);\n }\n\n async updateTools(next: Array<IToolWithEventService>): Promise<{ version: number }> {\n return this.configManager.updateTools(next);\n }\n async updateConfiguration(patch: Partial<IAgentConfig>): Promise<{ version: number }> {\n return this.configManager.updateConfiguration(patch);\n }\n async getConfiguration(): Promise<IConfigurationSnapshot> {\n return this.configManager.getConfiguration();\n }\n setModel(mc: IModelConfig): void {\n this.configManager.setModel(mc);\n }\n getModel(): IModelConfig {\n return this.configManager.getModel();\n }\n\n /**\n * Live system-prompt update (SSOT). Updates the agent's `config.systemMessage` and the active\n * conversation store's single head system message, so the next provider request carries the\n * change. This is the propagation path for a session's persona, self-verification toggle, and\n * AGENTS.md/CLAUDE.md staleness refresh. See agent-core SPEC → System Prompt (single source of\n * truth).\n */\n updateSystemPrompt(content: string): void {\n this.configManager.setSystemMessage(content);\n this.conversationHistory.getConversationStore(this.conversationId).setSystemPrompt(content);\n }\n\n /** Current live system prompt. */\n getSystemPrompt(): string | undefined {\n return this.configManager.getSystemMessage();\n }\n registerTool(tool: AbstractTool): void {\n this.configManager.registerTool(tool, this.tools);\n }\n unregisterTool(toolName: string): void {\n this.tools.removeTool(toolName);\n }\n /** The tool schemas the model is offered at the next request — resident plus loaded (CLI-1990). */\n getOfferedToolSchemas(): IToolSchema[] {\n return this.tools.getOfferedTools();\n }\n getConfig(): IAgentConfig {\n return { ...this.config };\n }\n\n swapDefaultProvider(newProvider: IAIProvider, model: string): void {\n this.aiProviders.addProvider(newProvider.name, newProvider);\n this.configManager.setModel({ provider: newProvider.name, model });\n }\n\n getStats(): ReturnType<typeof buildAgentStats> {\n return buildAgentStats({\n name: this.name,\n version: this.version,\n conversationId: this.conversationId,\n startTime: this.startTime,\n isFullyInitialized: this.isFullyInitialized,\n aiProviders: this.aiProviders,\n tools: this.tools,\n getPluginNames: () => this.getPluginNames(),\n getModuleNames: () => this.getModuleNames(),\n getHistory: () => this.getHistory(),\n });\n }\n\n /**\n * Best-effort disposal (CORE-013): never rejects for cleanup failures, so\n * `void agent.destroy()` is safe to fire-and-forget. Every cleanup step runs even if an\n * earlier one fails; failures are logged and returned in `errors` for callers that want a\n * hard signal.\n */\n async destroy(): Promise<IDestroyResult> {\n // CORE-022: idempotent terminal operation — new runs are rejected from this point,\n // and in-flight/queued runs settle before disposal begins (queue tail await).\n if (this.destroyed) return { errors: [] };\n this.destroyed = true;\n await this.runQueue.drained;\n return destroyAgent({\n name: this.name,\n isFullyInitialized: this.isFullyInitialized,\n moduleRegistry: this.moduleRegistry,\n eventEmitter: this.eventEmitter,\n executionService: this.executionService,\n // CORE-045: the disposal chain never reached these two, so a destroyed agent kept its tool\n // registry and provider map and still accepted `registerTool`.\n tools: this.tools,\n aiProviders: this.aiProviders,\n logger: this.logger,\n resetState: () => {\n this.isFullyInitialized = false;\n this.initializationPromise = undefined as Promise<void> | undefined;\n },\n });\n }\n\n /** CORE-022: a destroyed agent never revives — reject before touching the run queue. */\n private assertNotDestroyed(): void {\n if (this.destroyed) {\n throw new Error(\n `[LIFECYCLE] Agent \"${this.name}\" has been destroyed — create a new instance`,\n );\n }\n }\n\n protected override async initialize(): Promise<void> {\n await this.ensureFullyInitialized();\n }\n\n private async ensureFullyInitialized(): Promise<void> {\n this.assertNotDestroyed();\n if (this.isFullyInitialized) return;\n if (!this.initializationPromise) {\n // CORE-022: a failed init must not be cached — clear so a later call can retry.\n this.initializationPromise = this.doAsyncInit().catch((error: unknown) => {\n this.initializationPromise = undefined;\n throw error;\n });\n }\n await this.initializationPromise;\n }\n\n private doAsyncInit(): Promise<void> {\n return performDoAsyncInit({\n ctx: {\n config: this.config,\n aiProviders: this.aiProviders,\n tools: this.tools,\n agentFactory: this.agentFactory,\n conversationHistory: this.conversationHistory,\n moduleRegistry: this.moduleRegistry,\n eventEmitter: this.eventEmitter,\n eventService: this.eventService,\n logger: this.logger,\n },\n setExecutionService: (svc) => {\n this.executionService = svc;\n },\n setFullyInitialized: (v) => {\n this.isFullyInitialized = v;\n },\n });\n }\n\n private emitAgentEvent(eventType: string, data: Omit<IAgentEventData, 'timestamp'>): void {\n emitAgentEvent(\n this.agentEventService,\n this.conversationId,\n this.config.executionContext,\n eventType,\n data,\n );\n }\n}\n","import type { IToolResult } from '../interfaces/tool.js';\n\nexport const DEFAULT_TOOL_RESULT_WARNING_CHARS = 10_000;\nexport const DEFAULT_TOOL_RESULT_HARD_CHARS = 25_000;\nexport const MAX_TOOL_RESULT_CHARS = 500_000;\nconst OPAQUE_REFERENCE = /^tool-result:[A-Za-z0-9_-]{22,64}$/u;\nconst ADMITTED_RESULT = Symbol.for('@robota-sdk/tool-result-admitted');\n\nexport type TToolResultAdmissionErrorCode =\n | 'invalid-policy'\n | 'invalid-override'\n | 'spill-unavailable'\n | 'spill-write-failed'\n | 'invalid-reference';\n\nexport class ToolResultAdmissionError extends Error {\n constructor(readonly code: TToolResultAdmissionErrorCode) {\n super(`Tool result admission failed (${code})`);\n this.name = 'ToolResultAdmissionError';\n }\n}\n\n/** The host owns secure persistence; core only admits its opaque reference. */\nexport interface IToolResultSpillStore {\n write(content: string): Promise<{ readonly reference: string }>;\n}\n\nexport interface IToolResultAdmissionOptions {\n readonly warningChars?: number;\n readonly hardChars?: number;\n readonly repositoryMaxChars?: number;\n readonly spillStore?: IToolResultSpillStore;\n readonly onWarning?: (event: {\n readonly toolName: string;\n readonly resultChars: number;\n readonly warningChars: number;\n }) => void;\n}\n\n/** True only for an envelope the generic admission owner returned in this process. */\nexport function wasToolResultAdmitted(result: IToolResult): boolean {\n return Object.getOwnPropertyDescriptor(result, ADMITTED_RESULT)?.value === true;\n}\n\nfunction markAdmitted(result: IToolResult): IToolResult {\n return Object.defineProperty({ ...result }, ADMITTED_RESULT, { value: true });\n}\n\nfunction modelFacingText(result: IToolResult): string {\n if (result.success) {\n if (typeof result.data === 'string') return result.data;\n return JSON.stringify(result.data) ?? '';\n }\n const data =\n result.data === undefined\n ? ''\n : typeof result.data === 'string'\n ? result.data\n : (JSON.stringify(result.data) ?? '');\n return `${result.error ?? ''}${data}`;\n}\n\nfunction positiveSafeInteger(value: number): boolean {\n return Number.isSafeInteger(value) && value > 0;\n}\n\nfunction resolveLimits(\n options: IToolResultAdmissionOptions,\n requestedMaxChars?: number,\n): {\n warningChars: number;\n hardChars: number;\n} {\n const warningChars = options.warningChars ?? DEFAULT_TOOL_RESULT_WARNING_CHARS;\n const hardChars = options.hardChars ?? DEFAULT_TOOL_RESULT_HARD_CHARS;\n const repositoryMaxChars = options.repositoryMaxChars ?? MAX_TOOL_RESULT_CHARS;\n if (\n !positiveSafeInteger(warningChars) ||\n !positiveSafeInteger(hardChars) ||\n !positiveSafeInteger(repositoryMaxChars) ||\n warningChars >= hardChars ||\n hardChars > repositoryMaxChars ||\n repositoryMaxChars > MAX_TOOL_RESULT_CHARS\n ) {\n throw new ToolResultAdmissionError('invalid-policy');\n }\n if (requestedMaxChars === undefined) return { warningChars, hardChars };\n if (!positiveSafeInteger(requestedMaxChars)) {\n throw new ToolResultAdmissionError('invalid-override');\n }\n return {\n warningChars,\n hardChars: Math.max(hardChars, Math.min(requestedMaxChars, repositoryMaxChars)),\n };\n}\n\n/** Core's one admission step for a tool envelope before any observer sees its body. */\nexport async function admitToolResult(\n toolName: string,\n result: IToolResult,\n options: IToolResultAdmissionOptions = {},\n requestedMaxChars?: number,\n): Promise<IToolResult> {\n const { warningChars, hardChars } = resolveLimits(options, requestedMaxChars);\n const content = modelFacingText(result);\n const resultChars = content.length;\n if (resultChars > warningChars) {\n options.onWarning?.({ toolName, resultChars, warningChars });\n }\n if (resultChars > hardChars) {\n if (!options.spillStore) throw new ToolResultAdmissionError('spill-unavailable');\n let reference: string;\n try {\n reference = (await options.spillStore.write(content)).reference;\n } catch {\n throw new ToolResultAdmissionError('spill-write-failed');\n }\n if (!OPAQUE_REFERENCE.test(reference) || reference.length > hardChars) {\n throw new ToolResultAdmissionError('invalid-reference');\n }\n return markAdmitted(\n result.success\n ? { success: true, data: reference }\n : { success: false, error: `Tool failure details: ${reference}` },\n );\n }\n return markAdmitted(result);\n}\n","import type {\n IBaseEventData,\n IEventContext,\n IEventService,\n TEventListener,\n} from '../interfaces/event-service';\nimport type {\n IEventHistoryModule,\n IEventHistoryRecord,\n IEventHistorySnapshot,\n} from '../interfaces/history-module';\n\nexport class EventHistoryModule implements IEventHistoryModule {\n private readonly store: IEventHistoryModule;\n private readonly listener: TEventListener;\n private sequenceId = 0;\n\n constructor(store: IEventHistoryModule, eventService: IEventService) {\n this.store = store;\n this.listener = (eventName: string, eventData: IBaseEventData, context?: IEventContext) => {\n if (!context?.ownerPath?.length) {\n throw new Error(`[HISTORY-MODULE] Missing ownerPath for ${eventName}`);\n }\n const record: IEventHistoryRecord = {\n eventName,\n sequenceId: this.nextSequenceId(),\n timestamp: eventData.timestamp,\n eventData,\n context,\n };\n this.store.append(record);\n };\n eventService.subscribe(this.listener);\n }\n\n append(record: IEventHistoryRecord): void {\n this.store.append(record);\n }\n\n read(fromSequenceId: number, toSequenceId?: number): IEventHistoryRecord[] {\n return this.store.read(fromSequenceId, toSequenceId);\n }\n\n readStream(fromSequenceId: number, toSequenceId?: number): AsyncIterable<IEventHistoryRecord> {\n return this.store.readStream(fromSequenceId, toSequenceId);\n }\n\n getSnapshot(): IEventHistorySnapshot | undefined {\n return this.store.getSnapshot?.();\n }\n\n detach(eventService: IEventService): void {\n eventService.unsubscribe(this.listener);\n }\n\n private nextSequenceId(): number {\n this.sequenceId += 1;\n return this.sequenceId;\n }\n}\n","/**\n * Neutral orchestration lifecycle event names (SELFHOST-001).\n *\n * Mirrors the existing `task-events` / `user-events` pattern: a const name set +\n * a prefix + a union type. These are emitted by the framework orchestration\n * mechanism over the existing `IEventService`. The names are pure mechanism —\n * no app-domain identity fields anywhere (TRANS-001 neutrality; enforced by the\n * `orchestration-neutrality` harness scan).\n */\nexport const ORCHESTRATION_EVENTS = {\n /** An orchestration run began. */\n STARTED: 'started',\n /** A single step began executing. */\n STEP_STARTED: 'step_started',\n /** A single step finished executing. */\n STEP_COMPLETED: 'step_completed',\n /** The orchestration run finished successfully. */\n COMPLETED: 'completed',\n /** The orchestration run failed. */\n FAILED: 'failed',\n} as const;\n\nexport const ORCHESTRATION_EVENT_PREFIX = 'orchestration' as const;\n\nexport type TOrchestrationEvent = (typeof ORCHESTRATION_EVENTS)[keyof typeof ORCHESTRATION_EVENTS];\n","import type { IEventService } from '../interfaces/event-service';\nimport type { IUniversalObjectValue, TUniversalValue } from '../interfaces/types';\n\n/**\n * Configuration for execution proxy\n */\nexport interface IExecutionProxyConfig {\n eventService: IEventService;\n sourceType: 'agent' | 'tool';\n sourceId: string;\n enabledEvents?: {\n execution?: boolean;\n toolCall?: boolean;\n task?: boolean;\n };\n}\n\n/** Internal target shape for proxy interception */\nexport type TExecutionProxyTarget = Record<string, TUniversalValue>;\n\n/** Internal args shape for proxy interception */\nexport type TExecutionProxyArgs = TUniversalValue[];\n\n/**\n * Metadata extractor function type\n */\nexport type TMetadataExtractor = (\n target: TExecutionProxyTarget,\n methodName: string,\n args: TExecutionProxyArgs,\n) => Record<string, TUniversalValue>;\n\n/**\n * Method configuration for proxy\n */\nexport interface IMethodConfig {\n startEvent?: string;\n completeEvent?: string;\n errorEvent?: string;\n extractMetadata?: TMetadataExtractor;\n extractResult?: (result: TUniversalValue) => Record<string, TUniversalValue>;\n}\n\n/**\n * Narrow TUniversalValue to IUniversalObjectValue (object, not array, not Date).\n */\nexport function asObjectValue(\n input: TUniversalValue | undefined,\n): IUniversalObjectValue | undefined {\n if (!input || typeof input !== 'object' || Array.isArray(input) || input instanceof Date) {\n return undefined;\n }\n return input as IUniversalObjectValue;\n}\n\n/**\n * Return the string length of input, or 0 if not a string.\n */\nexport function getStringLength(input: TUniversalValue | undefined): number {\n return typeof input === 'string' ? input.length : 0;\n}\n","import {\n asObjectValue,\n getStringLength,\n type IExecutionProxyConfig,\n type IMethodConfig,\n type TExecutionProxyTarget,\n type TExecutionProxyArgs,\n} from './execution-proxy-types';\nimport { AGENT_EVENTS } from '../agents/constants';\nimport { TOOL_EVENTS } from '../services/tool-execution-service';\n\nimport type { IBaseEventData, IEventService } from '../interfaces/event-service';\nimport type { TUniversalValue } from '../interfaces/types';\n\nexport type {\n IExecutionProxyConfig,\n IMethodConfig,\n TMetadataExtractor,\n} from './execution-proxy-types';\n\nconst ID_RADIX = 36;\nconst ID_RANDOM_LENGTH = 9;\n\n/**\n * ExecutionProxy - Automatic event emission using Proxy pattern\n *\n * This class wraps target objects and automatically emits events\n * around method execution without modifying business logic.\n *\n * Benefits:\n * - Zero business logic pollution\n * - Automatic event emission\n * - Configurable per method\n * - AOP (Aspect-Oriented Programming) pattern\n */\nexport class ExecutionProxy<T extends object = object> {\n private config: IExecutionProxyConfig;\n private methodConfigs: Map<string, IMethodConfig> = new Map();\n\n constructor(config: IExecutionProxyConfig) {\n this.config = config;\n }\n\n /**\n * Configure specific methods for event emission\n */\n configureMethod(methodName: string, config: IMethodConfig): this {\n this.methodConfigs.set(methodName, config);\n return this;\n }\n\n /**\n * Configure multiple methods with standard patterns\n */\n configureStandardMethods(): this {\n // Agent execution methods\n if (this.config.sourceType === 'agent') {\n this.configureMethod('run', {\n startEvent: AGENT_EVENTS.EXECUTION_START,\n completeEvent: AGENT_EVENTS.EXECUTION_COMPLETE,\n errorEvent: AGENT_EVENTS.EXECUTION_ERROR,\n extractMetadata: (target, methodName, args) => ({\n inputLength: getStringLength(args[0]),\n conversationId: target.conversationId,\n options: asObjectValue(args[1]) || {},\n }),\n extractResult: (result) => ({ response: result }),\n });\n\n this.configureMethod('runStream', {\n startEvent: AGENT_EVENTS.EXECUTION_START,\n completeEvent: AGENT_EVENTS.EXECUTION_COMPLETE,\n errorEvent: AGENT_EVENTS.EXECUTION_ERROR,\n extractMetadata: (target, methodName, args) => ({\n inputLength: getStringLength(args[0]),\n conversationId: target.conversationId,\n streaming: true,\n options: asObjectValue(args[1]) || {},\n }),\n });\n }\n\n // Tool execution methods\n if (this.config.sourceType === 'tool') {\n this.configureMethod('execute', {\n startEvent: TOOL_EVENTS.CALL_START,\n completeEvent: TOOL_EVENTS.CALL_COMPLETE,\n errorEvent: TOOL_EVENTS.CALL_ERROR,\n extractMetadata: (target, methodName, args) => ({\n toolName: asObjectValue(target.schema)?.name || target.constructor.name,\n parameters: args[0],\n parametersCount: asObjectValue(args[0])\n ? Object.keys(asObjectValue(args[0]) || {}).length\n : 0,\n context: args[1],\n }),\n extractResult: (result) => ({\n result:\n typeof asObjectValue(result)?.data === 'string'\n ? asObjectValue(result)?.data || ''\n : JSON.stringify(asObjectValue(result)?.data),\n success: asObjectValue(result)?.success,\n }),\n });\n }\n\n return this;\n }\n\n /**\n * Create a proxy wrapper around the target object\n */\n wrap(target: T): T {\n return new Proxy(target, {\n get: (target, prop, receiver) => {\n const originalMethod = Reflect.get(target, prop, receiver);\n if (typeof prop !== 'string') {\n return originalMethod;\n }\n const methodName = prop;\n\n // Only wrap methods that are configured\n if (typeof originalMethod === 'function' && this.methodConfigs.has(methodName)) {\n const methodConfig = this.methodConfigs.get(methodName)!;\n\n return async (...args: TExecutionProxyArgs) => {\n const startTime = Date.now();\n const executionId = this.generateExecutionId();\n const proxyTarget = target as TExecutionProxyTarget;\n\n try {\n // Emit start event\n if (methodConfig.startEvent) {\n const metadata =\n methodConfig.extractMetadata?.(proxyTarget, methodName, args) || {};\n this.emitEvent(methodConfig.startEvent, {\n timestamp: new Date(),\n metadata: {\n ...metadata,\n executionId,\n methodName,\n phase: 'start',\n },\n });\n }\n\n // Execute original method\n const result = (await originalMethod.apply(target, args)) as TUniversalValue;\n const duration = Date.now() - startTime;\n\n // Emit complete event\n if (methodConfig.completeEvent) {\n const extractedResult = methodConfig.extractResult?.(result) || {};\n const metadata =\n methodConfig.extractMetadata?.(proxyTarget, methodName, args) || {};\n this.emitEvent(methodConfig.completeEvent, {\n timestamp: new Date(),\n ...extractedResult,\n metadata: {\n ...metadata,\n executionId,\n methodName,\n duration,\n phase: 'complete',\n success: true,\n },\n });\n }\n\n return result;\n } catch (error) {\n const duration = Date.now() - startTime;\n\n // Emit error event\n if (methodConfig.errorEvent) {\n const metadata =\n methodConfig.extractMetadata?.(proxyTarget, methodName, args) || {};\n this.emitEvent(methodConfig.errorEvent, {\n timestamp: new Date(),\n error: error instanceof Error ? error.message : String(error),\n metadata: {\n ...metadata,\n executionId,\n methodName,\n duration,\n phase: 'error',\n errorName: error instanceof Error ? error.name : 'UnknownError',\n success: false,\n },\n });\n }\n\n throw error;\n }\n };\n }\n\n return originalMethod;\n },\n }) as T;\n }\n\n /**\n * Emit event with standard ServiceEventData format\n */\n private emitEvent(eventType: string, additionalData: Partial<IBaseEventData>): void {\n const baseMetadata = {\n emitterSourceType: this.config.sourceType,\n emitterSourceId: this.config.sourceId,\n };\n\n const eventData: IBaseEventData = {\n timestamp: new Date(),\n ...(additionalData.metadata\n ? { metadata: { ...baseMetadata, ...additionalData.metadata } }\n : { metadata: baseMetadata }),\n ...additionalData,\n };\n\n this.config.eventService.emit(eventType, eventData);\n }\n\n /**\n * Generate unique execution ID\n */\n private generateExecutionId(): string {\n return `${this.config.sourceType}-${this.config.sourceId}-${Date.now()}-${Math.random().toString(ID_RADIX).substr(2, ID_RANDOM_LENGTH)}`;\n }\n}\n\n/**\n * Factory function to create execution proxy with standard configuration\n */\nexport function createExecutionProxy<T extends object>(\n target: T,\n config: IExecutionProxyConfig,\n): T {\n const proxy = new ExecutionProxy<T>(config);\n proxy.configureStandardMethods();\n return proxy.wrap(target);\n}\n\n/**\n * Decorator function for automatic event emission\n * Usage: @withEventEmission(eventService, 'agent', 'agent-id')\n */\nexport function withEventEmission(\n eventService: IEventService,\n sourceType: 'agent' | 'tool',\n sourceId: string,\n) {\n return function <T extends object>(target: T): T {\n return createExecutionProxy(target, {\n eventService,\n sourceType,\n sourceId,\n }) as T;\n };\n}\n","/**\n * Permission system types — Claude Code compatible permission model.\n */\n\n/**\n * Permission modes (Claude Code compatible)\n * - plan: read-only tools only\n * - default: reads auto, writes/bash need approval\n * - acceptEdits: reads + writes auto, bash needs approval\n * - bypassPermissions: all tools auto\n * - auto: reads and in-workspace edits auto; anything else a model classifier decides, and a person\n * when the classifier keeps refusing\n */\nexport type TPermissionMode = 'plan' | 'default' | 'acceptEdits' | 'bypassPermissions' | 'auto';\n\n/**\n * Friendly trust level aliases\n * - safe → plan\n * - moderate → default\n * - full → acceptEdits\n */\nexport type TTrustLevel = 'safe' | 'moderate' | 'full';\n\nexport const TRUST_TO_MODE: Record<TTrustLevel, TPermissionMode> = {\n safe: 'plan',\n moderate: 'default',\n full: 'acceptEdits',\n};\n\n/**\n * Outcome of a permission evaluation\n * - auto: proceed without prompting\n * - approve: prompt user for approval\n * - deny: block the action\n */\nexport type TPermissionDecision = 'auto' | 'approve' | 'deny';\n\n/**\n * Per-task permission policy for a spawned background / subagent task (CORE-025).\n *\n * SSOT lives here (the permission-logic home) rather than in a transport package, because\n * `agent-interface-transport` → `agent-core` is a one-way dependency. The background-task request\n * contract in `agent-interface-execution` uses this union for `permissionPolicy` without re-exporting it.\n *\n * - `inherit-allowlist` (default): inherit the parent session allow/deny rules — matched → allow,\n * unmatched → deny (never prompt). The detached-safe locked-down default.\n * - `preapproved`: allow only the task's own declared allowlist; everything else denies.\n * - `prompt`: route to a human approver; fail-closed to deny when no surface can answer.\n * - `deny`: deny every privileged call (call-scoped structured deny; does not force-fail the task).\n */\nexport type TBackgroundPermissionPolicy = 'inherit-allowlist' | 'preapproved' | 'prompt' | 'deny';\n\n/**\n * The policy a spawn site gets when it has no reason to choose another (ARCH-031).\n *\n * ONE definition, owned by the package that owns {@link TBackgroundPermissionPolicy}. It replaces two\n * independent `?? 'inherit-allowlist'` fallbacks — one in `agent-executor`'s subagent manager, one in\n * `agent-framework`'s workspace spawner — which were the default for a security-relevant value declared\n * twice in two packages, with nothing keeping them equal.\n *\n * `permissionPolicy` is REQUIRED on a spawn request, so every site states its policy rather than\n * inheriting one applied in the middle of a projection. This constant is what they state when the\n * answer is \"the usual one\".\n */\nexport const DEFAULT_BACKGROUND_PERMISSION_POLICY: TBackgroundPermissionPolicy =\n 'inherit-allowlist';\n","/**\n * Shell-line segmentation for the `command` argument matcher (issue #2427).\n *\n * Split out of `argument-matchers.ts`, which owns HOW a pattern of a declared kind is compared with\n * an argument; this module owns the one question underneath the `command` kind — where a shell line\n * stops being ONE command. Two answers over the same quoting rules: whether a line carries a second\n * command at all ({@link hasUnquotedCommandSeparator}, the ALLOW direction's refusal), and what the\n * individual commands are ({@link splitCommandSegments}, which the DENY direction judges one by\n * one). Keeping both here is what keeps them agreeing on what a separator IS.\n *\n * No Node builtin: `agent-core` ships a browser bundle (CORE-028), and this is pure string work.\n */\n\n/**\n * Does the command line carry a second command? A separator (`;`, `&`, `&&`, `|`, `||`, newline)\n * outside quotes, or a substitution (`$(`, backtick, `<(`, `>(`) outside SINGLE quotes — double\n * quotes do not stop the shell from running what is inside `\"$(…)\"`. A backslash outside single\n * quotes escapes the next character. `Bash(git *)` then does not match `git status; rm -rf /`.\n *\n * The anti-goal (issue #2427): refusal comes from RECOGNISING a separator, not from escaping more\n * characters in the glob — `*` in a pattern still stands for any run of characters, so the\n * pattern's author keeps writing `git *` and the gate keeps `git commit -m \"a; b\"` matchable.\n */\nexport function hasUnquotedCommandSeparator(command: string): boolean {\n let quote: \"'\" | '\"' | undefined;\n for (let index = 0; index < command.length; index += 1) {\n const char = command[index]!;\n if (quote === \"'\") {\n if (char === \"'\") quote = undefined;\n continue;\n }\n if (char === '\\\\') {\n index += 1;\n continue;\n }\n const next = command[index + 1];\n if (char === '`' || (char === '$' && next === '(')) return true;\n if (quote === '\"') {\n if (char === '\"') quote = undefined;\n continue;\n }\n if (char === \"'\" || char === '\"') {\n quote = char;\n continue;\n }\n if (char === ';' || char === '|' || char === '\\n') return true;\n if ((char === '<' || char === '>') && next === '(') return true;\n // `2>&1`, `<&0` and `&>log` are redirections, not a second command.\n if (char === '&') {\n const previous = command[index - 1];\n if (previous !== '>' && previous !== '<' && next !== '>') return true;\n }\n }\n return false;\n}\n\n/**\n * Cut a command line into the individual commands it runs: at every unquoted separator, and at\n * every substitution boundary — `$(…)`, `` `…` ``, `<(…)`, `>(…)` — whose contents are a command of\n * their own even inside double quotes. The quoting rules are `hasUnquotedCommandSeparator`'s, so\n * the two functions agree on what a separator IS; a separator the shell would treat as literal text\n * (single- or double-quoted, or backslash-escaped) does not cut, and a redirection (`2>&1`, `&>log`)\n * is not a cut either.\n *\n * Segment text is kept RAW (quotes included, ends trimmed): the pattern glob is written against the\n * command line as the caller wrote it, so unquoting here would change what `Bash(rm *)` compares\n * with. Empty segments are dropped.\n */\nexport function splitCommandSegments(command: string): string[] {\n const scan: IScanState = { segments: [], current: '', quote: undefined, substitutionDepth: 0 };\n for (let index = 0; index < command.length; index += 1) {\n // The order below IS the rule: single-quoted text and backslash escapes are literal first, a\n // substitution runs whatever quoting surrounds it next, double quotes only then suppress the\n // remaining separators. `hasUnquotedCommandSeparator` asks the same questions in the same order.\n const literal = consumeLiteralText(scan, command, index);\n if (literal !== undefined) {\n index = literal;\n continue;\n }\n const substitution = consumeSubstitutionOpen(scan, command, index);\n if (substitution !== undefined) {\n index = substitution;\n continue;\n }\n if (consumeQuote(scan, command[index]!)) continue;\n const separator = consumeSeparator(scan, command, index);\n if (separator !== undefined) {\n index = separator;\n continue;\n }\n scan.current += command[index]!;\n }\n cut(scan);\n return scan.segments;\n}\n\n/** The scanner's whole state: what has been cut off, what is being accumulated, and where it is. */\ninterface IScanState {\n segments: string[];\n current: string;\n quote: \"'\" | '\"' | undefined;\n substitutionDepth: number;\n}\n\n/** End the segment under construction. An empty one is dropped, so `a ;; b` is two commands. */\nfunction cut(scan: IScanState): void {\n const trimmed = scan.current.trim();\n if (trimmed !== '') scan.segments.push(trimmed);\n scan.current = '';\n}\n\n/**\n * Text that cannot be a boundary whatever follows: the body of a single-quoted run, and a\n * backslash with the character it escapes (which the shell honours inside double quotes too).\n * Returns the last index consumed, or `undefined` when this character is not literal text.\n */\nfunction consumeLiteralText(scan: IScanState, command: string, index: number): number | undefined {\n const char = command[index]!;\n if (scan.quote === \"'\") {\n scan.current += char;\n if (char === \"'\") scan.quote = undefined;\n return index;\n }\n if (char === '\\\\') {\n const escaped = command[index + 1];\n scan.current += escaped === undefined ? char : char + escaped;\n return index + 1;\n }\n return undefined;\n}\n\n/**\n * A substitution runs its contents whatever quoting surrounds it — `\"$(…)\"` included — so it cuts\n * before the double-quote rule is consulted. Returns the last index consumed, else `undefined`.\n */\nfunction consumeSubstitutionOpen(\n scan: IScanState,\n command: string,\n index: number,\n): number | undefined {\n const char = command[index]!;\n if (char === '`') {\n cut(scan);\n return index;\n }\n if (char === '$' && command[index + 1] === '(') {\n cut(scan);\n scan.substitutionDepth += 1;\n return index + 1;\n }\n return undefined;\n}\n\n/** Enter or leave a quoted run, keeping the quote character in the segment text. */\nfunction consumeQuote(scan: IScanState, char: string): boolean {\n if (scan.quote === '\"') {\n scan.current += char;\n if (char === '\"') scan.quote = undefined;\n return true;\n }\n if (char === \"'\" || char === '\"') {\n scan.quote = char;\n scan.current += char;\n return true;\n }\n return false;\n}\n\n/**\n * The boundaries that only apply outside quotes: process substitution (`<(`, `>(`), the `)` that\n * closes one, and the plain separators `;` `|` `&` and newline. Returns the last index consumed,\n * else `undefined`.\n */\nfunction consumeSeparator(scan: IScanState, command: string, index: number): number | undefined {\n const char = command[index]!;\n if ((char === '<' || char === '>') && command[index + 1] === '(') {\n cut(scan);\n scan.substitutionDepth += 1;\n return index + 1;\n }\n if (char === ')' && scan.substitutionDepth > 0) {\n cut(scan);\n scan.substitutionDepth -= 1;\n return index;\n }\n if (char === ';' || char === '|' || char === '\\n') {\n cut(scan);\n return index;\n }\n if (char === '&' && startsASecondCommand(command, index)) {\n cut(scan);\n return index;\n }\n return undefined;\n}\n\n/** `2>&1`, `<&0` and `&>log` are redirections, not a second command. */\nfunction startsASecondCommand(command: string, index: number): boolean {\n const previous = command[index - 1];\n return previous !== '>' && previous !== '<' && command[index + 1] !== '>';\n}\n","/**\n * The per-kind argument matchers the permission gate dispatches to (CORE-049, issue #2350).\n *\n * Kept beside the gate rather than inside it: the gate owns WHEN a pattern is consulted (deny,\n * unevaluable, allow, mode policy); this module owns HOW one pattern is compared with one argument\n * of a declared kind. Nothing here reads the profile registry or the mode — and nothing here\n * imports a Node builtin: `agent-core` ships a browser bundle (CORE-028), so path normalisation is\n * lexical and IDN mapping goes through the WHATWG `URL` the platform provides.\n */\n\nimport { hasUnquotedCommandSeparator, splitCommandSegments } from './command-segments.js';\n/**\n * What kind of thing a tool's primary argument is — which decides how a pattern is matched against\n * it. CORE-049 (issue #2350): one glob served every kind, so `WebFetch(https://*.example.com/**)`\n * was a wildcard over the whole URL string — query, fragment, userinfo and path included — and\n * `Read(/src/*)` crossed `/`. Each kind has its own delimiter and its own canonical form:\n *\n * - `url` — the pattern is split by a grammar (scheme, host, port, path) and the ARGUMENT is\n * parsed with `new URL`, so alternate host encodings canonicalise before comparison;\n * query and fragment never participate; only special schemes are comparable.\n * - `path` — separators normalised, both sides lexically normalised; `*` stays inside one\n * segment, `**` crosses.\n * - `command` — a shell-style glob (`*` any run of characters) over ONE command: on the ALLOW side\n * an argument that carries a separator (`;` `&` `|` newline) or a substitution (`$(`\n * backtick `<(` `>(`) outside single quotes is not a command the pattern names\n * (issue #2427); on the DENY side the same line is cut at those boundaries and every\n * command it runs is judged, so a chained command cannot walk past a deny entry.\n * - `text` — today's glob, for arguments that are neither (a search query, a glob pattern).\n *\n * A bare `*` or `**` argument pattern matches ANY invocation of the tool, for every kind and for a\n * tool that declared no argument at all — the contract `toolNamesToPatterns` (preset\n * `allowedTools`/`deniedTools` → `Tool(*)`) relies on.\n */\nexport type TArgumentKind = 'path' | 'url' | 'command' | 'text';\n\n/**\n * One match is three answers, not two. A pattern or argument the matcher cannot interpret in the\n * declared kind is UNEVALUABLE — `url`: the argument does not parse, carries userinfo, has no host\n * or a non-special scheme, or a path segment does not percent-decode or decodes to a separator\n * (`%2F`); the pattern does not fit the grammar, its literal host does not parse, or a segment of\n * its path does not decode; `path`: a relative argument under an absolute pattern. An unevaluable deny is not \"not denied\" (CORE-030: \"I cannot tell\" is not \"no\"):\n * `hasUnevaluableArgumentPattern` reports it and the gate prompts instead of falling through to the\n * allow list and the mode policy, which for an `inspect` tool is `auto` in every mode.\n */\nexport type TPatternMatch = 'match' | 'no-match' | 'unevaluable';\n\n/**\n * Which LIST the pattern being evaluated came from — because for the `command` kind the two lists\n * are not mirror images of each other, and treating them as one is a permission bypass.\n *\n * An allow pattern answers \"is THIS the command I blessed?\", so a line carrying a second command is\n * not it (issue #2427). A deny pattern answers \"does this line RUN the command I forbade?\", and\n * there the same rule reads \"not denied\": `deny: ['Bash(rm *)']` stopped matching\n * `rm -rf / ; echo done`, which then fell through to `allow: ['Bash']` or to the mode policy and\n * was auto-approved. Appending `; echo done` to walk past a deny entry is precisely what a deny\n * list exists to stop, so the deny direction looks INSIDE the line instead of refusing to judge it.\n *\n * Every other kind (`path`, `url`, `text`) matches identically in both directions and ignores this.\n */\nexport type TMatchDirection = 'allow' | 'deny';\n\nconst REGEX_SPECIALS = /[.+^${}()|[\\]\\\\]/g;\n\n/**\n * Convert a glob-style wildcard pattern to a RegExp — the `text` matcher, and the first half of\n * the `command` one.\n * Only `*` and `**` wildcards are supported (same semantics as minimatch lite).\n */\nexport function globToRegex(glob: string): RegExp {\n const escaped = glob\n .replace(REGEX_SPECIALS, '\\\\$&') // escape regex specials except * ?\n .replace(/\\*\\*/g, '.+') // ** → one-or-more any char\n .replace(/\\*/g, '.*'); // * → zero-or-more any char (shell-style, not path-segment restricted)\n return new RegExp(`^${escaped}$`);\n}\n\n/**\n * The `command` matcher. The glob decides whether the pattern names this command; what a separator\n * or substitution outside quotes MEANS depends on which list the pattern came from\n * ({@link TMatchDirection}).\n *\n * ALLOW (issue #2427): a line carrying a second command is not the one command the pattern named,\n * so it is `no-match` and the invocation goes on to be judged by the mode. A pattern without a\n * wildcard is the exact line and matches it — an operator who allowed `git status && git push`\n * verbatim wrote the whole line, and only the whole line is allowed.\n *\n * DENY: refusing to judge a chained line would answer \"not denied\", which auto-approves it. So the\n * glob is tried against the whole line AND against each command the line runs: `deny: ['Bash(rm *)']`\n * catches `rm -rf / ; echo done`, `git status; rm -rf /` and `echo $(rm -rf /tmp/x)` alike. Quoting\n * is still honoured, so `echo \"rm -rf /\"` — which runs no `rm` — is not denied.\n */\nexport function matchCommand(\n pattern: string,\n argument: string,\n direction: TMatchDirection,\n): TPatternMatch {\n const regex = globToRegex(pattern);\n if (direction === 'deny') {\n if (regex.test(argument)) return 'match';\n return splitCommandSegments(argument).some((segment) => regex.test(segment))\n ? 'match'\n : 'no-match';\n }\n if (!regex.test(argument)) return 'no-match';\n if (!pattern.includes('*')) return 'match';\n return hasUnquotedCommandSeparator(argument) ? 'no-match' : 'match';\n}\n\n/**\n * A segment glob: `*` never crosses `/`; `**` does, gitignore-style — `a/**` also matches `a`,\n * `a/**\\/b` also matches `a/b` (zero or more directories), and a bare `**` matches anything.\n */\nfunction segmentGlobToRegex(glob: string): RegExp {\n // Adjacent `**` mean what one means (gitignore: `a/**/**/b` is `a/**/b`); then tokenise so the\n // two wildcards never collide — `**` crosses segments, `*` stays inside one. A `\\uE000` mark is a\n // literal `*` that percent-decoding produced (`%2A`): it must not become a wildcard.\n const body = glob\n .replace(/\\*\\*(?:\\/\\*\\*)+/g, '**')\n .split(/(\\/\\*\\*\\/|\\/\\*\\*$|^\\*\\*\\/|\\*\\*)/)\n .map((token) => {\n if (token === '/**/') return '(?:/.*)?/';\n if (token === '/**') return '(?:/.*)?';\n if (token === '**/') return '(?:.*/)?';\n if (token === '**') return '.*';\n return token\n .replace(REGEX_SPECIALS, '\\\\$&')\n .replace(/\\*/g, '[^/]*')\n .replace(/\\uE000/g, '\\\\*');\n })\n .join('');\n return new RegExp(`^${body}$`);\n}\n\n/** `/…` on every platform; `X:/…` is absolute too, so a Windows argument is judged, not dropped. */\nfunction isAbsolutePathLike(normalised: string): boolean {\n return normalised.startsWith('/') || /^[A-Za-z]:(?=\\/|$)/.test(normalised);\n}\n\n/**\n * `\\` → `/`, `.`/`..` collapsed lexically (no filesystem access, no Node builtin), a drive letter\n * lower-cased (case-insensitive filesystems). A leading `..` on an absolute path stays at the root,\n * as `path.posix.normalize` does; on a relative path it is kept, so `../x` remains `../x`.\n */\nfunction normalisePathText(text: string): string {\n const slashed = text.replace(/\\\\/g, '/');\n const absolute = slashed.startsWith('/');\n const out: string[] = [];\n for (const segment of slashed.split('/')) {\n if (segment === '' || segment === '.') continue;\n if (segment === '..') {\n if (out.length > 0 && out[out.length - 1] !== '..') out.pop();\n else if (!absolute) out.push('..');\n continue;\n }\n out.push(segment);\n }\n const joined = (absolute ? '/' : '') + out.join('/');\n const normalised = joined === '' ? '.' : joined;\n return normalised.replace(/^[A-Za-z]:(?=\\/|$)/, (drive) => drive.toLowerCase());\n}\n\n/** The `path` matcher: separators and `.`/`..` normalised lexically; a relative argument under an absolute pattern is unevaluable. */\nexport function matchPath(pattern: string, argument: string): TPatternMatch {\n const normalisedPattern = normalisePathText(pattern);\n const normalisedArgument = normalisePathText(argument);\n if (isAbsolutePathLike(normalisedPattern) && !isAbsolutePathLike(normalisedArgument)) {\n // No base to resolve the argument against (issue #2429 owns where that happens). Not \"no\".\n return 'unevaluable';\n }\n return segmentGlobToRegex(normalisedPattern).test(normalisedArgument) ? 'match' : 'no-match';\n}\n\n/**\n * The grammar a `url` PATTERN must fit: `scheme://host[:port][/path]` — scheme a literal or `*`;\n * host a bracketed IPv6 literal or labels carrying `*`/`**` (never `@`, `:`, `/`, `?`, `#`); port a\n * number or `*`; path optional. Userinfo, query and fragment do not fit: such a pattern is not a\n * host pattern and is refused as unevaluable rather than guessed at.\n */\nconst URL_PATTERN_GRAMMAR =\n /^(\\*|[a-z][a-z0-9+.-]*):\\/\\/(\\[[0-9a-fA-F:.]+\\]|[^/\\\\:?#@[\\]]+)(?::(\\d+|\\*))?(\\/[^?#]*)?$/i;\n\n/** The schemes whose host `new URL` canonicalises; any other scheme keeps its host opaque. */\nconst SPECIAL_SCHEMES: ReadonlySet<string> = new Set(['http', 'https', 'ws', 'wss', 'ftp']);\nconst DEFAULT_PORT: Readonly<Record<string, string>> = {\n http: '80',\n https: '443',\n ws: '80',\n wss: '443',\n ftp: '21',\n};\n\n/** Both sides drop one trailing dot and lower-case; `new URL` does neither for the trailing dot. */\nfunction canonicalHostText(host: string): string {\n return host.replace(/\\.$/, '').toLowerCase();\n}\n\n/** A single host label in its ASCII (punycode) form via the platform URL parser; null when invalid. */\nfunction labelToASCII(label: string): string | null {\n try {\n const host = new URL(`http://${label}/`).hostname;\n return host === '' || host.includes('.') ? null : host;\n } catch {\n // allow-fallback: a label the URL parser refuses is reported as an unevaluable pattern by the\n // caller (a prompt on the deny side), never as a match or a silent non-match.\n return null;\n }\n}\n\n/**\n * A wildcard host pattern as a RegExp over the argument's canonical hostname. `*` as a whole\n * label = one or more labels; `**` as a whole label = zero or more (so `**.example.com` covers the\n * apex); `*` inside a label = within that label; `*` as the entire host = any host. Literal labels\n * are mapped to their ASCII (punycode) form by the platform URL parser, so an IDN pattern meets the\n * argument's punycode form; a label the parser refuses or splits makes the pattern unevaluable. `a**b` inside a label\n * is not a rule this grammar states and yields null (unevaluable).\n */\nfunction hostPatternToRegex(hostPattern: string): RegExp | null {\n // Adjacent `**` labels mean what one means.\n const labels = canonicalHostText(hostPattern)\n .replace(/\\*\\*(?:\\.\\*\\*)+/g, '**')\n .split('.');\n const parts: string[] = [];\n const LABELS = '[^.]+(?:\\\\.[^.]+)*'; // one or more dot-separated labels\n for (const [index, label] of labels.entries()) {\n const first = index === 0;\n const last = index === labels.length - 1;\n // Dots between labels are LITERAL — `*.example.com` must not match `evilexample.com`. Only a\n // `**` label, which may stand for zero labels, absorbs the dot beside it.\n if (label === '**') {\n if (first && last) parts.push(LABELS);\n else if (last) parts.push(`(?:\\\\.${LABELS})?`);\n else parts.push(`${first ? '' : '\\\\.'}(?:${LABELS}\\\\.)?`);\n continue;\n }\n const previousWasAnyLabels = !first && labels[index - 1] === '**';\n const dot = first || previousWasAnyLabels ? '' : '\\\\.';\n if (label === '*') parts.push(`${dot}${LABELS}`);\n else if (label.includes('**')) return null;\n else if (label.includes('*')) {\n parts.push(`${dot}${label.replace(REGEX_SPECIALS, '\\\\$&').replace(/\\*/g, '[^.]*')}`);\n } else {\n const ascii = labelToASCII(label);\n if (ascii === null) return null;\n parts.push(`${dot}${ascii.replace(REGEX_SPECIALS, '\\\\$&')}`);\n }\n }\n return new RegExp(`^${parts.join('')}$`);\n}\n\n/**\n * A percent-decoded pathname, segment by segment; null when a segment does not decode or decodes\n * to something containing `/` (`%2F`) — such a segment is neither a separator nor a name a pattern\n * segment could equal, so it is reported as unevaluable rather than guessed at.\n */\nfunction decodedSegments(pathname: string): string | null {\n try {\n const segments = pathname.split('/').map((segment) => decodeURIComponent(segment));\n if (segments.some((segment) => segment.includes('/'))) return null;\n return segments.join('/');\n } catch {\n // allow-fallback: a segment that does not percent-decode is reported by the caller as\n // UNEVALUABLE (a prompt on the deny side), never as a match or a silent non-match.\n return null;\n }\n}\n\n/** The argument as a `URL` whose host can be compared; null when it cannot be. */\nfunction parseComparableUrl(argument: string): URL | null {\n let url: URL;\n try {\n url = new URL(argument);\n } catch {\n // allow-fallback: an argument that does not parse is reported by the caller as UNEVALUABLE.\n return null;\n }\n const scheme = url.protocol.slice(0, -1).toLowerCase();\n if (!SPECIAL_SCHEMES.has(scheme)) return null; // `file:`, `foo:`: host opaque or absent\n if (url.hostname === '') return null;\n if (url.username !== '' || url.password !== '') return null;\n return url;\n}\n\n/** The host clause: a wildcard pattern by regex, a literal one canonicalised like the argument. */\nfunction matchHost(hostPattern: string, host: string): TPatternMatch {\n if (hostPattern.includes('*')) {\n const regex = hostPatternToRegex(hostPattern);\n if (regex === null) return 'unevaluable';\n return regex.test(host) ? 'match' : 'no-match';\n }\n // A literal pattern host is canonicalised the way the argument's was — by a special scheme,\n // whatever the pattern's scheme (including `*`).\n let literal: string;\n try {\n literal = new URL(`http://${hostPattern}/`).hostname;\n } catch {\n // allow-fallback: a literal host the parser refuses is reported as UNEVALUABLE, never matched.\n return 'unevaluable';\n }\n return canonicalHostText(literal) === host ? 'match' : 'no-match';\n}\n\n/** The port clause: absent means the scheme default only; `*` means any; else the exact port. */\nfunction matchPort(portPattern: string | undefined, url: URL, scheme: string): boolean {\n if (portPattern === undefined) return url.port === '';\n if (portPattern === '*') return true;\n const port = url.port === '' ? DEFAULT_PORT[scheme] : url.port;\n return portPattern === port;\n}\n\n/** The path clause: both sides percent-decoded segment by segment, then a segment glob. */\nfunction matchPathname(pathPattern: string, pathname: string): TPatternMatch {\n const decoded = decodedSegments(pathname);\n // A percent-encoded `*` in the PATTERN is a literal star, not a wildcard: mark it before decoding.\n const decodedPattern = decodedSegments(pathPattern.replace(/%2a/gi, '\\uE000'));\n if (decoded === null || decodedPattern === null) return 'unevaluable';\n return segmentGlobToRegex(decodedPattern).test(decoded) ? 'match' : 'no-match';\n}\n\n/** The `url` matcher: the pattern by grammar, the argument by `new URL`, compared structurally. */\nexport function matchUrl(pattern: string, argument: string): TPatternMatch {\n const grammar = URL_PATTERN_GRAMMAR.exec(pattern);\n if (grammar === null) return 'unevaluable';\n const [, schemePattern, hostPattern, portPattern, pathPattern] = grammar;\n\n const url = parseComparableUrl(argument);\n if (url === null) return 'unevaluable';\n const scheme = url.protocol.slice(0, -1).toLowerCase();\n if (schemePattern !== '*' && schemePattern.toLowerCase() !== scheme) return 'no-match';\n\n const host = matchHost(hostPattern, canonicalHostText(url.hostname));\n if (host !== 'match') return host;\n if (!matchPort(portPattern, url, scheme)) return 'no-match';\n if (pathPattern !== undefined) return matchPathname(pathPattern, url.pathname);\n return 'match';\n}\n","/**\n * Permission mode definitions.\n *\n * A permission mode answers one question — how much does this session do without asking? — and it\n * answers it about a KIND of action, not about a named product tool.\n *\n * CORE-030: this file used to enumerate `TKnownToolName`\n * (`'Shell' | 'Bash' | 'Read' | 'Write' | 'Edit' | …`) and key the policy matrix on it. That put a\n * product's tool inventory in the vendor-neutral foundation, two layers below the packages that\n * define those tools, with nothing coupling the two lists — and the drift was not hypothetical:\n * `Agent`, `BackgroundProcess`, `CodebaseRetrieval` and `ExecuteCommand` were all produced tools the\n * matrix had never heard of. A read-only retrieval tool therefore prompted on every call and was\n * refused outright in plan mode, because \"unknown\" is the only thing the foundation could say about\n * it.\n *\n * The foundation now owns the POLICY (what each mode does about each kind of action) and each tool\n * owns its own CLASSIFICATION (which kind it is), declared where the tool is defined. Neither can\n * drift from the other, because neither restates the other's half.\n *\n * The modes themselves are Claude Code-compatible:\n * - plan: inspect freely, change nothing\n * - default: safe reads proceed, changes and command execution need approval\n * - acceptEdits: reads and workspace edits proceed, command execution still needs approval\n * - bypassPermissions: everything proceeds\n */\n\nimport type { TPermissionMode, TPermissionDecision } from './types.js';\n\n/**\n * What kind of action a tool performs, from the permission system's point of view.\n *\n * These are the only distinctions the modes actually make, derived from the matrix this replaced:\n *\n * - `inspect` — observes without changing anything the user would want to approve. Reading a file,\n * searching, fetching a page, looking at the screen. Asking the user a question is here too: it\n * changes nothing, and prompting for permission to prompt is not a decision anyone wants to make.\n * - `modify` — changes the user's workspace. Writing and editing files. This is the distinction\n * `acceptEdits` exists for: it is the class that mode stops asking about.\n * - `execute` — runs an arbitrary command, or acts outside the workspace where the blast radius is\n * not bounded by a path. Shell, and a GUI action that clicks something real. `acceptEdits`\n * deliberately does NOT cover this: accepting edits is not accepting execution.\n *\n * A tool that fits none of these is not a new class by default — it takes the unclassified fallback\n * below, which prompts. Adding a class means a mode has to say something new about it.\n */\nexport type TToolRiskClass = 'inspect' | 'modify' | 'execute';\n\n/**\n * Permission mode → risk class → decision.\n *\n * `'auto'` proceeds silently, `'approve'` asks the user, `'deny'` refuses (see `./types.js`).\n */\nexport const RISK_CLASS_POLICY: Record<\n TPermissionMode,\n Record<TToolRiskClass, TPermissionDecision>\n> = {\n plan: {\n inspect: 'auto',\n modify: 'deny',\n execute: 'deny',\n },\n default: {\n inspect: 'auto',\n modify: 'approve',\n execute: 'approve',\n },\n acceptEdits: {\n inspect: 'auto',\n // The whole point of this mode.\n modify: 'auto',\n // And the whole point of it stopping here.\n execute: 'approve',\n },\n bypassPermissions: {\n inspect: 'auto',\n modify: 'auto',\n execute: 'auto',\n },\n // `approve` here means \"not decided by the mode\": the session routes it to the classifier, not\n // straight to a person. Edits are contained to the workspace by the file tools themselves.\n auto: {\n inspect: 'auto',\n modify: 'auto',\n execute: 'approve',\n },\n};\n\n/**\n * Decision for a tool whose owner has not declared a risk class.\n *\n * Fail-safe rather than fail-open: `'approve'` asks the user, it does not proceed. `plan` refuses,\n * because a mode whose promise is \"change nothing\" cannot keep that promise about an action it\n * cannot classify.\n */\nexport const UNCLASSIFIED_TOOL_FALLBACK: Record<TPermissionMode, TPermissionDecision> = {\n plan: 'deny',\n default: 'approve',\n acceptEdits: 'approve',\n bypassPermissions: 'auto',\n auto: 'approve',\n};\n","/**\n * The calls no rule and no mode may auto-approve (issue #3081, never-auto-approve set).\n *\n * Two families live here, both answered from the call's own arguments:\n *\n * - **critical-path removal** — a shell line that runs `rm`/`rmdir` against the filesystem root, a\n * top-level directory, the home directory, or the working directory or one of its parents;\n * - **protected paths** — a modify-class call whose path argument lands in a directory or file that\n * holds repository, agent or shell configuration, where a silent write widens what later turns,\n * child sessions or the user's shell will trust.\n *\n * Pure string work — `agent-core` ships a browser bundle (CORE-028), so no Node builtin.\n */\n\nimport { splitCommandSegments } from './command-segments.js';\n\n/** Directories whose contents configure the repository, the agent or its hooks. */\nexport const PROTECTED_DIRECTORY_NAMES: readonly string[] = ['.git', '.robota', '.claude', '.agents'];\n\n/** Files that configure git, npm, MCP servers or the user's shell, wherever they sit. */\nexport const PROTECTED_FILE_NAMES: readonly string[] = [\n '.mcp.json',\n '.gitconfig',\n '.npmrc',\n '.bashrc',\n '.bash_profile',\n '.bash_login',\n '.zshrc',\n '.zshenv',\n '.zprofile',\n '.profile',\n];\n\n/**\n * An isolated subagent's worktree lives under `.robota/worktrees/<name>` (and Claude Code's under\n * `.claude/worktrees`). Its files are ordinary workspace files; protection resumes for any protected\n * name inside the worktree.\n */\nconst WORKTREE_CONTAINER = 'worktrees';\n\nfunction pathSegments(path: string): string[] {\n return path\n .replace(/\\\\/g, '/')\n .split('/')\n .filter((segment) => segment !== '' && segment !== '.');\n}\n\n/**\n * Collapse `.` and `..` lexically, keeping a leading `..` of a relative path. Without this a path\n * like `.robota/worktrees/../settings.json` reads as a worktree file while naming the settings file.\n */\nfunction resolvedSegments(path: string): string[] {\n const out: string[] = [];\n for (const segment of pathSegments(path)) {\n if (segment !== '..') out.push(segment);\n else if (out.length > 0 && out[out.length - 1] !== '..') out.pop();\n else out.push(segment);\n }\n return out;\n}\n\n/** Whether a path names a protected directory, something inside one, or a protected file. */\nexport function isProtectedPath(path: string): boolean {\n const segments = resolvedSegments(path);\n const last = segments[segments.length - 1];\n if (last !== undefined && PROTECTED_FILE_NAMES.includes(last)) return true;\n for (let index = 0; index < segments.length; index += 1) {\n const segment = segments[index]!;\n if (!PROTECTED_DIRECTORY_NAMES.includes(segment)) continue;\n const isWorktreeEntry =\n (segment === '.robota' || segment === '.claude') &&\n segments[index + 1] === WORKTREE_CONTAINER &&\n segments[index + 2] !== undefined;\n if (isWorktreeEntry) {\n index += 2;\n continue;\n }\n return true;\n }\n return false;\n}\n\n/** Where a removal is judged from. Either may be unknown; what is unknown is not guessed. */\nexport interface ICriticalPathContext {\n /** The session's execution root. */\n cwd?: string;\n /** The user's home directory. */\n homeDirectory?: string;\n}\n\nfunction normaliseAbsolute(path: string): string {\n const out: string[] = [];\n for (const segment of pathSegments(path)) {\n if (segment === '..') out.pop();\n else out.push(segment);\n }\n return `/${out.join('/')}`;\n}\n\nfunction unquoteWord(word: string): string {\n return word.replace(/^(['\"])(.*)\\1$/, '$2');\n}\n\n/** `~`, `$HOME` or `${HOME}`, then the rest of the path (possibly empty). */\nconst HOME_PREFIX = /^(?:~|\\$HOME|\\$\\{HOME\\})(?=\\/|$)(.*)$/;\n\nfunction isCriticalTarget(word: string, context: ICriticalPathContext): boolean {\n const text = unquoteWord(word);\n const home = HOME_PREFIX.exec(text);\n let absolute: string;\n if (home !== null) {\n const rest = home[1] ?? '';\n if (context.homeDirectory === undefined) return rest.replace(/\\/+/g, '') === '';\n absolute = normaliseAbsolute(`${context.homeDirectory}/${rest}`);\n } else if (text === '' || text.startsWith('$')) {\n return false;\n } else if (text.startsWith('/')) {\n absolute = normaliseAbsolute(text);\n } else {\n if (context.cwd === undefined) return false;\n absolute = normaliseAbsolute(`${context.cwd}/${text}`);\n }\n // The root, and every top-level directory (`/usr`, `/home`, …).\n if (pathSegments(absolute).length <= 1) return true;\n if (\n context.homeDirectory !== undefined &&\n absolute === normaliseAbsolute(context.homeDirectory)\n ) {\n return true;\n }\n if (context.cwd !== undefined) {\n const cwd = normaliseAbsolute(context.cwd);\n // The working directory itself, or any of its parents.\n if (cwd === absolute || cwd.startsWith(`${absolute}/`)) return true;\n }\n return false;\n}\n\nconst REMOVAL_COMMANDS = new Set(['rm', 'rmdir']);\n/**\n * Wrappers that run the command after them unchanged, and which of their options take a value\n * (so the value is not mistaken for the program).\n */\nconst TRANSPARENT_WRAPPERS: ReadonlyMap<string, ReadonlySet<string>> = new Map([\n ['sudo', new Set(['-u', '-g', '-h', '-p', '-C', '-D', '-r', '-t', '-U', '-T'])],\n ['nice', new Set(['-n'])],\n ['env', new Set(['-u', '-C', '-S'])],\n ['command', new Set<string>()],\n ['builtin', new Set<string>()],\n ['nohup', new Set<string>()],\n ['time', new Set<string>()],\n]);\n\n/** Index of the program a segment runs, past assignments, wrappers and the wrappers' options. */\nfunction programIndex(words: readonly string[]): number {\n let index = 0;\n let valueOptions: ReadonlySet<string> | undefined;\n while (index < words.length) {\n const word = words[index]!;\n if (/^[A-Za-z_]\\w*=/.test(word)) {\n index += 1;\n continue;\n }\n const wrapper = TRANSPARENT_WRAPPERS.get(word);\n if (wrapper !== undefined) {\n valueOptions = wrapper;\n index += 1;\n continue;\n }\n if (valueOptions !== undefined && word.startsWith('-')) {\n index += valueOptions.has(word) ? 2 : 1;\n continue;\n }\n return index;\n }\n return index;\n}\n\n/**\n * Whether a shell line removes a critical path in any of the commands it runs. The line is cut the\n * way the deny direction cuts it, so a removal cannot hide behind an unrelated command before it.\n */\nexport function removesCriticalPath(command: string, context: ICriticalPathContext): boolean {\n return splitCommandSegments(command).some((segment) => {\n const words = segment.split(/\\s+/).filter((word) => word !== '');\n const index = programIndex(words);\n const program = words[index];\n if (program === undefined) return false;\n const name = program.slice(program.lastIndexOf('/') + 1);\n if (!REMOVAL_COMMANDS.has(name)) return false;\n let optionsEnded = false;\n return words.slice(index + 1).some((word) => {\n if (!optionsEnded && word === '--') {\n optionsEnded = true;\n return false;\n }\n if (!optionsEnded && word.startsWith('-')) return false;\n return isCriticalTarget(word, context);\n });\n });\n}\n","/**\n * The built-in read-only shell commands: a call that only looks is decided like a read, so it runs\n * without a prompt in every mode (issue #3082).\n *\n * The set is fixed, not configurable: a user who wants a prompt for one of these adds an `ask` or\n * `deny` rule, which the gate checks first. Every rule below fails toward \"not read-only\" — a line\n * this module cannot fully account for is an ordinary command and takes the ordinary path.\n *\n * Two limits make \"looks like a read\" mean what `Read` means. The line stays inside the workspace:\n * no absolute, home-relative, climbing or provider path, no glob that could match `..`, and every\n * path operand resolves inside once symlinks are followed (by the host's resolver). And it uses only\n * printable ASCII syntax every shell the tool may run (sh, bash, zsh, fish, PowerShell) reads the\n * same way: plain words, quotes, pipes and separators, and redirects — no expansion, substitution,\n * grouping or comment.\n *\n * No Node builtin: `agent-core` ships a browser bundle, and this is pure string work.\n */\n\nimport { splitCommandSegments } from './command-segments.js';\n\n/** Past this length a line is not inspected at all. */\nconst MAX_INSPECTED_LENGTH = 10_000;\n\n/** Commands that read and print and nothing else, whatever their arguments. */\nconst PLAIN_READERS = new Set([\n 'ls',\n 'cat',\n 'echo',\n 'pwd',\n 'head',\n 'tail',\n 'grep',\n 'wc',\n 'which',\n 'stat',\n 'du',\n 'cd',\n]);\n\n/** `find` predicates that run, delete or write. */\nconst FIND_ACTIONS = new Set([\n '-exec',\n '-execdir',\n '-ok',\n '-okdir',\n '-delete',\n '-fprint',\n '-fprint0',\n '-fprintf',\n '-fls',\n]);\n\n/**\n * The short option letters each command may carry, matched inside a cluster (`-rn`) and with a\n * numeric value attached (`-n5`). An allowlist, not a denylist: the flags that follow symlinks or\n * read a file named elsewhere differ between GNU and BSD (`grep -S`, `grep -R`, `ls -L`), so a\n * letter not listed here fails closed. `find` predicates are words, judged separately.\n */\nconst ALLOWED_SHORT_OPTIONS: Readonly<Record<string, string>> = {\n ls: 'aAlhtrSR1dFGinpsucCgmoQvx',\n cat: 'nbsvetAE',\n head: 'nqvc',\n tail: 'nqvcfF',\n grep: 'rinlLvcwxEFGPHhoqsABCmz',\n wc: 'lwcmL',\n stat: 'cftx',\n du: 'hsacdkmx',\n which: 'a',\n pwd: 'LP',\n cd: 'LP',\n};\n\n/** Any option whose value is a file to read, or a list of files: `--file`, `--exclude-from`, `-files0-from`. */\nconst FILE_VALUED_OPTION = /^--?[A-Za-z0-9-]*(file|from|contents)(=|$)/;\n\n/**\n * Long options refused for any command in the set. GNU `getopt_long` and git both accept any\n * unambiguous prefix (`--deref`), so a word that could abbreviate one of these is refused too.\n */\nconst REFUSED_LONG_OPTIONS = [\n '--dereference',\n '--dereference-recursive',\n '--dereference-args',\n '--dereference-command-line',\n '--file',\n '--files0-from',\n '--exclude-from',\n '--from-file',\n '--to-file',\n '--contents',\n '--ignore-revs-file',\n '--output',\n '--output-directory',\n '--ext-diff',\n '--no-index',\n '--open-files-in-pager',\n];\n\nfunction abbreviatesRefusedOption(text: string): boolean {\n if (!text.startsWith('--') || text.length <= 2) return false;\n const name = text.split('=', 1)[0]!;\n return REFUSED_LONG_OPTIONS.some((option) => option.startsWith(name));\n}\n\nfunction usesRefusedOption(command: string, args: readonly IWord[]): boolean {\n if (\n optionWords(args).some(\n (word) => FILE_VALUED_OPTION.test(word.text) || abbreviatesRefusedOption(word.text),\n )\n ) {\n return true;\n }\n if (command === 'find') {\n return optionWords(args).some((word) => word.text === '-L' || word.text === '-follow');\n }\n const allowed = ALLOWED_SHORT_OPTIONS[command];\n if (allowed === undefined) return false;\n return optionWords(args).some(({ text }) => {\n if (text.startsWith('--') || !/^-[A-Za-z]/.test(text)) return false;\n return [...text.slice(1)].some((letter) => !/\\d/.test(letter) && !allowed.includes(letter));\n });\n}\n\nconst GIT_READERS = new Set([\n 'status',\n 'log',\n 'diff',\n 'show',\n 'rev-parse',\n 'ls-files',\n 'describe',\n 'branch',\n 'remote',\n]);\n\n/** `git branch` options that put it in list mode; without one of them a name creates a branch. */\nconst GIT_BRANCH_LIST_OPTIONS = new Set([\n '-l',\n '--list',\n '--show-current',\n '--merged',\n '--no-merged',\n '--contains',\n '--no-contains',\n '--points-at',\n]);\nconst GIT_BRANCH_DISPLAY_OPTIONS = new Set([\n '-a',\n '--all',\n '-r',\n '--remotes',\n '-v',\n '-vv',\n '--verbose',\n '--color',\n '--no-color',\n]);\n\ninterface IWord {\n /** The word as the command receives it, quotes removed. */\n readonly text: string;\n /** An unquoted glob character: what the command receives is not `text`. */\n readonly expands: boolean;\n}\n\n/** Output redirection targets that write nothing. */\nconst DISCARD_TARGETS = new Set(['/dev/null']);\n\n/**\n * The only characters an unquoted word may carry. Everything else — `$`, `{`, `(`, `#`, `!`, `^`,\n * backslash, backtick — means expansion, substitution, a comment, or a construct that differs\n * between bash, zsh, fish and PowerShell, and a line using one is not inspected further.\n */\nconst UNQUOTED_WORD_CHARACTER = /[A-Za-z0-9_./:=@+,*?[\\]~-]/;\n/** Inside double quotes these still expand or escape. */\nconst DOUBLE_QUOTE_ACTIVE = new Set(['$', '`', '\\\\', '!']);\nconst GLOB_CHARACTERS = new Set(['*', '?', '[']);\n\n/**\n * Whether a word names something outside the session's working directory: an absolute or\n * home-relative path, or a `..` that climbs, also as an option's value (`--file=/x`, `-f/x`).\n * The shell tool itself is not confined, so looking outside is not treated as a read.\n */\nfunction leavesWorkspace(text: string): boolean {\n return (\n /(^|[=,:])[/~]/.test(text) ||\n /^-[A-Za-z]+[/~]/.test(text) ||\n /(^|[/=,:]|^-[A-Za-z]+)\\.\\.(\\/|$)/.test(text) ||\n // A drive or provider prefix (`C:x`, `Env:`, `HKCU:`) names another place in PowerShell.\n /(^|[=,])[A-Za-z][A-Za-z0-9]*:/.test(text) ||\n globMayClimb(text)\n );\n}\n\n/**\n * Whether a glob could match `..`, which some shells (dash, bash before 5.2) do for a pattern\n * starting with `.`, `?` or `[`. A glob is accepted only in the last path segment, and not there\n * in those forms.\n */\nfunction globMayClimb(text: string): boolean {\n const segments = text.split('/');\n const hasGlob = (segment: string): boolean => /[*?[]/.test(segment);\n if (segments.slice(0, -1).some(hasGlob)) return true;\n const last = segments[segments.length - 1]!;\n return hasGlob(last) && /^[.?[]/.test(last);\n}\n\n/**\n * Whether the line expands or substitutes anything outside single quotes. Checked on the whole\n * line, before it is cut into segments, because the cut happens at substitution boundaries.\n */\nfunction hasActiveExpansion(line: string): boolean {\n let quote: \"'\" | '\"' | undefined;\n for (const char of line) {\n if (quote === \"'\") {\n if (char === \"'\") quote = undefined;\n continue;\n }\n if (char === '$' || char === '`' || char === '\\\\') return true;\n if (quote === '\"') {\n if (char === '\"') quote = undefined;\n continue;\n }\n if (char === \"'\" || char === '\"') quote = char;\n else if (char === '(' || char === ')' || char === '{' || char === '}') return true;\n }\n return false;\n}\n\ninterface ISegmentScan {\n readonly words: IWord[];\n /** Something the scan could not account for as read-only. */\n readonly refused: boolean;\n}\n\n/**\n * Split one segment into words and judge its redirections. An output redirect is allowed only to a\n * target that writes nothing or to another descriptor; an input redirect only from inside the\n * workspace; a here-doc is refused because its body lines are not segments of their own.\n */\nfunction scanSegment(segment: string): ISegmentScan {\n const words: IWord[] = [];\n let text = '';\n let expands = false;\n let inWord = false;\n let quote: \"'\" | '\"' | undefined;\n let pendingRedirect: 'output' | 'input' | 'duplicate' | undefined;\n let refused = false;\n\n const endWord = (): void => {\n if (!inWord) return;\n if (pendingRedirect === 'output') {\n if (!DISCARD_TARGETS.has(text) || expands) refused = true;\n } else if (pendingRedirect === 'duplicate') {\n // `2>&1`, `>&-`: another descriptor. Anything else after `>&` is a file (`>&out` = `&>out`).\n if (!/^(\\d+|-)$/.test(text)) refused = true;\n } else if (pendingRedirect === 'input') {\n if (expands || leavesWorkspace(text)) refused = true;\n } else {\n words.push({ text, expands });\n }\n pendingRedirect = undefined;\n text = '';\n expands = false;\n inWord = false;\n };\n\n for (let index = 0; index < segment.length && !refused; index += 1) {\n const char = segment[index]!;\n if (quote === \"'\") {\n if (char === \"'\") quote = undefined;\n else text += char;\n continue;\n }\n if (quote === '\"') {\n if (char === '\"') quote = undefined;\n else if (DOUBLE_QUOTE_ACTIVE.has(char)) refused = true;\n else text += char;\n continue;\n }\n if (char === \"'\" || char === '\"') {\n quote = char;\n inWord = true;\n continue;\n }\n if (char === ' ' || char === '\\t') {\n endWord();\n continue;\n }\n if (char === '>' || char === '<' || (char === '&' && segment[index + 1] === '>')) {\n // A word of digits right before the operator is its descriptor (`2>`), not an argument.\n if (inWord && !/^\\d+$/.test(text)) endWord();\n text = '';\n expands = false;\n inWord = false;\n if (char === '&') index += 1;\n const operator = char === '&' ? '>' : char;\n let next = segment[index + 1];\n if (operator === '<' && (next === '<' || next === '>')) {\n refused = true;\n break;\n }\n if (next === operator || next === '|') {\n index += 1;\n next = segment[index + 1];\n }\n if (next === '&' && char !== '&') {\n index += 1;\n pendingRedirect = 'duplicate';\n continue;\n }\n pendingRedirect = operator === '>' ? 'output' : 'input';\n continue;\n }\n if (!UNQUOTED_WORD_CHARACTER.test(char)) {\n refused = true;\n break;\n }\n // `HEAD~1` is a revision; a leading `~` is the home directory, which `leavesWorkspace` refuses.\n if (GLOB_CHARACTERS.has(char)) expands = true;\n text += char;\n inWord = true;\n }\n if (quote !== undefined) refused = true;\n endWord();\n // A redirect with no target is not something this scan can vouch for.\n if (pendingRedirect !== undefined) refused = true;\n return { words, refused };\n}\n\n/** The words before `--` that start with `-`; after `--` every word is an operand. */\nfunction optionWords(args: readonly IWord[]): IWord[] {\n const end = args.findIndex((word) => word.text === '--');\n return (end < 0 ? args : args.slice(0, end)).filter((word) => word.text.startsWith('-'));\n}\n\nfunction isReadOnlyFind(args: readonly IWord[]): boolean {\n return args.every((word) => !word.expands && !FIND_ACTIONS.has(word.text));\n}\n\n/** Mirrors git's own rule: only these put `git branch` in list mode, where names are patterns. */\nfunction isReadOnlyGitBranch(args: readonly IWord[]): boolean {\n const options = args.filter((word) => word.text.startsWith('-'));\n const listing = options.some((word) => GIT_BRANCH_LIST_OPTIONS.has(word.text));\n return (\n options.every(\n (word) => GIT_BRANCH_LIST_OPTIONS.has(word.text) || GIT_BRANCH_DISPLAY_OPTIONS.has(word.text),\n ) &&\n (listing || options.length === args.length)\n );\n}\n\nfunction isReadOnlyGit(args: readonly IWord[]): boolean {\n // Global options (`-c`, `-C`, `--exec-path`, …) change what git runs and where; only the pager\n // switch is known to be harmless.\n const rest = args[0]?.text === '--no-pager' ? args.slice(1) : args;\n const [subcommand, ...subArgs] = rest;\n if (subcommand === undefined || subcommand.expands || !GIT_READERS.has(subcommand.text)) {\n return false;\n }\n if (subArgs.some((word) => word.expands)) return false;\n // `--output` writes a file and `--ext-diff` runs a configured program.\n // `-X` and `-O` read an exclude or order file named anywhere.\n if (subArgs.some((word) => /^-[XO]/.test(word.text))) return false;\n // `--no-index` compares arbitrary files rather than the repository.\n if (subArgs.some((word) => /^--(output|ext-diff|open-files-in-pager|no-index)/.test(word.text))) {\n return false;\n }\n if (subcommand.text === 'branch') return isReadOnlyGitBranch(subArgs);\n if (subcommand.text === 'remote') {\n return subArgs.every((word) => word.text === '-v' || word.text === '--verbose');\n }\n return true;\n}\n\nfunction isReadOnlySegment(words: readonly IWord[]): boolean {\n const [command, ...args] = words;\n if (command === undefined || command.expands) return false;\n // A leading assignment (`PAGER=… git log`) configures what runs; a path is not the built-in.\n if (command.text.includes('=') || command.text.includes('/')) return false;\n // A leading `@` splats a variable in PowerShell and a leading `=` names a path in zsh.\n if (args.some((word) => /^[@=]/.test(word.text))) return false;\n // An unquoted glob expands to names the resolver never sees — a symlink out, or a file named\n // like an option (`-L`) — and for `echo` it lists a directory wherever it is.\n if (args.some((word) => word.expands)) return false;\n if (command.text === 'echo') return true;\n if (args.some((word) => leavesWorkspace(word.text))) return false;\n if (usesRefusedOption(command.text, args)) return false;\n // `cd` alone goes home and `cd -` goes back; only a named directory inside the workspace stays.\n if (command.text === 'cd') return args.length === 1 && args[0]!.text !== '-' && !args[0]!.expands;\n if (PLAIN_READERS.has(command.text)) return true;\n if (command.text === 'find') return isReadOnlyFind(args);\n if (command.text === 'git') return isReadOnlyGit(args);\n return false;\n}\n\n/** Commands whose operands are not paths the command opens. */\nconst NON_PATH_OPERANDS = new Set(['echo', 'which', 'git']);\n\n/**\n * Resolve every operand that could be a path, following symlinks, and require it to stay inside the\n * workspace — the check `Read` makes. A `cd` moves the base for the commands after it.\n */\nfunction operandsStayInWorkspace(\n segments: readonly (readonly IWord[])[],\n resolve: TResolveInWorkspace | undefined,\n): boolean {\n let base: string | undefined;\n for (const [command, ...args] of segments) {\n if (NON_PATH_OPERANDS.has(command!.text)) continue;\n // Options are resolved too: where parsing stops at the first operand (BSD, or\n // `POSIXLY_CORRECT`), a later `-sl` is a file. A word that names no file resolves inside.\n for (const word of args) {\n if (word.text === '--') continue;\n if (resolve === undefined) return false;\n const resolved = resolve(base, word.text);\n if (resolved === undefined) return false;\n if (command!.text === 'cd') base = resolved;\n }\n }\n return true;\n}\n\n/**\n * Resolve `path` against `base` (the working directory when absent), following symlinks, and return\n * where it really is — or `undefined` when that is outside the workspace. A path that does not\n * exist resolves through its nearest existing ancestor.\n */\nexport type TResolveInWorkspace = (base: string | undefined, path: string) => string | undefined;\n\nexport interface IReadOnlyCommandContext {\n /**\n * The call runs somewhere other than the session's working directory, so its relative paths are\n * not the workspace's and git would read another repository's configuration, which can name\n * programs to run.\n */\n readonly otherDirectory?: boolean;\n /**\n * Supplied by a host with a filesystem. Without it a command with a path operand is not\n * read-only, since a symlink inside the workspace can point anywhere.\n */\n readonly resolveInWorkspace?: TResolveInWorkspace;\n}\n\n/**\n * Whether every command the line runs is in the built-in read-only set. A compound line qualifies\n * only when each of its commands does on its own.\n */\nexport function isReadOnlyCommandLine(\n line: string,\n context: IReadOnlyCommandContext = {},\n): boolean {\n if (context.otherDirectory === true) return false;\n if (line.length > MAX_INSPECTED_LENGTH || hasActiveExpansion(line)) return false;\n // Other shells read some non-ASCII characters as syntax (PowerShell's curly quotes and dashes).\n if (/[^\\t\\n\\x20-\\x7e]/.test(line)) return false;\n const segments = splitCommandSegments(line);\n if (segments.length === 0) return false;\n const scanned = segments.map(scanSegment);\n if (scanned.some((segment) => segment.refused || !isReadOnlySegment(segment.words))) {\n return false;\n }\n const commands = scanned.map((segment) => segment.words[0]!.text);\n // `cd` then `git` runs git in another repository, under that repository's configuration.\n if (commands.includes('git') && commands.includes('cd')) return false;\n return operandsStayInWorkspace(\n scanned.map((segment) => segment.words),\n context.resolveInWorkspace,\n );\n}\n","/**\n * Permission gate — evaluates whether a tool call is auto-approved, needs user approval, or denied.\n *\n * ONE ordered policy for every caller class (issue #3081): the interactive session, background\n * tasks and subagents differ only in the context they pass, never in the order.\n *\n * 1. Deny list match → deny\n * 2. Outside the caller's ceiling → deny, in every mode\n * The reply to a peer outside a turn a peer's message started → deny\n * 3. Deny list UNEVALUABLE (CORE-030) → ask\n * 4. Never-auto-approve set → ask, in every mode: an ask rule, a critical-path removal, a\n * modify-class call on a protected path\n * 5. The caller asks about everything → ask\n * 6. bypassPermissions → auto\n * 7. Allow list match → auto\n * 8. Mode policy lookup\n *\n * In plan mode an ask about anything but an inspect-class call is a deny.\n *\n * Pattern syntax (same as Claude Code):\n * - `Bash(pnpm *)` — Bash tool whose command starts with \"pnpm \"\n * - `Read(/src/**)` — Read tool whose filePath is under /src/\n * - `Write(*)` — Write tool with any argument\n * - `ToolName` — match any invocation of that tool\n * - `Bash(run_in_background:true)` — deny/ask only: a named top-level parameter's value\n * - `github__*` — a glob in the tool-name position (allow only after a literal `<server>__`)\n */\n\nimport { globToRegex, matchCommand, matchPath, matchUrl } from './argument-matchers.js';\nimport { RISK_CLASS_POLICY, UNCLASSIFIED_TOOL_FALLBACK } from './permission-mode.js';\nimport { isProtectedPath, removesCriticalPath } from './permission-safeguards.js';\nimport { isReadOnlyCommandLine } from './read-only-commands.js';\nimport type { TResolveInWorkspace } from './read-only-commands.js';\n\nimport type { TArgumentKind, TMatchDirection, TPatternMatch } from './argument-matchers.js';\nimport type { TToolRiskClass } from './permission-mode.js';\nimport type { ICriticalPathContext } from './permission-safeguards.js';\nimport type { TPermissionMode, TPermissionDecision } from './types.js';\n\n/**\n * Tool arguments passed from the LLM invocation.\n * The values relevant to permission matching are strings.\n */\nexport type TToolArgs = Record<string, string | number | boolean | object>;\n\n/**\n * Permission list entries (allow / deny / ask).\n * Each entry is a pattern string such as \"Bash(pnpm *)\" or \"Read(/src/**)\".\n */\nexport interface IPermissionLists {\n allow?: readonly string[];\n deny?: readonly string[];\n /** Calls that always ask, in every mode including bypassPermissions. */\n ask?: readonly string[];\n}\n\n/** What the caller adds to the rules: where it runs, and how far it may go. */\nexport interface IPermissionEvaluationContext extends ICriticalPathContext {\n /**\n * The most this caller may do. A call no pattern here matches is denied in every mode, bypass\n * included. Absent means no ceiling; an empty list denies everything.\n */\n ceiling?: readonly string[];\n /** Every call that is not denied asks, whatever the mode or allow list says. */\n askAll?: boolean;\n /**\n * Where a path really is, symlinks followed, or `undefined` outside the workspace. Supplied by a\n * host with a filesystem; without it a read-only command naming a path is not treated as a read.\n */\n resolveInWorkspace?: TResolveInWorkspace;\n /**\n * This call runs inside an OS sandbox whose settings let a confined command proceed without a\n * prompt. It turns an `execute` ask into `auto` in `default` and `acceptEdits` only; everything\n * before the mode step, and plan mode's refusal, still hold.\n */\n sandboxAutoApproved?: boolean;\n /**\n * This turn was started by a message from another agent session. It decides only whether the\n * reply to that session exists; every other call is decided as in any turn.\n */\n peerTurn?: boolean;\n}\n\n/**\n * Parse a permission pattern entry into tool name and optional argument pattern.\n *\n * Examples:\n * - \"Bash\" → { toolName: \"Bash\", argPattern: undefined }\n * - \"Bash(pnpm *)\" → { toolName: \"Bash\", argPattern: \"pnpm *\" }\n * - \"Read(/src/**)\" → { toolName: \"Read\", argPattern: \"/src/**\" }\n */\nexport function parsePattern(pattern: string): {\n toolName: string;\n argPattern: string | undefined;\n} {\n const parenIdx = pattern.indexOf('(');\n if (parenIdx === -1) {\n return { toolName: pattern.trim(), argPattern: undefined };\n }\n\n const toolName = pattern.slice(0, parenIdx).trim();\n const argPattern = pattern.slice(parenIdx + 1, pattern.lastIndexOf(')')).trim();\n return { toolName, argPattern };\n}\n\n/**\n * What a tool's owner declares about it for permission purposes.\n *\n * Both halves used to live in this file as hardcoded product-name tables — an argument-key `switch`\n * and a mode-policy matrix keyed on a closed union of tool names — two layers below the packages\n * that define those tools, with nothing coupling the lists. CORE-030.\n */\n/**\n * The argument a tool's permission patterns are scoped to, and what kind of thing it is. One\n * object, so a key cannot be declared without its kind — a key alone would leave the tool on the\n * string glob that matched a URL's query as its host (CORE-049).\n */\nexport type { TArgumentKind, TMatchDirection, TPatternMatch } from './argument-matchers.js';\n\nexport interface IToolPermissionArgument {\n /** `Shell(rm *)` matches against `command`; `Read(/src/**)` against `filePath`. */\n key: string;\n /** How a pattern is matched against that argument. */\n kind: TArgumentKind;\n}\n\nexport interface IToolPermissionProfile {\n /**\n * Which argument this tool's permission patterns are scoped to, and its kind.\n *\n * Without it an argument-scoped pattern is UNEVALUABLE for this tool (a bare `Tool(*)` still\n * matches — it names no argument), and an unevaluable deny is not an allow — the gate prompts\n * rather than proceeding.\n */\n argument?: IToolPermissionArgument;\n /**\n * What kind of action this tool performs, which is what the modes actually decide about.\n *\n * Omitting it is not neutral: an unclassified tool takes the fallback, which prompts on every\n * call and is refused in plan mode.\n */\n riskClass?: TToolRiskClass;\n /**\n * The tool's top-level input parameter names. `Tool(name:value)` is a parameter rule only when\n * `name` is one of these — keyed on the schema, not the text's shape, so `WebFetch(https://…)`\n * stays a URL pattern. Declared by whoever holds the schema (the session registers every tool it\n * wraps, MCP tools included).\n */\n parameters?: readonly string[];\n /**\n * Other registered names for the same implementation. A rule naming any of them names this tool\n * too, so a deny cannot be sidestepped by calling the alias it did not spell out.\n */\n aliases?: readonly string[];\n /** The tool answers the peer whose message started the current turn; it exists only there. */\n repliesToPeer?: boolean;\n}\n\n/** Profiles contributed by the packages that own the tools. */\nconst toolProfiles = new Map<string, IToolPermissionProfile>();\n\n/**\n * Declare how a tool is treated by the permission system. CORE-030.\n *\n * Called by the package that DEFINES the tool, at the point it is created, so a tool's existence\n * and its classification arrive together. The foundation cannot know a product's tool inventory,\n * and every attempt to hardcode it drifted: `Agent`, `BackgroundProcess`, `CodebaseRetrieval` and\n * `ExecuteCommand` were all produced tools the old matrix had never heard of.\n *\n * Merges rather than replaces, so a tool may declare its argument key and its risk class from\n * different places without one silently erasing the other.\n */\nexport function registerToolPermissionProfile(\n toolName: string,\n profile: IToolPermissionProfile,\n): void {\n toolProfiles.set(toolName, { ...toolProfiles.get(toolName), ...profile });\n}\n\n/** Forget registered profiles. For tests and for hosts that rebuild a registry. */\nexport function clearRegisteredToolProfiles(): void {\n toolProfiles.clear();\n}\n\n/** What has been declared about a tool, or an empty profile when nobody has said anything. */\nexport function getToolPermissionProfile(toolName: string): IToolPermissionProfile {\n return toolProfiles.get(toolName) ?? {};\n}\n\n/**\n * Whether a pattern's tool-name part names this tool: exact, or a `*` glob over the name — the\n * tool's own name or any alias it declared.\n */\nexport function toolNameMatches(patternName: string, toolName: string): boolean {\n const names = [toolName, ...(toolProfiles.get(toolName)?.aliases ?? [])];\n if (!patternName.includes('*')) return names.includes(patternName);\n const glob = globToRegex(patternName);\n return names.some((name) => glob.test(name));\n}\n\n/** A `name:value` argument pattern that names one of the tool's parameters. */\nexport interface IParameterRule {\n name: string;\n value: string;\n}\n\n/**\n * Read an argument pattern as a parameter rule. `'primary'` when it names the tool's primary field\n * — that field is matched by the ordinary `Tool(pattern)` form, and a rule written against it is\n * refused rather than silently ignored. `undefined` when it is an ordinary argument pattern.\n */\nexport function parseParameterRule(\n toolName: string,\n argPattern: string,\n): IParameterRule | 'primary' | undefined {\n const match = /^([A-Za-z_]\\w*):([\\s\\S]*)$/.exec(argPattern);\n if (match === null) return undefined;\n const name = match[1]!;\n const profile = toolProfiles.get(toolName);\n if (profile?.argument?.key === name) return 'primary';\n if (profile?.parameters?.includes(name) !== true) return undefined;\n return { name, value: match[2]! };\n}\n\n/** A parameter's value against the rule's glob, compared as the model sent it (issue #3081). */\nfunction matchParameter(rule: IParameterRule, args: TToolArgs): TPatternMatch {\n if (!Object.prototype.hasOwnProperty.call(args, rule.name)) return 'no-match';\n const value: unknown = args[rule.name];\n if (value === undefined) return 'no-match';\n if (typeof value !== 'string' && typeof value !== 'number' && typeof value !== 'boolean') {\n return 'unevaluable';\n }\n return globToRegex(rule.value).test(String(value)) ? 'match' : 'no-match';\n}\n\n/**\n * Whether a deny list removes this tool outright — a bare name, `Tool(*)` or `Tool(**)`, glob names\n * included. Such a tool is withheld from the model entirely rather than offered and then refused.\n */\nexport function isToolDeniedOutright(toolName: string, deny: readonly string[]): boolean {\n return deny.some((pattern) => {\n const parsed = parsePattern(pattern);\n const bare =\n parsed.argPattern === undefined || parsed.argPattern === '*' || parsed.argPattern === '**';\n return bare && toolNameMatches(parsed.toolName, toolName);\n });\n}\n\n/** Which argument a pattern is matched against, or `undefined` when nobody has said. */\nfunction argumentKeyFor(toolName: string): string | undefined {\n return toolProfiles.get(toolName)?.argument?.key;\n}\n\nfunction primaryArg(toolName: string, args: TToolArgs): string | undefined {\n const key = argumentKeyFor(toolName);\n if (key === undefined) return undefined;\n const value = args[key];\n return typeof value === 'string' ? value : undefined;\n}\n\n/**\n * Test whether a tool invocation matches ANY pattern in a list (allow or deny).\n * Shared by `evaluatePermission` and the CORE-025 policy resolver so pattern semantics stay in one place.\n *\n * `direction` says which list these patterns came from. It defaults to `'allow'`, the narrower\n * reading, so a caller that forgets it never widens what a deny entry lets through — a DENY list\n * must pass `'deny'` explicitly, because for a `command` argument the two directions differ (see\n * {@link TMatchDirection}).\n */\nexport function matchesAnyPattern(\n toolName: string,\n args: TToolArgs,\n patterns: readonly string[],\n direction: TMatchDirection = 'allow',\n): boolean {\n return patterns.some(\n (pattern) => evaluateArgumentPattern(toolName, args, pattern, direction) === 'match',\n );\n}\n\n/**\n * Whether an argument-scoped pattern for this tool cannot be evaluated at all. CORE-030.\n *\n * `matchesPattern` answers `false` when the argument is unknowable, and `false` from a DENY list\n * means \"not denied\" — so `MyTool(secrets/**)` lost to a broader `allow: ['MyTool']` and the\n * invocation was auto-approved. \"I cannot tell\" is not \"no\".\n */\nexport function hasUnevaluableArgumentPattern(\n toolName: string,\n args: TToolArgs,\n patterns: readonly string[],\n): boolean {\n // Two shapes of \"I cannot tell\": nobody declared which argument the pattern is about (CORE-030),\n // or the argument or the pattern cannot be interpreted in the declared kind (CORE-049). A tool\n // whose key IS known but which was invoked without that argument is a real NON-match — the\n // pattern is about `path`, there is no path, so there is nothing to deny — and it goes back to\n // the allow list. (Review of #1596 caught those two conditions collapsing into one.)\n return patterns.some(\n (pattern) => evaluateArgumentPattern(toolName, args, pattern, 'deny') === 'unevaluable',\n );\n}\n\n/**\n * One invocation against one permission pattern entry: `match`, `no-match`, or `unevaluable`.\n *\n * `direction` reaches only the `command` matcher, the one kind whose answer depends on which list\n * the pattern came from (see {@link TMatchDirection}).\n */\nfunction evaluateArgumentPattern(\n toolName: string,\n args: TToolArgs,\n pattern: string,\n direction: TMatchDirection,\n): TPatternMatch {\n const parsed = parsePattern(pattern);\n\n // Tool name must match (case-sensitive), exactly or by a name glob.\n if (!toolNameMatches(parsed.toolName, toolName)) {\n return 'no-match';\n }\n\n // No argument constraint, or a bare wildcard → any invocation of that tool, whatever its kind —\n // and whether or not it declared an argument: `Tool(*)` names none.\n if (parsed.argPattern === undefined || parsed.argPattern === '*' || parsed.argPattern === '**') {\n return 'match';\n }\n\n // A named parameter (issue #3081). Deny and ask only: in an allow list it never widens anything.\n const parameterRule = parseParameterRule(toolName, parsed.argPattern);\n if (parameterRule === 'primary') return 'unevaluable';\n if (parameterRule !== undefined) {\n return direction === 'deny' ? matchParameter(parameterRule, args) : 'no-match';\n }\n\n // Nobody declared which argument this pattern is about (CORE-030)\n const argument = toolProfiles.get(toolName)?.argument;\n if (argument === undefined) {\n return 'unevaluable';\n }\n\n const primary = primaryArg(toolName, args);\n if (primary === undefined) {\n return 'no-match';\n }\n\n switch (argument.kind) {\n case 'url':\n return matchUrl(parsed.argPattern, primary);\n case 'path':\n return matchPath(parsed.argPattern, primary);\n case 'command':\n return matchCommand(parsed.argPattern, primary, direction);\n case 'text':\n return globToRegex(parsed.argPattern).test(primary) ? 'match' : 'no-match';\n default: {\n // A kind this switch does not name would otherwise land on the string glob — the failure\n // mode CORE-049 removes. The compiler holds the enumeration closed.\n const exhaustive: never = argument.kind;\n throw new Error(`unknown argument kind: ${String(exhaustive)}`);\n }\n }\n}\n\n/** Whether a call belongs to the never-auto-approve set beyond explicit ask rules. */\nfunction isNeverAutoApproved(\n toolName: string,\n toolArgs: TToolArgs,\n context: ICriticalPathContext,\n): boolean {\n const profile = toolProfiles.get(toolName);\n const argument = profile?.argument;\n if (argument === undefined) return false;\n const value = toolArgs[argument.key];\n if (typeof value !== 'string') return false;\n if (argument.kind === 'command') return removesCriticalPath(value, context);\n if (argument.kind === 'path' && profile?.riskClass === 'modify') return isProtectedPath(value);\n return false;\n}\n\n/** An ask rule matches the call, or cannot be evaluated for it, or the call is in the never-auto set. */\nfunction isMandatoryAsk(\n toolName: string,\n toolArgs: TToolArgs,\n ask: readonly string[],\n context: ICriticalPathContext,\n): boolean {\n return (\n matchesAnyPattern(toolName, toolArgs, ask, 'deny') ||\n hasUnevaluableArgumentPattern(toolName, toolArgs, ask) ||\n isNeverAutoApproved(toolName, toolArgs, context)\n );\n}\n\n/**\n * Whether an ask about this call must reach a person EVERY time — never answered by a consent the\n * session or project remembered from an earlier call. A remembered scope is wide (`Bash(rm *)`\n * from one `rm -rf build`); honouring it here would let one approval stand in for every later\n * critical-path removal, protected write or ask-rule call (issue #3081).\n */\nexport function requiresFreshApproval(\n toolName: string,\n toolArgs: TToolArgs,\n permissions: IPermissionLists = {},\n context: ICriticalPathContext = {},\n): boolean {\n return (\n hasUnevaluableArgumentPattern(toolName, toolArgs, permissions.deny ?? []) ||\n isMandatoryAsk(toolName, toolArgs, permissions.ask ?? [], context)\n );\n}\n\n/** Arguments that move a command out of the session's working directory. */\nconst DIRECTORY_ARGUMENT_KEYS = ['workingDirectory', 'cwd'] as const;\n\n/**\n * The tool's declared risk class, narrowed for this one call: a command tool running only built-in\n * read-only commands is decided like a read.\n */\nfunction effectiveRiskClass(\n toolName: string,\n toolArgs: TToolArgs,\n context: IPermissionEvaluationContext,\n): TToolRiskClass | undefined {\n const profile = toolProfiles.get(toolName);\n if (profile?.riskClass !== 'execute' || profile.argument?.kind !== 'command') {\n return profile?.riskClass;\n }\n const command = toolArgs[profile.argument.key];\n if (typeof command !== 'string') return profile.riskClass;\n const otherDirectory = DIRECTORY_ARGUMENT_KEYS.some((key) => toolArgs[key] !== undefined);\n const readOnly = isReadOnlyCommandLine(command, {\n otherDirectory,\n ...(context.resolveInWorkspace !== undefined\n ? { resolveInWorkspace: context.resolveInWorkspace }\n : {}),\n });\n return readOnly ? 'inspect' : profile.riskClass;\n}\n\n/**\n * Evaluate whether a tool invocation should be auto-approved, require user approval, or be denied.\n *\n * @param toolName Name of the tool being invoked (e.g. \"Bash\", \"Write\")\n * @param toolArgs Arguments provided by the LLM\n * @param mode Active permission mode\n * @param permissions Allow/deny/ask lists from config\n * @param context The caller's execution root, home directory, ceiling and ask-everything flag\n */\nexport function evaluatePermission(\n toolName: string,\n toolArgs: TToolArgs,\n mode: TPermissionMode,\n permissions: IPermissionLists = {},\n context: IPermissionEvaluationContext = {},\n): TPermissionDecision {\n const { allow = [], deny = [], ask = [] } = permissions;\n const riskClass = effectiveRiskClass(toolName, toolArgs, context);\n // Plan mode's promise is \"change nothing\": an ask about anything that could change something is\n // a refusal there, and only an inspect-class call may still reach a person.\n const askDecision: TPermissionDecision =\n mode === 'plan' && riskClass !== 'inspect' ? 'deny' : 'approve';\n\n // 1. A matching deny blocks immediately.\n if (matchesAnyPattern(toolName, toolArgs, deny, 'deny')) {\n return 'deny';\n }\n\n // 2. The caller's ceiling only narrows. It is checked before bypass, so a background task or\n // subagent under a permissive mode still cannot reach past what it was given (CORE-025).\n if (context.ceiling !== undefined && !matchesAnyPattern(toolName, toolArgs, context.ceiling)) {\n return 'deny';\n }\n\n // 2b. The reply belongs to a turn a peer's message started; outside one there is nobody to\n // answer. Inside one, the steps below decide it like any call that sends something off this\n // machine. A peer turn changes nothing else: its calls are decided like the session's own.\n if (toolProfiles.get(toolName)?.repliesToPeer === true && context.peerTurn !== true) {\n return 'deny';\n }\n\n // 3. CORE-030: a deny the gate could not EVALUATE is not a deny that did not match. Asking is\n // the answer: refusing outright would break a call the pattern was never about, and\n // auto-approving is what this exists to stop. Plan mode refuses.\n if (hasUnevaluableArgumentPattern(toolName, toolArgs, deny)) {\n return mode === 'plan' ? 'deny' : 'approve';\n }\n\n // 4. The never-auto-approve set holds in every mode, bypass included. An ask rule is read in\n // the deny direction, and one it cannot evaluate asks too: both are \"stop and ask\".\n if (isMandatoryAsk(toolName, toolArgs, ask, context)) {\n return askDecision;\n }\n\n // 5. The caller routes every remaining call to a person.\n if (context.askAll === true) {\n return askDecision;\n }\n\n // 6. Bypass proceeds with everything the steps above let through; allow rules add nothing.\n if (mode === 'bypassPermissions') {\n return 'auto';\n }\n\n // 7. Allow list.\n if (matchesAnyPattern(toolName, toolArgs, allow)) {\n return 'auto';\n }\n\n // 8. What the mode says about this KIND of action, which is the only thing it decides. A command\n // the OS confines is the exception the user opted into: it proceeds where the mode would ask.\n if (\n context.sandboxAutoApproved === true &&\n riskClass === 'execute' &&\n (mode === 'default' || mode === 'acceptEdits' || mode === 'auto')\n ) {\n return 'auto';\n }\n if (riskClass !== undefined) {\n return RISK_CLASS_POLICY[mode][riskClass];\n }\n\n // Nobody declared what this tool does — fail safe, which means ask rather than proceed.\n return UNCLASSIFIED_TOOL_FALLBACK[mode];\n}\n","/**\n * Background/subagent permission POLICY (CORE-025), projected onto the one evaluator.\n *\n * A spawned background task carries a `permissionPolicy` (`inherit-allowlist | preapproved | prompt | deny`).\n * It used to have its own resolver with its own order, so the same call could be decided differently\n * depending on who made it (issue #3081). A policy is now only what it adds to `evaluatePermission`'s\n * inputs — a ceiling, an ask-everything flag, and the task's own lists — so the order is shared and\n * a policy can only narrow:\n *\n * - `deny` → an empty ceiling: every call is denied.\n * - `prompt` → every call that is not denied asks (the approver fail-closes to deny with no surface).\n * - `preapproved` → the TASK allowlist is the ceiling and is auto-approved within it.\n * - `inherit-allowlist` → the PARENT's effective allowlist is the ceiling.\n *\n * The ceiling is checked before bypassPermissions, so a detached task under a permissive mode still\n * cannot reach past what it was given.\n */\n\nimport type { TBackgroundPermissionPolicy } from './types.js';\n\n/**\n * Rules available to the projection. `task*` are the spawned task's own declared lists;\n * `parentAllow` is the parent session's effective allowlist that `inherit-allowlist` inherits.\n */\nexport interface IPermissionPolicyContext {\n taskAllow?: readonly string[];\n taskDeny?: readonly string[];\n parentAllow?: readonly string[];\n}\n\n/** What a policy adds to the evaluator's inputs. */\nexport interface IPermissionPolicyProjection {\n /** Absent means the policy sets no ceiling. */\n ceiling?: readonly string[];\n askAll: boolean;\n /** Added to the session's allow list. */\n allow: readonly string[];\n /** Added to the session's deny list. */\n deny: readonly string[];\n}\n\nexport function projectPermissionPolicy(\n policy: TBackgroundPermissionPolicy,\n context: IPermissionPolicyContext = {},\n): IPermissionPolicyProjection {\n const deny = context.taskDeny ?? [];\n switch (policy) {\n case 'deny':\n return { ceiling: [], askAll: false, allow: [], deny };\n case 'prompt':\n return { askAll: true, allow: [], deny };\n case 'preapproved': {\n const taskAllow = context.taskAllow ?? [];\n return { ceiling: taskAllow, askAll: false, allow: taskAllow, deny };\n }\n case 'inherit-allowlist':\n return { ceiling: context.parentAllow ?? [], askAll: false, allow: [], deny };\n default: {\n const exhaustive: never = policy;\n throw new Error(`unknown permission policy: ${String(exhaustive)}`);\n }\n }\n}\n","/**\n * Refuse a malformed permission pattern where the operator WROTE it, not at the gate (issue #2428).\n *\n * CORE-049 made a pattern the gate cannot interpret UNEVALUABLE at evaluation time — a deny that\n * cannot be evaluated prompts rather than silently passing. That is the floor. But an operator who\n * wrote `WebFetch(https://a b)` or `Grep(src/**)`-style narrowing for a tool that declares no\n * argument learned of it only when an invocation reached the gate, one prompt at a time. This is\n * the loud surface above the floor: the same grammar, asked at load, answering with the pattern and\n * the reason before any turn runs.\n *\n * What is NOT refused here, and why: a pattern naming a tool with NO registered profile at all. A\n * profile arrives with the tool that defines it (CORE-030), and a config may legitimately name a\n * tool a later-loaded pack provides; for that pattern the gate's unevaluable route remains the\n * answer. A tool whose profile IS known but declares no argument is a different case — the pattern\n * can never be evaluated, whatever loads later.\n */\n\nimport { matchUrl } from './argument-matchers.js';\nimport { getToolPermissionProfile, parseParameterRule, parsePattern } from './permission-gate.js';\n\nimport type { TMatchDirection } from './argument-matchers.js';\n\n/** A pattern and the reason it cannot be evaluated by the gate. */\nexport interface IPermissionPatternProblem {\n readonly pattern: string;\n readonly reason: string;\n}\n\n/** The shape of a parameter rule's argument: `name:` then anything but `//`, which is a URL scheme. */\nconst NAMED_ARGUMENT = /^[A-Za-z_]\\w*:(?!\\/\\/)/;\n\n/** A well-formed URL argument, used to ask the URL matcher whether the PATTERN side is readable. */\nconst URL_PROBE = 'https://probe.invalid/';\n\n/**\n * An allow rule may glob the tool name only after a literal `<server>__` prefix (issue #3081): an\n * unanchored `*` or `Read*` would grant tools nobody named, including ones a later pack adds.\n */\nfunction isAnchoredNameGlob(toolName: string): boolean {\n return toolName.slice(0, toolName.indexOf('*')).includes('__');\n}\n\n/**\n * The reason one pattern is malformed, or undefined when the gate can evaluate it.\n *\n * `direction` is the list the pattern sits in. Allow rules are held to a narrower grammar: no\n * parameter rules and no unanchored tool-name globs, because in an allow list either would grant\n * more than the operator could see.\n */\nexport function validatePermissionPattern(\n pattern: string,\n direction: TMatchDirection = 'deny',\n): string | undefined {\n const trimmed = pattern.trim();\n if (trimmed === '') return 'is empty';\n if (trimmed.includes('(') && !trimmed.endsWith(')')) return 'opens \"(\" without closing it';\n const { toolName, argPattern } = parsePattern(trimmed);\n if (toolName === '') return 'names no tool';\n if (direction === 'allow' && toolName.includes('*') && !isAnchoredNameGlob(toolName)) {\n return 'globs the tool name without a literal \"<server>__\" prefix, which an allow rule may not do';\n }\n if (argPattern === undefined || argPattern === '*' || argPattern === '**') return undefined;\n if (argPattern === '') return 'has an empty argument pattern; write Tool or Tool(*) instead';\n if (toolName.includes('*')) {\n // Judged per tool at the gate — except that an allow rule may never name a parameter.\n return direction === 'allow' && NAMED_ARGUMENT.test(argPattern)\n ? 'matches a named parameter, which only deny and ask rules may do'\n : undefined;\n }\n const parameterRule = parseParameterRule(toolName, argPattern);\n if (parameterRule !== undefined && parameterRule !== 'primary') {\n return direction === 'allow'\n ? 'matches a named parameter, which only deny and ask rules may do'\n : undefined;\n }\n\n const profile = getToolPermissionProfile(toolName);\n // `name:value` against a tool whose parameters are not registered yet: whether it is a parameter\n // rule depends on the schema, which arrives when the session wraps its tools. It is checked again\n // then, before any turn runs; judging it now would refuse a valid rule.\n if (\n profile.parameters === undefined &&\n NAMED_ARGUMENT.test(argPattern) &&\n parseParameterRule(toolName, argPattern) === undefined\n ) {\n return undefined;\n }\n if (profile.argument === undefined) {\n if (profile.riskClass === undefined) return undefined; // nobody has declared this tool yet\n return `tool \"${toolName}\" declares no argument key, so an argument-scoped pattern can never be evaluated`;\n }\n if (profile.argument.kind === 'url' && matchUrl(argPattern, URL_PROBE) === 'unevaluable') {\n return `does not fit the URL pattern grammar scheme://host[:port][/path] that \"${toolName}\" is matched by`;\n }\n return undefined;\n}\n\n/** Every pattern in `patterns` the gate could not evaluate, with its reason. */\nexport function findInvalidPermissionPatterns(\n patterns: readonly string[],\n direction: TMatchDirection = 'deny',\n): IPermissionPatternProblem[] {\n const problems: IPermissionPatternProblem[] = [];\n for (const pattern of patterns) {\n const reason = validatePermissionPattern(pattern, direction);\n if (reason !== undefined) problems.push({ pattern, reason });\n }\n return problems;\n}\n\n/**\n * Patterns that load but do not do what they say (issue #3081): a parameter rule naming the tool's\n * PRIMARY field. That field is matched by the ordinary `Tool(pattern)` form, so the gate treats the\n * rule as unevaluable (an ask, never a silent pass) and the operator is told how to write it.\n */\nexport function findPermissionPatternWarnings(\n patterns: readonly string[],\n): IPermissionPatternProblem[] {\n const problems: IPermissionPatternProblem[] = [];\n for (const pattern of patterns) {\n const { toolName, argPattern } = parsePattern(pattern.trim());\n if (argPattern === undefined || toolName.includes('*')) continue;\n const profile = getToolPermissionProfile(toolName);\n const parameterRule = parseParameterRule(toolName, argPattern);\n if (\n parameterRule === undefined &&\n profile.parameters !== undefined &&\n profile.argument?.kind !== 'url' &&\n NAMED_ARGUMENT.test(argPattern)\n ) {\n // Most likely a misspelt parameter: read as an ordinary argument pattern, it rarely matches.\n problems.push({\n pattern,\n reason: `names no parameter of \"${toolName}\" (${profile.parameters.join(', ')}), so it is read as an ordinary argument pattern`,\n });\n continue;\n }\n if (parameterRule !== 'primary') continue;\n const key = getToolPermissionProfile(toolName).argument?.key ?? '';\n problems.push({\n pattern,\n reason: `names \"${toolName}\"'s primary field \"${key}\", so it asks on every call; write ${toolName}(${argPattern.slice(key.length + 1)}) instead`,\n });\n }\n return problems;\n}\n","import { findInvalidPermissionPatterns } from './pattern-validation.js';\n\n/**\n * A preset's tool LISTS as permission PATTERNS.\n *\n * ARCH-040 Group C (issue #1934). A preset names tools (`Read`, `Bash`); the enforcer matches\n * patterns (`Read(*)`). One function because two paths need the answer — the startup merge in\n * `create-session.ts` and the live re-application `/preset` performs — and a translation written\n * twice is one rename away from two sessions disagreeing about what the same preset permits.\n */\nexport function toolNamesToPatterns(names: readonly string[] | undefined): string[] {\n return (names ?? []).map((name) => `${name}(*)`);\n}\n\n/**\n * The enforcer's rules after a preset's lists are applied.\n *\n * The two lists combine differently, and the difference is the decision rather than a detail:\n *\n * - **the allowlist REPLACES** what the preset layer previously contributed — it states the complete\n * permitted set, so a later, more specific layer supersedes the earlier answer;\n * - **the denylist UNIONS** — a denial is not weakened by a later layer that forgot to repeat it.\n *\n * `base` is what the session was configured with independently of any preset (its own settings,\n * defaults, command auto-allows). Those survive both operations: a preset chooses among what the\n * session permits, it does not widen it.\n */\nexport function applyPresetToolLists(\n base: { allow: readonly string[]; deny: readonly string[] },\n preset: { allowedTools?: readonly string[]; deniedTools?: readonly string[] },\n): { allow: string[]; deny: string[] } {\n const allowed = toolNamesToPatterns(preset.allowedTools);\n // Issue #3081: tool names are globbed now, so a preset naming `*` or `Read*` would grant tools\n // nobody listed. Held to the allow grammar on every path — startup and a live `/preset` alike.\n const problems = findInvalidPermissionPatterns(allowed, 'allow');\n if (problems.length > 0) {\n const listed = problems.map(({ pattern, reason }) => `\"${pattern}\" ${reason}`).join('; ');\n throw new Error(`Invalid preset allowedTools: ${listed}.`);\n }\n return {\n allow: [...base.allow, ...allowed],\n deny: [...new Set([...base.deny, ...toolNamesToPatterns(preset.deniedTools)])],\n };\n}\n","/**\n * Allow rules `auto` mode sets aside while it is on (issue #3082).\n *\n * The classifier is there to look at arbitrary execution; an allow rule that already approves\n * arbitrary execution would answer first and the classifier would never see it. So a rule that\n * approves running any program, any interpreter script, any package script or any subagent is not\n * applied in `auto` mode; a narrow rule (`Bash(npm test)`) still is. Leaving the mode restores them —\n * nothing is removed from the settings, the mode only reads fewer of them.\n */\n\nimport { getToolPermissionProfile, parsePattern, toolNameMatches } from './permission-gate.js';\n\n/** Tools whose argument is a shell command line. */\nconst SHELL_TOOLS = ['Bash', 'Shell', 'BackgroundProcess'];\n/** Tools that run whatever they are given, whatever their argument says. */\nconst DELEGATING_TOOLS = ['Agent'];\n/** Execution tools a name glob could reach. */\nconst EXECUTION_TOOLS = [...SHELL_TOOLS, ...DELEGATING_TOOLS, 'ExecuteCommand', 'Computer'];\n\n/** Programs that run whatever code or command they are given. */\nconst INTERPRETERS = [\n 'python',\n 'node',\n 'deno',\n 'bun',\n 'ruby',\n 'perl',\n 'php',\n 'bash',\n 'sh',\n 'zsh',\n 'fish',\n 'pwsh',\n 'powershell',\n 'cmd',\n 'env',\n 'xargs',\n 'eval',\n 'exec',\n 'sudo',\n 'timeout',\n 'nohup',\n 'nice',\n 'time',\n 'command',\n 'setsid',\n 'stdbuf',\n 'watch',\n 'ssh',\n 'docker',\n 'podman',\n 'find',\n];\n\n/** Package-manager commands that run a package's own scripts or binaries. */\nconst PACKAGE_RUNNERS = [\n 'npm run',\n 'npm run-script',\n 'npm exec',\n 'npm x',\n 'npx',\n 'pnpm',\n 'pnpx',\n 'yarn',\n 'bunx',\n 'uv run',\n 'uvx',\n 'pipx run',\n 'cargo run',\n 'go run',\n 'make',\n 'just',\n].map((runner) => runner.split(' '));\n\n/** Words after a runner that still leave the script or package open. */\nconst RUNNER_PASSTHROUGH = new Set(['run', 'run-script', 'exec', 'dlx', 'x', '--']);\n\nfunction programName(word: string): string {\n return (word.split(/[\\\\/]/).pop() ?? word).replace(/(\\.exe)?$/i, '').replace(/[\\d.]+$/, '');\n}\n\n/**\n * Whether the words before a command pattern's `*` leave the program open. `partial` means the `*`\n * continues the last word (`py*`), so that word matches anything it begins.\n */\nfunction leavesProgramOpen(words: readonly string[], partial: boolean): boolean {\n if (words.length === 0) return true;\n const same = (candidate: string, word: string, last: boolean): boolean =>\n partial && last ? candidate.startsWith(word) : candidate === word;\n const first = programName(words[0]!);\n if (INTERPRETERS.some((name) => same(name, first, words.length === 1))) return true;\n for (const runner of PACKAGE_RUNNERS) {\n const covered = Math.min(runner.length, words.length);\n const matches = runner\n .slice(0, covered)\n .every((part, index) =>\n same(part, index === 0 ? first : words[index]!, index === words.length - 1),\n );\n if (!matches) continue;\n // `npm *`: the pattern stops inside the runner, so any of its scripts matches.\n if (words.length <= runner.length) return true;\n let rest = words.slice(runner.length);\n while (rest.length > 0 && (rest[0]!.startsWith('-') || RUNNER_PASSTHROUGH.has(rest[0]!))) {\n rest = rest.slice(1);\n }\n return rest.length === 0 || leavesProgramOpen(rest, partial);\n }\n return false;\n}\n\n/**\n * A command pattern approves arbitrary execution when it is a bare wildcard, when the program it\n * names runs whatever code it is given, or when it stops at a package runner (`npm run *`,\n * `pnpm exec *`) so any script matches. `Bash(pnpm test*)` names one script and stays.\n */\nfunction approvesAnyCommand(argument: string): boolean {\n const trimmed = argument.trim();\n if (!trimmed.includes('*')) return false;\n const before = trimmed.slice(0, trimmed.indexOf('*'));\n const words = before\n .trim()\n .split(/\\s+/)\n .filter((word) => word.length > 0);\n const partial = before.length > 0 && !/\\s$/.test(before);\n return leavesProgramOpen(words, partial);\n}\n\n/** Whether an allow rule approves arbitrary execution, and so is set aside in `auto` mode. */\nexport function isBroadExecutionAllowRule(pattern: string): boolean {\n const { toolName, argPattern } = parsePattern(pattern);\n const reaches = (tools: readonly string[]): boolean =>\n tools.some((tool) => toolNameMatches(toolName, tool));\n if (reaches(DELEGATING_TOOLS)) return true;\n // A name glob (`Ba*`) reaching an execution tool is as broad as naming it with no argument.\n if (toolName.includes('*')) return reaches(EXECUTION_TOOLS);\n const executes =\n EXECUTION_TOOLS.includes(toolName) ||\n getToolPermissionProfile(toolName).riskClass === 'execute';\n if (!executes) return false;\n if (argPattern === undefined || argPattern.trim() === '*') return true;\n return SHELL_TOOLS.includes(toolName) && approvesAnyCommand(argPattern);\n}\n\n/** The allow rules `auto` mode applies: all but the broad execution ones. */\nexport function allowRulesForAutoMode(allow: readonly string[]): string[] {\n return allow.filter((pattern) => !isBroadExecutionAllowRule(pattern));\n}\n","/**\n * Model pricing — SSOT for per-model token cost.\n *\n * Sibling of `models.ts` (which owns context-window/output metadata). Consumers that need to\n * compute or estimate cost (cost display, budget/rate limiting) must read from here rather than\n * embedding their own price tables.\n *\n * Prices are USD per 1,000,000 tokens (as of May 2026 — update when providers change rates).\n */\n\nexport interface IModelPrice {\n inputPerMillion: number;\n outputPerMillion: number;\n}\n\nconst TOKENS_PER_MILLION = 1_000_000;\nconst TOKENS_PER_THOUSAND = 1_000;\nconst BLEND_DIVISOR = 2;\n\n/** Exact per-model prices, keyed by API model ID. */\nexport const MODEL_PRICES: Record<string, IModelPrice> = {\n // Anthropic Claude 4\n 'claude-opus-4-7': { inputPerMillion: 15, outputPerMillion: 75 },\n 'claude-opus-4-5': { inputPerMillion: 15, outputPerMillion: 75 },\n 'claude-sonnet-4-6': { inputPerMillion: 3, outputPerMillion: 15 },\n 'claude-sonnet-4-5': { inputPerMillion: 3, outputPerMillion: 15 },\n 'claude-haiku-4-5': { inputPerMillion: 0.8, outputPerMillion: 4 },\n // Anthropic Claude 3\n 'claude-3-5-sonnet-20241022': { inputPerMillion: 3, outputPerMillion: 15 },\n 'claude-3-5-haiku-20241022': { inputPerMillion: 0.8, outputPerMillion: 4 },\n 'claude-3-opus-20240229': { inputPerMillion: 15, outputPerMillion: 75 },\n // OpenAI\n 'gpt-4o': { inputPerMillion: 2.5, outputPerMillion: 10 },\n 'gpt-4o-mini': { inputPerMillion: 0.15, outputPerMillion: 0.6 },\n o1: { inputPerMillion: 15, outputPerMillion: 60 },\n 'o1-mini': { inputPerMillion: 3, outputPerMillion: 12 },\n o3: { inputPerMillion: 10, outputPerMillion: 40 },\n 'o3-mini': { inputPerMillion: 1.1, outputPerMillion: 4.4 },\n // DeepSeek\n 'deepseek-chat': { inputPerMillion: 0.14, outputPerMillion: 0.28 },\n 'deepseek-reasoner': { inputPerMillion: 0.55, outputPerMillion: 2.19 },\n // Google Gemini\n 'gemini-2.0-flash': { inputPerMillion: 0.1, outputPerMillion: 0.4 },\n 'gemini-2.0-flash-thinking': { inputPerMillion: 0.35, outputPerMillion: 3.5 },\n 'gemini-1.5-pro': { inputPerMillion: 1.25, outputPerMillion: 5 },\n 'gemini-1.5-flash': { inputPerMillion: 0.075, outputPerMillion: 0.3 },\n};\n\n/** Family-level fallback prices for unrecognized exact IDs (matched in order). */\nconst PATTERN_PRICES: Array<{ pattern: RegExp; price: IModelPrice }> = [\n { pattern: /claude-opus/i, price: { inputPerMillion: 15, outputPerMillion: 75 } },\n { pattern: /claude-sonnet/i, price: { inputPerMillion: 3, outputPerMillion: 15 } },\n { pattern: /claude-haiku/i, price: { inputPerMillion: 0.8, outputPerMillion: 4 } },\n { pattern: /gpt-4o-mini/i, price: { inputPerMillion: 0.15, outputPerMillion: 0.6 } },\n { pattern: /gpt-4/i, price: { inputPerMillion: 2.5, outputPerMillion: 10 } },\n { pattern: /deepseek/i, price: { inputPerMillion: 0.14, outputPerMillion: 0.28 } },\n { pattern: /gemini-2/i, price: { inputPerMillion: 0.1, outputPerMillion: 0.4 } },\n { pattern: /gemini-1/i, price: { inputPerMillion: 1.25, outputPerMillion: 5 } },\n];\n\n/** Resolve a model's price by exact ID, then family pattern. Returns undefined if unknown. */\nexport function lookupModelPrice(modelId: string): IModelPrice | undefined {\n const exact = Object.hasOwn(MODEL_PRICES, modelId) ? MODEL_PRICES[modelId] : undefined;\n if (exact) return exact;\n for (const { pattern, price } of PATTERN_PRICES) {\n if (pattern.test(modelId)) return price;\n }\n return undefined;\n}\n\n/** Exact USD cost for an input/output token split, or undefined if the model is unknown. */\nexport function calculateModelCost(\n modelId: string,\n inputTokens: number,\n outputTokens: number,\n): number | undefined {\n const price = lookupModelPrice(modelId);\n if (!price) return undefined;\n return (\n (inputTokens / TOKENS_PER_MILLION) * price.inputPerMillion +\n (outputTokens / TOKENS_PER_MILLION) * price.outputPerMillion\n );\n}\n\n/**\n * Blended USD-per-1000-tokens rate for budget estimation when an input/output split is not\n * available (e.g. rate limiting). Averages the input and output per-million prices. Returns\n * undefined if the model is unknown so callers can apply their own fallback rate.\n */\nexport function estimateBlendedCostPer1000(modelId: string): number | undefined {\n const price = lookupModelPrice(modelId);\n if (!price) return undefined;\n return (price.inputPerMillion + price.outputPerMillion) / BLEND_DIVISOR / TOKENS_PER_THOUSAND;\n}\n","/**\n * Which hooks in a config apply to a given event input.\n *\n * Selection is a separate question from execution: it depends only on the config and the input, has\n * no side effects, and answers the same way whether or not any executor exists. Keeping it out of\n * `hook-runner.ts` leaves that file about dispatch and aggregation.\n */\n\nimport type { IHookGroup, IHookInput } from './types.js';\n\n/** Check if a tool name matches a hook group's matcher pattern. */\nexport function matchesGroup(group: IHookGroup, matcherTarget: string | undefined): boolean {\n // Empty matcher = match everything\n if (!group.matcher) return true;\n if (!matcherTarget) return false;\n try {\n return new RegExp(group.matcher).test(matcherTarget);\n } catch {\n // allow-fallback: invalid regex → fall back to exact string match\n return group.matcher === matcherTarget;\n }\n}\n\nexport function getMatcherTarget(input: IHookInput): string | undefined {\n if (input.tool_name) return input.tool_name;\n if (input.hook_event_name === 'SubagentStart' || input.hook_event_name === 'SubagentStop') {\n return input.agent_type ?? input.agent_id;\n }\n if (input.hook_event_name === 'SessionEnd') return input.reason;\n return undefined;\n}\n","/**\n * Hook runner — executes hooks for lifecycle events using the strategy pattern.\n *\n * Dispatches to registered IHookTypeExecutor implementations by definition type.\n * Default executors: CommandExecutor (shell), HttpExecutor (HTTP POST).\n *\n * Outcome semantics (SEC-015). Executors return a decoded `THookOutcome`, not an exit code:\n * - `allow` → its stdout is decoded for the response protocol below\n * - `deny` → blocks, carrying the hook's reason\n * - `error` → the hook rendered NO verdict; recorded in `IRunHooksResult.errors`. Whether that\n * BLOCKS is a per-event policy this runner deliberately does not decide: it reports, and the\n * enforcement boundary reads `HOOK_ENFORCEMENT_POLICY` (SEC-016). `PreToolUse` fails closed on it\n * today; every other event is advisory, because no other fire site consults `blocked` at all.\n *\n * stdout JSON semantics (Claude Code compatible):\n * - { continue: false } → block, regardless of exit code\n * - PreToolUse: { hookSpecificOutput: { permissionDecision, updatedInput } }\n * - UserPromptSubmit: { decision: \"block\" } → block; hookSpecificOutput.additionalContext → injected into stdout\n */\n\nimport { matchesGroup, getMatcherTarget } from './hook-matching.js';\nimport { PERMISSION_PRIORITY, interpretAllowOutcome } from './response-protocol.js';\n\nimport type { TPermissionDecision } from './response-protocol.js';\nimport type { ISubprocessTraceEnv } from '../interfaces/trace-context.js';\nimport type {\n THookEvent,\n THooksConfig,\n IHookInput,\n IHookTypeExecutor,\n IHookErrorOutcome,\n ICommandHookDefinition,\n THookOutcome,\n} from './types.js';\n\n/**\n * The command slot's call shape: the trace environment is a third argument that only a command\n * executor is handed, so it never enters `IHookInput` — which command hooks read as stdin JSON and\n * HTTP hooks receive as the body — and no other hook type ever sees it.\n */\ninterface ICommandHookTraceExecutor {\n execute(\n definition: ICommandHookDefinition,\n input: IHookInput,\n traceEnv: ISubprocessTraceEnv,\n ): Promise<THookOutcome>;\n}\n\n/**\n * The default executors, loaded only when a caller supplies none (CORE-028).\n *\n * `CommandExecutor` imports `node:child_process`, and a STATIC import of it here put that specifier\n * into the browser build — which declares a `browser` export condition and cannot provide it. The\n * aliasing workaround made that worse rather than better: `child_process` resolved to an empty\n * object, so a build-time contract violation became a deferred `TypeError` in a user's page.\n *\n * A dynamic import keeps them out of the browser graph while leaving Node behaviour identical: this\n * function is reached only on the branch where the caller passed no executors, and `runHooks` was\n * already async, so nothing above changes shape. A browser caller that supplies its own executors\n * never loads them at all; one that does not gets the same failure it would get from\n * `node:child_process` itself, which is the honest outcome rather than a silent empty object.\n */\nasync function createDefaultExecutors(): Promise<IHookTypeExecutor[]> {\n const [{ CommandExecutor }, { HttpExecutor }] = await Promise.all([\n // eslint-disable-next-line no-restricted-syntax -- CORE-028: keeps `node:child_process` out of the browser build's static graph\n import('./executors/command-executor.js'),\n // eslint-disable-next-line no-restricted-syntax -- CORE-028: loaded on the same branch as its sibling above\n import('./executors/http-executor.js'),\n ]);\n return [new CommandExecutor(), new HttpExecutor()];\n}\n\n/** Result of running hooks for an event. */\nexport interface IRunHooksResult {\n blocked: boolean;\n reason?: string;\n /** Collected stdout from all hooks that returned `allow`. */\n stdout: string;\n /** Parsed updatedInput from PreToolUse hookSpecificOutput (PreToolUse only). */\n updatedInput?: Record<string, unknown>;\n /** Highest-priority permissionDecision from PreToolUse hooks (PreToolUse only). */\n permissionDecision?: TPermissionDecision;\n /**\n * Hook types that were configured but had no registered executor, so nothing ran for them.\n *\n * Reported rather than logged. `AGENTS.md` makes \"silence is not success\" a rule-level invariant,\n * and a runner that skipped an unrecognised type quietly broke it: a config declaring\n * `{ type: 'guardrail', … }` with no guardrail registry supplied DISABLED the gate, and the author\n * saw no error at all. A `console.warn` would satisfy the letter of that comment while still being\n * invisible to a caller and untestable; a field on the result is something the caller can act on\n * and a test can assert.\n *\n * Absent when every configured hook had an executor — the ordinary case draws no attention.\n */\n unknownHookTypes?: readonly string[];\n /**\n * Hook executions that rendered no verdict (SEC-015). Absent when every hook decided.\n *\n * This is the field an enforcing consumer needs in order to fail closed, and its absence is why\n * it could not. A runner that folded `error` into `allow` would leave this `undefined` while\n * returning the same `blocked` value as correct code — which is exactly why the tests assert on\n * this rather than on `blocked` alone.\n */\n errors?: readonly IHookErrorOutcome[];\n}\n\n/**\n * Run all hooks for a given event.\n *\n * For PreToolUse: if any hook returns the `deny` outcome, or an `allow` whose stdout carries a JSON\n * deny directive, the tool call is blocked.\n * JSON stdout responses are parsed and applied per Claude Code spec.\n * Returns { blocked: true, reason } if blocked, otherwise { blocked: false, stdout }.\n *\n * @param config - Hooks configuration mapping events to hook groups\n * @param event - The lifecycle event being fired\n * @param input - Hook input data passed to executors\n * @param executors - Optional array of hook type executors (defaults to command + http)\n * @param traceEnv - The prompt's trace for command hook children, when the host enabled it\n */\nexport async function runHooks(\n config: THooksConfig | undefined,\n event: THookEvent,\n input: IHookInput,\n executors?: IHookTypeExecutor[],\n traceEnv?: ISubprocessTraceEnv,\n): Promise<IRunHooksResult> {\n if (!config) return { blocked: false, stdout: '' };\n\n const unknownHookTypes = new Set<string>();\n /** Hooks that rendered no verdict. Reported, never folded into a verdict — see `errors`. */\n const errors: IHookErrorOutcome[] = [];\n /**\n * The two \"what did NOT decide\" facts, carried on EVERY return path.\n *\n * They are built in one place because the previous shape repeated the `unknownHookTypes` spread at\n * each early return, and a second such field would have been four more chances to omit it on the\n * path that matters most — the one that returns early because something blocked.\n */\n const diagnostics = (): Pick<IRunHooksResult, 'unknownHookTypes' | 'errors'> => ({\n ...(unknownHookTypes.size > 0 && { unknownHookTypes: [...unknownHookTypes].sort() }),\n ...(errors.length > 0 && { errors: [...errors] }),\n });\n const groups = config[event];\n if (!groups || groups.length === 0) return { blocked: false, stdout: '' };\n\n const resolvedExecutors = executors ?? (await createDefaultExecutors());\n const executorMap = new Map<string, IHookTypeExecutor>();\n for (const executor of resolvedExecutors) {\n executorMap.set(executor.type, executor);\n }\n\n const stdoutParts: string[] = [];\n const matcherTarget = getMatcherTarget(input);\n\n // PreToolUse multi-hook priority tracking\n let highestPermissionPriority = -1;\n let highestPermissionDecision: TPermissionDecision | undefined;\n let lastUpdatedInput: Record<string, unknown> | undefined;\n\n for (const group of groups) {\n if (!matchesGroup(group, matcherTarget)) continue;\n\n // Merge group-level env vars into hook input\n const groupInput = group.env ? { ...input, env: { ...input.env, ...group.env } } : input;\n\n for (const hook of group.hooks) {\n const executor = executorMap.get(hook.type);\n if (!executor) {\n // Nothing runs for this hook, and the caller is TOLD so — see `unknownHookTypes`. The\n // comment here used to promise a warning that was never emitted.\n unknownHookTypes.add(hook.type);\n continue;\n }\n\n const outcome =\n hook.type === 'command' && traceEnv !== undefined\n ? await (executor as unknown as ICommandHookTraceExecutor).execute(hook, groupInput, traceEnv)\n : await executor.execute(hook, groupInput);\n\n // An explicit denial blocks, exactly as exit code 2 did.\n if (outcome.outcome === 'deny') {\n return {\n blocked: true,\n reason: outcome.reason || 'Blocked by hook',\n stdout: stdoutParts.join('\\n'),\n ...diagnostics(),\n };\n }\n\n // No verdict. Recorded and skipped — the hook's output is NOT read, because a hook that\n // failed has not said anything, and treating its stdout as a response is how a malformed\n // body came to be a verdict in the first place. Whether this BLOCKS is the boundary's call,\n // read from `HOOK_ENFORCEMENT_POLICY` — the runner reports and does not enforce (SEC-016).\n if (outcome.outcome === 'error') {\n errors.push(outcome);\n continue;\n }\n\n // The body's meaning is the protocol module's call (issue #2191); this loop only aggregates.\n const interpretation = interpretAllowOutcome(outcome.stdout, event);\n stdoutParts.push(...interpretation.context);\n\n if (interpretation.blockReason !== undefined) {\n return {\n blocked: true,\n reason: interpretation.blockReason,\n stdout: stdoutParts.join('\\n'),\n ...(interpretation.permissionDecision === 'deny' && {\n permissionDecision: 'deny' as const,\n }),\n ...diagnostics(),\n };\n }\n\n if (interpretation.permissionDecision !== undefined) {\n const priority = PERMISSION_PRIORITY[interpretation.permissionDecision];\n if (priority > highestPermissionPriority) {\n highestPermissionPriority = priority;\n highestPermissionDecision = interpretation.permissionDecision;\n }\n // Track updatedInput from the highest-priority decision\n if (priority >= highestPermissionPriority && interpretation.updatedInput !== undefined) {\n lastUpdatedInput = interpretation.updatedInput;\n }\n }\n }\n }\n\n const finalResult: IRunHooksResult = {\n blocked: false,\n stdout: stdoutParts.join('\\n'),\n };\n\n if (highestPermissionDecision !== undefined) {\n finalResult.permissionDecision = highestPermissionDecision;\n }\n if (lastUpdatedInput !== undefined) {\n finalResult.updatedInput = lastUpdatedInput;\n }\n const { unknownHookTypes: unrecognised, errors: failed } = diagnostics();\n if (unrecognised !== undefined) finalResult.unknownHookTypes = unrecognised;\n if (failed !== undefined) finalResult.errors = failed;\n\n return finalResult;\n}\n","/**\n * SELFHOST-005 — guardrail hook executor.\n *\n * A registered `IHookTypeExecutor` (`type: 'guardrail'`) that fans out the registered guardrail SET in\n * PARALLEL and FAILS FAST: the first guardrail that returns `pass: false` (or throws — fail-safe) maps\n * onto the `deny` outcome `runHooks` understands (SEC-015; formerly exit code 2), so a guardrail block flows\n * through the SAME `runHooks` → `runPreToolHook` → `PermissionEnforcer` denial path hooks already use —\n * no new runner, no second turn-blocking mechanism. Parallelism lives INSIDE the executor; the guardrail\n * SET runs concurrently while the turn still carries exactly one block decision.\n *\n * The guardrail functions (the POLICY) are the consumer's, injected at construction (registered in\n * `agent-framework`); this executor is pure neutral mechanism.\n */\n\nimport type {\n THookOutcome,\n IHookInput,\n IHookTypeExecutor,\n THookDefinition,\n TGuardrail,\n} from '../types.js';\n\n/** Internal: a guardrail failure carried out of the parallel race so the first one blocks. */\nclass GuardrailBlock extends Error {\n constructor(\n readonly guardrailName: string,\n readonly guardrailReason: string,\n ) {\n super(guardrailReason);\n this.name = 'GuardrailBlock';\n }\n}\n\nexport class GuardrailExecutor implements IHookTypeExecutor {\n readonly type = 'guardrail';\n private readonly guardrails: Map<string, TGuardrail>;\n\n constructor(guardrails: Map<string, TGuardrail> | Record<string, TGuardrail>) {\n this.guardrails =\n guardrails instanceof Map ? new Map(guardrails) : new Map(Object.entries(guardrails));\n }\n\n async execute(definition: THookDefinition, input: IHookInput): Promise<THookOutcome> {\n if (definition.type !== 'guardrail') {\n // Defensive: the runner dispatches by type, so this should never happen. It answers `error`\n // rather than `allow` because a mis-dispatched gate has rendered no verdict — the old\n // exit-code-0 here was itself a small instance of the coercion SEC-015 removes.\n return {\n outcome: 'error',\n source: 'guardrail',\n kind: 'malformed-response',\n reason: `GuardrailExecutor received a '${definition.type}' definition`,\n };\n }\n\n // Fail-safe on misconfiguration: a NAMED guardrail that isn't registered is a config error that\n // must NOT silently disable the gate — block the turn with a clear reason. (An omitted name list\n // runs all registered guardrails; an empty registry then legitimately passes.)\n if (definition.guardrails) {\n const unknown = definition.guardrails.filter((name) => !this.guardrails.has(name));\n if (unknown.length > 0) {\n return {\n outcome: 'deny',\n source: 'guardrail',\n reason: `Unknown guardrail(s) referenced but not registered: ${unknown.join(', ')}`,\n };\n }\n }\n\n const selected = this.selectGuardrails(definition.guardrails);\n if (selected.length === 0) return { outcome: 'allow', source: 'guardrail', stdout: '' };\n\n try {\n // Parallel fan-out + fail-fast: Promise.all rejects on the FIRST guardrail that blocks/throws,\n // without waiting for the rest — so the earliest failure is the turn's block decision.\n await Promise.all(\n selected.map(async ([name, guardrail]) => {\n let result;\n try {\n result = await guardrail(input);\n } catch (err) {\n // Fail-safe: a guardrail that cannot evaluate blocks the turn (it is an enforcement gate).\n const reason = err instanceof Error ? err.message : String(err);\n throw new GuardrailBlock(name, `Guardrail \"${name}\" errored: ${reason}`);\n }\n if (!result.pass) {\n throw new GuardrailBlock(name, result.reason ?? `Guardrail \"${name}\" blocked the turn`);\n }\n }),\n );\n } catch (err) {\n if (err instanceof GuardrailBlock) {\n return { outcome: 'deny', source: 'guardrail', reason: err.guardrailReason };\n }\n throw err;\n }\n\n return { outcome: 'allow', source: 'guardrail', stdout: '' };\n }\n\n /** Resolve the definition's optional name list to registered guardrails; omitted ⇒ all. */\n private selectGuardrails(names?: string[]): Array<[string, TGuardrail]> {\n if (!names) return [...this.guardrails.entries()];\n const selected: Array<[string, TGuardrail]> = [];\n for (const name of names) {\n const guardrail = this.guardrails.get(name);\n if (guardrail) selected.push([name, guardrail]);\n }\n return selected;\n }\n}\n","/**\n * SEC-016 — the per-event enforcement posture table.\n *\n * ## Why a table, and why it carries a reachability field\n *\n * Issue #2083 made a hook's failure representable: `runHooks` reports every execution that reached no\n * verdict on `IRunHooksResult.errors`. Nothing consumed it, so an enforcing hook that timed out or\n * could not spawn was still indistinguishable at the boundary from one that approved. This table is\n * what a consumer reads to decide whether that matters for a given event.\n *\n * The second field is the one that needs justifying. Measured across the tree: of the sixteen\n * `THookEvent` members, exactly ONE — `PreToolUse` — has a fire site that can block. The other\n * fifteen are advisory by construction, not by decision: seven fire `void`, five are called without\n * `await`, and three await a result they never inspect for `blocked`. A table that recorded only a\n * posture would therefore be fifteen-sixteenths inert, and — worse — unfalsifiable in the direction\n * that matters, because marking one of those events `enforcing` would change nothing while reading as\n * though it had.\n *\n * `enforcementReachable` records whether the event's fire site can honour an enforcing posture.\n * It is deliberately RECORDED rather than derived: deriving it would require the runner to know its\n * caller, which inverts the dependency the hooks module exists to keep clean.\n * `assertPolicyCoherent` below rejects internally contradictory rows; callers must preserve the\n * recorded reachability when they change a fire site.\n */\n\nimport type { THookEvent } from './types.js';\n\n/** Whether a failed hook blocks at this event, or is merely reported. */\nexport type THookEnforcementPosture = 'enforcing' | 'advisory';\n\nexport interface IHookEventPolicy {\n readonly posture: THookEnforcementPosture;\n /**\n * Whether this event's fire site awaits `runHooks` and consults `blocked`. An `enforcing` posture\n * at a site where this is `false` is a claim the code cannot honour.\n */\n readonly enforcementReachable: boolean;\n /** Why this event has this posture — read by whoever considers changing it. */\n readonly rationale: string;\n}\n\n/** Advisory because the fire site discards the result outright. */\nfunction firesAndForgets(where: string): IHookEventPolicy {\n return {\n posture: 'advisory',\n enforcementReachable: false,\n rationale: `Fire-and-forget at ${where}: the result is never awaited, so no posture can be honoured here.`,\n };\n}\n\n/** Advisory because the fire site awaits but never inspects `blocked`. */\nfunction awaitsButIgnoresBlocked(where: string, reads: string): IHookEventPolicy {\n return {\n posture: 'advisory',\n enforcementReachable: false,\n rationale: `Awaited at ${where} but only ${reads} is read; \\`blocked\\` is never consulted.`,\n };\n}\n\n/**\n * Freeze the table AND every row in it.\n *\n * `Object.freeze` is shallow and `readonly` is compile-time only, so a single-level freeze leaves\n * `HOOK_ENFORCEMENT_POLICY.PreToolUse.posture = 'advisory'` working at runtime — silently disarming\n * the gate `isEnforcing` consults on every tool call. For a table whose entire value is that it\n * cannot drift, freezing the outer object states an intent the code only half-delivers.\n */\nfunction deepFreezePolicy(\n policy: Record<THookEvent, IHookEventPolicy>,\n): Readonly<Record<THookEvent, IHookEventPolicy>> {\n for (const row of Object.values(policy)) Object.freeze(row);\n return Object.freeze(policy);\n}\n\n/**\n * The posture for every lifecycle event.\n *\n * Exhaustive over `THookEvent` by construction — `Record` makes a missing member a compile error.\n *\n * An EXTRA member is caught by three things, none of which is `assertPolicyCoherent`. That function\n * checks only that the table is non-empty and that no row claims `enforcing` while\n * `enforcementReachable` is false; it has no runtime knowledge of the union and was measured not to\n * throw on an unknown key. An earlier version of this sentence credited it anyway, which is worse\n * than saying nothing: a reader trusting it could delete the test below believing this function\n * covered the case. What actually catches an extra member:\n *\n * 1. the compiler's excess-property check on the object literal passed to `deepFreezePolicy`;\n * 2. the test asserting `Object.keys(HOOK_ENFORCEMENT_POLICY)` equals the union exactly.\n */\nexport const HOOK_ENFORCEMENT_POLICY: Readonly<Record<THookEvent, IHookEventPolicy>> =\n deepFreezePolicy({\n PreToolUse: {\n posture: 'enforcing',\n enforcementReachable: true,\n rationale:\n 'The tool-execution gate. `runPreToolHook` awaits the result and turns `blocked` into a denial, so a hook that reached no verdict must not read as approval (tracker issue #2075).',\n },\n\n // ── Awaited, but the result's `blocked` is never consulted ───────────────────────────────────\n SessionEnd: awaitsButIgnoresBlocked('session-lifecycle.ts', 'nothing'),\n PreCompact: awaitsButIgnoresBlocked('compaction-orchestrator.ts', 'nothing'),\n UserPromptSubmit: awaitsButIgnoresBlocked('session-run.ts', '`stdout`'),\n\n // ── Called without `await` ───────────────────────────────────────────────────────────────────\n PostToolUse: firesAndForgets('tool-hook-helpers.ts'),\n SessionStart: firesAndForgets('session-lifecycle.ts'),\n PostCompact: firesAndForgets('session-history-ops.ts'),\n Stop: firesAndForgets('session-run.ts'),\n StopFailure: firesAndForgets('session-run.ts'),\n\n // ── Explicitly `void`, by SELFHOST-009 design for the informational events ───────────────────\n SubagentStart: firesAndForgets('background-task-hooks.ts'),\n SubagentStop: firesAndForgets('background-task-hooks.ts'),\n WorktreeCreate: firesAndForgets('worktree-subagent-runner.ts'),\n WorktreeRemove: firesAndForgets('worktree-subagent-runner.ts'),\n PreModelCall: firesAndForgets('session-run.ts'),\n PostModelCall: firesAndForgets('session-run.ts'),\n PermissionDecision: firesAndForgets('permission-enforcer.ts'),\n });\n\n/** Does a hook that reached no verdict block at this event? */\nexport function isEnforcing(event: THookEvent): boolean {\n return HOOK_ENFORCEMENT_POLICY[event].posture === 'enforcing';\n}\n\n/**\n * The table's internal invariant: a row may not claim to enforce where enforcement is unreachable.\n *\n * This catches the NARROW contradiction — `posture: 'enforcing'` with `enforcementReachable: false`\n * — without needing the harness scan, which is the point: the two checks must be independent, or\n * whichever one is skipped becomes the only thing standing between the two fields. The scan carries\n * the WIDER case, where both fields are flipped together and the row is internally consistent while\n * still describing a gate the fire site cannot operate.\n *\n * @throws when a row is self-contradictory, naming the event.\n */\nexport function assertPolicyCoherent(\n policy: Readonly<Record<string, IHookEventPolicy>> = HOOK_ENFORCEMENT_POLICY,\n): void {\n const rows = Object.entries(policy);\n\n // A table with no rows is degenerate, not coherent.\n // Without this, the only test of the production form was vacuous: changing the default binding to\n // `= {}` left every agent-core hook test green, because an empty table has nothing dishonest in\n // it. Rejecting the empty table prevents a vacuous success.\n if (rows.length === 0) {\n throw new Error(\n 'Hook enforcement policy is empty. A table with no rows has nothing to check, which is a ' +\n 'degenerate policy rather than a coherent one — most likely the default binding to ' +\n 'HOOK_ENFORCEMENT_POLICY was broken.',\n );\n }\n\n const dishonest = rows\n .filter(([, entry]) => entry.posture === 'enforcing' && !entry.enforcementReachable)\n .map(([event]) => event);\n\n if (dishonest.length > 0) {\n throw new Error(\n `Hook enforcement policy is self-contradictory: ${dishonest.join(', ')} ` +\n `claim posture 'enforcing' while recording enforcementReachable: false. ` +\n `Either the fire site was changed and the flag is stale, or the posture asserts a gate that cannot run.`,\n );\n }\n}\n"],"mappings":"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"}
|