@mininglamp-oss/octo-runtime 1.1.0 → 1.1.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.
Files changed (149) hide show
  1. package/README.md +4 -2
  2. package/apps/cli/README.md +3 -1
  3. package/apps/cli/dist/build-info.json +2 -2
  4. package/apps/cli/dist/extras.d.ts +4 -2
  5. package/apps/cli/dist/extras.js +20 -21
  6. package/apps/cli/dist/help.js +3 -0
  7. package/apps/cli/dist/logs.d.ts +10 -0
  8. package/apps/cli/dist/logs.js +186 -0
  9. package/apps/cli/dist/main.d.ts +1 -0
  10. package/apps/cli/dist/main.js +94 -19
  11. package/apps/cli/dist/{default_adapters.json → manifest.json} +10 -0
  12. package/apps/cli/dist/module-manifest.d.ts +3 -0
  13. package/apps/cli/dist/module-manifest.js +11 -0
  14. package/apps/cli/dist/openclaw.js +30 -6
  15. package/apps/cli/dist/output.js +3 -0
  16. package/apps/cli/dist/playboard.js +10 -8
  17. package/apps/cli/dist/status-output.d.ts +10 -0
  18. package/apps/cli/dist/status-output.js +65 -0
  19. package/apps/cli/dist/worker.d.ts +1 -0
  20. package/apps/cli/dist/worker.js +18 -0
  21. package/dist/public/host.d.ts +1 -0
  22. package/node_modules/@mininglamp-oss/octo-runtime-acp-client/package.json +3 -3
  23. package/node_modules/@mininglamp-oss/octo-runtime-adapter-acp/package.json +4 -4
  24. package/node_modules/@mininglamp-oss/octo-runtime-adapter-antigravity/package.json +3 -3
  25. package/node_modules/@mininglamp-oss/octo-runtime-adapter-claude-code/package.json +3 -3
  26. package/node_modules/@mininglamp-oss/octo-runtime-adapter-codebuddy/package.json +4 -4
  27. package/node_modules/@mininglamp-oss/octo-runtime-adapter-codex/package.json +3 -3
  28. package/node_modules/@mininglamp-oss/octo-runtime-adapter-grok-build/dist/adapter.d.ts +54 -0
  29. package/node_modules/@mininglamp-oss/octo-runtime-adapter-grok-build/dist/adapter.js +399 -0
  30. package/node_modules/@mininglamp-oss/octo-runtime-adapter-grok-build/dist/client.d.ts +14 -0
  31. package/node_modules/@mininglamp-oss/octo-runtime-adapter-grok-build/dist/client.js +156 -0
  32. package/node_modules/@mininglamp-oss/octo-runtime-adapter-grok-build/dist/index.d.ts +29 -0
  33. package/node_modules/@mininglamp-oss/octo-runtime-adapter-grok-build/dist/index.js +273 -0
  34. package/node_modules/@mininglamp-oss/octo-runtime-adapter-grok-build/dist/interactions.d.ts +27 -0
  35. package/node_modules/@mininglamp-oss/octo-runtime-adapter-grok-build/dist/interactions.js +161 -0
  36. package/node_modules/@mininglamp-oss/octo-runtime-adapter-grok-build/package.json +17 -0
  37. package/node_modules/@mininglamp-oss/octo-runtime-adapter-hermes/package.json +2 -2
  38. package/node_modules/@mininglamp-oss/octo-runtime-adapter-kimi-code/package.json +2 -2
  39. package/node_modules/@mininglamp-oss/octo-runtime-adapter-mcode/package.json +2 -2
  40. package/node_modules/@mininglamp-oss/octo-runtime-adapter-openclaw/dist/compatibility.d.ts +24 -0
  41. package/node_modules/@mininglamp-oss/octo-runtime-adapter-openclaw/dist/compatibility.js +181 -0
  42. package/node_modules/@mininglamp-oss/octo-runtime-adapter-openclaw/dist/gateway.d.ts +9 -0
  43. package/node_modules/@mininglamp-oss/octo-runtime-adapter-openclaw/dist/gateway.js +24 -8
  44. package/node_modules/@mininglamp-oss/octo-runtime-adapter-openclaw/dist/index.js +229 -225
  45. package/node_modules/@mininglamp-oss/octo-runtime-adapter-openclaw/package.json +3 -3
  46. package/node_modules/@mininglamp-oss/octo-runtime-adapter-opencode/package.json +4 -4
  47. package/node_modules/@mininglamp-oss/octo-runtime-adapter-qodercli/package.json +2 -2
  48. package/node_modules/@mininglamp-oss/octo-runtime-adapter-qoderclicn/package.json +2 -2
  49. package/node_modules/@mininglamp-oss/octo-runtime-adapter-sdk/dist/approval.d.ts +4 -0
  50. package/node_modules/@mininglamp-oss/octo-runtime-adapter-sdk/dist/approval.js +5 -6
  51. package/node_modules/@mininglamp-oss/octo-runtime-adapter-sdk/dist/index.d.ts +1 -0
  52. package/node_modules/@mininglamp-oss/octo-runtime-adapter-sdk/dist/index.js +1 -0
  53. package/node_modules/@mininglamp-oss/octo-runtime-adapter-sdk/dist/module-manifest.d.ts +33 -0
  54. package/node_modules/@mininglamp-oss/octo-runtime-adapter-sdk/dist/module-manifest.js +118 -0
  55. package/node_modules/@mininglamp-oss/octo-runtime-adapter-sdk/dist/runtime-log-worker.js +7 -5
  56. package/node_modules/@mininglamp-oss/octo-runtime-adapter-sdk/dist/runtime-log.d.ts +3 -0
  57. package/node_modules/@mininglamp-oss/octo-runtime-adapter-sdk/dist/runtime-log.js +45 -10
  58. package/node_modules/@mininglamp-oss/octo-runtime-adapter-sdk/dist/service-status.d.ts +11 -0
  59. package/node_modules/@mininglamp-oss/octo-runtime-adapter-sdk/dist/service-status.js +70 -0
  60. package/node_modules/@mininglamp-oss/octo-runtime-adapter-sdk/package.json +5 -3
  61. package/node_modules/@mininglamp-oss/octo-runtime-adapter-zcode-gui/package.json +3 -3
  62. package/node_modules/@mininglamp-oss/octo-runtime-cli/dist/build-info.json +2 -2
  63. package/node_modules/@mininglamp-oss/octo-runtime-cli/dist/extras.d.ts +4 -2
  64. package/node_modules/@mininglamp-oss/octo-runtime-cli/dist/extras.js +20 -21
  65. package/node_modules/@mininglamp-oss/octo-runtime-cli/dist/help.js +3 -0
  66. package/node_modules/@mininglamp-oss/octo-runtime-cli/dist/logs.d.ts +10 -0
  67. package/node_modules/@mininglamp-oss/octo-runtime-cli/dist/logs.js +186 -0
  68. package/node_modules/@mininglamp-oss/octo-runtime-cli/dist/main.d.ts +1 -0
  69. package/node_modules/@mininglamp-oss/octo-runtime-cli/dist/main.js +94 -19
  70. package/node_modules/@mininglamp-oss/octo-runtime-cli/dist/{default_adapters.json → manifest.json} +10 -0
  71. package/node_modules/@mininglamp-oss/octo-runtime-cli/dist/module-manifest.d.ts +3 -0
  72. package/node_modules/@mininglamp-oss/octo-runtime-cli/dist/module-manifest.js +11 -0
  73. package/node_modules/@mininglamp-oss/octo-runtime-cli/dist/openclaw.js +30 -6
  74. package/node_modules/@mininglamp-oss/octo-runtime-cli/dist/output.js +3 -0
  75. package/node_modules/@mininglamp-oss/octo-runtime-cli/dist/playboard.js +10 -8
  76. package/node_modules/@mininglamp-oss/octo-runtime-cli/dist/status-output.d.ts +10 -0
  77. package/node_modules/@mininglamp-oss/octo-runtime-cli/dist/status-output.js +65 -0
  78. package/node_modules/@mininglamp-oss/octo-runtime-cli/dist/worker.d.ts +1 -0
  79. package/node_modules/@mininglamp-oss/octo-runtime-cli/dist/worker.js +18 -0
  80. package/node_modules/@mininglamp-oss/octo-runtime-cli/package.json +23 -9
  81. package/node_modules/@mininglamp-oss/octo-runtime-cross-service/package.json +2 -2
  82. package/node_modules/@mininglamp-oss/octo-runtime-executor-core/dist/model-input.d.ts +1 -1
  83. package/node_modules/@mininglamp-oss/octo-runtime-executor-core/dist/model-input.js +13 -9
  84. package/node_modules/@mininglamp-oss/octo-runtime-executor-core/package.json +3 -3
  85. package/node_modules/@mininglamp-oss/octo-runtime-executor-kernel/dist/heartbeat.d.ts +16 -0
  86. package/node_modules/@mininglamp-oss/octo-runtime-executor-kernel/dist/heartbeat.js +59 -0
  87. package/node_modules/@mininglamp-oss/octo-runtime-executor-kernel/dist/invocation-manifest.d.ts +1 -0
  88. package/node_modules/@mininglamp-oss/octo-runtime-executor-kernel/dist/invocation-manifest.js +4 -1
  89. package/node_modules/@mininglamp-oss/octo-runtime-executor-kernel/dist/manifest-adapters.d.ts +6 -0
  90. package/node_modules/@mininglamp-oss/octo-runtime-executor-kernel/dist/manifest-adapters.js +88 -0
  91. package/node_modules/@mininglamp-oss/octo-runtime-executor-kernel/dist/module-specifier.d.ts +1 -2
  92. package/node_modules/@mininglamp-oss/octo-runtime-executor-kernel/dist/module-specifier.js +2 -9
  93. package/node_modules/@mininglamp-oss/octo-runtime-executor-kernel/dist/process.d.ts +7 -2
  94. package/node_modules/@mininglamp-oss/octo-runtime-executor-kernel/dist/process.js +138 -9
  95. package/node_modules/@mininglamp-oss/octo-runtime-executor-kernel/dist/runner.js +3 -92
  96. package/node_modules/@mininglamp-oss/octo-runtime-executor-kernel/dist/serve.js +36 -12
  97. package/node_modules/@mininglamp-oss/octo-runtime-executor-kernel/dist/server.d.ts +4 -1
  98. package/node_modules/@mininglamp-oss/octo-runtime-executor-kernel/dist/server.js +14 -6
  99. package/node_modules/@mininglamp-oss/octo-runtime-executor-kernel/dist/service.js +2 -1
  100. package/node_modules/@mininglamp-oss/octo-runtime-executor-kernel/dist/supervisor.d.ts +2 -2
  101. package/node_modules/@mininglamp-oss/octo-runtime-executor-kernel/dist/supervisor.js +57 -34
  102. package/node_modules/@mininglamp-oss/octo-runtime-executor-kernel/package.json +8 -16
  103. package/node_modules/@mininglamp-oss/octo-runtime-extra-channel-gateway/config-schema.json +2 -2
  104. package/node_modules/@mininglamp-oss/octo-runtime-extra-channel-gateway/dist/application/im-channel.js +18 -18
  105. package/node_modules/@mininglamp-oss/octo-runtime-extra-channel-gateway/dist/contracts.d.ts +1 -0
  106. package/node_modules/@mininglamp-oss/octo-runtime-extra-channel-gateway/dist/execution/dispatcher.js +24 -0
  107. package/node_modules/@mininglamp-oss/octo-runtime-extra-channel-gateway/dist/transport/contexts.js +2 -2
  108. package/node_modules/@mininglamp-oss/octo-runtime-extra-channel-gateway/dist/transport/mentions.d.ts +5 -2
  109. package/node_modules/@mininglamp-oss/octo-runtime-extra-channel-gateway/dist/transport/mentions.js +19 -5
  110. package/node_modules/@mininglamp-oss/octo-runtime-extra-channel-gateway/dist/transport/normalize.js +1 -0
  111. package/node_modules/@mininglamp-oss/octo-runtime-extra-channel-gateway/package.json +6 -6
  112. package/node_modules/@mininglamp-oss/octo-runtime-extra-channel-wecom/config-schema.json +2 -2
  113. package/node_modules/@mininglamp-oss/octo-runtime-extra-channel-wecom/package.json +5 -5
  114. package/node_modules/@mininglamp-oss/octo-runtime-extra-webui/config-schema.json +2 -2
  115. package/node_modules/@mininglamp-oss/octo-runtime-extra-webui/dist/index.js +1 -1
  116. package/node_modules/@mininglamp-oss/octo-runtime-extra-webui/dist/store.d.ts +4 -1
  117. package/node_modules/@mininglamp-oss/octo-runtime-extra-webui/dist/store.js +54 -4
  118. package/node_modules/@mininglamp-oss/octo-runtime-extra-webui/package.json +2 -2
  119. package/node_modules/@mininglamp-oss/octo-runtime-host-sdk/dist/extra-config.d.ts +8 -1
  120. package/node_modules/@mininglamp-oss/octo-runtime-host-sdk/dist/extra-config.js +27 -12
  121. package/node_modules/@mininglamp-oss/octo-runtime-host-sdk/dist/extra-service.js +39 -2
  122. package/node_modules/@mininglamp-oss/octo-runtime-host-sdk/dist/index.d.ts +1 -0
  123. package/node_modules/@mininglamp-oss/octo-runtime-host-sdk/package.json +4 -4
  124. package/node_modules/@mininglamp-oss/octo-runtime-protocol/package.json +1 -1
  125. package/node_modules/import-meta-resolve/index.d.ts +19 -0
  126. package/node_modules/import-meta-resolve/index.d.ts.map +1 -0
  127. package/node_modules/import-meta-resolve/index.js +47 -0
  128. package/node_modules/import-meta-resolve/lib/errors.d.ts +24 -0
  129. package/node_modules/import-meta-resolve/lib/errors.d.ts.map +1 -0
  130. package/node_modules/import-meta-resolve/lib/errors.js +504 -0
  131. package/node_modules/import-meta-resolve/lib/get-format.d.ts +13 -0
  132. package/node_modules/import-meta-resolve/lib/get-format.d.ts.map +1 -0
  133. package/node_modules/import-meta-resolve/lib/get-format.js +159 -0
  134. package/node_modules/import-meta-resolve/lib/package-json-reader.d.ts +31 -0
  135. package/node_modules/import-meta-resolve/lib/package-json-reader.d.ts.map +1 -0
  136. package/node_modules/import-meta-resolve/lib/package-json-reader.js +177 -0
  137. package/node_modules/import-meta-resolve/lib/resolve.d.ts +29 -0
  138. package/node_modules/import-meta-resolve/lib/resolve.d.ts.map +1 -0
  139. package/node_modules/import-meta-resolve/lib/resolve.js +1301 -0
  140. package/node_modules/import-meta-resolve/lib/utils.d.ts +6 -0
  141. package/node_modules/import-meta-resolve/lib/utils.d.ts.map +1 -0
  142. package/node_modules/import-meta-resolve/lib/utils.js +47 -0
  143. package/node_modules/import-meta-resolve/license +74 -0
  144. package/node_modules/import-meta-resolve/package.json +78 -0
  145. package/node_modules/import-meta-resolve/readme.md +252 -0
  146. package/package.json +30 -26
  147. package/packages/octo-runtime-extra-channel-gateway/config-schema.json +2 -2
  148. package/packages/octo-runtime-extra-channel-wecom/config-schema.json +2 -2
  149. package/packages/octo-runtime-extra-webui/config-schema.json +2 -2
