openclaw-openagent 1.0.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 (113) hide show
  1. package/index.ts +114 -0
  2. package/openclaw.plugin.json +159 -0
  3. package/package.json +79 -0
  4. package/skills/clawlink/SKILL.md +145 -0
  5. package/skills/clawlink/SKILL.md.bak +165 -0
  6. package/src/app/channel-tools.ts +249 -0
  7. package/src/app/discovery-tools.ts +273 -0
  8. package/src/app/hooks.ts +60 -0
  9. package/src/app/index.ts +78 -0
  10. package/src/app/messaging-tools.ts +79 -0
  11. package/src/app/ops-tools.ts +155 -0
  12. package/src/app/remote-agent-tool.ts +476 -0
  13. package/src/app/types.ts +67 -0
  14. package/src/app/verbose-preflight.ts +190 -0
  15. package/src/auth/config.ts +197 -0
  16. package/src/auth/credential-manager.ts +146 -0
  17. package/src/auth/index.ts +24 -0
  18. package/src/auth/verify.ts +99 -0
  19. package/src/channel.ts +565 -0
  20. package/src/compat.ts +82 -0
  21. package/src/config/config-schema.ts +39 -0
  22. package/src/messaging/aggregator.ts +120 -0
  23. package/src/messaging/collector.ts +89 -0
  24. package/src/messaging/executor.ts +72 -0
  25. package/src/messaging/inbound.ts +150 -0
  26. package/src/messaging/index.ts +11 -0
  27. package/src/messaging/mention-protocol.ts +94 -0
  28. package/src/messaging/process-c2c-request.ts +564 -0
  29. package/src/messaging/process-message.ts +373 -0
  30. package/src/messaging/scheduler.ts +55 -0
  31. package/src/messaging/types.ts +38 -0
  32. package/src/plugin-ui/assets/agentbook-icon.svg +5 -0
  33. package/src/plugin-ui/assets/magic.svg +5 -0
  34. package/src/plugin-ui/assets/openagent-override.js +9329 -0
  35. package/src/plugin-ui/build.cjs +175 -0
  36. package/src/plugin-ui/index.ts +18 -0
  37. package/src/plugin-ui/modules/agent-book/panel/agent-book.js +458 -0
  38. package/src/plugin-ui/modules/agent-book/panel/agent-card.js +154 -0
  39. package/src/plugin-ui/modules/agent-book/panel/agent-data.js +644 -0
  40. package/src/plugin-ui/modules/agent-book/panel/inject-ui.js +456 -0
  41. package/src/plugin-ui/modules/agent-book/panel/mention-state.js +206 -0
  42. package/src/plugin-ui/modules/agent-book/panel/styles.js +670 -0
  43. package/src/plugin-ui/modules/agent-book/remote-agent-tool/components-core.js +293 -0
  44. package/src/plugin-ui/modules/agent-book/remote-agent-tool/thought-chain-card.js +208 -0
  45. package/src/plugin-ui/modules/agent-book/scanner.js +119 -0
  46. package/src/plugin-ui/modules/agent-book/travelcard/travel-cards.js +500 -0
  47. package/src/plugin-ui/modules/agent-book/travelcard/travel-engine.js +652 -0
  48. package/src/plugin-ui/modules/agent-book/travelcard/travel-styles.js +251 -0
  49. package/src/plugin-ui/modules/loader/bootstrap.js +38 -0
  50. package/src/plugin-ui/modules/loader/shared-state.js +560 -0
  51. package/src/plugin-ui/modules/loader/ws-intercept.js +199 -0
  52. package/src/plugin-ui/modules/remote-agent/chunk-parser.js +161 -0
  53. package/src/plugin-ui/modules/remote-agent/execution-card.js +269 -0
  54. package/src/plugin-ui/modules/remote-agent/markdown-renderer.js +256 -0
  55. package/src/plugin-ui/modules/remote-agent/native-style-adapter.js +146 -0
  56. package/src/plugin-ui/modules/remote-agent/output-card.js +259 -0
  57. package/src/plugin-ui/modules/remote-agent/progress-store.js +363 -0
  58. package/src/plugin-ui/modules/remote-agent/render-hooks.js +1609 -0
  59. package/src/plugin-ui/modules/remote-agent/styles.js +668 -0
  60. package/src/plugin-ui/modules/remote-agent/tool-card-model.js +56 -0
  61. package/src/plugin-ui/ui-extension-loader/backup.ts +92 -0
  62. package/src/plugin-ui/ui-extension-loader/index.ts +276 -0
  63. package/src/plugin-ui/ui-extension-loader/locator.ts +152 -0
  64. package/src/plugin-ui/ui-extension-loader/manifest.ts +57 -0
  65. package/src/plugin-ui/ui-extension-loader/registry-regex.ts +729 -0
  66. package/src/plugin-ui/ui-extension-loader/removed-extensions.ts +70 -0
  67. package/src/plugin-ui/ui-extension-loader/types.ts +68 -0
  68. package/src/proxy/auth-proxy.ts +356 -0
  69. package/src/runtime/account.ts +572 -0
  70. package/src/runtime/index.ts +7 -0
  71. package/src/runtime/plugin-runtime.ts +94 -0
  72. package/src/runtime/registry.ts +71 -0
  73. package/src/sdk/CLASS_MAP.md +143 -0
  74. package/src/sdk/index.d.ts +126 -0
  75. package/src/sdk/index.js +23990 -0
  76. package/src/sdk/modules/cloud-search-module.js +1117 -0
  77. package/src/sdk/modules/follow-module.js +1069 -0
  78. package/src/sdk/modules/group-module.js +7397 -0
  79. package/src/sdk/modules/relationship-module.js +2269 -0
  80. package/src/sdk/modules/signaling-module.js +1468 -0
  81. package/src/sdk/modules/tim-upload-plugin.js +730 -0
  82. package/src/sdk/node-env/http-request.js +90 -0
  83. package/src/sdk/node-env/index.js +57 -0
  84. package/src/sdk/node-env/storage.js +114 -0
  85. package/src/sdk/package.json +10 -0
  86. package/src/sdk/tsconfig.json +16 -0
  87. package/src/state/pending-invocation-store.ts +43 -0
  88. package/src/state/store.ts +676 -0
  89. package/src/tim/c2c.ts +451 -0
  90. package/src/tim/channels.ts +364 -0
  91. package/src/tim/client.ts +330 -0
  92. package/src/tim/index.ts +18 -0
  93. package/src/tim/messages.ts +166 -0
  94. package/src/tim/sdk-logger-init.ts +50 -0
  95. package/src/tools.ts +10 -0
  96. package/src/transport/factory.ts +95 -0
  97. package/src/transport/oasn/index.ts +17 -0
  98. package/src/transport/oasn/oasn-agent-card.ts +111 -0
  99. package/src/transport/oasn/oasn-discovery.ts +108 -0
  100. package/src/transport/oasn/oasn-files.ts +210 -0
  101. package/src/transport/oasn/oasn-http.ts +483 -0
  102. package/src/transport/oasn/oasn-invocation.ts +527 -0
  103. package/src/transport/oasn/oasn-normalize.ts +159 -0
  104. package/src/transport/oasn/oasn-register.ts +106 -0
  105. package/src/transport/oasn/oasn-transport.ts +341 -0
  106. package/src/transport/oasn/oasn-types.ts +353 -0
  107. package/src/transport/tim/index.ts +8 -0
  108. package/src/transport/tim/tim-transport.ts +515 -0
  109. package/src/transport/types.ts +541 -0
  110. package/src/types/openclaw.d.ts +97 -0
  111. package/src/types/tencentcloud-chat.d.ts +15 -0
  112. package/src/util/http.ts +113 -0
  113. package/src/util/logger.ts +131 -0
