@things-factory/board-ai 10.1.5 → 10.1.6

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.
Files changed (199) hide show
  1. package/client/components/default-catalog-entries.ts +1 -1
  2. package/client/components/default-slash-templates.ts +1 -1
  3. package/client/index.ts +27 -6
  4. package/dist-client/client/components/default-catalog-entries.d.ts +1 -1
  5. package/dist-client/client/components/default-catalog-entries.js.map +1 -1
  6. package/dist-client/client/components/default-slash-templates.d.ts +1 -1
  7. package/dist-client/client/components/default-slash-templates.js.map +1 -1
  8. package/dist-client/client/index.d.ts +3 -11
  9. package/dist-client/client/index.js +25 -6
  10. package/dist-client/client/index.js.map +1 -1
  11. package/dist-client/server/service/assistant.d.ts +22 -22
  12. package/dist-client/server/service/assistant.js +32 -70
  13. package/dist-client/server/service/assistant.js.map +1 -1
  14. package/dist-client/server/service/grounding.d.ts +2 -12
  15. package/dist-client/server/service/grounding.js +15 -23
  16. package/dist-client/server/service/grounding.js.map +1 -1
  17. package/dist-client/server/service/types.d.ts +2 -4
  18. package/dist-client/server/service/types.js.map +1 -1
  19. package/dist-client/server/service/validation/board-model-schema.d.ts +270 -270
  20. package/dist-client/tsconfig.tsbuildinfo +1 -1
  21. package/dist-server/service/assistant.d.ts +22 -22
  22. package/dist-server/service/assistant.js +25 -76
  23. package/dist-server/service/assistant.js.map +1 -1
  24. package/dist-server/service/board-ai-resolver.js +41 -30
  25. package/dist-server/service/board-ai-resolver.js.map +1 -1
  26. package/dist-server/service/board-session-resolver.d.ts +12 -0
  27. package/dist-server/service/board-session-resolver.js +203 -0
  28. package/dist-server/service/board-session-resolver.js.map +1 -0
  29. package/dist-server/service/board-tool-rights.d.ts +7 -0
  30. package/dist-server/service/board-tool-rights.js +62 -0
  31. package/dist-server/service/board-tool-rights.js.map +1 -0
  32. package/dist-server/service/grounding.d.ts +2 -12
  33. package/dist-server/service/grounding.js +16 -24
  34. package/dist-server/service/grounding.js.map +1 -1
  35. package/dist-server/service/index.d.ts +4 -10
  36. package/dist-server/service/index.js +16 -23
  37. package/dist-server/service/index.js.map +1 -1
  38. package/dist-server/service/patch-entry/board-patch-subscription.js +2 -2
  39. package/dist-server/service/patch-entry/board-patch-subscription.js.map +1 -1
  40. package/dist-server/service/patch-entry/patch-entry.d.ts +1 -1
  41. package/dist-server/service/patch-entry/patch-entry.js +3 -3
  42. package/dist-server/service/patch-entry/patch-entry.js.map +1 -1
  43. package/dist-server/service/types.d.ts +2 -4
  44. package/dist-server/service/types.js.map +1 -1
  45. package/dist-server/tsconfig.tsbuildinfo +1 -1
  46. package/package.json +6 -5
  47. package/server/service/apply-patch-drift.test.ts +3 -1
  48. package/server/service/assistant.ts +47 -73
  49. package/server/service/board-ai-resolver.ts +22 -12
  50. package/server/service/board-session-resolver.ts +183 -0
  51. package/server/service/board-tool-rights.test.ts +96 -0
  52. package/server/service/board-tool-rights.ts +73 -0
  53. package/server/service/dock-contract.test.ts +3 -0
  54. package/server/service/grounding.test.ts +3 -3
  55. package/server/service/grounding.ts +15 -34
  56. package/server/service/index.ts +16 -22
  57. package/server/service/patch-entry/board-patch-subscription.ts +1 -1
  58. package/server/service/patch-entry/patch-entry.ts +3 -2
  59. package/server/service/registry-tool-loop.test.ts +1 -0
  60. package/server/service/tool-exposure.test.ts +2 -0
  61. package/server/service/types.ts +3 -4
  62. package/client/components/board-ai-chat.test.ts +0 -149
  63. package/client/components/board-ai-chat.ts +0 -3184
  64. package/client/components/chat-echo-dedup.test.ts +0 -230
  65. package/client/components/chat-echo-dedup.ts +0 -155
  66. package/client/components/chat-input-builder.ts +0 -69
  67. package/client/components/markdown.test.ts +0 -518
  68. package/client/components/markdown.ts +0 -508
  69. package/client/components/mention-popup-helpers.ts +0 -433
  70. package/client/components/mention-popup.test.ts +0 -588
  71. package/client/components/mention-popup.ts +0 -238
  72. package/client/utils/board-edit-patch.ts +0 -374
  73. package/dist-client/client/components/board-ai-chat.d.ts +0 -384
  74. package/dist-client/client/components/board-ai-chat.js +0 -3008
  75. package/dist-client/client/components/board-ai-chat.js.map +0 -1
  76. package/dist-client/client/components/board-ai-chat.test.d.ts +0 -1
  77. package/dist-client/client/components/board-ai-chat.test.js +0 -138
  78. package/dist-client/client/components/board-ai-chat.test.js.map +0 -1
  79. package/dist-client/client/components/chat-echo-dedup.d.ts +0 -54
  80. package/dist-client/client/components/chat-echo-dedup.js +0 -115
  81. package/dist-client/client/components/chat-echo-dedup.js.map +0 -1
  82. package/dist-client/client/components/chat-echo-dedup.test.d.ts +0 -1
  83. package/dist-client/client/components/chat-echo-dedup.test.js +0 -203
  84. package/dist-client/client/components/chat-echo-dedup.test.js.map +0 -1
  85. package/dist-client/client/components/chat-input-builder.d.ts +0 -55
  86. package/dist-client/client/components/chat-input-builder.js +0 -32
  87. package/dist-client/client/components/chat-input-builder.js.map +0 -1
  88. package/dist-client/client/components/markdown.d.ts +0 -60
  89. package/dist-client/client/components/markdown.js +0 -422
  90. package/dist-client/client/components/markdown.js.map +0 -1
  91. package/dist-client/client/components/markdown.test.d.ts +0 -1
  92. package/dist-client/client/components/markdown.test.js +0 -418
  93. package/dist-client/client/components/markdown.test.js.map +0 -1
  94. package/dist-client/client/components/mention-popup-helpers.d.ts +0 -165
  95. package/dist-client/client/components/mention-popup-helpers.js +0 -330
  96. package/dist-client/client/components/mention-popup-helpers.js.map +0 -1
  97. package/dist-client/client/components/mention-popup.d.ts +0 -35
  98. package/dist-client/client/components/mention-popup.js +0 -223
  99. package/dist-client/client/components/mention-popup.js.map +0 -1
  100. package/dist-client/client/components/mention-popup.test.d.ts +0 -1
  101. package/dist-client/client/components/mention-popup.test.js +0 -474
  102. package/dist-client/client/components/mention-popup.test.js.map +0 -1
  103. package/dist-client/client/utils/board-edit-patch.d.ts +0 -157
  104. package/dist-client/client/utils/board-edit-patch.js +0 -284
  105. package/dist-client/client/utils/board-edit-patch.js.map +0 -1
  106. package/dist-server/service/chat-message/chat-message-broadcast.d.ts +0 -13
  107. package/dist-server/service/chat-message/chat-message-broadcast.js +0 -13
  108. package/dist-server/service/chat-message/chat-message-broadcast.js.map +0 -1
  109. package/dist-server/service/chat-message/chat-message-publish.d.ts +0 -6
  110. package/dist-server/service/chat-message/chat-message-publish.js +0 -27
  111. package/dist-server/service/chat-message/chat-message-publish.js.map +0 -1
  112. package/dist-server/service/chat-message/chat-message-subscription.d.ts +0 -8
  113. package/dist-server/service/chat-message/chat-message-subscription.js +0 -53
  114. package/dist-server/service/chat-message/chat-message-subscription.js.map +0 -1
  115. package/dist-server/service/chat-message/chat-message.d.ts +0 -68
  116. package/dist-server/service/chat-message/chat-message.js +0 -172
  117. package/dist-server/service/chat-message/chat-message.js.map +0 -1
  118. package/dist-server/service/chat-message/fold-history.d.ts +0 -43
  119. package/dist-server/service/chat-message/fold-history.js +0 -33
  120. package/dist-server/service/chat-message/fold-history.js.map +0 -1
  121. package/dist-server/service/chat-message/history-summary.d.ts +0 -43
  122. package/dist-server/service/chat-message/history-summary.js +0 -77
  123. package/dist-server/service/chat-message/history-summary.js.map +0 -1
  124. package/dist-server/service/chat-message/index.d.ts +0 -5
  125. package/dist-server/service/chat-message/index.js +0 -12
  126. package/dist-server/service/chat-message/index.js.map +0 -1
  127. package/dist-server/service/chat-message/llm-history.d.ts +0 -46
  128. package/dist-server/service/chat-message/llm-history.js +0 -87
  129. package/dist-server/service/chat-message/llm-history.js.map +0 -1
  130. package/dist-server/service/chat-session/chat-session.d.ts +0 -62
  131. package/dist-server/service/chat-session/chat-session.js +0 -164
  132. package/dist-server/service/chat-session/chat-session.js.map +0 -1
  133. package/dist-server/service/chat-session/index.d.ts +0 -3
  134. package/dist-server/service/chat-session/index.js +0 -7
  135. package/dist-server/service/chat-session/index.js.map +0 -1
  136. package/dist-server/service/chat-session/session-activity-broadcast.d.ts +0 -30
  137. package/dist-server/service/chat-session/session-activity-broadcast.js +0 -34
  138. package/dist-server/service/chat-session/session-activity-broadcast.js.map +0 -1
  139. package/dist-server/service/chat-session/session-activity-publish.d.ts +0 -12
  140. package/dist-server/service/chat-session/session-activity-publish.js +0 -37
  141. package/dist-server/service/chat-session/session-activity-publish.js.map +0 -1
  142. package/dist-server/service/chat-session/session-activity-subscription.d.ts +0 -14
  143. package/dist-server/service/chat-session/session-activity-subscription.js +0 -87
  144. package/dist-server/service/chat-session/session-activity-subscription.js.map +0 -1
  145. package/dist-server/service/chat-session/session-anchor.d.ts +0 -12
  146. package/dist-server/service/chat-session/session-anchor.js +0 -20
  147. package/dist-server/service/chat-session/session-anchor.js.map +0 -1
  148. package/dist-server/service/chat-session/session-inbox.d.ts +0 -80
  149. package/dist-server/service/chat-session/session-inbox.js +0 -133
  150. package/dist-server/service/chat-session/session-inbox.js.map +0 -1
  151. package/dist-server/service/chat-session-participant/chat-session-participant.d.ts +0 -49
  152. package/dist-server/service/chat-session-participant/chat-session-participant.js +0 -141
  153. package/dist-server/service/chat-session-participant/chat-session-participant.js.map +0 -1
  154. package/dist-server/service/chat-session-participant/index.d.ts +0 -4
  155. package/dist-server/service/chat-session-participant/index.js +0 -10
  156. package/dist-server/service/chat-session-participant/index.js.map +0 -1
  157. package/dist-server/service/chat-session-participant/invite-notification.d.ts +0 -27
  158. package/dist-server/service/chat-session-participant/invite-notification.js +0 -30
  159. package/dist-server/service/chat-session-participant/invite-notification.js.map +0 -1
  160. package/dist-server/service/chat-session-participant/presence.d.ts +0 -4
  161. package/dist-server/service/chat-session-participant/presence.js +0 -22
  162. package/dist-server/service/chat-session-participant/presence.js.map +0 -1
  163. package/dist-server/service/chat-session-resolver.d.ts +0 -102
  164. package/dist-server/service/chat-session-resolver.js +0 -856
  165. package/dist-server/service/chat-session-resolver.js.map +0 -1
  166. package/dist-server/service/subscribe-auth.d.ts +0 -14
  167. package/dist-server/service/subscribe-auth.js +0 -33
  168. package/dist-server/service/subscribe-auth.js.map +0 -1
  169. package/server/service/chat-message/chat-message-broadcast.integration.test.ts +0 -73
  170. package/server/service/chat-message/chat-message-broadcast.test.ts +0 -40
  171. package/server/service/chat-message/chat-message-broadcast.ts +0 -27
  172. package/server/service/chat-message/chat-message-publish.ts +0 -22
  173. package/server/service/chat-message/chat-message-subscription.ts +0 -41
  174. package/server/service/chat-message/chat-message.ts +0 -195
  175. package/server/service/chat-message/fold-history.test.ts +0 -98
  176. package/server/service/chat-message/fold-history.ts +0 -77
  177. package/server/service/chat-message/history-summary.test.ts +0 -127
  178. package/server/service/chat-message/history-summary.ts +0 -100
  179. package/server/service/chat-message/index.ts +0 -12
  180. package/server/service/chat-message/llm-history.test.ts +0 -194
  181. package/server/service/chat-message/llm-history.ts +0 -163
  182. package/server/service/chat-session/chat-session.ts +0 -182
  183. package/server/service/chat-session/index.ts +0 -5
  184. package/server/service/chat-session/session-activity-broadcast.ts +0 -57
  185. package/server/service/chat-session/session-activity-publish.ts +0 -44
  186. package/server/service/chat-session/session-activity-subscription.ts +0 -67
  187. package/server/service/chat-session/session-anchor.ts +0 -35
  188. package/server/service/chat-session/session-inbox.test.ts +0 -185
  189. package/server/service/chat-session/session-inbox.ts +0 -161
  190. package/server/service/chat-session-participant/chat-session-participant.ts +0 -135
  191. package/server/service/chat-session-participant/index.ts +0 -6
  192. package/server/service/chat-session-participant/invite-notification.test.ts +0 -30
  193. package/server/service/chat-session-participant/invite-notification.ts +0 -48
  194. package/server/service/chat-session-participant/presence.test.ts +0 -39
  195. package/server/service/chat-session-participant/presence.ts +0 -21
  196. package/server/service/chat-session-resolver.ts +0 -779
  197. package/server/service/session-anchor.test.ts +0 -65
  198. package/server/service/subscribe-auth.test.ts +0 -57
  199. package/server/service/subscribe-auth.ts +0 -34
