openclaw-openagent 1.0.5 → 1.0.6

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.js CHANGED
@@ -20,6 +20,7 @@ import { logger } from './src/util/logger.js';
20
20
  // ── Runtime reference ─────────────────────────────────────────────────────
21
21
  // Saved from api.runtime during register(), accessible by other modules.
22
22
  let _runtime;
23
+ let _fullModeRegistered = false;
23
24
  export function getOpenagentRuntime() {
24
25
  return _runtime;
25
26
  }
@@ -63,8 +64,15 @@ export default {
63
64
  logger.info('[entry] Channel adapter registered');
64
65
  // P1-2: registrationMode exists in 2026.3.22+; skip heavy registrations in
65
66
  // setup-only mode (e.g. `openclaw channels list`).
67
+ // IMPORTANT: once registered in full mode, a subsequent hot-reload may
68
+ // re-invoke register() with mode='tool-discovery'. In that case we must
69
+ // still re-register tools/hooks so the gateway doesn't drop them.
66
70
  const mode = api.registrationMode;
67
- if (mode && mode !== 'full') {
71
+ if (mode && mode !== 'full' && _fullModeRegistered) {
72
+ logger.info(`[entry] Re-registering in ${mode} mode (full mode preserved)`);
73
+ // Fall through — re-register tools to avoid gateway dropping them.
74
+ }
75
+ else if (mode && mode !== 'full') {
68
76
  logger.info(`[entry] Setup-only mode (registrationMode=${mode}), skipping tools/hooks`);
69
77
  return;
70
78
  }
@@ -97,6 +105,7 @@ export default {
97
105
  logger.warn(`[entry] Control UI injection failed: ${err.message}`);
98
106
  });
99
107
  logger.info('[entry] Tools + hooks registered (full mode)');
108
+ _fullModeRegistered = true;
100
109
  },
101
110
  };
102
111
  // Named exports for direct imports
@@ -2,7 +2,7 @@
2
2
  * OpenAgent UI Override — Auto-generated, do not edit directly!
3
3
  *
4
4
  * Source: src/plugin-ui/modules/
5
- * Built: 2026-06-25T07:20:29.082Z
5
+ * Built: 2026-06-25T08:37:18.204Z
6
6
  *
7
7
  * To modify, edit the source modules and run:
8
8
  * npm run build:override
@@ -22,6 +22,15 @@ import { isUnconfiguredOasnApiBase } from '../auth/config.js';
22
22
  const AUTH_UPSTREAM_TIM = 'https://auth.ai-talk.live';
23
23
  const PROXY_TIMEOUT_MS = 15_000;
24
24
  const MAX_BODY_BYTES = 64 * 1024; // 64KB — tagline API body is ~100 bytes
25
+ /**
26
+ * 获取当前 OASN access API base URL,用于解析响应中的相对路径。
27
+ */
28
+ function getOasnAccessBase() {
29
+ const rt = registry.getDefault();
30
+ if (rt?.transportType !== 'oasn')
31
+ return '';
32
+ return (rt.config?.accessApiBase || rt.config?.apiBase || '').replace(/\/+$/, '');
33
+ }
25
34
  /**
26
35
  * 根据当前 active runtime 的 transport 类型决定上游。
27
36
  *
@@ -127,7 +136,30 @@ export function createAuthProxyHandler() {
127
136
  const contentType = upstream.headers.get('content-type');
128
137
  if (contentType)
129
138
  res.setHeader('Content-Type', contentType);
130
- const buf = Buffer.from(await upstream.arrayBuffer());
139
+ let buf = Buffer.from(await upstream.arrayBuffer());
140
+ // Resolve OASN-relative URLs in GET invocation responses so the
141
+ // frontend receives absolute URLs (launch_url, content_url, etc.).
142
+ if (method === 'GET' && /^\/api\/invocations\/[^/]+$/.test(targetPath) && buf.length > 0) {
143
+ try {
144
+ const isJson = contentType?.includes('json');
145
+ if (isJson) {
146
+ const oasnBase = getOasnAccessBase();
147
+ if (oasnBase) {
148
+ const text = buf.toString('utf-8');
149
+ const resolved = text.replace(/"(launch_url|content_url)":"(\/[^"]+)"/g, (_m, key, path) => {
150
+ try {
151
+ return `"${key}":"${new URL(path, oasnBase).toString()}"`;
152
+ }
153
+ catch {
154
+ return _m;
155
+ }
156
+ });
157
+ buf = Buffer.from(resolved, 'utf-8');
158
+ }
159
+ }
160
+ }
161
+ catch { /* best-effort; don't break proxy on parse errors */ }
162
+ }
131
163
  res.end(buf);
132
164
  logger.info(`[proxy] ${method} ${url.pathname} → ${upstream.status} (${buf.length} bytes)`);
133
165
  }
