diff --git a/.changeset/bright-docs-integrations.md b/.changeset/bright-docs-integrations.md new file mode 100644 index 000000000..49a927239 --- /dev/null +++ b/.changeset/bright-docs-integrations.md @@ -0,0 +1,5 @@ +--- +"@agentskit/integrations": patch +--- + +Document the public API. diff --git a/.changeset/quiet-docs-memory.md b/.changeset/quiet-docs-memory.md new file mode 100644 index 000000000..53286511d --- /dev/null +++ b/.changeset/quiet-docs-memory.md @@ -0,0 +1,5 @@ +--- +"@agentskit/memory": patch +--- + +Document the public API. diff --git a/.changeset/quiet-observability-docs.md b/.changeset/quiet-observability-docs.md new file mode 100644 index 000000000..ddac555f8 --- /dev/null +++ b/.changeset/quiet-observability-docs.md @@ -0,0 +1,5 @@ +--- +'@agentskit/observability': patch +--- + +Document the public API. diff --git a/docs/stability/jsdoc-coverage-v1.json b/docs/stability/jsdoc-coverage-v1.json index 6d5f253ff..e9da3f22e 100644 --- a/docs/stability/jsdoc-coverage-v1.json +++ b/docs/stability/jsdoc-coverage-v1.json @@ -15,272 +15,11 @@ ], "@agentskit/eval": [], "@agentskit/ink": [], - "@agentskit/integrations": [ - ".::acuityIntegration", - ".::airtableIntegration", - ".::ApiKeyAuthSpec", - ".::apolloIntegration", - ".::asanaIntegration", - ".::assemblyaiIntegration", - ".::attioIntegration", - ".::AuthSpec", - ".::azureOpenaiIntegration", - ".::baserowIntegration", - ".::bigcommerceIntegration", - ".::boxIntegration", - ".::calComIntegration", - ".::calendlyIntegration", - ".::coingeckoIntegration", - ".::confluenceIntegration", - ".::createRegistry", - ".::deepgramIntegration", - ".::discordIntegration", - ".::dropboxIntegration", - ".::elevenlabsIntegration", - ".::EmailAttachment", - ".::EmailConfig", - ".::emailIntegration", - ".::EmailMessage", - ".::EmailSendMessage", - ".::EmailSendResult", - ".::EmailTransport", - ".::figmaIntegration", - ".::firecrawlIntegration", - ".::getIntegration", - ".::githubActionsIntegration", - ".::githubIntegration", - ".::gmailIntegration", - ".::googleCalendarIntegration", - ".::googleDriveIntegration", - ".::HttpJsonRequest", - ".::HttpToolOptions", - ".::hubspotIntegration", - ".::ImapClient", - ".::ImapFetchOptions", - ".::Integration", - ".::IntegrationAction", - ".::integrationsByCategory", - ".::IntegrationTrigger", - ".::intercomIntegration", - ".::jiraIntegration", - ".::linearIntegration", - ".::linearTriageIntegration", - ".::listIntegrations", - ".::mailchimpIntegration", - ".::mapsIntegration", - ".::NoAuthSpec", - ".::notionIntegration", - ".::OAuth2AuthSpec", - ".::openaiImagesIntegration", - ".::pagerdutyIntegration", - ".::pipedriveIntegration", - ".::readerIntegration", - ".::registerIntegration", - ".::RetryableHttpMethod", - ".::RetryPolicy", - ".::salesforceIntegration", - ".::sendgridIntegration", - ".::sentryIntegration", - ".::shopifyIntegration", - ".::SideEffect", - ".::slackIntegration", - ".::stripeIntegration", - ".::TeamsAdaptiveCard", - ".::TeamsAdaptiveCardAction", - ".::TeamsBotClient", - ".::TeamsBotMessage", - ".::TeamsBotSendResult", - ".::teamsIntegration", - ".::TeamsMessageCard", - ".::telegramIntegration", - ".::twilioIntegration", - ".::VerifyResult", - ".::weatherIntegration", - ".::WebhookInput", - ".::WebhookSecretAuthSpec", - ".::whatsappIntegration", - ".::whisperIntegration", - "./testing::validateAction", - "./testing::validateTrigger" - ], + "@agentskit/integrations": [], "@agentskit/mcp": [], - "@agentskit/memory": [ - ".::ChatMemoryRedactionOptions", - ".::chroma", - ".::ChromaConfig", - ".::createEncryptedMemory", - ".::createFileStore", - ".::createInMemoryStore", - ".::createKvMemoryFromConfig", - ".::createKvMemoryFromConfigAuto", - ".::CreateKvMemoryFromConfigOpts", - ".::createLocalStorageStore", - ".::CreateLocalStorageStoreOpts", - ".::createRedisStore", - ".::CreateRedisStoreOpts", - ".::createSqliteStore", - ".::CreateSqliteStoreOpts", - ".::createVectorStore", - ".::CreateVectorStoreOpts", - ".::EncryptedEnvelope", - ".::FileKvConfig", - ".::fileVectorMemory", - ".::FileVectorMemoryConfig", - ".::ForgetReport", - ".::ForgetSubjectResult", - ".::GraphEdge", - ".::GraphMemory", - ".::GraphQuery", - ".::HierarchicalMemory", - ".::HierarchicalMemoryOptions", - ".::HierarchicalRecall", - ".::InMemoryKvConfig", - ".::isMemoryBackendSupported", - ".::KvEntry", - ".::KvMemoryConfig", - ".::LocalStorageKvConfig", - ".::LocalStorageLike", - ".::MEMORY_BACKEND_SUPPORT", - ".::MemoryBackendNotImplementedError", - ".::MemoryBackendStatus", - ".::MemoryEmbedderLike", - ".::MemoryVectorStoreLike", - ".::MilvusConfig", - ".::milvusVectorStore", - ".::MongoAtlasVectorConfig", - ".::mongoAtlasVectorStore", - ".::PersonalizationStore", - ".::pgvector", - ".::PgVectorConfig", - ".::pinecone", - ".::PineconeConfig", - ".::qdrant", - ".::QdrantConfig", - ".::redisChatMemory", - ".::RedisChatMemoryConfig", - ".::RedisConnectionConfig", - ".::RedisKvConfig", - ".::RedisLike", - ".::redisVectorMemory", - ".::RedisVectorMemoryConfig", - ".::RemoteHttpConfig", - ".::sqliteChatMemory", - ".::SqliteChatMemoryConfig", - ".::SqliteKvConfig", - ".::SqliteLike", - ".::SqliteOpener", - ".::SqliteStmt", - ".::SupabaseVectorStoreConfig", - ".::TursoChatMemoryConfig", - ".::UpstashVectorConfig", - ".::VectorKvConfig", - ".::VectorMemoryRedactionOptions", - ".::VectorStore", - ".::VectorStoreDocument", - ".::VectorStoreResult", - ".::WeaviateConfig", - ".::weaviateVectorStore", - ".::WebStorageLike", - ".::WebStorageMemoryMigration", - ".::WebStorageMemoryOptions", - ".::wrapChatMemoryWithRedaction", - "./personalization::PersonalizationStore", - "./web-storage::WebStorageLike", - "./web-storage::WebStorageMemoryMigration", - "./web-storage::WebStorageMemoryOptions" - ], + "@agentskit/memory": [], "@agentskit/net": [], - "@agentskit/observability": [ - ".::AdvancedCostGuardOptions", - ".::AppendAuditInput", - ".::appendPiiAuditEvents", - ".::AuditEntry", - ".::AuditLogOptions", - ".::AuditLogStore", - ".::AuditVerifyResult", - ".::AxiomSinkConfig", - ".::AxiomSinkObserver", - ".::BisectOpts", - ".::BisectVerdict", - ".::buildTimeline", - ".::ChargebackGroupKey", - ".::chargebackReport", - ".::ChargebackReport", - ".::ChargebackReportOptions", - ".::chargebackReportToCsv", - ".::ChargebackRow", - ".::consoleLogger", - ".::ConsoleLoggerConfig", - ".::ControlAuditEntry", - ".::ControlSurface", - ".::ControlSurfaceOptions", - ".::CostAlertEvent", - ".::CostAlertSink", - ".::CostAlertType", - ".::CostCaps", - ".::CostCapWindow", - ".::CostGuardMode", - ".::CostGuardOptions", - ".::createAdvancedCostGuard", - ".::createControlSurface", - ".::createTopologyGraph", - ".::DatadogSinkConfig", - ".::DatadogSinkObserver", - ".::DEFAULT_SLO_TARGETS", - ".::DevtoolsClient", - ".::DevtoolsEnvelope", - ".::DevtoolsServer", - ".::DevtoolsServerOptions", - ".::diffState", - ".::FileTraceSink", - ".::LangSmithConfig", - ".::LangSmithObserver", - ".::MultiTenantCostGuardOptions", - ".::NewRelicSinkConfig", - ".::NewRelicSinkObserver", - ".::ObserverRedactionOptions", - ".::OpenTelemetryConfig", - ".::OpenTelemetryObserver", - ".::PiiAuditAction", - ".::PiiAuditInput", - ".::PiiAuditPayload", - ".::positionAt", - ".::replayEvents", - ".::ReplayHandler", - ".::ReplayOracle", - ".::ReplayPosition", - ".::RunSnapshot", - ".::SignedAuditLog", - ".::sloObserver", - ".::SloObserver", - ".::SloOptions", - ".::SloSnapshot", - ".::StateDiffEntry", - ".::Timeline", - ".::TimelineRow", - ".::TopologyEdge", - ".::TopologyGraph", - ".::TopologyGraphOptions", - ".::TopologyGraphSnapshot", - ".::TraceReport", - ".::TraceSpan", - ".::TraceTrackerCallbacks", - ".::UnknownModelPolicy", - ".::WebhookAlertSinkOptions", - ".::wrapObserverWithRedaction", - "./cost-guard::assertFiniteNonNegative", - "./cost-guard::assertFinitePositive", - "./cost-guard::CostGuardOptions", - "./cost-guard::hasPriceFor", - "./cost-guard::resolvePrice", - "./cost-guard::resolvePriceSafely", - "./cost-guard::UnknownModelPolicy", - "./cost-guard::validateTokenPrices", - "./langfuse::LangfuseConfig", - "./langfuse::LangfuseObserver", - "./trace-tracker::TraceSpan", - "./trace-tracker::TraceTrackerCallbacks" - ], + "@agentskit/observability": [], "@agentskit/rag": [], "@agentskit/react": [], "@agentskit/react-native": [], @@ -291,25 +30,7 @@ "@agentskit/statechart": [], "@agentskit/svelte": [], "@agentskit/templates": [], - "@agentskit/tools": [ - "./integrations::EmailAttachment", - "./integrations::EmailConfig", - "./integrations::EmailMessage", - "./integrations::EmailSendMessage", - "./integrations::EmailSendResult", - "./integrations::EmailTransport", - "./integrations::HttpJsonRequest", - "./integrations::HttpToolOptions", - "./integrations::ImapClient", - "./integrations::ImapFetchOptions", - "./integrations::RetryPolicy", - "./integrations::TeamsAdaptiveCard", - "./integrations::TeamsAdaptiveCardAction", - "./integrations::TeamsBotClient", - "./integrations::TeamsBotMessage", - "./integrations::TeamsBotSendResult", - "./integrations::TeamsMessageCard" - ], + "@agentskit/tools": [], "@agentskit/vue": [] } } diff --git a/packages/integrations/src/contract.ts b/packages/integrations/src/contract.ts index c993c8f74..3ed10feaa 100644 --- a/packages/integrations/src/contract.ts +++ b/packages/integrations/src/contract.ts @@ -6,6 +6,7 @@ import type { IntegrationHttp } from './http' // Side effects — lets a host enforce an autonomy/approval gate per action. // --------------------------------------------------------------------------- +/** Declared blast radius of an integration action. */ export type SideEffect = 'none' | 'read' | 'write' | 'destructive' | 'external' // --------------------------------------------------------------------------- @@ -27,10 +28,12 @@ export interface OAuth2ProviderSpec { extraAuthParams?: Record } +/** OAuth2 authorization configuration for a service integration. */ export interface OAuth2AuthSpec extends OAuth2ProviderSpec { kind: 'oauth2' } +/** Header-based API key authentication configuration. */ export interface ApiKeyAuthSpec { kind: 'apiKey' /** Header the credential is sent in (e.g. `authorization`). */ @@ -41,16 +44,19 @@ export interface ApiKeyAuthSpec { envHint?: string } +/** Authentication configuration for verifying inbound webhook signatures. */ export interface WebhookSecretAuthSpec { kind: 'webhookSecret' /** Signature scheme used to verify inbound webhooks. */ scheme: 'hmac-sha256' | 'ed25519' | 'custom' } +/** Authentication marker for integrations that require no credentials. */ export interface NoAuthSpec { kind: 'none' } +/** Supported declarative authentication configurations for integrations. */ export type AuthSpec = | OAuth2AuthSpec | ApiKeyAuthSpec @@ -86,6 +92,7 @@ export interface IntegrationActionContext { config: unknown } +/** An executable provider operation that can be projected into a tool. */ export interface IntegrationAction { /** Stable, namespaced id, e.g. `slack_post_message`. */ name: string @@ -107,6 +114,7 @@ export interface IntegrationAction { // canonical normalized event a host trigger layer can consume. // --------------------------------------------------------------------------- +/** Request data supplied to a trigger's webhook verifier. */ export interface WebhookInput { /** Verification secret (signing secret / shared token). */ secret: string @@ -118,6 +126,7 @@ export interface WebhookInput { requestUrl?: string } +/** Result returned by an integration webhook signature verifier. */ export type VerifyResult = { ok: true } | { ok: false; reason: string } /** External thread reference — basis for session stitching across turns. */ @@ -136,6 +145,7 @@ export interface NormalizedEvent { raw?: unknown } +/** Webhook trigger that verifies and normalizes provider events. */ export interface IntegrationTrigger { /** Stable id, e.g. `slack.message`. */ name: string @@ -174,6 +184,7 @@ export interface ConfigField { placeholder?: string } +/** Complete service descriptor shared by integration projections. */ export interface Integration { /** Service slug, e.g. `slack`. */ name: string diff --git a/packages/integrations/src/http.ts b/packages/integrations/src/http.ts index 172985aaa..8f48b8ba1 100644 --- a/packages/integrations/src/http.ts +++ b/packages/integrations/src/http.ts @@ -12,6 +12,7 @@ import { composeTimeoutSignal } from './http-timeout' export { readResponseBytes, readResponseText } from './http-body' export { composeTimeoutSignal } from './http-timeout' +/** Configuration for an authenticated, origin-confined integration HTTP client. */ export interface HttpToolOptions { baseUrl?: string /** Header bag merged into every request (auth, user-agent, etc.). */ @@ -32,6 +33,7 @@ export interface HttpToolOptions { retry?: RetryPolicy } +/** Retry limits and delays for retryable integration HTTP requests. */ export interface RetryPolicy { /** Total attempts, including the first request. Defaults to 1; valid range is 1–100. */ maxAttempts?: number @@ -43,10 +45,12 @@ export interface RetryPolicy { methods?: RetryableHttpMethod[] } +/** HTTP methods for which the integration client can retry requests. */ export type RetryableHttpMethod = NonNullable const MAX_TIMEOUT_MS = 2_147_483_647 +/** Request options accepted by `httpJson` and a bound integration client. */ export interface HttpJsonRequest { /** HTTP method. Defaults to GET. */ method?: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' diff --git a/packages/integrations/src/registry.ts b/packages/integrations/src/registry.ts index 4b04e79f1..2d9a1ccdb 100644 --- a/packages/integrations/src/registry.ts +++ b/packages/integrations/src/registry.ts @@ -16,6 +16,16 @@ export interface IntegrationRegistry { byCategory(category: string): Integration[] } +/** Creates an isolated in-memory registry seeded with optional descriptors. + * @param initial Integrations to register when the registry is created. + * @returns A registry with register, lookup, list, and category methods. + * @throws {ConfigError} When two initial integrations have the same name. + * @example + * ```ts + * const registry = createRegistry([slackIntegration]) + * const slack = registry.get('slack') + * ``` + */ export function createRegistry(initial: Integration[] = []): IntegrationRegistry { const map = new Map() @@ -48,18 +58,33 @@ export function createRegistry(initial: Integration[] = []): IntegrationRegistry */ const defaultRegistry = createRegistry() +/** Adds an integration to the default catalog. + * @param integration Descriptor to register. + * @throws {ConfigError} When an integration with the same name is registered. + */ export function registerIntegration(integration: Integration): void { defaultRegistry.register(integration) } +/** Looks up an integration by its service slug in the default catalog. + * @param name Integration slug. + * @returns The matching descriptor, or `undefined` when not registered. + */ export function getIntegration(name: string): Integration | undefined { return defaultRegistry.get(name) } +/** Returns all descriptors registered in the default catalog. + * @returns A new array of integration descriptors. + */ export function listIntegrations(): Integration[] { return defaultRegistry.list() } +/** Returns default-catalog integrations that include the requested category. + * @param category Category slug to match. + * @returns Matching integration descriptors. + */ export function integrationsByCategory(category: string): Integration[] { return defaultRegistry.byCategory(category) } diff --git a/packages/integrations/src/services/acuity/index.ts b/packages/integrations/src/services/acuity/index.ts index 9b5667be7..4ce99ce8f 100644 --- a/packages/integrations/src/services/acuity/index.ts +++ b/packages/integrations/src/services/acuity/index.ts @@ -3,6 +3,7 @@ import { CONFIG_FIELDS } from '../../config-fields' import { registerIntegration } from '../../registry' import { acuityActions } from './actions' +/** Descriptor for the Acuity Scheduling service integration. */ export const acuityIntegration = defineIntegration({ name: 'acuity', displayName: 'Acuity Scheduling', diff --git a/packages/integrations/src/services/airtable/index.ts b/packages/integrations/src/services/airtable/index.ts index 80cc9c3e8..935e3078a 100644 --- a/packages/integrations/src/services/airtable/index.ts +++ b/packages/integrations/src/services/airtable/index.ts @@ -2,6 +2,7 @@ import { defineIntegration } from '../../contract' import { registerIntegration } from '../../registry' import { airtableActions } from './actions' +/** Descriptor for the Airtable service integration. */ export const airtableIntegration = defineIntegration({ name: 'airtable', displayName: 'Airtable', diff --git a/packages/integrations/src/services/apollo/index.ts b/packages/integrations/src/services/apollo/index.ts index 8c0580179..1869faffe 100644 --- a/packages/integrations/src/services/apollo/index.ts +++ b/packages/integrations/src/services/apollo/index.ts @@ -2,6 +2,7 @@ import { defineIntegration } from '../../contract' import { registerIntegration } from '../../registry' import { apolloActions } from './actions' +/** Descriptor for the Apollo.io service integration. */ export const apolloIntegration = defineIntegration({ name: 'apollo', displayName: 'Apollo.io', diff --git a/packages/integrations/src/services/asana/index.ts b/packages/integrations/src/services/asana/index.ts index 3e1d24078..57c09484d 100644 --- a/packages/integrations/src/services/asana/index.ts +++ b/packages/integrations/src/services/asana/index.ts @@ -2,6 +2,7 @@ import { defineIntegration } from '../../contract' import { registerIntegration } from '../../registry' import { asanaActions } from './actions' +/** Descriptor for the Asana service integration. */ export const asanaIntegration = defineIntegration({ name: 'asana', displayName: 'Asana', diff --git a/packages/integrations/src/services/assemblyai/index.ts b/packages/integrations/src/services/assemblyai/index.ts index 7553d4c8d..c686840d9 100644 --- a/packages/integrations/src/services/assemblyai/index.ts +++ b/packages/integrations/src/services/assemblyai/index.ts @@ -2,6 +2,7 @@ import { defineIntegration } from '../../contract' import { registerIntegration } from '../../registry' import { assemblyaiActions } from './actions' +/** Descriptor for the AssemblyAI service integration. */ export const assemblyaiIntegration = defineIntegration({ name: 'assemblyai', displayName: 'AssemblyAI', diff --git a/packages/integrations/src/services/attio/index.ts b/packages/integrations/src/services/attio/index.ts index 15cb06256..aa54d85f1 100644 --- a/packages/integrations/src/services/attio/index.ts +++ b/packages/integrations/src/services/attio/index.ts @@ -2,6 +2,7 @@ import { defineIntegration } from '../../contract' import { registerIntegration } from '../../registry' import { attioActions } from './actions' +/** Descriptor for the Attio service integration. */ export const attioIntegration = defineIntegration({ name: 'attio', displayName: 'Attio', diff --git a/packages/integrations/src/services/azure-openai/index.ts b/packages/integrations/src/services/azure-openai/index.ts index 00a11935d..c7fc02c73 100644 --- a/packages/integrations/src/services/azure-openai/index.ts +++ b/packages/integrations/src/services/azure-openai/index.ts @@ -2,6 +2,7 @@ import { defineIntegration } from '../../contract' import { registerIntegration } from '../../registry' import { azureOpenaiActions } from './actions' +/** Descriptor for the Azure OpenAI service integration. */ export const azureOpenaiIntegration = defineIntegration({ name: 'azure-openai', displayName: 'Azure OpenAI', diff --git a/packages/integrations/src/services/baserow/index.ts b/packages/integrations/src/services/baserow/index.ts index d1e91ee83..269671ea5 100644 --- a/packages/integrations/src/services/baserow/index.ts +++ b/packages/integrations/src/services/baserow/index.ts @@ -2,6 +2,7 @@ import { defineIntegration } from '../../contract' import { registerIntegration } from '../../registry' import { baserowActions } from './actions' +/** Descriptor for the Baserow service integration. */ export const baserowIntegration = defineIntegration({ name: 'baserow', displayName: 'Baserow', diff --git a/packages/integrations/src/services/bigcommerce/index.ts b/packages/integrations/src/services/bigcommerce/index.ts index ad82dd46c..f536686e8 100644 --- a/packages/integrations/src/services/bigcommerce/index.ts +++ b/packages/integrations/src/services/bigcommerce/index.ts @@ -2,6 +2,7 @@ import { defineIntegration } from '../../contract' import { registerIntegration } from '../../registry' import { bigcommerceActions } from './actions' +/** Descriptor for the BigCommerce service integration. */ export const bigcommerceIntegration = defineIntegration({ name: 'bigcommerce', displayName: 'BigCommerce', diff --git a/packages/integrations/src/services/box/index.ts b/packages/integrations/src/services/box/index.ts index bf8db5c8b..20df04c90 100644 --- a/packages/integrations/src/services/box/index.ts +++ b/packages/integrations/src/services/box/index.ts @@ -2,6 +2,7 @@ import { defineIntegration } from '../../contract' import { registerIntegration } from '../../registry' import { boxActions } from './actions' +/** Descriptor for the Box service integration. */ export const boxIntegration = defineIntegration({ name: 'box', displayName: 'Box', diff --git a/packages/integrations/src/services/cal-com/index.ts b/packages/integrations/src/services/cal-com/index.ts index e3c08516b..43cb867a6 100644 --- a/packages/integrations/src/services/cal-com/index.ts +++ b/packages/integrations/src/services/cal-com/index.ts @@ -3,6 +3,7 @@ import { CONFIG_FIELDS } from '../../config-fields' import { registerIntegration } from '../../registry' import { calComActions } from './actions' +/** Descriptor for the Cal.com service integration. */ export const calComIntegration = defineIntegration({ name: 'cal-com', displayName: 'Cal.com', diff --git a/packages/integrations/src/services/calendly/index.ts b/packages/integrations/src/services/calendly/index.ts index a86fd8f1c..835f8d430 100644 --- a/packages/integrations/src/services/calendly/index.ts +++ b/packages/integrations/src/services/calendly/index.ts @@ -2,6 +2,7 @@ import { defineIntegration } from '../../contract' import { registerIntegration } from '../../registry' import { calendlyActions } from './actions' +/** Descriptor for the Calendly service integration. */ export const calendlyIntegration = defineIntegration({ name: 'calendly', displayName: 'Calendly', diff --git a/packages/integrations/src/services/coingecko/index.ts b/packages/integrations/src/services/coingecko/index.ts index 6e2bfea90..0b361a13c 100644 --- a/packages/integrations/src/services/coingecko/index.ts +++ b/packages/integrations/src/services/coingecko/index.ts @@ -2,6 +2,7 @@ import { defineIntegration } from '../../contract' import { registerIntegration } from '../../registry' import { coingeckoActions } from './actions' +/** Descriptor for the CoinGecko service integration. */ export const coingeckoIntegration = defineIntegration({ name: 'coingecko', displayName: 'CoinGecko', diff --git a/packages/integrations/src/services/confluence/index.ts b/packages/integrations/src/services/confluence/index.ts index ad2a02daa..054bb354f 100644 --- a/packages/integrations/src/services/confluence/index.ts +++ b/packages/integrations/src/services/confluence/index.ts @@ -4,6 +4,7 @@ import { registerIntegration } from '../../registry' import { OAUTH_SPECS } from '../../oauth-specs' import { confluenceActions } from './actions' +/** Descriptor for the Confluence service integration. */ export const confluenceIntegration = defineIntegration({ name: 'confluence', displayName: 'Confluence', diff --git a/packages/integrations/src/services/deepgram/index.ts b/packages/integrations/src/services/deepgram/index.ts index 892f58e90..751a783fc 100644 --- a/packages/integrations/src/services/deepgram/index.ts +++ b/packages/integrations/src/services/deepgram/index.ts @@ -3,6 +3,7 @@ import { CONFIG_FIELDS } from '../../config-fields' import { registerIntegration } from '../../registry' import { deepgramActions } from './actions' +/** Descriptor for the Deepgram service integration. */ export const deepgramIntegration = defineIntegration({ name: 'deepgram', displayName: 'Deepgram', diff --git a/packages/integrations/src/services/discord/index.ts b/packages/integrations/src/services/discord/index.ts index 70cb9c68a..9219bd07d 100644 --- a/packages/integrations/src/services/discord/index.ts +++ b/packages/integrations/src/services/discord/index.ts @@ -4,6 +4,7 @@ import { OAUTH_SPECS } from '../../oauth-specs' import { discordActions } from './actions' import { discordTriggers } from './triggers' +/** Descriptor for the Discord service integration. */ export const discordIntegration = defineIntegration({ name: 'discord', displayName: 'Discord', diff --git a/packages/integrations/src/services/dropbox/index.ts b/packages/integrations/src/services/dropbox/index.ts index a103a8a1d..ce14c3b02 100644 --- a/packages/integrations/src/services/dropbox/index.ts +++ b/packages/integrations/src/services/dropbox/index.ts @@ -3,6 +3,7 @@ import { registerIntegration } from '../../registry' import { OAUTH_SPECS } from '../../oauth-specs' import { dropboxActions } from './actions' +/** Descriptor for the Dropbox service integration. */ export const dropboxIntegration = defineIntegration({ name: 'dropbox', displayName: 'Dropbox', diff --git a/packages/integrations/src/services/elevenlabs/index.ts b/packages/integrations/src/services/elevenlabs/index.ts index f8fcf2b81..e5f95352c 100644 --- a/packages/integrations/src/services/elevenlabs/index.ts +++ b/packages/integrations/src/services/elevenlabs/index.ts @@ -3,6 +3,7 @@ import { CONFIG_FIELDS } from '../../config-fields' import { registerIntegration } from '../../registry' import { elevenlabsActions } from './actions' +/** Descriptor for the ElevenLabs service integration. */ export const elevenlabsIntegration = defineIntegration({ name: 'elevenlabs', displayName: 'ElevenLabs', diff --git a/packages/integrations/src/services/email/index.ts b/packages/integrations/src/services/email/index.ts index 1265838f2..ef767754e 100644 --- a/packages/integrations/src/services/email/index.ts +++ b/packages/integrations/src/services/email/index.ts @@ -3,6 +3,7 @@ import { CONFIG_FIELDS } from '../../config-fields' import { registerIntegration } from '../../registry' import { emailActions } from './actions' +/** Descriptor for the Email (SMTP/IMAP) service integration. */ export const emailIntegration = defineIntegration({ name: 'email', displayName: 'Email (SMTP/IMAP)', diff --git a/packages/integrations/src/services/email/types.ts b/packages/integrations/src/services/email/types.ts index 9e8d837a7..092bb723e 100644 --- a/packages/integrations/src/services/email/types.ts +++ b/packages/integrations/src/services/email/types.ts @@ -1,3 +1,4 @@ +/** File attachment accepted by the email transport. */ export interface EmailAttachment { filename: string /** UTF-8 text contents. Use `contentBase64` for binary. */ @@ -6,6 +7,7 @@ export interface EmailAttachment { contentType?: string } +/** Outbound message data passed to the email transport. */ export interface EmailSendMessage { from: string to: string | string[] @@ -17,16 +19,19 @@ export interface EmailSendMessage { attachments?: EmailAttachment[] } +/** Provider result returned after sending an email. */ export interface EmailSendResult { messageId: string accepted?: string[] rejected?: string[] } +/** Host-provided transport used by the email integration to send messages. */ export interface EmailTransport { send: (msg: EmailSendMessage) => Promise } +/** Email message returned by the IMAP client. */ export interface EmailMessage { id: string uid?: number @@ -40,6 +45,7 @@ export interface EmailMessage { attachments?: Array<{ filename: string; contentType: string; size: number }> } +/** Filters and result limit for an IMAP message fetch. */ export interface ImapFetchOptions { mailbox?: string unseenOnly?: boolean @@ -51,10 +57,12 @@ export interface ImapFetchOptions { limit?: number } +/** Host-provided client used to fetch messages from an IMAP mailbox. */ export interface ImapClient { fetch: (opts: ImapFetchOptions) => Promise } +/** Optional send and receive transports used by the email integration. */ export interface EmailConfig { transport?: EmailTransport imap?: ImapClient diff --git a/packages/integrations/src/services/figma/index.ts b/packages/integrations/src/services/figma/index.ts index 4333b510e..aef092e4b 100644 --- a/packages/integrations/src/services/figma/index.ts +++ b/packages/integrations/src/services/figma/index.ts @@ -2,6 +2,7 @@ import { defineIntegration } from '../../contract' import { registerIntegration } from '../../registry' import { figmaActions } from './actions' +/** Descriptor for the Figma service integration. */ export const figmaIntegration = defineIntegration({ name: 'figma', displayName: 'Figma', diff --git a/packages/integrations/src/services/firecrawl/index.ts b/packages/integrations/src/services/firecrawl/index.ts index 19e3c48a5..1a03dfbd2 100644 --- a/packages/integrations/src/services/firecrawl/index.ts +++ b/packages/integrations/src/services/firecrawl/index.ts @@ -2,6 +2,7 @@ import { defineIntegration } from '../../contract' import { registerIntegration } from '../../registry' import { firecrawlActions } from './actions' +/** Descriptor for the Firecrawl service integration. */ export const firecrawlIntegration = defineIntegration({ name: 'firecrawl', displayName: 'Firecrawl', diff --git a/packages/integrations/src/services/github-actions/index.ts b/packages/integrations/src/services/github-actions/index.ts index 94cabd24a..f215ca1b2 100644 --- a/packages/integrations/src/services/github-actions/index.ts +++ b/packages/integrations/src/services/github-actions/index.ts @@ -2,6 +2,7 @@ import { defineIntegration } from '../../contract' import { registerIntegration } from '../../registry' import { githubActionsActions } from './actions' +/** Descriptor for the GitHub Actions service integration. */ export const githubActionsIntegration = defineIntegration({ name: 'github-actions', displayName: 'GitHub Actions', diff --git a/packages/integrations/src/services/github/index.ts b/packages/integrations/src/services/github/index.ts index c61f30410..a4f7df3c9 100644 --- a/packages/integrations/src/services/github/index.ts +++ b/packages/integrations/src/services/github/index.ts @@ -4,6 +4,7 @@ import { OAUTH_SPECS } from '../../oauth-specs' import { githubActionsList } from './actions' import { githubTriggers } from './triggers' +/** Descriptor for the GitHub service integration. */ export const githubIntegration = defineIntegration({ name: 'github', displayName: 'GitHub', diff --git a/packages/integrations/src/services/gmail/index.ts b/packages/integrations/src/services/gmail/index.ts index 7ca490c32..a1fec7330 100644 --- a/packages/integrations/src/services/gmail/index.ts +++ b/packages/integrations/src/services/gmail/index.ts @@ -3,6 +3,7 @@ import { registerIntegration } from '../../registry' import { OAUTH_SPECS } from '../../oauth-specs' import { gmailActions } from './actions' +/** Descriptor for the Gmail service integration. */ export const gmailIntegration = defineIntegration({ name: 'gmail', displayName: 'Gmail', diff --git a/packages/integrations/src/services/google-calendar/index.ts b/packages/integrations/src/services/google-calendar/index.ts index 31910e086..e9d85edb9 100644 --- a/packages/integrations/src/services/google-calendar/index.ts +++ b/packages/integrations/src/services/google-calendar/index.ts @@ -3,6 +3,7 @@ import { registerIntegration } from '../../registry' import { OAUTH_SPECS } from '../../oauth-specs' import { googleCalendarActions } from './actions' +/** Descriptor for the Google Calendar service integration. */ export const googleCalendarIntegration = defineIntegration({ name: 'google-calendar', displayName: 'Google Calendar', diff --git a/packages/integrations/src/services/google-drive/index.ts b/packages/integrations/src/services/google-drive/index.ts index d5fe68811..9cd61e1c9 100644 --- a/packages/integrations/src/services/google-drive/index.ts +++ b/packages/integrations/src/services/google-drive/index.ts @@ -3,6 +3,7 @@ import { registerIntegration } from '../../registry' import { OAUTH_SPECS } from '../../oauth-specs' import { googleDriveActions } from './actions' +/** Descriptor for the Google Drive service integration. */ export const googleDriveIntegration = defineIntegration({ name: 'google-drive', displayName: 'Google Drive', diff --git a/packages/integrations/src/services/hubspot/index.ts b/packages/integrations/src/services/hubspot/index.ts index c8eb1e858..75146d963 100644 --- a/packages/integrations/src/services/hubspot/index.ts +++ b/packages/integrations/src/services/hubspot/index.ts @@ -2,6 +2,7 @@ import { defineIntegration } from '../../contract' import { registerIntegration } from '../../registry' import { hubspotActions } from './actions' +/** Descriptor for the HubSpot service integration. */ export const hubspotIntegration = defineIntegration({ name: 'hubspot', displayName: 'HubSpot', diff --git a/packages/integrations/src/services/intercom/index.ts b/packages/integrations/src/services/intercom/index.ts index 0bda63c3b..602c70cc7 100644 --- a/packages/integrations/src/services/intercom/index.ts +++ b/packages/integrations/src/services/intercom/index.ts @@ -2,6 +2,7 @@ import { defineIntegration } from '../../contract' import { registerIntegration } from '../../registry' import { intercomActions } from './actions' +/** Descriptor for the Intercom service integration. */ export const intercomIntegration = defineIntegration({ name: 'intercom', displayName: 'Intercom', diff --git a/packages/integrations/src/services/jira/index.ts b/packages/integrations/src/services/jira/index.ts index 27ae41289..1016f0221 100644 --- a/packages/integrations/src/services/jira/index.ts +++ b/packages/integrations/src/services/jira/index.ts @@ -4,6 +4,7 @@ import { registerIntegration } from '../../registry' import { OAUTH_SPECS } from '../../oauth-specs' import { jiraActions } from './actions' +/** Descriptor for the Jira service integration. */ export const jiraIntegration = defineIntegration({ name: 'jira', displayName: 'Jira', diff --git a/packages/integrations/src/services/linear-triage/index.ts b/packages/integrations/src/services/linear-triage/index.ts index e8b97c458..cc4ec7bd8 100644 --- a/packages/integrations/src/services/linear-triage/index.ts +++ b/packages/integrations/src/services/linear-triage/index.ts @@ -2,6 +2,7 @@ import { defineIntegration } from '../../contract' import { registerIntegration } from '../../registry' import { linearTriageActions } from './actions' +/** Descriptor for the Linear Triage service integration. */ export const linearTriageIntegration = defineIntegration({ name: 'linear-triage', displayName: 'Linear Triage', diff --git a/packages/integrations/src/services/linear/index.ts b/packages/integrations/src/services/linear/index.ts index 38fef61c5..945cd91e8 100644 --- a/packages/integrations/src/services/linear/index.ts +++ b/packages/integrations/src/services/linear/index.ts @@ -4,6 +4,7 @@ import { OAUTH_SPECS } from '../../oauth-specs' import { linearActions } from './actions' import { linearTriggers } from './triggers' +/** Descriptor for the Linear service integration. */ export const linearIntegration = defineIntegration({ name: 'linear', displayName: 'Linear', diff --git a/packages/integrations/src/services/mailchimp/index.ts b/packages/integrations/src/services/mailchimp/index.ts index 64c454dee..e81b76de0 100644 --- a/packages/integrations/src/services/mailchimp/index.ts +++ b/packages/integrations/src/services/mailchimp/index.ts @@ -3,6 +3,7 @@ import { CONFIG_FIELDS } from '../../config-fields' import { registerIntegration } from '../../registry' import { mailchimpActions } from './actions' +/** Descriptor for the Mailchimp service integration. */ export const mailchimpIntegration = defineIntegration({ name: 'mailchimp', displayName: 'Mailchimp', diff --git a/packages/integrations/src/services/maps/index.ts b/packages/integrations/src/services/maps/index.ts index 9091fa6ca..4dd489cbd 100644 --- a/packages/integrations/src/services/maps/index.ts +++ b/packages/integrations/src/services/maps/index.ts @@ -2,6 +2,7 @@ import { defineIntegration } from '../../contract' import { registerIntegration } from '../../registry' import { mapsActions } from './actions' +/** Descriptor for the Maps (OpenStreetMap / Nominatim) service integration. */ export const mapsIntegration = defineIntegration({ name: 'maps', displayName: 'Maps (OpenStreetMap / Nominatim)', diff --git a/packages/integrations/src/services/notion/index.ts b/packages/integrations/src/services/notion/index.ts index c5bb8132c..93b31fc41 100644 --- a/packages/integrations/src/services/notion/index.ts +++ b/packages/integrations/src/services/notion/index.ts @@ -3,6 +3,7 @@ import { registerIntegration } from '../../registry' import { OAUTH_SPECS } from '../../oauth-specs' import { notionActions } from './actions' +/** Descriptor for the Notion service integration. */ export const notionIntegration = defineIntegration({ name: 'notion', displayName: 'Notion', diff --git a/packages/integrations/src/services/openai-images/index.ts b/packages/integrations/src/services/openai-images/index.ts index dac0545d9..a8b9dd7ec 100644 --- a/packages/integrations/src/services/openai-images/index.ts +++ b/packages/integrations/src/services/openai-images/index.ts @@ -2,6 +2,7 @@ import { defineIntegration } from '../../contract' import { registerIntegration } from '../../registry' import { openaiImagesActions } from './actions' +/** Descriptor for the OpenAI Images service integration. */ export const openaiImagesIntegration = defineIntegration({ name: 'openai-images', displayName: 'OpenAI Images', diff --git a/packages/integrations/src/services/pagerduty/index.ts b/packages/integrations/src/services/pagerduty/index.ts index 8c495cc2f..a4e55ba7c 100644 --- a/packages/integrations/src/services/pagerduty/index.ts +++ b/packages/integrations/src/services/pagerduty/index.ts @@ -5,6 +5,7 @@ import { OAUTH_SPECS } from '../../oauth-specs' import { pagerdutyActions } from './actions' import { pagerdutyTriggers } from './triggers' +/** Descriptor for the PagerDuty service integration. */ export const pagerdutyIntegration = defineIntegration({ name: 'pagerduty', displayName: 'PagerDuty', diff --git a/packages/integrations/src/services/pipedrive/index.ts b/packages/integrations/src/services/pipedrive/index.ts index f38b2356e..b15746f1b 100644 --- a/packages/integrations/src/services/pipedrive/index.ts +++ b/packages/integrations/src/services/pipedrive/index.ts @@ -3,6 +3,7 @@ import { CONFIG_FIELDS } from '../../config-fields' import { registerIntegration } from '../../registry' import { pipedriveActions } from './actions' +/** Descriptor for the Pipedrive service integration. */ export const pipedriveIntegration = defineIntegration({ name: 'pipedrive', displayName: 'Pipedrive', diff --git a/packages/integrations/src/services/reader/index.ts b/packages/integrations/src/services/reader/index.ts index 3d02490ac..7699d20a0 100644 --- a/packages/integrations/src/services/reader/index.ts +++ b/packages/integrations/src/services/reader/index.ts @@ -2,6 +2,7 @@ import { defineIntegration } from '../../contract' import { registerIntegration } from '../../registry' import { readerActions } from './actions' +/** Descriptor for the Jina Reader service integration. */ export const readerIntegration = defineIntegration({ name: 'reader', displayName: 'Jina Reader', diff --git a/packages/integrations/src/services/salesforce/index.ts b/packages/integrations/src/services/salesforce/index.ts index 471b7f504..b52310124 100644 --- a/packages/integrations/src/services/salesforce/index.ts +++ b/packages/integrations/src/services/salesforce/index.ts @@ -3,6 +3,7 @@ import { registerIntegration } from '../../registry' import { OAUTH_SPECS } from '../../oauth-specs' import { salesforceActions } from './actions' +/** Descriptor for the Salesforce service integration. */ export const salesforceIntegration = defineIntegration({ name: 'salesforce', displayName: 'Salesforce', diff --git a/packages/integrations/src/services/sendgrid/index.ts b/packages/integrations/src/services/sendgrid/index.ts index 353017933..c1398ff18 100644 --- a/packages/integrations/src/services/sendgrid/index.ts +++ b/packages/integrations/src/services/sendgrid/index.ts @@ -2,6 +2,7 @@ import { defineIntegration } from '../../contract' import { registerIntegration } from '../../registry' import { sendgridActions } from './actions' +/** Descriptor for the SendGrid service integration. */ export const sendgridIntegration = defineIntegration({ name: 'sendgrid', displayName: 'SendGrid', diff --git a/packages/integrations/src/services/sentry/index.ts b/packages/integrations/src/services/sentry/index.ts index c82c9d39a..32720e7d5 100644 --- a/packages/integrations/src/services/sentry/index.ts +++ b/packages/integrations/src/services/sentry/index.ts @@ -4,6 +4,7 @@ import { OAUTH_SPECS } from '../../oauth-specs' import { sentryActions } from './actions' import { sentryTriggers } from './triggers' +/** Descriptor for the Sentry service integration. */ export const sentryIntegration = defineIntegration({ name: 'sentry', displayName: 'Sentry', diff --git a/packages/integrations/src/services/shopify/index.ts b/packages/integrations/src/services/shopify/index.ts index 371099b74..c46246376 100644 --- a/packages/integrations/src/services/shopify/index.ts +++ b/packages/integrations/src/services/shopify/index.ts @@ -2,6 +2,7 @@ import { defineIntegration } from '../../contract' import { registerIntegration } from '../../registry' import { shopifyActions } from './actions' +/** Descriptor for the Shopify service integration. */ export const shopifyIntegration = defineIntegration({ name: 'shopify', displayName: 'Shopify', diff --git a/packages/integrations/src/services/slack/index.ts b/packages/integrations/src/services/slack/index.ts index 5ff63ed93..f35d595ef 100644 --- a/packages/integrations/src/services/slack/index.ts +++ b/packages/integrations/src/services/slack/index.ts @@ -5,6 +5,7 @@ import { slackAuth } from './auth' import { slackActions } from './actions' import { slackTriggers } from './triggers' +/** Descriptor for the Slack service integration. */ export const slackIntegration = defineIntegration({ name: 'slack', displayName: 'Slack', diff --git a/packages/integrations/src/services/stripe/index.ts b/packages/integrations/src/services/stripe/index.ts index a308d8b50..8e10dafa6 100644 --- a/packages/integrations/src/services/stripe/index.ts +++ b/packages/integrations/src/services/stripe/index.ts @@ -5,6 +5,7 @@ import { OAUTH_SPECS } from '../../oauth-specs' import { stripeActions } from './actions' import { stripeWebhook } from './webhook' +/** Descriptor for the Stripe service integration. */ export const stripeIntegration = defineIntegration({ name: 'stripe', displayName: 'Stripe', diff --git a/packages/integrations/src/services/teams/cards.ts b/packages/integrations/src/services/teams/cards.ts index 6cc17e189..cbd59ab3e 100644 --- a/packages/integrations/src/services/teams/cards.ts +++ b/packages/integrations/src/services/teams/cards.ts @@ -1,3 +1,4 @@ +/** Button action rendered in a Teams Adaptive Card. */ export interface TeamsAdaptiveCardAction { type: 'Action.OpenUrl' | 'Action.Submit' title: string @@ -5,6 +6,7 @@ export interface TeamsAdaptiveCardAction { data?: Record } +/** Adaptive Card payload supported by the Teams integration. */ export interface TeamsAdaptiveCard { contentType: 'application/vnd.microsoft.card.adaptive' content: { @@ -16,6 +18,7 @@ export interface TeamsAdaptiveCard { } } +/** Legacy Teams connector message card payload. */ export interface TeamsMessageCard { contentType: 'application/vnd.microsoft.teams.card.o365connector' content: { @@ -71,6 +74,7 @@ export function messageCard(input: { } } +/** Message accepted by the host-provided Teams bot client. */ export interface TeamsBotMessage { conversationId: string serviceUrl?: string @@ -80,11 +84,13 @@ export interface TeamsBotMessage { signal?: AbortSignal } +/** Result returned after a Teams bot sends a message. */ export interface TeamsBotSendResult { id: string conversationId: string } +/** Host-provided client used by the Teams integration to send messages. */ export interface TeamsBotClient { send: (msg: TeamsBotMessage) => Promise } diff --git a/packages/integrations/src/services/teams/index.ts b/packages/integrations/src/services/teams/index.ts index e22b05243..872ded66a 100644 --- a/packages/integrations/src/services/teams/index.ts +++ b/packages/integrations/src/services/teams/index.ts @@ -3,6 +3,7 @@ import { CONFIG_FIELDS } from '../../config-fields' import { registerIntegration } from '../../registry' import { teamsActions } from './actions' +/** Descriptor for the Microsoft Teams service integration. */ export const teamsIntegration = defineIntegration({ name: 'teams', displayName: 'Microsoft Teams', diff --git a/packages/integrations/src/services/telegram/index.ts b/packages/integrations/src/services/telegram/index.ts index d97c00c11..db26f9bdc 100644 --- a/packages/integrations/src/services/telegram/index.ts +++ b/packages/integrations/src/services/telegram/index.ts @@ -4,6 +4,7 @@ import { registerIntegration } from '../../registry' import { telegramActions } from './actions' import { telegramTriggers } from './triggers' +/** Descriptor for the Telegram service integration. */ export const telegramIntegration = defineIntegration({ name: 'telegram', displayName: 'Telegram', diff --git a/packages/integrations/src/services/twilio/index.ts b/packages/integrations/src/services/twilio/index.ts index b3b4df72c..674208c82 100644 --- a/packages/integrations/src/services/twilio/index.ts +++ b/packages/integrations/src/services/twilio/index.ts @@ -4,6 +4,7 @@ import { registerIntegration } from '../../registry' import { twilioActions } from './actions' import { twilioTriggers } from './triggers' +/** Descriptor for the Twilio service integration. */ export const twilioIntegration = defineIntegration({ name: 'twilio', displayName: 'Twilio', diff --git a/packages/integrations/src/services/weather/index.ts b/packages/integrations/src/services/weather/index.ts index a5692d7b7..8916baa94 100644 --- a/packages/integrations/src/services/weather/index.ts +++ b/packages/integrations/src/services/weather/index.ts @@ -2,6 +2,7 @@ import { defineIntegration } from '../../contract' import { registerIntegration } from '../../registry' import { weatherActions } from './actions' +/** Descriptor for the Weather (OpenWeatherMap) service integration. */ export const weatherIntegration = defineIntegration({ name: 'weather', displayName: 'Weather (OpenWeatherMap)', diff --git a/packages/integrations/src/services/whatsapp/index.ts b/packages/integrations/src/services/whatsapp/index.ts index 1f232f333..b2977cf7b 100644 --- a/packages/integrations/src/services/whatsapp/index.ts +++ b/packages/integrations/src/services/whatsapp/index.ts @@ -4,6 +4,7 @@ import { registerIntegration } from '../../registry' import { whatsappActions } from './actions' import { whatsappTriggers } from './triggers' +/** Descriptor for the WhatsApp Cloud API service integration. */ export const whatsappIntegration = defineIntegration({ name: 'whatsapp', displayName: 'WhatsApp Cloud API', diff --git a/packages/integrations/src/services/whisper/index.ts b/packages/integrations/src/services/whisper/index.ts index 7c750616a..7ed6657e7 100644 --- a/packages/integrations/src/services/whisper/index.ts +++ b/packages/integrations/src/services/whisper/index.ts @@ -3,6 +3,7 @@ import { CONFIG_FIELDS } from '../../config-fields' import { registerIntegration } from '../../registry' import { whisperActions } from './actions' +/** Descriptor for the OpenAI Whisper service integration. */ export const whisperIntegration = defineIntegration({ name: 'whisper', displayName: 'OpenAI Whisper', diff --git a/packages/integrations/src/testing/validate.ts b/packages/integrations/src/testing/validate.ts index 1558bbeb4..34b33f5ba 100644 --- a/packages/integrations/src/testing/validate.ts +++ b/packages/integrations/src/testing/validate.ts @@ -21,6 +21,11 @@ function isObjectSchema(schema: JSONSchema7 | undefined): boolean { return !!schema && schema.type === 'object' } +/** Checks an action descriptor and returns every shape problem found. + * @param action Action descriptor to inspect. + * @param path Dotted path used as the problem location prefix. + * @returns Problems found, or an empty array when the action is valid. + */ export function validateAction(action: IntegrationAction, path: string): ValidationProblem[] { const problems: ValidationProblem[] = [] if (!ACTION_NAME_RE.test(action.name)) { @@ -38,6 +43,11 @@ export function validateAction(action: IntegrationAction, path: string): Validat return problems } +/** Checks a trigger descriptor and returns every shape problem found. + * @param trigger Trigger descriptor to inspect. + * @param path Dotted path used as the problem location prefix. + * @returns Problems found, or an empty array when the trigger is valid. + */ export function validateTrigger(trigger: IntegrationTrigger, path: string): ValidationProblem[] { const problems: ValidationProblem[] = [] if (!trigger.name?.trim()) { diff --git a/packages/memory/src/encrypted.ts b/packages/memory/src/encrypted.ts index cc63dcc78..ae4fcde48 100644 --- a/packages/memory/src/encrypted.ts +++ b/packages/memory/src/encrypted.ts @@ -15,6 +15,7 @@ type MemoryOperationOptions = Parameters[0] * during onboarding and stored only on their device. */ +/** Backing memory, encryption key, and optional Web Crypto adapters. */ export interface EncryptedMemoryOptions { backing: ChatMemory /** 32-byte raw key (e.g. `crypto.getRandomValues(new Uint8Array(32))`). */ @@ -27,6 +28,7 @@ export interface EncryptedMemoryOptions { aad?: Uint8Array } +/** Base64 ciphertext, initialization vector, and content-length marker. */ export interface EncryptedEnvelope { ciphertext: string iv: string @@ -65,6 +67,17 @@ async function resolveKey( return subtle.importKey('raw', raw as BufferSource, { name: 'AES-GCM' }, false, ['encrypt', 'decrypt']) } +/** Wraps chat memory with AES-GCM encryption using caller-owned key material. + * @param options Backing memory, key, and optional Web Crypto settings. + * @returns A chat memory that encrypts saved content and decrypts loaded content. + * @throws {ConfigError} When the key is invalid. + * @throws {MemoryError} When Web Crypto is unavailable. + * @example + * ```ts + * const key = crypto.getRandomValues(new Uint8Array(32)) + * const memory = await createEncryptedMemory({ backing, key }) + * ``` + */ export async function createEncryptedMemory( options: EncryptedMemoryOptions, ): Promise { diff --git a/packages/memory/src/file-vector.ts b/packages/memory/src/file-vector.ts index 66031c7a3..dd144cbf8 100644 --- a/packages/memory/src/file-vector.ts +++ b/packages/memory/src/file-vector.ts @@ -3,6 +3,7 @@ import type { VectorMemory, VectorDocument, RetrievedDocument } from '@agentskit import type { VectorStore } from './vector-store' import { matchesFilter } from './vector/filter' +/** On-disk path and optional vector-store adapter for file vector memory. */ export interface FileVectorMemoryConfig { path: string store?: VectorStore @@ -90,6 +91,16 @@ function createVectraStore(dirPath: string): VectorStore { } } +/** Creates a persistent vector memory backed by a local Vectra index. + * @param config Index path and optional vector-store adapter. + * @returns A vector memory that stores and searches local embeddings. + * @throws {MemoryError} When the optional `vectra` dependency is unavailable. + * @example + * ```ts + * const memory = fileVectorMemory({ path: './vectors' }) + * await memory.store([{ id: 'guide', content: 'Guide text', embedding }]) + * ``` + */ export function fileVectorMemory(config: FileVectorMemoryConfig): VectorMemory { const store = config.store ?? createVectraStore(config.path) const contentCache = new Map() diff --git a/packages/memory/src/forget.ts b/packages/memory/src/forget.ts index cc0db550a..d65351b7d 100644 --- a/packages/memory/src/forget.ts +++ b/packages/memory/src/forget.ts @@ -26,6 +26,7 @@ export interface ForgettableMemory { forgetSubject: (subjectId: string) => Promise } +/** Per-backend result returned by subject-data deletion. */ export interface ForgetReport { backend: string deletedCount: number @@ -35,6 +36,7 @@ export interface ForgetReport { failures?: Array<{ id: string; reason: string }> } +/** Aggregate outcome of deleting a subject from multiple memory backends. */ export interface ForgetSubjectResult { subjectId: string reports: ForgetReport[] @@ -67,6 +69,9 @@ async function hash(input: string): Promise { * Walk every memory passed in and run `forgetSubject(subjectId)` on * any that implement it. Missing capabilities are reported so callers * cannot mistake a partial deletion for a complete one. + * @param memories Memory instances to inspect for deletion capability. + * @param subjectId Subject identifier to delete. + * @returns Per-backend reports and an `incomplete` flag for skipped or failed backends. */ export async function forgetSubject( memories: Array, @@ -100,6 +105,9 @@ export async function forgetSubject( /** * Helper for backends that key records by `metadata.subjectId`. Wraps * any `delete(ids)`-style API into a `ForgettableMemory`. + * @param memory Object to extend with the deletion capability. + * @param options Backend label and functions for listing and deleting matching ids. + * @returns The same object with `ForgettableMemory` methods and metadata. */ export function makeForgettable( memory: M, diff --git a/packages/memory/src/graph.ts b/packages/memory/src/graph.ts index d5f2f6217..4c7722a5b 100644 --- a/packages/memory/src/graph.ts +++ b/packages/memory/src/graph.ts @@ -16,6 +16,7 @@ export interface GraphNode> { updatedAt?: string } +/** Directed relationship between two graph nodes. */ export interface GraphEdge> { id: string /** Verb / relation type — 'knows', 'works-at', 'cites'. */ @@ -27,6 +28,7 @@ export interface GraphEdge> { properties?: TProps } +/** Optional node or edge fields used to filter graph lookups. */ export interface GraphQuery { kind?: string label?: string @@ -34,6 +36,7 @@ export interface GraphQuery { to?: string } +/** Knowledge-graph operations accepted by graph memory consumers. */ export interface GraphMemory { upsertNode: (node: GraphNode) => Promise> upsertEdge: (edge: GraphEdge) => Promise> diff --git a/packages/memory/src/hierarchical.ts b/packages/memory/src/hierarchical.ts index 1b2bafe9f..f297cbe3b 100644 --- a/packages/memory/src/hierarchical.ts +++ b/packages/memory/src/hierarchical.ts @@ -3,6 +3,7 @@ import type { ChatMemory, Message } from '@agentskit/core' type MemoryOperationOptions = Parameters[0] +/** Search and indexing operations for the recall tier of hierarchical memory. */ export interface HierarchicalRecall { /** * Index a message for later retrieval. Called once per message as @@ -20,6 +21,7 @@ export interface HierarchicalRecall { clear?: () => void | Promise } +/** Working, recall, and archival stores used by hierarchical memory. */ export interface HierarchicalMemoryOptions { /** Hot window — the messages always loaded in full. */ working: ChatMemory @@ -42,6 +44,7 @@ export interface HierarchicalMemoryOptions { recallTopK?: number } +/** Tiered chat memory with accessors for archival history and the working window. */ export interface HierarchicalMemory extends ChatMemory { /** Full archival history. Always the source of truth. */ archival: () => Promise @@ -67,6 +70,8 @@ function mergeChronological(a: Message[], b: Message[]): Message[] { * * On every `load`, the hub returns working + up to `recallTopK` * messages surfaced by the recall tier, spliced chronologically. + * @param options Working and archival memories plus optional recall settings. + * @returns A chat memory that keeps an archival history and bounded working window. */ export function createHierarchicalMemory( options: HierarchicalMemoryOptions, diff --git a/packages/memory/src/kv-store-basic.ts b/packages/memory/src/kv-store-basic.ts index 6027c5723..c4c82f082 100644 --- a/packages/memory/src/kv-store-basic.ts +++ b/packages/memory/src/kv-store-basic.ts @@ -27,6 +27,11 @@ const enqueueFileWrite = (path: string, task: () => Promise): Promise { validateKvRetention(config) const store = new Map() @@ -49,6 +54,10 @@ export const createInMemoryStore = (config: InMemoryKvConfig): AgentskitMemorySt } } +/** Creates a JSON file key-value store with atomic file replacement. + * @param config File path and optional retention settings. + * @returns A persistent key-value store backed by the configured file. + */ export const createFileStore = (config: FileKvConfig): AgentskitMemoryStore => { const path = config.path @@ -103,6 +112,7 @@ export const createFileStore = (config: FileKvConfig): AgentskitMemoryStore => { } } +/** Options for creating a browser local-storage or file fallback store. */ export interface CreateLocalStorageStoreOpts { readonly config: LocalStorageKvConfig readonly storage?: LocalStorageLike @@ -116,6 +126,11 @@ const resolveLocalStorage = (): LocalStorageLike | undefined => { const defaultLocalStoragePath = (): string => `${process.cwd()}/.agentskit/memory-localstorage.json` +/** Creates a local-storage store, falling back to a JSON file when unavailable. + * @param options Storage configuration and optional storage/file adapters. + * @returns A key-value store backed by Web Storage or the configured file. + * @throws {ConfigError} When retention limits are invalid. + */ export const createLocalStorageStore = ({ config, storage = resolveLocalStorage(), diff --git a/packages/memory/src/kv-store-factory.ts b/packages/memory/src/kv-store-factory.ts index ec03047d0..f8a2bb27c 100644 --- a/packages/memory/src/kv-store-factory.ts +++ b/packages/memory/src/kv-store-factory.ts @@ -17,6 +17,7 @@ import type { SqliteOpener, } from './kv-store-types' +/** Error raised when a requested key-value memory backend is not implemented. */ export class MemoryBackendNotImplementedError extends Error { readonly code = 'MEMORY_BACKEND_NOT_IMPLEMENTED' readonly backend: KvMemoryConfig['backend'] @@ -29,8 +30,10 @@ export class MemoryBackendNotImplementedError extends Error { } } +/** Availability status reported for a key-value memory backend. */ export type MemoryBackendStatus = 'supported' | 'planned' +/** Current support status for each key-value memory backend. */ export const MEMORY_BACKEND_SUPPORT: Readonly> = { 'in-memory': 'supported', file: 'supported', @@ -40,9 +43,14 @@ export const MEMORY_BACKEND_SUPPORT: Readonly MEMORY_BACKEND_SUPPORT[backend] === 'supported' +/** Options and injected drivers for creating a configured KV memory store. */ export interface CreateKvMemoryFromConfigOpts { readonly config: KvMemoryConfig readonly sqlite?: SqliteOpener @@ -52,6 +60,16 @@ export interface CreateKvMemoryFromConfigOpts { readonly embedder?: MemoryEmbedderLike } +/** Creates a KV store for the selected backend using supplied dependencies. + * @param options Backend config and optional database, cache, vector, and embedding adapters. + * @returns A store implementing asynchronous `get` and `set`. + * @throws {MemoryError} When a selected external backend lacks a required adapter. + * @example + * ```ts + * const store = createKvMemoryFromConfig({ config: { backend: 'in-memory' } }) + * await store.set('job:42', { status: 'ready' }) + * ``` + */ export const createKvMemoryFromConfig = ({ config, sqlite, @@ -109,6 +127,11 @@ export const createKvMemoryFromConfig = ({ throw new MemoryBackendNotImplementedError((exhausted as { backend: KvMemoryConfig['backend'] }).backend) } +/** Creates a KV store and lazy-loads the optional SQLite or Redis driver. + * @param config Backend discriminator and settings. + * @returns A store implementing asynchronous `get` and `set`. + * @throws {MemoryError} When an optional driver is missing or vector adapters are not injected. + */ export const createKvMemoryFromConfigAuto = async (config: KvMemoryConfig): Promise => { if (config.backend === 'sqlite') { const sqlite = await tryDefaultSqliteOpener() diff --git a/packages/memory/src/kv-store-redis.ts b/packages/memory/src/kv-store-redis.ts index 783008daa..1f7b611c3 100644 --- a/packages/memory/src/kv-store-redis.ts +++ b/packages/memory/src/kv-store-redis.ts @@ -8,11 +8,18 @@ interface RedisEnvelope { readonly insertedAt: number } +/** Redis store settings and injected Redis client. */ export interface CreateRedisStoreOpts { readonly config: RedisKvConfig readonly client: RedisLike } +/** Creates a Redis key-value store using the supplied client. + * @param options Redis configuration and client. + * @returns A key-value store backed by the configured Redis prefix. + * @throws {ConfigError} When retention limits are invalid. + * @throws {MemoryError} When Redis commands fail. + */ export const createRedisStore = ({ config, client }: CreateRedisStoreOpts): AgentskitMemoryStore => { validateKvRetention(config) const prefix = config.prefix @@ -70,7 +77,10 @@ export const createRedisStore = ({ config, client }: CreateRedisStoreOpts): Agen } } -/** Bridge an `ioredis`-style client to the {@link RedisLike} options-object shape. */ +/** Bridges an ioredis-style client to the {@link RedisLike} options-object shape. + * @param io Client with positional Redis command options. + * @returns A client using the memory package's Redis contract. + */ export const adaptIoredis = (io: { get(key: string): Promise set(key: string, value: string, mode?: string, ttl?: number): Promise @@ -84,7 +94,11 @@ export const adaptIoredis = (io: { keys: (pattern) => io.keys(pattern), }) -/** Lazy-import `redis` (node-redis v4), connect, and return a client; `undefined` if absent. */ +/** Loads and connects node-redis, returning `undefined` when it is unavailable. + * @param url Redis connection URL. + * @returns A connected client, or `undefined` when the optional package is absent. + * @throws {MemoryError} When the client cannot connect. + */ export const tryDefaultRedisClient = async (url: string): Promise => { try { const moduleId = 'redis' diff --git a/packages/memory/src/kv-store-sqlite.ts b/packages/memory/src/kv-store-sqlite.ts index 647bdd5f7..19ec4eef7 100644 --- a/packages/memory/src/kv-store-sqlite.ts +++ b/packages/memory/src/kv-store-sqlite.ts @@ -9,11 +9,16 @@ import { validateKvRetention, } from './kv-store-types' +/** SQLite store settings and injected database opener. */ export interface CreateSqliteStoreOpts { readonly config: SqliteKvConfig readonly open: SqliteOpener } +/** Creates a SQLite key-value store using the supplied database opener. + * @param options SQLite configuration and opener. + * @returns A key-value store backed by the configured database. + */ export const createSqliteStore = ({ config, open }: CreateSqliteStoreOpts): AgentskitMemoryStore => { validateKvRetention(config) const db = open(config.path) @@ -67,6 +72,7 @@ export const createSqliteStore = ({ config, open }: CreateSqliteStoreOpts): Agen /** * Lazy-import `better-sqlite3` and return an opener, or `undefined` when the * optional peer dep is absent (caller surfaces AK_MEMORY_PEER_MISSING). + * @returns An opener, or `undefined` when `better-sqlite3` is unavailable. */ export const tryDefaultSqliteOpener = async (): Promise => { try { diff --git a/packages/memory/src/kv-store-types.ts b/packages/memory/src/kv-store-types.ts index 15c42f6b2..b3e3fb8df 100644 --- a/packages/memory/src/kv-store-types.ts +++ b/packages/memory/src/kv-store-types.ts @@ -13,6 +13,7 @@ export interface AgentskitMemoryStore { set(key: string, value: unknown): Promise } +/** Stored value and insertion timestamp used by the KV backends. */ export interface KvEntry { readonly value: unknown readonly insertedAt: number @@ -52,32 +53,39 @@ interface CommonKvConfig { readonly ttlSeconds?: number } +/** Configuration for the in-memory key-value backend. */ export interface InMemoryKvConfig extends CommonKvConfig { readonly backend: 'in-memory' } +/** Configuration for the JSON file key-value backend. */ export interface FileKvConfig extends CommonKvConfig { readonly backend: 'file' readonly path: string } +/** Configuration for the SQLite key-value backend. */ export interface SqliteKvConfig extends CommonKvConfig { readonly backend: 'sqlite' readonly path: string } +/** Configuration for the Redis key-value backend. */ export interface RedisKvConfig extends CommonKvConfig { readonly backend: 'redis' readonly url: string readonly prefix: string } +/** Configuration for the vector-backed key-value backend. */ export interface VectorKvConfig extends CommonKvConfig { readonly backend: 'vector' readonly provider: string readonly collection: string } +/** Configuration for the browser local-storage key-value backend. */ export interface LocalStorageKvConfig extends CommonKvConfig { readonly backend: 'localstorage' readonly key: string } +/** Discriminated configuration accepted by the KV memory factories. */ export type KvMemoryConfig = | InMemoryKvConfig | FileKvConfig @@ -88,6 +96,7 @@ export type KvMemoryConfig = // --- Injected-dependency contracts (so the store stays driver-agnostic) --- +/** Minimal Redis client operations required by the memory backends. */ export interface RedisLike { get(key: string): Promise set(key: string, value: string, options?: { readonly EX?: number }): Promise @@ -95,19 +104,23 @@ export interface RedisLike { keys(pattern: string): Promise } +/** Minimal prepared-statement operations used by SQLite memory stores. */ export interface SqliteStmt { run(...params: unknown[]): void get(...params: unknown[]): unknown all(...params: unknown[]): unknown[] } +/** Minimal SQLite database operations required by memory stores. */ export interface SqliteLike { exec(sql: string): void prepare(sql: string): SqliteStmt } +/** Opens a SQLite database at the given path. */ export type SqliteOpener = (path: string) => SqliteLike +/** Minimal vector store operations required by vector-backed KV memory. */ export interface MemoryVectorStoreLike { upsert( rows: readonly { @@ -123,10 +136,12 @@ export interface MemoryVectorStoreLike { ): Promise }[]> } +/** Embedder contract used by vector-backed KV memory. */ export interface MemoryEmbedderLike { embed(texts: readonly string[]): Promise } +/** Minimal Web Storage methods required by the local-storage backend. */ export interface LocalStorageLike { getItem(key: string): string | null setItem(key: string, value: string): void diff --git a/packages/memory/src/kv-store-vector.ts b/packages/memory/src/kv-store-vector.ts index df7c1e53e..6ea9666de 100644 --- a/packages/memory/src/kv-store-vector.ts +++ b/packages/memory/src/kv-store-vector.ts @@ -11,12 +11,18 @@ import { validateKvRetention, } from './kv-store-types' +/** Dependencies for creating a vector-backed key-value store. */ export interface CreateVectorStoreOpts { readonly config: VectorKvConfig readonly vectorStore: MemoryVectorStoreLike readonly embedder: MemoryEmbedderLike } +/** Creates a key-value store that embeds keys and stores values in a vector store. + * @param options Vector config, store, and embedder. + * @returns A key-value store with a similarity-based `recall` method. + * @throws {MemoryError} When the embedder returns no vector. + */ export const createVectorStore = ({ config, vectorStore, diff --git a/packages/memory/src/personalization.ts b/packages/memory/src/personalization.ts index fc7319ffd..f4803e5a9 100644 --- a/packages/memory/src/personalization.ts +++ b/packages/memory/src/personalization.ts @@ -13,6 +13,7 @@ export interface PersonalizationProfile { updatedAt: string } +/** Persistence contract for retrieving, replacing, merging, and deleting profiles. */ export interface PersonalizationStore { get: (subjectId: string) => Promise set: (profile: PersonalizationProfile) => Promise diff --git a/packages/memory/src/redaction.ts b/packages/memory/src/redaction.ts index eca45284e..4296f8c04 100644 --- a/packages/memory/src/redaction.ts +++ b/packages/memory/src/redaction.ts @@ -32,6 +32,7 @@ type MemoryOperationOptions = Parameters[0] export type RedactionMode = 'redact' | 'tokenize' +/** Rules, mode, and token vault settings for chat-memory redaction. */ export interface ChatMemoryRedactionOptions { /** * Rules to apply. Pass `DEFAULT_PII_RULES` for the baseline set, @@ -48,6 +49,7 @@ export interface ChatMemoryRedactionOptions { audit?: RedactionAuditSink } +/** Redaction and tokenization settings for vector document content. */ export interface VectorMemoryRedactionOptions extends ChatMemoryRedactionOptions {} async function transform( @@ -78,6 +80,12 @@ async function transform( return createPIIRedactor({ rules: opts.rules }).redact(input).value } +/** Wraps chat memory to redact or tokenize message content before saves. + * @param inner Chat memory implementation to wrap. + * @param options Redaction rules and optional tokenization settings. + * @returns A chat memory wrapper that redacts saved message content. + * @throws {ConfigError} When tokenization lacks a vault or allowed roles. + */ export function wrapChatMemoryWithRedaction( inner: ChatMemory, options: ChatMemoryRedactionOptions, diff --git a/packages/memory/src/redis-chat.ts b/packages/memory/src/redis-chat.ts index 59cbe727d..2359ee915 100644 --- a/packages/memory/src/redis-chat.ts +++ b/packages/memory/src/redis-chat.ts @@ -9,6 +9,7 @@ import { createRedisClientAdapter } from './redis-client' type MemoryOperationOptions = Parameters[0] +/** Redis connection and key-prefix settings for chat memory. */ export interface RedisChatMemoryConfig extends RedisConnectionConfig { keyPrefix?: string conversationId?: string @@ -23,6 +24,11 @@ function decodeMessages(json: string | null): Message[] { return decodeStoredMessages(json, 'redisChatMemory') } +/** Creates a chat memory that stores conversation snapshots in Redis. + * @param config Redis URL or client and optional namespace settings. + * @returns A chat memory backed by Redis. + * @throws {MemoryError} When the optional Redis dependency is missing or cannot connect. + */ export function redisChatMemory(config: RedisChatMemoryConfig): ChatMemory { const prefix = config.keyPrefix ?? 'agentskit:chat' const convId = config.conversationId ?? 'default' diff --git a/packages/memory/src/redis-client.ts b/packages/memory/src/redis-client.ts index 16e17ea83..1a4f24003 100644 --- a/packages/memory/src/redis-client.ts +++ b/packages/memory/src/redis-client.ts @@ -5,6 +5,7 @@ import { ErrorCodes, MemoryError } from '@agentskit/core' * Abstracts the underlying Redis library so it can be swapped * (e.g., from `redis` to `ioredis`) without changing consumers. */ +/** Redis client operations used by the chat and vector memory backends. */ export interface RedisClientAdapter { get(key: string): Promise set(key: string, value: string): Promise @@ -14,11 +15,17 @@ export interface RedisClientAdapter { call(command: string, ...args: (string | number | Buffer)[]): Promise } +/** Connection URL and optional injected Redis adapter. */ export interface RedisConnectionConfig { url: string client?: RedisClientAdapter } +/** Creates a node-redis adapter and connects it to the supplied URL. + * @param url Redis connection URL. + * @returns A connected Redis client adapter. + * @throws {MemoryError} When the optional Redis dependency is missing. + */ export async function createRedisClientAdapter(url: string): Promise { let redis: typeof import('redis') try { diff --git a/packages/memory/src/redis-vector.ts b/packages/memory/src/redis-vector.ts index f13b28bce..abf31b40c 100644 --- a/packages/memory/src/redis-vector.ts +++ b/packages/memory/src/redis-vector.ts @@ -2,6 +2,7 @@ import type { VectorMemory, VectorDocument, RetrievedDocument } from '@agentskit import type { RedisClientAdapter, RedisConnectionConfig } from './redis-client' import { createRedisClientAdapter } from './redis-client' +/** Redis connection and index settings for vector memory. */ export interface RedisVectorMemoryConfig extends RedisConnectionConfig { indexName?: string keyPrefix?: string @@ -16,6 +17,11 @@ function float32Buffer(vector: number[]): Buffer { return buffer } +/** Creates a vector memory backed by Redis vector search commands. + * @param config Redis URL or client and optional index settings. + * @returns A vector memory backed by the configured Redis index. + * @throws {MemoryError} When the optional Redis dependency is missing or cannot connect. + */ export function redisVectorMemory(config: RedisVectorMemoryConfig): VectorMemory { const indexName = config.indexName ?? 'agentskit:vectors:idx' const prefix = config.keyPrefix ?? 'agentskit:vec' diff --git a/packages/memory/src/sqlite.ts b/packages/memory/src/sqlite.ts index b0929ecbb..b3dce0fc3 100644 --- a/packages/memory/src/sqlite.ts +++ b/packages/memory/src/sqlite.ts @@ -11,6 +11,7 @@ import { decodeStoredMessages } from './decode' type MemoryOperationOptions = Parameters[0] +/** Database path and optional SQLite opener for chat memory. */ export interface SqliteChatMemoryConfig { path: string conversationId?: string @@ -46,6 +47,11 @@ async function openDatabase(path: string): Promise { } } +/** Creates a chat memory that stores conversation snapshots in SQLite. + * @param config Database path and optional opener. + * @returns A chat memory backed by the configured database. + * @throws {MemoryError} When the optional SQLite dependency is missing or cannot open the database. + */ export function sqliteChatMemory(config: SqliteChatMemoryConfig): ChatMemory { const conversationId = config.conversationId ?? 'default' let dbPromise: Promise | null = null diff --git a/packages/memory/src/turso.ts b/packages/memory/src/turso.ts index 2509b6f8d..c7aa39931 100644 --- a/packages/memory/src/turso.ts +++ b/packages/memory/src/turso.ts @@ -11,6 +11,7 @@ import { decodeStoredMessages } from './decode' type MemoryOperationOptions = Parameters[0] +/** Turso URL, auth token, and optional database client settings. */ export interface TursoChatMemoryConfig { /** libSQL URL — file:..., libsql://..., or http://... */ url: string diff --git a/packages/memory/src/vector-store.ts b/packages/memory/src/vector-store.ts index 99780ca06..9e7303e6f 100644 --- a/packages/memory/src/vector-store.ts +++ b/packages/memory/src/vector-store.ts @@ -1,15 +1,18 @@ +/** Vector and metadata fields stored by a backend-neutral vector store. */ export interface VectorStoreDocument { id: string vector: number[] metadata: Record } +/** Search result returned by a backend-neutral vector store. */ export interface VectorStoreResult { id: string score: number metadata: Record } +/** Backend-neutral upsert, query, and delete contract for vector data. */ export interface VectorStore { upsert(docs: VectorStoreDocument[]): Promise query(vector: number[], topK: number): Promise diff --git a/packages/memory/src/vector/chroma.ts b/packages/memory/src/vector/chroma.ts index 9af75d366..28f69588c 100644 --- a/packages/memory/src/vector/chroma.ts +++ b/packages/memory/src/vector/chroma.ts @@ -2,6 +2,7 @@ import { ErrorCodes, MemoryError } from '@agentskit/core' import type { RetrievedDocument, VectorDocument, VectorMemory } from '@agentskit/core' import { remoteJson, type RemoteHttpConfig } from './http' +/** URL, optional API key, and collection settings for Chroma. */ export interface ChromaConfig extends RemoteHttpConfig { /** Base URL of a running Chroma HTTP server. */ url: string @@ -33,6 +34,10 @@ async function call( }) } +/** Creates a vector memory backed by Chroma's HTTP API. + * @param config Chroma URL, collection, credentials, and search defaults. + * @returns A vector memory backed by the configured collection. + */ export function chroma(config: ChromaConfig): VectorMemory { const defaultTopK = Math.max(1, config.topK ?? 10) let urlEnd = config.url.length diff --git a/packages/memory/src/vector/http.ts b/packages/memory/src/vector/http.ts index 340f8f455..8c612b34e 100644 --- a/packages/memory/src/vector/http.ts +++ b/packages/memory/src/vector/http.ts @@ -1,6 +1,7 @@ import { ErrorCodes, MemoryError } from '@agentskit/core' import { NetError, NetErrorCodes, readText } from '@agentskit/net' +/** Shared credentials, fetch, and timeout settings for HTTP vector stores. */ export interface RemoteHttpConfig { /** * Fetch implementation for remote vector calls. Defaults to `globalThis.fetch`. diff --git a/packages/memory/src/vector/milvus.ts b/packages/memory/src/vector/milvus.ts index 538865d3e..160030f73 100644 --- a/packages/memory/src/vector/milvus.ts +++ b/packages/memory/src/vector/milvus.ts @@ -2,6 +2,7 @@ import type { RetrievedDocument, VectorDocument, VectorMemory } from '@agentskit import { remoteJson, type RemoteHttpConfig } from './http' import { validateIdentifier } from './validation' +/** URL, collection, and credentials for a Milvus-compatible HTTP API. */ export interface MilvusConfig extends RemoteHttpConfig { /** Milvus REST endpoint, e.g. `https://in03-xxx.api.gcp-us-west1.zillizcloud.com`. */ url: string @@ -28,6 +29,10 @@ async function call( }) } +/** Creates a vector memory backed by the Milvus HTTP API. + * @param config Endpoint, collection, credentials, and search defaults. + * @returns A vector memory backed by the configured collection. + */ export function milvusVectorStore(config: MilvusConfig): VectorMemory { const collection = validateIdentifier(config.collection, 'collection') const defaultTopK = Math.max(1, config.topK ?? 10) diff --git a/packages/memory/src/vector/mongo-atlas.ts b/packages/memory/src/vector/mongo-atlas.ts index 16929ed1f..036aad6dd 100644 --- a/packages/memory/src/vector/mongo-atlas.ts +++ b/packages/memory/src/vector/mongo-atlas.ts @@ -16,6 +16,7 @@ export interface MongoCollectionLike { } } +/** Collection adapter and search settings for MongoDB Atlas vector memory. */ export interface MongoAtlasVectorConfig { collection: MongoCollectionLike /** Atlas Search index name on the embedding field. */ @@ -27,6 +28,10 @@ export interface MongoAtlasVectorConfig { topK?: number } +/** Creates a vector memory backed by a MongoDB Atlas collection. + * @param config Collection adapter, vector field, and search settings. + * @returns A vector memory backed by the configured collection. + */ export function mongoAtlasVectorStore(config: MongoAtlasVectorConfig): VectorMemory { const defaultTopK = Math.max(1, config.topK ?? 10) const vectorField = config.vectorField ?? 'embedding' diff --git a/packages/memory/src/vector/pgvector.ts b/packages/memory/src/vector/pgvector.ts index fc545a6e6..24096b3b0 100644 --- a/packages/memory/src/vector/pgvector.ts +++ b/packages/memory/src/vector/pgvector.ts @@ -9,6 +9,7 @@ import { validateIdentifier } from './validation' * `metadata jsonb`. */ +/** Async SQL query adapter used by the pgvector backend. */ export interface PgVectorRunner { query: >( sql: string, @@ -16,6 +17,7 @@ export interface PgVectorRunner { ) => Promise<{ rows: T[] }> } +/** SQL runner, table, and search defaults for pgvector memory. */ export interface PgVectorConfig { runner: PgVectorRunner /** Table name. Default 'agentskit_vectors'. */ @@ -28,6 +30,10 @@ function formatVector(embedding: number[]): string { return `[${embedding.join(',')}]` } +/** Creates a vector memory backed by a PostgreSQL pgvector table. + * @param config SQL runner and optional table and result limit. + * @returns A vector memory that upserts and searches the configured table. + */ export function pgvector(config: PgVectorConfig): VectorMemory { const table = validateIdentifier(config.table ?? 'agentskit_vectors', 'table') const defaultTopK = Math.max(1, config.topK ?? 10) diff --git a/packages/memory/src/vector/pinecone.ts b/packages/memory/src/vector/pinecone.ts index 6d29e58af..6c9a96c4a 100644 --- a/packages/memory/src/vector/pinecone.ts +++ b/packages/memory/src/vector/pinecone.ts @@ -1,6 +1,7 @@ import type { RetrievedDocument, VectorDocument, VectorMemory } from '@agentskit/core' import { remoteJson, type RemoteHttpConfig } from './http' +/** Index URL, API key, namespace, and search settings for Pinecone. */ export interface PineconeConfig extends RemoteHttpConfig { /** Full index URL, e.g. `https://-.svc..pinecone.io`. */ indexUrl: string @@ -22,6 +23,10 @@ async function call(config: PineconeConfig, path: string, body: unknown): Pro }) } +/** Creates a vector memory backed by the Pinecone vector API. + * @param config Index endpoint, API key, and optional namespace and result limit. + * @returns A vector memory backed by the configured Pinecone index. + */ export function pinecone(config: PineconeConfig): VectorMemory { const defaultTopK = Math.max(1, config.topK ?? 10) const namespace = config.namespace ?? '' diff --git a/packages/memory/src/vector/qdrant.ts b/packages/memory/src/vector/qdrant.ts index 9253939f6..8cbfab6fb 100644 --- a/packages/memory/src/vector/qdrant.ts +++ b/packages/memory/src/vector/qdrant.ts @@ -2,6 +2,7 @@ import type { RetrievedDocument, VectorDocument, VectorMemory } from '@agentskit import { remoteJson, type RemoteHttpConfig } from './http' import { validateIdentifier } from './validation' +/** Endpoint, collection, credentials, and search defaults for Qdrant. */ export interface QdrantConfig extends RemoteHttpConfig { /** Base URL, e.g. `https://xxx.cluster-qdrant.io`. */ url: string @@ -46,6 +47,10 @@ async function call( }) } +/** Creates a vector memory backed by a Qdrant collection. + * @param config Qdrant endpoint, collection, and optional credentials and result limit. + * @returns A vector memory backed by the configured collection. + */ export function qdrant(config: QdrantConfig): VectorMemory { const collection = encodeURIComponent(validateIdentifier(config.collection, 'collection')) const defaultTopK = Math.max(1, config.topK ?? 10) diff --git a/packages/memory/src/vector/supabase.ts b/packages/memory/src/vector/supabase.ts index 8cdd8f2af..e1f4ebf5f 100644 --- a/packages/memory/src/vector/supabase.ts +++ b/packages/memory/src/vector/supabase.ts @@ -1,6 +1,7 @@ import { ErrorCodes, MemoryError } from '@agentskit/core' import type { RetrievedDocument, VectorMemory, VectorSearchOptions } from '@agentskit/core' +/** Supabase client and table settings for vector memory. */ export interface SupabaseVectorStoreConfig { /** Supabase project URL, e.g. `https://xyz.supabase.co`. */ url: string @@ -76,6 +77,10 @@ function throwOnError(result: SupabaseResult, operation: string): void * purpose-specific similarity-search RPC. The service-role key stays * server-side and `@supabase/supabase-js` is loaded lazily. */ +/** Creates a vector memory backed by a Supabase table and RPC search function. + * @param config Supabase client, table, and optional search settings. + * @returns A vector memory backed by the configured Supabase schema. + */ export function supabaseVectorStore(config: SupabaseVectorStoreConfig): VectorMemory { const table = config.table ?? 'agentskit_vectors' const matchFunction = config.matchFunction ?? 'match_agentskit_vectors' diff --git a/packages/memory/src/vector/upstash.ts b/packages/memory/src/vector/upstash.ts index 2f2333875..09ff9ee3b 100644 --- a/packages/memory/src/vector/upstash.ts +++ b/packages/memory/src/vector/upstash.ts @@ -1,6 +1,7 @@ import type { RetrievedDocument, VectorDocument, VectorMemory } from '@agentskit/core' import { remoteJson, type RemoteHttpConfig } from './http' +/** REST URL, token, and index settings for Upstash Vector. */ export interface UpstashVectorConfig extends RemoteHttpConfig { url: string token: string diff --git a/packages/memory/src/vector/weaviate.ts b/packages/memory/src/vector/weaviate.ts index 8fdcca231..b1ac0fe5b 100644 --- a/packages/memory/src/vector/weaviate.ts +++ b/packages/memory/src/vector/weaviate.ts @@ -2,6 +2,7 @@ import type { RetrievedDocument, VectorDocument, VectorMemory } from '@agentskit import { remoteJson, type RemoteHttpConfig } from './http' import { validateIdentifier } from './validation' +/** Endpoint, class, credentials, and search settings for Weaviate. */ export interface WeaviateConfig extends RemoteHttpConfig { /** Cluster URL, e.g. `https://my-cluster.weaviate.network`. */ url: string @@ -28,6 +29,10 @@ async function call( }) } +/** Creates a vector memory backed by a Weaviate class. + * @param config Weaviate endpoint, class, and optional credentials and result limit. + * @returns A vector memory backed by the configured class. + */ export function weaviateVectorStore(config: WeaviateConfig): VectorMemory { const defaultTopK = Math.max(1, config.topK ?? 10) const className = validateIdentifier(config.className, 'className') diff --git a/packages/memory/src/web-storage.ts b/packages/memory/src/web-storage.ts index facee0c6c..dc972d05f 100644 --- a/packages/memory/src/web-storage.ts +++ b/packages/memory/src/web-storage.ts @@ -2,17 +2,20 @@ import { deserializeMessages, ErrorCodes, MemoryError, serializeMessages } from import { validateMemoryRecord } from '@agentskit/core/memory-validation' import type { ChatMemory, Message } from '@agentskit/core' +/** Minimal Web Storage methods required by browser chat memory. */ export interface WebStorageLike { readonly getItem: (key: string) => string | null readonly setItem: (key: string, value: string) => void readonly removeItem: (key: string) => void } +/** Adapter for reading legacy records into canonical AgentsKit messages. */ export interface WebStorageMemoryMigration { readonly keys: readonly string[] readonly read: (value: unknown, key: string) => readonly Message[] | undefined } +/** Storage key, bounds, and optional migration settings for web memory. */ export interface WebStorageMemoryOptions { readonly key: string readonly getStorage: () => WebStorageLike | undefined @@ -71,6 +74,17 @@ const encodeRecord = (messages: readonly Message[], maxRecordBytes: number): str /** * Creates a validated, bounded ChatMemory over an injected browser Web Storage backend. * The storage getter is evaluated lazily so browser globals can remain SSR-safe. + * @param options Storage key, getter, retention limits, and optional migration. + * @returns A chat memory that validates and bounds records in Web Storage. + * @throws {TypeError} When the key or a configured limit is invalid. + * @throws {MemoryError} When a saved message record is invalid or exceeds its byte limit. + * @example + * ```ts + * const memory = createWebStorageMemory({ + * key: 'agentskit-chat', + * getStorage: () => globalThis.localStorage, + * }) + * ``` */ export function createWebStorageMemory({ key, diff --git a/packages/observability-langfuse/src/langfuse-types.ts b/packages/observability-langfuse/src/langfuse-types.ts index 417790fc5..31d77f382 100644 --- a/packages/observability-langfuse/src/langfuse-types.ts +++ b/packages/observability-langfuse/src/langfuse-types.ts @@ -1,5 +1,6 @@ import type { Observer } from '@agentskit/core' +/** Credentials, trace metadata, batching, and error settings for Langfuse. */ export interface LangfuseConfig { publicKey?: string secretKey?: string @@ -17,6 +18,7 @@ export interface LangfuseConfig { onError?: (error: unknown) => void | Promise } +/** Langfuse observer with explicit flush and shutdown methods. */ export interface LangfuseObserver extends Observer { flush: () => Promise shutdown: () => Promise diff --git a/packages/observability-langfuse/src/langfuse.ts b/packages/observability-langfuse/src/langfuse.ts index 458f9dc16..e6faae875 100644 --- a/packages/observability-langfuse/src/langfuse.ts +++ b/packages/observability-langfuse/src/langfuse.ts @@ -19,8 +19,14 @@ import type { export type { LangfuseConfig, LangfuseObserver } from './langfuse-types' /** - * Langfuse observer factory. Construction is pure (no SDK import / I/O). - * One Langfuse trace per agent run, inferred only by `agent:step` with step 1. + * Create a lazy-loading observer that maps each agent run to a Langfuse trace. + * Construction does not import the SDK or perform I/O; a run boundary is inferred from `agent:step` 1. + * @param config Optional Langfuse credentials, metadata, batching, and error callback. + * @returns An observer with `flush` and idempotent `shutdown` methods. + * @example + * ```ts + * const observer = langfuse({ publicKey: 'pk-lf-...', secretKey: 'sk-lf-...' }) + * ``` */ export function langfuse(config: LangfuseConfig = {}): LangfuseObserver { validateConfig(config) diff --git a/packages/observability/src/audit-log.ts b/packages/observability/src/audit-log.ts index 93c1a6438..c34bbed6e 100644 --- a/packages/observability/src/audit-log.ts +++ b/packages/observability/src/audit-log.ts @@ -1,6 +1,7 @@ import { createHash, createHmac } from 'node:crypto' import type { PIIRedactionHit } from '@agentskit/core/security' +/** Signed, sequence-numbered audit record linked to its predecessor. */ export interface AuditEntry { /** Monotonic sequence within a log. Starts at 1. */ seq: number @@ -14,6 +15,7 @@ export interface AuditEntry { signature: string } +/** Append-only storage operations required by the signed audit log. */ export interface AuditLogStore { append: (entry: AuditEntry) => Promise list: () => Promise @@ -21,6 +23,7 @@ export interface AuditLogStore { clear?: () => Promise } +/** Secret, storage, and clock settings for a signed audit log. */ export interface AuditLogOptions { /** HMAC secret — rotate out-of-band. */ secret: string @@ -29,12 +32,14 @@ export interface AuditLogOptions { now?: () => Date } +/** Caller-supplied values for one audit record. */ export interface AppendAuditInput { actor: string action: string payload: TPayload } +/** Result of validating audit entry signatures and hash links. */ export interface AuditVerifyResult { ok: boolean /** First entry where the chain broke, or null when ok. */ @@ -42,14 +47,17 @@ export interface AuditVerifyResult { entryCount: number } +/** Operations exposed by a signed hash-chained audit log. */ export interface SignedAuditLog { append: (input: AppendAuditInput) => Promise> verify: () => Promise list: () => Promise } +/** Audit action names emitted for PII redaction and reveal events. */ export type PiiAuditAction = 'pii:redact' | 'pii:reveal' | 'pii:reveal-denied' +/** PII scan details converted to signed audit records. */ export interface PiiAuditInput { actor: string action: PiiAuditAction @@ -58,6 +66,7 @@ export interface PiiAuditInput { reason?: string } +/** PII match metadata stored in an audit record without matched text. */ export interface PiiAuditPayload { subjectId?: string rule: string @@ -149,6 +158,12 @@ export function createSignedAuditLog(options: AuditLogOptions): SignedAuditLog { } } +/** + * Append one audit record for each PII hit, storing offsets but no matched text. + * @param log Signed audit log that receives the records. + * @param input Actor, action, subject, hits, and optional reason to record. + * @returns The appended records in hit order. + */ export async function appendPiiAuditEvents( log: SignedAuditLog, input: PiiAuditInput, @@ -175,7 +190,10 @@ export async function appendPiiAuditEvents( return entries } -/** In-memory `AuditLogStore` — tests, demos, transient deployments. */ +/** + * Create a transient in-memory audit store for tests, demos, or short-lived deployments. + * @returns An empty store implementing the audit log storage contract. + */ export function createInMemoryAuditStore(): AuditLogStore { const entries: AuditEntry[] = [] return { diff --git a/packages/observability/src/axiom.ts b/packages/observability/src/axiom.ts index 6fd1e20c4..4c8d7f846 100644 --- a/packages/observability/src/axiom.ts +++ b/packages/observability/src/axiom.ts @@ -6,6 +6,7 @@ import { type LifecycleObserver, } from './http-batch-sink' +/** Axiom dataset credentials, endpoint, service label, and batch settings. */ export interface AxiomSinkConfig extends HttpBatchOptions { /** Axiom API token. */ token: string @@ -17,6 +18,7 @@ export interface AxiomSinkConfig extends HttpBatchOptions { service?: string } +/** Lifecycle observer returned by `axiomSink`. */ export type AxiomSinkObserver = LifecycleObserver function endpointFor(config: AxiomSinkConfig): string { @@ -45,8 +47,9 @@ function spanToEvent( } /** - * Axiom sink. Batches span start/end events to a dataset ingest endpoint. - * Errors are isolated. + * Create a batched HTTP sink that exports span start and end events to an Axiom dataset; failures are isolated. + * @param config Axiom credentials, dataset, and optional endpoint and batch settings. + * @returns A lifecycle observer with `flush` and `shutdown` methods. */ export function axiomSink(config: AxiomSinkConfig): AxiomSinkObserver { return createHttpBatchSink({ diff --git a/packages/observability/src/console-logger.ts b/packages/observability/src/console-logger.ts index d24b4e363..895960460 100644 --- a/packages/observability/src/console-logger.ts +++ b/packages/observability/src/console-logger.ts @@ -1,6 +1,7 @@ import type { AgentEvent, Observer } from '@agentskit/core' import { safeSnapshot } from './trace-tracker' +/** Output format for the console event logger. */ export interface ConsoleLoggerConfig { format?: 'human' | 'json' } @@ -76,6 +77,11 @@ function formatJSON(event: AgentEvent): string { return JSON.stringify(base) } +/** + * Create an observer that writes agent events to stdout in human or JSON form. + * @param config Optional output format; defaults to the human-readable format. + * @returns An observer that writes one formatted line per event. + */ export function consoleLogger(config: ConsoleLoggerConfig = {}): Observer { const { format = 'human' } = config const formatter = format === 'json' ? formatJSON : formatHuman diff --git a/packages/observability/src/cost-chargeback.ts b/packages/observability/src/cost-chargeback.ts index 32d5ba806..ff6de6a0a 100644 --- a/packages/observability/src/cost-chargeback.ts +++ b/packages/observability/src/cost-chargeback.ts @@ -34,6 +34,7 @@ export interface CostSample { costUsd?: number } +/** Fields supported as chargeback report grouping keys. */ export type ChargebackGroupKey = | 'tenant' | 'user' @@ -45,6 +46,7 @@ export type ChargebackGroupKey = | 'tenant+tool' | 'tenant+model' +/** Grouping, pricing, and inclusive time-window options for a chargeback report. */ export interface ChargebackReportOptions { /** Group key. Default `'tenant'`. */ groupBy?: ChargebackGroupKey @@ -58,6 +60,7 @@ export interface ChargebackReportOptions { to?: string } +/** Aggregated token and spend totals for one chargeback group. */ export interface ChargebackRow { /** Composite group key, joined with '/' for multi-field groups. */ group: string @@ -72,6 +75,7 @@ export interface ChargebackRow { lastAt: string } +/** Aggregated chargeback rows and totals for the requested window. */ export interface ChargebackReport { groupBy: ChargebackGroupKey rows: ChargebackRow[] @@ -130,6 +134,13 @@ function validateSample(sample: CostSample, index: number): void { } } +/** + * Group call samples and calculate token and dollar totals. + * @param samples Per-call usage records to aggregate. + * @param options Grouping, price overrides, and time-window filters. + * @returns Rows sorted by descending spend, plus report totals. + * @throws {ConfigError} When a sample has invalid identity, token, or cost fields. + */ export function chargebackReport( samples: CostSample[], options: ChargebackReportOptions = {}, @@ -204,6 +215,11 @@ function escapeCsv(field: string | number): string { return s } +/** + * Serialize a chargeback report as CSV, including a final totals row. + * @param report Aggregated report to serialize. + * @returns CSV text with a trailing newline. + */ export function chargebackReportToCsv(report: ChargebackReport): string { const lines = [CSV_HEADERS.join(',')] const renderRow = (cells: Array): string => diff --git a/packages/observability/src/cost-guard-advanced-types.ts b/packages/observability/src/cost-guard-advanced-types.ts index 45267a0f1..2e5d68c26 100644 --- a/packages/observability/src/cost-guard-advanced-types.ts +++ b/packages/observability/src/cost-guard-advanced-types.ts @@ -1,7 +1,9 @@ import type { TokenPrice, CostGuardErrorHandler, UnknownModelPolicy } from './cost-guard' +/** Enforcement policy: report only, expose rejection state, or disable the tenant. */ export type CostGuardMode = 'warn' | 'reject' | 'kill' +/** Spend limit and rolling duration for one cost cap. */ export interface CostCapWindow { /** Window length in milliseconds. */ windowMs: number @@ -9,6 +11,7 @@ export interface CostCapWindow { budgetUsd: number } +/** Named rolling spend limits applied to a tenant. */ export interface CostCaps { perMinute?: CostCapWindow perDay?: CostCapWindow @@ -17,12 +20,14 @@ export interface CostCaps { custom?: Record } +/** Event kinds emitted when a budget threshold, forecast, or disablement occurs. */ export type CostAlertType = | 'cost:threshold' | 'cost:exceeded' | 'cost:disabled' | 'cost:forecast' +/** JSON-safe details for a cost guard alert. */ export interface CostAlertEvent { type: CostAlertType tenant: string @@ -47,8 +52,10 @@ export interface CostAlertEvent { reason?: string } +/** Receives cost alerts in registration order. */ export type CostAlertSink = (event: CostAlertEvent) => void | Promise +/** Configuration for per-tenant budgets, rolling caps, and enforcement. */ export interface AdvancedCostGuardOptions { /** Per-tenant USD budgets (overall, applied alongside windows). */ budgets: Record diff --git a/packages/observability/src/cost-guard-advanced.ts b/packages/observability/src/cost-guard-advanced.ts index 14c68163e..9b3d8912b 100644 --- a/packages/observability/src/cost-guard-advanced.ts +++ b/packages/observability/src/cost-guard-advanced.ts @@ -42,12 +42,7 @@ export { } from './cost-guard-alert-sinks' export type { WebhookAlertSinkOptions } from './cost-guard-alert-sinks' -/** - * Production-grade cost guard. Extends the multi-tenant guard with modes - * (`warn` / `reject` / `kill`), rolling window caps, threshold + forecast - * alerts, and pluggable sinks. Closes #787–#789. - */ - +/** Observer interface and per-tenant controls returned by `createAdvancedCostGuard`. */ export interface AdvancedCostGuard extends Observer { setTenant: (tenant: string | undefined) => void costUsd: (tenant: string) => number @@ -66,6 +61,16 @@ export interface AdvancedCostGuard extends Observer { tenants: () => string[] } +/** + * Create a per-tenant cost guard with rolling caps and configurable enforcement. + * @param options Budgets, caps, pricing, enforcement mode, and alert sinks. + * @returns An observer with tenant state and control methods. + * @throws {ConfigError} When options are invalid or kill mode has no `disableRuntime` callback. + * @example + * ```ts + * const guard = createAdvancedCostGuard({ budgets: { acme: 10 }, mode: 'reject' }) + * ``` + */ export function createAdvancedCostGuard( options: AdvancedCostGuardOptions, ): AdvancedCostGuard { diff --git a/packages/observability/src/cost-guard-alert-sinks.ts b/packages/observability/src/cost-guard-alert-sinks.ts index 435a2f552..bfcf915c8 100644 --- a/packages/observability/src/cost-guard-alert-sinks.ts +++ b/packages/observability/src/cost-guard-alert-sinks.ts @@ -6,7 +6,10 @@ function resolveGlobalFetch(): typeof fetch | undefined { return typeof candidate === 'function' ? (candidate as typeof fetch) : undefined } -/** Console alert sink — `[cost:] $/$`. */ +/** + * Create an alert sink that writes cost alert details to stderr. + * @returns A sink that formats one concise line for each alert. + */ export function consoleAlertSink(): CostAlertSink { return event => { const line = `[${event.type}] tenant=${event.tenant} window=${event.window} ` + @@ -18,6 +21,7 @@ export function consoleAlertSink(): CostAlertSink { } } +/** HTTP and retry settings for `webhookAlertSink`. */ export interface WebhookAlertSinkOptions { url: string /** Override fetch (tests / custom clients). */ @@ -26,7 +30,11 @@ export interface WebhookAlertSinkOptions { headers?: Record } -/** Generic webhook sink — POSTs the event JSON. Rejects on HTTP !ok. */ +/** + * Create a sink that posts cost alerts as JSON to a webhook endpoint. + * @param options Endpoint and optional fetch implementation and headers. + * @returns An async sink that rejects when the HTTP response is not successful. + */ export function webhookAlertSink(options: WebhookAlertSinkOptions): CostAlertSink { // Prefer injected fetch; fall back to globalThis so missing global never ReferenceErrors. const fetchImpl = options.fetch ?? resolveGlobalFetch() @@ -44,8 +52,12 @@ export function webhookAlertSink(options: WebhookAlertSinkOptions): CostAlertSin } /** - * Throttle wrapper — at most one alert per (tenant, window, type) - * per `windowMs`. Wrap any sink to bound emit rate. + * Throttle alerts by tenant, window, type, and threshold for the given interval. + * @param sink Sink to wrap. + * @param windowMs Minimum interval between matching alerts. + * @param now Clock used to compare alert times; defaults to `Date.now`. + * @returns A sink that forwards at most one matching alert per interval. + * @throws {ConfigError} When `windowMs` is not finite and positive. */ export function throttle( sink: CostAlertSink, diff --git a/packages/observability/src/cost-guard-multi-tenant.ts b/packages/observability/src/cost-guard-multi-tenant.ts index d0e2de5e4..e865f8312 100644 --- a/packages/observability/src/cost-guard-multi-tenant.ts +++ b/packages/observability/src/cost-guard-multi-tenant.ts @@ -12,6 +12,7 @@ import { type CostGuardErrorHandler, } from './cost-guard' +/** Per-tenant budgets, pricing, tenant resolver, and isolated callbacks. */ export interface MultiTenantCostGuardOptions { /** * Per-tenant USD budgets. Tenants not listed here either inherit diff --git a/packages/observability/src/cost-guard.ts b/packages/observability/src/cost-guard.ts index 141410ade..751aefdd3 100644 --- a/packages/observability/src/cost-guard.ts +++ b/packages/observability/src/cost-guard.ts @@ -8,6 +8,7 @@ export interface TokenPrice { output: number } +/** Controls whether pricing an unlisted model fails or treats it as free. */ export type UnknownModelPolicy = 'error' | 'allow-zero' /** Isolated error reporter shared by all cost guards. */ @@ -47,6 +48,7 @@ export const DEFAULT_PRICES: Record = { 'ollama': { input: 0, output: 0 }, } +/** Configuration for an observer that tracks cumulative token spend. */ export interface CostGuardOptions { /** Hard budget in USD. Aborts the run when exceeded. */ budgetUsd: number @@ -109,6 +111,12 @@ export function priceFor( return { input: 0, output: 0 } } +/** + * Check whether a model matches a configured price prefix. + * @param model Model id to look up; missing ids never match. + * @param prices Price prefixes to inspect. Defaults to the built-in table. + * @returns Whether any case-insensitive prefix matches the model. + */ export function hasPriceFor( model: string | undefined, prices: Record = DEFAULT_PRICES, @@ -117,6 +125,14 @@ export function hasPriceFor( return Object.keys(prices).some(key => model.toLowerCase().startsWith(key.toLowerCase())) } +/** + * Resolve a model price, applying the selected policy when no prefix matches. + * @param model Model id to price. + * @param prices Price prefixes to inspect. + * @param policy Behavior when no price matches. Defaults to `error`. + * @returns The first matching price, or zero pricing when allowed. + * @throws {ConfigError} When no price matches and `policy` is `error`. + */ export function resolvePrice( model: string | undefined, prices: Record, @@ -131,6 +147,14 @@ export function resolvePrice( }) } +/** + * Resolve a price and report lookup errors through an isolated error callback. + * @param model Model id to price. + * @param prices Price prefixes to inspect. + * @param policy Behavior when no price matches. + * @param onError Optional isolated error callback. + * @returns The resolved price, or `undefined` when lookup fails. + */ export function resolvePriceSafely( model: string | undefined, prices: Record, @@ -195,6 +219,13 @@ export function invokeCostGuardCallback( } } +/** + * Throw a configuration error unless a value is finite and non-negative. + * @param scope Name of the config or helper being validated. + * @param name Name of the value in that scope. + * @param value Value to validate. + * @throws {ConfigError} When `value` is negative or non-finite. + */ export function assertFiniteNonNegative( scope: string, name: string, @@ -209,6 +240,13 @@ export function assertFiniteNonNegative( } } +/** + * Throw a configuration error unless a value is finite and greater than zero. + * @param scope Name of the config or helper being validated. + * @param name Name of the value in that scope. + * @param value Value to validate. + * @throws {ConfigError} When `value` is not finite and positive. + */ export function assertFinitePositive( scope: string, name: string, @@ -223,6 +261,12 @@ export function assertFinitePositive( } } +/** + * Validate every input and output price in an optional price table. + * @param scope Name included in validation errors. + * @param prices Optional model-to-price table to validate. + * @throws {ConfigError} When any configured price is negative or non-finite. + */ export function validateTokenPrices( scope: string, prices: Record | undefined, diff --git a/packages/observability/src/datadog.ts b/packages/observability/src/datadog.ts index ba51747be..92654ec17 100644 --- a/packages/observability/src/datadog.ts +++ b/packages/observability/src/datadog.ts @@ -6,6 +6,7 @@ import { type LifecycleObserver, } from './http-batch-sink' +/** Datadog API key, site, service tags, and batch settings. */ export interface DatadogSinkConfig extends HttpBatchOptions { apiKey: string /** Datadog site, defaults to `datadoghq.com` (US1). Use `datadoghq.eu`, `us5.datadoghq.com`, etc. */ @@ -16,6 +17,7 @@ export interface DatadogSinkConfig extends HttpBatchOptions { env?: string } +/** Lifecycle observer returned by `datadogSink`. */ export type DatadogSinkObserver = LifecycleObserver function siteEndpoint(site = 'datadoghq.com'): string { @@ -48,8 +50,9 @@ function spanToLog( } /** - * Datadog Logs sink. Batches span start/end as JSON log entries to Datadog's - * HTTP intake. Failures are isolated — observability never breaks the main loop. + * Create a batched HTTP sink that exports span events as JSON logs to Datadog; failures are isolated. + * @param config API key, Datadog site, service tags, and batch settings. + * @returns A lifecycle observer with `flush` and `shutdown` methods. */ export function datadogSink(config: DatadogSinkConfig): DatadogSinkObserver { return createHttpBatchSink({ diff --git a/packages/observability/src/devtools.ts b/packages/observability/src/devtools.ts index 7b767d133..d79e04ca9 100644 --- a/packages/observability/src/devtools.ts +++ b/packages/observability/src/devtools.ts @@ -1,17 +1,20 @@ import type { AgentEvent, Observer } from '@agentskit/core' import { ConfigError, createId, ErrorCodes } from '@agentskit/core' +/** Transport endpoint that receives devtools envelopes. */ export interface DevtoolsClient { id: string send: (event: DevtoolsEnvelope) => void close?: () => void } +/** Wire messages for connection setup, event delivery, and replay completion. */ export type DevtoolsEnvelope = | { type: 'hello'; protocol: 1; serverId: string; since: string } | { type: 'agent-event'; seq: number; at: number; event: AgentEvent } | { type: 'replay-end'; seq: number } +/** Buffer and server identity settings for the in-process devtools hub. */ export interface DevtoolsServerOptions { /** Max events to retain in the ring buffer. Default 500. */ bufferSize?: number @@ -19,6 +22,7 @@ export interface DevtoolsServerOptions { serverId?: string } +/** Observer, transport hooks, and retained event buffer returned by the hub. */ export interface DevtoolsServer { /** Observer you can plug into `createRuntime({ observers: [...] })`. */ observer: Observer @@ -33,14 +37,15 @@ export interface DevtoolsServer { } /** - * In-process pub/sub hub for agent events. Transport-agnostic — hand - * the returned `attach` function any object that can `send` envelopes - * (an SSE response, a WebSocket, a test sink). Designed as the - * contract a browser devtools extension speaks against. - * - * New clients receive a `hello` envelope followed by a replay of the - * ring buffer (so the extension can jump in mid-session and see - * recent history), then `replay-end`, then the live feed. + * Create a transport-agnostic event hub; new clients receive hello, buffered replay, and the live feed. + * @param options Optional buffer size and server id. + * @returns A runtime observer and transport-agnostic client management methods. + * @throws {ConfigError} When `bufferSize` is not a positive integer. + * @example + * ```ts + * const devtools = createDevtoolsServer() + * const detach = devtools.attach({ id: 'panel', send: envelope => socket.send(toSseFrame(envelope)) }) + * ``` */ export function createDevtoolsServer(options: DevtoolsServerOptions = {}): DevtoolsServer { if (options.bufferSize !== undefined && @@ -123,9 +128,9 @@ export function createDevtoolsServer(options: DevtoolsServerOptions = {}): Devto } /** - * Serialize a devtools envelope as a single `data: ...\n\n` SSE frame. - * Framework-agnostic — hook into Express / Hono / plain http by - * writing the returned string to your response. + * Serialize one devtools envelope as an SSE data frame for Express, Hono, or Node HTTP. + * @param envelope Message to serialize. + * @returns A complete `data:` frame terminated by a blank line. */ export function toSseFrame(envelope: DevtoolsEnvelope): string { return `data: ${JSON.stringify(envelope)}\n\n` diff --git a/packages/observability/src/langsmith.ts b/packages/observability/src/langsmith.ts index 1945314c5..11639f4ac 100644 --- a/packages/observability/src/langsmith.ts +++ b/packages/observability/src/langsmith.ts @@ -2,6 +2,7 @@ import type { AgentEvent, Observer } from '@agentskit/core' import { createTraceTracker, type TraceSpan } from './trace-tracker' import { snapshotAttributes } from './http-batch-sink' +/** API key, project, endpoint, and isolated error callback for LangSmith. */ export interface LangSmithConfig { apiKey: string projectName?: string @@ -10,6 +11,7 @@ export interface LangSmithConfig { onError?: (error: unknown) => void | Promise } +/** LangSmith observer with explicit batch flushing and shutdown lifecycle. */ export interface LangSmithObserver extends Observer { flush(): Promise shutdown(): Promise @@ -43,8 +45,13 @@ function emitError( } /** - * LangSmith observer. Construction is pure (no SDK import). The SDK is loaded - * lazily on the first span that needs a remote run. + * Create a lazy-loading observer that exports tracked spans to LangSmith without construction-time I/O. + * @param config LangSmith credentials and optional project, endpoint, and error handler. + * @returns An observer with `flush` and idempotent `shutdown` methods. + * @example + * ```ts + * const observer = langsmith({ apiKey: process.env.LANGSMITH_API_KEY! }) + * ``` */ export function langsmith(config: LangSmithConfig): LangSmithObserver { const { apiKey, projectName = 'agentskit', endpoint = 'https://api.smith.langchain.com' } = config diff --git a/packages/observability/src/new-relic.ts b/packages/observability/src/new-relic.ts index e30e31545..10f8c1f9b 100644 --- a/packages/observability/src/new-relic.ts +++ b/packages/observability/src/new-relic.ts @@ -6,6 +6,7 @@ import { type LifecycleObserver, } from './http-batch-sink' +/** New Relic API key, region, service label, and batch settings. */ export interface NewRelicSinkConfig extends HttpBatchOptions { /** New Relic license / API key (NRAK-... or license key). */ apiKey: string @@ -15,6 +16,7 @@ export interface NewRelicSinkConfig extends HttpBatchOptions { service?: string } +/** Lifecycle observer returned by `newRelicSink`. */ export type NewRelicSinkObserver = LifecycleObserver function endpointFor(region: 'US' | 'EU' = 'US'): string { @@ -45,8 +47,9 @@ function spanToLog( } /** - * New Relic Logs sink. Batches span start/end events to New Relic's Log API. - * Errors are isolated. + * Create a batched HTTP sink that exports span events to New Relic Logs; failures are isolated. + * @param config API key, region, service name, and batch settings. + * @returns A lifecycle observer with `flush` and `shutdown` methods. */ export function newRelicSink(config: NewRelicSinkConfig): NewRelicSinkObserver { return createHttpBatchSink({ diff --git a/packages/observability/src/opentelemetry.ts b/packages/observability/src/opentelemetry.ts index 8bdaceb33..ec7738f97 100644 --- a/packages/observability/src/opentelemetry.ts +++ b/packages/observability/src/opentelemetry.ts @@ -2,6 +2,7 @@ import type { AgentEvent, Observer } from '@agentskit/core' import { createTraceTracker, type TraceSpan } from './trace-tracker' import { snapshotAttributes } from './http-batch-sink' +/** OTLP endpoint, service name, and isolated error callback. */ export interface OpenTelemetryConfig { endpoint?: string serviceName?: string @@ -9,6 +10,7 @@ export interface OpenTelemetryConfig { onError?: (error: unknown) => void | Promise } +/** OpenTelemetry observer with explicit flush and shutdown lifecycle. */ export interface OpenTelemetryObserver extends Observer { flush(): Promise shutdown(): Promise @@ -67,8 +69,13 @@ function emitError( } /** - * OpenTelemetry observer. Construction is pure. SDK modules load lazily on the - * first span. Owned providers use OTel JS v2 `spanProcessors` constructor config. + * Create a lazy-loading observer that exports tracked spans through OpenTelemetry using the v2 `spanProcessors` config. + * @param config Optional OTLP endpoint, service name, and error callback. + * @returns An observer with `flush` and idempotent `shutdown` methods. + * @example + * ```ts + * const observer = opentelemetry({ endpoint: 'http://localhost:4318/v1/traces' }) + * ``` */ export function opentelemetry(config: OpenTelemetryConfig = {}): OpenTelemetryObserver { const { endpoint = 'http://localhost:4318/v1/traces', serviceName = 'agentskit' } = config diff --git a/packages/observability/src/prod-control.ts b/packages/observability/src/prod-control.ts index fb9c6aa8b..f6e4e9f35 100644 --- a/packages/observability/src/prod-control.ts +++ b/packages/observability/src/prod-control.ts @@ -1,22 +1,6 @@ import { ConfigError, ErrorCodes, type AgentEvent, type Observer } from '@agentskit/core' -/** - * Production agent control surface. Devtools (#35) is dev-only; this - * is the auth-gated production counterpart that lets ops: - * - * - pause an agent loop - * - step a paused loop one iteration - * - inject tool overrides for the next call to a tool - * - snapshot the current state for support tickets - * - replay from a previously-captured snapshot - * - * Designed as a transport-agnostic engine — the same `ControlSurface` - * sits behind an HTTP endpoint, an MCP server, or in-process tests. - * `httpHandler()` ships a bearer-token-gated REST surface so a - * default deployment is one `createServer(handler)` call. - * - * Closes issue #784. - */ +/** Auth-gated, transport-agnostic controls for pausing runs, overriding tools, and capturing or restoring snapshots. */ export interface ToolOverride { /** Tool to override on the next call. */ @@ -33,6 +17,7 @@ export interface ToolOverride { reason?: string } +/** Captured paused state, retained events, and pending tool overrides for a run. */ export interface RunSnapshot { runId: string /** ISO timestamp. */ @@ -48,6 +33,7 @@ export interface RunSnapshot { metadata?: Record } +/** Retention, run correlation, audit, and HTTP authentication settings. */ export interface ControlSurfaceOptions { /** Max events retained per run for snapshots. Default 200. */ snapshotBufferSize?: number @@ -72,6 +58,7 @@ export interface ControlSurfaceOptions { maxRuns?: number } +/** Audit record for a production control action. */ export interface ControlAuditEntry { /** ISO timestamp. */ at: string @@ -83,6 +70,7 @@ export interface ControlAuditEntry { payload?: Record } +/** Runtime hooks and administrative controls returned by `createControlSurface`. */ export interface ControlSurface { /** Plug into `createRuntime({ observers: [control.observer] })`. */ observer: Observer @@ -197,6 +185,17 @@ function assertRunId(runId: string): void { } } +/** + * Create a transport-agnostic control surface for pausing, stepping, and inspecting runs. + * @param options Event retention, run-id resolution, audit, and optional bearer-token settings. + * @returns Observer and control methods for runtime hooks or an HTTP handler. + * @throws {ConfigError} When configured limits are not positive integers or a run id is invalid. + * @example + * ```ts + * const control = createControlSurface({ defaultRunId: 'run-1' }) + * await control.awaitResume('run-1') + * ``` + */ export function createControlSurface(options: ControlSurfaceOptions = {}): ControlSurface { if (options.snapshotBufferSize !== undefined) { assertPositiveInteger('snapshotBufferSize', options.snapshotBufferSize) diff --git a/packages/observability/src/redaction.ts b/packages/observability/src/redaction.ts index ba6ec8f3a..dad028980 100644 --- a/packages/observability/src/redaction.ts +++ b/packages/observability/src/redaction.ts @@ -23,8 +23,10 @@ import { * Closes issue #792. */ +/** Whether observer payloads replace PII or tokenize it through a vault. */ export type RedactionMode = 'redact' | 'tokenize' +/** Rules, mode, vault, roles, and audit sink used to sanitize observer events. */ export interface ObserverRedactionOptions { /** * Rules to apply. Pass `DEFAULT_PII_RULES` for the baseline set, @@ -136,6 +138,13 @@ async function redactEvent( } } +/** + * Wrap an observer so supported event content is redacted or tokenized before delivery. + * @param inner Observer that receives the sanitized event copy. + * @param options PII rules and optional tokenization or audit settings. + * @returns An observer that forwards sanitized events to `inner`. + * @throws {ConfigError} In tokenize mode when vault or allowed roles are missing. + */ export function wrapObserverWithRedaction( inner: Observer, options: ObserverRedactionOptions, diff --git a/packages/observability/src/replay-bisect.ts b/packages/observability/src/replay-bisect.ts index d868f2b4e..ce3af6546 100644 --- a/packages/observability/src/replay-bisect.ts +++ b/packages/observability/src/replay-bisect.ts @@ -3,14 +3,17 @@ // that replays the run at a given change-index and returns ok/fail. The // bisector walks the history with O(log n) probes. +/** Result of probing a change history for the earliest pass-to-fail transition. */ export type BisectVerdict = | { readonly kind: 'culprit'; readonly index: number; readonly probes: number } | { readonly kind: 'all_clean'; readonly probes: number } | { readonly kind: 'all_broken'; readonly probes: number } | { readonly kind: 'inconsistent'; readonly probes: number; readonly detail: string } +/** Replays a history prefix ending at an index and reports whether it passes. */ export type ReplayOracle = (changeIndex: number) => Promise<'pass' | 'fail'> +/** Probe limit and optional callback for `replayBisect`. */ export type BisectOpts = { readonly maxProbes?: number readonly onProbe?: (changeIndex: number, result: 'pass' | 'fail') => void diff --git a/packages/observability/src/replay-timeline.ts b/packages/observability/src/replay-timeline.ts index 1ad0eb9a0..cad8b1f5d 100644 --- a/packages/observability/src/replay-timeline.ts +++ b/packages/observability/src/replay-timeline.ts @@ -13,6 +13,7 @@ import { ErrorCodes, RuntimeError } from '@agentskit/core' +/** Recorded execution checkpoint consumed by the replay timeline helpers. */ export type ReplayStep = { readonly id: string readonly nodeId: string @@ -25,6 +26,7 @@ export type ReplayStep = { readonly outcome: 'ok' | 'failed' | 'paused' | 'skipped' } +/** Cumulative metrics and outcome at one recorded replay checkpoint. */ export type TimelineRow = { readonly index: number readonly stepId: string @@ -36,6 +38,7 @@ export type TimelineRow = { readonly outcome: ReplayStep['outcome'] } +/** Timeline rows, totals, and start/end timestamps for a replay. */ export type Timeline = { readonly rows: readonly TimelineRow[] readonly totalCostUsd: number @@ -44,6 +47,11 @@ export type Timeline = { readonly span: { readonly startedAt: number; readonly endedAt: number } } +/** + * Build cumulative cost, token, and latency totals from recorded steps. + * @param steps Checkpoints in chronological order. + * @returns Timeline rows and totals, with a zero-length span for no steps. + */ export const buildTimeline = (steps: readonly ReplayStep[]): Timeline => { let cost = 0 let tokens = 0 @@ -76,11 +84,18 @@ export const buildTimeline = (steps: readonly ReplayStep[]): Timeline => { } } +/** One property addition, removal, or change between two state snapshots. */ export type StateDiffEntry = | { readonly kind: 'add'; readonly key: string; readonly value: unknown } | { readonly kind: 'remove'; readonly key: string; readonly previous: unknown } | { readonly kind: 'change'; readonly key: string; readonly previous: unknown; readonly value: unknown } +/** + * Compare two shallow state records and return changed property entries. + * @param previous State before the checkpoint. + * @param next State at the checkpoint. + * @returns Added, removed, or changed top-level properties in key order. + */ export const diffState = ( previous: Readonly>, next: Readonly>, @@ -101,12 +116,21 @@ export const diffState = ( return entries } +/** Selected timeline row and its state difference from the previous step. */ export type ReplayPosition = { readonly index: number readonly cumulative: TimelineRow readonly stateDiffFromPrevious: readonly StateDiffEntry[] } +/** + * Select a replay step and calculate its difference from the prior state. + * @param steps Recorded steps used to read adjacent state snapshots. + * @param timeline Timeline built from the same step sequence. + * @param index Zero-based row index to select. + * @returns The selected cumulative row and state difference. + * @throws {RuntimeError} When the index is outside the timeline rows. + */ export const positionAt = ( steps: readonly ReplayStep[], timeline: Timeline, diff --git a/packages/observability/src/replay.ts b/packages/observability/src/replay.ts index dc70eb7ae..44e545525 100644 --- a/packages/observability/src/replay.ts +++ b/packages/observability/src/replay.ts @@ -6,8 +6,15 @@ // (`AgentEvent`, `TraceSpan`, or a host application's own event union) without // coupling the replay driver to a specific schema. +/** Asynchronous or synchronous consumer invoked for each replayed event. */ export type ReplayHandler = (event: E) => void | Promise +/** + * Replay events sequentially through each handler in registration order. + * @param events Ordered event history to replay. + * @param handlers Consumers invoked for each event. + * @returns A promise that resolves after every handler completes. + */ export const replayEvents = async ( events: readonly E[], handlers: readonly ReplayHandler[], diff --git a/packages/observability/src/slo.ts b/packages/observability/src/slo.ts index 14a511674..efd3bbb67 100644 --- a/packages/observability/src/slo.ts +++ b/packages/observability/src/slo.ts @@ -21,6 +21,7 @@ import type { CostAlertEvent, CostAlertSink } from './cost-guard-advanced' * Closes issue #796. */ +/** Target rates and latency used to evaluate the SLO snapshot. */ export interface SloTargets { /** 0–1. Default 0.99. */ successRate?: number @@ -32,6 +33,7 @@ export interface SloTargets { streamingStallRate?: number } +/** Target, stall threshold, burn windows, alert sink, and clock for an SLO observer. */ export interface SloOptions { targets?: SloTargets /** First-token latency above this counts as a stall. Default 8000ms. */ @@ -44,6 +46,7 @@ export interface SloOptions { now?: () => number } +/** Default SLO thresholds used when an observer does not override them. */ export const DEFAULT_SLO_TARGETS: Required = { successRate: 0.99, latencyP95Ms: 5_000, @@ -70,6 +73,7 @@ interface ActiveOp { stall: boolean } +/** Aggregated rates and latency quantiles for a time window. */ export interface SloSnapshot { windowMs: number total: number @@ -81,6 +85,7 @@ export interface SloSnapshot { streamingStallRate: number } +/** Observer with metric snapshots, exporters, and timer cleanup. */ export interface SloObserver extends Observer { snapshot: (windowMs?: number) => SloSnapshot /** Prometheus exposition text (`# HELP / # TYPE / metric{...} value`). */ @@ -154,6 +159,16 @@ function validateOptions(options: SloOptions): void { if (t.latencyP95Ms !== undefined) assertFiniteNonNegative('targets.latencyP95Ms', t.latencyP95Ms) } +/** + * Create an observer that records SLO metrics and periodically emits burn-rate alerts. + * @param options Optional targets, windows, alert sink, and clock. + * @returns An observer with snapshot, Prometheus, OTEL, and stop methods. + * @throws {ConfigError} When a target or window has an invalid value. + * @example + * ```ts + * const slo = sloObserver({ targets: { successRate: 0.995 } }) + * ``` + */ export function sloObserver(options: SloOptions = {}): SloObserver { validateOptions(options) diff --git a/packages/observability/src/topology-graph.ts b/packages/observability/src/topology-graph.ts index 1af84a822..5e91f622f 100644 --- a/packages/observability/src/topology-graph.ts +++ b/packages/observability/src/topology-graph.ts @@ -1,8 +1,4 @@ -/** - * Mirrors the `TopologyLogEvent` shape from `@agentskit/runtime`. We - * redefine it here to avoid a runtime → observability dependency - * cycle; the contract is stable (defined alongside topologies.ts). - */ +/** Runtime topology event mirrored here to avoid an observability-to-runtime dependency cycle. */ export interface TopologyLogEvent { topology: string phase: 'dispatch' | 'agent:start' | 'agent:end' | 'merge' | 'done' @@ -27,6 +23,7 @@ export interface TopologyLogEvent { * Closes issue #785. */ +/** Agent node and activity counters in a topology graph. */ export interface TopologyNode { id: string /** Display label. Defaults to the agent id. */ @@ -41,6 +38,7 @@ export interface TopologyNode { lastActiveAt: number } +/** Directed communication edge between agents in a topology graph. */ export interface TopologyEdge { /** `from→to` (stable id). */ id: string @@ -53,6 +51,7 @@ export interface TopologyEdge { lastResult?: string } +/** Mutable topology graph with serializers and change subscriptions. */ export interface TopologyGraph { nodes: Map edges: Map @@ -73,6 +72,7 @@ export interface TopologyGraph { reset: () => void } +/** JSON-serializable node and edge snapshot with update time. */ export interface TopologyGraphSnapshot { nodes: TopologyNode[] edges: TopologyEdge[] @@ -80,6 +80,7 @@ export interface TopologyGraphSnapshot { updatedAt: string } +/** Snippet length and clock overrides for topology graph creation. */ export interface TopologyGraphOptions { /** Truncation length for task/result tooltips. Default 80. */ snippetLength?: number @@ -94,6 +95,16 @@ function trim(value: string | undefined, max: number): string | undefined { const ROOT = '__root__' +/** + * Create an in-memory graph for topology dispatch and agent activity events. + * @param options Optional snippet length and clock override. + * @returns A mutable graph with JSON, Mermaid, ASCII, and subscription APIs. + * @example + * ```ts + * const graph = createTopologyGraph() + * graph.ingest({ topology: 'swarm', phase: 'agent:start', agent: 'writer' }) + * ``` + */ export function createTopologyGraph(options: TopologyGraphOptions = {}): TopologyGraph { const snippet = options.snippetLength ?? 80 const now = options.now ?? (() => Date.now()) @@ -208,7 +219,10 @@ export function createTopologyGraph(options: TopologyGraphOptions = {}): Topolog for (const edge of childEdges) { const child = nodes.get(edge.to) if (!child) continue - const tag = child.errorCount > 0 ? '✗' : child.endCount > 0 ? '✓' : '…' + let tag: string + if (child.errorCount > 0) tag = '✗' + else if (child.endCount > 0) tag = '✓' + else tag = '…' lines.push(` ├─ ${tag} ${child.label} (${child.startCount} starts, ${child.endCount} done)`) } return lines.join('\n') diff --git a/packages/observability/src/trace-tracker.ts b/packages/observability/src/trace-tracker.ts index b96735edb..b0c42d33f 100644 --- a/packages/observability/src/trace-tracker.ts +++ b/packages/observability/src/trace-tracker.ts @@ -11,6 +11,7 @@ type CorrelationContext = { type CorrelatedAgentEvent = AgentEvent & { readonly correlation?: CorrelationContext } +/** Span identity, timing, attributes, and completion status produced by the tracker. */ export interface TraceSpan { id: string name: string @@ -21,6 +22,7 @@ export interface TraceSpan { status: 'ok' | 'error' } +/** Callbacks invoked when the tracker starts or completes a span. */ export interface TraceTrackerCallbacks { onSpanStart: (span: TraceSpan) => void onSpanEnd: (span: TraceSpan) => void @@ -33,8 +35,9 @@ function boundSnapshot(value: string): string { } /** - * JSON-ish snapshot that never throws on circular refs or BigInt. - * Result is always a string, bounded to SNAPSHOT_LIMIT. + * Convert a value to a bounded JSON-like string without throwing on circular references or BigInt. + * @param value Value to serialize. + * @returns A string no longer than 500 characters, or a fallback for unserializable values. */ export function safeSnapshot(value: unknown): string { try { @@ -72,11 +75,14 @@ function generateSpanId(): string { } /** - * Builds nested spans from a sequential AgentEvent stream. - * - * Assumption: events for the same kind (llm/tool/delegate) are sequential - * and non-interleaved. When present, the optional correlation envelope is - * copied to span attributes; it does not change the ordering contract. + * Build nested spans from a sequential AgentsKit event stream; same-kind events are assumed non-interleaved. + * @param callbacks Receivers for span start and completion events. + * @returns An event handler and `flush` method for closing open spans; correlation fields are copied to attributes. + * @example + * ```ts + * const tracker = createTraceTracker({ onSpanStart: save, onSpanEnd: save }) + * tracker.handle(event) + * ``` */ export function createTraceTracker(callbacks: TraceTrackerCallbacks) { const spanStack: TraceSpan[] = [] diff --git a/packages/observability/src/trace-viewer.ts b/packages/observability/src/trace-viewer.ts index e87764676..cc27b4591 100644 --- a/packages/observability/src/trace-viewer.ts +++ b/packages/observability/src/trace-viewer.ts @@ -1,6 +1,7 @@ import type { TraceSpan } from './trace-tracker' import { ConfigError, ErrorCodes } from '@agentskit/core' +/** Summary metrics and spans for one trace, used by JSON and HTML exporters. */ export interface TraceReport { traceId: string startTime: number @@ -93,6 +94,7 @@ ${rows} ` } +/** Span collector with a disk flush operation that writes JSON and optional HTML. */ export interface FileTraceSink { /** Observer-compatible span callbacks. Plug into `createTraceTracker`. */ onSpanStart: (span: TraceSpan) => void @@ -104,10 +106,14 @@ export interface FileTraceSink { } /** - * Collect spans in memory and write them to disk on demand. The - * default layout under `dir` is: - * .json — TraceReport (JSON) - * .html — offline viewer page (when html !== false) + * Collect spans in memory and write a JSON report and optional offline HTML viewer to a directory. + * @param dir Destination directory created on the first flush. + * @returns Span callbacks, a copy of collected spans, and an async flush method. + * @example + * ```ts + * const sink = createFileTraceSink('./traces') + * const paths = await sink.flush({ traceId: 'run-42' }) + * ``` */ export function createFileTraceSink(dir: string): FileTraceSink { const spans: TraceSpan[] = []