@things-factory/board-ai 10.0.0 โ 10.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/client/components/board-ai-chat.ts +107 -2
- package/client/components/chat-echo-dedup.ts +3 -0
- package/client/components/chat-input-builder.ts +6 -0
- package/dist-client/client/components/board-ai-chat.d.ts +17 -0
- package/dist-client/client/components/board-ai-chat.js +102 -2
- package/dist-client/client/components/board-ai-chat.js.map +1 -1
- package/dist-client/client/components/chat-echo-dedup.d.ts +2 -0
- package/dist-client/client/components/chat-echo-dedup.js +1 -0
- package/dist-client/client/components/chat-echo-dedup.js.map +1 -1
- package/dist-client/client/components/chat-input-builder.d.ts +5 -0
- package/dist-client/client/components/chat-input-builder.js +1 -0
- package/dist-client/client/components/chat-input-builder.js.map +1 -1
- package/dist-client/server/service/agentic-loop.d.ts +18 -0
- package/dist-client/server/service/agentic-loop.js +10 -1
- package/dist-client/server/service/agentic-loop.js.map +1 -1
- package/dist-client/server/service/assistant.js +14 -2
- package/dist-client/server/service/assistant.js.map +1 -1
- package/dist-client/server/service/grounding.d.ts +17 -0
- package/dist-client/server/service/grounding.js +42 -0
- package/dist-client/server/service/grounding.js.map +1 -0
- package/dist-client/server/service/types.d.ts +16 -0
- package/dist-client/server/service/types.js.map +1 -1
- package/dist-client/tsconfig.tsbuildinfo +1 -1
- package/dist-server/service/agentic-loop.d.ts +18 -0
- package/dist-server/service/agentic-loop.js +10 -1
- package/dist-server/service/agentic-loop.js.map +1 -1
- package/dist-server/service/assistant.js +14 -2
- package/dist-server/service/assistant.js.map +1 -1
- package/dist-server/service/board-ai-resolver.d.ts +2 -0
- package/dist-server/service/board-ai-resolver.js +22 -1
- package/dist-server/service/board-ai-resolver.js.map +1 -1
- package/dist-server/service/chat-message/chat-message.d.ts +12 -0
- package/dist-server/service/chat-message/chat-message.js +23 -0
- package/dist-server/service/chat-message/chat-message.js.map +1 -1
- package/dist-server/service/chat-session/session-inbox.d.ts +26 -0
- package/dist-server/service/chat-session/session-inbox.js +41 -0
- package/dist-server/service/chat-session/session-inbox.js.map +1 -1
- package/dist-server/service/chat-session-participant/chat-session-participant.d.ts +11 -0
- package/dist-server/service/chat-session-participant/chat-session-participant.js +17 -1
- package/dist-server/service/chat-session-participant/chat-session-participant.js.map +1 -1
- package/dist-server/service/chat-session-resolver.d.ts +44 -1
- package/dist-server/service/chat-session-resolver.js +306 -6
- package/dist-server/service/chat-session-resolver.js.map +1 -1
- package/dist-server/service/grounding.d.ts +17 -0
- package/dist-server/service/grounding.js +46 -0
- package/dist-server/service/grounding.js.map +1 -0
- package/dist-server/service/types.d.ts +16 -0
- package/dist-server/service/types.js.map +1 -1
- package/dist-server/tsconfig.tsbuildinfo +1 -1
- package/package.json +5 -5
- package/server/service/agentic-loop.test.ts +63 -0
- package/server/service/agentic-loop.ts +28 -1
- package/server/service/assistant.ts +15 -2
- package/server/service/board-ai-resolver.ts +23 -1
- package/server/service/chat-message/chat-message.ts +26 -0
- package/server/service/chat-session/session-inbox.test.ts +69 -1
- package/server/service/chat-session/session-inbox.ts +45 -0
- package/server/service/chat-session-participant/chat-session-participant.ts +14 -0
- package/server/service/chat-session-resolver.ts +297 -5
- package/server/service/grounding.test.ts +55 -0
- package/server/service/grounding.ts +53 -0
- package/server/service/types.ts +16 -0
- package/translations/en.json +3 -1
- package/translations/ja.json +3 -1
- package/translations/ko.json +2 -0
- package/translations/ms.json +3 -1
- package/translations/zh.json +3 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chat-session-resolver.js","sourceRoot":"","sources":["../../server/service/chat-session-resolver.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * ChatSession lifecycle resolver โ start/get/recordDirectPatch/revertPatch + ๋ฉ์์งยทํจ์น ํ์ด์ง query.\n *\n * ํต์ฌ: `recordDirectPatch` โ ์ฌ์ฉ์๊ฐ ๋ชจ๋ธ๋ฌ์์ ์ง์ ํธ์ง ์ ํด๋ผ์ด์ธํธ๊ฐ ํธ์ถ.\n * ์ด๊ฒ PatchEntry(source:'user-direct') + system ๋ฉ์์ง ์๋ ์ถ๊ฐ โ AI ๊ฐ ๋ชจ๋ ๋ณ๊ฒฝ์ ์ธ์ง.\n */\nimport { Resolver, Query, Mutation, Arg, Ctx, Directive, Int, ObjectType, Field, ID } from 'type-graphql'\nimport { GraphQLJSON } from 'graphql-scalars'\nimport { User } from '@things-factory/auth-base'\nimport { buildDomainUsersQueryBuilder } from '@things-factory/auth-base/dist-server/utils/get-domain-users.js'\n\nimport { getRepository } from '@things-factory/shell'\nimport { In } from 'typeorm'\n\nimport { ChatSession } from './chat-session/chat-session.js'\nimport { anchorColumns, anchorWhere } from './chat-session/session-anchor.js'\nimport { buildInbox, activityPatch } from './chat-session/session-inbox.js'\nimport { publishSessionActivity } from './chat-session/session-activity-publish.js'\nimport { ChatMessage } from './chat-message/chat-message.js'\nimport { ChatSessionParticipant } from './chat-session-participant/chat-session-participant.js'\nimport { PatchEntry } from './patch-entry/patch-entry.js'\nimport { publishBoardPatch } from './patch-entry/board-patch-subscription.js'\nimport { publishChatMessage } from './chat-message/chat-message-publish.js'\n\n@ObjectType({\n description:\n 'Session list entry for the inbox โ a session plus this viewer\\'s unread state. Ordered by recent activity so a user can find where to go back to.'\n})\nclass ChatSessionInboxEntry {\n @Field(type => ID, { nullable: true, description: 'Session id.' })\n id?: string\n\n @Field({ nullable: true, description: 'User-given session name (tab label).' })\n name?: string\n\n @Field({ nullable: true, description: \"What the session is anchored to: 'board' | 'space' | 'instance' | 'none'.\" })\n anchorType?: string\n\n @Field({ nullable: true, description: 'Id of the anchored target.' })\n anchorId?: string\n\n @Field({ nullable: true, description: 'Connected board id (board-anchored sessions).' })\n boardId?: string\n\n @Field({ nullable: true, description: 'Timestamp of the last message (list ordering / unread comparison).' })\n lastMessageAt?: Date\n\n @Field({ nullable: true, description: 'Short preview of the last message.' })\n lastMessagePreview?: string\n\n @Field({ nullable: true, description: 'Session creation timestamp.' })\n createdAt?: Date\n\n @Field({ description: 'Whether this viewer has unread activity in the session.' })\n unread!: boolean\n\n @Field({ description: 'Whether this viewer is a participant of the session (non-participants get no unread state).' })\n participant!: boolean\n}\n\n@Resolver()\nexport class ChatSessionResolver {\n @Query(() => ChatSession, { nullable: true, description: 'Get AI chat session by id.' })\n @Directive('@privilege(category: \"board-ai\", privilege: \"query\")')\n async chatSession(\n @Arg('id') id: string,\n @Ctx() context: ResolverContext\n ): Promise<ChatSession | null> {\n const { domain } = context.state\n return (await getRepository(ChatSession).findOneBy({ id, domain: { id: domain.id } })) ?? null\n }\n\n @Query(() => ChatSession, { nullable: true, description: 'Get AI chat session by board id (returns first match โ backward compat single-session lookup).' })\n @Directive('@privilege(category: \"board-ai\", privilege: \"query\")')\n async chatSessionByBoard(\n @Arg('boardId') boardId: string,\n @Ctx() context: ResolverContext\n ): Promise<ChatSession | null> {\n const { domain } = context.state\n return (\n (await getRepository(ChatSession).findOneBy({ boardId, domain: { id: domain.id } })) ?? null\n )\n }\n\n @Query(() => [ChatSession], {\n description:\n 'List AI chat sessions anchored to a target (oldest first). Anchor decides the nature and the history boundary of the conversation: board = authoring, space = the site and the twins running there. Board anchor also matches legacy rows that only have boardId.'\n })\n @Directive('@privilege(category: \"board-ai\", privilege: \"query\")')\n async chatSessionsByAnchor(\n @Arg('anchorType') anchorType: string,\n @Arg('anchorId') anchorId: string,\n @Ctx() context: ResolverContext\n ): Promise<ChatSession[]> {\n const { domain } = context.state\n return await getRepository(ChatSession).find({\n where: anchorWhere(domain.id, anchorType, anchorId),\n order: { createdAt: 'ASC' }\n })\n }\n\n /** ๋ณด๋ ์ ์ฉ ์ง์
์ โ ์ต์ปค ์กฐํ์ ์์ ๋ํผ(๊ธฐ์กด ์๋น์ ๋ฌด๋ณ๊ฒฝ). */\n @Query(() => [ChatSession], {\n description: 'List all AI chat sessions for a board (oldest first). Thin wrapper over chatSessionsByAnchor(board).'\n })\n @Directive('@privilege(category: \"board-ai\", privilege: \"query\")')\n async chatSessionsByBoard(\n @Arg('boardId') boardId: string,\n @Ctx() context: ResolverContext\n ): Promise<ChatSession[]> {\n return await this.chatSessionsByAnchor('board', boardId, context)\n }\n\n /**\n * ๋ฐ์ํธ์งํจ โ ์ต์ปค์ ์ธ์
๋ชฉ๋ก + ๋ด ์ ์ฝ์ ์ํ. ์ต๊ทผ ํ๋์.\n * ์ง๊ณ ์ฟผ๋ฆฌ๋ฅผ ์ฐ์ง ์๋๋ค: ์ธ์
์ ๋น์ ๊ทํ๋ lastMessageAt ๊ณผ ๋ด ์ฐธ์ฌ์ lastReadAt ์ **๊ฐ ๋น๊ต**ํ๋ค\n * (5๊ฐ DB ๋๋ผ์ด๋ฒ ์ง์ ๋๋ฌธ์ group by/MAX ๋ฅผ ๋ชฉ๋ก ๊ฒฝ๋ก์ ๋์ง ์๋๋ค).\n */\n @Query(() => [ChatSessionInboxEntry], {\n description:\n \"List sessions anchored to a target with this viewer's unread state, ordered by recent activity. Uses the denormalized last-activity timestamp compared against the viewer's read point โ no per-session aggregation.\"\n })\n @Directive('@privilege(category: \"board-ai\", privilege: \"query\")')\n async chatSessionInbox(\n @Arg('anchorType') anchorType: string,\n @Arg('anchorId') anchorId: string,\n @Ctx() context: ResolverContext\n ): Promise<ChatSessionInboxEntry[]> {\n const { domain, user } = context.state\n const sessions = await getRepository(ChatSession).find({\n where: anchorWhere(domain.id, anchorType, anchorId)\n })\n if (sessions.length === 0) return []\n const mine = await getRepository(ChatSessionParticipant).find({\n where: { domain: { id: domain.id } as any, user: { id: user.id } as any, session: { id: In(sessions.map(s => s.id!)) } as any }\n })\n return buildInbox(sessions as any, mine as any) as any\n }\n\n /**\n * ์ธ์
์ด๋ฆ ๋ณ๊ฒฝ โ **์ฐธ์ฌ์ ๋๊ตฌ๋** ํ ์ ์๋ค.\n *\n * ์ ์์ ์ ์ ์ฉ์ด ์๋๊ฐ: ์ด๋ฆ์ ๋ํ์ ์ฃผ์ ํ์ด๊ณ ํ์๋ ์ฌ๋ฟ์ด ํ๋ค. ๋
ผ์๊ฐ ํ๋ฌ ์ฃผ์ ๊ฐ ๋ฌ๋ผ์ก๋๋ฐ\n * ๋ง๋ ์ฌ๋๋ง ๊ณ ์น ์ ์์ผ๋ฉด ๊ทธ ์ฌ๋์ด ์์ ๋ ๋ชฉ๋ก์ด ๊ณ์ ์ด๊ธ๋๋ค. ๋๋๋ฆด ์ ์๋ ๋ณ๊ฒฝ์ด๊ณ ๋ํ\n * ๋ด์ฉ์ ์ํฅ์ด ์์ผ๋ฏ๋ก ๊ถํ์ ์ขํ ์ด์ ๊ฐ ์๋ค(๋๋๋ฆด ์ ์๋ ๊ฒ๋ง ์ขํ๋ค).\n *\n * ๋ณ๊ฒฝ์ **meta ํ๋**์ผ๋ก ๋ฐฉ์กํ๋ค โ ๋ชจ๋ ์ฐธ์ฌ์ ๋ชฉ๋ก์ ์ฆ์ ๋ฐ์๋์ง๋ง ์ ์ฝ์ ๋ฐฐ์ง๋ ์ฌ๋ฆฌ์ง ์๋๋ค\n * (์ด๋ฆ ๋ณ๊ฒฝ์ \"์ ์์\" ์ผ๋ก ์๋ฆฌ๋ฉด ์์์ด๋ค).\n */\n @Mutation(() => Boolean, {\n description:\n 'Rename a chat session. Any participant may rename it โ the name is the topic label of a shared deliberation and the change is reversible. Broadcast as meta activity so every participant sees it without raising unread badges.'\n })\n @Directive('@privilege(category: \"board-ai\", privilege: \"mutation\")')\n async renameAISession(\n @Arg('sessionId') sessionId: string,\n @Arg('name') name: string,\n @Ctx() context: ResolverContext\n ): Promise<boolean> {\n const { domain, user } = context.state\n const trimmed = (name ?? '').trim().slice(0, 200)\n if (!trimmed) return false // ๋น ์ด๋ฆ์ผ๋ก ์ง์ฐ์ง ์๋๋ค โ ์ง์ฐ๋ ค๋ฉด ๋ณ๋ ์๋๊ฐ ํ์ํ๋ค\n const participant = await getRepository(ChatSessionParticipant).findOne({\n where: { domain: { id: domain.id } as any, session: { id: sessionId } as any, user: { id: user.id } as any }\n })\n if (!participant) return false // ์ฐธ์ฌ์๊ฐ ์๋๋ฉด ๋จ์ ๋ํ ์ ๋ชฉ์ ๋ฐ๊ฟ ์ ์๋ค\n const session = await getRepository(ChatSession).findOneBy({ id: sessionId, domain: { id: domain.id } as any })\n if (!session) return false\n await getRepository(ChatSession).update(sessionId, { name: trimmed, updater: user } as any)\n publishSessionActivity({\n domainId: domain.id,\n sessionId,\n kind: 'meta',\n anchorType: (session as any).anchorType,\n anchorId: (session as any).anchorId,\n actorId: user?.id\n })\n return true\n }\n\n /**\n * ์ฝ์ ์ง์ ๊ฐฑ์ โ ์ด ์ธ์
์ ์ฌ๊ธฐ๊น์ง ์ฝ์๋ค. ๋ฉฑ๋ฑ(์ฌ๋ฌ ๋ฒ ํธ์ถํด๋ ์ต์ ์๊ฐ์ผ๋ก๋ง ์ด๋).\n * ์ ์ ํ์(lastSeenAt)์ ๋ถ๋ฆฌํ๋ค โ ์ฐฝ์ ์ด์ด ๋๊ณ ํ๋ฉด์ ์ ๋ณผ ์ ์๋ค.\n */\n @Mutation(() => Boolean, {\n description:\n \"Mark a session as read up to now for the current user. Idempotent. Distinct from presence (lastSeenAt) โ a window can be open without being read.\"\n })\n @Directive('@privilege(category: \"board-ai\", privilege: \"mutation\")')\n async markSessionRead(\n @Arg('sessionId') sessionId: string,\n @Ctx() context: ResolverContext\n ): Promise<boolean> {\n const { domain, user } = context.state\n const repo = getRepository(ChatSessionParticipant)\n const mine = await repo.findOne({\n where: { domain: { id: domain.id } as any, session: { id: sessionId } as any, user: { id: user.id } as any }\n })\n /* ์ฐธ์ฌ์๊ฐ ์๋๋ฉด ์ฝ์ ์ํ๋ฅผ ๋ง๋ค์ง ์๋๋ค โ ์ฐธ์ฌํ์ง ์์ ๋ํ์ ๋ด ์ฝ์ ์ง์ ์ ๋จ๊ธฐ์ง ์๋๋ค. */\n if (!mine) return false\n await repo.update(mine.id!, { lastReadAt: new Date(), updater: user } as any)\n return true\n }\n\n @Query(() => [User], {\n description:\n 'List users in the current domain for `@` mention popup. board-ai ๊ถํ์ด๋ฉด ๋๊ตฌ๋ ๋ฉ์
์ฉ ๊ฒ์ ๊ฐ๋ฅ (๊ด๋ฆฌ์ ์ ์ฉ users() ์ ๋ณ๋).'\n })\n @Directive('@privilege(category: \"board-ai\", privilege: \"query\")')\n async domainUsersForMention(\n @Arg('query', { nullable: true, description: 'Substring to match against name/email (case-insensitive). Empty โ all.' }) query: string | undefined,\n @Arg('limit', () => Int, { nullable: true, defaultValue: 50 }) limit: number,\n @Ctx() context: ResolverContext\n ): Promise<User[]> {\n const { domain } = context.state\n const qb = buildDomainUsersQueryBuilder(domain.id, 'USER')\n if (query?.trim()) {\n const q = `%${query.trim().toLowerCase()}%`\n qb.andWhere('(LOWER(USER.name) LIKE :q OR LOWER(USER.email) LIKE :q)', { q })\n }\n qb.orderBy('USER.name', 'ASC').limit(limit)\n return await qb.getMany()\n }\n\n @Query(() => [ChatSessionParticipant], {\n description: 'List participants of a ChatSession (members / owner).'\n })\n @Directive('@privilege(category: \"board-ai\", privilege: \"query\")')\n async chatSessionParticipants(\n @Arg('sessionId') sessionId: string,\n @Ctx() context: ResolverContext\n ): Promise<ChatSessionParticipant[]> {\n const { domain } = context.state\n const session = await getRepository(ChatSession).findOneBy({\n id: sessionId,\n domain: { id: domain.id }\n })\n if (!session) return []\n return await getRepository(ChatSessionParticipant).find({\n where: { session: { id: sessionId } as any, domain: { id: domain.id } },\n order: { createdAt: 'ASC' }\n })\n }\n\n @Mutation(() => Boolean, {\n description: 'Presence heartbeat โ bump current user\\'s lastSeenAt in the session (online indicator).'\n })\n @Directive('@privilege(category: \"board-ai\", privilege: \"mutation\")')\n async touchPresence(@Arg('sessionId') sessionId: string, @Ctx() context: ResolverContext): Promise<boolean> {\n const { domain, user } = context.state\n const repo = getRepository(ChatSessionParticipant)\n const part = await repo.findOne({\n where: { session: { id: sessionId } as any, user: { id: user.id } as any, domain: { id: domain.id } as any }\n })\n if (!part) return false // ์ฐธ์ฌ์๊ฐ ์๋๋ฉด heartbeat ๋ฌด์ (์ด๋ ์ )\n await repo.update(part.id!, { lastSeenAt: new Date(), updater: user } as any)\n return true\n }\n\n @Query(() => [ChatMessage], { description: 'List chat messages of a session, oldest first.' })\n @Directive('@privilege(category: \"board-ai\", privilege: \"query\")')\n async chatMessages(\n @Arg('sessionId') sessionId: string,\n @Arg('limit', () => Int, { nullable: true, defaultValue: 100 }) limit: number,\n @Arg('offset', () => Int, { nullable: true, defaultValue: 0 }) offset: number,\n @Ctx() context: ResolverContext\n ): Promise<ChatMessage[]> {\n const { domain } = context.state\n const session = await getRepository(ChatSession).findOneBy({\n id: sessionId,\n domain: { id: domain.id }\n })\n if (!session) return []\n return await getRepository(ChatMessage).find({\n where: { session: { id: sessionId } as any },\n // creator: ๊ทธ๋ฃน์ฑ ๋ฐ์ ์ ํ์(name) + ์๊ธฐ ์ฌ๋ถ ํ์ (email). ๋ด๋ถ ๊ด๋ฆฌํค(id)์ ์์กดํ์ง ์๋๋ค.\n relations: { creator: true },\n order: { createdAt: 'ASC' },\n take: limit,\n skip: offset\n })\n }\n\n @Query(() => [PatchEntry], { description: 'List patch entries of a session, newest first.' })\n @Directive('@privilege(category: \"board-ai\", privilege: \"query\")')\n async chatPatches(\n @Arg('sessionId') sessionId: string,\n @Arg('limit', () => Int, { nullable: true, defaultValue: 100 }) limit: number,\n @Ctx() context: ResolverContext\n ): Promise<PatchEntry[]> {\n const { domain } = context.state\n const session = await getRepository(ChatSession).findOneBy({\n id: sessionId,\n domain: { id: domain.id }\n })\n if (!session) return []\n return await getRepository(PatchEntry).find({\n where: { session: { id: sessionId } as any },\n order: { createdAt: 'DESC' },\n take: limit\n })\n }\n\n @Directive('@transaction')\n @Mutation(() => ChatSession, {\n description:\n 'Start (or get existing) AI chat session anchored to a target. Idempotent โ returns first existing or creates one. Use anchorType board for board authoring, space for a site (its co-located twins).'\n })\n @Directive('@privilege(category: \"board-ai\", privilege: \"mutation\")')\n async startAISession(\n @Arg('anchorType') anchorType: string,\n @Arg('anchorId') anchorId: string,\n @Ctx() context: ResolverContext\n ): Promise<ChatSession> {\n const { domain, user, tx } = context.state\n const repo = getRepository(ChatSession, tx)\n\n const existing = await repo.findOneBy(anchorWhere(domain.id, anchorType, anchorId))\n if (existing) return existing\n\n const session = await repo.save({\n domain,\n ...anchorColumns(anchorType, anchorId),\n creator: user,\n updater: user\n } as any)\n // creator ๋ฅผ owner participant ๋ก ์๋ ๋ฑ๋ก โ ๋ค์๊ฐ ์ฑํ
๊ธฐ๋ฐ.\n await getRepository(ChatSessionParticipant, tx).save({\n domain,\n session: { id: session.id } as any,\n user,\n role: 'owner',\n creator: user,\n updater: user\n } as any)\n return session\n }\n\n /** ๋ณด๋ ์ ์ฉ ์ง์
์ โ ์ต์ปค ์์์ ์์ ๋ํผ(๊ธฐ์กด ์๋น์ ๋ฌด๋ณ๊ฒฝ). */\n @Mutation(() => ChatSession, {\n description: 'Start (or get existing) AI chat session for a board. Thin wrapper over startAISession(board).'\n })\n @Directive('@privilege(category: \"board-ai\", privilege: \"mutation\")')\n async startBoardAISession(\n @Arg('boardId') boardId: string,\n @Ctx() context: ResolverContext\n ): Promise<ChatSession> {\n return await this.startAISession('board', boardId, context)\n }\n\n @Directive('@transaction')\n @Mutation(() => ChatSession, {\n description:\n 'Always create a new AI chat session anchored to a target (no idempotent reuse). For multi-session UX โ ์ ํญ ์ด๊ธฐ.'\n })\n @Directive('@privilege(category: \"board-ai\", privilege: \"mutation\")')\n async createAISession(\n @Arg('anchorType') anchorType: string,\n @Arg('anchorId') anchorId: string,\n @Arg('name', { nullable: true, description: 'Optional name (defaults to auto-generated `์ธ์
N`).' }) name: string | undefined,\n @Ctx() context: ResolverContext\n ): Promise<ChatSession> {\n const { domain, user, tx } = context.state\n const repo = getRepository(ChatSession, tx)\n\n // ์ด๋ฆ ๋ฏธ์ง์ ์ ์๋ ์์ฑ โ **๊ฐ์ ์ต์ปค**์ ๊ธฐ์กด ์ธ์
์ + 1.\n let finalName = name?.trim()\n if (!finalName) {\n const count = await repo.count({ where: anchorWhere(domain.id, anchorType, anchorId) })\n finalName = `์ธ์
${count + 1}`\n }\n\n const session = await repo.save({\n domain,\n ...anchorColumns(anchorType, anchorId),\n creator: user,\n updater: user,\n name: finalName\n } as any)\n // creator ๋ฅผ owner participant ๋ก ์๋ ๋ฑ๋ก.\n await getRepository(ChatSessionParticipant, tx).save({\n domain,\n session: { id: session.id } as any,\n user,\n role: 'owner',\n creator: user,\n updater: user\n } as any)\n return session\n }\n\n @Directive('@transaction')\n @Mutation(() => Boolean, {\n description: 'Rename a ChatSession (tab label).'\n })\n @Directive('@privilege(category: \"board-ai\", privilege: \"mutation\")')\n async renameChatSession(\n @Arg('sessionId') sessionId: string,\n @Arg('name') name: string,\n @Ctx() context: ResolverContext\n ): Promise<boolean> {\n const { domain, user, tx } = context.state\n const repo = getRepository(ChatSession, tx)\n const session = await repo.findOneBy({ id: sessionId, domain: { id: domain.id } })\n if (!session) throw new Error(`ChatSession ${sessionId} not found`)\n await repo.update(sessionId, { name: name.trim() || null, updater: user } as any)\n return true\n }\n\n @Directive('@transaction')\n @Mutation(() => PatchEntry, {\n description: 'Record a patch from user direct edit. Adds a system message so AI sees the change next turn.'\n })\n @Directive('@privilege(category: \"board-ai\", privilege: \"mutation\")')\n async recordDirectPatch(\n @Arg('sessionId') sessionId: string,\n @Arg('ops', () => GraphQLJSON) ops: any[],\n @Arg('summary', { nullable: true }) summary: string | undefined,\n @Ctx() context: ResolverContext\n ): Promise<PatchEntry> {\n const { domain, tx, user } = context.state\n const session = await getRepository(ChatSession, tx).findOneBy({\n id: sessionId,\n domain: { id: domain.id }\n })\n if (!session) throw new Error(`ChatSession ${sessionId} not found`)\n\n const entry = await getRepository(PatchEntry, tx).save({\n session: { id: session.id } as any,\n source: 'user-direct',\n ops: JSON.stringify(ops || []),\n summary,\n reverted: false\n } as any)\n\n // AI ์ปจํ
์คํธ ํ๋ฆ โ system ๋ฉ์์ง ์๋ ์ถ๊ฐ. creator = ์ง์ ํธ์งํ ์ฌ์ฉ์.\n // parentMessage = ์ง์ in-session ๋ฉ์์ง (timeline ์ฐ์์ฑ ์ ์ง โ system ๋ chain ์ ํฉ๋ฅ).\n const previousLast = await getRepository(ChatMessage, tx).findOne({\n where: { session: { id: session.id } as any },\n order: { createdAt: 'DESC' }\n })\n const sysMsg = await getRepository(ChatMessage, tx).save({\n session: { id: session.id } as any,\n role: 'system',\n content: `User directly edited the board: ${summary ?? `${(ops || []).length} op(s)`}`,\n relatedPatchId: entry.id,\n creator: user,\n updater: user,\n parentMessage: previousLast ? ({ id: previousLast.id } as any) : undefined\n } as any)\n\n /* ์ธ์
ํ๋ ๊ฐฑ์ โ ์ง์ ํธ์ง๋ ๋ค๋ฅธ ์ฐธ์ฌ์์๊ฒ๋ ์ ์์์ด๋ค(๋ชฉ๋ก ์ ๋ ฌยท์ ์ฝ์ ํ์ ). */\n try {\n await getRepository(ChatSession, tx).update(session.id!, activityPatch(sysMsg.content) as any)\n } catch {\n /* best-effort โ ํธ์ง ๊ธฐ๋ก์ ๋ง์ง ์๋๋ค */\n }\n publishSessionActivity({\n domainId: domain.id,\n sessionId: session.id!,\n kind: 'message',\n anchorType: (session as any).anchorType,\n anchorId: (session as any).anchorId,\n preview: sysMsg.content,\n actorId: user?.id\n })\n\n // C1: user-direct ํธ์ง๋ ๊ฐ์ board ๊ตฌ๋
์์๊ฒ ๋ฐฉ์ก (AIยทํ์ฐธ์ฌ์ ์ค์๊ฐ ๋ฐ์). best-effort.\n publishBoardPatch({ domainId: domain.id, boardId: session.boardId, patch: entry })\n // C4: ์ง์ ํธ์ง system ๋ฉ์์ง๋ฅผ ๊ฐ์ ์ธ์
๊ตฌ๋
์์๊ฒ ๋ฐฉ์ก (transcript ์ค์๊ฐ ์ผ๊ด์ฑ). best-effort.\n publishChatMessage({ domainId: domain.id, sessionId: session.id, message: sysMsg })\n\n return entry\n }\n\n @Directive('@transaction')\n @Mutation(() => Boolean, { description: 'Mark a patch as reverted (does not undo, only flags).' })\n @Directive('@privilege(category: \"board-ai\", privilege: \"mutation\")')\n async revertPatch(\n @Arg('patchId') patchId: string,\n @Ctx() context: ResolverContext\n ): Promise<boolean> {\n const { tx } = context.state\n await getRepository(PatchEntry, tx).update(patchId, { reverted: true })\n return true\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"chat-session-resolver.js","sourceRoot":"","sources":["../../server/service/chat-session-resolver.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * ChatSession lifecycle resolver โ start/get/recordDirectPatch/revertPatch + ๋ฉ์์งยทํจ์น ํ์ด์ง query.\n *\n * ํต์ฌ: `recordDirectPatch` โ ์ฌ์ฉ์๊ฐ ๋ชจ๋ธ๋ฌ์์ ์ง์ ํธ์ง ์ ํด๋ผ์ด์ธํธ๊ฐ ํธ์ถ.\n * ์ด๊ฒ PatchEntry(source:'user-direct') + system ๋ฉ์์ง ์๋ ์ถ๊ฐ โ AI ๊ฐ ๋ชจ๋ ๋ณ๊ฒฝ์ ์ธ์ง.\n */\nimport { Resolver, Query, Mutation, Arg, Ctx, Directive, Int, ObjectType, Field, ID } from 'type-graphql'\nimport { GraphQLJSON } from 'graphql-scalars'\nimport { User } from '@things-factory/auth-base'\nimport { buildDomainUsersQueryBuilder } from '@things-factory/auth-base/dist-server/utils/get-domain-users.js'\n\nimport { getRepository } from '@things-factory/shell'\nimport { In } from 'typeorm'\n\nimport { ChatSession } from './chat-session/chat-session.js'\nimport { anchorColumns, anchorWhere } from './chat-session/session-anchor.js'\nimport { buildInbox, applyHidden, activityPatch, searchInbox, INBOX_SCAN_CAP } from './chat-session/session-inbox.js'\nimport { publishSessionActivity } from './chat-session/session-activity-publish.js'\nimport { ChatMessage } from './chat-message/chat-message.js'\nimport { ChatSessionParticipant } from './chat-session-participant/chat-session-participant.js'\nimport { PatchEntry } from './patch-entry/patch-entry.js'\nimport { publishBoardPatch } from './patch-entry/board-patch-subscription.js'\nimport { publishChatMessage } from './chat-message/chat-message-publish.js'\n\n@ObjectType({\n description:\n 'Session list entry for the inbox โ a session plus this viewer\\'s unread state. Ordered by recent activity so a user can find where to go back to.'\n})\nclass ChatSessionInboxEntry {\n @Field(type => ID, { nullable: true, description: 'Session id.' })\n id?: string\n\n @Field({ nullable: true, description: 'User-given session name (tab label).' })\n name?: string\n\n @Field({ nullable: true, description: \"What the session is anchored to: 'board' | 'space' | 'instance' | 'none'.\" })\n anchorType?: string\n\n @Field({ nullable: true, description: 'Id of the anchored target.' })\n anchorId?: string\n\n @Field({ nullable: true, description: 'Connected board id (board-anchored sessions).' })\n boardId?: string\n\n @Field({ nullable: true, description: 'Timestamp of the last message (list ordering / unread comparison).' })\n lastMessageAt?: Date\n\n @Field({ nullable: true, description: 'Short preview of the last message.' })\n lastMessagePreview?: string\n\n @Field({ nullable: true, description: 'Session creation timestamp.' })\n createdAt?: Date\n\n @Field({ description: 'Whether this viewer has unread activity in the session.' })\n unread!: boolean\n\n @Field({ description: 'Whether this viewer is a participant of the session (non-participants get no unread state).' })\n participant!: boolean\n\n /* ์ญ์ ๋ ๋๋๋ฆด ์ ์์ผ๋ฏ๋ก **๋ง๋ ์ฌ๋**๋ง ํ๋ค โ ํด๋ผ์ด์ธํธ๊ฐ ๋ฒํผ์ ๋ณด์ผ์ง ํ๋จํ๋ ๊ทผ๊ฑฐ.\n * (๊ถํ ํ์ ์ ์๋ฒ๊ฐ ๋ค์ ํ๋ค. ์ด ๊ฐ์ UI ํํธ์ผ ๋ฟ์ด๋ค.) */\n @Field({ description: 'Whether this viewer created the session โ only the creator may delete it.' })\n mine!: boolean\n\n /* ์จ๊น์ ๋์๊ฒ๋ง ์ ์ฉ๋๊ณ ๋๋๋ฆด ์ ์๋ค โ ํํฐ๋ฅผ ์ผ ์ฌ์ฉ์๊ฐ ๋ฌด์์ด ์จ๊ฒจ์ง ๊ฒ์ธ์ง ์์์ผ ํ๋ค. */\n @Field({ nullable: true, description: 'Whether this viewer hid the session from their own list (only returned when showHidden is on).' })\n hidden?: boolean\n}\n\n@Resolver()\nexport class ChatSessionResolver {\n @Query(() => ChatSession, { nullable: true, description: 'Get AI chat session by id.' })\n @Directive('@privilege(category: \"board-ai\", privilege: \"query\")')\n async chatSession(\n @Arg('id') id: string,\n @Ctx() context: ResolverContext\n ): Promise<ChatSession | null> {\n const { domain } = context.state\n return (await getRepository(ChatSession).findOneBy({ id, domain: { id: domain.id } })) ?? null\n }\n\n @Query(() => ChatSession, { nullable: true, description: 'Get AI chat session by board id (returns first match โ backward compat single-session lookup).' })\n @Directive('@privilege(category: \"board-ai\", privilege: \"query\")')\n async chatSessionByBoard(\n @Arg('boardId') boardId: string,\n @Ctx() context: ResolverContext\n ): Promise<ChatSession | null> {\n const { domain } = context.state\n return (\n (await getRepository(ChatSession).findOneBy({ boardId, domain: { id: domain.id } })) ?? null\n )\n }\n\n @Query(() => [ChatSession], {\n description:\n 'List AI chat sessions anchored to a target (oldest first). Anchor decides the nature and the history boundary of the conversation: board = authoring, space = the site and the twins running there. Board anchor also matches legacy rows that only have boardId.'\n })\n @Directive('@privilege(category: \"board-ai\", privilege: \"query\")')\n async chatSessionsByAnchor(\n @Arg('anchorType') anchorType: string,\n @Arg('anchorId') anchorId: string,\n @Ctx() context: ResolverContext\n ): Promise<ChatSession[]> {\n const { domain } = context.state\n return await getRepository(ChatSession).find({\n where: anchorWhere(domain.id, anchorType, anchorId),\n order: { createdAt: 'ASC' }\n })\n }\n\n /** ๋ณด๋ ์ ์ฉ ์ง์
์ โ ์ต์ปค ์กฐํ์ ์์ ๋ํผ(๊ธฐ์กด ์๋น์ ๋ฌด๋ณ๊ฒฝ). */\n @Query(() => [ChatSession], {\n description: 'List all AI chat sessions for a board (oldest first). Thin wrapper over chatSessionsByAnchor(board).'\n })\n @Directive('@privilege(category: \"board-ai\", privilege: \"query\")')\n async chatSessionsByBoard(\n @Arg('boardId') boardId: string,\n @Ctx() context: ResolverContext\n ): Promise<ChatSession[]> {\n return await this.chatSessionsByAnchor('board', boardId, context)\n }\n\n /**\n * ๋ฐ์ํธ์งํจ โ ์ต์ปค์ ์ธ์
๋ชฉ๋ก + ๋ด ์ ์ฝ์ ์ํ. ์ต๊ทผ ํ๋์.\n * ์ง๊ณ ์ฟผ๋ฆฌ๋ฅผ ์ฐ์ง ์๋๋ค: ์ธ์
์ ๋น์ ๊ทํ๋ lastMessageAt ๊ณผ ๋ด ์ฐธ์ฌ์ lastReadAt ์ **๊ฐ ๋น๊ต**ํ๋ค\n * (5๊ฐ DB ๋๋ผ์ด๋ฒ ์ง์ ๋๋ฌธ์ group by/MAX ๋ฅผ ๋ชฉ๋ก ๊ฒฝ๋ก์ ๋์ง ์๋๋ค).\n */\n @Query(() => [ChatSessionInboxEntry], {\n description:\n \"List sessions anchored to a target with this viewer's unread state, most recent activity first. Supports free-text search over name and last preview, a mine-only filter, hidden inclusion, and paging. Uses the denormalized last-activity timestamp compared against the viewer's read point โ no per-session aggregation.\"\n })\n @Directive('@privilege(category: \"board-ai\", privilege: \"query\")')\n async chatSessionInbox(\n @Arg('anchorType') anchorType: string,\n @Arg('anchorId') anchorId: string,\n @Ctx() context: ResolverContext,\n /* ์จ๊ธด ๋ํ ๋ณด๊ธฐ โ ์จ๊น์ด ํ ๋ฒ ๋ฃ์ผ๋ฉด ๋ชป ๊บผ๋ด๋ ํจ์ ์ด ๋์ง ์๋๋ก ํํฐ๋ฅผ ์ค๋ค. */\n @Arg('showHidden', { nullable: true }) showHidden?: boolean,\n /* ๋๋ ๋ชฉ๋ก ๋์ โ ๊ฒ์ยท์์ ํํฐยทํ์ด์ง. ๋ชฉ๋ก UI ๋ ์ฒ์๋ถํฐ ์ด๊ฑธ ๊ฐ๊ณ ์์ด์ผ ํ๋ค. */\n @Arg('search', { nullable: true }) search?: string,\n @Arg('mineOnly', { nullable: true }) mineOnly?: boolean,\n @Arg('limit', () => Int, { nullable: true }) limit?: number,\n @Arg('offset', () => Int, { nullable: true }) offset?: number\n ): Promise<ChatSessionInboxEntry[]> {\n const filtered = await this._inboxFiltered(anchorType, anchorId, context, { showHidden, search, mineOnly })\n const from = Math.max(0, offset ?? 0)\n const size = Math.min(Math.max(1, limit ?? 50), 200)\n return filtered.slice(from, from + size) as any\n }\n\n /**\n * ํํฐ๋ฅผ ํต๊ณผํ **์ ์ฒด ๊ฐ์** โ \"๋ ๋ณด๊ธฐ\" ๊ฐ ๋จ์๋์ง, ๊ฒ์ ๊ฒฐ๊ณผ๊ฐ ๋ช ๊ฑด์ธ์ง.\n *\n * ๋ชฉ๋ก๊ณผ ๊ฐ์ ์์ฒญ์ ๋ด์ ๊ฐ์ ธ๊ฐ๋ฏ๋ก ์๋ณต์ ๋์ง ์๋๋ค. ๊ฐ์๋ฅผ ๋ชจ๋ฅด๋ฉด ์ฌ์ฉ์๋ ๋ชฉ๋ก์ ๋์ด\n * ํ์ด์ง์ ๋์ธ์ง ์๋ฃ์ ๋์ธ์ง ๊ตฌ๋ณํ ์ ์๋ค.\n */\n @Query(() => Int, {\n description:\n 'Total number of sessions matching the same filters as chatSessionInbox (before paging). Request it alongside the list so the UI can tell \"end of page\" from \"end of data\".'\n })\n @Directive('@privilege(category: \"board-ai\", privilege: \"query\")')\n async chatSessionInboxTotal(\n @Arg('anchorType') anchorType: string,\n @Arg('anchorId') anchorId: string,\n @Ctx() context: ResolverContext,\n @Arg('showHidden', { nullable: true }) showHidden?: boolean,\n @Arg('search', { nullable: true }) search?: string,\n @Arg('mineOnly', { nullable: true }) mineOnly?: boolean\n ): Promise<number> {\n return (await this._inboxFiltered(anchorType, anchorId, context, { showHidden, search, mineOnly })).length\n }\n\n /** ํํฐ ์ ์ฉ(ํ์ด์ง ์ ) โ ๋ชฉ๋กยท๊ฐ์๊ฐ **๊ฐ์ ๊ท์น**์ ์ฐ๋๋ก ํ ๊ณณ์ ๋๋ค(์ด๊ธ๋๋ฉด \"๋ ๋ณด๊ธฐ\" ๊ฐ ๊ฑฐ์ง๋ง์ด ๋๋ค). */\n private async _inboxFiltered(\n anchorType: string,\n anchorId: string,\n context: ResolverContext,\n opts: { showHidden?: boolean; search?: string; mineOnly?: boolean }\n ): Promise<ChatSessionInboxEntry[]> {\n const all = await this._inboxEntries(anchorType, anchorId, context)\n let entries = opts.showHidden ? all : all.filter(e => !e.hidden)\n if (opts.mineOnly) entries = entries.filter(e => (e as any).mine)\n return searchInbox(entries as any, opts.search) as any\n }\n\n /**\n * ๋ด๊ฐ ์จ๊ธด ๋ํ ์ โ ํํฐ์ \"๋ช ๊ฐ๊ฐ ์ ํ ์๋์ง\" ๋ฅผ ๋ณด์ฌ์ฃผ๊ธฐ ์ํ ๊ฐ.\n *\n * ์จ๊ธด ๊ฒ์ด ๋ช ๊ฐ์ธ์ง ๋ชจ๋ฅด๋ฉด ํํฐ๋ฅผ ๋๋ฌ ๋ณผ ์ด์ ๊ฐ ์๊ธฐ์ง ์๋๋ค(์จ๊ธด ์ฌ์ค ์์ฒด๋ฅผ ์๋๋ค).\n * ๋ชฉ๋ก ์กฐํ์ **๊ฐ์ ์์ฒญ**์ ๋ด์ ๊ฐ์ ธ๊ฐ ์ ์์ผ๋ฏ๋ก ์๋ณต์ ๋์ง ์๋๋ค.\n */\n @Query(() => Int, {\n description:\n \"Number of sessions on this anchor that the caller has hidden and that have had no activity since. Meant to be requested alongside chatSessionInbox in the same operation so the filter can say how many are folded away.\"\n })\n @Directive('@privilege(category: \"board-ai\", privilege: \"query\")')\n async hiddenSessionCount(\n @Arg('anchorType') anchorType: string,\n @Arg('anchorId') anchorId: string,\n @Ctx() context: ResolverContext\n ): Promise<number> {\n const all = await this._inboxEntries(anchorType, anchorId, context)\n return all.filter(e => e.hidden).length\n }\n\n /** ๋ชฉ๋ก ์กฐ๋ฆฝ โ ์จ๊น ํ์๊น์ง ๋ถ์ธ **์ ์ฒด**. ๋ชฉ๋กยท๊ฐ์ ๋ ์ง์
์ ์ด ๊ฐ์ ๊ท์น์ ์ฐ๋๋ก ํ ๊ณณ์ ๋๋ค. */\n private async _inboxEntries(\n anchorType: string,\n anchorId: string,\n context: ResolverContext\n ): Promise<ChatSessionInboxEntry[]> {\n const { domain, user } = context.state\n /* ์กฐํ ์ํ โ ํ ์ต์ปค์ ๋ํ๊ฐ ์๋ฌด๋ฆฌ ๋์ด๋ ํ ๋ฒ์ ์ด๋งํผ๋ง ํ๋๋ค. ์ต๊ทผ ํ๋์์ผ๋ก ์๋ฅธ๋ค\n * (์ค๋๋ ๋ํ๊ฐ ์๋ฆฌ๋ ๊ฒ์ด ์ต๊ทผ ๋ํ๊ฐ ์๋ฆฌ๋ ๊ฒ๋ณด๋ค ๋ซ๋ค). ์ ๋ ฌยท๊ฒ์ยทํ์ด์ง๋ ์์ ๋ก์ง์ด ํ๋ค. */\n const sessions = await getRepository(ChatSession).find({\n where: anchorWhere(domain.id, anchorType, anchorId),\n order: { lastMessageAt: 'DESC' },\n take: INBOX_SCAN_CAP\n })\n if (sessions.length === 0) return []\n const rows = await getRepository(ChatSessionParticipant).find({\n where: { domain: { id: domain.id } as any, user: { id: user.id } as any, session: { id: In(sessions.map(s => s.id!)) } as any }\n })\n /* 'viewer' ๋ ๋ํ์ ๋ ์ฌ๋์ด ์๋๋ค โ ์จ๊น์ ๊ธฐ๋กํ๋ ค๊ณ ๋ง๋ ํ์ด๋ฏ๋ก ์ฝ์ยท์ ์ฝ์ ํ์ ์์ ๋บ๋ค.\n * (์ฐธ์ฌ์๊ฐ ์๋ ์ฌ๋์๊ฒ ๋จ์ ํ์ ๋ฐฐ์ง๋ฅผ ๋์ฐ์ง ์๋๋ค.) */\n const participations = rows.filter(r => r.role !== 'viewer')\n const hiddenAt = new Map(rows.map(r => [(r as any).sessionId as string, r.hiddenAt]))\n /* ๋ด๊ฐ ๋ง๋ ๋ํ์ธ์ง ํ์ โ ์ญ์ ๋ฒํผ์ ๋ณด์ผ์ง ๊ฒฐ์ ํ๋ UI ํํธ(๊ถํ์ ์๋ฒ๊ฐ ๋ค์ ํ์ ํ๋ค). */\n const createdByMe = new Set(sessions.filter(s => (s as any).creatorId === user?.id).map(s => s.id))\n const entries = buildInbox(sessions as any, participations as any).map(entry => ({\n ...entry,\n mine: createdByMe.has(entry.id)\n }))\n /* showHidden=true ๋ก ๋ถ๋ฌ **์ ์ฒด**๋ฅผ ์ป๋๋ค โ ์จ๊น ์ฌ๋ถ ํ์ ์ ๋ ๊ณณ์ ๋ณต์ ํ์ง ์๊ธฐ ์ํจ. */\n return applyHidden(entries as any, hiddenAt, true) as any\n }\n\n /**\n * ์ธ์
์ญ์ โ **๋ง๋ ์ฌ๋๋ง.**\n *\n * ํ์๋ ์ฌ๋ฟ์ ๊ธฐ๋ก์ด๊ณ ์ญ์ ๋ ํ๋ฉด์์ ๋๋๋ฆด ์ ์๋ค. ๊ทธ๋์ ๊ถํ์ ์ขํ๋ค(์ด๋ฆ ๋ณ๊ฒฝ์ ๋๋๋ฆด ์\n * ์์ด์ ๋๊ตฌ๋ ํ ์ ์๋ ๊ฒ๊ณผ ๋๋น). ๊ถํ์ด ์๋ ์ฌ๋์๊ฒ๋ `hideAISession`(๋ด ๋ชฉ๋ก์์๋ง ์จ๊น)์ด\n * ์๋ค โ ๋จ์ ๊ธฐ๋ก์ ์ง์ฐ์ง ์๊ณ ์๊ธฐ ๋ชฉ๋ก์ ์ ๋ฆฌํ๋ ๊ธธ.\n *\n * ์ํํธ ์ญ์ (deletedAt)๋ค โ ๋ฉ์์งยทํจ์น๋ ์ธ์
์ ํตํด์๋ง ๋๋ฌํ๋ฏ๋ก ํจ๊ป ์ฌ๋ผ์ง๊ณ , ์๋ชป ์ง์ด ๊ฒฝ์ฐ\n * ๋ฐ์ดํฐ๋ก๋ ๋จ์ ์๋ค. ๋ค๋ฅธ ์ฐธ์ฌ์ ๋ชฉ๋ก์์๋ ์ฌ๋ผ์ ธ์ผ ํ๋ฏ๋ก meta ํ๋์ผ๋ก ๋ฐฉ์กํ๋ค.\n */\n @Mutation(() => Boolean, {\n description:\n 'Delete a chat session โ creator only, since a shared deliberation cannot be un-deleted from the UI. Participants who are not the creator can hide it from their own list instead (hideAISession). Soft delete; broadcast as meta activity so every list drops it.'\n })\n @Directive('@privilege(category: \"board-ai\", privilege: \"mutation\")')\n async deleteAISession(@Arg('sessionId') sessionId: string, @Ctx() context: ResolverContext): Promise<boolean> {\n const { domain, user } = context.state\n const repo = getRepository(ChatSession)\n const session = await repo.findOneBy({ id: sessionId, domain: { id: domain.id } as any })\n if (!session) return false\n if (!user?.id || (session as any).creatorId !== user.id) {\n /* ์กฐ์ฉํ ๋ฌด๋์์ด ์๋๋ผ ๋ช
์ ์คํจ โ ์ง์์ง ์ค ์๊ณ ๋์ด๊ฐ๋ฉด ์ ๋๋ค. */\n throw new Error('Only the user who created this session may delete it. Hide it from your own list instead.')\n }\n await repo.softDelete(sessionId)\n publishSessionActivity({\n domainId: domain.id,\n sessionId,\n kind: 'meta',\n anchorType: (session as any).anchorType,\n anchorId: (session as any).anchorId,\n actorId: user?.id\n })\n return true\n }\n\n /**\n * ๋ด ๋ชฉ๋ก์์ ์จ๊ธฐ๊ธฐยท๋๋๋ฆฌ๊ธฐ โ **๋์๊ฒ๋ง** ์ ์ฉ๋๋ค(๋ํยท๋ค๋ฅธ ์ฐธ์ฌ์ ๋ชฉ๋ก์ ๊ทธ๋๋ก).\n *\n * ์ฐธ์ฌ์๊ฐ ์๋์ด๋ ์จ๊ธธ ์ ์์ด์ผ ํ๋ค โ ๋ชฉ๋ก์๋ ๊ฐ์ ๊ณต๊ฐ์ ๋จ์ ํ์๋ ๋ณด์ด๊ณ , ๊ทธ๊ฒ์ ์ ๋ฆฌํ๋\n * ๊ฒ์ ๋จ์๊ฒ ์๋ฌด ์ํฅ์ด ์๋ค. ๊ทธ ๊ฒฝ์ฐ 'viewer' ์ญํ ๋ก ๊ธฐ๋ก๋ง ๋จ๊ธด๋ค(์ฐธ์ฌ์ ๋ช
๋ถยท๋ฐฐ์ง์๋ ๋ค์ง ์๋๋ค).\n */\n @Mutation(() => Boolean, {\n description:\n 'Hide (or unhide) a session from the calling user\\'s own list. Per-user and reversible โ the session and other participants are unaffected. Activity newer than the hide makes it reappear; the inbox filter (showHidden) reveals hidden ones.'\n })\n @Directive('@privilege(category: \"board-ai\", privilege: \"mutation\")')\n async hideAISession(\n @Arg('sessionId') sessionId: string,\n @Ctx() context: ResolverContext,\n @Arg('hidden', { nullable: true }) hidden?: boolean\n ): Promise<boolean> {\n const { domain, user } = context.state\n if (!user?.id) return false\n const session = await getRepository(ChatSession).findOneBy({ id: sessionId, domain: { id: domain.id } as any })\n if (!session) return false\n const repo = getRepository(ChatSessionParticipant)\n const existing = await repo.findOne({\n where: { domain: { id: domain.id } as any, session: { id: sessionId } as any, user: { id: user.id } as any }\n })\n const hiddenAt = hidden === false ? null : new Date()\n if (existing) {\n await repo.update(existing.id!, { hiddenAt, updater: user } as any)\n } else {\n if (hidden === false) return true // ์จ๊ธด ์ ์ด ์์ผ๋ฉด ๋๋๋ฆด ๊ฒ๋ ์๋ค\n await repo.save({\n domain: { id: domain.id } as any,\n session: { id: sessionId } as any,\n user: { id: user.id } as any,\n role: 'viewer', // ๋ํ์ ๋ ๊ฒ์ด ์๋๋ผ ์จ๊น๋ง ๊ธฐ๋กํ๋ค\n hiddenAt,\n creator: user,\n updater: user\n } as any)\n }\n return true\n }\n\n /**\n * ์ธ์
์ด๋ฆ ๋ณ๊ฒฝ โ **์ฐธ์ฌ์ ๋๊ตฌ๋** ํ ์ ์๋ค.\n *\n * ์ ์์ ์ ์ ์ฉ์ด ์๋๊ฐ: ์ด๋ฆ์ ๋ํ์ ์ฃผ์ ํ์ด๊ณ ํ์๋ ์ฌ๋ฟ์ด ํ๋ค. ๋
ผ์๊ฐ ํ๋ฌ ์ฃผ์ ๊ฐ ๋ฌ๋ผ์ก๋๋ฐ\n * ๋ง๋ ์ฌ๋๋ง ๊ณ ์น ์ ์์ผ๋ฉด ๊ทธ ์ฌ๋์ด ์์ ๋ ๋ชฉ๋ก์ด ๊ณ์ ์ด๊ธ๋๋ค. ๋๋๋ฆด ์ ์๋ ๋ณ๊ฒฝ์ด๊ณ ๋ํ\n * ๋ด์ฉ์ ์ํฅ์ด ์์ผ๋ฏ๋ก ๊ถํ์ ์ขํ ์ด์ ๊ฐ ์๋ค(๋๋๋ฆด ์ ์๋ ๊ฒ๋ง ์ขํ๋ค).\n *\n * ๋ณ๊ฒฝ์ **meta ํ๋**์ผ๋ก ๋ฐฉ์กํ๋ค โ ๋ชจ๋ ์ฐธ์ฌ์ ๋ชฉ๋ก์ ์ฆ์ ๋ฐ์๋์ง๋ง ์ ์ฝ์ ๋ฐฐ์ง๋ ์ฌ๋ฆฌ์ง ์๋๋ค\n * (์ด๋ฆ ๋ณ๊ฒฝ์ \"์ ์์\" ์ผ๋ก ์๋ฆฌ๋ฉด ์์์ด๋ค).\n */\n @Mutation(() => Boolean, {\n description:\n 'Rename a chat session. Any participant may rename it โ the name is the topic label of a shared deliberation and the change is reversible. Broadcast as meta activity so every participant sees it without raising unread badges.'\n })\n @Directive('@privilege(category: \"board-ai\", privilege: \"mutation\")')\n async renameAISession(\n @Arg('sessionId') sessionId: string,\n @Arg('name') name: string,\n @Ctx() context: ResolverContext\n ): Promise<boolean> {\n const { domain, user } = context.state\n const trimmed = (name ?? '').trim().slice(0, 200)\n if (!trimmed) return false // ๋น ์ด๋ฆ์ผ๋ก ์ง์ฐ์ง ์๋๋ค โ ์ง์ฐ๋ ค๋ฉด ๋ณ๋ ์๋๊ฐ ํ์ํ๋ค\n const participant = await getRepository(ChatSessionParticipant).findOne({\n where: { domain: { id: domain.id } as any, session: { id: sessionId } as any, user: { id: user.id } as any }\n })\n if (!participant) return false // ์ฐธ์ฌ์๊ฐ ์๋๋ฉด ๋จ์ ๋ํ ์ ๋ชฉ์ ๋ฐ๊ฟ ์ ์๋ค\n const session = await getRepository(ChatSession).findOneBy({ id: sessionId, domain: { id: domain.id } as any })\n if (!session) return false\n await getRepository(ChatSession).update(sessionId, { name: trimmed, updater: user } as any)\n publishSessionActivity({\n domainId: domain.id,\n sessionId,\n kind: 'meta',\n anchorType: (session as any).anchorType,\n anchorId: (session as any).anchorId,\n actorId: user?.id\n })\n return true\n }\n\n /**\n * ์ฝ์ ์ง์ ๊ฐฑ์ โ ์ด ์ธ์
์ ์ฌ๊ธฐ๊น์ง ์ฝ์๋ค. ๋ฉฑ๋ฑ(์ฌ๋ฌ ๋ฒ ํธ์ถํด๋ ์ต์ ์๊ฐ์ผ๋ก๋ง ์ด๋).\n * ์ ์ ํ์(lastSeenAt)์ ๋ถ๋ฆฌํ๋ค โ ์ฐฝ์ ์ด์ด ๋๊ณ ํ๋ฉด์ ์ ๋ณผ ์ ์๋ค.\n */\n @Mutation(() => Boolean, {\n description:\n \"Mark a session as read up to now for the current user. Idempotent. Distinct from presence (lastSeenAt) โ a window can be open without being read.\"\n })\n @Directive('@privilege(category: \"board-ai\", privilege: \"mutation\")')\n async markSessionRead(\n @Arg('sessionId') sessionId: string,\n @Ctx() context: ResolverContext\n ): Promise<boolean> {\n const { domain, user } = context.state\n const repo = getRepository(ChatSessionParticipant)\n const mine = await repo.findOne({\n where: { domain: { id: domain.id } as any, session: { id: sessionId } as any, user: { id: user.id } as any }\n })\n /* ์ฐธ์ฌ์๊ฐ ์๋๋ฉด ์ฝ์ ์ํ๋ฅผ ๋ง๋ค์ง ์๋๋ค โ ์ฐธ์ฌํ์ง ์์ ๋ํ์ ๋ด ์ฝ์ ์ง์ ์ ๋จ๊ธฐ์ง ์๋๋ค. */\n if (!mine) return false\n await repo.update(mine.id!, { lastReadAt: new Date(), updater: user } as any)\n return true\n }\n\n @Query(() => [User], {\n description:\n 'List users in the current domain for `@` mention popup. board-ai ๊ถํ์ด๋ฉด ๋๊ตฌ๋ ๋ฉ์
์ฉ ๊ฒ์ ๊ฐ๋ฅ (๊ด๋ฆฌ์ ์ ์ฉ users() ์ ๋ณ๋).'\n })\n @Directive('@privilege(category: \"board-ai\", privilege: \"query\")')\n async domainUsersForMention(\n @Arg('query', { nullable: true, description: 'Substring to match against name/email (case-insensitive). Empty โ all.' }) query: string | undefined,\n @Arg('limit', () => Int, { nullable: true, defaultValue: 50 }) limit: number,\n @Ctx() context: ResolverContext\n ): Promise<User[]> {\n const { domain } = context.state\n const qb = buildDomainUsersQueryBuilder(domain.id, 'USER')\n if (query?.trim()) {\n const q = `%${query.trim().toLowerCase()}%`\n qb.andWhere('(LOWER(USER.name) LIKE :q OR LOWER(USER.email) LIKE :q)', { q })\n }\n qb.orderBy('USER.name', 'ASC').limit(limit)\n return await qb.getMany()\n }\n\n @Query(() => [ChatSessionParticipant], {\n description: 'List participants of a ChatSession (members / owner).'\n })\n @Directive('@privilege(category: \"board-ai\", privilege: \"query\")')\n async chatSessionParticipants(\n @Arg('sessionId') sessionId: string,\n @Ctx() context: ResolverContext\n ): Promise<ChatSessionParticipant[]> {\n const { domain } = context.state\n const session = await getRepository(ChatSession).findOneBy({\n id: sessionId,\n domain: { id: domain.id }\n })\n if (!session) return []\n return await getRepository(ChatSessionParticipant).find({\n where: { session: { id: sessionId } as any, domain: { id: domain.id } },\n order: { createdAt: 'ASC' }\n })\n }\n\n @Mutation(() => Boolean, {\n description: 'Presence heartbeat โ bump current user\\'s lastSeenAt in the session (online indicator).'\n })\n @Directive('@privilege(category: \"board-ai\", privilege: \"mutation\")')\n async touchPresence(@Arg('sessionId') sessionId: string, @Ctx() context: ResolverContext): Promise<boolean> {\n const { domain, user } = context.state\n const repo = getRepository(ChatSessionParticipant)\n const part = await repo.findOne({\n where: { session: { id: sessionId } as any, user: { id: user.id } as any, domain: { id: domain.id } as any }\n })\n if (!part) return false // ์ฐธ์ฌ์๊ฐ ์๋๋ฉด heartbeat ๋ฌด์ (์ด๋ ์ )\n await repo.update(part.id!, { lastSeenAt: new Date(), updater: user } as any)\n return true\n }\n\n @Query(() => [ChatMessage], { description: 'List chat messages of a session, oldest first.' })\n @Directive('@privilege(category: \"board-ai\", privilege: \"query\")')\n async chatMessages(\n @Arg('sessionId') sessionId: string,\n @Arg('limit', () => Int, { nullable: true, defaultValue: 100 }) limit: number,\n @Arg('offset', () => Int, { nullable: true, defaultValue: 0 }) offset: number,\n @Ctx() context: ResolverContext\n ): Promise<ChatMessage[]> {\n const { domain } = context.state\n const session = await getRepository(ChatSession).findOneBy({\n id: sessionId,\n domain: { id: domain.id }\n })\n if (!session) return []\n return await getRepository(ChatMessage).find({\n where: { session: { id: sessionId } as any },\n // creator: ๊ทธ๋ฃน์ฑ ๋ฐ์ ์ ํ์(name) + ์๊ธฐ ์ฌ๋ถ ํ์ (email). ๋ด๋ถ ๊ด๋ฆฌํค(id)์ ์์กดํ์ง ์๋๋ค.\n relations: { creator: true },\n order: { createdAt: 'ASC' },\n take: limit,\n skip: offset\n })\n }\n\n @Query(() => [PatchEntry], { description: 'List patch entries of a session, newest first.' })\n @Directive('@privilege(category: \"board-ai\", privilege: \"query\")')\n async chatPatches(\n @Arg('sessionId') sessionId: string,\n @Arg('limit', () => Int, { nullable: true, defaultValue: 100 }) limit: number,\n @Ctx() context: ResolverContext\n ): Promise<PatchEntry[]> {\n const { domain } = context.state\n const session = await getRepository(ChatSession).findOneBy({\n id: sessionId,\n domain: { id: domain.id }\n })\n if (!session) return []\n return await getRepository(PatchEntry).find({\n where: { session: { id: sessionId } as any },\n order: { createdAt: 'DESC' },\n take: limit\n })\n }\n\n @Directive('@transaction')\n @Mutation(() => ChatSession, {\n description:\n 'Start (or get existing) AI chat session anchored to a target. Idempotent โ returns first existing or creates one. Use anchorType board for board authoring, space for a site (its co-located twins).'\n })\n @Directive('@privilege(category: \"board-ai\", privilege: \"mutation\")')\n async startAISession(\n @Arg('anchorType') anchorType: string,\n @Arg('anchorId') anchorId: string,\n @Ctx() context: ResolverContext\n ): Promise<ChatSession> {\n const { domain, user, tx } = context.state\n const repo = getRepository(ChatSession, tx)\n\n const existing = await repo.findOneBy(anchorWhere(domain.id, anchorType, anchorId))\n if (existing) return existing\n\n const session = await repo.save({\n domain,\n ...anchorColumns(anchorType, anchorId),\n creator: user,\n updater: user\n } as any)\n // creator ๋ฅผ owner participant ๋ก ์๋ ๋ฑ๋ก โ ๋ค์๊ฐ ์ฑํ
๊ธฐ๋ฐ.\n await getRepository(ChatSessionParticipant, tx).save({\n domain,\n session: { id: session.id } as any,\n user,\n role: 'owner',\n creator: user,\n updater: user\n } as any)\n return session\n }\n\n /** ๋ณด๋ ์ ์ฉ ์ง์
์ โ ์ต์ปค ์์์ ์์ ๋ํผ(๊ธฐ์กด ์๋น์ ๋ฌด๋ณ๊ฒฝ). */\n @Mutation(() => ChatSession, {\n description: 'Start (or get existing) AI chat session for a board. Thin wrapper over startAISession(board).'\n })\n @Directive('@privilege(category: \"board-ai\", privilege: \"mutation\")')\n async startBoardAISession(\n @Arg('boardId') boardId: string,\n @Ctx() context: ResolverContext\n ): Promise<ChatSession> {\n return await this.startAISession('board', boardId, context)\n }\n\n @Directive('@transaction')\n @Mutation(() => ChatSession, {\n description:\n 'Always create a new AI chat session anchored to a target (no idempotent reuse). For multi-session UX โ ์ ํญ ์ด๊ธฐ.'\n })\n @Directive('@privilege(category: \"board-ai\", privilege: \"mutation\")')\n async createAISession(\n @Arg('anchorType') anchorType: string,\n @Arg('anchorId') anchorId: string,\n @Arg('name', { nullable: true, description: 'Optional name (defaults to auto-generated `์ธ์
N`).' }) name: string | undefined,\n @Ctx() context: ResolverContext\n ): Promise<ChatSession> {\n const { domain, user, tx } = context.state\n const repo = getRepository(ChatSession, tx)\n\n // ์ด๋ฆ ๋ฏธ์ง์ ์ ์๋ ์์ฑ โ **๊ฐ์ ์ต์ปค**์ ๊ธฐ์กด ์ธ์
์ + 1.\n let finalName = name?.trim()\n if (!finalName) {\n const count = await repo.count({ where: anchorWhere(domain.id, anchorType, anchorId) })\n finalName = `์ธ์
${count + 1}`\n }\n\n const session = await repo.save({\n domain,\n ...anchorColumns(anchorType, anchorId),\n creator: user,\n updater: user,\n name: finalName\n } as any)\n // creator ๋ฅผ owner participant ๋ก ์๋ ๋ฑ๋ก.\n await getRepository(ChatSessionParticipant, tx).save({\n domain,\n session: { id: session.id } as any,\n user,\n role: 'owner',\n creator: user,\n updater: user\n } as any)\n return session\n }\n\n @Directive('@transaction')\n @Mutation(() => Boolean, {\n description: 'Rename a ChatSession (tab label).'\n })\n @Directive('@privilege(category: \"board-ai\", privilege: \"mutation\")')\n async renameChatSession(\n @Arg('sessionId') sessionId: string,\n @Arg('name') name: string,\n @Ctx() context: ResolverContext\n ): Promise<boolean> {\n const { domain, user, tx } = context.state\n const repo = getRepository(ChatSession, tx)\n const session = await repo.findOneBy({ id: sessionId, domain: { id: domain.id } })\n if (!session) throw new Error(`ChatSession ${sessionId} not found`)\n await repo.update(sessionId, { name: name.trim() || null, updater: user } as any)\n return true\n }\n\n @Directive('@transaction')\n @Mutation(() => Boolean, {\n description:\n 'Append a system note to a session โ context that did not come from a participant typing (e.g. a conversation carried over from another surface, an external state change). The AI sees it as part of the shared history.'\n })\n @Directive('@privilege(category: \"board-ai\", privilege: \"mutation\")')\n async appendSessionNote(\n @Arg('sessionId') sessionId: string,\n @Arg('content') content: string,\n @Ctx() context: ResolverContext\n ): Promise<boolean> {\n const { domain, user, tx } = context.state\n const session = await getRepository(ChatSession, tx).findOneBy({ id: sessionId, domain: { id: domain.id } })\n if (!session) throw new Error(`ChatSession ${sessionId} not found`)\n /* ํ๋กฌํํธ๊ฐ ํ ๊ธฐ๋ก์ผ๋ก ํญ์ฆํ์ง ์๋๋ก ์๋ฅธ๋ค โ ๋งฅ๋ฝ ์ ๋ฌ์ด ๋ชฉ์ ์ด๊ณ ์ ๋ฌธ ๋ณด์กด์ด ์๋๋ค. */\n const body = (content ?? '').trim().slice(0, 4000)\n if (!body) return false\n\n const previousLast = await getRepository(ChatMessage, tx).findOne({\n where: { session: { id: session.id } as any },\n order: { createdAt: 'DESC' }\n })\n const sysMsg = await getRepository(ChatMessage, tx).save({\n session: { id: session.id } as any,\n role: 'system',\n content: body,\n creator: user,\n updater: user,\n parentMessage: previousLast ? ({ id: previousLast.id } as any) : undefined\n } as any)\n\n /* ํ๋ ๊ฐฑ์ + ๋ฐฉ์ก โ ๋ค๋ฅธ ์ฐธ์ฌ์ ๋ชฉ๋กยท์ ์ฝ์๊ณผ ์ด๋ ค ์๋ ํ๋ฉด์ transcript ์ผ๊ด์ฑ. best-effort. */\n try {\n await getRepository(ChatSession, tx).update(session.id!, activityPatch(body) as any)\n } catch {\n /* ๊ธฐ๋ก ์์ฒด๋ฅผ ๋ง์ง ์๋๋ค */\n }\n publishSessionActivity({\n domainId: domain.id,\n sessionId: session.id!,\n kind: 'message',\n anchorType: (session as any).anchorType,\n anchorId: (session as any).anchorId,\n preview: body,\n actorId: user?.id\n })\n publishChatMessage({ domainId: domain.id, sessionId: session.id, message: sysMsg })\n return true\n }\n\n @Directive('@transaction')\n @Mutation(() => Boolean, {\n description:\n 'Carry a conversation from another surface into this session as its own turns (user / assistant), preserving order. Use when a lightweight exchange is promoted into a persistent discussion โ the participants should read it as the conversation continuing, not as a machine dump.'\n })\n @Directive('@privilege(category: \"board-ai\", privilege: \"mutation\")')\n async appendSessionTurns(\n @Arg('sessionId') sessionId: string,\n @Arg('turns', () => GraphQLJSON) turns: { role?: string; content?: string }[],\n @Ctx() context: ResolverContext\n ): Promise<boolean> {\n const { domain, user, tx } = context.state\n const session = await getRepository(ChatSession, tx).findOneBy({ id: sessionId, domain: { id: domain.id } })\n if (!session) throw new Error(`ChatSession ${sessionId} not found`)\n\n /* ์ฎ๊ฒจ์จ ๋ํ๋ **๊ทธ ๋ํ์ ๋ฐ์ธ ๊ทธ๋๋ก** ๋ค์ด๊ฐ๋ค โ ํ ๋ฉ์ด๋ฆฌ ๊ธฐ๋ก์ผ๋ก ๋ญ์น๋ฉด ์ฌ๋์ด ์ฝ์ ์ ์๊ณ \n * (ํ๋ฉด ํ๋๋ฅผ ์ก์๋จน๋ ์ดํค๋ฆญ ๋ฉ์ด๋ฆฌ), ๋งํฌ๋ค์ด๋ ์ฃฝ๋๋ค. ๋์ ๊ฐ์ยท๊ธธ์ด๋ ์ ํํ๋ค: ๋งฅ๋ฝ ์ ๋ฌ์ด\n * ๋ชฉ์ ์ด๊ณ ์ ๋ฌธ ๋ณด์กด์ด ์๋๋ค. */\n const rows = (Array.isArray(turns) ? turns : [])\n .map(t => ({\n role: t?.role === 'ai' || t?.role === 'assistant' ? 'assistant' : t?.role === 'user' ? 'user' : 'system',\n content: (t?.content ?? '').trim().slice(0, 4000)\n }))\n .filter(t => t.content)\n .slice(-40)\n if (!rows.length) return false\n\n let previous = await getRepository(ChatMessage, tx).findOne({\n where: { session: { id: session.id } as any },\n order: { createdAt: 'DESC' }\n })\n const saved: ChatMessage[] = []\n for (const row of rows) {\n previous = await getRepository(ChatMessage, tx).save({\n session: { id: session.id } as any,\n role: row.role,\n content: row.content,\n creator: user,\n updater: user,\n parentMessage: previous ? ({ id: previous.id } as any) : undefined\n } as any)\n saved.push(previous!)\n }\n\n /* ํ๋์ ๋ง์ง๋ง ๋ฐ์ธ ๊ธฐ์ค ํ ๋ฒ๋ง โ ์ฎ๊ธด ์ค๋ง๋ค ๋ชฉ๋ก์ ํ๋ค ์ด์ ๊ฐ ์๋ค. */\n const last = rows[rows.length - 1]\n try {\n await getRepository(ChatSession, tx).update(session.id!, activityPatch(last.content) as any)\n } catch {\n /* best-effort โ ์ฎ๊ธฐ๊ธฐ ์์ฒด๋ฅผ ๋ง์ง ์๋๋ค */\n }\n publishSessionActivity({\n domainId: domain.id,\n sessionId: session.id!,\n kind: 'message',\n anchorType: (session as any).anchorType,\n anchorId: (session as any).anchorId,\n preview: last.content,\n actorId: user?.id\n })\n for (const message of saved) {\n publishChatMessage({ domainId: domain.id, sessionId: session.id, message })\n }\n return true\n }\n\n @Directive('@transaction')\n @Mutation(() => PatchEntry, {\n description: 'Record a patch from user direct edit. Adds a system message so AI sees the change next turn.'\n })\n @Directive('@privilege(category: \"board-ai\", privilege: \"mutation\")')\n async recordDirectPatch(\n @Arg('sessionId') sessionId: string,\n @Arg('ops', () => GraphQLJSON) ops: any[],\n @Arg('summary', { nullable: true }) summary: string | undefined,\n @Ctx() context: ResolverContext\n ): Promise<PatchEntry> {\n const { domain, tx, user } = context.state\n const session = await getRepository(ChatSession, tx).findOneBy({\n id: sessionId,\n domain: { id: domain.id }\n })\n if (!session) throw new Error(`ChatSession ${sessionId} not found`)\n\n const entry = await getRepository(PatchEntry, tx).save({\n session: { id: session.id } as any,\n source: 'user-direct',\n ops: JSON.stringify(ops || []),\n summary,\n reverted: false\n } as any)\n\n // AI ์ปจํ
์คํธ ํ๋ฆ โ system ๋ฉ์์ง ์๋ ์ถ๊ฐ. creator = ์ง์ ํธ์งํ ์ฌ์ฉ์.\n // parentMessage = ์ง์ in-session ๋ฉ์์ง (timeline ์ฐ์์ฑ ์ ์ง โ system ๋ chain ์ ํฉ๋ฅ).\n const previousLast = await getRepository(ChatMessage, tx).findOne({\n where: { session: { id: session.id } as any },\n order: { createdAt: 'DESC' }\n })\n const sysMsg = await getRepository(ChatMessage, tx).save({\n session: { id: session.id } as any,\n role: 'system',\n content: `User directly edited the board: ${summary ?? `${(ops || []).length} op(s)`}`,\n relatedPatchId: entry.id,\n creator: user,\n updater: user,\n parentMessage: previousLast ? ({ id: previousLast.id } as any) : undefined\n } as any)\n\n /* ์ธ์
ํ๋ ๊ฐฑ์ โ ์ง์ ํธ์ง๋ ๋ค๋ฅธ ์ฐธ์ฌ์์๊ฒ๋ ์ ์์์ด๋ค(๋ชฉ๋ก ์ ๋ ฌยท์ ์ฝ์ ํ์ ). */\n try {\n await getRepository(ChatSession, tx).update(session.id!, activityPatch(sysMsg.content) as any)\n } catch {\n /* best-effort โ ํธ์ง ๊ธฐ๋ก์ ๋ง์ง ์๋๋ค */\n }\n publishSessionActivity({\n domainId: domain.id,\n sessionId: session.id!,\n kind: 'message',\n anchorType: (session as any).anchorType,\n anchorId: (session as any).anchorId,\n preview: sysMsg.content,\n actorId: user?.id\n })\n\n // C1: user-direct ํธ์ง๋ ๊ฐ์ board ๊ตฌ๋
์์๊ฒ ๋ฐฉ์ก (AIยทํ์ฐธ์ฌ์ ์ค์๊ฐ ๋ฐ์). best-effort.\n publishBoardPatch({ domainId: domain.id, boardId: session.boardId, patch: entry })\n // C4: ์ง์ ํธ์ง system ๋ฉ์์ง๋ฅผ ๊ฐ์ ์ธ์
๊ตฌ๋
์์๊ฒ ๋ฐฉ์ก (transcript ์ค์๊ฐ ์ผ๊ด์ฑ). best-effort.\n publishChatMessage({ domainId: domain.id, sessionId: session.id, message: sysMsg })\n\n return entry\n }\n\n @Directive('@transaction')\n @Mutation(() => Boolean, { description: 'Mark a patch as reverted (does not undo, only flags).' })\n @Directive('@privilege(category: \"board-ai\", privilege: \"mutation\")')\n async revertPatch(\n @Arg('patchId') patchId: string,\n @Ctx() context: ResolverContext\n ): Promise<boolean> {\n const { tx } = context.state\n await getRepository(PatchEntry, tx).update(patchId, { reverted: true })\n return true\n }\n}\n"]}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export interface GroundingSources {
|
|
2
|
+
/** ์์คํ
ํ๋กฌํํธ(ํ์
๋ชฉ๋กยท๊ท์น). */
|
|
3
|
+
systemPrompt?: string;
|
|
4
|
+
/** ๋ณด๋ ์ํ ์์ฝ ๋ฑ ๋ํ ์์ ๋ถ์ธ ๋ฌธ๋งฅ. */
|
|
5
|
+
boardContext?: string;
|
|
6
|
+
/** ์ฌ์ฉ์ยท์ด์์คํดํธ ์ด๋ ฅ ํ
์คํธ. */
|
|
7
|
+
messages?: string[];
|
|
8
|
+
/** tool_result ๋ก ํ์ ๋ ์๋ฌธ(์๊ฐ์). */
|
|
9
|
+
toolResults?: string[];
|
|
10
|
+
}
|
|
11
|
+
/** ๊ทผ๊ฑฐ์งํฉ์ ํ ๋ฉ์ด๋ฆฌ ๋ฌธ์์ด๋ก. (id ํ ํฐ ๋์กฐ๋ง ํ๋ฏ๋ก ๊ตฌ๋ถ์๋ ๊ฐํ์ผ๋ก ์ถฉ๋ถํ๋ค.) */
|
|
12
|
+
export declare function buildGroundedCorpus(sources: GroundingSources): string;
|
|
13
|
+
/**
|
|
14
|
+
* ๋ต์ด ๊ทผ๊ฑฐ ๋ฐ์ ์๋ณ์๋ฅผ ์ง๋ชฉํ์ผ๋ฉด ๊ทธ ๋ชฉ๋ก. ๋น๋ฉด ์ ์ง ์ ์.
|
|
15
|
+
* ๋ต์ ๊ณ ์น๊ฑฐ๋ ๋ง์ง ์๋๋ค โ ์ฌ์ฉ์์๊ฒ ํ์ํ ๊ฒฝ๊ณ ๋ง ๋ธ๋ค.
|
|
16
|
+
*/
|
|
17
|
+
export declare function checkReplyGrounding(reply: string, sources: GroundingSources): string[];
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.buildGroundedCorpus = buildGroundedCorpus;
|
|
4
|
+
exports.checkReplyGrounding = checkReplyGrounding;
|
|
5
|
+
/*
|
|
6
|
+
* ์ ์ง ๊ฒ์ฌ โ ์ด ๋ํ๋ฉด์ ๋ต์ด **๋ชจ๋ธ์ด ์ค์ ๋ก ๋ฐ์ ๊ฒ** ์์์ ๋งํ๋์ง.
|
|
7
|
+
*
|
|
8
|
+
* โโ ์ board-ai ์ ํ์ํ๊ฐ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
9
|
+
* ํ์ ๋ํฌ(operato-twin)๋ board-ai ์์ ์ ์๊ณ , ์ฌ๊ธฐ์ ์ฌ๋๋ค์ด ์ด์ ์ํ๋ฅผ ๋ฌป๋๋ค.
|
|
10
|
+
* ํค๋ ๊ฒฝ๋ก(twin-ai)์๋ ์ ์ง ๊ฐ๋๊ฐ ์์์ง๋ง ๋ํฌ ๊ฒฝ๋ก์๋ ์์๋ค โ ๊ฐ์ ์ง๋ฌธ์ ๋ํด
|
|
11
|
+
* ํ์ชฝ์ ๊ฒ์ฆ๋๊ณ ํ์ชฝ์ ๊ฒ์ฆ๋์ง ์๋ ์ํ์๋ค. ํ์ ๊ท์น์ ๊ณต์ฉ ๋ชจ๋์ด ์์ ํ๊ณ
|
|
12
|
+
* (`@things-factory/ai-client-base` ์ grounding), ์ด ํ์ผ์ **๋ฌด์์ ๊ทผ๊ฑฐ๋ก ๋ณผ ๊ฒ์ธ๊ฐ**๋ง ์ ํ๋ค.
|
|
13
|
+
*
|
|
14
|
+
* โโ ๊ทผ๊ฑฐ์งํฉ์ ์ ์ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
15
|
+
* ๋ชจ๋ธ์ด ์ด ํด์ ๋ฐ์ ์ ๋ถ๋ค. ํ๋๋ผ๋ ๋นผ๋ฉด ์ ์ ๋ต์ด ๊ฒฝ๊ณ ๋ฅผ ๋ฐ๋๋ค(์คํ):
|
|
16
|
+
* ยท systemPrompt โ ์์ฑ ๊ฐ๋ฅํ ์ปดํฌ๋ํธ ํ์
๋ชฉ๋ก ๋ฑ. ์ฌ๊ธฐ ์๋ ์ด๋ฆ์ ๋งํ๋ ๊ฑด ์ ์์ด๋ค.
|
|
17
|
+
* ยท boardContext โ ํ์ฌ ๋ณด๋ ์์ฝ(์ปดํฌ๋ํธ idยท์ด๋ฆ). ๋ณด๋๋ฅผ ๋๊ณ ๋งํ๋ ๊ทผ๊ฑฐ.
|
|
18
|
+
* ยท messages โ ์ฌ์ฉ์ยท์ด๋ ฅ ํ
์คํธ. ์ฌ์ฉ์๊ฐ ๋งํ ์๋ณ์๋ฅผ ๋๋ฐ๋ ๊ฑด ์ ์์ด๋ค.
|
|
19
|
+
* ยท toolResults โ ๋๊ตฌ๊ฐ ๋๋ ค์ค ์๋ฌธ(์์ถ ์ ). ์ด์ ์ํ ๋ต์ ์ ์ผํ ์ฌ์ค ๊ทผ๊ฑฐ.
|
|
20
|
+
*
|
|
21
|
+
* โโ ์ฌ์ ๊ฑฐ๋ฆฌ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
22
|
+
* ์๋ณ์๋ง ๋ณธ๋ค. "์ง๊ฒ์ฐจ๋ค์ด ๋ฐ์๊ฒ ์์ง์ธ๋ค" ์ฒ๋ผ **์๋ณ์ ์์ด ์ง์ด๋ธ ์์ **์ ์ก์ง ๋ชปํ๋ค โ
|
|
23
|
+
* ๊ทธ๊ฑด ๋๊ตฌ๋ฅผ ๋ถ๋ฅด์ง ์๊ณ ๋ตํ ๊ฒฝ์ฐ์ด๊ณ , ๋๊ตฌ ํธ์ถ์ ๊ฐ์ ํ๋ ๋ณ๋ ๋ ๋ฒ์ ๋ชซ์ด๋ค.
|
|
24
|
+
*/
|
|
25
|
+
const ai_client_base_1 = require("@things-factory/ai-client-base");
|
|
26
|
+
/** ๊ทผ๊ฑฐ์งํฉ์ ํ ๋ฉ์ด๋ฆฌ ๋ฌธ์์ด๋ก. (id ํ ํฐ ๋์กฐ๋ง ํ๋ฏ๋ก ๊ตฌ๋ถ์๋ ๊ฐํ์ผ๋ก ์ถฉ๋ถํ๋ค.) */
|
|
27
|
+
function buildGroundedCorpus(sources) {
|
|
28
|
+
return [
|
|
29
|
+
sources.systemPrompt ?? '',
|
|
30
|
+
sources.boardContext ?? '',
|
|
31
|
+
...(sources.messages ?? []),
|
|
32
|
+
...(sources.toolResults ?? [])
|
|
33
|
+
]
|
|
34
|
+
.filter(Boolean)
|
|
35
|
+
.join('\n');
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* ๋ต์ด ๊ทผ๊ฑฐ ๋ฐ์ ์๋ณ์๋ฅผ ์ง๋ชฉํ์ผ๋ฉด ๊ทธ ๋ชฉ๋ก. ๋น๋ฉด ์ ์ง ์ ์.
|
|
39
|
+
* ๋ต์ ๊ณ ์น๊ฑฐ๋ ๋ง์ง ์๋๋ค โ ์ฌ์ฉ์์๊ฒ ํ์ํ ๊ฒฝ๊ณ ๋ง ๋ธ๋ค.
|
|
40
|
+
*/
|
|
41
|
+
function checkReplyGrounding(reply, sources) {
|
|
42
|
+
if (!reply)
|
|
43
|
+
return [];
|
|
44
|
+
return (0, ai_client_base_1.groundingWarnings)(reply, buildGroundedCorpus(sources));
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=grounding.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"grounding.js","sourceRoot":"","sources":["../../server/service/grounding.ts"],"names":[],"mappings":";;AAkCA,kDASC;AAMD,kDAGC;AApDD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,mEAAkE;AAalE,wDAAwD;AACxD,SAAgB,mBAAmB,CAAC,OAAyB;IAC3D,OAAO;QACL,OAAO,CAAC,YAAY,IAAI,EAAE;QAC1B,OAAO,CAAC,YAAY,IAAI,EAAE;QAC1B,GAAG,CAAC,OAAO,CAAC,QAAQ,IAAI,EAAE,CAAC;QAC3B,GAAG,CAAC,OAAO,CAAC,WAAW,IAAI,EAAE,CAAC;KAC/B;SACE,MAAM,CAAC,OAAO,CAAC;SACf,IAAI,CAAC,IAAI,CAAC,CAAA;AACf,CAAC;AAED;;;GAGG;AACH,SAAgB,mBAAmB,CAAC,KAAa,EAAE,OAAyB;IAC1E,IAAI,CAAC,KAAK;QAAE,OAAO,EAAE,CAAA;IACrB,OAAO,IAAA,kCAAiB,EAAC,KAAK,EAAE,mBAAmB,CAAC,OAAO,CAAC,CAAC,CAAA;AAC/D,CAAC","sourcesContent":["/*\n * ์ ์ง ๊ฒ์ฌ โ ์ด ๋ํ๋ฉด์ ๋ต์ด **๋ชจ๋ธ์ด ์ค์ ๋ก ๋ฐ์ ๊ฒ** ์์์ ๋งํ๋์ง.\n *\n * โโ ์ board-ai ์ ํ์ํ๊ฐ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n * ํ์ ๋ํฌ(operato-twin)๋ board-ai ์์ ์ ์๊ณ , ์ฌ๊ธฐ์ ์ฌ๋๋ค์ด ์ด์ ์ํ๋ฅผ ๋ฌป๋๋ค.\n * ํค๋ ๊ฒฝ๋ก(twin-ai)์๋ ์ ์ง ๊ฐ๋๊ฐ ์์์ง๋ง ๋ํฌ ๊ฒฝ๋ก์๋ ์์๋ค โ ๊ฐ์ ์ง๋ฌธ์ ๋ํด\n * ํ์ชฝ์ ๊ฒ์ฆ๋๊ณ ํ์ชฝ์ ๊ฒ์ฆ๋์ง ์๋ ์ํ์๋ค. ํ์ ๊ท์น์ ๊ณต์ฉ ๋ชจ๋์ด ์์ ํ๊ณ \n * (`@things-factory/ai-client-base` ์ grounding), ์ด ํ์ผ์ **๋ฌด์์ ๊ทผ๊ฑฐ๋ก ๋ณผ ๊ฒ์ธ๊ฐ**๋ง ์ ํ๋ค.\n *\n * โโ ๊ทผ๊ฑฐ์งํฉ์ ์ ์ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n * ๋ชจ๋ธ์ด ์ด ํด์ ๋ฐ์ ์ ๋ถ๋ค. ํ๋๋ผ๋ ๋นผ๋ฉด ์ ์ ๋ต์ด ๊ฒฝ๊ณ ๋ฅผ ๋ฐ๋๋ค(์คํ):\n * ยท systemPrompt โ ์์ฑ ๊ฐ๋ฅํ ์ปดํฌ๋ํธ ํ์
๋ชฉ๋ก ๋ฑ. ์ฌ๊ธฐ ์๋ ์ด๋ฆ์ ๋งํ๋ ๊ฑด ์ ์์ด๋ค.\n * ยท boardContext โ ํ์ฌ ๋ณด๋ ์์ฝ(์ปดํฌ๋ํธ idยท์ด๋ฆ). ๋ณด๋๋ฅผ ๋๊ณ ๋งํ๋ ๊ทผ๊ฑฐ.\n * ยท messages โ ์ฌ์ฉ์ยท์ด๋ ฅ ํ
์คํธ. ์ฌ์ฉ์๊ฐ ๋งํ ์๋ณ์๋ฅผ ๋๋ฐ๋ ๊ฑด ์ ์์ด๋ค.\n * ยท toolResults โ ๋๊ตฌ๊ฐ ๋๋ ค์ค ์๋ฌธ(์์ถ ์ ). ์ด์ ์ํ ๋ต์ ์ ์ผํ ์ฌ์ค ๊ทผ๊ฑฐ.\n *\n * โโ ์ฌ์ ๊ฑฐ๋ฆฌ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n * ์๋ณ์๋ง ๋ณธ๋ค. \"์ง๊ฒ์ฐจ๋ค์ด ๋ฐ์๊ฒ ์์ง์ธ๋ค\" ์ฒ๋ผ **์๋ณ์ ์์ด ์ง์ด๋ธ ์์ **์ ์ก์ง ๋ชปํ๋ค โ\n * ๊ทธ๊ฑด ๋๊ตฌ๋ฅผ ๋ถ๋ฅด์ง ์๊ณ ๋ตํ ๊ฒฝ์ฐ์ด๊ณ , ๋๊ตฌ ํธ์ถ์ ๊ฐ์ ํ๋ ๋ณ๋ ๋ ๋ฒ์ ๋ชซ์ด๋ค.\n */\nimport { groundingWarnings } from '@things-factory/ai-client-base'\n\nexport interface GroundingSources {\n /** ์์คํ
ํ๋กฌํํธ(ํ์
๋ชฉ๋กยท๊ท์น). */\n systemPrompt?: string\n /** ๋ณด๋ ์ํ ์์ฝ ๋ฑ ๋ํ ์์ ๋ถ์ธ ๋ฌธ๋งฅ. */\n boardContext?: string\n /** ์ฌ์ฉ์ยท์ด์์คํดํธ ์ด๋ ฅ ํ
์คํธ. */\n messages?: string[]\n /** tool_result ๋ก ํ์ ๋ ์๋ฌธ(์๊ฐ์). */\n toolResults?: string[]\n}\n\n/** ๊ทผ๊ฑฐ์งํฉ์ ํ ๋ฉ์ด๋ฆฌ ๋ฌธ์์ด๋ก. (id ํ ํฐ ๋์กฐ๋ง ํ๋ฏ๋ก ๊ตฌ๋ถ์๋ ๊ฐํ์ผ๋ก ์ถฉ๋ถํ๋ค.) */\nexport function buildGroundedCorpus(sources: GroundingSources): string {\n return [\n sources.systemPrompt ?? '',\n sources.boardContext ?? '',\n ...(sources.messages ?? []),\n ...(sources.toolResults ?? [])\n ]\n .filter(Boolean)\n .join('\\n')\n}\n\n/**\n * ๋ต์ด ๊ทผ๊ฑฐ ๋ฐ์ ์๋ณ์๋ฅผ ์ง๋ชฉํ์ผ๋ฉด ๊ทธ ๋ชฉ๋ก. ๋น๋ฉด ์ ์ง ์ ์.\n * ๋ต์ ๊ณ ์น๊ฑฐ๋ ๋ง์ง ์๋๋ค โ ์ฌ์ฉ์์๊ฒ ํ์ํ ๊ฒฝ๊ณ ๋ง ๋ธ๋ค.\n */\nexport function checkReplyGrounding(reply: string, sources: GroundingSources): string[] {\n if (!reply) return []\n return groundingWarnings(reply, buildGroundedCorpus(sources))\n}\n"]}
|
|
@@ -25,6 +25,15 @@ export interface ChatOptions {
|
|
|
25
25
|
* ๋๋๋ฆด ์ ์๋ ํธ์ง์ด ํ ๋ํ์ ์์ด์ง ์๊ฒ ํ๋ค.
|
|
26
26
|
*/
|
|
27
27
|
boardTools?: boolean;
|
|
28
|
+
/**
|
|
29
|
+
* **์ฒซ ํด์ ๋๊ตฌ ํธ์ถ์ ๊ฐ์ **ํ๋ค. ๋ผ์ด๋ธ ์ํ๋ฅผ ๋ค๋ฃจ๋ ๋ํ๋ฉด(์ด์ ํ์)์์ ์ผ ๋ค.
|
|
30
|
+
*
|
|
31
|
+
* ์ ์ง ๊ฐ๋๋ ๋ต์ด ์ง์ด๋ธ **์๋ณ์**๋ฅผ ์ก์ง๋ง, ์๋ณ์ ์์ด ์ง์ด๋ธ **์ํฉ ์์ **์ ์ก์ง ๋ชปํ๋ค
|
|
32
|
+
* ("์ง๊ฒ์ฐจ๋ค์ด ๋ฐ์๊ฒ ์์ง์ด๊ณ ์๋ค" โ ์ค์ ๋ก ๋์จ ๋ต์ด๋ค). ๊ทธ๊ฑด ๋๊ตฌ๋ฅผ ์์ ๋ถ๋ฅด์ง ์๊ณ ๋ตํ
|
|
33
|
+
* ๊ฒฝ์ฐ์ฌ์ ์ฌํ ๊ฒ์ฌ๋ก ๋ง์ ์ ์๋ค. ์ฒซ ํด์ ๋ฌด์์ด๋ ์กฐํํ๊ฒ ๋ง๋ค๋ฉด ๊ทผ๊ฑฐ ์์ด ์ํ๋ฅผ ๋จ์ธํ
|
|
34
|
+
* ๊ธธ์ด ์์ด์ง๋ค. ์ผ๊ณ ๋๋ ํ๋จ์ ๋ํ๋ฉด์ด ํ๋ค โ ์๋ฒ๊ฐ ์ง๋ฌธ ๋ด์ฉ์ ๋์น๋ก ๋ถ๋ฅํ์ง ์๋๋ค.
|
|
35
|
+
*/
|
|
36
|
+
requireGroundingTools?: boolean;
|
|
28
37
|
/**
|
|
29
38
|
* ํธ์คํธ(๋ํ๋ฉด)๊ฐ ์ค์ด ๋ณด๋ด๋ **๋ฌธ๋งฅ** โ ๋๊ตฌ๊ฐ ctx.state.host ๋ก ์ฝ๋๋ค.
|
|
30
39
|
*
|
|
@@ -131,6 +140,13 @@ export interface ChatResponse {
|
|
|
131
140
|
followUp?: string;
|
|
132
141
|
/** AI ๊ฐ ์๋ต ๋ง๋๋ ๊ณผ์ ์์ ํธ์ถํ ๋๊ตฌ๋ค (์๊ฐ์). UI fold-able ๋ฐ์ค์ฉ. */
|
|
133
142
|
toolUsages?: ToolUsage[];
|
|
143
|
+
/**
|
|
144
|
+
* ์ ์ง ๊ฒฝ๊ณ โ ๋ต์ด ์ธ๊ธํ์ผ๋ ๋ชจ๋ธ์ด ๋ฐ์ ๊ทผ๊ฑฐ(ํ๋กฌํํธยท๋ณด๋ ๋ฌธ๋งฅยท์ด๋ ฅยท๋๊ตฌ ๊ฒฐ๊ณผ)์ ์๋ ์๋ณ์.
|
|
145
|
+
*
|
|
146
|
+
* ์์ผ๋ฉด ๊ทธ ๋์์ **๋ง๋ค์ด ๋ธ ๊ฒ์ผ ์ ์๋ค**. ๋ต์ ๋ง๊ฑฐ๋ ๊ณ ์น์ง ์๊ณ ์ฌ์ฉ์์๊ฒ ํ์ํ๋ค โ
|
|
147
|
+
* ํ์ ๊ท์นยท์ฌ์ ๊ฑฐ๋ฆฌ๋ ./grounding ์ฐธ์กฐ. ๋น๋ฉด(undefined) ์ ์ง ์ ์.
|
|
148
|
+
*/
|
|
149
|
+
groundingWarnings?: string[];
|
|
134
150
|
}
|
|
135
151
|
export interface BoardEditPatch {
|
|
136
152
|
ops: BoardEditOp[];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../server/service/types.ts"],"names":[],"mappings":"","sourcesContent":["/**\n * Board AI โ ์์ฐ์ด ์ฑํ
์ธํฐํ์ด์ค ํ์
์ ์.\n *\n * ํต์ฌ ๊ฐ๋
:\n * - ๋จ์ผ ์ง์
์ `chat()`. ์๋ ๋ถ๋ฅ(์์ฑ/ํธ์ง/์คํ์ผ/์ง๋ฌธ)๋ AI ์ ์ผ.\n * - ์ถ๋ ฅ์ ํญ์ `ChatResponse`. ๋ณด๋ ๋ณ๊ฒฝ์ด ์์ผ๋ฉด `patch` ๋๋ด.\n * - patch ์ op ๋ ์ง๊ต 4 ์ข
(add / remove / modify / replace).\n * style/move ๋ฑ์ modify.patch ์์ ํก์.\n */\nimport type { BoardComponent, BoardModel } from '@things-factory/board-import'\n\nexport interface LLMMessage {\n role: 'user' | 'assistant'\n content: string\n}\n\nexport interface ChatOptions {\n /**\n * ์ด ๋ํ์ ๋
ธ์ถํ **์ธ๋ถ ๋๊ตฌ ์นดํ
๊ณ ๋ฆฌ** ํ์ดํธ๋ฆฌ์คํธ(registerToolCategory ์ด๋ฆ).\n * ๋ฏธ์ง์ = ๋ฑ๋ก๋ ์ ๋ถ(ํํ ๋์). ์ฑ๊ฒฉ์ด ๋ค๋ฅธ ๋ํ๋ฉด(๋ณด๋ ์ ์ ๋ํฌ ยท ์ด์ ๋ํฌ)์ด\n * ์๋ก์ ๋ฅ๋ ฅ์ ๊ฐ์ง ์๊ฒ ํ๋ ๊ฒฝ๊ณ โ ์ ์๋ฟ ์๋๋ผ ์คํ ํ์ ์๋ ์ ์ฉ๋๋ค.\n */\n toolCategories?: string[]\n /**\n * ์ฝ์ด ๋ณด๋ ํธ์ง ๋๊ตฌ(addComponent ยท ์คํ์ผ๋ง ยท ์ฌ ์กฐ์) ๋
ธ์ถ ์ฌ๋ถ. ๊ธฐ๋ณธ true.\n * ์ด์ ๋ํ์ฒ๋ผ ๋ณด๋๋ฅผ ๊ณ ์น ์ด์ ๊ฐ ์๋ ๋ฉด์์๋ false ๋ก ๊บผ์, ๋๋๋ฆด ์ ์๋ ํ๋๊ณผ\n * ๋๋๋ฆด ์ ์๋ ํธ์ง์ด ํ ๋ํ์ ์์ด์ง ์๊ฒ ํ๋ค.\n */\n boardTools?: boolean\n /**\n * ํธ์คํธ(๋ํ๋ฉด)๊ฐ ์ค์ด ๋ณด๋ด๋ **๋ฌธ๋งฅ** โ ๋๊ตฌ๊ฐ ctx.state.host ๋ก ์ฝ๋๋ค.\n *\n * ์ ํ์ํ๊ฐ: ๋ํ๋ฉด๋ง๋ค \"์ง๊ธ ๋ฌด์์ ๋ณด๊ณ ์๋์ง\" ๊ฐ ๋ค๋ฅด๋ค(์ด๋ ๊ณต๊ฐยท์ด๋ ์ธ์คํด์คยท์ด๋ ๋ณด๋).\n * ์ด๊ฒ ์์ด๋ ๋๊ตฌ๊ฐ ๋์์ ์ ์ ์์ด ๋ชจ๋ธ์ด ์ฌ์ฉ์์๊ฒ ์๋ณ์๋ฅผ ๋๋ฌป๋๋ค โ ์ ํ์ผ๋ก ์ฑ๋ฆฝํ์ง ์๋๋ค.\n * ๋ณด๋ ๋ํ๋ ๋ณด๋ ๋ชจ๋ธ์ ๊ฐ์ธํด ์ฐํํ ์ ์์์ง๋ง ๋ณด๋๊ฐ ์๋ ๋ํ๋ฉด(๊ณต๊ฐ ํ์)์ ํต๋ก๊ฐ ์์๋ค.\n *\n * ์ ๋ขฐ ๊ฒฝ๊ณ: ์ด ๊ฐ์ **ํด๋ผ์ด์ธํธ๊ฐ ๋ณด๋ธ ๊ฒ**์ด๋ค. ๋๋ฉ์ธยท์ฌ์ฉ์ ๊ฐ์ ๊ถํ ํ์ ์ ์ฐ์ง ๋ง ๊ฒ\n * (๊ทธ๊ฑด ์๋ฒ๊ฐ ์ธ์
์์ ์ป๋ ctx.state.domain/user ๊ฐ ์ ๋ณธ). ์ฌ๊ธฐ ๊ฐ์ \"๋ฌด์์ ๋ณด๊ณ ์๋์ง\" ๋ฒ์\n * ํํธ์ด๋ฉฐ, ๋๊ตฌ๋ ๊ทธ ๋ฒ์๊ฐ ํธ์ถ์ ํ
๋ํธ ์์์ธ์ง ๋ฐ๋์ ๊ฒ์ฆํ๋ค.\n */\n hostContext?: any\n /** board-import ์ registry scope โ ๋ฑ๋ก๋ ImportRule ์์ type/category ํ๋ณด ์ถ์ถ */\n scopes?: string[]\n /** ์ฌ์ฉ ๊ฐ๋ฅํ ๋๋ฉ์ธ type (override). ๋ฏธ์ง์ ์ scopes ์์ ์๋ ์ถ์ถ */\n knownTypes?: string[]\n /** ์ฌ์ฉ ๊ฐ๋ฅํ ์นดํ
๊ณ ๋ฆฌ (override). ๋ฏธ์ง์ ์ scopes ์์ ์๋ ์ถ์ถ */\n categories?: string[]\n /**\n * ์ปดํฌ๋ํธ type ๋ณ ์ ํจ ์์ฑ ์คํด.\n * LLM ์ด ์ ํํ ์ปดํฌ๋ํธ ์์ฑ์ ํ๋๋ก type ์ description, group, default model ํค ์ ๋ฌ.\n *\n * ์:\n * [{ type: 'rect', description: 'Rectangle', group: 'shape',\n * properties: { fillStyle: '#fff', strokeStyle: '#000' } }, ...]\n */\n componentSchemas?: ComponentSchema[]\n /**\n * ์ฌ์ฉ์๊ฐ ๋ชจ๋ธ๋ฌ์์ ํ์ฌ ์ ํํ ์ปดํฌ๋ํธ์ `refid` ๋ชฉ๋ก.\n *\n * refid ๋ things-scene ์ด ๋ชจ๋ ์ปดํฌ๋ํธ์ ์๋ ๋ฐ๊ธํ๋ universal numeric handle.\n * id (๋ฐ์ดํฐ ๋ฐ์ธ๋ฉ ์ด๋ฆ, unique ์๋) ์๋ ๋ค๋ฅธ ๊ฐ๋
โ ์ ํ์ ํญ์ refid ๋ก ํํ.\n */\n selectedRefids?: number[]\n /**\n * popup ์์ ์ฌ์ฉ์๊ฐ ๋ช
์ ์ ํํ #mention ๋งคํ โ {token, refid}.\n * server ๊ฐ mention ํด์ ์ ์ด ๋งคํ์ ์ฐ์ ์ฌ์ฉ. ๋ณธ๋ฌธ์ #token ๋ง ๋จ๊ณ \n * refid ๋ ์ฌ์ฉ์์๊ฒ ๋
ธ์ถ๋์ง ์์ (LLM mention map ์๋ง ์ฒจ๋ถ).\n */\n mentionPicks?: Array<{ token: string; refid: number }>\n /** LLM ๋ชจ๋ธ override */\n model?: string\n /** LLM ์ต์
*/\n temperature?: number\n maxTokens?: number\n /**\n * Tool ์นดํ
๊ณ ๋ฆฌ (read/external) builder ๊ฐ ์ฌ์ฉํ ์ปจํ
์คํธ.\n *\n * board-ai ์์ฒด๋ ResolverContext / typeorm ์ ์ง์ ์์ง ์์ง๋ง, ์ธ๋ถ ๋๋ฉ์ธ ํจํค์ง๊ฐ\n * ๋ฑ๋กํ tool (์: board-import ์ importBoardAsync) ์ server-side ์์กด์ฑ (๋๋ฉ์ธ,\n * ์ฌ์ฉ์, ํธ๋์ญ์
) ์ด ํ์ํ ์ ์๋ค. board-ai-resolver ๊ฐ ResolverContext.state ๋ฑ์\n * ์ด ํ๋๋ก ์ ๋ฌํ๋ฉด, dispatch ์ closure ๋ก builder ์ ctx.state ์ ์ฃผ์
.\n *\n * ๋ฏธ์ง์ ์ด๋ฉด ์ธ๋ถ builder ๋ ctx.state === undefined โ ๋น ์๋ต์ด๋ ์๋ฌ๋ฅผ ๋ฐํํ ์ฑ
์.\n */\n toolCallContext?: any\n}\n\nexport interface ComponentSchema {\n type: string\n description?: string\n group?: string\n /**\n * ์ขํ/ํฌ๊ธฐ/๊ฒฝ๋ก ๊ด๋ จ ํค๋ค โ type ๋ง๋ค ๋ค๋ฆ.\n * ์) ['left', 'top', 'width', 'height'] vs ['cx', 'cy', 'radius'] vs ['points']\n * LLM ์ด type ๋ณ ์ ํํ ์ขํ ํค๋ฅผ ์ฌ์ฉํ๋๋ก ๋ช
์.\n */\n geometryKeys?: string[]\n /**\n * ์ขํ ์ธ type ํนํ ์์ฑ (style, value, min/max ๋ฑ).\n * default ๊ฐ ๋๋ keys ๋ง โ LLM ์ token ์ ๊ฐ์ ์ํด ํธ์ถ์๊ฐ ์ ์ ํ ์์ถ.\n */\n properties?: Record<string, any>\n}\n\n/**\n * AI ๊ฐ ์๋ต์ ๋ง๋๋ ๋์ ํธ์ถํ ๋๊ตฌ์ ์๊ฐ์ trace.\n *\n * UX ๋ชฉ์ โ ์ฌ์ฉ์๊ฐ \"์ ์ด๋ ๊ฒ ๋ตํ์ง\" ์๋ฌธ ๊ฐ์ง ๋ fold-able ๋ฐ์ค์์ ํ์ธ.\n * ๋๋ฒ๊ทธ์ฉ + ์ ๋ขฐ๋ ํฅ์.\n */\nexport interface ToolUsage {\n /** ๋๊ตฌ ์ด๋ฆ (์: 'getSelection', 'modifyBoard', 'addComponent') */\n name: string\n /** ํธ์ถ ์ธ์ JSON */\n arguments: any\n /** ๋๊ตฌ ๊ฒฐ๊ณผ โ read tool ์ ์ค์ ๊ฐ (truncated ๊ฐ๋ฅ), write tool ์ queued ๋ง์ปค */\n result: any\n /** read tool / write tool ๋ถ๋ฅ */\n kind: 'read' | 'write' | 'unknown'\n}\n\nexport interface ChatResponse {\n /** ์ฌ์ฉ์์๊ฒ ๋ณด์ฌ์ค ํ
์คํธ ์๋ต */\n reply: string\n /** ๋ณด๋ ๋ณ๊ฒฝ์ด ์์ผ๋ฉด patch */\n patch?: BoardEditPatch\n /**\n * Scene ์กฐ์ action (ephemeral โ ๋ชจ๋ธ ๋ณ๊ฒฝ ์์ / undo ์ํฅ ์์).\n * ์๊ฐ์ ์ํ์ค๋ก ํธ์คํธ๊ฐ things-scene API ์ง์ ์คํ.\n */\n actions?: BoardActionOp[]\n /** ๋ชจํธํ ์
๋ ฅ ์ ๋ช
ํํ ์ง๋ฌธ (patch ์์) */\n followUp?: string\n /** AI ๊ฐ ์๋ต ๋ง๋๋ ๊ณผ์ ์์ ํธ์ถํ ๋๊ตฌ๋ค (์๊ฐ์). UI fold-able ๋ฐ์ค์ฉ. */\n toolUsages?: ToolUsage[]\n}\n\nexport interface BoardEditPatch {\n ops: BoardEditOp[]\n /** ์ฌ์ฉ์ ๊ฒ์์ฉ 1-2 ๋ฌธ์ฅ ์์ฝ */\n summary: string\n /** 0..1 ์ ๋ขฐ๋ */\n confidence: number\n}\n\n/**\n * ๋ณด๋ ๋ณ๊ฒฝ op.\n *\n * ์๋ณ์ ์ ์ฑ
โ ๊ธฐ์กด ์ปดํฌ๋ํธ ํ๊นํ
์ `refid` (number) ๋ง ์ฌ์ฉ.\n * things-scene ์ ๋ชจ๋ ์ปดํฌ๋ํธ๋ `refid` ๋ฅผ ์๋ ๋ฐ๊ธ๋ฐ๋๋ค (universal).\n * `model.id` ๋ optional metadata ์ผ ๋ฟ โ ํญ์ ์กด์ฌํ์ง ์์ผ๋ฏ๋ก targeting ์๋\n * ๋ถ์ ํฉ. ๋ณ๊ฐ ๊ฐ๋
์ด๋ฏ๋ก BoardEditOp / tool ์ธ์์์๋ ๋ณ๊ฐ ์๋ณ์๋ก ๋ถ๋ฆฌํ์ง\n * ์๊ณ refid ๋จ์ผ ์ฑ๋๋ก ์ผ์ํ.\n *\n * ๊ณ์ธต โ ๋ณด๋๋ **์ต์์ ๋ถ๋ชจ** (things-scene ์ model-layer) ์ด๊ณ ๊ทธ ์์ฒด๋ก ์๊ธฐ\n * ์์ฑ์ ๊ฐ๋๋ค (fillStyle, width, height, fitMode, translate, scale, sky, skyColor,\n * exposure, hemi/dirLight ๊ณ์ด, camera ๊ณ์ด). ์์ ์ปดํฌ๋ํธ์ ๋ณ๊ฐ. ๋ณด๋ ์์ฑ ๋ณ๊ฒฝ์\n * `modifyBoard`, ์์ ๋ณ๊ฒฝ์ `modify` (refid ๊ธฐ๋ฐ).\n *\n * ์ฃผ์ โ `name` ์ ๋ณด๋ *์ํฐํฐ* (DB row) ์ ์ปฌ๋ผ์ด์ง scene MODEL ์ ํ๋๊ฐ ์๋๋ค.\n * things-scene ์ model-layer ๊ฐ ์ธ์ ์ ํจ. modifyBoard ๋ก name ์ ๋ณด๋ด๋ฉด model\n * JSON ์ ์ฃฝ์ ํ๋๋ก ๋ฐํ ๋ฟ ๋ ๋๋ง/๋์์ ์ํฅ ์์. ๋ณด๋ ๋ผ๋ฒจ ๋ณ๊ฒฝ์ GraphQL\n * boardPatch (BoardPatch input ์ name ํ๋) ์์ญ.\n *\n * style ๋ณ๊ฒฝ / ์ด๋ / ํฌ๊ธฐ ๋ณ๊ฒฝ ๋ฑ ์์ ์ปดํฌ๋ํธ์ ๋ณ๊ฒฝ์ ๋ชจ๋ `modify.patch` ์์\n * ํก์. ๋ณด๋ root ์์ฑ ๋ณ๊ฒฝ์ `modifyBoard.patch` ๋ก.\n */\n/**\n * Phase 2 โ Scene ์กฐ์ op ๋ค. ๋ชจ๋ธ ์ฐจ์ (์ขํ / ๋ถ๋ชจ-์์ ๊ด๊ณ / z-order) ๋ณ๊ฒฝ์ด์ง๋ง\n * things-scene ์ ์์ฒด API (align/distribute/group/ungroup/zorder) ๊ฐ ์ผ๊ด๋ ๊ฒฐ๊ณผ๋ฅผ\n * ๋ณด์ฅํ๋ฏ๋ก ํธ์คํธ๊ฐ ์ง์ ํธ์ถ. ๋ชจ๋ธ ์ฐจ์ ์๋ฎฌ๋ ์ด์
(apply-patch) ์ ๋จ์ํ โ\n * scene ํธ์ถ ๊ฒฐ๊ณผ๊ฐ ์ ๋ณธ.\n */\nexport type AlignDirection =\n | 'left'\n | 'right'\n | 'center'\n | 'top'\n | 'middle'\n | 'bottom'\n\nexport type DistributeAxis = 'horizontal' | 'vertical'\n\nexport type ZorderDirection = 'front' | 'back' | 'forward' | 'backward'\n\n/**\n * Sugar layout โ `arrange` op ์ layout ์ข
๋ฅ.\n *\n * ์๋: align/distribute ์์ ์น๋ high-level ์๋ ํํ. AI ๊ฐ \"3x2 ๊ทธ๋ฆฌ๋๋ก\",\n * \"ํ ์ค๋ก\", \"์ธ๋ก๋ก ์ผ๋ ฌ\" ๊ฐ์ ์์ฐ์ด๋ฅผ ํฝ์
๋
ธ๊ฐ๋ค ์์ด ๋จ์ผ op ๋ก ํํ.\n *\n * left/top ๋ง ๋ณ๊ฒฝ โ width/height ๋ ์ ์ง. AI ๊ฐ ์ฌ์ด์ฆ๋ ๋ฐ๊พธ๋ ค๋ฉด ๋ณ๋ modify.\n *\n * ์์น ๊ณ์ฐ์ ํธ์คํธ (things-scene ์ธก) ๊ฐ ๋ด๋น โ ๊ฐ ์ปดํฌ๋ํธ์ ํ์ฌ width/height ๋ฅผ\n * ์ ํํ ์์์ผ ํ๋ฏ๋ก model ์ฐจ์ ์๋ฎฌ๋ ์ด์
์ SCENE_ONLY (apply-patch noop).\n */\nexport type ArrangeLayout =\n | { type: 'grid'; cols: number; gap?: number; anchor?: { left: number; top: number } }\n | {\n type: 'row'\n gap?: number\n anchor?: { left: number; top: number }\n align?: 'start' | 'center' | 'end'\n }\n | {\n type: 'column'\n gap?: number\n anchor?: { left: number; top: number }\n align?: 'start' | 'center' | 'end'\n }\n\n/**\n * C-1 โ Scene ์กฐ์ action ๋ค (ephemeral). ๋ชจ๋ธ ๋ณ๊ฒฝ X, ๋ฐ๋ผ์ BoardEditOp ์ ๋ณ๊ฐ\n * ์ฑ๋ (board-action-execute ์ด๋ฒคํธ). undo ํ์คํ ๋ฆฌ ๋ฏธ์ํฅ, dirty flag ๋ฏธ์ํฅ.\n *\n * ์ข
๋ฅ:\n * - selectComponents: scene.selected ์ง์ set (์ฌ์ฉ์ ์ ํ ๋ณ๊ฒฝ)\n * - centerToComponent: ํน์ ์ปดํฌ๋ํธ๋ก view ์ด๋\n * - fitToView: ๋ณด๋ ์ ์ฒด๊ฐ ๋ณด์ด๋๋ก fit\n * - setSceneMode: edit / view ๋ชจ๋ ์ ํ\n */\nexport type BoardActionOp =\n | { action: 'selectComponents'; refids: number[] }\n | { action: 'centerToComponent'; refid: number; animated?: boolean }\n | { action: 'fitToView'; mode?: 'fit' | 'ratio' | 'width' | 'height' }\n | { action: 'setSceneMode'; mode: 'edit' | 'view' }\n /** ๋ค์ค ์ปดํฌ๋ํธ outline highlight โ search/finder UX ์ \"์ด๊ฒ ๋ชจ๋ ๋งค์นญ์ด๋ค\" ์๊ฐํ.\n * things-scene ์ highlightSearchResults API ์์ (2D/3D ๋ชจ๋ ์ง์). */\n | { action: 'highlightComponents'; refids: number[] }\n\nexport type BoardEditOp =\n | { op: 'add'; component: BoardComponent }\n | { op: 'remove'; refid: number }\n | { op: 'modify'; refid: number; patch: Partial<BoardComponent> }\n | { op: 'modifyBoard'; patch: Partial<BoardModel> }\n | { op: 'replace'; board: BoardModel }\n | { op: 'align'; refids: number[]; direction: AlignDirection }\n | { op: 'distribute'; refids: number[]; axis: DistributeAxis }\n | { op: 'group'; refids: number[] }\n | { op: 'ungroup'; refid: number }\n | { op: 'zorder'; refid: number; direction: ZorderDirection }\n | { op: 'arrange'; refids: number[]; layout: ArrangeLayout }\n\n/**\n * BoardAIAssistant โ ์์ฐ์ด ์ฑํ
์ผ๋ก ๋ณด๋๋ฅผ ๋ค๋ฃจ๋ ๋จ์ผ ์ธํฐํ์ด์ค.\n *\n * ์ฌ์ฉ:\n * const ai = new DefaultBoardAIAssistant(baseClient, { scopes: ['fmsim'] })\n * const r = await ai.chat([{ role: 'user', content: 'AGV 3๋ ์ถ๊ฐ' }], currentBoard)\n * if (r.patch) currentBoard = applyBoardEditPatch(currentBoard, r.patch)\n */\nexport interface BoardAIAssistant {\n readonly id: string\n chat(\n messages: LLMMessage[],\n currentBoard: BoardModel | undefined,\n options?: ChatOptions\n ): Promise<ChatResponse>\n}\n"]}
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../server/service/types.ts"],"names":[],"mappings":"","sourcesContent":["/**\n * Board AI โ ์์ฐ์ด ์ฑํ
์ธํฐํ์ด์ค ํ์
์ ์.\n *\n * ํต์ฌ ๊ฐ๋
:\n * - ๋จ์ผ ์ง์
์ `chat()`. ์๋ ๋ถ๋ฅ(์์ฑ/ํธ์ง/์คํ์ผ/์ง๋ฌธ)๋ AI ์ ์ผ.\n * - ์ถ๋ ฅ์ ํญ์ `ChatResponse`. ๋ณด๋ ๋ณ๊ฒฝ์ด ์์ผ๋ฉด `patch` ๋๋ด.\n * - patch ์ op ๋ ์ง๊ต 4 ์ข
(add / remove / modify / replace).\n * style/move ๋ฑ์ modify.patch ์์ ํก์.\n */\nimport type { BoardComponent, BoardModel } from '@things-factory/board-import'\n\nexport interface LLMMessage {\n role: 'user' | 'assistant'\n content: string\n}\n\nexport interface ChatOptions {\n /**\n * ์ด ๋ํ์ ๋
ธ์ถํ **์ธ๋ถ ๋๊ตฌ ์นดํ
๊ณ ๋ฆฌ** ํ์ดํธ๋ฆฌ์คํธ(registerToolCategory ์ด๋ฆ).\n * ๋ฏธ์ง์ = ๋ฑ๋ก๋ ์ ๋ถ(ํํ ๋์). ์ฑ๊ฒฉ์ด ๋ค๋ฅธ ๋ํ๋ฉด(๋ณด๋ ์ ์ ๋ํฌ ยท ์ด์ ๋ํฌ)์ด\n * ์๋ก์ ๋ฅ๋ ฅ์ ๊ฐ์ง ์๊ฒ ํ๋ ๊ฒฝ๊ณ โ ์ ์๋ฟ ์๋๋ผ ์คํ ํ์ ์๋ ์ ์ฉ๋๋ค.\n */\n toolCategories?: string[]\n /**\n * ์ฝ์ด ๋ณด๋ ํธ์ง ๋๊ตฌ(addComponent ยท ์คํ์ผ๋ง ยท ์ฌ ์กฐ์) ๋
ธ์ถ ์ฌ๋ถ. ๊ธฐ๋ณธ true.\n * ์ด์ ๋ํ์ฒ๋ผ ๋ณด๋๋ฅผ ๊ณ ์น ์ด์ ๊ฐ ์๋ ๋ฉด์์๋ false ๋ก ๊บผ์, ๋๋๋ฆด ์ ์๋ ํ๋๊ณผ\n * ๋๋๋ฆด ์ ์๋ ํธ์ง์ด ํ ๋ํ์ ์์ด์ง ์๊ฒ ํ๋ค.\n */\n boardTools?: boolean\n /**\n * **์ฒซ ํด์ ๋๊ตฌ ํธ์ถ์ ๊ฐ์ **ํ๋ค. ๋ผ์ด๋ธ ์ํ๋ฅผ ๋ค๋ฃจ๋ ๋ํ๋ฉด(์ด์ ํ์)์์ ์ผ ๋ค.\n *\n * ์ ์ง ๊ฐ๋๋ ๋ต์ด ์ง์ด๋ธ **์๋ณ์**๋ฅผ ์ก์ง๋ง, ์๋ณ์ ์์ด ์ง์ด๋ธ **์ํฉ ์์ **์ ์ก์ง ๋ชปํ๋ค\n * (\"์ง๊ฒ์ฐจ๋ค์ด ๋ฐ์๊ฒ ์์ง์ด๊ณ ์๋ค\" โ ์ค์ ๋ก ๋์จ ๋ต์ด๋ค). ๊ทธ๊ฑด ๋๊ตฌ๋ฅผ ์์ ๋ถ๋ฅด์ง ์๊ณ ๋ตํ\n * ๊ฒฝ์ฐ์ฌ์ ์ฌํ ๊ฒ์ฌ๋ก ๋ง์ ์ ์๋ค. ์ฒซ ํด์ ๋ฌด์์ด๋ ์กฐํํ๊ฒ ๋ง๋ค๋ฉด ๊ทผ๊ฑฐ ์์ด ์ํ๋ฅผ ๋จ์ธํ \n * ๊ธธ์ด ์์ด์ง๋ค. ์ผ๊ณ ๋๋ ํ๋จ์ ๋ํ๋ฉด์ด ํ๋ค โ ์๋ฒ๊ฐ ์ง๋ฌธ ๋ด์ฉ์ ๋์น๋ก ๋ถ๋ฅํ์ง ์๋๋ค.\n */\n requireGroundingTools?: boolean\n /**\n * ํธ์คํธ(๋ํ๋ฉด)๊ฐ ์ค์ด ๋ณด๋ด๋ **๋ฌธ๋งฅ** โ ๋๊ตฌ๊ฐ ctx.state.host ๋ก ์ฝ๋๋ค.\n *\n * ์ ํ์ํ๊ฐ: ๋ํ๋ฉด๋ง๋ค \"์ง๊ธ ๋ฌด์์ ๋ณด๊ณ ์๋์ง\" ๊ฐ ๋ค๋ฅด๋ค(์ด๋ ๊ณต๊ฐยท์ด๋ ์ธ์คํด์คยท์ด๋ ๋ณด๋).\n * ์ด๊ฒ ์์ด๋ ๋๊ตฌ๊ฐ ๋์์ ์ ์ ์์ด ๋ชจ๋ธ์ด ์ฌ์ฉ์์๊ฒ ์๋ณ์๋ฅผ ๋๋ฌป๋๋ค โ ์ ํ์ผ๋ก ์ฑ๋ฆฝํ์ง ์๋๋ค.\n * ๋ณด๋ ๋ํ๋ ๋ณด๋ ๋ชจ๋ธ์ ๊ฐ์ธํด ์ฐํํ ์ ์์์ง๋ง ๋ณด๋๊ฐ ์๋ ๋ํ๋ฉด(๊ณต๊ฐ ํ์)์ ํต๋ก๊ฐ ์์๋ค.\n *\n * ์ ๋ขฐ ๊ฒฝ๊ณ: ์ด ๊ฐ์ **ํด๋ผ์ด์ธํธ๊ฐ ๋ณด๋ธ ๊ฒ**์ด๋ค. ๋๋ฉ์ธยท์ฌ์ฉ์ ๊ฐ์ ๊ถํ ํ์ ์ ์ฐ์ง ๋ง ๊ฒ\n * (๊ทธ๊ฑด ์๋ฒ๊ฐ ์ธ์
์์ ์ป๋ ctx.state.domain/user ๊ฐ ์ ๋ณธ). ์ฌ๊ธฐ ๊ฐ์ \"๋ฌด์์ ๋ณด๊ณ ์๋์ง\" ๋ฒ์\n * ํํธ์ด๋ฉฐ, ๋๊ตฌ๋ ๊ทธ ๋ฒ์๊ฐ ํธ์ถ์ ํ
๋ํธ ์์์ธ์ง ๋ฐ๋์ ๊ฒ์ฆํ๋ค.\n */\n hostContext?: any\n /** board-import ์ registry scope โ ๋ฑ๋ก๋ ImportRule ์์ type/category ํ๋ณด ์ถ์ถ */\n scopes?: string[]\n /** ์ฌ์ฉ ๊ฐ๋ฅํ ๋๋ฉ์ธ type (override). ๋ฏธ์ง์ ์ scopes ์์ ์๋ ์ถ์ถ */\n knownTypes?: string[]\n /** ์ฌ์ฉ ๊ฐ๋ฅํ ์นดํ
๊ณ ๋ฆฌ (override). ๋ฏธ์ง์ ์ scopes ์์ ์๋ ์ถ์ถ */\n categories?: string[]\n /**\n * ์ปดํฌ๋ํธ type ๋ณ ์ ํจ ์์ฑ ์คํด.\n * LLM ์ด ์ ํํ ์ปดํฌ๋ํธ ์์ฑ์ ํ๋๋ก type ์ description, group, default model ํค ์ ๋ฌ.\n *\n * ์:\n * [{ type: 'rect', description: 'Rectangle', group: 'shape',\n * properties: { fillStyle: '#fff', strokeStyle: '#000' } }, ...]\n */\n componentSchemas?: ComponentSchema[]\n /**\n * ์ฌ์ฉ์๊ฐ ๋ชจ๋ธ๋ฌ์์ ํ์ฌ ์ ํํ ์ปดํฌ๋ํธ์ `refid` ๋ชฉ๋ก.\n *\n * refid ๋ things-scene ์ด ๋ชจ๋ ์ปดํฌ๋ํธ์ ์๋ ๋ฐ๊ธํ๋ universal numeric handle.\n * id (๋ฐ์ดํฐ ๋ฐ์ธ๋ฉ ์ด๋ฆ, unique ์๋) ์๋ ๋ค๋ฅธ ๊ฐ๋
โ ์ ํ์ ํญ์ refid ๋ก ํํ.\n */\n selectedRefids?: number[]\n /**\n * popup ์์ ์ฌ์ฉ์๊ฐ ๋ช
์ ์ ํํ #mention ๋งคํ โ {token, refid}.\n * server ๊ฐ mention ํด์ ์ ์ด ๋งคํ์ ์ฐ์ ์ฌ์ฉ. ๋ณธ๋ฌธ์ #token ๋ง ๋จ๊ณ \n * refid ๋ ์ฌ์ฉ์์๊ฒ ๋
ธ์ถ๋์ง ์์ (LLM mention map ์๋ง ์ฒจ๋ถ).\n */\n mentionPicks?: Array<{ token: string; refid: number }>\n /** LLM ๋ชจ๋ธ override */\n model?: string\n /** LLM ์ต์
*/\n temperature?: number\n maxTokens?: number\n /**\n * Tool ์นดํ
๊ณ ๋ฆฌ (read/external) builder ๊ฐ ์ฌ์ฉํ ์ปจํ
์คํธ.\n *\n * board-ai ์์ฒด๋ ResolverContext / typeorm ์ ์ง์ ์์ง ์์ง๋ง, ์ธ๋ถ ๋๋ฉ์ธ ํจํค์ง๊ฐ\n * ๋ฑ๋กํ tool (์: board-import ์ importBoardAsync) ์ server-side ์์กด์ฑ (๋๋ฉ์ธ,\n * ์ฌ์ฉ์, ํธ๋์ญ์
) ์ด ํ์ํ ์ ์๋ค. board-ai-resolver ๊ฐ ResolverContext.state ๋ฑ์\n * ์ด ํ๋๋ก ์ ๋ฌํ๋ฉด, dispatch ์ closure ๋ก builder ์ ctx.state ์ ์ฃผ์
.\n *\n * ๋ฏธ์ง์ ์ด๋ฉด ์ธ๋ถ builder ๋ ctx.state === undefined โ ๋น ์๋ต์ด๋ ์๋ฌ๋ฅผ ๋ฐํํ ์ฑ
์.\n */\n toolCallContext?: any\n}\n\nexport interface ComponentSchema {\n type: string\n description?: string\n group?: string\n /**\n * ์ขํ/ํฌ๊ธฐ/๊ฒฝ๋ก ๊ด๋ จ ํค๋ค โ type ๋ง๋ค ๋ค๋ฆ.\n * ์) ['left', 'top', 'width', 'height'] vs ['cx', 'cy', 'radius'] vs ['points']\n * LLM ์ด type ๋ณ ์ ํํ ์ขํ ํค๋ฅผ ์ฌ์ฉํ๋๋ก ๋ช
์.\n */\n geometryKeys?: string[]\n /**\n * ์ขํ ์ธ type ํนํ ์์ฑ (style, value, min/max ๋ฑ).\n * default ๊ฐ ๋๋ keys ๋ง โ LLM ์ token ์ ๊ฐ์ ์ํด ํธ์ถ์๊ฐ ์ ์ ํ ์์ถ.\n */\n properties?: Record<string, any>\n}\n\n/**\n * AI ๊ฐ ์๋ต์ ๋ง๋๋ ๋์ ํธ์ถํ ๋๊ตฌ์ ์๊ฐ์ trace.\n *\n * UX ๋ชฉ์ โ ์ฌ์ฉ์๊ฐ \"์ ์ด๋ ๊ฒ ๋ตํ์ง\" ์๋ฌธ ๊ฐ์ง ๋ fold-able ๋ฐ์ค์์ ํ์ธ.\n * ๋๋ฒ๊ทธ์ฉ + ์ ๋ขฐ๋ ํฅ์.\n */\nexport interface ToolUsage {\n /** ๋๊ตฌ ์ด๋ฆ (์: 'getSelection', 'modifyBoard', 'addComponent') */\n name: string\n /** ํธ์ถ ์ธ์ JSON */\n arguments: any\n /** ๋๊ตฌ ๊ฒฐ๊ณผ โ read tool ์ ์ค์ ๊ฐ (truncated ๊ฐ๋ฅ), write tool ์ queued ๋ง์ปค */\n result: any\n /** read tool / write tool ๋ถ๋ฅ */\n kind: 'read' | 'write' | 'unknown'\n}\n\nexport interface ChatResponse {\n /** ์ฌ์ฉ์์๊ฒ ๋ณด์ฌ์ค ํ
์คํธ ์๋ต */\n reply: string\n /** ๋ณด๋ ๋ณ๊ฒฝ์ด ์์ผ๋ฉด patch */\n patch?: BoardEditPatch\n /**\n * Scene ์กฐ์ action (ephemeral โ ๋ชจ๋ธ ๋ณ๊ฒฝ ์์ / undo ์ํฅ ์์).\n * ์๊ฐ์ ์ํ์ค๋ก ํธ์คํธ๊ฐ things-scene API ์ง์ ์คํ.\n */\n actions?: BoardActionOp[]\n /** ๋ชจํธํ ์
๋ ฅ ์ ๋ช
ํํ ์ง๋ฌธ (patch ์์) */\n followUp?: string\n /** AI ๊ฐ ์๋ต ๋ง๋๋ ๊ณผ์ ์์ ํธ์ถํ ๋๊ตฌ๋ค (์๊ฐ์). UI fold-able ๋ฐ์ค์ฉ. */\n toolUsages?: ToolUsage[]\n /**\n * ์ ์ง ๊ฒฝ๊ณ โ ๋ต์ด ์ธ๊ธํ์ผ๋ ๋ชจ๋ธ์ด ๋ฐ์ ๊ทผ๊ฑฐ(ํ๋กฌํํธยท๋ณด๋ ๋ฌธ๋งฅยท์ด๋ ฅยท๋๊ตฌ ๊ฒฐ๊ณผ)์ ์๋ ์๋ณ์.\n *\n * ์์ผ๋ฉด ๊ทธ ๋์์ **๋ง๋ค์ด ๋ธ ๊ฒ์ผ ์ ์๋ค**. ๋ต์ ๋ง๊ฑฐ๋ ๊ณ ์น์ง ์๊ณ ์ฌ์ฉ์์๊ฒ ํ์ํ๋ค โ\n * ํ์ ๊ท์นยท์ฌ์ ๊ฑฐ๋ฆฌ๋ ./grounding ์ฐธ์กฐ. ๋น๋ฉด(undefined) ์ ์ง ์ ์.\n */\n groundingWarnings?: string[]\n}\n\nexport interface BoardEditPatch {\n ops: BoardEditOp[]\n /** ์ฌ์ฉ์ ๊ฒ์์ฉ 1-2 ๋ฌธ์ฅ ์์ฝ */\n summary: string\n /** 0..1 ์ ๋ขฐ๋ */\n confidence: number\n}\n\n/**\n * ๋ณด๋ ๋ณ๊ฒฝ op.\n *\n * ์๋ณ์ ์ ์ฑ
โ ๊ธฐ์กด ์ปดํฌ๋ํธ ํ๊นํ
์ `refid` (number) ๋ง ์ฌ์ฉ.\n * things-scene ์ ๋ชจ๋ ์ปดํฌ๋ํธ๋ `refid` ๋ฅผ ์๋ ๋ฐ๊ธ๋ฐ๋๋ค (universal).\n * `model.id` ๋ optional metadata ์ผ ๋ฟ โ ํญ์ ์กด์ฌํ์ง ์์ผ๋ฏ๋ก targeting ์๋\n * ๋ถ์ ํฉ. ๋ณ๊ฐ ๊ฐ๋
์ด๋ฏ๋ก BoardEditOp / tool ์ธ์์์๋ ๋ณ๊ฐ ์๋ณ์๋ก ๋ถ๋ฆฌํ์ง\n * ์๊ณ refid ๋จ์ผ ์ฑ๋๋ก ์ผ์ํ.\n *\n * ๊ณ์ธต โ ๋ณด๋๋ **์ต์์ ๋ถ๋ชจ** (things-scene ์ model-layer) ์ด๊ณ ๊ทธ ์์ฒด๋ก ์๊ธฐ\n * ์์ฑ์ ๊ฐ๋๋ค (fillStyle, width, height, fitMode, translate, scale, sky, skyColor,\n * exposure, hemi/dirLight ๊ณ์ด, camera ๊ณ์ด). ์์ ์ปดํฌ๋ํธ์ ๋ณ๊ฐ. ๋ณด๋ ์์ฑ ๋ณ๊ฒฝ์\n * `modifyBoard`, ์์ ๋ณ๊ฒฝ์ `modify` (refid ๊ธฐ๋ฐ).\n *\n * ์ฃผ์ โ `name` ์ ๋ณด๋ *์ํฐํฐ* (DB row) ์ ์ปฌ๋ผ์ด์ง scene MODEL ์ ํ๋๊ฐ ์๋๋ค.\n * things-scene ์ model-layer ๊ฐ ์ธ์ ์ ํจ. modifyBoard ๋ก name ์ ๋ณด๋ด๋ฉด model\n * JSON ์ ์ฃฝ์ ํ๋๋ก ๋ฐํ ๋ฟ ๋ ๋๋ง/๋์์ ์ํฅ ์์. ๋ณด๋ ๋ผ๋ฒจ ๋ณ๊ฒฝ์ GraphQL\n * boardPatch (BoardPatch input ์ name ํ๋) ์์ญ.\n *\n * style ๋ณ๊ฒฝ / ์ด๋ / ํฌ๊ธฐ ๋ณ๊ฒฝ ๋ฑ ์์ ์ปดํฌ๋ํธ์ ๋ณ๊ฒฝ์ ๋ชจ๋ `modify.patch` ์์\n * ํก์. ๋ณด๋ root ์์ฑ ๋ณ๊ฒฝ์ `modifyBoard.patch` ๋ก.\n */\n/**\n * Phase 2 โ Scene ์กฐ์ op ๋ค. ๋ชจ๋ธ ์ฐจ์ (์ขํ / ๋ถ๋ชจ-์์ ๊ด๊ณ / z-order) ๋ณ๊ฒฝ์ด์ง๋ง\n * things-scene ์ ์์ฒด API (align/distribute/group/ungroup/zorder) ๊ฐ ์ผ๊ด๋ ๊ฒฐ๊ณผ๋ฅผ\n * ๋ณด์ฅํ๋ฏ๋ก ํธ์คํธ๊ฐ ์ง์ ํธ์ถ. ๋ชจ๋ธ ์ฐจ์ ์๋ฎฌ๋ ์ด์
(apply-patch) ์ ๋จ์ํ โ\n * scene ํธ์ถ ๊ฒฐ๊ณผ๊ฐ ์ ๋ณธ.\n */\nexport type AlignDirection =\n | 'left'\n | 'right'\n | 'center'\n | 'top'\n | 'middle'\n | 'bottom'\n\nexport type DistributeAxis = 'horizontal' | 'vertical'\n\nexport type ZorderDirection = 'front' | 'back' | 'forward' | 'backward'\n\n/**\n * Sugar layout โ `arrange` op ์ layout ์ข
๋ฅ.\n *\n * ์๋: align/distribute ์์ ์น๋ high-level ์๋ ํํ. AI ๊ฐ \"3x2 ๊ทธ๋ฆฌ๋๋ก\",\n * \"ํ ์ค๋ก\", \"์ธ๋ก๋ก ์ผ๋ ฌ\" ๊ฐ์ ์์ฐ์ด๋ฅผ ํฝ์
๋
ธ๊ฐ๋ค ์์ด ๋จ์ผ op ๋ก ํํ.\n *\n * left/top ๋ง ๋ณ๊ฒฝ โ width/height ๋ ์ ์ง. AI ๊ฐ ์ฌ์ด์ฆ๋ ๋ฐ๊พธ๋ ค๋ฉด ๋ณ๋ modify.\n *\n * ์์น ๊ณ์ฐ์ ํธ์คํธ (things-scene ์ธก) ๊ฐ ๋ด๋น โ ๊ฐ ์ปดํฌ๋ํธ์ ํ์ฌ width/height ๋ฅผ\n * ์ ํํ ์์์ผ ํ๋ฏ๋ก model ์ฐจ์ ์๋ฎฌ๋ ์ด์
์ SCENE_ONLY (apply-patch noop).\n */\nexport type ArrangeLayout =\n | { type: 'grid'; cols: number; gap?: number; anchor?: { left: number; top: number } }\n | {\n type: 'row'\n gap?: number\n anchor?: { left: number; top: number }\n align?: 'start' | 'center' | 'end'\n }\n | {\n type: 'column'\n gap?: number\n anchor?: { left: number; top: number }\n align?: 'start' | 'center' | 'end'\n }\n\n/**\n * C-1 โ Scene ์กฐ์ action ๋ค (ephemeral). ๋ชจ๋ธ ๋ณ๊ฒฝ X, ๋ฐ๋ผ์ BoardEditOp ์ ๋ณ๊ฐ\n * ์ฑ๋ (board-action-execute ์ด๋ฒคํธ). undo ํ์คํ ๋ฆฌ ๋ฏธ์ํฅ, dirty flag ๋ฏธ์ํฅ.\n *\n * ์ข
๋ฅ:\n * - selectComponents: scene.selected ์ง์ set (์ฌ์ฉ์ ์ ํ ๋ณ๊ฒฝ)\n * - centerToComponent: ํน์ ์ปดํฌ๋ํธ๋ก view ์ด๋\n * - fitToView: ๋ณด๋ ์ ์ฒด๊ฐ ๋ณด์ด๋๋ก fit\n * - setSceneMode: edit / view ๋ชจ๋ ์ ํ\n */\nexport type BoardActionOp =\n | { action: 'selectComponents'; refids: number[] }\n | { action: 'centerToComponent'; refid: number; animated?: boolean }\n | { action: 'fitToView'; mode?: 'fit' | 'ratio' | 'width' | 'height' }\n | { action: 'setSceneMode'; mode: 'edit' | 'view' }\n /** ๋ค์ค ์ปดํฌ๋ํธ outline highlight โ search/finder UX ์ \"์ด๊ฒ ๋ชจ๋ ๋งค์นญ์ด๋ค\" ์๊ฐํ.\n * things-scene ์ highlightSearchResults API ์์ (2D/3D ๋ชจ๋ ์ง์). */\n | { action: 'highlightComponents'; refids: number[] }\n\nexport type BoardEditOp =\n | { op: 'add'; component: BoardComponent }\n | { op: 'remove'; refid: number }\n | { op: 'modify'; refid: number; patch: Partial<BoardComponent> }\n | { op: 'modifyBoard'; patch: Partial<BoardModel> }\n | { op: 'replace'; board: BoardModel }\n | { op: 'align'; refids: number[]; direction: AlignDirection }\n | { op: 'distribute'; refids: number[]; axis: DistributeAxis }\n | { op: 'group'; refids: number[] }\n | { op: 'ungroup'; refid: number }\n | { op: 'zorder'; refid: number; direction: ZorderDirection }\n | { op: 'arrange'; refids: number[]; layout: ArrangeLayout }\n\n/**\n * BoardAIAssistant โ ์์ฐ์ด ์ฑํ
์ผ๋ก ๋ณด๋๋ฅผ ๋ค๋ฃจ๋ ๋จ์ผ ์ธํฐํ์ด์ค.\n *\n * ์ฌ์ฉ:\n * const ai = new DefaultBoardAIAssistant(baseClient, { scopes: ['fmsim'] })\n * const r = await ai.chat([{ role: 'user', content: 'AGV 3๋ ์ถ๊ฐ' }], currentBoard)\n * if (r.patch) currentBoard = applyBoardEditPatch(currentBoard, r.patch)\n */\nexport interface BoardAIAssistant {\n readonly id: string\n chat(\n messages: LLMMessage[],\n currentBoard: BoardModel | undefined,\n options?: ChatOptions\n ): Promise<ChatResponse>\n}\n"]}
|