Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 14 additions & 8 deletions packages/core/src/agent/Agent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { InjectionSymbols } from '../constants'
import { JwsService } from '../crypto/JwsService'
import { CredoError } from '../error'
import { DependencyManager } from '../plugins'
import { StorageUpdateService, StorageVersionRepository, UpdateAssistant } from '../storage'
import { isStorageUpToDate, StorageUpdateService, StorageVersionRepository, UpdateAssistant } from '../storage'
import type { InitConfig } from '../types'
import { AgentConfig } from './AgentConfig'
import type { AgentDependencies } from './AgentDependencies'
Expand Down Expand Up @@ -87,23 +87,29 @@ export class Agent<AgentModules extends AgentModulesInput = any> extends BaseAge

// Make sure the storage is up to date
const storageUpdateService = this.dependencyManager.resolve(StorageUpdateService)
const isStorageUpToDate = await storageUpdateService.isUpToDate(this.agentContext)
this.logger.info(`Agent storage is ${isStorageUpToDate ? '' : 'not '}up to date.`)
const currentStorageVersion = await storageUpdateService.getCurrentStorageVersion(this.agentContext)
const mustUpdate = !isStorageUpToDate(currentStorageVersion, StorageUpdateService.previousFrameworkStorageVersion)
const canUpdate = !isStorageUpToDate(currentStorageVersion, StorageUpdateService.frameworkStorageVersion)
if (canUpdate) {
this.logger.info(
`Agent storage is not up to date. Current storage version is ${currentStorageVersion}, latest storage version is ${StorageUpdateService.frameworkStorageVersion}`
)
} else {
this.logger.info(`Agent storage is up to date. `)
}

