@turingflow/agent-kit 0.0.0-stage → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (93) hide show
  1. package/README.md +546 -2
  2. package/dist/agent.d.ts +27 -0
  3. package/dist/agent.js +31 -0
  4. package/dist/cli.d.ts +5 -0
  5. package/dist/cli.js +105 -0
  6. package/dist/handlers.d.ts +92 -0
  7. package/dist/handlers.js +211 -0
  8. package/dist/index.d.ts +13 -0
  9. package/dist/index.js +10 -0
  10. package/dist/sdk.d.ts +106 -0
  11. package/dist/sdk.js +309 -0
  12. package/dist/server/agent.d.ts +27 -0
  13. package/dist/server/agent.js +31 -0
  14. package/dist/server/artifact-hooks.d.ts +6 -0
  15. package/dist/server/artifact-hooks.js +37 -0
  16. package/dist/server/artifact-tool-tracker.d.ts +24 -0
  17. package/dist/server/artifact-tool-tracker.js +347 -0
  18. package/dist/server/artifacts.d.ts +227 -0
  19. package/dist/server/artifacts.js +1061 -0
  20. package/dist/server/auth/config.d.ts +34 -0
  21. package/dist/server/auth/config.js +82 -0
  22. package/dist/server/auth/db.d.ts +159 -0
  23. package/dist/server/auth/db.js +680 -0
  24. package/dist/server/auth/handlers.d.ts +27 -0
  25. package/dist/server/auth/handlers.js +297 -0
  26. package/dist/server/auth/index.d.ts +15 -0
  27. package/dist/server/auth/index.js +14 -0
  28. package/dist/server/auth/login-options.d.ts +14 -0
  29. package/dist/server/auth/login-options.js +50 -0
  30. package/dist/server/auth/providers/dingtalk.d.ts +16 -0
  31. package/dist/server/auth/providers/dingtalk.js +177 -0
  32. package/dist/server/auth/providers/feishu.d.ts +15 -0
  33. package/dist/server/auth/providers/feishu.js +100 -0
  34. package/dist/server/auth/providers/index.d.ts +13 -0
  35. package/dist/server/auth/providers/index.js +24 -0
  36. package/dist/server/auth/session.d.ts +48 -0
  37. package/dist/server/auth/session.js +108 -0
  38. package/dist/server/auth/types.d.ts +118 -0
  39. package/dist/server/auth/types.js +7 -0
  40. package/dist/server/browser-agent-mcp.d.ts +67 -0
  41. package/dist/server/browser-agent-mcp.js +608 -0
  42. package/dist/server/cli.d.ts +6 -0
  43. package/dist/server/cli.js +112 -0
  44. package/dist/server/debug-log.d.ts +25 -0
  45. package/dist/server/debug-log.js +86 -0
  46. package/dist/server/handlers.d.ts +141 -0
  47. package/dist/server/handlers.js +523 -0
  48. package/dist/server/index.d.ts +30 -0
  49. package/dist/server/index.js +28 -0
  50. package/dist/server/kit-api.d.ts +23 -0
  51. package/dist/server/kit-api.js +153 -0
  52. package/dist/server/model-sources.d.ts +32 -0
  53. package/dist/server/model-sources.js +58 -0
  54. package/dist/server/oa.d.ts +87 -0
  55. package/dist/server/oa.js +397 -0
  56. package/dist/server/providers/openrouter.d.ts +51 -0
  57. package/dist/server/providers/openrouter.js +283 -0
  58. package/dist/server/render-markdown.d.ts +2 -0
  59. package/dist/server/render-markdown.js +50 -0
  60. package/dist/server/sdk.d.ts +259 -0
  61. package/dist/server/sdk.js +1991 -0
  62. package/dist/server/session-access.d.ts +5 -0
  63. package/dist/server/session-access.js +68 -0
  64. package/dist/server/session-fork.d.ts +10 -0
  65. package/dist/server/session-fork.js +142 -0
  66. package/dist/server/session-store.d.ts +56 -0
  67. package/dist/server/session-store.js +148 -0
  68. package/dist/server/sessions.d.ts +24 -0
  69. package/dist/server/sessions.js +541 -0
  70. package/dist/server/share.d.ts +15 -0
  71. package/dist/server/share.js +433 -0
  72. package/dist/server/tool-activity.d.ts +2 -0
  73. package/dist/server/tool-activity.js +26 -0
  74. package/dist/server/transcription/xiaomi-mimo.d.ts +8 -0
  75. package/dist/server/transcription/xiaomi-mimo.js +86 -0
  76. package/dist/server/upload.d.ts +13 -0
  77. package/dist/server/upload.js +81 -0
  78. package/dist/server/user-files.d.ts +28 -0
  79. package/dist/server/user-files.js +311 -0
  80. package/dist/server/voice.d.ts +25 -0
  81. package/dist/server/voice.js +61 -0
  82. package/dist/server/web-fetch.d.ts +71 -0
  83. package/dist/server/web-fetch.js +330 -0
  84. package/dist/styles.css +3354 -0
  85. package/dist/transcription/xiaomi-mimo.d.ts +8 -0
  86. package/dist/transcription/xiaomi-mimo.js +86 -0
  87. package/dist/ui/index.d.ts +352 -0
  88. package/dist/ui/index.js +7730 -0
  89. package/dist/upload.d.ts +13 -0
  90. package/dist/upload.js +81 -0
  91. package/dist/voice.d.ts +25 -0
  92. package/dist/voice.js +61 -0
  93. package/package.json +74 -4