@@ -3,6 +3,7 @@ import { canonicalTerminalStatus } from "@mininglamp-oss/octo-runtime-protocol";
3
3
  import { randomUUID } from "node:crypto";
4
4
  import { OpenClawGatewayClient } from "./gateway.js";
5
5
  import { resolveOpenClawGateway, localGatewayFailure } from "./local-gateway.js";
6
+ import { resolveGatewayContract, resolveGatewayPermission, gatewayCreateParams, gatewayLegacyPermissionParams, gatewayTerminal, isGatewayRunPending } from "./compatibility.js";
6
7
  export const OPENCLAW_PROVIDER_OPTIONS = {
7
8
  url: "OPENCLAW_GATEWAY_URL",
8
9
  token: "OPENCLAW_GATEWAY_TOKEN",
@@ -60,10 +61,7 @@ export function buildOpenClawGatewayInvocation(req) {
60
61
  const createParams = {
61
62
  key: sessionKey,
62
63
  agentId,
63
- permissionMode: req.approvalMode === "full_access" ? "full" : "guarded",
64
- idempotencyKey: `${requestId}-session`,
65
- ...(model ? { model } : {}),
66
- ...(thinking ? { thinkingLevel: thinking } : {})
64
+ ...(model ? { model } : {})
67
65
  };
68
66
  const agentParams = {
69
67
  message,
@@ -156,7 +154,7 @@ function normalizeGatewayAgentEvent(payload, state) {
156
154
  return [];
157
155
  state.lastSeq = seq;
158
156
  const events = [];
159
- const stepId = `openclaw:${nonEmptyString(native.runId) ?? "run"}`;
157
+ const stepId = (state.stepId ??= `openclaw:${nonEmptyString(native.runId) ?? "run"}`);
160
158
  const ensureStep = () => {
161
159
  if (state.stepStarted)
162
160
  return;
@@ -165,9 +163,13 @@ function normalizeGatewayAgentEvent(payload, state) {
165
163
  };
166
164
  if (stream === "lifecycle") {
167
165
  const phase = nonEmptyString(data.phase);
166
+ const terminal = gatewayTerminal(data, "lifecycle");
168
167
  if (phase === "start")
169
168
  ensureStep();
170
- if ((phase === "end" || phase === "error") && state.stepStarted && !state.stepFinished) {
169
+ if ((phase === "end" || phase === "error") &&
170
+ terminal &&
171
+ state.stepStarted &&
172
+ !state.stepFinished) {
171
173
  state.stepFinished = true;
172
174
  const finishReason = nonEmptyString(data.stopReason);
173
175
  events.push({
@@ -175,7 +177,7 @@ function normalizeGatewayAgentEvent(payload, state) {
175
177
  type: "model_step.finished",
176
178
  payload: {
177
179
  stepId,
178
- status: canonicalTerminalStatus(phase === "error" ? "failed" : data.aborted === true ? "cancelled" : "completed"),
180
+ status: canonicalTerminalStatus(terminal),
179
181
  ...(finishReason ? { finishReason } : {})
180
182
  }
181
183
  });
@@ -319,12 +321,9 @@ function terminalState(payload) {
319
321
  if (native?.stream !== "lifecycle")
320
322
  return undefined;
321
323
  const data = asRecord(native.data);
322
- const phase = nonEmptyString(data?.phase);
323
- if (phase === "error")
324
- return data?.aborted === true ? "cancelled" : "failed";
325
- if (phase === "end")
326
- return data?.aborted === true ? "cancelled" : "completed";
327
- return undefined;
324
+ if (data?.phase !== "end" && data?.phase !== "error")
325
+ return undefined;
326
+ return gatewayTerminal(data, "lifecycle");
328
327
  }
329
328
  function terminalError(payload) {
330
329
  return (nonEmptyString(asRecord(asRecord(payload)?.data)?.error) ?? "OpenClaw Gateway agent run failed");
@@ -334,19 +333,10 @@ async function waitForConfirmedTerminal(client, runId, expected, deadlineAt) {
334
333
  const waitMs = Math.max(1, Math.min(30_000, deadlineAt - Date.now()));
335
334
  const result = asRecord(await client.request("agent.wait", { runId, timeoutMs: waitMs }, { timeoutMs: waitMs + 2_000 }));
336
335
  const status = nonEmptyString(result?.status);
337
- const stopReason = nonEmptyString(result?.stopReason);
338
- const endedAt = finiteNumber(result?.endedAt);
339
- const cancelled = endedAt !== undefined && (stopReason === "aborted" || stopReason === "restart");
340
- const actual = cancelled
341
- ? "cancelled"
342
- : status === "ok"
343
- ? "completed"
344
- : status === "error" || (status === "timeout" && endedAt !== undefined)
345
- ? "failed"
346
- : undefined;
347
- if (actual === expected)
348
- return;
349
- if (!actual && (status === "pending" || status === "timeout")) {
336
+ const actual = gatewayTerminal(result, "wait");
337
+ if (actual && (expected === undefined || actual === expected))
338
+ return actual;
339
+ if (!actual && (isGatewayRunPending(result) || status === "timeout")) {
350
340
  await new Promise((resolve) => setTimeout(resolve, Math.min(250, Math.max(0, deadlineAt - Date.now()))));
351
341
  continue;
352
342
  }
@@ -355,14 +345,15 @@ async function waitForConfirmedTerminal(client, runId, expected, deadlineAt) {
355
345
  ? `OpenClaw Gateway confirmed ${actual ?? status ?? "unknown"}, not ${expected}: ${error}`
356
346
  : `OpenClaw Gateway confirmed ${actual ?? status ?? "unknown"}, not ${expected}`);
357
347
  }
358
- throw new Error(`OpenClaw Gateway did not confirm ${expected} before the invocation deadline`);
348
+ throw new Error(`OpenClaw Gateway did not confirm ${expected ?? "a terminal state"} before the invocation deadline`);
359
349
  }
360
- function normalizeFinalResponse(value, state) {
350
+ function normalizeFinalResponse(value, state, runId) {
361
351
  const response = asRecord(value);
362
352
  const result = asRecord(response?.result);
363
353
  const meta = asRecord(result?.meta);
364
354
  const agentMeta = asRecord(meta?.agentMeta);
365
355
  const events = [];
356
+ const stepId = (state.stepId ??= `openclaw:${runId}`);
366
357
  const payloads = Array.isArray(result?.payloads) ? result.payloads : [];
367
358
  const finalText = payloads
368
359
  .map((item) => nonEmptyString(asRecord(item)?.text) ?? "")
@@ -375,7 +366,7 @@ function normalizeFinalResponse(value, state) {
375
366
  events.push({
376
367
  protocolVersion: 2,
377
368
  type: "model_step.started",
378
- payload: { stepId: `openclaw:${nonEmptyString(response?.runId) ?? "run"}` }
369
+ payload: { stepId }
379
370
  });
380
371
  };
381
372
  if (finalText) {
@@ -412,14 +403,7 @@ function normalizeFinalResponse(value, state) {
412
403
  });
413
404
  if (usageUpdate)
414
405
  events.push(usageUpdate);
415
- const status = nonEmptyString(response?.status);
416
- const terminal = status === "ok"
417
- ? meta?.aborted === true
418
- ? "cancelled"
419
- : "completed"
420
- : status
421
- ? "failed"
422
- : undefined;
406
+ const terminal = gatewayTerminal(response, "final");
423
407
  if (terminal && !state.stepFinished) {
424
408
  ensureStep();
425
409
  state.stepFinished = true;
@@ -427,7 +411,7 @@ function normalizeFinalResponse(value, state) {
427
411
  protocolVersion: 2,
428
412
  type: "model_step.finished",
429
413
  payload: {
430
- stepId: `openclaw:${nonEmptyString(response?.runId) ?? "run"}`,
414
+ stepId,
431
415
  status: canonicalTerminalStatus(terminal === "cancelled" ? "cancelled" : terminal === "failed" ? "failed" : "completed"),
432
416
  ...(nonEmptyString(meta?.stopReason)
433
417
  ? { finishReason: nonEmptyString(meta?.stopReason) }
@@ -443,32 +427,10 @@ function normalizeFinalResponse(value, state) {
443
427
  : {})
444
428
  };
445
429
  }
446
- function assertRuntimeGatewayContract(value) {
447
- const hello = asRecord(value);
448
- const features = asRecord(hello?.features);
449
- const methods = Array.isArray(features?.methods) ? features.methods : [];
450
- const events = Array.isArray(features?.events) ? features.events : [];
451
- if (hello?.protocol !== 4)
452
- throw new Error(`unsupported OpenClaw Gateway protocol: ${String(hello?.protocol)}`);
453
- const requiredMethods = [
454
- "sessions.create",
455
- "sessions.messages.subscribe",
456
- "agent",
457
- "agent.wait",
458
- "sessions.abort"
459
- ];
460
- requiredMethods.unshift("agents.list");
461
- for (const method of requiredMethods) {
462
- if (!methods.includes(method))
463
- throw new Error(`OpenClaw Gateway does not advertise required method ${method}`);
464
- }
465
- if (!events.includes("agent"))
466
- throw new Error("OpenClaw Gateway does not advertise the agent event stream");
467
- }
468
430
  async function* invokeOpenClawGateway(req, invocation, context, clientFactory, permissions) {
469
431
  const client = clientFactory(invocation.gateway);
470
432
  const requestAbort = new AbortController();
471
- let resourceFailure = false;
433
+ let resourceFailure;
472
434
  let terminal;
473
435
  let closing;
474
436
  const stop = (cancel = false) => {
@@ -477,7 +439,7 @@ async function* invokeOpenClawGateway(req, invocation, context, clientFactory, p
477
439
  unsubscribe();
478
440
  requestAbort.abort();
479
441
  closing = (async () => {
480
- if (cancel && agentAccepted)
442
+ if (cancel && agentDispatched)
481
443
  await client
482
444
  .request("sessions.abort", {
483
445
  key: providerSessionKey,
@@ -491,25 +453,74 @@ async function* invokeOpenClawGateway(req, invocation, context, clientFactory, p
491
453
  void closing.catch(() => undefined);
492
454
  return closing;
493
455
  };
494
- permissions.bindTransport(() => stop(!terminal));
456
+ let cancellation;
457
+ const confirmCancellation = () => {
458
+ cancellation ??= (async () => {
459
+ if (!agentDispatched)
460
+ return;
461
+ let recoveryClient;
462
+ try {
463
+ const abortParams = {
464
+ key: providerSessionKey,
465
+ runId: acceptedRunId,
466
+ agentId: invocation.agentId
467
+ };
468
+ let controlClient = client;
469
+ try {
470
+ await controlClient.request("sessions.abort", abortParams, { timeoutMs: 5_000 });
471
+ }
472
+ catch {
473
+ recoveryClient = clientFactory(invocation.gateway);
474
+ resolveGatewayContract(await recoveryClient.connect());
475
+ controlClient = recoveryClient;
476
+ await controlClient.request("sessions.abort", abortParams, { timeoutMs: 5_000 });
477
+ }
478
+ await waitForConfirmedTerminal(controlClient, acceptedRunId, "cancelled", Date.now() + 30_000);
479
+ terminal ??= "cancelled";
480
+ }
481
+ finally {
482
+ await recoveryClient?.close();
483
+ }
484
+ })();
485
+ return cancellation;
486
+ };
487
+ // 桥和执行循环可能同时收到取消;共用一次 abort/对账,确认后才关闭连接。
488
+ permissions.bindTransport(async () => {
489
+ if (req.signal?.aborted && !terminal) {
490
+ try {
491
+ await confirmCancellation();
492
+ }
493
+ catch {
494
+ // 执行源负责发出取消对账失败;清理桥不重复抛出同一错误。
495
+ }
496
+ finally {
497
+ await stop(false);
498
+ }
499
+ }
500
+ else
501
+ await stop(!terminal);
502
+ });
495
503
  const queue = new DriverQueue({
496
504
  discardOnFailure: true,
497
505
  limits: context?.streamLimits,
498
506
  boundary: "openclaw.event_queue",
499
- onFailure: () => {
500
- resourceFailure = true;
507
+ onFailure: (error) => {
508
+ if (req.signal?.aborted)
509
+ return;
510
+ resourceFailure = error;
501
511
  void stop(true);
502
512
  }
503
513
  });
504
514
  const iterator = queue[Symbol.asyncIterator]();
505
515
  let acceptedRunId = invocation.requestId;
516
+ let agentDispatched = false;
506
517
  let agentAccepted = false;
507
518
  const seenApprovals = new Set();
508
519
  const activeApprovals = new Map();
509
520
  let providerSessionKey = invocation.sessionKey;
510
521
  const routedApprovals = new Set();
511
522
  const acceptEvent = (event) => {
512
- if (closing)
523
+ if (closing || terminal)
513
524
  return;
514
525
  const payload = asRecord(event.payload);
515
526
  if (event.event === "agent") {
@@ -555,32 +566,98 @@ async function* invokeOpenClawGateway(req, invocation, context, clientFactory, p
555
566
  messages: new Map(),
556
567
  tools: new Set()
557
568
  };
569
+ // 原生终态和步骤收尾共用出口;旧等待失败不能覆盖已确认的结果或丢失步骤结束。
570
+ const terminalEvents = (outcome, message) => {
571
+ const events = [];
572
+ if (state.stepStarted && !state.stepFinished) {
573
+ state.stepFinished = true;
574
+ events.push({
575
+ protocolVersion: 2,
576
+ type: "model_step.finished",
577
+ payload: { stepId: state.stepId, status: canonicalTerminalStatus(outcome) }
578
+ });
579
+ }
580
+ events.push({
581
+ protocolVersion: 2,
582
+ type: "message.update",
583
+ payload: {
584
+ ...gatewayMessage(state, "final", state.assistantItemId),
585
+ role: "assistant",
586
+ status: outcome === "cancelled" ? "stopped" : outcome,
587
+ text: state.assistantText,
588
+ channel: "final"
589
+ }
590
+ });
591
+ if (outcome === "cancelled")
592
+ events.push({
593
+ protocolVersion: 2,
594
+ type: "run.cancelled",
595
+ payload: { reason: String(req.signal?.reason ?? "openclaw_aborted") }
596
+ });
597
+ else if (outcome === "completed")
598
+ events.push({ protocolVersion: 2, type: "run.completed", payload: {} });
599
+ else
600
+ events.push({
601
+ protocolVersion: 2,
602
+ type: "run.failed",
603
+ payload: {
604
+ message: message ?? "OpenClaw Gateway agent run failed",
605
+ adapterType: "openclaw"
606
+ }
607
+ });
608
+ return events;
609
+ };
558
610
  try {
559
611
  const hello = await client.connect();
560
- assertRuntimeGatewayContract(hello);
561
- if (req.approvalMode === "ask") {
562
- const features = asRecord(asRecord(hello)?.features);
563
- if (!Array.isArray(features?.methods) ||
564
- !features.methods.includes("exec.approval.resolve") ||
565
- !features.methods.includes("exec.approval.list") ||
566
- !Array.isArray(features.events) ||
567
- !features.events.includes("exec.approval.requested") ||
568
- !features.events.includes("exec.approval.resolved")) {
569
- throw new Error("APPROVAL_MODE_UNSUPPORTED: OpenClaw Gateway has no approval transport");
570
- }
571
- }
612
+ const contract = resolveGatewayContract(hello);
613
+ const policy = resolveGatewayPermission(contract, req.approvalMode);
614
+ permissions.options.effectiveApprovalMode = policy.effective;
615
+ // 参数在真实握手之后生成;probe 的版本快照不作为本次执行依据。
616
+ const createParams = gatewayCreateParams(contract, policy, invocation.createParams, invocation.requestId, invocation.agentParams.thinking);
617
+ if (policy.fallbackReason)
618
+ yield {
619
+ protocolVersion: 2,
620
+ type: "run.notice",
621
+ payload: {
622
+ noticeId: `${req.invocationId}:openclaw-permission`,
623
+ code: "provider_diagnostic",
624
+ severity: "warning",
625
+ params: {
626
+ adapter: "openclaw",
627
+ diagnosticId: `openclaw-compat-${randomUUID()}`,
628
+ category: "permission_fallback",
629
+ message: `OpenClaw ${contract.version}: requested ask; using full_access for this invocation (${policy.fallbackReason}).`
630
+ }
631
+ }
632
+ };
572
633
  await assertExistingAgent(client, invocation.agentId, req.signal);
573
- const created = asRecord(await client.request("sessions.create", invocation.createParams, {
634
+ const created = asRecord(await client.request("sessions.create", createParams, {
574
635
  timeoutMs: 30_000,
575
636
  signal: req.signal
576
637
  }));
577
- providerSessionKey = nonEmptyString(created?.key) ?? invocation.sessionKey;
638
+ const createdKey = nonEmptyString(created?.key);
639
+ if (!createdKey)
640
+ throw new Error("OpenClaw Gateway returned no created session key");
641
+ providerSessionKey = createdKey;
578
642
  invocation.agentParams.sessionKey = providerSessionKey;
643
+ if (contract.family === "legacy") {
644
+ const patched = asRecord(await client.request("sessions.patch", gatewayLegacyPermissionParams(providerSessionKey), {
645
+ timeoutMs: 10_000,
646
+ signal: req.signal
647
+ }));
648
+ const entry = asRecord(patched?.entry);
649
+ if (patched?.ok !== true ||
650
+ patched.key !== providerSessionKey ||
651
+ entry?.execSecurity !== "full" ||
652
+ entry.execAsk !== "off") {
653
+ throw new Error("OPENCLAW_PERMISSION_UNAVAILABLE: legacy session policy was not confirmed");
654
+ }
655
+ }
579
656
  await client.request("sessions.messages.subscribe", {
580
657
  key: providerSessionKey,
581
658
  agentId: invocation.agentId
582
659
  }, { timeoutMs: 10_000, signal: req.signal });
583
- if (req.approvalMode === "ask") {
660
+ if (policy.effective === "ask") {
584
661
  const pending = await client.request("exec.approval.list", {}, { timeoutMs: 10_000, signal: req.signal });
585
662
  if (!Array.isArray(pending))
586
663
  throw new Error("OpenClaw Gateway returned invalid pending approvals");
@@ -598,6 +675,9 @@ async function* invokeOpenClawGateway(req, invocation, context, clientFactory, p
598
675
  }
599
676
  }
600
677
  };
678
+ if (req.signal?.aborted)
679
+ throw new Error("OpenClaw invocation aborted before dispatch");
680
+ agentDispatched = true;
601
681
  const request = client.request("agent", invocation.agentParams, {
602
682
  expectFinal: true,
603
683
  timeoutMs: null,
@@ -612,18 +692,46 @@ async function* invokeOpenClawGateway(req, invocation, context, clientFactory, p
612
692
  void request.then((result) => queue.push({ done: true, result }), (error) => queue.push({ error: error instanceof Error ? error : new Error(String(error)) }));
613
693
  while (!terminal) {
614
694
  const next = await iterator.next();
695
+ if (terminal)
696
+ break;
615
697
  if (next.done)
616
698
  throw new Error("OpenClaw event queue closed before terminal");
617
699
  const item = next.value;
618
700
  if (item.error)
619
701
  throw item.error;
620
702
  if (item.done) {
621
- const reconciled = normalizeFinalResponse(item.result, state);
703
+ const reconciled = normalizeFinalResponse(item.result, state, acceptedRunId);
704
+ terminal = reconciled.terminal;
705
+ // 先保存原生终态,避免消费者在接收收尾事件时取消而覆盖真实结果。
622
706
  for (const event of reconciled.events)
623
707
  yield event;
624
- terminal = reconciled.terminal;
708
+ if (!terminal) {
709
+ const confirmed = await waitForConfirmedTerminal(client, acceptedRunId, undefined, invocation.reconciliationDeadlineAt);
710
+ if (resourceFailure)
711
+ throw resourceFailure;
712
+ terminal ??= confirmed;
713
+ if (!state.stepFinished) {
714
+ if (!state.stepStarted) {
715
+ state.stepStarted = true;
716
+ yield {
717
+ protocolVersion: 2,
718
+ type: "model_step.started",
719
+ payload: { stepId: state.stepId }
720
+ };
721
+ }
722
+ state.stepFinished = true;
723
+ yield {
724
+ protocolVersion: 2,
725
+ type: "model_step.finished",
726
+ payload: {
727
+ stepId: state.stepId,
728
+ status: canonicalTerminalStatus(terminal)
729
+ }
730
+ };
731
+ }
732
+ }
625
733
  if (terminal === "failed")
626
- throw new Error(reconciled.error);
734
+ throw new Error(reconciled.error ?? "OpenClaw Gateway agent run failed");
627
735
  break;
628
736
  }
629
737
  if (item.event?.event === "exec.approval.resolved") {
@@ -718,151 +826,58 @@ async function* invokeOpenClawGateway(req, invocation, context, clientFactory, p
718
826
  const runId = nonEmptyString(native?.runId);
719
827
  if (!runId || (runId !== acceptedRunId && runId !== invocation.requestId))
720
828
  continue;
829
+ const nativeTerminal = terminalState(item.event.payload);
830
+ if (nativeTerminal) {
831
+ const confirmed = await waitForConfirmedTerminal(client, runId, nativeTerminal, invocation.reconciliationDeadlineAt);
832
+ if (resourceFailure)
833
+ throw resourceFailure;
834
+ // await 期间取消任务可能先完成;较早发出的等待不能覆盖较新的确认。
835
+ terminal ??= confirmed;
836
+ if (terminal !== nativeTerminal)
837
+ break;
838
+ }
721
839
  const events = normalizeGatewayAgentEvent(item.event.payload, state);
722
840
  for (const event of events)
723
841
  yield event;
724
- terminal = terminalState(item.event.payload);
725
- if (terminal) {
726
- await waitForConfirmedTerminal(client, runId, terminal, invocation.reconciliationDeadlineAt);
727
- if (terminal === "failed")
728
- throw new Error(terminalError(item.event.payload));
729
- }
842
+ if (terminal === "failed")
843
+ throw new Error(terminalError(item.event.payload));
730
844
  }
731
- if (req.signal?.aborted || terminal === "cancelled") {
732
- yield {
733
- protocolVersion: 2,
734
- type: "message.update",
735
- payload: {
736
- ...gatewayMessage(state, "final", state.assistantItemId),
737
- role: "assistant",
738
- status: "stopped",
739
- text: state.assistantText,
740
- channel: "final"
741
- }
742
- };
743
- yield {
744
- protocolVersion: 2,
745
- type: "run.cancelled",
746
- payload: { reason: String(req.signal?.reason ?? "openclaw_aborted") }
747
- };
748
- return;
749
- }
750
- if (terminal !== "completed")
845
+ if (resourceFailure)
846
+ throw resourceFailure;
847
+ if (terminal !== "completed" && terminal !== "cancelled")
751
848
  throw new Error("OpenClaw Gateway stream ended without a terminal lifecycle event");
752
- yield {
753
- protocolVersion: 2,
754
- type: "message.update",
755
- payload: {
756
- ...gatewayMessage(state, "final", state.assistantItemId),
757
- role: "assistant",
758
- status: "completed",
759
- text: state.assistantText,
760
- channel: "final"
761
- }
762
- };
763
- yield { protocolVersion: 2, type: "run.completed", payload: {} };
849
+ yield* terminalEvents(terminal);
764
850
  }
765
851
  catch (error) {
766
- if (req.signal?.aborted) {
767
- if (!agentAccepted) {
768
- yield {
769
- protocolVersion: 2,
770
- type: "message.update",
771
- payload: {
772
- ...gatewayMessage(state, "final", state.assistantItemId),
773
- role: "assistant",
774
- status: "stopped",
775
- text: state.assistantText,
776
- channel: "final"
777
- }
778
- };
779
- yield {
780
- protocolVersion: 2,
781
- type: "run.cancelled",
782
- payload: { reason: String(req.signal.reason ?? "openclaw_aborted_before_dispatch") }
783
- };
852
+ let message = resourceFailure?.message ?? (error instanceof Error ? error.message : String(error));
853
+ if (!resourceFailure && terminal) {
854
+ yield* terminalEvents(terminal, message);
855
+ return;
856
+ }
857
+ if (!resourceFailure && req.signal?.aborted) {
858
+ if (!agentDispatched) {
859
+ yield* terminalEvents("cancelled");
784
860
  return;
785
861
  }
786
- let recoveryClient;
787
862
  try {
788
- const abortParams = {
789
- key: providerSessionKey,
790
- runId: acceptedRunId,
791
- agentId: invocation.agentId
792
- };
793
- let controlClient = client;
794
- try {
795
- await controlClient.request("sessions.abort", abortParams, { timeoutMs: 5_000 });
796
- }
797
- catch {
798
- recoveryClient = clientFactory(invocation.gateway);
799
- assertRuntimeGatewayContract(await recoveryClient.connect());
800
- controlClient = recoveryClient;
801
- await controlClient.request("sessions.abort", abortParams, { timeoutMs: 5_000 });
802
- }
803
- await waitForConfirmedTerminal(controlClient, acceptedRunId, "cancelled", Date.now() + 30_000);
804
- yield {
805
- protocolVersion: 2,
806
- type: "message.update",
807
- payload: {
808
- ...gatewayMessage(state, "final", state.assistantItemId),
809
- role: "assistant",
810
- status: "stopped",
811
- text: state.assistantText,
812
- channel: "final"
813
- }
814
- };
815
- yield {
816
- protocolVersion: 2,
817
- type: "run.cancelled",
818
- payload: { reason: String(req.signal.reason ?? "openclaw_aborted") }
819
- };
863
+ await confirmCancellation();
820
864
  }
821
865
  catch (abortError) {
822
- const message = abortError instanceof Error
823
- ? abortError.message
824
- : "OpenClaw Gateway abort confirmation failed";
825
- yield {
826
- protocolVersion: 2,
827
- type: "message.update",
828
- payload: {
829
- ...gatewayMessage(state, "final", state.assistantItemId),
830
- role: "assistant",
831
- status: "failed",
832
- text: state.assistantText,
833
- channel: "final"
834
- }
835
- };
836
- yield {
837
- protocolVersion: 2,
838
- type: "run.failed",
839
- payload: { message, adapterType: "openclaw" }
840
- };
841
- }
842
- finally {
843
- await recoveryClient?.close();
866
+ message =
867
+ abortError instanceof Error
868
+ ? abortError.message
869
+ : "OpenClaw Gateway abort confirmation failed";
844
870
  }
871
+ yield* terminalEvents(terminal ?? "failed", message);
845
872
  return;
846
873
  }
847
- let message = error instanceof Error ? error.message : String(error);
848
- if (!resourceFailure && agentAccepted && terminal !== "failed" && terminal !== "cancelled") {
874
+ if (!resourceFailure && agentAccepted) {
849
875
  const recoveryClient = clientFactory(invocation.gateway);
850
876
  try {
851
- assertRuntimeGatewayContract(await recoveryClient.connect());
852
- await waitForConfirmedTerminal(recoveryClient, acceptedRunId, "completed", invocation.reconciliationDeadlineAt);
853
- yield {
854
- protocolVersion: 2,
855
- type: "message.update",
856
- payload: {
857
- ...gatewayMessage(state, "final", state.assistantItemId),
858
- role: "assistant",
859
- status: "completed",
860
- text: state.assistantText,
861
- channel: "final"
862
- }
863
- };
864
- yield { protocolVersion: 2, type: "run.completed", payload: {} };
865
- return;
877
+ resolveGatewayContract(await recoveryClient.connect());
878
+ const confirmed = await waitForConfirmedTerminal(recoveryClient, acceptedRunId, undefined, invocation.reconciliationDeadlineAt);
879
+ terminal ??= confirmed;
880
+ message = `OpenClaw Gateway confirmed a failed run after disconnect: ${message}`;
866
881
  }
867
882
  catch (recoveryError) {
868
883
  const detail = recoveryError instanceof Error ? recoveryError.message : "unknown reconciliation failure";
@@ -872,18 +887,7 @@ async function* invokeOpenClawGateway(req, invocation, context, clientFactory, p
872
887
  await recoveryClient.close();
873
888
  }
874
889
  }
875
- yield {
876
- protocolVersion: 2,
877
- type: "message.update",
878
- payload: {
879
- ...gatewayMessage(state, "final", state.assistantItemId),
880
- role: "assistant",
881
- status: "failed",
882
- text: state.assistantText,
883
- channel: "final"
884
- }
885
- };
886
- yield { protocolVersion: 2, type: "run.failed", payload: { message, adapterType: "openclaw" } };
890
+ yield* terminalEvents(resourceFailure ? "failed" : (terminal ?? "failed"), resourceFailure?.message ?? message);
887
891
  }
888
892
  finally {
889
893
  req.signal?.removeEventListener("abort", onAbort);
@@ -900,7 +904,7 @@ export function createOpenClawAdapter({ clientFactory = (options) => new OpenCla
900
904
  let client;
901
905
  try {
902
906
  client = clientFactory(await resolveOpenClawGateway(options?.providerOptions));
903
- assertRuntimeGatewayContract(await client.connect());
907
+ resolveGatewayContract(await client.connect());
904
908
  await client.request("agents.list", {});
905
909
  return { available: true, command: "openclaw-gateway" };
906
910
  }
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@mininglamp-oss/octo-runtime-adapter-openclaw",
3
- "version": "1.1.0",
3
+ "version": "1.1.2",
4
4
  "private": true,
5
5
  "type": "module",
6
6
  "exports": "./dist/index.js",
7
7
  "dependencies": {
8
- "@mininglamp-oss/octo-runtime-protocol": "1.1.0",
9
- "@mininglamp-oss/octo-runtime-adapter-sdk": "1.1.0",
8
+ "@mininglamp-oss/octo-runtime-protocol": "1.1.2",
9
+ "@mininglamp-oss/octo-runtime-adapter-sdk": "1.1.2",
10
10
  "ws": "8.22.0"
11
11
  },
12
12
  "types": "./dist/index.d.ts",