@@ -1,47 +1,28 @@
1
1
  /*
2
2
  * 접지 검사 — 이 대화면의 답이 **모델이 실제로 받은 것** 안에서 말했는지.
3
3
  *
4
- * ── 왜 board-ai 에 필요한가 ─────────────────────────────────────────────────
5
- * 협의 도크(operato-twin)는 board-ai 위에 서 있고, 여기서 사람들이 운영 상태를 묻는다.
6
- * 헤더 경로(twin-ai)에는 접지 가드가 있었지만 도크 경로에는 없었다 — 같은 질문에 대해
7
- * 한쪽은 검증되고 한쪽은 검증되지 않는 상태였다. 판정 규칙은 공용 모듈이 소유하고
8
- * (`@things-factory/ai-client-base` 의 grounding), 이 파일은 **무엇을 근거로 볼 것인가**만 정한다.
4
+ * ── 이 파일에 무엇이 남았나 (2026-09-10) ────────────────────────────────────
5
+ * 판정 규칙은 처음부터 `@things-factory/ai-client-base` 에 있었고, **근거집합의 모양**은 여기
6
+ * 있었다. 그래서 보드가 없는 제품은 규칙만 있고 쓸 길이 없었다 — 접지 검사를 하려면 보드
7
+ * 편집기를 지나야 했다. 자리는 있고 길이 없는 쪽이다.
9
8
  *
10
- * ── 근거집합의 정의 ─────────────────────────────────────────────────────────
11
- * 모델이 이 턴에 받은 전부다. 하나라도 빼면 정상 답이 경고를 받는다(오탐):
12
- * · systemPrompt — 생성 가능한 컴포넌트 타입 목록 등. 여기 있는 이름을 말하는 건 정상이다.
13
- * · boardContext — 현재 보드 요약(컴포넌트 id·이름). 보드를 두고 말하는 근거.
14
- * · messages — 사용자·이력 텍스트. 사용자가 말한 식별자를 되받는 건 정상이다.
15
- * · toolResults — 도구가 돌려준 원문(압축 전). 운영 상태 답의 유일한 사실 근거.
9
+ * 그 모양(`GroundingSources` · `buildGroundedCorpus`)을 공용 패키지로 옮겼다. 칸 하나가
10
+ * 바뀌었다: `boardContext` → `hostContext`. 근거는 보드일 수도, 공장 현황일 수도, 저작 중인
11
+ * 자산일 수도 있고, 그것을 아는 것은 호스트뿐이다.
12
+ *
13
+ * **베끼지 않고 옮겼다** — 같은 글이 두 곳에 있으면 한쪽만 고쳐진다. 여기 남은 것은 이 패키지의
14
+ * 소비처(9개 앱이 이 패키지를 지난다)가 이름을 그대로 쓰게 하는 재수출 하나다.
16
15
  *
17
16
  * ── 사정거리 ────────────────────────────────────────────────────────────────
18
17
  * 식별자만 본다. "지게차들이 바쁘게 움직인다" 처럼 **식별자 없이 지어낸 서술**은 잡지 못한다 —
19
18
  * 그건 도구를 부르지 않고 답한 경우이고, 도구 호출을 강제하는 별도 레버의 몫이다.
19
+ *
20
+ * 그리고 식별자 관례가 **소문자**다(`ID_TOKEN`). 대문자 식별자를 쓰는 제품(plant 의 `WO-…`,
21
+ * 트윈의 `TAG-FUNC-…`)에는 이 가드가 닿지 않는다 — 공용 패키지 쪽 판단이 필요한 별 건이다.
20
22
  */