package/index.ts CHANGED
@@ -25,6 +25,7 @@ import { logger } from './src/util/logger.js';
25
25
  // Saved from api.runtime during register(), accessible by other modules.
26
26
 
27
27
  let _runtime: OpenClawPluginApi['runtime'] | undefined;
28
+ let _fullModeRegistered = false;
28
29
 
29
30
  export function getOpenagentRuntime(): OpenClawPluginApi['runtime'] | undefined {
30
31
  return _runtime;
@@ -80,8 +81,14 @@ export default {
80
81
 
81
82
  // P1-2: registrationMode exists in 2026.3.22+; skip heavy registrations in
82
83
  // setup-only mode (e.g. `openclaw channels list`).
84
+ // IMPORTANT: once registered in full mode, a subsequent hot-reload may
85
+ // re-invoke register() with mode='tool-discovery'. In that case we must
86
+ // still re-register tools/hooks so the gateway doesn't drop them.
83
87
  const mode = (api as { registrationMode?: string }).registrationMode;
84
- if (mode && mode !== 'full') {
88
+ if (mode && mode !== 'full' && _fullModeRegistered) {
89
+ logger.info(`[entry] Re-registering in ${mode} mode (full mode preserved)`);
90
+ // Fall through — re-register tools to avoid gateway dropping them.
91
+ } else if (mode && mode !== 'full') {
85
92
  logger.info(`[entry] Setup-only mode (registrationMode=${mode}), skipping tools/hooks`);
86
93
  return;
87
94
  }
@@ -116,6 +123,7 @@ export default {
116
123
  });
117
124
 
118
125
  logger.info('[entry] Tools + hooks registered (full mode)');
126
+ _fullModeRegistered = true;
119
127
  },
120
128
  };
121
129
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openclaw-openagent",
3
- "version": "1.0.5",
3
+ "version": "1.0.6",
4
4
  "type": "module",
5
5
  "description": "OpenAgent channel plugin for OpenClaw",
6
6
  "license": "MIT",
@@ -2,7 +2,7 @@
2
2
  * OpenAgent UI Override — Auto-generated, do not edit directly!
3
3
  *
4
4
  * Source: src/plugin-ui/modules/
5
- * Built: 2026-06-25T07:20:29.082Z
5
+ * Built: 2026-06-25T08:37:18.204Z
6
6
  *
7
7
  * To modify, edit the source modules and run:
8
8
  * npm run build:override
@@ -26,6 +26,15 @@ const AUTH_UPSTREAM_TIM = 'https://auth.ai-talk.live';
26
26
  const PROXY_TIMEOUT_MS = 15_000;
27
27
  const MAX_BODY_BYTES = 64 * 1024; // 64KB — tagline API body is ~100 bytes
28
28
 
29
+ /**
30
+ * 获取当前 OASN access API base URL,用于解析响应中的相对路径。
31
+ */
32
+ function getOasnAccessBase(): string {
33
+ const rt = registry.getDefault();
34
+ if (rt?.transportType !== 'oasn') return '';
35
+ return (rt.config?.accessApiBase || rt.config?.apiBase || '').replace(/\/+$/, '');
36
+ }
37
+
29
38
  /**
30
39
  * 根据当前 active runtime 的 transport 类型决定上游。
31
40
  *
@@ -143,7 +152,31 @@ export function createAuthProxyHandler() {
143
152
  const contentType = upstream.headers.get('content-type');
144
153
  if (contentType) res.setHeader('Content-Type', contentType);
145
154
 
146
- const buf = Buffer.from(await upstream.arrayBuffer());
155
+ let buf = Buffer.from(await upstream.arrayBuffer());
156
+
157
+ // Resolve OASN-relative URLs in GET invocation responses so the
158
+ // frontend receives absolute URLs (launch_url, content_url, etc.).
159
+ if (method === 'GET' && /^\/api\/invocations\/[^/]+$/.test(targetPath) && buf.length > 0) {
160
+ try {
161
+ const isJson = contentType?.includes('json');
162
+ if (isJson) {
163
+ const oasnBase = getOasnAccessBase();
164
+ if (oasnBase) {
165
+ const text = buf.toString('utf-8');
166
+ const resolved = text.replace(
167
+ /"(launch_url|content_url)":"(\/[^"]+)"/g,
168
+ (_m: string, key: string, path: string) => {
169
+ try {
170
+ return `"${key}":"${new URL(path, oasnBase).toString()}"`;
171
+ } catch { return _m; }
172
+ },
173
+ );
174
+ buf = Buffer.from(resolved, 'utf-8');
175
+ }
176
+ }
177
+ } catch { /* best-effort; don't break proxy on parse errors */ }
178
+ }
179
+
147
180
  res.end(buf);
148
181
 
149
182
  logger.info(`[proxy] ${method} ${url.pathname} → ${upstream.status} (${buf.length} bytes)`);