weifuwu 0.57.0 → 0.59.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/README.md +189 -11
- package/dist/ai/agent.d.ts +50 -0
- package/dist/ai/client.d.ts +104 -0
- package/dist/ai/index.d.ts +54 -0
- package/dist/ai/sse.d.ts +26 -0
- package/dist/ai/types.d.ts +148 -0
- package/dist/client/ai.d.ts +59 -0
- package/dist/client/index.d.ts +3 -0
- package/dist/client/index.js +128 -0
- package/dist/components/ApprovalCard/ApprovalCard.d.ts +30 -0
- package/dist/components/Avatar/Avatar.d.ts +2 -0
- package/dist/components/Card/Card.d.ts +4 -0
- package/dist/components/Input/Input.d.ts +2 -0
- package/dist/components/SegmentedControl/SegmentedControl.d.ts +22 -0
- package/dist/components/StatCard/StatCard.d.ts +2 -0
- package/dist/components/Textarea/Textarea.d.ts +4 -0
- package/dist/components/ToolCallCard/ToolCallCard.d.ts +23 -0
- package/dist/components/index.d.ts +6 -0
- package/dist/components/index.js +133 -9
- package/dist/components/style.css +945 -116
- package/dist/index.d.ts +3 -0
- package/dist/index.js +372 -0
- package/dist/layout/weifuwu-layout.css +636 -90
- package/package.json +1 -1
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* weifuwu/client AI 解码器 — 消费 wf: 协议(docs/ai-contract.md)
|
|
3
|
+
*
|
|
4
|
+
* 协议的前端参考实现:POST → 解析 SSE → 按事件名分发回调。
|
|
5
|
+
*
|
|
6
|
+
* - 零依赖:fetch + ReadableStream + 自研 SSE 解析
|
|
7
|
+
* - 未知事件透传不抛错(协议 §6):x:* 走 onEvent,未订阅的跳过
|
|
8
|
+
* - 事件录制(副产品):record 开启时记录完整事件序列,可导出为测试 fixture
|
|
9
|
+
* - trace 桥(协议 §7):默认自动生成 X-Trace-Id 并随请求发送,
|
|
10
|
+
* 后端以之作为 wf:message_start.id → 整个 agent run 一次搜完
|
|
11
|
+
* - abort:handle.abort() 或外部 signal → 取消请求 → 后端断开 → provider 取消
|
|
12
|
+
*/
|
|
13
|
+
import type { WfApprovalRequest, WfDone, WfError, WfStreamEvent, WfToolCall, WfToolProgress, WfToolResult, WfUsage } from '../ai/types.ts';
|
|
14
|
+
export interface AiStreamCallbacks {
|
|
15
|
+
/** wf:token — 增量文本,直接 append */
|
|
16
|
+
onToken?: (text: string) => void;
|
|
17
|
+
/** wf:tool_call — 完整工具调用(后端已聚合) */
|
|
18
|
+
onToolCall?: (call: WfToolCall) => void;
|
|
19
|
+
/** wf:tool_result — ok:false 不代表会话结束 */
|
|
20
|
+
onToolResult?: (result: WfToolResult) => void;
|
|
21
|
+
/** wf:tool_progress — 长任务进度 */
|
|
22
|
+
onToolProgress?: (p: WfToolProgress) => void;
|
|
23
|
+
/** wf:step — 步骤可视化(agent 扩展) */
|
|
24
|
+
onStep?: (s: {
|
|
25
|
+
type: 'llm' | 'tool';
|
|
26
|
+
content?: string;
|
|
27
|
+
toolCallId?: string;
|
|
28
|
+
name?: string;
|
|
29
|
+
}) => void;
|
|
30
|
+
/** wf:approval_request — 渲染审批卡片 */
|
|
31
|
+
onApproval?: (req: WfApprovalRequest) => void;
|
|
32
|
+
/** wf:usage — token 计数 */
|
|
33
|
+
onUsage?: (u: WfUsage) => void;
|
|
34
|
+
/** wf:done — 收尾 */
|
|
35
|
+
onDone?: (d: WfDone) => void;
|
|
36
|
+
/** wf:error — 错误即值,结构化降级 */
|
|
37
|
+
onError?: (e: WfError) => void;
|
|
38
|
+
/** x:* 自定义事件透传兜底(协议 §6:框架不解释) */
|
|
39
|
+
onEvent?: (name: string, data: unknown) => void;
|
|
40
|
+
}
|
|
41
|
+
export interface AiStreamOptions extends AiStreamCallbacks {
|
|
42
|
+
signal?: AbortSignal;
|
|
43
|
+
headers?: Record<string, string>;
|
|
44
|
+
/** 显式指定 traceId;默认自动生成(协议 §7) */
|
|
45
|
+
traceId?: string;
|
|
46
|
+
/** 录制事件序列(调试/导出 fixture),默认开启,环形上限 1000 */
|
|
47
|
+
record?: boolean;
|
|
48
|
+
}
|
|
49
|
+
export interface AiStreamHandle {
|
|
50
|
+
/** 取消请求(用户停止/组件卸载/导航跳走时调用) */
|
|
51
|
+
abort: () => void;
|
|
52
|
+
/** 流结束(正常 done / error / abort 都 resolve) */
|
|
53
|
+
done: Promise<void>;
|
|
54
|
+
/** 本次请求使用的 traceId(自动生成的也能拿到) */
|
|
55
|
+
traceId: string;
|
|
56
|
+
/** 录制的事件序列(record: true 时) */
|
|
57
|
+
events: WfStreamEvent[];
|
|
58
|
+
}
|
|
59
|
+
export declare function aiStream(url: string, body: unknown, options?: AiStreamOptions): AiStreamHandle;
|
package/dist/client/index.d.ts
CHANGED
|
@@ -31,6 +31,9 @@ export { ApiError } from './middleware/api.ts';
|
|
|
31
31
|
export type { AuthClient, AuthOptions, AuthInjected } from './middleware/auth.ts';
|
|
32
32
|
export { extendCtx } from './types.ts';
|
|
33
33
|
export type { WfuiContext, AppMiddleware, RouteDef } from './types.ts';
|
|
34
|
+
export { aiStream } from './ai.ts';
|
|
35
|
+
export type { AiStreamCallbacks, AiStreamOptions, AiStreamHandle } from './ai.ts';
|
|
36
|
+
export type { WfStreamEvent, WfMessageStart, WfToken, WfUsage, WfDone, WfError, WfErrorCode, WfToolCall, WfToolResult, WfToolProgress, WfStep, WfApprovalRequest, WfApprovalResponse, WfApprovalDecision, ChatMessage, ChatParams, MessageRole, ToolCall, ToolDefinition, } from '../ai/types.ts';
|
|
34
37
|
export { ErrorBoundary } from './error-boundary.ts';
|
|
35
38
|
export type { ErrorBoundaryProps } from './error-boundary.ts';
|
|
36
39
|
export { i18n } from './i18n.ts';
|
package/dist/client/index.js
CHANGED
|
@@ -1584,6 +1584,133 @@ function auth(options) {
|
|
|
1584
1584
|
};
|
|
1585
1585
|
}
|
|
1586
1586
|
|
|
1587
|
+
// src/client/ai.ts
|
|
1588
|
+
var RECORD_LIMIT = 1e3;
|
|
1589
|
+
function aiStream(url, body, options) {
|
|
1590
|
+
const controller = new AbortController();
|
|
1591
|
+
const external = options?.signal;
|
|
1592
|
+
if (external) {
|
|
1593
|
+
if (external.aborted) controller.abort();
|
|
1594
|
+
else external.addEventListener("abort", () => controller.abort(), { once: true });
|
|
1595
|
+
}
|
|
1596
|
+
const traceId = options?.traceId ?? randomId();
|
|
1597
|
+
const record = options?.record !== false;
|
|
1598
|
+
const events = [];
|
|
1599
|
+
const done = (async () => {
|
|
1600
|
+
let res;
|
|
1601
|
+
try {
|
|
1602
|
+
res = await fetch(url, {
|
|
1603
|
+
method: "POST",
|
|
1604
|
+
headers: {
|
|
1605
|
+
"Content-Type": "application/json",
|
|
1606
|
+
"X-Trace-Id": traceId,
|
|
1607
|
+
Accept: "text/event-stream",
|
|
1608
|
+
...options?.headers
|
|
1609
|
+
},
|
|
1610
|
+
body: JSON.stringify(body),
|
|
1611
|
+
signal: controller.signal
|
|
1612
|
+
});
|
|
1613
|
+
} catch (err) {
|
|
1614
|
+
if (controller.signal.aborted) return;
|
|
1615
|
+
options?.onError?.({ code: "provider_error", message: err instanceof Error ? err.message : String(err) });
|
|
1616
|
+
return;
|
|
1617
|
+
}
|
|
1618
|
+
if (!res.ok) {
|
|
1619
|
+
options?.onError?.({
|
|
1620
|
+
code: httpErrorCode(res.status),
|
|
1621
|
+
message: `HTTP ${res.status} ${res.statusText}`
|
|
1622
|
+
});
|
|
1623
|
+
return;
|
|
1624
|
+
}
|
|
1625
|
+
try {
|
|
1626
|
+
for await (const { name, data } of parseWfEvents(res.body)) {
|
|
1627
|
+
if (controller.signal.aborted) return;
|
|
1628
|
+
pushEvent(events, { name, data }, record);
|
|
1629
|
+
dispatch(name, data, options ?? {});
|
|
1630
|
+
}
|
|
1631
|
+
} catch (err) {
|
|
1632
|
+
if (controller.signal.aborted) return;
|
|
1633
|
+
options?.onError?.({ code: "provider_error", message: err instanceof Error ? err.message : String(err) });
|
|
1634
|
+
}
|
|
1635
|
+
})();
|
|
1636
|
+
return {
|
|
1637
|
+
abort: () => controller.abort(),
|
|
1638
|
+
done,
|
|
1639
|
+
traceId,
|
|
1640
|
+
events
|
|
1641
|
+
};
|
|
1642
|
+
}
|
|
1643
|
+
function dispatch(name, data, o) {
|
|
1644
|
+
switch (name) {
|
|
1645
|
+
case "wf:token":
|
|
1646
|
+
return o.onToken?.(data.text);
|
|
1647
|
+
case "wf:tool_call":
|
|
1648
|
+
return o.onToolCall?.(data);
|
|
1649
|
+
case "wf:tool_result":
|
|
1650
|
+
return o.onToolResult?.(data);
|
|
1651
|
+
case "wf:tool_progress":
|
|
1652
|
+
return o.onToolProgress?.(data);
|
|
1653
|
+
case "wf:step":
|
|
1654
|
+
return o.onStep?.(data);
|
|
1655
|
+
case "wf:approval_request":
|
|
1656
|
+
return o.onApproval?.(data);
|
|
1657
|
+
case "wf:usage":
|
|
1658
|
+
return o.onUsage?.(data);
|
|
1659
|
+
case "wf:done":
|
|
1660
|
+
return o.onDone?.(data);
|
|
1661
|
+
case "wf:error":
|
|
1662
|
+
return o.onError?.(data);
|
|
1663
|
+
default:
|
|
1664
|
+
return o.onEvent?.(name, data);
|
|
1665
|
+
}
|
|
1666
|
+
}
|
|
1667
|
+
async function* parseWfEvents(stream) {
|
|
1668
|
+
const reader = stream.getReader();
|
|
1669
|
+
const decoder = new TextDecoder();
|
|
1670
|
+
let buffer = "";
|
|
1671
|
+
try {
|
|
1672
|
+
while (true) {
|
|
1673
|
+
const { done, value } = await reader.read();
|
|
1674
|
+
if (done) break;
|
|
1675
|
+
buffer += decoder.decode(value, { stream: true });
|
|
1676
|
+
const blocks = buffer.split("\n\n");
|
|
1677
|
+
buffer = blocks.pop() ?? "";
|
|
1678
|
+
for (const block of blocks) {
|
|
1679
|
+
let name = "message";
|
|
1680
|
+
let data = "";
|
|
1681
|
+
for (const line of block.split("\n")) {
|
|
1682
|
+
if (line.startsWith("event: ")) name = line.slice(7);
|
|
1683
|
+
else if (line.startsWith("data: ")) data += line.slice(6);
|
|
1684
|
+
}
|
|
1685
|
+
if (!data) continue;
|
|
1686
|
+
try {
|
|
1687
|
+
yield { name, data: JSON.parse(data) };
|
|
1688
|
+
} catch {
|
|
1689
|
+
}
|
|
1690
|
+
}
|
|
1691
|
+
}
|
|
1692
|
+
} finally {
|
|
1693
|
+
reader.releaseLock();
|
|
1694
|
+
}
|
|
1695
|
+
}
|
|
1696
|
+
function pushEvent(events, e, record) {
|
|
1697
|
+
if (!record) return;
|
|
1698
|
+
if (events.length >= RECORD_LIMIT) events.shift();
|
|
1699
|
+
events.push(e);
|
|
1700
|
+
}
|
|
1701
|
+
function httpErrorCode(status) {
|
|
1702
|
+
if (status === 401 || status === 403) return "auth_failed";
|
|
1703
|
+
if (status === 429) return "rate_limited";
|
|
1704
|
+
if (status >= 500) return "provider_error";
|
|
1705
|
+
return "invalid_request";
|
|
1706
|
+
}
|
|
1707
|
+
function randomId() {
|
|
1708
|
+
if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
|
|
1709
|
+
return crypto.randomUUID();
|
|
1710
|
+
}
|
|
1711
|
+
return `trace-${Date.now()}-${Math.random().toString(36).slice(2, 10)}`;
|
|
1712
|
+
}
|
|
1713
|
+
|
|
1587
1714
|
// src/client/error-boundary.ts
|
|
1588
1715
|
function ErrorBoundary(props, ctx) {
|
|
1589
1716
|
let error = null;
|
|
@@ -1842,6 +1969,7 @@ export {
|
|
|
1842
1969
|
Fragment,
|
|
1843
1970
|
Portal,
|
|
1844
1971
|
RouteView,
|
|
1972
|
+
aiStream,
|
|
1845
1973
|
api,
|
|
1846
1974
|
asyncComponent,
|
|
1847
1975
|
auth,
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { Component } from '../../client/vnode.ts';
|
|
2
|
+
import type { WfApprovalRequest } from '../../ai/types.ts';
|
|
3
|
+
/**
|
|
4
|
+
* ApprovalCard — 人工审批卡片(wf: 协议 §4.5 交互原语)
|
|
5
|
+
*
|
|
6
|
+
* 状态机:pending(待批,允许/拒绝 + 备注)→ approved / rejected / timeout(终态)。
|
|
7
|
+
* 纯受控组件:决策回传由 onApprove / onReject 上抛(app 负责 POST /approve)。
|
|
8
|
+
*
|
|
9
|
+
* ```tsx
|
|
10
|
+
* <ApprovalCard
|
|
11
|
+
* request={approvalReq}
|
|
12
|
+
* onApprove={() => respond('approved')}
|
|
13
|
+
* onReject={(note) => respond('rejected', note)}
|
|
14
|
+
* />
|
|
15
|
+
* ```
|
|
16
|
+
*/
|
|
17
|
+
export type ApprovalStatus = 'pending' | 'approved' | 'rejected' | 'timeout';
|
|
18
|
+
export interface ApprovalCardProps {
|
|
19
|
+
/** wf:approval_request 数据 */
|
|
20
|
+
request: WfApprovalRequest;
|
|
21
|
+
/** 卡片状态(默认 pending) */
|
|
22
|
+
status?: ApprovalStatus;
|
|
23
|
+
/** 用户点"允许" */
|
|
24
|
+
onApprove?: () => void;
|
|
25
|
+
/** 用户点"拒绝",note 为可选备注(进 agent 上下文) */
|
|
26
|
+
onReject?: (note?: string) => void;
|
|
27
|
+
/** 自定义详情渲染(默认显示 name + args) */
|
|
28
|
+
renderDetail?: (request: WfApprovalRequest) => any;
|
|
29
|
+
}
|
|
30
|
+
export declare const ApprovalCard: Component<ApprovalCardProps>;
|
|
@@ -3,6 +3,10 @@ export interface CardProps {
|
|
|
3
3
|
variant?: 'default' | 'outlined';
|
|
4
4
|
padding?: 'sm' | 'md' | 'lg';
|
|
5
5
|
clickable?: boolean;
|
|
6
|
+
/** hover 抬升(阴影 + 上移),适合可点击/可悬停的卡片 */
|
|
7
|
+
hover?: boolean;
|
|
8
|
+
/** 选中态(边框高亮 + 品牌浅底),适合选择卡片 */
|
|
9
|
+
active?: boolean;
|
|
6
10
|
onClick?: () => void;
|
|
7
11
|
children?: any;
|
|
8
12
|
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { Component } from '../../client/vnode.ts';
|
|
2
|
+
export interface SegmentedOption {
|
|
3
|
+
value: string;
|
|
4
|
+
label: string;
|
|
5
|
+
disabled?: boolean;
|
|
6
|
+
}
|
|
7
|
+
export interface SegmentedControlProps {
|
|
8
|
+
/** 选项列表(label 可为字符串或任意 VNode) */
|
|
9
|
+
options: SegmentedOption[];
|
|
10
|
+
/** 当前选中值 */
|
|
11
|
+
value?: string;
|
|
12
|
+
onChange?: (value: string) => void;
|
|
13
|
+
size?: 'sm' | 'md';
|
|
14
|
+
/** 撑满父容器宽度(选项等分) */
|
|
15
|
+
block?: boolean;
|
|
16
|
+
ariaLabel?: string;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* 分段控件 — 单选切换(模式切换 / 状态筛选 / 模板选择)
|
|
20
|
+
* 语义:toggle group(aria-pressed),键盘 focus-visible 可见
|
|
21
|
+
*/
|
|
22
|
+
export declare const SegmentedControl: Component<SegmentedControlProps>;
|
|
@@ -8,6 +8,10 @@ export interface TextareaProps {
|
|
|
8
8
|
error?: string;
|
|
9
9
|
hint?: string;
|
|
10
10
|
rows?: number;
|
|
11
|
+
/** 最大字符数(同时限制输入) */
|
|
12
|
+
maxLength?: number;
|
|
13
|
+
/** 显示字数统计(右下角;配合受控 value 实时更新) */
|
|
14
|
+
showCount?: boolean;
|
|
11
15
|
onInput?: (e: Event) => void;
|
|
12
16
|
}
|
|
13
17
|
export declare const Textarea: Component<TextareaProps>;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { Component } from '../../client/vnode.ts';
|
|
2
|
+
import type { WfToolCall, WfToolProgress, WfToolResult } from '../../ai/types.ts';
|
|
3
|
+
/**
|
|
4
|
+
* ToolCallCard — 工具调用卡片(wf: 协议 §4 交互原语)
|
|
5
|
+
*
|
|
6
|
+
* 纯展示组件:接收协议事件数据 + 可选回调,无内部状态。
|
|
7
|
+
* 状态机:running(等待/执行中,带进度条)→ ok / error(有 result 时)。
|
|
8
|
+
*
|
|
9
|
+
* ```tsx
|
|
10
|
+
* <ToolCallCard call={toolCall} progress={progress} result={result} />
|
|
11
|
+
* ```
|
|
12
|
+
*/
|
|
13
|
+
export interface ToolCallCardProps {
|
|
14
|
+
/** wf:tool_call 数据 */
|
|
15
|
+
call: WfToolCall;
|
|
16
|
+
/** wf:tool_progress 数据(可选,展示进度条) */
|
|
17
|
+
progress?: WfToolProgress;
|
|
18
|
+
/** wf:tool_result 数据(可选,ok/error 终态) */
|
|
19
|
+
result?: WfToolResult;
|
|
20
|
+
/** 自定义参数渲染(默认 JSON.stringify) */
|
|
21
|
+
renderArgs?: (args: Record<string, unknown>) => any;
|
|
22
|
+
}
|
|
23
|
+
export declare const ToolCallCard: Component<ToolCallCardProps>;
|
|
@@ -59,6 +59,8 @@ export { Slider } from './Slider/Slider.ts';
|
|
|
59
59
|
export type { SliderProps } from './Slider/Slider.ts';
|
|
60
60
|
export { SearchInput } from './SearchInput/SearchInput.ts';
|
|
61
61
|
export type { SearchInputProps } from './SearchInput/SearchInput.ts';
|
|
62
|
+
export { SegmentedControl } from './SegmentedControl/SegmentedControl.ts';
|
|
63
|
+
export type { SegmentedControlProps, SegmentedOption } from './SegmentedControl/SegmentedControl.ts';
|
|
62
64
|
export { ProgressBar } from './ProgressBar/ProgressBar.ts';
|
|
63
65
|
export type { ProgressBarProps } from './ProgressBar/ProgressBar.ts';
|
|
64
66
|
export { Accordion } from './Accordion/Accordion.ts';
|
|
@@ -92,3 +94,7 @@ export type { EditorProps, ToolbarItem } from './Editor/Editor.ts';
|
|
|
92
94
|
export { ThemeSwitch } from './ThemeSwitch/ThemeSwitch.ts';
|
|
93
95
|
export type { ThemeSwitchProps, ThemeMode } from './ThemeSwitch/ThemeSwitch.ts';
|
|
94
96
|
export { applyTheme, getTheme } from './ThemeSwitch/ThemeSwitch.ts';
|
|
97
|
+
export { ToolCallCard } from './ToolCallCard/ToolCallCard.ts';
|
|
98
|
+
export type { ToolCallCardProps } from './ToolCallCard/ToolCallCard.ts';
|
|
99
|
+
export { ApprovalCard } from './ApprovalCard/ApprovalCard.ts';
|
|
100
|
+
export type { ApprovalCardProps, ApprovalStatus } from './ApprovalCard/ApprovalCard.ts';
|
package/dist/components/index.js
CHANGED
|
@@ -52,9 +52,9 @@ var Button = (_init, ctx) => (props) => {
|
|
|
52
52
|
|
|
53
53
|
// src/components/Input/Input.ts
|
|
54
54
|
var Input = (_init) => (props) => {
|
|
55
|
-
const { label, name, type = "text", value, placeholder, required, disabled, error, hint, onInput, onChange } = props;
|
|
55
|
+
const { label, name, type = "text", value, placeholder, required, disabled, error, hint, variant = "default", onInput, onChange } = props;
|
|
56
56
|
const inputEl = h("input", {
|
|
57
|
-
class: "wf-input"
|
|
57
|
+
class: `wf-input${variant === "borderless" ? " wf-input--borderless" : ""}`,
|
|
58
58
|
name: name || void 0,
|
|
59
59
|
type,
|
|
60
60
|
value: value ?? "",
|
|
@@ -79,7 +79,7 @@ var Input = (_init) => (props) => {
|
|
|
79
79
|
|
|
80
80
|
// src/components/Textarea/Textarea.ts
|
|
81
81
|
var Textarea = (_init, _ctx) => (props) => {
|
|
82
|
-
const { label, value, placeholder, required, disabled, error, hint, rows = 3, onInput } = props;
|
|
82
|
+
const { label, value, placeholder, required, disabled, error, hint, rows = 3, maxLength, showCount, onInput } = props;
|
|
83
83
|
const textareaEl = h("textarea", {
|
|
84
84
|
class: "wf-textarea",
|
|
85
85
|
value: value ?? "",
|
|
@@ -87,6 +87,7 @@ var Textarea = (_init, _ctx) => (props) => {
|
|
|
87
87
|
required: required || void 0,
|
|
88
88
|
disabled: disabled || void 0,
|
|
89
89
|
rows,
|
|
90
|
+
maxLength,
|
|
90
91
|
onInput
|
|
91
92
|
});
|
|
92
93
|
const children = [];
|
|
@@ -96,6 +97,14 @@ var Textarea = (_init, _ctx) => (props) => {
|
|
|
96
97
|
children.push(h("label", { class: "wf-textarea-label" }, labelContent));
|
|
97
98
|
}
|
|
98
99
|
children.push(textareaEl);
|
|
100
|
+
if (showCount) {
|
|
101
|
+
const len = (value ?? "").length;
|
|
102
|
+
const over = maxLength != null && len > maxLength;
|
|
103
|
+
children.push(h("div", {
|
|
104
|
+
class: `wf-textarea-count${over ? " wf-textarea-count--over" : ""}`,
|
|
105
|
+
"aria-live": "polite"
|
|
106
|
+
}, maxLength != null ? `${len}/${maxLength}` : String(len)));
|
|
107
|
+
}
|
|
99
108
|
if (error) children.push(h("div", { class: "wf-textarea-err" }, error));
|
|
100
109
|
if (hint && !error) children.push(h("div", { class: "wf-textarea-hint" }, hint));
|
|
101
110
|
return h("div", { class: `wf-textarea-wrap${error ? " wf-textarea--err" : ""}` }, children);
|
|
@@ -1059,12 +1068,14 @@ function getPageRange(current, total) {
|
|
|
1059
1068
|
|
|
1060
1069
|
// src/components/Card/Card.ts
|
|
1061
1070
|
var Card = (_init, _ctx) => (props) => {
|
|
1062
|
-
const { variant = "default", padding = "md", clickable, onClick, children } = props;
|
|
1071
|
+
const { variant = "default", padding = "md", clickable, hover, active, onClick, children } = props;
|
|
1063
1072
|
const cls = [
|
|
1064
1073
|
"wf-card",
|
|
1065
1074
|
`wf-card--${variant}`,
|
|
1066
1075
|
`wf-card--pad-${padding}`,
|
|
1067
|
-
clickable && "wf-card--clickable"
|
|
1076
|
+
clickable && "wf-card--clickable",
|
|
1077
|
+
hover && "wf-card--hover",
|
|
1078
|
+
active && "wf-card--active"
|
|
1068
1079
|
].filter(Boolean).join(" ");
|
|
1069
1080
|
return h("div", { class: cls, onClick, role: clickable ? "button" : void 0, tabindex: clickable ? 0 : void 0 }, children);
|
|
1070
1081
|
};
|
|
@@ -1086,7 +1097,7 @@ function hashColor(name) {
|
|
|
1086
1097
|
return COLORS[Math.abs(hash) % COLORS.length];
|
|
1087
1098
|
}
|
|
1088
1099
|
var Avatar = (_init, _ctx) => (props) => {
|
|
1089
|
-
const { name = "", src, size = "md" } = props;
|
|
1100
|
+
const { name = "", src, size = "md", color } = props;
|
|
1090
1101
|
const initial = name.trim()[0]?.toUpperCase() ?? "?";
|
|
1091
1102
|
if (src) {
|
|
1092
1103
|
return h("img", {
|
|
@@ -1097,7 +1108,7 @@ var Avatar = (_init, _ctx) => (props) => {
|
|
|
1097
1108
|
}
|
|
1098
1109
|
return h("div", {
|
|
1099
1110
|
class: `wf-avatar wf-avatar--${size}`,
|
|
1100
|
-
style: { background: hashColor(name) }
|
|
1111
|
+
style: { background: color ?? hashColor(name) }
|
|
1101
1112
|
}, initial);
|
|
1102
1113
|
};
|
|
1103
1114
|
|
|
@@ -1113,7 +1124,7 @@ var Tag = (_init, _ctx) => (props) => {
|
|
|
1113
1124
|
|
|
1114
1125
|
// src/components/StatCard/StatCard.ts
|
|
1115
1126
|
var StatCard = (_init, _ctx) => (props) => {
|
|
1116
|
-
const { label, value, trend, trendLabel, icon } = props;
|
|
1127
|
+
const { label, value, trend, trendLabel, icon, onClick } = props;
|
|
1117
1128
|
const children = [];
|
|
1118
1129
|
if (icon) children.push(h("div", { class: "wf-stat-icon" }, icon));
|
|
1119
1130
|
children.push(h("div", { class: "wf-stat-value" }, String(value)));
|
|
@@ -1126,7 +1137,12 @@ var StatCard = (_init, _ctx) => (props) => {
|
|
|
1126
1137
|
trendLabel ? h("span", { class: "wf-stat-trend-label" }, trendLabel) : null
|
|
1127
1138
|
].filter(Boolean)));
|
|
1128
1139
|
}
|
|
1129
|
-
return h("div", {
|
|
1140
|
+
return h("div", {
|
|
1141
|
+
class: `wf-stat${onClick ? " wf-stat--clickable" : ""}`,
|
|
1142
|
+
onClick,
|
|
1143
|
+
role: onClick ? "button" : void 0,
|
|
1144
|
+
tabindex: onClick ? 0 : void 0
|
|
1145
|
+
}, children);
|
|
1130
1146
|
};
|
|
1131
1147
|
|
|
1132
1148
|
// src/components/Steps/Steps.ts
|
|
@@ -1279,6 +1295,27 @@ var SearchInput = (_init, _ctx) => (props) => {
|
|
|
1279
1295
|
].filter(Boolean));
|
|
1280
1296
|
};
|
|
1281
1297
|
|
|
1298
|
+
// src/components/SegmentedControl/SegmentedControl.ts
|
|
1299
|
+
var SegmentedControl = (_init, _ctx) => (props) => {
|
|
1300
|
+
const { options, value, onChange, size = "md", block, ariaLabel } = props;
|
|
1301
|
+
const cls = [
|
|
1302
|
+
"wf-segmented",
|
|
1303
|
+
size === "sm" && "wf-segmented--sm",
|
|
1304
|
+
block && "wf-segmented--block"
|
|
1305
|
+
].filter(Boolean).join(" ");
|
|
1306
|
+
return h(
|
|
1307
|
+
"div",
|
|
1308
|
+
{ class: cls, role: "group", "aria-label": ariaLabel },
|
|
1309
|
+
options.map((opt) => h("button", {
|
|
1310
|
+
type: "button",
|
|
1311
|
+
class: `wf-segmented-option${opt.value === value ? " wf-segmented-option--active" : ""}`,
|
|
1312
|
+
"aria-pressed": opt.value === value ? "true" : "false",
|
|
1313
|
+
disabled: opt.disabled || void 0,
|
|
1314
|
+
onClick: opt.disabled ? void 0 : () => onChange?.(opt.value)
|
|
1315
|
+
}, opt.label))
|
|
1316
|
+
);
|
|
1317
|
+
};
|
|
1318
|
+
|
|
1282
1319
|
// src/components/ProgressBar/ProgressBar.ts
|
|
1283
1320
|
var ProgressBar = (_init, ctx) => (props) => {
|
|
1284
1321
|
const { value = 0, max = 100, label, showValue } = props;
|
|
@@ -3084,9 +3121,94 @@ var ThemeSwitch = (initProps, ctx) => {
|
|
|
3084
3121
|
}, segments);
|
|
3085
3122
|
};
|
|
3086
3123
|
};
|
|
3124
|
+
|
|
3125
|
+
// src/components/ToolCallCard/ToolCallCard.ts
|
|
3126
|
+
var stateIcon = { running: "\u2699", ok: "\u2713", error: "\u2715" };
|
|
3127
|
+
var ToolCallCard = (_init, _ctx) => (props) => {
|
|
3128
|
+
const { call, progress, result, renderArgs } = props;
|
|
3129
|
+
const state = result ? result.ok ? "ok" : "error" : "running";
|
|
3130
|
+
const argsNode = renderArgs ? renderArgs(call.args) : h("code", { class: "wf-toolcall-args" }, JSON.stringify(call.args));
|
|
3131
|
+
const progressNode = progress ? [
|
|
3132
|
+
progress.message ? h("div", { class: "wf-toolcall-msg" }, `${progress.message} (${progress.step}/${progress.total})`) : null,
|
|
3133
|
+
h("div", { class: "wf-toolcall-bar", role: "progressbar", "aria-valuenow": progress.step, "aria-valuemax": progress.total }, [
|
|
3134
|
+
h("div", {
|
|
3135
|
+
class: "wf-toolcall-bar-fill",
|
|
3136
|
+
style: { width: `${Math.min(100, progress.step / Math.max(1, progress.total) * 100)}%` }
|
|
3137
|
+
})
|
|
3138
|
+
])
|
|
3139
|
+
] : null;
|
|
3140
|
+
const errorNode = result && !result.ok && result.error ? h("div", { class: "wf-toolcall-error" }, `${result.error.code}: ${result.error.message}`) : null;
|
|
3141
|
+
return h("div", { class: `wf-toolcall wf-toolcall--${state}` }, [
|
|
3142
|
+
h("div", { class: "wf-toolcall-header" }, [
|
|
3143
|
+
h("span", { class: `wf-toolcall-icon wf-toolcall-icon--${state}` }, stateIcon[state]),
|
|
3144
|
+
h("span", { class: "wf-toolcall-name" }, call.name)
|
|
3145
|
+
]),
|
|
3146
|
+
h("div", { class: "wf-toolcall-body" }, [argsNode, progressNode, errorNode].filter(Boolean))
|
|
3147
|
+
]);
|
|
3148
|
+
};
|
|
3149
|
+
|
|
3150
|
+
// src/components/ApprovalCard/ApprovalCard.ts
|
|
3151
|
+
var statusText = {
|
|
3152
|
+
pending: "\u7B49\u5F85\u5BA1\u6279",
|
|
3153
|
+
approved: "\u5DF2\u6279\u51C6",
|
|
3154
|
+
rejected: "\u5DF2\u62D2\u7EDD",
|
|
3155
|
+
timeout: "\u5BA1\u6279\u8D85\u65F6"
|
|
3156
|
+
};
|
|
3157
|
+
var ApprovalCard = (_init, ctx) => {
|
|
3158
|
+
let note = "";
|
|
3159
|
+
let showNote = false;
|
|
3160
|
+
return (props) => {
|
|
3161
|
+
const { request, status = "pending", onApprove, onReject, renderDetail } = props;
|
|
3162
|
+
const detail = renderDetail ? renderDetail(request) : [
|
|
3163
|
+
h("div", { class: "wf-approval-name" }, request.name),
|
|
3164
|
+
h("code", { class: "wf-approval-args" }, JSON.stringify(request.args))
|
|
3165
|
+
];
|
|
3166
|
+
const actions = status === "pending" ? h("div", { class: "wf-approval-actions" }, [
|
|
3167
|
+
showNote ? h("div", { class: "wf-approval-note" }, [
|
|
3168
|
+
h("input", {
|
|
3169
|
+
class: "wf-approval-note-input",
|
|
3170
|
+
placeholder: "\u5907\u6CE8\uFF08\u62D2\u7EDD\u539F\u56E0\uFF0C\u5C06\u8FDB\u5165 agent \u4E0A\u4E0B\u6587\uFF09\u2026",
|
|
3171
|
+
value: note,
|
|
3172
|
+
onInput: (e) => {
|
|
3173
|
+
note = e.target.value;
|
|
3174
|
+
}
|
|
3175
|
+
})
|
|
3176
|
+
]) : null,
|
|
3177
|
+
h("div", { class: "wf-approval-btns" }, [
|
|
3178
|
+
h("button", {
|
|
3179
|
+
class: "wf-btn wf-btn--primary wf-btn--sm",
|
|
3180
|
+
type: "button",
|
|
3181
|
+
onClick: () => onApprove?.()
|
|
3182
|
+
}, "\u5141\u8BB8"),
|
|
3183
|
+
h("button", {
|
|
3184
|
+
class: "wf-btn wf-btn--danger wf-btn--sm",
|
|
3185
|
+
type: "button",
|
|
3186
|
+
onClick: () => {
|
|
3187
|
+
if (!showNote) {
|
|
3188
|
+
showNote = true;
|
|
3189
|
+
ctx.ui.render();
|
|
3190
|
+
return;
|
|
3191
|
+
}
|
|
3192
|
+
onReject?.(note);
|
|
3193
|
+
}
|
|
3194
|
+
}, showNote ? "\u786E\u8BA4\u62D2\u7EDD" : "\u62D2\u7EDD")
|
|
3195
|
+
])
|
|
3196
|
+
].filter(Boolean)) : h("div", { class: `wf-approval-status wf-approval-status--${status}` }, statusText[status]);
|
|
3197
|
+
return h("div", { class: `wf-approval wf-approval--${status}` }, [
|
|
3198
|
+
h("div", { class: "wf-approval-header" }, [
|
|
3199
|
+
h("span", { class: "wf-approval-icon" }, status === "pending" ? "\u23F8" : status === "approved" ? "\u2713" : "\u2715"),
|
|
3200
|
+
h("span", { class: "wf-approval-title" }, "\u5DE5\u5177\u5BA1\u6279")
|
|
3201
|
+
]),
|
|
3202
|
+
h("div", { class: "wf-approval-detail" }, detail),
|
|
3203
|
+
request.reason ? h("div", { class: "wf-approval-reason" }, request.reason) : null,
|
|
3204
|
+
actions
|
|
3205
|
+
]);
|
|
3206
|
+
};
|
|
3207
|
+
};
|
|
3087
3208
|
export {
|
|
3088
3209
|
Accordion,
|
|
3089
3210
|
Alert,
|
|
3211
|
+
ApprovalCard,
|
|
3090
3212
|
Avatar,
|
|
3091
3213
|
Badge,
|
|
3092
3214
|
Breadcrumb,
|
|
@@ -3115,6 +3237,7 @@ export {
|
|
|
3115
3237
|
ProgressBar,
|
|
3116
3238
|
RadioGroup,
|
|
3117
3239
|
SearchInput,
|
|
3240
|
+
SegmentedControl,
|
|
3118
3241
|
Select,
|
|
3119
3242
|
Skeleton,
|
|
3120
3243
|
Slider,
|
|
@@ -3127,6 +3250,7 @@ export {
|
|
|
3127
3250
|
Textarea,
|
|
3128
3251
|
ThemeSwitch,
|
|
3129
3252
|
Toast,
|
|
3253
|
+
ToolCallCard,
|
|
3130
3254
|
Tooltip,
|
|
3131
3255
|
applyTheme,
|
|
3132
3256
|
confirm,
|