@things-factory/board-ai 10.1.7 → 10.1.13

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.
@@ -0,0 +1,15 @@
1
+ {
2
+ "keep": {
3
+ "days": true,
4
+ "amount": 14
5
+ },
6
+ "auditLog": "logs/.5e5d741d8b7784a2fbad65eedc0fd46946aaf6f2-audit.json",
7
+ "files": [
8
+ {
9
+ "date": 1789195002942,
10
+ "name": "logs/connections-2026-09-12-15.log",
11
+ "hash": "cf643fb0881a2a037b9657d9f0cab3f858825cbc597ef955ba6335a9305911c5"
12
+ }
13
+ ],
14
+ "hashType": "sha256"
15
+ }
File without changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@things-factory/board-ai",
3
- "version": "10.1.7",
3
+ "version": "10.1.13",
4
4
  "main": "dist-server/index.js",
5
5
  "browser": "dist-client/client/index.js",
6
6
  "things-factory": true,
@@ -31,10 +31,10 @@
31
31
  "@operato/graphql": "^10.0.0",
32
32
  "@operato/i18n": "^10.0.0",
33
33
  "@operato/styles": "^10.0.0",
34
- "@things-factory/ai-assistant": "^10.1.7",
35
- "@things-factory/ai-client-base": "^10.1.7",
34
+ "@things-factory/ai-assistant": "^10.1.13",
35
+ "@things-factory/ai-client-base": "^10.1.8",
36
36
  "@things-factory/auth-base": "^10.1.7",
37
- "@things-factory/board-import": "^10.1.7",
37
+ "@things-factory/board-import": "^10.1.8",
38
38
  "@things-factory/env": "^10.1.3",
39
39
  "@things-factory/shell": "^10.1.7",
40
40
  "dompurify": "^3.0.0",
@@ -46,5 +46,5 @@
46
46
  "copyfiles": "^2.4.1",
47
47
  "rimraf": "^5.0.0"
48
48
  },
49
- "gitHead": "9a036f83f5751f9e4af9180e9a0018f716a4ba27"
49
+ "gitHead": "f2cd3d27e32e71cca1d3af5499ef54249b1cc111"
50
50
  }
@@ -19,6 +19,7 @@ import {
19
19
  buildBoardEditTools,
20
20
  DefaultBoardAIAssistant
21
21
  } from './assistant'
22
+ import { isGroundedAnalysisContract } from '@things-factory/ai-client-base'
22
23
 
