@mininglamp-oss/octo-runtime 1.1.1 → 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 (54) hide show
  1. package/apps/cli/dist/build-info.json +2 -2
  2. package/apps/cli/dist/manifest.json +5 -0
  3. package/node_modules/@mininglamp-oss/octo-runtime-acp-client/package.json +3 -3
  4. package/node_modules/@mininglamp-oss/octo-runtime-adapter-acp/package.json +4 -4
  5. package/node_modules/@mininglamp-oss/octo-runtime-adapter-antigravity/package.json +3 -3
  6. package/node_modules/@mininglamp-oss/octo-runtime-adapter-claude-code/package.json +3 -3
  7. package/node_modules/@mininglamp-oss/octo-runtime-adapter-codebuddy/package.json +4 -4
  8. package/node_modules/@mininglamp-oss/octo-runtime-adapter-codex/package.json +3 -3
  9. package/node_modules/@mininglamp-oss/octo-runtime-adapter-grok-build/dist/adapter.d.ts +54 -0
  10. package/node_modules/@mininglamp-oss/octo-runtime-adapter-grok-build/dist/adapter.js +399 -0
  11. package/node_modules/@mininglamp-oss/octo-runtime-adapter-grok-build/dist/client.d.ts +14 -0
  12. package/node_modules/@mininglamp-oss/octo-runtime-adapter-grok-build/dist/client.js +156 -0
  13. package/node_modules/@mininglamp-oss/octo-runtime-adapter-grok-build/dist/index.d.ts +29 -0
  14. package/node_modules/@mininglamp-oss/octo-runtime-adapter-grok-build/dist/index.js +273 -0
  15. package/node_modules/@mininglamp-oss/octo-runtime-adapter-grok-build/dist/interactions.d.ts +27 -0
  16. package/node_modules/@mininglamp-oss/octo-runtime-adapter-grok-build/dist/interactions.js +161 -0
  17. package/node_modules/@mininglamp-oss/octo-runtime-adapter-grok-build/package.json +17 -0
  18. package/node_modules/@mininglamp-oss/octo-runtime-adapter-hermes/package.json +2 -2
  19. package/node_modules/@mininglamp-oss/octo-runtime-adapter-kimi-code/package.json +2 -2
  20. package/node_modules/@mininglamp-oss/octo-runtime-adapter-mcode/package.json +2 -2
  21. package/node_modules/@mininglamp-oss/octo-runtime-adapter-openclaw/dist/compatibility.d.ts +24 -0
  22. package/node_modules/@mininglamp-oss/octo-runtime-adapter-openclaw/dist/compatibility.js +181 -0
  23. package/node_modules/@mininglamp-oss/octo-runtime-adapter-openclaw/dist/gateway.d.ts +9 -0
  24. package/node_modules/@mininglamp-oss/octo-runtime-adapter-openclaw/dist/gateway.js +24 -8
  25. package/node_modules/@mininglamp-oss/octo-runtime-adapter-openclaw/dist/index.js +229 -225
  26. package/node_modules/@mininglamp-oss/octo-runtime-adapter-openclaw/package.json +3 -3
  27. package/node_modules/@mininglamp-oss/octo-runtime-adapter-opencode/package.json +4 -4
  28. package/node_modules/@mininglamp-oss/octo-runtime-adapter-qodercli/package.json +2 -2
  29. package/node_modules/@mininglamp-oss/octo-runtime-adapter-qoderclicn/package.json +2 -2
  30. package/node_modules/@mininglamp-oss/octo-runtime-adapter-sdk/dist/approval.d.ts +4 -0
  31. package/node_modules/@mininglamp-oss/octo-runtime-adapter-sdk/dist/approval.js +5 -6
  32. package/node_modules/@mininglamp-oss/octo-runtime-adapter-sdk/package.json +2 -2
  33. package/node_modules/@mininglamp-oss/octo-runtime-adapter-zcode-gui/package.json +3 -3
  34. package/node_modules/@mininglamp-oss/octo-runtime-cli/dist/build-info.json +2 -2
  35. package/node_modules/@mininglamp-oss/octo-runtime-cli/dist/manifest.json +5 -0
  36. package/node_modules/@mininglamp-oss/octo-runtime-cli/package.json +23 -22
  37. package/node_modules/@mininglamp-oss/octo-runtime-cross-service/package.json +1 -1
  38. package/node_modules/@mininglamp-oss/octo-runtime-executor-core/dist/model-input.d.ts +1 -1
  39. package/node_modules/@mininglamp-oss/octo-runtime-executor-core/dist/model-input.js +13 -9
  40. package/node_modules/@mininglamp-oss/octo-runtime-executor-core/package.json +3 -3
  41. package/node_modules/@mininglamp-oss/octo-runtime-executor-kernel/package.json +4 -4
  42. package/node_modules/@mininglamp-oss/octo-runtime-extra-channel-gateway/dist/application/im-channel.js +2 -1
  43. package/node_modules/@mininglamp-oss/octo-runtime-extra-channel-gateway/dist/contracts.d.ts +1 -0
  44. package/node_modules/@mininglamp-oss/octo-runtime-extra-channel-gateway/dist/execution/dispatcher.js +24 -0
  45. package/node_modules/@mininglamp-oss/octo-runtime-extra-channel-gateway/dist/transport/contexts.js +2 -2
  46. package/node_modules/@mininglamp-oss/octo-runtime-extra-channel-gateway/dist/transport/mentions.d.ts +5 -2
  47. package/node_modules/@mininglamp-oss/octo-runtime-extra-channel-gateway/dist/transport/mentions.js +19 -5
  48. package/node_modules/@mininglamp-oss/octo-runtime-extra-channel-gateway/dist/transport/normalize.js +1 -0
  49. package/node_modules/@mininglamp-oss/octo-runtime-extra-channel-gateway/package.json +6 -6
  50. package/node_modules/@mininglamp-oss/octo-runtime-extra-channel-wecom/package.json +5 -5
  51. package/node_modules/@mininglamp-oss/octo-runtime-extra-webui/package.json +2 -2
  52. package/node_modules/@mininglamp-oss/octo-runtime-host-sdk/package.json +4 -4
  53. package/node_modules/@mininglamp-oss/octo-runtime-protocol/package.json +1 -1
  54. package/package.json +27 -25
