@db3.ai/app 0.1.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +31 -0
- package/README.md +241 -0
- package/agent-instructions.md +69 -0
- package/bin/db3-agents.mjs +140 -0
- package/bin/db3.mjs +11 -0
- package/dist/ai/AIErrors.d.ts +33 -0
- package/dist/ai/AIErrors.js +43 -0
- package/dist/ai/AIFailover.d.ts +25 -0
- package/dist/ai/AIFailover.js +96 -0
- package/dist/ai/AIProviders.d.ts +35 -0
- package/dist/ai/AIProviders.js +197 -0
- package/dist/ai/AIQuotaDeferredError.d.ts +19 -0
- package/dist/ai/AIQuotaDeferredError.js +25 -0
- package/dist/ai/AIRateLimiter.d.ts +103 -0
- package/dist/ai/AIRateLimiter.js +690 -0
- package/dist/ai/Agent.d.ts +633 -0
- package/dist/ai/Agent.js +2976 -0
- package/dist/ai/AgentHistory.d.ts +11 -0
- package/dist/ai/AgentHistory.js +495 -0
- package/dist/ai/AgentRunJob.d.ts +21 -0
- package/dist/ai/AgentRunJob.js +53 -0
- package/dist/ai/Ai.d.ts +375 -0
- package/dist/ai/Ai.js +1771 -0
- package/dist/ai/AiConversation.d.ts +17 -0
- package/dist/ai/AiConversation.js +38 -0
- package/dist/ai/AiExecutionContext.d.ts +7 -0
- package/dist/ai/AiExecutionContext.js +16 -0
- package/dist/ai/AiMessage.d.ts +43 -0
- package/dist/ai/AiMessage.js +105 -0
- package/dist/ai/AiRateLimitBucket.d.ts +69 -0
- package/dist/ai/AiRateLimitBucket.js +138 -0
- package/dist/ai/AiRateLimitReservation.d.ts +56 -0
- package/dist/ai/AiRateLimitReservation.js +101 -0
- package/dist/ai/AiRequest.d.ts +78 -0
- package/dist/ai/AiRequest.js +384 -0
- package/dist/ai/Estimates.d.ts +26 -0
- package/dist/ai/Estimates.js +34 -0
- package/dist/ai/Models.d.ts +88 -0
- package/dist/ai/Models.js +328 -0
- package/dist/ai/OpenAIProviderError.d.ts +30 -0
- package/dist/ai/OpenAIProviderError.js +77 -0
- package/dist/ai/OpenAIQuotaRetry.d.ts +27 -0
- package/dist/ai/OpenAIQuotaRetry.js +144 -0
- package/dist/ai/ProviderCosts.d.ts +55 -0
- package/dist/ai/ProviderCosts.js +108 -0
- package/dist/ai/ResponsesProviderCall.d.ts +13 -0
- package/dist/ai/ResponsesProviderCall.js +29 -0
- package/dist/ai/agentCitations.d.ts +27 -0
- package/dist/ai/agentCitations.js +153 -0
- package/dist/ai/contracts/AI.d.ts +347 -0
- package/dist/ai/contracts/AI.js +13 -0
- package/dist/ai/contracts/Agent.d.ts +476 -0
- package/dist/ai/contracts/Agent.js +1 -0
- package/dist/ai/contracts/AiRequestRunCostSummary.d.ts +31 -0
- package/dist/ai/contracts/AiRequestRunCostSummary.js +1 -0
- package/dist/ai/contracts/Pricing.d.ts +88 -0
- package/dist/ai/contracts/Pricing.js +1 -0
- package/dist/ai/contracts/Providers.d.ts +68 -0
- package/dist/ai/contracts/Providers.js +1 -0
- package/dist/ai/contracts/QuotaRetry.d.ts +38 -0
- package/dist/ai/contracts/QuotaRetry.js +1 -0
- package/dist/ai/contracts/RateLimits.d.ts +45 -0
- package/dist/ai/contracts/RateLimits.js +1 -0
- package/dist/ai/contracts/ResponsesProviderCall.d.ts +28 -0
- package/dist/ai/contracts/ResponsesProviderCall.js +1 -0
- package/dist/ai/contracts/index.d.ts +8 -0
- package/dist/ai/contracts/index.js +8 -0
- package/dist/ai/index.d.ts +27 -0
- package/dist/ai/index.js +27 -0
- package/dist/ai/registry.d.ts +28 -0
- package/dist/ai/registry.js +49 -0
- package/dist/ai/sdkNodeCompatibility.d.ts +76 -0
- package/dist/ai/toolCallRecovery.d.ts +16 -0
- package/dist/ai/toolCallRecovery.js +71 -0
- package/dist/ai/toolHelpers.d.ts +65 -0
- package/dist/ai/toolHelpers.js +106 -0
- package/dist/auth/Auth.d.ts +641 -0
- package/dist/auth/Auth.js +927 -0
- package/dist/auth/AuthProvider.d.ts +104 -0
- package/dist/auth/AuthProvider.js +185 -0
- package/dist/auth/AuthToken.d.ts +123 -0
- package/dist/auth/AuthToken.js +156 -0
- package/dist/auth/PasswordResetToken.d.ts +33 -0
- package/dist/auth/PasswordResetToken.js +64 -0
- package/dist/auth/UserIdentity.d.ts +46 -0
- package/dist/auth/UserIdentity.js +72 -0
- package/dist/auth/contracts/AuthProviderDriver.d.ts +94 -0
- package/dist/auth/contracts/AuthProviderDriver.js +1 -0
- package/dist/auth/contracts/index.d.ts +1 -0
- package/dist/auth/contracts/index.js +1 -0
- package/dist/auth/index.d.ts +8 -0
- package/dist/auth/index.js +8 -0
- package/dist/auth/passwordHash.d.ts +26 -0
- package/dist/auth/passwordHash.js +96 -0
- package/dist/auth/providers/GoogleAuthProvider.d.ts +135 -0
- package/dist/auth/providers/GoogleAuthProvider.js +305 -0
- package/dist/auth/providers/PasswordAuthProvider.d.ts +115 -0
- package/dist/auth/providers/PasswordAuthProvider.js +195 -0
- package/dist/auth/providers/index.d.ts +3 -0
- package/dist/auth/providers/index.js +3 -0
- package/dist/auth/providers/resolveAuthProviders.d.ts +29 -0
- package/dist/auth/providers/resolveAuthProviders.js +111 -0
- package/dist/cache/Cache.d.ts +67 -0
- package/dist/cache/Cache.js +115 -0
- package/dist/cache/contracts/CacheDriver.d.ts +10 -0
- package/dist/cache/contracts/CacheDriver.js +1 -0
- package/dist/cache/contracts/CacheOperations.d.ts +26 -0
- package/dist/cache/contracts/CacheOperations.js +1 -0
- package/dist/cache/contracts/CacheOptions.d.ts +51 -0
- package/dist/cache/contracts/CacheOptions.js +1 -0
- package/dist/cache/contracts/CacheRepository.d.ts +45 -0
- package/dist/cache/contracts/CacheRepository.js +1 -0
- package/dist/cache/contracts/index.d.ts +4 -0
- package/dist/cache/contracts/index.js +4 -0
- package/dist/cache/drivers/CacheManagerDriver.d.ts +55 -0
- package/dist/cache/drivers/CacheManagerDriver.js +68 -0
- package/dist/cache/drivers/createCacheDriver.d.ts +8 -0
- package/dist/cache/drivers/createCacheDriver.js +147 -0
- package/dist/cache/index.d.ts +2 -0
- package/dist/cache/index.js +2 -0
- package/dist/cli/Cli.d.ts +17 -0
- package/dist/cli/Cli.js +120 -0
- package/dist/cli/commands/repl.d.ts +9 -0
- package/dist/cli/commands/repl.js +27 -0
- package/dist/cli/contracts/CliCommand.d.ts +30 -0
- package/dist/cli/contracts/CliCommand.js +1 -0
- package/dist/cli/contracts/CliConfig.d.ts +9 -0
- package/dist/cli/contracts/CliConfig.js +1 -0
- package/dist/cli/contracts/CliOptions.d.ts +13 -0
- package/dist/cli/contracts/CliOptions.js +1 -0
- package/dist/cli/contracts/CommandDefinition.d.ts +18 -0
- package/dist/cli/contracts/CommandDefinition.js +1 -0
- package/dist/cli/contracts/ReplOptions.d.ts +11 -0
- package/dist/cli/contracts/ReplOptions.js +1 -0
- package/dist/cli/contracts/index.d.ts +5 -0
- package/dist/cli/contracts/index.js +1 -0
- package/dist/cli/defineCommand.d.ts +10 -0
- package/dist/cli/defineCommand.js +25 -0
- package/dist/cli/index.d.ts +5 -0
- package/dist/cli/index.js +5 -0
- package/dist/cli/runDb3.d.ts +11 -0
- package/dist/cli/runDb3.js +70 -0
- package/dist/cli/runRepl.d.ts +12 -0
- package/dist/cli/runRepl.js +54 -0
- package/dist/config/Config.d.ts +48 -0
- package/dist/config/Config.js +80 -0
- package/dist/config/env.d.ts +26 -0
- package/dist/config/env.js +117 -0
- package/dist/config/index.d.ts +2 -0
- package/dist/config/index.js +2 -0
- package/dist/db/ActiveProjection.d.ts +90 -0
- package/dist/db/ActiveProjection.js +134 -0
- package/dist/db/ActiveQueryBuilder.d.ts +268 -0
- package/dist/db/ActiveQueryBuilder.js +621 -0
- package/dist/db/ActiveRecord.d.ts +483 -0
- package/dist/db/ActiveRecord.js +765 -0
- package/dist/db/Database.d.ts +277 -0
- package/dist/db/Database.js +827 -0
- package/dist/db/FieldType.d.ts +540 -0
- package/dist/db/FieldType.js +706 -0
- package/dist/db/SoftDeletes.d.ts +30 -0
- package/dist/db/SoftDeletes.js +93 -0
- package/dist/db/commands/check.d.ts +6 -0
- package/dist/db/commands/check.js +8 -0
- package/dist/db/commands/index.d.ts +6 -0
- package/dist/db/commands/index.js +17 -0
- package/dist/db/commands/makeMigration.d.ts +7 -0
- package/dist/db/commands/makeMigration.js +9 -0
- package/dist/db/commands/migrate.d.ts +6 -0
- package/dist/db/commands/migrate.js +8 -0
- package/dist/db/connection.d.ts +10 -0
- package/dist/db/connection.js +55 -0
- package/dist/db/contracts/ActiveRecordDefinition.d.ts +64 -0
- package/dist/db/contracts/ActiveRecordDefinition.js +1 -0
- package/dist/db/contracts/DatabaseBackup.d.ts +7 -0
- package/dist/db/contracts/DatabaseBackup.js +1 -0
- package/dist/db/contracts/DatabaseMigrationsConfig.d.ts +9 -0
- package/dist/db/contracts/DatabaseMigrationsConfig.js +1 -0
- package/dist/db/contracts/index.d.ts +3 -0
- package/dist/db/contracts/index.js +3 -0
- package/dist/db/dialects/columnTypes.d.ts +20 -0
- package/dist/db/dialects/columnTypes.js +67 -0
- package/dist/db/dialects/index.d.ts +6 -0
- package/dist/db/dialects/index.js +6 -0
- package/dist/db/dialects/mariadb.d.ts +7 -0
- package/dist/db/dialects/mariadb.js +35 -0
- package/dist/db/dialects/mysql.d.ts +14 -0
- package/dist/db/dialects/mysql.js +203 -0
- package/dist/db/dialects/postgres.d.ts +5 -0
- package/dist/db/dialects/postgres.js +106 -0
- package/dist/db/dialects/resolveDialect.d.ts +14 -0
- package/dist/db/dialects/resolveDialect.js +57 -0
- package/dist/db/dialects/types.d.ts +44 -0
- package/dist/db/dialects/types.js +1 -0
- package/dist/db/errors.d.ts +15 -0
- package/dist/db/errors.js +20 -0
- package/dist/db/fields/BooleanField.d.ts +29 -0
- package/dist/db/fields/BooleanField.js +89 -0
- package/dist/db/fields/CharUuidField.d.ts +29 -0
- package/dist/db/fields/CharUuidField.js +63 -0
- package/dist/db/fields/ChoiceStringField.d.ts +25 -0
- package/dist/db/fields/ChoiceStringField.js +58 -0
- package/dist/db/fields/DecimalField.d.ts +20 -0
- package/dist/db/fields/DecimalField.js +105 -0
- package/dist/db/fields/EmailField.d.ts +31 -0
- package/dist/db/fields/EmailField.js +52 -0
- package/dist/db/fields/EncryptedJsonField.d.ts +82 -0
- package/dist/db/fields/EncryptedJsonField.js +169 -0
- package/dist/db/fields/IntegerField.d.ts +35 -0
- package/dist/db/fields/IntegerField.js +139 -0
- package/dist/db/fields/JsonField.d.ts +40 -0
- package/dist/db/fields/JsonField.js +79 -0
- package/dist/db/fields/JsonStringField.d.ts +21 -0
- package/dist/db/fields/JsonStringField.js +41 -0
- package/dist/db/fields/LinkField.d.ts +180 -0
- package/dist/db/fields/LinkField.js +359 -0
- package/dist/db/fields/PasswordField.d.ts +93 -0
- package/dist/db/fields/PasswordField.js +180 -0
- package/dist/db/fields/StringField.d.ts +43 -0
- package/dist/db/fields/StringField.js +102 -0
- package/dist/db/fields/StringListField.d.ts +54 -0
- package/dist/db/fields/StringListField.js +124 -0
- package/dist/db/fields/TextField.d.ts +25 -0
- package/dist/db/fields/TextField.js +44 -0
- package/dist/db/fields/TimestampField.d.ts +47 -0
- package/dist/db/fields/TimestampField.js +97 -0
- package/dist/db/fields/UlidField.d.ts +69 -0
- package/dist/db/fields/UlidField.js +114 -0
- package/dist/db/fields/UrlField.d.ts +30 -0
- package/dist/db/fields/UrlField.js +61 -0
- package/dist/db/fields/VectorField.d.ts +64 -0
- package/dist/db/fields/VectorField.js +180 -0
- package/dist/db/fields/createField.d.ts +2 -0
- package/dist/db/fields/createField.js +13 -0
- package/dist/db/fields/field.d.ts +36 -0
- package/dist/db/fields/field.js +101 -0
- package/dist/db/fields/index.d.ts +18 -0
- package/dist/db/fields/index.js +18 -0
- package/dist/db/fields/resolveFields.d.ts +17 -0
- package/dist/db/fields/resolveFields.js +38 -0
- package/dist/db/index.d.ts +13 -0
- package/dist/db/index.js +13 -0
- package/dist/db/migrations/DatabaseMigrationManager.d.ts +57 -0
- package/dist/db/migrations/DatabaseMigrationManager.js +589 -0
- package/dist/db/migrations/DatabaseSchemaInspector.d.ts +19 -0
- package/dist/db/migrations/DatabaseSchemaInspector.js +384 -0
- package/dist/db/migrations/KnexMigrationRenderer.d.ts +11 -0
- package/dist/db/migrations/KnexMigrationRenderer.js +390 -0
- package/dist/db/migrations/ModelSchemaCollector.d.ts +29 -0
- package/dist/db/migrations/ModelSchemaCollector.js +183 -0
- package/dist/db/migrations/SchemaDiffer.d.ts +13 -0
- package/dist/db/migrations/SchemaDiffer.js +427 -0
- package/dist/db/migrations/SchemaNames.d.ts +27 -0
- package/dist/db/migrations/SchemaNames.js +46 -0
- package/dist/db/migrations/SchemaSnapshotSerializer.d.ts +30 -0
- package/dist/db/migrations/SchemaSnapshotSerializer.js +49 -0
- package/dist/db/migrations/contracts/DatabaseMigration.d.ts +118 -0
- package/dist/db/migrations/contracts/DatabaseMigration.js +1 -0
- package/dist/db/migrations/contracts/SchemaChange.d.ts +83 -0
- package/dist/db/migrations/contracts/SchemaChange.js +1 -0
- package/dist/db/migrations/contracts/SchemaSnapshot.d.ts +94 -0
- package/dist/db/migrations/contracts/SchemaSnapshot.js +1 -0
- package/dist/db/migrations/contracts/index.d.ts +3 -0
- package/dist/db/migrations/contracts/index.js +3 -0
- package/dist/db/migrations/errors.d.ts +35 -0
- package/dist/db/migrations/errors.js +45 -0
- package/dist/db/migrations/index.d.ts +10 -0
- package/dist/db/migrations/index.js +10 -0
- package/dist/db/migrations/promoteDestructiveSchemaChanges.d.ts +19 -0
- package/dist/db/migrations/promoteDestructiveSchemaChanges.js +102 -0
- package/dist/db/queryMonitor.d.ts +142 -0
- package/dist/db/queryMonitor.js +357 -0
- package/dist/db/sqlErrors.d.ts +11 -0
- package/dist/db/sqlErrors.js +17 -0
- package/dist/db/test/db.d.ts +11 -0
- package/dist/db/test/db.js +109 -0
- package/dist/devtools/HttpEventDispatcher.d.ts +19 -0
- package/dist/devtools/HttpEventDispatcher.js +180 -0
- package/dist/devtools/contracts/DevtoolsEventDispatcher.d.ts +53 -0
- package/dist/devtools/contracts/DevtoolsEventDispatcher.js +1 -0
- package/dist/devtools/contracts/index.d.ts +1 -0
- package/dist/devtools/contracts/index.js +1 -0
- package/dist/devtools/environment.d.ts +10 -0
- package/dist/devtools/environment.js +14 -0
- package/dist/devtools/index.d.ts +3 -0
- package/dist/devtools/index.js +3 -0
- package/dist/events/Events.d.ts +70 -0
- package/dist/events/Events.js +126 -0
- package/dist/events/contracts/EventConstructor.d.ts +12 -0
- package/dist/events/contracts/EventConstructor.js +1 -0
- package/dist/events/contracts/EventListener.d.ts +6 -0
- package/dist/events/contracts/EventListener.js +1 -0
- package/dist/events/contracts/EventUnsubscribe.d.ts +4 -0
- package/dist/events/contracts/EventUnsubscribe.js +1 -0
- package/dist/events/contracts/index.d.ts +3 -0
- package/dist/events/contracts/index.js +3 -0
- package/dist/events/index.d.ts +2 -0
- package/dist/events/index.js +2 -0
- package/dist/flows/FlowBlockRegistry.d.ts +39 -0
- package/dist/flows/FlowBlockRegistry.js +66 -0
- package/dist/flows/FlowCompiler.d.ts +26 -0
- package/dist/flows/FlowCompiler.js +488 -0
- package/dist/flows/FlowDefinitionError.d.ts +21 -0
- package/dist/flows/FlowDefinitionError.js +16 -0
- package/dist/flows/FlowStepJob.d.ts +28 -0
- package/dist/flows/FlowStepJob.js +31 -0
- package/dist/flows/FlowValueValidator.d.ts +32 -0
- package/dist/flows/FlowValueValidator.js +105 -0
- package/dist/flows/Flows.d.ts +102 -0
- package/dist/flows/Flows.js +871 -0
- package/dist/flows/blocks/FlowInput.d.ts +10 -0
- package/dist/flows/blocks/FlowInput.js +29 -0
- package/dist/flows/blocks/FlowOutput.d.ts +10 -0
- package/dist/flows/blocks/FlowOutput.js +29 -0
- package/dist/flows/blocks/Subflow.d.ts +10 -0
- package/dist/flows/blocks/Subflow.js +21 -0
- package/dist/flows/blocks/index.d.ts +6 -0
- package/dist/flows/blocks/index.js +8 -0
- package/dist/flows/constants.d.ts +55 -0
- package/dist/flows/constants.js +47 -0
- package/dist/flows/contracts/FlowBlock.d.ts +64 -0
- package/dist/flows/contracts/FlowBlock.js +1 -0
- package/dist/flows/contracts/FlowCompiler.d.ts +30 -0
- package/dist/flows/contracts/FlowCompiler.js +1 -0
- package/dist/flows/contracts/FlowDefinition.d.ts +118 -0
- package/dist/flows/contracts/FlowDefinition.js +1 -0
- package/dist/flows/contracts/FlowDefinitionStore.d.ts +47 -0
- package/dist/flows/contracts/FlowDefinitionStore.js +1 -0
- package/dist/flows/contracts/FlowRun.d.ts +40 -0
- package/dist/flows/contracts/FlowRun.js +1 -0
- package/dist/flows/contracts/FlowValue.d.ts +49 -0
- package/dist/flows/contracts/FlowValue.js +1 -0
- package/dist/flows/contracts/FlowsService.d.ts +37 -0
- package/dist/flows/contracts/FlowsService.js +1 -0
- package/dist/flows/contracts/index.d.ts +7 -0
- package/dist/flows/contracts/index.js +7 -0
- package/dist/flows/defineBlock.d.ts +18 -0
- package/dist/flows/defineBlock.js +19 -0
- package/dist/flows/drivers/FileFlowDefinitionStore.d.ts +53 -0
- package/dist/flows/drivers/FileFlowDefinitionStore.js +313 -0
- package/dist/flows/drivers/index.d.ts +1 -0
- package/dist/flows/drivers/index.js +1 -0
- package/dist/flows/errors.d.ts +8 -0
- package/dist/flows/errors.js +19 -0
- package/dist/flows/index.d.ts +13 -0
- package/dist/flows/index.js +13 -0
- package/dist/flows/models/FlowRun.d.ts +55 -0
- package/dist/flows/models/FlowRun.js +126 -0
- package/dist/flows/models/FlowRunEvent.d.ts +41 -0
- package/dist/flows/models/FlowRunEvent.js +85 -0
- package/dist/flows/models/FlowStepRun.d.ts +56 -0
- package/dist/flows/models/FlowStepRun.js +137 -0
- package/dist/flows/models/index.d.ts +10 -0
- package/dist/flows/models/index.js +14 -0
- package/dist/index.d.ts +25 -0
- package/dist/index.js +16 -0
- package/dist/logging/Log.d.ts +66 -0
- package/dist/logging/Log.js +79 -0
- package/dist/logging/contracts/HttpExchange.d.ts +50 -0
- package/dist/logging/contracts/HttpExchange.js +1 -0
- package/dist/logging/contracts/Logger.d.ts +41 -0
- package/dist/logging/contracts/Logger.js +1 -0
- package/dist/logging/contracts/LoggerDriver.d.ts +16 -0
- package/dist/logging/contracts/LoggerDriver.js +1 -0
- package/dist/logging/contracts/LoggingOptions.d.ts +49 -0
- package/dist/logging/contracts/LoggingOptions.js +1 -0
- package/dist/logging/contracts/index.d.ts +4 -0
- package/dist/logging/contracts/index.js +4 -0
- package/dist/logging/drivers/PinoLoggerDriver.d.ts +24 -0
- package/dist/logging/drivers/PinoLoggerDriver.js +291 -0
- package/dist/logging/drivers/index.d.ts +1 -0
- package/dist/logging/drivers/index.js +1 -0
- package/dist/logging/index.d.ts +3 -0
- package/dist/logging/index.js +3 -0
- package/dist/logging/transports/DevtoolsLogTransport.d.ts +35 -0
- package/dist/logging/transports/DevtoolsLogTransport.js +96 -0
- package/dist/mail/Mail.d.ts +62 -0
- package/dist/mail/Mail.js +98 -0
- package/dist/mail/index.d.ts +4 -0
- package/dist/mail/index.js +4 -0
- package/dist/mail/transports/FileMailTransport.d.ts +12 -0
- package/dist/mail/transports/FileMailTransport.js +41 -0
- package/dist/mail/transports/MailgunTransport.d.ts +22 -0
- package/dist/mail/transports/MailgunTransport.js +57 -0
- package/dist/mail/transports/ResendTransport.d.ts +14 -0
- package/dist/mail/transports/ResendTransport.js +55 -0
- package/dist/media/MediaFile.d.ts +48 -0
- package/dist/media/MediaFile.js +104 -0
- package/dist/media/MediaItem.d.ts +47 -0
- package/dist/media/MediaItem.js +106 -0
- package/dist/media/MediaLibrary.d.ts +42 -0
- package/dist/media/MediaLibrary.js +94 -0
- package/dist/media/MediaManager.d.ts +159 -0
- package/dist/media/MediaManager.js +754 -0
- package/dist/media/constants.d.ts +27 -0
- package/dist/media/constants.js +19 -0
- package/dist/media/contracts/MediaOptions.d.ts +8 -0
- package/dist/media/contracts/MediaOptions.js +1 -0
- package/dist/media/contracts/index.d.ts +1 -0
- package/dist/media/contracts/index.js +1 -0
- package/dist/media/image/ImageReconstructionError.d.ts +15 -0
- package/dist/media/image/ImageReconstructionError.js +18 -0
- package/dist/media/image/ImageVariantRenderer.d.ts +44 -0
- package/dist/media/image/ImageVariantRenderer.js +337 -0
- package/dist/media/image/ImageVariantRequest.d.ts +28 -0
- package/dist/media/image/ImageVariantRequest.js +55 -0
- package/dist/media/image/contracts/ImageProcessor.d.ts +46 -0
- package/dist/media/image/contracts/ImageProcessor.js +1 -0
- package/dist/media/image/contracts/ImageVariant.d.ts +31 -0
- package/dist/media/image/contracts/ImageVariant.js +7 -0
- package/dist/media/image/contracts/ImageVariantCacheOptions.d.ts +20 -0
- package/dist/media/image/contracts/ImageVariantCacheOptions.js +1 -0
- package/dist/media/image/contracts/index.d.ts +3 -0
- package/dist/media/image/contracts/index.js +3 -0
- package/dist/media/image/index.d.ts +5 -0
- package/dist/media/image/index.js +5 -0
- package/dist/media/image/processors/SharpImageProcessor.d.ts +25 -0
- package/dist/media/image/processors/SharpImageProcessor.js +112 -0
- package/dist/media/image/processors/index.d.ts +1 -0
- package/dist/media/image/processors/index.js +1 -0
- package/dist/media/index.d.ts +8 -0
- package/dist/media/index.js +8 -0
- package/dist/media/types.d.ts +129 -0
- package/dist/media/types.js +1 -0
- package/dist/queue/FailedJob.d.ts +31 -0
- package/dist/queue/FailedJob.js +41 -0
- package/dist/queue/Queue.d.ts +208 -0
- package/dist/queue/Queue.js +685 -0
- package/dist/queue/QueueEvents.d.ts +31 -0
- package/dist/queue/QueueEvents.js +49 -0
- package/dist/queue/QueueRetryLaterError.d.ts +23 -0
- package/dist/queue/QueueRetryLaterError.js +34 -0
- package/dist/queue/QueueWorker.d.ts +72 -0
- package/dist/queue/QueueWorker.js +236 -0
- package/dist/queue/QueueableJob.d.ts +109 -0
- package/dist/queue/QueueableJob.js +137 -0
- package/dist/queue/QueuedJob.d.ts +31 -0
- package/dist/queue/QueuedJob.js +52 -0
- package/dist/queue/RetryPolicy.d.ts +51 -0
- package/dist/queue/RetryPolicy.js +84 -0
- package/dist/queue/commands/index.d.ts +4 -0
- package/dist/queue/commands/index.js +11 -0
- package/dist/queue/commands/makeJob.d.ts +7 -0
- package/dist/queue/commands/makeJob.js +9 -0
- package/dist/queue/console.d.ts +60 -0
- package/dist/queue/console.js +348 -0
- package/dist/queue/contracts/CreateJob.d.ts +12 -0
- package/dist/queue/contracts/CreateJob.js +1 -0
- package/dist/queue/contracts/QueueDriver.d.ts +122 -0
- package/dist/queue/contracts/QueueDriver.js +1 -0
- package/dist/queue/contracts/QueueEvents.d.ts +61 -0
- package/dist/queue/contracts/QueueEvents.js +1 -0
- package/dist/queue/contracts/QueuePayload.d.ts +136 -0
- package/dist/queue/contracts/QueuePayload.js +1 -0
- package/dist/queue/contracts/QueueRetry.d.ts +43 -0
- package/dist/queue/contracts/QueueRetry.js +1 -0
- package/dist/queue/contracts/QueueService.d.ts +199 -0
- package/dist/queue/contracts/QueueService.js +1 -0
- package/dist/queue/contracts/QueueWorkerLifecycle.d.ts +65 -0
- package/dist/queue/contracts/QueueWorkerLifecycle.js +1 -0
- package/dist/queue/contracts/QueueableJob.d.ts +50 -0
- package/dist/queue/contracts/QueueableJob.js +1 -0
- package/dist/queue/contracts/RedisQueueDriver.d.ts +37 -0
- package/dist/queue/contracts/RedisQueueDriver.js +1 -0
- package/dist/queue/contracts/index.d.ts +9 -0
- package/dist/queue/contracts/index.js +9 -0
- package/dist/queue/createJob.d.ts +18 -0
- package/dist/queue/createJob.js +52 -0
- package/dist/queue/drivers/DatabaseQueueDriver.d.ts +83 -0
- package/dist/queue/drivers/DatabaseQueueDriver.js +393 -0
- package/dist/queue/drivers/RedisQueueDriver.d.ts +102 -0
- package/dist/queue/drivers/RedisQueueDriver.js +641 -0
- package/dist/queue/index.d.ts +13 -0
- package/dist/queue/index.js +13 -0
- package/dist/queue/queueMonitor.d.ts +133 -0
- package/dist/queue/queueMonitor.js +238 -0
- package/dist/scheduler/ScheduledCall.d.ts +25 -0
- package/dist/scheduler/ScheduledCall.js +31 -0
- package/dist/scheduler/ScheduledEvent.d.ts +74 -0
- package/dist/scheduler/ScheduledEvent.js +115 -0
- package/dist/scheduler/ScheduledJob.d.ts +34 -0
- package/dist/scheduler/ScheduledJob.js +50 -0
- package/dist/scheduler/ScheduledOccurrence.d.ts +74 -0
- package/dist/scheduler/ScheduledOccurrence.js +194 -0
- package/dist/scheduler/ScheduledOccurrenceRecorder.d.ts +34 -0
- package/dist/scheduler/ScheduledOccurrenceRecorder.js +106 -0
- package/dist/scheduler/Scheduler.d.ts +76 -0
- package/dist/scheduler/Scheduler.js +186 -0
- package/dist/scheduler/SchedulerWorker.d.ts +37 -0
- package/dist/scheduler/SchedulerWorker.js +119 -0
- package/dist/scheduler/console.d.ts +18 -0
- package/dist/scheduler/console.js +288 -0
- package/dist/scheduler/constants.d.ts +13 -0
- package/dist/scheduler/constants.js +23 -0
- package/dist/scheduler/contracts/Scheduler.d.ts +104 -0
- package/dist/scheduler/contracts/Scheduler.js +1 -0
- package/dist/scheduler/contracts/SchedulerConsole.d.ts +37 -0
- package/dist/scheduler/contracts/SchedulerConsole.js +1 -0
- package/dist/scheduler/contracts/SchedulerWorker.d.ts +18 -0
- package/dist/scheduler/contracts/SchedulerWorker.js +1 -0
- package/dist/scheduler/contracts/index.d.ts +3 -0
- package/dist/scheduler/contracts/index.js +3 -0
- package/dist/scheduler/index.d.ts +9 -0
- package/dist/scheduler/index.js +9 -0
- package/dist/scheduler/scheduleTime.d.ts +30 -0
- package/dist/scheduler/scheduleTime.js +64 -0
- package/dist/security/Security.d.ts +60 -0
- package/dist/security/Security.js +252 -0
- package/dist/security/SecurityError.d.ts +13 -0
- package/dist/security/SecurityError.js +16 -0
- package/dist/security/contracts/SecurityOptions.d.ts +17 -0
- package/dist/security/contracts/SecurityOptions.js +1 -0
- package/dist/security/contracts/SecurityPayload.d.ts +13 -0
- package/dist/security/contracts/SecurityPayload.js +1 -0
- package/dist/security/contracts/index.d.ts +2 -0
- package/dist/security/contracts/index.js +2 -0
- package/dist/security/ensureAppKey.d.ts +16 -0
- package/dist/security/ensureAppKey.js +69 -0
- package/dist/security/index.d.ts +4 -0
- package/dist/security/index.js +4 -0
- package/dist/serialization/Serializable.d.ts +17 -0
- package/dist/serialization/Serializable.js +1 -0
- package/dist/serialization/SerializationError.d.ts +40 -0
- package/dist/serialization/SerializationError.js +42 -0
- package/dist/serialization/SerializationRegistry.d.ts +76 -0
- package/dist/serialization/SerializationRegistry.js +153 -0
- package/dist/serialization/SerializationRegistryError.d.ts +18 -0
- package/dist/serialization/SerializationRegistryError.js +18 -0
- package/dist/serialization/Serializer.d.ts +37 -0
- package/dist/serialization/Serializer.js +477 -0
- package/dist/serialization/contracts/SerializableClass.d.ts +20 -0
- package/dist/serialization/contracts/SerializableClass.js +1 -0
- package/dist/serialization/contracts/SerializedValue.d.ts +59 -0
- package/dist/serialization/contracts/SerializedValue.js +19 -0
- package/dist/serialization/contracts/SerializerOptions.d.ts +17 -0
- package/dist/serialization/contracts/SerializerOptions.js +1 -0
- package/dist/serialization/contracts/SerializerService.d.ts +26 -0
- package/dist/serialization/contracts/SerializerService.js +1 -0
- package/dist/serialization/contracts/index.d.ts +4 -0
- package/dist/serialization/contracts/index.js +4 -0
- package/dist/serialization/index.d.ts +6 -0
- package/dist/serialization/index.js +6 -0
- package/dist/server/App.d.ts +141 -0
- package/dist/server/App.js +225 -0
- package/dist/server/RequestContext.d.ts +42 -0
- package/dist/server/RequestContext.js +95 -0
- package/dist/server/appContext.d.ts +34 -0
- package/dist/server/appContext.js +42 -0
- package/dist/server/index.d.ts +3 -0
- package/dist/server/index.js +3 -0
- package/dist/ssr/constants.d.ts +6 -0
- package/dist/ssr/constants.js +6 -0
- package/dist/ssr/contracts/DocumentHead.d.ts +32 -0
- package/dist/ssr/contracts/DocumentHead.js +1 -0
- package/dist/ssr/contracts/SsrRenderContext.d.ts +23 -0
- package/dist/ssr/contracts/SsrRenderContext.js +1 -0
- package/dist/ssr/contracts/SsrRenderResult.d.ts +21 -0
- package/dist/ssr/contracts/SsrRenderResult.js +1 -0
- package/dist/ssr/contracts/SsrRenderer.d.ts +9 -0
- package/dist/ssr/contracts/SsrRenderer.js +1 -0
- package/dist/ssr/contracts/SsrRequest.d.ts +16 -0
- package/dist/ssr/contracts/SsrRequest.js +1 -0
- package/dist/ssr/contracts/index.d.ts +5 -0
- package/dist/ssr/contracts/index.js +1 -0
- package/dist/ssr/createSsrRenderContext.d.ts +9 -0
- package/dist/ssr/createSsrRenderContext.js +20 -0
- package/dist/ssr/fastify/contracts/FastifySsrOptions.d.ts +21 -0
- package/dist/ssr/fastify/contracts/FastifySsrOptions.js +1 -0
- package/dist/ssr/fastify/contracts/index.d.ts +1 -0
- package/dist/ssr/fastify/contracts/index.js +1 -0
- package/dist/ssr/fastify/fastifySsr.d.ts +25 -0
- package/dist/ssr/fastify/fastifySsr.js +89 -0
- package/dist/ssr/fastify/index.d.ts +2 -0
- package/dist/ssr/fastify/index.js +1 -0
- package/dist/ssr/index.d.ts +6 -0
- package/dist/ssr/index.js +5 -0
- package/dist/ssr/renderDocumentHead.d.ts +8 -0
- package/dist/ssr/renderDocumentHead.js +62 -0
- package/dist/ssr/renderSsrDocument.d.ts +14 -0
- package/dist/ssr/renderSsrDocument.js +28 -0
- package/dist/ssr/serializeSsrState.d.ts +10 -0
- package/dist/ssr/serializeSsrState.js +18 -0
- package/dist/ssr/vite/contracts/ViteSsrOptions.d.ts +45 -0
- package/dist/ssr/vite/contracts/ViteSsrOptions.js +1 -0
- package/dist/ssr/vite/contracts/index.d.ts +1 -0
- package/dist/ssr/vite/contracts/index.js +1 -0
- package/dist/ssr/vite/fastifyViteSsr.d.ts +24 -0
- package/dist/ssr/vite/fastifyViteSsr.js +213 -0
- package/dist/ssr/vite/index.d.ts +4 -0
- package/dist/ssr/vite/index.js +2 -0
- package/dist/ssr/vite/viteSsrManifest.d.ts +16 -0
- package/dist/ssr/vite/viteSsrManifest.js +63 -0
- package/dist/storage/Storage.d.ts +244 -0
- package/dist/storage/Storage.js +348 -0
- package/dist/storage/contents.d.ts +8 -0
- package/dist/storage/contents.js +18 -0
- package/dist/storage/contracts/StorageListing.d.ts +50 -0
- package/dist/storage/contracts/StorageListing.js +1 -0
- package/dist/storage/contracts/index.d.ts +1 -0
- package/dist/storage/contracts/index.js +1 -0
- package/dist/storage/drivers/FlystorageDisk.d.ts +185 -0
- package/dist/storage/drivers/FlystorageDisk.js +250 -0
- package/dist/storage/drivers/FlystorageListing.d.ts +27 -0
- package/dist/storage/drivers/FlystorageListing.js +69 -0
- package/dist/storage/drivers/LocalStorageDisk.d.ts +25 -0
- package/dist/storage/drivers/LocalStorageDisk.js +38 -0
- package/dist/storage/drivers/S3StorageDisk.d.ts +17 -0
- package/dist/storage/drivers/S3StorageDisk.js +102 -0
- package/dist/storage/drivers/index.d.ts +3 -0
- package/dist/storage/drivers/index.js +3 -0
- package/dist/storage/index.d.ts +7 -0
- package/dist/storage/index.js +7 -0
- package/dist/storage/mime.d.ts +7 -0
- package/dist/storage/mime.js +28 -0
- package/dist/storage/path.d.ts +22 -0
- package/dist/storage/path.js +61 -0
- package/dist/storage/types.d.ts +218 -0
- package/dist/storage/types.js +1 -0
- package/dist/url/UrlGenerator.d.ts +32 -0
- package/dist/url/UrlGenerator.js +61 -0
- package/dist/url/contracts/UrlGeneratorOptions.d.ts +13 -0
- package/dist/url/contracts/UrlGeneratorOptions.js +1 -0
- package/dist/url/contracts/index.d.ts +1 -0
- package/dist/url/contracts/index.js +1 -0
- package/dist/url/index.d.ts +2 -0
- package/dist/url/index.js +2 -0
- package/dist/validation/index.d.ts +28 -0
- package/dist/validation/index.js +260 -0
- package/package.json +290 -0
- package/src/ai/AIErrors.ts +46 -0
- package/src/ai/AIFailover.ts +101 -0
- package/src/ai/AIProviders.ts +228 -0
- package/src/ai/AIQuotaDeferredError.ts +26 -0
- package/src/ai/AIRateLimiter.ts +880 -0
- package/src/ai/Agent.ts +3630 -0
- package/src/ai/AgentHistory.ts +576 -0
- package/src/ai/AgentRunJob.ts +65 -0
- package/src/ai/Ai.ts +2176 -0
- package/src/ai/AiConversation.ts +49 -0
- package/src/ai/AiExecutionContext.ts +19 -0
- package/src/ai/AiMessage.ts +131 -0
- package/src/ai/AiRateLimitBucket.ts +163 -0
- package/src/ai/AiRateLimitReservation.ts +117 -0
- package/src/ai/AiRequest.ts +466 -0
- package/src/ai/Estimates.ts +36 -0
- package/src/ai/Models.ts +373 -0
- package/src/ai/OpenAIProviderError.ts +98 -0
- package/src/ai/OpenAIQuotaRetry.ts +183 -0
- package/src/ai/ProviderCosts.ts +156 -0
- package/src/ai/README.md +187 -0
- package/src/ai/ResponsesProviderCall.ts +34 -0
- package/src/ai/agentCitations.ts +186 -0
- package/src/ai/contracts/AI.ts +380 -0
- package/src/ai/contracts/Agent.ts +539 -0
- package/src/ai/contracts/AiRequestRunCostSummary.ts +31 -0
- package/src/ai/contracts/Pricing.ts +95 -0
- package/src/ai/contracts/Providers.ts +73 -0
- package/src/ai/contracts/QuotaRetry.ts +39 -0
- package/src/ai/contracts/RateLimits.ts +49 -0
- package/src/ai/contracts/ResponsesProviderCall.ts +30 -0
- package/src/ai/contracts/index.ts +8 -0
- package/src/ai/examples/Conversation.ts +12 -0
- package/src/ai/examples/HelpAgent.ts +27 -0
- package/src/ai/examples/createHelpImage.ts +13 -0
- package/src/ai/index.ts +27 -0
- package/src/ai/registry.ts +70 -0
- package/src/ai/sdkNodeCompatibility.d.ts +76 -0
- package/src/ai/toolCallRecovery.ts +82 -0
- package/src/ai/toolHelpers.ts +145 -0
- package/src/auth/Auth.ts +1422 -0
- package/src/auth/AuthProvider.ts +251 -0
- package/src/auth/AuthToken.ts +239 -0
- package/src/auth/PasswordResetToken.ts +93 -0
- package/src/auth/README.md +396 -0
- package/src/auth/UserIdentity.ts +112 -0
- package/src/auth/contracts/AuthProviderDriver.ts +114 -0
- package/src/auth/contracts/index.ts +1 -0
- package/src/auth/examples/runPasswordAuth.ts +45 -0
- package/src/auth/index.ts +8 -0
- package/src/auth/passwordHash.ts +160 -0
- package/src/auth/providers/GoogleAuthProvider.ts +470 -0
- package/src/auth/providers/PasswordAuthProvider.ts +256 -0
- package/src/auth/providers/index.ts +3 -0
- package/src/auth/providers/resolveAuthProviders.ts +166 -0
- package/src/cache/Cache.ts +151 -0
- package/src/cache/README.md +137 -0
- package/src/cache/contracts/CacheDriver.ts +11 -0
- package/src/cache/contracts/CacheOperations.ts +28 -0
- package/src/cache/contracts/CacheOptions.ts +56 -0
- package/src/cache/contracts/CacheRepository.ts +62 -0
- package/src/cache/contracts/index.ts +4 -0
- package/src/cache/drivers/CacheManagerDriver.ts +84 -0
- package/src/cache/drivers/createCacheDriver.ts +191 -0
- package/src/cache/examples/runNoteCache.ts +37 -0
- package/src/cache/index.ts +2 -0
- package/src/cli/Cli.ts +110 -0
- package/src/cli/README.md +164 -0
- package/src/cli/commands/repl.ts +29 -0
- package/src/cli/contracts/CliCommand.ts +33 -0
- package/src/cli/contracts/CliConfig.ts +10 -0
- package/src/cli/contracts/CliOptions.ts +13 -0
- package/src/cli/contracts/CommandDefinition.ts +19 -0
- package/src/cli/contracts/ReplOptions.ts +11 -0
- package/src/cli/contracts/index.ts +5 -0
- package/src/cli/defineCommand.ts +25 -0
- package/src/cli/index.ts +5 -0
- package/src/cli/runDb3.ts +63 -0
- package/src/cli/runRepl.ts +55 -0
- package/src/config/Config.ts +110 -0
- package/src/config/README.md +142 -0
- package/src/config/env.ts +164 -0
- package/src/config/examples/loadNotesConfig.ts +29 -0
- package/src/config/examples/runConfig.ts +40 -0
- package/src/config/index.ts +2 -0
- package/src/db/ActiveProjection.ts +311 -0
- package/src/db/ActiveQueryBuilder.ts +831 -0
- package/src/db/ActiveRecord.ts +1317 -0
- package/src/db/Database.ts +1283 -0
- package/src/db/FieldType.ts +1243 -0
- package/src/db/README.md +508 -0
- package/src/db/SoftDeletes.ts +158 -0
- package/src/db/commands/check.ts +10 -0
- package/src/db/commands/index.ts +19 -0
- package/src/db/commands/makeMigration.ts +11 -0
- package/src/db/commands/migrate.ts +10 -0
- package/src/db/connection.ts +68 -0
- package/src/db/contracts/ActiveRecordDefinition.ts +69 -0
- package/src/db/contracts/DatabaseBackup.ts +7 -0
- package/src/db/contracts/DatabaseMigrationsConfig.ts +10 -0
- package/src/db/contracts/index.ts +3 -0
- package/src/db/dialects/columnTypes.ts +103 -0
- package/src/db/dialects/index.ts +6 -0
- package/src/db/dialects/mariadb.ts +51 -0
- package/src/db/dialects/mysql.ts +277 -0
- package/src/db/dialects/postgres.ts +143 -0
- package/src/db/dialects/resolveDialect.ts +88 -0
- package/src/db/dialects/types.ts +59 -0
- package/src/db/errors.ts +22 -0
- package/src/db/examples/DefinedUser.ts +20 -0
- package/src/db/examples/FieldNote.ts +27 -0
- package/src/db/examples/KnowledgeNote.ts +29 -0
- package/src/db/examples/NoteCodeField.ts +9 -0
- package/src/db/examples/createNotesTogether.ts +24 -0
- package/src/db/examples/outputs/workspace-notes.json +9 -0
- package/src/db/examples/runFieldNotes.ts +51 -0
- package/src/db/examples/runNoteMigrations.ts +64 -0
- package/src/db/examples/runWorkspaceNotes.ts +86 -0
- package/src/db/examples/workspaceNotes.ts +57 -0
- package/src/db/fields/BooleanField.ts +128 -0
- package/src/db/fields/CharUuidField.ts +91 -0
- package/src/db/fields/ChoiceStringField.ts +97 -0
- package/src/db/fields/DecimalField.ts +157 -0
- package/src/db/fields/EmailField.ts +79 -0
- package/src/db/fields/EncryptedJsonField.ts +211 -0
- package/src/db/fields/IntegerField.ts +200 -0
- package/src/db/fields/JsonField.ts +108 -0
- package/src/db/fields/JsonStringField.ts +63 -0
- package/src/db/fields/LinkField.ts +502 -0
- package/src/db/fields/PasswordField.ts +294 -0
- package/src/db/fields/StringField.ts +154 -0
- package/src/db/fields/StringListField.ts +179 -0
- package/src/db/fields/TextField.ts +71 -0
- package/src/db/fields/TimestampField.ts +164 -0
- package/src/db/fields/UlidField.ts +189 -0
- package/src/db/fields/UrlField.ts +97 -0
- package/src/db/fields/VectorField.ts +266 -0
- package/src/db/fields/createField.ts +22 -0
- package/src/db/fields/field.ts +209 -0
- package/src/db/fields/index.ts +76 -0
- package/src/db/fields/resolveFields.ts +69 -0
- package/src/db/index.ts +13 -0
- package/src/db/migrations/DatabaseMigrationManager.ts +756 -0
- package/src/db/migrations/DatabaseSchemaInspector.ts +541 -0
- package/src/db/migrations/KnexMigrationRenderer.ts +490 -0
- package/src/db/migrations/ModelSchemaCollector.ts +240 -0
- package/src/db/migrations/SchemaDiffer.ts +541 -0
- package/src/db/migrations/SchemaNames.ts +62 -0
- package/src/db/migrations/SchemaSnapshotSerializer.ts +59 -0
- package/src/db/migrations/contracts/DatabaseMigration.ts +143 -0
- package/src/db/migrations/contracts/SchemaChange.ts +113 -0
- package/src/db/migrations/contracts/SchemaSnapshot.ts +122 -0
- package/src/db/migrations/contracts/index.ts +3 -0
- package/src/db/migrations/errors.ts +45 -0
- package/src/db/migrations/index.ts +10 -0
- package/src/db/migrations/promoteDestructiveSchemaChanges.ts +120 -0
- package/src/db/queryMonitor.ts +549 -0
- package/src/db/sqlErrors.ts +36 -0
- package/src/db/test/db.ts +159 -0
- package/src/devtools/HttpEventDispatcher.ts +214 -0
- package/src/devtools/contracts/DevtoolsEventDispatcher.ts +57 -0
- package/src/devtools/contracts/index.ts +1 -0
- package/src/devtools/environment.ts +18 -0
- package/src/devtools/index.ts +3 -0
- package/src/events/Events.ts +165 -0
- package/src/events/README.md +106 -0
- package/src/events/contracts/EventConstructor.ts +12 -0
- package/src/events/contracts/EventListener.ts +8 -0
- package/src/events/contracts/EventUnsubscribe.ts +4 -0
- package/src/events/contracts/index.ts +3 -0
- package/src/events/examples/NoteSaved.ts +9 -0
- package/src/events/examples/runNoteEvents.ts +31 -0
- package/src/events/index.ts +2 -0
- package/src/flows/FlowBlockRegistry.ts +79 -0
- package/src/flows/FlowCompiler.ts +624 -0
- package/src/flows/FlowDefinitionError.ts +24 -0
- package/src/flows/FlowStepJob.ts +54 -0
- package/src/flows/FlowValueValidator.ts +120 -0
- package/src/flows/Flows.ts +1118 -0
- package/src/flows/README.md +144 -0
- package/src/flows/blocks/FlowInput.ts +32 -0
- package/src/flows/blocks/FlowOutput.ts +32 -0
- package/src/flows/blocks/Subflow.ts +24 -0
- package/src/flows/blocks/index.ts +11 -0
- package/src/flows/constants.ts +62 -0
- package/src/flows/contracts/FlowBlock.ts +73 -0
- package/src/flows/contracts/FlowCompiler.ts +32 -0
- package/src/flows/contracts/FlowDefinition.ts +126 -0
- package/src/flows/contracts/FlowDefinitionStore.ts +52 -0
- package/src/flows/contracts/FlowRun.ts +44 -0
- package/src/flows/contracts/FlowValue.ts +54 -0
- package/src/flows/contracts/FlowsService.ts +39 -0
- package/src/flows/contracts/index.ts +7 -0
- package/src/flows/defineBlock.ts +25 -0
- package/src/flows/drivers/FileFlowDefinitionStore.ts +372 -0
- package/src/flows/drivers/index.ts +1 -0
- package/src/flows/errors.ts +22 -0
- package/src/flows/examples/FlowExampleApp.ts +15 -0
- package/src/flows/examples/createTextFlow.ts +14 -0
- package/src/flows/examples/normalizeTextBlock.ts +15 -0
- package/src/flows/examples/runTextFlow.ts +46 -0
- package/src/flows/examples/uppercaseTextBlock.ts +11 -0
- package/src/flows/index.ts +13 -0
- package/src/flows/models/FlowRun.ts +164 -0
- package/src/flows/models/FlowRunEvent.ts +108 -0
- package/src/flows/models/FlowStepRun.ts +176 -0
- package/src/flows/models/index.ts +16 -0
- package/src/index.ts +40 -0
- package/src/logging/Log.ts +100 -0
- package/src/logging/README.md +139 -0
- package/src/logging/contracts/HttpExchange.ts +53 -0
- package/src/logging/contracts/Logger.ts +45 -0
- package/src/logging/contracts/LoggerDriver.ts +19 -0
- package/src/logging/contracts/LoggingOptions.ts +51 -0
- package/src/logging/contracts/index.ts +4 -0
- package/src/logging/drivers/PinoLoggerDriver.ts +376 -0
- package/src/logging/drivers/index.ts +1 -0
- package/src/logging/examples/runNoteLogs.ts +38 -0
- package/src/logging/index.ts +3 -0
- package/src/logging/transports/DevtoolsLogTransport.ts +142 -0
- package/src/mail/Mail.ts +188 -0
- package/src/mail/README.md +206 -0
- package/src/mail/examples/runMailPreview.ts +44 -0
- package/src/mail/examples/welcomeMessage.ts +26 -0
- package/src/mail/index.ts +4 -0
- package/src/mail/transports/FileMailTransport.ts +58 -0
- package/src/mail/transports/MailgunTransport.ts +85 -0
- package/src/mail/transports/ResendTransport.ts +80 -0
- package/src/media/MediaFile.ts +132 -0
- package/src/media/MediaItem.ts +132 -0
- package/src/media/MediaLibrary.ts +117 -0
- package/src/media/MediaManager.ts +874 -0
- package/src/media/README.md +358 -0
- package/src/media/constants.ts +31 -0
- package/src/media/contracts/MediaOptions.ts +9 -0
- package/src/media/contracts/index.ts +1 -0
- package/src/media/examples/createPrivateFileServer.ts +55 -0
- package/src/media/examples/runPrivateFiles.ts +45 -0
- package/src/media/examples/runProjectMedia.ts +46 -0
- package/src/media/image/ImageReconstructionError.ts +18 -0
- package/src/media/image/ImageVariantRenderer.ts +386 -0
- package/src/media/image/ImageVariantRequest.ts +65 -0
- package/src/media/image/contracts/ImageProcessor.ts +53 -0
- package/src/media/image/contracts/ImageVariant.ts +37 -0
- package/src/media/image/contracts/ImageVariantCacheOptions.ts +21 -0
- package/src/media/image/contracts/index.ts +3 -0
- package/src/media/image/index.ts +5 -0
- package/src/media/image/processors/SharpImageProcessor.ts +121 -0
- package/src/media/image/processors/index.ts +1 -0
- package/src/media/index.ts +8 -0
- package/src/media/types.ts +168 -0
- package/src/queue/FailedJob.ts +58 -0
- package/src/queue/Queue.ts +938 -0
- package/src/queue/QueueEvents.ts +57 -0
- package/src/queue/QueueRetryLaterError.ts +40 -0
- package/src/queue/QueueWorker.ts +296 -0
- package/src/queue/QueueableJob.ts +167 -0
- package/src/queue/QueuedJob.ts +69 -0
- package/src/queue/README.md +368 -0
- package/src/queue/RetryPolicy.ts +129 -0
- package/src/queue/commands/index.ts +13 -0
- package/src/queue/commands/makeJob.ts +11 -0
- package/src/queue/console.ts +518 -0
- package/src/queue/contracts/CreateJob.ts +13 -0
- package/src/queue/contracts/QueueDriver.ts +135 -0
- package/src/queue/contracts/QueueEvents.ts +77 -0
- package/src/queue/contracts/QueuePayload.ts +150 -0
- package/src/queue/contracts/QueueRetry.ts +47 -0
- package/src/queue/contracts/QueueService.ts +219 -0
- package/src/queue/contracts/QueueWorkerLifecycle.ts +71 -0
- package/src/queue/contracts/QueueableJob.ts +56 -0
- package/src/queue/contracts/RedisQueueDriver.ts +37 -0
- package/src/queue/contracts/index.ts +9 -0
- package/src/queue/createJob.ts +54 -0
- package/src/queue/drivers/DatabaseQueueDriver.ts +449 -0
- package/src/queue/drivers/RedisQueueDriver.ts +733 -0
- package/src/queue/examples/DeferredReportJob.ts +25 -0
- package/src/queue/examples/GenerateReportJob.ts +37 -0
- package/src/queue/examples/WriteReportJob.ts +37 -0
- package/src/queue/examples/createAndProcessReportJob.ts +29 -0
- package/src/queue/examples/dispatchReportWorkflows.ts +40 -0
- package/src/queue/examples/manageReportRetries.ts +47 -0
- package/src/queue/examples/outputs/create-and-process-report-job.json +6 -0
- package/src/queue/examples/outputs/dispatch-report-workflows.json +14 -0
- package/src/queue/examples/outputs/manage-report-retries.json +24 -0
- package/src/queue/examples/outputs/queue-reports.json +11 -0
- package/src/queue/examples/reportConsole.ts +47 -0
- package/src/queue/examples/runBackpressure.ts +27 -0
- package/src/queue/examples/runQueueReports.ts +80 -0
- package/src/queue/examples/runQueueWorkflows.ts +43 -0
- package/src/queue/index.ts +13 -0
- package/src/queue/queueMonitor.ts +368 -0
- package/src/scheduler/README.md +139 -0
- package/src/scheduler/ScheduledCall.ts +36 -0
- package/src/scheduler/ScheduledEvent.ts +149 -0
- package/src/scheduler/ScheduledJob.ts +58 -0
- package/src/scheduler/ScheduledOccurrence.ts +250 -0
- package/src/scheduler/ScheduledOccurrenceRecorder.ts +125 -0
- package/src/scheduler/Scheduler.ts +225 -0
- package/src/scheduler/SchedulerWorker.ts +151 -0
- package/src/scheduler/console.ts +368 -0
- package/src/scheduler/constants.ts +27 -0
- package/src/scheduler/contracts/Scheduler.ts +123 -0
- package/src/scheduler/contracts/SchedulerConsole.ts +40 -0
- package/src/scheduler/contracts/SchedulerWorker.ts +23 -0
- package/src/scheduler/contracts/index.ts +3 -0
- package/src/scheduler/examples/RecoverableSummaryJob.ts +18 -0
- package/src/scheduler/examples/WriteDailySummaryJob.ts +17 -0
- package/src/scheduler/examples/registerDailySummary.ts +13 -0
- package/src/scheduler/examples/runDailySummary.ts +46 -0
- package/src/scheduler/examples/runScheduledReplay.ts +60 -0
- package/src/scheduler/index.ts +9 -0
- package/src/scheduler/scheduleTime.ts +78 -0
- package/src/security/README.md +130 -0
- package/src/security/Security.ts +346 -0
- package/src/security/SecurityError.ts +16 -0
- package/src/security/contracts/SecurityOptions.ts +20 -0
- package/src/security/contracts/SecurityPayload.ts +14 -0
- package/src/security/contracts/index.ts +2 -0
- package/src/security/ensureAppKey.ts +82 -0
- package/src/security/examples/runSecretRoundTrip.ts +42 -0
- package/src/security/index.ts +4 -0
- package/src/serialization/README.md +169 -0
- package/src/serialization/Serializable.ts +17 -0
- package/src/serialization/SerializationError.ts +91 -0
- package/src/serialization/SerializationRegistry.ts +208 -0
- package/src/serialization/SerializationRegistryError.ts +24 -0
- package/src/serialization/Serializer.ts +793 -0
- package/src/serialization/contracts/SerializableClass.ts +26 -0
- package/src/serialization/contracts/SerializedValue.ts +71 -0
- package/src/serialization/contracts/SerializerOptions.ts +19 -0
- package/src/serialization/contracts/SerializerService.ts +29 -0
- package/src/serialization/contracts/index.ts +4 -0
- package/src/serialization/examples/ExportRequest.ts +25 -0
- package/src/serialization/examples/runExportSerialization.ts +24 -0
- package/src/serialization/index.ts +6 -0
- package/src/server/App.ts +326 -0
- package/src/server/README.md +219 -0
- package/src/server/RequestContext.ts +122 -0
- package/src/server/appContext.ts +59 -0
- package/src/server/examples/createFirstServer.ts +25 -0
- package/src/server/examples/startFirstServer.ts +19 -0
- package/src/server/index.ts +16 -0
- package/src/ssr/README.md +158 -0
- package/src/ssr/constants.ts +8 -0
- package/src/ssr/contracts/DocumentHead.ts +35 -0
- package/src/ssr/contracts/SsrRenderContext.ts +25 -0
- package/src/ssr/contracts/SsrRenderResult.ts +23 -0
- package/src/ssr/contracts/SsrRenderer.ts +12 -0
- package/src/ssr/contracts/SsrRequest.ts +17 -0
- package/src/ssr/contracts/index.ts +19 -0
- package/src/ssr/createSsrRenderContext.ts +25 -0
- package/src/ssr/examples/createPublicPageServer.ts +32 -0
- package/src/ssr/examples/runPublicPages.ts +25 -0
- package/src/ssr/fastify/contracts/FastifySsrOptions.ts +24 -0
- package/src/ssr/fastify/contracts/index.ts +5 -0
- package/src/ssr/fastify/fastifySsr.ts +110 -0
- package/src/ssr/fastify/index.ts +2 -0
- package/src/ssr/index.ts +10 -0
- package/src/ssr/renderDocumentHead.ts +72 -0
- package/src/ssr/renderSsrDocument.ts +35 -0
- package/src/ssr/serializeSsrState.ts +19 -0
- package/src/ssr/vite/contracts/ViteSsrOptions.ts +52 -0
- package/src/ssr/vite/contracts/index.ts +6 -0
- package/src/ssr/vite/fastifyViteSsr.ts +279 -0
- package/src/ssr/vite/index.ts +4 -0
- package/src/ssr/vite/viteSsrManifest.ts +92 -0
- package/src/storage/README.md +310 -0
- package/src/storage/Storage.ts +392 -0
- package/src/storage/contents.ts +23 -0
- package/src/storage/contracts/StorageListing.ts +55 -0
- package/src/storage/contracts/index.ts +1 -0
- package/src/storage/drivers/FlystorageDisk.ts +295 -0
- package/src/storage/drivers/FlystorageListing.ts +78 -0
- package/src/storage/drivers/LocalStorageDisk.ts +45 -0
- package/src/storage/drivers/S3StorageDisk.ts +114 -0
- package/src/storage/drivers/index.ts +3 -0
- package/src/storage/examples/runStorage.ts +37 -0
- package/src/storage/examples/runStreamExport.ts +41 -0
- package/src/storage/examples/writeCsvExport.ts +45 -0
- package/src/storage/index.ts +7 -0
- package/src/storage/mime.ts +30 -0
- package/src/storage/path.ts +76 -0
- package/src/storage/types.ts +251 -0
- package/src/url/README.md +41 -0
- package/src/url/UrlGenerator.ts +72 -0
- package/src/url/contracts/UrlGeneratorOptions.ts +14 -0
- package/src/url/contracts/index.ts +1 -0
- package/src/url/examples/runApplicationLinks.ts +33 -0
- package/src/url/index.ts +2 -0
- package/src/validation/README.md +433 -0
- package/src/validation/examples/runNoteValidation.ts +18 -0
- package/src/validation/examples/validateNoteInput.ts +31 -0
- package/src/validation/index.ts +398 -0
- package/templates/AGENTS.md +15 -0
package/dist/ai/Agent.js
ADDED
|
@@ -0,0 +1,2976 @@
|
|
|
1
|
+
import { aiExecutionContext } from './AiExecutionContext.js';
|
|
2
|
+
import { Agent as SdkAgent, Runner, generateTraceId } from '@openai/agents';
|
|
3
|
+
import { isQueueRetryLaterError } from '@db3.ai/app/queue';
|
|
4
|
+
import { agentMarkdownWithCitations, normalizedAgentCitations } from '@db3.ai/pure';
|
|
5
|
+
import { app } from '../server/appContext.js';
|
|
6
|
+
import { AI_MESSAGE_ROLE, AI_MESSAGE_TOOL_STATE } from './AiMessage.js';
|
|
7
|
+
import { AI_REQUEST_STATUS } from './AiRequest.js';
|
|
8
|
+
import { AI_PROVIDER, AIQuotaDeferredError, AIRateLimitDeferredError, isFailoverableFailure, openAIProviderError, responsesRateLimitEndpoint, simulatedProviderOutage } from './index.js';
|
|
9
|
+
import { AIAllowanceExceededError } from './AIErrors.js';
|
|
10
|
+
import { estimateTokensFromText } from './Estimates.js';
|
|
11
|
+
import { calculateAIHostedToolCost, calculateAIRequestCostUSD, calculateAIRequestEntriesCostUSD, combineAIRequestCostUSD } from './Models.js';
|
|
12
|
+
import { AgentRunJob } from './AgentRunJob.js';
|
|
13
|
+
import { openAIQuotaRetryDecision, withOpenAIQuotaRetryMetadata, withoutOpenAIQuotaRetryMetadata } from './OpenAIQuotaRetry.js';
|
|
14
|
+
import { agentCitationFromStreamRecord, agentCitationsFromFinalModelResponse, rememberAgentCitation } from './agentCitations.js';
|
|
15
|
+
import { serializeQueuedAgent } from './registry.js';
|
|
16
|
+
import { agentToolResultFromStructuredOutput } from './toolHelpers.js';
|
|
17
|
+
import { INTERRUPTED_TOOL_CALL_MESSAGE, unresolvedToolCallIds } from './toolCallRecovery.js';
|
|
18
|
+
/**
|
|
19
|
+
* Shared persisted Agents SDK runtime for interactive and queued application agents.
|
|
20
|
+
*/
|
|
21
|
+
export class Agent {
|
|
22
|
+
context;
|
|
23
|
+
maxTurns = 8;
|
|
24
|
+
maxPreviousMessages = 50;
|
|
25
|
+
/** Provider reasoning effort used for every run of this agent. */
|
|
26
|
+
reasoningEffort = null;
|
|
27
|
+
agentName = this.constructor.name;
|
|
28
|
+
sdkAgentName = this.constructor.name;
|
|
29
|
+
workflowName = this.constructor.name;
|
|
30
|
+
/** Optional agent-specific model. Omit to use the global `app().ai.model`. */
|
|
31
|
+
model;
|
|
32
|
+
currentInput = null;
|
|
33
|
+
/**
|
|
34
|
+
* Creates a persisted agent runtime for the supplied app context.
|
|
35
|
+
*
|
|
36
|
+
* @param context - Trusted user, application scope, and optional conversation context.
|
|
37
|
+
*/
|
|
38
|
+
constructor(context) {
|
|
39
|
+
this.context = context;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Returns the complete constructor context for durable agent reconstruction.
|
|
43
|
+
*
|
|
44
|
+
* ActiveRecord values are reduced to registered model references by the
|
|
45
|
+
* framework serializer. Mutable fluent input remains explicit run payload
|
|
46
|
+
* data and is intentionally not part of constructor state.
|
|
47
|
+
*
|
|
48
|
+
* @returns Complete context accepted by this agent's constructor.
|
|
49
|
+
*/
|
|
50
|
+
toJSON() {
|
|
51
|
+
return this.context;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Sets the user or task input for the next stream or queued run.
|
|
55
|
+
*
|
|
56
|
+
* @param message - User or system task input for the agent.
|
|
57
|
+
* @returns This agent instance for fluent calls.
|
|
58
|
+
*/
|
|
59
|
+
input(message) {
|
|
60
|
+
this.currentInput = { message };
|
|
61
|
+
return this;
|
|
62
|
+
}
|
|
63
|
+
async stream(messageOrEmit, emit) {
|
|
64
|
+
const streamInput = this.resolveStreamInput(messageOrEmit, emit);
|
|
65
|
+
let state = null;
|
|
66
|
+
const traceId = generateTraceId();
|
|
67
|
+
try {
|
|
68
|
+
const prepared = await this.prepareRun(streamInput.message, 'ndjson', traceId);
|
|
69
|
+
state = prepared.state;
|
|
70
|
+
await streamInput.emit({
|
|
71
|
+
type: 'conversation.created',
|
|
72
|
+
conversationId: String(state.conversation.id),
|
|
73
|
+
aiRequestId: state.aiRequest.id ? String(state.aiRequest.id) : null,
|
|
74
|
+
traceId,
|
|
75
|
+
toolDefinitions: state.toolDefinitions,
|
|
76
|
+
});
|
|
77
|
+
await streamInput.emit({
|
|
78
|
+
type: 'message.created',
|
|
79
|
+
id: String(state.metadata.userMessageId),
|
|
80
|
+
role: 'user',
|
|
81
|
+
content: streamInput.message,
|
|
82
|
+
createdAt: state.metadata.userMessageCreatedAt,
|
|
83
|
+
});
|
|
84
|
+
const result = await this.executePreparedRun(prepared, streamInput.emit);
|
|
85
|
+
await streamInput.emit({
|
|
86
|
+
type: 'run.completed',
|
|
87
|
+
conversationId: result.conversationId,
|
|
88
|
+
aiRequestId: result.aiRequestId,
|
|
89
|
+
traceId,
|
|
90
|
+
usage: result.usage,
|
|
91
|
+
creditCost: result.creditCost,
|
|
92
|
+
...(this.exposeProviderCosts() ? { costUSD: result.costUSD } : {}),
|
|
93
|
+
finalOutput: result.finalOutput,
|
|
94
|
+
});
|
|
95
|
+
return result;
|
|
96
|
+
}
|
|
97
|
+
catch (error) {
|
|
98
|
+
const payload = agentErrorPayload(error, `Unable to run ${this.agentName}.`);
|
|
99
|
+
if (state) {
|
|
100
|
+
await this.failTrackedRun(state, payload.message);
|
|
101
|
+
}
|
|
102
|
+
await streamInput.emit({
|
|
103
|
+
type: 'run.error',
|
|
104
|
+
conversationId: state?.conversation.id ? String(state.conversation.id) : null,
|
|
105
|
+
aiRequestId: state?.aiRequest.id ? String(state.aiRequest.id) : null,
|
|
106
|
+
traceId,
|
|
107
|
+
error: payload,
|
|
108
|
+
});
|
|
109
|
+
return null;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
/** Runs this agent to completion, preserving the same history and tool lifecycle as stream(). */
|
|
113
|
+
async run(message) {
|
|
114
|
+
let failure = null;
|
|
115
|
+
const result = await this.stream(message, event => { if (event.type === 'run.error')
|
|
116
|
+
failure = event.error.message; });
|
|
117
|
+
if (!result)
|
|
118
|
+
throw new Error(failure ?? 'Agent run failed.');
|
|
119
|
+
return result;
|
|
120
|
+
}
|
|
121
|
+
/** Generates and optionally stores an image under the active agent attempt. */
|
|
122
|
+
generateImage(input, options = {}) {
|
|
123
|
+
return app().ai.generateImage(input, { user: this.userId(), [app().ai.scopeField]: this.scopeId(), ...options });
|
|
124
|
+
}
|
|
125
|
+
/** Generates an embedding under the active agent attempt. */
|
|
126
|
+
generateEmbedding(input, model, options = {}) {
|
|
127
|
+
return app().ai.generateEmbedding(input, model, { user: this.userId(), [app().ai.scopeField]: this.scopeId(), ...options });
|
|
128
|
+
}
|
|
129
|
+
/** Generates schema-validated output under the active agent attempt. */
|
|
130
|
+
generateStructured(input, options = {}) {
|
|
131
|
+
return app().ai.generateStructured(input, { user: this.userId(), [app().ai.scopeField]: this.scopeId(), ...options });
|
|
132
|
+
}
|
|
133
|
+
async queue(messageOrOptions = {}, options = {}) {
|
|
134
|
+
const queueInput = this.resolveQueueInput(messageOrOptions, options);
|
|
135
|
+
const traceId = generateTraceId();
|
|
136
|
+
const serializedAgent = await this.serializeForQueue();
|
|
137
|
+
const prepared = await this.prepareRun(queueInput.message, 'queue', traceId);
|
|
138
|
+
const payload = this.queuedRunPayload(prepared, serializedAgent);
|
|
139
|
+
try {
|
|
140
|
+
const jobId = await app().queue.dispatch(new AgentRunJob(payload), queueInput.options);
|
|
141
|
+
await this.markQueued(prepared.state, jobId);
|
|
142
|
+
return {
|
|
143
|
+
jobId,
|
|
144
|
+
conversationId: String(prepared.state.conversation.id),
|
|
145
|
+
aiRequestId: prepared.state.aiRequest.id ? String(prepared.state.aiRequest.id) : null,
|
|
146
|
+
traceId,
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
catch (error) {
|
|
150
|
+
await this.failTrackedRun(prepared.state, error instanceof Error ? error.message : 'Unable to queue agent run.');
|
|
151
|
+
throw error;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
/** Serializes a registered agent before queue preparation creates audit records. */
|
|
155
|
+
async serializeForQueue() {
|
|
156
|
+
return serializeQueuedAgent(this.agentName, this);
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Resolves the current stream input from the fluent input state or shortcut argument.
|
|
160
|
+
*
|
|
161
|
+
* @param messageOrEmit - Optional message shortcut or stream event sink.
|
|
162
|
+
* @param emit - Optional stream event sink when a message shortcut is supplied.
|
|
163
|
+
* @returns Resolved message and event sink for this stream run.
|
|
164
|
+
*/
|
|
165
|
+
resolveStreamInput(messageOrEmit, emit) {
|
|
166
|
+
if (typeof messageOrEmit === 'string') {
|
|
167
|
+
this.input(messageOrEmit);
|
|
168
|
+
return {
|
|
169
|
+
message: this.resolvedInputMessage(),
|
|
170
|
+
emit: emit ?? noopAgentEventSink,
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
return {
|
|
174
|
+
message: this.resolvedInputMessage(),
|
|
175
|
+
emit: messageOrEmit ?? noopAgentEventSink,
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Resolves the current queue input from the fluent input state or shortcut argument.
|
|
180
|
+
*
|
|
181
|
+
* @param messageOrOptions - Optional message shortcut or dispatch options.
|
|
182
|
+
* @param options - Optional dispatch options when a message shortcut is supplied.
|
|
183
|
+
* @returns Resolved message and dispatch options for this queued run.
|
|
184
|
+
*/
|
|
185
|
+
resolveQueueInput(messageOrOptions, options) {
|
|
186
|
+
if (typeof messageOrOptions === 'string') {
|
|
187
|
+
this.input(messageOrOptions);
|
|
188
|
+
return {
|
|
189
|
+
message: this.resolvedInputMessage(),
|
|
190
|
+
options,
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
return {
|
|
194
|
+
message: this.resolvedInputMessage(),
|
|
195
|
+
options: messageOrOptions,
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* Returns the currently configured input message or throws before work starts.
|
|
200
|
+
*
|
|
201
|
+
* @returns Current run input message.
|
|
202
|
+
*/
|
|
203
|
+
resolvedInputMessage() {
|
|
204
|
+
if (this.currentInput === null) {
|
|
205
|
+
throw new Error(`${this.agentName} requires input before it can run.`);
|
|
206
|
+
}
|
|
207
|
+
return this.currentInput.message;
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* Resumes a prepared queued run from a worker process.
|
|
211
|
+
*
|
|
212
|
+
* @param payload - Queued agent run payload.
|
|
213
|
+
* @returns Completed run metadata and final output.
|
|
214
|
+
*/
|
|
215
|
+
async runQueued(payload) {
|
|
216
|
+
if (payload.agentName !== this.agentName) {
|
|
217
|
+
throw new Error(`Queued payload for "${payload.agentName}" cannot run on "${this.agentName}".`);
|
|
218
|
+
}
|
|
219
|
+
const prepared = await this.preparedRunFromQueuedPayload(payload);
|
|
220
|
+
try {
|
|
221
|
+
if (recordValue(prepared.state.rootAiRequest.response)?.providerFinalized === true) {
|
|
222
|
+
return await this.resumeFinalizedTrackedRun(prepared);
|
|
223
|
+
}
|
|
224
|
+
return await this.executePreparedRun(prepared, async () => { });
|
|
225
|
+
}
|
|
226
|
+
catch (error) {
|
|
227
|
+
if (isQueueRetryLaterError(error))
|
|
228
|
+
throw error;
|
|
229
|
+
const quotaRetry = openAIQuotaRetryDecision(error, prepared.state.aiRequest);
|
|
230
|
+
if (quotaRetry && !quotaRetry.expired) {
|
|
231
|
+
await this.deferTrackedRun(prepared.state, quotaRetry);
|
|
232
|
+
throw new AIQuotaDeferredError(quotaRetry.delaySeconds, quotaRetry.retryAt, quotaRetry.retryUntil, quotaRetry.deferralCount, quotaRetry.message);
|
|
233
|
+
}
|
|
234
|
+
const providerError = openAIProviderError(error);
|
|
235
|
+
if (quotaRetry) {
|
|
236
|
+
prepared.state.aiRequest.metadata = withOpenAIQuotaRetryMetadata(prepared.state.aiRequest.metadata, quotaRetry.metadata);
|
|
237
|
+
}
|
|
238
|
+
await this.failTrackedRun(prepared.state, error instanceof Error ? error.message : `Unable to run ${this.agentName}.`, providerError.code);
|
|
239
|
+
throw error;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
243
|
+
* Resumes only settlement for a queued run whose provider output is durable.
|
|
244
|
+
*
|
|
245
|
+
* This closes the credit-settlement/root-save retry window without replaying
|
|
246
|
+
* model turns, hosted tools, images, or embeddings that already completed.
|
|
247
|
+
*
|
|
248
|
+
* @param prepared - Restored queued root with a provider-finalized response.
|
|
249
|
+
* @returns Completed run result rebuilt from the persisted root response.
|
|
250
|
+
*/
|
|
251
|
+
async resumeFinalizedTrackedRun(prepared) {
|
|
252
|
+
const billing = await this.settleFinalizedTrackedRun(prepared.state);
|
|
253
|
+
const response = recordValue(prepared.state.rootAiRequest.response);
|
|
254
|
+
return {
|
|
255
|
+
conversationId: String(prepared.state.conversation.id),
|
|
256
|
+
aiRequestId: prepared.state.rootAiRequest.id ? String(prepared.state.rootAiRequest.id) : null,
|
|
257
|
+
traceId: prepared.traceId,
|
|
258
|
+
usage: billing.usage,
|
|
259
|
+
creditCost: billing.creditCost,
|
|
260
|
+
costUSD: billing.costUSD,
|
|
261
|
+
finalOutput: stringValue(response?.finalOutput) ?? '',
|
|
262
|
+
};
|
|
263
|
+
}
|
|
264
|
+
/**
|
|
265
|
+
* Returns the reasoning summary mode for this agent, or null to keep it off.
|
|
266
|
+
*
|
|
267
|
+
* @returns Reasoning summary mode requested from the provider.
|
|
268
|
+
*/
|
|
269
|
+
reasoningSummaryMode() {
|
|
270
|
+
return null;
|
|
271
|
+
}
|
|
272
|
+
/**
|
|
273
|
+
* Returns a structured output schema for the SDK agent, or null for text output.
|
|
274
|
+
*
|
|
275
|
+
* @returns Agent output type used to parse final model output.
|
|
276
|
+
*/
|
|
277
|
+
outputType() {
|
|
278
|
+
return null;
|
|
279
|
+
}
|
|
280
|
+
/**
|
|
281
|
+
* Converts the SDK final output into the assistant message text stored by application.
|
|
282
|
+
*
|
|
283
|
+
* @param finalOutput - Final output returned by the Agents SDK.
|
|
284
|
+
* @param streamedText - Text accumulated from output deltas while streaming.
|
|
285
|
+
* @returns Assistant message content to persist and emit.
|
|
286
|
+
*/
|
|
287
|
+
finalOutputText(finalOutput, streamedText) {
|
|
288
|
+
return defaultAgentFinalOutputText(finalOutput, streamedText);
|
|
289
|
+
}
|
|
290
|
+
/**
|
|
291
|
+
* Performs app-owned side effects after the model has produced a final output.
|
|
292
|
+
*
|
|
293
|
+
* @param _state - Active persistence state for the completed run.
|
|
294
|
+
* @param _finalOutput - Final output returned by the Agents SDK.
|
|
295
|
+
* @returns Optional metadata to store on the tracked AI response.
|
|
296
|
+
*/
|
|
297
|
+
async afterFinalOutput(_state, _finalOutput) {
|
|
298
|
+
return null;
|
|
299
|
+
}
|
|
300
|
+
/**
|
|
301
|
+
* Returns structured final output to store on the tracked AI response.
|
|
302
|
+
*
|
|
303
|
+
* @param finalOutput - Final output returned by the Agents SDK.
|
|
304
|
+
* @returns Structured output for audit storage, or undefined for plain text.
|
|
305
|
+
*/
|
|
306
|
+
structuredFinalOutput(finalOutput) {
|
|
307
|
+
return typeof finalOutput === 'object' && finalOutput !== null ? finalOutput : undefined;
|
|
308
|
+
}
|
|
309
|
+
/**
|
|
310
|
+
* Builds the complete provider input for a run.
|
|
311
|
+
*
|
|
312
|
+
* @param context - Current message and previous provider-shaped input items.
|
|
313
|
+
* @returns Provider-compatible input items for this run.
|
|
314
|
+
*/
|
|
315
|
+
async buildInput(context) {
|
|
316
|
+
return [
|
|
317
|
+
...context.previousMessages,
|
|
318
|
+
this.userMessage(context.message),
|
|
319
|
+
];
|
|
320
|
+
}
|
|
321
|
+
/**
|
|
322
|
+
* Builds a provider-compatible user message.
|
|
323
|
+
*
|
|
324
|
+
* @param content - Message text to send as user input.
|
|
325
|
+
* @returns Agents SDK user message item.
|
|
326
|
+
*/
|
|
327
|
+
userMessage(content) {
|
|
328
|
+
return userInputMessage(content);
|
|
329
|
+
}
|
|
330
|
+
/**
|
|
331
|
+
* Builds a provider-compatible system message.
|
|
332
|
+
*
|
|
333
|
+
* @param content - System context or instruction text.
|
|
334
|
+
* @returns Agents SDK system message item.
|
|
335
|
+
*/
|
|
336
|
+
systemMessage(content) {
|
|
337
|
+
return systemInputMessage(content);
|
|
338
|
+
}
|
|
339
|
+
/**
|
|
340
|
+
* Builds a provider-compatible assistant message.
|
|
341
|
+
*
|
|
342
|
+
* @param content - Assistant text from an earlier turn.
|
|
343
|
+
* @returns Agents SDK assistant message item.
|
|
344
|
+
*/
|
|
345
|
+
assistantMessage(content) {
|
|
346
|
+
return assistantInputMessage(content);
|
|
347
|
+
}
|
|
348
|
+
/**
|
|
349
|
+
* Returns lightweight queue metadata used without reconstructing the agent.
|
|
350
|
+
*
|
|
351
|
+
* Subclasses should expose only identifiers needed by lifecycle projections.
|
|
352
|
+
* Constructor state belongs in `toJSON()` and is not duplicated here.
|
|
353
|
+
*
|
|
354
|
+
* @returns Application-owned queue lifecycle metadata.
|
|
355
|
+
*/
|
|
356
|
+
queueMetadata() {
|
|
357
|
+
return {};
|
|
358
|
+
}
|
|
359
|
+
/**
|
|
360
|
+
* Builds the trace metadata for an SDK runner invocation.
|
|
361
|
+
*
|
|
362
|
+
* @param conversation - Conversation attached to the run.
|
|
363
|
+
* @returns Trace metadata sent to the Agents SDK.
|
|
364
|
+
*/
|
|
365
|
+
traceMetadata(conversation) {
|
|
366
|
+
return {
|
|
367
|
+
app: 'db3',
|
|
368
|
+
agent: this.agentName,
|
|
369
|
+
scopeId: this.scopeId(),
|
|
370
|
+
[`${app().ai.scopeField}Id`]: this.scopeId(),
|
|
371
|
+
conversationId: String(conversation.id),
|
|
372
|
+
};
|
|
373
|
+
}
|
|
374
|
+
/**
|
|
375
|
+
* Returns additional server-owned values to expose to local tools.
|
|
376
|
+
*
|
|
377
|
+
* Subclasses can add task identifiers here when a queued run needs to keep
|
|
378
|
+
* model-visible tool arguments separate from application-owned boundaries.
|
|
379
|
+
*
|
|
380
|
+
* @param _state - Active persistence state, or undefined for a no-run preview.
|
|
381
|
+
* @returns Additional tool context values.
|
|
382
|
+
*/
|
|
383
|
+
toolRunContext(_state) {
|
|
384
|
+
return {};
|
|
385
|
+
}
|
|
386
|
+
/**
|
|
387
|
+
* Returns application-owned metadata that scopes a conversation.
|
|
388
|
+
*
|
|
389
|
+
* Values are persisted when a conversation is created and compared again
|
|
390
|
+
* before later turns are appended, preventing one workflow context from
|
|
391
|
+
* accidentally continuing inside another.
|
|
392
|
+
*
|
|
393
|
+
* @returns Stable conversation-scope metadata for this agent instance.
|
|
394
|
+
*/
|
|
395
|
+
conversationMetadata() {
|
|
396
|
+
return {};
|
|
397
|
+
}
|
|
398
|
+
/**
|
|
399
|
+
* Returns persisted agent identities permitted to continue this conversation.
|
|
400
|
+
*
|
|
401
|
+
* Concrete agents normally accept only their own stable identity. A narrowly
|
|
402
|
+
* scoped replacement agent may override this hook to continue conversations
|
|
403
|
+
* created by the exact predecessor it supersedes.
|
|
404
|
+
*
|
|
405
|
+
* @returns Persisted agent names accepted by conversation authorization.
|
|
406
|
+
*/
|
|
407
|
+
conversationAgentNames() {
|
|
408
|
+
return [this.agentName];
|
|
409
|
+
}
|
|
410
|
+
/**
|
|
411
|
+
* Builds the title for a newly created conversation.
|
|
412
|
+
*
|
|
413
|
+
* @param message - Initial message for the run.
|
|
414
|
+
* @returns Compact conversation title.
|
|
415
|
+
*/
|
|
416
|
+
conversationTitle(message) {
|
|
417
|
+
const title = message.replace(/\s+/g, ' ').trim();
|
|
418
|
+
if (title.length <= 72)
|
|
419
|
+
return title || `${this.sdkAgentName} conversation`;
|
|
420
|
+
return `${title.slice(0, 69).trim()}...`;
|
|
421
|
+
}
|
|
422
|
+
/**
|
|
423
|
+
* Resolves the model used by this agent run.
|
|
424
|
+
*
|
|
425
|
+
* @returns Agent-specific model or the global application model.
|
|
426
|
+
*/
|
|
427
|
+
resolvedModel() {
|
|
428
|
+
return this.model ?? app().ai.model;
|
|
429
|
+
}
|
|
430
|
+
/**
|
|
431
|
+
* Returns the application credit charge reserved before this agent turn.
|
|
432
|
+
*
|
|
433
|
+
* The shared runtime remains unmetered by default because concrete agents
|
|
434
|
+
* own the product bucket and minimum debit that permits work to begin.
|
|
435
|
+
* Provider retries reuse the same tracked request id, so allowance adapters
|
|
436
|
+
* can make repeated checks idempotent.
|
|
437
|
+
*
|
|
438
|
+
* @returns Concrete agent charge, or null when funded by another workflow.
|
|
439
|
+
*/
|
|
440
|
+
usageCharge() {
|
|
441
|
+
return null;
|
|
442
|
+
}
|
|
443
|
+
/**
|
|
444
|
+
* Returns the billable charge for this invocation.
|
|
445
|
+
*
|
|
446
|
+
* Nested agents belong to the outer request tree and therefore cannot
|
|
447
|
+
* reserve or settle credits independently.
|
|
448
|
+
*
|
|
449
|
+
* @returns Top-level product charge, or null for nested and unmetered runs.
|
|
450
|
+
*/
|
|
451
|
+
billableUsageCharge() {
|
|
452
|
+
return this.context.parentAiRequestId ? null : this.usageCharge();
|
|
453
|
+
}
|
|
454
|
+
/**
|
|
455
|
+
* Returns the model settings shared by live execution and dry-run previews.
|
|
456
|
+
*
|
|
457
|
+
* @returns Agents SDK model settings for this agent.
|
|
458
|
+
*/
|
|
459
|
+
modelSettings() {
|
|
460
|
+
const reasoningSummaryMode = this.reasoningSummaryMode();
|
|
461
|
+
return {
|
|
462
|
+
parallelToolCalls: false,
|
|
463
|
+
toolChoice: 'auto',
|
|
464
|
+
...(this.reasoningEffort || reasoningSummaryMode ? {
|
|
465
|
+
reasoning: {
|
|
466
|
+
...(this.reasoningEffort ? { effort: this.reasoningEffort } : {}),
|
|
467
|
+
...(reasoningSummaryMode ? { summary: reasoningSummaryMode } : {}),
|
|
468
|
+
},
|
|
469
|
+
} : {}),
|
|
470
|
+
};
|
|
471
|
+
}
|
|
472
|
+
/**
|
|
473
|
+
* Returns the exact first-turn OpenAI Responses request body without calling
|
|
474
|
+
* OpenAI or creating persistence state.
|
|
475
|
+
*
|
|
476
|
+
* The preview enters the same Agents SDK request-preparation path used by a
|
|
477
|
+
* live run. A request-capturing model stops execution at the provider boundary
|
|
478
|
+
* before any network transport or tool callback can run.
|
|
479
|
+
*
|
|
480
|
+
* @returns JSON request body that would be sent to `responses.create`.
|
|
481
|
+
*
|
|
482
|
+
* @example
|
|
483
|
+
* const request = await agent
|
|
484
|
+
* .input('Complete this task.')
|
|
485
|
+
* .previewRequest();
|
|
486
|
+
*/
|
|
487
|
+
async previewRequest() {
|
|
488
|
+
const model = this.resolvedModel();
|
|
489
|
+
const invocation = await this.prepareAgentInvocation(this.resolvedInputMessage(), []);
|
|
490
|
+
return openAIResponseRequestBody({
|
|
491
|
+
agent: this.sdkAgent(invocation, model),
|
|
492
|
+
context: this.requestPreviewContext(),
|
|
493
|
+
input: invocation.input,
|
|
494
|
+
maxTurns: this.maxTurns,
|
|
495
|
+
model,
|
|
496
|
+
modelSettings: invocation.modelSettings,
|
|
497
|
+
});
|
|
498
|
+
}
|
|
499
|
+
/**
|
|
500
|
+
* Builds the application-owned values used for one SDK model invocation.
|
|
501
|
+
*
|
|
502
|
+
* @param message - Current user or task message.
|
|
503
|
+
* @param previousMessages - Prior provider-compatible conversation input.
|
|
504
|
+
* @returns Prepared values shared by live execution and request previews.
|
|
505
|
+
*/
|
|
506
|
+
async prepareAgentInvocation(message, previousMessages) {
|
|
507
|
+
const tools = this.tools();
|
|
508
|
+
return {
|
|
509
|
+
instructions: await this.instructions(),
|
|
510
|
+
input: await this.buildInput({
|
|
511
|
+
message,
|
|
512
|
+
previousMessages,
|
|
513
|
+
}),
|
|
514
|
+
modelSettings: this.modelSettings(),
|
|
515
|
+
outputType: this.outputType(),
|
|
516
|
+
tools,
|
|
517
|
+
toolDefinitions: agentToolDefinitions(tools),
|
|
518
|
+
};
|
|
519
|
+
}
|
|
520
|
+
/**
|
|
521
|
+
* Creates the SDK Agent from one shared prepared invocation.
|
|
522
|
+
*
|
|
523
|
+
* @param invocation - Application-owned request values.
|
|
524
|
+
* @param model - Provider model selected for this attempt.
|
|
525
|
+
* @returns Configured Agents SDK Agent.
|
|
526
|
+
*/
|
|
527
|
+
sdkAgent(invocation, model) {
|
|
528
|
+
return new SdkAgent({
|
|
529
|
+
name: this.sdkAgentName,
|
|
530
|
+
instructions: invocation.instructions,
|
|
531
|
+
model,
|
|
532
|
+
tools: invocation.tools,
|
|
533
|
+
...(invocation.outputType ? { outputType: invocation.outputType } : {}),
|
|
534
|
+
});
|
|
535
|
+
}
|
|
536
|
+
/**
|
|
537
|
+
* Builds non-persisted SDK context for first-request preparation.
|
|
538
|
+
*
|
|
539
|
+
* These runtime-only values are not included in the OpenAI request. They let
|
|
540
|
+
* the Runner evaluate the same configured tools and dynamic SDK capabilities
|
|
541
|
+
* without creating a conversation or AI request.
|
|
542
|
+
*
|
|
543
|
+
* @returns Tool context used only while the SDK prepares the preview request.
|
|
544
|
+
*/
|
|
545
|
+
requestPreviewContext() {
|
|
546
|
+
return {
|
|
547
|
+
...this.toolRunContext(),
|
|
548
|
+
userId: this.userId(),
|
|
549
|
+
scopeId: this.scopeId(),
|
|
550
|
+
[`${app().ai.scopeField}Id`]: this.scopeId(),
|
|
551
|
+
conversationId: this.context.conversationId || 'request-preview',
|
|
552
|
+
aiRequestId: null,
|
|
553
|
+
rootAiRequestId: null,
|
|
554
|
+
traceId: 'request-preview',
|
|
555
|
+
emitToolProgress: noopAgentEventSink,
|
|
556
|
+
};
|
|
557
|
+
}
|
|
558
|
+
/**
|
|
559
|
+
* Returns the provider failover selection for this agent's runs.
|
|
560
|
+
*
|
|
561
|
+
* Return an ordered provider list to fail over using each provider's default
|
|
562
|
+
* model, or an ordered provider-to-model record to pin a comparable model per
|
|
563
|
+
* provider. The agent's reasoning settings apply to every attempt. Null uses
|
|
564
|
+
* the app default chain, which is OpenAI-only unless configured otherwise.
|
|
565
|
+
*
|
|
566
|
+
* @example
|
|
567
|
+
* protected override provider(): AIProviderSelection {
|
|
568
|
+
* return {
|
|
569
|
+
* [AI_PROVIDER.openai]: this.resolvedModel(),
|
|
570
|
+
* [AI_PROVIDER.openrouter]: 'comparable-model',
|
|
571
|
+
* };
|
|
572
|
+
* }
|
|
573
|
+
*
|
|
574
|
+
* @returns Provider selection for this agent, or null for the app default.
|
|
575
|
+
*/
|
|
576
|
+
provider() {
|
|
577
|
+
return null;
|
|
578
|
+
}
|
|
579
|
+
/**
|
|
580
|
+
* Resolves a new or existing conversation and verifies it belongs to this context.
|
|
581
|
+
*
|
|
582
|
+
* @param message - Current run message.
|
|
583
|
+
* @param traceId - Trace id generated for this run.
|
|
584
|
+
* @param transport - Transport that started the run.
|
|
585
|
+
* @returns Conversation for the run.
|
|
586
|
+
*/
|
|
587
|
+
async resolveConversation(message, traceId, transport) {
|
|
588
|
+
if (this.context.conversationId) {
|
|
589
|
+
const conversation = await app().ai.models.conversation.findOrFail(this.context.conversationId);
|
|
590
|
+
this.assertConversationAccess(conversation);
|
|
591
|
+
return conversation;
|
|
592
|
+
}
|
|
593
|
+
return await new (app().ai.models.conversation)({
|
|
594
|
+
user: this.userId() || null,
|
|
595
|
+
[app().ai.scopeField]: this.scopeId(),
|
|
596
|
+
agent: this.agentName,
|
|
597
|
+
title: this.conversationTitle(message),
|
|
598
|
+
metadata: {
|
|
599
|
+
traceId,
|
|
600
|
+
transport,
|
|
601
|
+
...this.conversationMetadata(),
|
|
602
|
+
},
|
|
603
|
+
}).save();
|
|
604
|
+
}
|
|
605
|
+
/**
|
|
606
|
+
* Throws when a requested conversation is not owned by this agent context.
|
|
607
|
+
*
|
|
608
|
+
* @param conversation - Existing conversation requested by the caller.
|
|
609
|
+
*/
|
|
610
|
+
assertConversationAccess(conversation) {
|
|
611
|
+
const conversationUserId = entityRefId(conversation.user);
|
|
612
|
+
const conversationScopeId = entityRefId(conversation[app().ai.scopeField]);
|
|
613
|
+
if ((conversationUserId ?? '') !== this.userId()) {
|
|
614
|
+
throw new AgentAuthorizationError('Permission denied.');
|
|
615
|
+
}
|
|
616
|
+
if ((conversationScopeId ?? '') !== this.scopeId()) {
|
|
617
|
+
throw new AgentAuthorizationError('Permission denied.');
|
|
618
|
+
}
|
|
619
|
+
if (conversation.agent && !this.conversationAgentNames().includes(conversation.agent)) {
|
|
620
|
+
throw new AgentAuthorizationError('Permission denied.');
|
|
621
|
+
}
|
|
622
|
+
for (const [key, expectedValue] of Object.entries(this.conversationMetadata())) {
|
|
623
|
+
const metadata = conversation.metadata ?? {};
|
|
624
|
+
if (!Object.prototype.hasOwnProperty.call(metadata, key))
|
|
625
|
+
continue;
|
|
626
|
+
const actualValue = metadata[key] ?? null;
|
|
627
|
+
if (actualValue !== expectedValue) {
|
|
628
|
+
throw new AgentAuthorizationError('Permission denied.');
|
|
629
|
+
}
|
|
630
|
+
}
|
|
631
|
+
}
|
|
632
|
+
/**
|
|
633
|
+
* Prepares conversation, request, and input messages before an SDK run starts.
|
|
634
|
+
*
|
|
635
|
+
* @param message - Current run message.
|
|
636
|
+
* @param transport - Transport that started the run.
|
|
637
|
+
* @param traceId - Trace id for the run.
|
|
638
|
+
* @returns Prepared run state ready for stream or queue execution.
|
|
639
|
+
*/
|
|
640
|
+
async prepareRun(message, transport, traceId) {
|
|
641
|
+
const model = this.resolvedModel();
|
|
642
|
+
const conversation = await this.resolveConversation(message, traceId, transport);
|
|
643
|
+
const previousMessages = await this.previousMessages(conversation);
|
|
644
|
+
const invocation = await this.prepareAgentInvocation(message, previousMessages);
|
|
645
|
+
const state = await this.startTrackedRun({
|
|
646
|
+
conversation,
|
|
647
|
+
invocation,
|
|
648
|
+
message,
|
|
649
|
+
model,
|
|
650
|
+
traceId,
|
|
651
|
+
transport,
|
|
652
|
+
});
|
|
653
|
+
const userMessage = await this.saveMessage(state, {
|
|
654
|
+
role: AI_MESSAGE_ROLE.user,
|
|
655
|
+
content: message,
|
|
656
|
+
contentJson: null,
|
|
657
|
+
metadata: {
|
|
658
|
+
eventType: 'user_message',
|
|
659
|
+
traceId,
|
|
660
|
+
},
|
|
661
|
+
});
|
|
662
|
+
state.metadata.userMessageId = String(userMessage.id);
|
|
663
|
+
state.metadata.userMessageCreatedAt = dateString(userMessage.createdAt);
|
|
664
|
+
return {
|
|
665
|
+
message,
|
|
666
|
+
model,
|
|
667
|
+
traceId,
|
|
668
|
+
previousMessages,
|
|
669
|
+
invocation,
|
|
670
|
+
state,
|
|
671
|
+
};
|
|
672
|
+
}
|
|
673
|
+
/**
|
|
674
|
+
* Loads a prepared run from a queued payload.
|
|
675
|
+
*
|
|
676
|
+
* @param payload - Queued run payload.
|
|
677
|
+
* @returns Prepared run state for worker execution.
|
|
678
|
+
*/
|
|
679
|
+
async preparedRunFromQueuedPayload(payload) {
|
|
680
|
+
if (!payload.aiRequestId) {
|
|
681
|
+
throw new Error('Queued agent run is missing an AI request id.');
|
|
682
|
+
}
|
|
683
|
+
const conversation = await app().ai.models.conversation.findOrFail(payload.conversationId);
|
|
684
|
+
const aiRequest = await app().ai.models.request.findOrFail(payload.aiRequestId);
|
|
685
|
+
this.assertConversationAccess(conversation);
|
|
686
|
+
const previousMessages = await this.previousMessages(conversation, aiRequest.id ? String(aiRequest.id) : null);
|
|
687
|
+
const invocation = await this.prepareAgentInvocation(payload.message, previousMessages);
|
|
688
|
+
return {
|
|
689
|
+
message: payload.message,
|
|
690
|
+
model: payload.model,
|
|
691
|
+
traceId: payload.traceId,
|
|
692
|
+
previousMessages,
|
|
693
|
+
invocation,
|
|
694
|
+
state: {
|
|
695
|
+
conversation,
|
|
696
|
+
rootAiRequest: aiRequest,
|
|
697
|
+
aiRequest,
|
|
698
|
+
nextSequence: await nextMessageSequence(conversation),
|
|
699
|
+
model: payload.model,
|
|
700
|
+
traceId: payload.traceId,
|
|
701
|
+
startTimeMs: Date.now(),
|
|
702
|
+
metadata: {},
|
|
703
|
+
toolDefinitions: invocation.toolDefinitions,
|
|
704
|
+
hostedToolUsage: {},
|
|
705
|
+
hostedToolCallIds: new Set(),
|
|
706
|
+
citations: [],
|
|
707
|
+
toolArgumentsByCallId: {},
|
|
708
|
+
},
|
|
709
|
+
};
|
|
710
|
+
}
|
|
711
|
+
/**
|
|
712
|
+
* Executes a prepared SDK run and persists assistant output, tools, and usage.
|
|
713
|
+
*
|
|
714
|
+
* @param prepared - Prepared run state.
|
|
715
|
+
* @param emit - Stream event sink, or a no-op for queued runs.
|
|
716
|
+
* @returns Completed run metadata.
|
|
717
|
+
*/
|
|
718
|
+
async executePreparedRun(prepared, emit) {
|
|
719
|
+
const { state } = prepared;
|
|
720
|
+
const invocation = prepared.invocation;
|
|
721
|
+
const instructions = invocation.instructions;
|
|
722
|
+
const modelInput = invocation.input;
|
|
723
|
+
const attempts = app().ai.resolveProviders(this.provider(), prepared.model);
|
|
724
|
+
const attemptFailures = [];
|
|
725
|
+
await this.attachPromptRequestPayload(state, {
|
|
726
|
+
instructions,
|
|
727
|
+
input: modelInput,
|
|
728
|
+
message: prepared.message,
|
|
729
|
+
previousMessages: prepared.previousMessages,
|
|
730
|
+
});
|
|
731
|
+
await emit(this.promptContextEvent(state, {
|
|
732
|
+
instructions,
|
|
733
|
+
input: modelInput,
|
|
734
|
+
model: prepared.model,
|
|
735
|
+
}));
|
|
736
|
+
for (let index = 0; index < attempts.length; index++) {
|
|
737
|
+
const attempt = attempts[index];
|
|
738
|
+
const hasFallback = index < attempts.length - 1;
|
|
739
|
+
const attemptStartMs = Date.now();
|
|
740
|
+
let rateLimitLease = null;
|
|
741
|
+
let sawStreamEvent = false;
|
|
742
|
+
let activeUsage = null;
|
|
743
|
+
let attemptState = null;
|
|
744
|
+
let attemptSettled = false;
|
|
745
|
+
let providerStarted = false;
|
|
746
|
+
try {
|
|
747
|
+
attemptState = await this.startTrackedAttempt(state, attempt, attemptStartMs);
|
|
748
|
+
rateLimitLease = await this.acquireProviderCapacity(prepared, instructions, modelInput, attempt, attemptState);
|
|
749
|
+
const simulatedOutage = simulatedProviderOutage(attempt.provider);
|
|
750
|
+
if (simulatedOutage)
|
|
751
|
+
throw simulatedOutage;
|
|
752
|
+
const executionState = attemptState;
|
|
753
|
+
return await aiExecutionContext.run(executionState, async () => {
|
|
754
|
+
providerStarted = true;
|
|
755
|
+
const runner = new Runner({
|
|
756
|
+
model: attempt.model,
|
|
757
|
+
modelProvider: app().ai.createAgentProvider(attempt, rateLimitLease),
|
|
758
|
+
modelSettings: modelSettingsForProvider(invocation.modelSettings, attempt.provider),
|
|
759
|
+
tracingDisabled: process.env.OPENAI_AGENTS_TRACING_DISABLED === 'true',
|
|
760
|
+
traceIncludeSensitiveData: false,
|
|
761
|
+
workflowName: this.workflowName,
|
|
762
|
+
traceId: prepared.traceId,
|
|
763
|
+
groupId: String(state.conversation.id),
|
|
764
|
+
traceMetadata: this.traceMetadata(state.conversation),
|
|
765
|
+
});
|
|
766
|
+
const sdkAgent = this.sdkAgent(invocation, attempt.model);
|
|
767
|
+
const sdkContext = this.sdkContext(executionState, emit);
|
|
768
|
+
const stream = await runner.run(sdkAgent, modelInput, {
|
|
769
|
+
stream: true,
|
|
770
|
+
context: sdkContext,
|
|
771
|
+
maxTurns: this.maxTurns,
|
|
772
|
+
reasoningItemIdPolicy: 'preserve',
|
|
773
|
+
});
|
|
774
|
+
activeUsage = stream.runContext.usage;
|
|
775
|
+
let assistantText = '';
|
|
776
|
+
for await (const event of stream) {
|
|
777
|
+
sawStreamEvent = true;
|
|
778
|
+
const streamEvent = await this.streamEventFromSdkEvent(executionState, event);
|
|
779
|
+
if (!streamEvent)
|
|
780
|
+
continue;
|
|
781
|
+
if (streamEvent.type === 'text.delta') {
|
|
782
|
+
assistantText += streamEvent.delta;
|
|
783
|
+
}
|
|
784
|
+
await emit(streamEvent);
|
|
785
|
+
}
|
|
786
|
+
await stream.completed;
|
|
787
|
+
const rawFinalOutput = this.finalOutputText(stream.finalOutput, assistantText);
|
|
788
|
+
const finalResponseCitations = agentCitationsFromFinalModelResponse(stream.rawResponses);
|
|
789
|
+
const citations = finalResponseCitations ?? normalizedAgentCitations(executionState.citations);
|
|
790
|
+
for (const citation of citations) {
|
|
791
|
+
if (!rememberAgentCitation(executionState.citations, citation))
|
|
792
|
+
continue;
|
|
793
|
+
await emit({
|
|
794
|
+
type: 'citation.added',
|
|
795
|
+
citation,
|
|
796
|
+
});
|
|
797
|
+
}
|
|
798
|
+
await this.completeTrackedAttempt(executionState, activeUsage, stream.lastResponseId ?? null);
|
|
799
|
+
attemptSettled = true;
|
|
800
|
+
const structuredOutput = this.structuredFinalOutput(stream.finalOutput);
|
|
801
|
+
const finalOutput = agentMarkdownWithCitations(rawFinalOutput, citations);
|
|
802
|
+
const outputMetadata = await this.afterFinalOutput(state, stream.finalOutput);
|
|
803
|
+
const assistantMessage = await this.saveMessage(executionState, {
|
|
804
|
+
role: AI_MESSAGE_ROLE.assistant,
|
|
805
|
+
content: finalOutput,
|
|
806
|
+
contentJson: {
|
|
807
|
+
type: 'assistant_text',
|
|
808
|
+
citations,
|
|
809
|
+
},
|
|
810
|
+
metadata: {
|
|
811
|
+
eventType: 'assistant_message',
|
|
812
|
+
traceId: prepared.traceId,
|
|
813
|
+
lastResponseId: stream.lastResponseId ?? null,
|
|
814
|
+
},
|
|
815
|
+
});
|
|
816
|
+
const billing = await this.completeTrackedRun(state, {
|
|
817
|
+
finalOutput,
|
|
818
|
+
citations,
|
|
819
|
+
lastResponseId: stream.lastResponseId ?? null,
|
|
820
|
+
successfulAttemptAiRequestId: executionState.aiRequest.id ? String(executionState.aiRequest.id) : null,
|
|
821
|
+
structuredOutput,
|
|
822
|
+
outputMetadata,
|
|
823
|
+
});
|
|
824
|
+
await emit({
|
|
825
|
+
type: 'message.completed',
|
|
826
|
+
id: String(assistantMessage.id),
|
|
827
|
+
role: 'assistant',
|
|
828
|
+
content: finalOutput,
|
|
829
|
+
citations,
|
|
830
|
+
createdAt: dateString(assistantMessage.createdAt),
|
|
831
|
+
});
|
|
832
|
+
return {
|
|
833
|
+
conversationId: String(state.conversation.id),
|
|
834
|
+
aiRequestId: state.aiRequest.id ? String(state.aiRequest.id) : null,
|
|
835
|
+
traceId: prepared.traceId,
|
|
836
|
+
usage: billing.usage,
|
|
837
|
+
creditCost: billing.creditCost,
|
|
838
|
+
costUSD: billing.costUSD,
|
|
839
|
+
finalOutput,
|
|
840
|
+
};
|
|
841
|
+
});
|
|
842
|
+
}
|
|
843
|
+
catch (caught) {
|
|
844
|
+
const error = agentRateLimitError(caught);
|
|
845
|
+
if (attemptState && !attemptSettled) {
|
|
846
|
+
await this.failTrackedAttempt(attemptState, activeUsage, providerStarted, error);
|
|
847
|
+
}
|
|
848
|
+
// Failover is only safe before the SDK has streamed anything: once
|
|
849
|
+
// events arrive, tool calls and partial output may already be
|
|
850
|
+
// persisted or visible, and replaying them would duplicate work.
|
|
851
|
+
if (hasFallback && !sawStreamEvent && isFailoverableFailure(error)) {
|
|
852
|
+
const details = openAIProviderError(error);
|
|
853
|
+
attemptFailures.push({
|
|
854
|
+
provider: attempt.provider,
|
|
855
|
+
model: attempt.model,
|
|
856
|
+
status: details.status,
|
|
857
|
+
code: details.code,
|
|
858
|
+
message: details.message,
|
|
859
|
+
durationMs: Date.now() - attemptStartMs,
|
|
860
|
+
});
|
|
861
|
+
await this.recordProviderAttempts(state, attemptFailures);
|
|
862
|
+
continue;
|
|
863
|
+
}
|
|
864
|
+
throw error;
|
|
865
|
+
}
|
|
866
|
+
finally {
|
|
867
|
+
await app().ai.releaseRateLimit(rateLimitLease);
|
|
868
|
+
}
|
|
869
|
+
}
|
|
870
|
+
// Unreachable: the final attempt always returns or throws above.
|
|
871
|
+
throw new Error(`Unable to run ${this.agentName}: no provider attempt completed.`);
|
|
872
|
+
}
|
|
873
|
+
/**
|
|
874
|
+
* Creates the append-only request row for one SDK provider execution attempt.
|
|
875
|
+
*
|
|
876
|
+
* The logical root is reused by queue retries, while every provider attempt has
|
|
877
|
+
* its own immutable cost boundary. Tool children use this attempt as their
|
|
878
|
+
* parent so replayed or concurrent work cannot overwrite earlier spend.
|
|
879
|
+
*
|
|
880
|
+
* @param rootState - Logical run root and shared conversation state.
|
|
881
|
+
* @param attempt - Provider and model selected for this execution.
|
|
882
|
+
* @param startedAtMs - Attempt start timestamp in milliseconds.
|
|
883
|
+
* @returns Persistence state scoped to the new provider attempt.
|
|
884
|
+
*/
|
|
885
|
+
async startTrackedAttempt(rootState, attempt, startedAtMs) {
|
|
886
|
+
const aiRequest = await new (app().ai.models.request)({
|
|
887
|
+
conversation: rootState.conversation,
|
|
888
|
+
parentAiRequest: rootState.rootAiRequest,
|
|
889
|
+
user: rootState.rootAiRequest.user,
|
|
890
|
+
[app().ai.scopeField]: rootState.rootAiRequest[app().ai.scopeField],
|
|
891
|
+
provider: attempt.provider,
|
|
892
|
+
model: attempt.model,
|
|
893
|
+
operation: 'agents.run.attempt',
|
|
894
|
+
status: AI_REQUEST_STATUS.pending,
|
|
895
|
+
request: {
|
|
896
|
+
rootAiRequestId: rootState.rootAiRequest.id,
|
|
897
|
+
traceId: rootState.traceId,
|
|
898
|
+
},
|
|
899
|
+
startedAt: new Date(startedAtMs),
|
|
900
|
+
metadata: {
|
|
901
|
+
agent: this.agentName,
|
|
902
|
+
traceId: rootState.traceId,
|
|
903
|
+
outcome: 'provider_attempt',
|
|
904
|
+
},
|
|
905
|
+
}).save();
|
|
906
|
+
return {
|
|
907
|
+
...rootState,
|
|
908
|
+
aiRequest,
|
|
909
|
+
nextSequence: await nextMessageSequence(rootState.conversation),
|
|
910
|
+
model: attempt.model,
|
|
911
|
+
startTimeMs: startedAtMs,
|
|
912
|
+
metadata: { ...rootState.metadata },
|
|
913
|
+
hostedToolUsage: {},
|
|
914
|
+
hostedToolCallIds: new Set(),
|
|
915
|
+
citations: [],
|
|
916
|
+
toolArgumentsByCallId: {},
|
|
917
|
+
};
|
|
918
|
+
}
|
|
919
|
+
/**
|
|
920
|
+
* Finalizes one successful provider attempt before application side effects run.
|
|
921
|
+
*
|
|
922
|
+
* @param state - Attempt-scoped persistence state.
|
|
923
|
+
* @param sdkUsage - Complete Agents SDK usage for this attempt.
|
|
924
|
+
* @param lastResponseId - Last provider response id in the attempt.
|
|
925
|
+
*/
|
|
926
|
+
async completeTrackedAttempt(state, sdkUsage, lastResponseId) {
|
|
927
|
+
const usage = agentRunUsage(sdkUsage);
|
|
928
|
+
const requestUsageEntries = agentRequestCostUsageEntries(sdkUsage);
|
|
929
|
+
const cost = agentAttemptCost(state.aiRequest.provider, state.model, usage, requestUsageEntries, state.hostedToolUsage);
|
|
930
|
+
state.aiRequest.assign({
|
|
931
|
+
response: agentAttemptResponse(usage, requestUsageEntries, cost, state.hostedToolUsage, {
|
|
932
|
+
lastResponseId,
|
|
933
|
+
}),
|
|
934
|
+
status: AI_REQUEST_STATUS.completed,
|
|
935
|
+
completedAt: new Date(),
|
|
936
|
+
durationMs: Date.now() - state.startTimeMs,
|
|
937
|
+
inputTokens: usage.inputTokens,
|
|
938
|
+
outputTokens: usage.outputTokens,
|
|
939
|
+
totalTokens: usage.totalTokens,
|
|
940
|
+
reasoningTokens: usage.reasoningTokens,
|
|
941
|
+
cachedTokens: usage.cachedTokens,
|
|
942
|
+
cacheWriteTokens: usage.cacheWriteTokens,
|
|
943
|
+
costUSD: cost.costUSD,
|
|
944
|
+
knownCostUSD: cost.knownCostUSD,
|
|
945
|
+
errorCode: null,
|
|
946
|
+
errorMessage: null,
|
|
947
|
+
});
|
|
948
|
+
await state.aiRequest.save();
|
|
949
|
+
}
|
|
950
|
+
/**
|
|
951
|
+
* Finalizes a failed provider attempt with every usage dimension observed.
|
|
952
|
+
*
|
|
953
|
+
* @param state - Attempt-scoped persistence state.
|
|
954
|
+
* @param sdkUsage - Partial SDK usage accumulated before failure.
|
|
955
|
+
* @param providerStarted - Whether execution crossed the provider boundary.
|
|
956
|
+
* @param error - Error that ended the attempt.
|
|
957
|
+
*/
|
|
958
|
+
async failTrackedAttempt(state, sdkUsage, providerStarted, error) {
|
|
959
|
+
const usage = sdkUsage ? agentRunUsage(sdkUsage) : emptyAgentRunUsage();
|
|
960
|
+
const requestUsageEntries = sdkUsage ? agentRequestCostUsageEntries(sdkUsage) : [];
|
|
961
|
+
const hasBillableUsage = sdkUsage
|
|
962
|
+
? hasBillableAgentAttemptUsage(sdkUsage, state.hostedToolUsage)
|
|
963
|
+
: Object.values(state.hostedToolUsage).some(count => Number.isFinite(count) && count > 0);
|
|
964
|
+
const cost = hasBillableUsage
|
|
965
|
+
? agentAttemptCost(state.aiRequest.provider, state.model, usage, requestUsageEntries, state.hostedToolUsage)
|
|
966
|
+
: emptyAgentAttemptCost(providerStarted);
|
|
967
|
+
const message = error instanceof Error ? error.message : `Unable to run ${this.agentName}.`;
|
|
968
|
+
state.aiRequest.assign({
|
|
969
|
+
response: agentAttemptResponse(usage, requestUsageEntries, cost, state.hostedToolUsage, {
|
|
970
|
+
error: message,
|
|
971
|
+
}),
|
|
972
|
+
status: AI_REQUEST_STATUS.failed,
|
|
973
|
+
completedAt: new Date(),
|
|
974
|
+
durationMs: Date.now() - state.startTimeMs,
|
|
975
|
+
inputTokens: usage.inputTokens,
|
|
976
|
+
outputTokens: usage.outputTokens,
|
|
977
|
+
totalTokens: usage.totalTokens,
|
|
978
|
+
reasoningTokens: usage.reasoningTokens,
|
|
979
|
+
cachedTokens: usage.cachedTokens,
|
|
980
|
+
cacheWriteTokens: usage.cacheWriteTokens,
|
|
981
|
+
costUSD: cost.costUSD,
|
|
982
|
+
knownCostUSD: cost.knownCostUSD,
|
|
983
|
+
errorCode: openAIProviderError(error).code,
|
|
984
|
+
errorMessage: message,
|
|
985
|
+
metadata: {
|
|
986
|
+
...(state.aiRequest.metadata ?? {}),
|
|
987
|
+
outcome: hasBillableUsage ? 'failed_after_provider_usage' : 'failed_without_reported_usage',
|
|
988
|
+
providerStarted,
|
|
989
|
+
},
|
|
990
|
+
});
|
|
991
|
+
await state.aiRequest.save();
|
|
992
|
+
}
|
|
993
|
+
/**
|
|
994
|
+
* Persists sanitized failed provider attempts for auditing and debugging.
|
|
995
|
+
*
|
|
996
|
+
* @param state - Active run persistence state.
|
|
997
|
+
* @param failures - Failed attempts collected so far.
|
|
998
|
+
*/
|
|
999
|
+
async recordProviderAttempts(state, failures) {
|
|
1000
|
+
state.aiRequest.assign({
|
|
1001
|
+
metadata: {
|
|
1002
|
+
...(state.aiRequest.metadata ?? {}),
|
|
1003
|
+
providerAttempts: failures,
|
|
1004
|
+
},
|
|
1005
|
+
});
|
|
1006
|
+
await state.aiRequest.save();
|
|
1007
|
+
}
|
|
1008
|
+
/**
|
|
1009
|
+
* Checks app allowance and reserves capacity for the attempt's first HTTP request.
|
|
1010
|
+
*
|
|
1011
|
+
* @param prepared - Prepared run state with an existing AiRequest row.
|
|
1012
|
+
* @param instructions - System instructions sent to the SDK agent.
|
|
1013
|
+
* @param input - Complete model input for token estimation.
|
|
1014
|
+
* @param attempt - Provider attempt about to run.
|
|
1015
|
+
* @param attemptState - Append-only request row for this provider execution.
|
|
1016
|
+
* @returns Active provider rate-limit lease, or null when rate limiting is disabled.
|
|
1017
|
+
*/
|
|
1018
|
+
async acquireProviderCapacity(prepared, instructions, input, attempt, attemptState) {
|
|
1019
|
+
const operation = prepared.state.aiRequest.operation || 'agents.run.stream';
|
|
1020
|
+
const estimatedTokens = estimatedAgentRunTokens({ instructions, input });
|
|
1021
|
+
await app().ai.checkAllowance({
|
|
1022
|
+
provider: attempt.provider,
|
|
1023
|
+
endpoint: responsesRateLimitEndpoint(),
|
|
1024
|
+
model: attempt.model,
|
|
1025
|
+
operation,
|
|
1026
|
+
user: this.userId() || null,
|
|
1027
|
+
scope: this.scopeId() || null,
|
|
1028
|
+
aiRequest: prepared.state.rootAiRequest,
|
|
1029
|
+
estimatedTokens,
|
|
1030
|
+
usage: this.billableUsageCharge(),
|
|
1031
|
+
metadata: {
|
|
1032
|
+
agent: this.agentName,
|
|
1033
|
+
traceId: prepared.traceId,
|
|
1034
|
+
toolNames: prepared.invocation.toolDefinitions.map(tool => tool.name),
|
|
1035
|
+
},
|
|
1036
|
+
});
|
|
1037
|
+
const lease = await app().ai.acquireRateLimit({
|
|
1038
|
+
provider: attempt.provider,
|
|
1039
|
+
endpoint: responsesRateLimitEndpoint(),
|
|
1040
|
+
model: attempt.model,
|
|
1041
|
+
operation,
|
|
1042
|
+
estimatedTokens,
|
|
1043
|
+
aiRequest: attemptState.aiRequest,
|
|
1044
|
+
});
|
|
1045
|
+
try {
|
|
1046
|
+
await this.attachRateLimitBucket(attemptState, lease);
|
|
1047
|
+
return lease;
|
|
1048
|
+
}
|
|
1049
|
+
catch (error) {
|
|
1050
|
+
await app().ai.releaseRateLimit(lease);
|
|
1051
|
+
throw error;
|
|
1052
|
+
}
|
|
1053
|
+
}
|
|
1054
|
+
/**
|
|
1055
|
+
* Stores the current provider bucket on the tracked request for audit/debugging.
|
|
1056
|
+
*
|
|
1057
|
+
* @param state - Active run persistence state.
|
|
1058
|
+
* @param lease - Provider rate-limit lease returned by the AI service.
|
|
1059
|
+
*/
|
|
1060
|
+
async attachRateLimitBucket(state, lease) {
|
|
1061
|
+
if (!lease?.bucket)
|
|
1062
|
+
return;
|
|
1063
|
+
state.aiRequest.assign({
|
|
1064
|
+
rateLimitBucket: lease.bucket,
|
|
1065
|
+
});
|
|
1066
|
+
await state.aiRequest.save();
|
|
1067
|
+
}
|
|
1068
|
+
/**
|
|
1069
|
+
* Stores the exact system instructions and built SDK input used for a run.
|
|
1070
|
+
*
|
|
1071
|
+
* @param state - Active run persistence state.
|
|
1072
|
+
* @param input - Prompt data sent to the Agents SDK runner.
|
|
1073
|
+
*/
|
|
1074
|
+
async attachPromptRequestPayload(state, input) {
|
|
1075
|
+
state.aiRequest.assign({
|
|
1076
|
+
request: {
|
|
1077
|
+
...(recordValue(state.aiRequest.request) ?? {}),
|
|
1078
|
+
message: input.message,
|
|
1079
|
+
previousMessages: input.previousMessages,
|
|
1080
|
+
instructions: input.instructions,
|
|
1081
|
+
input: input.input,
|
|
1082
|
+
prompt: promptMessagesForRequest(input.instructions, input.input),
|
|
1083
|
+
},
|
|
1084
|
+
});
|
|
1085
|
+
await state.aiRequest.save();
|
|
1086
|
+
}
|
|
1087
|
+
/**
|
|
1088
|
+
* Builds the debug timeline event for the exact prompt sent to the SDK.
|
|
1089
|
+
*
|
|
1090
|
+
* @param state - Active run persistence state.
|
|
1091
|
+
* @param input - System instructions, model input, and model name for the run.
|
|
1092
|
+
* @returns Prompt-context stream event for the frontend timeline.
|
|
1093
|
+
*/
|
|
1094
|
+
promptContextEvent(state, input) {
|
|
1095
|
+
return {
|
|
1096
|
+
type: 'prompt.context',
|
|
1097
|
+
id: promptContextId(state.aiRequest.id, state.traceId),
|
|
1098
|
+
aiRequestId: state.aiRequest.id ? String(state.aiRequest.id) : null,
|
|
1099
|
+
traceId: state.traceId,
|
|
1100
|
+
model: input.model,
|
|
1101
|
+
createdAt: dateString(state.aiRequest.startedAt ?? state.aiRequest.createdAt),
|
|
1102
|
+
userMessageId: state.metadata.userMessageId ?? null,
|
|
1103
|
+
messages: promptContextMessages(input.instructions, input.input),
|
|
1104
|
+
};
|
|
1105
|
+
}
|
|
1106
|
+
/**
|
|
1107
|
+
* Creates the pending provider request row and records the system message.
|
|
1108
|
+
*
|
|
1109
|
+
* @param input - Run metadata needed for persistence.
|
|
1110
|
+
* @returns Persistence state for subsequent messages and completion.
|
|
1111
|
+
*/
|
|
1112
|
+
async startTrackedRun(input) {
|
|
1113
|
+
const toolDefinitions = input.invocation.toolDefinitions;
|
|
1114
|
+
const aiRequest = await new (app().ai.models.request)({
|
|
1115
|
+
conversation: input.conversation,
|
|
1116
|
+
parentAiRequest: this.context.parentAiRequestId ?? null,
|
|
1117
|
+
user: this.userId() || null,
|
|
1118
|
+
[app().ai.scopeField]: this.scopeId(),
|
|
1119
|
+
provider: AI_PROVIDER.openai,
|
|
1120
|
+
model: input.model,
|
|
1121
|
+
operation: input.transport === 'queue' ? 'agents.run.queue' : 'agents.run.stream',
|
|
1122
|
+
status: AI_REQUEST_STATUS.pending,
|
|
1123
|
+
costUSD: 0,
|
|
1124
|
+
knownCostUSD: 0,
|
|
1125
|
+
request: {
|
|
1126
|
+
message: input.message,
|
|
1127
|
+
model: input.model,
|
|
1128
|
+
tools: toolDefinitions.map(tool => tool.name),
|
|
1129
|
+
toolDefinitions,
|
|
1130
|
+
traceId: input.traceId,
|
|
1131
|
+
},
|
|
1132
|
+
metadata: {
|
|
1133
|
+
agent: this.agentName,
|
|
1134
|
+
traceId: input.traceId,
|
|
1135
|
+
transport: input.transport,
|
|
1136
|
+
},
|
|
1137
|
+
startedAt: new Date(),
|
|
1138
|
+
}).save();
|
|
1139
|
+
const state = {
|
|
1140
|
+
conversation: input.conversation,
|
|
1141
|
+
rootAiRequest: aiRequest,
|
|
1142
|
+
aiRequest,
|
|
1143
|
+
nextSequence: await nextMessageSequence(input.conversation),
|
|
1144
|
+
model: input.model,
|
|
1145
|
+
traceId: input.traceId,
|
|
1146
|
+
startTimeMs: Date.now(),
|
|
1147
|
+
metadata: {},
|
|
1148
|
+
toolDefinitions,
|
|
1149
|
+
hostedToolUsage: {},
|
|
1150
|
+
hostedToolCallIds: new Set(),
|
|
1151
|
+
citations: [],
|
|
1152
|
+
toolArgumentsByCallId: {},
|
|
1153
|
+
};
|
|
1154
|
+
await this.saveMessage(state, {
|
|
1155
|
+
role: AI_MESSAGE_ROLE.system,
|
|
1156
|
+
content: input.invocation.instructions,
|
|
1157
|
+
contentJson: null,
|
|
1158
|
+
metadata: {
|
|
1159
|
+
eventType: 'system_instructions',
|
|
1160
|
+
traceId: input.traceId,
|
|
1161
|
+
},
|
|
1162
|
+
});
|
|
1163
|
+
return state;
|
|
1164
|
+
}
|
|
1165
|
+
/**
|
|
1166
|
+
* Builds the run context object shared with local function tools.
|
|
1167
|
+
*
|
|
1168
|
+
* @param state - Active run persistence state.
|
|
1169
|
+
* @param emit - Stream event sink, or no-op for queued runs.
|
|
1170
|
+
* @returns Agents SDK run context.
|
|
1171
|
+
*/
|
|
1172
|
+
sdkContext(state, emit) {
|
|
1173
|
+
return {
|
|
1174
|
+
...this.toolRunContext(state),
|
|
1175
|
+
userId: this.userId(),
|
|
1176
|
+
scopeId: this.scopeId(),
|
|
1177
|
+
[`${app().ai.scopeField}Id`]: this.scopeId(),
|
|
1178
|
+
conversationId: String(state.conversation.id),
|
|
1179
|
+
aiRequestId: state.aiRequest.id ? String(state.aiRequest.id) : null,
|
|
1180
|
+
rootAiRequestId: state.rootAiRequest.id ? String(state.rootAiRequest.id) : null,
|
|
1181
|
+
traceId: state.traceId,
|
|
1182
|
+
emitToolProgress: async (progress) => {
|
|
1183
|
+
await emit({
|
|
1184
|
+
type: 'tool.progress',
|
|
1185
|
+
id: progress.toolCallId,
|
|
1186
|
+
toolName: progress.toolName,
|
|
1187
|
+
progress: {
|
|
1188
|
+
id: `${progress.toolCallId}:${Date.now()}`,
|
|
1189
|
+
message: progress.message,
|
|
1190
|
+
current: progress.current,
|
|
1191
|
+
total: progress.total,
|
|
1192
|
+
data: progress.data,
|
|
1193
|
+
createdAt: new Date().toISOString(),
|
|
1194
|
+
},
|
|
1195
|
+
});
|
|
1196
|
+
},
|
|
1197
|
+
};
|
|
1198
|
+
}
|
|
1199
|
+
/**
|
|
1200
|
+
* Converts an Agents SDK stream event into a application frontend stream event.
|
|
1201
|
+
*
|
|
1202
|
+
* @param state - Active run persistence state.
|
|
1203
|
+
* @param event - SDK stream event.
|
|
1204
|
+
* @returns Normalized stream event, or null when the event is not displayed.
|
|
1205
|
+
*/
|
|
1206
|
+
async streamEventFromSdkEvent(state, event) {
|
|
1207
|
+
if (event.type === 'raw_model_stream_event') {
|
|
1208
|
+
return await this.rawModelStreamEvent(state, event.data);
|
|
1209
|
+
}
|
|
1210
|
+
if (event.type !== 'run_item_stream_event')
|
|
1211
|
+
return null;
|
|
1212
|
+
if (event.name === 'tool_called')
|
|
1213
|
+
return await this.toolCalledEvent(state, event.item);
|
|
1214
|
+
if (event.name === 'tool_output')
|
|
1215
|
+
return await this.toolOutputEvent(state, event.item);
|
|
1216
|
+
if (event.name === 'tool_search_called')
|
|
1217
|
+
return await this.toolCalledEvent(state, event.item);
|
|
1218
|
+
if (event.name === 'tool_search_output_created')
|
|
1219
|
+
return await this.toolOutputEvent(state, event.item);
|
|
1220
|
+
return null;
|
|
1221
|
+
}
|
|
1222
|
+
/**
|
|
1223
|
+
* Converts raw model stream data into a persisted app stream event.
|
|
1224
|
+
*
|
|
1225
|
+
* @param state - Active run persistence state.
|
|
1226
|
+
* @param data - Raw SDK model stream data.
|
|
1227
|
+
* @returns Normalized stream event, or null when ignored.
|
|
1228
|
+
*/
|
|
1229
|
+
async rawModelStreamEvent(state, data) {
|
|
1230
|
+
const record = recordValue(data);
|
|
1231
|
+
if (!record)
|
|
1232
|
+
return null;
|
|
1233
|
+
const citation = agentCitationFromStreamRecord(record);
|
|
1234
|
+
if (citation) {
|
|
1235
|
+
if (!rememberAgentCitation(state.citations, citation))
|
|
1236
|
+
return null;
|
|
1237
|
+
return {
|
|
1238
|
+
type: 'citation.added',
|
|
1239
|
+
citation,
|
|
1240
|
+
};
|
|
1241
|
+
}
|
|
1242
|
+
if (record.type === 'response.reasoning_summary_text.done') {
|
|
1243
|
+
return await this.reasoningSummaryCompletedEvent(state, record);
|
|
1244
|
+
}
|
|
1245
|
+
return rawModelStreamRecordEvent(record, state.toolDefinitions);
|
|
1246
|
+
}
|
|
1247
|
+
/**
|
|
1248
|
+
* Persists a completed reasoning summary and returns its stream event.
|
|
1249
|
+
*
|
|
1250
|
+
* @param state - Active run persistence state.
|
|
1251
|
+
* @param record - Raw Responses reasoning summary completion event.
|
|
1252
|
+
* @returns Reasoning summary completion event, or null when malformed.
|
|
1253
|
+
*/
|
|
1254
|
+
async reasoningSummaryCompletedEvent(state, record) {
|
|
1255
|
+
const id = reasoningSummaryEventId(record);
|
|
1256
|
+
const text = stringValue(record.text);
|
|
1257
|
+
if (!id || !text)
|
|
1258
|
+
return null;
|
|
1259
|
+
const message = await this.saveMessage(state, {
|
|
1260
|
+
role: AI_MESSAGE_ROLE.system,
|
|
1261
|
+
content: text,
|
|
1262
|
+
contentJson: {
|
|
1263
|
+
type: 'reasoning_summary',
|
|
1264
|
+
id,
|
|
1265
|
+
text,
|
|
1266
|
+
},
|
|
1267
|
+
metadata: {
|
|
1268
|
+
eventType: 'reasoning_summary',
|
|
1269
|
+
traceId: state.traceId,
|
|
1270
|
+
},
|
|
1271
|
+
});
|
|
1272
|
+
return {
|
|
1273
|
+
type: 'reasoning.summary.completed',
|
|
1274
|
+
id,
|
|
1275
|
+
text,
|
|
1276
|
+
createdAt: dateString(message.createdAt),
|
|
1277
|
+
};
|
|
1278
|
+
}
|
|
1279
|
+
/**
|
|
1280
|
+
* Persists and emits a tool-call start event.
|
|
1281
|
+
*
|
|
1282
|
+
* @param state - Active run persistence state.
|
|
1283
|
+
* @param item - SDK run item.
|
|
1284
|
+
* @returns Tool calling event or final hosted-tool output event.
|
|
1285
|
+
*/
|
|
1286
|
+
async toolCalledEvent(state, item) {
|
|
1287
|
+
const rawItem = rawItemFromRunItem(item);
|
|
1288
|
+
const toolName = hostedToolNameFromRawItem(rawItem) ?? stringValue(rawItem?.name) ?? 'unknown_tool';
|
|
1289
|
+
const callId = toolCallId(rawItem, toolName);
|
|
1290
|
+
const argumentsValue = toolArguments(rawItem);
|
|
1291
|
+
const toolDefinition = this.toolDefinition(state, toolName);
|
|
1292
|
+
rememberToolArguments(state, callId, argumentsValue);
|
|
1293
|
+
if (hostedToolCompleted(rawItem)) {
|
|
1294
|
+
return await this.toolOutputEvent(state, item);
|
|
1295
|
+
}
|
|
1296
|
+
await this.saveMessage(state, {
|
|
1297
|
+
role: AI_MESSAGE_ROLE.tool,
|
|
1298
|
+
content: `${toolName} started.`,
|
|
1299
|
+
contentJson: {
|
|
1300
|
+
state: AI_MESSAGE_TOOL_STATE.calling,
|
|
1301
|
+
arguments: argumentsValue,
|
|
1302
|
+
},
|
|
1303
|
+
toolCallId: callId,
|
|
1304
|
+
toolName,
|
|
1305
|
+
toolState: AI_MESSAGE_TOOL_STATE.calling,
|
|
1306
|
+
metadata: {
|
|
1307
|
+
eventType: 'tool_calling',
|
|
1308
|
+
traceId: state.traceId,
|
|
1309
|
+
},
|
|
1310
|
+
});
|
|
1311
|
+
return {
|
|
1312
|
+
type: 'tool.calling',
|
|
1313
|
+
id: callId,
|
|
1314
|
+
toolName,
|
|
1315
|
+
arguments: argumentsValue,
|
|
1316
|
+
toolDefinition,
|
|
1317
|
+
};
|
|
1318
|
+
}
|
|
1319
|
+
/**
|
|
1320
|
+
* Persists and emits a tool output event.
|
|
1321
|
+
*
|
|
1322
|
+
* @param state - Active run persistence state.
|
|
1323
|
+
* @param item - SDK run item.
|
|
1324
|
+
* @returns Tool success or error event.
|
|
1325
|
+
*/
|
|
1326
|
+
async toolOutputEvent(state, item) {
|
|
1327
|
+
const rawItem = rawItemFromRunItem(item);
|
|
1328
|
+
const output = outputFromRunItem(item, rawItem);
|
|
1329
|
+
const hostedToolName = hostedToolNameFromRawItem(rawItem);
|
|
1330
|
+
const toolName = hostedToolName ?? stringValue(rawItem?.name) ?? outputToolName(rawItem) ?? 'unknown_tool';
|
|
1331
|
+
const callId = toolCallId(rawItem, toolName);
|
|
1332
|
+
const argumentsValue = toolOutputArguments(state, callId, toolArguments(rawItem));
|
|
1333
|
+
const parsedOutput = parseToolOutput(output);
|
|
1334
|
+
const errorMessage = hostedToolErrorMessage(rawItem) ?? toolResultErrorMessage(parsedOutput);
|
|
1335
|
+
const toolState = errorMessage ? AI_MESSAGE_TOOL_STATE.error : AI_MESSAGE_TOOL_STATE.success;
|
|
1336
|
+
recordHostedToolUsage(state, hostedToolName, callId, rawItem);
|
|
1337
|
+
await this.saveMessage(state, {
|
|
1338
|
+
role: AI_MESSAGE_ROLE.tool,
|
|
1339
|
+
content: errorMessage ? `${toolName} failed.` : `${toolName} completed.`,
|
|
1340
|
+
contentJson: {
|
|
1341
|
+
state: toolState,
|
|
1342
|
+
arguments: argumentsValue,
|
|
1343
|
+
result: parsedOutput,
|
|
1344
|
+
},
|
|
1345
|
+
toolCallId: callId,
|
|
1346
|
+
toolName,
|
|
1347
|
+
toolState,
|
|
1348
|
+
metadata: {
|
|
1349
|
+
eventType: errorMessage ? 'tool_error' : 'tool_success',
|
|
1350
|
+
traceId: state.traceId,
|
|
1351
|
+
},
|
|
1352
|
+
});
|
|
1353
|
+
if (errorMessage) {
|
|
1354
|
+
return {
|
|
1355
|
+
type: 'tool.error',
|
|
1356
|
+
id: callId,
|
|
1357
|
+
toolName,
|
|
1358
|
+
arguments: argumentsValue,
|
|
1359
|
+
error: {
|
|
1360
|
+
message: errorMessage,
|
|
1361
|
+
details: parsedOutput,
|
|
1362
|
+
},
|
|
1363
|
+
};
|
|
1364
|
+
}
|
|
1365
|
+
return {
|
|
1366
|
+
type: 'tool.success',
|
|
1367
|
+
id: callId,
|
|
1368
|
+
toolName,
|
|
1369
|
+
arguments: argumentsValue,
|
|
1370
|
+
result: parsedOutput,
|
|
1371
|
+
};
|
|
1372
|
+
}
|
|
1373
|
+
/**
|
|
1374
|
+
* Saves one normalized AI message and increments the persisted sequence.
|
|
1375
|
+
*
|
|
1376
|
+
* @param state - Active run persistence state.
|
|
1377
|
+
* @param input - Message fields to persist.
|
|
1378
|
+
* @returns Persisted message record.
|
|
1379
|
+
*/
|
|
1380
|
+
async saveMessage(state, input) {
|
|
1381
|
+
const message = await new (app().ai.models.message)({
|
|
1382
|
+
conversation: state.conversation,
|
|
1383
|
+
aiRequest: state.rootAiRequest,
|
|
1384
|
+
user: entityRefId(state.rootAiRequest.user),
|
|
1385
|
+
[app().ai.scopeField]: entityRefId(state.rootAiRequest[app().ai.scopeField]),
|
|
1386
|
+
role: input.role,
|
|
1387
|
+
sequence: state.nextSequence,
|
|
1388
|
+
content: input.content,
|
|
1389
|
+
contentJson: input.contentJson,
|
|
1390
|
+
toolCallId: input.toolCallId ?? null,
|
|
1391
|
+
toolName: input.toolName ?? null,
|
|
1392
|
+
toolState: input.toolState ?? null,
|
|
1393
|
+
provider: state.aiRequest.provider ?? AI_PROVIDER.openai,
|
|
1394
|
+
model: state.model,
|
|
1395
|
+
metadata: input.metadata,
|
|
1396
|
+
}).save();
|
|
1397
|
+
state.nextSequence += 1;
|
|
1398
|
+
return message;
|
|
1399
|
+
}
|
|
1400
|
+
/**
|
|
1401
|
+
* Stores the provider-finalized logical run and settles its recursive cost tree.
|
|
1402
|
+
*
|
|
1403
|
+
* The attempt row is already durable before this method runs. Persisting the
|
|
1404
|
+
* provider-finalized marker before credit settlement lets a queued retry resume
|
|
1405
|
+
* settlement without making another provider request.
|
|
1406
|
+
*
|
|
1407
|
+
* @param state - Logical root persistence state.
|
|
1408
|
+
* @param input - Final output and successful attempt identity.
|
|
1409
|
+
* @returns Settled application-credit charge and recorded provider cost.
|
|
1410
|
+
*/
|
|
1411
|
+
async completeTrackedRun(state, input) {
|
|
1412
|
+
const response = {
|
|
1413
|
+
finalOutput: input.finalOutput,
|
|
1414
|
+
citations: input.citations,
|
|
1415
|
+
lastResponseId: input.lastResponseId,
|
|
1416
|
+
traceId: state.traceId,
|
|
1417
|
+
providerFinalized: true,
|
|
1418
|
+
successfulAttemptAiRequestId: input.successfulAttemptAiRequestId,
|
|
1419
|
+
...(input.structuredOutput !== undefined ? { structuredOutput: input.structuredOutput } : {}),
|
|
1420
|
+
...(input.outputMetadata ? { outputMetadata: input.outputMetadata } : {}),
|
|
1421
|
+
};
|
|
1422
|
+
state.rootAiRequest.assign({
|
|
1423
|
+
response,
|
|
1424
|
+
status: AI_REQUEST_STATUS.pending,
|
|
1425
|
+
completedAt: null,
|
|
1426
|
+
durationMs: Date.now() - state.startTimeMs,
|
|
1427
|
+
inputTokens: null,
|
|
1428
|
+
outputTokens: null,
|
|
1429
|
+
totalTokens: null,
|
|
1430
|
+
reasoningTokens: null,
|
|
1431
|
+
cachedTokens: null,
|
|
1432
|
+
cacheWriteTokens: null,
|
|
1433
|
+
costUSD: 0,
|
|
1434
|
+
knownCostUSD: 0,
|
|
1435
|
+
errorCode: null,
|
|
1436
|
+
errorMessage: null,
|
|
1437
|
+
metadata: withoutOpenAIQuotaRetryMetadata(state.rootAiRequest.metadata),
|
|
1438
|
+
});
|
|
1439
|
+
await state.rootAiRequest.save();
|
|
1440
|
+
return await this.settleFinalizedTrackedRun(state);
|
|
1441
|
+
}
|
|
1442
|
+
/** Controls whether streamed events expose provider costs to this viewer. */
|
|
1443
|
+
exposeProviderCosts() { return false; }
|
|
1444
|
+
/** Aggregates provider usage; applications may extend this hook to settle their own credit ledger. */
|
|
1445
|
+
async settleUsage(rootAiRequest, _initialCharge) {
|
|
1446
|
+
const run = await app().ai.models.request.runCostSummary(String(rootAiRequest.id));
|
|
1447
|
+
if (!run)
|
|
1448
|
+
throw new Error('Tracked AI request tree is missing.');
|
|
1449
|
+
return { run, creditCost: null };
|
|
1450
|
+
}
|
|
1451
|
+
/**
|
|
1452
|
+
* Settles and completes a root whose provider attempts are already durable.
|
|
1453
|
+
*
|
|
1454
|
+
* @param state - Logical root persistence state.
|
|
1455
|
+
* @returns Recursive usage, settled credits, and complete provider cost.
|
|
1456
|
+
*/
|
|
1457
|
+
async settleFinalizedTrackedRun(state) {
|
|
1458
|
+
const settlement = await this.settleUsage(state.rootAiRequest, this.billableUsageCharge());
|
|
1459
|
+
const run = settlement.run;
|
|
1460
|
+
const usage = {
|
|
1461
|
+
requests: run.providerRequestCount,
|
|
1462
|
+
inputTokens: run.inputTokens,
|
|
1463
|
+
outputTokens: run.outputTokens,
|
|
1464
|
+
totalTokens: run.totalTokens,
|
|
1465
|
+
reasoningTokens: run.reasoningTokens,
|
|
1466
|
+
cachedTokens: run.cachedTokens,
|
|
1467
|
+
cacheWriteTokens: run.cacheWriteTokens,
|
|
1468
|
+
};
|
|
1469
|
+
const response = recordValue(state.rootAiRequest.response) ?? {};
|
|
1470
|
+
const lastResponseId = stringValue(response.lastResponseId);
|
|
1471
|
+
state.rootAiRequest.assign({
|
|
1472
|
+
status: AI_REQUEST_STATUS.completed,
|
|
1473
|
+
completedAt: new Date(),
|
|
1474
|
+
errorCode: null,
|
|
1475
|
+
errorMessage: null,
|
|
1476
|
+
costUSD: 0,
|
|
1477
|
+
knownCostUSD: 0,
|
|
1478
|
+
response: {
|
|
1479
|
+
...response,
|
|
1480
|
+
usage,
|
|
1481
|
+
cost: {
|
|
1482
|
+
rootCostUSD: run.rootCostUSD,
|
|
1483
|
+
childCostUSD: run.childCostUSD,
|
|
1484
|
+
totalCostUSD: run.totalCostUSD,
|
|
1485
|
+
requestCount: run.requestCount,
|
|
1486
|
+
providerRequestCount: run.providerRequestCount,
|
|
1487
|
+
unpricedRequestCount: run.unpricedRequestCount,
|
|
1488
|
+
creditCost: settlement.creditCost,
|
|
1489
|
+
},
|
|
1490
|
+
},
|
|
1491
|
+
});
|
|
1492
|
+
await state.rootAiRequest.save();
|
|
1493
|
+
await this.touchConversation(state, {
|
|
1494
|
+
lastTraceId: state.traceId,
|
|
1495
|
+
lastResponseId,
|
|
1496
|
+
lastStatus: AI_REQUEST_STATUS.completed,
|
|
1497
|
+
lastError: null,
|
|
1498
|
+
nextRetryAt: null,
|
|
1499
|
+
retryUntil: null,
|
|
1500
|
+
});
|
|
1501
|
+
return {
|
|
1502
|
+
usage,
|
|
1503
|
+
creditCost: settlement.creditCost,
|
|
1504
|
+
costUSD: run.unpricedRequestCount > 0 ? null : run.totalCostUSD,
|
|
1505
|
+
};
|
|
1506
|
+
}
|
|
1507
|
+
/**
|
|
1508
|
+
* Keeps a quota-blocked queued run pending and records its next retry.
|
|
1509
|
+
*
|
|
1510
|
+
* @param state - Active run persistence state.
|
|
1511
|
+
* @param quotaRetry - Bounded exponential quota retry decision.
|
|
1512
|
+
*/
|
|
1513
|
+
async deferTrackedRun(state, quotaRetry) {
|
|
1514
|
+
state.aiRequest.assign({
|
|
1515
|
+
status: AI_REQUEST_STATUS.pending,
|
|
1516
|
+
completedAt: null,
|
|
1517
|
+
durationMs: null,
|
|
1518
|
+
errorCode: quotaRetry.code,
|
|
1519
|
+
errorMessage: quotaRetry.message,
|
|
1520
|
+
metadata: withOpenAIQuotaRetryMetadata(state.aiRequest.metadata, quotaRetry.metadata),
|
|
1521
|
+
});
|
|
1522
|
+
await state.aiRequest.save();
|
|
1523
|
+
await this.touchConversation(state, {
|
|
1524
|
+
lastTraceId: state.traceId,
|
|
1525
|
+
lastStatus: AI_REQUEST_STATUS.pending,
|
|
1526
|
+
lastError: quotaRetry.message,
|
|
1527
|
+
nextRetryAt: quotaRetry.retryAt.toISOString(),
|
|
1528
|
+
retryUntil: quotaRetry.retryUntil.toISOString(),
|
|
1529
|
+
});
|
|
1530
|
+
}
|
|
1531
|
+
/**
|
|
1532
|
+
* Marks the tracked AI request as failed.
|
|
1533
|
+
*
|
|
1534
|
+
* @param state - Active run persistence state.
|
|
1535
|
+
* @param message - Failure message to persist.
|
|
1536
|
+
* @param errorCode - Provider error code, when available.
|
|
1537
|
+
*/
|
|
1538
|
+
async failTrackedRun(state, message, errorCode = null) {
|
|
1539
|
+
state.aiRequest.assign({
|
|
1540
|
+
status: AI_REQUEST_STATUS.failed,
|
|
1541
|
+
completedAt: new Date(),
|
|
1542
|
+
durationMs: Date.now() - state.startTimeMs,
|
|
1543
|
+
errorCode,
|
|
1544
|
+
errorMessage: message,
|
|
1545
|
+
response: {
|
|
1546
|
+
...(recordValue(state.aiRequest.response) ?? {}),
|
|
1547
|
+
traceId: state.traceId,
|
|
1548
|
+
error: message,
|
|
1549
|
+
},
|
|
1550
|
+
});
|
|
1551
|
+
await state.aiRequest.save();
|
|
1552
|
+
await this.touchConversation(state, {
|
|
1553
|
+
lastTraceId: state.traceId,
|
|
1554
|
+
lastStatus: AI_REQUEST_STATUS.failed,
|
|
1555
|
+
lastError: message,
|
|
1556
|
+
nextRetryAt: null,
|
|
1557
|
+
});
|
|
1558
|
+
}
|
|
1559
|
+
/**
|
|
1560
|
+
* Touches the conversation row so history sorting reflects the latest agent turn.
|
|
1561
|
+
*
|
|
1562
|
+
* Agent-owned scope metadata is reapplied on every update so lifecycle fields
|
|
1563
|
+
* cannot erase the stable identity used by workflow-specific history lookups.
|
|
1564
|
+
*
|
|
1565
|
+
* @param state - Active run persistence state.
|
|
1566
|
+
* @param metadata - Metadata fields to merge onto the conversation.
|
|
1567
|
+
* @returns Nothing after the conversation metadata is persisted.
|
|
1568
|
+
*/
|
|
1569
|
+
async touchConversation(state, metadata) {
|
|
1570
|
+
state.conversation.assign({
|
|
1571
|
+
metadata: {
|
|
1572
|
+
...(state.conversation.metadata ?? {}),
|
|
1573
|
+
...this.conversationMetadata(),
|
|
1574
|
+
...metadata,
|
|
1575
|
+
},
|
|
1576
|
+
});
|
|
1577
|
+
await state.conversation.save();
|
|
1578
|
+
}
|
|
1579
|
+
/**
|
|
1580
|
+
* Loads the previous conversation flow for prompt continuity.
|
|
1581
|
+
*
|
|
1582
|
+
* @param conversation - Conversation to read from.
|
|
1583
|
+
* @param excludeAiRequestId - Current run request id to exclude when a queued run resumes.
|
|
1584
|
+
* @returns Previous turns and tool events in provider-compatible input shape.
|
|
1585
|
+
*/
|
|
1586
|
+
async previousMessages(conversation, excludeAiRequestId = null) {
|
|
1587
|
+
if (!conversation.id)
|
|
1588
|
+
return [];
|
|
1589
|
+
const messages = await app().ai.models.message
|
|
1590
|
+
.where('conversation', String(conversation.id))
|
|
1591
|
+
.orderBy('sequence', 'desc')
|
|
1592
|
+
.limit((this.maxPreviousMessages * 2) + 12)
|
|
1593
|
+
.all();
|
|
1594
|
+
const replayMessages = messages
|
|
1595
|
+
.reverse()
|
|
1596
|
+
.filter(message => !excludeAiRequestId || entityRefId(message.aiRequest) !== excludeAiRequestId);
|
|
1597
|
+
const unresolvedCallIds = unresolvedToolCallIds(replayMessages);
|
|
1598
|
+
const seenToolCallIds = new Set();
|
|
1599
|
+
return replayMessages
|
|
1600
|
+
.flatMap(message => agentInputItemsFromAiMessage(message, seenToolCallIds, unresolvedCallIds))
|
|
1601
|
+
.slice(-this.maxPreviousMessages);
|
|
1602
|
+
}
|
|
1603
|
+
/**
|
|
1604
|
+
* Builds the queue payload for a prepared background run.
|
|
1605
|
+
*
|
|
1606
|
+
* @param prepared - Prepared run state.
|
|
1607
|
+
* @param serializedAgent - Versioned constructor-state envelope.
|
|
1608
|
+
* @returns Queue-safe payload.
|
|
1609
|
+
*/
|
|
1610
|
+
queuedRunPayload(prepared, serializedAgent) {
|
|
1611
|
+
return {
|
|
1612
|
+
agentName: this.agentName,
|
|
1613
|
+
agent: serializedAgent,
|
|
1614
|
+
message: prepared.message,
|
|
1615
|
+
metadata: this.queueMetadata(),
|
|
1616
|
+
conversationId: String(prepared.state.conversation.id),
|
|
1617
|
+
aiRequestId: prepared.state.aiRequest.id ? String(prepared.state.aiRequest.id) : null,
|
|
1618
|
+
traceId: prepared.traceId,
|
|
1619
|
+
model: prepared.model,
|
|
1620
|
+
};
|
|
1621
|
+
}
|
|
1622
|
+
/**
|
|
1623
|
+
* Stores the queue job id on the pending AI request for debugging.
|
|
1624
|
+
*
|
|
1625
|
+
* @param state - Active run persistence state.
|
|
1626
|
+
* @param jobId - Queue job id returned by the queue driver.
|
|
1627
|
+
*/
|
|
1628
|
+
async markQueued(state, jobId) {
|
|
1629
|
+
state.aiRequest.assign({
|
|
1630
|
+
request: {
|
|
1631
|
+
...(recordValue(state.aiRequest.request) ?? {}),
|
|
1632
|
+
queueJobId: jobId,
|
|
1633
|
+
},
|
|
1634
|
+
metadata: {
|
|
1635
|
+
...(state.aiRequest.metadata ?? {}),
|
|
1636
|
+
queueJobId: jobId,
|
|
1637
|
+
},
|
|
1638
|
+
});
|
|
1639
|
+
await state.aiRequest.save();
|
|
1640
|
+
}
|
|
1641
|
+
/**
|
|
1642
|
+
* Returns the public tool definition for a tool name.
|
|
1643
|
+
*
|
|
1644
|
+
* @param state - Active run carrying metadata derived from its configured tools.
|
|
1645
|
+
* @param toolName - SDK or hosted tool name.
|
|
1646
|
+
* @returns Public tool definition, or null when unavailable.
|
|
1647
|
+
*/
|
|
1648
|
+
toolDefinition(state, toolName) {
|
|
1649
|
+
return state.toolDefinitions.find(definition => definition.name === toolName) ?? null;
|
|
1650
|
+
}
|
|
1651
|
+
/**
|
|
1652
|
+
* Returns the active user id as a string.
|
|
1653
|
+
*
|
|
1654
|
+
* @returns Active user id, or an empty string when unavailable.
|
|
1655
|
+
*/
|
|
1656
|
+
userId() {
|
|
1657
|
+
return contextIdentity(this.context.user);
|
|
1658
|
+
}
|
|
1659
|
+
/**
|
|
1660
|
+
* Returns the active application scope id as a string.
|
|
1661
|
+
*
|
|
1662
|
+
* @returns Active application scope id.
|
|
1663
|
+
*/
|
|
1664
|
+
scopeId() {
|
|
1665
|
+
return contextIdentity(this.context.scope);
|
|
1666
|
+
}
|
|
1667
|
+
}
|
|
1668
|
+
/**
|
|
1669
|
+
* Restores local capacity deferrals wrapped as connection failures by the SDK.
|
|
1670
|
+
*
|
|
1671
|
+
* @param error - SDK or application failure from an agent turn.
|
|
1672
|
+
* @returns Original limiter deferral, or the unchanged failure for normal handling.
|
|
1673
|
+
*/
|
|
1674
|
+
function agentRateLimitError(error) {
|
|
1675
|
+
const seen = new Set();
|
|
1676
|
+
let current = error;
|
|
1677
|
+
while (current instanceof Error && !seen.has(current)) {
|
|
1678
|
+
if (current instanceof AIRateLimitDeferredError)
|
|
1679
|
+
return current;
|
|
1680
|
+
seen.add(current);
|
|
1681
|
+
current = current.cause;
|
|
1682
|
+
}
|
|
1683
|
+
return error;
|
|
1684
|
+
}
|
|
1685
|
+
/**
|
|
1686
|
+
* Builds frontend-safe metadata from the executable tools returned by an agent.
|
|
1687
|
+
*
|
|
1688
|
+
* @param tools - Executable tools configured for one agent invocation.
|
|
1689
|
+
* @returns Serializable definitions in provider tool order.
|
|
1690
|
+
*/
|
|
1691
|
+
function agentToolDefinitions(tools) {
|
|
1692
|
+
return tools.map(tool => ({
|
|
1693
|
+
name: tool.name,
|
|
1694
|
+
title: tool.title,
|
|
1695
|
+
description: tool.description,
|
|
1696
|
+
}));
|
|
1697
|
+
}
|
|
1698
|
+
/**
|
|
1699
|
+
* Captures the exact Responses request prepared by the Agents SDK Runner.
|
|
1700
|
+
*
|
|
1701
|
+
* The capturing model invokes the OpenAI provider's own request builder and
|
|
1702
|
+
* stops before transport. Awaiting the Runner is important because its request
|
|
1703
|
+
* preparation includes enabled-tool serialization, output-schema conversion,
|
|
1704
|
+
* and model-specific default settings.
|
|
1705
|
+
*
|
|
1706
|
+
* @param preview - Shared SDK Agent, input, context, and model configuration.
|
|
1707
|
+
* @returns JSON-safe `responses.create` request body.
|
|
1708
|
+
*/
|
|
1709
|
+
async function openAIResponseRequestBody(preview) {
|
|
1710
|
+
const [{ OpenAIResponsesModel }, { default: OpenAI }] = await Promise.all([
|
|
1711
|
+
import('@openai/agents'),
|
|
1712
|
+
import('openai'),
|
|
1713
|
+
]);
|
|
1714
|
+
const requestCaptured = new Error('OpenAI request preview captured.');
|
|
1715
|
+
let requestBody = null;
|
|
1716
|
+
/**
|
|
1717
|
+
* Request-only model that stops before the OpenAI transport call.
|
|
1718
|
+
*/
|
|
1719
|
+
class OpenAIRequestPreviewModel extends OpenAIResponsesModel {
|
|
1720
|
+
/**
|
|
1721
|
+
* Captures the JSON body passed to the OpenAI Responses client.
|
|
1722
|
+
*
|
|
1723
|
+
* @param request - Complete ModelRequest prepared by the SDK Runner.
|
|
1724
|
+
* @returns Async iterable that stops with the private capture sentinel.
|
|
1725
|
+
*/
|
|
1726
|
+
async *getStreamedResponse(request) {
|
|
1727
|
+
const built = this._buildResponsesCreateRequest(request, true);
|
|
1728
|
+
requestBody = JSON.parse(JSON.stringify(built.requestData));
|
|
1729
|
+
throw requestCaptured;
|
|
1730
|
+
}
|
|
1731
|
+
}
|
|
1732
|
+
const previewModel = new OpenAIRequestPreviewModel(new OpenAI({ apiKey: 'dry-run-request-preview' }), preview.model);
|
|
1733
|
+
const runner = new Runner({
|
|
1734
|
+
model: preview.model,
|
|
1735
|
+
modelProvider: {
|
|
1736
|
+
/**
|
|
1737
|
+
* Returns the request-capturing model instead of a transport model.
|
|
1738
|
+
*
|
|
1739
|
+
* @returns OpenAI Responses model that stops before network transport.
|
|
1740
|
+
*/
|
|
1741
|
+
async getModel() {
|
|
1742
|
+
return previewModel;
|
|
1743
|
+
},
|
|
1744
|
+
},
|
|
1745
|
+
modelSettings: preview.modelSettings,
|
|
1746
|
+
tracingDisabled: true,
|
|
1747
|
+
traceIncludeSensitiveData: false,
|
|
1748
|
+
});
|
|
1749
|
+
const stream = await runner.run(preview.agent, preview.input, {
|
|
1750
|
+
stream: true,
|
|
1751
|
+
context: preview.context,
|
|
1752
|
+
maxTurns: preview.maxTurns,
|
|
1753
|
+
reasoningItemIdPolicy: 'preserve',
|
|
1754
|
+
});
|
|
1755
|
+
try {
|
|
1756
|
+
await stream.completed;
|
|
1757
|
+
}
|
|
1758
|
+
catch (error) {
|
|
1759
|
+
if (error !== requestCaptured)
|
|
1760
|
+
throw error;
|
|
1761
|
+
}
|
|
1762
|
+
if (requestBody === null) {
|
|
1763
|
+
throw new Error('The Agents SDK did not prepare an OpenAI request preview.');
|
|
1764
|
+
}
|
|
1765
|
+
return requestBody;
|
|
1766
|
+
}
|
|
1767
|
+
/**
|
|
1768
|
+
* Accepts stream events when the caller does not need live output.
|
|
1769
|
+
*/
|
|
1770
|
+
async function noopAgentEventSink() { }
|
|
1771
|
+
/**
|
|
1772
|
+
* Raised when a user asks for an inaccessible agent conversation.
|
|
1773
|
+
*/
|
|
1774
|
+
export class AgentAuthorizationError extends Error {
|
|
1775
|
+
/**
|
|
1776
|
+
* Creates an agent authorization error.
|
|
1777
|
+
*
|
|
1778
|
+
* @param message - Public error message.
|
|
1779
|
+
*/
|
|
1780
|
+
constructor(message) {
|
|
1781
|
+
super(message);
|
|
1782
|
+
this.name = 'AgentAuthorizationError';
|
|
1783
|
+
}
|
|
1784
|
+
}
|
|
1785
|
+
/**
|
|
1786
|
+
* Returns the next message sequence for a conversation.
|
|
1787
|
+
*
|
|
1788
|
+
* @param conversation - Conversation to append to.
|
|
1789
|
+
* @returns Next message sequence number.
|
|
1790
|
+
*/
|
|
1791
|
+
async function nextMessageSequence(conversation) {
|
|
1792
|
+
if (!conversation.id)
|
|
1793
|
+
return 1;
|
|
1794
|
+
const lastMessage = await app().ai.models.message
|
|
1795
|
+
.where('conversation', String(conversation.id))
|
|
1796
|
+
.orderBy('sequence', 'desc')
|
|
1797
|
+
.first();
|
|
1798
|
+
return (lastMessage?.sequence ?? 0) + 1;
|
|
1799
|
+
}
|
|
1800
|
+
/**
|
|
1801
|
+
* Normalizes link-field entity refs to their string id.
|
|
1802
|
+
*
|
|
1803
|
+
* @param value - Unknown entity reference value.
|
|
1804
|
+
* @returns Entity id string or null.
|
|
1805
|
+
*/
|
|
1806
|
+
function entityRefId(value) {
|
|
1807
|
+
if (typeof value === 'string')
|
|
1808
|
+
return value;
|
|
1809
|
+
if (!value || typeof value !== 'object')
|
|
1810
|
+
return null;
|
|
1811
|
+
const id = value.id;
|
|
1812
|
+
return id === null || id === undefined ? null : String(id);
|
|
1813
|
+
}
|
|
1814
|
+
/**
|
|
1815
|
+
* Converts raw model stream records into text, reasoning, or hosted-tool events.
|
|
1816
|
+
*
|
|
1817
|
+
* @param record - Raw SDK model stream record.
|
|
1818
|
+
* @param toolDefinitions - Public tool definitions available to the active agent.
|
|
1819
|
+
* @returns Normalized stream event, or null when ignored.
|
|
1820
|
+
*/
|
|
1821
|
+
function rawModelStreamRecordEvent(record, toolDefinitions) {
|
|
1822
|
+
if (record.type === 'response.reasoning_summary_text.delta') {
|
|
1823
|
+
const id = reasoningSummaryEventId(record);
|
|
1824
|
+
const delta = stringValue(record.delta);
|
|
1825
|
+
return id && delta ? { type: 'reasoning.summary.delta', id, delta } : null;
|
|
1826
|
+
}
|
|
1827
|
+
if (record.type !== 'response.output_text.delta' && record.type !== 'output_text_delta') {
|
|
1828
|
+
return rawHostedToolStreamEvent(record, toolDefinitions);
|
|
1829
|
+
}
|
|
1830
|
+
const delta = stringValue(record.delta);
|
|
1831
|
+
return delta ? { type: 'text.delta', delta } : null;
|
|
1832
|
+
}
|
|
1833
|
+
/**
|
|
1834
|
+
* Builds a stable timeline id for one reasoning summary stream item.
|
|
1835
|
+
*
|
|
1836
|
+
* @param record - Raw Responses reasoning summary stream event.
|
|
1837
|
+
* @returns Stable summary id, or null when the event has no item id.
|
|
1838
|
+
*/
|
|
1839
|
+
function reasoningSummaryEventId(record) {
|
|
1840
|
+
const itemId = stringValue(record.item_id) || stringValue(record.itemId);
|
|
1841
|
+
const summaryIndex = typeof record.summary_index === 'number' ? record.summary_index : record.summaryIndex;
|
|
1842
|
+
if (!itemId)
|
|
1843
|
+
return null;
|
|
1844
|
+
return `${itemId}:${typeof summaryIndex === 'number' ? summaryIndex : 0}`;
|
|
1845
|
+
}
|
|
1846
|
+
/**
|
|
1847
|
+
* Converts raw Responses hosted-tool lifecycle events into tool-card updates.
|
|
1848
|
+
*
|
|
1849
|
+
* @param record - Raw hosted-tool stream record.
|
|
1850
|
+
* @param toolDefinitions - Public tool definitions available to the active agent.
|
|
1851
|
+
* @returns Normalized stream event, or null when ignored.
|
|
1852
|
+
*/
|
|
1853
|
+
function rawHostedToolStreamEvent(record, toolDefinitions) {
|
|
1854
|
+
const eventType = stringValue(record.type);
|
|
1855
|
+
const outputItem = recordValue(record.item);
|
|
1856
|
+
const outputItemToolName = hostedToolNameFromRawItem(outputItem);
|
|
1857
|
+
if (eventType === 'response.output_item.added' && outputItemToolName) {
|
|
1858
|
+
return {
|
|
1859
|
+
type: 'tool.calling',
|
|
1860
|
+
id: rawHostedToolItemCallId(outputItem, outputItemToolName),
|
|
1861
|
+
toolName: outputItemToolName,
|
|
1862
|
+
arguments: rawHostedToolItemArguments(outputItem),
|
|
1863
|
+
toolDefinition: toolDefinitions.find(definition => definition.name === outputItemToolName) ?? null,
|
|
1864
|
+
};
|
|
1865
|
+
}
|
|
1866
|
+
if (eventType === 'response.output_item.done' && outputItemToolName) {
|
|
1867
|
+
const callId = rawHostedToolItemCallId(outputItem, outputItemToolName);
|
|
1868
|
+
const status = stringValue(outputItem?.status);
|
|
1869
|
+
if (status === 'failed' || status === 'incomplete') {
|
|
1870
|
+
return {
|
|
1871
|
+
type: 'tool.error',
|
|
1872
|
+
id: callId,
|
|
1873
|
+
toolName: outputItemToolName,
|
|
1874
|
+
arguments: rawHostedToolItemArguments(outputItem),
|
|
1875
|
+
error: {
|
|
1876
|
+
message: `${outputItemToolName} ${status}.`,
|
|
1877
|
+
details: outputItem,
|
|
1878
|
+
},
|
|
1879
|
+
};
|
|
1880
|
+
}
|
|
1881
|
+
return {
|
|
1882
|
+
type: 'tool.success',
|
|
1883
|
+
id: callId,
|
|
1884
|
+
toolName: outputItemToolName,
|
|
1885
|
+
arguments: rawHostedToolItemArguments(outputItem),
|
|
1886
|
+
result: outputItem,
|
|
1887
|
+
};
|
|
1888
|
+
}
|
|
1889
|
+
const toolName = hostedToolNameFromRawEvent(eventType);
|
|
1890
|
+
if (!eventType || !toolName)
|
|
1891
|
+
return null;
|
|
1892
|
+
const callId = rawHostedToolCallId(record, toolName);
|
|
1893
|
+
const result = rawHostedToolResult(record);
|
|
1894
|
+
if (eventType.endsWith('.completed')) {
|
|
1895
|
+
return {
|
|
1896
|
+
type: 'tool.success',
|
|
1897
|
+
id: callId,
|
|
1898
|
+
toolName,
|
|
1899
|
+
result,
|
|
1900
|
+
};
|
|
1901
|
+
}
|
|
1902
|
+
if (eventType.endsWith('.failed')) {
|
|
1903
|
+
return {
|
|
1904
|
+
type: 'tool.error',
|
|
1905
|
+
id: callId,
|
|
1906
|
+
toolName,
|
|
1907
|
+
error: {
|
|
1908
|
+
message: 'The hosted tool failed.',
|
|
1909
|
+
details: result,
|
|
1910
|
+
},
|
|
1911
|
+
};
|
|
1912
|
+
}
|
|
1913
|
+
if (eventType.endsWith('.in_progress')) {
|
|
1914
|
+
return {
|
|
1915
|
+
type: 'tool.calling',
|
|
1916
|
+
id: callId,
|
|
1917
|
+
toolName,
|
|
1918
|
+
arguments: rawHostedToolArguments(record),
|
|
1919
|
+
toolDefinition: toolDefinitions.find(definition => definition.name === toolName) ?? null,
|
|
1920
|
+
};
|
|
1921
|
+
}
|
|
1922
|
+
return {
|
|
1923
|
+
type: 'tool.progress',
|
|
1924
|
+
id: callId,
|
|
1925
|
+
toolName,
|
|
1926
|
+
progress: {
|
|
1927
|
+
id: `${callId}:${eventType}`,
|
|
1928
|
+
message: rawHostedToolProgressMessage(eventType),
|
|
1929
|
+
data: rawHostedToolProgressData(record),
|
|
1930
|
+
createdAt: new Date().toISOString(),
|
|
1931
|
+
},
|
|
1932
|
+
};
|
|
1933
|
+
}
|
|
1934
|
+
/**
|
|
1935
|
+
* Extracts the raw model item from an Agents SDK run item.
|
|
1936
|
+
*
|
|
1937
|
+
* @param item - SDK run item.
|
|
1938
|
+
* @returns Raw model item record or null.
|
|
1939
|
+
*/
|
|
1940
|
+
function rawItemFromRunItem(item) {
|
|
1941
|
+
const record = recordValue(item);
|
|
1942
|
+
return recordValue(record?.rawItem);
|
|
1943
|
+
}
|
|
1944
|
+
/**
|
|
1945
|
+
* Extracts a tool output payload from an Agents SDK run item.
|
|
1946
|
+
*
|
|
1947
|
+
* @param item - SDK run item.
|
|
1948
|
+
* @param rawItem - Raw model item record.
|
|
1949
|
+
* @returns Tool output payload.
|
|
1950
|
+
*/
|
|
1951
|
+
function outputFromRunItem(item, rawItem) {
|
|
1952
|
+
const record = recordValue(item);
|
|
1953
|
+
if (record && 'output' in record && record.output !== undefined && record.output !== null)
|
|
1954
|
+
return record.output;
|
|
1955
|
+
if (rawItem && 'output' in rawItem && rawItem.output !== undefined && rawItem.output !== null)
|
|
1956
|
+
return rawItem.output;
|
|
1957
|
+
if (rawItem?.providerData)
|
|
1958
|
+
return rawItem.providerData;
|
|
1959
|
+
return rawItem;
|
|
1960
|
+
}
|
|
1961
|
+
/**
|
|
1962
|
+
* Returns a stable id for a tool call.
|
|
1963
|
+
*
|
|
1964
|
+
* @param rawItem - Raw SDK item.
|
|
1965
|
+
* @param fallback - Fallback id when the SDK item has no id.
|
|
1966
|
+
* @returns Stable tool call id.
|
|
1967
|
+
*/
|
|
1968
|
+
function toolCallId(rawItem, fallback) {
|
|
1969
|
+
return stringValue(rawItem?.callId) || stringValue(rawItem?.call_id) || stringValue(rawItem?.id) || fallback;
|
|
1970
|
+
}
|
|
1971
|
+
/**
|
|
1972
|
+
* Reads the tool name from a function-call result when available.
|
|
1973
|
+
*
|
|
1974
|
+
* @param rawItem - Raw SDK item.
|
|
1975
|
+
* @returns Tool name or null.
|
|
1976
|
+
*/
|
|
1977
|
+
function outputToolName(rawItem) {
|
|
1978
|
+
return stringValue(rawItem?.name);
|
|
1979
|
+
}
|
|
1980
|
+
/**
|
|
1981
|
+
* Extracts the best available tool arguments for local and hosted tool calls.
|
|
1982
|
+
*
|
|
1983
|
+
* @param rawItem - Raw SDK item.
|
|
1984
|
+
* @returns Tool arguments.
|
|
1985
|
+
*/
|
|
1986
|
+
function toolArguments(rawItem) {
|
|
1987
|
+
const providerData = recordValue(rawItem?.providerData);
|
|
1988
|
+
const providerAction = providerData?.action ?? providerData?.query ?? providerData?.queries;
|
|
1989
|
+
return parseToolArguments(rawItem?.arguments ?? providerAction ?? {});
|
|
1990
|
+
}
|
|
1991
|
+
/**
|
|
1992
|
+
* Remembers non-empty tool arguments from the call item for later output items.
|
|
1993
|
+
*
|
|
1994
|
+
* @param state - Active run persistence state.
|
|
1995
|
+
* @param callId - Stable tool call id.
|
|
1996
|
+
* @param value - Parsed argument payload from the SDK item.
|
|
1997
|
+
*/
|
|
1998
|
+
function rememberToolArguments(state, callId, value) {
|
|
1999
|
+
if (!hasToolArguments(value))
|
|
2000
|
+
return;
|
|
2001
|
+
state.toolArgumentsByCallId[callId] = value;
|
|
2002
|
+
}
|
|
2003
|
+
/**
|
|
2004
|
+
* Returns output-item arguments, falling back to the matching call item.
|
|
2005
|
+
*
|
|
2006
|
+
* @param state - Active run persistence state.
|
|
2007
|
+
* @param callId - Stable tool call id.
|
|
2008
|
+
* @param value - Parsed output item argument payload.
|
|
2009
|
+
* @returns Best available arguments for the tool call.
|
|
2010
|
+
*/
|
|
2011
|
+
function toolOutputArguments(state, callId, value) {
|
|
2012
|
+
if (hasToolArguments(value)) {
|
|
2013
|
+
state.toolArgumentsByCallId[callId] = value;
|
|
2014
|
+
return value;
|
|
2015
|
+
}
|
|
2016
|
+
return state.toolArgumentsByCallId[callId] ?? value;
|
|
2017
|
+
}
|
|
2018
|
+
/**
|
|
2019
|
+
* Returns true when a parsed argument payload carries model-provided input.
|
|
2020
|
+
*
|
|
2021
|
+
* @param value - Parsed argument payload.
|
|
2022
|
+
* @returns True when the payload should replace existing arguments.
|
|
2023
|
+
*/
|
|
2024
|
+
function hasToolArguments(value) {
|
|
2025
|
+
if (value === undefined || value === null)
|
|
2026
|
+
return false;
|
|
2027
|
+
if (Array.isArray(value))
|
|
2028
|
+
return value.length > 0;
|
|
2029
|
+
const record = recordValue(value);
|
|
2030
|
+
if (record)
|
|
2031
|
+
return Object.keys(record).length > 0;
|
|
2032
|
+
return true;
|
|
2033
|
+
}
|
|
2034
|
+
/**
|
|
2035
|
+
* Parses a tool-call arguments value when the SDK supplies JSON text.
|
|
2036
|
+
*
|
|
2037
|
+
* @param value - Unknown arguments value.
|
|
2038
|
+
* @returns Parsed arguments value.
|
|
2039
|
+
*/
|
|
2040
|
+
function parseToolArguments(value) {
|
|
2041
|
+
if (typeof value !== 'string')
|
|
2042
|
+
return value ?? {};
|
|
2043
|
+
return parseJson(value) ?? value;
|
|
2044
|
+
}
|
|
2045
|
+
/**
|
|
2046
|
+
* Parses a function-tool output value into the result shape returned by the tool.
|
|
2047
|
+
*
|
|
2048
|
+
* @param value - Unknown tool output value.
|
|
2049
|
+
* @returns Parsed tool output value.
|
|
2050
|
+
*/
|
|
2051
|
+
function parseToolOutput(value) {
|
|
2052
|
+
const structuredResult = agentToolResultFromStructuredOutput(value);
|
|
2053
|
+
if (structuredResult !== null)
|
|
2054
|
+
return structuredResult;
|
|
2055
|
+
if (typeof value !== 'string')
|
|
2056
|
+
return value;
|
|
2057
|
+
return parseJson(value) ?? value;
|
|
2058
|
+
}
|
|
2059
|
+
/**
|
|
2060
|
+
* Returns a tool-level error message when the tool result reports one.
|
|
2061
|
+
*
|
|
2062
|
+
* @param value - Parsed tool output value.
|
|
2063
|
+
* @returns Error message or null.
|
|
2064
|
+
*/
|
|
2065
|
+
function toolResultErrorMessage(value) {
|
|
2066
|
+
const record = recordValue(value);
|
|
2067
|
+
if (record?.status !== 'error')
|
|
2068
|
+
return null;
|
|
2069
|
+
return stringValue(record.message) ?? 'The tool failed.';
|
|
2070
|
+
}
|
|
2071
|
+
/**
|
|
2072
|
+
* Returns a hosted-tool error when the provider marks the call as failed.
|
|
2073
|
+
*
|
|
2074
|
+
* @param rawItem - Raw SDK item.
|
|
2075
|
+
* @returns Hosted tool error message or null.
|
|
2076
|
+
*/
|
|
2077
|
+
function hostedToolErrorMessage(rawItem) {
|
|
2078
|
+
const status = stringValue(rawItem?.status);
|
|
2079
|
+
if (status !== 'failed' && status !== 'incomplete')
|
|
2080
|
+
return null;
|
|
2081
|
+
return `${stringValue(rawItem?.name) ?? 'Hosted tool'} ${status}.`;
|
|
2082
|
+
}
|
|
2083
|
+
/**
|
|
2084
|
+
* Returns true when a hosted tool call item already contains its final status.
|
|
2085
|
+
*
|
|
2086
|
+
* @param rawItem - Raw SDK item.
|
|
2087
|
+
* @returns True when the hosted tool has completed.
|
|
2088
|
+
*/
|
|
2089
|
+
function hostedToolCompleted(rawItem) {
|
|
2090
|
+
const status = rawItem?.status;
|
|
2091
|
+
return hostedToolNameFromRawItem(rawItem) !== null
|
|
2092
|
+
&& (status === 'completed' || status === 'failed' || status === 'incomplete');
|
|
2093
|
+
}
|
|
2094
|
+
/**
|
|
2095
|
+
* Maps raw Responses hosted-tool event names to the normalized tool name.
|
|
2096
|
+
*
|
|
2097
|
+
* @param eventType - Raw event type.
|
|
2098
|
+
* @returns Hosted tool name or null.
|
|
2099
|
+
*/
|
|
2100
|
+
function hostedToolNameFromRawEvent(eventType) {
|
|
2101
|
+
if (!eventType)
|
|
2102
|
+
return null;
|
|
2103
|
+
if (eventType.startsWith('response.web_search_call.'))
|
|
2104
|
+
return 'web_search_call';
|
|
2105
|
+
if (eventType.startsWith('response.image_generation_call.'))
|
|
2106
|
+
return 'image_generation_call';
|
|
2107
|
+
return null;
|
|
2108
|
+
}
|
|
2109
|
+
/**
|
|
2110
|
+
* Maps raw Responses output items to hosted tool names.
|
|
2111
|
+
*
|
|
2112
|
+
* @param item - Raw output item.
|
|
2113
|
+
* @returns Hosted tool name or null.
|
|
2114
|
+
*/
|
|
2115
|
+
function hostedToolNameFromRawItem(item) {
|
|
2116
|
+
const type = stringValue(item?.type);
|
|
2117
|
+
if (type === 'web_search_call')
|
|
2118
|
+
return 'web_search_call';
|
|
2119
|
+
if (type === 'image_generation_call')
|
|
2120
|
+
return 'image_generation_call';
|
|
2121
|
+
if (type === 'hosted_tool_call')
|
|
2122
|
+
return stringValue(item?.name);
|
|
2123
|
+
return null;
|
|
2124
|
+
}
|
|
2125
|
+
/**
|
|
2126
|
+
* Records one completed hosted provider-tool call on the active request.
|
|
2127
|
+
*
|
|
2128
|
+
* Web searches are recorded only for `search` actions because page opens are
|
|
2129
|
+
* included in history but are not separate billable calls. Other hosted tools
|
|
2130
|
+
* are retained so the pricing layer can either price them or mark the request
|
|
2131
|
+
* incomplete instead of silently omitting a provider charge.
|
|
2132
|
+
*
|
|
2133
|
+
* @param state - Active run persistence state.
|
|
2134
|
+
* @param toolName - Normalized hosted tool name.
|
|
2135
|
+
* @param callId - Stable provider call id used to prevent duplicate billing.
|
|
2136
|
+
* @param rawItem - Completed raw provider tool item.
|
|
2137
|
+
*/
|
|
2138
|
+
function recordHostedToolUsage(state, toolName, callId, rawItem) {
|
|
2139
|
+
if (!toolName)
|
|
2140
|
+
return;
|
|
2141
|
+
if (state.hostedToolCallIds.has(callId))
|
|
2142
|
+
return;
|
|
2143
|
+
if (toolName === 'web_search_call') {
|
|
2144
|
+
const providerData = recordValue(rawItem?.providerData);
|
|
2145
|
+
const action = recordValue(rawItem?.action) ?? recordValue(providerData?.action);
|
|
2146
|
+
if (stringValue(action?.type) !== 'search')
|
|
2147
|
+
return;
|
|
2148
|
+
}
|
|
2149
|
+
state.hostedToolCallIds.add(callId);
|
|
2150
|
+
state.hostedToolUsage[toolName] = (state.hostedToolUsage[toolName] ?? 0) + 1;
|
|
2151
|
+
}
|
|
2152
|
+
/**
|
|
2153
|
+
* Extracts a stable hosted-tool call id from a raw Responses output item.
|
|
2154
|
+
*
|
|
2155
|
+
* @param item - Raw output item.
|
|
2156
|
+
* @param toolName - Hosted tool name.
|
|
2157
|
+
* @returns Stable tool call id.
|
|
2158
|
+
*/
|
|
2159
|
+
function rawHostedToolItemCallId(item, toolName) {
|
|
2160
|
+
return stringValue(item?.id) || stringValue(item?.call_id) || stringValue(item?.callId) || toolName;
|
|
2161
|
+
}
|
|
2162
|
+
/**
|
|
2163
|
+
* Extracts hosted-tool arguments from a raw Responses output item.
|
|
2164
|
+
*
|
|
2165
|
+
* @param item - Raw output item.
|
|
2166
|
+
* @returns Hosted tool arguments.
|
|
2167
|
+
*/
|
|
2168
|
+
function rawHostedToolItemArguments(item) {
|
|
2169
|
+
return recordValue(item?.action) ?? item?.query ?? item?.queries ?? {};
|
|
2170
|
+
}
|
|
2171
|
+
/**
|
|
2172
|
+
* Extracts a stable hosted-tool call id from a raw Responses stream event.
|
|
2173
|
+
*
|
|
2174
|
+
* @param record - Raw stream event.
|
|
2175
|
+
* @param toolName - Hosted tool name.
|
|
2176
|
+
* @returns Stable tool call id.
|
|
2177
|
+
*/
|
|
2178
|
+
function rawHostedToolCallId(record, toolName) {
|
|
2179
|
+
return stringValue(record.item_id)
|
|
2180
|
+
|| stringValue(record.itemId)
|
|
2181
|
+
|| stringValue(record.id)
|
|
2182
|
+
|| `${toolName}:${String(record.output_index ?? record.sequence_number ?? 'active')}`;
|
|
2183
|
+
}
|
|
2184
|
+
/**
|
|
2185
|
+
* Extracts hosted-tool arguments from a raw Responses stream event.
|
|
2186
|
+
*
|
|
2187
|
+
* @param record - Raw stream event.
|
|
2188
|
+
* @returns Hosted tool arguments.
|
|
2189
|
+
*/
|
|
2190
|
+
function rawHostedToolArguments(record) {
|
|
2191
|
+
return recordValue(record.action) ?? recordValue(record.query) ?? {};
|
|
2192
|
+
}
|
|
2193
|
+
/**
|
|
2194
|
+
* Builds a compact hosted-tool result payload for raw completed events.
|
|
2195
|
+
*
|
|
2196
|
+
* @param record - Raw stream event.
|
|
2197
|
+
* @returns Compact hosted-tool result.
|
|
2198
|
+
*/
|
|
2199
|
+
function rawHostedToolResult(record) {
|
|
2200
|
+
const item = recordValue(record.item);
|
|
2201
|
+
return item ?? compactHostedToolRecord(record);
|
|
2202
|
+
}
|
|
2203
|
+
/**
|
|
2204
|
+
* Builds compact progress data for hosted tools without large binary previews.
|
|
2205
|
+
*
|
|
2206
|
+
* @param record - Raw stream event.
|
|
2207
|
+
* @returns Compact progress data.
|
|
2208
|
+
*/
|
|
2209
|
+
function rawHostedToolProgressData(record) {
|
|
2210
|
+
const data = compactHostedToolRecord(record);
|
|
2211
|
+
if ('partial_image_b64' in record) {
|
|
2212
|
+
data.hasPartialImage = true;
|
|
2213
|
+
}
|
|
2214
|
+
return data;
|
|
2215
|
+
}
|
|
2216
|
+
/**
|
|
2217
|
+
* Returns a user-facing hosted-tool progress message.
|
|
2218
|
+
*
|
|
2219
|
+
* @param eventType - Raw hosted-tool event type.
|
|
2220
|
+
* @returns Human-readable progress message.
|
|
2221
|
+
*/
|
|
2222
|
+
function rawHostedToolProgressMessage(eventType) {
|
|
2223
|
+
if (eventType.includes('.searching'))
|
|
2224
|
+
return 'Searching the web';
|
|
2225
|
+
if (eventType.includes('.generating'))
|
|
2226
|
+
return 'Generating image';
|
|
2227
|
+
if (eventType.includes('.partial_image'))
|
|
2228
|
+
return 'Receiving image preview';
|
|
2229
|
+
return 'Using hosted tool';
|
|
2230
|
+
}
|
|
2231
|
+
/**
|
|
2232
|
+
* Copies safe scalar hosted-tool fields for progress and generic result views.
|
|
2233
|
+
*
|
|
2234
|
+
* @param record - Raw hosted-tool record.
|
|
2235
|
+
* @returns Compact record without large binary fields.
|
|
2236
|
+
*/
|
|
2237
|
+
function compactHostedToolRecord(record) {
|
|
2238
|
+
const compact = {};
|
|
2239
|
+
for (const [key, value] of Object.entries(record)) {
|
|
2240
|
+
if (key === 'partial_image_b64')
|
|
2241
|
+
continue;
|
|
2242
|
+
if (value === null || ['string', 'number', 'boolean'].includes(typeof value)) {
|
|
2243
|
+
compact[key] = value;
|
|
2244
|
+
}
|
|
2245
|
+
}
|
|
2246
|
+
return compact;
|
|
2247
|
+
}
|
|
2248
|
+
/**
|
|
2249
|
+
* Parses JSON and returns null when the input is not valid JSON.
|
|
2250
|
+
*
|
|
2251
|
+
* @param value - JSON string to parse.
|
|
2252
|
+
* @returns Parsed value or null.
|
|
2253
|
+
*/
|
|
2254
|
+
function parseJson(value) {
|
|
2255
|
+
try {
|
|
2256
|
+
return JSON.parse(value);
|
|
2257
|
+
}
|
|
2258
|
+
catch {
|
|
2259
|
+
return null;
|
|
2260
|
+
}
|
|
2261
|
+
}
|
|
2262
|
+
/**
|
|
2263
|
+
* Creates a provider-compatible user message.
|
|
2264
|
+
*
|
|
2265
|
+
* @param content - Message text to send as user input.
|
|
2266
|
+
* @returns Agents SDK user message item.
|
|
2267
|
+
*/
|
|
2268
|
+
function userInputMessage(content) {
|
|
2269
|
+
return {
|
|
2270
|
+
type: 'message',
|
|
2271
|
+
role: AI_MESSAGE_ROLE.user,
|
|
2272
|
+
content,
|
|
2273
|
+
};
|
|
2274
|
+
}
|
|
2275
|
+
/**
|
|
2276
|
+
* Creates a provider-compatible assistant message from persisted text.
|
|
2277
|
+
*
|
|
2278
|
+
* @param content - Assistant text stored from an earlier run.
|
|
2279
|
+
* @returns Agents SDK assistant message item.
|
|
2280
|
+
*/
|
|
2281
|
+
function assistantInputMessage(content) {
|
|
2282
|
+
return {
|
|
2283
|
+
type: 'message',
|
|
2284
|
+
role: AI_MESSAGE_ROLE.assistant,
|
|
2285
|
+
status: 'completed',
|
|
2286
|
+
content: [
|
|
2287
|
+
{
|
|
2288
|
+
type: 'output_text',
|
|
2289
|
+
text: content,
|
|
2290
|
+
},
|
|
2291
|
+
],
|
|
2292
|
+
};
|
|
2293
|
+
}
|
|
2294
|
+
/**
|
|
2295
|
+
* Creates a provider-compatible system message for debug snapshots.
|
|
2296
|
+
*
|
|
2297
|
+
* @param content - System instruction text.
|
|
2298
|
+
* @returns Agents SDK system message item.
|
|
2299
|
+
*/
|
|
2300
|
+
function systemInputMessage(content) {
|
|
2301
|
+
return {
|
|
2302
|
+
type: 'message',
|
|
2303
|
+
role: AI_MESSAGE_ROLE.system,
|
|
2304
|
+
content,
|
|
2305
|
+
};
|
|
2306
|
+
}
|
|
2307
|
+
/**
|
|
2308
|
+
* Converts one persisted conversation row into SDK input items.
|
|
2309
|
+
*
|
|
2310
|
+
* Tool result rows require a matching call item. When the original call row is
|
|
2311
|
+
* outside the replay window, the result row carries enough normalized data to
|
|
2312
|
+
* synthesize the call immediately before the result.
|
|
2313
|
+
*
|
|
2314
|
+
* @param message - Persisted conversation row.
|
|
2315
|
+
* @param seenToolCallIds - Tool call ids already emitted into the replay input.
|
|
2316
|
+
* @param unresolvedCallIds - Calls that have no persisted terminal result.
|
|
2317
|
+
* @returns Provider-compatible input items for the row.
|
|
2318
|
+
*/
|
|
2319
|
+
function agentInputItemsFromAiMessage(message, seenToolCallIds, unresolvedCallIds) {
|
|
2320
|
+
if (message.role === AI_MESSAGE_ROLE.assistant) {
|
|
2321
|
+
return [assistantInputMessage(message.content ?? '')];
|
|
2322
|
+
}
|
|
2323
|
+
if (message.role === AI_MESSAGE_ROLE.user) {
|
|
2324
|
+
return [userInputMessage(message.content ?? '')];
|
|
2325
|
+
}
|
|
2326
|
+
if (message.role === AI_MESSAGE_ROLE.tool) {
|
|
2327
|
+
return toolInputItemsFromAiMessage(message, seenToolCallIds, unresolvedCallIds);
|
|
2328
|
+
}
|
|
2329
|
+
return [];
|
|
2330
|
+
}
|
|
2331
|
+
/**
|
|
2332
|
+
* Converts one persisted tool timeline row into SDK function-call input items.
|
|
2333
|
+
*
|
|
2334
|
+
* @param message - Persisted tool message.
|
|
2335
|
+
* @param seenToolCallIds - Tool call ids already emitted into the replay input.
|
|
2336
|
+
* @param unresolvedCallIds - Calls that have no persisted terminal result.
|
|
2337
|
+
* @returns Provider-compatible function call and result items for the row.
|
|
2338
|
+
*/
|
|
2339
|
+
function toolInputItemsFromAiMessage(message, seenToolCallIds, unresolvedCallIds) {
|
|
2340
|
+
const content = recordValue(message.contentJson);
|
|
2341
|
+
const state = persistedToolState(message, content);
|
|
2342
|
+
const toolName = message.toolName || stringValue(content?.toolName);
|
|
2343
|
+
const callId = message.toolCallId || stringValue(content?.callId) || stringValue(content?.call_id);
|
|
2344
|
+
const argumentsValue = content?.arguments ?? {};
|
|
2345
|
+
if (!state || !toolName || !callId)
|
|
2346
|
+
return [];
|
|
2347
|
+
if (state === AI_MESSAGE_TOOL_STATE.calling) {
|
|
2348
|
+
seenToolCallIds.add(callId);
|
|
2349
|
+
return unresolvedCallIds.has(callId)
|
|
2350
|
+
? [
|
|
2351
|
+
toolCallInputItem(toolName, callId, argumentsValue),
|
|
2352
|
+
interruptedToolResultInputItem(toolName, callId),
|
|
2353
|
+
]
|
|
2354
|
+
: [toolCallInputItem(toolName, callId, argumentsValue)];
|
|
2355
|
+
}
|
|
2356
|
+
const items = [];
|
|
2357
|
+
if (!seenToolCallIds.has(callId)) {
|
|
2358
|
+
items.push(toolCallInputItem(toolName, callId, argumentsValue));
|
|
2359
|
+
seenToolCallIds.add(callId);
|
|
2360
|
+
}
|
|
2361
|
+
items.push(toolResultInputItem(toolName, callId, state, content, message));
|
|
2362
|
+
return items;
|
|
2363
|
+
}
|
|
2364
|
+
/**
|
|
2365
|
+
* Reads the normalized lifecycle state from a persisted tool row.
|
|
2366
|
+
*
|
|
2367
|
+
* @param message - Persisted tool message.
|
|
2368
|
+
* @param content - Parsed tool message payload.
|
|
2369
|
+
* @returns Normalized tool state, or null when unsupported.
|
|
2370
|
+
*/
|
|
2371
|
+
function persistedToolState(message, content) {
|
|
2372
|
+
const state = message.toolState ?? stringValue(content?.state);
|
|
2373
|
+
if (state === AI_MESSAGE_TOOL_STATE.calling
|
|
2374
|
+
|| state === AI_MESSAGE_TOOL_STATE.success
|
|
2375
|
+
|| state === AI_MESSAGE_TOOL_STATE.error) {
|
|
2376
|
+
return state;
|
|
2377
|
+
}
|
|
2378
|
+
return null;
|
|
2379
|
+
}
|
|
2380
|
+
/**
|
|
2381
|
+
* Builds the SDK input item representing a previous model tool call.
|
|
2382
|
+
*
|
|
2383
|
+
* @param name - Tool name shown to the model.
|
|
2384
|
+
* @param callId - Provider call id that links the call to its result.
|
|
2385
|
+
* @param argumentsValue - Tool arguments supplied by the model.
|
|
2386
|
+
* @returns Function-call input item accepted by the Agents SDK.
|
|
2387
|
+
*/
|
|
2388
|
+
function toolCallInputItem(name, callId, argumentsValue) {
|
|
2389
|
+
return {
|
|
2390
|
+
type: 'function_call',
|
|
2391
|
+
callId,
|
|
2392
|
+
name,
|
|
2393
|
+
status: 'completed',
|
|
2394
|
+
arguments: serializedToolArguments(argumentsValue),
|
|
2395
|
+
};
|
|
2396
|
+
}
|
|
2397
|
+
/**
|
|
2398
|
+
* Builds the SDK input item representing a previous tool result.
|
|
2399
|
+
*
|
|
2400
|
+
* @param name - Tool name shown to the model.
|
|
2401
|
+
* @param callId - Provider call id that links the result to its call.
|
|
2402
|
+
* @param state - Persisted tool completion state.
|
|
2403
|
+
* @param content - Parsed persisted tool payload.
|
|
2404
|
+
* @param message - Persisted tool message.
|
|
2405
|
+
* @returns Function-result input item accepted by the Agents SDK.
|
|
2406
|
+
*/
|
|
2407
|
+
function toolResultInputItem(name, callId, state, content, message) {
|
|
2408
|
+
return {
|
|
2409
|
+
type: 'function_call_result',
|
|
2410
|
+
name,
|
|
2411
|
+
callId,
|
|
2412
|
+
status: 'completed',
|
|
2413
|
+
output: serializedToolOutput(name, state, content, message),
|
|
2414
|
+
};
|
|
2415
|
+
}
|
|
2416
|
+
/**
|
|
2417
|
+
* Builds a synthetic result that closes an interrupted persisted function call.
|
|
2418
|
+
*
|
|
2419
|
+
* The result is supplied only to future model turns. The tool is not executed
|
|
2420
|
+
* again automatically because a partially completed tool may have side effects.
|
|
2421
|
+
*
|
|
2422
|
+
* @param name - Persisted function tool name.
|
|
2423
|
+
* @param callId - Provider call id that must receive a matching output.
|
|
2424
|
+
* @returns Provider-compatible error result for the interrupted call.
|
|
2425
|
+
*/
|
|
2426
|
+
function interruptedToolResultInputItem(name, callId) {
|
|
2427
|
+
return {
|
|
2428
|
+
type: 'function_call_result',
|
|
2429
|
+
name,
|
|
2430
|
+
callId,
|
|
2431
|
+
status: 'completed',
|
|
2432
|
+
output: serializedToolValue({
|
|
2433
|
+
status: 'error',
|
|
2434
|
+
message: INTERRUPTED_TOOL_CALL_MESSAGE,
|
|
2435
|
+
}),
|
|
2436
|
+
};
|
|
2437
|
+
}
|
|
2438
|
+
/**
|
|
2439
|
+
* Serializes model-provided tool arguments for SDK replay.
|
|
2440
|
+
*
|
|
2441
|
+
* @param value - Persisted arguments payload.
|
|
2442
|
+
* @returns JSON argument string expected by function-call items.
|
|
2443
|
+
*/
|
|
2444
|
+
function serializedToolArguments(value) {
|
|
2445
|
+
if (typeof value === 'string')
|
|
2446
|
+
return value;
|
|
2447
|
+
return serializedToolValue(value ?? {});
|
|
2448
|
+
}
|
|
2449
|
+
/**
|
|
2450
|
+
* Serializes stored tool output for SDK replay.
|
|
2451
|
+
*
|
|
2452
|
+
* @param name - Tool name used for fallback error text.
|
|
2453
|
+
* @param state - Persisted tool completion state.
|
|
2454
|
+
* @param content - Parsed persisted tool payload.
|
|
2455
|
+
* @param message - Persisted tool message.
|
|
2456
|
+
* @returns Tool output string for a function-result item.
|
|
2457
|
+
*/
|
|
2458
|
+
function serializedToolOutput(name, state, content, message) {
|
|
2459
|
+
const result = content && 'result' in content ? content.result : message.content ?? '';
|
|
2460
|
+
if (state === AI_MESSAGE_TOOL_STATE.error) {
|
|
2461
|
+
return serializedToolValue({
|
|
2462
|
+
status: 'error',
|
|
2463
|
+
message: message.content || `${name} failed.`,
|
|
2464
|
+
result,
|
|
2465
|
+
});
|
|
2466
|
+
}
|
|
2467
|
+
return serializedToolValue(result);
|
|
2468
|
+
}
|
|
2469
|
+
/**
|
|
2470
|
+
* Safely serializes a tool payload for model replay and debug display.
|
|
2471
|
+
*
|
|
2472
|
+
* @param value - Tool payload to serialize.
|
|
2473
|
+
* @returns JSON text, plain string value, or a string fallback.
|
|
2474
|
+
*/
|
|
2475
|
+
function serializedToolValue(value) {
|
|
2476
|
+
if (typeof value === 'string')
|
|
2477
|
+
return value;
|
|
2478
|
+
try {
|
|
2479
|
+
return JSON.stringify(value ?? {});
|
|
2480
|
+
}
|
|
2481
|
+
catch {
|
|
2482
|
+
return String(value);
|
|
2483
|
+
}
|
|
2484
|
+
}
|
|
2485
|
+
/**
|
|
2486
|
+
* Builds the complete debug prompt array stored with an AI request.
|
|
2487
|
+
*
|
|
2488
|
+
* @param instructions - System instructions configured on the SDK agent.
|
|
2489
|
+
* @param input - Provider-compatible runner input.
|
|
2490
|
+
* @returns Prompt messages for request auditing.
|
|
2491
|
+
*/
|
|
2492
|
+
function promptMessagesForRequest(instructions, input) {
|
|
2493
|
+
return [
|
|
2494
|
+
systemInputMessage(instructions),
|
|
2495
|
+
...input,
|
|
2496
|
+
];
|
|
2497
|
+
}
|
|
2498
|
+
/**
|
|
2499
|
+
* Builds frontend prompt-context messages from provider-compatible input items.
|
|
2500
|
+
*
|
|
2501
|
+
* @param instructions - System instructions configured on the SDK agent.
|
|
2502
|
+
* @param input - Provider-compatible runner input.
|
|
2503
|
+
* @returns Role-tagged text messages for the debug UI.
|
|
2504
|
+
*/
|
|
2505
|
+
function promptContextMessages(instructions, input) {
|
|
2506
|
+
return promptMessagesForRequest(instructions, input)
|
|
2507
|
+
.map(promptContextMessageFromInputItem)
|
|
2508
|
+
.filter((message) => message !== null);
|
|
2509
|
+
}
|
|
2510
|
+
/**
|
|
2511
|
+
* Converts one SDK input item into a prompt-context text message when possible.
|
|
2512
|
+
*
|
|
2513
|
+
* @param item - Provider-compatible input item.
|
|
2514
|
+
* @returns Frontend prompt-context message, or null for unsupported items.
|
|
2515
|
+
*/
|
|
2516
|
+
function promptContextMessageFromInputItem(item) {
|
|
2517
|
+
const record = recordValue(item);
|
|
2518
|
+
if (!record)
|
|
2519
|
+
return null;
|
|
2520
|
+
const toolMessage = promptContextMessageFromToolItem(record);
|
|
2521
|
+
if (toolMessage)
|
|
2522
|
+
return toolMessage;
|
|
2523
|
+
const role = record?.role;
|
|
2524
|
+
if (role !== AI_MESSAGE_ROLE.system
|
|
2525
|
+
&& role !== AI_MESSAGE_ROLE.user
|
|
2526
|
+
&& role !== AI_MESSAGE_ROLE.assistant
|
|
2527
|
+
&& role !== AI_MESSAGE_ROLE.tool) {
|
|
2528
|
+
return null;
|
|
2529
|
+
}
|
|
2530
|
+
const content = inputContentText(record.content);
|
|
2531
|
+
if (content === null)
|
|
2532
|
+
return null;
|
|
2533
|
+
return {
|
|
2534
|
+
role,
|
|
2535
|
+
content,
|
|
2536
|
+
};
|
|
2537
|
+
}
|
|
2538
|
+
/**
|
|
2539
|
+
* Converts SDK tool input items into readable prompt-context messages.
|
|
2540
|
+
*
|
|
2541
|
+
* @param item - Provider-compatible tool input item.
|
|
2542
|
+
* @returns Tool prompt-context message, or null when the item is not a tool.
|
|
2543
|
+
*/
|
|
2544
|
+
function promptContextMessageFromToolItem(item) {
|
|
2545
|
+
const type = item.type;
|
|
2546
|
+
if (type === 'function_call') {
|
|
2547
|
+
const name = stringValue(item.name) || 'unknown_tool';
|
|
2548
|
+
return {
|
|
2549
|
+
role: AI_MESSAGE_ROLE.tool,
|
|
2550
|
+
content: [
|
|
2551
|
+
`Tool call: ${name}`,
|
|
2552
|
+
`Call ID: ${stringValue(item.callId) || stringValue(item.call_id) || 'unknown'}`,
|
|
2553
|
+
'Arguments:',
|
|
2554
|
+
promptPayloadText(item.arguments),
|
|
2555
|
+
].join('\n'),
|
|
2556
|
+
};
|
|
2557
|
+
}
|
|
2558
|
+
if (type === 'function_call_result') {
|
|
2559
|
+
const name = stringValue(item.name) || 'unknown_tool';
|
|
2560
|
+
return {
|
|
2561
|
+
role: AI_MESSAGE_ROLE.tool,
|
|
2562
|
+
content: [
|
|
2563
|
+
`Tool result: ${name}`,
|
|
2564
|
+
`Call ID: ${stringValue(item.callId) || stringValue(item.call_id) || 'unknown'}`,
|
|
2565
|
+
'Output:',
|
|
2566
|
+
promptPayloadText(item.output),
|
|
2567
|
+
].join('\n'),
|
|
2568
|
+
};
|
|
2569
|
+
}
|
|
2570
|
+
if (type === 'hosted_tool_call') {
|
|
2571
|
+
const name = stringValue(item.name) || 'hosted_tool';
|
|
2572
|
+
const output = item.output === undefined ? null : ['Output:', promptPayloadText(item.output)].join('\n');
|
|
2573
|
+
return {
|
|
2574
|
+
role: AI_MESSAGE_ROLE.tool,
|
|
2575
|
+
content: [
|
|
2576
|
+
`Hosted tool: ${name}`,
|
|
2577
|
+
`Status: ${stringValue(item.status) || 'unknown'}`,
|
|
2578
|
+
'Arguments:',
|
|
2579
|
+
promptPayloadText(item.arguments),
|
|
2580
|
+
output,
|
|
2581
|
+
].filter((line) => line !== null).join('\n'),
|
|
2582
|
+
};
|
|
2583
|
+
}
|
|
2584
|
+
return null;
|
|
2585
|
+
}
|
|
2586
|
+
/**
|
|
2587
|
+
* Converts provider message content into readable text for debugging.
|
|
2588
|
+
*
|
|
2589
|
+
* @param value - String or content-part array from an SDK message.
|
|
2590
|
+
* @returns Readable text, or null when no text can be extracted.
|
|
2591
|
+
*/
|
|
2592
|
+
function inputContentText(value) {
|
|
2593
|
+
if (typeof value === 'string')
|
|
2594
|
+
return value;
|
|
2595
|
+
if (!Array.isArray(value))
|
|
2596
|
+
return null;
|
|
2597
|
+
const text = value
|
|
2598
|
+
.map(inputContentPartText)
|
|
2599
|
+
.filter((part) => part !== null)
|
|
2600
|
+
.join('\n');
|
|
2601
|
+
return text || null;
|
|
2602
|
+
}
|
|
2603
|
+
/**
|
|
2604
|
+
* Converts one provider content part into readable text.
|
|
2605
|
+
*
|
|
2606
|
+
* @param value - Unknown content part.
|
|
2607
|
+
* @returns Text extracted from the content part, or null when unsupported.
|
|
2608
|
+
*/
|
|
2609
|
+
function inputContentPartText(value) {
|
|
2610
|
+
const part = recordValue(value);
|
|
2611
|
+
if (!part)
|
|
2612
|
+
return null;
|
|
2613
|
+
if (typeof part.text === 'string')
|
|
2614
|
+
return part.text;
|
|
2615
|
+
if (typeof part.refusal === 'string')
|
|
2616
|
+
return part.refusal;
|
|
2617
|
+
if (typeof part.transcript === 'string')
|
|
2618
|
+
return part.transcript;
|
|
2619
|
+
return null;
|
|
2620
|
+
}
|
|
2621
|
+
/**
|
|
2622
|
+
* Converts an arbitrary prompt payload into readable debug text.
|
|
2623
|
+
*
|
|
2624
|
+
* @param value - Unknown prompt payload.
|
|
2625
|
+
* @returns Human-readable prompt payload text.
|
|
2626
|
+
*/
|
|
2627
|
+
function promptPayloadText(value) {
|
|
2628
|
+
const content = inputContentText(value);
|
|
2629
|
+
if (content !== null)
|
|
2630
|
+
return prettyJsonText(content);
|
|
2631
|
+
if (value === undefined)
|
|
2632
|
+
return '{}';
|
|
2633
|
+
return prettyJsonText(value);
|
|
2634
|
+
}
|
|
2635
|
+
/**
|
|
2636
|
+
* Pretty-prints JSON strings and objects without truncating prompt content.
|
|
2637
|
+
*
|
|
2638
|
+
* @param value - Unknown payload value.
|
|
2639
|
+
* @returns Readable JSON or scalar text.
|
|
2640
|
+
*/
|
|
2641
|
+
function prettyJsonText(value) {
|
|
2642
|
+
if (typeof value === 'string') {
|
|
2643
|
+
const parsed = parseJson(value);
|
|
2644
|
+
if (parsed !== null)
|
|
2645
|
+
return prettyJsonText(parsed);
|
|
2646
|
+
return value;
|
|
2647
|
+
}
|
|
2648
|
+
try {
|
|
2649
|
+
return JSON.stringify(value, null, 2);
|
|
2650
|
+
}
|
|
2651
|
+
catch {
|
|
2652
|
+
return String(value);
|
|
2653
|
+
}
|
|
2654
|
+
}
|
|
2655
|
+
/**
|
|
2656
|
+
* Estimates the provider token cost for a full agent run before usage is known.
|
|
2657
|
+
*
|
|
2658
|
+
* @param input - System instructions and complete SDK input.
|
|
2659
|
+
* @returns Non-zero token estimate for rate-limit reservations.
|
|
2660
|
+
*/
|
|
2661
|
+
function estimatedAgentRunTokens(input) {
|
|
2662
|
+
const text = [
|
|
2663
|
+
input.instructions,
|
|
2664
|
+
...promptContextMessages('', input.input).map(message => message.content),
|
|
2665
|
+
].join('\n');
|
|
2666
|
+
return estimateTokensFromText(text);
|
|
2667
|
+
}
|
|
2668
|
+
/**
|
|
2669
|
+
* Converts the SDK final output value into text for persistence and display.
|
|
2670
|
+
*
|
|
2671
|
+
* @param finalOutput - SDK final output.
|
|
2672
|
+
* @param streamedText - Text collected from streaming deltas.
|
|
2673
|
+
* @returns Final output text.
|
|
2674
|
+
*/
|
|
2675
|
+
function defaultAgentFinalOutputText(finalOutput, streamedText) {
|
|
2676
|
+
if (typeof finalOutput === 'string' && finalOutput.trim())
|
|
2677
|
+
return finalOutput;
|
|
2678
|
+
return streamedText.trim();
|
|
2679
|
+
}
|
|
2680
|
+
/**
|
|
2681
|
+
* Converts SDK usage into the app's normalized usage summary.
|
|
2682
|
+
*
|
|
2683
|
+
* @param usage - Agents SDK usage object.
|
|
2684
|
+
* @returns Normalized usage summary.
|
|
2685
|
+
*/
|
|
2686
|
+
function agentRunUsage(usage) {
|
|
2687
|
+
return {
|
|
2688
|
+
requests: usage.requests,
|
|
2689
|
+
inputTokens: numberOrNull(usage.inputTokens),
|
|
2690
|
+
outputTokens: numberOrNull(usage.outputTokens),
|
|
2691
|
+
totalTokens: numberOrNull(usage.totalTokens),
|
|
2692
|
+
reasoningTokens: sumTokenDetails(usage.outputTokensDetails, 'reasoning_tokens'),
|
|
2693
|
+
cachedTokens: sumTokenDetails(usage.inputTokensDetails, 'cached_tokens'),
|
|
2694
|
+
cacheWriteTokens: sumTokenDetails(usage.inputTokensDetails, 'cache_write_tokens'),
|
|
2695
|
+
};
|
|
2696
|
+
}
|
|
2697
|
+
/**
|
|
2698
|
+
* Normalizes the SDK's individual provider-request usage for accurate pricing.
|
|
2699
|
+
*
|
|
2700
|
+
* @param usage - Agents SDK aggregate usage object.
|
|
2701
|
+
* @returns Individual request entries with cached-input details preserved.
|
|
2702
|
+
*/
|
|
2703
|
+
function agentRequestCostUsageEntries(usage) {
|
|
2704
|
+
return (usage.requestUsageEntries ?? []).map(entry => ({
|
|
2705
|
+
inputTokens: numberOrNull(entry.inputTokens),
|
|
2706
|
+
outputTokens: numberOrNull(entry.outputTokens),
|
|
2707
|
+
cachedTokens: tokenDetailValue(entry.inputTokensDetails, 'cached_tokens'),
|
|
2708
|
+
cacheWriteTokens: tokenDetailValue(entry.inputTokensDetails, 'cache_write_tokens'),
|
|
2709
|
+
...(entry.endpoint ? { endpoint: entry.endpoint } : {}),
|
|
2710
|
+
}));
|
|
2711
|
+
}
|
|
2712
|
+
/**
|
|
2713
|
+
* Prices one agent attempt only when its provider and usage granularity are safe.
|
|
2714
|
+
*
|
|
2715
|
+
* Long-context and cache-write charges apply per provider request. Multiple SDK
|
|
2716
|
+
* requests therefore require a complete request-usage entry set; aggregate
|
|
2717
|
+
* fallback is accepted only for exactly one request.
|
|
2718
|
+
*
|
|
2719
|
+
* @param provider - Provider that executed the attempt.
|
|
2720
|
+
* @param model - Provider model used by the attempt.
|
|
2721
|
+
* @param usage - Aggregate attempt usage.
|
|
2722
|
+
* @param requestUsageEntries - Per-provider-request usage entries.
|
|
2723
|
+
* @param hostedToolUsage - Completed hosted provider-tool calls.
|
|
2724
|
+
* @returns Complete attempt cost and any unpriced dimensions.
|
|
2725
|
+
*/
|
|
2726
|
+
function agentAttemptCost(provider, model, usage, requestUsageEntries, hostedToolUsage) {
|
|
2727
|
+
const usesPerRequestUsage = usage.requests > 0
|
|
2728
|
+
&& requestUsageEntries.length === usage.requests;
|
|
2729
|
+
const usesSingleRequestAggregate = usage.requests === 1
|
|
2730
|
+
&& requestUsageEntries.length === 0;
|
|
2731
|
+
const modelCostUSD = provider === AI_PROVIDER.openai
|
|
2732
|
+
? usesPerRequestUsage
|
|
2733
|
+
? calculateAIRequestEntriesCostUSD(model, requestUsageEntries)
|
|
2734
|
+
: usesSingleRequestAggregate
|
|
2735
|
+
? calculateAIRequestCostUSD(model, usage)
|
|
2736
|
+
: null
|
|
2737
|
+
: null;
|
|
2738
|
+
const hostedToolCost = provider === AI_PROVIDER.openai
|
|
2739
|
+
? calculateAIHostedToolCost(hostedToolUsage)
|
|
2740
|
+
: {
|
|
2741
|
+
costUSD: 0,
|
|
2742
|
+
unpricedUsage: normalizedHostedToolUsage(hostedToolUsage),
|
|
2743
|
+
};
|
|
2744
|
+
const knownCostUSD = combineAIRequestCostUSD(modelCostUSD ?? 0, hostedToolCost.costUSD) ?? 0;
|
|
2745
|
+
const costUSD = Object.keys(hostedToolCost.unpricedUsage).length === 0
|
|
2746
|
+
? combineAIRequestCostUSD(modelCostUSD, hostedToolCost.costUSD)
|
|
2747
|
+
: null;
|
|
2748
|
+
return {
|
|
2749
|
+
modelCostUSD,
|
|
2750
|
+
hostedToolCostUSD: hostedToolCost.costUSD,
|
|
2751
|
+
unpricedHostedToolUsage: hostedToolCost.unpricedUsage,
|
|
2752
|
+
knownCostUSD,
|
|
2753
|
+
costUSD,
|
|
2754
|
+
pricingUsage: provider !== AI_PROVIDER.openai
|
|
2755
|
+
? 'unpriced_incomplete'
|
|
2756
|
+
: usesPerRequestUsage
|
|
2757
|
+
? 'per_request'
|
|
2758
|
+
: usesSingleRequestAggregate
|
|
2759
|
+
? 'single_request_aggregate'
|
|
2760
|
+
: 'unpriced_incomplete',
|
|
2761
|
+
};
|
|
2762
|
+
}
|
|
2763
|
+
/**
|
|
2764
|
+
* Normalizes completed hosted-tool counts when provider-specific pricing is absent.
|
|
2765
|
+
*
|
|
2766
|
+
* @param usage - Hosted-tool counts observed during one provider attempt.
|
|
2767
|
+
* @returns Positive whole call counts that must remain explicitly unpriced.
|
|
2768
|
+
*/
|
|
2769
|
+
function normalizedHostedToolUsage(usage) {
|
|
2770
|
+
const normalized = {};
|
|
2771
|
+
for (const [toolName, count] of Object.entries(usage)) {
|
|
2772
|
+
if (!Number.isFinite(count) || count <= 0)
|
|
2773
|
+
continue;
|
|
2774
|
+
normalized[toolName] = Math.trunc(count);
|
|
2775
|
+
}
|
|
2776
|
+
return normalized;
|
|
2777
|
+
}
|
|
2778
|
+
/**
|
|
2779
|
+
* Returns a cost result for an attempt with no observed billable usage.
|
|
2780
|
+
*
|
|
2781
|
+
* @param providerStarted - Whether execution may have crossed the provider boundary.
|
|
2782
|
+
* @returns Confirmed zero before provider work, otherwise an unknown cost.
|
|
2783
|
+
*/
|
|
2784
|
+
function emptyAgentAttemptCost(providerStarted) {
|
|
2785
|
+
return {
|
|
2786
|
+
modelCostUSD: providerStarted ? null : 0,
|
|
2787
|
+
hostedToolCostUSD: 0,
|
|
2788
|
+
unpricedHostedToolUsage: {},
|
|
2789
|
+
knownCostUSD: 0,
|
|
2790
|
+
costUSD: providerStarted ? null : 0,
|
|
2791
|
+
pricingUsage: providerStarted ? 'unpriced_incomplete' : 'known_zero',
|
|
2792
|
+
};
|
|
2793
|
+
}
|
|
2794
|
+
/**
|
|
2795
|
+
* Builds the persisted response payload for one provider attempt.
|
|
2796
|
+
*
|
|
2797
|
+
* @param usage - Normalized aggregate usage.
|
|
2798
|
+
* @param requestUsageEntries - Per-provider-request usage entries.
|
|
2799
|
+
* @param cost - Complete and partial cost result.
|
|
2800
|
+
* @param hostedToolUsage - Completed hosted provider-tool counts.
|
|
2801
|
+
* @param metadata - Attempt result fields such as response id or error.
|
|
2802
|
+
* @returns Auditable attempt response without raw model content.
|
|
2803
|
+
*/
|
|
2804
|
+
function agentAttemptResponse(usage, requestUsageEntries, cost, hostedToolUsage, metadata) {
|
|
2805
|
+
return {
|
|
2806
|
+
...metadata,
|
|
2807
|
+
usage,
|
|
2808
|
+
cost: {
|
|
2809
|
+
modelCostUSD: cost.modelCostUSD,
|
|
2810
|
+
hostedToolCostUSD: cost.hostedToolCostUSD,
|
|
2811
|
+
unpricedHostedToolUsage: cost.unpricedHostedToolUsage,
|
|
2812
|
+
knownCostUSD: cost.knownCostUSD,
|
|
2813
|
+
requestCostUSD: cost.costUSD,
|
|
2814
|
+
hostedToolUsage,
|
|
2815
|
+
pricingUsage: cost.pricingUsage,
|
|
2816
|
+
requestUsageEntries,
|
|
2817
|
+
},
|
|
2818
|
+
};
|
|
2819
|
+
}
|
|
2820
|
+
/**
|
|
2821
|
+
* Returns the absence-preserving usage shape for an attempt without SDK usage.
|
|
2822
|
+
*
|
|
2823
|
+
* @returns Empty usage with no invented provider token counts.
|
|
2824
|
+
*/
|
|
2825
|
+
function emptyAgentRunUsage() {
|
|
2826
|
+
return {
|
|
2827
|
+
requests: 0,
|
|
2828
|
+
inputTokens: null,
|
|
2829
|
+
outputTokens: null,
|
|
2830
|
+
totalTokens: null,
|
|
2831
|
+
reasoningTokens: null,
|
|
2832
|
+
cachedTokens: null,
|
|
2833
|
+
cacheWriteTokens: null,
|
|
2834
|
+
};
|
|
2835
|
+
}
|
|
2836
|
+
/**
|
|
2837
|
+
* Applies Standard service tier only to direct OpenAI provider requests.
|
|
2838
|
+
*
|
|
2839
|
+
* @param settings - Agent-owned model settings.
|
|
2840
|
+
* @param provider - Provider selected for the current attempt.
|
|
2841
|
+
* @returns Provider-safe settings with deterministic OpenAI billing tier.
|
|
2842
|
+
*/
|
|
2843
|
+
function modelSettingsForProvider(settings, provider) {
|
|
2844
|
+
if (provider !== AI_PROVIDER.openai)
|
|
2845
|
+
return settings;
|
|
2846
|
+
return {
|
|
2847
|
+
...settings,
|
|
2848
|
+
providerData: {
|
|
2849
|
+
...(settings.providerData ?? {}),
|
|
2850
|
+
service_tier: 'default',
|
|
2851
|
+
},
|
|
2852
|
+
};
|
|
2853
|
+
}
|
|
2854
|
+
/**
|
|
2855
|
+
* Checks whether a failed agent attempt accumulated any potentially billable work.
|
|
2856
|
+
*
|
|
2857
|
+
* @param usage - Mutable Agents SDK usage collected during the attempt.
|
|
2858
|
+
* @param hostedToolUsage - Completed hosted provider-tool calls for the attempt.
|
|
2859
|
+
* @returns True when a failed-attempt child request should preserve usage.
|
|
2860
|
+
*/
|
|
2861
|
+
function hasBillableAgentAttemptUsage(usage, hostedToolUsage) {
|
|
2862
|
+
return usage.requests > 0
|
|
2863
|
+
|| usage.inputTokens > 0
|
|
2864
|
+
|| usage.outputTokens > 0
|
|
2865
|
+
|| Object.values(hostedToolUsage).some(count => Number.isFinite(count) && count > 0);
|
|
2866
|
+
}
|
|
2867
|
+
/**
|
|
2868
|
+
* Sums one token detail field across the SDK's aggregate detail records.
|
|
2869
|
+
*
|
|
2870
|
+
* @param details - Usage detail records.
|
|
2871
|
+
* @param key - Detail key to sum.
|
|
2872
|
+
* @returns Total when positive, otherwise null.
|
|
2873
|
+
*/
|
|
2874
|
+
function sumTokenDetails(details, key) {
|
|
2875
|
+
const total = details.reduce((sum, detail) => {
|
|
2876
|
+
const value = detail[key];
|
|
2877
|
+
return typeof value === 'number' && Number.isFinite(value) ? sum + value : sum;
|
|
2878
|
+
}, 0);
|
|
2879
|
+
return total > 0 ? total : null;
|
|
2880
|
+
}
|
|
2881
|
+
/**
|
|
2882
|
+
* Reads one token detail from an individual SDK request usage entry.
|
|
2883
|
+
*
|
|
2884
|
+
* @param details - Provider request token-detail record.
|
|
2885
|
+
* @param key - Detail key to read.
|
|
2886
|
+
* @returns Non-negative integer detail value, or null when absent.
|
|
2887
|
+
*/
|
|
2888
|
+
function tokenDetailValue(details, key) {
|
|
2889
|
+
const value = details[key];
|
|
2890
|
+
return typeof value === 'number' && Number.isFinite(value) && value >= 0
|
|
2891
|
+
? Math.trunc(value)
|
|
2892
|
+
: null;
|
|
2893
|
+
}
|
|
2894
|
+
/**
|
|
2895
|
+
* Normalizes finite numbers while preserving unknown usage values as null.
|
|
2896
|
+
*
|
|
2897
|
+
* @param value - Numeric usage value.
|
|
2898
|
+
* @returns Integer usage value or null.
|
|
2899
|
+
*/
|
|
2900
|
+
function numberOrNull(value) {
|
|
2901
|
+
return Number.isFinite(value) ? Math.trunc(value) : null;
|
|
2902
|
+
}
|
|
2903
|
+
/**
|
|
2904
|
+
* Creates the public agent error payload for stream errors.
|
|
2905
|
+
*
|
|
2906
|
+
* @param error - Unknown error value.
|
|
2907
|
+
* @param fallback - Fallback public error message.
|
|
2908
|
+
* @returns Public stream error payload.
|
|
2909
|
+
*/
|
|
2910
|
+
function agentErrorPayload(error, fallback) {
|
|
2911
|
+
return {
|
|
2912
|
+
code: error instanceof AIAllowanceExceededError ? error.publicCode : undefined,
|
|
2913
|
+
message: error instanceof Error && error.message ? error.message : fallback,
|
|
2914
|
+
details: error instanceof AgentAuthorizationError ? undefined : errorDetails(error),
|
|
2915
|
+
};
|
|
2916
|
+
}
|
|
2917
|
+
/**
|
|
2918
|
+
* Returns safe developer-facing error details without including secrets.
|
|
2919
|
+
*
|
|
2920
|
+
* @param error - Unknown error value.
|
|
2921
|
+
* @returns Safe error details.
|
|
2922
|
+
*/
|
|
2923
|
+
function errorDetails(error) {
|
|
2924
|
+
if (error instanceof Error) {
|
|
2925
|
+
return {
|
|
2926
|
+
name: error.name,
|
|
2927
|
+
message: error.message,
|
|
2928
|
+
stack: process.env.NODE_ENV === 'production' ? undefined : error.stack,
|
|
2929
|
+
};
|
|
2930
|
+
}
|
|
2931
|
+
return error;
|
|
2932
|
+
}
|
|
2933
|
+
/**
|
|
2934
|
+
* Safely narrows unknown values to object records.
|
|
2935
|
+
*
|
|
2936
|
+
* @param value - Unknown value.
|
|
2937
|
+
* @returns Object record or null.
|
|
2938
|
+
*/
|
|
2939
|
+
function recordValue(value) {
|
|
2940
|
+
return value !== null && typeof value === 'object' ? value : null;
|
|
2941
|
+
}
|
|
2942
|
+
/**
|
|
2943
|
+
* Returns a string value when the unknown input is a non-empty string.
|
|
2944
|
+
*
|
|
2945
|
+
* @param value - Unknown value.
|
|
2946
|
+
* @returns String value or null.
|
|
2947
|
+
*/
|
|
2948
|
+
function stringValue(value) {
|
|
2949
|
+
return typeof value === 'string' && value.length > 0 ? value : null;
|
|
2950
|
+
}
|
|
2951
|
+
/**
|
|
2952
|
+
* Builds a stable frontend id for a prompt-context timeline item.
|
|
2953
|
+
*
|
|
2954
|
+
* @param aiRequestId - Persisted AI request id when available.
|
|
2955
|
+
* @param traceId - Provider trace id used as a fallback.
|
|
2956
|
+
* @returns Prompt-context timeline id.
|
|
2957
|
+
*/
|
|
2958
|
+
function promptContextId(aiRequestId, traceId) {
|
|
2959
|
+
const id = aiRequestId === null || aiRequestId === undefined ? traceId : String(aiRequestId);
|
|
2960
|
+
return `prompt_context:${id}`;
|
|
2961
|
+
}
|
|
2962
|
+
/**
|
|
2963
|
+
* Serializes dates for stream events.
|
|
2964
|
+
*
|
|
2965
|
+
* @param value - Date value to serialize.
|
|
2966
|
+
* @returns ISO timestamp.
|
|
2967
|
+
*/
|
|
2968
|
+
function dateString(value) {
|
|
2969
|
+
return value instanceof Date ? value.toISOString() : new Date().toISOString();
|
|
2970
|
+
}
|
|
2971
|
+
/** Normalizes a trusted app context identity without requiring a particular user or tenant model. */
|
|
2972
|
+
function contextIdentity(value) {
|
|
2973
|
+
if (typeof value === 'string')
|
|
2974
|
+
return value;
|
|
2975
|
+
return value?.id == null ? '' : String(value.id);
|
|
2976
|
+
}
|