21
- import { groundingWarnings } from '@things-factory/ai-client-base'
23
+ import { buildGroundedCorpus, groundingWarnings, type GroundingSources } from '@things-factory/ai-client-base'
22
24
 
23
- export interface GroundingSources {
24
- /** 시스템 프롬프트(타입 목록·규칙). */
25
- systemPrompt?: string
26
- /** 보드 상태 요약 등 대화 앞에 붙인 문맥. */
27
- boardContext?: string
28
- /** 사용자·어시스턴트 이력 텍스트. */
29
- messages?: string[]
30
- /** tool_result 로 회신된 원문(시간순). */
31
- toolResults?: string[]
32
- }
33
-
34
- /** 근거집합을 한 덩어리 문자열로. (id 토큰 대조만 하므로 구분자는 개행으로 충분하다.) */
35
- export function buildGroundedCorpus(sources: GroundingSources): string {
36
- return [
37
- sources.systemPrompt ?? '',
38
- sources.boardContext ?? '',
39
- ...(sources.messages ?? []),
40
- ...(sources.toolResults ?? [])
41
- ]
42
- .filter(Boolean)
43
- .join('\n')
44
- }
25
+ export { buildGroundedCorpus, type GroundingSources }
45
26
 
46
27
  /**
47
28
  * 답이 근거 밖의 식별자를 지목했으면 그 목록. 비면 접지 정상.
@@ -1,11 +1,17 @@
1
+ /*
2
+ * 대화 기계는 **`@things-factory/ai-assistant` 로 나갔다** (2026-09-10).
3
+ *
4
+ * 세션·메시지·참가자·인박스·구독은 보드가 없는 제품에도 뜻이 있다. 여기 남은 것은 보드 저작이다.
5
+ * 아래 재수출은 이 패키지를 지나는 소비처(아홉 앱)가 이름을 그대로 쓰게 한다 — 베낀 것이 아니라
6
+ * 가리키는 것이다.
7
+ *
8
+ * 자르는 선과 이유는 `things-factory/docs/design/ai-modules.md`.
9
+ */
10
+ export * from '@things-factory/ai-assistant'
11
+
1
12
  import { BoardAIChatResolver } from './board-ai-resolver.js'
