@elevasis/core 0.7.0 → 0.8.0
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/package.json +3 -3
- package/src/README.md +41 -41
- package/src/__tests__/publish.test.ts +18 -18
- package/src/__tests__/{template-foundations-compatibility.test.ts → template-core-compatibility.test.ts} +99 -99
- package/src/_gen/__tests__/__snapshots__/contracts.md.snap +1135 -1131
- package/src/_gen/__tests__/scaffold-contracts.test.ts +53 -53
- package/src/_gen/scaffold-contracts.ts +45 -45
- package/src/auth/multi-tenancy/credentials/README.md +38 -38
- package/src/auth/multi-tenancy/credentials/index.ts +6 -6
- package/src/auth/multi-tenancy/credentials/server/encryption.ts +39 -39
- package/src/auth/multi-tenancy/credentials/server/service.ts +60 -60
- package/src/auth/multi-tenancy/index.ts +17 -17
- package/src/auth/multi-tenancy/invitations/api-schemas.ts +107 -107
- package/src/auth/multi-tenancy/invitations/index.ts +37 -37
- package/src/auth/multi-tenancy/invitations/invitation.ts +86 -86
- package/src/auth/multi-tenancy/invitations/server/index.ts +25 -25
- package/src/auth/multi-tenancy/invitations/server/transforms.ts +24 -24
- package/src/auth/multi-tenancy/invitations/server/workos.ts +24 -24
- package/src/auth/multi-tenancy/invitations/supabase.ts +50 -50
- package/src/auth/multi-tenancy/memberships/api-schemas.ts +126 -126
- package/src/auth/multi-tenancy/memberships/index.ts +21 -21
- package/src/auth/multi-tenancy/memberships/membership.ts +138 -138
- package/src/auth/multi-tenancy/memberships/server/index.ts +15 -15
- package/src/auth/multi-tenancy/memberships/server/transforms.ts +32 -32
- package/src/auth/multi-tenancy/memberships/server/workos.ts +21 -21
- package/src/auth/multi-tenancy/memberships/supabase.ts +46 -46
- package/src/auth/multi-tenancy/organizations/api-schemas.ts +128 -128
- package/src/auth/multi-tenancy/organizations/index.ts +23 -23
- package/src/auth/multi-tenancy/organizations/organization.ts +24 -24
- package/src/auth/multi-tenancy/organizations/server/index.ts +10 -10
- package/src/auth/multi-tenancy/organizations/server/transforms.ts +35 -35
- package/src/auth/multi-tenancy/organizations/server/workos.ts +20 -20
- package/src/auth/multi-tenancy/types.ts +83 -83
- package/src/auth/multi-tenancy/users/api-schemas.ts +194 -194
- package/src/auth/multi-tenancy/users/index.ts +27 -27
- package/src/auth/multi-tenancy/users/server/index.ts +19 -19
- package/src/auth/multi-tenancy/users/server/transforms.ts +21 -21
- package/src/auth/multi-tenancy/users/server/workos.ts +16 -16
- package/src/auth/multi-tenancy/users/user.ts +65 -65
- package/src/business/README.md +52 -52
- package/src/business/__tests__/entities-published.test.ts +33 -33
- package/src/business/acquisition/api-schemas.ts +759 -759
- package/src/business/acquisition/index.ts +109 -109
- package/src/business/acquisition/types.ts +402 -402
- package/src/business/base-entities.test.ts +481 -481
- package/src/business/base-entities.ts +241 -241
- package/src/business/entities-published.ts +24 -24
- package/src/business/index.ts +15 -15
- package/src/business/pdf/browser/pdfmake-browser.ts +229 -229
- package/src/business/pdf/index.ts +10 -10
- package/src/business/pdf/server/index.ts +21 -21
- package/src/business/pdf/server/themes/default.ts +8 -8
- package/src/business/pdf/server/themes/index.ts +9 -9
- package/src/business/pdf/server/themes/types.ts +8 -8
- package/src/business/pdf/types.ts +272 -272
- package/src/business/projects/index.ts +2 -1
- package/src/business/projects/sse-events.ts +21 -0
- package/src/business/projects/types.ts +89 -89
- package/src/business/sales/api-schemas.ts +75 -75
- package/src/business/seo/__tests__/linking.test.ts +549 -549
- package/src/business/seo/__tests__/types.test.ts +404 -404
- package/src/business/seo/index.ts +2 -2
- package/src/business/seo/linking.ts +281 -281
- package/src/business/seo/types.ts +199 -199
- package/src/commands/queue/index.ts +3 -3
- package/src/commands/queue/schemas.test.ts +593 -593
- package/src/commands/queue/schemas.ts +125 -125
- package/src/commands/queue/sse-events.ts +61 -61
- package/src/commands/queue/types/action.ts +52 -52
- package/src/commands/queue/types/checkpoint.ts +44 -44
- package/src/commands/queue/types/index.ts +7 -7
- package/src/commands/queue/types/task.ts +116 -116
- package/src/commands/queue/types.ts +14 -14
- package/src/content/distribution-metadata.ts +61 -61
- package/src/content/index.ts +10 -10
- package/src/deployments/index.ts +22 -22
- package/src/execution/core/__tests__/archived-logs.test.ts +72 -72
- package/src/execution/core/index.ts +11 -11
- package/src/execution/core/runner-types.ts +80 -80
- package/src/execution/core/server/environment.ts +31 -31
- package/src/execution/core/sse-executions.ts +119 -119
- package/src/execution/core/types.ts +29 -29
- package/src/execution/engine/__tests__/fixtures/test-agents.ts +4 -4
- package/src/execution/engine/__tests__/timeout.test.ts +565 -565
- package/src/execution/engine/agent/__tests__/errors.test.ts +508 -508
- package/src/execution/engine/agent/actions/__tests__/processor.test.ts +531 -531
- package/src/execution/engine/agent/actions/executor.ts +205 -205
- package/src/execution/engine/agent/actions/navigate-knowledge-executor.ts +230 -230
- package/src/execution/engine/agent/actions/processor.ts +116 -116
- package/src/execution/engine/agent/actions/types.ts +70 -70
- package/src/execution/engine/agent/core/agent.ts +810 -810
- package/src/execution/engine/agent/core/types.ts +155 -155
- package/src/execution/engine/agent/errors.ts +251 -251
- package/src/execution/engine/agent/index.ts +78 -78
- package/src/execution/engine/agent/knowledge-map/types.ts +106 -106
- package/src/execution/engine/agent/knowledge-map/utils.ts +101 -101
- package/src/execution/engine/agent/memory/__tests__/manager.test.ts +754 -754
- package/src/execution/engine/agent/memory/domains.ts +99 -99
- package/src/execution/engine/agent/memory/manager.ts +365 -365
- package/src/execution/engine/agent/memory/processor.ts +66 -66
- package/src/execution/engine/agent/memory/types.ts +90 -90
- package/src/execution/engine/agent/memory/utils.ts +134 -134
- package/src/execution/engine/agent/observability/logging.ts +467 -467
- package/src/execution/engine/agent/observability/types.ts +64 -64
- package/src/execution/engine/agent/reasoning/adapters/agent-adapter-helpers.ts +349 -349
- package/src/execution/engine/agent/reasoning/processor.ts +92 -92
- package/src/execution/engine/agent/reasoning/prompt-sections/base-actions.ts +134 -134
- package/src/execution/engine/agent/reasoning/prompt-sections/completion.ts +49 -49
- package/src/execution/engine/agent/reasoning/prompt-sections/knowledge-map.ts +93 -93
- package/src/execution/engine/agent/reasoning/prompt-sections/memory.ts +65 -65
- package/src/execution/engine/agent/reasoning/prompt-sections/tools.ts +44 -44
- package/src/execution/engine/agent/reasoning/request-builder.ts +169 -169
- package/src/execution/engine/agent/reasoning/types.ts +18 -18
- package/src/execution/engine/base/errors.ts +118 -118
- package/src/execution/engine/base/index.ts +2 -2
- package/src/execution/engine/base/logging.ts +31 -31
- package/src/execution/engine/base/serialization.ts +324 -324
- package/src/execution/engine/base/types.ts +126 -126
- package/src/execution/engine/base/utils.ts +41 -41
- package/src/execution/engine/index.ts +434 -434
- package/src/execution/engine/interface/index.ts +1 -1
- package/src/execution/engine/interface/types.ts +62 -62
- package/src/execution/engine/llm/__tests__/model-info.test.ts +50 -50
- package/src/execution/engine/llm/__tests__/model-validation.test.ts +321 -321
- package/src/execution/engine/llm/__tests__/response-schema-validator.test.ts +115 -115
- package/src/execution/engine/llm/adapters/__tests__/adapter-factory.test.ts +375 -375
- package/src/execution/engine/llm/adapters/__tests__/anthropic-adapter.test.ts +463 -463
- package/src/execution/engine/llm/adapters/__tests__/anthropic.integration.test.ts +177 -177
- package/src/execution/engine/llm/adapters/__tests__/google-adapter.test.ts +722 -722
- package/src/execution/engine/llm/adapters/__tests__/google.integration.test.ts +376 -376
- package/src/execution/engine/llm/adapters/__tests__/openai-adapter.test.ts +551 -551
- package/src/execution/engine/llm/adapters/__tests__/openrouter-adapter.test.ts +563 -563
- package/src/execution/engine/llm/adapters/__tests__/openrouter.integration.test.ts +105 -105
- package/src/execution/engine/llm/adapters/__tests__/universal-adapter.test.ts +537 -537
- package/src/execution/engine/llm/adapters/circuit-breaker.ts +147 -147
- package/src/execution/engine/llm/adapters/index.ts +17 -17
- package/src/execution/engine/llm/adapters/mock-adapter.ts +116 -116
- package/src/execution/engine/llm/adapters/server/adapter-factory.ts +130 -130
- package/src/execution/engine/llm/adapters/server/anthropic.ts +137 -137
- package/src/execution/engine/llm/adapters/server/google.ts +283 -283
- package/src/execution/engine/llm/adapters/server/index.ts +12 -12
- package/src/execution/engine/llm/adapters/server/openai.ts +206 -206
- package/src/execution/engine/llm/adapters/server/openrouter.ts +235 -235
- package/src/execution/engine/llm/adapters/universal-adapter.ts +230 -230
- package/src/execution/engine/llm/errors.ts +186 -186
- package/src/execution/engine/llm/model-info.ts +332 -332
- package/src/execution/engine/llm/response-schema-validator.ts +113 -113
- package/src/execution/engine/llm/types.ts +86 -86
- package/src/execution/engine/test-utils/index.ts +6 -6
- package/src/execution/engine/test-utils/mocks.ts +56 -56
- package/src/execution/engine/tools/integration/base-integration-adapter.ts +50 -50
- package/src/execution/engine/tools/integration/index.ts +53 -53
- package/src/execution/engine/tools/integration/server/adapters/anymailfinder/anymailfinder-adapter.ts +73 -73
- package/src/execution/engine/tools/integration/server/adapters/anymailfinder/anymailfinder-tools.ts +209 -209
- package/src/execution/engine/tools/integration/server/adapters/anymailfinder/fetch/find-company-email/index.ts +82 -82
- package/src/execution/engine/tools/integration/server/adapters/anymailfinder/fetch/find-decision-maker-email/index.ts +122 -122
- package/src/execution/engine/tools/integration/server/adapters/anymailfinder/fetch/find-person-email/index.ts +89 -89
- package/src/execution/engine/tools/integration/server/adapters/anymailfinder/fetch/verify-email/index.ts +84 -84
- package/src/execution/engine/tools/integration/server/adapters/anymailfinder/index.ts +16 -16
- package/src/execution/engine/tools/integration/server/adapters/apify/__tests__/apify-run-actor.integration.test.ts +293 -293
- package/src/execution/engine/tools/integration/server/adapters/apify/apify-adapter.ts +100 -100
- package/src/execution/engine/tools/integration/server/adapters/apify/apify-tools.ts +217 -217
- package/src/execution/engine/tools/integration/server/adapters/apify/fetch/get-dataset-items/index.ts +92 -92
- package/src/execution/engine/tools/integration/server/adapters/apify/fetch/run-actor/index.ts +218 -218
- package/src/execution/engine/tools/integration/server/adapters/apify/fetch/start-actor/index.ts +87 -87
- package/src/execution/engine/tools/integration/server/adapters/apify/index.ts +11 -11
- package/src/execution/engine/tools/integration/server/adapters/attio/__tests__/attio-crud.integration.test.ts +361 -361
- package/src/execution/engine/tools/integration/server/adapters/attio/attio-adapter.ts +162 -162
- package/src/execution/engine/tools/integration/server/adapters/attio/attio-tools.ts +594 -594
- package/src/execution/engine/tools/integration/server/adapters/attio/fetch/create-attribute/index.ts +214 -214
- package/src/execution/engine/tools/integration/server/adapters/attio/fetch/create-note/index.ts +152 -152
- package/src/execution/engine/tools/integration/server/adapters/attio/fetch/create-record/index.ts +141 -141
- package/src/execution/engine/tools/integration/server/adapters/attio/fetch/delete-note/index.ts +86 -86
- package/src/execution/engine/tools/integration/server/adapters/attio/fetch/delete-record/index.ts +105 -105
- package/src/execution/engine/tools/integration/server/adapters/attio/fetch/get-record/index.ts +118 -118
- package/src/execution/engine/tools/integration/server/adapters/attio/fetch/list-attributes/index.ts +165 -165
- package/src/execution/engine/tools/integration/server/adapters/attio/fetch/list-notes/index.ts +96 -96
- package/src/execution/engine/tools/integration/server/adapters/attio/fetch/list-objects/index.ts +104 -104
- package/src/execution/engine/tools/integration/server/adapters/attio/fetch/list-records/index.ts +156 -156
- package/src/execution/engine/tools/integration/server/adapters/attio/fetch/update-attribute/index.ts +220 -220
- package/src/execution/engine/tools/integration/server/adapters/attio/fetch/update-record/index.ts +140 -140
- package/src/execution/engine/tools/integration/server/adapters/attio/fetch/utils/types.ts +146 -146
- package/src/execution/engine/tools/integration/server/adapters/attio/index.ts +31 -31
- package/src/execution/engine/tools/integration/server/adapters/gmail/gmail-adapter.ts +210 -210
- package/src/execution/engine/tools/integration/server/adapters/gmail/gmail-tools.ts +104 -104
- package/src/execution/engine/tools/integration/server/adapters/google-sheets/__tests__/google-sheets.integration.test.ts +261 -261
- package/src/execution/engine/tools/integration/server/adapters/google-sheets/google-sheets-adapter.ts +1189 -1189
- package/src/execution/engine/tools/integration/server/adapters/google-sheets/google-sheets-tools.ts +641 -641
- package/src/execution/engine/tools/integration/server/adapters/google-sheets/index.ts +18 -18
- package/src/execution/engine/tools/integration/server/adapters/instantly/fetch/activate-campaign/index.ts +86 -86
- package/src/execution/engine/tools/integration/server/adapters/instantly/fetch/add-to-campaign/__tests__/index.test.ts +289 -289
- package/src/execution/engine/tools/integration/server/adapters/instantly/fetch/add-to-campaign/index.ts +154 -154
- package/src/execution/engine/tools/integration/server/adapters/instantly/fetch/bulk-add-leads/__tests__/index.test.ts +325 -325
- package/src/execution/engine/tools/integration/server/adapters/instantly/fetch/bulk-add-leads/index.ts +153 -153
- package/src/execution/engine/tools/integration/server/adapters/instantly/fetch/bulk-delete-leads/index.ts +84 -84
- package/src/execution/engine/tools/integration/server/adapters/instantly/fetch/create-campaign/index.ts +125 -125
- package/src/execution/engine/tools/integration/server/adapters/instantly/fetch/create-inbox-test/index.ts +107 -107
- package/src/execution/engine/tools/integration/server/adapters/instantly/fetch/delete-campaign/index.ts +85 -85
- package/src/execution/engine/tools/integration/server/adapters/instantly/fetch/get-account-health/index.ts +91 -91
- package/src/execution/engine/tools/integration/server/adapters/instantly/fetch/get-campaign/index.ts +92 -92
- package/src/execution/engine/tools/integration/server/adapters/instantly/fetch/get-campaign-analytics/__tests__/index.test.ts +195 -195
- package/src/execution/engine/tools/integration/server/adapters/instantly/fetch/get-campaign-analytics/index.ts +113 -113
- package/src/execution/engine/tools/integration/server/adapters/instantly/fetch/get-daily-campaign-analytics/index.ts +104 -104
- package/src/execution/engine/tools/integration/server/adapters/instantly/fetch/get-emails/index.ts +155 -155
- package/src/execution/engine/tools/integration/server/adapters/instantly/fetch/get-step-analytics/__tests__/index.test.ts +196 -196
- package/src/execution/engine/tools/integration/server/adapters/instantly/fetch/get-step-analytics/index.ts +102 -102
- package/src/execution/engine/tools/integration/server/adapters/instantly/fetch/list-campaigns/__tests__/index.test.ts +189 -189
- package/src/execution/engine/tools/integration/server/adapters/instantly/fetch/list-campaigns/index.ts +87 -87
- package/src/execution/engine/tools/integration/server/adapters/instantly/fetch/list-leads/index.ts +112 -112
- package/src/execution/engine/tools/integration/server/adapters/instantly/fetch/patch-lead/index.ts +76 -76
- package/src/execution/engine/tools/integration/server/adapters/instantly/fetch/pause-campaign/index.ts +86 -86
- package/src/execution/engine/tools/integration/server/adapters/instantly/fetch/remove-from-subsequence/index.ts +98 -98
- package/src/execution/engine/tools/integration/server/adapters/instantly/fetch/send-reply/index.ts +126 -126
- package/src/execution/engine/tools/integration/server/adapters/instantly/fetch/update-campaign/__tests__/index.test.ts +193 -193
- package/src/execution/engine/tools/integration/server/adapters/instantly/fetch/update-campaign/index.ts +99 -99
- package/src/execution/engine/tools/integration/server/adapters/instantly/fetch/update-interest-status/__tests__/index.test.ts +621 -621
- package/src/execution/engine/tools/integration/server/adapters/instantly/fetch/update-interest-status/index.ts +125 -125
- package/src/execution/engine/tools/integration/server/adapters/instantly/index.ts +29 -29
- package/src/execution/engine/tools/integration/server/adapters/instantly/instantly-adapter.ts +178 -178
- package/src/execution/engine/tools/integration/server/adapters/instantly/instantly-tools.ts +1473 -1473
- package/src/execution/engine/tools/integration/server/adapters/millionverifier/fetch/check-credits/index.ts +59 -59
- package/src/execution/engine/tools/integration/server/adapters/millionverifier/fetch/verify-email/index.ts +102 -102
- package/src/execution/engine/tools/integration/server/adapters/millionverifier/index.ts +17 -17
- package/src/execution/engine/tools/integration/server/adapters/millionverifier/millionverifier-adapter.ts +80 -80
- package/src/execution/engine/tools/integration/server/adapters/millionverifier/millionverifier-tools.ts +102 -102
- package/src/execution/engine/tools/integration/server/adapters/resend/fetch/get-email/index.ts +102 -102
- package/src/execution/engine/tools/integration/server/adapters/resend/fetch/send-email/index.ts +134 -134
- package/src/execution/engine/tools/integration/server/adapters/resend/fetch/utils/types.ts +75 -75
- package/src/execution/engine/tools/integration/server/adapters/resend/index.ts +27 -27
- package/src/execution/engine/tools/integration/server/adapters/resend/resend-adapter.ts +108 -108
- package/src/execution/engine/tools/integration/server/adapters/resend/resend-tools.ts +132 -132
- package/src/execution/engine/tools/integration/server/adapters/signature-api/fetch/create-envelope/index.ts +274 -274
- package/src/execution/engine/tools/integration/server/adapters/signature-api/fetch/download-document/index.ts +230 -230
- package/src/execution/engine/tools/integration/server/adapters/signature-api/fetch/get-envelope/index.ts +133 -133
- package/src/execution/engine/tools/integration/server/adapters/signature-api/fetch/void-envelope/index.ts +90 -90
- package/src/execution/engine/tools/integration/server/adapters/stripe/fetch/utils/types.ts +210 -210
- package/src/execution/engine/tools/integration/server/adapters/stripe/stripe-adapter.ts +517 -517
- package/src/execution/engine/tools/integration/server/adapters/stripe/stripe-tools.ts +309 -309
- package/src/execution/engine/tools/integration/server/adapters/tomba/fetch/domain-search/index.ts +133 -133
- package/src/execution/engine/tools/integration/server/adapters/tomba/fetch/email-finder/index.ts +122 -122
- package/src/execution/engine/tools/integration/server/adapters/tomba/fetch/email-verifier/index.ts +111 -111
- package/src/execution/engine/tools/integration/server/adapters/tomba/index.ts +11 -11
- package/src/execution/engine/tools/integration/server/adapters/tomba/tomba-adapter.ts +78 -78
- package/src/execution/engine/tools/integration/server/adapters/tomba/tomba-tools.ts +222 -222
- package/src/execution/engine/tools/integration/server/index.ts +61 -61
- package/src/execution/engine/tools/integration/service.ts +161 -161
- package/src/execution/engine/tools/integration/tool.ts +253 -253
- package/src/execution/engine/tools/integration/types/anymailfinder.ts +74 -74
- package/src/execution/engine/tools/integration/types/apify.ts +92 -92
- package/src/execution/engine/tools/integration/types/index.ts +19 -19
- package/src/execution/engine/tools/integration/types/instantly.ts +557 -557
- package/src/execution/engine/tools/integration/types/millionverifier.ts +56 -56
- package/src/execution/engine/tools/integration/types/stripe.ts +162 -162
- package/src/execution/engine/tools/integration/types/tomba.ts +94 -94
- package/src/execution/engine/tools/lead-service-types.ts +884 -884
- package/src/execution/engine/tools/llm/index.ts +11 -11
- package/src/execution/engine/tools/llm/server/index.ts +8 -8
- package/src/execution/engine/tools/llm/server/llm-call-tool.ts +118 -118
- package/src/execution/engine/tools/platform/__tests__/pdf.test.ts +441 -441
- package/src/execution/engine/tools/platform/acquisition/company-tools.ts +248 -248
- package/src/execution/engine/tools/platform/acquisition/contact-tools.ts +319 -319
- package/src/execution/engine/tools/platform/acquisition/index.ts +43 -43
- package/src/execution/engine/tools/platform/acquisition/list-tools.ts +148 -148
- package/src/execution/engine/tools/platform/acquisition/types.ts +260 -260
- package/src/execution/engine/tools/platform/email/index.ts +122 -122
- package/src/execution/engine/tools/platform/email/types.ts +96 -96
- package/src/execution/engine/tools/platform/index.ts +157 -157
- package/src/execution/engine/tools/platform/notification.ts +81 -81
- package/src/execution/engine/tools/platform/pdf/index.ts +110 -110
- package/src/execution/engine/tools/platform/pdf/types.ts +77 -77
- package/src/execution/engine/tools/platform/scheduler.ts +87 -87
- package/src/execution/engine/tools/platform/storage/index.ts +370 -370
- package/src/execution/engine/tools/platform/types.ts +148 -148
- package/src/execution/engine/tools/registry.ts +700 -699
- package/src/execution/engine/tools/tool-maps.ts +786 -786
- package/src/execution/engine/tools/types.ts +233 -233
- package/src/execution/engine/workflow/__tests__/errors.test.ts +139 -139
- package/src/execution/engine/workflow/errors.ts +63 -63
- package/src/execution/engine/workflow/helpers/index.ts +11 -11
- package/src/execution/engine/workflow/helpers/server/index.ts +8 -8
- package/src/execution/engine/workflow/helpers/server/llm-call.ts +93 -93
- package/src/execution/engine/workflow/index.ts +19 -19
- package/src/execution/engine/workflow/log-truncate.ts +26 -26
- package/src/execution/engine/workflow/logging.ts +191 -191
- package/src/execution/engine/workflow/types.ts +182 -182
- package/src/execution/engine/workflow/utils.ts +280 -280
- package/src/execution/engine/workflow/workflow.ts +168 -168
- package/src/execution/index.ts +3 -3
- package/src/execution/scheduler/__tests__/api-schemas.test.ts +733 -733
- package/src/execution/scheduler/__tests__/utils.test.ts +1009 -1009
- package/src/execution/scheduler/api-schemas.ts +296 -296
- package/src/execution/scheduler/index.ts +50 -50
- package/src/execution/scheduler/schemas.ts +264 -264
- package/src/execution/scheduler/types.ts +111 -111
- package/src/execution/scheduler/utils.ts +364 -364
- package/src/forms/index.ts +7 -7
- package/src/forms/schemas.ts +69 -69
- package/src/forms/types.ts +70 -70
- package/src/index.ts +71 -60
- package/src/integrations/credentials/__tests__/schemas.test.ts +82 -82
- package/src/integrations/credentials/__tests__/utils.test.ts +144 -144
- package/src/integrations/credentials/api-schemas.ts +143 -143
- package/src/integrations/credentials/index.ts +32 -32
- package/src/integrations/credentials/schemas.ts +164 -164
- package/src/integrations/credentials/utils.ts +59 -59
- package/src/integrations/oauth/__tests__/provider-registry.test.ts +59 -59
- package/src/integrations/oauth/api-schemas.ts +92 -92
- package/src/integrations/oauth/index.ts +19 -19
- package/src/integrations/oauth/provider-registry.ts +61 -61
- package/src/integrations/oauth/server/__tests__/refresh-concurrent.test.ts +183 -183
- package/src/integrations/oauth/server/__tests__/refresh.test.ts +577 -577
- package/src/integrations/oauth/server/credentials.ts +39 -39
- package/src/integrations/oauth/server/refresh.ts +214 -214
- package/src/integrations/oauth/types.ts +34 -34
- package/src/integrations/webhook-endpoints/__tests__/api-schemas.test.ts +318 -318
- package/src/integrations/webhook-endpoints/api-schemas.ts +102 -102
- package/src/integrations/webhook-endpoints/index.ts +28 -28
- package/src/integrations/webhook-endpoints/types.ts +51 -51
- package/src/operations/activities/api-schemas.ts +79 -79
- package/src/operations/activities/index.ts +9 -9
- package/src/operations/activities/sse-events.ts +30 -30
- package/src/operations/activities/types.ts +63 -63
- package/src/operations/debug-logs/client.ts +60 -60
- package/src/operations/debug-logs/debug-logger.ts +83 -83
- package/src/operations/debug-logs/index.ts +8 -8
- package/src/operations/debug-logs/server.ts +19 -19
- package/src/operations/debug-logs/types.ts +33 -33
- package/src/operations/index.ts +50 -50
- package/src/operations/notifications/api-schemas.ts +91 -91
- package/src/operations/notifications/index.ts +3 -3
- package/src/operations/notifications/sse-events.ts +21 -21
- package/src/operations/notifications/types.ts +47 -47
- package/src/operations/observability/__tests__/openrouter-cost-flow.test.ts +297 -297
- package/src/operations/observability/__tests__/utils.test.ts +54 -54
- package/src/operations/observability/ai-usage-collector.ts +64 -64
- package/src/operations/observability/index.ts +13 -13
- package/src/operations/observability/metrics-collector.ts +49 -49
- package/src/operations/observability/schemas.ts +39 -39
- package/src/operations/observability/types.ts +463 -463
- package/src/operations/observability/utils.ts +77 -77
- package/src/operations/sessions/__tests__/manager.test.ts +821 -821
- package/src/operations/sessions/index.ts +26 -26
- package/src/operations/sessions/server/manager.ts +90 -90
- package/src/operations/sessions/server/session.ts +180 -180
- package/src/operations/sessions/types.ts +98 -98
- package/src/operations/triggers/index.ts +12 -12
- package/src/operations/triggers/webhook/definitions/instantly-account-error.ts +44 -44
- package/src/operations/triggers/webhook/definitions/instantly-auto-reply-received.ts +51 -51
- package/src/operations/triggers/webhook/definitions/instantly-campaign-completed.ts +45 -45
- package/src/operations/triggers/webhook/definitions/instantly-email-bounced.ts +49 -49
- package/src/operations/triggers/webhook/definitions/instantly-lead-unsubscribed.ts +45 -45
- package/src/operations/triggers/webhook/definitions/instantly-reply-received.ts +54 -54
- package/src/operations/triggers/webhook/index.ts +35 -35
- package/src/operations/triggers/webhook/types.ts +74 -74
- package/src/organization-model/README.md +97 -97
- package/src/organization-model/__tests__/defaults.test.ts +175 -175
- package/src/organization-model/__tests__/domains/customers.test.ts +295 -295
- package/src/organization-model/__tests__/domains/goals.test.ts +479 -479
- package/src/organization-model/__tests__/domains/identity.test.ts +279 -279
- package/src/organization-model/__tests__/domains/navigation.test.ts +212 -212
- package/src/organization-model/__tests__/domains/offerings.test.ts +419 -419
- package/src/organization-model/__tests__/domains/operations.test.ts +203 -203
- package/src/organization-model/__tests__/domains/resource-mappings.test.ts +362 -362
- package/src/organization-model/__tests__/domains/roles.test.ts +347 -347
- package/src/organization-model/__tests__/domains/statuses.test.ts +243 -243
- package/src/organization-model/__tests__/foundation.test.ts +105 -105
- package/src/organization-model/__tests__/graph.test.ts +894 -894
- package/src/organization-model/__tests__/resolve.test.ts +690 -690
- package/src/organization-model/__tests__/schema.test.ts +407 -407
- package/src/organization-model/contracts.ts +14 -14
- package/src/organization-model/defaults.ts +148 -148
- package/src/organization-model/domains/branding.ts +22 -22
- package/src/organization-model/domains/customers.ts +75 -75
- package/src/organization-model/domains/features.ts +22 -22
- package/src/organization-model/domains/goals.ts +80 -80
- package/src/organization-model/domains/identity.ts +94 -94
- package/src/organization-model/domains/navigation.ts +391 -391
- package/src/organization-model/domains/offerings.ts +66 -66
- package/src/organization-model/domains/operations.ts +85 -85
- package/src/organization-model/domains/projects.ts +48 -48
- package/src/organization-model/domains/prospecting.ts +33 -33
- package/src/organization-model/domains/roles.ts +55 -55
- package/src/organization-model/domains/sales.ts +94 -94
- package/src/organization-model/domains/shared.ts +62 -62
- package/src/organization-model/domains/statuses.ts +130 -130
- package/src/organization-model/foundation.ts +97 -97
- package/src/organization-model/graph/build.ts +399 -399
- package/src/organization-model/graph/index.ts +4 -4
- package/src/organization-model/graph/schema.ts +48 -48
- package/src/organization-model/graph/types.ts +40 -40
- package/src/organization-model/index.ts +13 -13
- package/src/organization-model/organization-graph.mdx +272 -272
- package/src/organization-model/organization-model.mdx +320 -320
- package/src/organization-model/published.ts +85 -85
- package/src/organization-model/resolve.ts +66 -66
- package/src/organization-model/schema.ts +287 -287
- package/src/organization-model/types.ts +46 -46
- package/src/platform/api/index.ts +1 -1
- package/src/platform/api/types.ts +35 -35
- package/src/platform/constants/http.ts +37 -37
- package/src/platform/constants/index.ts +5 -5
- package/src/platform/constants/limits.ts +32 -32
- package/src/platform/constants/resilience.ts +51 -51
- package/src/platform/constants/timeouts.ts +20 -20
- package/src/platform/constants/versions.ts +3 -3
- package/src/platform/registry/__tests__/resource-registry-static.test.ts +347 -347
- package/src/platform/registry/__tests__/resource-registry.integration.test.ts +1028 -1028
- package/src/platform/registry/__tests__/resource-registry.list-executable.test.ts +393 -393
- package/src/platform/registry/__tests__/resource-registry.test.ts +2005 -2005
- package/src/platform/registry/__tests__/serialization.test.ts +1127 -1127
- package/src/platform/registry/command-view.ts +180 -180
- package/src/platform/registry/domains.ts +165 -165
- package/src/platform/registry/index.ts +93 -93
- package/src/platform/registry/reserved.ts +24 -24
- package/src/platform/registry/resource-metadata.ts +59 -59
- package/src/platform/registry/resource-registry.command-queue-groups.test.ts +129 -129
- package/src/platform/registry/resource-registry.ts +876 -876
- package/src/platform/registry/serialization.ts +273 -273
- package/src/platform/registry/serialized-types.ts +231 -231
- package/src/platform/registry/stats-types.ts +66 -66
- package/src/platform/registry/types.ts +404 -404
- package/src/platform/registry/validation.ts +513 -513
- package/src/platform/resilience/__tests__/rate-limiter.test.ts +471 -471
- package/src/platform/resilience/circuit-breaker.ts +164 -164
- package/src/platform/resilience/errors.ts +68 -68
- package/src/platform/resilience/http-error-mapper.ts +129 -129
- package/src/platform/resilience/index.ts +93 -93
- package/src/platform/resilience/rate-limiter-types.ts +46 -46
- package/src/platform/resilience/rate-limiter.ts +140 -140
- package/src/platform/resilience/retry.ts +89 -89
- package/src/platform/resilience/timeout.ts +63 -63
- package/src/platform/sse/events.ts +37 -34
- package/src/platform/sse/index.ts +7 -7
- package/src/platform/utils/__tests__/validation.test.ts +1083 -1083
- package/src/platform/utils/currency.ts +96 -96
- package/src/platform/utils/debounce.ts +52 -52
- package/src/platform/utils/error.ts +41 -41
- package/src/platform/utils/hmac.test.ts +97 -97
- package/src/platform/utils/index.ts +32 -32
- package/src/platform/utils/server/betterstack-logger.ts +210 -210
- package/src/platform/utils/server/hmac.ts +44 -44
- package/src/platform/utils/server/unsubscribe.ts +111 -111
- package/src/platform/utils/token-counter.ts +96 -96
- package/src/platform/utils/validation.ts +425 -425
- package/src/projects/api-schemas.ts +268 -268
- package/src/published.ts +1 -1
- package/src/reference/_generated/contracts.md +611 -607
- package/src/reference/glossary.md +105 -105
- package/src/requests/__tests__/api-schemas.test.ts +277 -277
- package/src/requests/api-schemas.ts +83 -83
- package/src/requests/index.ts +1 -1
- package/src/scaffold-registry/__tests__/index.test.ts +17 -0
- package/src/scaffold-registry/__tests__/schema.test.ts +329 -230
- package/src/scaffold-registry/index.ts +205 -189
- package/src/scaffold-registry/schema.ts +196 -128
- package/src/server.ts +272 -272
- package/src/supabase/database.types.ts +2719 -2719
- package/src/supabase/helpers.ts +20 -20
- package/src/supabase/index.ts +52 -52
- package/src/supabase/server/client.ts +58 -58
- package/src/test-utils/README.md +38 -38
- package/src/test-utils/browser-mocks.ts +54 -54
- package/src/test-utils/fixtures/api-keys.ts +52 -52
- package/src/test-utils/fixtures/index.ts +4 -4
- package/src/test-utils/fixtures/memberships.ts +80 -80
- package/src/test-utils/fixtures/organizations.ts +69 -69
- package/src/test-utils/fixtures/users.ts +79 -79
- package/src/test-utils/index.ts +11 -11
- package/src/test-utils/mocks/index.ts +2 -2
- package/src/test-utils/mocks/supabase.ts +142 -142
- package/src/test-utils/mocks/workos.ts +108 -108
- package/src/test-utils/rls/RLSTestContext.ts +556 -556
- package/src/test-utils/rls/index.ts +1 -1
|
@@ -1,531 +1,531 @@
|
|
|
1
|
-
import { describe, it, expect, vi } from 'vitest'
|
|
2
|
-
import { processActions } from '../processor'
|
|
3
|
-
import type { IterationContext } from '../../core/types'
|
|
4
|
-
import type { LLMIterationResponse } from '../../reasoning/types'
|
|
5
|
-
import type { AgentAction, ToolCallAction, CompleteAction, MessageAction } from '../types'
|
|
6
|
-
import type { ExecutionContext } from '../../../base/types'
|
|
7
|
-
|
|
8
|
-
describe('processActions - validateActionSequence', () => {
|
|
9
|
-
const createMockIterationContext = (): IterationContext => {
|
|
10
|
-
const mockMemoryManager: Record<string, unknown> = {
|
|
11
|
-
addToHistory: vi.fn(),
|
|
12
|
-
getHistory: vi.fn(() => []),
|
|
13
|
-
estimateTokens: vi.fn(() => 0),
|
|
14
|
-
clear: vi.fn()
|
|
15
|
-
}
|
|
16
|
-
const context = {
|
|
17
|
-
executionContext: {
|
|
18
|
-
executionId: 'exec-123',
|
|
19
|
-
organizationId: 'org-123',
|
|
20
|
-
userId: 'user-123',
|
|
21
|
-
logger: {
|
|
22
|
-
info: vi.fn(),
|
|
23
|
-
error: vi.fn(),
|
|
24
|
-
warn: vi.fn(),
|
|
25
|
-
debug: vi.fn()
|
|
26
|
-
}
|
|
27
|
-
} as ExecutionContext,
|
|
28
|
-
toolRegistry: new Map(),
|
|
29
|
-
config: {
|
|
30
|
-
type: 'agent' as const,
|
|
31
|
-
resourceId: 'test-agent',
|
|
32
|
-
name: 'Test Agent',
|
|
33
|
-
description: 'Test',
|
|
34
|
-
environment: 'dev',
|
|
35
|
-
systemPrompt: 'Test'
|
|
36
|
-
},
|
|
37
|
-
contract: {
|
|
38
|
-
inputSchema: {},
|
|
39
|
-
outputSchema: {}
|
|
40
|
-
},
|
|
41
|
-
logger: {
|
|
42
|
-
action: vi.fn(),
|
|
43
|
-
info: vi.fn(),
|
|
44
|
-
error: vi.fn(),
|
|
45
|
-
warn: vi.fn(),
|
|
46
|
-
debug: vi.fn()
|
|
47
|
-
},
|
|
48
|
-
modelConfig: {
|
|
49
|
-
provider: 'mock' as const,
|
|
50
|
-
model: 'mock',
|
|
51
|
-
apiKey: 'test'
|
|
52
|
-
},
|
|
53
|
-
memoryManager: mockMemoryManager,
|
|
54
|
-
iteration: 0
|
|
55
|
-
} as IterationContext
|
|
56
|
-
return context
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
const createMockResponse = (actions: AgentAction[]): LLMIterationResponse => ({
|
|
60
|
-
reasoning: 'Test reasoning',
|
|
61
|
-
nextActions: actions
|
|
62
|
-
})
|
|
63
|
-
|
|
64
|
-
describe('valid action sequences', () => {
|
|
65
|
-
it('allows single complete action', async () => {
|
|
66
|
-
const context = createMockIterationContext()
|
|
67
|
-
const response = createMockResponse([{ type: 'complete' }])
|
|
68
|
-
|
|
69
|
-
const result = await processActions(context, response)
|
|
70
|
-
|
|
71
|
-
expect(result.shouldComplete).toBe(true)
|
|
72
|
-
})
|
|
73
|
-
|
|
74
|
-
it('allows single tool-call action', async () => {
|
|
75
|
-
const context = createMockIterationContext()
|
|
76
|
-
const toolAction: ToolCallAction = {
|
|
77
|
-
type: 'tool-call',
|
|
78
|
-
id: 'tool-1',
|
|
79
|
-
name: 'testTool',
|
|
80
|
-
input: {}
|
|
81
|
-
}
|
|
82
|
-
const response = createMockResponse([toolAction])
|
|
83
|
-
|
|
84
|
-
// Tool not found is handled gracefully (adds error to memory, doesn't throw)
|
|
85
|
-
const result = await processActions(context, response)
|
|
86
|
-
expect(result.shouldComplete).toBe(false)
|
|
87
|
-
})
|
|
88
|
-
|
|
89
|
-
it('allows multiple tool-call actions', async () => {
|
|
90
|
-
const context = createMockIterationContext()
|
|
91
|
-
const actions: ToolCallAction[] = [
|
|
92
|
-
{ type: 'tool-call', id: 'tool-1', name: 'tool1', input: {} },
|
|
93
|
-
{ type: 'tool-call', id: 'tool-2', name: 'tool2', input: {} }
|
|
94
|
-
]
|
|
95
|
-
const response = createMockResponse(actions)
|
|
96
|
-
|
|
97
|
-
// Tools not found are handled gracefully (adds errors to memory, doesn't throw)
|
|
98
|
-
const result = await processActions(context, response)
|
|
99
|
-
expect(result.shouldComplete).toBe(false)
|
|
100
|
-
})
|
|
101
|
-
|
|
102
|
-
it('allows message action before complete', async () => {
|
|
103
|
-
const context = createMockIterationContext()
|
|
104
|
-
const actions: AgentAction[] = [{ type: 'message', text: 'Processing complete' }, { type: 'complete' }]
|
|
105
|
-
const response = createMockResponse(actions)
|
|
106
|
-
|
|
107
|
-
const result = await processActions(context, response)
|
|
108
|
-
|
|
109
|
-
expect(result.shouldComplete).toBe(true)
|
|
110
|
-
})
|
|
111
|
-
|
|
112
|
-
it('allows multiple message actions before complete', async () => {
|
|
113
|
-
const context = createMockIterationContext()
|
|
114
|
-
const actions: AgentAction[] = [
|
|
115
|
-
{ type: 'message', text: 'Step 1 done' },
|
|
116
|
-
{ type: 'message', text: 'Step 2 done' },
|
|
117
|
-
{ type: 'complete' }
|
|
118
|
-
]
|
|
119
|
-
const response = createMockResponse(actions)
|
|
120
|
-
|
|
121
|
-
const result = await processActions(context, response)
|
|
122
|
-
|
|
123
|
-
expect(result.shouldComplete).toBe(true)
|
|
124
|
-
})
|
|
125
|
-
})
|
|
126
|
-
|
|
127
|
-
describe('invalid action sequences', () => {
|
|
128
|
-
it('throws error for multiple complete actions', async () => {
|
|
129
|
-
const context = createMockIterationContext()
|
|
130
|
-
const actions: CompleteAction[] = [{ type: 'complete' }, { type: 'complete' }]
|
|
131
|
-
const response = createMockResponse(actions)
|
|
132
|
-
|
|
133
|
-
await expect(processActions(context, response)).rejects.toThrow(
|
|
134
|
-
'Multiple complete actions not allowed in single iteration'
|
|
135
|
-
)
|
|
136
|
-
})
|
|
137
|
-
|
|
138
|
-
it('allows tool-call mixed with complete (side-effect tools execute first)', async () => {
|
|
139
|
-
const context = createMockIterationContext()
|
|
140
|
-
|
|
141
|
-
const mockTool = {
|
|
142
|
-
name: 'testTool',
|
|
143
|
-
inputSchema: { parse: (x: unknown) => x },
|
|
144
|
-
outputSchema: { parse: (x: unknown) => x },
|
|
145
|
-
execute: vi.fn(async () => ({ result: 'done' }))
|
|
146
|
-
}
|
|
147
|
-
context.toolRegistry.set('testTool', mockTool as unknown as import('../../tools/types').Tool)
|
|
148
|
-
|
|
149
|
-
const actions: AgentAction[] = [
|
|
150
|
-
{ type: 'tool-call', id: 'tool-1', name: 'testTool', input: {} },
|
|
151
|
-
{ type: 'complete' }
|
|
152
|
-
]
|
|
153
|
-
const response = createMockResponse(actions)
|
|
154
|
-
|
|
155
|
-
const result = await processActions(context, response)
|
|
156
|
-
|
|
157
|
-
expect(mockTool.execute).toHaveBeenCalledTimes(1)
|
|
158
|
-
expect(result.shouldComplete).toBe(true)
|
|
159
|
-
})
|
|
160
|
-
|
|
161
|
-
it('allows complete before tool-call (tools still execute first)', async () => {
|
|
162
|
-
const context = createMockIterationContext()
|
|
163
|
-
|
|
164
|
-
const mockTool = {
|
|
165
|
-
name: 'testTool',
|
|
166
|
-
inputSchema: { parse: (x: unknown) => x },
|
|
167
|
-
outputSchema: { parse: (x: unknown) => x },
|
|
168
|
-
execute: vi.fn(async () => ({ result: 'done' }))
|
|
169
|
-
}
|
|
170
|
-
context.toolRegistry.set('testTool', mockTool as unknown as import('../../tools/types').Tool)
|
|
171
|
-
|
|
172
|
-
const actions: AgentAction[] = [
|
|
173
|
-
{ type: 'complete' },
|
|
174
|
-
{ type: 'tool-call', id: 'tool-1', name: 'testTool', input: {} }
|
|
175
|
-
]
|
|
176
|
-
const response = createMockResponse(actions)
|
|
177
|
-
|
|
178
|
-
const result = await processActions(context, response)
|
|
179
|
-
|
|
180
|
-
expect(mockTool.execute).toHaveBeenCalledTimes(1)
|
|
181
|
-
expect(result.shouldComplete).toBe(true)
|
|
182
|
-
})
|
|
183
|
-
})
|
|
184
|
-
|
|
185
|
-
describe('action processing behavior', () => {
|
|
186
|
-
it('handles message action with session context', async () => {
|
|
187
|
-
const onMessageEvent = vi.fn()
|
|
188
|
-
|
|
189
|
-
const context = createMockIterationContext()
|
|
190
|
-
context.executionContext.onMessageEvent = onMessageEvent
|
|
191
|
-
|
|
192
|
-
const messageAction: MessageAction = {
|
|
193
|
-
type: 'message',
|
|
194
|
-
text: 'Hello from agent'
|
|
195
|
-
}
|
|
196
|
-
const response = createMockResponse([messageAction, { type: 'complete' }])
|
|
197
|
-
|
|
198
|
-
await processActions(context, response)
|
|
199
|
-
|
|
200
|
-
expect(onMessageEvent).toHaveBeenCalledWith({
|
|
201
|
-
type: 'assistant_message',
|
|
202
|
-
text: 'Hello from agent'
|
|
203
|
-
})
|
|
204
|
-
})
|
|
205
|
-
|
|
206
|
-
it('handles message action without session context', async () => {
|
|
207
|
-
const context = createMockIterationContext()
|
|
208
|
-
// No sessionContext
|
|
209
|
-
|
|
210
|
-
const messageAction: MessageAction = {
|
|
211
|
-
type: 'message',
|
|
212
|
-
text: 'Hello from agent'
|
|
213
|
-
}
|
|
214
|
-
const response = createMockResponse([messageAction, { type: 'complete' }])
|
|
215
|
-
|
|
216
|
-
// Should not throw - just silently skip streaming
|
|
217
|
-
const result = await processActions(context, response)
|
|
218
|
-
|
|
219
|
-
expect(result.shouldComplete).toBe(true)
|
|
220
|
-
})
|
|
221
|
-
|
|
222
|
-
it('processes multiple messages in order', async () => {
|
|
223
|
-
const onMessageEvent = vi.fn()
|
|
224
|
-
|
|
225
|
-
const context = createMockIterationContext()
|
|
226
|
-
context.executionContext.onMessageEvent = onMessageEvent
|
|
227
|
-
|
|
228
|
-
const actions: AgentAction[] = [
|
|
229
|
-
{ type: 'message', text: 'First message' },
|
|
230
|
-
{ type: 'message', text: 'Second message' },
|
|
231
|
-
{ type: 'message', text: 'Third message' },
|
|
232
|
-
{ type: 'complete' }
|
|
233
|
-
]
|
|
234
|
-
const response = createMockResponse(actions)
|
|
235
|
-
|
|
236
|
-
await processActions(context, response)
|
|
237
|
-
|
|
238
|
-
expect(onMessageEvent).toHaveBeenCalledTimes(3)
|
|
239
|
-
expect(onMessageEvent).toHaveBeenNthCalledWith(1, {
|
|
240
|
-
type: 'assistant_message',
|
|
241
|
-
text: 'First message'
|
|
242
|
-
})
|
|
243
|
-
expect(onMessageEvent).toHaveBeenNthCalledWith(2, {
|
|
244
|
-
type: 'assistant_message',
|
|
245
|
-
text: 'Second message'
|
|
246
|
-
})
|
|
247
|
-
expect(onMessageEvent).toHaveBeenNthCalledWith(3, {
|
|
248
|
-
type: 'assistant_message',
|
|
249
|
-
text: 'Third message'
|
|
250
|
-
})
|
|
251
|
-
})
|
|
252
|
-
|
|
253
|
-
it('returns shouldComplete: false when no complete action', async () => {
|
|
254
|
-
const context = createMockIterationContext()
|
|
255
|
-
const response = createMockResponse([])
|
|
256
|
-
|
|
257
|
-
const result = await processActions(context, response)
|
|
258
|
-
|
|
259
|
-
expect(result.shouldComplete).toBe(false)
|
|
260
|
-
})
|
|
261
|
-
|
|
262
|
-
it('returns shouldComplete: true when complete action present', async () => {
|
|
263
|
-
const context = createMockIterationContext()
|
|
264
|
-
const response = createMockResponse([{ type: 'complete' }])
|
|
265
|
-
|
|
266
|
-
const result = await processActions(context, response)
|
|
267
|
-
|
|
268
|
-
expect(result.shouldComplete).toBe(true)
|
|
269
|
-
})
|
|
270
|
-
})
|
|
271
|
-
|
|
272
|
-
describe('edge cases', () => {
|
|
273
|
-
it('handles empty action array', async () => {
|
|
274
|
-
const context = createMockIterationContext()
|
|
275
|
-
const response = createMockResponse([])
|
|
276
|
-
|
|
277
|
-
const result = await processActions(context, response)
|
|
278
|
-
|
|
279
|
-
expect(result.shouldComplete).toBe(false)
|
|
280
|
-
})
|
|
281
|
-
|
|
282
|
-
it('validates actions before executing any', async () => {
|
|
283
|
-
const context = createMockIterationContext()
|
|
284
|
-
const executeTool = vi.fn()
|
|
285
|
-
const mockTool = { name: 'testTool', execute: executeTool } as Partial<import('../../tools/types').Tool>
|
|
286
|
-
context.toolRegistry.set('testTool', mockTool as import('../../tools/types').Tool)
|
|
287
|
-
|
|
288
|
-
// Invalid: multiple completes
|
|
289
|
-
const actions: AgentAction[] = [
|
|
290
|
-
{ type: 'tool-call', id: 'tool-1', name: 'testTool', input: {} },
|
|
291
|
-
{ type: 'complete' },
|
|
292
|
-
{ type: 'complete' }
|
|
293
|
-
]
|
|
294
|
-
const response = createMockResponse(actions)
|
|
295
|
-
|
|
296
|
-
await expect(processActions(context, response)).rejects.toThrow('Multiple complete actions not allowed')
|
|
297
|
-
|
|
298
|
-
// Tool should NOT have been executed (validation happens first)
|
|
299
|
-
expect(executeTool).not.toHaveBeenCalled()
|
|
300
|
-
})
|
|
301
|
-
})
|
|
302
|
-
|
|
303
|
-
describe('validation rules compliance', () => {
|
|
304
|
-
it('enforces Rule 1: no duplicate completions', async () => {
|
|
305
|
-
const context = createMockIterationContext()
|
|
306
|
-
const actions = [{ type: 'complete' }, { type: 'complete' }, { type: 'complete' }] as AgentAction[]
|
|
307
|
-
const response = createMockResponse(actions)
|
|
308
|
-
|
|
309
|
-
await expect(processActions(context, response)).rejects.toThrow(
|
|
310
|
-
'Multiple complete actions not allowed in single iteration'
|
|
311
|
-
)
|
|
312
|
-
})
|
|
313
|
-
|
|
314
|
-
it('enforces Rule 2: complete cannot mix with navigate-knowledge', async () => {
|
|
315
|
-
const context = createMockIterationContext()
|
|
316
|
-
const actions: AgentAction[] = [
|
|
317
|
-
{ type: 'complete' },
|
|
318
|
-
{ type: 'navigate-knowledge', id: 'nav-1', nodeId: 'node-1' }
|
|
319
|
-
]
|
|
320
|
-
const response = createMockResponse(actions)
|
|
321
|
-
|
|
322
|
-
await expect(processActions(context, response)).rejects.toThrow(
|
|
323
|
-
'Complete action cannot mix with navigate-knowledge actions'
|
|
324
|
-
)
|
|
325
|
-
})
|
|
326
|
-
|
|
327
|
-
it('allows Rule 2 exception: complete can mix with tool-call', async () => {
|
|
328
|
-
const context = createMockIterationContext()
|
|
329
|
-
const actions: AgentAction[] = [
|
|
330
|
-
{ type: 'complete' },
|
|
331
|
-
{ type: 'tool-call', id: 'tool-1', name: 'tool', input: {} }
|
|
332
|
-
]
|
|
333
|
-
const response = createMockResponse(actions)
|
|
334
|
-
|
|
335
|
-
// Should not throw — tool calls are side-effect compatible with completion
|
|
336
|
-
const result = await processActions(context, response)
|
|
337
|
-
expect(result.shouldComplete).toBe(true)
|
|
338
|
-
})
|
|
339
|
-
|
|
340
|
-
it('allows message with complete (exception to Rule 2)', async () => {
|
|
341
|
-
const context = createMockIterationContext()
|
|
342
|
-
const actions: AgentAction[] = [{ type: 'message', text: 'Done!' }, { type: 'complete' }]
|
|
343
|
-
const response = createMockResponse(actions)
|
|
344
|
-
|
|
345
|
-
const result = await processActions(context, response)
|
|
346
|
-
|
|
347
|
-
expect(result.shouldComplete).toBe(true)
|
|
348
|
-
})
|
|
349
|
-
})
|
|
350
|
-
|
|
351
|
-
describe('parallel tool execution', () => {
|
|
352
|
-
it('executes multiple tool calls concurrently', async () => {
|
|
353
|
-
const context = createMockIterationContext()
|
|
354
|
-
const executionOrder: string[] = []
|
|
355
|
-
|
|
356
|
-
// Create mock tools with configurable delays
|
|
357
|
-
const mockTool1 = {
|
|
358
|
-
name: 'tool1',
|
|
359
|
-
inputSchema: { parse: (x: unknown) => x },
|
|
360
|
-
outputSchema: { parse: (x: unknown) => x },
|
|
361
|
-
execute: vi.fn(async () => {
|
|
362
|
-
executionOrder.push('tool1-start')
|
|
363
|
-
await new Promise((resolve) => setTimeout(resolve, 50))
|
|
364
|
-
executionOrder.push('tool1-end')
|
|
365
|
-
return { result: 'tool1' }
|
|
366
|
-
})
|
|
367
|
-
}
|
|
368
|
-
const mockTool2 = {
|
|
369
|
-
name: 'tool2',
|
|
370
|
-
inputSchema: { parse: (x: unknown) => x },
|
|
371
|
-
outputSchema: { parse: (x: unknown) => x },
|
|
372
|
-
execute: vi.fn(async () => {
|
|
373
|
-
executionOrder.push('tool2-start')
|
|
374
|
-
await new Promise((resolve) => setTimeout(resolve, 50))
|
|
375
|
-
executionOrder.push('tool2-end')
|
|
376
|
-
return { result: 'tool2' }
|
|
377
|
-
})
|
|
378
|
-
}
|
|
379
|
-
|
|
380
|
-
context.toolRegistry.set('tool1', mockTool1 as unknown as import('../../tools/types').Tool)
|
|
381
|
-
context.toolRegistry.set('tool2', mockTool2 as unknown as import('../../tools/types').Tool)
|
|
382
|
-
|
|
383
|
-
const actions: ToolCallAction[] = [
|
|
384
|
-
{ type: 'tool-call', id: 'call-1', name: 'tool1', input: {} },
|
|
385
|
-
{ type: 'tool-call', id: 'call-2', name: 'tool2', input: {} }
|
|
386
|
-
]
|
|
387
|
-
const response = createMockResponse(actions)
|
|
388
|
-
|
|
389
|
-
await processActions(context, response)
|
|
390
|
-
|
|
391
|
-
// Both tools should have been executed
|
|
392
|
-
expect(mockTool1.execute).toHaveBeenCalledTimes(1)
|
|
393
|
-
expect(mockTool2.execute).toHaveBeenCalledTimes(1)
|
|
394
|
-
|
|
395
|
-
// Verify parallel execution: both starts should happen before any end
|
|
396
|
-
// (In sequential execution, we'd see: tool1-start, tool1-end, tool2-start, tool2-end)
|
|
397
|
-
const tool1StartIndex = executionOrder.indexOf('tool1-start')
|
|
398
|
-
const tool2StartIndex = executionOrder.indexOf('tool2-start')
|
|
399
|
-
const tool1EndIndex = executionOrder.indexOf('tool1-end')
|
|
400
|
-
const tool2EndIndex = executionOrder.indexOf('tool2-end')
|
|
401
|
-
|
|
402
|
-
// Both should start before either ends (parallel behavior)
|
|
403
|
-
expect(tool1StartIndex).toBeLessThan(tool1EndIndex)
|
|
404
|
-
expect(tool2StartIndex).toBeLessThan(tool2EndIndex)
|
|
405
|
-
// If running in parallel, both starts should happen before ends complete
|
|
406
|
-
expect(Math.max(tool1StartIndex, tool2StartIndex)).toBeLessThan(Math.max(tool1EndIndex, tool2EndIndex))
|
|
407
|
-
})
|
|
408
|
-
|
|
409
|
-
it('handles mixed actions: tool calls in parallel, others sequential', async () => {
|
|
410
|
-
const context = createMockIterationContext()
|
|
411
|
-
const onMessageEvent = vi.fn()
|
|
412
|
-
context.executionContext.onMessageEvent = onMessageEvent
|
|
413
|
-
|
|
414
|
-
// Create mock tools
|
|
415
|
-
const mockTool1 = {
|
|
416
|
-
name: 'tool1',
|
|
417
|
-
inputSchema: { parse: (x: unknown) => x },
|
|
418
|
-
outputSchema: { parse: (x: unknown) => x },
|
|
419
|
-
execute: vi.fn(async () => ({ result: 'tool1' }))
|
|
420
|
-
}
|
|
421
|
-
const mockTool2 = {
|
|
422
|
-
name: 'tool2',
|
|
423
|
-
inputSchema: { parse: (x: unknown) => x },
|
|
424
|
-
outputSchema: { parse: (x: unknown) => x },
|
|
425
|
-
execute: vi.fn(async () => ({ result: 'tool2' }))
|
|
426
|
-
}
|
|
427
|
-
|
|
428
|
-
context.toolRegistry.set('tool1', mockTool1 as unknown as import('../../tools/types').Tool)
|
|
429
|
-
context.toolRegistry.set('tool2', mockTool2 as unknown as import('../../tools/types').Tool)
|
|
430
|
-
|
|
431
|
-
// Mix tool calls with messages
|
|
432
|
-
const actions: AgentAction[] = [
|
|
433
|
-
{ type: 'message', text: 'Starting work...' },
|
|
434
|
-
{ type: 'tool-call', id: 'call-1', name: 'tool1', input: {} },
|
|
435
|
-
{ type: 'tool-call', id: 'call-2', name: 'tool2', input: {} }
|
|
436
|
-
]
|
|
437
|
-
const response = createMockResponse(actions)
|
|
438
|
-
|
|
439
|
-
await processActions(context, response)
|
|
440
|
-
|
|
441
|
-
// Both tools should be executed
|
|
442
|
-
expect(mockTool1.execute).toHaveBeenCalledTimes(1)
|
|
443
|
-
expect(mockTool2.execute).toHaveBeenCalledTimes(1)
|
|
444
|
-
|
|
445
|
-
// Message should also be sent
|
|
446
|
-
expect(onMessageEvent).toHaveBeenCalledWith({
|
|
447
|
-
type: 'assistant_message',
|
|
448
|
-
text: 'Starting work...'
|
|
449
|
-
})
|
|
450
|
-
})
|
|
451
|
-
|
|
452
|
-
it('handles partial failure: successful tools complete even when one fails', async () => {
|
|
453
|
-
const context = createMockIterationContext()
|
|
454
|
-
|
|
455
|
-
// Create one successful and one failing tool
|
|
456
|
-
const mockSuccessTool = {
|
|
457
|
-
name: 'successTool',
|
|
458
|
-
inputSchema: { parse: (x: unknown) => x },
|
|
459
|
-
outputSchema: { parse: (x: unknown) => x },
|
|
460
|
-
execute: vi.fn(async () => ({ result: 'success' }))
|
|
461
|
-
}
|
|
462
|
-
const mockFailTool = {
|
|
463
|
-
name: 'failTool',
|
|
464
|
-
inputSchema: { parse: (x: unknown) => x },
|
|
465
|
-
outputSchema: { parse: (x: unknown) => x },
|
|
466
|
-
execute: vi.fn(async () => {
|
|
467
|
-
throw new Error('Tool failed intentionally')
|
|
468
|
-
})
|
|
469
|
-
}
|
|
470
|
-
|
|
471
|
-
context.toolRegistry.set('successTool', mockSuccessTool as unknown as import('../../tools/types').Tool)
|
|
472
|
-
context.toolRegistry.set('failTool', mockFailTool as unknown as import('../../tools/types').Tool)
|
|
473
|
-
|
|
474
|
-
const actions: ToolCallAction[] = [
|
|
475
|
-
{ type: 'tool-call', id: 'call-1', name: 'successTool', input: {} },
|
|
476
|
-
{ type: 'tool-call', id: 'call-2', name: 'failTool', input: {} }
|
|
477
|
-
]
|
|
478
|
-
const response = createMockResponse(actions)
|
|
479
|
-
|
|
480
|
-
// Should not throw - Promise.allSettled handles partial failures
|
|
481
|
-
const result = await processActions(context, response)
|
|
482
|
-
|
|
483
|
-
// Both tools should have been attempted
|
|
484
|
-
expect(mockSuccessTool.execute).toHaveBeenCalledTimes(1)
|
|
485
|
-
expect(mockFailTool.execute).toHaveBeenCalledTimes(1)
|
|
486
|
-
|
|
487
|
-
// Should complete without throwing
|
|
488
|
-
expect(result.shouldComplete).toBe(false)
|
|
489
|
-
})
|
|
490
|
-
|
|
491
|
-
it('maintains timing advantage for parallel execution', async () => {
|
|
492
|
-
const context = createMockIterationContext()
|
|
493
|
-
const TOOL_DELAY = 100 // ms per tool (high enough to distinguish parallel vs sequential under load)
|
|
494
|
-
|
|
495
|
-
// Create multiple tools with configurable delays
|
|
496
|
-
const createDelayedTool = (name: string) => ({
|
|
497
|
-
name,
|
|
498
|
-
inputSchema: { parse: (x: unknown) => x },
|
|
499
|
-
outputSchema: { parse: (x: unknown) => x },
|
|
500
|
-
execute: vi.fn(async () => {
|
|
501
|
-
await new Promise((resolve) => setTimeout(resolve, TOOL_DELAY))
|
|
502
|
-
return { result: name }
|
|
503
|
-
})
|
|
504
|
-
})
|
|
505
|
-
|
|
506
|
-
const tools = ['tool1', 'tool2', 'tool3'].map(createDelayedTool)
|
|
507
|
-
tools.forEach((tool) => {
|
|
508
|
-
context.toolRegistry.set(tool.name, tool as unknown as import('../../tools/types').Tool)
|
|
509
|
-
})
|
|
510
|
-
|
|
511
|
-
const actions: ToolCallAction[] = tools.map((tool, i) => ({
|
|
512
|
-
type: 'tool-call',
|
|
513
|
-
id: `call-${i}`,
|
|
514
|
-
name: tool.name,
|
|
515
|
-
input: {}
|
|
516
|
-
}))
|
|
517
|
-
const response = createMockResponse(actions)
|
|
518
|
-
|
|
519
|
-
const startTime = Date.now()
|
|
520
|
-
await processActions(context, response)
|
|
521
|
-
const endTime = Date.now()
|
|
522
|
-
const totalTime = endTime - startTime
|
|
523
|
-
|
|
524
|
-
// In parallel: ~TOOL_DELAY ms (all run simultaneously)
|
|
525
|
-
// In sequential: ~TOOL_DELAY * 3 = 90ms (one after another)
|
|
526
|
-
// Allow some overhead, but should be significantly less than sequential time
|
|
527
|
-
const sequentialTime = TOOL_DELAY * tools.length
|
|
528
|
-
expect(totalTime).toBeLessThan(sequentialTime * 0.8) // At least 20% faster than sequential
|
|
529
|
-
})
|
|
530
|
-
})
|
|
531
|
-
})
|
|
1
|
+
import { describe, it, expect, vi } from 'vitest'
|
|
2
|
+
import { processActions } from '../processor'
|
|
3
|
+
import type { IterationContext } from '../../core/types'
|
|
4
|
+
import type { LLMIterationResponse } from '../../reasoning/types'
|
|
5
|
+
import type { AgentAction, ToolCallAction, CompleteAction, MessageAction } from '../types'
|
|
6
|
+
import type { ExecutionContext } from '../../../base/types'
|
|
7
|
+
|
|
8
|
+
describe('processActions - validateActionSequence', () => {
|
|
9
|
+
const createMockIterationContext = (): IterationContext => {
|
|
10
|
+
const mockMemoryManager: Record<string, unknown> = {
|
|
11
|
+
addToHistory: vi.fn(),
|
|
12
|
+
getHistory: vi.fn(() => []),
|
|
13
|
+
estimateTokens: vi.fn(() => 0),
|
|
14
|
+
clear: vi.fn()
|
|
15
|
+
}
|
|
16
|
+
const context = {
|
|
17
|
+
executionContext: {
|
|
18
|
+
executionId: 'exec-123',
|
|
19
|
+
organizationId: 'org-123',
|
|
20
|
+
userId: 'user-123',
|
|
21
|
+
logger: {
|
|
22
|
+
info: vi.fn(),
|
|
23
|
+
error: vi.fn(),
|
|
24
|
+
warn: vi.fn(),
|
|
25
|
+
debug: vi.fn()
|
|
26
|
+
}
|
|
27
|
+
} as ExecutionContext,
|
|
28
|
+
toolRegistry: new Map(),
|
|
29
|
+
config: {
|
|
30
|
+
type: 'agent' as const,
|
|
31
|
+
resourceId: 'test-agent',
|
|
32
|
+
name: 'Test Agent',
|
|
33
|
+
description: 'Test',
|
|
34
|
+
environment: 'dev',
|
|
35
|
+
systemPrompt: 'Test'
|
|
36
|
+
},
|
|
37
|
+
contract: {
|
|
38
|
+
inputSchema: {},
|
|
39
|
+
outputSchema: {}
|
|
40
|
+
},
|
|
41
|
+
logger: {
|
|
42
|
+
action: vi.fn(),
|
|
43
|
+
info: vi.fn(),
|
|
44
|
+
error: vi.fn(),
|
|
45
|
+
warn: vi.fn(),
|
|
46
|
+
debug: vi.fn()
|
|
47
|
+
},
|
|
48
|
+
modelConfig: {
|
|
49
|
+
provider: 'mock' as const,
|
|
50
|
+
model: 'mock',
|
|
51
|
+
apiKey: 'test'
|
|
52
|
+
},
|
|
53
|
+
memoryManager: mockMemoryManager,
|
|
54
|
+
iteration: 0
|
|
55
|
+
} as IterationContext
|
|
56
|
+
return context
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const createMockResponse = (actions: AgentAction[]): LLMIterationResponse => ({
|
|
60
|
+
reasoning: 'Test reasoning',
|
|
61
|
+
nextActions: actions
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
describe('valid action sequences', () => {
|
|
65
|
+
it('allows single complete action', async () => {
|
|
66
|
+
const context = createMockIterationContext()
|
|
67
|
+
const response = createMockResponse([{ type: 'complete' }])
|
|
68
|
+
|
|
69
|
+
const result = await processActions(context, response)
|
|
70
|
+
|
|
71
|
+
expect(result.shouldComplete).toBe(true)
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
it('allows single tool-call action', async () => {
|
|
75
|
+
const context = createMockIterationContext()
|
|
76
|
+
const toolAction: ToolCallAction = {
|
|
77
|
+
type: 'tool-call',
|
|
78
|
+
id: 'tool-1',
|
|
79
|
+
name: 'testTool',
|
|
80
|
+
input: {}
|
|
81
|
+
}
|
|
82
|
+
const response = createMockResponse([toolAction])
|
|
83
|
+
|
|
84
|
+
// Tool not found is handled gracefully (adds error to memory, doesn't throw)
|
|
85
|
+
const result = await processActions(context, response)
|
|
86
|
+
expect(result.shouldComplete).toBe(false)
|
|
87
|
+
})
|
|
88
|
+
|
|
89
|
+
it('allows multiple tool-call actions', async () => {
|
|
90
|
+
const context = createMockIterationContext()
|
|
91
|
+
const actions: ToolCallAction[] = [
|
|
92
|
+
{ type: 'tool-call', id: 'tool-1', name: 'tool1', input: {} },
|
|
93
|
+
{ type: 'tool-call', id: 'tool-2', name: 'tool2', input: {} }
|
|
94
|
+
]
|
|
95
|
+
const response = createMockResponse(actions)
|
|
96
|
+
|
|
97
|
+
// Tools not found are handled gracefully (adds errors to memory, doesn't throw)
|
|
98
|
+
const result = await processActions(context, response)
|
|
99
|
+
expect(result.shouldComplete).toBe(false)
|
|
100
|
+
})
|
|
101
|
+
|
|
102
|
+
it('allows message action before complete', async () => {
|
|
103
|
+
const context = createMockIterationContext()
|
|
104
|
+
const actions: AgentAction[] = [{ type: 'message', text: 'Processing complete' }, { type: 'complete' }]
|
|
105
|
+
const response = createMockResponse(actions)
|
|
106
|
+
|
|
107
|
+
const result = await processActions(context, response)
|
|
108
|
+
|
|
109
|
+
expect(result.shouldComplete).toBe(true)
|
|
110
|
+
})
|
|
111
|
+
|
|
112
|
+
it('allows multiple message actions before complete', async () => {
|
|
113
|
+
const context = createMockIterationContext()
|
|
114
|
+
const actions: AgentAction[] = [
|
|
115
|
+
{ type: 'message', text: 'Step 1 done' },
|
|
116
|
+
{ type: 'message', text: 'Step 2 done' },
|
|
117
|
+
{ type: 'complete' }
|
|
118
|
+
]
|
|
119
|
+
const response = createMockResponse(actions)
|
|
120
|
+
|
|
121
|
+
const result = await processActions(context, response)
|
|
122
|
+
|
|
123
|
+
expect(result.shouldComplete).toBe(true)
|
|
124
|
+
})
|
|
125
|
+
})
|
|
126
|
+
|
|
127
|
+
describe('invalid action sequences', () => {
|
|
128
|
+
it('throws error for multiple complete actions', async () => {
|
|
129
|
+
const context = createMockIterationContext()
|
|
130
|
+
const actions: CompleteAction[] = [{ type: 'complete' }, { type: 'complete' }]
|
|
131
|
+
const response = createMockResponse(actions)
|
|
132
|
+
|
|
133
|
+
await expect(processActions(context, response)).rejects.toThrow(
|
|
134
|
+
'Multiple complete actions not allowed in single iteration'
|
|
135
|
+
)
|
|
136
|
+
})
|
|
137
|
+
|
|
138
|
+
it('allows tool-call mixed with complete (side-effect tools execute first)', async () => {
|
|
139
|
+
const context = createMockIterationContext()
|
|
140
|
+
|
|
141
|
+
const mockTool = {
|
|
142
|
+
name: 'testTool',
|
|
143
|
+
inputSchema: { parse: (x: unknown) => x },
|
|
144
|
+
outputSchema: { parse: (x: unknown) => x },
|
|
145
|
+
execute: vi.fn(async () => ({ result: 'done' }))
|
|
146
|
+
}
|
|
147
|
+
context.toolRegistry.set('testTool', mockTool as unknown as import('../../tools/types').Tool)
|
|
148
|
+
|
|
149
|
+
const actions: AgentAction[] = [
|
|
150
|
+
{ type: 'tool-call', id: 'tool-1', name: 'testTool', input: {} },
|
|
151
|
+
{ type: 'complete' }
|
|
152
|
+
]
|
|
153
|
+
const response = createMockResponse(actions)
|
|
154
|
+
|
|
155
|
+
const result = await processActions(context, response)
|
|
156
|
+
|
|
157
|
+
expect(mockTool.execute).toHaveBeenCalledTimes(1)
|
|
158
|
+
expect(result.shouldComplete).toBe(true)
|
|
159
|
+
})
|
|
160
|
+
|
|
161
|
+
it('allows complete before tool-call (tools still execute first)', async () => {
|
|
162
|
+
const context = createMockIterationContext()
|
|
163
|
+
|
|
164
|
+
const mockTool = {
|
|
165
|
+
name: 'testTool',
|
|
166
|
+
inputSchema: { parse: (x: unknown) => x },
|
|
167
|
+
outputSchema: { parse: (x: unknown) => x },
|
|
168
|
+
execute: vi.fn(async () => ({ result: 'done' }))
|
|
169
|
+
}
|
|
170
|
+
context.toolRegistry.set('testTool', mockTool as unknown as import('../../tools/types').Tool)
|
|
171
|
+
|
|
172
|
+
const actions: AgentAction[] = [
|
|
173
|
+
{ type: 'complete' },
|
|
174
|
+
{ type: 'tool-call', id: 'tool-1', name: 'testTool', input: {} }
|
|
175
|
+
]
|
|
176
|
+
const response = createMockResponse(actions)
|
|
177
|
+
|
|
178
|
+
const result = await processActions(context, response)
|
|
179
|
+
|
|
180
|
+
expect(mockTool.execute).toHaveBeenCalledTimes(1)
|
|
181
|
+
expect(result.shouldComplete).toBe(true)
|
|
182
|
+
})
|
|
183
|
+
})
|
|
184
|
+
|
|
185
|
+
describe('action processing behavior', () => {
|
|
186
|
+
it('handles message action with session context', async () => {
|
|
187
|
+
const onMessageEvent = vi.fn()
|
|
188
|
+
|
|
189
|
+
const context = createMockIterationContext()
|
|
190
|
+
context.executionContext.onMessageEvent = onMessageEvent
|
|
191
|
+
|
|
192
|
+
const messageAction: MessageAction = {
|
|
193
|
+
type: 'message',
|
|
194
|
+
text: 'Hello from agent'
|
|
195
|
+
}
|
|
196
|
+
const response = createMockResponse([messageAction, { type: 'complete' }])
|
|
197
|
+
|
|
198
|
+
await processActions(context, response)
|
|
199
|
+
|
|
200
|
+
expect(onMessageEvent).toHaveBeenCalledWith({
|
|
201
|
+
type: 'assistant_message',
|
|
202
|
+
text: 'Hello from agent'
|
|
203
|
+
})
|
|
204
|
+
})
|
|
205
|
+
|
|
206
|
+
it('handles message action without session context', async () => {
|
|
207
|
+
const context = createMockIterationContext()
|
|
208
|
+
// No sessionContext
|
|
209
|
+
|
|
210
|
+
const messageAction: MessageAction = {
|
|
211
|
+
type: 'message',
|
|
212
|
+
text: 'Hello from agent'
|
|
213
|
+
}
|
|
214
|
+
const response = createMockResponse([messageAction, { type: 'complete' }])
|
|
215
|
+
|
|
216
|
+
// Should not throw - just silently skip streaming
|
|
217
|
+
const result = await processActions(context, response)
|
|
218
|
+
|
|
219
|
+
expect(result.shouldComplete).toBe(true)
|
|
220
|
+
})
|
|
221
|
+
|
|
222
|
+
it('processes multiple messages in order', async () => {
|
|
223
|
+
const onMessageEvent = vi.fn()
|
|
224
|
+
|
|
225
|
+
const context = createMockIterationContext()
|
|
226
|
+
context.executionContext.onMessageEvent = onMessageEvent
|
|
227
|
+
|
|
228
|
+
const actions: AgentAction[] = [
|
|
229
|
+
{ type: 'message', text: 'First message' },
|
|
230
|
+
{ type: 'message', text: 'Second message' },
|
|
231
|
+
{ type: 'message', text: 'Third message' },
|
|
232
|
+
{ type: 'complete' }
|
|
233
|
+
]
|
|
234
|
+
const response = createMockResponse(actions)
|
|
235
|
+
|
|
236
|
+
await processActions(context, response)
|
|
237
|
+
|
|
238
|
+
expect(onMessageEvent).toHaveBeenCalledTimes(3)
|
|
239
|
+
expect(onMessageEvent).toHaveBeenNthCalledWith(1, {
|
|
240
|
+
type: 'assistant_message',
|
|
241
|
+
text: 'First message'
|
|
242
|
+
})
|
|
243
|
+
expect(onMessageEvent).toHaveBeenNthCalledWith(2, {
|
|
244
|
+
type: 'assistant_message',
|
|
245
|
+
text: 'Second message'
|
|
246
|
+
})
|
|
247
|
+
expect(onMessageEvent).toHaveBeenNthCalledWith(3, {
|
|
248
|
+
type: 'assistant_message',
|
|
249
|
+
text: 'Third message'
|
|
250
|
+
})
|
|
251
|
+
})
|
|
252
|
+
|
|
253
|
+
it('returns shouldComplete: false when no complete action', async () => {
|
|
254
|
+
const context = createMockIterationContext()
|
|
255
|
+
const response = createMockResponse([])
|
|
256
|
+
|
|
257
|
+
const result = await processActions(context, response)
|
|
258
|
+
|
|
259
|
+
expect(result.shouldComplete).toBe(false)
|
|
260
|
+
})
|
|
261
|
+
|
|
262
|
+
it('returns shouldComplete: true when complete action present', async () => {
|
|
263
|
+
const context = createMockIterationContext()
|
|
264
|
+
const response = createMockResponse([{ type: 'complete' }])
|
|
265
|
+
|
|
266
|
+
const result = await processActions(context, response)
|
|
267
|
+
|
|
268
|
+
expect(result.shouldComplete).toBe(true)
|
|
269
|
+
})
|
|
270
|
+
})
|
|
271
|
+
|
|
272
|
+
describe('edge cases', () => {
|
|
273
|
+
it('handles empty action array', async () => {
|
|
274
|
+
const context = createMockIterationContext()
|
|
275
|
+
const response = createMockResponse([])
|
|
276
|
+
|
|
277
|
+
const result = await processActions(context, response)
|
|
278
|
+
|
|
279
|
+
expect(result.shouldComplete).toBe(false)
|
|
280
|
+
})
|
|
281
|
+
|
|
282
|
+
it('validates actions before executing any', async () => {
|
|
283
|
+
const context = createMockIterationContext()
|
|
284
|
+
const executeTool = vi.fn()
|
|
285
|
+
const mockTool = { name: 'testTool', execute: executeTool } as Partial<import('../../tools/types').Tool>
|
|
286
|
+
context.toolRegistry.set('testTool', mockTool as import('../../tools/types').Tool)
|
|
287
|
+
|
|
288
|
+
// Invalid: multiple completes
|
|
289
|
+
const actions: AgentAction[] = [
|
|
290
|
+
{ type: 'tool-call', id: 'tool-1', name: 'testTool', input: {} },
|
|
291
|
+
{ type: 'complete' },
|
|
292
|
+
{ type: 'complete' }
|
|
293
|
+
]
|
|
294
|
+
const response = createMockResponse(actions)
|
|
295
|
+
|
|
296
|
+
await expect(processActions(context, response)).rejects.toThrow('Multiple complete actions not allowed')
|
|
297
|
+
|
|
298
|
+
// Tool should NOT have been executed (validation happens first)
|
|
299
|
+
expect(executeTool).not.toHaveBeenCalled()
|
|
300
|
+
})
|
|
301
|
+
})
|
|
302
|
+
|
|
303
|
+
describe('validation rules compliance', () => {
|
|
304
|
+
it('enforces Rule 1: no duplicate completions', async () => {
|
|
305
|
+
const context = createMockIterationContext()
|
|
306
|
+
const actions = [{ type: 'complete' }, { type: 'complete' }, { type: 'complete' }] as AgentAction[]
|
|
307
|
+
const response = createMockResponse(actions)
|
|
308
|
+
|
|
309
|
+
await expect(processActions(context, response)).rejects.toThrow(
|
|
310
|
+
'Multiple complete actions not allowed in single iteration'
|
|
311
|
+
)
|
|
312
|
+
})
|
|
313
|
+
|
|
314
|
+
it('enforces Rule 2: complete cannot mix with navigate-knowledge', async () => {
|
|
315
|
+
const context = createMockIterationContext()
|
|
316
|
+
const actions: AgentAction[] = [
|
|
317
|
+
{ type: 'complete' },
|
|
318
|
+
{ type: 'navigate-knowledge', id: 'nav-1', nodeId: 'node-1' }
|
|
319
|
+
]
|
|
320
|
+
const response = createMockResponse(actions)
|
|
321
|
+
|
|
322
|
+
await expect(processActions(context, response)).rejects.toThrow(
|
|
323
|
+
'Complete action cannot mix with navigate-knowledge actions'
|
|
324
|
+
)
|
|
325
|
+
})
|
|
326
|
+
|
|
327
|
+
it('allows Rule 2 exception: complete can mix with tool-call', async () => {
|
|
328
|
+
const context = createMockIterationContext()
|
|
329
|
+
const actions: AgentAction[] = [
|
|
330
|
+
{ type: 'complete' },
|
|
331
|
+
{ type: 'tool-call', id: 'tool-1', name: 'tool', input: {} }
|
|
332
|
+
]
|
|
333
|
+
const response = createMockResponse(actions)
|
|
334
|
+
|
|
335
|
+
// Should not throw — tool calls are side-effect compatible with completion
|
|
336
|
+
const result = await processActions(context, response)
|
|
337
|
+
expect(result.shouldComplete).toBe(true)
|
|
338
|
+
})
|
|
339
|
+
|
|
340
|
+
it('allows message with complete (exception to Rule 2)', async () => {
|
|
341
|
+
const context = createMockIterationContext()
|
|
342
|
+
const actions: AgentAction[] = [{ type: 'message', text: 'Done!' }, { type: 'complete' }]
|
|
343
|
+
const response = createMockResponse(actions)
|
|
344
|
+
|
|
345
|
+
const result = await processActions(context, response)
|
|
346
|
+
|
|
347
|
+
expect(result.shouldComplete).toBe(true)
|
|
348
|
+
})
|
|
349
|
+
})
|
|
350
|
+
|
|
351
|
+
describe('parallel tool execution', () => {
|
|
352
|
+
it('executes multiple tool calls concurrently', async () => {
|
|
353
|
+
const context = createMockIterationContext()
|
|
354
|
+
const executionOrder: string[] = []
|
|
355
|
+
|
|
356
|
+
// Create mock tools with configurable delays
|
|
357
|
+
const mockTool1 = {
|
|
358
|
+
name: 'tool1',
|
|
359
|
+
inputSchema: { parse: (x: unknown) => x },
|
|
360
|
+
outputSchema: { parse: (x: unknown) => x },
|
|
361
|
+
execute: vi.fn(async () => {
|
|
362
|
+
executionOrder.push('tool1-start')
|
|
363
|
+
await new Promise((resolve) => setTimeout(resolve, 50))
|
|
364
|
+
executionOrder.push('tool1-end')
|
|
365
|
+
return { result: 'tool1' }
|
|
366
|
+
})
|
|
367
|
+
}
|
|
368
|
+
const mockTool2 = {
|
|
369
|
+
name: 'tool2',
|
|
370
|
+
inputSchema: { parse: (x: unknown) => x },
|
|
371
|
+
outputSchema: { parse: (x: unknown) => x },
|
|
372
|
+
execute: vi.fn(async () => {
|
|
373
|
+
executionOrder.push('tool2-start')
|
|
374
|
+
await new Promise((resolve) => setTimeout(resolve, 50))
|
|
375
|
+
executionOrder.push('tool2-end')
|
|
376
|
+
return { result: 'tool2' }
|
|
377
|
+
})
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
context.toolRegistry.set('tool1', mockTool1 as unknown as import('../../tools/types').Tool)
|
|
381
|
+
context.toolRegistry.set('tool2', mockTool2 as unknown as import('../../tools/types').Tool)
|
|
382
|
+
|
|
383
|
+
const actions: ToolCallAction[] = [
|
|
384
|
+
{ type: 'tool-call', id: 'call-1', name: 'tool1', input: {} },
|
|
385
|
+
{ type: 'tool-call', id: 'call-2', name: 'tool2', input: {} }
|
|
386
|
+
]
|
|
387
|
+
const response = createMockResponse(actions)
|
|
388
|
+
|
|
389
|
+
await processActions(context, response)
|
|
390
|
+
|
|
391
|
+
// Both tools should have been executed
|
|
392
|
+
expect(mockTool1.execute).toHaveBeenCalledTimes(1)
|
|
393
|
+
expect(mockTool2.execute).toHaveBeenCalledTimes(1)
|
|
394
|
+
|
|
395
|
+
// Verify parallel execution: both starts should happen before any end
|
|
396
|
+
// (In sequential execution, we'd see: tool1-start, tool1-end, tool2-start, tool2-end)
|
|
397
|
+
const tool1StartIndex = executionOrder.indexOf('tool1-start')
|
|
398
|
+
const tool2StartIndex = executionOrder.indexOf('tool2-start')
|
|
399
|
+
const tool1EndIndex = executionOrder.indexOf('tool1-end')
|
|
400
|
+
const tool2EndIndex = executionOrder.indexOf('tool2-end')
|
|
401
|
+
|
|
402
|
+
// Both should start before either ends (parallel behavior)
|
|
403
|
+
expect(tool1StartIndex).toBeLessThan(tool1EndIndex)
|
|
404
|
+
expect(tool2StartIndex).toBeLessThan(tool2EndIndex)
|
|
405
|
+
// If running in parallel, both starts should happen before ends complete
|
|
406
|
+
expect(Math.max(tool1StartIndex, tool2StartIndex)).toBeLessThan(Math.max(tool1EndIndex, tool2EndIndex))
|
|
407
|
+
})
|
|
408
|
+
|
|
409
|
+
it('handles mixed actions: tool calls in parallel, others sequential', async () => {
|
|
410
|
+
const context = createMockIterationContext()
|
|
411
|
+
const onMessageEvent = vi.fn()
|
|
412
|
+
context.executionContext.onMessageEvent = onMessageEvent
|
|
413
|
+
|
|
414
|
+
// Create mock tools
|
|
415
|
+
const mockTool1 = {
|
|
416
|
+
name: 'tool1',
|
|
417
|
+
inputSchema: { parse: (x: unknown) => x },
|
|
418
|
+
outputSchema: { parse: (x: unknown) => x },
|
|
419
|
+
execute: vi.fn(async () => ({ result: 'tool1' }))
|
|
420
|
+
}
|
|
421
|
+
const mockTool2 = {
|
|
422
|
+
name: 'tool2',
|
|
423
|
+
inputSchema: { parse: (x: unknown) => x },
|
|
424
|
+
outputSchema: { parse: (x: unknown) => x },
|
|
425
|
+
execute: vi.fn(async () => ({ result: 'tool2' }))
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
context.toolRegistry.set('tool1', mockTool1 as unknown as import('../../tools/types').Tool)
|
|
429
|
+
context.toolRegistry.set('tool2', mockTool2 as unknown as import('../../tools/types').Tool)
|
|
430
|
+
|
|
431
|
+
// Mix tool calls with messages
|
|
432
|
+
const actions: AgentAction[] = [
|
|
433
|
+
{ type: 'message', text: 'Starting work...' },
|
|
434
|
+
{ type: 'tool-call', id: 'call-1', name: 'tool1', input: {} },
|
|
435
|
+
{ type: 'tool-call', id: 'call-2', name: 'tool2', input: {} }
|
|
436
|
+
]
|
|
437
|
+
const response = createMockResponse(actions)
|
|
438
|
+
|
|
439
|
+
await processActions(context, response)
|
|
440
|
+
|
|
441
|
+
// Both tools should be executed
|
|
442
|
+
expect(mockTool1.execute).toHaveBeenCalledTimes(1)
|
|
443
|
+
expect(mockTool2.execute).toHaveBeenCalledTimes(1)
|
|
444
|
+
|
|
445
|
+
// Message should also be sent
|
|
446
|
+
expect(onMessageEvent).toHaveBeenCalledWith({
|
|
447
|
+
type: 'assistant_message',
|
|
448
|
+
text: 'Starting work...'
|
|
449
|
+
})
|
|
450
|
+
})
|
|
451
|
+
|
|
452
|
+
it('handles partial failure: successful tools complete even when one fails', async () => {
|
|
453
|
+
const context = createMockIterationContext()
|
|
454
|
+
|
|
455
|
+
// Create one successful and one failing tool
|
|
456
|
+
const mockSuccessTool = {
|
|
457
|
+
name: 'successTool',
|
|
458
|
+
inputSchema: { parse: (x: unknown) => x },
|
|
459
|
+
outputSchema: { parse: (x: unknown) => x },
|
|
460
|
+
execute: vi.fn(async () => ({ result: 'success' }))
|
|
461
|
+
}
|
|
462
|
+
const mockFailTool = {
|
|
463
|
+
name: 'failTool',
|
|
464
|
+
inputSchema: { parse: (x: unknown) => x },
|
|
465
|
+
outputSchema: { parse: (x: unknown) => x },
|
|
466
|
+
execute: vi.fn(async () => {
|
|
467
|
+
throw new Error('Tool failed intentionally')
|
|
468
|
+
})
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
context.toolRegistry.set('successTool', mockSuccessTool as unknown as import('../../tools/types').Tool)
|
|
472
|
+
context.toolRegistry.set('failTool', mockFailTool as unknown as import('../../tools/types').Tool)
|
|
473
|
+
|
|
474
|
+
const actions: ToolCallAction[] = [
|
|
475
|
+
{ type: 'tool-call', id: 'call-1', name: 'successTool', input: {} },
|
|
476
|
+
{ type: 'tool-call', id: 'call-2', name: 'failTool', input: {} }
|
|
477
|
+
]
|
|
478
|
+
const response = createMockResponse(actions)
|
|
479
|
+
|
|
480
|
+
// Should not throw - Promise.allSettled handles partial failures
|
|
481
|
+
const result = await processActions(context, response)
|
|
482
|
+
|
|
483
|
+
// Both tools should have been attempted
|
|
484
|
+
expect(mockSuccessTool.execute).toHaveBeenCalledTimes(1)
|
|
485
|
+
expect(mockFailTool.execute).toHaveBeenCalledTimes(1)
|
|
486
|
+
|
|
487
|
+
// Should complete without throwing
|
|
488
|
+
expect(result.shouldComplete).toBe(false)
|
|
489
|
+
})
|
|
490
|
+
|
|
491
|
+
it('maintains timing advantage for parallel execution', async () => {
|
|
492
|
+
const context = createMockIterationContext()
|
|
493
|
+
const TOOL_DELAY = 100 // ms per tool (high enough to distinguish parallel vs sequential under load)
|
|
494
|
+
|
|
495
|
+
// Create multiple tools with configurable delays
|
|
496
|
+
const createDelayedTool = (name: string) => ({
|
|
497
|
+
name,
|
|
498
|
+
inputSchema: { parse: (x: unknown) => x },
|
|
499
|
+
outputSchema: { parse: (x: unknown) => x },
|
|
500
|
+
execute: vi.fn(async () => {
|
|
501
|
+
await new Promise((resolve) => setTimeout(resolve, TOOL_DELAY))
|
|
502
|
+
return { result: name }
|
|
503
|
+
})
|
|
504
|
+
})
|
|
505
|
+
|
|
506
|
+
const tools = ['tool1', 'tool2', 'tool3'].map(createDelayedTool)
|
|
507
|
+
tools.forEach((tool) => {
|
|
508
|
+
context.toolRegistry.set(tool.name, tool as unknown as import('../../tools/types').Tool)
|
|
509
|
+
})
|
|
510
|
+
|
|
511
|
+
const actions: ToolCallAction[] = tools.map((tool, i) => ({
|
|
512
|
+
type: 'tool-call',
|
|
513
|
+
id: `call-${i}`,
|
|
514
|
+
name: tool.name,
|
|
515
|
+
input: {}
|
|
516
|
+
}))
|
|
517
|
+
const response = createMockResponse(actions)
|
|
518
|
+
|
|
519
|
+
const startTime = Date.now()
|
|
520
|
+
await processActions(context, response)
|
|
521
|
+
const endTime = Date.now()
|
|
522
|
+
const totalTime = endTime - startTime
|
|
523
|
+
|
|
524
|
+
// In parallel: ~TOOL_DELAY ms (all run simultaneously)
|
|
525
|
+
// In sequential: ~TOOL_DELAY * 3 = 90ms (one after another)
|
|
526
|
+
// Allow some overhead, but should be significantly less than sequential time
|
|
527
|
+
const sequentialTime = TOOL_DELAY * tools.length
|
|
528
|
+
expect(totalTime).toBeLessThan(sequentialTime * 0.8) // At least 20% faster than sequential
|
|
529
|
+
})
|
|
530
|
+
})
|
|
531
|
+
})
|