@@ -0,0 +1,100 @@
1
+ export function createFeishuProvider(cfg) {
2
+ const id = "feishu";
3
+ const base = cfg.baseUrl;
4
+ function isConfigured() {
5
+ return Boolean(cfg.appId && cfg.appSecret);
6
+ }
7
+ function getAuthorizeUrl(redirectUri, state) {
8
+ const url = new URL(`${base}/open-apis/authen/v1/authorize`);
9
+ url.searchParams.set("app_id", cfg.appId);
10
+ url.searchParams.set("redirect_uri", redirectUri);
11
+ url.searchParams.set("response_type", "code");
12
+ // 空格分隔:im:message = 用户身份读取/发送消息(分享「以当前用户身份发消息」);
13
+ // offline_access = 换取 refresh_token(user_access_token 2h 过期后刷新续期)
14
+ url.searchParams.set("scope", "im:message offline_access");
15
+ url.searchParams.set("state", state);
16
+ return url.toString();
17
+ }
18
+ /** 取企业内部应用 app_access_token(仅支持 internal;ISV 应用需 app_ticket 流程,未实现)。 */
19
+ async function getAppAccessToken() {
20
+ const res = await fetch(`${base}/open-apis/auth/v3/app_access_token/internal`, {
21
+ method: "POST",
22
+ headers: { "Content-Type": "application/json" },
23
+ body: JSON.stringify({ app_id: cfg.appId, app_secret: cfg.appSecret }),
24
+ cache: "no-store",
25
+ });
26
+ const json = (await res.json().catch(() => ({})));
27
+ const token = json.app_access_token || json.data?.app_access_token;
28
+ if (!res.ok || !token) {
29
+ throw new Error(`飞书 app_access_token 换取失败 (${res.status})`);
30
+ }
31
+ return token;
32
+ }
33
+ /** OIDC:用 authorization_code 换 user_access_token(网页与客户端 code 通用)。 */
34
+ async function exchangeOidcCode(code) {
35
+ const appAccessToken = await getAppAccessToken();
36
+ const tokenRes = await fetch(`${base}/open-apis/authen/v1/oidc/access_token`, {
37
+ method: "POST",
38
+ headers: { "Content-Type": "application/json" },
39
+ body: JSON.stringify({
40
+ grant_type: "authorization_code",
41
+ code,
42
+ app_access_token: appAccessToken,
43
+ }),
44
+ cache: "no-store",
45
+ });
46
+ const tokenJson = (await tokenRes.json().catch(() => ({})));
47
+ const data = tokenJson.data || tokenJson;
48
+ const userAccessToken = data.access_token || tokenJson.access_token;
49
+ if (!tokenRes.ok || !userAccessToken) {
50
+ // 附带飞书业务错误码/信息(HTTP 200 + JSON 错误),便于定位 20003 等
51
+ const detail = tokenJson.code != null ? `code=${tokenJson.code} msg=${tokenJson.msg ?? ""}` : "";
52
+ throw new Error(`飞书 user_access_token 换取失败 (${tokenRes.status}) ${detail}`.trim());
53
+ }
54
+ const infoRes = await fetch(`${base}/open-apis/authen/v1/user_info`, {
55
+ headers: { Authorization: `Bearer ${userAccessToken}` },
56
+ cache: "no-store",
57
+ });
58
+ const infoJson = (await infoRes.json().catch(() => ({})));
59
+ const u = infoJson.data || infoJson;
60
+ // 令牌随用户落库(oauthToken),供「以当前用户身份发消息」等服务端调用使用;
61
+ // refresh_token 仅在申请了 offline_access scope 时返回
62
+ const oauthToken = {
63
+ accessToken: userAccessToken,
64
+ refreshToken: data.refresh_token || undefined,
65
+ };
66
+ const unionId = String(u.union_id || u.unionId || "");
67
+ const openId = String(u.open_id || u.openId || "");
68
+ if (!infoRes.ok || (!unionId && !openId)) {
69
+ console.warn("[feishu] user_info 不可读,仅以已验证身份继续登录");
70
+ return {
71
+ provider: id,
72
+ unionId: unionId || `verified:${userAccessToken.slice(0, 16)}`,
73
+ openId,
74
+ name: "飞书用户",
75
+ oauthToken,
76
+ raw: { ...u, _verified: true },
77
+ };
78
+ }
79
+ return {
80
+ provider: id,
81
+ unionId,
82
+ openId,
83
+ userCode: String(u.employee_id || u.employeeId || ""),
84
+ name: String(u.name || "飞书用户"),
85
+ avatar: String(u.avatar_url || u.avatarUrl || ""),
86
+ email: String(u.email || ""),
87
+ mobile: String(u.mobile || ""),
88
+ oauthToken,
89
+ raw: u,
90
+ };
91
+ }
92
+ return {
93
+ id,
94
+ supportsClientSso: true,
95
+ isConfigured,
96
+ getAuthorizeUrl,
97
+ exchangeOAuthCode: exchangeOidcCode,
98
+ exchangeClientCode: exchangeOidcCode,
99
+ };
100
+ }
@@ -0,0 +1,13 @@
1
+ /**
2
+ * agent-kit · 认证提供方工厂
3
+ *
4
+ * 按 method / 指定方式返回对应的认证提供方实例;未配置或非具体平台时返回 null。
5
+ * 上层只依赖 AuthProvider 抽象,不感知具体平台。
6
+ */
7
+ import type { AuthConfig, AuthProvider, AuthProviderId } from "../types.js";
8
+ /** 按指定平台 id 构造提供方实例(不依赖 config.method;多方式场景下按按钮逐个取)。 */
9
+ export declare function createProviderFor(config: AuthConfig, id: AuthProviderId): AuthProvider | null;
10
+ /** 根据认证配置构造当前主启用的提供方;method 非具体平台或对应平台未配置时返回 null。 */
11
+ export declare function createProvider(config: AuthConfig): AuthProvider | null;
12
+ export { createDingTalkProvider } from "./dingtalk.js";
13
+ export { createFeishuProvider } from "./feishu.js";
@@ -0,0 +1,24 @@
1
+ import { createDingTalkProvider } from "./dingtalk.js";
2
+ import { createFeishuProvider } from "./feishu.js";
3
+ /** 按指定平台 id 构造提供方实例(不依赖 config.method;多方式场景下按按钮逐个取)。 */
4
+ export function createProviderFor(config, id) {
5
+ if (id === "dingtalk") {
6
+ const p = createDingTalkProvider(config.dingtalk);
7
+ return p.isConfigured() ? p : null;
8
+ }
9
+ if (id === "feishu") {
10
+ const p = createFeishuProvider(config.feishu);
11
+ return p.isConfigured() ? p : null;
12
+ }
13
+ return null;
14
+ }
15
+ /** 根据认证配置构造当前主启用的提供方;method 非具体平台或对应平台未配置时返回 null。 */
16
+ export function createProvider(config) {
17
+ if (config.method === "dingtalk")
18
+ return createProviderFor(config, "dingtalk");
19
+ if (config.method === "feishu")
20
+ return createProviderFor(config, "feishu");
21
+ return null;
22
+ }
23
+ export { createDingTalkProvider } from "./dingtalk.js";
24
+ export { createFeishuProvider } from "./feishu.js";
@@ -0,0 +1,48 @@
1
+ import type { AuthUser, SessionUser } from "./types.js";
2
+ /** 生成一次性 state(防 CSRF),用于 OAuth 授权跳转。 */
3
+ export declare function generateState(): string;
4
+ /** 由归一化用户构造会话用户(sub = provider:unionId,作为全链路用户主体键)。 */
5
+ export declare function toSessionUser(user: AuthUser): SessionUser;
6
+ /**
7
+ * 解析主体键 `${provider}:${unionId}` → { provider, unionId }。
8
+ * unionId 自身可能含 `:`,故只按**第一个** `:` 切分。
9
+ * 非法(缺 `:`)时返回 provider=""、unionId=原串,交由调用方决定是否视为未登录。
10
+ */
11
+ export declare function parseSessionKey(sub: string): {
12
+ provider: string;
13
+ unionId: string;
14
+ };
15
+ /** 签发会话 token。 */
16
+ export declare function createSessionToken(sessionUser: SessionUser, secret: string): string;
17
+ /** 验证并解析会话 token;失效 / 篡改 / 过期均返回 null。 */
18
+ export declare function verifySessionToken(token: string | undefined | null, secret: string): SessionUser | null;
19
+ export interface CookieOptions {
20
+ path: string;
21
+ secure: boolean;
22
+ maxAgeSeconds?: number;
23
+ }
24
+ /**
25
+ * 标准会话 Cookie 选项。
26
+ * - secure=false(本地 http / 同 site 场景,如桌面端 dev):SameSite=Lax,无 Secure。
27
+ * 桌面端正确姿势:主进程把页面 host 统一为 127.0.0.1(与引擎同 site),Lax cookie 随
28
+ * fetch 正常携带。
29
+ * - secure=true:SameSite=None + Secure。注意:Chromium 的 Secure cookie 例外仅限
30
+ * localhost 主机名,**不含 127.0.0.1**——在 http://127.0.0.1 上 Secure cookie 会被浏览器
31
+ * 拒绝发送(存储有、请求不带,表现为"每次启动都要重新登录"),因此本地 http 引擎
32
+ * 绝不能开 secure。
33
+ */
34
+ export declare function sessionCookieOptions(cookiePath: string, secure: boolean, maxAgeSeconds?: number): {
35
+ httpOnly: boolean;
36
+ sameSite: "none" | "lax";
37
+ secure: boolean;
38
+ path: string;
39
+ maxAge: number;
40
+ };
41
+ /** 短期(10 分钟)state Cookie 选项,用于 OAuth 往返校验(同会话策略)。 */
42
+ export declare function stateCookieOptions(cookiePath: string, secure: boolean, maxAgeSeconds?: number): {
43
+ httpOnly: boolean;
44
+ sameSite: "none" | "lax";
45
+ secure: boolean;
46
+ path: string;
47
+ maxAge: number;
48
+ };
@@ -0,0 +1,108 @@
1
+ /**
2
+ * agent-kit · 会话与 Cookie 工具
3
+ *
4
+ * 会话采用「无状态签名 token」:payload 经 base64url 编码,再用 HMAC-SHA256 签名,
5
+ * 写入 httpOnly Cookie。验证时不查库即可确认身份未被篡改,过期由 exp 字段控制。
6
+ * 与 hotline 思路一致,但全部参数化(密钥 / Cookie 名 / 路径由调用方传入),
7
+ * 不写死任何项目专属常量,便于多 app 复用。
8
+ */
9
+ import { createHmac, randomUUID, timingSafeEqual } from "node:crypto";
10
+ const SESSION_MAX_AGE_SECONDS = 60 * 60 * 24 * 7; // 7 天
11
+ function base64UrlEncode(input) {
12
+ return Buffer.from(input)
13
+ .toString("base64")
14
+ .replace(/\+/g, "-")
15
+ .replace(/\//g, "_")
16
+ .replace(/=+$/g, "");
17
+ }
18
+ function base64UrlDecode(input) {
19
+ const normalized = input.replace(/-/g, "+").replace(/_/g, "/");
20
+ const padded = normalized.padEnd(Math.ceil(normalized.length / 4) * 4, "=");
21
+ return Buffer.from(padded, "base64");
22
+ }
23
+ function sign(value, secret) {
24
+ return base64UrlEncode(createHmac("sha256", secret).update(value).digest());
25
+ }
26
+ /** 生成一次性 state(防 CSRF),用于 OAuth 授权跳转。 */
27
+ export function generateState() {
28
+ return randomUUID();
29
+ }
30
+ /** 由归一化用户构造会话用户(sub = provider:unionId,作为全链路用户主体键)。 */
31
+ export function toSessionUser(user) {
32
+ return {
33
+ sub: `${user.provider}:${user.unionId}`,
34
+ provider: user.provider,
35
+ unionId: user.unionId,
36
+ openId: user.openId,
37
+ name: user.name || "用户",
38
+ avatar: user.avatar || "",
39
+ exp: Math.floor(Date.now() / 1000) + SESSION_MAX_AGE_SECONDS,
40
+ };
41
+ }
42
+ /**
43
+ * 解析主体键 `${provider}:${unionId}` → { provider, unionId }。
44
+ * unionId 自身可能含 `:`,故只按**第一个** `:` 切分。
45
+ * 非法(缺 `:`)时返回 provider=""、unionId=原串,交由调用方决定是否视为未登录。
46
+ */
47
+ export function parseSessionKey(sub) {
48
+ const idx = sub.indexOf(":");
49
+ if (idx < 0)
50
+ return { provider: "", unionId: sub };
51
+ return { provider: sub.slice(0, idx), unionId: sub.slice(idx + 1) };
52
+ }
53
+ /** 签发会话 token。 */
54
+ export function createSessionToken(sessionUser, secret) {
55
+ const payload = base64UrlEncode(JSON.stringify(sessionUser));
56
+ return `${payload}.${sign(payload, secret)}`;
57
+ }
58
+ /** 验证并解析会话 token;失效 / 篡改 / 过期均返回 null。 */
59
+ export function verifySessionToken(token, secret) {
60
+ if (!token || !token.includes("."))
61
+ return null;
62
+ const [payload, signature] = token.split(".");
63
+ if (!payload || !signature)
64
+ return null;
65
+ const expected = sign(payload, secret);
66
+ const a = Buffer.from(signature);
67
+ const b = Buffer.from(expected);
68
+ if (a.length !== b.length || !timingSafeEqual(a, b))
69
+ return null;
70
+ try {
71
+ const user = JSON.parse(base64UrlDecode(payload).toString("utf8"));
72
+ if (!user.sub || !user.exp || user.exp <= Math.floor(Date.now() / 1000))
73
+ return null;
74
+ return user;
75
+ }
76
+ catch {
77
+ return null;
78
+ }
79
+ }
80
+ /**
81
+ * 标准会话 Cookie 选项。
82
+ * - secure=false(本地 http / 同 site 场景,如桌面端 dev):SameSite=Lax,无 Secure。
83
+ * 桌面端正确姿势:主进程把页面 host 统一为 127.0.0.1(与引擎同 site),Lax cookie 随
84
+ * fetch 正常携带。
85
+ * - secure=true:SameSite=None + Secure。注意:Chromium 的 Secure cookie 例外仅限
86
+ * localhost 主机名,**不含 127.0.0.1**——在 http://127.0.0.1 上 Secure cookie 会被浏览器
87
+ * 拒绝发送(存储有、请求不带,表现为"每次启动都要重新登录"),因此本地 http 引擎
88
+ * 绝不能开 secure。
89
+ */
90
+ export function sessionCookieOptions(cookiePath, secure, maxAgeSeconds = SESSION_MAX_AGE_SECONDS) {
91
+ return {
92
+ httpOnly: true,
93
+ sameSite: (secure ? "none" : "lax"),
94
+ secure,
95
+ path: cookiePath,
96
+ maxAge: maxAgeSeconds,
97
+ };
98
+ }
99
+ /** 短期(10 分钟)state Cookie 选项,用于 OAuth 往返校验(同会话策略)。 */
100
+ export function stateCookieOptions(cookiePath, secure, maxAgeSeconds = 10 * 60) {
101
+ return {
102
+ httpOnly: true,
103
+ sameSite: (secure ? "none" : "lax"),
104
+ secure,
105
+ path: cookiePath,
106
+ maxAge: maxAgeSeconds,
107
+ };
108
+ }
@@ -0,0 +1,118 @@
1
+ /**
2
+ * agent-kit · 认证类型定义
3
+ *
4
+ * 抽象层核心:所有认证提供方(钉钉 / 飞书 / 自建 builtin)都归一化为 AuthUser;
5
+ * 上层(会话、数据库、路由)只认 AuthUser,不关心来自哪个平台。
6
+ */
7
+ export type AuthProviderId = "dingtalk" | "feishu" | "builtin";
8
+ /**
9
+ * AUTH_PROVIDER 合法取值:OAuth 平台 + builtin(自建账号体系)+ adaptive + none 关闭。
10
+ * builtin 目前仅留口子:类型 / 配置解析 / 登录页均认可该方式,
11
+ * 但「自建登录系统(页面 + 用户名密码会话)」尚未实现——
12
+ * isMethodConfigured("builtin") 暂恒 false,因此 builtin 暂不会出现在登录方式清单里。
13
+ * adaptive:按客户端 UA 自动决定走钉钉还是飞书(钉钉 App → 钉钉免登/OAuth,飞书 App → 飞书 OAuth,
14
+ * 其他浏览器 → 渲染登录方式选择器)。配置上要求至少一个 OAuth 平台 env 齐全才能启用。
15
+ */
16
+ export type AuthMethod = AuthProviderId | "none" | "adaptive";
17
+ /** 归一化后的用户身份(跨提供方统一结构)。 */
18
+ export interface AuthUser {
19
+ /** 来源平台 */
20
+ provider: AuthProviderId;
21
+ /** 跨应用唯一 ID(钉钉 unionid / 飞书 union_id)—— 数据库主匹配键 */
22
+ unionId: string;
23
+ /** 企业内唯一 ID(钉钉 openId / 飞书 open_id) */
24
+ openId: string;
25
+ /** 企业内部工号(钉钉 userid / 飞书 employee_id),可为空 */
26
+ userCode?: string;
27
+ /** 展示名 */
28
+ name: string;
29
+ /** 头像 URL */
30
+ avatar?: string;
31
+ /** 邮箱(提供方返回时才有) */
32
+ email?: string;
33
+ /** 手机号(提供方返回时才有) */
34
+ mobile?: string;
35
+ /** 部门名(钉钉通讯录可解析;飞书需额外权限) */
36
+ deptName?: string;
37
+ /** OAuth 令牌(不落 session,仅用于落库持久化:飞书用户身份发消息等场景) */
38
+ oauthToken?: {
39
+ accessToken: string;
40
+ refreshToken?: string;
41
+ };
42
+ /** 提供方原始档案(落库到 raw_profile),便于扩展字段 */
43
+ raw?: Record<string, unknown>;
44
+ }
45
+ /** 写入会话 Cookie 的精简用户(无敏感字段)。 */
46
+ export interface SessionUser {
47
+ /** 用户主体键:${provider}:${unionId} —— 全链路(会话 / 归属 / 分享 / DB)以此为准 */
48
+ sub: string;
49
+ provider: AuthProviderId;
50
+ unionId: string;
51
+ openId: string;
52
+ name: string;
53
+ avatar?: string;
54
+ exp: number;
55
+ }
56
+ /**
57
+ * 认证提供方抽象接口。
58
+ * 每个具体实现(钉钉 / 飞书)只需实现:构建网页 OAuth 授权 URL、用网页 code 换用户、
59
+ * 以及可选的客户端内 JSAPI 免登 code 换用户。
60
+ *
61
+ * 注意:builtin(自建账号体系)不是 OAuth 平台,不实现本接口;
62
+ * 其登录系统(页面 + 用户名密码校验 + 会话签发)后续单独实现,届时复用 finalizeLogin 落库与会话。
63
+ */
64
+ export interface AuthProvider {
65
+ /** 提供方标识 */
66
+ readonly id: AuthProviderId;
67
+ /** 是否支持客户端内 JSAPI 免登(钉钉/飞书均支持) */
68
+ readonly supportsClientSso: boolean;
69
+ /** 是否已配置完该方式所需的全部 env(未配置时不应启用) */
70
+ isConfigured(): boolean;
71
+ /** 构建网页 OAuth 授权 URL(用户扫码 / 授权页) */
72
+ getAuthorizeUrl(redirectUri: string, state: string): string;
73
+ /** 用网页 OAuth 的 auth code 换取归一化用户 */
74
+ exchangeOAuthCode(code: string, redirectUri?: string): Promise<AuthUser>;
75
+ /** 用客户端内 JSAPI 免登 code 换取归一化用户(可选) */
76
+ exchangeClientCode?(code: string): Promise<AuthUser>;
77
+ }
78
+ /** 认证配置(由 env 解析,见 config.ts)。 */
79
+ export interface AuthConfig {
80
+ /**
81
+ * AUTH_PROVIDER 完整解析结果(按 `,` 或 `|` 分隔、去重、过滤非法值、忽略 none 与其它值共存时的 none)。
82
+ * 可含 builtin / dingtalk / feishu;顺序即展示顺序。
83
+ */
84
+ methods: AuthMethod[];
85
+ /**
86
+ * 主认证方式(methods 中第一个非 none 的值;不存在时 "none")。
87
+ * 保留给单方式场景与历史逻辑:dingtalk | feishu | builtin | adaptive | none
88
+ */
89
+ method: "dingtalk" | "feishu" | "builtin" | "adaptive" | "none";
90
+ /** 对外基础地址(拼接回调跳转用),如 http://localhost:3100 */
91
+ publicUrl: string;
92
+ /** 会话 Cookie 路径(需与 Next basePath 一致,如 /agent) */
93
+ cookiePath: string;
94
+ /** 会话签名密钥 */
95
+ sessionSecret: string;
96
+ /** Cookie 是否 secure */
97
+ secureCookie: boolean;
98
+ /** 钉钉配置(method=dingtalk 时必填) */
99
+ dingtalk: {
100
+ clientId: string;
101
+ clientSecret: string;
102
+ corpId: string;
103
+ /** 企业内部应用微应用 AgentId(env DD_AGENT_ID)。H5 JSAPI 前端鉴权(分享到钉钉会话)必填 */
104
+ agentId: string;
105
+ /** 机器人 code(env DD_ROBOT_CODE,可选)。发送群消息用;未配置时默认用 clientId(企业内部应用机器人 code = AppKey) */
106
+ robotCode?: string;
107
+ /** 互动卡片模板 ID(env DD_CARD_TEMPLATE_ID)。用户身份发送分享(sendMessageToGroup)必填;在钉钉开发者后台「卡片平台」创建模板后获取 */
108
+ cardTemplateId?: string;
109
+ redirectUri?: string;
110
+ };
111
+ /** 飞书配置(method=feishu 时必填)。仅支持企业内部应用(isv 应用商店应用未实现) */
112
+ feishu: {
113
+ appId: string;
114
+ appSecret: string;
115
+ baseUrl: string;
116
+ redirectUri?: string;
117
+ };
118
+ }
@@ -0,0 +1,7 @@
1
+ /**
2
+ * agent-kit · 认证类型定义
3
+ *
4
+ * 抽象层核心:所有认证提供方(钉钉 / 飞书 / 自建 builtin)都归一化为 AuthUser;
5
+ * 上层(会话、数据库、路由)只认 AuthUser,不关心来自哪个平台。
6
+ */
7
+ export {};
@@ -0,0 +1,67 @@
1
+ /**
2
+ * agent-kit · browser-agent MCP 工具(computer use:AI 自主控制浏览器)
3
+ *
4
+ * 设计:把"浏览器操作智能体"封装成一个 MCP 工具 control_browser(task),由聊天模型(hy3)
5
+ * 在对话中**自主决定**何时调用——无需用户在 UI 上手动触发。
6
+ *
7
+ * 工具内部是一个纯视觉 computer-use 循环(与 web-fetch 同款 Playwright 持久上下文):
8
+ * 截图 → 把截图作为图片发给 hy3(allowedTools:[] 关掉工具、maxTurns:1 不自循环,仅做视觉
9
+ * 推理输出动作 JSON)→ 解析并执行(click/type/scroll/navigate/wait/done/ask)→ 循环。
10
+ *
11
+ * 关键能力:
12
+ * - 全程通过 SSE 事件(screenshot / thinking / action / done / ask / finished)外发,
13
+ * 聊天模型经 canUseTool 拦截时注册订阅者,过程事件同步转发进聊天 SSE,
14
+ * 前端 thinking 展开区实时展示浏览器截图与动作(headless 无独立窗口)。
15
+ * - 单例 BrowserAgentService 同时服务「手动入口(/api/browser/session)」与
16
+ * 「自主 control_browser 工具」,二者共用同一会话注册表,避免重复实现。
17
+ * - 容错解析:容忍 Markdown 代码块、尾随逗号;连续无效操作(疑似卡死)自动停止。
18
+ *
19
+ * 暴露:control_browser(task: string, max_steps?: number) → { summary, finalUrl, finalTitle, steps }
20
+ */
21
+ import { type SdkMcpServerResult } from "@tencent-ai/agent-sdk";
22
+ export interface BrowserTaskResult {
23
+ summary: string;
24
+ finalUrl: string;
25
+ finalTitle: string;
26
+ steps: string[];
27
+ stopped: boolean;
28
+ }
29
+ /**
30
+ * BrowserAgentService:浏览器 computer-use 单例。
31
+ * 同时服务「手动入口(/api/browser/session)」与「自主 control_browser 工具」。
32
+ * 同一时刻串行执行一个任务(共享 profile 目录)。
33
+ */
34
+ export declare class BrowserAgentService {
35
+ private static instance;
36
+ private queue;
37
+ private readonly profileDir;
38
+ private sessions;
39
+ /** 下一个任务的聊天流订阅者:control_browser 工具经 canUseTool 拦截时设置,
40
+ * run() 创建会话后自动挂到该会话,浏览器过程事件同步转发进聊天 SSE。 */
41
+ private pendingSubscriber;
42
+ private constructor();
43
+ static get(): BrowserAgentService;
44
+ /** 注册下一个任务的聊天流订阅者(canUseTool 拦截 control_browser 时调用) */
45
+ setPendingSubscriber(cb: (event: string, data: unknown) => void): void;
46
+ /** 启动一个浏览器任务(异步执行),立即返回会话 id 与完成 Promise。
47
+ * headless 模式无可见窗口;过程事件经 subscriber 转发进聊天 thinking 展示。 */
48
+ run(task: string, maxSteps?: number, notify?: boolean): {
49
+ id: string;
50
+ done: Promise<BrowserTaskResult>;
51
+ };
52
+ /** 自主工具调用入口:返回最终结论(headless 无弹窗;过程事件进聊天 thinking) */
53
+ runTask(task: string, maxSteps?: number): Promise<BrowserTaskResult>;
54
+ /** 把已存在的会话 SSE 流挂到某个控制面板(手动入口或自主模式自动弹窗都走这里) */
55
+ attach(id: string): ReadableStream<Uint8Array>;
56
+ input(id: string, text: string): boolean;
57
+ stop(id: string): boolean;
58
+ private doRun;
59
+ private waitForHuman;
60
+ private execute;
61
+ }
62
+ /** 每次调用创建独立 McpServer 实例(绝不共享):agent-sdk 每个 query 的 transport 都会对
63
+ * 传入实例调用 server.connect(),而 MCP Protocol 实例只允许 connect 一次;共享实例在并发
64
+ * 或先后复用时抛 "Already connected to a transport"。薄壳开销可忽略(BrowserAgentService 为单例)。 */
65
+ export declare function createBrowserAgentMcpServer(): SdkMcpServerResult;
66
+ /** 工具在模型上下文中暴露的名称(server 名连字符转下划线) */
67
+ export declare const BROWSER_AGENT_TOOL_NAME = "mcp__browser_agent__control_browser";