2
- import { ChatSessionResolver } from './chat-session-resolver.js'
3
- import { MySessionActivitySubscription } from './chat-session/session-activity-subscription.js'
13
+ import { BoardSessionResolver } from './board-session-resolver.js'
4
14
  import { BoardPatchSubscription } from './patch-entry/board-patch-subscription.js'
5
- import { BoardChatMessageSubscription } from './chat-message/chat-message-subscription.js'
6
- import { entities as ChatSessionEntities } from './chat-session/index.js'
7
- import { entities as ChatMessageEntities } from './chat-message/index.js'
8
- import { entities as ChatSessionParticipantEntities } from './chat-session-participant/index.js'
9
15
  import { entities as PatchEntryEntities } from './patch-entry/index.js'
10
16
 
11
17
  export * from './types.js'
@@ -15,28 +21,16 @@ export * from './prefab-registry.js'
15
21
  export * from './mention-resolver.js'
16
22
  export * from './catalog-resolver.js'
17
23
  export * from './board-ai-resolver.js'
18
- export * from './chat-session-resolver.js'
19
- /* 세션 앵커 순수 로직 — 호스트가 앵커 종류를 참조할 수 있게 공개(리졸버는 데코레이터 때문에 무거움). */
20
- export * from './chat-session/session-anchor.js'
21
- export * from './chat-session/index.js'
22
- export * from './chat-message/index.js'
23
- export * from './chat-session-participant/index.js'
24
24
  export * from './patch-entry/index.js'
