@things-factory/board-ai 10.0.18 → 10.1.0
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 +1 -1
- package/dist-client/server/service/assistant.js +13 -6
- package/dist-client/server/service/assistant.js.map +1 -1
- package/dist-client/server/service/types.d.ts +5 -29
- package/dist-client/server/service/types.js.map +1 -1
- package/dist-client/tsconfig.tsbuildinfo +1 -1
- package/dist-server/service/assistant.d.ts +1 -1
- package/dist-server/service/assistant.js +24 -17
- package/dist-server/service/assistant.js.map +1 -1
- package/dist-server/service/types.d.ts +5 -29
- 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 +18 -7
- package/server/service/types.ts +6 -29
- package/dist-client/server/service/agentic-loop.d.ts +0 -121
- package/dist-client/server/service/agentic-loop.js +0 -349
- package/dist-client/server/service/agentic-loop.js.map +0 -1
- package/dist-server/service/agentic-loop.d.ts +0 -121
- package/dist-server/service/agentic-loop.js +0 -354
- package/dist-server/service/agentic-loop.js.map +0 -1
- package/server/service/agentic-loop.test.ts +0 -859
- package/server/service/agentic-loop.ts +0 -533
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
import type { AIClient, AITool, AIToolCall, AIToolChatResult } from '@things-factory/ai-client-base';
|
|
5
5
|
import { type BoardModel, type ComponentCategory } from '@things-factory/board-import';
|
|
6
6
|
import type { BoardAIAssistant, BoardEditOp, ChatOptions, ChatResponse, LLMMessage } from './types.js';
|
|
7
|
-
import { type AgenticLoopResult } from '
|
|
7
|
+
import { type AgenticLoopResult } from '@things-factory/ai-client-base';
|
|
8
8
|
import { type ToolSpec, type ToolCategoryFilter } from '@things-factory/ai-client-base';
|
|
9
9
|
export interface BoardAIAssistantOptions {
|
|
10
10
|
/** 기본 scope (chat 호출 시 옵션이 없으면 사용) */
|
|
@@ -22,11 +22,18 @@ const catalog_resolver_1 = require("./catalog-resolver");
|
|
|
22
22
|
// styling write tool builder 들은 registry (./styling/registry.ts) 에서 등록 + dispatch.
|
|
23
23
|
// 직접 import 안 함 — 신규 styling tool 추가 시 registry 에만 spec 추가하면 됨.
|
|
24
24
|
const read_tools_1 = require("./styling/read-tools");
|
|
25
|
-
|
|
25
|
+
/*
|
|
26
|
+
* 도구 루프는 **계약 층이 소유한다**(2026-09-05). 전에는 이 패키지 안에 있었고, twin-ai 에 같은
|
|
27
|
+
* 모양이 한 벌 더 있었다 — 그래서 안전 장치가 서로 반대로 갈렸다(여기는 중단·조기종료, 저쪽은
|
|
28
|
+
* 접지 가드). 합친 것이 `@things-factory/ai-client-base` 에 있다.
|
|
29
|
+
*
|
|
30
|
+
* board 의 것(문서·선택 refid·편집 op)은 타입 매개변수로 넘긴다 — 루프는 그 모양을 모른다.
|
|
31
|
+
*/
|
|
32
|
+
const ai_client_base_1 = require("@things-factory/ai-client-base");
|
|
26
33
|
const grounding_1 = require("./grounding");
|
|
27
34
|
const component_tree_1 = require("./component-tree");
|
|
28
35
|
const registry_js_1 = require("./styling/registry.js");
|
|
29
|
-
const
|
|
36
|
+
const ai_client_base_2 = require("@things-factory/ai-client-base");
|
|
30
37
|
const tool_validation_1 = require("./validation/tool-validation");
|
|
31
38
|
const ALL_CATEGORIES = [
|
|
32
39
|
'container',
|
|
@@ -102,7 +109,7 @@ class DefaultBoardAIAssistant {
|
|
|
102
109
|
* 실제로 그 공백에서 사고가 났다 — 조치 요청에 제안 도구를 부르지 않고 "제안해 두었습니다" 라고만
|
|
103
110
|
* 답해, 사용자에게 없는 버튼을 누르라고 안내했다. 규율은 도구를 등록한 쪽이 소유하고 여기서는
|
|
104
111
|
* 모아 붙이기만 한다(도메인 지식이 board-ai 프롬프트로 새지 않는다). */
|
|
105
|
-
const guidance = (0,
|
|
112
|
+
const guidance = (0, ai_client_base_2.getCategoryGuidance)(options.toolCategories);
|
|
106
113
|
const systemPrompt = this.buildSystemPromptForTools(knownTypes, categories, schemas) +
|
|
107
114
|
(guidance.length ? `\n\n==== TOOL USE RULES (from the tools exposed to this conversation) ====\n${guidance.join('\n')}` : '');
|
|
108
115
|
const selectedRefids = (options.selectedRefids ?? []).filter((n) => typeof n === 'number' && Number.isFinite(n));
|
|
@@ -156,7 +163,7 @@ class DefaultBoardAIAssistant {
|
|
|
156
163
|
// 3) 미등록 / 잘못된 분기 — 빈 응답. agentic-loop 가 LLM 에 회신 후 다음 turn.
|
|
157
164
|
return undefined;
|
|
158
165
|
};
|
|
159
|
-
const loopResult = await (0,
|
|
166
|
+
const loopResult = await (0, ai_client_base_1.runAgenticLoop)({
|
|
160
167
|
initialConversation: conversation,
|
|
161
168
|
tools,
|
|
162
169
|
options: {
|
|
@@ -173,13 +180,13 @@ class DefaultBoardAIAssistant {
|
|
|
173
180
|
isReadTool: gate.isRead,
|
|
174
181
|
isWriteTool: gate.isWrite,
|
|
175
182
|
isActionTool: gate.isAction,
|
|
176
|
-
executeReadTool: wrappedExecuteReadTool,
|
|
177
|
-
|
|
178
|
-
|
|
183
|
+
executeReadTool: (tc, ctx) => wrappedExecuteReadTool(tc, ctx.board, ctx.selectedRefids),
|
|
184
|
+
/* 문서에서 부품을 꺼내는 일은 **여기서** 한다 — 루프는 board 의 모양을 모른다. */
|
|
185
|
+
validateWriteToolCall: (tc, ctx) => (0, tool_validation_1.validateWriteToolCall)(tc, (ctx.board?.components ?? [])),
|
|
186
|
+
toolCallToOp: toolCallToBoardActionOp,
|
|
179
187
|
summarizeToolResult
|
|
180
188
|
},
|
|
181
|
-
currentBoard,
|
|
182
|
-
selectedRefids
|
|
189
|
+
context: { board: currentBoard, selectedRefids }
|
|
183
190
|
});
|
|
184
191
|
const accumulatedWriteCalls = loopResult.accumulatedWriteCalls;
|
|
185
192
|
const accumulatedActions = loopResult.accumulatedActions;
|
|
@@ -1012,7 +1019,7 @@ function buildBoardEditTools(knownTypes, exposure = {}) {
|
|
|
1012
1019
|
/* 코어(보드 편집) 도구를 끈 대화는 **외부 카테고리 도구만** 남긴다.
|
|
1013
1020
|
* 배열 리터럴 안 어디에 있든 이름 기준으로 걸러 누락이 없게 한다. */
|
|
1014
1021
|
if (!gate.coreOn) {
|
|
1015
|
-
const externalNames = new Set((0,
|
|
1022
|
+
const externalNames = new Set((0, ai_client_base_2.getToolSpecsFor)(gate.filter).map(spec => spec.name));
|
|
1016
1023
|
return tools.filter(tool => externalNames.has(tool.name));
|
|
1017
1024
|
}
|
|
1018
1025
|
return tools;
|
|
@@ -1788,7 +1795,7 @@ function isReadTool(name) {
|
|
|
1788
1795
|
// tool-registry plugin point — 'read' 와 'external' 는 LLM 측에서 동일하게 다뤄짐
|
|
1789
1796
|
// (server 즉시 실행 + 결과 회신). external 은 board model 외부 entity 변경이
|
|
1790
1797
|
// 가능한 점에서 의미 차이가 있지만, dispatch path 는 read 와 같다.
|
|
1791
|
-
const kind = (0,
|
|
1798
|
+
const kind = (0, ai_client_base_2.getToolKind)(name);
|
|
1792
1799
|
return kind === 'read' || kind === 'external';
|
|
1793
1800
|
}
|
|
1794
1801
|
/**
|
|
@@ -1820,7 +1827,7 @@ function formatAbortNotice(abortReason) {
|
|
|
1820
1827
|
/* 남의 말(SDK 원문)을 사용자에게 보여주지 않는다 — "Error fetching from undefined: [503 …]" 은
|
|
1821
1828
|
* 사용자가 할 수 있는 일을 알려주지 않는다. 일시 장애는 이미 몇 번 다시 시도한 뒤이므로,
|
|
1822
1829
|
* 지금 필요한 안내는 "잠시 후 다시" 하나다. 원문은 서버 로그에 남는다. */
|
|
1823
|
-
return (0,
|
|
1830
|
+
return (0, ai_client_base_2.isTransientAIError)({ message: abortReason.message })
|
|
1824
1831
|
? '\n\n_(AI 서비스가 일시적으로 응답하지 않았어요. 잠시 후 다시 시도해 주세요.)_'
|
|
1825
1832
|
: '\n\n_(처리 중 오류가 발생했어요. 같은 요청이 계속 실패하면 관리자에게 알려 주세요.)_';
|
|
1826
1833
|
case 'max_iterations':
|
|
@@ -1867,24 +1874,24 @@ function summarizeToolResult(value, depth = 0) {
|
|
|
1867
1874
|
function isWriteTool(name) {
|
|
1868
1875
|
if (WRITE_TOOL_NAMES.has(name))
|
|
1869
1876
|
return true;
|
|
1870
|
-
return (0,
|
|
1877
|
+
return (0, ai_client_base_2.getToolKind)(name) === 'write';
|
|
1871
1878
|
}
|
|
1872
1879
|
function isActionTool(name) {
|
|
1873
1880
|
if (ACTION_TOOL_NAMES.has(name))
|
|
1874
1881
|
return true;
|
|
1875
|
-
return (0,
|
|
1882
|
+
return (0, ai_client_base_2.getToolKind)(name) === 'action';
|
|
1876
1883
|
}
|
|
1877
1884
|
function buildToolGate(exposure = {}) {
|
|
1878
1885
|
const coreOn = exposure.boardTools !== false;
|
|
1879
1886
|
const filter = exposure.toolCategories;
|
|
1880
|
-
const kind = (name) => (0,
|
|
1887
|
+
const kind = (name) => (0, ai_client_base_2.getToolKind)(name, filter);
|
|
1881
1888
|
return {
|
|
1882
1889
|
coreOn,
|
|
1883
1890
|
filter,
|
|
1884
1891
|
isRead: name => (coreOn && READ_TOOL_NAMES.has(name)) || kind(name) === 'read' || kind(name) === 'external',
|
|
1885
1892
|
isWrite: name => (coreOn && WRITE_TOOL_NAMES.has(name)) || kind(name) === 'write',
|
|
1886
1893
|
isAction: name => (coreOn && ACTION_TOOL_NAMES.has(name)) || kind(name) === 'action',
|
|
1887
|
-
spec: name => (0,
|
|
1894
|
+
spec: name => (0, ai_client_base_2.findToolSpec)(name, filter)
|
|
1888
1895
|
};
|
|
1889
1896
|
}
|
|
1890
1897
|
/**
|
|
@@ -1893,7 +1900,7 @@ function buildToolGate(exposure = {}) {
|
|
|
1893
1900
|
* (board-import 등) 도 본 함수로 합집합. buildBoardEditTools 의 spread 부분에서 호출.
|
|
1894
1901
|
*/
|
|
1895
1902
|
function buildExternalCategoryDefinitions(filter) {
|
|
1896
|
-
return (0,
|
|
1903
|
+
return (0, ai_client_base_2.getToolSpecsFor)(filter).map(spec => ({
|
|
1897
1904
|
name: spec.name,
|
|
1898
1905
|
description: spec.themeNote ? `${spec.description} ${spec.themeNote}` : spec.description,
|
|
1899
1906
|
parameters: spec.schema
|