@things-factory/ai-client-base 10.0.0-beta.64 → 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-server/service/index.d.ts +1 -0
- package/dist-server/service/index.js +1 -0
- package/dist-server/service/index.js.map +1 -1
- package/dist-server/service/tool-registry/index.d.ts +7 -0
- package/dist-server/service/tool-registry/index.js +18 -0
- package/dist-server/service/tool-registry/index.js.map +1 -0
- package/dist-server/service/tool-registry/registry.d.ts +66 -0
- package/dist-server/service/tool-registry/registry.js +92 -0
- package/dist-server/service/tool-registry/registry.js.map +1 -0
- package/dist-server/service/tool-registry/types.d.ts +118 -0
- package/dist-server/service/tool-registry/types.js +31 -0
- package/dist-server/service/tool-registry/types.js.map +1 -0
- package/dist-server/tsconfig.tsbuildinfo +1 -1
- package/package.json +2 -2
- package/server/service/index.ts +1 -0
- package/server/service/tool-registry/index.ts +32 -0
- package/server/service/tool-registry/registry.test.ts +185 -0
- package/server/service/tool-registry/registry.ts +121 -0
- package/server/service/tool-registry/types.ts +149 -0
|
@@ -5,4 +5,5 @@ tslib_1.__exportStar(require("./types.js"), exports);
|
|
|
5
5
|
tslib_1.__exportStar(require("./factory.js"), exports);
|
|
6
6
|
tslib_1.__exportStar(require("./providers/index.js"), exports);
|
|
7
7
|
tslib_1.__exportStar(require("./utils/index.js"), exports);
|
|
8
|
+
tslib_1.__exportStar(require("./tool-registry/index.js"), exports);
|
|
8
9
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../server/service/index.ts"],"names":[],"mappings":";;;AAAA,qDAA0B;AAC1B,uDAA4B;AAC5B,+DAAoC;AACpC,2DAAgC","sourcesContent":["export * from './types.js'\nexport * from './factory.js'\nexport * from './providers/index.js'\nexport * from './utils/index.js'\n"]}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../server/service/index.ts"],"names":[],"mappings":";;;AAAA,qDAA0B;AAC1B,uDAA4B;AAC5B,+DAAoC;AACpC,2DAAgC;AAChC,mEAAwC","sourcesContent":["export * from './types.js'\nexport * from './factory.js'\nexport * from './providers/index.js'\nexport * from './utils/index.js'\nexport * from './tool-registry/index.js'\n"]}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool Registry — board-ai 의 외부 도메인 LLM tool 노출 plugin point.
|
|
3
|
+
*
|
|
4
|
+
* 자세한 설계는 ./types 와 ./registry 의 헤더 주석 참조.
|
|
5
|
+
*/
|
|
6
|
+
export { registerToolCategory, getToolCategories, getAllToolSpecs, findToolSpec, getToolKind, hasTool, getCategorySpecs, clearToolRegistry } from './registry';
|
|
7
|
+
export type { ToolSpec, ToolSpecBase, ReadToolSpec, WriteToolSpec, ActionToolSpec, ExternalToolSpec, ToolCategory, ReadToolBuilder, WriteToolBuilder, ActionToolBuilder, ExternalToolBuilder, ReadToolContext, WriteToolContext, ExternalToolContext } from './types';
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.clearToolRegistry = exports.getCategorySpecs = exports.hasTool = exports.getToolKind = exports.findToolSpec = exports.getAllToolSpecs = exports.getToolCategories = exports.registerToolCategory = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Tool Registry — board-ai 의 외부 도메인 LLM tool 노출 plugin point.
|
|
6
|
+
*
|
|
7
|
+
* 자세한 설계는 ./types 와 ./registry 의 헤더 주석 참조.
|
|
8
|
+
*/
|
|
9
|
+
var registry_1 = require("./registry");
|
|
10
|
+
Object.defineProperty(exports, "registerToolCategory", { enumerable: true, get: function () { return registry_1.registerToolCategory; } });
|
|
11
|
+
Object.defineProperty(exports, "getToolCategories", { enumerable: true, get: function () { return registry_1.getToolCategories; } });
|
|
12
|
+
Object.defineProperty(exports, "getAllToolSpecs", { enumerable: true, get: function () { return registry_1.getAllToolSpecs; } });
|
|
13
|
+
Object.defineProperty(exports, "findToolSpec", { enumerable: true, get: function () { return registry_1.findToolSpec; } });
|
|
14
|
+
Object.defineProperty(exports, "getToolKind", { enumerable: true, get: function () { return registry_1.getToolKind; } });
|
|
15
|
+
Object.defineProperty(exports, "hasTool", { enumerable: true, get: function () { return registry_1.hasTool; } });
|
|
16
|
+
Object.defineProperty(exports, "getCategorySpecs", { enumerable: true, get: function () { return registry_1.getCategorySpecs; } });
|
|
17
|
+
Object.defineProperty(exports, "clearToolRegistry", { enumerable: true, get: function () { return registry_1.clearToolRegistry; } });
|
|
18
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../server/service/tool-registry/index.ts"],"names":[],"mappings":";;;AAAA;;;;GAIG;AACH,uCASmB;AARjB,gHAAA,oBAAoB,OAAA;AACpB,6GAAA,iBAAiB,OAAA;AACjB,2GAAA,eAAe,OAAA;AACf,wGAAA,YAAY,OAAA;AACZ,uGAAA,WAAW,OAAA;AACX,mGAAA,OAAO,OAAA;AACP,4GAAA,gBAAgB,OAAA;AAChB,6GAAA,iBAAiB,OAAA","sourcesContent":["/**\n * Tool Registry — board-ai 의 외부 도메인 LLM tool 노출 plugin point.\n *\n * 자세한 설계는 ./types 와 ./registry 의 헤더 주석 참조.\n */\nexport {\n registerToolCategory,\n getToolCategories,\n getAllToolSpecs,\n findToolSpec,\n getToolKind,\n hasTool,\n getCategorySpecs,\n clearToolRegistry\n} from './registry'\n\nexport type {\n ToolSpec,\n ToolSpecBase,\n ReadToolSpec,\n WriteToolSpec,\n ActionToolSpec,\n ExternalToolSpec,\n ToolCategory,\n ReadToolBuilder,\n WriteToolBuilder,\n ActionToolBuilder,\n ExternalToolBuilder,\n ReadToolContext,\n WriteToolContext,\n ExternalToolContext\n} from './types'\n"]}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ToolCategoryRegistry — 외부 도메인 패키지가 LLM tool category 를 동적 등록하는 점.
|
|
3
|
+
*
|
|
4
|
+
* 사용 패턴 (외부 패키지의 server bootstrap):
|
|
5
|
+
* ```ts
|
|
6
|
+
* import { registerToolCategory } from '@things-factory/board-ai'
|
|
7
|
+
*
|
|
8
|
+
* registerToolCategory({
|
|
9
|
+
* name: 'board-import',
|
|
10
|
+
* specs: [
|
|
11
|
+
* { kind: 'external', name: 'importBoardAsync', schema: {...}, builder: ... },
|
|
12
|
+
* { kind: 'read', name: 'getImportSession', schema: {...}, builder: ... },
|
|
13
|
+
* ...
|
|
14
|
+
* ]
|
|
15
|
+
* })
|
|
16
|
+
* ```
|
|
17
|
+
*
|
|
18
|
+
* board-ai assistant.ts 의 buildBoardEditTools / dispatch / isWriteTool 등이
|
|
19
|
+
* 본 registry 에서 자동 도출.
|
|
20
|
+
*
|
|
21
|
+
* 정책:
|
|
22
|
+
* - 카테고리 이름은 unique. 같은 이름으로 재등록하면 덮어쓰기 (외부 패키지의
|
|
23
|
+
* hot-reload / dev 환경 대응). console.warn 으로 알림.
|
|
24
|
+
* - tool name 은 카테고리 간 통틀어 unique. 충돌 시 등록 거부 + 명확한 에러
|
|
25
|
+
* (LLM dispatch 가 모호해지지 않도록).
|
|
26
|
+
* - clear() 는 테스트 전용. 운영 환경에서 호출 금지.
|
|
27
|
+
*/
|
|
28
|
+
import type { ToolCategory, ToolSpec } from './types';
|
|
29
|
+
/**
|
|
30
|
+
* 카테고리 등록. tool name 충돌 시 throw, 이름 중복 등록 시 덮어쓰기 + warn.
|
|
31
|
+
*/
|
|
32
|
+
export declare function registerToolCategory(category: ToolCategory): void;
|
|
33
|
+
/**
|
|
34
|
+
* 등록된 모든 카테고리 (등록 순서 보존). 외부에서 불변 read-only 로 사용.
|
|
35
|
+
*/
|
|
36
|
+
export declare function getToolCategories(): ReadonlyArray<ToolCategory>;
|
|
37
|
+
/**
|
|
38
|
+
* 등록된 모든 tool spec 의 평면 view. assistant.ts 의 buildBoardEditTools 가
|
|
39
|
+
* LLM tool 정의 합집합으로 사용.
|
|
40
|
+
*/
|
|
41
|
+
export declare function getAllToolSpecs(): ReadonlyArray<ToolSpec>;
|
|
42
|
+
/**
|
|
43
|
+
* tool name 으로 spec 검색. 없으면 undefined.
|
|
44
|
+
*/
|
|
45
|
+
export declare function findToolSpec(name: string): ToolSpec | undefined;
|
|
46
|
+
/**
|
|
47
|
+
* tool name 의 카테고리 (read/write/action/external). 미등록 tool 은 undefined.
|
|
48
|
+
* assistant.ts 의 isReadTool / isWriteTool / isActionTool 이 이 함수에 위임할 수 있다.
|
|
49
|
+
*/
|
|
50
|
+
export declare function getToolKind(name: string): ToolSpec['kind'] | undefined;
|
|
51
|
+
/**
|
|
52
|
+
* 등록된 tool 인지. dispatch path 가 hardcoded set 와 registry 양쪽 fallback 시 사용.
|
|
53
|
+
*/
|
|
54
|
+
export declare function hasTool(name: string): boolean;
|
|
55
|
+
/**
|
|
56
|
+
* 카테고리 이름으로 spec 만 추출.
|
|
57
|
+
*/
|
|
58
|
+
export declare function getCategorySpecs(categoryName: string): ReadonlyArray<ToolSpec>;
|
|
59
|
+
/**
|
|
60
|
+
* 테스트 전용 — 모든 등록 해제. 운영 환경에서 호출 금지.
|
|
61
|
+
*
|
|
62
|
+
* jest 의 setupFilesAfterEach 또는 명시적 afterEach 에서 호출해 테스트 간 격리.
|
|
63
|
+
* 실제로 STYLING_TOOLS 는 board-ai 자체 부트스트랩에서 다시 등록되므로 clear 후
|
|
64
|
+
* 명시 register 가 필요한 것은 동적 카테고리 (board-import 등) 뿐.
|
|
65
|
+
*/
|
|
66
|
+
export declare function clearToolRegistry(): void;
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.registerToolCategory = registerToolCategory;
|
|
4
|
+
exports.getToolCategories = getToolCategories;
|
|
5
|
+
exports.getAllToolSpecs = getAllToolSpecs;
|
|
6
|
+
exports.findToolSpec = findToolSpec;
|
|
7
|
+
exports.getToolKind = getToolKind;
|
|
8
|
+
exports.hasTool = hasTool;
|
|
9
|
+
exports.getCategorySpecs = getCategorySpecs;
|
|
10
|
+
exports.clearToolRegistry = clearToolRegistry;
|
|
11
|
+
const categories = new Map();
|
|
12
|
+
/**
|
|
13
|
+
* 카테고리 등록. tool name 충돌 시 throw, 이름 중복 등록 시 덮어쓰기 + warn.
|
|
14
|
+
*/
|
|
15
|
+
function registerToolCategory(category) {
|
|
16
|
+
if (categories.has(category.name)) {
|
|
17
|
+
console.warn(`[board-ai/tool-registry] category '${category.name}' already registered — overwriting. ` +
|
|
18
|
+
`(dev hot-reload 시 정상이지만 운영 환경에서 발생하면 buildup bug)`);
|
|
19
|
+
}
|
|
20
|
+
// tool name 충돌 검사 — 다른 카테고리에 같은 name 있으면 거부
|
|
21
|
+
const newNames = new Set(category.specs.map(s => s.name));
|
|
22
|
+
for (const [otherName, other] of categories) {
|
|
23
|
+
if (otherName === category.name)
|
|
24
|
+
continue; // 같은 카테고리 재등록은 덮어쓰기 OK
|
|
25
|
+
for (const spec of other.specs) {
|
|
26
|
+
if (newNames.has(spec.name)) {
|
|
27
|
+
throw new Error(`[board-ai/tool-registry] tool name '${spec.name}' already registered in category ` +
|
|
28
|
+
`'${otherName}', cannot register in '${category.name}'. tool names must be globally unique.`);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
categories.set(category.name, category);
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* 등록된 모든 카테고리 (등록 순서 보존). 외부에서 불변 read-only 로 사용.
|
|
36
|
+
*/
|
|
37
|
+
function getToolCategories() {
|
|
38
|
+
return Array.from(categories.values());
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* 등록된 모든 tool spec 의 평면 view. assistant.ts 의 buildBoardEditTools 가
|
|
42
|
+
* LLM tool 정의 합집합으로 사용.
|
|
43
|
+
*/
|
|
44
|
+
function getAllToolSpecs() {
|
|
45
|
+
const out = [];
|
|
46
|
+
for (const cat of categories.values()) {
|
|
47
|
+
for (const spec of cat.specs)
|
|
48
|
+
out.push(spec);
|
|
49
|
+
}
|
|
50
|
+
return out;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* tool name 으로 spec 검색. 없으면 undefined.
|
|
54
|
+
*/
|
|
55
|
+
function findToolSpec(name) {
|
|
56
|
+
for (const cat of categories.values()) {
|
|
57
|
+
const spec = cat.specs.find(s => s.name === name);
|
|
58
|
+
if (spec)
|
|
59
|
+
return spec;
|
|
60
|
+
}
|
|
61
|
+
return undefined;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* tool name 의 카테고리 (read/write/action/external). 미등록 tool 은 undefined.
|
|
65
|
+
* assistant.ts 의 isReadTool / isWriteTool / isActionTool 이 이 함수에 위임할 수 있다.
|
|
66
|
+
*/
|
|
67
|
+
function getToolKind(name) {
|
|
68
|
+
return findToolSpec(name)?.kind;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* 등록된 tool 인지. dispatch path 가 hardcoded set 와 registry 양쪽 fallback 시 사용.
|
|
72
|
+
*/
|
|
73
|
+
function hasTool(name) {
|
|
74
|
+
return findToolSpec(name) !== undefined;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* 카테고리 이름으로 spec 만 추출.
|
|
78
|
+
*/
|
|
79
|
+
function getCategorySpecs(categoryName) {
|
|
80
|
+
return categories.get(categoryName)?.specs ?? [];
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* 테스트 전용 — 모든 등록 해제. 운영 환경에서 호출 금지.
|
|
84
|
+
*
|
|
85
|
+
* jest 의 setupFilesAfterEach 또는 명시적 afterEach 에서 호출해 테스트 간 격리.
|
|
86
|
+
* 실제로 STYLING_TOOLS 는 board-ai 자체 부트스트랩에서 다시 등록되므로 clear 후
|
|
87
|
+
* 명시 register 가 필요한 것은 동적 카테고리 (board-import 등) 뿐.
|
|
88
|
+
*/
|
|
89
|
+
function clearToolRegistry() {
|
|
90
|
+
categories.clear();
|
|
91
|
+
}
|
|
92
|
+
//# sourceMappingURL=registry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.js","sourceRoot":"","sources":["../../../server/service/tool-registry/registry.ts"],"names":[],"mappings":";;AAkCA,oDAuBC;AAKD,8CAEC;AAMD,0CAMC;AAKD,oCAMC;AAMD,kCAEC;AAKD,0BAEC;AAKD,4CAEC;AASD,8CAEC;AA3FD,MAAM,UAAU,GAA8B,IAAI,GAAG,EAAE,CAAA;AAEvD;;GAEG;AACH,SAAgB,oBAAoB,CAAC,QAAsB;IACzD,IAAI,UAAU,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;QAClC,OAAO,CAAC,IAAI,CACV,sCAAsC,QAAQ,CAAC,IAAI,sCAAsC;YACvF,mDAAmD,CACtD,CAAA;IACH,CAAC;IAED,4CAA4C;IAC5C,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAA;IACzD,KAAK,MAAM,CAAC,SAAS,EAAE,KAAK,CAAC,IAAI,UAAU,EAAE,CAAC;QAC5C,IAAI,SAAS,KAAK,QAAQ,CAAC,IAAI;YAAE,SAAQ,CAAC,uBAAuB;QACjE,KAAK,MAAM,IAAI,IAAI,KAAK,CAAC,KAAK,EAAE,CAAC;YAC/B,IAAI,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;gBAC5B,MAAM,IAAI,KAAK,CACb,uCAAuC,IAAI,CAAC,IAAI,mCAAmC;oBACjF,IAAI,SAAS,0BAA0B,QAAQ,CAAC,IAAI,wCAAwC,CAC/F,CAAA;YACH,CAAC;QACH,CAAC;IACH,CAAC;IAED,UAAU,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAA;AACzC,CAAC;AAED;;GAEG;AACH,SAAgB,iBAAiB;IAC/B,OAAO,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,MAAM,EAAE,CAAC,CAAA;AACxC,CAAC;AAED;;;GAGG;AACH,SAAgB,eAAe;IAC7B,MAAM,GAAG,GAAe,EAAE,CAAA;IAC1B,KAAK,MAAM,GAAG,IAAI,UAAU,CAAC,MAAM,EAAE,EAAE,CAAC;QACtC,KAAK,MAAM,IAAI,IAAI,GAAG,CAAC,KAAK;YAAE,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IAC9C,CAAC;IACD,OAAO,GAAG,CAAA;AACZ,CAAC;AAED;;GAEG;AACH,SAAgB,YAAY,CAAC,IAAY;IACvC,KAAK,MAAM,GAAG,IAAI,UAAU,CAAC,MAAM,EAAE,EAAE,CAAC;QACtC,MAAM,IAAI,GAAG,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,CAAA;QACjD,IAAI,IAAI;YAAE,OAAO,IAAI,CAAA;IACvB,CAAC;IACD,OAAO,SAAS,CAAA;AAClB,CAAC;AAED;;;GAGG;AACH,SAAgB,WAAW,CAAC,IAAY;IACtC,OAAO,YAAY,CAAC,IAAI,CAAC,EAAE,IAAI,CAAA;AACjC,CAAC;AAED;;GAEG;AACH,SAAgB,OAAO,CAAC,IAAY;IAClC,OAAO,YAAY,CAAC,IAAI,CAAC,KAAK,SAAS,CAAA;AACzC,CAAC;AAED;;GAEG;AACH,SAAgB,gBAAgB,CAAC,YAAoB;IACnD,OAAO,UAAU,CAAC,GAAG,CAAC,YAAY,CAAC,EAAE,KAAK,IAAI,EAAE,CAAA;AAClD,CAAC;AAED;;;;;;GAMG;AACH,SAAgB,iBAAiB;IAC/B,UAAU,CAAC,KAAK,EAAE,CAAA;AACpB,CAAC","sourcesContent":["/**\n * ToolCategoryRegistry — 외부 도메인 패키지가 LLM tool category 를 동적 등록하는 점.\n *\n * 사용 패턴 (외부 패키지의 server bootstrap):\n * ```ts\n * import { registerToolCategory } from '@things-factory/board-ai'\n *\n * registerToolCategory({\n * name: 'board-import',\n * specs: [\n * { kind: 'external', name: 'importBoardAsync', schema: {...}, builder: ... },\n * { kind: 'read', name: 'getImportSession', schema: {...}, builder: ... },\n * ...\n * ]\n * })\n * ```\n *\n * board-ai assistant.ts 의 buildBoardEditTools / dispatch / isWriteTool 등이\n * 본 registry 에서 자동 도출.\n *\n * 정책:\n * - 카테고리 이름은 unique. 같은 이름으로 재등록하면 덮어쓰기 (외부 패키지의\n * hot-reload / dev 환경 대응). console.warn 으로 알림.\n * - tool name 은 카테고리 간 통틀어 unique. 충돌 시 등록 거부 + 명확한 에러\n * (LLM dispatch 가 모호해지지 않도록).\n * - clear() 는 테스트 전용. 운영 환경에서 호출 금지.\n */\nimport type { ToolCategory, ToolSpec } from './types'\n\nconst categories: Map<string, ToolCategory> = new Map()\n\n/**\n * 카테고리 등록. tool name 충돌 시 throw, 이름 중복 등록 시 덮어쓰기 + warn.\n */\nexport function registerToolCategory(category: ToolCategory): void {\n if (categories.has(category.name)) {\n console.warn(\n `[board-ai/tool-registry] category '${category.name}' already registered — overwriting. ` +\n `(dev hot-reload 시 정상이지만 운영 환경에서 발생하면 buildup bug)`\n )\n }\n\n // tool name 충돌 검사 — 다른 카테고리에 같은 name 있으면 거부\n const newNames = new Set(category.specs.map(s => s.name))\n for (const [otherName, other] of categories) {\n if (otherName === category.name) continue // 같은 카테고리 재등록은 덮어쓰기 OK\n for (const spec of other.specs) {\n if (newNames.has(spec.name)) {\n throw new Error(\n `[board-ai/tool-registry] tool name '${spec.name}' already registered in category ` +\n `'${otherName}', cannot register in '${category.name}'. tool names must be globally unique.`\n )\n }\n }\n }\n\n categories.set(category.name, category)\n}\n\n/**\n * 등록된 모든 카테고리 (등록 순서 보존). 외부에서 불변 read-only 로 사용.\n */\nexport function getToolCategories(): ReadonlyArray<ToolCategory> {\n return Array.from(categories.values())\n}\n\n/**\n * 등록된 모든 tool spec 의 평면 view. assistant.ts 의 buildBoardEditTools 가\n * LLM tool 정의 합집합으로 사용.\n */\nexport function getAllToolSpecs(): ReadonlyArray<ToolSpec> {\n const out: ToolSpec[] = []\n for (const cat of categories.values()) {\n for (const spec of cat.specs) out.push(spec)\n }\n return out\n}\n\n/**\n * tool name 으로 spec 검색. 없으면 undefined.\n */\nexport function findToolSpec(name: string): ToolSpec | undefined {\n for (const cat of categories.values()) {\n const spec = cat.specs.find(s => s.name === name)\n if (spec) return spec\n }\n return undefined\n}\n\n/**\n * tool name 의 카테고리 (read/write/action/external). 미등록 tool 은 undefined.\n * assistant.ts 의 isReadTool / isWriteTool / isActionTool 이 이 함수에 위임할 수 있다.\n */\nexport function getToolKind(name: string): ToolSpec['kind'] | undefined {\n return findToolSpec(name)?.kind\n}\n\n/**\n * 등록된 tool 인지. dispatch path 가 hardcoded set 와 registry 양쪽 fallback 시 사용.\n */\nexport function hasTool(name: string): boolean {\n return findToolSpec(name) !== undefined\n}\n\n/**\n * 카테고리 이름으로 spec 만 추출.\n */\nexport function getCategorySpecs(categoryName: string): ReadonlyArray<ToolSpec> {\n return categories.get(categoryName)?.specs ?? []\n}\n\n/**\n * 테스트 전용 — 모든 등록 해제. 운영 환경에서 호출 금지.\n *\n * jest 의 setupFilesAfterEach 또는 명시적 afterEach 에서 호출해 테스트 간 격리.\n * 실제로 STYLING_TOOLS 는 board-ai 자체 부트스트랩에서 다시 등록되므로 clear 후\n * 명시 register 가 필요한 것은 동적 카테고리 (board-import 등) 뿐.\n */\nexport function clearToolRegistry(): void {\n categories.clear()\n}\n"]}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool Registry — board-ai 의 LLM tool 노출 plugin point.
|
|
3
|
+
*
|
|
4
|
+
* 동기:
|
|
5
|
+
* 기존엔 board-ai 가 자기 도메인 (board edit) tool 들만 hardcoded 정의했고, styling
|
|
6
|
+
* 영역만 STYLING_TOOLS registry 로 분리되어 있었다. 외부 도메인 패키지 (board-import,
|
|
7
|
+
* fmsim 등) 가 자기 tool 을 LLM 에 노출하려면 board-ai 자체를 fork/수정해야 했다.
|
|
8
|
+
*
|
|
9
|
+
* 본 registry 는 외부 패키지가 server bootstrap 시 자기 tool category 를 등록하면
|
|
10
|
+
* assistant.ts 의 buildBoardEditTools / dispatch / isWriteTool 등이 자동으로 통합
|
|
11
|
+
* 하도록 한다. styling-tools 의 single-source-of-truth 패턴을 일반화한 형태.
|
|
12
|
+
*
|
|
13
|
+
* 설계 원칙:
|
|
14
|
+
* - **카테고리별 builder 시그니처 다양성을 통합**: read 는 (args, ctx) → any,
|
|
15
|
+
* write 는 (args, components) → BoardEditOp[], action 은 (args) → BoardActionOp.
|
|
16
|
+
* 하나의 ToolSpec 에 모든 시그니처를 union 으로 담지 않고, 카테고리에 맞는
|
|
17
|
+
* builder 만 채우면 되도록 카테고리별 sub-interface 분리.
|
|
18
|
+
* - **kind 필드로 자가 분류**: registry 가 isReadTool / isWriteTool 자동 도출.
|
|
19
|
+
* hardcoded set 동기화 누락 위험 제거.
|
|
20
|
+
* - **점진 마이그레이션**: 기존 STYLING_TOOLS 가 본 registry 의 첫 사용자.
|
|
21
|
+
* 점진적으로 다른 hardcoded tool 들 (addComponent / alignComponents 등) 도
|
|
22
|
+
* 같은 registry 로 흡수 가능. 한 단계씩 byte-단위 동등성 단위 테스트 보장.
|
|
23
|
+
*/
|
|
24
|
+
/**
|
|
25
|
+
* Read tool — server 측 즉시 실행, 결과를 LLM 에 회신. board model 변경 X.
|
|
26
|
+
* 예: getSelection / findComponents / importSession (query)
|
|
27
|
+
*/
|
|
28
|
+
export type ReadToolBuilder = (args: any, context: ReadToolContext) => any | Promise<any>;
|
|
29
|
+
export interface ReadToolContext {
|
|
30
|
+
/** 현재 board model — 일부 read tool 이 사용 (getSelection 등). */
|
|
31
|
+
board?: any;
|
|
32
|
+
/** 현재 선택된 refids. */
|
|
33
|
+
selectedRefids?: number[];
|
|
34
|
+
/** 호출자 도메인 / 사용자 / 트랜잭션. registry 외부에서 주입. */
|
|
35
|
+
state?: any;
|
|
36
|
+
/** 이외 주입은 카테고리별로 자유. tool 등록자가 type 좁힐 수 있도록 unknown 으로 보존. */
|
|
37
|
+
[k: string]: any;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Write tool — domain edit op 발생. host 가 patch 적용 후 영속화.
|
|
41
|
+
* 예: board-ai 의 addComponent / setFill / modifyBoard.
|
|
42
|
+
*
|
|
43
|
+
* builder 의 return type 은 unknown 으로 둔다 — 도메인별 dispatcher (예: board-ai 의
|
|
44
|
+
* toolCallToBoardEditOp) 가 자기 EditOp[] 로 cast. ops/errors wrapper 형태도 동일 의미.
|
|
45
|
+
*/
|
|
46
|
+
export type WriteToolBuilder = (args: any, context: WriteToolContext) => any[] | {
|
|
47
|
+
ops: any[];
|
|
48
|
+
errors?: string[];
|
|
49
|
+
} | null;
|
|
50
|
+
export interface WriteToolContext {
|
|
51
|
+
components?: ReadonlyArray<any>;
|
|
52
|
+
[k: string]: any;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Action tool — ephemeral scene 조작 (select / center / fit / sceneMode).
|
|
56
|
+
* board model 변경 X, undo 영향 X. host 가 별도 channel 로 적용.
|
|
57
|
+
*
|
|
58
|
+
* return type 은 unknown — 도메인별 dispatcher (예: board-ai 의 toolCallToBoardActionOp)
|
|
59
|
+
* 가 자기 BoardActionOp 으로 cast.
|
|
60
|
+
*/
|
|
61
|
+
export type ActionToolBuilder = (args: any) => any | null;
|
|
62
|
+
/**
|
|
63
|
+
* External-call tool — 외부 service / mutation / RPC 호출. 직접 board model 영향 X
|
|
64
|
+
* (별도 entity 변경은 가능). 결과는 LLM 에 회신.
|
|
65
|
+
*
|
|
66
|
+
* board-import 의 importBoardAsync / materializeImportSession 같이 board-ai 외부
|
|
67
|
+
* 도메인을 호출하는 tool 의 카테고리.
|
|
68
|
+
*/
|
|
69
|
+
export type ExternalToolBuilder = (args: any, context: ExternalToolContext) => any | Promise<any>;
|
|
70
|
+
export interface ExternalToolContext {
|
|
71
|
+
state?: any;
|
|
72
|
+
[k: string]: any;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* 모든 ToolSpec 공통 메타데이터.
|
|
76
|
+
*/
|
|
77
|
+
export interface ToolSpecBase {
|
|
78
|
+
/** AIToolCall.name 매칭. 전 카테고리 통틀어 unique. */
|
|
79
|
+
name: string;
|
|
80
|
+
/** 기능 설명 (영문 위주). LLM 의 tool description 으로 사용. */
|
|
81
|
+
description: string;
|
|
82
|
+
/**
|
|
83
|
+
* 선택 — 정책 / 테마 가이드 단문. tool description 끝에 자동 부착.
|
|
84
|
+
* styling-tools 의 themeNote 와 동일 의미. 기타 카테고리도 사용 가능.
|
|
85
|
+
*/
|
|
86
|
+
themeNote?: string;
|
|
87
|
+
/** JSON Schema for parameters — LLM tool schema 에 그대로 노출. */
|
|
88
|
+
schema: any;
|
|
89
|
+
}
|
|
90
|
+
export interface ReadToolSpec extends ToolSpecBase {
|
|
91
|
+
kind: 'read';
|
|
92
|
+
builder: ReadToolBuilder;
|
|
93
|
+
}
|
|
94
|
+
export interface WriteToolSpec extends ToolSpecBase {
|
|
95
|
+
kind: 'write';
|
|
96
|
+
builder: WriteToolBuilder;
|
|
97
|
+
}
|
|
98
|
+
export interface ActionToolSpec extends ToolSpecBase {
|
|
99
|
+
kind: 'action';
|
|
100
|
+
builder: ActionToolBuilder;
|
|
101
|
+
}
|
|
102
|
+
export interface ExternalToolSpec extends ToolSpecBase {
|
|
103
|
+
kind: 'external';
|
|
104
|
+
builder: ExternalToolBuilder;
|
|
105
|
+
}
|
|
106
|
+
export type ToolSpec = ReadToolSpec | WriteToolSpec | ActionToolSpec | ExternalToolSpec;
|
|
107
|
+
/**
|
|
108
|
+
* 한 도메인 / 패키지가 등록하는 tool 묶음.
|
|
109
|
+
* 카테고리 이름은 식별자 (debug log / 분쟁 시 origin 추적). unique.
|
|
110
|
+
*/
|
|
111
|
+
export interface ToolCategory {
|
|
112
|
+
/** 등록 식별자. 예: 'styling', 'board-import', 'fmsim'. */
|
|
113
|
+
name: string;
|
|
114
|
+
/** 이 카테고리에 속한 tool spec 들. */
|
|
115
|
+
specs: ToolSpec[];
|
|
116
|
+
/** 선택 — 디버깅용 짧은 설명. */
|
|
117
|
+
description?: string;
|
|
118
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Tool Registry — board-ai 의 LLM tool 노출 plugin point.
|
|
4
|
+
*
|
|
5
|
+
* 동기:
|
|
6
|
+
* 기존엔 board-ai 가 자기 도메인 (board edit) tool 들만 hardcoded 정의했고, styling
|
|
7
|
+
* 영역만 STYLING_TOOLS registry 로 분리되어 있었다. 외부 도메인 패키지 (board-import,
|
|
8
|
+
* fmsim 등) 가 자기 tool 을 LLM 에 노출하려면 board-ai 자체를 fork/수정해야 했다.
|
|
9
|
+
*
|
|
10
|
+
* 본 registry 는 외부 패키지가 server bootstrap 시 자기 tool category 를 등록하면
|
|
11
|
+
* assistant.ts 의 buildBoardEditTools / dispatch / isWriteTool 등이 자동으로 통합
|
|
12
|
+
* 하도록 한다. styling-tools 의 single-source-of-truth 패턴을 일반화한 형태.
|
|
13
|
+
*
|
|
14
|
+
* 설계 원칙:
|
|
15
|
+
* - **카테고리별 builder 시그니처 다양성을 통합**: read 는 (args, ctx) → any,
|
|
16
|
+
* write 는 (args, components) → BoardEditOp[], action 은 (args) → BoardActionOp.
|
|
17
|
+
* 하나의 ToolSpec 에 모든 시그니처를 union 으로 담지 않고, 카테고리에 맞는
|
|
18
|
+
* builder 만 채우면 되도록 카테고리별 sub-interface 분리.
|
|
19
|
+
* - **kind 필드로 자가 분류**: registry 가 isReadTool / isWriteTool 자동 도출.
|
|
20
|
+
* hardcoded set 동기화 누락 위험 제거.
|
|
21
|
+
* - **점진 마이그레이션**: 기존 STYLING_TOOLS 가 본 registry 의 첫 사용자.
|
|
22
|
+
* 점진적으로 다른 hardcoded tool 들 (addComponent / alignComponents 등) 도
|
|
23
|
+
* 같은 registry 로 흡수 가능. 한 단계씩 byte-단위 동등성 단위 테스트 보장.
|
|
24
|
+
*/
|
|
25
|
+
// 본 registry 는 LLM tool 노출 plugin point 에 한정되므로 도메인 type (BoardEditOp,
|
|
26
|
+
// BoardActionOp 등) 은 알지 않는다. builder return 은 unknown 으로 두고, 카테고리
|
|
27
|
+
// dispatcher (board-ai 의 toolCallToBoardEditOp / toolCallToBoardActionOp 등) 가 자기
|
|
28
|
+
// 도메인 type 으로 좁힌다. 사용자가 ToolSpec<TWrite, TAction> generic 까지 정밀화하면
|
|
29
|
+
// 좋겠지만, 11~50 개 spec 마다 type 인자 전파가 부담이라 unknown 으로 합의.
|
|
30
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
31
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../server/service/tool-registry/types.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,uEAAuE;AACvE,kEAAkE;AAClE,iFAAiF;AACjF,mEAAmE;AACnE,wDAAwD","sourcesContent":["/**\n * Tool Registry — board-ai 의 LLM tool 노출 plugin point.\n *\n * 동기:\n * 기존엔 board-ai 가 자기 도메인 (board edit) tool 들만 hardcoded 정의했고, styling\n * 영역만 STYLING_TOOLS registry 로 분리되어 있었다. 외부 도메인 패키지 (board-import,\n * fmsim 등) 가 자기 tool 을 LLM 에 노출하려면 board-ai 자체를 fork/수정해야 했다.\n *\n * 본 registry 는 외부 패키지가 server bootstrap 시 자기 tool category 를 등록하면\n * assistant.ts 의 buildBoardEditTools / dispatch / isWriteTool 등이 자동으로 통합\n * 하도록 한다. styling-tools 의 single-source-of-truth 패턴을 일반화한 형태.\n *\n * 설계 원칙:\n * - **카테고리별 builder 시그니처 다양성을 통합**: read 는 (args, ctx) → any,\n * write 는 (args, components) → BoardEditOp[], action 은 (args) → BoardActionOp.\n * 하나의 ToolSpec 에 모든 시그니처를 union 으로 담지 않고, 카테고리에 맞는\n * builder 만 채우면 되도록 카테고리별 sub-interface 분리.\n * - **kind 필드로 자가 분류**: registry 가 isReadTool / isWriteTool 자동 도출.\n * hardcoded set 동기화 누락 위험 제거.\n * - **점진 마이그레이션**: 기존 STYLING_TOOLS 가 본 registry 의 첫 사용자.\n * 점진적으로 다른 hardcoded tool 들 (addComponent / alignComponents 등) 도\n * 같은 registry 로 흡수 가능. 한 단계씩 byte-단위 동등성 단위 테스트 보장.\n */\n// 본 registry 는 LLM tool 노출 plugin point 에 한정되므로 도메인 type (BoardEditOp,\n// BoardActionOp 등) 은 알지 않는다. builder return 은 unknown 으로 두고, 카테고리\n// dispatcher (board-ai 의 toolCallToBoardEditOp / toolCallToBoardActionOp 등) 가 자기\n// 도메인 type 으로 좁힌다. 사용자가 ToolSpec<TWrite, TAction> generic 까지 정밀화하면\n// 좋겠지만, 11~50 개 spec 마다 type 인자 전파가 부담이라 unknown 으로 합의.\n\n// ── 카테고리별 builder 시그니처 ──────────────────────────────────────\n\n/**\n * Read tool — server 측 즉시 실행, 결과를 LLM 에 회신. board model 변경 X.\n * 예: getSelection / findComponents / importSession (query)\n */\nexport type ReadToolBuilder = (\n args: any,\n context: ReadToolContext\n) => any | Promise<any>\n\nexport interface ReadToolContext {\n /** 현재 board model — 일부 read tool 이 사용 (getSelection 등). */\n board?: any\n /** 현재 선택된 refids. */\n selectedRefids?: number[]\n /** 호출자 도메인 / 사용자 / 트랜잭션. registry 외부에서 주입. */\n state?: any\n /** 이외 주입은 카테고리별로 자유. tool 등록자가 type 좁힐 수 있도록 unknown 으로 보존. */\n [k: string]: any\n}\n\n/**\n * Write tool — domain edit op 발생. host 가 patch 적용 후 영속화.\n * 예: board-ai 의 addComponent / setFill / modifyBoard.\n *\n * builder 의 return type 은 unknown 으로 둔다 — 도메인별 dispatcher (예: board-ai 의\n * toolCallToBoardEditOp) 가 자기 EditOp[] 로 cast. ops/errors wrapper 형태도 동일 의미.\n */\nexport type WriteToolBuilder = (\n args: any,\n context: WriteToolContext\n) => any[] | { ops: any[]; errors?: string[] } | null\n\nexport interface WriteToolContext {\n components?: ReadonlyArray<any>\n [k: string]: any\n}\n\n/**\n * Action tool — ephemeral scene 조작 (select / center / fit / sceneMode).\n * board model 변경 X, undo 영향 X. host 가 별도 channel 로 적용.\n *\n * return type 은 unknown — 도메인별 dispatcher (예: board-ai 의 toolCallToBoardActionOp)\n * 가 자기 BoardActionOp 으로 cast.\n */\nexport type ActionToolBuilder = (args: any) => any | null\n\n/**\n * External-call tool — 외부 service / mutation / RPC 호출. 직접 board model 영향 X\n * (별도 entity 변경은 가능). 결과는 LLM 에 회신.\n *\n * board-import 의 importBoardAsync / materializeImportSession 같이 board-ai 외부\n * 도메인을 호출하는 tool 의 카테고리.\n */\nexport type ExternalToolBuilder = (\n args: any,\n context: ExternalToolContext\n) => any | Promise<any>\n\nexport interface ExternalToolContext {\n state?: any\n [k: string]: any\n}\n\n// ── ToolSpec — 카테고리별 변형 ──────────────────────────────────────\n\n/**\n * 모든 ToolSpec 공통 메타데이터.\n */\nexport interface ToolSpecBase {\n /** AIToolCall.name 매칭. 전 카테고리 통틀어 unique. */\n name: string\n /** 기능 설명 (영문 위주). LLM 의 tool description 으로 사용. */\n description: string\n /**\n * 선택 — 정책 / 테마 가이드 단문. tool description 끝에 자동 부착.\n * styling-tools 의 themeNote 와 동일 의미. 기타 카테고리도 사용 가능.\n */\n themeNote?: string\n /** JSON Schema for parameters — LLM tool schema 에 그대로 노출. */\n schema: any\n}\n\nexport interface ReadToolSpec extends ToolSpecBase {\n kind: 'read'\n builder: ReadToolBuilder\n}\n\nexport interface WriteToolSpec extends ToolSpecBase {\n kind: 'write'\n builder: WriteToolBuilder\n}\n\nexport interface ActionToolSpec extends ToolSpecBase {\n kind: 'action'\n builder: ActionToolBuilder\n}\n\nexport interface ExternalToolSpec extends ToolSpecBase {\n kind: 'external'\n builder: ExternalToolBuilder\n}\n\nexport type ToolSpec = ReadToolSpec | WriteToolSpec | ActionToolSpec | ExternalToolSpec\n\n// ── 카테고리 (등록 단위) ─────────────────────────────────────────────\n\n/**\n * 한 도메인 / 패키지가 등록하는 tool 묶음.\n * 카테고리 이름은 식별자 (debug log / 분쟁 시 origin 추적). unique.\n */\nexport interface ToolCategory {\n /** 등록 식별자. 예: 'styling', 'board-import', 'fmsim'. */\n name: string\n /** 이 카테고리에 속한 tool spec 들. */\n specs: ToolSpec[]\n /** 선택 — 디버깅용 짧은 설명. */\n description?: string\n}\n"]}
|