|
|
|
|
@ -5,7 +5,7 @@ import { ConversationPage } from "#app/entity/ConversationPage.js";
|
|
|
|
|
import { Logger } from "#app/utils/logger.js";
|
|
|
|
|
import Koa, { Next } from "koa";
|
|
|
|
|
import Router from "koa-router";
|
|
|
|
|
import { ActionRes, CreateNewPageReq, CreateNewPageReqType, GetConversationInfoRes, GetConversationInfoResType, GetDialogueInfoRes, GetDialogueInfoResType, GetMessageContentQuery, GetPageInfoRes, GetPageInfoResType, GetPageListRes, GetPageListResType, OverrideDialogueMessagesReq, OverrideDialogueMessagesReqType, UpdateDialogueMessagesReq, UpdateDialogueMessagesReqType, type ActionResType } from "./schemas/MemoryControllerSchemas.js";
|
|
|
|
|
import { ActionRes, CreateNewPageReq, CreateNewPageReqType, GetConversationInfoRes, GetConversationInfoResType, GetDialogueInfoRes, GetDialogueInfoResType, GetMessageContentQuery, GetPageInfoRes, GetPageInfoResType, GetPageListRes, GetPageListResType, GetPageMetadataRes, GetPageMetadataResType, OverrideDialogueMessagesReq, OverrideDialogueMessagesReqType, pageIdSchema, UpdateDialogueMessagesReq, UpdateDialogueMessagesReqType, UpdatePageMetadataReq, UpdatePageMetadataReqType, type ActionResType } from "./schemas/MemoryControllerSchemas.js";
|
|
|
|
|
import { body, responses, routeConfig, SwaggerRouter, z } from "koa-swagger-decorator";
|
|
|
|
|
|
|
|
|
|
type ResponsesConfig = Parameters<typeof routeConfig>[0]['responses'];
|
|
|
|
|
@ -484,12 +484,33 @@ export class MemoryController {
|
|
|
|
|
|
|
|
|
|
const body = ctx.request.body as CreateNewPageReqType;
|
|
|
|
|
|
|
|
|
|
let newMetadata: any = body.metadata ?? {};
|
|
|
|
|
if (!(typeof newMetadata === 'object')) {
|
|
|
|
|
newMetadata = {};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const conversation = await this.getConversationInfo(ctx);
|
|
|
|
|
if (!conversation) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
await conversation.createNewPage(ctx.application, body.metadata ?? undefined);
|
|
|
|
|
if (body.inheritMetadata) {
|
|
|
|
|
const currentPage = await ctx.database!.getRepository(ConversationPage)
|
|
|
|
|
.findOneBy({ conversationId: conversation.conversationId, pageId: conversation.currentPage });
|
|
|
|
|
if (currentPage) {
|
|
|
|
|
let currentMetadata = currentPage.metadata;
|
|
|
|
|
if (!(typeof currentMetadata === 'object')) {
|
|
|
|
|
currentMetadata = {};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
newMetadata = {
|
|
|
|
|
...currentMetadata,
|
|
|
|
|
...newMetadata,
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
await conversation.createNewPage(ctx.application, newMetadata ?? undefined);
|
|
|
|
|
|
|
|
|
|
ctx.status = 200;
|
|
|
|
|
ctx.body = {
|
|
|
|
|
@ -506,7 +527,7 @@ export class MemoryController {
|
|
|
|
|
request: {
|
|
|
|
|
params: z.object({
|
|
|
|
|
conversationId: z.string().describe('The conversation ID to retrieve the page for.'),
|
|
|
|
|
pageId: z.number().describe('The page ID to retrieve information for.'),
|
|
|
|
|
pageId: pageIdSchema,
|
|
|
|
|
}),
|
|
|
|
|
},
|
|
|
|
|
responses: DefaultResponses,
|
|
|
|
|
@ -545,4 +566,336 @@ export class MemoryController {
|
|
|
|
|
|
|
|
|
|
return pageData;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@routeConfig({
|
|
|
|
|
method: 'get',
|
|
|
|
|
path: '/memory/v1/{conversationId}/page/{pageId}/metadata',
|
|
|
|
|
summary: 'Get metadata of a specific page in a conversation',
|
|
|
|
|
operationId: 'getPageMetadata',
|
|
|
|
|
request: {
|
|
|
|
|
params: z.object({
|
|
|
|
|
conversationId: z.string().describe('The conversation ID to retrieve the page for.'),
|
|
|
|
|
pageId: pageIdSchema,
|
|
|
|
|
}),
|
|
|
|
|
},
|
|
|
|
|
responses: DefaultResponses,
|
|
|
|
|
})
|
|
|
|
|
@responses(GetPageMetadataRes)
|
|
|
|
|
public async getPageMetadata(ctx: Koa.ParameterizedContext): Promise<any> {
|
|
|
|
|
const page = await this.getPageInfo(ctx);
|
|
|
|
|
if (!page) {
|
|
|
|
|
ctx.status = 404;
|
|
|
|
|
ctx.body = { error: 'Page not found' };
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ctx.status = 200;
|
|
|
|
|
ctx.body = {
|
|
|
|
|
metadata: page.metadata,
|
|
|
|
|
} as GetPageMetadataResType;
|
|
|
|
|
|
|
|
|
|
return page.metadata;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@routeConfig({
|
|
|
|
|
method: 'get',
|
|
|
|
|
path: '/memory/v1/{conversationId}/page/{pageId}/metadata/{varKey}',
|
|
|
|
|
summary: 'Get a specific metadata variable from a page in a conversation',
|
|
|
|
|
operationId: 'getPageMetadataVariable',
|
|
|
|
|
request: {
|
|
|
|
|
params: z.object({
|
|
|
|
|
conversationId: z.string().describe('The conversation ID to retrieve the page for.'),
|
|
|
|
|
pageId: pageIdSchema,
|
|
|
|
|
varKey: z.string().describe('The key of the metadata variable to retrieve.'),
|
|
|
|
|
}),
|
|
|
|
|
},
|
|
|
|
|
responses: DefaultResponses,
|
|
|
|
|
})
|
|
|
|
|
@responses(z.string() as any)
|
|
|
|
|
public async getPageMetadataVariable(ctx: Koa.ParameterizedContext): Promise<any> {
|
|
|
|
|
const page = await this.getPageInfo(ctx);
|
|
|
|
|
if (!page) {
|
|
|
|
|
ctx.status = 404;
|
|
|
|
|
ctx.body = { error: 'Page not found' };
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const varKey = ctx.params.varKey as string;
|
|
|
|
|
const metadataValue = page.metadata[varKey];
|
|
|
|
|
|
|
|
|
|
if (metadataValue === undefined) {
|
|
|
|
|
ctx.status = 404;
|
|
|
|
|
ctx.body = { error: `Metadata variable "${varKey}" not found` };
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ctx.status = 200;
|
|
|
|
|
ctx.body = metadataValue;
|
|
|
|
|
|
|
|
|
|
return metadataValue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@routeConfig({
|
|
|
|
|
method: 'get',
|
|
|
|
|
path: '/memory/v1/{conversationId}/page/{pageId}/metadata/{varKey}/json',
|
|
|
|
|
summary: 'Get a specific metadata variable from a page in a conversation as JSON',
|
|
|
|
|
operationId: 'getPageMetadataVariableJson',
|
|
|
|
|
request: {
|
|
|
|
|
params: z.object({
|
|
|
|
|
conversationId: z.string().describe('The conversation ID to retrieve the page for.'),
|
|
|
|
|
pageId: pageIdSchema,
|
|
|
|
|
varKey: z.string().describe('The key of the metadata variable to retrieve.'),
|
|
|
|
|
}),
|
|
|
|
|
},
|
|
|
|
|
responses: DefaultResponses,
|
|
|
|
|
})
|
|
|
|
|
@responses(z.string() as any)
|
|
|
|
|
public async getPageMetadataVariableJson(ctx: Koa.ParameterizedContext): Promise<any> {
|
|
|
|
|
const metadataValue = await this.getPageMetadataVariable(ctx);
|
|
|
|
|
if (metadataValue === null) {
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
const jsonValue = JSON.stringify(metadataValue);
|
|
|
|
|
ctx.status = 200;
|
|
|
|
|
ctx.type = 'application/json';
|
|
|
|
|
ctx.body = jsonValue;
|
|
|
|
|
return jsonValue;
|
|
|
|
|
} catch (error) {
|
|
|
|
|
ctx.status = 500;
|
|
|
|
|
ctx.body = { error: `Failed to convert metadata variable "${ctx.params.varKey}" to JSON` };
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@routeConfig({
|
|
|
|
|
method: 'post',
|
|
|
|
|
path: '/memory/v1/{conversationId}/page/{pageId}/metadata',
|
|
|
|
|
summary: 'Update metadata of a specific page in a conversation',
|
|
|
|
|
operationId: 'updatePageMetadata',
|
|
|
|
|
request: {
|
|
|
|
|
params: z.object({
|
|
|
|
|
conversationId: z.string().describe('The conversation ID to update the page metadata for.'),
|
|
|
|
|
pageId: pageIdSchema,
|
|
|
|
|
}),
|
|
|
|
|
query: z.object({
|
|
|
|
|
override: z.boolean().optional().default(false).describe('Whether to override existing metadata.'),
|
|
|
|
|
}),
|
|
|
|
|
},
|
|
|
|
|
responses: DefaultResponses,
|
|
|
|
|
})
|
|
|
|
|
@body(UpdatePageMetadataReq)
|
|
|
|
|
@responses(ActionRes)
|
|
|
|
|
public async updatePageMetadata(ctx: Koa.ParameterizedContext): Promise<void> {
|
|
|
|
|
if (!this.checkDb(ctx)) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
UpdatePageMetadataReq.parse(ctx.request.body);
|
|
|
|
|
} catch (error: any) {
|
|
|
|
|
ctx.status = 422;
|
|
|
|
|
ctx.body = {
|
|
|
|
|
success: false,
|
|
|
|
|
message: 'Invalid request body',
|
|
|
|
|
error: error.message,
|
|
|
|
|
} as ActionResType;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
const body = ctx.request.body as UpdatePageMetadataReqType;
|
|
|
|
|
|
|
|
|
|
const page = await this.getPageInfo(ctx);
|
|
|
|
|
if (!page) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (typeof page.metadata !== 'object') {
|
|
|
|
|
page.metadata = {};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (ctx.query.override) {
|
|
|
|
|
page.metadata = body.metadata;
|
|
|
|
|
} else {
|
|
|
|
|
page.metadata = { ...page.metadata, ...body.metadata };
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
await ctx.database!.getRepository(ConversationPage)
|
|
|
|
|
.save(page);
|
|
|
|
|
|
|
|
|
|
ctx.status = 200;
|
|
|
|
|
ctx.body = {
|
|
|
|
|
success: true,
|
|
|
|
|
message: 'OK',
|
|
|
|
|
} as ActionResType;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@routeConfig({
|
|
|
|
|
method: 'post',
|
|
|
|
|
path: '/memory/v1/{conversationId}/page/{pageId}/metadata/{varKey}',
|
|
|
|
|
summary: 'Update a specific metadata variable of a page in a conversation',
|
|
|
|
|
operationId: 'updatePageMetadataVariable',
|
|
|
|
|
request: {
|
|
|
|
|
params: z.object({
|
|
|
|
|
conversationId: z.string().describe('The conversation ID to update the page metadata for.'),
|
|
|
|
|
pageId: pageIdSchema,
|
|
|
|
|
varKey: z.string().describe('The key of the metadata variable to update.'),
|
|
|
|
|
}),
|
|
|
|
|
},
|
|
|
|
|
responses: DefaultResponses,
|
|
|
|
|
})
|
|
|
|
|
@body(z.string().describe('The new value for the metadata variable.') as any)
|
|
|
|
|
@responses(ActionRes)
|
|
|
|
|
public async updatePageMetadataVariable(ctx: Koa.ParameterizedContext): Promise<void> {
|
|
|
|
|
if (!this.checkDb(ctx)) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const page = await this.getPageInfo(ctx);
|
|
|
|
|
if (!page) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const varKey = ctx.params.varKey as string;
|
|
|
|
|
const newValue = ctx.request.body as string;
|
|
|
|
|
|
|
|
|
|
if (typeof page.metadata !== 'object') {
|
|
|
|
|
page.metadata = {};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
page.metadata[varKey] = newValue;
|
|
|
|
|
|
|
|
|
|
await ctx.database!.getRepository(ConversationPage)
|
|
|
|
|
.save(page);
|
|
|
|
|
|
|
|
|
|
ctx.status = 200;
|
|
|
|
|
ctx.body = {
|
|
|
|
|
success: true,
|
|
|
|
|
message: `OK`,
|
|
|
|
|
} as ActionResType;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@routeConfig({
|
|
|
|
|
method: 'post',
|
|
|
|
|
path: '/memory/v1/{conversationId}/page/{pageId}/metadata/{varKey}/json',
|
|
|
|
|
summary: 'Update a specific metadata variable of a page in a conversation as JSON',
|
|
|
|
|
operationId: 'updatePageMetadataVariableJson',
|
|
|
|
|
request: {
|
|
|
|
|
params: z.object({
|
|
|
|
|
conversationId: z.string().describe('The conversation ID to update the page metadata for.'),
|
|
|
|
|
pageId: pageIdSchema,
|
|
|
|
|
varKey: z.string().describe('The key of the metadata variable to update.'),
|
|
|
|
|
}),
|
|
|
|
|
},
|
|
|
|
|
responses: DefaultResponses,
|
|
|
|
|
})
|
|
|
|
|
@body(z.string().describe('The new value for the metadata variable as JSON.') as any)
|
|
|
|
|
@responses(ActionRes)
|
|
|
|
|
public async updatePageMetadataVariableJson(ctx: Koa.ParameterizedContext): Promise<void> {
|
|
|
|
|
if (!this.checkDb(ctx)) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const page = await this.getPageInfo(ctx);
|
|
|
|
|
if (!page) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const varKey = ctx.params.varKey as string;
|
|
|
|
|
const newValue = ctx.request.body as string;
|
|
|
|
|
|
|
|
|
|
if (typeof page.metadata !== 'object') {
|
|
|
|
|
page.metadata = {};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
page.metadata[varKey] = JSON.parse(newValue);
|
|
|
|
|
|
|
|
|
|
await ctx.database!.getRepository(ConversationPage)
|
|
|
|
|
.save(page);
|
|
|
|
|
|
|
|
|
|
ctx.status = 200;
|
|
|
|
|
ctx.body = {
|
|
|
|
|
success: true,
|
|
|
|
|
message: `OK`,
|
|
|
|
|
} as ActionResType;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@routeConfig({
|
|
|
|
|
method: 'delete',
|
|
|
|
|
path: '/memory/v1/{conversationId}/page/{pageId}/metadata',
|
|
|
|
|
summary: 'Clear metadata of a specific page in a conversation',
|
|
|
|
|
operationId: 'deletePageMetadata',
|
|
|
|
|
request: {
|
|
|
|
|
params: z.object({
|
|
|
|
|
conversationId: z.string().describe('The conversation ID to clear the page metadata for.'),
|
|
|
|
|
pageId: pageIdSchema,
|
|
|
|
|
}),
|
|
|
|
|
},
|
|
|
|
|
responses: DefaultResponses,
|
|
|
|
|
})
|
|
|
|
|
@responses(ActionRes)
|
|
|
|
|
public async deletePageMetadata(ctx: Koa.ParameterizedContext): Promise<void> {
|
|
|
|
|
if (!this.checkDb(ctx)) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const page = await this.getPageInfo(ctx);
|
|
|
|
|
if (!page) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
page.metadata = {};
|
|
|
|
|
|
|
|
|
|
await ctx.database!.getRepository(ConversationPage)
|
|
|
|
|
.save(page);
|
|
|
|
|
|
|
|
|
|
ctx.status = 200;
|
|
|
|
|
ctx.body = {
|
|
|
|
|
success: true,
|
|
|
|
|
message: `OK`,
|
|
|
|
|
} as ActionResType;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@routeConfig({
|
|
|
|
|
method: 'delete',
|
|
|
|
|
path: '/memory/v1/{conversationId}/page/{pageId}/metadata/{varKey}',
|
|
|
|
|
summary: 'Delete a specific metadata variable from a page in a conversation',
|
|
|
|
|
operationId: 'deletePageMetadataVariable',
|
|
|
|
|
request: {
|
|
|
|
|
params: z.object({
|
|
|
|
|
conversationId: z.string().describe('The conversation ID to delete the page metadata variable from.'),
|
|
|
|
|
pageId: pageIdSchema,
|
|
|
|
|
varKey: z.string().describe('The key of the metadata variable to delete.'),
|
|
|
|
|
}),
|
|
|
|
|
},
|
|
|
|
|
responses: DefaultResponses,
|
|
|
|
|
})
|
|
|
|
|
@responses(ActionRes)
|
|
|
|
|
public async deletePageMetadataVariable(ctx: Koa.ParameterizedContext): Promise<void> {
|
|
|
|
|
if (!this.checkDb(ctx)) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const page = await this.getPageInfo(ctx);
|
|
|
|
|
if (!page) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const varKey = ctx.params.varKey as string;
|
|
|
|
|
|
|
|
|
|
if (typeof page.metadata !== 'object' || !page.metadata) {
|
|
|
|
|
page.metadata = {};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
delete page.metadata[varKey];
|
|
|
|
|
|
|
|
|
|
await ctx.database!.getRepository(ConversationPage)
|
|
|
|
|
.save(page);
|
|
|
|
|
|
|
|
|
|
ctx.status = 200;
|
|
|
|
|
ctx.body = {
|
|
|
|
|
success: true,
|
|
|
|
|
message: `OK`,
|
|
|
|
|
} as ActionResType;
|
|
|
|
|
}
|
|
|
|
|
}
|