23
24
  describe('toolCallToBoardEditOp', () => {
24
25
  test('addComponent: 정상 인자', () => {
@@ -1845,6 +1846,10 @@ describe('agentic loop (chatViaTools) — mock provider', () => {
1845
1846
  // result 는 summarized 객체
1846
1847
  expect(u.result.count).toBe(1)
1847
1848
  expect(u.result.selected[0].name).toBe('AGV-1')
1849
+ expect(isGroundedAnalysisContract(r.analysis)).toBe(true)
1850
+ expect(r.analysis?.kind).toBe('board.analysis.v1')
1851
+ expect(r.analysis?.approvalRequired).toBe(true)
1852
+ expect(r.analysis?.approval.mode).toBe('confirm')
1848
1853
  })
1849
1854
 
1850
1855
  test('toolUsages 수집 — write tool 은 queued 마커', async () => {
@@ -310,6 +310,22 @@ export class DefaultBoardAIAssistant implements BoardAIAssistant {
310
310
  toolResults: loopResult.groundedTexts
311
311
  })
312
312
 
313
+ const analysis = (toolUsages.length || patch || accumulatedActions.length || loopResult.proposals.length)
314
+ ? {
315
+ kind: 'board.analysis.v1' as const,
316
+ scope: { boardId: (currentBoard as any)?.id },
317
+ window: { turn: messages.length },
318
+ confidence: { level: warnings.length ? 'low' as const : 'medium' as const, reasons: warnings.length ? ['grounding-warning'] : ['tool-or-board-context'] },
319
+ limitations: warnings.map(code => ({ code })),
320
+ claims: [{ code: patch ? 'board.patch-proposed' : 'board.context-reviewed', severity: 'info' as const, evidence: { toolCalls: toolUsages.length, componentCount: components.length }, method: 'board-agentic-loop', assumptions: ['Board context is current for this turn.'] }],
321
+ facts: { board: boardContext, toolUsages },
322
+ ...(patch ? { proposal: patch } : accumulatedActions.length ? { proposal: accumulatedActions } : {}),
323
+ approvalRequired: true as const,
324
+ approval: { required: true as const, mode: 'confirm' as const, reason: patch || accumulatedActions.length ? 'Board or scene change requires user confirmation.' : 'Analysis is advisory.' },
325
+ trace: { source: 'board-ai', generatedAt: new Date().toISOString(), version: '1' }
326
+ }
327
+ : undefined
328
+
313
329
  return {
314
330
  reply,
315
331
  patch,
@@ -318,7 +334,8 @@ export class DefaultBoardAIAssistant implements BoardAIAssistant {
318
334
  actions: accumulatedActions.length > 0 ? accumulatedActions : undefined,
319
335
  /* 제안은 실행 전 상태다 — 대화면이 확인 버튼을 그린다. 서버는 실행하지 않는다. */
320
336
  proposals: loopResult.proposals.length > 0 ? loopResult.proposals : undefined,
321
- groundingWarnings: warnings.length > 0 ? warnings : undefined
337
+ groundingWarnings: warnings.length > 0 ? warnings : undefined,
338
+ analysis
322
339
  }
323
340
  }
324
341
 
@@ -245,6 +245,13 @@ class BoardAIChatOutput {
245
245
  'Ungrounded identifiers mentioned by the reply — present in the answer but absent from everything the model received (prompt, board context, history, tool results). Hallucination candidates surfaced to the user; the reply itself is not altered. Null when the answer is grounded.'
246
246
  })
247
247
  groundingWarnings?: any
248
+
249
+ @Field(() => GraphQLJSON, {
250
+ nullable: true,
251
+ description:
252
+ 'Grounded analysis contract for this turn: scope, evidence-backed claims, limitations, proposal and explicit approval boundary. Null when the turn did not perform an analysis.'
253
+ })
254
+ analysis?: any
248
255
  }
249
256
 
250
257
  @Resolver()
@@ -513,7 +520,8 @@ export class BoardAIChatResolver {
513
520
  actions: r.actions && r.actions.length > 0 ? r.actions : null,
514
521
  proposals: r.proposals && r.proposals.length > 0 ? r.proposals : null,
515
522
  historyFolded: historyFolded ?? null,
516
- groundingWarnings: r.groundingWarnings && r.groundingWarnings.length > 0 ? r.groundingWarnings : null
523
+ groundingWarnings: r.groundingWarnings && r.groundingWarnings.length > 0 ? r.groundingWarnings : null,
524
+ analysis: r.analysis ?? null
517
525
  }
518
526
  }
519
527
 
@@ -117,8 +117,14 @@ export interface ComponentSchema {
117
117
  * import 를 그대로 두기 위해서다 — 뜻의 정본은 저쪽 한 곳이다.
118
118
  */
119
119
  import type { ToolUsage } from '@things-factory/ai-client-base'
120
+ import type { AIAnalysisClaim, GroundedAnalysisContract } from '@things-factory/ai-client-base'
120
121
  export type { ToolUsage }
121
122
 
123
+ /** Board-specific extension of the shared evidence/approval analysis boundary. */
124
+ export interface BoardGroundedAnalysis extends GroundedAnalysisContract<any, AIAnalysisClaim, BoardEditPatch | BoardActionOp[]> {
125
+ kind: 'board.analysis.v1'
126
+ }
127
+
122
128
 
123
129
  export interface ChatResponse {
124
130
  /** 사용자에게 보여줄 텍스트 응답 */
@@ -148,6 +154,8 @@ export interface ChatResponse {
148
154
  * 판정 규칙·사정거리는 ./grounding 참조. 비면(undefined) 접지 정상.
149
155
  */
150
156
  groundingWarnings?: string[]
157
+ /** Present when the turn inspected state or proposed a board/action change. */
158
+ analysis?: BoardGroundedAnalysis
151
159
  }
152
160
 
153
161
  export interface BoardEditPatch {