@things-factory/board-ai 10.0.0-beta.71 → 10.0.0-beta.72
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.js +67 -5
- package/dist-client/server/service/assistant.js.map +1 -1
- package/dist-client/server/service/types.d.ts +11 -0
- package/dist-client/server/service/types.js.map +1 -1
- package/dist-client/tsconfig.tsbuildinfo +1 -1
- package/dist-server/service/assistant.js +70 -8
- package/dist-server/service/assistant.js.map +1 -1
- package/dist-server/service/board-ai-resolver.js +5 -1
- package/dist-server/service/board-ai-resolver.js.map +1 -1
- package/dist-server/service/types.d.ts +11 -0
- package/dist-server/service/types.js.map +1 -1
- package/dist-server/tsconfig.tsbuildinfo +1 -1
- package/package.json +6 -6
- package/server/service/assistant.ts +73 -5
- package/server/service/board-ai-resolver.ts +5 -1
- package/server/service/types.ts +11 -0
|
@@ -7,7 +7,8 @@ import { resolveCatalogMentions } from './catalog-resolver';
|
|
|
7
7
|
import { buildComponentStyleSummary } from './styling/read-tools';
|
|
8
8
|
import { runAgenticLoop } from './agentic-loop';
|
|
9
9
|
import { collectAllComponents, findComponentByRefid } from './component-tree';
|
|
10
|
-
import { isStylingTool, dispatchStylingTool, buildStylingToolDefinitions } from './styling/registry';
|
|
10
|
+
import { isStylingTool, dispatchStylingTool, buildStylingToolDefinitions } from './styling/registry.js';
|
|
11
|
+
import { getAllToolSpecs, getToolKind, findToolSpec } from '@things-factory/ai-client-base';
|
|
11
12
|
import { validateWriteToolCall } from './validation/tool-validation';
|
|
12
13
|
const ALL_CATEGORIES = [
|
|
13
14
|
'container',
|
|
@@ -99,6 +100,29 @@ export class DefaultBoardAIAssistant {
|
|
|
99
100
|
];
|
|
100
101
|
// multi-turn agentic loop — LLM 이 read 호출 → 서버 실행 → 결과 회신 → LLM 추론 반복.
|
|
101
102
|
// write tool 은 누적해 client 에 patch 로 전달. 본체는 ./agentic-loop 에 분리.
|
|
103
|
+
//
|
|
104
|
+
// executeReadTool 은 closure wrapper — board-ai 자체 read tool (READ_TOOL_NAMES) 은
|
|
105
|
+
// 기존 hardcoded executeReadTool 로 dispatch, registry 에 등록된 read/external tool
|
|
106
|
+
// 은 spec.builder 에 ctx (board, selectedRefids, state=options.toolCallContext) 주입.
|
|
107
|
+
const toolCallContext = options.toolCallContext;
|
|
108
|
+
const wrappedExecuteReadTool = (call, board, selectedRefids) => {
|
|
109
|
+
// 1) board-ai 코어 read tool — 기존 hardcoded 경로
|
|
110
|
+
if (READ_TOOL_NAMES.has(call.name)) {
|
|
111
|
+
return executeReadTool(call, board, selectedRefids);
|
|
112
|
+
}
|
|
113
|
+
// 2) registry — read 와 external 둘 다 동일 dispatch path (LLM 회신 측면 동일).
|
|
114
|
+
// external builder 가 server-side mutation 호출하는 케이스라 ctx.state 주입 필수.
|
|
115
|
+
const spec = findToolSpec(call.name);
|
|
116
|
+
if (spec && (spec.kind === 'read' || spec.kind === 'external')) {
|
|
117
|
+
return spec.builder(call.arguments ?? {}, {
|
|
118
|
+
board,
|
|
119
|
+
selectedRefids,
|
|
120
|
+
state: toolCallContext
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
// 3) 미등록 / 잘못된 분기 — 빈 응답. agentic-loop 가 LLM 에 회신 후 다음 turn.
|
|
124
|
+
return undefined;
|
|
125
|
+
};
|
|
102
126
|
const loopResult = await runAgenticLoop({
|
|
103
127
|
initialConversation: conversation,
|
|
104
128
|
tools,
|
|
@@ -113,7 +137,7 @@ export class DefaultBoardAIAssistant {
|
|
|
113
137
|
isReadTool,
|
|
114
138
|
isWriteTool,
|
|
115
139
|
isActionTool,
|
|
116
|
-
executeReadTool,
|
|
140
|
+
executeReadTool: wrappedExecuteReadTool,
|
|
117
141
|
validateWriteToolCall,
|
|
118
142
|
toolCallToBoardActionOp,
|
|
119
143
|
summarizeToolResult
|
|
@@ -529,6 +553,10 @@ export function buildBoardEditTools(knownTypes) {
|
|
|
529
553
|
// styling registry 에서 자동 도출 — setFill 부터 점진 이전 중.
|
|
530
554
|
// 다음 tool 들은 registry 로 옮겨질 때마다 본 spread 가 자동 흡수.
|
|
531
555
|
...buildStylingToolDefinitions(),
|
|
556
|
+
// tool-registry plugin point — 외부 도메인 패키지 (board-import 등) 가
|
|
557
|
+
// registerToolCategory() 로 등록한 모든 tool 의 LLM 정의를 spread.
|
|
558
|
+
// styling 처럼 board-ai 코어 안에 정의되지 않고 외부에서 들어오는 카테고리들.
|
|
559
|
+
...buildExternalCategoryDefinitions(),
|
|
532
560
|
{
|
|
533
561
|
name: 'getComponentStyle',
|
|
534
562
|
description: "Get the current STYLING state of a component (read-only). Useful before modifying styles to understand what's already applied (avoid blind overwrites). Returns fill / stroke / shadow / material3d / font / opacity / visibility / text. Use `aspects` to limit response size.",
|
|
@@ -1698,7 +1726,13 @@ const LAYOUT_TEMPLATES = {
|
|
|
1698
1726
|
]
|
|
1699
1727
|
};
|
|
1700
1728
|
export function isReadTool(name) {
|
|
1701
|
-
|
|
1729
|
+
if (READ_TOOL_NAMES.has(name))
|
|
1730
|
+
return true;
|
|
1731
|
+
// tool-registry plugin point — 'read' 와 'external' 는 LLM 측에서 동일하게 다뤄짐
|
|
1732
|
+
// (server 즉시 실행 + 결과 회신). external 은 board model 외부 entity 변경이
|
|
1733
|
+
// 가능한 점에서 의미 차이가 있지만, dispatch path 는 read 와 같다.
|
|
1734
|
+
const kind = getToolKind(name);
|
|
1735
|
+
return kind === 'read' || kind === 'external';
|
|
1702
1736
|
}
|
|
1703
1737
|
/**
|
|
1704
1738
|
* 등록된 색 팔레트 이름 목록 — catalog-resolver / 클라이언트 popup 데이터 source.
|
|
@@ -1769,10 +1803,26 @@ export function summarizeToolResult(value, depth = 0) {
|
|
|
1769
1803
|
return undefined;
|
|
1770
1804
|
}
|
|
1771
1805
|
export function isWriteTool(name) {
|
|
1772
|
-
|
|
1806
|
+
if (WRITE_TOOL_NAMES.has(name))
|
|
1807
|
+
return true;
|
|
1808
|
+
return getToolKind(name) === 'write';
|
|
1773
1809
|
}
|
|
1774
1810
|
export function isActionTool(name) {
|
|
1775
|
-
|
|
1811
|
+
if (ACTION_TOOL_NAMES.has(name))
|
|
1812
|
+
return true;
|
|
1813
|
+
return getToolKind(name) === 'action';
|
|
1814
|
+
}
|
|
1815
|
+
/**
|
|
1816
|
+
* tool-registry plugin point — 등록된 모든 외부 카테고리의 LLM tool 정의를 도출.
|
|
1817
|
+
* styling-tools 가 buildStylingToolDefinitions 로 자기 정의를 내보내듯, 외부 카테고리
|
|
1818
|
+
* (board-import 등) 도 본 함수로 합집합. buildBoardEditTools 의 spread 부분에서 호출.
|
|
1819
|
+
*/
|
|
1820
|
+
function buildExternalCategoryDefinitions() {
|
|
1821
|
+
return getAllToolSpecs().map(spec => ({
|
|
1822
|
+
name: spec.name,
|
|
1823
|
+
description: spec.themeNote ? `${spec.description} ${spec.themeNote}` : spec.description,
|
|
1824
|
+
parameters: spec.schema
|
|
1825
|
+
}));
|
|
1776
1826
|
}
|
|
1777
1827
|
/**
|
|
1778
1828
|
* Tool call → BoardActionOp 변환 (C-1 ephemeral scene 조작).
|
|
@@ -1846,6 +1896,18 @@ export function toolCallToBoardEditOp(tc, components = []) {
|
|
|
1846
1896
|
if (isStylingTool(tc.name)) {
|
|
1847
1897
|
return dispatchStylingTool(tc.name, args, components);
|
|
1848
1898
|
}
|
|
1899
|
+
// tool-registry plugin point — 외부 등록 'write' 카테고리 dispatch.
|
|
1900
|
+
// builder 결과는 BoardEditOp[] | { ops, errors? } | null 셋 중 하나.
|
|
1901
|
+
// (read/external 카테고리는 별도 dispatch path — agentic loop 의 executeReadTool 이 직접 처리.)
|
|
1902
|
+
const registrySpec = findToolSpec(tc.name);
|
|
1903
|
+
if (registrySpec && registrySpec.kind === 'write') {
|
|
1904
|
+
const r = registrySpec.builder(args, { components });
|
|
1905
|
+
if (!r)
|
|
1906
|
+
return null;
|
|
1907
|
+
if (Array.isArray(r))
|
|
1908
|
+
return r.length > 0 ? r : null;
|
|
1909
|
+
return r.ops.length > 0 ? r.ops : null;
|
|
1910
|
+
}
|
|
1849
1911
|
switch (tc.name) {
|
|
1850
1912
|
case 'addComponent': {
|
|
1851
1913
|
if (typeof args.type !== 'string')
|