openclaw-openagent 1.0.0 → 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +25 -0
- package/dist/index.js +105 -0
- package/dist/src/app/channel-tools.d.ts +28 -0
- package/dist/src/app/channel-tools.js +251 -0
- package/dist/src/app/discovery-tools.d.ts +35 -0
- package/dist/src/app/discovery-tools.js +243 -0
- package/dist/src/app/download-file-tool.d.ts +10 -0
- package/dist/src/app/download-file-tool.js +104 -0
- package/dist/src/app/hooks.d.ts +14 -0
- package/dist/src/app/hooks.js +118 -0
- package/dist/src/app/index.d.ts +13 -0
- package/dist/src/app/index.js +44 -0
- package/dist/src/app/messaging-tools.d.ts +11 -0
- package/dist/src/app/messaging-tools.js +79 -0
- package/dist/src/app/ops-tools.d.ts +21 -0
- package/dist/src/app/ops-tools.js +158 -0
- package/dist/src/app/remote-agent-tool.d.ts +27 -0
- package/dist/src/app/remote-agent-tool.js +461 -0
- package/dist/src/app/types.d.ts +61 -0
- package/dist/src/app/types.js +11 -0
- package/dist/src/app/upload-file-tool.d.ts +16 -0
- package/dist/src/app/upload-file-tool.js +353 -0
- package/dist/src/app/verbose-preflight.d.ts +2 -0
- package/dist/src/app/verbose-preflight.js +145 -0
- package/dist/src/auth/config.d.ts +79 -0
- package/dist/src/auth/config.js +133 -0
- package/dist/src/auth/credential-manager.d.ts +65 -0
- package/dist/src/auth/credential-manager.js +122 -0
- package/dist/src/auth/index.d.ts +6 -0
- package/dist/src/auth/index.js +6 -0
- package/dist/src/auth/verify.d.ts +42 -0
- package/dist/src/auth/verify.js +60 -0
- package/dist/src/channel.d.ts +269 -0
- package/dist/src/channel.js +488 -0
- package/dist/src/compat.d.ts +37 -0
- package/dist/src/compat.js +70 -0
- package/dist/src/config/config-schema.d.ts +56 -0
- package/dist/src/config/config-schema.js +34 -0
- package/dist/src/messaging/aggregator.d.ts +25 -0
- package/dist/src/messaging/aggregator.js +90 -0
- package/dist/src/messaging/collector.d.ts +27 -0
- package/dist/src/messaging/collector.js +76 -0
- package/dist/src/messaging/executor.d.ts +14 -0
- package/dist/src/messaging/executor.js +59 -0
- package/dist/src/messaging/inbound.d.ts +97 -0
- package/dist/src/messaging/inbound.js +63 -0
- package/dist/src/messaging/index.d.ts +10 -0
- package/dist/src/messaging/index.js +9 -0
- package/dist/src/messaging/mention-protocol.d.ts +42 -0
- package/dist/src/messaging/mention-protocol.js +74 -0
- package/dist/src/messaging/process-c2c-request.d.ts +55 -0
- package/dist/src/messaging/process-c2c-request.js +445 -0
- package/dist/src/messaging/process-message.d.ts +62 -0
- package/dist/src/messaging/process-message.js +282 -0
- package/dist/src/messaging/scheduler.d.ts +17 -0
- package/dist/src/messaging/scheduler.js +47 -0
- package/dist/src/messaging/types.d.ts +34 -0
- package/dist/src/messaging/types.js +4 -0
- package/dist/src/plugin-ui/assets/openagent-override.js +9267 -0
- package/dist/src/plugin-ui/index.d.ts +13 -0
- package/dist/src/plugin-ui/index.js +16 -0
- package/dist/src/plugin-ui/ui-extension-loader/backup.d.ts +23 -0
- package/dist/src/plugin-ui/ui-extension-loader/backup.js +82 -0
- package/dist/src/plugin-ui/ui-extension-loader/index.d.ts +28 -0
- package/dist/src/plugin-ui/ui-extension-loader/index.js +240 -0
- package/dist/src/plugin-ui/ui-extension-loader/locator.d.ts +35 -0
- package/dist/src/plugin-ui/ui-extension-loader/locator.js +129 -0
- package/dist/src/plugin-ui/ui-extension-loader/manifest.d.ts +26 -0
- package/dist/src/plugin-ui/ui-extension-loader/manifest.js +45 -0
- package/dist/src/plugin-ui/ui-extension-loader/registry-regex.d.ts +9 -0
- package/dist/src/plugin-ui/ui-extension-loader/registry-regex.js +701 -0
- package/dist/src/plugin-ui/ui-extension-loader/removed-extensions.d.ts +8 -0
- package/dist/src/plugin-ui/ui-extension-loader/removed-extensions.js +58 -0
- package/dist/src/plugin-ui/ui-extension-loader/types.d.ts +55 -0
- package/dist/src/plugin-ui/ui-extension-loader/types.js +23 -0
- package/dist/src/proxy/auth-proxy.d.ts +20 -0
- package/dist/src/proxy/auth-proxy.js +337 -0
- package/dist/src/runtime/account.d.ts +156 -0
- package/dist/src/runtime/account.js +491 -0
- package/dist/src/runtime/index.d.ts +5 -0
- package/dist/src/runtime/index.js +6 -0
- package/dist/src/runtime/plugin-runtime.d.ts +40 -0
- package/dist/src/runtime/plugin-runtime.js +72 -0
- package/dist/src/runtime/registry.d.ts +41 -0
- package/dist/src/runtime/registry.js +60 -0
- package/dist/src/sdk/CLASS_MAP.md +143 -0
- package/dist/src/sdk/index.d.ts +126 -0
- package/dist/src/sdk/index.js +23990 -0
- package/dist/src/sdk/modules/cloud-search-module.js +1117 -0
- package/dist/src/sdk/modules/follow-module.js +1069 -0
- package/dist/src/sdk/modules/group-module.js +7397 -0
- package/dist/src/sdk/modules/relationship-module.js +2269 -0
- package/dist/src/sdk/modules/signaling-module.js +1468 -0
- package/dist/src/sdk/modules/tim-upload-plugin.js +730 -0
- package/dist/src/sdk/node-env/http-request.js +90 -0
- package/dist/src/sdk/node-env/index.js +57 -0
- package/dist/src/sdk/node-env/storage.js +114 -0
- package/dist/src/sdk/package.json +10 -0
- package/dist/src/sdk/sdk/CLASS_MAP.md +143 -0
- package/dist/src/sdk/sdk/index.d.ts +126 -0
- package/dist/src/sdk/sdk/index.js +23990 -0
- package/dist/src/sdk/sdk/modules/cloud-search-module.js +1117 -0
- package/dist/src/sdk/sdk/modules/follow-module.js +1069 -0
- package/dist/src/sdk/sdk/modules/group-module.js +7397 -0
- package/dist/src/sdk/sdk/modules/relationship-module.js +2269 -0
- package/dist/src/sdk/sdk/modules/signaling-module.js +1468 -0
- package/dist/src/sdk/sdk/modules/tim-upload-plugin.js +730 -0
- package/dist/src/sdk/sdk/node-env/http-request.js +90 -0
- package/dist/src/sdk/sdk/node-env/index.js +57 -0
- package/dist/src/sdk/sdk/node-env/storage.js +114 -0
- package/dist/src/sdk/sdk/package.json +10 -0
- package/dist/src/sdk/sdk/tsconfig.json +16 -0
- package/dist/src/sdk/tsconfig.json +16 -0
- package/dist/src/state/pending-invocation-store.d.ts +26 -0
- package/dist/src/state/pending-invocation-store.js +39 -0
- package/dist/src/state/store.d.ts +165 -0
- package/dist/src/state/store.js +535 -0
- package/dist/src/tim/c2c.d.ts +83 -0
- package/dist/src/tim/c2c.js +318 -0
- package/dist/src/tim/channels.d.ts +95 -0
- package/dist/src/tim/channels.js +279 -0
- package/dist/src/tim/client.d.ts +54 -0
- package/dist/src/tim/client.js +268 -0
- package/dist/src/tim/index.d.ts +6 -0
- package/dist/src/tim/index.js +6 -0
- package/dist/src/tim/messages.d.ts +50 -0
- package/dist/src/tim/messages.js +104 -0
- package/dist/src/tim/sdk-logger-init.d.ts +13 -0
- package/dist/src/tim/sdk-logger-init.js +46 -0
- package/dist/src/tools.d.ts +9 -0
- package/dist/src/tools.js +8 -0
- package/dist/src/transport/factory.d.ts +63 -0
- package/dist/src/transport/factory.js +54 -0
- package/dist/src/transport/oasn/index.d.ts +12 -0
- package/dist/src/transport/oasn/index.js +9 -0
- package/dist/src/transport/oasn/oasn-agent-card.d.ts +38 -0
- package/dist/src/transport/oasn/oasn-agent-card.js +102 -0
- package/dist/src/transport/oasn/oasn-discovery.d.ts +33 -0
- package/dist/src/transport/oasn/oasn-discovery.js +97 -0
- package/dist/src/transport/oasn/oasn-files.d.ts +64 -0
- package/dist/src/transport/oasn/oasn-files.js +174 -0
- package/dist/src/transport/oasn/oasn-http.d.ts +98 -0
- package/dist/src/transport/oasn/oasn-http.js +362 -0
- package/dist/src/transport/oasn/oasn-invocation.d.ts +154 -0
- package/dist/src/transport/oasn/oasn-invocation.js +432 -0
- package/dist/src/transport/oasn/oasn-normalize.d.ts +6 -0
- package/dist/src/transport/oasn/oasn-normalize.js +112 -0
- package/dist/src/transport/oasn/oasn-register.d.ts +19 -0
- package/dist/src/transport/oasn/oasn-register.js +24 -0
- package/dist/src/transport/oasn/oasn-transport.d.ts +114 -0
- package/dist/src/transport/oasn/oasn-transport.js +230 -0
- package/dist/src/transport/oasn/oasn-types.d.ts +331 -0
- package/dist/src/transport/oasn/oasn-types.js +44 -0
- package/dist/src/transport/tim/index.d.ts +7 -0
- package/dist/src/transport/tim/index.js +6 -0
- package/dist/src/transport/tim/tim-transport.d.ts +122 -0
- package/dist/src/transport/tim/tim-transport.js +402 -0
- package/dist/src/transport/types.d.ts +450 -0
- package/dist/src/transport/types.js +38 -0
- package/dist/src/util/http.d.ts +21 -0
- package/dist/src/util/http.js +93 -0
- package/dist/src/util/logger.d.ts +20 -0
- package/dist/src/util/logger.js +100 -0
- package/dist/src/util/url-resolver.d.ts +7 -0
- package/dist/src/util/url-resolver.js +20 -0
- package/index.ts +11 -0
- package/openclaw.plugin.json +9 -0
- package/package.json +7 -4
- package/src/app/download-file-tool.ts +133 -0
- package/src/app/hooks.ts +89 -5
- package/src/app/index.ts +6 -0
- package/src/app/remote-agent-tool.ts +46 -0
- package/src/app/types.ts +1 -0
- package/src/app/upload-file-tool.ts +411 -0
- package/src/plugin-ui/assets/openagent-override.js +1 -63
- package/src/plugin-ui/modules/agent-book/panel/agent-book.js +0 -61
- package/src/plugin-ui/modules/agent-book/panel/agent-data.js +0 -1
- package/src/plugin-ui/ui-extension-loader/registry-regex.ts +30 -13
- package/src/runtime/account.ts +0 -23
- package/src/transport/oasn/oasn-files.ts +5 -5
- package/src/transport/oasn/oasn-invocation.ts +44 -2
- package/src/transport/oasn/oasn-normalize.ts +0 -26
- package/src/transport/oasn/oasn-register.ts +8 -81
- package/src/transport/oasn/oasn-transport.ts +9 -32
- package/src/transport/oasn/oasn-types.ts +53 -6
- package/src/transport/types.ts +33 -36
- package/src/util/url-resolver.ts +17 -0
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export type RemovedRevertResult = 'none' | 'restored' | 'failed';
|
|
2
|
+
export type RemovedUIExtension = {
|
|
3
|
+
id: string;
|
|
4
|
+
/** Which shared file group this removed extension belongs to (if any). */
|
|
5
|
+
sharedFile?: string;
|
|
6
|
+
revert(controlUiDir: string): RemovedRevertResult;
|
|
7
|
+
};
|
|
8
|
+
export declare const REMOVED_UI_EXTENSIONS: RemovedUIExtension[];
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { readFileSync } from 'node:fs';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import { logger } from '../../util/logger.js';
|
|
4
|
+
import { findFileByPrefix, resolveOpenClawDistDir } from './locator.js';
|
|
5
|
+
import { restoreFile } from './backup.js';
|
|
6
|
+
function fileNeedsRemoval(filepath, id, fingerprints) {
|
|
7
|
+
const content = readFileSync(filepath, 'utf-8');
|
|
8
|
+
return content.includes(`/*openagent:${id}`) || fingerprints.some(fp => content.includes(fp));
|
|
9
|
+
}
|
|
10
|
+
function restoreRemovedPatch(filepath, id, fingerprints) {
|
|
11
|
+
if (!filepath)
|
|
12
|
+
return 'none';
|
|
13
|
+
if (!fileNeedsRemoval(filepath, id, fingerprints))
|
|
14
|
+
return 'none';
|
|
15
|
+
const restored = restoreFile(filepath);
|
|
16
|
+
if (!restored) {
|
|
17
|
+
logger.warn(`[ui-ext] ${id}: removed extension is present but no backup exists; refusing to continue`);
|
|
18
|
+
return 'failed';
|
|
19
|
+
}
|
|
20
|
+
logger.info(`[ui-ext] ${id}: removed extension reverted from backup`);
|
|
21
|
+
return 'restored';
|
|
22
|
+
}
|
|
23
|
+
export const REMOVED_UI_EXTENSIONS = [
|
|
24
|
+
{
|
|
25
|
+
id: 'gateway-openagent-tool-payload',
|
|
26
|
+
revert(controlUiDir) {
|
|
27
|
+
const distDir = resolveOpenClawDistDir(controlUiDir);
|
|
28
|
+
const gatewayPath = distDir ? findFileByPrefix(distDir, 'gateway-cli-') : null;
|
|
29
|
+
return restoreRemovedPatch(gatewayPath, this.id, [
|
|
30
|
+
'__openagentToolCallIds',
|
|
31
|
+
'__openagentKeepToolPayload',
|
|
32
|
+
'__openagentEffectiveToolVerbose',
|
|
33
|
+
]);
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
id: 'agent-event-openagent-tool-result',
|
|
38
|
+
revert(controlUiDir) {
|
|
39
|
+
const distDir = resolveOpenClawDistDir(controlUiDir);
|
|
40
|
+
const agentBundlePath = distDir ? findFileByPrefix(distDir, 'auth-profiles-') : null;
|
|
41
|
+
return restoreRemovedPatch(agentBundlePath, this.id, [
|
|
42
|
+
'__openagentIsRemoteToolName',
|
|
43
|
+
]);
|
|
44
|
+
},
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
id: 'marked-expose',
|
|
48
|
+
sharedFile: 'index-bundle',
|
|
49
|
+
revert(controlUiDir) {
|
|
50
|
+
const assetsDir = join(controlUiDir, 'assets');
|
|
51
|
+
const bundlePath = findFileByPrefix(assetsDir, 'index-');
|
|
52
|
+
return restoreRemovedPatch(bundlePath, this.id, [
|
|
53
|
+
'window.__openagentMarked=',
|
|
54
|
+
'__openagentMarked',
|
|
55
|
+
]);
|
|
56
|
+
},
|
|
57
|
+
},
|
|
58
|
+
];
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* UIExtension 类型定义与注册表
|
|
3
|
+
*
|
|
4
|
+
* 每个 UIExtension 是一个独立的、可增删的扩展点。
|
|
5
|
+
* 框架只关心 id 和 version,具体操作由 apply/revert 内部处理。
|
|
6
|
+
*/
|
|
7
|
+
export interface UIExtension {
|
|
8
|
+
/** 唯一标识(如 'override-script'、'html-script-tag') */
|
|
9
|
+
id: string;
|
|
10
|
+
/** 内容版本,改了 apply 逻辑就递增 */
|
|
11
|
+
version: number;
|
|
12
|
+
/**
|
|
13
|
+
* 共享文件标识(可选)。
|
|
14
|
+
*
|
|
15
|
+
* 多个扩展修改同一文件时(如 toolcard-render 和 toolcallid-propagate 都改 index-*.js),
|
|
16
|
+
* 设置相同的 sharedFile 值。reconciler 会把它们作为一组处理:
|
|
17
|
+
* 任何一个需要变更 → 恢复 backup → 重新 apply 全组中应保留的扩展。
|
|
18
|
+
*
|
|
19
|
+
* 不设置此字段的扩展独立 apply/revert,不受其他扩展影响。
|
|
20
|
+
*/
|
|
21
|
+
sharedFile?: string;
|
|
22
|
+
/**
|
|
23
|
+
* 每次启动都调用 apply(可选)。
|
|
24
|
+
*
|
|
25
|
+
* 默认行为:manifest version 匹配时跳过 apply。
|
|
26
|
+
* 设为 true 后:即使 version 不变也调用 apply,由 apply 内部判断是否需要操作。
|
|
27
|
+
* 适用于内容可能独立于 version 变化的扩展(如 override-script 的产物文件)。
|
|
28
|
+
*/
|
|
29
|
+
alwaysApply?: boolean;
|
|
30
|
+
/**
|
|
31
|
+
* 加载扩展。
|
|
32
|
+
* 接收 control-ui 目录路径,内部自行决定改什么文件、怎么改。
|
|
33
|
+
* 返回 true 表示成功,false 表示失败(不写入 manifest,下次重试)。
|
|
34
|
+
*/
|
|
35
|
+
apply: (controlUiDir: string) => boolean;
|
|
36
|
+
/**
|
|
37
|
+
* 卸载扩展。
|
|
38
|
+
* 还原 apply 所做的全部修改。
|
|
39
|
+
* 注意:共享文件的扩展不应单独调用 revert,由 reconciler 统一处理。
|
|
40
|
+
*/
|
|
41
|
+
revert: (controlUiDir: string) => void;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* OpenAgent 标记前缀,注入的代码旁加此注释以标识修改来源。
|
|
45
|
+
* 格式:/*openagent:<extension-id>* /
|
|
46
|
+
*/
|
|
47
|
+
export declare const OPENAGENT_MARKER_PREFIX = "/*openagent:";
|
|
48
|
+
/**
|
|
49
|
+
* 生成标记注释。
|
|
50
|
+
*/
|
|
51
|
+
export declare function makeMarker(extensionId: string): string;
|
|
52
|
+
/**
|
|
53
|
+
* 检查内容中是否包含指定扩展点的标记。
|
|
54
|
+
*/
|
|
55
|
+
export declare function hasMarker(content: string, extensionId: string): boolean;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* UIExtension 类型定义与注册表
|
|
3
|
+
*
|
|
4
|
+
* 每个 UIExtension 是一个独立的、可增删的扩展点。
|
|
5
|
+
* 框架只关心 id 和 version,具体操作由 apply/revert 内部处理。
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* OpenAgent 标记前缀,注入的代码旁加此注释以标识修改来源。
|
|
9
|
+
* 格式:/*openagent:<extension-id>* /
|
|
10
|
+
*/
|
|
11
|
+
export const OPENAGENT_MARKER_PREFIX = '/*openagent:';
|
|
12
|
+
/**
|
|
13
|
+
* 生成标记注释。
|
|
14
|
+
*/
|
|
15
|
+
export function makeMarker(extensionId) {
|
|
16
|
+
return `/*openagent:${extensionId}*/`;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* 检查内容中是否包含指定扩展点的标记。
|
|
20
|
+
*/
|
|
21
|
+
export function hasMarker(content, extensionId) {
|
|
22
|
+
return content.includes(makeMarker(extensionId));
|
|
23
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Auth API Proxy — Gateway-side reverse proxy for auth.ai-talk.live
|
|
3
|
+
*
|
|
4
|
+
* Eliminates CSP connect-src patching by proxying browser requests
|
|
5
|
+
* through a same-origin plugin HTTP route:
|
|
6
|
+
*
|
|
7
|
+
* Browser: fetch('/plugins/openagent/api/agents')
|
|
8
|
+
* → Gateway plugin-http stage
|
|
9
|
+
* → this handler
|
|
10
|
+
* → fetch('https://auth.ai-talk.live/api/agents')
|
|
11
|
+
* → response back to browser
|
|
12
|
+
*
|
|
13
|
+
* Registered via api.registerHttpRoute() in index.ts.
|
|
14
|
+
* See: docs/audit/022-A-loader-audit-v1.md §4.7–4.10
|
|
15
|
+
*/
|
|
16
|
+
import type { IncomingMessage, ServerResponse } from 'node:http';
|
|
17
|
+
/** Returns the gateway base URL as seen by the browser (e.g. http://localhost:18794). */
|
|
18
|
+
export declare function getGatewayBaseUrl(): string;
|
|
19
|
+
export declare function createAuthProxyHandler(): (req: IncomingMessage, res: ServerResponse) => Promise<boolean>;
|
|
20
|
+
export declare function isAllowedOasnProxyRequest(method: string, pathname: string): boolean;
|
|
@@ -0,0 +1,337 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Auth API Proxy — Gateway-side reverse proxy for auth.ai-talk.live
|
|
3
|
+
*
|
|
4
|
+
* Eliminates CSP connect-src patching by proxying browser requests
|
|
5
|
+
* through a same-origin plugin HTTP route:
|
|
6
|
+
*
|
|
7
|
+
* Browser: fetch('/plugins/openagent/api/agents')
|
|
8
|
+
* → Gateway plugin-http stage
|
|
9
|
+
* → this handler
|
|
10
|
+
* → fetch('https://auth.ai-talk.live/api/agents')
|
|
11
|
+
* → response back to browser
|
|
12
|
+
*
|
|
13
|
+
* Registered via api.registerHttpRoute() in index.ts.
|
|
14
|
+
* See: docs/audit/022-A-loader-audit-v1.md §4.7–4.10
|
|
15
|
+
*/
|
|
16
|
+
import fs from 'node:fs';
|
|
17
|
+
import nodePath from 'node:path';
|
|
18
|
+
import { logger } from '../util/logger.js';
|
|
19
|
+
import { registry } from '../runtime/registry.js';
|
|
20
|
+
import { isUnconfiguredOasnApiBase } from '../auth/config.js';
|
|
21
|
+
/** TIM 路径默认上游(兼容旧版) */
|
|
22
|
+
const AUTH_UPSTREAM_TIM = 'https://auth.ai-talk.live';
|
|
23
|
+
const PROXY_TIMEOUT_MS = 15_000;
|
|
24
|
+
const MAX_BODY_BYTES = 64 * 1024; // 64KB — tagline API body is ~100 bytes
|
|
25
|
+
/**
|
|
26
|
+
* 根据当前 active runtime 的 transport 类型决定上游。
|
|
27
|
+
*
|
|
28
|
+
* - transport='oasn':Discovery/onboarding 用 account.apiBase;
|
|
29
|
+
* Access-layer endpoint 用 account.accessApiBase(未配置时回落到 apiBase)
|
|
30
|
+
* - transport='tim' 或无 active runtime:fallback 到 AUTH_UPSTREAM_TIM
|
|
31
|
+
*
|
|
32
|
+
* 浏览器侧 Agent Book 通过 /plugins/openagent/api/* 统一访问,由此处分流。
|
|
33
|
+
*/
|
|
34
|
+
function pickUpstream(method, pathname) {
|
|
35
|
+
const rt = registry.getDefault();
|
|
36
|
+
if (rt?.transportType === 'oasn') {
|
|
37
|
+
const apiBase = rt.config?.apiBase;
|
|
38
|
+
const accessApiBase = rt.config?.accessApiBase || apiBase;
|
|
39
|
+
const upstream = isAccessLayerProxyPath(method, pathname) ? accessApiBase : apiBase;
|
|
40
|
+
return isUnconfiguredOasnApiBase(upstream) ? null : upstream ?? null;
|
|
41
|
+
}
|
|
42
|
+
return AUTH_UPSTREAM_TIM;
|
|
43
|
+
}
|
|
44
|
+
// ── Gateway base URL detection ──────────────────────────────────────────
|
|
45
|
+
// Captured from the first incoming HTTP request's Host header.
|
|
46
|
+
// Handles Docker port mapping: container port ≠ host port.
|
|
47
|
+
let _gatewayBaseUrl;
|
|
48
|
+
/** Returns the gateway base URL as seen by the browser (e.g. http://localhost:18794). */
|
|
49
|
+
export function getGatewayBaseUrl() {
|
|
50
|
+
return _gatewayBaseUrl ?? `http://localhost:18794`;
|
|
51
|
+
}
|
|
52
|
+
// ── Handler factory ─────────────────────────────────────────────────────
|
|
53
|
+
export function createAuthProxyHandler() {
|
|
54
|
+
return async (req, res) => {
|
|
55
|
+
// Gateway strips the matched prefix; req.url is the path after prefix removal.
|
|
56
|
+
// E.g. /plugins/openagent/api/agents → req.url = /api/agents
|
|
57
|
+
const url = new URL(req.url ?? '/', `http://${req.headers.host ?? 'localhost'}`);
|
|
58
|
+
logger.info(`[proxy] RECEIVED: ${req.method} ${req.url}`);
|
|
59
|
+
// Capture the gateway's external base URL from the browser's request.
|
|
60
|
+
// Reads standard reverse-proxy headers for correct protocol/host detection:
|
|
61
|
+
// - Local: http://localhost:18794
|
|
62
|
+
// - Docker: http://127.0.0.1:18794 (port mapped)
|
|
63
|
+
// - Nginx: https://oc6.openagent.club (X-Forwarded-Proto/Host)
|
|
64
|
+
if (!_gatewayBaseUrl && req.headers.host) {
|
|
65
|
+
const proto = req.headers['x-forwarded-proto']?.split(',')[0]?.trim() || 'http';
|
|
66
|
+
const host = req.headers['x-forwarded-host']?.split(',')[0]?.trim() || req.headers.host;
|
|
67
|
+
_gatewayBaseUrl = `${proto}://${host}`;
|
|
68
|
+
logger.info(`[proxy] Gateway base URL detected: ${_gatewayBaseUrl}`);
|
|
69
|
+
}
|
|
70
|
+
// ── T4: Serve local media files from /tmp/openclaw/openagent-media/ ──
|
|
71
|
+
// Files downloaded from remote agents via C2C are stored here.
|
|
72
|
+
// Tool result references them as MEDIA:http://localhost:PORT/plugins/openagent/media/{filename}
|
|
73
|
+
// to pass through the framework's filterToolResultMediaUrls (http URLs bypass whitelist check).
|
|
74
|
+
if (url.pathname.startsWith('/media/')) {
|
|
75
|
+
return serveLocalMedia(url.pathname, res);
|
|
76
|
+
}
|
|
77
|
+
// req.url may or may not have the /plugins/openagent prefix stripped by Gateway
|
|
78
|
+
// (behavior varies across Gateway versions), so strip it defensively.
|
|
79
|
+
let targetPath = url.pathname;
|
|
80
|
+
if (targetPath.startsWith('/plugins/openagent')) {
|
|
81
|
+
targetPath = targetPath.slice('/plugins/openagent'.length);
|
|
82
|
+
}
|
|
83
|
+
// v3.9+ 双轨抽象:上游按当前 transport 切换(OASN → api.oasn.ai;TIM → auth.ai-talk.live)
|
|
84
|
+
const method = req.method ?? 'GET';
|
|
85
|
+
const rt = registry.getDefault();
|
|
86
|
+
if (!rt && isOasnProxyPath(method, targetPath)) {
|
|
87
|
+
writeJson(res, 503, {
|
|
88
|
+
error: 'OASN account is not configured',
|
|
89
|
+
detail: 'Run openclaw-plugin-openagent-cli install to register this device before opening Agent Book.',
|
|
90
|
+
});
|
|
91
|
+
return true;
|
|
92
|
+
}
|
|
93
|
+
if (rt && rt.transportType !== 'oasn' && isOasnProxyPath(method, targetPath)) {
|
|
94
|
+
writeJson(res, 503, {
|
|
95
|
+
error: 'OASN transport is not active',
|
|
96
|
+
detail: 'Agent Book discovery requires an installed OASN account.',
|
|
97
|
+
});
|
|
98
|
+
return true;
|
|
99
|
+
}
|
|
100
|
+
if (rt?.transportType === 'oasn' && !isAllowedOasnProxyRequest(method, targetPath)) {
|
|
101
|
+
logger.warn(`[proxy] blocked OASN proxy path: ${method} ${targetPath}`);
|
|
102
|
+
writeJson(res, 403, { error: 'proxy path not allowed' });
|
|
103
|
+
return true;
|
|
104
|
+
}
|
|
105
|
+
const upstreamBase = pickUpstream(method, targetPath);
|
|
106
|
+
if (!upstreamBase) {
|
|
107
|
+
writeJson(res, 503, { error: 'OASN api_base is not configured' });
|
|
108
|
+
return true;
|
|
109
|
+
}
|
|
110
|
+
const targetUrl = new URL(targetPath + url.search, upstreamBase).href;
|
|
111
|
+
logger.info(`[proxy] ${method} ${url.pathname} → ${targetUrl}`);
|
|
112
|
+
try {
|
|
113
|
+
// Read request body for non-GET methods
|
|
114
|
+
let body;
|
|
115
|
+
if (method !== 'GET' && method !== 'HEAD') {
|
|
116
|
+
body = await readBody(req, MAX_BODY_BYTES);
|
|
117
|
+
}
|
|
118
|
+
// Forward to upstream with timeout
|
|
119
|
+
const upstream = await fetch(targetUrl, {
|
|
120
|
+
method,
|
|
121
|
+
headers: buildUpstreamHeaders(req),
|
|
122
|
+
body,
|
|
123
|
+
signal: AbortSignal.timeout(PROXY_TIMEOUT_MS),
|
|
124
|
+
});
|
|
125
|
+
// Relay response (binary-safe for images)
|
|
126
|
+
res.statusCode = upstream.status;
|
|
127
|
+
const contentType = upstream.headers.get('content-type');
|
|
128
|
+
if (contentType)
|
|
129
|
+
res.setHeader('Content-Type', contentType);
|
|
130
|
+
const buf = Buffer.from(await upstream.arrayBuffer());
|
|
131
|
+
res.end(buf);
|
|
132
|
+
logger.info(`[proxy] ${method} ${url.pathname} → ${upstream.status} (${buf.length} bytes)`);
|
|
133
|
+
}
|
|
134
|
+
catch (err) {
|
|
135
|
+
const msg = err.message;
|
|
136
|
+
logger.warn(`[proxy] ${method} ${targetUrl} failed: ${msg}`);
|
|
137
|
+
if (!res.headersSent) {
|
|
138
|
+
writeJson(res, 502, { error: 'proxy upstream failed', detail: msg });
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
return true;
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
// ── T4: Local media serve ────────────────────────────────────────────────
|
|
145
|
+
const MEDIA_DIR = '/tmp/openclaw/openagent-media';
|
|
146
|
+
/** MIME type lookup for common media extensions. */
|
|
147
|
+
const MIME_MAP = {
|
|
148
|
+
'.mp3': 'audio/mpeg',
|
|
149
|
+
'.wav': 'audio/wav',
|
|
150
|
+
'.ogg': 'audio/ogg',
|
|
151
|
+
'.m4a': 'audio/mp4',
|
|
152
|
+
'.mp4': 'video/mp4',
|
|
153
|
+
'.webm': 'video/webm',
|
|
154
|
+
'.png': 'image/png',
|
|
155
|
+
'.jpg': 'image/jpeg',
|
|
156
|
+
'.jpeg': 'image/jpeg',
|
|
157
|
+
'.gif': 'image/gif',
|
|
158
|
+
'.webp': 'image/webp',
|
|
159
|
+
'.pdf': 'application/pdf',
|
|
160
|
+
'.txt': 'text/plain',
|
|
161
|
+
};
|
|
162
|
+
/**
|
|
163
|
+
* Serve a file from the local openagent-media directory.
|
|
164
|
+
* Used by T4 remote file transfer — tool result references files as
|
|
165
|
+
* MEDIA:http://localhost:PORT/plugins/openagent/media/{filename}
|
|
166
|
+
*
|
|
167
|
+
* @returns true (request handled)
|
|
168
|
+
*/
|
|
169
|
+
function serveLocalMedia(pathname, res) {
|
|
170
|
+
// /media/{filename} → {filename} (prefix already stripped by Gateway)
|
|
171
|
+
const raw = pathname.replace('/media/', '');
|
|
172
|
+
const fileName = decodeURIComponent(raw);
|
|
173
|
+
// Security: block path traversal, null bytes, and directory components
|
|
174
|
+
if (!fileName || fileName.includes('..') || fileName.includes('/') || fileName.includes('\\') || fileName.includes('\0')) {
|
|
175
|
+
logger.warn(`[proxy/media] Blocked unsafe path: ${raw}`);
|
|
176
|
+
res.statusCode = 400;
|
|
177
|
+
res.end('Bad request');
|
|
178
|
+
return true;
|
|
179
|
+
}
|
|
180
|
+
const filePath = nodePath.join(MEDIA_DIR, fileName);
|
|
181
|
+
// Double-check: resolved path must stay within MEDIA_DIR
|
|
182
|
+
if (!nodePath.resolve(filePath).startsWith(nodePath.resolve(MEDIA_DIR) + nodePath.sep) &&
|
|
183
|
+
nodePath.resolve(filePath) !== nodePath.resolve(MEDIA_DIR)) {
|
|
184
|
+
logger.warn(`[proxy/media] Path escape attempt: ${fileName} → ${filePath}`);
|
|
185
|
+
res.statusCode = 400;
|
|
186
|
+
res.end('Bad request');
|
|
187
|
+
return true;
|
|
188
|
+
}
|
|
189
|
+
if (!fs.existsSync(filePath)) {
|
|
190
|
+
logger.debug(`[proxy/media] File not found: ${filePath}`);
|
|
191
|
+
res.statusCode = 404;
|
|
192
|
+
res.end('Not found');
|
|
193
|
+
return true;
|
|
194
|
+
}
|
|
195
|
+
try {
|
|
196
|
+
const ext = nodePath.extname(fileName).toLowerCase();
|
|
197
|
+
const contentType = MIME_MAP[ext] ?? 'application/octet-stream';
|
|
198
|
+
const stat = fs.statSync(filePath);
|
|
199
|
+
res.setHeader('Content-Type', contentType);
|
|
200
|
+
res.setHeader('Content-Length', stat.size);
|
|
201
|
+
// Allow browser to cache media for 1 hour
|
|
202
|
+
res.setHeader('Cache-Control', 'private, max-age=3600');
|
|
203
|
+
const stream = fs.createReadStream(filePath);
|
|
204
|
+
stream.pipe(res);
|
|
205
|
+
stream.on('error', (err) => {
|
|
206
|
+
logger.error(`[proxy/media] Stream error: ${err.message} file=${fileName}`);
|
|
207
|
+
if (!res.headersSent) {
|
|
208
|
+
res.statusCode = 500;
|
|
209
|
+
res.end('Internal error');
|
|
210
|
+
}
|
|
211
|
+
});
|
|
212
|
+
logger.info(`[proxy/media] Serving ${fileName} (${contentType}, ${stat.size} bytes)`);
|
|
213
|
+
}
|
|
214
|
+
catch (err) {
|
|
215
|
+
logger.error(`[proxy/media] Error serving ${fileName}: ${err.message}`);
|
|
216
|
+
if (!res.headersSent) {
|
|
217
|
+
res.statusCode = 500;
|
|
218
|
+
res.end('Internal error');
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
return true;
|
|
222
|
+
}
|
|
223
|
+
// ── Helpers ──────────────────────────────────────────────────────────────
|
|
224
|
+
/**
|
|
225
|
+
* Build headers for the upstream request.
|
|
226
|
+
* Forwards Content-Type and Authorization (needed by tagline API).
|
|
227
|
+
*
|
|
228
|
+
* OASN 模式:浏览器端没有 api_key,代理自动注入 Bearer token。
|
|
229
|
+
* TIM 模式:转发浏览器自带的 Authorization(如有)。
|
|
230
|
+
*/
|
|
231
|
+
function buildUpstreamHeaders(req) {
|
|
232
|
+
const headers = {};
|
|
233
|
+
const ct = req.headers['content-type'];
|
|
234
|
+
if (ct)
|
|
235
|
+
headers['Content-Type'] = ct;
|
|
236
|
+
const rt = registry.getDefault();
|
|
237
|
+
if (rt?.transportType === 'oasn') {
|
|
238
|
+
if (rt.config?.apiKey)
|
|
239
|
+
headers['Authorization'] = `Bearer ${rt.config.apiKey}`;
|
|
240
|
+
return headers;
|
|
241
|
+
}
|
|
242
|
+
// TIM mode: keep forwarding browser Authorization for the legacy auth API.
|
|
243
|
+
const auth = req.headers['authorization'];
|
|
244
|
+
if (auth) {
|
|
245
|
+
headers['Authorization'] = auth;
|
|
246
|
+
}
|
|
247
|
+
return headers;
|
|
248
|
+
}
|
|
249
|
+
export function isAllowedOasnProxyRequest(method, pathname) {
|
|
250
|
+
const m = method.toUpperCase();
|
|
251
|
+
const p = pathname.startsWith('/') ? pathname : `/${pathname}`;
|
|
252
|
+
const isRead = m === 'GET' || m === 'HEAD';
|
|
253
|
+
if (isRead && p === '/api/agent-card-categories')
|
|
254
|
+
return true;
|
|
255
|
+
if (isRead && /^\/api\/agent-cards\/[^/]+$/.test(p))
|
|
256
|
+
return true;
|
|
257
|
+
if (m === 'POST' && /^\/api\/agent-cards\/search\/(by-query|by-category|by-tags)$/.test(p))
|
|
258
|
+
return true;
|
|
259
|
+
if (isRead && /^\/api\/agents\/[^/]+$/.test(p))
|
|
260
|
+
return true;
|
|
261
|
+
if (m === 'POST' && p === '/api/agents/claim')
|
|
262
|
+
return true;
|
|
263
|
+
if (m === 'POST' && p === '/api/invocations')
|
|
264
|
+
return true;
|
|
265
|
+
if (isRead && /^\/api\/invocations\/[^/]+$/.test(p))
|
|
266
|
+
return true;
|
|
267
|
+
if (m === 'POST' && p === '/api/files')
|
|
268
|
+
return true;
|
|
269
|
+
if (isRead && /^\/api\/artifacts\/[^/]+\/content$/.test(p))
|
|
270
|
+
return true;
|
|
271
|
+
if (isRead && p.startsWith('/avatars/'))
|
|
272
|
+
return true;
|
|
273
|
+
return false;
|
|
274
|
+
}
|
|
275
|
+
function isAccessLayerProxyPath(method, pathname) {
|
|
276
|
+
const m = method.toUpperCase();
|
|
277
|
+
const p = pathname.startsWith('/') ? pathname : `/${pathname}`;
|
|
278
|
+
const isRead = m === 'GET' || m === 'HEAD';
|
|
279
|
+
if (m === 'POST' && p === '/api/invocations')
|
|
280
|
+
return true;
|
|
281
|
+
if (isRead && /^\/api\/invocations\/[^/]+$/.test(p))
|
|
282
|
+
return true;
|
|
283
|
+
if (m === 'POST' && p === '/api/files')
|
|
284
|
+
return true;
|
|
285
|
+
if (isRead && /^\/api\/artifacts\/[^/]+\/content$/.test(p))
|
|
286
|
+
return true;
|
|
287
|
+
return false;
|
|
288
|
+
}
|
|
289
|
+
function isOasnProxyPath(method, pathname) {
|
|
290
|
+
const m = method.toUpperCase();
|
|
291
|
+
const p = pathname.startsWith('/') ? pathname : `/${pathname}`;
|
|
292
|
+
const isRead = m === 'GET' || m === 'HEAD';
|
|
293
|
+
if (isRead && p === '/api/agent-card-categories')
|
|
294
|
+
return true;
|
|
295
|
+
if (isRead && /^\/api\/agent-cards\/[^/]+$/.test(p))
|
|
296
|
+
return true;
|
|
297
|
+
if (m === 'POST' && /^\/api\/agent-cards\/search\/(by-query|by-category|by-tags)$/.test(p))
|
|
298
|
+
return true;
|
|
299
|
+
if (isRead && /^\/api\/agents\/[^/]+$/.test(p))
|
|
300
|
+
return true;
|
|
301
|
+
if (m === 'POST' && p === '/api/agents/claim')
|
|
302
|
+
return true;
|
|
303
|
+
if (m === 'POST' && p === '/api/invocations')
|
|
304
|
+
return true;
|
|
305
|
+
if (isRead && /^\/api\/invocations\/[^/]+$/.test(p))
|
|
306
|
+
return true;
|
|
307
|
+
if (m === 'POST' && p === '/api/files')
|
|
308
|
+
return true;
|
|
309
|
+
if (isRead && /^\/api\/artifacts\/[^/]+\/content$/.test(p))
|
|
310
|
+
return true;
|
|
311
|
+
return false;
|
|
312
|
+
}
|
|
313
|
+
function writeJson(res, statusCode, body) {
|
|
314
|
+
res.statusCode = statusCode;
|
|
315
|
+
res.setHeader('Content-Type', 'application/json');
|
|
316
|
+
res.end(JSON.stringify(body));
|
|
317
|
+
}
|
|
318
|
+
/**
|
|
319
|
+
* Read the request body with a size limit.
|
|
320
|
+
*/
|
|
321
|
+
function readBody(req, maxBytes) {
|
|
322
|
+
return new Promise((resolve, reject) => {
|
|
323
|
+
const chunks = [];
|
|
324
|
+
let total = 0;
|
|
325
|
+
req.on('data', (chunk) => {
|
|
326
|
+
total += chunk.length;
|
|
327
|
+
if (total > maxBytes) {
|
|
328
|
+
req.destroy();
|
|
329
|
+
reject(new Error(`Request body exceeds ${maxBytes} bytes`));
|
|
330
|
+
return;
|
|
331
|
+
}
|
|
332
|
+
chunks.push(chunk);
|
|
333
|
+
});
|
|
334
|
+
req.on('end', () => resolve(Buffer.concat(chunks).toString('utf-8')));
|
|
335
|
+
req.on('error', reject);
|
|
336
|
+
});
|
|
337
|
+
}
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AccountRuntime — All per-account state and lifecycle
|
|
3
|
+
*
|
|
4
|
+
* Owns the lifecycle of a single active account:
|
|
5
|
+
* 1. StateStore (SQLite)
|
|
6
|
+
* 2. CredentialManager (auth token lifecycle)
|
|
7
|
+
* 3. TIMClient (SDK connection)
|
|
8
|
+
* 4. Message pipeline: channelRuntime dispatch (via process-message.ts)
|
|
9
|
+
*
|
|
10
|
+
* Supports "half-alive" mode: when agent is not yet claimed,
|
|
11
|
+
* start() succeeds without TIM connection. Tools trigger
|
|
12
|
+
* lazy connection via ensureConnected().
|
|
13
|
+
*
|
|
14
|
+
* v3.2.0: Replaced shell-out executor pipeline with channelRuntime dispatch.
|
|
15
|
+
* See docs/audit/004-messaging-pipeline-v3.1.4.md for migration context.
|
|
16
|
+
*
|
|
17
|
+
* v3.9.0: 引入 AgentTransport 双轨抽象。
|
|
18
|
+
* - transport='oasn'(默认):走 OASN HTTP API,不再创建 TIMClient
|
|
19
|
+
* - transport='tim'(显式配置回退):保留原 TIMClient + CredentialManager 路径
|
|
20
|
+
* 两条路径在 start() 内按 config.transport 字段分发;旧路径在阶段 4 上层切换完毕后再删除。
|
|
21
|
+
* 详见 docs/specs/2026-06-16-oasn-transport-abstraction-design.md §5.2
|
|
22
|
+
*/
|
|
23
|
+
import { StateStore } from '../state/store.js';
|
|
24
|
+
import { TIMClient } from '../tim/client.js';
|
|
25
|
+
import type { AgentTransport } from '../transport/types.js';
|
|
26
|
+
import { type OpenagentAccountConfig, type TransportType } from '../auth/config.js';
|
|
27
|
+
import type { ChannelInfo, MemberInfo } from '../tim/channels.js';
|
|
28
|
+
import type { HistoryMessage, SendResult } from '../tim/messages.js';
|
|
29
|
+
export declare class AccountRuntime {
|
|
30
|
+
readonly accountId: string;
|
|
31
|
+
store: StateStore | null;
|
|
32
|
+
client: TIMClient | null;
|
|
33
|
+
/**
|
|
34
|
+
* v3.9+ 双轨抽象:统一 transport 接口。
|
|
35
|
+
*
|
|
36
|
+
* - transport='tim' 下:内部仍持有 TIMClient(this.client)作为 SDK 直连;
|
|
37
|
+
* transport 实例额外提供能力接口,便于阶段 4 上层调用
|
|
38
|
+
* - transport='oasn' 下:this.client 始终为 null,所有调用走 transport
|
|
39
|
+
*
|
|
40
|
+
* 阶段 4 完成后,上层将不再直接访问 this.client,只使用 this.transport。
|
|
41
|
+
*/
|
|
42
|
+
transport: AgentTransport | null;
|
|
43
|
+
private credentialManager;
|
|
44
|
+
private _transportType;
|
|
45
|
+
private _claimStatus;
|
|
46
|
+
private _claimUrl;
|
|
47
|
+
private _claimExpiresAt;
|
|
48
|
+
private _caAccessToken;
|
|
49
|
+
private _statusPollTimer;
|
|
50
|
+
private _running;
|
|
51
|
+
private _config;
|
|
52
|
+
private _cfg;
|
|
53
|
+
private _connectingPromise;
|
|
54
|
+
constructor(accountId: string);
|
|
55
|
+
get isRunning(): boolean;
|
|
56
|
+
get config(): OpenagentAccountConfig | null;
|
|
57
|
+
/** v3.9+ 当前账号选择的 transport 类型('oasn' | 'tim') */
|
|
58
|
+
get transportType(): TransportType;
|
|
59
|
+
get claimStatus(): OpenagentAccountConfig['status'];
|
|
60
|
+
get claimUrl(): string;
|
|
61
|
+
get claimExpiresAt(): string;
|
|
62
|
+
get caAccessToken(): string | undefined;
|
|
63
|
+
get isOasnClaimed(): boolean;
|
|
64
|
+
/**
|
|
65
|
+
* Account startup with half-alive support.
|
|
66
|
+
*
|
|
67
|
+
* If agent is claimed: full startup (StateStore + TIM + pipeline).
|
|
68
|
+
* If agent is unclaimed: half-alive (StateStore only, _running = true).
|
|
69
|
+
* Tools will trigger lazy connection via ensureConnected().
|
|
70
|
+
*
|
|
71
|
+
* IMPORTANT: This method NEVER throws for unclaimed/credential errors.
|
|
72
|
+
* It must return normally so channel.ts reaches the blocking await Promise,
|
|
73
|
+
* preventing OpenClaw auto-restart.
|
|
74
|
+
*
|
|
75
|
+
* @param cfg - Full OpenClaw config object, needed for channelRuntime APIs
|
|
76
|
+
*/
|
|
77
|
+
start(account: OpenagentAccountConfig, _pipelineConfig?: {
|
|
78
|
+
batchWindowMs?: number;
|
|
79
|
+
maxBatchSize?: number;
|
|
80
|
+
}, cfg?: Record<string, unknown>): Promise<void>;
|
|
81
|
+
/**
|
|
82
|
+
* OASN 连接路径(v3.9+)。
|
|
83
|
+
*
|
|
84
|
+
* 与 _connectTIM 不同:
|
|
85
|
+
* - 无 WebSocket,ready() 只校验 api_key 有效性(GET /api/agent-cards/{agent_id})
|
|
86
|
+
* - 不需要 channelRuntime 接管 'message' / 'c2c_request' 事件(OASN ClientAgent 不接收外来 Invocation)
|
|
87
|
+
* - 'credential_expired' 事件由 OasnTransport 在 401 时触发,处理:清 transport + 标记 half-alive
|
|
88
|
+
*/
|
|
89
|
+
private _connectOASN;
|
|
90
|
+
/**
|
|
91
|
+
* 将 OASN 账号状态持久化到 OpenClaw 配置文件。
|
|
92
|
+
*
|
|
93
|
+
* 写入位置:~/.openclaw/openclaw.json → channels.openagent.accounts.{accountId}
|
|
94
|
+
* 采用 merge 策略。CA access_token 永远只留在 runtime 内存,不写入配置。
|
|
95
|
+
*/
|
|
96
|
+
private _saveOasnAccountConfig;
|
|
97
|
+
private _syncOasnStatus;
|
|
98
|
+
private _scheduleOasnStatusPolling;
|
|
99
|
+
private _stopOasnStatusPolling;
|
|
100
|
+
assertOasnInvocationAllowed(): void;
|
|
101
|
+
/**
|
|
102
|
+
* Connect TIM and wire the channelRuntime dispatch pipeline.
|
|
103
|
+
* Called by start() and ensureConnected().
|
|
104
|
+
*/
|
|
105
|
+
private _connectTIM;
|
|
106
|
+
/**
|
|
107
|
+
* Ensure TIM is connected before executing a tool operation.
|
|
108
|
+
* If not connected, attempts lazy connection.
|
|
109
|
+
*
|
|
110
|
+
* v3.9+:OASN 路径下走 _connectOASN();TIM 路径维持原行为。
|
|
111
|
+
*
|
|
112
|
+
* @throws CredentialError — propagated to tool, which returns a user-friendly message
|
|
113
|
+
*/
|
|
114
|
+
ensureConnected(): Promise<void>;
|
|
115
|
+
/**
|
|
116
|
+
* Graceful shutdown of all modules.
|
|
117
|
+
*/
|
|
118
|
+
stop(): Promise<void>;
|
|
119
|
+
private _cleanup;
|
|
120
|
+
/**
|
|
121
|
+
* @deprecated Pipeline batching is now handled by channelRuntime.
|
|
122
|
+
* Retained for backward compatibility with openagent_set_strategy tool.
|
|
123
|
+
*/
|
|
124
|
+
updateStrategy(_config: {
|
|
125
|
+
batchWindowMs?: number;
|
|
126
|
+
maxBatchSize?: number;
|
|
127
|
+
}): {
|
|
128
|
+
batchWindowMs: number;
|
|
129
|
+
maxBatchSize: number;
|
|
130
|
+
};
|
|
131
|
+
/**
|
|
132
|
+
* @deprecated Scheduler queue no longer exists in channelRuntime mode.
|
|
133
|
+
*/
|
|
134
|
+
get schedulerQueueSize(): number;
|
|
135
|
+
listChannels(): Promise<ChannelInfo[]>;
|
|
136
|
+
searchChannels(keyword: string): Promise<ChannelInfo[]>;
|
|
137
|
+
joinChannel(channelId: string): Promise<{
|
|
138
|
+
success: boolean;
|
|
139
|
+
message: string;
|
|
140
|
+
}>;
|
|
141
|
+
leaveChannel(channelId: string): Promise<{
|
|
142
|
+
success: boolean;
|
|
143
|
+
message: string;
|
|
144
|
+
}>;
|
|
145
|
+
getMembers(channelId: string): Promise<MemberInfo[]>;
|
|
146
|
+
createChannel(name: string, description?: string, skill?: string): Promise<{
|
|
147
|
+
success: boolean;
|
|
148
|
+
channelId: string;
|
|
149
|
+
}>;
|
|
150
|
+
getChannelSkill(channelId: string): Promise<string | null>;
|
|
151
|
+
setChannelSkill(channelId: string, skill: string): Promise<{
|
|
152
|
+
success: boolean;
|
|
153
|
+
}>;
|
|
154
|
+
sendMessage(channelId: string, text: string): Promise<SendResult>;
|
|
155
|
+
fetchMessages(channelId: string, count?: number): Promise<HistoryMessage[]>;
|
|
156
|
+
}
|