25
25
 
26
- export const entities = [
27
- ...ChatSessionEntities,
28
- ...ChatMessageEntities,
29
- ...ChatSessionParticipantEntities,
30
- ...PatchEntryEntities
31
- ]
26
+ /* 세션 계열 엔티티는 `ai-assistant` 가 낸다 — 프레임워크가 의존을 타고 재귀로 모은다. */
27
+ export const entities = [...PatchEntryEntities]
32
28
 
33
29
  export const schema = {
34
30
  resolverClasses: [
35
31
  BoardAIChatResolver,
36
- ChatSessionResolver,
32
+ /* 보드에 매인 op 여섯 — 중립 세션 op 과 갈랐다(2026-09-10). */
33
+ BoardSessionResolver,
37
34
  BoardPatchSubscription,
38
- BoardChatMessageSubscription,
39
- /* 내가 참여한 모든 세션의 활동 — 창을 닫아 둔 표면이 배지·목록을 갱신할 수 있게. */
40
- MySessionActivitySubscription
41
35
  ]
42
36
  }
@@ -12,7 +12,7 @@ import { filter, pipe } from 'graphql-yoga'
12
12
  import { pubsub } from '@things-factory/shell'
13
13
  import { PatchEntry } from './patch-entry.js'
14
14
  import { BOARD_PATCH_TOPIC, boardPatchFilter, type BoardPatchPayload } from './board-patch-broadcast.js'