@@ -0,0 +1,156 @@
1
+ import { AcpClient } from "@mininglamp-oss/octo-runtime-acp-client";
2
+ import { INVOKE_REQUEST_MAX_BYTES } from "@mininglamp-oss/octo-runtime-protocol";
3
+ import { spawn } from "node:child_process";
4
+ import { createInterface } from "node:readline";
5
+ export class GrokBuildRpcError extends Error {
6
+ code;
7
+ data;
8
+ constructor(error) {
9
+ super(typeof error.message === "string" ? error.message : "Grok Build ACP request failed");
10
+ this.code = error.code;
11
+ this.data = error.data;
12
+ }
13
+ }
14
+ /** 标准 RPC 和更新队列沿用通用客户端;此实例只补充 Grok Build 的反向请求和错误信息。 */
15
+ class GrokBuildAcpClient extends AcpClient {
16
+ child;
17
+ options;
18
+ #rpcErrors = new Map();
19
+ #activeRequests = new Set();
20
+ #reader;
21
+ #stderr = "";
22
+ #disconnected = false;
23
+ #closing = false;
24
+ constructor(child, options) {
25
+ super({ ...options, child, processGroup: process.platform !== "win32" });
26
+ this.child = child;
27
+ this.options = options;
28
+ child.stderr.on("data", this.#captureStderr);
29
+ child.stdout.once("end", this.#disconnect);
30
+ this.#reader = createInterface({ input: child.stdout });
31
+ this.#reader.on("error", () => undefined);
32
+ this.#reader.on("line", (line) => {
33
+ // 通用客户端在解析前执行容量守卫;旁路观察器也不解析超过协议上限的帧。
34
+ if (Buffer.byteLength(line) > INVOKE_REQUEST_MAX_BYTES)
35
+ return;
36
+ let message;
37
+ try {
38
+ message = JSON.parse(line);
39
+ }
40
+ catch {
41
+ return;
42
+ }
43
+ if (!isRecord(message))
44
+ return;
45
+ if (typeof message.id === "number" && isRecord(message.error)) {
46
+ if (this.#activeRequests.has(message.id))
47
+ this.#rpcErrors.set(message.id, message.error);
48
+ return;
49
+ }
50
+ if ((typeof message.id !== "number" && typeof message.id !== "string") ||
51
+ typeof message.method !== "string" ||
52
+ message.method === "session/request_permission")
53
+ return;
54
+ const params = isRecord(message.params) ? message.params : {};
55
+ void Promise.resolve()
56
+ .then(() => {
57
+ if (!options.requestHandler)
58
+ throw new Error("GROK_CLIENT_METHOD_UNSUPPORTED");
59
+ return options.requestHandler(message.method, params);
60
+ })
61
+ .then((result) => this.#reply({ id: message.id, result }, params), () => this.#reply({
62
+ id: message.id,
63
+ error: { code: -32603, message: "Grok Build client request failed" }
64
+ }));
65
+ });
66
+ }
67
+ #captureStderr = (value) => {
68
+ this.#stderr = (this.#stderr + value.toString()).slice(-8192);
69
+ };
70
+ #disconnect = () => {
71
+ if (this.#closing)
72
+ return;
73
+ this.#disconnected = true;
74
+ setImmediate(() => {
75
+ void this.close().catch(() => undefined);
76
+ });
77
+ };
78
+ #reply(message, params) {
79
+ if (this.#closing)
80
+ return;
81
+ const failed = (error) => {
82
+ if (params)
83
+ this.options.onRequestResponseFailed?.(params, error);
84
+ void this.close().catch(() => undefined);
85
+ };
86
+ try {
87
+ this.child.stdin.write(`${JSON.stringify({ jsonrpc: "2.0", ...message })}\n`, (error) => {
88
+ if (error)
89
+ failed(error);
90
+ else if (params)
91
+ this.options.onRequestResponseWritten?.(params);
92
+ });
93
+ }
94
+ catch (error) {
95
+ failed(error instanceof Error ? error : new Error("Grok Build response delivery failed"));
96
+ }
97
+ }
98
+ async request(method, params, options = {}) {
99
+ const requestId = options.requestId ?? this.reserveRequestId();
100
+ this.#activeRequests.add(requestId);
101
+ try {
102
+ return await super.request(method, params, { ...options, requestId });
103
+ }
104
+ catch (error) {
105
+ const rpcError = this.#rpcErrors.get(requestId);
106
+ if (rpcError)
107
+ throw new GrokBuildRpcError(rpcError);
108
+ if (this.#disconnected && error instanceof Error && error.message === "ACP client closed")
109
+ throw new Error(this.#stderr.trim() || "ACP stdout disconnected", { cause: error });
110
+ throw error;
111
+ }
112
+ finally {
113
+ this.#activeRequests.delete(requestId);
114
+ this.#rpcErrors.delete(requestId);
115
+ }
116
+ }
117
+ close() {
118
+ this.#closing = true;
119
+ this.child.stdout.removeListener("end", this.#disconnect);
120
+ this.child.stderr.removeListener("data", this.#captureStderr);
121
+ this.#reader.close();
122
+ return super.close();
123
+ }
124
+ async *prompt(...args) {
125
+ try {
126
+ yield* super.prompt(...args);
127
+ }
128
+ catch (error) {
129
+ if (this.#disconnected && error instanceof Error && error.message === "ACP client closed")
130
+ throw new Error(this.#stderr.trim() || "ACP stdout disconnected", { cause: error });
131
+ throw error;
132
+ }
133
+ }
134
+ }
135
+ export function spawnGrokBuildAcpClient(options) {
136
+ const child = spawn(options.command, options.args ?? [], {
137
+ cwd: options.cwd,
138
+ env: { ...process.env, ...options.env },
139
+ stdio: ["pipe", "pipe", "pipe"],
140
+ detached: process.platform !== "win32"
141
+ });
142
+ const client = new GrokBuildAcpClient(child, options);
143
+ if (options.signal?.aborted)
144
+ void client.close().catch(() => undefined);
145
+ else if (options.signal) {
146
+ const abort = () => {
147
+ void client.close().catch(() => undefined);
148
+ };
149
+ options.signal.addEventListener("abort", abort, { once: true });
150
+ child.once("exit", () => options.signal?.removeEventListener("abort", abort));
151
+ }
152
+ return client;
153
+ }
154
+ function isRecord(value) {
155
+ return value !== null && typeof value === "object" && !Array.isArray(value);
156
+ }
@@ -0,0 +1,29 @@
1
+ import { spawnGrokBuildAcpClient } from "./client.js";
2
+ import { type CanonicalEvent, type InvokeRequest } from "@mininglamp-oss/octo-runtime-adapter-sdk";
3
+ import type { InteractionResponse } from "@mininglamp-oss/octo-runtime-protocol";
4
+ export declare const GROK_BUILD_TESTED_VERSION = "1.0.67";
5
+ /** 宿主可指定已安装命令;每次调用拥有独立 ACP 子进程,不连接用户常驻 leader。 */
6
+ export declare function createGrokBuildAdapter({ command, acpClientFactory }?: {
7
+ command?: string;
8
+ acpClientFactory?: typeof spawnGrokBuildAcpClient;
9
+ }): Readonly<{
10
+ invoke(request: InvokeRequest, context?: Parameters<(request: InvokeRequest, context?: import("@mininglamp-oss/octo-runtime-adapter-sdk").AdapterInvocationContext) => AsyncGenerator<CanonicalEvent>>[1]): AsyncGenerator<CanonicalEvent, void, any>;
11
+ metadata: {
12
+ mcp: true;
13
+ type: string;
14
+ agentSources: "provisioned"[];
15
+ };
16
+ probe: () => Promise<import("@mininglamp-oss/octo-runtime-adapter-sdk").ProbeResult>;
17
+ respondInteraction: (invocationId: string, response: InteractionResponse) => Promise<void>;
18
+ }>;
19
+ export declare const grokBuildAdapter: Readonly<{
20
+ invoke(request: InvokeRequest, context?: Parameters<(request: InvokeRequest, context?: import("@mininglamp-oss/octo-runtime-adapter-sdk").AdapterInvocationContext) => AsyncGenerator<CanonicalEvent>>[1]): AsyncGenerator<CanonicalEvent, void, any>;
21
+ metadata: {
22
+ mcp: true;
23
+ type: string;
24
+ agentSources: "provisioned"[];
25
+ };
26
+ probe: () => Promise<import("@mininglamp-oss/octo-runtime-adapter-sdk").ProbeResult>;
27
+ respondInteraction: (invocationId: string, response: InteractionResponse) => Promise<void>;
28
+ }>;
29
+ export default grokBuildAdapter;
@@ -0,0 +1,273 @@
1
+ import { GrokBuildRpcError, spawnGrokBuildAcpClient } from "./client.js";
2
+ import { createGrokBuildAcpAdapter } from "./adapter.js";
3
+ import { initialControlInstructions, invocationEnvironment, invocationMcpServers, probeCommand } from "@mininglamp-oss/octo-runtime-adapter-sdk";
4
+ export const GROK_BUILD_TESTED_VERSION = "1.0.67";
5
+ const levels = { low: "low", medium: "medium", high: "high", xhigh: "xhigh" };
6
+ function supportedVersion(version) {
7
+ if (typeof version !== "string")
8
+ return false;
9
+ const match = /^(\d+)\.(\d+)\.(\d+)$/.exec(version);
10
+ return !!match && Number(match[1]) === 1 && (Number(match[2]) > 0 || Number(match[3]) >= 67);
11
+ }
12
+ /** 宿主可指定已安装命令;每次调用拥有独立 ACP 子进程,不连接用户常驻 leader。 */
13
+ export function createGrokBuildAdapter({ command = "grok", acpClientFactory = spawnGrokBuildAcpClient } = {}) {
14
+ const adapter = createGrokBuildAcpAdapter({
15
+ type: "grok-build",
16
+ provider: "grok-build",
17
+ command,
18
+ args: ["--no-auto-update", "agent", "--no-leader", "stdio"],
19
+ controlInstructions: "session",
20
+ reasoningLevels: levels,
21
+ async probe() {
22
+ const result = await probeCommand(command);
23
+ if (!result.available)
24
+ return {
25
+ ...result,
26
+ reason: "command_not_found: install Grok Build and put grok on PATH"
27
+ };
28
+ return supportedVersion(result.version)
29
+ ? result
30
+ : {
31
+ ...result,
32
+ available: false,
33
+ reason: `grok_version_unsupported: install Grok Build ${GROK_BUILD_TESTED_VERSION} or a compatible 1.x release`
34
+ };
35
+ },
36
+ async initialize(client, init, _request, env) {
37
+ const version = record(init._meta).agentVersion ?? (await probeCommand(command, { env })).version;
38
+ if (init.protocolVersion !== 1 || !supportedVersion(version))
39
+ throw new Error(`GROK_VERSION_UNSUPPORTED: expected ACP v1 and Grok Build >= ${GROK_BUILD_TESTED_VERSION}, < 2.0.0`);
40
+ const methods = Array.isArray(init.authMethods)
41
+ ? init.authMethods.map((m) => record(m).id)
42
+ : [];
43
+ // 只按 harness 广告顺序协商非交互握手;凭据来源和可用性由 harness 判断。
44
+ const methodId = methods.find((id) => id === "xai.api_key" || id === "cached_token");
45
+ if (!methodId)
46
+ throw new Error("GROK_AUTH_REQUIRED: Grok Build did not advertise a supported non-interactive ACP authentication method; check the harness setup");
47
+ try {
48
+ await client.request("authenticate", { methodId, _meta: { headless: true } }, { timeoutMs: 30_000 });
49
+ }
50
+ catch {
51
+ throw new Error("GROK_AUTH_FAILED: Grok Build rejected ACP authentication; check the harness setup");
52
+ }
53
+ },
54
+ sessionParams(params, request, fresh) {
55
+ // 原生 rules 仅用于新会话;恢复不改系统指令,也不恢复工作区文件快照。
56
+ const rules = initialControlInstructions(request, fresh);
57
+ return {
58
+ ...params,
59
+ _meta: {
60
+ yoloMode: request.approvalMode === "full_access",
61
+ autoMode: false,
62
+ ...(fresh ? (rules ? { rules } : {}) : { "x.ai/restore_code": false })
63
+ }
64
+ };
65
+ },
66
+ isMissingSessionError: (error) => error instanceof GrokBuildRpcError &&
67
+ error.code === -32603 &&
68
+ record(error.data).code === "FS_NOT_FOUND",
69
+ selectActmode(_session, sessionId, requested) {
70
+ // 1.0.67 不发布 modes,但实现标准 set_mode(default/plan);成功响应后才发布 applied。
71
+ return {
72
+ method: "session/set_mode",
73
+ params: { sessionId, modeId: requested },
74
+ effective: requested,
75
+ nativeMode: requested,
76
+ unchanged: false
77
+ };
78
+ },
79
+ async *configureSession(client, session, sessionId, request) {
80
+ const requested = request.agentConfig.effort;
81
+ if (requested === undefined)
82
+ return;
83
+ const option = (Array.isArray(session.configOptions) ? session.configOptions : [])
84
+ .map(record)
85
+ .find((value) => value.id === "reasoning_effort");
86
+ const available = (Array.isArray(option?.options) ? option.options : []).map((value) => record(value).value);
87
+ const effective = available.includes(requested)
88
+ ? requested
89
+ : requested === "xhigh" && available.includes("high")
90
+ ? "high"
91
+ : undefined;
92
+ if (effective === undefined || effective !== requested)
93
+ yield reasoningWarning(request, effective === undefined ? "REASONING_EFFORT_NOT_APPLIED" : "REASONING_EFFORT_DOWNGRADED");
94
+ if (effective !== undefined && option?.currentValue !== effective) {
95
+ const result = record(await client.request("session/set_config_option", {
96
+ sessionId,
97
+ configId: "reasoning_effort",
98
+ value: effective
99
+ }));
100
+ const applied = (Array.isArray(result.configOptions) ? result.configOptions : [])
101
+ .map(record)
102
+ .find((value) => value.id === "reasoning_effort");
103
+ if (applied?.currentValue !== effective)
104
+ throw new Error("GROK_REASONING_UNCONFIRMED: provider did not confirm the requested effort");
105
+ }
106
+ },
107
+ clientOptions(_request, bridge) {
108
+ return {
109
+ requestHandler(method, original) {
110
+ // ACP 扩展仅给方法名加下划线,params 仍为原生请求正文。
111
+ const nativeMethod = method.startsWith("_") ? method.slice(1) : method;
112
+ const params = original;
113
+ if (nativeMethod === "x.ai/ask_user_question") {
114
+ const questions = questionFields(params.questions);
115
+ return bridge.requestQuestion(original, { questions }, (response) => questionResponse(questions, response));
116
+ }
117
+ if (nativeMethod === "x.ai/exit_plan_mode") {
118
+ return bridge.requestQuestion(original, {
119
+ questions: [
120
+ {
121
+ id: "decision",
122
+ question: typeof params.planContent === "string"
123
+ ? params.planContent
124
+ : "Review the plan",
125
+ options: [{ label: "Approve" }, { label: "Abandon" }]
126
+ }
127
+ ]
128
+ }, (response) => {
129
+ if (response.outcome === "cancelled")
130
+ return { outcome: "cancelled" };
131
+ const answer = answerValues(response, "decision");
132
+ if (answer.length !== 1 || !["Approve", "Abandon"].includes(answer[0]))
133
+ throw new Error("GROK_PLAN_RESPONSE_INVALID");
134
+ return { outcome: answer[0] === "Approve" ? "approved" : "abandoned" };
135
+ });
136
+ }
137
+ throw new Error("GROK_CLIENT_METHOD_UNSUPPORTED");
138
+ },
139
+ onRequestResponseWritten: (params) => bridge.responseWritten(params),
140
+ onRequestResponseFailed: (params, error) => bridge.responseFailed(params, error)
141
+ };
142
+ },
143
+ validatePromptResult(update) {
144
+ const meta = record(update._meta);
145
+ if (meta.completionKind !== undefined)
146
+ throw new Error("GROK_PROMPT_INCOMPLETE: prompt was removed from the provider queue");
147
+ if (!["end_turn", "cancelled"].includes(String(update.stopReason)))
148
+ throw new Error("GROK_PROMPT_INCOMPLETE: provider did not report end_turn");
149
+ const usage = record(meta.usage);
150
+ const payload = {};
151
+ for (const key of [
152
+ "inputTokens",
153
+ "outputTokens",
154
+ "totalTokens",
155
+ "cachedReadTokens",
156
+ "reasoningTokens"
157
+ ]) {
158
+ const value = usage[key] ?? meta[key];
159
+ if (typeof value === "number" && Number.isFinite(value) && value >= 0)
160
+ payload[key] = value;
161
+ }
162
+ if (typeof meta.modelId === "string")
163
+ payload.model = meta.modelId;
164
+ return Object.keys(payload).length
165
+ ? [{ protocolVersion: 2, type: "usage.update", payload }]
166
+ : [];
167
+ }
168
+ }, { command, acpClientFactory });
169
+ return Object.freeze({
170
+ ...adapter,
171
+ async *invoke(request, context) {
172
+ if (request.agentConfig.sandbox !== undefined)
173
+ throw new Error("SANDBOX_UNSUPPORTED: grok-build ACP has no per-session sandbox override");
174
+ // Grok 的 MCP 配置会展开模板;拒绝不能可靠保留的最终字面量,不改写用户配置。
175
+ const env = invocationEnvironment(request);
176
+ const mcp = invocationMcpServers(request, env);
177
+ if (JSON.stringify(mcp).includes("${"))
178
+ throw new Error("MCP_LITERAL_UNSUPPORTED: grok-build");
179
+ try {
180
+ yield* adapter.invoke(request, context);
181
+ }
182
+ catch (error) {
183
+ throw publicFailure(error, env);
184
+ }
185
+ }
186
+ });
187
+ }
188
+ function publicFailure(error, env) {
189
+ if (record(error).code === "ENOENT")
190
+ return new Error("GROK_START_FAILED: check Grok Build installation, PATH and invocation workdir");
191
+ // 原始 cause/stack 也可能含凭据,公开错误只保留脱敏消息,不挂回原始错误。
192
+ const secrets = Object.entries(env)
193
+ .filter(([key, value]) => value && /token|secret|password|api.?key/i.test(key))
194
+ .map(([, value]) => value)
195
+ .sort((left, right) => right.length - left.length);
196
+ let safe = error instanceof Error ? error.message : "Grok Build ACP invocation failed";
197
+ for (const secret of secrets)
198
+ safe = safe.split(secret).join("[REDACTED]");
199
+ const failure = new Error(safe);
200
+ const details = record(error);
201
+ if (typeof details.code === "string" && /^[A-Z][A-Z0-9_]*$/.test(details.code))
202
+ Object.assign(failure, { code: details.code });
203
+ for (const key of ["boundary", "measuredBytes", "limitBytes", "itemCount", "limitItems"]) {
204
+ const value = details[key];
205
+ if ((key === "boundary" && typeof value === "string" && /^[a-z0-9._-]+$/.test(value)) ||
206
+ (key !== "boundary" && typeof value === "number" && Number.isFinite(value)))
207
+ Object.assign(failure, { [key]: value });
208
+ }
209
+ return failure;
210
+ }
211
+ function reasoningWarning(request, warningCode) {
212
+ return {
213
+ protocolVersion: 2,
214
+ type: "run.notice",
215
+ payload: {
216
+ noticeId: `${request.invocationId}:grok-reasoning`,
217
+ code: "config_warning",
218
+ severity: "warning",
219
+ params: { warningCode }
220
+ }
221
+ };
222
+ }
223
+ function questionFields(value) {
224
+ if (!Array.isArray(value) || value.length === 0 || value.length > 16)
225
+ throw new Error("GROK_QUESTION_INVALID");
226
+ const seen = new Set();
227
+ return value.map((entry, index) => {
228
+ const question = record(entry);
229
+ if (typeof question.question !== "string" || !question.question || seen.has(question.question))
230
+ throw new Error("GROK_QUESTION_INVALID");
231
+ seen.add(question.question);
232
+ return { ...question, id: `q${index}` };
233
+ });
234
+ }
235
+ function answerValues(response, id) {
236
+ if (response.outcome !== "answered")
237
+ throw new Error("GROK_QUESTION_RESPONSE_INVALID");
238
+ const answers = record(record(response.value)[id]).answers;
239
+ if (!Array.isArray(answers) ||
240
+ answers.length === 0 ||
241
+ !answers.every((value) => typeof value === "string" && value.length > 0))
242
+ throw new Error("GROK_QUESTION_RESPONSE_INVALID");
243
+ return answers;
244
+ }
245
+ function questionResponse(questions, response) {
246
+ if (response.outcome === "cancelled")
247
+ return { outcome: "cancelled" };
248
+ const answers = {};
249
+ const annotations = {};
250
+ for (const question of questions) {
251
+ const values = answerValues(response, String(question.id));
252
+ const labels = (Array.isArray(question.options) ? question.options : []).map((option) => record(option).label);
253
+ const selected = values.filter((value) => labels.includes(value));
254
+ const custom = values.filter((value) => !labels.includes(value));
255
+ if (question.multiSelect !== true && values.length !== 1)
256
+ throw new Error("GROK_QUESTION_RESPONSE_INVALID");
257
+ answers[String(question.question)] = custom.length ? [...selected, "Other"] : selected;
258
+ if (custom.length)
259
+ annotations[String(question.question)] = { notes: custom.join("\n") };
260
+ }
261
+ return {
262
+ outcome: "accepted",
263
+ answers,
264
+ ...(Object.keys(annotations).length ? { annotations } : {})
265
+ };
266
+ }
267
+ function record(value) {
268
+ return value !== null && typeof value === "object" && !Array.isArray(value)
269
+ ? value
270
+ : {};
271
+ }
272
+ export const grokBuildAdapter = createGrokBuildAdapter();
273
+ export default grokBuildAdapter;
@@ -0,0 +1,27 @@
1
+ import { AcpApprovalBridge, type CanonicalEvent, type InvokeRequest } from "@mininglamp-oss/octo-runtime-adapter-sdk";
2
+ import type { InteractionResponse } from "@mininglamp-oss/octo-runtime-protocol";
3
+ type JsonRecord = Record<string, unknown>;
4
+ interface Question {
5
+ params: JsonRecord;
6
+ answer: (response: InteractionResponse) => JsonRecord;
7
+ resolve: (result: JsonRecord) => void;
8
+ reject: (error: Error) => void;
9
+ written: Promise<void>;
10
+ confirm: () => void;
11
+ fail: (error: Error) => void;
12
+ timer: NodeJS.Timeout;
13
+ expiresAt: number;
14
+ responding: boolean;
15
+ }
16
+ /** 标准权限沿用 SDK;原生追问和计划确认只存在于当前 Grok Build 调用。 */
17
+ export declare class GrokBuildInteractionBridge extends AcpApprovalBridge {
18
+ #private;
19
+ constructor(request: InvokeRequest);
20
+ requestQuestion(params: JsonRecord, request: JsonRecord, answer: Question["answer"]): Promise<JsonRecord>;
21
+ respond(response: InteractionResponse): Promise<void>;
22
+ responseWritten(params: JsonRecord): void;
23
+ responseFailed(params: JsonRecord, error: Error): void;
24
+ stream(source: AsyncIterable<CanonicalEvent>): AsyncGenerator<CanonicalEvent>;
25
+ close(reason: string): void;
26
+ }
27
+ export {};
@@ -0,0 +1,161 @@
1
+ import { AcpApprovalBridge, sanitizePublicValue } from "@mininglamp-oss/octo-runtime-adapter-sdk";
2
+ import { randomUUID } from "node:crypto";
3
+ /** 标准权限沿用 SDK;原生追问和计划确认只存在于当前 Grok Build 调用。 */
4
+ export class GrokBuildInteractionBridge extends AcpApprovalBridge {
5
+ #questions = new Map();
6
+ #events = [];
7
+ #wake;
8
+ #error;
9
+ #closed = false;
10
+ constructor(request) {
11
+ super(request);
12
+ }
13
+ requestQuestion(params, request, answer) {
14
+ if (this.#closed || this.request.signal?.aborted || this.#questions.size >= 16)
15
+ return Promise.reject(new Error("APPROVAL_WAIT_UNAVAILABLE"));
16
+ const interactionId = `interaction_${randomUUID()}`;
17
+ const expiresAt = Date.now() + this.timeoutMs;
18
+ let confirm;
19
+ let fail;
20
+ const written = new Promise((resolve, reject) => {
21
+ confirm = resolve;
22
+ fail = reject;
23
+ });
24
+ void written.catch(() => undefined);
25
+ const result = new Promise((resolve, reject) => {
26
+ const timer = setTimeout(() => {
27
+ this.#error = new Error("APPROVAL_EXPIRED");
28
+ this.#questions.delete(interactionId);
29
+ reject(this.#error);
30
+ fail(this.#error);
31
+ this.#resolved(interactionId, "expired", "approval_timeout");
32
+ }, this.timeoutMs);
33
+ timer.unref();
34
+ this.#questions.set(interactionId, {
35
+ params,
36
+ answer,
37
+ resolve,
38
+ reject,
39
+ written,
40
+ confirm,
41
+ fail,
42
+ timer,
43
+ expiresAt,
44
+ responding: false
45
+ });
46
+ });
47
+ this.#emit({
48
+ protocolVersion: 2,
49
+ type: "interaction.requested",
50
+ payload: {
51
+ interactionId,
52
+ kind: "question",
53
+ executionInstanceId: this.request.invocationId,
54
+ expiresAt: new Date(expiresAt).toISOString(),
55
+ request: sanitizePublicValue(request)
56
+ }
57
+ });
58
+ return result;
59
+ }
60
+ async respond(response) {
61
+ const pending = this.#questions.get(response.interactionId);
62
+ if (!pending)
63
+ return super.respond(response);
64
+ if (pending.responding || pending.expiresAt <= Date.now() || this.request.signal?.aborted)
65
+ throw new Error("INTERACTION_NOT_ACTIVE");
66
+ const result = pending.answer(response);
67
+ pending.responding = true;
68
+ pending.resolve(result);
69
+ await pending.written;
70
+ if (!this.#questions.has(response.interactionId) || this.#closed)
71
+ throw new Error("INTERACTION_NOT_ACTIVE");
72
+ clearTimeout(pending.timer);
73
+ this.#questions.delete(response.interactionId);
74
+ this.#emit({
75
+ protocolVersion: 2,
76
+ type: "interaction.resolved",
77
+ payload: {
78
+ interactionId: response.interactionId,
79
+ executionInstanceId: this.request.invocationId,
80
+ status: "resolved",
81
+ outcome: response.outcome
82
+ }
83
+ });
84
+ }
85
+ responseWritten(params) {
86
+ super.responseWritten(params);
87
+ for (const pending of this.#questions.values())
88
+ if (pending.params === params)
89
+ pending.confirm();
90
+ }
91
+ responseFailed(params, error) {
92
+ for (const pending of this.#questions.values())
93
+ if (pending.params === params)
94
+ pending.fail(error);
95
+ this.#error = error;
96
+ super.responseFailed(params, error);
97
+ this.#wake?.();
98
+ }
99
+ async *stream(source) {
100
+ const iterator = super.stream(source);
101
+ let next = iterator.next();
102
+ void next.catch(() => undefined);
103
+ try {
104
+ while (true) {
105
+ while (this.#events.length)
106
+ yield this.#events.shift();
107
+ if (this.#error)
108
+ throw this.#error;
109
+ const wake = new Promise((resolve) => {
110
+ this.#wake = () => resolve(null);
111
+ });
112
+ const result = await Promise.race([next, wake]);
113
+ this.#wake = undefined;
114
+ if (result === null)
115
+ continue;
116
+ while (this.#events.length)
117
+ yield this.#events.shift();
118
+ if (result.done)
119
+ return;
120
+ yield result.value;
121
+ next = iterator.next();
122
+ void next.catch(() => undefined);
123
+ }
124
+ }
125
+ catch (error) {
126
+ this.close("execution_lost");
127
+ while (this.#events.length)
128
+ yield this.#events.shift();
129
+ throw error;
130
+ }
131
+ finally {
132
+ this.close("execution_lost");
133
+ await iterator.return(undefined);
134
+ }
135
+ }
136
+ close(reason) {
137
+ super.close(reason);
138
+ if (this.#closed)
139
+ return;
140
+ this.#closed = true;
141
+ for (const [interactionId, pending] of this.#questions) {
142
+ clearTimeout(pending.timer);
143
+ const error = new Error("INTERACTION_NOT_ACTIVE");
144
+ pending.reject(error);
145
+ pending.fail(error);
146
+ this.#resolved(interactionId, "invalidated", reason);
147
+ }
148
+ this.#questions.clear();
149
+ }
150
+ #resolved(interactionId, status, reasonCode) {
151
+ this.#emit({
152
+ protocolVersion: 2,
153
+ type: "interaction.resolved",
154
+ payload: { interactionId, executionInstanceId: this.request.invocationId, status, reasonCode }
155
+ });
156
+ }
157
+ #emit(event) {
158
+ this.#events.push(event);
159
+ this.#wake?.();
160
+ }
161
+ }
@@ -0,0 +1,17 @@
1
+ {
2
+ "name": "@mininglamp-oss/octo-runtime-adapter-grok-build",
3
+ "version": "1.1.2",
4
+ "private": true,
5
+ "type": "module",
6
+ "exports": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "files": [
9
+ "dist"
10
+ ],
11
+ "dependencies": {
12
+ "@mininglamp-oss/octo-runtime-acp-client": "1.1.2",
13
+ "@mininglamp-oss/octo-runtime-adapter-acp": "1.1.2",
14
+ "@mininglamp-oss/octo-runtime-adapter-sdk": "1.1.2",
15
+ "@mininglamp-oss/octo-runtime-protocol": "1.1.2"
16
+ }
17
+ }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mininglamp-oss/octo-runtime-adapter-hermes",
3
- "version": "1.1.1",
3
+ "version": "1.1.2",
4
4
  "private": true,
5
5
  "type": "module",
6
6
  "exports": "./dist/index.js",
@@ -9,6 +9,6 @@
9
9
  "dist"
10
10
  ],
11
11
  "dependencies": {
12
- "@mininglamp-oss/octo-runtime-adapter-acp": "1.1.1"
12
+ "@mininglamp-oss/octo-runtime-adapter-acp": "1.1.2"
13
13
  }
14
14
  }