@things-factory/board-ai 10.1.176 → 10.1.178
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/dist-client/server/service/assistant.d.ts +2 -2
- package/dist-client/server/service/assistant.js +5 -4
- package/dist-client/server/service/assistant.js.map +1 -1
- package/dist-client/tsconfig.tsbuildinfo +1 -1
- package/dist-server/service/assistant.d.ts +2 -2
- package/dist-server/service/assistant.js +4 -3
- package/dist-server/service/assistant.js.map +1 -1
- package/dist-server/tsconfig.tsbuildinfo +1 -1
- package/package.json +7 -7
- package/server/service/assistant.test.ts +23 -38
- package/server/service/assistant.ts +5 -4
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@things-factory/board-ai",
|
|
3
|
-
"version": "10.1.
|
|
3
|
+
"version": "10.1.178",
|
|
4
4
|
"main": "dist-server/index.js",
|
|
5
5
|
"browser": "dist-client/client/index.js",
|
|
6
6
|
"things-factory": true,
|
|
@@ -32,12 +32,12 @@
|
|
|
32
32
|
"@operato/i18n": "^10.0.0",
|
|
33
33
|
"@operato/scene-ops": "^10.14.1",
|
|
34
34
|
"@operato/styles": "^10.0.0",
|
|
35
|
-
"@things-factory/ai-assistant": "^10.1.
|
|
36
|
-
"@things-factory/ai-client-base": "^10.1.
|
|
37
|
-
"@things-factory/auth-base": "^10.1.
|
|
38
|
-
"@things-factory/board-import": "^10.1.
|
|
35
|
+
"@things-factory/ai-assistant": "^10.1.178",
|
|
36
|
+
"@things-factory/ai-client-base": "^10.1.178",
|
|
37
|
+
"@things-factory/auth-base": "^10.1.178",
|
|
38
|
+
"@things-factory/board-import": "^10.1.178",
|
|
39
39
|
"@things-factory/env": "^10.1.149",
|
|
40
|
-
"@things-factory/shell": "^10.1.
|
|
40
|
+
"@things-factory/shell": "^10.1.178",
|
|
41
41
|
"dompurify": "^3.0.0",
|
|
42
42
|
"graphql-tag": "^2.12.6",
|
|
43
43
|
"lit": "^3.1.2",
|
|
@@ -47,5 +47,5 @@
|
|
|
47
47
|
"copyfiles": "^2.4.1",
|
|
48
48
|
"rimraf": "^5.0.0"
|
|
49
49
|
},
|
|
50
|
-
"gitHead": "
|
|
50
|
+
"gitHead": "d57448d3f3045f72a9f24b877a3e306eb34cbaf1"
|
|
51
51
|
}
|
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
isActionTool,
|
|
16
16
|
executeReadTool,
|
|
17
17
|
summarizeBoard,
|
|
18
|
-
|
|
18
|
+
resultShapeOf,
|
|
19
19
|
buildBoardEditTools,
|
|
20
20
|
DefaultBoardAIAssistant
|
|
21
21
|
} from './assistant'
|
|
@@ -1857,9 +1857,9 @@ describe('agentic loop (chatViaTools) — mock provider', () => {
|
|
|
1857
1857
|
expect(u.name).toBe('getSelection')
|
|
1858
1858
|
expect(u.kind).toBe('read')
|
|
1859
1859
|
expect(u.arguments).toEqual({})
|
|
1860
|
-
// result 는
|
|
1861
|
-
expect(u.result.count
|
|
1862
|
-
expect(u.result.
|
|
1860
|
+
// result 는 값이 아니라 모양 — 건수 · 키 이름 (ADR-0061 결정 8)
|
|
1861
|
+
expect(u.result).toMatchObject({ count: 1, keys: expect.arrayContaining(['selected']) })
|
|
1862
|
+
expect(JSON.stringify(u.result)).not.toMatch(/AGV-1/)
|
|
1863
1863
|
expect(isGroundedAnalysisContract(r.analysis)).toBe(true)
|
|
1864
1864
|
expect(r.analysis?.kind).toBe('board.analysis.v1')
|
|
1865
1865
|
expect(r.analysis?.approvalRequired).toBe(true)
|
|
@@ -1885,7 +1885,7 @@ describe('agentic loop (chatViaTools) — mock provider', () => {
|
|
|
1885
1885
|
const u = r.toolUsages![0]
|
|
1886
1886
|
expect(u.name).toBe('addComponent')
|
|
1887
1887
|
expect(u.kind).toBe('write')
|
|
1888
|
-
expect(u.result.
|
|
1888
|
+
expect(u.result.keys).toContain('queued')
|
|
1889
1889
|
})
|
|
1890
1890
|
|
|
1891
1891
|
test('toolUsages 수집 — read + write 혼합 시간순 보존', async () => {
|
|
@@ -1929,7 +1929,7 @@ describe('agentic loop (chatViaTools) — mock provider', () => {
|
|
|
1929
1929
|
const r = await a.chat([{ role: 'user', content: 'x' }], undefined)
|
|
1930
1930
|
expect(r.toolUsages).toHaveLength(1)
|
|
1931
1931
|
expect(r.toolUsages![0].kind).toBe('unknown')
|
|
1932
|
-
expect(r.toolUsages![0].result.
|
|
1932
|
+
expect(r.toolUsages![0].result.errorCode).toMatch(/unknown/i)
|
|
1933
1933
|
})
|
|
1934
1934
|
|
|
1935
1935
|
test('actions 수집 — selectComponents 호출 시 ChatResponse.actions 누적', async () => {
|
|
@@ -2011,43 +2011,28 @@ describe('agentic loop (chatViaTools) — mock provider', () => {
|
|
|
2011
2011
|
})
|
|
2012
2012
|
})
|
|
2013
2013
|
|
|
2014
|
-
describe('
|
|
2015
|
-
test('
|
|
2016
|
-
|
|
2017
|
-
|
|
2018
|
-
expect(
|
|
2019
|
-
expect(
|
|
2014
|
+
describe('resultShapeOf — 대화 행에 남는 결과의 모양 (ADR-0061 결정 8)', () => {
|
|
2015
|
+
test('값이 아니라 크기 · 건수 · 키 이름만 남는다', () => {
|
|
2016
|
+
const pay = { read: 2, rows: [{ name: '김급여', net: 3100000 }, { name: '이급여', net: 2900000 }] }
|
|
2017
|
+
const shape = resultShapeOf(pay)
|
|
2018
|
+
expect(shape).toEqual({ size: JSON.stringify(pay).length, count: 2, keys: ['read', 'rows'] })
|
|
2019
|
+
expect(JSON.stringify(shape)).not.toMatch(/김급여|3100000/)
|
|
2020
2020
|
})
|
|
2021
2021
|
|
|
2022
|
-
test('
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
expect(
|
|
2026
|
-
expect(r.length).toBeLessThan(long.length)
|
|
2022
|
+
test('목록은 건수, 값 하나는 크기만', () => {
|
|
2023
|
+
expect(resultShapeOf([1, 2, 3])).toEqual({ size: 7, count: 3 })
|
|
2024
|
+
expect(resultShapeOf('hello')).toEqual({ size: 7 })
|
|
2025
|
+
expect(resultShapeOf(null)).toEqual({ size: 4 })
|
|
2027
2026
|
})
|
|
2028
2027
|
|
|
2029
|
-
test('
|
|
2030
|
-
|
|
2031
|
-
|
|
2032
|
-
expect(r.length).toBe(6) // 5 + marker
|
|
2033
|
-
expect(r[5]).toMatch(/items\]/)
|
|
2028
|
+
test('거절과 실패는 코드로', () => {
|
|
2029
|
+
expect(resultShapeOf({ rejected: true, error: 'query-failed', message: '김급여 unauthorized' })).toMatchObject({ errorCode: 'query-failed' })
|
|
2030
|
+
expect(JSON.stringify(resultShapeOf({ error: 'tool-failed', message: 'the ledger of 김급여' }))).not.toMatch(/김급여/)
|
|
2034
2031
|
})
|
|
2035
2032
|
|
|
2036
|
-
test('
|
|
2037
|
-
const
|
|
2038
|
-
|
|
2039
|
-
expect(
|
|
2040
|
-
expect(r.b.c).toMatch(/…/)
|
|
2041
|
-
})
|
|
2042
|
-
|
|
2043
|
-
test('depth 3 초과 object 는 키 목록 string 으로 압축', () => {
|
|
2044
|
-
const deep = { l1: { l2: { l3: { l4: { x: 1, y: 2, z: 3 } } } } }
|
|
2045
|
-
const r = summarizeToolResult(deep)
|
|
2046
|
-
// l1 (d0) → l2 (d1) → l3 (d2) 까지 object 유지, l3 의 값은 d3 진입 → string
|
|
2047
|
-
expect(typeof r.l1).toBe('object')
|
|
2048
|
-
expect(typeof r.l1.l2).toBe('object')
|
|
2049
|
-
// l3 자체가 d3 에서 평가되어 키 목록 문자열로 압축됨
|
|
2050
|
-
expect(typeof r.l1.l2.l3).toBe('string')
|
|
2051
|
-
expect(r.l1.l2.l3).toMatch(/^\{l4/)
|
|
2033
|
+
test('키가 많으면 앞의 것만 이름으로, 나머지는 수로', () => {
|
|
2034
|
+
const wide = Object.fromEntries(Array.from({ length: 25 }, (_, i) => [`k${i}`, i]))
|
|
2035
|
+
expect(resultShapeOf(wide)).toMatchObject({ moreKeys: 5 })
|
|
2036
|
+
expect(resultShapeOf(wide).keys).toHaveLength(20)
|
|
2052
2037
|
})
|
|
2053
2038
|
})
|
|
@@ -41,7 +41,7 @@ import { buildComponentStyleSummary } from './styling/read-tools'
|
|
|
41
41
|
import {
|
|
42
42
|
runAgenticLoop,
|
|
43
43
|
formatAbortNotice,
|
|
44
|
-
|
|
44
|
+
resultShapeOf,
|
|
45
45
|
registryToolGate,
|
|
46
46
|
extendToolGate,
|
|
47
47
|
type ToolGate as NeutralToolGate,
|
|
@@ -270,7 +270,8 @@ export class DefaultBoardAIAssistant implements BoardAIAssistant {
|
|
|
270
270
|
/* 문서에서 부품을 꺼내는 일은 **여기서** 한다 — 루프는 board 의 모양을 모른다. */
|
|
271
271
|
validateWriteToolCall: (tc, ctx) => validateWriteToolCall(tc, (ctx.board?.components ?? []) as any[]),
|
|
272
272
|
toolCallToOp: toolCallToSceneActionOp,
|
|
273
|
-
|
|
273
|
+
/* The conversation row keeps each answer's shape, never its values (ADR-0061 decision 8). */
|
|
274
|
+
summarizeToolResult: resultShapeOf
|
|
274
275
|
},
|
|
275
276
|
context: { board: currentBoard, selectedRefids }
|
|
276
277
|
})
|
|
@@ -2034,7 +2035,7 @@ export function listLayoutTemplateNames(): string[] {
|
|
|
2034
2035
|
}
|
|
2035
2036
|
|
|
2036
2037
|
/*
|
|
2037
|
-
* 중단 통지 · 도구
|
|
2038
|
+
* 중단 통지 · 도구 결과의 모양 — **공용 패키지에 있다** (2026-09-10, 결과는 값 대신 모양 2026-10-17).
|
|
2038
2039
|
*
|
|
2039
2040
|
* 둘 다 보드를 모르는 함수였다. 옮긴 이유는 중복이 아니라 **한쪽만 갖고 있었던 것**이다:
|
|
2040
2041
|
* `twin-ai` 는 `summarizeToolResult: v => v` 로 요약을 아예 안 하고 있었다. 한 제품은 압축해서
|
|
@@ -2045,7 +2046,7 @@ export function listLayoutTemplateNames(): string[] {
|
|
|
2045
2046
|
*
|
|
2046
2047
|
* 여기 남은 것은 재수출이다. 이 패키지를 지나는 소비처가 이름을 그대로 쓰게 한다.
|
|
2047
2048
|
*/
|
|
2048
|
-
export { formatAbortNotice,
|
|
2049
|
+
export { formatAbortNotice, resultShapeOf }
|
|
2049
2050
|
|
|
2050
2051
|
|
|
2051
2052
|
export function isWriteTool(name: string): boolean {
|