if (!isStorageUpToDate && this.agentConfig.autoUpdateStorageOnStartup) {
if (canUpdate && this.agentConfig.autoUpdateStorageOnStartup) {
const updateAssistant = new UpdateAssistant(this)

await updateAssistant.initialize()
await updateAssistant.update()
} else if (!isStorageUpToDate) {
const currentVersion = await storageUpdateService.getCurrentStorageVersion(this.agentContext)

} else if (mustUpdate) {
// Close agent context to prevent un-initialized agent with initialized agent context
await this.dependencyManager.closeAgentContext(this.agentContext)

throw new CredoError(
// TODO: add link to where documentation on how to update can be found.
`Current agent storage is not up to date. To prevent the framework state from getting corrupted the agent initialization is aborted. Make sure to update the agent storage (currently at ${currentVersion}) to the latest version (${UpdateAssistant.frameworkStorageVersion}). You can also downgrade your version of Credo.`
`Current agent storage is not up to date. To prevent the framework state from getting corrupted the agent initialization is aborted. Make sure to update the agent storage (currently at ${currentStorageVersion}) to the latest or previous version (${UpdateAssistant.frameworkStorageVersion} or ${UpdateAssistant.previousFrameworkStorageVersion}). You can also downgrade your version of Credo.`
)
}

Expand Down
10 changes: 9 additions & 1 deletion packages/core/src/storage/migration/StorageUpdateService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,11 @@ import { isStorageUpToDate } from './isUpToDate'
import { StorageVersionRecord } from './repository/StorageVersionRecord'
import { StorageVersionRepository } from './repository/StorageVersionRepository'
import type { UpdateToVersion } from './updates'
import { CURRENT_FRAMEWORK_STORAGE_VERSION, INITIAL_STORAGE_VERSION } from './updates'
import {
CURRENT_FRAMEWORK_STORAGE_VERSION,
INITIAL_STORAGE_VERSION,
PREVIOUS_FRAMEWORK_STORAGE_VERSION,
} from './updates'

@injectable()
export class StorageUpdateService {
Expand Down Expand Up @@ -46,6 +50,10 @@ export class StorageUpdateService {
return CURRENT_FRAMEWORK_STORAGE_VERSION
}

public static get previousFrameworkStorageVersion() {
return PREVIOUS_FRAMEWORK_STORAGE_VERSION
}

public async setCurrentStorageVersion(agentContext: AgentContext, storageVersion: VersionString) {
this.logger.debug(`Setting current agent storage version to ${storageVersion}`)
const storageVersionRecord = await this.storageVersionRepository.findById(
Expand Down
11 changes: 10 additions & 1 deletion packages/core/src/storage/migration/UpdateAssistant.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,12 @@ import { StorageUpdateError } from './error/StorageUpdateError'

import { StorageUpdateService } from './StorageUpdateService'
import type { Update, UpdateConfig, UpdateToVersion } from './updates'
import { CURRENT_FRAMEWORK_STORAGE_VERSION, DEFAULT_UPDATE_CONFIG, supportedUpdates } from './updates'
import {
CURRENT_FRAMEWORK_STORAGE_VERSION,
DEFAULT_UPDATE_CONFIG,
PREVIOUS_FRAMEWORK_STORAGE_VERSION,
supportedUpdates,
} from './updates'

export interface UpdateAssistantUpdateOptions {
updateToVersion?: UpdateToVersion
Expand Down Expand Up @@ -43,6 +48,10 @@ export class UpdateAssistant<Agent extends BaseAgent<any> = BaseAgent> {
return CURRENT_FRAMEWORK_STORAGE_VERSION
}

public static get previousFrameworkStorageVersion() {
return PREVIOUS_FRAMEWORK_STORAGE_VERSION
}

public async getNeededUpdates(toVersion?: UpdateToVersion) {
const currentStorageVersion = parseVersionString(
await this.storageUpdateService.getCurrentStorageVersion(this.agent.context)
Expand Down
5 changes: 5 additions & 0 deletions packages/core/src/storage/migration/updates.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,11 @@ export const CURRENT_FRAMEWORK_STORAGE_VERSION = supportedUpdates[supportedUpdat
typeof supportedUpdates
>['toVersion']

// Previous version is second-last toVersion from the supported updates
export const PREVIOUS_FRAMEWORK_STORAGE_VERSION = supportedUpdates[supportedUpdates.length - 2].toVersion as LastItem<
typeof supportedUpdates
>['toVersion']

export const STORAGE_VERSION_RECORD_ID = 'STORAGE_VERSION_RECORD_ID'

type LastItem<T extends readonly unknown[]> = T extends readonly [...infer _, infer U] ? U : T[0] | undefined
Expand Down
16 changes: 12 additions & 4 deletions packages/tenants/src/context/TenantAgentContextProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
JsonEncoder,
Kms,
type Logger,
StorageUpdateService,
TypedArrayEncoder,
UpdateAssistant,
type UpdateAssistantUpdateOptions,
Expand Down Expand Up @@ -67,18 +68,25 @@ export class TenantAgentContextProvider implements AgentContextProvider {

// TODO: maybe we can look at not having to retrieve the tenant record if there's already a context available.
const tenantRecord = await this.tenantRecordService.getTenantById(this.rootAgentContext, tenantId)
const shouldUpdate = !isStorageUpToDate(tenantRecord.storageVersion)
const canUpdate = !isStorageUpToDate(tenantRecord.storageVersion)
const mustUpdate = !isStorageUpToDate(
tenantRecord.storageVersion,
StorageUpdateService.previousFrameworkStorageVersion
)

// If the tenant storage is not up to date, and autoUpdate is disabled we throw an error
if (shouldUpdate && !this.rootAgentContext.config.autoUpdateStorageOnStartup) {
if (mustUpdate && !this.rootAgentContext.config.autoUpdateStorageOnStartup) {
throw new CredoError(
`Current agent storage for tenant ${tenantRecord.id} is not up to date. To prevent the tenant state from getting corrupted the tenant initialization is aborted. Make sure to update the tenant storage (currently at ${tenantRecord.storageVersion}) to the latest version (${UpdateAssistant.frameworkStorageVersion}). You can also downgrade your version of Credo.`
`Current agent storage for tenant ${tenantRecord.id} is not up to date. To prevent the tenant state from getting corrupted the tenant initialization is aborted. Make sure to update the tenant storage (currently at ${tenantRecord.storageVersion}) to the latest or previous version (${UpdateAssistant.frameworkStorageVersion} or ${UpdateAssistant.frameworkStorageVersion}). You can also downgrade your version of Credo.`
)
}

const agentContext = await this.tenantSessionCoordinator.getContextForSession(tenantRecord, {
provisionContext,
runInMutex: shouldUpdate ? (agentContext) => this._updateTenantStorage(tenantRecord, agentContext) : undefined,
runInMutex:
canUpdate && this.rootAgentContext.config.autoUpdateStorageOnStartup
? (agentContext) => this._updateTenantStorage(tenantRecord, agentContext)
: undefined,
})

this.logger.debug(`Created tenant agent context for context correlation id '${contextCorrelationId}'`)
Expand Down
Loading