15
- import { assertDomainSubscribeAllowed } from '../subscribe-auth.js'
15
+ import { assertDomainSubscribeAllowed } from '@things-factory/ai-assistant'
16
16
 
17
17
  export { BOARD_PATCH_TOPIC, boardPatchFilter } from './board-patch-broadcast.js'
18
18
  export type { BoardPatchPayload } from './board-patch-broadcast.js'
@@ -23,7 +23,7 @@ import { GraphQLJSON } from 'graphql-scalars'
23
23
 
24
24
  import { config } from '@things-factory/env'
25
25
 
26
- import { ChatSession } from '../chat-session/chat-session.js'
26
+ import { ChatSession } from '@things-factory/ai-assistant'
27
27
 
28
28
  const ORMCONFIG = config.get('ormconfig', {})
29
29
  const DATABASE_TYPE = ORMCONFIG.type
@@ -36,7 +36,8 @@ export class PatchEntry {
36
36
  @Field(type => ID, { nullable: true })
37
37
  readonly id?: string
38
38
 
39
- @ManyToOne(type => ChatSession, session => session.patches, { onDelete: 'CASCADE' })
39
+ /* 역방향(`ChatSession.patches`)을 두지 않는다 — 세션은 중립이고 보드 패치를 몰라야 한다. */
40
+ @ManyToOne(type => ChatSession, { onDelete: 'CASCADE' })
40
41
  session?: ChatSession
41
42
 
42
43
  @RelationId((patch: PatchEntry) => patch.session)
@@ -62,6 +62,7 @@ function toolResultsSeen(seen: any[][]): any[] {
62
62
  /* 외부 도메인 패키지를 흉내낸 카테고리 — read 는 **async**(DB 조회 대역), write 는 op 생성. */
63
63
  const CATEGORY: ToolCategory = {
64
64
  name: 'test-domain',
65
+ guidance: '- fixture guidance for test-domain',
65
66
  specs: [
66
67
  {
67
68
  kind: 'read',
@@ -27,6 +27,7 @@ import {
27
27
  /* 두 개의 가짜 외부 카테고리 — 하나는 보드 저작 계열, 하나는 운영 계열. */
28
28
  const AUTHORING: ToolCategory = {
29
29
  name: 'test-authoring',
30
+ guidance: '- fixture guidance for test-authoring',
30
31
  specs: [
31
32
  {
32
33
  kind: 'write',
@@ -39,6 +40,7 @@ const AUTHORING: ToolCategory = {
39
40
  }
40
41
  const OPS: ToolCategory = {
41
42
  name: 'test-ops',
43
+ guidance: '- fixture guidance for test-ops',
42
44
  specs: [
43
45
  {
44
46
  kind: 'read',
@@ -9,10 +9,9 @@
9
9
  */
10
10
  import type { BoardComponent, BoardModel } from '@things-factory/board-import'
11
11
 
12
- export interface LLMMessage {
13
- role: 'user' | 'assistant'
14
- content: string
15
- }
12
+ /* 대화 한 줄은 도메인을 모른다 — 정의는 `@things-factory/ai-assistant` 에 있다(2026-09-10). */
13
+ import type { LLMMessage } from '@things-factory/ai-assistant'
14
+ export type { LLMMessage }
16
15
 
17
16
  export interface ChatOptions {
18
17
  /**
@@ -1,149 +0,0 @@
1
- /**
2
- * board-ai-chat.ts 의 pure helper 회귀 방지.
3
- *
4
- * 핵심 보호:
5
- * - GraphQL mutation input 에 selectedRefids 가 항상 포함되는지 — 누락이 사용자
6
- * 보고된 "AI 가 선택된 컴포넌트를 모른다" 의 root cause 였다.
7
- * - 식별자 정책 — refid (universal numeric) 가 selection 채널의 표준. id 는 데이터
8
- * 바인딩 이름이며 unique 가 아니라 selection 에 부적합.
9
- */
10
- import { buildChatMutationInput } from './chat-input-builder'
11
-
12
- describe('buildChatMutationInput — mutation input 회귀 방지', () => {
13
- test('selectedRefids 가 input 에 반드시 포함된다 (root cause regression)', () => {
14
- const input = buildChatMutationInput({
15
- sessionId: 'session-1',
16
- history: [{ role: 'user', content: 'hi' }],
17
- liveBoard: { width: 1000, height: 600, components: [] },
18
- selectedRefids: [35]
19
- })
20
- expect(input).toHaveProperty('selectedRefids', [35])
21
- })
22
-
23
- test('selectedRefids 빈 배열도 누락 없이 포함', () => {
24
- const input = buildChatMutationInput({
25
- history: [],
26
- liveBoard: null,
27
- selectedRefids: []
28
- })
29
- expect(input.selectedRefids).toEqual([])
30
- })
31
-
32
- test('모든 expected 필드 존재', () => {
33
- const input = buildChatMutationInput({
34
- sessionId: 's1',
35
- history: [{ role: 'user', content: 'hi' }],
36
- liveBoard: { components: [] },
37
- scopes: ['fmsim'],
38
- knownTypes: ['rect'],
39
- categories: ['equipment'],
40
- componentSchemas: [{ type: 'rect' }],
41
- selectedRefids: [1, 2]
42
- })
43
- expect(Object.keys(input).sort()).toEqual([
44
- 'categories',
45
- 'componentSchemas',
46
- 'currentBoard',
47
- 'knownTypes',
48
- 'messages',
49
- 'scopes',
50
- 'selectedRefids',
51
- 'sessionId'
52
- ])
53
- })
54
-
55
- test('sessionId 누락 → null 정규화', () => {
56
- const input = buildChatMutationInput({
57
- history: [],
58
- liveBoard: null,
59
- selectedRefids: []
60
- })
61
- expect(input.sessionId).toBeNull()
62
- })
63
-
64
- test('liveBoard 누락 → null 정규화', () => {
65
- const input = buildChatMutationInput({
66
- history: [],
67
- liveBoard: undefined,
68
- selectedRefids: []
69
- })
70
- expect(input.currentBoard).toBeNull()
71
- })
72
-
73
- test('messages 가 history 그대로', () => {
74
- const history = [
75
- { role: 'user' as const, content: 'msg1' },
76
- { role: 'assistant' as const, content: 'reply1' }
77
- ]
78
- const input = buildChatMutationInput({
79
- history,
80
- liveBoard: null,
81
- selectedRefids: []
82
- })
83
- expect(input.messages).toBe(history)
84
- })
85
-
86
- test('liveBoard 가 그대로 currentBoard 로 매핑', () => {
87
- const board = {
88
- width: 1920,
89
- height: 1080,
90
- components: [{ refid: 1, type: 'rect' }]
91
- }
92
- const input = buildChatMutationInput({
93
- history: [],
94
- liveBoard: board,
95
- selectedRefids: []
96
- })
97
- expect(input.currentBoard).toBe(board)
98
- })
99
-
100
- test('scopes / knownTypes / categories 누락 시 undefined', () => {
101
- const input = buildChatMutationInput({
102
- history: [],
103
- liveBoard: null,
104
- selectedRefids: []
105
- })
106
- expect(input.scopes).toBeUndefined()
107
- expect(input.knownTypes).toBeUndefined()
108
- expect(input.categories).toBeUndefined()
109
- expect(input.componentSchemas).toBeUndefined()
110
- })
111
-
112
- test('selectedRefids 다중 항목 (number 배열, stringify 없음)', () => {
113
- const input = buildChatMutationInput({
114
- history: [],
115
- liveBoard: null,
116
- selectedRefids: [35, 127, 4096]
117
- })
118
- expect(input.selectedRefids).toEqual([35, 127, 4096])
119
- })
120
-
121
- test('mentions (popup picks) — 빈 배열은 input 에 안 들어감 (server 부담 X)', () => {
122
- const input = buildChatMutationInput({
123
- history: [],
124
- liveBoard: null,
125
- selectedRefids: [],
126
- mentions: []
127
- })
128
- expect(input.mentions).toBeUndefined()
129
- })
130
-
131
- test('mentions — 항목 있으면 input 에 그대로 통과', () => {
132
- const input = buildChatMutationInput({
133
- history: [{ role: 'user', content: '#경광등1 빨갛게' }],
134
- liveBoard: null,
135
- selectedRefids: [],
136
- mentions: [{ token: '경광등1', refid: 35 }]
137
- })
138
- expect(input.mentions).toEqual([{ token: '경광등1', refid: 35 }])
139
- })
140
-
141
- test('mentions 미지정 시 input 에 키 자체가 없음 (backwards compat)', () => {
142
- const input = buildChatMutationInput({
143
- history: [],
144
- liveBoard: null,
145
- selectedRefids: []
146
- })
147
- expect('mentions' in input).toBe(false)
148
- })
149
- })