> Discover all available pages from the documentation index: https://mastra.zisheng.pro/ko/llms.txt # 저장 Storage API는 모든 방법에서 일관된 페이지 매김 및 이름 지정 패턴으로 표준화되었습니다. ## 데이터베이스 마이그레이션 일반적인 마이그레이션 프로세스(예: Prisma Migrate, Drizzle Kit 또는 DBA 검토 프로세스)를 통해 이러한 SQL 마이그레이션을 실행하세요. ### 득점자 테이블 열 이름 바꾸기 `mastra_scorers`의 `runtimeContext` 열 이름이 `requestContext`로 변경되었습니다. :::note\[이 마이그레이션이 필요한 대상] Evals/채점과 함께 `@mastra/pg` 또는 `@mastra/libsql`을 사용하며 `runtimeContext` 열에 기존 데이터가 있는 경우에만 필요합니다. ::: :::중요\[그것이 없으면 고장나는 것] 기존 점수 기록에는 요청 컨텍스트 데이터에 액세스할 수 없습니다. ::: v1을 배포한 후(초기화 시 새 `requestContext` 열이 생성됨) 데이터를 복사하고 이전 열을 삭제하세요. ```sql UPDATE mastra_scorers SET "requestContext" = "runtimeContext" WHERE "runtimeContext" IS NOT NULL; ALTER TABLE mastra_scorers DROP COLUMN "runtimeContext"; ``` ### 중복 스팬 마이그레이션 이전 버전의 Mastra에서 업그레이드하는 경우 `mastra_spans` 테이블에 중복된 `(traceId, spanId)` 항목이 있을 수 있습니다. V1은 데이터 무결성을 보장하기 위해 이러한 열에 고유 제약 조건을 추가하지만 중복 항목이 있으면 이 제약 조건을 추가할 수 없습니다. :::note\[이 마이그레이션이 필요한 사람] v1 이전 Mastra 버전의 기존 범위 데이터가 있고 중복 키 위반 또는 제약 조건 생성 실패에 대한 오류가 발생한 경우에만 해당됩니다. ::: :::중요\[그것이 없으면 고장나는 것] 고유 제약 조건을 추가하려고 하면 스토리지 초기화가 실패하거나 "중복 키 값이 고유 제약 조건을 위반합니다"와 같은 오류가 표시될 수 있습니다. ::: #### 옵션 1: CLI 사용(권장) 자동으로 스팬 중복을 제거하고 제약조건을 추가하는 마이그레이션 명령어를 실행합니다. ```bash npx mastra migrate ``` CLI는 마이그레이션을 실행하기 전에 프로젝트를 번들링하고 구성된 스토리지에 연결합니다. 중복 항목을 제거할 때 가장 완전한 레코드(`endTime` 및 속성)를 유지합니다. #### 옵션 2: 수동 SQL(PostgreSQL) 마이그레이션을 수동으로 실행하려는 경우: ```sql -- Remove duplicates, keeping the most complete record DELETE FROM mastra_spans a USING mastra_spans b WHERE a.ctid < b.ctid AND a."traceId" = b."traceId" AND a."spanId" = b."spanId"; -- Add the unique constraint ALTER TABLE mastra_spans ADD CONSTRAINT mastra_spans_trace_span_unique UNIQUE ("traceId", "spanId"); ``` #### 옵션 3: 수동 마이그레이션(기타 데이터베이스) ClickHouse, LibSQL, MongoDB 또는 MSSQL의 경우 프로그래밍 방식 API를 사용합니다. ```typescript const storage = mastra.getStorage() const observabilityStore = await storage.getStore('observability') // Check if migration is needed const status = await observabilityStore?.checkSpansMigrationStatus() console.log(status) // Run the migration const result = await observabilityStore?.migrateSpans() console.log(result) ``` ### JSON 열(TEXT → JSONB) **PostgreSQL에만 해당됩니다.**그`mastra_threads`의 `metadata` 열과 `mastra_workflow_snapshot`의 `snapshot` 열이 TEXT에서 JSONB로 변경되었습니다. :::참고\[권장] JSONB로 마이그레이션하면 기본 PostgreSQL JSON 연산자와 GIN 인덱싱이 활성화되어 JSON 필드에 대한 쿼리 성능이 향상됩니다. ::: ```sql ALTER TABLE mastra_threads ALTER COLUMN metadata TYPE jsonb USING metadata::jsonb; ALTER TABLE mastra_workflow_snapshot ALTER COLUMN snapshot TYPE jsonb USING snapshot::jsonb; ``` ## 추가됨 ### 저장 구성`MastraCompositeStore` `MastraCompositeStore`이제 다양한 어댑터에서 스토리지 도메인을 구성할 수 있습니다. 다양한 목적을 위해 다양한 데이터베이스가 필요한 경우 이를 사용하세요. 예를 들어 Memory 및 Workflow에는 PostgreSQL이 필요하지만 Observability에는 특수 데이터베이스가 필요합니다. ```typescript import { MastraCompositeStore } from '@mastra/core/storage' import { MemoryPG, WorkflowsPG, ScoresPG } from '@mastra/pg' import { MemoryLibSQL } from '@mastra/libsql' import { Mastra } from '@mastra/core' // Compose domains from different stores const mastra = new Mastra({ storage: new MastraCompositeStore({ id: 'composite', domains: { memory: new MemoryLibSQL({ url: 'file:./local.db' }), workflows: new WorkflowsPG({ connectionString: process.env.DATABASE_URL }), scores: new ScoresPG({ connectionString: process.env.DATABASE_URL }), }, }), }) ``` 자세한 내용은 [스토리지 컴포지션 레퍼런스](https://mastra.zisheng.pro/ko/reference/storage/composite)를 참조하세요. ## 변경됨 ### `MastraStorage`다음으로 이름이 변경됨`MastraCompositeStore` 여러 도메인을 서로 다른 기본 스토어로 라우팅하는 복합 스토리지 구현이라는 역할을 더 잘 나타내도록 `MastraStorage` 클래스의 이름이 `MastraCompositeStore`로 변경되었습니다. 이를 통해 일반적인 "Mastra Storage" 개념(Mastra 인스턴스의 `storage` 속성)과 혼동되는 것을 방지합니다. 이전 `MastraStorage` 이름은 하위 호환성을 위해 더 이상 사용되지 않는 별칭으로 계속 제공되지만 향후 버전에서 제거될 예정입니다. 마이그레이션하려면 가져오기 및 인스턴스화를 업데이트하세요. ```diff - import { MastraStorage } from "@mastra/core/storage"; + import { MastraCompositeStore } from "@mastra/core/storage"; import { MemoryLibSQL } from "@mastra/libsql"; import { WorkflowsPG } from "@mastra/pg"; export const mastra = new Mastra({ - storage: new MastraStorage({ + storage: new MastraCompositeStore({ id: "composite", domains: { memory: new MemoryLibSQL({ url: "file:./memory.db" }), workflows: new WorkflowsPG({ connectionString: process.env.DATABASE_URL }), }, }), }); ``` :::참고 `PostgresStore` 또는 `LibSQLStore` 같은 단일 스토어 구현을 직접 사용한다면 기존 구성을 유지하세요. 이 변경은 복합 스토리지에 `MastraStorage`를 명시적으로 사용하는 코드에만 영향을 줍니다. ::: ### 스토리지 인스턴스에 필수인 `id` 속성 이제 스토리지 인스턴스에는 `id` 속성이 필요합니다. 이 고유 식별자는 Mastra 내에서 스토리지 인스턴스를 추적하고 관리하는 데 사용됩니다. `id`는 애플리케이션의 각 스토리지 인스턴스를 설명하는 고유한 문자열이어야 합니다. 마이그레이션하려면 스토리지 생성자에 `id` 필드를 추가하세요. ```diff const storage = new PostgresStore({ + id: 'main-postgres-store', connectionString: process.env.POSTGRES_CONNECTION_STRING, schemaName: 'public', }); const upstashStore = new UpstashStore({ + id: 'upstash-cache-store', url: process.env.UPSTASH_REDIS_REST_URL, token: process.env.UPSTASH_REDIS_REST_TOKEN, }); ``` ### 페이지네이션을 `offset/limit`에서 `page/perPage`로 변경 이제 모든 페이지네이션 API는 페이지 기반 웹 페이지네이션에 맞춰 `offset`과 `limit` 대신 `page`와 `perPage`를 사용합니다. 마이그레이션하려면 모든 페이지네이션 매개변수를 `offset/limit`에서 `page/perPage`로 업데이트하세요. `page`는 0부터 시작합니다. ```diff memoryStore.listMessages({ threadId: 'thread-123', - offset: 0, - limit: 20, + page: 0, + perPage: 20, }); ``` ### `getMessagesPaginated`에게`listMessages` `getMessagesPaginated()` 메서드가 `listMessages()`로 대체되었습니다. 새 메서드는 페이지네이션 없이 모든 레코드를 가져오는 `perPage: false`를 지원합니다. 이 변경은 `list*` 명명 규칙과 일치하며 모든 레코드를 가져올 때의 유연성을 높입니다. 마이그레이션하려면 메서드 이름을 바꾸고 페이지네이션 매개변수를 업데이트하세요. 이제 모든 레코드를 가져올 때 `perPage: false`를 사용할 수 있습니다. ```diff + const memoryStore = await storage.getStore('memory'); + // Paginated - const result = await storage.getMessagesPaginated({ + const result = await memoryStore?.listMessages({ threadId: 'thread-123', - offset: 0, - limit: 20, + page: 0, + perPage: 20, }); // Fetch all records (no pagination limit) + const allMessages = await memoryStore?.listMessages({ + threadId: 'thread-123', + page: 0, + perPage: false, + }); ``` :::tip\[코드모드] Mastra의 codemod CLI를 사용하여 코드를 자동으로 업데이트할 수 있습니다. ```bash npx @mastra/codemod@latest v1/storage-get-messages-paginated . ``` ::: ### 다음을 통한 도메인별 스토리지 액세스`getStore()` 이제 스토리지 작업은 스토리지 인스턴스에서 직접 액세스하는 대신 도메인별 저장소를 통해 액세스됩니다. 도메인에는 다음이 포함됩니다. - **`memory`**- 스레드, 메시지, 리소스 - **`workflows`**- Workflow 스냅샷 - **`scores`**- 평가점수 - **`observability`**- 추적 및 범위 - **`agents`**- 저장된 Agent 데이터 마이그레이션하려면 도메인 이름으로 `getStore()`를 호출한 다음 반환된 스토어에서 메서드를 호출하세요. ```diff const storage = mastra.getStorage(); // Memory operations (threads, messages, resources) - const thread = await storage.getThread({ threadId: '123' }); - await storage.saveThread({ thread }); + const memoryStore = await storage.getStore('memory'); + const thread = await memoryStore?.getThreadById({ threadId: '123' }); + await memoryStore?.saveThread({ thread }); // Workflow operations (snapshots) - const snapshot = await storage.loadWorkflowSnapshot({ runId, workflowName }); - await storage.persistWorkflowSnapshot({ runId, workflowName, snapshot }); + const workflowStore = await storage.getStore('workflows'); + const snapshot = await workflowStore?.loadWorkflowSnapshot({ runId, workflowName }); + await workflowStore?.persistWorkflowSnapshot({ runId, workflowName, snapshot }); // Observability operations (traces, spans) - const traces = await storage.listTraces({ page: 0, perPage: 20 }); + const observabilityStore = await storage.getStore('observability'); + const traces = await observabilityStore?.listTraces({ page: 0, perPage: 20 }); // Score operations (evaluations) - const scores = await storage.listScoresByScorerId({ scorerId: 'helpfulness' }); + const scoresStore = await storage.getStore('scores'); + const scores = await scoresStore?.listScoresByScorerId({ scorerId: 'helpfulness' }); ``` ### `getThreadsByResourceId`에게`listThreads` `getThreadsByResourceId()` 메서드가 `listThreads()`로 대체되었습니다. 새 메서드는 페이지네이션과 `resourceId`, `metadata` 또는 둘 모두를 기준으로 한 필터링을 지원합니다. :::중요한 이전 `getThreadsByResourceId()`는 페이지네이션 없이 일치하는 모든 스레드를 반환했습니다. 새 `listThreads()`에는 페이지네이션 매개변수가 필요합니다. 모든 스레드를 가져오는 이전 동작을 유지하려면 `perPage: false`를 사용하세요. ::: 마이그레이션하려면 Memory 스토어와 페이지네이션 및 선택적 필터 객체를 지원하는 새 `listThreads()` 메서드를 사용하세요. ```diff - const threads = await storage.getThreadsByResourceId({ - resourceId: 'res-123', - }); + const memoryStore = await storage.getStore('memory'); + + // Paginated (recommended for large datasets) + const result = await memoryStore?.listThreads({ + filter: { resourceId: 'res-123' }, + page: 0, + perPage: 20, + }); + const threads = result?.threads; + + // Or fetch all threads like before (use perPage: false) + const allResult = await memoryStore?.listThreads({ + filter: { resourceId: 'res-123' }, + perPage: false, + }); + const allThreads = allResult?.threads; ``` 새로운 방법은 다음도 지원합니다. - 모든 스레드 나열(필터 생략) - 메타데이터로만 필터링 - 결합된 리소스 ID + 메타데이터 필터 ```typescript // List all threads await memoryStore?.listThreads({ page: 0, perPage: 20 }) // Filter by metadata only await memoryStore?.listThreads({ filter: { metadata: { status: 'active' } }, page: 0, perPage: 20, }) // Combined filter await memoryStore?.listThreads({ filter: { resourceId: 'user-123', metadata: { category: 'support' }, }, page: 0, perPage: 20, }) ``` :::tip\[코드모드] Mastra의 codemod CLI를 사용하여 코드를 자동으로 업데이트할 수 있습니다. ```bash npx @mastra/codemod@latest v1/storage-list-threads-by-resource-to-list-threads . ``` ::: ### `getWorkflowRuns`에게`listWorkflowRuns` `getWorkflowRuns()` 메서드의 이름이 `listWorkflowRuns()`로 변경되었습니다. 이 변경은 컬렉션을 반환하는 메서드에 `list*`를 사용하는 규칙과 일치합니다. 마이그레이션하려면 Workflow 저장소를 사용하고 메서드 호출 이름을 바꾸고 페이지 매김 매개 변수를 업데이트하세요. ```diff - const runs = await storage.getWorkflowRuns({ + const workflowStore = await storage.getStore('workflows'); + const runs = await workflowStore?.listWorkflowRuns({ fromDate, toDate, + page: 0, + perPage: 20, }); ``` :::tip\[코드모드] Mastra의 codemod CLI를 사용하여 코드를 자동으로 업데이트할 수 있습니다. ```bash npx @mastra/codemod@latest v1/storage-list-workflow-runs . ``` ::: ### `getMessagesById`에게`listMessagesById` `getMessagesById()` 메서드의 이름이 `listMessagesById()`로 변경되었습니다. 이 변경은 컬렉션을 반환하는 메서드에 `list*`를 사용하는 규칙과 일치합니다. 마이그레이션하려면 Memory 저장소를 사용하고 메서드 호출의 이름을 바꾸세요. ```diff + const memoryStore = await storage.getStore('memory'); - const result = await storage.getMessagesById({ + const result = await memoryStore?.listMessagesById({ messageIds: ['msg-1', 'msg-2'], }); ``` :::tip\[코드모드] Mastra의 codemod CLI를 사용하여 코드를 자동으로 업데이트할 수 있습니다. ```bash npx @mastra/codemod@latest v1/storage-list-messages-by-id . ``` ::: ### 스토리지 `getMessages` 및 `saveMessages` 시그니처 `getMessages()` 및 `saveMessages()` 메서드의 시그니처와 반환 타입이 변경되었습니다. 형식 오버로드가 제거되었으며 이제 이 메서드들은 항상 `MastraDBMessage`를 사용합니다. 이 변경은 형식 변형을 제거하여 API를 단순화합니다. 마이그레이션하려면 Memory 저장소를 사용하고, 형식 매개변수를 제거하고, 일관된 반환 유형으로 작동하도록 코드를 업데이트하세요. ```diff + const memoryStore = await storage.getStore('memory'); + // Always returns { messages: MastraDBMessage[] } - const v1Messages = await storage.getMessages({ threadId, format: 'v1' }); - const v2Messages = await storage.getMessages({ threadId, format: 'v2' }); + const result = await memoryStore?.getMessages({ threadId }); + const messages = result?.messages; // MastraDBMessage[] // SaveMessages always uses MastraDBMessage - await storage.saveMessages({ messages: v1Messages, format: 'v1' }); - await storage.saveMessages({ messages: v2Messages, format: 'v2' }); + const saveResult = await memoryStore?.saveMessages({ messages: mastraDBMessages }); + const saved = saveResult?.messages; // MastraDBMessage[] ``` ### 위치 인수에서 명명된 인수까지 벡터 저장 API 이제 모든 벡터 저장 메서드는 위치 인수 대신 인수 개체를 사용합니다. 이렇게 하면 호출 사이트에서 각 값의 목적을 볼 수 있으며 인수 순서에 의존하지 않고 메서드 시그니처를 발전시킬 수 있습니다. 마이그레이션하려면 인수 객체를 사용하도록 모든 벡터 저장소 메서드 호출을 업데이트하세요. ```diff - await vectorDB.createIndex(indexName, 3, 'cosine'); + await vectorDB.createIndex({ + indexName: indexName, + dimension: 3, + metric: 'cosine', + }); - await vectorDB.upsert(indexName, [[1, 2, 3]], [{ test: 'data' }]); + await vectorDB.upsert({ + indexName: indexName, + vectors: [[1, 2, 3]], + metadata: [{ test: 'data' }], + }); - await vectorDB.query(indexName, [1, 2, 3], 5); + await vectorDB.query({ + indexName: indexName, + queryVector: [1, 2, 3], + topK: 5, + }); ``` ### 벡터 저장 메소드 이름 변경 `updateIndexById` 및 `deleteIndexById` 메서드의 이름이 각각 `updateVector`와 `deleteVector`로 변경되었습니다. 새 이름은 이 메서드가 벡터를 대상으로 작동한다는 점을 명확히 나타냅니다. 마이그레이션하려면 메서드 이름을 바꾸고 인수 개체를 전달하세요. ```diff - await vectorDB.updateIndexById(indexName, id, update); - await vectorDB.deleteIndexById(indexName, id); + await vectorDB.updateVector({ indexName, id, update }); + await vectorDB.deleteVector({ indexName, id }); ``` ### 연결 문자열에서 객체로의 PGVector 생성자 이제 PGVector 생성자에는 연결 문자열 대신 객체 매개변수가 필요합니다. 이 변경으로 모든 스토리지 어댑터에 걸쳐 더욱 일관된 API가 제공됩니다. 마이그레이션하려면 연결 문자열을 개체 속성으로 전달합니다. ```diff - const pgVector = new PgVector(process.env.POSTGRES_CONNECTION_STRING!); + const pgVector = new PgVector({ + connectionString: process.env.POSTGRES_CONNECTION_STRING, + }); ``` :::tip\[코드모드] Mastra의 codemod CLI를 사용하여 코드를 자동으로 업데이트할 수 있습니다. ```bash npx @mastra/codemod@latest v1/vector-pg-constructor . ``` ::: ### PGVector: `defineIndex`에서 `buildIndex`로 `defineIndex()` 메서드가 제거되고 `buildIndex()`로 대체되었습니다. 새 이름은 이 메서드가 인덱스를 빌드한다는 점을 명확히 나타냅니다. 마이그레이션하려면 메서드 이름을 바꾸고 인수 개체를 전달하세요. ```diff - await vectorDB.defineIndex(indexName, 'cosine', { type: 'flat' }); + await vectorDB.buildIndex({ + indexName: indexName, + metric: 'cosine', + indexConfig: { type: 'flat' }, + }); ``` ### `PostgresStore`: `schema`에서 `schemaName`으로 PostgresStore 생성자의 `schema` 매개변수 이름이 `schemaName`으로 변경되었습니다. 새 이름은 해당 값이 데이터베이스 스키마의 이름임을 명확히 나타냅니다. 마이그레이션하려면 매개변수 이름을 바꾸세요. ```diff const pgStore = new PostgresStore({ connectionString: process.env.POSTGRES_CONNECTION_STRING, - schema: customSchema, + schemaName: customSchema, }); ``` :::tip\[코드모드] Mastra의 codemod CLI를 사용하여 코드를 자동으로 업데이트할 수 있습니다. ```bash npx @mastra/codemod@latest v1/storage-postgres-schema-name . ``` ::: ### 저장 방법에 점수를 매김`listScoresBy*` pattern 점수 저장 API의 이름이 `listScoresBy*` 패턴을 따르도록 변경되었습니다. 이 변경으로 전반적인 API 명명 규칙과 일관성을 유지할 수 있습니다. 마이그레이션하려면 `getScores`를 `listScoresByScorerId` 및 관련 변형으로 변경하세요. ```diff - const scores = await storage.getScores({ scorerName: 'helpfulness-scorer' }); + const scores = await storage.listScoresByScorerId({ + scorerId: 'helpfulness-scorer', + }); + // Also available: listScoresByRunId, listScoresByEntityId, listScoresBySpan ``` ## 제거됨 ### 페이지가 매겨지지 않은 저장 기능 페이지네이션되지 않은 저장 기능이 페이지네이션 버전으로 대체되어 제거되었습니다. 이제 모든 목록 작업에 페이지네이션이 적용되지만 `perPage: false`를 사용하면 모든 레코드를 가져올 수 있습니다. 이 변경으로 API 전반의 일관성을 유지하고 대규모 데이터 세트가 실수로 로드되는 것을 방지할 수 있습니다. 마이그레이션하려면 도메인 저장소를 통해 페이지를 매긴 방법을 사용하세요. 모든 레코드를 가져오려면 다음을 사용하세요.`perPage: false`. ```diff - // Non-paginated direct access - const messages = await storage.getMessages({ threadId }); + // Use paginated methods via domain stores + const memoryStore = await storage.getStore('memory'); + const result = await memoryStore?.listMessages({ threadId, page: 0, perPage: 20 }); + // Or fetch all + const allMessages = await memoryStore?.listMessages({ + threadId, + page: 0, + perPage: false, + }); ``` ### `getTraces`그리고`getTracesPaginated` `getTraces()` 및 `getTracesPaginated()` 메서드가 스토리지에서 제거되었습니다. Trace에 액세스하려면 코어 스토리지 대신 Observability 패키지를 사용하세요. 마이그레이션하려면 대신 관측 가능성 스토리지 방법을 사용하세요. ```diff - const traces = await storage.getTraces({ traceId: 'trace-123' }); - const paginated = await storage.getTracesPaginated({ page: 0, perPage: 20 }); + // Use observability API for traces + import { initObservability } from '@mastra/observability'; + const observability = initObservability({ config: { ... } }); + // Access traces through observability API ``` ### 평가 테스트 유틸리티 Evals 도메인 테스트 유틸리티가 `@internal/test-utils`에서 제거되었습니다. 이 변경은 레거시 Evals 기능이 제거된 데 따른 것입니다. 마이그레이션하려면 전문 평가 테스트 유틸리티 대신 스토리지 API를 직접 사용하여 테스트하세요. ```diff - import { createEvalsTests } from '@internal/test-utils/domains/evals'; - createEvalsTests({ storage }); + // Use storage APIs directly for testing ``` ### MSSQL 스토리지의 TABLE\_EVALS MSSQL 스토리지 구현에서 `TABLE_EVALS` 테이블이 제거되었습니다. 이 변경은 레거시 Evals 기능이 제거된 데 따른 것입니다. 평가 기능이 포함된 MSSQL 스토리지를 사용하고 있는 경우 다른 스토리지 어댑터로 마이그레이션하거나 평가 기능을 제거하세요.