@falai/agent 3.4.5 → 4.0.0-alpha.1
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/README.md +41 -34
- package/dist/cjs/core/Agent.d.ts +22 -378
- package/dist/cjs/core/Agent.d.ts.map +1 -1
- package/dist/cjs/core/Agent.js +104 -1178
- package/dist/cjs/core/Agent.js.map +1 -1
- package/dist/cjs/core/CompactionEngine.d.ts.map +1 -1
- package/dist/cjs/core/CompactionEngine.js +5 -3
- package/dist/cjs/core/CompactionEngine.js.map +1 -1
- package/dist/cjs/core/FlowSpec.d.ts +136 -0
- package/dist/cjs/core/FlowSpec.d.ts.map +1 -0
- package/dist/cjs/core/FlowSpec.js +522 -0
- package/dist/cjs/core/FlowSpec.js.map +1 -0
- package/dist/cjs/core/Migrate.d.ts +38 -0
- package/dist/cjs/core/Migrate.d.ts.map +1 -0
- package/dist/cjs/core/Migrate.js +270 -0
- package/dist/cjs/core/Migrate.js.map +1 -0
- package/dist/cjs/core/Prompt.d.ts +54 -0
- package/dist/cjs/core/Prompt.d.ts.map +1 -0
- package/dist/cjs/core/Prompt.js +143 -0
- package/dist/cjs/core/Prompt.js.map +1 -0
- package/dist/cjs/core/Runner.d.ts +160 -0
- package/dist/cjs/core/Runner.d.ts.map +1 -0
- package/dist/cjs/core/Runner.js +1131 -0
- package/dist/cjs/core/Runner.js.map +1 -0
- package/dist/cjs/core/Speak.d.ts +37 -0
- package/dist/cjs/core/Speak.d.ts.map +1 -0
- package/dist/cjs/core/Speak.js +364 -0
- package/dist/cjs/core/Speak.js.map +1 -0
- package/dist/cjs/core/Understand.d.ts +28 -0
- package/dist/cjs/core/Understand.d.ts.map +1 -0
- package/dist/cjs/core/Understand.js +353 -0
- package/dist/cjs/core/Understand.js.map +1 -0
- package/dist/cjs/core/contracts.d.ts +122 -0
- package/dist/cjs/core/contracts.d.ts.map +1 -0
- package/dist/cjs/core/contracts.js +11 -0
- package/dist/cjs/core/contracts.js.map +1 -0
- package/dist/cjs/core/falai.d.ts +57 -0
- package/dist/cjs/core/falai.d.ts.map +1 -0
- package/dist/cjs/core/falai.js +43 -0
- package/dist/cjs/core/falai.js.map +1 -0
- package/dist/cjs/core/predicate.d.ts +9 -0
- package/dist/cjs/core/predicate.d.ts.map +1 -0
- package/dist/cjs/core/predicate.js +58 -0
- package/dist/cjs/core/predicate.js.map +1 -0
- package/dist/cjs/index.d.ts +26 -31
- package/dist/cjs/index.d.ts.map +1 -1
- package/dist/cjs/index.js +46 -68
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/persistence/MemoryStore.d.ts +15 -0
- package/dist/cjs/persistence/MemoryStore.d.ts.map +1 -0
- package/dist/cjs/persistence/MemoryStore.js +39 -0
- package/dist/cjs/persistence/MemoryStore.js.map +1 -0
- package/dist/cjs/persistence/MongoStore.d.ts +42 -0
- package/dist/cjs/persistence/MongoStore.d.ts.map +1 -0
- package/dist/cjs/persistence/MongoStore.js +60 -0
- package/dist/cjs/persistence/MongoStore.js.map +1 -0
- package/dist/cjs/persistence/OpenSearchStore.d.ts +86 -0
- package/dist/cjs/persistence/OpenSearchStore.d.ts.map +1 -0
- package/dist/cjs/persistence/OpenSearchStore.js +120 -0
- package/dist/cjs/persistence/OpenSearchStore.js.map +1 -0
- package/dist/cjs/persistence/PostgresStore.d.ts +41 -0
- package/dist/cjs/persistence/PostgresStore.d.ts.map +1 -0
- package/dist/cjs/persistence/PostgresStore.js +58 -0
- package/dist/cjs/persistence/PostgresStore.js.map +1 -0
- package/dist/cjs/persistence/PrismaStore.d.ts +65 -0
- package/dist/cjs/persistence/PrismaStore.d.ts.map +1 -0
- package/dist/cjs/persistence/PrismaStore.js +95 -0
- package/dist/cjs/persistence/PrismaStore.js.map +1 -0
- package/dist/cjs/persistence/RedisStore.d.ts +34 -0
- package/dist/cjs/persistence/RedisStore.d.ts.map +1 -0
- package/dist/cjs/persistence/RedisStore.js +61 -0
- package/dist/cjs/persistence/RedisStore.js.map +1 -0
- package/dist/cjs/persistence/SQLiteStore.d.ts +45 -0
- package/dist/cjs/persistence/SQLiteStore.d.ts.map +1 -0
- package/dist/cjs/persistence/SQLiteStore.js +74 -0
- package/dist/cjs/persistence/SQLiteStore.js.map +1 -0
- package/dist/cjs/persistence/sessionRow.d.ts +14 -0
- package/dist/cjs/persistence/sessionRow.d.ts.map +1 -0
- package/dist/cjs/persistence/sessionRow.js +50 -0
- package/dist/cjs/persistence/sessionRow.js.map +1 -0
- package/dist/cjs/providers/DeepSeekProvider.d.ts.map +1 -1
- package/dist/cjs/providers/DeepSeekProvider.js +8 -3
- package/dist/cjs/providers/DeepSeekProvider.js.map +1 -1
- package/dist/cjs/providers/GeminiProvider.d.ts +4 -3
- package/dist/cjs/providers/GeminiProvider.d.ts.map +1 -1
- package/dist/cjs/providers/GeminiProvider.js +4 -3
- package/dist/cjs/providers/GeminiProvider.js.map +1 -1
- package/dist/cjs/providers/OpenAICompatibleProvider.d.ts +4 -0
- package/dist/cjs/providers/OpenAICompatibleProvider.d.ts.map +1 -1
- package/dist/cjs/providers/OpenAICompatibleProvider.js +2 -0
- package/dist/cjs/providers/OpenAICompatibleProvider.js.map +1 -1
- package/dist/cjs/providers/OpenRouterProvider.d.ts.map +1 -1
- package/dist/cjs/providers/OpenRouterProvider.js +2 -4
- package/dist/cjs/providers/OpenRouterProvider.js.map +1 -1
- package/dist/cjs/providers/ProviderAdapter.d.ts +1 -1
- package/dist/cjs/providers/ProviderAdapter.d.ts.map +1 -1
- package/dist/cjs/providers/ProviderAdapter.js +33 -10
- package/dist/cjs/providers/ProviderAdapter.js.map +1 -1
- package/dist/cjs/types/agent.d.ts +153 -383
- package/dist/cjs/types/agent.d.ts.map +1 -1
- package/dist/cjs/types/agent.js +1 -1
- package/dist/cjs/types/ai.d.ts +32 -1
- package/dist/cjs/types/ai.d.ts.map +1 -1
- package/dist/cjs/types/compaction.d.ts +3 -1
- package/dist/cjs/types/compaction.d.ts.map +1 -1
- package/dist/cjs/types/errors.d.ts +9 -12
- package/dist/cjs/types/errors.d.ts.map +1 -1
- package/dist/cjs/types/errors.js +14 -17
- package/dist/cjs/types/errors.js.map +1 -1
- package/dist/cjs/types/flow.d.ts +265 -513
- package/dist/cjs/types/flow.d.ts.map +1 -1
- package/dist/cjs/types/flow.js +7 -1
- package/dist/cjs/types/flow.js.map +1 -1
- package/dist/cjs/types/history.d.ts +7 -18
- package/dist/cjs/types/history.d.ts.map +1 -1
- package/dist/cjs/types/history.js.map +1 -1
- package/dist/cjs/types/index.d.ts +9 -15
- package/dist/cjs/types/index.d.ts.map +1 -1
- package/dist/cjs/types/index.js +4 -14
- package/dist/cjs/types/index.js.map +1 -1
- package/dist/cjs/types/session.d.ts +94 -64
- package/dist/cjs/types/session.d.ts.map +1 -1
- package/dist/cjs/types/session.js +5 -1
- package/dist/cjs/types/session.js.map +1 -1
- package/dist/cjs/types/tool.d.ts +37 -207
- package/dist/cjs/types/tool.d.ts.map +1 -1
- package/dist/cjs/types/tool.js +5 -14
- package/dist/cjs/types/tool.js.map +1 -1
- package/dist/cjs/utils/clock.d.ts +28 -0
- package/dist/cjs/utils/clock.d.ts.map +1 -0
- package/dist/cjs/utils/clock.js +64 -0
- package/dist/cjs/utils/clock.js.map +1 -0
- package/dist/cjs/utils/duration.d.ts +11 -0
- package/dist/cjs/utils/duration.d.ts.map +1 -0
- package/dist/cjs/utils/duration.js +31 -0
- package/dist/cjs/utils/duration.js.map +1 -0
- package/dist/cjs/utils/history.d.ts +4 -1
- package/dist/cjs/utils/history.d.ts.map +1 -1
- package/dist/cjs/utils/history.js +2 -2
- package/dist/cjs/utils/history.js.map +1 -1
- package/dist/cjs/utils/index.d.ts +4 -10
- package/dist/cjs/utils/index.d.ts.map +1 -1
- package/dist/cjs/utils/index.js +14 -61
- package/dist/cjs/utils/index.js.map +1 -1
- package/dist/cjs/utils/json.d.ts +2 -0
- package/dist/cjs/utils/json.d.ts.map +1 -1
- package/dist/cjs/utils/json.js +5 -0
- package/dist/cjs/utils/json.js.map +1 -1
- package/dist/cjs/utils/outcomes.d.ts +48 -0
- package/dist/cjs/utils/outcomes.d.ts.map +1 -0
- package/dist/cjs/utils/outcomes.js +51 -0
- package/dist/cjs/utils/outcomes.js.map +1 -0
- package/dist/cjs/utils/schema.d.ts +50 -0
- package/dist/cjs/utils/schema.d.ts.map +1 -0
- package/dist/cjs/utils/schema.js +138 -0
- package/dist/cjs/utils/schema.js.map +1 -0
- package/dist/cjs/utils/streamingMessage.d.ts +3 -2
- package/dist/cjs/utils/streamingMessage.d.ts.map +1 -1
- package/dist/cjs/utils/streamingMessage.js +38 -4
- package/dist/cjs/utils/streamingMessage.js.map +1 -1
- package/dist/cjs/utils/template.d.ts +13 -149
- package/dist/cjs/utils/template.d.ts.map +1 -1
- package/dist/cjs/utils/template.js +31 -363
- package/dist/cjs/utils/template.js.map +1 -1
- package/dist/cjs/utils/usage.d.ts +19 -0
- package/dist/cjs/utils/usage.d.ts.map +1 -0
- package/dist/cjs/utils/usage.js +35 -0
- package/dist/cjs/utils/usage.js.map +1 -0
- package/dist/core/Agent.d.ts +22 -378
- package/dist/core/Agent.d.ts.map +1 -1
- package/dist/core/Agent.js +107 -1181
- package/dist/core/Agent.js.map +1 -1
- package/dist/core/CompactionEngine.d.ts.map +1 -1
- package/dist/core/CompactionEngine.js +5 -3
- package/dist/core/CompactionEngine.js.map +1 -1
- package/dist/core/FlowSpec.d.ts +136 -0
- package/dist/core/FlowSpec.d.ts.map +1 -0
- package/dist/core/FlowSpec.js +516 -0
- package/dist/core/FlowSpec.js.map +1 -0
- package/dist/core/Migrate.d.ts +38 -0
- package/dist/core/Migrate.d.ts.map +1 -0
- package/dist/core/Migrate.js +264 -0
- package/dist/core/Migrate.js.map +1 -0
- package/dist/core/Prompt.d.ts +54 -0
- package/dist/core/Prompt.d.ts.map +1 -0
- package/dist/core/Prompt.js +133 -0
- package/dist/core/Prompt.js.map +1 -0
- package/dist/core/Runner.d.ts +160 -0
- package/dist/core/Runner.d.ts.map +1 -0
- package/dist/core/Runner.js +1127 -0
- package/dist/core/Runner.js.map +1 -0
- package/dist/core/Speak.d.ts +37 -0
- package/dist/core/Speak.d.ts.map +1 -0
- package/dist/core/Speak.js +360 -0
- package/dist/core/Speak.js.map +1 -0
- package/dist/core/Understand.d.ts +28 -0
- package/dist/core/Understand.d.ts.map +1 -0
- package/dist/core/Understand.js +349 -0
- package/dist/core/Understand.js.map +1 -0
- package/dist/core/contracts.d.ts +122 -0
- package/dist/core/contracts.d.ts.map +1 -0
- package/dist/core/contracts.js +10 -0
- package/dist/core/contracts.js.map +1 -0
- package/dist/core/falai.d.ts +57 -0
- package/dist/core/falai.d.ts.map +1 -0
- package/dist/core/falai.js +40 -0
- package/dist/core/falai.js.map +1 -0
- package/dist/core/predicate.d.ts +9 -0
- package/dist/core/predicate.d.ts.map +1 -0
- package/dist/core/predicate.js +54 -0
- package/dist/core/predicate.js.map +1 -0
- package/dist/index.d.ts +26 -31
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +19 -24
- package/dist/index.js.map +1 -1
- package/dist/persistence/MemoryStore.d.ts +15 -0
- package/dist/persistence/MemoryStore.d.ts.map +1 -0
- package/dist/persistence/MemoryStore.js +35 -0
- package/dist/persistence/MemoryStore.js.map +1 -0
- package/dist/persistence/MongoStore.d.ts +42 -0
- package/dist/persistence/MongoStore.d.ts.map +1 -0
- package/dist/persistence/MongoStore.js +56 -0
- package/dist/persistence/MongoStore.js.map +1 -0
- package/dist/persistence/OpenSearchStore.d.ts +86 -0
- package/dist/persistence/OpenSearchStore.d.ts.map +1 -0
- package/dist/persistence/OpenSearchStore.js +116 -0
- package/dist/persistence/OpenSearchStore.js.map +1 -0
- package/dist/persistence/PostgresStore.d.ts +41 -0
- package/dist/persistence/PostgresStore.d.ts.map +1 -0
- package/dist/persistence/PostgresStore.js +54 -0
- package/dist/persistence/PostgresStore.js.map +1 -0
- package/dist/persistence/PrismaStore.d.ts +65 -0
- package/dist/persistence/PrismaStore.d.ts.map +1 -0
- package/dist/persistence/PrismaStore.js +91 -0
- package/dist/persistence/PrismaStore.js.map +1 -0
- package/dist/persistence/RedisStore.d.ts +34 -0
- package/dist/persistence/RedisStore.d.ts.map +1 -0
- package/dist/persistence/RedisStore.js +57 -0
- package/dist/persistence/RedisStore.js.map +1 -0
- package/dist/persistence/SQLiteStore.d.ts +45 -0
- package/dist/persistence/SQLiteStore.d.ts.map +1 -0
- package/dist/persistence/SQLiteStore.js +70 -0
- package/dist/persistence/SQLiteStore.js.map +1 -0
- package/dist/persistence/sessionRow.d.ts +14 -0
- package/dist/persistence/sessionRow.d.ts.map +1 -0
- package/dist/persistence/sessionRow.js +45 -0
- package/dist/persistence/sessionRow.js.map +1 -0
- package/dist/providers/DeepSeekProvider.d.ts.map +1 -1
- package/dist/providers/DeepSeekProvider.js +8 -3
- package/dist/providers/DeepSeekProvider.js.map +1 -1
- package/dist/providers/GeminiProvider.d.ts +4 -3
- package/dist/providers/GeminiProvider.d.ts.map +1 -1
- package/dist/providers/GeminiProvider.js +4 -3
- package/dist/providers/GeminiProvider.js.map +1 -1
- package/dist/providers/OpenAICompatibleProvider.d.ts +4 -0
- package/dist/providers/OpenAICompatibleProvider.d.ts.map +1 -1
- package/dist/providers/OpenAICompatibleProvider.js +2 -0
- package/dist/providers/OpenAICompatibleProvider.js.map +1 -1
- package/dist/providers/OpenRouterProvider.d.ts.map +1 -1
- package/dist/providers/OpenRouterProvider.js +2 -4
- package/dist/providers/OpenRouterProvider.js.map +1 -1
- package/dist/providers/ProviderAdapter.d.ts +1 -1
- package/dist/providers/ProviderAdapter.d.ts.map +1 -1
- package/dist/providers/ProviderAdapter.js +34 -11
- package/dist/providers/ProviderAdapter.js.map +1 -1
- package/dist/types/agent.d.ts +153 -383
- package/dist/types/agent.d.ts.map +1 -1
- package/dist/types/agent.js +1 -1
- package/dist/types/ai.d.ts +32 -1
- package/dist/types/ai.d.ts.map +1 -1
- package/dist/types/compaction.d.ts +3 -1
- package/dist/types/compaction.d.ts.map +1 -1
- package/dist/types/errors.d.ts +9 -12
- package/dist/types/errors.d.ts.map +1 -1
- package/dist/types/errors.js +12 -15
- package/dist/types/errors.js.map +1 -1
- package/dist/types/flow.d.ts +265 -513
- package/dist/types/flow.d.ts.map +1 -1
- package/dist/types/flow.js +7 -1
- package/dist/types/flow.js.map +1 -1
- package/dist/types/history.d.ts +7 -18
- package/dist/types/history.d.ts.map +1 -1
- package/dist/types/history.js.map +1 -1
- package/dist/types/index.d.ts +9 -15
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js +2 -7
- package/dist/types/index.js.map +1 -1
- package/dist/types/session.d.ts +94 -64
- package/dist/types/session.d.ts.map +1 -1
- package/dist/types/session.js +5 -1
- package/dist/types/session.js.map +1 -1
- package/dist/types/tool.d.ts +37 -207
- package/dist/types/tool.d.ts.map +1 -1
- package/dist/types/tool.js +6 -13
- package/dist/types/tool.js.map +1 -1
- package/dist/utils/clock.d.ts +28 -0
- package/dist/utils/clock.d.ts.map +1 -0
- package/dist/utils/clock.js +59 -0
- package/dist/utils/clock.js.map +1 -0
- package/dist/utils/duration.d.ts +11 -0
- package/dist/utils/duration.d.ts.map +1 -0
- package/dist/utils/duration.js +26 -0
- package/dist/utils/duration.js.map +1 -0
- package/dist/utils/history.d.ts +4 -1
- package/dist/utils/history.d.ts.map +1 -1
- package/dist/utils/history.js +2 -2
- package/dist/utils/history.js.map +1 -1
- package/dist/utils/index.d.ts +4 -10
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +4 -21
- package/dist/utils/index.js.map +1 -1
- package/dist/utils/json.d.ts +2 -0
- package/dist/utils/json.d.ts.map +1 -1
- package/dist/utils/json.js +4 -0
- package/dist/utils/json.js.map +1 -1
- package/dist/utils/outcomes.d.ts +48 -0
- package/dist/utils/outcomes.d.ts.map +1 -0
- package/dist/utils/outcomes.js +48 -0
- package/dist/utils/outcomes.js.map +1 -0
- package/dist/utils/schema.d.ts +50 -0
- package/dist/utils/schema.d.ts.map +1 -0
- package/dist/utils/schema.js +129 -0
- package/dist/utils/schema.js.map +1 -0
- package/dist/utils/streamingMessage.d.ts +3 -2
- package/dist/utils/streamingMessage.d.ts.map +1 -1
- package/dist/utils/streamingMessage.js +38 -4
- package/dist/utils/streamingMessage.js.map +1 -1
- package/dist/utils/template.d.ts +13 -149
- package/dist/utils/template.d.ts.map +1 -1
- package/dist/utils/template.js +28 -355
- package/dist/utils/template.js.map +1 -1
- package/dist/utils/usage.d.ts +19 -0
- package/dist/utils/usage.d.ts.map +1 -0
- package/dist/utils/usage.js +31 -0
- package/dist/utils/usage.js.map +1 -0
- package/docs/README.md +37 -19
- package/docs/concepts/architecture.md +117 -239
- package/docs/concepts/collection.md +170 -0
- package/docs/concepts/pipeline.md +132 -378
- package/docs/concepts/runs-and-waits.md +192 -0
- package/docs/guides/actions-and-events.md +276 -0
- package/docs/guides/branching.md +119 -208
- package/docs/guides/compaction.md +63 -158
- package/docs/guides/conditions.md +164 -128
- package/docs/guides/error-handling.md +168 -164
- package/docs/guides/flow-control.md +210 -349
- package/docs/guides/flows-from-json.md +224 -0
- package/docs/guides/instructions.md +125 -161
- package/docs/guides/persistence.md +182 -206
- package/docs/guides/streaming.md +50 -114
- package/docs/guides/testing.md +284 -0
- package/docs/guides/triggers.md +401 -0
- package/docs/migration/README.md +8 -15
- package/docs/migration/v1-to-v2.md +1 -1
- package/docs/migration/v2-3-to-v2-4.md +2 -2
- package/docs/migration/v2-6-to-v2-7.md +4 -4
- package/docs/migration/v3-to-v4.md +452 -0
- package/docs/reference/actions-events-conditions.md +396 -0
- package/docs/reference/agent.md +244 -0
- package/docs/reference/branches.md +75 -203
- package/docs/reference/errors.md +188 -144
- package/docs/reference/fields.md +125 -0
- package/docs/reference/flow-spec.md +248 -0
- package/docs/reference/flow.md +104 -192
- package/docs/reference/instruction.md +83 -137
- package/docs/reference/outcomes.md +273 -0
- package/docs/reference/providers.md +525 -302
- package/docs/reference/session.md +210 -0
- package/docs/reference/step.md +194 -312
- package/docs/reference/stores.md +496 -0
- package/docs/reference/tool.md +162 -231
- package/docs/reference/trigger.md +180 -0
- package/docs/rfc/v4-one-flow.md +477 -0
- package/docs/start/01-install.md +59 -44
- package/docs/start/02-first-agent.md +97 -147
- package/docs/start/03-collect-data.md +78 -183
- package/docs/start/04-add-tools.md +159 -227
- package/docs/start/05-go-to-production.md +167 -164
- package/examples/01-quickstart.ts +26 -16
- package/examples/02-fields.ts +75 -0
- package/examples/03-tools.ts +79 -119
- package/examples/04-instructions.ts +60 -87
- package/examples/05-branches.ts +78 -0
- package/examples/06-triggers-and-waits.ts +148 -0
- package/examples/07-streaming.ts +34 -60
- package/examples/08-store-and-migration.ts +97 -0
- package/examples/09-flows-from-json.ts +107 -0
- package/package.json +9 -6
- package/src/core/Agent.ts +116 -1512
- package/src/core/CompactionEngine.ts +7 -4
- package/src/core/FlowSpec.ts +712 -0
- package/src/core/Migrate.ts +256 -0
- package/src/core/Prompt.ts +156 -0
- package/src/core/Runner.ts +1181 -0
- package/src/core/Speak.ts +451 -0
- package/src/core/Understand.ts +422 -0
- package/src/core/contracts.ts +111 -0
- package/src/core/falai.ts +86 -0
- package/src/core/predicate.ts +56 -0
- package/src/index.ts +119 -147
- package/src/persistence/MemoryStore.ts +37 -0
- package/src/persistence/MongoStore.ts +89 -0
- package/src/persistence/OpenSearchStore.ts +153 -0
- package/src/persistence/PostgresStore.ts +89 -0
- package/src/persistence/PrismaStore.ts +127 -0
- package/src/persistence/RedisStore.ts +90 -0
- package/src/persistence/SQLiteStore.ts +103 -0
- package/src/persistence/sessionRow.ts +45 -0
- package/src/providers/DeepSeekProvider.ts +8 -3
- package/src/providers/GeminiProvider.ts +4 -3
- package/src/providers/OpenAICompatibleProvider.ts +6 -0
- package/src/providers/OpenRouterProvider.ts +2 -4
- package/src/providers/ProviderAdapter.ts +36 -8
- package/src/types/agent.ts +124 -397
- package/src/types/ai.ts +33 -1
- package/src/types/compaction.ts +3 -1
- package/src/types/errors.ts +13 -16
- package/src/types/flow.ts +249 -550
- package/src/types/history.ts +7 -20
- package/src/types/index.ts +87 -139
- package/src/types/session.ts +135 -70
- package/src/types/tool.ts +42 -267
- package/src/utils/clock.ts +70 -0
- package/src/utils/duration.ts +33 -0
- package/src/utils/history.ts +3 -2
- package/src/utils/index.ts +8 -66
- package/src/utils/json.ts +5 -0
- package/src/utils/outcomes.ts +56 -0
- package/src/utils/schema.ts +145 -0
- package/src/utils/streamingMessage.ts +34 -4
- package/src/utils/template.ts +32 -423
- package/src/utils/usage.ts +37 -0
- package/dist/adapters/MemoryAdapter.d.ts +0 -47
- package/dist/adapters/MemoryAdapter.d.ts.map +0 -1
- package/dist/adapters/MemoryAdapter.js +0 -204
- package/dist/adapters/MemoryAdapter.js.map +0 -1
- package/dist/adapters/MongoAdapter.d.ts +0 -97
- package/dist/adapters/MongoAdapter.d.ts.map +0 -1
- package/dist/adapters/MongoAdapter.js +0 -196
- package/dist/adapters/MongoAdapter.js.map +0 -1
- package/dist/adapters/OpenSearchAdapter.d.ts +0 -169
- package/dist/adapters/OpenSearchAdapter.d.ts.map +0 -1
- package/dist/adapters/OpenSearchAdapter.js +0 -471
- package/dist/adapters/OpenSearchAdapter.js.map +0 -1
- package/dist/adapters/PostgreSQLAdapter.d.ts +0 -85
- package/dist/adapters/PostgreSQLAdapter.d.ts.map +0 -1
- package/dist/adapters/PostgreSQLAdapter.js +0 -308
- package/dist/adapters/PostgreSQLAdapter.js.map +0 -1
- package/dist/adapters/PrismaAdapter.d.ts +0 -115
- package/dist/adapters/PrismaAdapter.d.ts.map +0 -1
- package/dist/adapters/PrismaAdapter.js +0 -406
- package/dist/adapters/PrismaAdapter.js.map +0 -1
- package/dist/adapters/RedisAdapter.d.ts +0 -72
- package/dist/adapters/RedisAdapter.d.ts.map +0 -1
- package/dist/adapters/RedisAdapter.js +0 -286
- package/dist/adapters/RedisAdapter.js.map +0 -1
- package/dist/adapters/SQLiteAdapter.d.ts +0 -86
- package/dist/adapters/SQLiteAdapter.d.ts.map +0 -1
- package/dist/adapters/SQLiteAdapter.js +0 -337
- package/dist/adapters/SQLiteAdapter.js.map +0 -1
- package/dist/adapters/index.d.ts +0 -17
- package/dist/adapters/index.d.ts.map +0 -1
- package/dist/adapters/index.js +0 -11
- package/dist/adapters/index.js.map +0 -1
- package/dist/adapters/sessionRow.d.ts +0 -22
- package/dist/adapters/sessionRow.d.ts.map +0 -1
- package/dist/adapters/sessionRow.js +0 -48
- package/dist/adapters/sessionRow.js.map +0 -1
- package/dist/cjs/adapters/MemoryAdapter.d.ts +0 -47
- package/dist/cjs/adapters/MemoryAdapter.d.ts.map +0 -1
- package/dist/cjs/adapters/MemoryAdapter.js +0 -208
- package/dist/cjs/adapters/MemoryAdapter.js.map +0 -1
- package/dist/cjs/adapters/MongoAdapter.d.ts +0 -97
- package/dist/cjs/adapters/MongoAdapter.d.ts.map +0 -1
- package/dist/cjs/adapters/MongoAdapter.js +0 -200
- package/dist/cjs/adapters/MongoAdapter.js.map +0 -1
- package/dist/cjs/adapters/OpenSearchAdapter.d.ts +0 -169
- package/dist/cjs/adapters/OpenSearchAdapter.d.ts.map +0 -1
- package/dist/cjs/adapters/OpenSearchAdapter.js +0 -475
- package/dist/cjs/adapters/OpenSearchAdapter.js.map +0 -1
- package/dist/cjs/adapters/PostgreSQLAdapter.d.ts +0 -85
- package/dist/cjs/adapters/PostgreSQLAdapter.d.ts.map +0 -1
- package/dist/cjs/adapters/PostgreSQLAdapter.js +0 -312
- package/dist/cjs/adapters/PostgreSQLAdapter.js.map +0 -1
- package/dist/cjs/adapters/PrismaAdapter.d.ts +0 -115
- package/dist/cjs/adapters/PrismaAdapter.d.ts.map +0 -1
- package/dist/cjs/adapters/PrismaAdapter.js +0 -410
- package/dist/cjs/adapters/PrismaAdapter.js.map +0 -1
- package/dist/cjs/adapters/RedisAdapter.d.ts +0 -72
- package/dist/cjs/adapters/RedisAdapter.d.ts.map +0 -1
- package/dist/cjs/adapters/RedisAdapter.js +0 -290
- package/dist/cjs/adapters/RedisAdapter.js.map +0 -1
- package/dist/cjs/adapters/SQLiteAdapter.d.ts +0 -86
- package/dist/cjs/adapters/SQLiteAdapter.d.ts.map +0 -1
- package/dist/cjs/adapters/SQLiteAdapter.js +0 -341
- package/dist/cjs/adapters/SQLiteAdapter.js.map +0 -1
- package/dist/cjs/adapters/index.d.ts +0 -17
- package/dist/cjs/adapters/index.d.ts.map +0 -1
- package/dist/cjs/adapters/index.js +0 -21
- package/dist/cjs/adapters/index.js.map +0 -1
- package/dist/cjs/adapters/sessionRow.d.ts +0 -22
- package/dist/cjs/adapters/sessionRow.d.ts.map +0 -1
- package/dist/cjs/adapters/sessionRow.js +0 -52
- package/dist/cjs/adapters/sessionRow.js.map +0 -1
- package/dist/cjs/constants/index.d.ts +0 -1
- package/dist/cjs/constants/index.d.ts.map +0 -1
- package/dist/cjs/constants/index.js +0 -4
- package/dist/cjs/constants/index.js.map +0 -1
- package/dist/cjs/core/AutoChainExecutor.d.ts +0 -97
- package/dist/cjs/core/AutoChainExecutor.d.ts.map +0 -1
- package/dist/cjs/core/AutoChainExecutor.js +0 -288
- package/dist/cjs/core/AutoChainExecutor.js.map +0 -1
- package/dist/cjs/core/BranchEvaluator.d.ts +0 -55
- package/dist/cjs/core/BranchEvaluator.d.ts.map +0 -1
- package/dist/cjs/core/BranchEvaluator.js +0 -125
- package/dist/cjs/core/BranchEvaluator.js.map +0 -1
- package/dist/cjs/core/DirectiveChainTracker.d.ts +0 -49
- package/dist/cjs/core/DirectiveChainTracker.d.ts.map +0 -1
- package/dist/cjs/core/DirectiveChainTracker.js +0 -121
- package/dist/cjs/core/DirectiveChainTracker.js.map +0 -1
- package/dist/cjs/core/Events.d.ts +0 -26
- package/dist/cjs/core/Events.d.ts.map +0 -1
- package/dist/cjs/core/Events.js +0 -144
- package/dist/cjs/core/Events.js.map +0 -1
- package/dist/cjs/core/Flow.d.ts +0 -183
- package/dist/cjs/core/Flow.d.ts.map +0 -1
- package/dist/cjs/core/Flow.js +0 -551
- package/dist/cjs/core/Flow.js.map +0 -1
- package/dist/cjs/core/FlowRouter.d.ts +0 -183
- package/dist/cjs/core/FlowRouter.d.ts.map +0 -1
- package/dist/cjs/core/FlowRouter.js +0 -1047
- package/dist/cjs/core/FlowRouter.js.map +0 -1
- package/dist/cjs/core/PersistenceManager.d.ts +0 -114
- package/dist/cjs/core/PersistenceManager.d.ts.map +0 -1
- package/dist/cjs/core/PersistenceManager.js +0 -336
- package/dist/cjs/core/PersistenceManager.js.map +0 -1
- package/dist/cjs/core/PromptComposer.d.ts +0 -47
- package/dist/cjs/core/PromptComposer.d.ts.map +0 -1
- package/dist/cjs/core/PromptComposer.js +0 -397
- package/dist/cjs/core/PromptComposer.js.map +0 -1
- package/dist/cjs/core/PromptSectionCache.d.ts +0 -48
- package/dist/cjs/core/PromptSectionCache.d.ts.map +0 -1
- package/dist/cjs/core/PromptSectionCache.js +0 -108
- package/dist/cjs/core/PromptSectionCache.js.map +0 -1
- package/dist/cjs/core/ResponseEngine.d.ts +0 -43
- package/dist/cjs/core/ResponseEngine.d.ts.map +0 -1
- package/dist/cjs/core/ResponseEngine.js +0 -235
- package/dist/cjs/core/ResponseEngine.js.map +0 -1
- package/dist/cjs/core/ResponseGenerationError.d.ts +0 -30
- package/dist/cjs/core/ResponseGenerationError.d.ts.map +0 -1
- package/dist/cjs/core/ResponseGenerationError.js +0 -35
- package/dist/cjs/core/ResponseGenerationError.js.map +0 -1
- package/dist/cjs/core/ResponseModal.d.ts +0 -305
- package/dist/cjs/core/ResponseModal.d.ts.map +0 -1
- package/dist/cjs/core/ResponseModal.js +0 -1414
- package/dist/cjs/core/ResponseModal.js.map +0 -1
- package/dist/cjs/core/ResponsePipeline.d.ts +0 -220
- package/dist/cjs/core/ResponsePipeline.d.ts.map +0 -1
- package/dist/cjs/core/ResponsePipeline.js +0 -1040
- package/dist/cjs/core/ResponsePipeline.js.map +0 -1
- package/dist/cjs/core/SessionFinalizer.d.ts +0 -34
- package/dist/cjs/core/SessionFinalizer.d.ts.map +0 -1
- package/dist/cjs/core/SessionFinalizer.js +0 -88
- package/dist/cjs/core/SessionFinalizer.js.map +0 -1
- package/dist/cjs/core/SessionManager.d.ts +0 -112
- package/dist/cjs/core/SessionManager.d.ts.map +0 -1
- package/dist/cjs/core/SessionManager.js +0 -308
- package/dist/cjs/core/SessionManager.js.map +0 -1
- package/dist/cjs/core/SignalCoordinator.d.ts +0 -103
- package/dist/cjs/core/SignalCoordinator.d.ts.map +0 -1
- package/dist/cjs/core/SignalCoordinator.js +0 -207
- package/dist/cjs/core/SignalCoordinator.js.map +0 -1
- package/dist/cjs/core/SignalEvaluator.d.ts +0 -86
- package/dist/cjs/core/SignalEvaluator.d.ts.map +0 -1
- package/dist/cjs/core/SignalEvaluator.js +0 -319
- package/dist/cjs/core/SignalEvaluator.js.map +0 -1
- package/dist/cjs/core/SignalProcessor.d.ts +0 -152
- package/dist/cjs/core/SignalProcessor.d.ts.map +0 -1
- package/dist/cjs/core/SignalProcessor.js +0 -505
- package/dist/cjs/core/SignalProcessor.js.map +0 -1
- package/dist/cjs/core/Step.d.ts +0 -184
- package/dist/cjs/core/Step.d.ts.map +0 -1
- package/dist/cjs/core/Step.js +0 -599
- package/dist/cjs/core/Step.js.map +0 -1
- package/dist/cjs/core/StepLifecycle.d.ts +0 -43
- package/dist/cjs/core/StepLifecycle.d.ts.map +0 -1
- package/dist/cjs/core/StepLifecycle.js +0 -180
- package/dist/cjs/core/StepLifecycle.js.map +0 -1
- package/dist/cjs/core/StreamingToolExecutor.d.ts +0 -142
- package/dist/cjs/core/StreamingToolExecutor.d.ts.map +0 -1
- package/dist/cjs/core/StreamingToolExecutor.js +0 -490
- package/dist/cjs/core/StreamingToolExecutor.js.map +0 -1
- package/dist/cjs/core/ToolLoopExecutor.d.ts +0 -133
- package/dist/cjs/core/ToolLoopExecutor.d.ts.map +0 -1
- package/dist/cjs/core/ToolLoopExecutor.js +0 -568
- package/dist/cjs/core/ToolLoopExecutor.js.map +0 -1
- package/dist/cjs/core/ToolManager.d.ts +0 -250
- package/dist/cjs/core/ToolManager.d.ts.map +0 -1
- package/dist/cjs/core/ToolManager.js +0 -1104
- package/dist/cjs/core/ToolManager.js.map +0 -1
- package/dist/cjs/core/createAgent.d.ts +0 -35
- package/dist/cjs/core/createAgent.d.ts.map +0 -1
- package/dist/cjs/core/createAgent.js +0 -39
- package/dist/cjs/core/createAgent.js.map +0 -1
- package/dist/cjs/core/flow-namespace.d.ts +0 -64
- package/dist/cjs/core/flow-namespace.d.ts.map +0 -1
- package/dist/cjs/core/flow-namespace.js +0 -182
- package/dist/cjs/core/flow-namespace.js.map +0 -1
- package/dist/cjs/core/toolGates.d.ts +0 -24
- package/dist/cjs/core/toolGates.d.ts.map +0 -1
- package/dist/cjs/core/toolGates.js +0 -52
- package/dist/cjs/core/toolGates.js.map +0 -1
- package/dist/cjs/types/persistence.d.ts +0 -254
- package/dist/cjs/types/persistence.d.ts.map +0 -1
- package/dist/cjs/types/persistence.js +0 -7
- package/dist/cjs/types/persistence.js.map +0 -1
- package/dist/cjs/types/prompt-cache.d.ts +0 -15
- package/dist/cjs/types/prompt-cache.d.ts.map +0 -1
- package/dist/cjs/types/prompt-cache.js +0 -6
- package/dist/cjs/types/prompt-cache.js.map +0 -1
- package/dist/cjs/types/signals.d.ts +0 -263
- package/dist/cjs/types/signals.d.ts.map +0 -1
- package/dist/cjs/types/signals.js +0 -11
- package/dist/cjs/types/signals.js.map +0 -1
- package/dist/cjs/types/template.d.ts +0 -84
- package/dist/cjs/types/template.d.ts.map +0 -1
- package/dist/cjs/types/template.js +0 -3
- package/dist/cjs/types/template.js.map +0 -1
- package/dist/cjs/utils/condition.d.ts +0 -63
- package/dist/cjs/utils/condition.d.ts.map +0 -1
- package/dist/cjs/utils/condition.js +0 -239
- package/dist/cjs/utils/condition.js.map +0 -1
- package/dist/cjs/utils/event.d.ts +0 -6
- package/dist/cjs/utils/event.d.ts.map +0 -1
- package/dist/cjs/utils/event.js +0 -20
- package/dist/cjs/utils/event.js.map +0 -1
- package/dist/cjs/utils/id.d.ts +0 -33
- package/dist/cjs/utils/id.d.ts.map +0 -1
- package/dist/cjs/utils/id.js +0 -84
- package/dist/cjs/utils/id.js.map +0 -1
- package/dist/cjs/utils/serialize.d.ts +0 -36
- package/dist/cjs/utils/serialize.d.ts.map +0 -1
- package/dist/cjs/utils/serialize.js +0 -77
- package/dist/cjs/utils/serialize.js.map +0 -1
- package/dist/cjs/utils/session.d.ts +0 -124
- package/dist/cjs/utils/session.d.ts.map +0 -1
- package/dist/cjs/utils/session.js +0 -396
- package/dist/cjs/utils/session.js.map +0 -1
- package/dist/constants/index.d.ts +0 -2
- package/dist/constants/index.d.ts.map +0 -1
- package/dist/constants/index.js +0 -4
- package/dist/constants/index.js.map +0 -1
- package/dist/core/AutoChainExecutor.d.ts +0 -97
- package/dist/core/AutoChainExecutor.d.ts.map +0 -1
- package/dist/core/AutoChainExecutor.js +0 -284
- package/dist/core/AutoChainExecutor.js.map +0 -1
- package/dist/core/BranchEvaluator.d.ts +0 -55
- package/dist/core/BranchEvaluator.d.ts.map +0 -1
- package/dist/core/BranchEvaluator.js +0 -121
- package/dist/core/BranchEvaluator.js.map +0 -1
- package/dist/core/DirectiveChainTracker.d.ts +0 -49
- package/dist/core/DirectiveChainTracker.d.ts.map +0 -1
- package/dist/core/DirectiveChainTracker.js +0 -117
- package/dist/core/DirectiveChainTracker.js.map +0 -1
- package/dist/core/Events.d.ts +0 -26
- package/dist/core/Events.d.ts.map +0 -1
- package/dist/core/Events.js +0 -137
- package/dist/core/Events.js.map +0 -1
- package/dist/core/Flow.d.ts +0 -183
- package/dist/core/Flow.d.ts.map +0 -1
- package/dist/core/Flow.js +0 -547
- package/dist/core/Flow.js.map +0 -1
- package/dist/core/FlowRouter.d.ts +0 -183
- package/dist/core/FlowRouter.d.ts.map +0 -1
- package/dist/core/FlowRouter.js +0 -1043
- package/dist/core/FlowRouter.js.map +0 -1
- package/dist/core/PersistenceManager.d.ts +0 -114
- package/dist/core/PersistenceManager.d.ts.map +0 -1
- package/dist/core/PersistenceManager.js +0 -332
- package/dist/core/PersistenceManager.js.map +0 -1
- package/dist/core/PromptComposer.d.ts +0 -47
- package/dist/core/PromptComposer.d.ts.map +0 -1
- package/dist/core/PromptComposer.js +0 -393
- package/dist/core/PromptComposer.js.map +0 -1
- package/dist/core/PromptSectionCache.d.ts +0 -48
- package/dist/core/PromptSectionCache.d.ts.map +0 -1
- package/dist/core/PromptSectionCache.js +0 -104
- package/dist/core/PromptSectionCache.js.map +0 -1
- package/dist/core/ResponseEngine.d.ts +0 -43
- package/dist/core/ResponseEngine.d.ts.map +0 -1
- package/dist/core/ResponseEngine.js +0 -231
- package/dist/core/ResponseEngine.js.map +0 -1
- package/dist/core/ResponseGenerationError.d.ts +0 -30
- package/dist/core/ResponseGenerationError.d.ts.map +0 -1
- package/dist/core/ResponseGenerationError.js +0 -31
- package/dist/core/ResponseGenerationError.js.map +0 -1
- package/dist/core/ResponseModal.d.ts +0 -305
- package/dist/core/ResponseModal.d.ts.map +0 -1
- package/dist/core/ResponseModal.js +0 -1410
- package/dist/core/ResponseModal.js.map +0 -1
- package/dist/core/ResponsePipeline.d.ts +0 -220
- package/dist/core/ResponsePipeline.d.ts.map +0 -1
- package/dist/core/ResponsePipeline.js +0 -1035
- package/dist/core/ResponsePipeline.js.map +0 -1
- package/dist/core/SessionFinalizer.d.ts +0 -34
- package/dist/core/SessionFinalizer.d.ts.map +0 -1
- package/dist/core/SessionFinalizer.js +0 -84
- package/dist/core/SessionFinalizer.js.map +0 -1
- package/dist/core/SessionManager.d.ts +0 -112
- package/dist/core/SessionManager.d.ts.map +0 -1
- package/dist/core/SessionManager.js +0 -301
- package/dist/core/SessionManager.js.map +0 -1
- package/dist/core/SignalCoordinator.d.ts +0 -103
- package/dist/core/SignalCoordinator.d.ts.map +0 -1
- package/dist/core/SignalCoordinator.js +0 -203
- package/dist/core/SignalCoordinator.js.map +0 -1
- package/dist/core/SignalEvaluator.d.ts +0 -86
- package/dist/core/SignalEvaluator.d.ts.map +0 -1
- package/dist/core/SignalEvaluator.js +0 -312
- package/dist/core/SignalEvaluator.js.map +0 -1
- package/dist/core/SignalProcessor.d.ts +0 -152
- package/dist/core/SignalProcessor.d.ts.map +0 -1
- package/dist/core/SignalProcessor.js +0 -498
- package/dist/core/SignalProcessor.js.map +0 -1
- package/dist/core/Step.d.ts +0 -184
- package/dist/core/Step.d.ts.map +0 -1
- package/dist/core/Step.js +0 -594
- package/dist/core/Step.js.map +0 -1
- package/dist/core/StepLifecycle.d.ts +0 -43
- package/dist/core/StepLifecycle.d.ts.map +0 -1
- package/dist/core/StepLifecycle.js +0 -176
- package/dist/core/StepLifecycle.js.map +0 -1
- package/dist/core/StreamingToolExecutor.d.ts +0 -142
- package/dist/core/StreamingToolExecutor.d.ts.map +0 -1
- package/dist/core/StreamingToolExecutor.js +0 -483
- package/dist/core/StreamingToolExecutor.js.map +0 -1
- package/dist/core/ToolLoopExecutor.d.ts +0 -133
- package/dist/core/ToolLoopExecutor.d.ts.map +0 -1
- package/dist/core/ToolLoopExecutor.js +0 -564
- package/dist/core/ToolLoopExecutor.js.map +0 -1
- package/dist/core/ToolManager.d.ts +0 -250
- package/dist/core/ToolManager.d.ts.map +0 -1
- package/dist/core/ToolManager.js +0 -1098
- package/dist/core/ToolManager.js.map +0 -1
- package/dist/core/createAgent.d.ts +0 -35
- package/dist/core/createAgent.d.ts.map +0 -1
- package/dist/core/createAgent.js +0 -36
- package/dist/core/createAgent.js.map +0 -1
- package/dist/core/flow-namespace.d.ts +0 -64
- package/dist/core/flow-namespace.d.ts.map +0 -1
- package/dist/core/flow-namespace.js +0 -179
- package/dist/core/flow-namespace.js.map +0 -1
- package/dist/core/toolGates.d.ts +0 -24
- package/dist/core/toolGates.d.ts.map +0 -1
- package/dist/core/toolGates.js +0 -49
- package/dist/core/toolGates.js.map +0 -1
- package/dist/types/persistence.d.ts +0 -254
- package/dist/types/persistence.d.ts.map +0 -1
- package/dist/types/persistence.js +0 -6
- package/dist/types/persistence.js.map +0 -1
- package/dist/types/prompt-cache.d.ts +0 -15
- package/dist/types/prompt-cache.d.ts.map +0 -1
- package/dist/types/prompt-cache.js +0 -5
- package/dist/types/prompt-cache.js.map +0 -1
- package/dist/types/signals.d.ts +0 -263
- package/dist/types/signals.d.ts.map +0 -1
- package/dist/types/signals.js +0 -10
- package/dist/types/signals.js.map +0 -1
- package/dist/types/template.d.ts +0 -84
- package/dist/types/template.d.ts.map +0 -1
- package/dist/types/template.js +0 -2
- package/dist/types/template.js.map +0 -1
- package/dist/utils/condition.d.ts +0 -63
- package/dist/utils/condition.d.ts.map +0 -1
- package/dist/utils/condition.js +0 -230
- package/dist/utils/condition.js.map +0 -1
- package/dist/utils/event.d.ts +0 -6
- package/dist/utils/event.d.ts.map +0 -1
- package/dist/utils/event.js +0 -17
- package/dist/utils/event.js.map +0 -1
- package/dist/utils/id.d.ts +0 -33
- package/dist/utils/id.d.ts.map +0 -1
- package/dist/utils/id.js +0 -77
- package/dist/utils/id.js.map +0 -1
- package/dist/utils/serialize.d.ts +0 -36
- package/dist/utils/serialize.d.ts.map +0 -1
- package/dist/utils/serialize.js +0 -72
- package/dist/utils/serialize.js.map +0 -1
- package/dist/utils/session.d.ts +0 -124
- package/dist/utils/session.d.ts.map +0 -1
- package/dist/utils/session.js +0 -379
- package/dist/utils/session.js.map +0 -1
- package/docs/concepts/directives.md +0 -369
- package/docs/reference/adapters.md +0 -543
- package/docs/reference/create-agent.md +0 -216
- package/docs/reference/directive.md +0 -242
- package/docs/reference/signals.md +0 -368
- package/examples/02-data-extraction.ts +0 -90
- package/examples/05-branching.ts +0 -140
- package/examples/06-flow-control.ts +0 -103
- package/examples/08-persistence.ts +0 -98
- package/examples/09-signals.ts +0 -144
- package/src/adapters/MemoryAdapter.ts +0 -281
- package/src/adapters/MongoAdapter.ts +0 -341
- package/src/adapters/OpenSearchAdapter.ts +0 -693
- package/src/adapters/PostgreSQLAdapter.ts +0 -487
- package/src/adapters/PrismaAdapter.ts +0 -617
- package/src/adapters/RedisAdapter.ts +0 -439
- package/src/adapters/SQLiteAdapter.ts +0 -496
- package/src/adapters/index.ts +0 -43
- package/src/adapters/sessionRow.ts +0 -57
- package/src/constants/index.ts +0 -2
- package/src/core/AutoChainExecutor.ts +0 -397
- package/src/core/BranchEvaluator.ts +0 -161
- package/src/core/DirectiveChainTracker.ts +0 -144
- package/src/core/Events.ts +0 -164
- package/src/core/Flow.ts +0 -665
- package/src/core/FlowRouter.ts +0 -1540
- package/src/core/PersistenceManager.ts +0 -446
- package/src/core/PromptComposer.ts +0 -448
- package/src/core/PromptSectionCache.ts +0 -125
- package/src/core/ResponseEngine.ts +0 -338
- package/src/core/ResponseGenerationError.ts +0 -53
- package/src/core/ResponseModal.ts +0 -1902
- package/src/core/ResponsePipeline.ts +0 -1404
- package/src/core/SessionFinalizer.ts +0 -108
- package/src/core/SessionManager.ts +0 -372
- package/src/core/SignalCoordinator.ts +0 -263
- package/src/core/SignalEvaluator.ts +0 -404
- package/src/core/SignalProcessor.ts +0 -663
- package/src/core/Step.ts +0 -782
- package/src/core/StepLifecycle.ts +0 -242
- package/src/core/StreamingToolExecutor.ts +0 -609
- package/src/core/ToolLoopExecutor.ts +0 -749
- package/src/core/ToolManager.ts +0 -1379
- package/src/core/createAgent.ts +0 -40
- package/src/core/flow-namespace.ts +0 -227
- package/src/core/toolGates.ts +0 -72
- package/src/types/persistence.ts +0 -303
- package/src/types/prompt-cache.ts +0 -17
- package/src/types/signals.ts +0 -338
- package/src/types/template.ts +0 -98
- package/src/utils/condition.ts +0 -296
- package/src/utils/event.ts +0 -16
- package/src/utils/id.ts +0 -91
- package/src/utils/serialize.ts +0 -86
- package/src/utils/session.ts +0 -501
|
@@ -1,1410 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* ResponseModal handles all response generation logic for the Agent
|
|
3
|
-
* Provides both streaming and non-streaming response generation with unified logic
|
|
4
|
-
*/
|
|
5
|
-
import { ResponseEngine } from "./ResponseEngine.js";
|
|
6
|
-
import { ResponsePipeline } from "./ResponsePipeline.js";
|
|
7
|
-
import { AutoChainExecutor } from "./AutoChainExecutor.js";
|
|
8
|
-
import { StepLifecycle } from "./StepLifecycle.js";
|
|
9
|
-
import { SessionFinalizer } from "./SessionFinalizer.js";
|
|
10
|
-
import { ToolLoopExecutor } from "./ToolLoopExecutor.js";
|
|
11
|
-
import { flow } from "./flow-namespace.js";
|
|
12
|
-
import { SignalCoordinator } from "./SignalCoordinator.js";
|
|
13
|
-
import { ResponseGenerationError } from "./ResponseGenerationError.js";
|
|
14
|
-
import { ProviderError, SessionConflictError } from "../types/errors.js";
|
|
15
|
-
import { cloneDeep, mergeCollected, logger, historyToEvents, completeCurrentFlow, render, userMessage, assistantMessage } from "../utils/index.js";
|
|
16
|
-
import { createTemplateContext } from "../utils/template.js";
|
|
17
|
-
import { StreamingMessageDecoder } from "../utils/streamingMessage.js";
|
|
18
|
-
import { extractEmbeddedJSONObject, isJSONShaped, tryParseJSONResponse } from "../utils/json.js";
|
|
19
|
-
/**
|
|
20
|
-
* ResponseModal class that encapsulates all response generation logic
|
|
21
|
-
* Uses unified approach for both streaming and non-streaming responses
|
|
22
|
-
*/
|
|
23
|
-
export class ResponseModal {
|
|
24
|
-
constructor(agent, options) {
|
|
25
|
-
this.agent = agent;
|
|
26
|
-
this.options = options;
|
|
27
|
-
// Initialize response engine
|
|
28
|
-
this.responseEngine = new ResponseEngine(this.agent.promptSectionCache);
|
|
29
|
-
// Signal pre/post phase orchestration
|
|
30
|
-
this.signalCoordinator = new SignalCoordinator({
|
|
31
|
-
getFlows: () => this.agent.getFlows(),
|
|
32
|
-
signalProcessor: this.agent.signalProcessor,
|
|
33
|
-
});
|
|
34
|
-
// Initialize response pipeline with agent dependencies
|
|
35
|
-
this.responsePipeline = new ResponsePipeline(this.agent.getAgentOptions(), () => this.agent.getFlows(), // Pass a function to get flows dynamically
|
|
36
|
-
this.agent.getFlowRouter(), this.signalCoordinator, this.agent.updateCollectedData.bind(this.agent), () => this.agent.schema);
|
|
37
|
-
// Step prepare/finalize execution, shared by the prepare phase and finalizer
|
|
38
|
-
this.stepLifecycle = new StepLifecycle({
|
|
39
|
-
getFlows: () => this.agent.getFlows(),
|
|
40
|
-
toolManager: this.getToolManager(),
|
|
41
|
-
updateContext: this.agent.updateContext.bind(this.agent),
|
|
42
|
-
updateData: this.agent.updateCollectedData.bind(this.agent),
|
|
43
|
-
});
|
|
44
|
-
// Single owner of end-of-turn finalization (compaction + persistence + sync)
|
|
45
|
-
this.sessionFinalizer = new SessionFinalizer({
|
|
46
|
-
getCompactionOptions: () => this.agent.getCompactionOptions(),
|
|
47
|
-
getPersistenceManager: () => this.agent.getPersistenceManager(),
|
|
48
|
-
getAgentOptions: () => this.agent.getAgentOptions(),
|
|
49
|
-
getCurrentSession: () => this.agent.currentSession,
|
|
50
|
-
setCurrentSession: (session) => { this.agent.currentSession = session; },
|
|
51
|
-
stepLifecycle: this.stepLifecycle,
|
|
52
|
-
enableAutoSave: this.options?.enableAutoSave,
|
|
53
|
-
});
|
|
54
|
-
// Tool follow-up loop (run tools, ask the LLM again) + streaming batch execution
|
|
55
|
-
this.toolLoopExecutor = new ToolLoopExecutor({
|
|
56
|
-
toolManager: this.getToolManager(),
|
|
57
|
-
getAgentOptions: () => this.agent.getAgentOptions(),
|
|
58
|
-
updateContext: this.agent.updateContext.bind(this.agent),
|
|
59
|
-
updateCollectedData: this.agent.updateCollectedData.bind(this.agent),
|
|
60
|
-
updateSessionData: this.agent.getUpdateDataMethod(),
|
|
61
|
-
maxToolLoops: this.options?.maxToolLoops,
|
|
62
|
-
});
|
|
63
|
-
}
|
|
64
|
-
/**
|
|
65
|
-
* Generate a non-streaming response using unified logic
|
|
66
|
-
*/
|
|
67
|
-
async respond(params) {
|
|
68
|
-
// Snapshot the managed session so a failed turn has no in-memory effect:
|
|
69
|
-
// without this, mutations made before the failure leave the live session
|
|
70
|
-
// diverged from persisted state
|
|
71
|
-
const preTurnSession = this.agent.session.current
|
|
72
|
-
? cloneDeep(this.agent.session.current)
|
|
73
|
-
: undefined;
|
|
74
|
-
try {
|
|
75
|
-
// Use unified response preparation and routing
|
|
76
|
-
const responseContext = await this.prepareUnifiedResponseContext(params);
|
|
77
|
-
// Generate response using unified logic
|
|
78
|
-
const result = await this.generateUnifiedResponse(responseContext);
|
|
79
|
-
// Finalize session — the non-streaming turn's single finalize
|
|
80
|
-
await this.sessionFinalizer.finalize(result.session, responseContext.effectiveContext);
|
|
81
|
-
return result;
|
|
82
|
-
}
|
|
83
|
-
catch (error) {
|
|
84
|
-
if (preTurnSession) {
|
|
85
|
-
this.agent.session.syncSession(preTurnSession);
|
|
86
|
-
}
|
|
87
|
-
// Typed library errors carry their own semantics (ProviderError.code,
|
|
88
|
-
// SessionConflictError) — rethrow bare so consumers can branch on
|
|
89
|
-
// them instead of string-matching. Everything else wraps with the
|
|
90
|
-
// original attached as `cause`.
|
|
91
|
-
if (error instanceof ProviderError || error instanceof SessionConflictError) {
|
|
92
|
-
throw error;
|
|
93
|
-
}
|
|
94
|
-
throw new ResponseGenerationError(`[ResponseGenerationError] Response generation failed: ${error instanceof Error ? error.message : String(error)}. ` +
|
|
95
|
-
`Check provider configuration and network connectivity.`, { originalError: error, params, phase: 'response_generation' });
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
/**
|
|
99
|
-
* Generate a streaming response using unified logic
|
|
100
|
-
*/
|
|
101
|
-
async *respondStream(params) {
|
|
102
|
-
// Same failed-turn rollback semantics as respond()
|
|
103
|
-
const preTurnSession = this.agent.session.current
|
|
104
|
-
? cloneDeep(this.agent.session.current)
|
|
105
|
-
: undefined;
|
|
106
|
-
try {
|
|
107
|
-
// Use unified response preparation and routing
|
|
108
|
-
const responseContext = await this.prepareUnifiedResponseContext(params);
|
|
109
|
-
// Generate streaming response using unified logic
|
|
110
|
-
yield* this.generateUnifiedStreamingResponse(responseContext);
|
|
111
|
-
}
|
|
112
|
-
catch (error) {
|
|
113
|
-
if (preTurnSession) {
|
|
114
|
-
this.agent.session.syncSession(preTurnSession);
|
|
115
|
-
}
|
|
116
|
-
// Stream error to caller
|
|
117
|
-
yield {
|
|
118
|
-
delta: "",
|
|
119
|
-
accumulated: "",
|
|
120
|
-
done: true,
|
|
121
|
-
session: params.session || await this.agent.session.getOrCreate(),
|
|
122
|
-
error: new ResponseGenerationError(`Streaming response failed: ${error instanceof Error ? error.message : String(error)}`, { originalError: error, params, phase: 'streaming' }),
|
|
123
|
-
};
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
/**
|
|
127
|
-
* Modern streaming API - simple interface like chat()
|
|
128
|
-
*/
|
|
129
|
-
async *stream(message, options) {
|
|
130
|
-
// Determine which history to use
|
|
131
|
-
let history;
|
|
132
|
-
if (options?.history) {
|
|
133
|
-
// Use provided history for this response only
|
|
134
|
-
history = options.history;
|
|
135
|
-
}
|
|
136
|
-
else {
|
|
137
|
-
// Add user message to session history if provided
|
|
138
|
-
if (message) {
|
|
139
|
-
await this.agent.session.addMessage("user", message);
|
|
140
|
-
}
|
|
141
|
-
history = this.agent.session.getHistory();
|
|
142
|
-
}
|
|
143
|
-
// Get or create session — session.data is the single source of truth,
|
|
144
|
-
// so no agent-side data merge is needed
|
|
145
|
-
const session = await this.agent.session.getOrCreate();
|
|
146
|
-
// Stream response using existing respondStream method
|
|
147
|
-
let finalMessage = "";
|
|
148
|
-
let finalizedSession;
|
|
149
|
-
for await (const chunk of this.respondStream({
|
|
150
|
-
history,
|
|
151
|
-
session,
|
|
152
|
-
contextOverride: options?.contextOverride,
|
|
153
|
-
signal: options?.signal,
|
|
154
|
-
})) {
|
|
155
|
-
// Accumulate the final message and capture finalized session
|
|
156
|
-
if (chunk.done) {
|
|
157
|
-
finalMessage = chunk.accumulated;
|
|
158
|
-
finalizedSession = chunk.session;
|
|
159
|
-
}
|
|
160
|
-
yield chunk;
|
|
161
|
-
}
|
|
162
|
-
// Sync finalized session to agent.session.current (skip in override-history mode)
|
|
163
|
-
// Must happen BEFORE addMessage so the assistant message is added on top of the synced session state
|
|
164
|
-
if (!options?.history && finalizedSession) {
|
|
165
|
-
this.agent.session.syncSession(finalizedSession);
|
|
166
|
-
}
|
|
167
|
-
// Add agent response to session history (only if not using override history)
|
|
168
|
-
if (!options?.history && finalMessage) {
|
|
169
|
-
await this.agent.session.addMessage("assistant", finalMessage);
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
/**
|
|
173
|
-
* Modern non-streaming API - equivalent to chat() but more explicit
|
|
174
|
-
*/
|
|
175
|
-
async generate(message, options) {
|
|
176
|
-
// Determine which history to use
|
|
177
|
-
let history;
|
|
178
|
-
if (options?.history) {
|
|
179
|
-
// Use provided history for this response only
|
|
180
|
-
history = options.history;
|
|
181
|
-
}
|
|
182
|
-
else {
|
|
183
|
-
// Add user message to session history if provided
|
|
184
|
-
if (message) {
|
|
185
|
-
await this.agent.session.addMessage("user", message);
|
|
186
|
-
}
|
|
187
|
-
history = this.agent.session.getHistory();
|
|
188
|
-
}
|
|
189
|
-
// Get or create session — session.data is the single source of truth,
|
|
190
|
-
// so no agent-side data merge is needed
|
|
191
|
-
const session = await this.agent.session.getOrCreate();
|
|
192
|
-
// Generate response using existing respond method
|
|
193
|
-
const result = await this.respond({
|
|
194
|
-
history,
|
|
195
|
-
session,
|
|
196
|
-
contextOverride: options?.contextOverride,
|
|
197
|
-
signal: options?.signal,
|
|
198
|
-
});
|
|
199
|
-
// Sync finalized session to agent.session.current (skip in override-history mode)
|
|
200
|
-
// Must happen BEFORE addMessage so the assistant message is added on top of the synced session state
|
|
201
|
-
if (!options?.history && result.session) {
|
|
202
|
-
this.agent.session.syncSession(result.session);
|
|
203
|
-
}
|
|
204
|
-
// Add agent response to session history (only if not using override history)
|
|
205
|
-
if (!options?.history) {
|
|
206
|
-
await this.agent.session.addMessage("assistant", result.message);
|
|
207
|
-
}
|
|
208
|
-
// Ensure the result includes the current session
|
|
209
|
-
return {
|
|
210
|
-
...result,
|
|
211
|
-
session: result.session || this.agent.session.current,
|
|
212
|
-
};
|
|
213
|
-
}
|
|
214
|
-
/**
|
|
215
|
-
* Get the response engine instance
|
|
216
|
-
* @internal
|
|
217
|
-
*/
|
|
218
|
-
getResponseEngine() {
|
|
219
|
-
return this.responseEngine;
|
|
220
|
-
}
|
|
221
|
-
/**
|
|
222
|
-
* Get the response pipeline instance
|
|
223
|
-
* @internal
|
|
224
|
-
*/
|
|
225
|
-
getResponsePipeline() {
|
|
226
|
-
return this.responsePipeline;
|
|
227
|
-
}
|
|
228
|
-
/**
|
|
229
|
-
* Get the ToolManager instance from the agent.
|
|
230
|
-
* @private
|
|
231
|
-
*/
|
|
232
|
-
getToolManager() {
|
|
233
|
-
return this.agent.tool;
|
|
234
|
-
}
|
|
235
|
-
/**
|
|
236
|
-
* Recover a structured payload from a schema-mandated response the provider
|
|
237
|
-
* could not parse. Raw protocol fragments must never surface as the
|
|
238
|
-
* user-visible reply. Three shapes arrive here:
|
|
239
|
-
* - a truncated or fence-wrapped envelope → one repair-parse;
|
|
240
|
-
* - conversational prose FOLLOWED BY the envelope (the model answered
|
|
241
|
-
* twice — the observed WhatsApp leak) → recover the embedded envelope,
|
|
242
|
-
* whose "message" field is the complete intended reply;
|
|
243
|
-
* - plain prose with nothing recoverable → `undefined`; the caller passes
|
|
244
|
-
* it through untouched. (An envelope truncated mid-stream after prose
|
|
245
|
-
* also lands here: the prose is user-worthy and the fragment carries
|
|
246
|
-
* nothing recoverable.)
|
|
247
|
-
* An unrecoverable JSON-SHAPED fragment throws so the turn fails LOUDLY
|
|
248
|
-
* and the caller's rollback/retry path engages instead of leaking
|
|
249
|
-
* `{"message": "…` to an end user.
|
|
250
|
-
*/
|
|
251
|
-
salvageStructuredOutput(raw, surface) {
|
|
252
|
-
const salvaged = tryParseJSONResponse(raw);
|
|
253
|
-
if (salvaged && typeof salvaged.message === "string") {
|
|
254
|
-
logger.warn(`[ResponseModal] Salvaged malformed structured output from ${surface} via JSON repair parse.`);
|
|
255
|
-
return { ...salvaged, message: salvaged.message };
|
|
256
|
-
}
|
|
257
|
-
const embedded = extractEmbeddedJSONObject(raw);
|
|
258
|
-
if (embedded && typeof embedded.message === "string") {
|
|
259
|
-
logger.warn(`[ResponseModal] Salvaged structured output embedded after prose from ${surface}.`);
|
|
260
|
-
return { ...embedded, message: embedded.message };
|
|
261
|
-
}
|
|
262
|
-
if (isJSONShaped(raw)) {
|
|
263
|
-
throw ResponseGenerationError.fromError(new Error("Model returned a schema-mandated response that could not be parsed as JSON. " +
|
|
264
|
-
`The ${surface} was failed instead of delivering raw protocol output to the user.`), 'structured_output_malformed', { responseSchemaName: 'response_output' });
|
|
265
|
-
}
|
|
266
|
-
return undefined;
|
|
267
|
-
}
|
|
268
|
-
/**
|
|
269
|
-
* Tool-emitted directives (ctx.dispatch / `{directive}` returns): state
|
|
270
|
-
* writes apply now; control flow queues for the next turn's
|
|
271
|
-
* pendingDirective applier (same deferred semantics as dispatch()).
|
|
272
|
-
*/
|
|
273
|
-
async applyToolEmittedDirectives(session, d) {
|
|
274
|
-
if (d.dataUpdate) {
|
|
275
|
-
session = mergeCollected(session, d.dataUpdate);
|
|
276
|
-
}
|
|
277
|
-
if (d.contextUpdate) {
|
|
278
|
-
await this.agent.updateContext(d.contextUpdate);
|
|
279
|
-
}
|
|
280
|
-
const control = { ...d };
|
|
281
|
-
delete control.dataUpdate;
|
|
282
|
-
delete control.contextUpdate;
|
|
283
|
-
if (Object.keys(control).length > 0) {
|
|
284
|
-
flow.queuePending(session, control);
|
|
285
|
-
}
|
|
286
|
-
return session;
|
|
287
|
-
}
|
|
288
|
-
/**
|
|
289
|
-
* Collect scoped instructions from agent, flow, and step into a ScopedInstructions value.
|
|
290
|
-
* @private
|
|
291
|
-
*/
|
|
292
|
-
collectScopedInstructions(flow, step) {
|
|
293
|
-
return {
|
|
294
|
-
global: this.agent.instructions,
|
|
295
|
-
flow: flow ? { flowTitle: flow.title, items: flow.instructions } : undefined,
|
|
296
|
-
step: step ? { stepId: step.id, items: step.getInstructions() } : undefined,
|
|
297
|
-
};
|
|
298
|
-
}
|
|
299
|
-
// UNIFIED RESPONSE LOGIC - Consolidates common logic between streaming and non-streaming
|
|
300
|
-
// ============================================================================
|
|
301
|
-
/**
|
|
302
|
-
* Unified response preparation - handles context setup, session management, and routing
|
|
303
|
-
* This consolidates common logic between streaming and non-streaming responses
|
|
304
|
-
* @private
|
|
305
|
-
*/
|
|
306
|
-
async prepareUnifiedResponseContext(params) {
|
|
307
|
-
try {
|
|
308
|
-
const { history: simpleHistory, contextOverride, signal, message: turnMessage, allowedFlows } = params;
|
|
309
|
-
// Validate input parameters
|
|
310
|
-
if (!simpleHistory) {
|
|
311
|
-
throw new ResponseGenerationError('[ResponseGenerationError] Missing history: history is required for response generation. ' +
|
|
312
|
-
'Pass a valid history array (or pass `message` alongside an existing history base).', { params, phase: 'validation' });
|
|
313
|
-
}
|
|
314
|
-
// `message` is the user turn: appended to what the model sees this
|
|
315
|
-
// turn AND recorded on the returned session's history.
|
|
316
|
-
const history = turnMessage
|
|
317
|
-
? [...simpleHistory, userMessage(turnMessage)]
|
|
318
|
-
: simpleHistory;
|
|
319
|
-
// Convert HistoryItem[] to Event[] for internal processing
|
|
320
|
-
const historyEvents = historyToEvents(history);
|
|
321
|
-
// Use ResponsePipeline for context and session preparation; context
|
|
322
|
-
// and session are passed explicitly — the pipeline holds no state
|
|
323
|
-
let responseContext;
|
|
324
|
-
try {
|
|
325
|
-
responseContext = await this.responsePipeline.prepareResponseContext({
|
|
326
|
-
contextOverride,
|
|
327
|
-
session: params.session ? cloneDeep(params.session) : undefined,
|
|
328
|
-
currentContext: await this.agent.getContext(),
|
|
329
|
-
currentSession: this.agent.currentSession,
|
|
330
|
-
});
|
|
331
|
-
}
|
|
332
|
-
catch (error) {
|
|
333
|
-
throw ResponseGenerationError.fromError(error, 'pipeline_context_preparation', params);
|
|
334
|
-
}
|
|
335
|
-
const { effectiveContext, contextAfterHook } = responseContext;
|
|
336
|
-
let session = responseContext.session;
|
|
337
|
-
// Sync the beforeRespond hook's context result back to the agent
|
|
338
|
-
if (contextAfterHook !== undefined) {
|
|
339
|
-
try {
|
|
340
|
-
await this.agent.updateContext(contextAfterHook);
|
|
341
|
-
}
|
|
342
|
-
catch (error) {
|
|
343
|
-
throw ResponseGenerationError.fromError(error, 'context_update_from_pipeline', params, { contextAfterHook });
|
|
344
|
-
}
|
|
345
|
-
}
|
|
346
|
-
// Apply data staged before any session existed (initialData,
|
|
347
|
-
// pre-session updateCollectedData calls). Reading the live session's
|
|
348
|
-
// data here would leak state across sessions when an explicit
|
|
349
|
-
// session is passed, so only the staging buffer is merged.
|
|
350
|
-
const stagedData = this.agent.consumePendingData();
|
|
351
|
-
if (Object.keys(stagedData).length > 0) {
|
|
352
|
-
try {
|
|
353
|
-
session = mergeCollected(session, stagedData);
|
|
354
|
-
logger.debug("[ResponseModal] Merged staged agent data into session:", stagedData);
|
|
355
|
-
}
|
|
356
|
-
catch (error) {
|
|
357
|
-
throw ResponseGenerationError.fromError(error, 'data_merging', params, { stagedData });
|
|
358
|
-
}
|
|
359
|
-
}
|
|
360
|
-
// Record the user turn on the session's own history so the returned
|
|
361
|
-
// session carries the full exchange (respond owns session.history
|
|
362
|
-
// when `message` is used).
|
|
363
|
-
if (turnMessage) {
|
|
364
|
-
session.history = [...(session.history ?? []), userMessage(turnMessage)];
|
|
365
|
-
}
|
|
366
|
-
// PHASE 1: PREPARE - Execute prepare function if current step has one
|
|
367
|
-
try {
|
|
368
|
-
const prepareDirective = await this.stepLifecycle.runPrepare(session, effectiveContext);
|
|
369
|
-
// Queue the control-flow directive for THIS turn: routing
|
|
370
|
-
// (handleRoutingAndStepSelection) consumes session.pendingDirective
|
|
371
|
-
// before deciding flow/step, so a prepare-phase goTo/goToStep/
|
|
372
|
-
// reset steers the current turn.
|
|
373
|
-
if (prepareDirective) {
|
|
374
|
-
flow.queuePending(session, prepareDirective);
|
|
375
|
-
}
|
|
376
|
-
}
|
|
377
|
-
catch (error) {
|
|
378
|
-
throw ResponseGenerationError.fromError(error, 'step_preparation', params, { session, effectiveContext });
|
|
379
|
-
}
|
|
380
|
-
// PHASE 2: ROUTING + STEP SELECTION - Determine which flow and step to use
|
|
381
|
-
// Performs pre-extraction and step selection
|
|
382
|
-
let routingResult;
|
|
383
|
-
try {
|
|
384
|
-
routingResult = await this.responsePipeline.routeAndSelectStep({
|
|
385
|
-
session,
|
|
386
|
-
history: historyEvents,
|
|
387
|
-
context: effectiveContext,
|
|
388
|
-
signal,
|
|
389
|
-
allowedFlows,
|
|
390
|
-
});
|
|
391
|
-
}
|
|
392
|
-
catch (error) {
|
|
393
|
-
throw ResponseGenerationError.fromError(error, 'routing_and_step_selection', params, { session, effectiveContext });
|
|
394
|
-
}
|
|
395
|
-
return {
|
|
396
|
-
effectiveContext,
|
|
397
|
-
session: routingResult.session,
|
|
398
|
-
history,
|
|
399
|
-
turnMessage,
|
|
400
|
-
selectedFlow: routingResult.selectedFlow,
|
|
401
|
-
selectedStep: routingResult.selectedStep,
|
|
402
|
-
responseDirectives: routingResult.responseDirectives,
|
|
403
|
-
isFlowComplete: routingResult.isFlowComplete,
|
|
404
|
-
signal,
|
|
405
|
-
signalFirings: routingResult.signalFirings,
|
|
406
|
-
signalPreDirective: routingResult.signalPreDirective,
|
|
407
|
-
signalHalted: routingResult.signalHalted,
|
|
408
|
-
signalHaltReply: routingResult.signalHaltReply,
|
|
409
|
-
endedFlows: routingResult.endedFlows,
|
|
410
|
-
};
|
|
411
|
-
}
|
|
412
|
-
catch (error) {
|
|
413
|
-
// Re-throw ResponseGenerationError as-is, wrap others
|
|
414
|
-
if (ResponseGenerationError.isResponseGenerationError(error)) {
|
|
415
|
-
throw error;
|
|
416
|
-
}
|
|
417
|
-
throw ResponseGenerationError.fromError(error, 'preparation', params);
|
|
418
|
-
}
|
|
419
|
-
}
|
|
420
|
-
/**
|
|
421
|
-
* Plan a turn: run signal-halt detection, the auto-chain walk, and flow/step
|
|
422
|
-
* selection, collapsing them into a single {@link TurnOutcome}. This is the
|
|
423
|
-
* shared decision spine for both the streaming and non-streaming paths — the
|
|
424
|
-
* only logic that genuinely differs between them is how each *renders* the
|
|
425
|
-
* outcome (await a value vs. yield chunks) and the leaf provider primitive it
|
|
426
|
-
* uses. Centralizing the decision here is what keeps the two paths from
|
|
427
|
-
* drifting (the class of bug behind the 2.4.x retry/empty fixes).
|
|
428
|
-
*
|
|
429
|
-
* The returned `session` reflects any auto-chain mutation; `signalFirings`
|
|
430
|
-
* is seeded with the pre-signal phase firings and is the live accumulator the
|
|
431
|
-
* post-phase tail appends to.
|
|
432
|
-
* @private
|
|
433
|
-
*/
|
|
434
|
-
async planTurn(responseContext) {
|
|
435
|
-
const { effectiveContext, history, selectedFlow, selectedStep, responseDirectives, isFlowComplete, signal, signalFirings: preSignalFirings, signalPreDirective, signalHalted, signalHaltReply, } = responseContext;
|
|
436
|
-
let session = responseContext.session;
|
|
437
|
-
// Accumulator for signal firings across both phases (fire order)
|
|
438
|
-
const signalFirings = [...(preSignalFirings || [])];
|
|
439
|
-
// Convert HistoryItem[] to Event[] for internal processing
|
|
440
|
-
const historyEvents = historyToEvents(history);
|
|
441
|
-
const base = { effectiveContext, history, historyEvents, signal, signalFirings };
|
|
442
|
-
// ── SIGNAL HALT (Requirement 8.2) ─────────────────────────────────────
|
|
443
|
-
// Pre-signal phase emitted halt → skip LLM call entirely. The post-signal
|
|
444
|
-
// phase still runs (it sees the complete turn context).
|
|
445
|
-
if (signalHalted) {
|
|
446
|
-
const haltMessage = signalHaltReply || '';
|
|
447
|
-
return {
|
|
448
|
-
...base, session,
|
|
449
|
-
outcome: { kind: 'halt', message: haltMessage, stoppedReason: haltMessage ? 'reply' : 'halt', runPostPhase: true },
|
|
450
|
-
};
|
|
451
|
-
}
|
|
452
|
-
if (selectedFlow && !isFlowComplete) {
|
|
453
|
-
// AUTO-CHAIN: Walk consecutive auto-steps before any LLM work. If the
|
|
454
|
-
// current step is auto, the executor advances through it (and any
|
|
455
|
-
// subsequent auto-steps) until an interactive step or terminal condition.
|
|
456
|
-
let resolvedStep = selectedStep;
|
|
457
|
-
const currentStepInstance = session.currentStep
|
|
458
|
-
? selectedFlow.getStep(session.currentStep.id)
|
|
459
|
-
: selectedStep;
|
|
460
|
-
if (currentStepInstance?.auto) {
|
|
461
|
-
const autoChainExecutor = new AutoChainExecutor({
|
|
462
|
-
maxAutoStepsPerTurn: this.agent.maxAutoStepsPerTurn,
|
|
463
|
-
});
|
|
464
|
-
const autoResult = await autoChainExecutor.run({
|
|
465
|
-
session,
|
|
466
|
-
context: effectiveContext,
|
|
467
|
-
flow: selectedFlow,
|
|
468
|
-
});
|
|
469
|
-
session = autoResult.session;
|
|
470
|
-
// Halt: emit the verbatim reply, no LLM call. Unlike signal halt,
|
|
471
|
-
// the auto-chain halt is a hard short-circuit that does NOT run the
|
|
472
|
-
// post-signal phase (preserved across both paths).
|
|
473
|
-
if (autoResult.stoppedReason === 'halt') {
|
|
474
|
-
return {
|
|
475
|
-
...base, session,
|
|
476
|
-
outcome: { kind: 'halt', message: autoResult.mergedDirective?.reply || '', stoppedReason: 'halt', runPostPhase: false },
|
|
477
|
-
};
|
|
478
|
-
}
|
|
479
|
-
// Flow completion or cross-flow redirect from auto-chain: the chain
|
|
480
|
-
// ended without resolving to an interactive step (last_step: no
|
|
481
|
-
// successor; completed: explicit complete; goto: cross-flow redirect).
|
|
482
|
-
if (autoResult.stoppedReason === 'last_step' || autoResult.stoppedReason === 'completed' || autoResult.stoppedReason === 'goto') {
|
|
483
|
-
logger.debug(`[ResponseModal] Auto-chain ended with ${autoResult.stoppedReason}`);
|
|
484
|
-
return {
|
|
485
|
-
...base, session,
|
|
486
|
-
outcome: { kind: 'flowComplete', selectedFlow, stoppedReason: autoResult.stoppedReason },
|
|
487
|
-
};
|
|
488
|
-
}
|
|
489
|
-
// Normal case: auto-chain resolved to an interactive step.
|
|
490
|
-
resolvedStep = autoResult.resolvedStep;
|
|
491
|
-
}
|
|
492
|
-
return {
|
|
493
|
-
...base, session,
|
|
494
|
-
outcome: { kind: 'flowStep', selectedFlow, step: resolvedStep, responseDirectives, signalPreDirective },
|
|
495
|
-
};
|
|
496
|
-
}
|
|
497
|
-
if (isFlowComplete && selectedFlow) {
|
|
498
|
-
// Flow completion path: pure state transition, no LLM call. The reason
|
|
499
|
-
// is 'last_step' (implicit terminus — no successor or all skipped).
|
|
500
|
-
logger.debug(`[ResponseModal] Releasing session to idle for completed flow: ${selectedFlow.title}`);
|
|
501
|
-
return {
|
|
502
|
-
...base, session,
|
|
503
|
-
outcome: { kind: 'flowComplete', selectedFlow, stoppedReason: 'last_step' },
|
|
504
|
-
};
|
|
505
|
-
}
|
|
506
|
-
// Fallback: no flows defined, generate a simple response.
|
|
507
|
-
return { ...base, session, outcome: { kind: 'fallback' } };
|
|
508
|
-
}
|
|
509
|
-
/**
|
|
510
|
-
* The shared post-signal phase tail (Requirement 9.1–9.4). Runs after the
|
|
511
|
-
* turn's message is known and before persistence, so post-phase signals see
|
|
512
|
-
* the complete turn result (assistant message, collected data, tool results)
|
|
513
|
-
* and can override the reply or wire a pendingDirective.
|
|
514
|
-
*
|
|
515
|
-
* `runPostPhase` is false only for the auto-chain halt short-circuit, which
|
|
516
|
-
* deliberately bypasses the post-phase in both paths; that branch still
|
|
517
|
-
* surfaces any pre-phase firings via `triggeredSignals`.
|
|
518
|
-
* @private
|
|
519
|
-
*/
|
|
520
|
-
async applyTurnPostPhase(params) {
|
|
521
|
-
const { session, context, historyEvents, message, signalFirings, runPostPhase } = params;
|
|
522
|
-
if (!runPostPhase) {
|
|
523
|
-
return {
|
|
524
|
-
session, message, replyOverridden: false,
|
|
525
|
-
triggeredSignals: signalFirings.length > 0 ? signalFirings : undefined,
|
|
526
|
-
};
|
|
527
|
-
}
|
|
528
|
-
const post = await this.signalCoordinator.applyPostPhase({ session, context, historyEvents, message });
|
|
529
|
-
signalFirings.push(...post.firings);
|
|
530
|
-
return {
|
|
531
|
-
session: post.session,
|
|
532
|
-
message: post.message,
|
|
533
|
-
replyOverridden: post.replyOverridden ?? false,
|
|
534
|
-
triggeredSignals: signalFirings.length > 0 ? signalFirings : undefined,
|
|
535
|
-
};
|
|
536
|
-
}
|
|
537
|
-
/**
|
|
538
|
-
* Unified response generation for non-streaming responses.
|
|
539
|
-
* Renders the shared {@link planTurn} outcome by awaiting the leaf primitive
|
|
540
|
-
* and running the shared post-phase tail; respond() owns the single finalize.
|
|
541
|
-
* @private
|
|
542
|
-
*/
|
|
543
|
-
async generateUnifiedResponse(responseContext) {
|
|
544
|
-
const plan = await this.planTurn(responseContext);
|
|
545
|
-
const { effectiveContext, history, historyEvents, signal, signalFirings } = plan;
|
|
546
|
-
let session = plan.session;
|
|
547
|
-
let message = '';
|
|
548
|
-
let toolCalls = undefined;
|
|
549
|
-
let executedSteps = [];
|
|
550
|
-
let stoppedReason;
|
|
551
|
-
let isFlowComplete = false;
|
|
552
|
-
let appliedInstructions;
|
|
553
|
-
let runPostPhase = true;
|
|
554
|
-
let tokensUsed;
|
|
555
|
-
const endedFlows = [...(responseContext.endedFlows ?? [])];
|
|
556
|
-
switch (plan.outcome.kind) {
|
|
557
|
-
case 'halt': {
|
|
558
|
-
message = plan.outcome.message;
|
|
559
|
-
stoppedReason = plan.outcome.stoppedReason;
|
|
560
|
-
runPostPhase = plan.outcome.runPostPhase;
|
|
561
|
-
break;
|
|
562
|
-
}
|
|
563
|
-
case 'flowComplete': {
|
|
564
|
-
session = await this.applyFlowCompletion({
|
|
565
|
-
selectedFlow: plan.outcome.selectedFlow,
|
|
566
|
-
session,
|
|
567
|
-
context: effectiveContext,
|
|
568
|
-
history,
|
|
569
|
-
});
|
|
570
|
-
isFlowComplete = true;
|
|
571
|
-
stoppedReason = plan.outcome.stoppedReason;
|
|
572
|
-
endedFlows.push({
|
|
573
|
-
flowId: plan.outcome.selectedFlow.id,
|
|
574
|
-
title: plan.outcome.selectedFlow.title,
|
|
575
|
-
reason: plan.outcome.stoppedReason,
|
|
576
|
-
});
|
|
577
|
-
break;
|
|
578
|
-
}
|
|
579
|
-
case 'flowStep': {
|
|
580
|
-
const result = await this.processFlowResponse({
|
|
581
|
-
selectedFlow: plan.outcome.selectedFlow,
|
|
582
|
-
selectedStep: plan.outcome.step,
|
|
583
|
-
responseDirectives: plan.outcome.responseDirectives,
|
|
584
|
-
session,
|
|
585
|
-
history,
|
|
586
|
-
context: effectiveContext,
|
|
587
|
-
historyEvents,
|
|
588
|
-
signal,
|
|
589
|
-
// Propagate signal pre-directive's appendPrompt for this turn's LLM call (Requirement 8.4)
|
|
590
|
-
transientAppendage: plan.outcome.signalPreDirective?.appendPrompt,
|
|
591
|
-
// Merge signal pre-directive (halt/reply/injectTools) into the pre-LLM bus
|
|
592
|
-
mergedPreDirective: plan.outcome.signalPreDirective,
|
|
593
|
-
});
|
|
594
|
-
message = result.message;
|
|
595
|
-
toolCalls = result.toolCalls;
|
|
596
|
-
session = result.session;
|
|
597
|
-
appliedInstructions = result.appliedInstructions;
|
|
598
|
-
tokensUsed = result.tokensUsed;
|
|
599
|
-
if (plan.outcome.step) {
|
|
600
|
-
executedSteps = [{ id: plan.outcome.step.id, flowId: plan.outcome.selectedFlow.id }];
|
|
601
|
-
}
|
|
602
|
-
// Use stoppedReason from processFlowResponse if set (halt/reply),
|
|
603
|
-
// otherwise default to 'needs_input' for normal LLM responses.
|
|
604
|
-
stoppedReason = result.stoppedReason || 'needs_input';
|
|
605
|
-
break;
|
|
606
|
-
}
|
|
607
|
-
case 'fallback': {
|
|
608
|
-
const fallbackResult = await this.generateFallbackResponse({
|
|
609
|
-
history,
|
|
610
|
-
context: effectiveContext,
|
|
611
|
-
session,
|
|
612
|
-
signal,
|
|
613
|
-
});
|
|
614
|
-
message = fallbackResult.message;
|
|
615
|
-
appliedInstructions = fallbackResult.appliedInstructions;
|
|
616
|
-
break;
|
|
617
|
-
}
|
|
618
|
-
}
|
|
619
|
-
const tail = await this.applyTurnPostPhase({
|
|
620
|
-
session, context: effectiveContext, historyEvents, message, signalFirings, runPostPhase,
|
|
621
|
-
});
|
|
622
|
-
// History ownership: with params.message the returned session carries
|
|
623
|
-
// the full exchange — the user turn was recorded pre-routing, the
|
|
624
|
-
// assistant tail lands here (post-phase, so overridden replies are the
|
|
625
|
-
// ones recorded). Empty tails are skipped.
|
|
626
|
-
if (responseContext.turnMessage && tail.message) {
|
|
627
|
-
tail.session.history = [...(tail.session.history ?? []), assistantMessage(tail.message)];
|
|
628
|
-
}
|
|
629
|
-
return {
|
|
630
|
-
message: tail.message,
|
|
631
|
-
session: tail.session,
|
|
632
|
-
toolCalls,
|
|
633
|
-
isFlowComplete,
|
|
634
|
-
executedSteps,
|
|
635
|
-
stoppedReason,
|
|
636
|
-
appliedInstructions,
|
|
637
|
-
triggeredSignals: tail.triggeredSignals,
|
|
638
|
-
...(tokensUsed !== undefined ? { metadata: { tokensUsed } } : {}),
|
|
639
|
-
...(endedFlows.length > 0 ? { endedFlows } : {}),
|
|
640
|
-
};
|
|
641
|
-
}
|
|
642
|
-
/**
|
|
643
|
-
* Process flow response with unified tool execution and data collection
|
|
644
|
-
* @private
|
|
645
|
-
*/
|
|
646
|
-
async processFlowResponse(params) {
|
|
647
|
-
const { selectedFlow, selectedStep, responseDirectives, history, context, historyEvents, signal, transientAppendage, mergedPreDirective } = params;
|
|
648
|
-
let session = params.session;
|
|
649
|
-
// Resolve the step to render (branches win over linear chain; requires enforced)
|
|
650
|
-
const stepResolution = await this.responsePipeline.resolveRenderStep({
|
|
651
|
-
selectedFlow,
|
|
652
|
-
selectedStep,
|
|
653
|
-
session,
|
|
654
|
-
context,
|
|
655
|
-
});
|
|
656
|
-
if (stepResolution.flowTransition) {
|
|
657
|
-
// Flow transition or completion — no local step to render
|
|
658
|
-
// Return empty message with updated session; caller handles flow transition
|
|
659
|
-
return { message: '', session: stepResolution.session };
|
|
660
|
-
}
|
|
661
|
-
const nextStep = stepResolution.nextStep;
|
|
662
|
-
session = stepResolution.session;
|
|
663
|
-
// Build response schema for this flow (with collect fields from step)
|
|
664
|
-
const responseSchema = this.responseEngine.responseSchemaForFlow(selectedFlow, nextStep, this.agent.schema);
|
|
665
|
-
// ── HALT SHORT-CIRCUIT (Requirement 2.5, 2.6, 2.7) ──────────────────────
|
|
666
|
-
// After pre-LLM emissions are merged, if `halt: true` then skip the LLM
|
|
667
|
-
// call entirely. The behavior depends on whether `reply` is also set.
|
|
668
|
-
if (mergedPreDirective?.halt) {
|
|
669
|
-
if (mergedPreDirective.reply) {
|
|
670
|
-
// halt + reply: emit the reply as the assistant message
|
|
671
|
-
logger.debug(`[ResponseModal] Halt with reply — skipping LLM call for step ${nextStep.id}`);
|
|
672
|
-
return { message: mergedPreDirective.reply, session, stoppedReason: 'reply' };
|
|
673
|
-
}
|
|
674
|
-
else {
|
|
675
|
-
// halt without reply: emit empty assistant content
|
|
676
|
-
logger.debug(`[ResponseModal] Halt without reply — skipping LLM call for step ${nextStep.id}`);
|
|
677
|
-
return { message: '', session, stoppedReason: 'halt' };
|
|
678
|
-
}
|
|
679
|
-
}
|
|
680
|
-
// ── STEP.REPLY SHORT-CIRCUIT (Requirement 25.1–25.7, 17.9) ──────────────
|
|
681
|
-
// A step with `reply` set emits a verbatim template response without LLM.
|
|
682
|
-
// onEnter and prepare have already fired normally at this point.
|
|
683
|
-
// If prepare returned a Directive with `reply`, that overrides
|
|
684
|
-
// the step-declared reply (last-emission-wins per Algorithm 4).
|
|
685
|
-
if (nextStep.reply != null) {
|
|
686
|
-
// Determine the effective reply: prepare-emitted reply wins over step-declared
|
|
687
|
-
const effectiveReply = mergedPreDirective?.reply ?? await render(nextStep.reply, createTemplateContext({ data: session.data || {}, context, session }));
|
|
688
|
-
logger.debug(`[ResponseModal] Step.reply — skipping LLM call for step ${nextStep.id}`);
|
|
689
|
-
return { message: effectiveReply, session, stoppedReason: 'reply' };
|
|
690
|
-
}
|
|
691
|
-
// Transient appendage: per-turn slot from Directive.appendPrompt.
|
|
692
|
-
// Fresh each turn, never cached, never persisted.
|
|
693
|
-
// Wrapped in try/finally to ensure cleanup even on abnormal termination.
|
|
694
|
-
let turnTransientAppendage = transientAppendage;
|
|
695
|
-
try {
|
|
696
|
-
// Build response prompt
|
|
697
|
-
const { prompt: responsePrompt, appliedInstructions } = await this.responseEngine.buildResponsePrompt({
|
|
698
|
-
flow: selectedFlow,
|
|
699
|
-
currentStep: nextStep,
|
|
700
|
-
rules: [],
|
|
701
|
-
prohibitions: [],
|
|
702
|
-
directives: responseDirectives,
|
|
703
|
-
history: historyEvents,
|
|
704
|
-
agentOptions: this.agent.getAgentOptions(),
|
|
705
|
-
instructions: this.collectScopedInstructions(selectedFlow, nextStep),
|
|
706
|
-
combinedTerms: this.agent.getTerms(),
|
|
707
|
-
context,
|
|
708
|
-
session,
|
|
709
|
-
agentSchema: this.agent.schema,
|
|
710
|
-
transientAppendage: turnTransientAppendage,
|
|
711
|
-
});
|
|
712
|
-
// Collect available tools for AI
|
|
713
|
-
const availableTools = this.collectAvailableTools(selectedFlow, nextStep);
|
|
714
|
-
// Generate message using AI provider
|
|
715
|
-
const agentOptions = this.agent.getAgentOptions();
|
|
716
|
-
const result = await agentOptions.provider.generateMessage({
|
|
717
|
-
prompt: responsePrompt,
|
|
718
|
-
history, // Use HistoryItem[] for AI provider
|
|
719
|
-
context,
|
|
720
|
-
tools: availableTools,
|
|
721
|
-
signal,
|
|
722
|
-
parameters: responseSchema ? { jsonSchema: responseSchema, schemaName: "response_output" } : undefined,
|
|
723
|
-
});
|
|
724
|
-
let structuredData = result.structured;
|
|
725
|
-
let message = structuredData?.message || result.message;
|
|
726
|
-
const tokensUsed = result.metadata?.tokensUsed;
|
|
727
|
-
// A schema was requested but the provider failed to parse the model's
|
|
728
|
-
// JSON (truncated output, fence-wrapped fragments). Raw protocol
|
|
729
|
-
// fragments must never surface as the user-visible reply: attempt one
|
|
730
|
-
// repair-parse, and if that fails fail the turn LOUDLY so the caller's
|
|
731
|
-
// rollback/retry path engages instead of leaking `{"message": "…` to
|
|
732
|
-
// an end user. Plain prose (not JSON-shaped at all) still passes
|
|
733
|
-
// through — it is not a protocol fragment.
|
|
734
|
-
if (!structuredData && responseSchema && message) {
|
|
735
|
-
const salvaged = this.salvageStructuredOutput(message, "turn");
|
|
736
|
-
if (salvaged) {
|
|
737
|
-
structuredData = salvaged;
|
|
738
|
-
message = salvaged.message;
|
|
739
|
-
}
|
|
740
|
-
}
|
|
741
|
-
const effectiveResult = structuredData ? { ...result, structured: structuredData } : result;
|
|
742
|
-
let toolCalls = structuredData?.toolCalls;
|
|
743
|
-
// Execute tools with unified loop handling
|
|
744
|
-
const toolResult = await this.toolLoopExecutor.runLoop({
|
|
745
|
-
toolCalls,
|
|
746
|
-
context,
|
|
747
|
-
session,
|
|
748
|
-
history,
|
|
749
|
-
selectedFlow,
|
|
750
|
-
responsePrompt,
|
|
751
|
-
availableTools,
|
|
752
|
-
responseSchema,
|
|
753
|
-
signal,
|
|
754
|
-
});
|
|
755
|
-
session = toolResult.session;
|
|
756
|
-
toolCalls = toolResult.finalToolCalls;
|
|
757
|
-
let toolStructured = toolResult.structured;
|
|
758
|
-
if (toolResult.finalMessage) {
|
|
759
|
-
// The tool loop's follow-up calls carry the SAME response schema,
|
|
760
|
-
// and their message replaces the one the guard above already
|
|
761
|
-
// cleared — so an envelope produced after the tools ran reaches
|
|
762
|
-
// the user through a path that guard never sees. (Observed
|
|
763
|
-
// 2026-09-11: a catalog lookup answered, then the closing call
|
|
764
|
-
// returned `{"message": "…"}` raw to a WhatsApp customer.)
|
|
765
|
-
const salvaged = responseSchema
|
|
766
|
-
? this.salvageStructuredOutput(toolResult.finalMessage, "turn")
|
|
767
|
-
: undefined;
|
|
768
|
-
message = salvaged?.message ?? toolResult.finalMessage;
|
|
769
|
-
if (salvaged)
|
|
770
|
-
toolStructured = salvaged;
|
|
771
|
-
}
|
|
772
|
-
// Tool-emitted directives (ctx.dispatch / `{directive}` returns):
|
|
773
|
-
// state writes apply now; control flow queues for the next turn's
|
|
774
|
-
// pendingDirective applier (same deferred semantics as dispatch()).
|
|
775
|
-
if (toolResult.directives) {
|
|
776
|
-
session = await this.applyToolEmittedDirectives(session, toolResult.directives);
|
|
777
|
-
}
|
|
778
|
-
// Collect data from response
|
|
779
|
-
// Use follow-up structured data from tool loop when available, fall back to original result
|
|
780
|
-
const dataSource = toolStructured
|
|
781
|
-
? { structured: toolStructured }
|
|
782
|
-
: effectiveResult;
|
|
783
|
-
session = await this.collectDataFromResponse({ result: dataSource, selectedFlow, nextStep, session });
|
|
784
|
-
return { message, toolCalls, session, appliedInstructions, tokensUsed };
|
|
785
|
-
}
|
|
786
|
-
finally {
|
|
787
|
-
// Drain the transient appendage at end of turn.
|
|
788
|
-
// This ensures Directive.appendPrompt does not leak to subsequent
|
|
789
|
-
// turns even when the turn terminates abnormally (error, abort, reject).
|
|
790
|
-
turnTransientAppendage = undefined;
|
|
791
|
-
}
|
|
792
|
-
}
|
|
793
|
-
/**
|
|
794
|
-
* Unified streaming response generation.
|
|
795
|
-
* Renders the shared {@link planTurn} outcome as a chunk stream and runs the
|
|
796
|
-
* shared post-phase tail on the final chunk (finalizing exactly once).
|
|
797
|
-
* @private
|
|
798
|
-
*/
|
|
799
|
-
async *generateUnifiedStreamingResponse(responseContext) {
|
|
800
|
-
const plan = await this.planTurn(responseContext);
|
|
801
|
-
const { effectiveContext, history, historyEvents, signal, signalFirings } = plan;
|
|
802
|
-
const session = plan.session;
|
|
803
|
-
// Build the inner chunk stream for the planned outcome. `runPostPhase` is
|
|
804
|
-
// the single post-phase gate (false only for auto-chain halt).
|
|
805
|
-
let innerStream;
|
|
806
|
-
let runPostPhase = true;
|
|
807
|
-
switch (plan.outcome.kind) {
|
|
808
|
-
case 'halt': {
|
|
809
|
-
runPostPhase = plan.outcome.runPostPhase;
|
|
810
|
-
innerStream = this.streamTerminalMessage({
|
|
811
|
-
message: plan.outcome.message,
|
|
812
|
-
stoppedReason: plan.outcome.stoppedReason,
|
|
813
|
-
session,
|
|
814
|
-
});
|
|
815
|
-
break;
|
|
816
|
-
}
|
|
817
|
-
case 'flowComplete': {
|
|
818
|
-
innerStream = this.streamFlowCompletion({
|
|
819
|
-
selectedFlow: plan.outcome.selectedFlow,
|
|
820
|
-
session,
|
|
821
|
-
context: effectiveContext,
|
|
822
|
-
history,
|
|
823
|
-
historyEvents,
|
|
824
|
-
stoppedReason: plan.outcome.stoppedReason,
|
|
825
|
-
});
|
|
826
|
-
break;
|
|
827
|
-
}
|
|
828
|
-
case 'flowStep': {
|
|
829
|
-
innerStream = this.processFlowStreamingResponse({
|
|
830
|
-
selectedFlow: plan.outcome.selectedFlow,
|
|
831
|
-
selectedStep: plan.outcome.step,
|
|
832
|
-
responseDirectives: plan.outcome.responseDirectives,
|
|
833
|
-
session,
|
|
834
|
-
history,
|
|
835
|
-
context: effectiveContext,
|
|
836
|
-
historyEvents,
|
|
837
|
-
signal,
|
|
838
|
-
transientAppendage: plan.outcome.signalPreDirective?.appendPrompt,
|
|
839
|
-
mergedPreDirective: plan.outcome.signalPreDirective,
|
|
840
|
-
});
|
|
841
|
-
break;
|
|
842
|
-
}
|
|
843
|
-
case 'fallback': {
|
|
844
|
-
innerStream = this.streamFallbackResponse({
|
|
845
|
-
history,
|
|
846
|
-
context: effectiveContext,
|
|
847
|
-
session,
|
|
848
|
-
signal,
|
|
849
|
-
});
|
|
850
|
-
break;
|
|
851
|
-
}
|
|
852
|
-
}
|
|
853
|
-
// ── Intercept the inner stream on the final chunk ──────────────────────
|
|
854
|
-
// Mirrors the non-streaming tail: post-signal phase runs first (when
|
|
855
|
-
// applicable), then the session is finalized exactly once, attaching
|
|
856
|
-
// triggeredSignals to the final chunk (Requirement 11.2).
|
|
857
|
-
for await (const chunk of innerStream) {
|
|
858
|
-
if (chunk.done) {
|
|
859
|
-
const tail = await this.applyTurnPostPhase({
|
|
860
|
-
session: chunk.session || session,
|
|
861
|
-
context: effectiveContext,
|
|
862
|
-
historyEvents,
|
|
863
|
-
message: chunk.accumulated,
|
|
864
|
-
signalFirings,
|
|
865
|
-
runPostPhase,
|
|
866
|
-
});
|
|
867
|
-
const accumulated = tail.message;
|
|
868
|
-
const delta = tail.replyOverridden ? accumulated : chunk.delta;
|
|
869
|
-
// History ownership (parity with the sync tail): with
|
|
870
|
-
// params.message the returned session carries the full
|
|
871
|
-
// exchange — the user turn was recorded pre-routing, the
|
|
872
|
-
// assistant tail lands here, BEFORE finalize persists it.
|
|
873
|
-
if (responseContext.turnMessage && tail.message) {
|
|
874
|
-
tail.session.history = [...(tail.session.history ?? []), assistantMessage(tail.message)];
|
|
875
|
-
}
|
|
876
|
-
// Single streaming exit: finalize the post-phase session so
|
|
877
|
-
// post-signal mutations (e.g. pendingDirective) are persisted.
|
|
878
|
-
await this.sessionFinalizer.finalize(tail.session, effectiveContext);
|
|
879
|
-
yield {
|
|
880
|
-
...chunk,
|
|
881
|
-
delta,
|
|
882
|
-
accumulated,
|
|
883
|
-
session: tail.session,
|
|
884
|
-
triggeredSignals: tail.triggeredSignals,
|
|
885
|
-
};
|
|
886
|
-
}
|
|
887
|
-
else {
|
|
888
|
-
yield chunk;
|
|
889
|
-
}
|
|
890
|
-
}
|
|
891
|
-
}
|
|
892
|
-
/**
|
|
893
|
-
* Emit a framework-authored message (a halt reply) as a single terminal
|
|
894
|
-
* chunk, to flow through the shared post-phase tail like any other inner
|
|
895
|
-
* stream. No LLM call, no provider text — so nothing to extract or finalize
|
|
896
|
-
* here; the caller's tail owns post-phase + finalize.
|
|
897
|
-
* @private
|
|
898
|
-
*/
|
|
899
|
-
// eslint-disable-next-line @typescript-eslint/require-await -- yield-only async generator; must be `async *` to satisfy the AsyncGenerator return type the caller switches on
|
|
900
|
-
async *streamTerminalMessage(params) {
|
|
901
|
-
yield {
|
|
902
|
-
delta: params.message,
|
|
903
|
-
accumulated: params.message,
|
|
904
|
-
done: true,
|
|
905
|
-
session: params.session,
|
|
906
|
-
toolCalls: undefined,
|
|
907
|
-
isFlowComplete: false,
|
|
908
|
-
stoppedReason: params.stoppedReason,
|
|
909
|
-
executedSteps: [],
|
|
910
|
-
};
|
|
911
|
-
}
|
|
912
|
-
/**
|
|
913
|
-
* Wrap a provider message stream so each chunk's `delta`/`accumulated` carry
|
|
914
|
-
* clean message text instead of the raw structured-JSON wrapper. The single
|
|
915
|
-
* point where streamed JSON is unwrapped — every streaming response variant
|
|
916
|
-
* (flow step, fallback) consumes provider chunks through here, so consumers
|
|
917
|
-
* and stored history never see `{"message":...}` fragments. `structured`,
|
|
918
|
-
* `done`, and `metadata` pass through untouched.
|
|
919
|
-
* @private
|
|
920
|
-
*/
|
|
921
|
-
async *decodeMessageStream(stream) {
|
|
922
|
-
const decoder = new StreamingMessageDecoder();
|
|
923
|
-
for await (const chunk of stream) {
|
|
924
|
-
const clean = decoder.push(chunk.accumulated);
|
|
925
|
-
yield { ...chunk, delta: clean.delta, accumulated: clean.message };
|
|
926
|
-
}
|
|
927
|
-
}
|
|
928
|
-
/**
|
|
929
|
-
* Process flow streaming response with unified tool execution and data collection
|
|
930
|
-
* @private
|
|
931
|
-
*/
|
|
932
|
-
async *processFlowStreamingResponse(params) {
|
|
933
|
-
const { selectedFlow, selectedStep, responseDirectives, history, context, historyEvents, signal, transientAppendage, mergedPreDirective } = params;
|
|
934
|
-
let session = params.session;
|
|
935
|
-
// Resolve the step to render (same logic as non-streaming)
|
|
936
|
-
const stepResolution = await this.responsePipeline.resolveRenderStep({
|
|
937
|
-
selectedFlow,
|
|
938
|
-
selectedStep,
|
|
939
|
-
session,
|
|
940
|
-
context,
|
|
941
|
-
});
|
|
942
|
-
if (stepResolution.flowTransition) {
|
|
943
|
-
// Flow transition or completion — no step to render
|
|
944
|
-
yield {
|
|
945
|
-
delta: '',
|
|
946
|
-
accumulated: '',
|
|
947
|
-
done: true,
|
|
948
|
-
session: stepResolution.session,
|
|
949
|
-
};
|
|
950
|
-
return;
|
|
951
|
-
}
|
|
952
|
-
const nextStep = stepResolution.nextStep;
|
|
953
|
-
session = stepResolution.session;
|
|
954
|
-
// Build response schema and prompt (same as non-streaming)
|
|
955
|
-
const responseSchema = this.responseEngine.responseSchemaForFlow(selectedFlow, nextStep, this.agent.schema);
|
|
956
|
-
// ── HALT SHORT-CIRCUIT (Requirement 2.5, 2.6, 2.7) ──────────────────────
|
|
957
|
-
// After pre-LLM emissions are merged, if `halt: true` then skip the LLM
|
|
958
|
-
// call entirely. Emit a single done chunk with the appropriate content.
|
|
959
|
-
if (mergedPreDirective?.halt) {
|
|
960
|
-
const reply = mergedPreDirective.reply || '';
|
|
961
|
-
const reason = mergedPreDirective.reply ? 'reply' : 'halt';
|
|
962
|
-
logger.debug(`[ResponseModal] Halt (streaming) — skipping LLM call for step ${nextStep.id}, stoppedReason: ${reason}`);
|
|
963
|
-
yield {
|
|
964
|
-
delta: reply,
|
|
965
|
-
accumulated: reply,
|
|
966
|
-
done: true,
|
|
967
|
-
session,
|
|
968
|
-
stoppedReason: reason,
|
|
969
|
-
executedSteps: [{ id: nextStep.id, flowId: selectedFlow.id }],
|
|
970
|
-
};
|
|
971
|
-
return;
|
|
972
|
-
}
|
|
973
|
-
// ── STEP.REPLY SHORT-CIRCUIT (Requirement 25.1–25.7, 17.9) ──────────────
|
|
974
|
-
// A step with `reply` set emits a verbatim template response without LLM.
|
|
975
|
-
// onEnter and prepare have already fired normally. If prepare returned
|
|
976
|
-
// a Directive with `reply`, that overrides the step-declared reply.
|
|
977
|
-
if (nextStep.reply != null) {
|
|
978
|
-
const effectiveReply = mergedPreDirective?.reply ?? await render(nextStep.reply, createTemplateContext({ data: session.data || {}, context, session }));
|
|
979
|
-
logger.debug(`[ResponseModal] Step.reply (streaming) — skipping LLM call for step ${nextStep.id}`);
|
|
980
|
-
yield {
|
|
981
|
-
delta: effectiveReply,
|
|
982
|
-
accumulated: effectiveReply,
|
|
983
|
-
done: true,
|
|
984
|
-
session,
|
|
985
|
-
stoppedReason: 'reply',
|
|
986
|
-
executedSteps: [{ id: nextStep.id, flowId: selectedFlow.id }],
|
|
987
|
-
};
|
|
988
|
-
return;
|
|
989
|
-
}
|
|
990
|
-
// Transient appendage: per-turn slot from Directive.appendPrompt.
|
|
991
|
-
// Fresh each turn, never cached, never persisted.
|
|
992
|
-
// Wrapped in try/finally to ensure cleanup even on abnormal termination.
|
|
993
|
-
let turnTransientAppendage = transientAppendage;
|
|
994
|
-
try {
|
|
995
|
-
const { prompt: responsePrompt, appliedInstructions } = await this.responseEngine.buildResponsePrompt({
|
|
996
|
-
flow: selectedFlow,
|
|
997
|
-
currentStep: nextStep,
|
|
998
|
-
rules: [],
|
|
999
|
-
prohibitions: [],
|
|
1000
|
-
directives: responseDirectives,
|
|
1001
|
-
history: historyEvents,
|
|
1002
|
-
agentOptions: this.agent.getAgentOptions(),
|
|
1003
|
-
instructions: this.collectScopedInstructions(selectedFlow, nextStep),
|
|
1004
|
-
combinedTerms: this.agent.getTerms(),
|
|
1005
|
-
context,
|
|
1006
|
-
session,
|
|
1007
|
-
agentSchema: this.agent.schema,
|
|
1008
|
-
transientAppendage: turnTransientAppendage,
|
|
1009
|
-
});
|
|
1010
|
-
// Collect available tools for AI
|
|
1011
|
-
const availableTools = this.collectAvailableTools(selectedFlow, nextStep);
|
|
1012
|
-
// Generate message stream using AI provider
|
|
1013
|
-
const agentOptions = this.agent.getAgentOptions();
|
|
1014
|
-
const stream = agentOptions.provider.generateMessageStream({
|
|
1015
|
-
prompt: responsePrompt,
|
|
1016
|
-
history, // Use HistoryItem[] for AI provider
|
|
1017
|
-
context,
|
|
1018
|
-
tools: availableTools,
|
|
1019
|
-
signal,
|
|
1020
|
-
parameters: { jsonSchema: responseSchema, schemaName: "response_stream_output" },
|
|
1021
|
-
});
|
|
1022
|
-
// Stream chunks with unified tool handling. decodeMessageStream gives
|
|
1023
|
-
// each chunk clean message text in delta/accumulated, so the non-done
|
|
1024
|
-
// deltas, the final accumulated, the post-phase message input, and the
|
|
1025
|
-
// assistant message stored by stream() are all clean — never the raw
|
|
1026
|
-
// JSON wrapper (matching the non-streaming structured.message extraction).
|
|
1027
|
-
for await (const chunk of this.decodeMessageStream(stream)) {
|
|
1028
|
-
let toolCalls = undefined;
|
|
1029
|
-
// Final message/structured may be replaced by a forced post-tool
|
|
1030
|
-
// response (see runStreamingBatch / gap: tools-ran-but-no-text).
|
|
1031
|
-
let finalDelta = chunk.delta;
|
|
1032
|
-
let finalAccumulated = chunk.accumulated;
|
|
1033
|
-
let finalStructured = chunk.structured;
|
|
1034
|
-
// Extract tool calls from AI response on final chunk
|
|
1035
|
-
if (chunk.done && chunk.structured?.toolCalls) {
|
|
1036
|
-
toolCalls = chunk.structured.toolCalls;
|
|
1037
|
-
// Concurrent execution for the initial batch of tool calls,
|
|
1038
|
-
// yielding tool-progress chunks as they arrive. The accumulated
|
|
1039
|
-
// preamble is already clean text.
|
|
1040
|
-
const batchResult = yield* this.toolLoopExecutor.runStreamingBatch({
|
|
1041
|
-
toolCalls,
|
|
1042
|
-
context,
|
|
1043
|
-
session,
|
|
1044
|
-
history,
|
|
1045
|
-
selectedFlow,
|
|
1046
|
-
step: nextStep,
|
|
1047
|
-
accumulated: chunk.accumulated,
|
|
1048
|
-
responsePrompt,
|
|
1049
|
-
availableTools,
|
|
1050
|
-
responseSchema,
|
|
1051
|
-
signal,
|
|
1052
|
-
});
|
|
1053
|
-
session = batchResult.session;
|
|
1054
|
-
toolCalls = batchResult.toolCalls;
|
|
1055
|
-
// Tool-emitted directives (ctx.dispatch / `{directive}`):
|
|
1056
|
-
// state writes apply now; control flow queues for the next
|
|
1057
|
-
// turn's pendingDirective applier (same deferred semantics
|
|
1058
|
-
// as dispatch()). A verbatim tool reply already replaced the
|
|
1059
|
-
// closing message inside runStreamingBatch.
|
|
1060
|
-
if (batchResult.directives) {
|
|
1061
|
-
session = await this.applyToolEmittedDirectives(session, batchResult.directives);
|
|
1062
|
-
}
|
|
1063
|
-
// Prefer the post-tool follow-up structured for collection and
|
|
1064
|
-
// emission whenever present — independent of whether a closing
|
|
1065
|
-
// message was forced — matching the non-streaming path's
|
|
1066
|
-
// `toolResult.structured ?? result` selection.
|
|
1067
|
-
finalStructured = batchResult.structured ?? finalStructured;
|
|
1068
|
-
// Tools ran but the model produced no result-aware text — use
|
|
1069
|
-
// the forced closing message (already clean) so we never emit the
|
|
1070
|
-
// bare preamble (or an empty message) as the final response. Its
|
|
1071
|
-
// delta is the portion not already streamed as the preamble.
|
|
1072
|
-
if (batchResult.finalMessage) {
|
|
1073
|
-
finalAccumulated = batchResult.finalMessage;
|
|
1074
|
-
finalDelta = batchResult.finalMessage.startsWith(chunk.accumulated)
|
|
1075
|
-
? batchResult.finalMessage.slice(chunk.accumulated.length)
|
|
1076
|
-
: batchResult.finalMessage;
|
|
1077
|
-
}
|
|
1078
|
-
}
|
|
1079
|
-
// Streaming twin of the non-streaming salvage guard: a schema was
|
|
1080
|
-
// requested but no structured payload arrived, and the accumulated
|
|
1081
|
-
// text is JSON-shaped (a protocol fragment) — repair-parse it or
|
|
1082
|
-
// fail the turn rather than leaking raw output to the user.
|
|
1083
|
-
if (chunk.done && !finalStructured && responseSchema && finalAccumulated) {
|
|
1084
|
-
const salvaged = this.salvageStructuredOutput(finalAccumulated, "stream");
|
|
1085
|
-
if (salvaged) {
|
|
1086
|
-
finalDelta = salvaged.message.startsWith(finalAccumulated)
|
|
1087
|
-
? salvaged.message.slice(finalAccumulated.length)
|
|
1088
|
-
: salvaged.message;
|
|
1089
|
-
finalStructured = salvaged;
|
|
1090
|
-
finalAccumulated = salvaged.message;
|
|
1091
|
-
}
|
|
1092
|
-
}
|
|
1093
|
-
// Collect data on the final chunk for any flow step — flow
|
|
1094
|
-
// required/optional fields are valid targets even without a step
|
|
1095
|
-
// `collect` — preferring the post-tool follow-up structured so a
|
|
1096
|
-
// tool-driven turn harvests fields the model produced after tools.
|
|
1097
|
-
if (chunk.done && finalStructured) {
|
|
1098
|
-
session = await this.collectDataFromResponse({
|
|
1099
|
-
result: { structured: finalStructured },
|
|
1100
|
-
selectedFlow,
|
|
1101
|
-
nextStep,
|
|
1102
|
-
session,
|
|
1103
|
-
});
|
|
1104
|
-
}
|
|
1105
|
-
// Response structure completeness (Requirement 8.1, 8.2, 8.3)
|
|
1106
|
-
// - executedSteps: single step executed in this response
|
|
1107
|
-
// - stoppedReason: 'needs_input' for single-step execution (waiting for user input)
|
|
1108
|
-
// - session.currentStep: reflects the executed step
|
|
1109
|
-
yield {
|
|
1110
|
-
delta: finalDelta,
|
|
1111
|
-
accumulated: finalAccumulated,
|
|
1112
|
-
done: chunk.done,
|
|
1113
|
-
session,
|
|
1114
|
-
toolCalls,
|
|
1115
|
-
isFlowComplete: false,
|
|
1116
|
-
executedSteps: chunk.done ? [{ id: nextStep.id, flowId: selectedFlow.id }] : undefined,
|
|
1117
|
-
stoppedReason: chunk.done ? 'needs_input' : undefined,
|
|
1118
|
-
metadata: chunk.metadata,
|
|
1119
|
-
structured: finalStructured,
|
|
1120
|
-
appliedInstructions: chunk.done ? appliedInstructions : undefined,
|
|
1121
|
-
};
|
|
1122
|
-
}
|
|
1123
|
-
}
|
|
1124
|
-
finally {
|
|
1125
|
-
// Drain the transient appendage at end of turn.
|
|
1126
|
-
// This ensures Directive.appendPrompt does not leak to subsequent
|
|
1127
|
-
// turns even when the turn terminates abnormally (error, abort, reject).
|
|
1128
|
-
turnTransientAppendage = undefined;
|
|
1129
|
-
}
|
|
1130
|
-
}
|
|
1131
|
-
/**
|
|
1132
|
-
* Unified data collection from AI response
|
|
1133
|
-
* @private
|
|
1134
|
-
*/
|
|
1135
|
-
async collectDataFromResponse(params) {
|
|
1136
|
-
try {
|
|
1137
|
-
const { result, selectedFlow, nextStep, session } = params;
|
|
1138
|
-
let updatedSession = session;
|
|
1139
|
-
// Extract collected data from final response (only for flow-based interactions)
|
|
1140
|
-
if (selectedFlow && result.structured) {
|
|
1141
|
-
try {
|
|
1142
|
-
const collectedData = {};
|
|
1143
|
-
// AgentStructuredResponse extends Record<string, unknown>, so we can safely access properties
|
|
1144
|
-
const structuredData = result.structured;
|
|
1145
|
-
// Collect ALL flow fields (required + optional) from structured response
|
|
1146
|
-
const allFlowFields = new Set();
|
|
1147
|
-
// Add flow required fields
|
|
1148
|
-
if (selectedFlow.requiredFields) {
|
|
1149
|
-
selectedFlow.requiredFields.forEach(field => allFlowFields.add(String(field)));
|
|
1150
|
-
}
|
|
1151
|
-
// Add flow optional fields
|
|
1152
|
-
if (selectedFlow.optionalFields) {
|
|
1153
|
-
selectedFlow.optionalFields.forEach(field => allFlowFields.add(String(field)));
|
|
1154
|
-
}
|
|
1155
|
-
// Also include current step's collect fields (in case they're not in flow fields)
|
|
1156
|
-
if (nextStep?.collect) {
|
|
1157
|
-
nextStep.collect.forEach(field => allFlowFields.add(String(field)));
|
|
1158
|
-
}
|
|
1159
|
-
// Extract all available fields from structured response
|
|
1160
|
-
for (const field of allFlowFields) {
|
|
1161
|
-
const fieldKey = String(field);
|
|
1162
|
-
if (fieldKey in structuredData && structuredData[fieldKey] !== undefined && structuredData[fieldKey] !== null) {
|
|
1163
|
-
collectedData[fieldKey] = structuredData[fieldKey];
|
|
1164
|
-
}
|
|
1165
|
-
}
|
|
1166
|
-
// Merge collected data into session using agent-level data validation
|
|
1167
|
-
if (Object.keys(collectedData).length > 0) {
|
|
1168
|
-
try {
|
|
1169
|
-
// Update agent-level collected data with validation
|
|
1170
|
-
await this.agent.updateCollectedData(collectedData);
|
|
1171
|
-
// Update session with validated data
|
|
1172
|
-
const updateDataMethod = this.agent.getUpdateDataMethod();
|
|
1173
|
-
updatedSession = await updateDataMethod(updatedSession, collectedData);
|
|
1174
|
-
logger.debug(`[ResponseModal] Collected data:`, collectedData);
|
|
1175
|
-
}
|
|
1176
|
-
catch (error) {
|
|
1177
|
-
logger.error(`[ResponseModal] Failed to update collected data:`, error);
|
|
1178
|
-
// Continue without updating data rather than failing completely
|
|
1179
|
-
}
|
|
1180
|
-
}
|
|
1181
|
-
}
|
|
1182
|
-
catch (error) {
|
|
1183
|
-
logger.error(`[ResponseModal] Error during data collection:`, error);
|
|
1184
|
-
// Continue without collecting data rather than failing completely
|
|
1185
|
-
}
|
|
1186
|
-
}
|
|
1187
|
-
// Extract any additional data from structured response
|
|
1188
|
-
// Since AgentStructuredResponse extends Record<string, unknown>, we can safely check for additional properties
|
|
1189
|
-
if (result.structured && "contextUpdate" in result.structured) {
|
|
1190
|
-
try {
|
|
1191
|
-
const contextUpdate = result.structured.contextUpdate;
|
|
1192
|
-
if (contextUpdate) {
|
|
1193
|
-
await this.agent.updateContext(contextUpdate);
|
|
1194
|
-
}
|
|
1195
|
-
}
|
|
1196
|
-
catch (error) {
|
|
1197
|
-
logger.error(`[ResponseModal] Failed to update context from structured response:`, error);
|
|
1198
|
-
// Continue without updating context rather than failing completely
|
|
1199
|
-
}
|
|
1200
|
-
}
|
|
1201
|
-
return updatedSession;
|
|
1202
|
-
}
|
|
1203
|
-
catch (error) {
|
|
1204
|
-
logger.error(`[ResponseModal] Error in collectDataFromResponse:`, error);
|
|
1205
|
-
// Return original session if data collection fails completely
|
|
1206
|
-
return params.session;
|
|
1207
|
-
}
|
|
1208
|
-
}
|
|
1209
|
-
/**
|
|
1210
|
-
* Apply flow completion: release the session to idle state.
|
|
1211
|
-
*
|
|
1212
|
-
* This is a pure state transition. The framework emits **no message of
|
|
1213
|
-
* its own** at the completion boundary — every word delivered to the
|
|
1214
|
-
* user comes from a developer-defined step prompt. If the dev wants a
|
|
1215
|
-
* closing turn, they add a final interactive step with their own
|
|
1216
|
-
* `prompt`; the framework respects that step's natural LLM output.
|
|
1217
|
-
*
|
|
1218
|
-
* Behavior:
|
|
1219
|
-
* - Marks the active `flowHistory` entry as `completed: true` and
|
|
1220
|
-
* stamps `exitedAt`.
|
|
1221
|
-
* - Evaluates `flow.onComplete` for an explicit follow-up transition.
|
|
1222
|
-
* When set, populates `session.pendingDirective` (the next turn's
|
|
1223
|
-
* pipeline applies it). When absent, the session is fully idle.
|
|
1224
|
-
* - Clears `currentFlow` and `currentStep` to `undefined`.
|
|
1225
|
-
* - Clears owned fields when the flow is `reentrant` so subsequent
|
|
1226
|
-
* re-selections start from a clean state.
|
|
1227
|
-
*
|
|
1228
|
-
* Returns the updated session. Callers compose any reply text from
|
|
1229
|
-
* their own sources (an upstream LLM turn, a directive's `reply`, or
|
|
1230
|
-
* an empty string for silent completion).
|
|
1231
|
-
*
|
|
1232
|
-
* @private
|
|
1233
|
-
*/
|
|
1234
|
-
async applyFlowCompletion(params) {
|
|
1235
|
-
const { selectedFlow, session, context } = params;
|
|
1236
|
-
// 1) Evaluate onComplete first — needs the still-active session shape.
|
|
1237
|
-
const transitionConfig = await selectedFlow.evaluateOnComplete({ data: session.data }, context);
|
|
1238
|
-
// 2) Release to idle. If the flow is reentrant, scrub its owned
|
|
1239
|
-
// fields so re-selection on a future turn starts clean. When
|
|
1240
|
-
// onComplete fires we still go idle here — the next turn's
|
|
1241
|
-
// pipeline applies the pendingDirective before any routing.
|
|
1242
|
-
const ownedFields = selectedFlow.reentrant
|
|
1243
|
-
? [
|
|
1244
|
-
...(selectedFlow.requiredFields ?? []),
|
|
1245
|
-
...(selectedFlow.optionalFields ?? []),
|
|
1246
|
-
]
|
|
1247
|
-
: undefined;
|
|
1248
|
-
let nextSession = completeCurrentFlow(session, {
|
|
1249
|
-
clearOwnedFields: ownedFields,
|
|
1250
|
-
});
|
|
1251
|
-
// 3) Wire pendingDirective when onComplete returned a target.
|
|
1252
|
-
if (transitionConfig) {
|
|
1253
|
-
const goToTarget = typeof transitionConfig.goTo === 'string'
|
|
1254
|
-
? transitionConfig.goTo
|
|
1255
|
-
: transitionConfig.goTo?.flow;
|
|
1256
|
-
const targetFlow = goToTarget ? this.agent.getFlows().find((r) => r.id === goToTarget ||
|
|
1257
|
-
r.title === goToTarget) : undefined;
|
|
1258
|
-
if (targetFlow) {
|
|
1259
|
-
nextSession = {
|
|
1260
|
-
...nextSession,
|
|
1261
|
-
pendingDirective: {
|
|
1262
|
-
goTo: targetFlow.id,
|
|
1263
|
-
},
|
|
1264
|
-
};
|
|
1265
|
-
logger.debug(`[ResponseModal] Flow ${selectedFlow.title} completed with pending directive to: ${targetFlow.title}`);
|
|
1266
|
-
}
|
|
1267
|
-
else if (goToTarget) {
|
|
1268
|
-
logger.warn(`[FlowConfigurationError] onComplete target not found: flow "${selectedFlow.title}" completed but onComplete target "${goToTarget}" does not match any flow. ` +
|
|
1269
|
-
`Fix the onComplete value to reference an existing flow id/title, or remove onComplete to release the session to idle.`);
|
|
1270
|
-
}
|
|
1271
|
-
}
|
|
1272
|
-
else {
|
|
1273
|
-
logger.debug(`[ResponseModal] Flow ${selectedFlow.title} completed; session released to idle.`);
|
|
1274
|
-
}
|
|
1275
|
-
return nextSession;
|
|
1276
|
-
}
|
|
1277
|
-
/**
|
|
1278
|
-
* Stream a flow completion as a single terminal chunk.
|
|
1279
|
-
*
|
|
1280
|
-
* No LLM call is made. The framework no longer authors a farewell — the
|
|
1281
|
-
* completion path is a pure state transition. The chunk emits an empty
|
|
1282
|
-
* `delta` and a `done: true` flag with the idle session attached so
|
|
1283
|
-
* downstream consumers can finalize cleanly.
|
|
1284
|
-
*
|
|
1285
|
-
* If the developer wants closing copy in a streaming response, they
|
|
1286
|
-
* should add a final interactive step whose own LLM turn delivers it.
|
|
1287
|
-
*
|
|
1288
|
-
* @private
|
|
1289
|
-
*/
|
|
1290
|
-
async *streamFlowCompletion(params) {
|
|
1291
|
-
const { selectedFlow, context, history } = params;
|
|
1292
|
-
const session = await this.applyFlowCompletion({
|
|
1293
|
-
selectedFlow,
|
|
1294
|
-
session: params.session,
|
|
1295
|
-
context,
|
|
1296
|
-
history,
|
|
1297
|
-
});
|
|
1298
|
-
yield {
|
|
1299
|
-
delta: '',
|
|
1300
|
-
accumulated: '',
|
|
1301
|
-
done: true,
|
|
1302
|
-
session,
|
|
1303
|
-
toolCalls: undefined,
|
|
1304
|
-
isFlowComplete: true,
|
|
1305
|
-
executedSteps: [],
|
|
1306
|
-
stoppedReason: params.stoppedReason ?? 'completed',
|
|
1307
|
-
};
|
|
1308
|
-
}
|
|
1309
|
-
/**
|
|
1310
|
-
* Generate fallback response when no flows are available
|
|
1311
|
-
* @private
|
|
1312
|
-
*/
|
|
1313
|
-
async generateFallbackResponse(params) {
|
|
1314
|
-
const { history, context, session, signal } = params;
|
|
1315
|
-
logger.debug(`[ResponseModal] No flow selected, generating basic response`);
|
|
1316
|
-
// Build basic response prompt without flow context
|
|
1317
|
-
const { prompt: fallbackPrompt, appliedInstructions } = await this.responseEngine.buildFallbackPrompt({
|
|
1318
|
-
agentOptions: this.agent.getAgentOptions(),
|
|
1319
|
-
terms: this.agent.getTerms(),
|
|
1320
|
-
instructions: this.collectScopedInstructions(),
|
|
1321
|
-
context,
|
|
1322
|
-
session,
|
|
1323
|
-
});
|
|
1324
|
-
const agentOptions = this.agent.getAgentOptions();
|
|
1325
|
-
const result = await agentOptions.provider.generateMessage({
|
|
1326
|
-
prompt: fallbackPrompt,
|
|
1327
|
-
history,
|
|
1328
|
-
context,
|
|
1329
|
-
signal,
|
|
1330
|
-
parameters: {
|
|
1331
|
-
jsonSchema: {
|
|
1332
|
-
type: "object",
|
|
1333
|
-
properties: { message: { type: "string" } },
|
|
1334
|
-
required: ["message"],
|
|
1335
|
-
additionalProperties: false,
|
|
1336
|
-
},
|
|
1337
|
-
schemaName: "fallback_response",
|
|
1338
|
-
},
|
|
1339
|
-
});
|
|
1340
|
-
return { message: result.structured?.message || result.message, appliedInstructions };
|
|
1341
|
-
}
|
|
1342
|
-
/**
|
|
1343
|
-
* Stream fallback response when no flows are available
|
|
1344
|
-
* @private
|
|
1345
|
-
*/
|
|
1346
|
-
async *streamFallbackResponse(params) {
|
|
1347
|
-
const { history, context, session, signal } = params;
|
|
1348
|
-
const { prompt: fallbackPrompt, appliedInstructions } = await this.responseEngine.buildFallbackPrompt({
|
|
1349
|
-
agentOptions: this.agent.getAgentOptions(),
|
|
1350
|
-
terms: this.agent.getTerms(),
|
|
1351
|
-
instructions: this.collectScopedInstructions(),
|
|
1352
|
-
context,
|
|
1353
|
-
session,
|
|
1354
|
-
});
|
|
1355
|
-
const agentOptions = this.agent.getAgentOptions();
|
|
1356
|
-
const stream = agentOptions.provider.generateMessageStream({
|
|
1357
|
-
prompt: fallbackPrompt,
|
|
1358
|
-
history,
|
|
1359
|
-
context,
|
|
1360
|
-
signal,
|
|
1361
|
-
parameters: {
|
|
1362
|
-
jsonSchema: {
|
|
1363
|
-
type: "object",
|
|
1364
|
-
properties: { message: { type: "string" } },
|
|
1365
|
-
required: ["message"],
|
|
1366
|
-
additionalProperties: false,
|
|
1367
|
-
},
|
|
1368
|
-
schemaName: "fallback_stream_response",
|
|
1369
|
-
},
|
|
1370
|
-
});
|
|
1371
|
-
// Decode the JSON wrapper to clean message text (same as the flow path).
|
|
1372
|
-
for await (const chunk of this.decodeMessageStream(stream)) {
|
|
1373
|
-
// Response structure completeness (Requirement 8.1, 8.2, 8.3)
|
|
1374
|
-
// - executedSteps: empty for fallback (no flow/step execution)
|
|
1375
|
-
// - stoppedReason: undefined for fallback (no flow context)
|
|
1376
|
-
// - session.currentStep: unchanged (no step progression)
|
|
1377
|
-
yield {
|
|
1378
|
-
delta: chunk.delta,
|
|
1379
|
-
accumulated: chunk.accumulated,
|
|
1380
|
-
done: chunk.done,
|
|
1381
|
-
session,
|
|
1382
|
-
toolCalls: undefined,
|
|
1383
|
-
isFlowComplete: false,
|
|
1384
|
-
executedSteps: chunk.done ? [] : undefined,
|
|
1385
|
-
stoppedReason: undefined,
|
|
1386
|
-
metadata: chunk.metadata,
|
|
1387
|
-
structured: chunk.structured,
|
|
1388
|
-
appliedInstructions: chunk.done ? appliedInstructions : undefined,
|
|
1389
|
-
};
|
|
1390
|
-
}
|
|
1391
|
-
}
|
|
1392
|
-
// ============================================================================
|
|
1393
|
-
// UTILITY METHODS - Helper methods for tool management and other utilities
|
|
1394
|
-
// ============================================================================
|
|
1395
|
-
/**
|
|
1396
|
-
* Collect all available tools for the given flow and step context.
|
|
1397
|
-
* Delegates to ToolManager for unified tool resolution and deduplication.
|
|
1398
|
-
* @private
|
|
1399
|
-
*/
|
|
1400
|
-
collectAvailableTools(flow, step) {
|
|
1401
|
-
const availableTools = this.getToolManager().getAvailable(undefined, step, flow);
|
|
1402
|
-
return availableTools.map((tool) => ({
|
|
1403
|
-
id: tool.id,
|
|
1404
|
-
name: tool.id,
|
|
1405
|
-
description: tool.description,
|
|
1406
|
-
parameters: tool.parameters,
|
|
1407
|
-
}));
|
|
1408
|
-
}
|
|
1409
|
-
}
|
|
1410
|
-
//# sourceMappingURL=ResponseModal.js.map
|