@elevasis/core 0.7.1 → 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 +1 -1
- 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 -2
- package/src/business/projects/sse-events.ts +21 -21
- 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 -700
- 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 -37
- 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 +607 -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,810 +1,810 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Agent class
|
|
3
|
-
* Autonomous agents that self-orchestrate with LLM and tool calling
|
|
4
|
-
* Uses universal protocol with vendor-independent message format
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import type { Contract, ExecutionContext } from '../../base/types'
|
|
8
|
-
import type { AgentConfig, IterationContext, AgentMemory, AgentDefinition, LLMAdapterFactory } from './types'
|
|
9
|
-
import type { Tool } from '../../tools/types'
|
|
10
|
-
import type { ModelConfig } from '../../llm/model-info'
|
|
11
|
-
import { createAgentLogger, type AgentScopedLogger } from '../observability/logging'
|
|
12
|
-
import { errorToString, getErrorDetails } from '../../../../platform/utils/error'
|
|
13
|
-
import { processReasoning } from '../reasoning/processor'
|
|
14
|
-
import { processActions } from '../actions/processor'
|
|
15
|
-
import { processMemory } from '../memory/processor'
|
|
16
|
-
import { MemoryManager } from '../memory/manager'
|
|
17
|
-
import { callLLMForAgentCompletion } from '../reasoning/adapters/agent-adapter-helpers'
|
|
18
|
-
import { zodToJsonSchema } from '@alcyone-labs/zod-to-json-schema'
|
|
19
|
-
import type { KnowledgeMap } from '../knowledge-map/types'
|
|
20
|
-
import { reloadKnowledgeMapTools } from '../knowledge-map/utils'
|
|
21
|
-
import type { z } from 'zod'
|
|
22
|
-
import { ZodError } from 'zod'
|
|
23
|
-
import {
|
|
24
|
-
AgentInitializationError,
|
|
25
|
-
AgentIterationError,
|
|
26
|
-
AgentCancellationError,
|
|
27
|
-
AgentCompletionError,
|
|
28
|
-
AgentOutputValidationError,
|
|
29
|
-
AgentMaxIterationsError,
|
|
30
|
-
AgentTimeoutError,
|
|
31
|
-
AgentStalledError
|
|
32
|
-
} from '../errors'
|
|
33
|
-
import { ExecutionError } from '../../base/errors'
|
|
34
|
-
|
|
35
|
-
/**
|
|
36
|
-
* Create a per-execution shallow copy of the knowledge map
|
|
37
|
-
* Prevents concurrent executions from mutating shared definition state
|
|
38
|
-
* (node.loaded, node.prompt, and child node flattening)
|
|
39
|
-
*/
|
|
40
|
-
function initializeKnowledgeMap(knowledgeMap?: KnowledgeMap): KnowledgeMap | undefined {
|
|
41
|
-
if (!knowledgeMap) return undefined
|
|
42
|
-
return {
|
|
43
|
-
nodes: Object.fromEntries(Object.entries(knowledgeMap.nodes).map(([id, node]) => [id, { ...node }]))
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
/**
|
|
48
|
-
* Autonomous agent that uses LLM reasoning and tool calling
|
|
49
|
-
* to complete tasks without predefined orchestration
|
|
50
|
-
*
|
|
51
|
-
* @template TInput - Input type validated by contract.inputSchema
|
|
52
|
-
* @template TOutput - Output type validated by contract.outputSchema
|
|
53
|
-
*/
|
|
54
|
-
export class Agent<TInput = unknown, TOutput = unknown> {
|
|
55
|
-
// Base properties from definition
|
|
56
|
-
public readonly config: AgentConfig
|
|
57
|
-
public readonly contract: Contract
|
|
58
|
-
private readonly toolRegistry: Map<string, Tool>
|
|
59
|
-
public readonly modelConfig: ModelConfig
|
|
60
|
-
private readonly knowledgeMap?: KnowledgeMap
|
|
61
|
-
private readonly definition: AgentDefinition
|
|
62
|
-
private readonly adapterFactory: LLMAdapterFactory
|
|
63
|
-
|
|
64
|
-
// Derived properties (computed from definition)
|
|
65
|
-
private readonly shouldGenerateOutput: boolean
|
|
66
|
-
|
|
67
|
-
// Runtime state (initialized during execution)
|
|
68
|
-
public memoryManager!: MemoryManager
|
|
69
|
-
private logger!: AgentScopedLogger
|
|
70
|
-
private executionContext!: ExecutionContext
|
|
71
|
-
private iterationNumber: number = 0 // Current iteration number (used for memory context filtering)
|
|
72
|
-
|
|
73
|
-
/**
|
|
74
|
-
* Create a new agent instance from definition
|
|
75
|
-
* Memory will be initialized during execution
|
|
76
|
-
*
|
|
77
|
-
* @param definition - Agent definition with config, contract, tools, and optional preloadMemory
|
|
78
|
-
* @param adapterFactory - Factory for creating LLM adapters (decouples engine from provider SDKs)
|
|
79
|
-
*/
|
|
80
|
-
constructor(definition: AgentDefinition, adapterFactory: LLMAdapterFactory) {
|
|
81
|
-
this.definition = definition
|
|
82
|
-
this.adapterFactory = adapterFactory
|
|
83
|
-
this.config = definition.config
|
|
84
|
-
this.contract = definition.contract
|
|
85
|
-
this.modelConfig = definition.modelConfig // Store model config from definition
|
|
86
|
-
this.knowledgeMap = initializeKnowledgeMap(definition.knowledgeMap)
|
|
87
|
-
|
|
88
|
-
// Initialize tool registry with base tools
|
|
89
|
-
this.toolRegistry = new Map()
|
|
90
|
-
for (const tool of definition.tools) {
|
|
91
|
-
this.toolRegistry.set(tool.name, tool)
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
// Derive shouldGenerateOutput from outputSchema presence (automatic detection)
|
|
95
|
-
this.shouldGenerateOutput = !!definition.contract.outputSchema
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
/**
|
|
99
|
-
* Execute the agent with validated input and context
|
|
100
|
-
* Orchestrates the three lifecycle phases: initialization, iteration, completion
|
|
101
|
-
*
|
|
102
|
-
* @param input - Raw input (will be validated against contract.inputSchema)
|
|
103
|
-
* @param context - Execution context (required for tracking, logging, and organization isolation)
|
|
104
|
-
* @returns Validated output matching contract.outputSchema, or null if no output schema
|
|
105
|
-
*/
|
|
106
|
-
async execute(input: TInput, context: ExecutionContext): Promise<TOutput | null> {
|
|
107
|
-
// Store execution context for completion phase
|
|
108
|
-
this.executionContext = context
|
|
109
|
-
|
|
110
|
-
// Emit agent started event
|
|
111
|
-
await context.onMessageEvent?.({ type: 'agent:started' })
|
|
112
|
-
|
|
113
|
-
try {
|
|
114
|
-
// Phase 1: Initialize
|
|
115
|
-
await this.initialize(input, context)
|
|
116
|
-
|
|
117
|
-
// Phase 2: Iterate (task execution)
|
|
118
|
-
await this.iterate(context)
|
|
119
|
-
|
|
120
|
-
// Phase 3: Complete (output generation)
|
|
121
|
-
const output = await this.complete()
|
|
122
|
-
|
|
123
|
-
// Emit agent completed event
|
|
124
|
-
await context.onMessageEvent?.({ type: 'agent:completed' })
|
|
125
|
-
|
|
126
|
-
return output
|
|
127
|
-
} catch (error) {
|
|
128
|
-
// Emit agent error event
|
|
129
|
-
await context.onMessageEvent?.({ type: 'agent:error', error: String(error) })
|
|
130
|
-
throw error
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
/**
|
|
135
|
-
* Register tools from a loaded knowledge node
|
|
136
|
-
* Called by navigate_knowledge tool during execution
|
|
137
|
-
*
|
|
138
|
-
* @param tools - Array of tools to register
|
|
139
|
-
* Note: Silently skips tools that are already registered
|
|
140
|
-
*/
|
|
141
|
-
public registerTools(tools: Tool[]): void {
|
|
142
|
-
for (const tool of tools) {
|
|
143
|
-
if (!this.toolRegistry.has(tool.name)) {
|
|
144
|
-
this.toolRegistry.set(tool.name, tool)
|
|
145
|
-
}
|
|
146
|
-
// Skip tools that are already registered (graceful handling)
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
/**
|
|
151
|
-
* Get all currently registered tools
|
|
152
|
-
* Used for system prompt generation and introspection
|
|
153
|
-
*
|
|
154
|
-
* @returns Array of all registered tools
|
|
155
|
-
*/
|
|
156
|
-
public getTools(): Tool[] {
|
|
157
|
-
return Array.from(this.toolRegistry.values())
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
/**
|
|
161
|
-
* Phase 1: Initialize the agent execution
|
|
162
|
-
* Validates input, initializes memory manager
|
|
163
|
-
*
|
|
164
|
-
* @param input - Raw input to validate
|
|
165
|
-
* @param context - Execution context
|
|
166
|
-
*/
|
|
167
|
-
private async initialize(input: TInput, context: ExecutionContext): Promise<void> {
|
|
168
|
-
const initStartTime = Date.now()
|
|
169
|
-
|
|
170
|
-
try {
|
|
171
|
-
// Create scoped logger for this execution
|
|
172
|
-
// Pass sessionId if present in context (now directly on ExecutionMetadata)
|
|
173
|
-
this.logger = createAgentLogger(context.logger, this.config.resourceId, context.sessionId)
|
|
174
|
-
|
|
175
|
-
this.logger.lifecycle('initialization', 'started', {
|
|
176
|
-
startTime: initStartTime
|
|
177
|
-
})
|
|
178
|
-
|
|
179
|
-
// Validate input
|
|
180
|
-
const validatedInput = this.contract.inputSchema.parse(input) as TInput
|
|
181
|
-
|
|
182
|
-
// Initialize memory manager (encapsulates all memory initialization)
|
|
183
|
-
this.memoryManager = await this.initializeMemoryManager(validatedInput, context)
|
|
184
|
-
|
|
185
|
-
const initEndTime = Date.now()
|
|
186
|
-
this.logger.lifecycle('initialization', 'completed', {
|
|
187
|
-
startTime: initStartTime,
|
|
188
|
-
endTime: initEndTime,
|
|
189
|
-
duration: initEndTime - initStartTime
|
|
190
|
-
})
|
|
191
|
-
} catch (error) {
|
|
192
|
-
this.wrapAndLogError('initialization', initStartTime, error)
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
/**
|
|
197
|
-
* Initialize memory manager with preloaded memory and input entry
|
|
198
|
-
* Encapsulates all memory initialization complexity
|
|
199
|
-
*
|
|
200
|
-
* Also handles cross-turn persistence: re-registers tools from knowledge nodes
|
|
201
|
-
* that were loaded in previous session turns.
|
|
202
|
-
*
|
|
203
|
-
* @param validatedInput - Validated input to add to memory history
|
|
204
|
-
* @param context - Execution context (passed to preloadMemory)
|
|
205
|
-
* @returns Initialized MemoryManager instance
|
|
206
|
-
*/
|
|
207
|
-
private async initializeMemoryManager(validatedInput: TInput, context: ExecutionContext): Promise<MemoryManager> {
|
|
208
|
-
// Preload memory if callback defined
|
|
209
|
-
let memory: AgentMemory
|
|
210
|
-
if (this.definition.preloadMemory) {
|
|
211
|
-
const preloadStartTime = Date.now()
|
|
212
|
-
memory = await this.definition.preloadMemory(context)
|
|
213
|
-
const preloadEndTime = Date.now()
|
|
214
|
-
this.logger.action(
|
|
215
|
-
'memory-preload',
|
|
216
|
-
`Preloaded ${Object.keys(memory.sessionMemory).length} session memory entries`,
|
|
217
|
-
0,
|
|
218
|
-
preloadStartTime,
|
|
219
|
-
preloadEndTime,
|
|
220
|
-
preloadEndTime - preloadStartTime
|
|
221
|
-
)
|
|
222
|
-
|
|
223
|
-
// Reload tools from knowledge map if state exists (cross-turn persistence)
|
|
224
|
-
await this.reloadKnowledgeMapTools(memory, context)
|
|
225
|
-
} else {
|
|
226
|
-
// Default: empty memory
|
|
227
|
-
memory = {
|
|
228
|
-
sessionMemory: {},
|
|
229
|
-
history: []
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
// Add input entry to history (iteration 0 = pre-iteration setup)
|
|
234
|
-
const inputStartTime = Date.now()
|
|
235
|
-
|
|
236
|
-
memory.history.push({
|
|
237
|
-
type: 'input',
|
|
238
|
-
content: JSON.stringify(validatedInput),
|
|
239
|
-
timestamp: Date.now(),
|
|
240
|
-
turnNumber: context.sessionTurnNumber ?? null,
|
|
241
|
-
iterationNumber: 0
|
|
242
|
-
})
|
|
243
|
-
const inputEndTime = Date.now()
|
|
244
|
-
|
|
245
|
-
this.logger.action(
|
|
246
|
-
'memory-input',
|
|
247
|
-
`Added input entry to history`,
|
|
248
|
-
0,
|
|
249
|
-
inputStartTime,
|
|
250
|
-
inputEndTime,
|
|
251
|
-
inputEndTime - inputStartTime
|
|
252
|
-
)
|
|
253
|
-
|
|
254
|
-
// Create and return memory manager (takes ownership of memory)
|
|
255
|
-
return new MemoryManager(memory, this.config.constraints, this.logger)
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
/**
|
|
259
|
-
* Reload tools from knowledge map state (cross-turn persistence)
|
|
260
|
-
*
|
|
261
|
-
* Reads the knowledge-map-state from sessionMemory and re-registers
|
|
262
|
-
* tools from previously loaded knowledge nodes.
|
|
263
|
-
*
|
|
264
|
-
* @param memory - Agent memory with sessionMemory state
|
|
265
|
-
* @param context - Execution context
|
|
266
|
-
*/
|
|
267
|
-
private async reloadKnowledgeMapTools(memory: AgentMemory, context: ExecutionContext): Promise<void> {
|
|
268
|
-
// Only reload if knowledge map exists
|
|
269
|
-
if (!this.knowledgeMap) {
|
|
270
|
-
return
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
const stateJson = memory.sessionMemory['knowledge-map-state']
|
|
274
|
-
if (!stateJson) {
|
|
275
|
-
return // No state to reload
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
const reloadStartTime = Date.now()
|
|
279
|
-
|
|
280
|
-
try {
|
|
281
|
-
const tools = await reloadKnowledgeMapTools(this.knowledgeMap, memory, context)
|
|
282
|
-
|
|
283
|
-
// Register reloaded tools (skip duplicates gracefully)
|
|
284
|
-
let registeredCount = 0
|
|
285
|
-
let skippedCount = 0
|
|
286
|
-
|
|
287
|
-
for (const tool of tools) {
|
|
288
|
-
if (this.toolRegistry.has(tool.name)) {
|
|
289
|
-
skippedCount++
|
|
290
|
-
} else {
|
|
291
|
-
this.toolRegistry.set(tool.name, tool)
|
|
292
|
-
registeredCount++
|
|
293
|
-
}
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
const reloadEndTime = Date.now()
|
|
297
|
-
|
|
298
|
-
if (registeredCount > 0) {
|
|
299
|
-
const state = JSON.parse(stateJson.content)
|
|
300
|
-
this.logger.action(
|
|
301
|
-
'knowledge-reload',
|
|
302
|
-
`Reloaded ${registeredCount} tools from ${state.loadedNodes.length} knowledge nodes: ${state.loadedNodes.join(', ')}`,
|
|
303
|
-
0,
|
|
304
|
-
reloadStartTime,
|
|
305
|
-
reloadEndTime,
|
|
306
|
-
reloadEndTime - reloadStartTime
|
|
307
|
-
)
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
if (skippedCount > 0) {
|
|
311
|
-
this.logger.action(
|
|
312
|
-
'knowledge-reload-skipped',
|
|
313
|
-
`Skipped ${skippedCount} already-registered tools during reload`,
|
|
314
|
-
0,
|
|
315
|
-
reloadStartTime,
|
|
316
|
-
reloadEndTime,
|
|
317
|
-
reloadEndTime - reloadStartTime
|
|
318
|
-
)
|
|
319
|
-
}
|
|
320
|
-
} catch (error) {
|
|
321
|
-
const errorMessage = errorToString(error)
|
|
322
|
-
const reloadEndTime = Date.now()
|
|
323
|
-
this.logger.action(
|
|
324
|
-
'knowledge-reload-failed',
|
|
325
|
-
`Failed to reload knowledge map: ${errorMessage}`,
|
|
326
|
-
0,
|
|
327
|
-
reloadStartTime,
|
|
328
|
-
reloadEndTime,
|
|
329
|
-
reloadEndTime - reloadStartTime
|
|
330
|
-
)
|
|
331
|
-
// Continue execution - tools can be re-loaded on demand if needed
|
|
332
|
-
}
|
|
333
|
-
}
|
|
334
|
-
|
|
335
|
-
/**
|
|
336
|
-
* Phase 2: Run the agent iteration loop
|
|
337
|
-
* Continues until LLM signals completion or max iterations reached
|
|
338
|
-
*
|
|
339
|
-
* @param context - Execution context
|
|
340
|
-
*/
|
|
341
|
-
private async iterate(context: ExecutionContext): Promise<void> {
|
|
342
|
-
const maxIterations = this.config.constraints?.maxIterations || 10
|
|
343
|
-
let iteration = 1
|
|
344
|
-
|
|
345
|
-
while (iteration <= maxIterations) {
|
|
346
|
-
// Check for abort (timeout, stalled, or cancellation)
|
|
347
|
-
if (context.signal?.aborted) {
|
|
348
|
-
if (context.signal.reason === 'timeout') {
|
|
349
|
-
throw new AgentTimeoutError(`Agent execution exceeded timeout (${this.config.constraints?.timeout}ms)`, {
|
|
350
|
-
timeout: this.config.constraints?.timeout ?? 0,
|
|
351
|
-
iteration
|
|
352
|
-
})
|
|
353
|
-
}
|
|
354
|
-
if (context.signal.reason === 'stalled') {
|
|
355
|
-
throw new AgentStalledError('Execution stalled: no heartbeat received within threshold', { iteration })
|
|
356
|
-
}
|
|
357
|
-
throw new AgentCancellationError('Execution cancelled by user', { iteration })
|
|
358
|
-
}
|
|
359
|
-
|
|
360
|
-
// Write heartbeat (non-fatal if it fails)
|
|
361
|
-
try {
|
|
362
|
-
await context.onHeartbeat?.()
|
|
363
|
-
} catch {
|
|
364
|
-
// Heartbeat failure is non-fatal — execution continues
|
|
365
|
-
}
|
|
366
|
-
|
|
367
|
-
const result = await this.runIteration(iteration, context)
|
|
368
|
-
if (result.shouldComplete) {
|
|
369
|
-
return // Exit iteration loop (output generated in completion phase)
|
|
370
|
-
}
|
|
371
|
-
|
|
372
|
-
iteration++
|
|
373
|
-
}
|
|
374
|
-
|
|
375
|
-
// Max iterations exceeded
|
|
376
|
-
throw new AgentMaxIterationsError(`Agent exceeded maximum iterations (${maxIterations})`, {
|
|
377
|
-
maxIterations,
|
|
378
|
-
currentIteration: maxIterations
|
|
379
|
-
})
|
|
380
|
-
}
|
|
381
|
-
|
|
382
|
-
/**
|
|
383
|
-
* Run a single iteration of the agent loop
|
|
384
|
-
*
|
|
385
|
-
* Three-phase execution:
|
|
386
|
-
* 1. REASON - Query LLM for next actions, store reasoning to memory
|
|
387
|
-
* 2. MEMORY - Process memory operations (set/delete session memory entries)
|
|
388
|
-
* 3. ACT - Execute planned actions, store tool results to memory
|
|
389
|
-
*
|
|
390
|
-
* @param iteration - Current iteration number (1-based)
|
|
391
|
-
* @param context - Execution context
|
|
392
|
-
* @returns Iteration result with completion flag (no finalAnswer - generated in completion phase)
|
|
393
|
-
*/
|
|
394
|
-
private async runIteration(iteration: number, context: ExecutionContext): Promise<{ shouldComplete: boolean }> {
|
|
395
|
-
const iterationStartTime = Date.now()
|
|
396
|
-
|
|
397
|
-
// Track current iteration number (used by toContext() for memory filtering)
|
|
398
|
-
this.iterationNumber = iteration
|
|
399
|
-
|
|
400
|
-
try {
|
|
401
|
-
this.logger.lifecycle('iteration', 'started', {
|
|
402
|
-
iteration,
|
|
403
|
-
startTime: iterationStartTime
|
|
404
|
-
})
|
|
405
|
-
|
|
406
|
-
// Build iteration context
|
|
407
|
-
const iterationContext: IterationContext = this.buildIterationContext(iteration, context)
|
|
408
|
-
|
|
409
|
-
// Phase 1: REASON - Get LLM's decision and store reasoning to memory
|
|
410
|
-
const response = await processReasoning(iterationContext)
|
|
411
|
-
|
|
412
|
-
// Phase 2: MEMORY - Process memory operations (agent-directed)
|
|
413
|
-
await processMemory(this.memoryManager, response, this.logger, iteration)
|
|
414
|
-
|
|
415
|
-
// Phase 3: ACT - Execute LLM's plan and store tool results to memory
|
|
416
|
-
const { shouldComplete } = await processActions(iterationContext, response)
|
|
417
|
-
|
|
418
|
-
// Log completion
|
|
419
|
-
this.logIterationEnd(iteration, iterationStartTime)
|
|
420
|
-
|
|
421
|
-
// Return result
|
|
422
|
-
return { shouldComplete }
|
|
423
|
-
} catch (error) {
|
|
424
|
-
this.wrapAndLogError('iteration', iterationStartTime, error, { iteration })
|
|
425
|
-
}
|
|
426
|
-
}
|
|
427
|
-
|
|
428
|
-
/**
|
|
429
|
-
* Log iteration end (success only - failures handled by wrapAndLogError)
|
|
430
|
-
*/
|
|
431
|
-
private logIterationEnd(iteration: number, startTime: number): void {
|
|
432
|
-
const endTime = Date.now()
|
|
433
|
-
const duration = endTime - startTime
|
|
434
|
-
|
|
435
|
-
this.logger.lifecycle('iteration', 'completed', {
|
|
436
|
-
iteration,
|
|
437
|
-
startTime,
|
|
438
|
-
endTime,
|
|
439
|
-
duration
|
|
440
|
-
})
|
|
441
|
-
}
|
|
442
|
-
|
|
443
|
-
/**
|
|
444
|
-
* Phase 3: Complete the agent execution
|
|
445
|
-
* Generates and validates structured output from execution history (if output schema present)
|
|
446
|
-
* Captures memory snapshot for persistence
|
|
447
|
-
*
|
|
448
|
-
* @returns Validated output or null if no output schema
|
|
449
|
-
*/
|
|
450
|
-
private async complete(): Promise<TOutput | null> {
|
|
451
|
-
const completionStartTime = Date.now()
|
|
452
|
-
|
|
453
|
-
try {
|
|
454
|
-
this.logger.lifecycle('completion', 'started', {
|
|
455
|
-
startTime: completionStartTime
|
|
456
|
-
})
|
|
457
|
-
|
|
458
|
-
// Conditionally generate output based on schema presence
|
|
459
|
-
let output: TOutput | null = null
|
|
460
|
-
let attempts: number | undefined
|
|
461
|
-
|
|
462
|
-
if (this.shouldGenerateOutput) {
|
|
463
|
-
// Generate output (includes retry logic internally)
|
|
464
|
-
const result = await this.generateFinalOutput()
|
|
465
|
-
output = result.output
|
|
466
|
-
attempts = result.attempts
|
|
467
|
-
} else {
|
|
468
|
-
// Skip output generation (side-effect only agent)
|
|
469
|
-
this.logger.action(
|
|
470
|
-
'completion-skipped',
|
|
471
|
-
'Output generation skipped (no output schema)',
|
|
472
|
-
0,
|
|
473
|
-
completionStartTime,
|
|
474
|
-
completionStartTime,
|
|
475
|
-
0
|
|
476
|
-
)
|
|
477
|
-
}
|
|
478
|
-
|
|
479
|
-
// Capture snapshot automatically (MemoryManager stores it)
|
|
480
|
-
this.memoryManager.toSnapshot()
|
|
481
|
-
|
|
482
|
-
const snapshot = this.memoryManager.getSnapshot()!
|
|
483
|
-
const completionEndTime = Date.now()
|
|
484
|
-
this.logger.lifecycle('completion', 'completed', {
|
|
485
|
-
startTime: completionStartTime,
|
|
486
|
-
endTime: completionEndTime,
|
|
487
|
-
duration: completionEndTime - completionStartTime,
|
|
488
|
-
attempts,
|
|
489
|
-
memorySize: {
|
|
490
|
-
sessionMemoryKeys: Object.keys(snapshot.sessionMemory).length,
|
|
491
|
-
historyEntries: snapshot.history.length
|
|
492
|
-
}
|
|
493
|
-
})
|
|
494
|
-
|
|
495
|
-
return output
|
|
496
|
-
} catch (error) {
|
|
497
|
-
this.wrapAndLogError('completion', completionStartTime, error)
|
|
498
|
-
}
|
|
499
|
-
}
|
|
500
|
-
|
|
501
|
-
/**
|
|
502
|
-
* Generate final output from execution history with retry logic
|
|
503
|
-
* Handles both initial generation and validation retry internally
|
|
504
|
-
*
|
|
505
|
-
* @returns Object with validated output and attempt count
|
|
506
|
-
*/
|
|
507
|
-
private async generateFinalOutput(): Promise<{ output: TOutput; attempts: number }> {
|
|
508
|
-
// Safety check: Ensure outputSchema exists before generating output
|
|
509
|
-
if (!this.contract.outputSchema) {
|
|
510
|
-
throw new AgentInitializationError(
|
|
511
|
-
`Internal error: generateFinalOutput called but contract.outputSchema is undefined`,
|
|
512
|
-
{
|
|
513
|
-
agentId: this.config.resourceId,
|
|
514
|
-
reason: 'missing_output_schema'
|
|
515
|
-
}
|
|
516
|
-
)
|
|
517
|
-
}
|
|
518
|
-
|
|
519
|
-
const outputSchema = zodToJsonSchema(this.contract.outputSchema as z.ZodSchema<any>, {
|
|
520
|
-
$refStrategy: 'none',
|
|
521
|
-
errorMessages: true
|
|
522
|
-
})
|
|
523
|
-
|
|
524
|
-
// Use model's configured temperature (some models like GPT-5-mini only support default)
|
|
525
|
-
const modelTemperature = this.modelConfig.temperature ?? 0.7
|
|
526
|
-
|
|
527
|
-
// Attempt 1: Initial generation
|
|
528
|
-
const initialOutput = await this.callLLMForOutput(
|
|
529
|
-
this.buildOutputGenerationPrompt(),
|
|
530
|
-
outputSchema,
|
|
531
|
-
modelTemperature,
|
|
532
|
-
'output-generation'
|
|
533
|
-
)
|
|
534
|
-
|
|
535
|
-
const initialResult = this.contract.outputSchema.safeParse(initialOutput)
|
|
536
|
-
|
|
537
|
-
if (initialResult.success) {
|
|
538
|
-
return { output: initialResult.data as TOutput, attempts: 1 }
|
|
539
|
-
}
|
|
540
|
-
|
|
541
|
-
// Attempt 1 failed - log and retry with error context
|
|
542
|
-
const validationTime = Date.now()
|
|
543
|
-
this.logger.action(
|
|
544
|
-
'completion-validation-failed',
|
|
545
|
-
`Output validation failed: ${initialResult.error.message}. Retrying with error context...`,
|
|
546
|
-
0,
|
|
547
|
-
validationTime,
|
|
548
|
-
validationTime,
|
|
549
|
-
0
|
|
550
|
-
)
|
|
551
|
-
|
|
552
|
-
// Attempt 2: Retry with validation errors (use same temperature)
|
|
553
|
-
const retryPrompt = this.buildRetryPrompt(initialOutput, initialResult.error)
|
|
554
|
-
const retryOutput = await this.callLLMForOutput(
|
|
555
|
-
retryPrompt,
|
|
556
|
-
outputSchema,
|
|
557
|
-
modelTemperature,
|
|
558
|
-
'output-generation-retry'
|
|
559
|
-
)
|
|
560
|
-
|
|
561
|
-
// Strict validation on retry (wrap Zod errors in typed core error)
|
|
562
|
-
try {
|
|
563
|
-
const finalOutput = this.contract.outputSchema.parse(retryOutput) as TOutput
|
|
564
|
-
return { output: finalOutput, attempts: 2 }
|
|
565
|
-
} catch (error) {
|
|
566
|
-
// Don't let Zod error bubble up - wrap in typed core error
|
|
567
|
-
throw new AgentOutputValidationError('Agent output validation failed after retry', {
|
|
568
|
-
agentId: this.config.resourceId,
|
|
569
|
-
attempts: 2,
|
|
570
|
-
zodError: error instanceof ZodError ? error.format() : error
|
|
571
|
-
})
|
|
572
|
-
}
|
|
573
|
-
}
|
|
574
|
-
|
|
575
|
-
/**
|
|
576
|
-
* Call LLM for output generation
|
|
577
|
-
* Shared logic for initial and retry attempts
|
|
578
|
-
*
|
|
579
|
-
* @param systemPrompt - System prompt for output generation
|
|
580
|
-
* @param outputSchema - JSON schema for output validation
|
|
581
|
-
* @param temperature - LLM temperature setting
|
|
582
|
-
* @param actionType - Action type for logging (output-generation or output-generation-retry)
|
|
583
|
-
* @returns Generated structured output
|
|
584
|
-
*/
|
|
585
|
-
private async callLLMForOutput(
|
|
586
|
-
systemPrompt: string,
|
|
587
|
-
outputSchema: unknown,
|
|
588
|
-
temperature: number,
|
|
589
|
-
actionType: 'output-generation' | 'output-generation-retry'
|
|
590
|
-
): Promise<unknown> {
|
|
591
|
-
const generationStartTime = Date.now()
|
|
592
|
-
|
|
593
|
-
try {
|
|
594
|
-
this.logger.action(actionType, `${actionType} started`, 0, generationStartTime, generationStartTime, 0)
|
|
595
|
-
|
|
596
|
-
// Get attempt number from action type (1 for initial, 2 for retry)
|
|
597
|
-
const attempt = actionType === 'output-generation' ? 1 : 2
|
|
598
|
-
|
|
599
|
-
const adapter = this.adapterFactory(
|
|
600
|
-
this.modelConfig,
|
|
601
|
-
this.executionContext?.aiUsageCollector,
|
|
602
|
-
'agent-completion',
|
|
603
|
-
{
|
|
604
|
-
type: 'agent-completion',
|
|
605
|
-
attempt: attempt as 1 | 2,
|
|
606
|
-
sessionId: this.executionContext?.sessionId,
|
|
607
|
-
turnNumber: this.executionContext?.sessionTurnNumber
|
|
608
|
-
}
|
|
609
|
-
)
|
|
610
|
-
|
|
611
|
-
// Call LLM for completion using agent-specific helper (returns output directly)
|
|
612
|
-
const structuredOutput = await callLLMForAgentCompletion(adapter, {
|
|
613
|
-
systemPrompt,
|
|
614
|
-
memoryContext: this.memoryManager.toContext(this.iterationNumber, this.executionContext?.sessionTurnNumber),
|
|
615
|
-
outputSchema,
|
|
616
|
-
constraints: {
|
|
617
|
-
maxOutputTokens: this.modelConfig.maxOutputTokens,
|
|
618
|
-
temperature
|
|
619
|
-
},
|
|
620
|
-
model: this.modelConfig.model,
|
|
621
|
-
signal: this.executionContext?.signal
|
|
622
|
-
})
|
|
623
|
-
|
|
624
|
-
const generationEndTime = Date.now()
|
|
625
|
-
const generationDuration = generationEndTime - generationStartTime
|
|
626
|
-
this.logger.action(
|
|
627
|
-
actionType,
|
|
628
|
-
`${actionType} completed (${generationDuration}ms)`,
|
|
629
|
-
0,
|
|
630
|
-
generationStartTime,
|
|
631
|
-
generationEndTime,
|
|
632
|
-
generationDuration
|
|
633
|
-
)
|
|
634
|
-
|
|
635
|
-
return structuredOutput
|
|
636
|
-
} catch (error) {
|
|
637
|
-
const errorMessage = errorToString(error)
|
|
638
|
-
const generationEndTime = Date.now()
|
|
639
|
-
const generationDuration = generationEndTime - generationStartTime
|
|
640
|
-
this.logger.action(
|
|
641
|
-
actionType,
|
|
642
|
-
`${actionType} failed: ${errorMessage} (${generationDuration}ms)`,
|
|
643
|
-
0,
|
|
644
|
-
generationStartTime,
|
|
645
|
-
generationEndTime,
|
|
646
|
-
generationDuration
|
|
647
|
-
)
|
|
648
|
-
throw error
|
|
649
|
-
}
|
|
650
|
-
}
|
|
651
|
-
|
|
652
|
-
/**
|
|
653
|
-
* Build system prompt for output generation phase
|
|
654
|
-
* Instructs LLM to synthesize execution history into structured output
|
|
655
|
-
* Note: Only called from generateFinalOutput() which ensures outputSchema exists
|
|
656
|
-
*
|
|
657
|
-
* @returns System prompt for completion phase
|
|
658
|
-
*/
|
|
659
|
-
private buildOutputGenerationPrompt(): string {
|
|
660
|
-
// Type assertion safe: only called from generateFinalOutput() which checks outputSchema exists
|
|
661
|
-
const schema = this.contract.outputSchema!
|
|
662
|
-
|
|
663
|
-
const schemaJson = zodToJsonSchema(schema as z.ZodSchema<any>, {
|
|
664
|
-
$refStrategy: 'none',
|
|
665
|
-
errorMessages: true
|
|
666
|
-
})
|
|
667
|
-
|
|
668
|
-
return `
|
|
669
|
-
You have completed a task. Generate the final output based on the execution history.
|
|
670
|
-
|
|
671
|
-
## Output Schema
|
|
672
|
-
|
|
673
|
-
The output MUST match this exact structure:
|
|
674
|
-
|
|
675
|
-
${JSON.stringify(schemaJson, null, 2)}
|
|
676
|
-
|
|
677
|
-
## Task Context
|
|
678
|
-
|
|
679
|
-
Review the execution history in the memory context below. Extract and structure the relevant information according to the schema.
|
|
680
|
-
|
|
681
|
-
## Requirements
|
|
682
|
-
|
|
683
|
-
- Include all required fields
|
|
684
|
-
- Use exact field names and types
|
|
685
|
-
- Ensure data integrity (no hallucination)
|
|
686
|
-
- Base output on actual execution results
|
|
687
|
-
|
|
688
|
-
Generate the final output now.
|
|
689
|
-
`.trim()
|
|
690
|
-
}
|
|
691
|
-
|
|
692
|
-
/**
|
|
693
|
-
* Build retry prompt with validation error context
|
|
694
|
-
*
|
|
695
|
-
* @param failedOutput - The output that failed validation
|
|
696
|
-
* @param validationError - Zod validation error with details
|
|
697
|
-
* @returns System prompt for retry attempt
|
|
698
|
-
*/
|
|
699
|
-
private buildRetryPrompt(failedOutput: unknown, validationError: z.ZodError): string {
|
|
700
|
-
return `
|
|
701
|
-
${this.buildOutputGenerationPrompt()}
|
|
702
|
-
|
|
703
|
-
## Previous Attempt (FAILED VALIDATION)
|
|
704
|
-
|
|
705
|
-
${JSON.stringify(failedOutput, null, 2)}
|
|
706
|
-
|
|
707
|
-
## Validation Errors
|
|
708
|
-
|
|
709
|
-
${validationError.issues.map((e) => `- ${e.path.join('.')}: ${e.message}`).join('\n')}
|
|
710
|
-
|
|
711
|
-
Fix the errors and generate a valid output.
|
|
712
|
-
`.trim()
|
|
713
|
-
}
|
|
714
|
-
|
|
715
|
-
/**
|
|
716
|
-
* Get memory snapshot after execution
|
|
717
|
-
* Delegates to MemoryManager.getSnapshot()
|
|
718
|
-
* @returns Memory snapshot (only available after execute() completes)
|
|
719
|
-
*/
|
|
720
|
-
public getMemorySnapshot(): AgentMemory | undefined {
|
|
721
|
-
return this.memoryManager.getSnapshot()
|
|
722
|
-
}
|
|
723
|
-
|
|
724
|
-
/**
|
|
725
|
-
* Build the execution context for the agent
|
|
726
|
-
* @param iteration - Current iteration number (1-based)
|
|
727
|
-
* @param context - Execution context
|
|
728
|
-
* @returns Agent execution context
|
|
729
|
-
*/
|
|
730
|
-
private buildIterationContext(iteration: number, context: ExecutionContext): IterationContext {
|
|
731
|
-
return {
|
|
732
|
-
config: this.config,
|
|
733
|
-
contract: this.contract,
|
|
734
|
-
toolRegistry: this.toolRegistry,
|
|
735
|
-
memoryManager: this.memoryManager,
|
|
736
|
-
executionContext: context,
|
|
737
|
-
iteration,
|
|
738
|
-
logger: this.logger,
|
|
739
|
-
modelConfig: this.modelConfig,
|
|
740
|
-
adapterFactory: this.adapterFactory,
|
|
741
|
-
knowledgeMap: this.knowledgeMap
|
|
742
|
-
}
|
|
743
|
-
}
|
|
744
|
-
|
|
745
|
-
/**
|
|
746
|
-
* Helper to wrap errors with lifecycle logging
|
|
747
|
-
* @param phase - Lifecycle phase (initialization, iteration, completion)
|
|
748
|
-
* @param startTime - Phase start timestamp
|
|
749
|
-
* @param error - Original error
|
|
750
|
-
* @param context - Additional error context
|
|
751
|
-
*/
|
|
752
|
-
private wrapAndLogError(
|
|
753
|
-
phase: 'initialization' | 'iteration' | 'completion',
|
|
754
|
-
startTime: number,
|
|
755
|
-
error: unknown,
|
|
756
|
-
context?: Record<string, unknown>
|
|
757
|
-
): never {
|
|
758
|
-
const errorMessage = errorToString(error)
|
|
759
|
-
const errorDetails = getErrorDetails(error)
|
|
760
|
-
const endTime = Date.now()
|
|
761
|
-
const duration = endTime - startTime
|
|
762
|
-
|
|
763
|
-
// Logger may not be created yet if error occurs during initialization
|
|
764
|
-
if (this.logger) {
|
|
765
|
-
const logContext: {
|
|
766
|
-
error: string
|
|
767
|
-
errorDetails: ReturnType<typeof getErrorDetails>
|
|
768
|
-
startTime: number
|
|
769
|
-
endTime: number
|
|
770
|
-
duration: number
|
|
771
|
-
iteration?: number
|
|
772
|
-
} = {
|
|
773
|
-
error: errorMessage,
|
|
774
|
-
errorDetails, // Include full error details for debugging
|
|
775
|
-
startTime,
|
|
776
|
-
endTime,
|
|
777
|
-
duration
|
|
778
|
-
}
|
|
779
|
-
|
|
780
|
-
if (phase === 'iteration' && context?.iteration) {
|
|
781
|
-
logContext.iteration = context.iteration as number
|
|
782
|
-
}
|
|
783
|
-
|
|
784
|
-
this.logger.lifecycle(phase, 'failed', logContext)
|
|
785
|
-
}
|
|
786
|
-
|
|
787
|
-
// If the error is already a typed ExecutionError, preserve it.
|
|
788
|
-
// Phase info is already captured in the lifecycle log above.
|
|
789
|
-
if (error instanceof ExecutionError) {
|
|
790
|
-
throw error
|
|
791
|
-
}
|
|
792
|
-
|
|
793
|
-
// Wrap non-ExecutionError instances in phase-appropriate class
|
|
794
|
-
const errorContext = {
|
|
795
|
-
...(context || {}),
|
|
796
|
-
agentId: this.config.resourceId,
|
|
797
|
-
originalError: error instanceof Error ? error.name : 'unknown',
|
|
798
|
-
...errorDetails // Include validation errors, stack traces, etc.
|
|
799
|
-
}
|
|
800
|
-
|
|
801
|
-
if (phase === 'initialization') {
|
|
802
|
-
throw new AgentInitializationError(errorMessage, errorContext)
|
|
803
|
-
} else if (phase === 'iteration') {
|
|
804
|
-
throw new AgentIterationError(errorMessage, errorContext)
|
|
805
|
-
} else {
|
|
806
|
-
// completion phase
|
|
807
|
-
throw new AgentCompletionError(errorMessage, errorContext)
|
|
808
|
-
}
|
|
809
|
-
}
|
|
810
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* Agent class
|
|
3
|
+
* Autonomous agents that self-orchestrate with LLM and tool calling
|
|
4
|
+
* Uses universal protocol with vendor-independent message format
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import type { Contract, ExecutionContext } from '../../base/types'
|
|
8
|
+
import type { AgentConfig, IterationContext, AgentMemory, AgentDefinition, LLMAdapterFactory } from './types'
|
|
9
|
+
import type { Tool } from '../../tools/types'
|
|
10
|
+
import type { ModelConfig } from '../../llm/model-info'
|
|
11
|
+
import { createAgentLogger, type AgentScopedLogger } from '../observability/logging'
|
|
12
|
+
import { errorToString, getErrorDetails } from '../../../../platform/utils/error'
|
|
13
|
+
import { processReasoning } from '../reasoning/processor'
|
|
14
|
+
import { processActions } from '../actions/processor'
|
|
15
|
+
import { processMemory } from '../memory/processor'
|
|
16
|
+
import { MemoryManager } from '../memory/manager'
|
|
17
|
+
import { callLLMForAgentCompletion } from '../reasoning/adapters/agent-adapter-helpers'
|
|
18
|
+
import { zodToJsonSchema } from '@alcyone-labs/zod-to-json-schema'
|
|
19
|
+
import type { KnowledgeMap } from '../knowledge-map/types'
|
|
20
|
+
import { reloadKnowledgeMapTools } from '../knowledge-map/utils'
|
|
21
|
+
import type { z } from 'zod'
|
|
22
|
+
import { ZodError } from 'zod'
|
|
23
|
+
import {
|
|
24
|
+
AgentInitializationError,
|
|
25
|
+
AgentIterationError,
|
|
26
|
+
AgentCancellationError,
|
|
27
|
+
AgentCompletionError,
|
|
28
|
+
AgentOutputValidationError,
|
|
29
|
+
AgentMaxIterationsError,
|
|
30
|
+
AgentTimeoutError,
|
|
31
|
+
AgentStalledError
|
|
32
|
+
} from '../errors'
|
|
33
|
+
import { ExecutionError } from '../../base/errors'
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Create a per-execution shallow copy of the knowledge map
|
|
37
|
+
* Prevents concurrent executions from mutating shared definition state
|
|
38
|
+
* (node.loaded, node.prompt, and child node flattening)
|
|
39
|
+
*/
|
|
40
|
+
function initializeKnowledgeMap(knowledgeMap?: KnowledgeMap): KnowledgeMap | undefined {
|
|
41
|
+
if (!knowledgeMap) return undefined
|
|
42
|
+
return {
|
|
43
|
+
nodes: Object.fromEntries(Object.entries(knowledgeMap.nodes).map(([id, node]) => [id, { ...node }]))
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Autonomous agent that uses LLM reasoning and tool calling
|
|
49
|
+
* to complete tasks without predefined orchestration
|
|
50
|
+
*
|
|
51
|
+
* @template TInput - Input type validated by contract.inputSchema
|
|
52
|
+
* @template TOutput - Output type validated by contract.outputSchema
|
|
53
|
+
*/
|
|
54
|
+
export class Agent<TInput = unknown, TOutput = unknown> {
|
|
55
|
+
// Base properties from definition
|
|
56
|
+
public readonly config: AgentConfig
|
|
57
|
+
public readonly contract: Contract
|
|
58
|
+
private readonly toolRegistry: Map<string, Tool>
|
|
59
|
+
public readonly modelConfig: ModelConfig
|
|
60
|
+
private readonly knowledgeMap?: KnowledgeMap
|
|
61
|
+
private readonly definition: AgentDefinition
|
|
62
|
+
private readonly adapterFactory: LLMAdapterFactory
|
|
63
|
+
|
|
64
|
+
// Derived properties (computed from definition)
|
|
65
|
+
private readonly shouldGenerateOutput: boolean
|
|
66
|
+
|
|
67
|
+
// Runtime state (initialized during execution)
|
|
68
|
+
public memoryManager!: MemoryManager
|
|
69
|
+
private logger!: AgentScopedLogger
|
|
70
|
+
private executionContext!: ExecutionContext
|
|
71
|
+
private iterationNumber: number = 0 // Current iteration number (used for memory context filtering)
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Create a new agent instance from definition
|
|
75
|
+
* Memory will be initialized during execution
|
|
76
|
+
*
|
|
77
|
+
* @param definition - Agent definition with config, contract, tools, and optional preloadMemory
|
|
78
|
+
* @param adapterFactory - Factory for creating LLM adapters (decouples engine from provider SDKs)
|
|
79
|
+
*/
|
|
80
|
+
constructor(definition: AgentDefinition, adapterFactory: LLMAdapterFactory) {
|
|
81
|
+
this.definition = definition
|
|
82
|
+
this.adapterFactory = adapterFactory
|
|
83
|
+
this.config = definition.config
|
|
84
|
+
this.contract = definition.contract
|
|
85
|
+
this.modelConfig = definition.modelConfig // Store model config from definition
|
|
86
|
+
this.knowledgeMap = initializeKnowledgeMap(definition.knowledgeMap)
|
|
87
|
+
|
|
88
|
+
// Initialize tool registry with base tools
|
|
89
|
+
this.toolRegistry = new Map()
|
|
90
|
+
for (const tool of definition.tools) {
|
|
91
|
+
this.toolRegistry.set(tool.name, tool)
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Derive shouldGenerateOutput from outputSchema presence (automatic detection)
|
|
95
|
+
this.shouldGenerateOutput = !!definition.contract.outputSchema
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Execute the agent with validated input and context
|
|
100
|
+
* Orchestrates the three lifecycle phases: initialization, iteration, completion
|
|
101
|
+
*
|
|
102
|
+
* @param input - Raw input (will be validated against contract.inputSchema)
|
|
103
|
+
* @param context - Execution context (required for tracking, logging, and organization isolation)
|
|
104
|
+
* @returns Validated output matching contract.outputSchema, or null if no output schema
|
|
105
|
+
*/
|
|
106
|
+
async execute(input: TInput, context: ExecutionContext): Promise<TOutput | null> {
|
|
107
|
+
// Store execution context for completion phase
|
|
108
|
+
this.executionContext = context
|
|
109
|
+
|
|
110
|
+
// Emit agent started event
|
|
111
|
+
await context.onMessageEvent?.({ type: 'agent:started' })
|
|
112
|
+
|
|
113
|
+
try {
|
|
114
|
+
// Phase 1: Initialize
|
|
115
|
+
await this.initialize(input, context)
|
|
116
|
+
|
|
117
|
+
// Phase 2: Iterate (task execution)
|
|
118
|
+
await this.iterate(context)
|
|
119
|
+
|
|
120
|
+
// Phase 3: Complete (output generation)
|
|
121
|
+
const output = await this.complete()
|
|
122
|
+
|
|
123
|
+
// Emit agent completed event
|
|
124
|
+
await context.onMessageEvent?.({ type: 'agent:completed' })
|
|
125
|
+
|
|
126
|
+
return output
|
|
127
|
+
} catch (error) {
|
|
128
|
+
// Emit agent error event
|
|
129
|
+
await context.onMessageEvent?.({ type: 'agent:error', error: String(error) })
|
|
130
|
+
throw error
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Register tools from a loaded knowledge node
|
|
136
|
+
* Called by navigate_knowledge tool during execution
|
|
137
|
+
*
|
|
138
|
+
* @param tools - Array of tools to register
|
|
139
|
+
* Note: Silently skips tools that are already registered
|
|
140
|
+
*/
|
|
141
|
+
public registerTools(tools: Tool[]): void {
|
|
142
|
+
for (const tool of tools) {
|
|
143
|
+
if (!this.toolRegistry.has(tool.name)) {
|
|
144
|
+
this.toolRegistry.set(tool.name, tool)
|
|
145
|
+
}
|
|
146
|
+
// Skip tools that are already registered (graceful handling)
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Get all currently registered tools
|
|
152
|
+
* Used for system prompt generation and introspection
|
|
153
|
+
*
|
|
154
|
+
* @returns Array of all registered tools
|
|
155
|
+
*/
|
|
156
|
+
public getTools(): Tool[] {
|
|
157
|
+
return Array.from(this.toolRegistry.values())
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Phase 1: Initialize the agent execution
|
|
162
|
+
* Validates input, initializes memory manager
|
|
163
|
+
*
|
|
164
|
+
* @param input - Raw input to validate
|
|
165
|
+
* @param context - Execution context
|
|
166
|
+
*/
|
|
167
|
+
private async initialize(input: TInput, context: ExecutionContext): Promise<void> {
|
|
168
|
+
const initStartTime = Date.now()
|
|
169
|
+
|
|
170
|
+
try {
|
|
171
|
+
// Create scoped logger for this execution
|
|
172
|
+
// Pass sessionId if present in context (now directly on ExecutionMetadata)
|
|
173
|
+
this.logger = createAgentLogger(context.logger, this.config.resourceId, context.sessionId)
|
|
174
|
+
|
|
175
|
+
this.logger.lifecycle('initialization', 'started', {
|
|
176
|
+
startTime: initStartTime
|
|
177
|
+
})
|
|
178
|
+
|
|
179
|
+
// Validate input
|
|
180
|
+
const validatedInput = this.contract.inputSchema.parse(input) as TInput
|
|
181
|
+
|
|
182
|
+
// Initialize memory manager (encapsulates all memory initialization)
|
|
183
|
+
this.memoryManager = await this.initializeMemoryManager(validatedInput, context)
|
|
184
|
+
|
|
185
|
+
const initEndTime = Date.now()
|
|
186
|
+
this.logger.lifecycle('initialization', 'completed', {
|
|
187
|
+
startTime: initStartTime,
|
|
188
|
+
endTime: initEndTime,
|
|
189
|
+
duration: initEndTime - initStartTime
|
|
190
|
+
})
|
|
191
|
+
} catch (error) {
|
|
192
|
+
this.wrapAndLogError('initialization', initStartTime, error)
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* Initialize memory manager with preloaded memory and input entry
|
|
198
|
+
* Encapsulates all memory initialization complexity
|
|
199
|
+
*
|
|
200
|
+
* Also handles cross-turn persistence: re-registers tools from knowledge nodes
|
|
201
|
+
* that were loaded in previous session turns.
|
|
202
|
+
*
|
|
203
|
+
* @param validatedInput - Validated input to add to memory history
|
|
204
|
+
* @param context - Execution context (passed to preloadMemory)
|
|
205
|
+
* @returns Initialized MemoryManager instance
|
|
206
|
+
*/
|
|
207
|
+
private async initializeMemoryManager(validatedInput: TInput, context: ExecutionContext): Promise<MemoryManager> {
|
|
208
|
+
// Preload memory if callback defined
|
|
209
|
+
let memory: AgentMemory
|
|
210
|
+
if (this.definition.preloadMemory) {
|
|
211
|
+
const preloadStartTime = Date.now()
|
|
212
|
+
memory = await this.definition.preloadMemory(context)
|
|
213
|
+
const preloadEndTime = Date.now()
|
|
214
|
+
this.logger.action(
|
|
215
|
+
'memory-preload',
|
|
216
|
+
`Preloaded ${Object.keys(memory.sessionMemory).length} session memory entries`,
|
|
217
|
+
0,
|
|
218
|
+
preloadStartTime,
|
|
219
|
+
preloadEndTime,
|
|
220
|
+
preloadEndTime - preloadStartTime
|
|
221
|
+
)
|
|
222
|
+
|
|
223
|
+
// Reload tools from knowledge map if state exists (cross-turn persistence)
|
|
224
|
+
await this.reloadKnowledgeMapTools(memory, context)
|
|
225
|
+
} else {
|
|
226
|
+
// Default: empty memory
|
|
227
|
+
memory = {
|
|
228
|
+
sessionMemory: {},
|
|
229
|
+
history: []
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
// Add input entry to history (iteration 0 = pre-iteration setup)
|
|
234
|
+
const inputStartTime = Date.now()
|
|
235
|
+
|
|
236
|
+
memory.history.push({
|
|
237
|
+
type: 'input',
|
|
238
|
+
content: JSON.stringify(validatedInput),
|
|
239
|
+
timestamp: Date.now(),
|
|
240
|
+
turnNumber: context.sessionTurnNumber ?? null,
|
|
241
|
+
iterationNumber: 0
|
|
242
|
+
})
|
|
243
|
+
const inputEndTime = Date.now()
|
|
244
|
+
|
|
245
|
+
this.logger.action(
|
|
246
|
+
'memory-input',
|
|
247
|
+
`Added input entry to history`,
|
|
248
|
+
0,
|
|
249
|
+
inputStartTime,
|
|
250
|
+
inputEndTime,
|
|
251
|
+
inputEndTime - inputStartTime
|
|
252
|
+
)
|
|
253
|
+
|
|
254
|
+
// Create and return memory manager (takes ownership of memory)
|
|
255
|
+
return new MemoryManager(memory, this.config.constraints, this.logger)
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
/**
|
|
259
|
+
* Reload tools from knowledge map state (cross-turn persistence)
|
|
260
|
+
*
|
|
261
|
+
* Reads the knowledge-map-state from sessionMemory and re-registers
|
|
262
|
+
* tools from previously loaded knowledge nodes.
|
|
263
|
+
*
|
|
264
|
+
* @param memory - Agent memory with sessionMemory state
|
|
265
|
+
* @param context - Execution context
|
|
266
|
+
*/
|
|
267
|
+
private async reloadKnowledgeMapTools(memory: AgentMemory, context: ExecutionContext): Promise<void> {
|
|
268
|
+
// Only reload if knowledge map exists
|
|
269
|
+
if (!this.knowledgeMap) {
|
|
270
|
+
return
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
const stateJson = memory.sessionMemory['knowledge-map-state']
|
|
274
|
+
if (!stateJson) {
|
|
275
|
+
return // No state to reload
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
const reloadStartTime = Date.now()
|
|
279
|
+
|
|
280
|
+
try {
|
|
281
|
+
const tools = await reloadKnowledgeMapTools(this.knowledgeMap, memory, context)
|
|
282
|
+
|
|
283
|
+
// Register reloaded tools (skip duplicates gracefully)
|
|
284
|
+
let registeredCount = 0
|
|
285
|
+
let skippedCount = 0
|
|
286
|
+
|
|
287
|
+
for (const tool of tools) {
|
|
288
|
+
if (this.toolRegistry.has(tool.name)) {
|
|
289
|
+
skippedCount++
|
|
290
|
+
} else {
|
|
291
|
+
this.toolRegistry.set(tool.name, tool)
|
|
292
|
+
registeredCount++
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
const reloadEndTime = Date.now()
|
|
297
|
+
|
|
298
|
+
if (registeredCount > 0) {
|
|
299
|
+
const state = JSON.parse(stateJson.content)
|
|
300
|
+
this.logger.action(
|
|
301
|
+
'knowledge-reload',
|
|
302
|
+
`Reloaded ${registeredCount} tools from ${state.loadedNodes.length} knowledge nodes: ${state.loadedNodes.join(', ')}`,
|
|
303
|
+
0,
|
|
304
|
+
reloadStartTime,
|
|
305
|
+
reloadEndTime,
|
|
306
|
+
reloadEndTime - reloadStartTime
|
|
307
|
+
)
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
if (skippedCount > 0) {
|
|
311
|
+
this.logger.action(
|
|
312
|
+
'knowledge-reload-skipped',
|
|
313
|
+
`Skipped ${skippedCount} already-registered tools during reload`,
|
|
314
|
+
0,
|
|
315
|
+
reloadStartTime,
|
|
316
|
+
reloadEndTime,
|
|
317
|
+
reloadEndTime - reloadStartTime
|
|
318
|
+
)
|
|
319
|
+
}
|
|
320
|
+
} catch (error) {
|
|
321
|
+
const errorMessage = errorToString(error)
|
|
322
|
+
const reloadEndTime = Date.now()
|
|
323
|
+
this.logger.action(
|
|
324
|
+
'knowledge-reload-failed',
|
|
325
|
+
`Failed to reload knowledge map: ${errorMessage}`,
|
|
326
|
+
0,
|
|
327
|
+
reloadStartTime,
|
|
328
|
+
reloadEndTime,
|
|
329
|
+
reloadEndTime - reloadStartTime
|
|
330
|
+
)
|
|
331
|
+
// Continue execution - tools can be re-loaded on demand if needed
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
/**
|
|
336
|
+
* Phase 2: Run the agent iteration loop
|
|
337
|
+
* Continues until LLM signals completion or max iterations reached
|
|
338
|
+
*
|
|
339
|
+
* @param context - Execution context
|
|
340
|
+
*/
|
|
341
|
+
private async iterate(context: ExecutionContext): Promise<void> {
|
|
342
|
+
const maxIterations = this.config.constraints?.maxIterations || 10
|
|
343
|
+
let iteration = 1
|
|
344
|
+
|
|
345
|
+
while (iteration <= maxIterations) {
|
|
346
|
+
// Check for abort (timeout, stalled, or cancellation)
|
|
347
|
+
if (context.signal?.aborted) {
|
|
348
|
+
if (context.signal.reason === 'timeout') {
|
|
349
|
+
throw new AgentTimeoutError(`Agent execution exceeded timeout (${this.config.constraints?.timeout}ms)`, {
|
|
350
|
+
timeout: this.config.constraints?.timeout ?? 0,
|
|
351
|
+
iteration
|
|
352
|
+
})
|
|
353
|
+
}
|
|
354
|
+
if (context.signal.reason === 'stalled') {
|
|
355
|
+
throw new AgentStalledError('Execution stalled: no heartbeat received within threshold', { iteration })
|
|
356
|
+
}
|
|
357
|
+
throw new AgentCancellationError('Execution cancelled by user', { iteration })
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
// Write heartbeat (non-fatal if it fails)
|
|
361
|
+
try {
|
|
362
|
+
await context.onHeartbeat?.()
|
|
363
|
+
} catch {
|
|
364
|
+
// Heartbeat failure is non-fatal — execution continues
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
const result = await this.runIteration(iteration, context)
|
|
368
|
+
if (result.shouldComplete) {
|
|
369
|
+
return // Exit iteration loop (output generated in completion phase)
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
iteration++
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
// Max iterations exceeded
|
|
376
|
+
throw new AgentMaxIterationsError(`Agent exceeded maximum iterations (${maxIterations})`, {
|
|
377
|
+
maxIterations,
|
|
378
|
+
currentIteration: maxIterations
|
|
379
|
+
})
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
/**
|
|
383
|
+
* Run a single iteration of the agent loop
|
|
384
|
+
*
|
|
385
|
+
* Three-phase execution:
|
|
386
|
+
* 1. REASON - Query LLM for next actions, store reasoning to memory
|
|
387
|
+
* 2. MEMORY - Process memory operations (set/delete session memory entries)
|
|
388
|
+
* 3. ACT - Execute planned actions, store tool results to memory
|
|
389
|
+
*
|
|
390
|
+
* @param iteration - Current iteration number (1-based)
|
|
391
|
+
* @param context - Execution context
|
|
392
|
+
* @returns Iteration result with completion flag (no finalAnswer - generated in completion phase)
|
|
393
|
+
*/
|
|
394
|
+
private async runIteration(iteration: number, context: ExecutionContext): Promise<{ shouldComplete: boolean }> {
|
|
395
|
+
const iterationStartTime = Date.now()
|
|
396
|
+
|
|
397
|
+
// Track current iteration number (used by toContext() for memory filtering)
|
|
398
|
+
this.iterationNumber = iteration
|
|
399
|
+
|
|
400
|
+
try {
|
|
401
|
+
this.logger.lifecycle('iteration', 'started', {
|
|
402
|
+
iteration,
|
|
403
|
+
startTime: iterationStartTime
|
|
404
|
+
})
|
|
405
|
+
|
|
406
|
+
// Build iteration context
|
|
407
|
+
const iterationContext: IterationContext = this.buildIterationContext(iteration, context)
|
|
408
|
+
|
|
409
|
+
// Phase 1: REASON - Get LLM's decision and store reasoning to memory
|
|
410
|
+
const response = await processReasoning(iterationContext)
|
|
411
|
+
|
|
412
|
+
// Phase 2: MEMORY - Process memory operations (agent-directed)
|
|
413
|
+
await processMemory(this.memoryManager, response, this.logger, iteration)
|
|
414
|
+
|
|
415
|
+
// Phase 3: ACT - Execute LLM's plan and store tool results to memory
|
|
416
|
+
const { shouldComplete } = await processActions(iterationContext, response)
|
|
417
|
+
|
|
418
|
+
// Log completion
|
|
419
|
+
this.logIterationEnd(iteration, iterationStartTime)
|
|
420
|
+
|
|
421
|
+
// Return result
|
|
422
|
+
return { shouldComplete }
|
|
423
|
+
} catch (error) {
|
|
424
|
+
this.wrapAndLogError('iteration', iterationStartTime, error, { iteration })
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
/**
|
|
429
|
+
* Log iteration end (success only - failures handled by wrapAndLogError)
|
|
430
|
+
*/
|
|
431
|
+
private logIterationEnd(iteration: number, startTime: number): void {
|
|
432
|
+
const endTime = Date.now()
|
|
433
|
+
const duration = endTime - startTime
|
|
434
|
+
|
|
435
|
+
this.logger.lifecycle('iteration', 'completed', {
|
|
436
|
+
iteration,
|
|
437
|
+
startTime,
|
|
438
|
+
endTime,
|
|
439
|
+
duration
|
|
440
|
+
})
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
/**
|
|
444
|
+
* Phase 3: Complete the agent execution
|
|
445
|
+
* Generates and validates structured output from execution history (if output schema present)
|
|
446
|
+
* Captures memory snapshot for persistence
|
|
447
|
+
*
|
|
448
|
+
* @returns Validated output or null if no output schema
|
|
449
|
+
*/
|
|
450
|
+
private async complete(): Promise<TOutput | null> {
|
|
451
|
+
const completionStartTime = Date.now()
|
|
452
|
+
|
|
453
|
+
try {
|
|
454
|
+
this.logger.lifecycle('completion', 'started', {
|
|
455
|
+
startTime: completionStartTime
|
|
456
|
+
})
|
|
457
|
+
|
|
458
|
+
// Conditionally generate output based on schema presence
|
|
459
|
+
let output: TOutput | null = null
|
|
460
|
+
let attempts: number | undefined
|
|
461
|
+
|
|
462
|
+
if (this.shouldGenerateOutput) {
|
|
463
|
+
// Generate output (includes retry logic internally)
|
|
464
|
+
const result = await this.generateFinalOutput()
|
|
465
|
+
output = result.output
|
|
466
|
+
attempts = result.attempts
|
|
467
|
+
} else {
|
|
468
|
+
// Skip output generation (side-effect only agent)
|
|
469
|
+
this.logger.action(
|
|
470
|
+
'completion-skipped',
|
|
471
|
+
'Output generation skipped (no output schema)',
|
|
472
|
+
0,
|
|
473
|
+
completionStartTime,
|
|
474
|
+
completionStartTime,
|
|
475
|
+
0
|
|
476
|
+
)
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
// Capture snapshot automatically (MemoryManager stores it)
|
|
480
|
+
this.memoryManager.toSnapshot()
|
|
481
|
+
|
|
482
|
+
const snapshot = this.memoryManager.getSnapshot()!
|
|
483
|
+
const completionEndTime = Date.now()
|
|
484
|
+
this.logger.lifecycle('completion', 'completed', {
|
|
485
|
+
startTime: completionStartTime,
|
|
486
|
+
endTime: completionEndTime,
|
|
487
|
+
duration: completionEndTime - completionStartTime,
|
|
488
|
+
attempts,
|
|
489
|
+
memorySize: {
|
|
490
|
+
sessionMemoryKeys: Object.keys(snapshot.sessionMemory).length,
|
|
491
|
+
historyEntries: snapshot.history.length
|
|
492
|
+
}
|
|
493
|
+
})
|
|
494
|
+
|
|
495
|
+
return output
|
|
496
|
+
} catch (error) {
|
|
497
|
+
this.wrapAndLogError('completion', completionStartTime, error)
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
/**
|
|
502
|
+
* Generate final output from execution history with retry logic
|
|
503
|
+
* Handles both initial generation and validation retry internally
|
|
504
|
+
*
|
|
505
|
+
* @returns Object with validated output and attempt count
|
|
506
|
+
*/
|
|
507
|
+
private async generateFinalOutput(): Promise<{ output: TOutput; attempts: number }> {
|
|
508
|
+
// Safety check: Ensure outputSchema exists before generating output
|
|
509
|
+
if (!this.contract.outputSchema) {
|
|
510
|
+
throw new AgentInitializationError(
|
|
511
|
+
`Internal error: generateFinalOutput called but contract.outputSchema is undefined`,
|
|
512
|
+
{
|
|
513
|
+
agentId: this.config.resourceId,
|
|
514
|
+
reason: 'missing_output_schema'
|
|
515
|
+
}
|
|
516
|
+
)
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
const outputSchema = zodToJsonSchema(this.contract.outputSchema as z.ZodSchema<any>, {
|
|
520
|
+
$refStrategy: 'none',
|
|
521
|
+
errorMessages: true
|
|
522
|
+
})
|
|
523
|
+
|
|
524
|
+
// Use model's configured temperature (some models like GPT-5-mini only support default)
|
|
525
|
+
const modelTemperature = this.modelConfig.temperature ?? 0.7
|
|
526
|
+
|
|
527
|
+
// Attempt 1: Initial generation
|
|
528
|
+
const initialOutput = await this.callLLMForOutput(
|
|
529
|
+
this.buildOutputGenerationPrompt(),
|
|
530
|
+
outputSchema,
|
|
531
|
+
modelTemperature,
|
|
532
|
+
'output-generation'
|
|
533
|
+
)
|
|
534
|
+
|
|
535
|
+
const initialResult = this.contract.outputSchema.safeParse(initialOutput)
|
|
536
|
+
|
|
537
|
+
if (initialResult.success) {
|
|
538
|
+
return { output: initialResult.data as TOutput, attempts: 1 }
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
// Attempt 1 failed - log and retry with error context
|
|
542
|
+
const validationTime = Date.now()
|
|
543
|
+
this.logger.action(
|
|
544
|
+
'completion-validation-failed',
|
|
545
|
+
`Output validation failed: ${initialResult.error.message}. Retrying with error context...`,
|
|
546
|
+
0,
|
|
547
|
+
validationTime,
|
|
548
|
+
validationTime,
|
|
549
|
+
0
|
|
550
|
+
)
|
|
551
|
+
|
|
552
|
+
// Attempt 2: Retry with validation errors (use same temperature)
|
|
553
|
+
const retryPrompt = this.buildRetryPrompt(initialOutput, initialResult.error)
|
|
554
|
+
const retryOutput = await this.callLLMForOutput(
|
|
555
|
+
retryPrompt,
|
|
556
|
+
outputSchema,
|
|
557
|
+
modelTemperature,
|
|
558
|
+
'output-generation-retry'
|
|
559
|
+
)
|
|
560
|
+
|
|
561
|
+
// Strict validation on retry (wrap Zod errors in typed core error)
|
|
562
|
+
try {
|
|
563
|
+
const finalOutput = this.contract.outputSchema.parse(retryOutput) as TOutput
|
|
564
|
+
return { output: finalOutput, attempts: 2 }
|
|
565
|
+
} catch (error) {
|
|
566
|
+
// Don't let Zod error bubble up - wrap in typed core error
|
|
567
|
+
throw new AgentOutputValidationError('Agent output validation failed after retry', {
|
|
568
|
+
agentId: this.config.resourceId,
|
|
569
|
+
attempts: 2,
|
|
570
|
+
zodError: error instanceof ZodError ? error.format() : error
|
|
571
|
+
})
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
/**
|
|
576
|
+
* Call LLM for output generation
|
|
577
|
+
* Shared logic for initial and retry attempts
|
|
578
|
+
*
|
|
579
|
+
* @param systemPrompt - System prompt for output generation
|
|
580
|
+
* @param outputSchema - JSON schema for output validation
|
|
581
|
+
* @param temperature - LLM temperature setting
|
|
582
|
+
* @param actionType - Action type for logging (output-generation or output-generation-retry)
|
|
583
|
+
* @returns Generated structured output
|
|
584
|
+
*/
|
|
585
|
+
private async callLLMForOutput(
|
|
586
|
+
systemPrompt: string,
|
|
587
|
+
outputSchema: unknown,
|
|
588
|
+
temperature: number,
|
|
589
|
+
actionType: 'output-generation' | 'output-generation-retry'
|
|
590
|
+
): Promise<unknown> {
|
|
591
|
+
const generationStartTime = Date.now()
|
|
592
|
+
|
|
593
|
+
try {
|
|
594
|
+
this.logger.action(actionType, `${actionType} started`, 0, generationStartTime, generationStartTime, 0)
|
|
595
|
+
|
|
596
|
+
// Get attempt number from action type (1 for initial, 2 for retry)
|
|
597
|
+
const attempt = actionType === 'output-generation' ? 1 : 2
|
|
598
|
+
|
|
599
|
+
const adapter = this.adapterFactory(
|
|
600
|
+
this.modelConfig,
|
|
601
|
+
this.executionContext?.aiUsageCollector,
|
|
602
|
+
'agent-completion',
|
|
603
|
+
{
|
|
604
|
+
type: 'agent-completion',
|
|
605
|
+
attempt: attempt as 1 | 2,
|
|
606
|
+
sessionId: this.executionContext?.sessionId,
|
|
607
|
+
turnNumber: this.executionContext?.sessionTurnNumber
|
|
608
|
+
}
|
|
609
|
+
)
|
|
610
|
+
|
|
611
|
+
// Call LLM for completion using agent-specific helper (returns output directly)
|
|
612
|
+
const structuredOutput = await callLLMForAgentCompletion(adapter, {
|
|
613
|
+
systemPrompt,
|
|
614
|
+
memoryContext: this.memoryManager.toContext(this.iterationNumber, this.executionContext?.sessionTurnNumber),
|
|
615
|
+
outputSchema,
|
|
616
|
+
constraints: {
|
|
617
|
+
maxOutputTokens: this.modelConfig.maxOutputTokens,
|
|
618
|
+
temperature
|
|
619
|
+
},
|
|
620
|
+
model: this.modelConfig.model,
|
|
621
|
+
signal: this.executionContext?.signal
|
|
622
|
+
})
|
|
623
|
+
|
|
624
|
+
const generationEndTime = Date.now()
|
|
625
|
+
const generationDuration = generationEndTime - generationStartTime
|
|
626
|
+
this.logger.action(
|
|
627
|
+
actionType,
|
|
628
|
+
`${actionType} completed (${generationDuration}ms)`,
|
|
629
|
+
0,
|
|
630
|
+
generationStartTime,
|
|
631
|
+
generationEndTime,
|
|
632
|
+
generationDuration
|
|
633
|
+
)
|
|
634
|
+
|
|
635
|
+
return structuredOutput
|
|
636
|
+
} catch (error) {
|
|
637
|
+
const errorMessage = errorToString(error)
|
|
638
|
+
const generationEndTime = Date.now()
|
|
639
|
+
const generationDuration = generationEndTime - generationStartTime
|
|
640
|
+
this.logger.action(
|
|
641
|
+
actionType,
|
|
642
|
+
`${actionType} failed: ${errorMessage} (${generationDuration}ms)`,
|
|
643
|
+
0,
|
|
644
|
+
generationStartTime,
|
|
645
|
+
generationEndTime,
|
|
646
|
+
generationDuration
|
|
647
|
+
)
|
|
648
|
+
throw error
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
/**
|
|
653
|
+
* Build system prompt for output generation phase
|
|
654
|
+
* Instructs LLM to synthesize execution history into structured output
|
|
655
|
+
* Note: Only called from generateFinalOutput() which ensures outputSchema exists
|
|
656
|
+
*
|
|
657
|
+
* @returns System prompt for completion phase
|
|
658
|
+
*/
|
|
659
|
+
private buildOutputGenerationPrompt(): string {
|
|
660
|
+
// Type assertion safe: only called from generateFinalOutput() which checks outputSchema exists
|
|
661
|
+
const schema = this.contract.outputSchema!
|
|
662
|
+
|
|
663
|
+
const schemaJson = zodToJsonSchema(schema as z.ZodSchema<any>, {
|
|
664
|
+
$refStrategy: 'none',
|
|
665
|
+
errorMessages: true
|
|
666
|
+
})
|
|
667
|
+
|
|
668
|
+
return `
|
|
669
|
+
You have completed a task. Generate the final output based on the execution history.
|
|
670
|
+
|
|
671
|
+
## Output Schema
|
|
672
|
+
|
|
673
|
+
The output MUST match this exact structure:
|
|
674
|
+
|
|
675
|
+
${JSON.stringify(schemaJson, null, 2)}
|
|
676
|
+
|
|
677
|
+
## Task Context
|
|
678
|
+
|
|
679
|
+
Review the execution history in the memory context below. Extract and structure the relevant information according to the schema.
|
|
680
|
+
|
|
681
|
+
## Requirements
|
|
682
|
+
|
|
683
|
+
- Include all required fields
|
|
684
|
+
- Use exact field names and types
|
|
685
|
+
- Ensure data integrity (no hallucination)
|
|
686
|
+
- Base output on actual execution results
|
|
687
|
+
|
|
688
|
+
Generate the final output now.
|
|
689
|
+
`.trim()
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
/**
|
|
693
|
+
* Build retry prompt with validation error context
|
|
694
|
+
*
|
|
695
|
+
* @param failedOutput - The output that failed validation
|
|
696
|
+
* @param validationError - Zod validation error with details
|
|
697
|
+
* @returns System prompt for retry attempt
|
|
698
|
+
*/
|
|
699
|
+
private buildRetryPrompt(failedOutput: unknown, validationError: z.ZodError): string {
|
|
700
|
+
return `
|
|
701
|
+
${this.buildOutputGenerationPrompt()}
|
|
702
|
+
|
|
703
|
+
## Previous Attempt (FAILED VALIDATION)
|
|
704
|
+
|
|
705
|
+
${JSON.stringify(failedOutput, null, 2)}
|
|
706
|
+
|
|
707
|
+
## Validation Errors
|
|
708
|
+
|
|
709
|
+
${validationError.issues.map((e) => `- ${e.path.join('.')}: ${e.message}`).join('\n')}
|
|
710
|
+
|
|
711
|
+
Fix the errors and generate a valid output.
|
|
712
|
+
`.trim()
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
/**
|
|
716
|
+
* Get memory snapshot after execution
|
|
717
|
+
* Delegates to MemoryManager.getSnapshot()
|
|
718
|
+
* @returns Memory snapshot (only available after execute() completes)
|
|
719
|
+
*/
|
|
720
|
+
public getMemorySnapshot(): AgentMemory | undefined {
|
|
721
|
+
return this.memoryManager.getSnapshot()
|
|
722
|
+
}
|
|
723
|
+
|
|
724
|
+
/**
|
|
725
|
+
* Build the execution context for the agent
|
|
726
|
+
* @param iteration - Current iteration number (1-based)
|
|
727
|
+
* @param context - Execution context
|
|
728
|
+
* @returns Agent execution context
|
|
729
|
+
*/
|
|
730
|
+
private buildIterationContext(iteration: number, context: ExecutionContext): IterationContext {
|
|
731
|
+
return {
|
|
732
|
+
config: this.config,
|
|
733
|
+
contract: this.contract,
|
|
734
|
+
toolRegistry: this.toolRegistry,
|
|
735
|
+
memoryManager: this.memoryManager,
|
|
736
|
+
executionContext: context,
|
|
737
|
+
iteration,
|
|
738
|
+
logger: this.logger,
|
|
739
|
+
modelConfig: this.modelConfig,
|
|
740
|
+
adapterFactory: this.adapterFactory,
|
|
741
|
+
knowledgeMap: this.knowledgeMap
|
|
742
|
+
}
|
|
743
|
+
}
|
|
744
|
+
|
|
745
|
+
/**
|
|
746
|
+
* Helper to wrap errors with lifecycle logging
|
|
747
|
+
* @param phase - Lifecycle phase (initialization, iteration, completion)
|
|
748
|
+
* @param startTime - Phase start timestamp
|
|
749
|
+
* @param error - Original error
|
|
750
|
+
* @param context - Additional error context
|
|
751
|
+
*/
|
|
752
|
+
private wrapAndLogError(
|
|
753
|
+
phase: 'initialization' | 'iteration' | 'completion',
|
|
754
|
+
startTime: number,
|
|
755
|
+
error: unknown,
|
|
756
|
+
context?: Record<string, unknown>
|
|
757
|
+
): never {
|
|
758
|
+
const errorMessage = errorToString(error)
|
|
759
|
+
const errorDetails = getErrorDetails(error)
|
|
760
|
+
const endTime = Date.now()
|
|
761
|
+
const duration = endTime - startTime
|
|
762
|
+
|
|
763
|
+
// Logger may not be created yet if error occurs during initialization
|
|
764
|
+
if (this.logger) {
|
|
765
|
+
const logContext: {
|
|
766
|
+
error: string
|
|
767
|
+
errorDetails: ReturnType<typeof getErrorDetails>
|
|
768
|
+
startTime: number
|
|
769
|
+
endTime: number
|
|
770
|
+
duration: number
|
|
771
|
+
iteration?: number
|
|
772
|
+
} = {
|
|
773
|
+
error: errorMessage,
|
|
774
|
+
errorDetails, // Include full error details for debugging
|
|
775
|
+
startTime,
|
|
776
|
+
endTime,
|
|
777
|
+
duration
|
|
778
|
+
}
|
|
779
|
+
|
|
780
|
+
if (phase === 'iteration' && context?.iteration) {
|
|
781
|
+
logContext.iteration = context.iteration as number
|
|
782
|
+
}
|
|
783
|
+
|
|
784
|
+
this.logger.lifecycle(phase, 'failed', logContext)
|
|
785
|
+
}
|
|
786
|
+
|
|
787
|
+
// If the error is already a typed ExecutionError, preserve it.
|
|
788
|
+
// Phase info is already captured in the lifecycle log above.
|
|
789
|
+
if (error instanceof ExecutionError) {
|
|
790
|
+
throw error
|
|
791
|
+
}
|
|
792
|
+
|
|
793
|
+
// Wrap non-ExecutionError instances in phase-appropriate class
|
|
794
|
+
const errorContext = {
|
|
795
|
+
...(context || {}),
|
|
796
|
+
agentId: this.config.resourceId,
|
|
797
|
+
originalError: error instanceof Error ? error.name : 'unknown',
|
|
798
|
+
...errorDetails // Include validation errors, stack traces, etc.
|
|
799
|
+
}
|
|
800
|
+
|
|
801
|
+
if (phase === 'initialization') {
|
|
802
|
+
throw new AgentInitializationError(errorMessage, errorContext)
|
|
803
|
+
} else if (phase === 'iteration') {
|
|
804
|
+
throw new AgentIterationError(errorMessage, errorContext)
|
|
805
|
+
} else {
|
|
806
|
+
// completion phase
|
|
807
|
+
throw new AgentCompletionError(errorMessage, errorContext)
|
|
808
|
+
}
|
|
809
|
+
}
|
|
810
|
+
}
|