@gravity-ui/aikit 2.3.0 → 2.4.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/build/cjs/components/organisms/AssistantMessage/defaultMessageTypeRegistry.js +6 -0
- package/build/cjs/components/organisms/AssistantMessage/defaultMessageTypeRegistry.js.map +1 -1
- package/build/cjs/hooks/index.d.ts +2 -0
- package/build/cjs/hooks/index.js +2 -0
- package/build/cjs/hooks/index.js.map +1 -1
- package/build/cjs/hooks/useToolResultContinuation.d.ts +31 -0
- package/build/cjs/hooks/useToolResultContinuation.js +91 -0
- package/build/cjs/hooks/useToolResultContinuation.js.map +1 -0
- package/build/cjs/hooks/useToolset.d.ts +24 -0
- package/build/cjs/hooks/useToolset.js +26 -0
- package/build/cjs/hooks/useToolset.js.map +1 -0
- package/build/cjs/package.json +1 -1
- package/build/cjs/utils/index.d.ts +1 -0
- package/build/cjs/utils/index.js +1 -0
- package/build/cjs/utils/index.js.map +1 -1
- package/build/cjs/utils/messageTypeRegistry.d.ts +8 -1
- package/build/cjs/utils/messageTypeRegistry.js +14 -2
- package/build/cjs/utils/messageTypeRegistry.js.map +1 -1
- package/build/cjs/utils/toolset/i18n/en.json +3 -0
- package/build/cjs/utils/toolset/i18n/index.d.ts +13 -0
- package/build/cjs/utils/toolset/i18n/index.js +10 -0
- package/build/cjs/utils/toolset/i18n/index.js.map +1 -0
- package/build/cjs/utils/toolset/i18n/ru.json +3 -0
- package/build/cjs/utils/toolset/index.d.ts +142 -0
- package/build/cjs/utils/toolset/index.js +183 -0
- package/build/cjs/utils/toolset/index.js.map +1 -0
- package/build/esm/components/organisms/AssistantMessage/defaultMessageTypeRegistry.js +6 -0
- package/build/esm/components/organisms/AssistantMessage/defaultMessageTypeRegistry.js.map +1 -1
- package/build/esm/hooks/index.d.ts +2 -0
- package/build/esm/hooks/index.js +2 -0
- package/build/esm/hooks/index.js.map +1 -1
- package/build/esm/hooks/useToolResultContinuation.d.ts +31 -0
- package/build/esm/hooks/useToolResultContinuation.js +87 -0
- package/build/esm/hooks/useToolResultContinuation.js.map +1 -0
- package/build/esm/hooks/useToolset.d.ts +24 -0
- package/build/esm/hooks/useToolset.js +23 -0
- package/build/esm/hooks/useToolset.js.map +1 -0
- package/build/esm/package.json +1 -1
- package/build/esm/utils/index.d.ts +1 -0
- package/build/esm/utils/index.js +1 -0
- package/build/esm/utils/index.js.map +1 -1
- package/build/esm/utils/messageTypeRegistry.d.ts +8 -1
- package/build/esm/utils/messageTypeRegistry.js +14 -2
- package/build/esm/utils/messageTypeRegistry.js.map +1 -1
- package/build/esm/utils/toolset/i18n/en.json +3 -0
- package/build/esm/utils/toolset/i18n/index.d.ts +13 -0
- package/build/esm/utils/toolset/i18n/index.js +6 -0
- package/build/esm/utils/toolset/i18n/index.js.map +1 -0
- package/build/esm/utils/toolset/i18n/ru.json +3 -0
- package/build/esm/utils/toolset/index.d.ts +142 -0
- package/build/esm/utils/toolset/index.js +176 -0
- package/build/esm/utils/toolset/index.js.map +1 -0
- package/docs/GENUI.md +627 -0
- package/docs/HOOKS.md +65 -11
- package/llms.txt +2 -1
- package/package.json +11 -1
|
@@ -10,12 +10,18 @@ function createDefaultMessageRegistry(transformOptions, shouldParseIncompleteMar
|
|
|
10
10
|
const registry = (0, messageTypeRegistry_1.createMessageRendererRegistry)();
|
|
11
11
|
(0, messageTypeRegistry_1.registerMessageRenderer)(registry, 'text', {
|
|
12
12
|
component: ({ part }) => ((0, jsx_runtime_1.jsx)(MarkdownRenderer_1.MarkdownRenderer, { content: part.data.text, transformOptions: transformOptions, shouldParseIncompleteMarkdown: shouldParseIncompleteMarkdown })),
|
|
13
|
+
}, {
|
|
14
|
+
isDefault: true,
|
|
13
15
|
});
|
|
14
16
|
(0, messageTypeRegistry_1.registerMessageRenderer)(registry, 'tool', {
|
|
15
17
|
component: ({ part }) => (0, jsx_runtime_1.jsx)(ToolMessage_1.ToolMessage, Object.assign({}, part.data)),
|
|
18
|
+
}, {
|
|
19
|
+
isDefault: true,
|
|
16
20
|
});
|
|
17
21
|
(0, messageTypeRegistry_1.registerMessageRenderer)(registry, 'thinking', {
|
|
18
22
|
component: ({ part }) => (0, jsx_runtime_1.jsx)(ThinkingMessage_1.ThinkingMessage, Object.assign({}, part.data)),
|
|
23
|
+
}, {
|
|
24
|
+
isDefault: true,
|
|
19
25
|
});
|
|
20
26
|
return registry;
|
|
21
27
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"defaultMessageTypeRegistry.js","sourceRoot":"../../../../../src","sources":["components/organisms/AssistantMessage/defaultMessageTypeRegistry.tsx"],"names":[],"mappings":";;AAgBA,
|
|
1
|
+
{"version":3,"file":"defaultMessageTypeRegistry.js","sourceRoot":"../../../../../src","sources":["components/organisms/AssistantMessage/defaultMessageTypeRegistry.tsx"],"names":[],"mappings":";;AAgBA,oEA8CC;;AAvDD,+EAI4C;AAC5C,4EAA8D;AAC9D,iEAAmD;AACnD,yDAA2C;AAE3C,SAAgB,4BAA4B,CACxC,gBAA8B,EAC9B,6BAAuC;IAEvC,MAAM,QAAQ,GAAG,IAAA,mDAA6B,GAAE,CAAC;IAEjD,IAAA,6CAAuB,EACnB,QAAQ,EACR,MAAM,EACN;QACI,SAAS,EAAE,CAAC,EAAC,IAAI,EAAC,EAAE,EAAE,CAAC,CACnB,uBAAC,mCAAgB,IACb,OAAO,EAAE,IAAI,CAAC,IAAI,CAAC,IAAI,EACvB,gBAAgB,EAAE,gBAAgB,EAClC,6BAA6B,EAAE,6BAA6B,GAC9D,CACL;KACJ,EACD;QACI,SAAS,EAAE,IAAI;KAClB,CACJ,CAAC;IAEF,IAAA,6CAAuB,EACnB,QAAQ,EACR,MAAM,EACN;QACI,SAAS,EAAE,CAAC,EAAC,IAAI,EAAC,EAAE,EAAE,CAAC,uBAAC,yBAAW,oBAAK,IAAI,CAAC,IAAI,EAAI;KACxD,EACD;QACI,SAAS,EAAE,IAAI;KAClB,CACJ,CAAC;IAEF,IAAA,6CAAuB,EACnB,QAAQ,EACR,UAAU,EACV;QACI,SAAS,EAAE,CAAC,EAAC,IAAI,EAAC,EAAE,EAAE,CAAC,uBAAC,iCAAe,oBAAK,IAAI,CAAC,IAAI,EAAI;KAC5D,EACD;QACI,SAAS,EAAE,IAAI;KAClB,CACJ,CAAC;IAEF,OAAO,QAAQ,CAAC;AACpB,CAAC","sourcesContent":["import type {OptionsType} from '@diplodoc/transform/lib/typings';\n\nimport type {\n TextMessageContent,\n ThinkingMessageContent,\n ToolMessageContent,\n} from '../../../types/messages';\nimport {\n type MessageRendererRegistry,\n createMessageRendererRegistry,\n registerMessageRenderer,\n} from '../../../utils/messageTypeRegistry';\nimport {MarkdownRenderer} from '../../atoms/MarkdownRenderer';\nimport {ThinkingMessage} from '../ThinkingMessage';\nimport {ToolMessage} from '../ToolMessage';\n\nexport function createDefaultMessageRegistry(\n transformOptions?: OptionsType,\n shouldParseIncompleteMarkdown?: boolean,\n): MessageRendererRegistry {\n const registry = createMessageRendererRegistry();\n\n registerMessageRenderer<TextMessageContent>(\n registry,\n 'text',\n {\n component: ({part}) => (\n <MarkdownRenderer\n content={part.data.text}\n transformOptions={transformOptions}\n shouldParseIncompleteMarkdown={shouldParseIncompleteMarkdown}\n />\n ),\n },\n {\n isDefault: true,\n },\n );\n\n registerMessageRenderer<ToolMessageContent>(\n registry,\n 'tool',\n {\n component: ({part}) => <ToolMessage {...part.data} />,\n },\n {\n isDefault: true,\n },\n );\n\n registerMessageRenderer<ThinkingMessageContent>(\n registry,\n 'thinking',\n {\n component: ({part}) => <ThinkingMessage {...part.data} />,\n },\n {\n isDefault: true,\n },\n );\n\n return registry;\n}\n"]}
|
package/build/cjs/hooks/index.js
CHANGED
|
@@ -8,4 +8,6 @@ tslib_1.__exportStar(require("./useScrollPreservation.js"), exports);
|
|
|
8
8
|
tslib_1.__exportStar(require("./useAutoCollapseOnSuccess.js"), exports);
|
|
9
9
|
tslib_1.__exportStar(require("./useAutoCollapseOnCancelled.js"), exports);
|
|
10
10
|
tslib_1.__exportStar(require("./useFileUploadStore.js"), exports);
|
|
11
|
+
tslib_1.__exportStar(require("./useToolset.js"), exports);
|
|
12
|
+
tslib_1.__exportStar(require("./useToolResultContinuation.js"), exports);
|
|
11
13
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"../../../src","sources":["hooks/index.ts"],"names":[],"mappings":";;;AAAA,sEAAmC;AACnC,8DAAiC;AACjC,8DAAiC;AACjC,qEAAwC;AACxC,wEAA2C;AAC3C,0EAA6C;AAC7C,kEAAqC","sourcesContent":["export * from './useDateFormatter';\nexport * from './useToolMessage';\nexport * from './useSmartScroll';\nexport * from './useScrollPreservation';\nexport * from './useAutoCollapseOnSuccess';\nexport * from './useAutoCollapseOnCancelled';\nexport * from './useFileUploadStore';\n"]}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"../../../src","sources":["hooks/index.ts"],"names":[],"mappings":";;;AAAA,sEAAmC;AACnC,8DAAiC;AACjC,8DAAiC;AACjC,qEAAwC;AACxC,wEAA2C;AAC3C,0EAA6C;AAC7C,kEAAqC;AACrC,0DAA6B;AAC7B,yEAA4C","sourcesContent":["export * from './useDateFormatter';\nexport * from './useToolMessage';\nexport * from './useSmartScroll';\nexport * from './useScrollPreservation';\nexport * from './useAutoCollapseOnSuccess';\nexport * from './useAutoCollapseOnCancelled';\nexport * from './useFileUploadStore';\nexport * from './useToolset';\nexport * from './useToolResultContinuation';\n"]}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { TChatMessage, TMessageContent } from "../types/messages.js";
|
|
2
|
+
import { type ToolExecutionStatus } from "../utils/toolset/index.js";
|
|
3
|
+
export type ToolSettledEvent<TCustom extends TMessageContent = never> = {
|
|
4
|
+
toolCallId: string;
|
|
5
|
+
toolName: string;
|
|
6
|
+
status: ToolExecutionStatus;
|
|
7
|
+
messages: TChatMessage<TCustom>[];
|
|
8
|
+
};
|
|
9
|
+
export type UseToolResultContinuationOptions<TCustom extends TMessageContent = never> = {
|
|
10
|
+
messages: TChatMessage<TCustom>[];
|
|
11
|
+
/**
|
|
12
|
+
* Called once per tool that transitioned from a pending status
|
|
13
|
+
* (`waitingConfirmation`, `waitingSubmission`, `loading`) to a terminal
|
|
14
|
+
* one (`success`, `error`, `cancelled`). Typical use: forward the
|
|
15
|
+
* updated transcript to the model.
|
|
16
|
+
*/
|
|
17
|
+
onSettled: (event: ToolSettledEvent<TCustom>) => void;
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* Pure: returns events for every tool whose status was pending in `prev`
|
|
21
|
+
* and is terminal in `next`. Tools that are already terminal in `prev`
|
|
22
|
+
* (replay/restore) do not produce events.
|
|
23
|
+
*/
|
|
24
|
+
export declare function findNewlySettledTools<TCustom extends TMessageContent = never>(prev: TChatMessage<TCustom>[], next: TChatMessage<TCustom>[]): ToolSettledEvent<TCustom>[];
|
|
25
|
+
/**
|
|
26
|
+
* Observe `messages` and fire `onSettled` once whenever a tool part
|
|
27
|
+
* transitions from pending to terminal. Tools already terminal on the
|
|
28
|
+
* first observed snapshot do not fire — replay/restore is intentionally
|
|
29
|
+
* silent. Pair with `useToolset` to forward results to the model.
|
|
30
|
+
*/
|
|
31
|
+
export declare function useToolResultContinuation<TCustom extends TMessageContent = never>(options: UseToolResultContinuationOptions<TCustom>): void;
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.findNewlySettledTools = findNewlySettledTools;
|
|
4
|
+
exports.useToolResultContinuation = useToolResultContinuation;
|
|
5
|
+
const react_1 = require("react");
|
|
6
|
+
const PENDING_STATUSES = new Set([
|
|
7
|
+
'waitingConfirmation',
|
|
8
|
+
'waitingSubmission',
|
|
9
|
+
'loading',
|
|
10
|
+
]);
|
|
11
|
+
const TERMINAL_STATUSES = new Set([
|
|
12
|
+
'success',
|
|
13
|
+
'error',
|
|
14
|
+
'cancelled',
|
|
15
|
+
]);
|
|
16
|
+
function isPending(status) {
|
|
17
|
+
return status !== undefined && PENDING_STATUSES.has(status);
|
|
18
|
+
}
|
|
19
|
+
function isTerminal(status) {
|
|
20
|
+
return status !== undefined && TERMINAL_STATUSES.has(status);
|
|
21
|
+
}
|
|
22
|
+
function isToolPartContent(part) {
|
|
23
|
+
return (part.type === 'tool' &&
|
|
24
|
+
typeof part.data === 'object' &&
|
|
25
|
+
part.data !== null &&
|
|
26
|
+
'toolCallId' in part.data);
|
|
27
|
+
}
|
|
28
|
+
function toContentParts(content) {
|
|
29
|
+
if (typeof content === 'string')
|
|
30
|
+
return [];
|
|
31
|
+
return Array.isArray(content) ? content : [content];
|
|
32
|
+
}
|
|
33
|
+
function collectToolPartsByCallId(messages) {
|
|
34
|
+
const map = new Map();
|
|
35
|
+
for (const msg of messages) {
|
|
36
|
+
if (msg.role !== 'assistant')
|
|
37
|
+
continue;
|
|
38
|
+
for (const part of toContentParts(msg.content)) {
|
|
39
|
+
if (!part || typeof part !== 'object')
|
|
40
|
+
continue;
|
|
41
|
+
if (!isToolPartContent(part))
|
|
42
|
+
continue;
|
|
43
|
+
map.set(part.data.toolCallId, part.data);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return map;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Pure: returns events for every tool whose status was pending in `prev`
|
|
50
|
+
* and is terminal in `next`. Tools that are already terminal in `prev`
|
|
51
|
+
* (replay/restore) do not produce events.
|
|
52
|
+
*/
|
|
53
|
+
function findNewlySettledTools(prev, next) {
|
|
54
|
+
var _a;
|
|
55
|
+
const prevParts = collectToolPartsByCallId(prev);
|
|
56
|
+
const events = [];
|
|
57
|
+
for (const [toolCallId, data] of collectToolPartsByCallId(next)) {
|
|
58
|
+
const prevStatus = (_a = prevParts.get(toolCallId)) === null || _a === void 0 ? void 0 : _a.status;
|
|
59
|
+
if (isPending(prevStatus) && isTerminal(data.status)) {
|
|
60
|
+
events.push({
|
|
61
|
+
toolCallId,
|
|
62
|
+
toolName: data.toolName,
|
|
63
|
+
status: data.status,
|
|
64
|
+
messages: next,
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
return events;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Observe `messages` and fire `onSettled` once whenever a tool part
|
|
72
|
+
* transitions from pending to terminal. Tools already terminal on the
|
|
73
|
+
* first observed snapshot do not fire — replay/restore is intentionally
|
|
74
|
+
* silent. Pair with `useToolset` to forward results to the model.
|
|
75
|
+
*/
|
|
76
|
+
function useToolResultContinuation(options) {
|
|
77
|
+
const { messages, onSettled } = options;
|
|
78
|
+
const onSettledRef = (0, react_1.useRef)(onSettled);
|
|
79
|
+
(0, react_1.useEffect)(() => {
|
|
80
|
+
onSettledRef.current = onSettled;
|
|
81
|
+
});
|
|
82
|
+
const prevMessagesRef = (0, react_1.useRef)(messages);
|
|
83
|
+
(0, react_1.useEffect)(() => {
|
|
84
|
+
const events = findNewlySettledTools(prevMessagesRef.current, messages);
|
|
85
|
+
prevMessagesRef.current = messages;
|
|
86
|
+
for (const event of events) {
|
|
87
|
+
onSettledRef.current(event);
|
|
88
|
+
}
|
|
89
|
+
}, [messages]);
|
|
90
|
+
}
|
|
91
|
+
//# sourceMappingURL=useToolResultContinuation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useToolResultContinuation.js","sourceRoot":"../../../src","sources":["hooks/useToolResultContinuation.ts"],"names":[],"mappings":";;AAoFA,sDAkBC;AAQD,8DAmBC;AAjID,iCAAwC;AA4BxC,MAAM,gBAAgB,GAA6B,IAAI,GAAG,CAAc;IACpE,qBAAqB;IACrB,mBAAmB;IACnB,SAAS;CACZ,CAAC,CAAC;AAEH,MAAM,iBAAiB,GAA6B,IAAI,GAAG,CAAc;IACrE,SAAS;IACT,OAAO;IACP,WAAW;CACd,CAAC,CAAC;AAEH,SAAS,SAAS,CAAC,MAA+B;IAC9C,OAAO,MAAM,KAAK,SAAS,IAAI,gBAAgB,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;AAChE,CAAC;AAED,SAAS,UAAU,CAAC,MAA+B;IAC/C,OAAO,MAAM,KAAK,SAAS,IAAI,iBAAiB,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;AACjE,CAAC;AAED,SAAS,iBAAiB,CAAC,IAAqB;IAC5C,OAAO,CACH,IAAI,CAAC,IAAI,KAAK,MAAM;QACpB,OAAO,IAAI,CAAC,IAAI,KAAK,QAAQ;QAC7B,IAAI,CAAC,IAAI,KAAK,IAAI;QAClB,YAAY,IAAI,IAAI,CAAC,IAAI,CAC5B,CAAC;AACN,CAAC;AAED,SAAS,cAAc,CACnB,OAAyC;IAEzC,IAAI,OAAO,OAAO,KAAK,QAAQ;QAAE,OAAO,EAAE,CAAC;IAC3C,OAAO,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;AACxD,CAAC;AAED,SAAS,wBAAwB,CAC7B,QAAiC;IAEjC,MAAM,GAAG,GAAG,IAAI,GAAG,EAA+B,CAAC;IACnD,KAAK,MAAM,GAAG,IAAI,QAAQ,EAAE,CAAC;QACzB,IAAI,GAAG,CAAC,IAAI,KAAK,WAAW;YAAE,SAAS;QACvC,KAAK,MAAM,IAAI,IAAI,cAAc,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC;YAC7C,IAAI,CAAC,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ;gBAAE,SAAS;YAChD,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC;gBAAE,SAAS;YACvC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;QAC7C,CAAC;IACL,CAAC;IACD,OAAO,GAAG,CAAC;AACf,CAAC;AAED;;;;GAIG;AACH,SAAgB,qBAAqB,CACjC,IAA6B,EAC7B,IAA6B;;IAE7B,MAAM,SAAS,GAAG,wBAAwB,CAAC,IAAI,CAAC,CAAC;IACjD,MAAM,MAAM,GAAgC,EAAE,CAAC;IAC/C,KAAK,MAAM,CAAC,UAAU,EAAE,IAAI,CAAC,IAAI,wBAAwB,CAAC,IAAI,CAAC,EAAE,CAAC;QAC9D,MAAM,UAAU,GAAG,MAAA,SAAS,CAAC,GAAG,CAAC,UAAU,CAAC,0CAAE,MAAM,CAAC;QACrD,IAAI,SAAS,CAAC,UAAU,CAAC,IAAI,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;YACnD,MAAM,CAAC,IAAI,CAAC;gBACR,UAAU;gBACV,QAAQ,EAAE,IAAI,CAAC,QAAQ;gBACvB,MAAM,EAAE,IAAI,CAAC,MAAM;gBACnB,QAAQ,EAAE,IAAI;aACjB,CAAC,CAAC;QACP,CAAC;IACL,CAAC;IACD,OAAO,MAAM,CAAC;AAClB,CAAC;AAED;;;;;GAKG;AACH,SAAgB,yBAAyB,CACrC,OAAkD;IAElD,MAAM,EAAC,QAAQ,EAAE,SAAS,EAAC,GAAG,OAAO,CAAC;IAEtC,MAAM,YAAY,GAAG,IAAA,cAAM,EAAC,SAAS,CAAC,CAAC;IACvC,IAAA,iBAAS,EAAC,GAAG,EAAE;QACX,YAAY,CAAC,OAAO,GAAG,SAAS,CAAC;IACrC,CAAC,CAAC,CAAC;IAEH,MAAM,eAAe,GAAG,IAAA,cAAM,EAAC,QAAQ,CAAC,CAAC;IAEzC,IAAA,iBAAS,EAAC,GAAG,EAAE;QACX,MAAM,MAAM,GAAG,qBAAqB,CAAC,eAAe,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;QACxE,eAAe,CAAC,OAAO,GAAG,QAAQ,CAAC;QACnC,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;YACzB,YAAY,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;QAChC,CAAC;IACL,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC;AACnB,CAAC","sourcesContent":["import {useEffect, useRef} from 'react';\n\nimport type {TChatMessage, TMessageContent} from '../types/messages';\nimport type {TToolStatus} from '../types/tool';\nimport {\n type ToolExecutionStatus,\n type ToolPartContent,\n type ToolPartContentData,\n} from '../utils/toolset';\n\nexport type ToolSettledEvent<TCustom extends TMessageContent = never> = {\n toolCallId: string;\n toolName: string;\n status: ToolExecutionStatus;\n messages: TChatMessage<TCustom>[];\n};\n\nexport type UseToolResultContinuationOptions<TCustom extends TMessageContent = never> = {\n messages: TChatMessage<TCustom>[];\n /**\n * Called once per tool that transitioned from a pending status\n * (`waitingConfirmation`, `waitingSubmission`, `loading`) to a terminal\n * one (`success`, `error`, `cancelled`). Typical use: forward the\n * updated transcript to the model.\n */\n onSettled: (event: ToolSettledEvent<TCustom>) => void;\n};\n\nconst PENDING_STATUSES: ReadonlySet<TToolStatus> = new Set<TToolStatus>([\n 'waitingConfirmation',\n 'waitingSubmission',\n 'loading',\n]);\n\nconst TERMINAL_STATUSES: ReadonlySet<TToolStatus> = new Set<TToolStatus>([\n 'success',\n 'error',\n 'cancelled',\n]);\n\nfunction isPending(status: TToolStatus | undefined): boolean {\n return status !== undefined && PENDING_STATUSES.has(status);\n}\n\nfunction isTerminal(status: TToolStatus | undefined): status is ToolExecutionStatus {\n return status !== undefined && TERMINAL_STATUSES.has(status);\n}\n\nfunction isToolPartContent(part: TMessageContent): part is ToolPartContent {\n return (\n part.type === 'tool' &&\n typeof part.data === 'object' &&\n part.data !== null &&\n 'toolCallId' in part.data\n );\n}\n\nfunction toContentParts<TCustom extends TMessageContent>(\n content: TChatMessage<TCustom>['content'],\n): TMessageContent[] {\n if (typeof content === 'string') return [];\n return Array.isArray(content) ? content : [content];\n}\n\nfunction collectToolPartsByCallId<TCustom extends TMessageContent>(\n messages: TChatMessage<TCustom>[],\n): Map<string, ToolPartContentData> {\n const map = new Map<string, ToolPartContentData>();\n for (const msg of messages) {\n if (msg.role !== 'assistant') continue;\n for (const part of toContentParts(msg.content)) {\n if (!part || typeof part !== 'object') continue;\n if (!isToolPartContent(part)) continue;\n map.set(part.data.toolCallId, part.data);\n }\n }\n return map;\n}\n\n/**\n * Pure: returns events for every tool whose status was pending in `prev`\n * and is terminal in `next`. Tools that are already terminal in `prev`\n * (replay/restore) do not produce events.\n */\nexport function findNewlySettledTools<TCustom extends TMessageContent = never>(\n prev: TChatMessage<TCustom>[],\n next: TChatMessage<TCustom>[],\n): ToolSettledEvent<TCustom>[] {\n const prevParts = collectToolPartsByCallId(prev);\n const events: ToolSettledEvent<TCustom>[] = [];\n for (const [toolCallId, data] of collectToolPartsByCallId(next)) {\n const prevStatus = prevParts.get(toolCallId)?.status;\n if (isPending(prevStatus) && isTerminal(data.status)) {\n events.push({\n toolCallId,\n toolName: data.toolName,\n status: data.status,\n messages: next,\n });\n }\n }\n return events;\n}\n\n/**\n * Observe `messages` and fire `onSettled` once whenever a tool part\n * transitions from pending to terminal. Tools already terminal on the\n * first observed snapshot do not fire — replay/restore is intentionally\n * silent. Pair with `useToolset` to forward results to the model.\n */\nexport function useToolResultContinuation<TCustom extends TMessageContent = never>(\n options: UseToolResultContinuationOptions<TCustom>,\n): void {\n const {messages, onSettled} = options;\n\n const onSettledRef = useRef(onSettled);\n useEffect(() => {\n onSettledRef.current = onSettled;\n });\n\n const prevMessagesRef = useRef(messages);\n\n useEffect(() => {\n const events = findNewlySettledTools(prevMessagesRef.current, messages);\n prevMessagesRef.current = messages;\n for (const event of events) {\n onSettledRef.current(event);\n }\n }, [messages]);\n}\n"]}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { Dispatch, SetStateAction } from 'react';
|
|
2
|
+
import type { TChatMessage, TMessageContent } from "../types/messages.js";
|
|
3
|
+
import type { MessageRendererRegistry } from "../utils/messageTypeRegistry.js";
|
|
4
|
+
import { type Toolset, type ToolsetResultEvent } from "../utils/toolset/index.js";
|
|
5
|
+
export type UseToolsetOptions<TCustom extends TMessageContent = never> = {
|
|
6
|
+
toolset: Toolset;
|
|
7
|
+
setMessages: Dispatch<SetStateAction<TChatMessage<TCustom>[]>>;
|
|
8
|
+
/** Existing registry to extend instead of starting from a fresh one. */
|
|
9
|
+
registry?: MessageRendererRegistry;
|
|
10
|
+
};
|
|
11
|
+
export type UseToolsetReturn = {
|
|
12
|
+
messageRendererRegistry: MessageRendererRegistry;
|
|
13
|
+
handleToolResult: (event: ToolsetResultEvent) => void;
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* Wire a toolset into the chat: returns a `MessageRendererRegistry` that
|
|
17
|
+
* renders tool parts via the toolset and a `handleToolResult` callback
|
|
18
|
+
* that merges results into history. To react to tool completion (e.g.
|
|
19
|
+
* forward to the model), pair with `useToolResultContinuation`.
|
|
20
|
+
*
|
|
21
|
+
* Pass the same `toolset` reference across renders (e.g. via `useMemo` or
|
|
22
|
+
* `createToolset`) so the registry stays stable.
|
|
23
|
+
*/
|
|
24
|
+
export declare function useToolset<TCustom extends TMessageContent = never>(options: UseToolsetOptions<TCustom>): UseToolsetReturn;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.useToolset = useToolset;
|
|
4
|
+
const react_1 = require("react");
|
|
5
|
+
const toolset_1 = require("../utils/toolset/index.js");
|
|
6
|
+
/**
|
|
7
|
+
* Wire a toolset into the chat: returns a `MessageRendererRegistry` that
|
|
8
|
+
* renders tool parts via the toolset and a `handleToolResult` callback
|
|
9
|
+
* that merges results into history. To react to tool completion (e.g.
|
|
10
|
+
* forward to the model), pair with `useToolResultContinuation`.
|
|
11
|
+
*
|
|
12
|
+
* Pass the same `toolset` reference across renders (e.g. via `useMemo` or
|
|
13
|
+
* `createToolset`) so the registry stays stable.
|
|
14
|
+
*/
|
|
15
|
+
function useToolset(options) {
|
|
16
|
+
const { toolset, setMessages, registry } = options;
|
|
17
|
+
const handleToolResult = (0, react_1.useCallback)((event) => {
|
|
18
|
+
setMessages((prev) => (0, toolset_1.applyToolResult)(prev, event));
|
|
19
|
+
}, [setMessages]);
|
|
20
|
+
const messageRendererRegistry = (0, react_1.useMemo)(() => (0, toolset_1.createToolsetRenderer)(toolset, {
|
|
21
|
+
onToolResult: handleToolResult,
|
|
22
|
+
registry,
|
|
23
|
+
}), [toolset, handleToolResult, registry]);
|
|
24
|
+
return { messageRendererRegistry, handleToolResult };
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=useToolset.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useToolset.js","sourceRoot":"../../../src","sources":["hooks/useToolset.ts"],"names":[],"mappings":";;AAiCA,gCAsBC;AAvDD,iCAA2C;AAK3C,uDAK0B;AAc1B;;;;;;;;GAQG;AACH,SAAgB,UAAU,CACtB,OAAmC;IAEnC,MAAM,EAAC,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAC,GAAG,OAAO,CAAC;IAEjD,MAAM,gBAAgB,GAAG,IAAA,mBAAW,EAChC,CAAC,KAAyB,EAAE,EAAE;QAC1B,WAAW,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAA,yBAAe,EAAC,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC;IACxD,CAAC,EACD,CAAC,WAAW,CAAC,CAChB,CAAC;IAEF,MAAM,uBAAuB,GAAG,IAAA,eAAO,EACnC,GAAG,EAAE,CACD,IAAA,+BAAqB,EAAC,OAAO,EAAE;QAC3B,YAAY,EAAE,gBAAgB;QAC9B,QAAQ;KACX,CAAC,EACN,CAAC,OAAO,EAAE,gBAAgB,EAAE,QAAQ,CAAC,CACxC,CAAC;IAEF,OAAO,EAAC,uBAAuB,EAAE,gBAAgB,EAAC,CAAC;AACvD,CAAC","sourcesContent":["import {useCallback, useMemo} from 'react';\nimport type {Dispatch, SetStateAction} from 'react';\n\nimport type {TChatMessage, TMessageContent} from '../types/messages';\nimport type {MessageRendererRegistry} from '../utils/messageTypeRegistry';\nimport {\n type Toolset,\n type ToolsetResultEvent,\n applyToolResult,\n createToolsetRenderer,\n} from '../utils/toolset';\n\nexport type UseToolsetOptions<TCustom extends TMessageContent = never> = {\n toolset: Toolset;\n setMessages: Dispatch<SetStateAction<TChatMessage<TCustom>[]>>;\n /** Existing registry to extend instead of starting from a fresh one. */\n registry?: MessageRendererRegistry;\n};\n\nexport type UseToolsetReturn = {\n messageRendererRegistry: MessageRendererRegistry;\n handleToolResult: (event: ToolsetResultEvent) => void;\n};\n\n/**\n * Wire a toolset into the chat: returns a `MessageRendererRegistry` that\n * renders tool parts via the toolset and a `handleToolResult` callback\n * that merges results into history. To react to tool completion (e.g.\n * forward to the model), pair with `useToolResultContinuation`.\n *\n * Pass the same `toolset` reference across renders (e.g. via `useMemo` or\n * `createToolset`) so the registry stays stable.\n */\nexport function useToolset<TCustom extends TMessageContent = never>(\n options: UseToolsetOptions<TCustom>,\n): UseToolsetReturn {\n const {toolset, setMessages, registry} = options;\n\n const handleToolResult = useCallback(\n (event: ToolsetResultEvent) => {\n setMessages((prev) => applyToolResult(prev, event));\n },\n [setMessages],\n );\n\n const messageRendererRegistry = useMemo(\n () =>\n createToolsetRenderer(toolset, {\n onToolResult: handleToolResult,\n registry,\n }),\n [toolset, handleToolResult, registry],\n );\n\n return {messageRendererRegistry, handleToolResult};\n}\n"]}
|
package/build/cjs/package.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":"2.
|
|
1
|
+
{"version":"2.4.0","type":"commonjs","sideEffects":["*.css","*.scss"]}
|
package/build/cjs/utils/index.js
CHANGED
|
@@ -7,4 +7,5 @@ tslib_1.__exportStar(require("./messageUtils.js"), exports);
|
|
|
7
7
|
tslib_1.__exportStar(require("./validation.js"), exports);
|
|
8
8
|
tslib_1.__exportStar(require("./messageTypeRegistry.js"), exports);
|
|
9
9
|
tslib_1.__exportStar(require("./clipboardUtils.js"), exports);
|
|
10
|
+
tslib_1.__exportStar(require("./toolset/index.js"), exports);
|
|
10
11
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"../../../src","sources":["utils/index.ts"],"names":[],"mappings":";;;AAAA,mBAAmB;AACnB,yDAA4B;AAC5B,4DAA+B;AAC/B,0DAA6B;AAC7B,mEAAsC;AACtC,8DAAiC","sourcesContent":["// Export utilities\nexport * from './chatUtils';\nexport * from './messageUtils';\nexport * from './validation';\nexport * from './messageTypeRegistry';\nexport * from './clipboardUtils';\n"]}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"../../../src","sources":["utils/index.ts"],"names":[],"mappings":";;;AAAA,mBAAmB;AACnB,yDAA4B;AAC5B,4DAA+B;AAC/B,0DAA6B;AAC7B,mEAAsC;AACtC,8DAAiC;AACjC,6DAA0B","sourcesContent":["// Export utilities\nexport * from './chatUtils';\nexport * from './messageUtils';\nexport * from './validation';\nexport * from './messageTypeRegistry';\nexport * from './clipboardUtils';\nexport * from './toolset';\n"]}
|
|
@@ -8,6 +8,13 @@ export type MessageRenderer<TContent extends TMessageContent = TMessageContent>
|
|
|
8
8
|
};
|
|
9
9
|
export type MessageRendererRegistry = Record<string, MessageRenderer>;
|
|
10
10
|
export declare function createMessageRendererRegistry(): MessageRendererRegistry;
|
|
11
|
-
export
|
|
11
|
+
export type RegisterMessageRendererOptions = {
|
|
12
|
+
/**
|
|
13
|
+
* Marks a renderer as built-in. Replacing built-in renderers is expected
|
|
14
|
+
* when consumers customize the default registry, so it does not warn.
|
|
15
|
+
*/
|
|
16
|
+
isDefault?: boolean;
|
|
17
|
+
};
|
|
18
|
+
export declare function registerMessageRenderer<TContent extends TMessageContent>(registry: MessageRendererRegistry, contentType: TContent['type'], renderer: MessageRenderer<TContent>, options?: RegisterMessageRendererOptions): MessageRendererRegistry;
|
|
12
19
|
export declare function getMessageRenderer(registry: MessageRendererRegistry, contentType: string): React.ComponentType<MessageContentComponentProps> | undefined;
|
|
13
20
|
export declare function mergeMessageRendererRegistries(defaultRegistry: MessageRendererRegistry, customRegistry: MessageRendererRegistry): MessageRendererRegistry;
|
|
@@ -4,12 +4,24 @@ exports.createMessageRendererRegistry = createMessageRendererRegistry;
|
|
|
4
4
|
exports.registerMessageRenderer = registerMessageRenderer;
|
|
5
5
|
exports.getMessageRenderer = getMessageRenderer;
|
|
6
6
|
exports.mergeMessageRendererRegistries = mergeMessageRendererRegistries;
|
|
7
|
+
const defaultRenderers = new WeakSet();
|
|
7
8
|
function createMessageRendererRegistry() {
|
|
8
9
|
return {};
|
|
9
10
|
}
|
|
10
|
-
function registerMessageRenderer(registry, contentType, renderer) {
|
|
11
|
+
function registerMessageRenderer(registry, contentType, renderer, options) {
|
|
12
|
+
const existingRenderer = registry[contentType];
|
|
13
|
+
if (process.env.NODE_ENV !== 'production' &&
|
|
14
|
+
existingRenderer &&
|
|
15
|
+
!defaultRenderers.has(existingRenderer)) {
|
|
16
|
+
// eslint-disable-next-line no-console
|
|
17
|
+
console.warn(`registerMessageRenderer: overwriting existing renderer for content type "${contentType}"`);
|
|
18
|
+
}
|
|
19
|
+
const registeredRenderer = renderer;
|
|
20
|
+
if (options === null || options === void 0 ? void 0 : options.isDefault) {
|
|
21
|
+
defaultRenderers.add(registeredRenderer);
|
|
22
|
+
}
|
|
11
23
|
Object.assign(registry, {
|
|
12
|
-
[contentType]:
|
|
24
|
+
[contentType]: registeredRenderer,
|
|
13
25
|
});
|
|
14
26
|
return registry;
|
|
15
27
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"messageTypeRegistry.js","sourceRoot":"../../../src","sources":["utils/messageTypeRegistry.ts"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"messageTypeRegistry.js","sourceRoot":"../../../src","sources":["utils/messageTypeRegistry.ts"],"names":[],"mappings":";;AAgBA,sEAEC;AAUD,0DAyBC;AAED,gDAKC;AAED,wEAQC;AAxDD,MAAM,gBAAgB,GAAG,IAAI,OAAO,EAAmB,CAAC;AAExD,SAAgB,6BAA6B;IACzC,OAAO,EAAE,CAAC;AACd,CAAC;AAUD,SAAgB,uBAAuB,CACnC,QAAiC,EACjC,WAA6B,EAC7B,QAAmC,EACnC,OAAwC;IAExC,MAAM,gBAAgB,GAAG,QAAQ,CAAC,WAAW,CAAC,CAAC;IAC/C,IACI,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,YAAY;QACrC,gBAAgB;QAChB,CAAC,gBAAgB,CAAC,GAAG,CAAC,gBAAgB,CAAC,EACzC,CAAC;QACC,sCAAsC;QACtC,OAAO,CAAC,IAAI,CACR,4EAA4E,WAAW,GAAG,CAC7F,CAAC;IACN,CAAC;IACD,MAAM,kBAAkB,GAAG,QAAsC,CAAC;IAClE,IAAI,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,SAAS,EAAE,CAAC;QACrB,gBAAgB,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAC;IAC7C,CAAC;IACD,MAAM,CAAC,MAAM,CAAC,QAAQ,EAAE;QACpB,CAAC,WAAW,CAAC,EAAE,kBAAkB;KACpC,CAAC,CAAC;IACH,OAAO,QAAQ,CAAC;AACpB,CAAC;AAED,SAAgB,kBAAkB,CAC9B,QAAiC,EACjC,WAAmB;;IAEnB,OAAO,MAAA,QAAQ,CAAC,WAAW,CAAC,0CAAE,SAAS,CAAC;AAC5C,CAAC;AAED,SAAgB,8BAA8B,CAC1C,eAAwC,EACxC,cAAuC;IAEvC,uCACO,eAAe,GACf,cAAc,EACnB;AACN,CAAC","sourcesContent":["import type React from 'react';\n\nimport type {TMessageContent} from '../types/messages';\n\nexport type MessageContentComponentProps<TContent extends TMessageContent = TMessageContent> = {\n part: TContent;\n};\n\nexport type MessageRenderer<TContent extends TMessageContent = TMessageContent> = {\n component: React.ComponentType<MessageContentComponentProps<TContent>>;\n};\n\nexport type MessageRendererRegistry = Record<string, MessageRenderer>;\n\nconst defaultRenderers = new WeakSet<MessageRenderer>();\n\nexport function createMessageRendererRegistry(): MessageRendererRegistry {\n return {};\n}\n\nexport type RegisterMessageRendererOptions = {\n /**\n * Marks a renderer as built-in. Replacing built-in renderers is expected\n * when consumers customize the default registry, so it does not warn.\n */\n isDefault?: boolean;\n};\n\nexport function registerMessageRenderer<TContent extends TMessageContent>(\n registry: MessageRendererRegistry,\n contentType: TContent['type'],\n renderer: MessageRenderer<TContent>,\n options?: RegisterMessageRendererOptions,\n): MessageRendererRegistry {\n const existingRenderer = registry[contentType];\n if (\n process.env.NODE_ENV !== 'production' &&\n existingRenderer &&\n !defaultRenderers.has(existingRenderer)\n ) {\n // eslint-disable-next-line no-console\n console.warn(\n `registerMessageRenderer: overwriting existing renderer for content type \"${contentType}\"`,\n );\n }\n const registeredRenderer = renderer as unknown as MessageRenderer;\n if (options?.isDefault) {\n defaultRenderers.add(registeredRenderer);\n }\n Object.assign(registry, {\n [contentType]: registeredRenderer,\n });\n return registry;\n}\n\nexport function getMessageRenderer(\n registry: MessageRendererRegistry,\n contentType: string,\n): React.ComponentType<MessageContentComponentProps> | undefined {\n return registry[contentType]?.component;\n}\n\nexport function mergeMessageRendererRegistries(\n defaultRegistry: MessageRendererRegistry,\n customRegistry: MessageRendererRegistry,\n): MessageRendererRegistry {\n return {\n ...defaultRegistry,\n ...customRegistry,\n };\n}\n"]}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export declare const i18n: ((key: "fallback-unknown-tool", params?: import("@gravity-ui/i18n").Params) => string) & {
|
|
2
|
+
Translation: import("react").ComponentType<{
|
|
3
|
+
children: (props: {
|
|
4
|
+
t: (key: "fallback-unknown-tool", params?: import("@gravity-ui/i18n").Params) => string;
|
|
5
|
+
}) => React.ReactNode;
|
|
6
|
+
}>;
|
|
7
|
+
useTranslation: () => {
|
|
8
|
+
t: (key: "fallback-unknown-tool", params?: import("@gravity-ui/i18n").Params) => string;
|
|
9
|
+
};
|
|
10
|
+
keysetData: {
|
|
11
|
+
"g-aikit-Toolset": Record<"fallback-unknown-tool", import("@gravity-ui/i18n").KeyData>;
|
|
12
|
+
};
|
|
13
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.i18n = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const i18n_1 = require("@gravity-ui/uikit/i18n");
|
|
6
|
+
const cn_1 = require("../../cn.js");
|
|
7
|
+
const en_json_1 = tslib_1.__importDefault(require("./en.json"));
|
|
8
|
+
const ru_json_1 = tslib_1.__importDefault(require("./ru.json"));
|
|
9
|
+
exports.i18n = (0, i18n_1.addComponentKeysets)({ en: en_json_1.default, ru: ru_json_1.default }, `${cn_1.NAMESPACE}Toolset`);
|
|
10
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"../../../../../src","sources":["utils/toolset/i18n/index.ts"],"names":[],"mappings":";;;;AAAA,iDAA2D;AAE3D,oCAAmC;AAEnC,gEAA2B;AAC3B,gEAA2B;AAEd,QAAA,IAAI,GAAG,IAAA,0BAAmB,EAAC,EAAC,EAAE,EAAF,iBAAE,EAAE,EAAE,EAAF,iBAAE,EAAC,EAAE,GAAG,cAAS,SAAS,CAAC,CAAC","sourcesContent":["import {addComponentKeysets} from '@gravity-ui/uikit/i18n';\n\nimport {NAMESPACE} from '../../cn';\n\nimport en from './en.json';\nimport ru from './ru.json';\n\nexport const i18n = addComponentKeysets({en, ru}, `${NAMESPACE}Toolset`);\n"]}
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import type { ComponentType } from 'react';
|
|
2
|
+
import type { TChatMessage, TMessageContent, ToolMessageContentData } from "../../types/messages.js";
|
|
3
|
+
import { type MessageRendererRegistry } from "../messageTypeRegistry.js";
|
|
4
|
+
export type ToolSchemaResult<TArgs> = {
|
|
5
|
+
success: true;
|
|
6
|
+
data: TArgs;
|
|
7
|
+
} | {
|
|
8
|
+
success: false;
|
|
9
|
+
error: {
|
|
10
|
+
message: string;
|
|
11
|
+
};
|
|
12
|
+
};
|
|
13
|
+
export type ToolSchema<TArgs> = {
|
|
14
|
+
validate: (input: unknown) => ToolSchemaResult<TArgs>;
|
|
15
|
+
};
|
|
16
|
+
export type ToolComponentProps<TArgs, TResult> = {
|
|
17
|
+
args: TArgs;
|
|
18
|
+
result?: TResult;
|
|
19
|
+
submitResult: (result: TResult) => void;
|
|
20
|
+
};
|
|
21
|
+
export type ToolExecutionStatus = 'success' | 'error' | 'cancelled';
|
|
22
|
+
/**
|
|
23
|
+
* Discriminated outcome returned by a tool's `execute` callback.
|
|
24
|
+
* A tool may also return a bare `TResult`; it is then treated as
|
|
25
|
+
* `{status: 'success', result}` to keep simple cases boilerplate-free.
|
|
26
|
+
*/
|
|
27
|
+
export type ToolExecutionOutcome<TResult> = {
|
|
28
|
+
status: 'success';
|
|
29
|
+
result: TResult;
|
|
30
|
+
} | {
|
|
31
|
+
status: 'error';
|
|
32
|
+
result?: TResult;
|
|
33
|
+
error?: {
|
|
34
|
+
message: string;
|
|
35
|
+
};
|
|
36
|
+
} | {
|
|
37
|
+
status: 'cancelled';
|
|
38
|
+
result?: TResult;
|
|
39
|
+
};
|
|
40
|
+
export type ToolDefinition<TArgs, TResult, TName extends string = string> = {
|
|
41
|
+
name: TName;
|
|
42
|
+
description: string;
|
|
43
|
+
parameters: Record<string, unknown>;
|
|
44
|
+
schema: ToolSchema<TArgs>;
|
|
45
|
+
component: ComponentType<ToolComponentProps<TArgs, TResult>>;
|
|
46
|
+
/**
|
|
47
|
+
* Run after the user submits a result inside the tool component.
|
|
48
|
+
* Return:
|
|
49
|
+
* - `TResult` (or a Promise of one) for a successful execution;
|
|
50
|
+
* - a `ToolExecutionOutcome<TResult>` to explicitly report `error`
|
|
51
|
+
* or `cancelled`. A thrown error is surfaced as `{status: 'error'}`.
|
|
52
|
+
*/
|
|
53
|
+
execute?: (params: {
|
|
54
|
+
args: TArgs;
|
|
55
|
+
result: TResult;
|
|
56
|
+
toolCallId: string;
|
|
57
|
+
}) => TResult | ToolExecutionOutcome<TResult> | Promise<TResult | ToolExecutionOutcome<TResult>>;
|
|
58
|
+
};
|
|
59
|
+
export type RuntimeToolDefinition<TName extends string = string> = {
|
|
60
|
+
name: TName;
|
|
61
|
+
description: string;
|
|
62
|
+
parameters: Record<string, unknown>;
|
|
63
|
+
validate: (input: unknown) => ToolSchemaResult<unknown>;
|
|
64
|
+
/**
|
|
65
|
+
* Rendered as `<Renderer ... />` JSX. Hooks placed at the top of this
|
|
66
|
+
* component work normally because it is a real React component, not a
|
|
67
|
+
* function called inside another render path.
|
|
68
|
+
*/
|
|
69
|
+
Renderer: ComponentType<ToolComponentProps<unknown, unknown>>;
|
|
70
|
+
execute: (params: {
|
|
71
|
+
args: unknown;
|
|
72
|
+
result: unknown;
|
|
73
|
+
toolCallId: string;
|
|
74
|
+
}) => unknown | ToolExecutionOutcome<unknown> | Promise<unknown | ToolExecutionOutcome<unknown>>;
|
|
75
|
+
};
|
|
76
|
+
export type Toolset = Record<string, RuntimeToolDefinition>;
|
|
77
|
+
export type ToolPartContentData<TArgs = unknown, TResult = unknown> = ToolMessageContentData & {
|
|
78
|
+
toolCallId: string;
|
|
79
|
+
args?: TArgs;
|
|
80
|
+
result?: TResult;
|
|
81
|
+
};
|
|
82
|
+
export type ToolPartContent<TArgs = unknown, TResult = unknown> = TMessageContent<'tool', ToolPartContentData<TArgs, TResult>>;
|
|
83
|
+
export type ToolsetResultEvent = {
|
|
84
|
+
toolCallId: string;
|
|
85
|
+
toolName: string;
|
|
86
|
+
status: ToolExecutionStatus;
|
|
87
|
+
result: unknown;
|
|
88
|
+
error?: {
|
|
89
|
+
message: string;
|
|
90
|
+
};
|
|
91
|
+
};
|
|
92
|
+
/**
|
|
93
|
+
* Wrap a typed tool definition into an erased runtime entry that the
|
|
94
|
+
* toolset renderer can dispatch by `toolName`. The literal `name` is
|
|
95
|
+
* preserved as a type parameter so `createToolset` can derive its keys.
|
|
96
|
+
*/
|
|
97
|
+
export declare function defineTool<TArgs, TResult, const TName extends string>(definition: ToolDefinition<TArgs, TResult, TName>): RuntimeToolDefinition<TName>;
|
|
98
|
+
/**
|
|
99
|
+
* Build a `Toolset` from a list of `defineTool(...)` results. Keys are
|
|
100
|
+
* derived from `definition.name`, so the call site cannot drift between
|
|
101
|
+
* a literal-object key and the embedded `name`. The return type narrows
|
|
102
|
+
* its keys to the union of literal tool names, giving name-autocomplete
|
|
103
|
+
* on lookups. Throws on duplicates.
|
|
104
|
+
*/
|
|
105
|
+
export declare function createToolset<const T extends readonly RuntimeToolDefinition<string>[]>(...tools: T): {
|
|
106
|
+
[K in T[number]['name']]: RuntimeToolDefinition<T[number]['name']>;
|
|
107
|
+
};
|
|
108
|
+
/**
|
|
109
|
+
* Map a `Toolset` to the OpenAI `tools[]` shape so chat clients can pass
|
|
110
|
+
* tool definitions to the model without reimplementing the conversion.
|
|
111
|
+
*/
|
|
112
|
+
export declare function toolsetToOpenAIDefinitions(toolset: Toolset): Array<{
|
|
113
|
+
type: 'function';
|
|
114
|
+
function: {
|
|
115
|
+
name: string;
|
|
116
|
+
description: string;
|
|
117
|
+
parameters: Record<string, unknown>;
|
|
118
|
+
};
|
|
119
|
+
}>;
|
|
120
|
+
export type CreateToolsetRendererOptions = {
|
|
121
|
+
onToolResult: (event: ToolsetResultEvent) => void;
|
|
122
|
+
/**
|
|
123
|
+
* Existing registry whose entries should be preserved. A shallow copy
|
|
124
|
+
* is taken; the input reference is never mutated.
|
|
125
|
+
*/
|
|
126
|
+
registry?: MessageRendererRegistry;
|
|
127
|
+
};
|
|
128
|
+
/**
|
|
129
|
+
* Build a `MessageRendererRegistry` whose `tool` renderer dispatches
|
|
130
|
+
* by `toolName` into the provided toolset. Unknown tools and invalid
|
|
131
|
+
* args fall back to a generic `<ToolMessage status="error" />`. Errors
|
|
132
|
+
* thrown inside `execute` are surfaced via an `error` outcome.
|
|
133
|
+
*/
|
|
134
|
+
export declare function createToolsetRenderer(toolset: Toolset, options: CreateToolsetRendererOptions): MessageRendererRegistry;
|
|
135
|
+
/**
|
|
136
|
+
* Merge a tool result into the matching `tool` part of the chat history.
|
|
137
|
+
* Honors `event.status` so the part reflects success / error / cancelled.
|
|
138
|
+
* For backward compatibility, a missing `status` is treated as `'success'`.
|
|
139
|
+
* Returns the original array reference when nothing matched, so React state
|
|
140
|
+
* setters can skip needless updates.
|
|
141
|
+
*/
|
|
142
|
+
export declare function applyToolResult<TCustom extends TMessageContent = never>(messages: TChatMessage<TCustom>[], event: ToolsetResultEvent): TChatMessage<TCustom>[];
|