@@ -0,0 +1,106 @@
1
+ /**
2
+ * OASN Agent 注册与认领
3
+ *
4
+ * 设计依据:
5
+ * - docs/specs/2026-06-16-oasn-api-module-mapping.md §2.1 / §2.2
6
+ *
7
+ * 调用时机:
8
+ * - registerAgent:插件首次安装、本地无 agent_id/api_key 时
9
+ * - claimAgent:用户主动触发认领(带 owner_email)
10
+ *
11
+ * 关键约束:
12
+ * - register 返回的 api_key **是明文且仅此一次**。调用方必须立即持久化(最好走 keychain,§11.6)
13
+ * - 当前后端 RegisterAgentCommand 只定义 platform;install_id/device_hint 需先扩展后端契约
14
+ */
15
+
16
+ import { logger } from '../../util/logger.js';
17
+ import type { AgentStatusResult, ClaimParams, ClaimResult, RegisterResult } from '../types.js';
18
+ import type { OasnHttpClient } from './oasn-http.js';
19
+ import {
20
+ OASN_ENDPOINTS,
21
+ type ClaimAgentRequest,
22
+ type ClaimAgentResponse,
23
+ type AgentStatusResponse,
24
+ type RegisterAgentRequest,
25
+ type RegisterAgentResponse,
26
+ } from './oasn-types.js';
27
+ import {
28
+ normalizeAgentStatus,
29
+ normalizeClaimResult,
30
+ normalizeRegisterResult,
31
+ } from './oasn-normalize.js';
32
+
33
+ /**
34
+ * OASN Agent 注册模块。
35
+ *
36
+ * 注意 register 和 claim 是 OASN-only 能力,TIM transport 不暴露这两个方法。
37
+ * AccountRuntime 在 transport-type === 'oasn' 时才能调用。
38
+ */
39
+ export class OasnRegister {
40
+ constructor(private readonly _http: OasnHttpClient) {}
41
+
42
+ /**
43
+ * 注册新 Agent(首次安装流程)。
44
+ *
45
+ * @param platform OpenClaw 上固定为 "openclaw"
46
+ * @returns 含一次性明文 api_key 的注册响应。调用方必须立即持久化。
47
+ */
48
+ async register(
49
+ platform: string,
50
+ _params?: { installId?: string; deviceHint?: string },
51
+ ): Promise<RegisterResult> {
52
+ const body: RegisterAgentRequest = { platform };
53
+
54
+ logger.info(`[transport/oasn/register] register platform=${platform}`);
55
+
56
+ // skipRetry=true:register 是不幂等的写入,重试可能创建多个 agent
57
+ const resp = await this._http.post<RegisterAgentResponse>(
58
+ OASN_ENDPOINTS.REGISTER,
59
+ body,
60
+ { skipRetry: true },
61
+ );
62
+
63
+ const result = normalizeRegisterResult(resp);
64
+ logger.info(`[transport/oasn/register] registered agent_id=${result.agent_id} status=${result.status}`);
65
+ return result;
66
+ }
67
+
68
+ /**
69
+ * 触发认领邮件发送。
70
+ * 认证方式由 OasnHttpClient 注入的 Bearer 决定:
71
+ * - 带 api_key:传入 { agent_id, owner_email }
72
+ * - 不带 api_key(首次进入):传入 { claim_token, owner_email }
73
+ */
74
+ async claim(params: ClaimParams): Promise<ClaimResult> {
75
+ if (!params.agent_id && !params.claim_token) {
76
+ throw new Error('OasnRegister.claim: must provide either agent_id or claim_token');
77
+ }
78
+ if (!params.owner_email) {
79
+ throw new Error('OasnRegister.claim: owner_email required');
80
+ }
81
+
82
+ const body: ClaimAgentRequest = {
83
+ ownerEmail: params.owner_email,
84
+ };
85
+ if (params.agent_id) body.agentId = params.agent_id;
86
+ if (params.claim_token) body.claimToken = params.claim_token;
87
+
88
+ logger.info(`[transport/oasn/register] claim email=${params.owner_email.replace(/(.).+(@.+)/, '$1***$2')}`);
89
+
90
+ const resp = await this._http.post<ClaimAgentResponse>(
91
+ OASN_ENDPOINTS.CLAIM,
92
+ body,
93
+ { skipRetry: true },
94
+ );
95
+
96
+ return normalizeClaimResult(resp);
97
+ }
98
+
99
+ async getStatus(agentId: string): Promise<AgentStatusResult> {
100
+ const resp = await this._http.get<AgentStatusResponse>(
101
+ OASN_ENDPOINTS.AGENT_STATUS(agentId),
102
+ { skipRetry: true },
103
+ );
104
+ return normalizeAgentStatus(resp);
105
+ }
106
+ }
@@ -0,0 +1,341 @@
1
+ /**
2
+ * OasnTransport —— 装配 OASN 子模块为统一的 AgentTransport
3
+ *
4
+ * 设计依据:
5
+ * - docs/specs/2026-06-16-oasn-transport-abstraction-design.md §2.4
6
+ * - docs/specs/2026-06-16-oasn-api-module-mapping.md §3.1
7
+ *
8
+ * 子模块组装:
9
+ * - OasnHttpClient HTTP 基础(Bearer 注入 / 重试 / 401 拦截)
10
+ * - OasnRegister register / claim
11
+ * - OasnAgentCard get / update / getCurrentOwner
12
+ * - OasnDiscovery search / categories
13
+ * - OasnInvocation sendTask / waitForTaskResult(核心路径)
14
+ * - OasnFiles upload / download + LRU
15
+ *
16
+ * 与 CoreTransport 契约的映射:
17
+ * - id = options.accountId
18
+ * - transportType= 'oasn'
19
+ * - ready() = 用 credentials.token 设置 Bearer,调 GET /api/agent-cards/{agent_id} 探活
20
+ * (404 也算成功 —— 未认领的 agent 仍能用 api_key,只是公开查询返 404)
21
+ * - dispose() = 释放 HTTP(无长连接)+ 清空 token
22
+ * - isReady = ready() 成功且 token 非空
23
+ * - 'credential_expired' 事件 = §11.5 401 撤销路径
24
+ *
25
+ * 与 TimTransport 的差异:
26
+ * - 不持有 WebSocket / 长连接 → dispose 几乎是 no-op
27
+ * - 不实现 IMChannelTransport(onTaskReceived / sendGroupMessage 等)
28
+ * - register/claim/updateAgentCard/uploadFile/downloadArtifact 是 OASN-only 能力
29
+ */
30
+
31
+ import { EventEmitter } from 'node:events';
32
+
33
+ import { logger } from '../../util/logger.js';
34
+ import {
35
+ makeTransportError,
36
+ type AgentCard,
37
+ type AgentCardPatch,
38
+ type AgentStatusResult,
39
+ type CategoryTree,
40
+ type ClaimParams,
41
+ type ClaimResult,
42
+ type CoreTransportEvent,
43
+ type DownloadArtifactResult,
44
+ type OasnTransport,
45
+ type OwnerInfo,
46
+ type ProgressCallback,
47
+ type RegisterResult,
48
+ type SearchQuery,
49
+ type SearchResult,
50
+ type TaskHandle,
51
+ type TaskRequest,
52
+ type TaskResult,
53
+ type TransportCredentials,
54
+ type TransportError,
55
+ type UploadFileParams,
56
+ type UploadFileResult,
57
+ } from '../types.js';
58
+ import { OasnAgentCard } from './oasn-agent-card.js';
59
+ import { OasnDiscovery } from './oasn-discovery.js';
60
+ import { OasnFiles } from './oasn-files.js';
61
+ import { OasnHttpClient } from './oasn-http.js';
62
+ import {
63
+ OasnInvocation,
64
+ type CreateInvocationOptions,
65
+ type PendingInvocationStore,
66
+ } from './oasn-invocation.js';
67
+ import { OasnRegister } from './oasn-register.js';
68
+
69
+ // ───────────────────────────────────────────────────────────────
70
+ // 构造选项
71
+ // ───────────────────────────────────────────────────────────────
72
+
73
+ export interface OasnTransportInitOptions {
74
+ /** 实例 id(多账户场景区分用) */
75
+ accountId: string;
76
+ /** OASN API base URL,例 `https://api.oasn.ai` */
77
+ apiBase: string;
78
+ /** Optional Access-layer API base URL for invocation/file/artifact endpoints. */
79
+ accessApiBase?: string;
80
+ /**
81
+ * 当前 agent_id(用于 ready() 探活 + register 后回填)。
82
+ * 可在 ready() 之前为空(未注册场景),但 sendTask 之类操作会失败。
83
+ */
84
+ agentId?: string;
85
+ /** §11.1 持久化钩子(接 StateStore.pending_invocations);可选 */
86
+ pendingStore?: PendingInvocationStore;
87
+ /** 单次 HTTP 超时(默认 30s) */
88
+ defaultTimeoutMs?: number;
89
+ /** retryable 错误自动重试次数(默认 3) */
90
+ maxRetries?: number;
91
+ }
92
+
93
+ // ───────────────────────────────────────────────────────────────
94
+ // 实现类
95
+ // ───────────────────────────────────────────────────────────────
96
+
97
+ export class OasnTransportImpl extends EventEmitter implements OasnTransport {
98
+ readonly transportType = 'oasn' as const;
99
+ readonly id: string;
100
+
101
+ private _http: OasnHttpClient;
102
+ private _accessHttp: OasnHttpClient;
103
+ private _agentCard: OasnAgentCard;
104
+ private _discovery: OasnDiscovery;
105
+ private _register: OasnRegister;
106
+ private _invocation: OasnInvocation;
107
+ private _files: OasnFiles;
108
+
109
+ private _agentId: string | undefined;
110
+ private _isReady = false;
111
+ private _claimStatus: AgentStatusResult['status'] | 'unknown' = 'unknown';
112
+
113
+ constructor(options: OasnTransportInitOptions) {
114
+ super();
115
+ this.id = options.accountId;
116
+ this._agentId = options.agentId;
117
+
118
+ // ── HTTP 层(含 401 撤销回调) ────────────────────────────────
119
+ const httpConfig = {
120
+ apiBase: options.apiBase,
121
+ defaultTimeoutMs: options.defaultTimeoutMs,
122
+ maxRetries: options.maxRetries,
123
+ onCredentialRevoked: () => this._onCredentialRevoked(),
124
+ };
125
+ this._http = new OasnHttpClient(httpConfig);
126
+ this._accessHttp = new OasnHttpClient({
127
+ ...httpConfig,
128
+ apiBase: options.accessApiBase || options.apiBase,
129
+ });
130
+
131
+ // ── 子模块(共享 HTTP 实例) ──────────────────────────────────
132
+ this._agentCard = new OasnAgentCard(this._http);
133
+ this._discovery = new OasnDiscovery(this._http);
134
+ this._register = new OasnRegister(this._http);
135
+ this._invocation = new OasnInvocation(this._accessHttp, options.pendingStore);
136
+ this._files = new OasnFiles(this._accessHttp);
137
+ }
138
+
139
+ // ═══════════════════════════════════════════════════════════════
140
+ // CoreTransport
141
+ // ═══════════════════════════════════════════════════════════════
142
+
143
+ /**
144
+ * 校验 api_key 有效性 + 进入可工作状态。
145
+ *
146
+ * 验证策略:
147
+ * 1. 设置 Bearer = credentials.token
148
+ * 2. 若 agentId 已知 → 调 GET /api/agent-cards/{agent_id}
149
+ * - status 接口返回 claimed 才允许后续 Invocation
150
+ * - 401 → onCredentialRevoked 回调,抛 TransportError
151
+ *
152
+ * 注:credentials.identity 在 OASN 场景下应等于 agent_id。
153
+ */
154
+ async ready(credentials: TransportCredentials): Promise<void> {
155
+ if (!credentials.token) {
156
+ throw makeTransportError('MISSING_CREDENTIAL', 'OASN ready: token (api_key) is required');
157
+ }
158
+ this._http.setToken(credentials.token);
159
+ this._accessHttp.setToken(credentials.token);
160
+
161
+ // 若构造时未传 agentId,则从 credentials.identity 读取
162
+ if (!this._agentId && credentials.identity) {
163
+ this._agentId = credentials.identity;
164
+ }
165
+
166
+ if (this._agentId) {
167
+ try {
168
+ const status = await this._register.getStatus(this._agentId);
169
+ this._claimStatus = status.status;
170
+ logger.info(
171
+ `[transport/oasn] ready agent_id=${this._agentId} `
172
+ + `claim_status=${status.status}`,
173
+ );
174
+ } catch (err) {
175
+ const te = err as TransportError;
176
+ // 401 已经在 HTTP 层触发了 onCredentialRevoked,再次显式抛
177
+ if (te.code === 'HTTP_401' || te.code === 'UNAUTHENTICATED') {
178
+ this._isReady = false;
179
+ throw te;
180
+ }
181
+ // 其他错误(网络/服务端 5xx 等):不阻止 ready,但保持 unknown,sendTask 会阻断
182
+ logger.warn(`[transport/oasn] ready probe failed code=${te.code} msg=${te.message}, continuing anyway`);
183
+ }
184
+ } else {
185
+ logger.info('[transport/oasn] ready called without agent_id; skipping probe (register flow expected)');
186
+ }
187
+
188
+ this._isReady = true;
189
+ }
190
+
191
+ async dispose(): Promise<void> {
192
+ // OASN 无长连接 —— 清 token 即可
193
+ this._http.setToken(undefined);
194
+ this._accessHttp.setToken(undefined);
195
+ this._isReady = false;
196
+ logger.info(`[transport/oasn] disposed account=${this.id}`);
197
+ }
198
+
199
+ get isReady(): boolean {
200
+ return this._isReady;
201
+ }
202
+
203
+ // EventEmitter 已经实现 on/off,此处仅做类型对齐(接口签名要求)
204
+ override on(event: CoreTransportEvent, handler: (...args: any[]) => void): this {
205
+ return super.on(event, handler);
206
+ }
207
+
208
+ override off(event: CoreTransportEvent, handler: (...args: any[]) => void): this {
209
+ return super.off(event, handler);
210
+ }
211
+
212
+ // ═══════════════════════════════════════════════════════════════
213
+ // TaskTransport(T2 核心路径)
214
+ // ═══════════════════════════════════════════════════════════════
215
+
216
+ /**
217
+ * 发起远程 Agent 调用 → POST /api/invocations。
218
+ *
219
+ * §11.1:若 task.requestId 视作 toolCallId 传入,OasnInvocation 会去 pendingStore
220
+ * 查同名记录,命中则复用 idempotency_key,避免重复创建 Invocation。
221
+ */
222
+ async sendTask(targetAgentId: string, task: TaskRequest): Promise<TaskHandle> {
223
+ if (!this._isReady) {
224
+ throw makeTransportError('NOT_READY', 'OASN transport not ready; call ready() first');
225
+ }
226
+ if (this._claimStatus !== 'claimed') {
227
+ throw makeTransportError(
228
+ 'REGISTRATION_NOT_ACTIVATED',
229
+ 'OASN ClientAgent must be claimed before creating invocations',
230
+ { retryable: false },
231
+ );
232
+ }
233
+
234
+ // 把 task.requestId 映射为 toolCallId(若存在)
235
+ const opts: CreateInvocationOptions = {};
236
+ if (task.requestId) opts.toolCallId = task.requestId;
237
+ if (task.timeoutMs !== undefined) opts.timeoutMs = task.timeoutMs;
238
+
239
+ return this._invocation.sendTask(targetAgentId, task, opts);
240
+ }
241
+
242
+ /** 等待结果(轮询 / 未来可升级到 SSE) */
243
+ waitForTaskResult(
244
+ handle: TaskHandle,
245
+ options: { timeoutMs: number; signal?: AbortSignal; onProgress?: ProgressCallback },
246
+ ): Promise<TaskResult> {
247
+ return this._invocation.waitForTaskResult(handle, options);
248
+ }
249
+
250
+ // ═══════════════════════════════════════════════════════════════
251
+ // DiscoveryTransport
252
+ // ═══════════════════════════════════════════════════════════════
253
+
254
+ searchAgents(query: SearchQuery): Promise<SearchResult> {
255
+ return this._discovery.search(query);
256
+ }
257
+
258
+ getAgent(agentId: string): Promise<AgentCard | null> {
259
+ return this._agentCard.get(agentId);
260
+ }
261
+
262
+ getCategories(params?: { agentType?: string }): Promise<CategoryTree> {
263
+ return this._discovery.getCategories(params);
264
+ }
265
+
266
+ // ═══════════════════════════════════════════════════════════════
267
+ // RegistrationTransport(OASN-only)
268
+ // ═══════════════════════════════════════════════════════════════
269
+
270
+ /**
271
+ * 注册新 Agent。
272
+ *
273
+ * 注意:register 不要求 ready() —— 首次安装时还没有 api_key。
274
+ * 但 register 成功后,调用方需立即把 api_key 持久化 + 调 ready() 进入可工作状态。
275
+ */
276
+ async registerAgent(
277
+ platform: string,
278
+ params?: { installId?: string; deviceHint?: string },
279
+ ): Promise<RegisterResult> {
280
+ const result = await this._register.register(platform, params);
281
+ // 回填 agentId(后续 ready() 探活会用到)
282
+ this._agentId = result.agent_id;
283
+ return result;
284
+ }
285
+
286
+ async claimAgent(params: ClaimParams): Promise<ClaimResult> {
287
+ const result = await this._register.claim(params);
288
+ this._claimStatus = 'claim_pending';
289
+ return result;
290
+ }
291
+
292
+ async getAgentStatus(agentId: string): Promise<AgentStatusResult> {
293
+ const result = await this._register.getStatus(agentId);
294
+ this._claimStatus = result.status;
295
+ return result;
296
+ }
297
+
298
+ updateAgentCard(agentId: string, patch: AgentCardPatch): Promise<AgentCard> {
299
+ return this._agentCard.update(agentId, patch);
300
+ }
301
+
302
+ getCurrentOwner(): Promise<OwnerInfo | null> {
303
+ return this._agentCard.getCurrentOwner();
304
+ }
305
+
306
+ // ═══════════════════════════════════════════════════════════════
307
+ // FileTransport(OASN-only)
308
+ // ═══════════════════════════════════════════════════════════════
309
+
310
+ uploadFile(file: UploadFileParams): Promise<UploadFileResult> {
311
+ // 默认走 LRU 路径,避免重复上传同一份内容
312
+ return this._files.ensureFileRef(file);
313
+ }
314
+
315
+ downloadArtifact(artifactId: string): Promise<DownloadArtifactResult> {
316
+ return this._files.downloadArtifact(artifactId);
317
+ }
318
+
319
+ // ═══════════════════════════════════════════════════════════════
320
+ // §11.5 401 撤销恢复路径
321
+ // ═══════════════════════════════════════════════════════════════
322
+
323
+ /**
324
+ * HTTP 层捕获 401 时调用:
325
+ * 1. 清掉本地 Bearer
326
+ * 2. 标记 not ready
327
+ * 3. 发 'credential_expired' 事件,AccountRuntime 接收后清凭证 + 引导 register
328
+ *
329
+ * 注意:不直接清 OpenClaw config —— config 持久层的清理由 AccountRuntime 决定。
330
+ */
331
+ private _onCredentialRevoked(): void {
332
+ if (!this._isReady) return; // 防止 ready 探活阶段重复触发
333
+ logger.error('[transport/oasn] api_key revoked (401 UNAUTHENTICATED) - emitting credential_expired');
334
+ this._http.setToken(undefined);
335
+ this._isReady = false;
336
+ this.emit('credential_expired', {
337
+ transportType: 'oasn',
338
+ accountId: this.id,
339
+ });
340
+ }
341
+ }