@ycodium-ai/agent-grok 0.2.2678 → 0.2.2694
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/README.md +11 -0
- package/dist/index.js +413 -122
- package/locales/en.json +5 -0
- package/locales/zh-CN.json +5 -0
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -47,6 +47,17 @@ Facts:
|
|
|
47
47
|
exist (the card's `extraEnv` `$absentPath` entry), unless the instance sets
|
|
48
48
|
`GROK_AUTH_PATH` itself. The login file in the account directory is left untouched.
|
|
49
49
|
Settings also gives a new instance that sets these variables its own account directory.
|
|
50
|
+
- Usage (ADR-0034), per instance, read only when the user asks:
|
|
51
|
+
- Quota: `ExecutorInstance.usage.readQuota` reads the weekly credit window from
|
|
52
|
+
`cli-chat-proxy.grok.com/v1/billing?format=credits` with the x.ai token in the instance's
|
|
53
|
+
account directory (only entries whose issuer starts with `https://auth.x.ai::`), through
|
|
54
|
+
`host.fetch`. An instance that sets `GROK_MODELS_BASE_URL` reports `customEndpoint` without
|
|
55
|
+
reading credentials; a signed-out instance with only `XAI_API_KEY` reports `unsupportedLogin`
|
|
56
|
+
(xAI's balance API needs a separate management key). Credentials are never refreshed or written.
|
|
57
|
+
- Tokens: no `readTokenUsage`. The turn's usage comes from the `session/prompt` reply's
|
|
58
|
+
`_meta.usage` and is booked on `turn.completed.payload.tokenUsage` (the host writes
|
|
59
|
+
`turn.usage`). The reply arrives a few milliseconds after `prompt_complete`, so
|
|
60
|
+
`turn.completed` waits up to 300 ms for it and carries no usage when it never comes.
|
|
50
61
|
|
|
51
62
|
Develop with `vp run --filter @ycodium-ai/agent-grok typecheck`, `build`, and `test`.
|
|
52
63
|
|
package/dist/index.js
CHANGED
|
@@ -156,7 +156,7 @@ var GROK_CARD = {
|
|
|
156
156
|
// src/grokInstance.ts
|
|
157
157
|
import * as NodeCrypto2 from "node:crypto";
|
|
158
158
|
import * as NodeOS2 from "node:os";
|
|
159
|
-
import * as
|
|
159
|
+
import * as NodePath4 from "node:path";
|
|
160
160
|
import { mergeLaunchEnv } from "@ycodium-ai/plugin-api/executor";
|
|
161
161
|
import { nodeStreamsFromHandle as nodeStreamsFromHandle2 } from "@ycodium-ai/plugin-api/process-stdin";
|
|
162
162
|
|
|
@@ -1429,14 +1429,14 @@ function codePointLength(str) {
|
|
|
1429
1429
|
const units = str.length;
|
|
1430
1430
|
if (!highSurrogate.test(str))
|
|
1431
1431
|
return units;
|
|
1432
|
-
let
|
|
1432
|
+
let count2 = units;
|
|
1433
1433
|
for (let i = 0; i < units - 1; i++) {
|
|
1434
1434
|
if ((str.charCodeAt(i) & 64512) === 55296 && (str.charCodeAt(i + 1) & 64512) === 56320) {
|
|
1435
|
-
|
|
1435
|
+
count2--;
|
|
1436
1436
|
i++;
|
|
1437
1437
|
}
|
|
1438
1438
|
}
|
|
1439
|
-
return
|
|
1439
|
+
return count2;
|
|
1440
1440
|
}
|
|
1441
1441
|
function getLengthableOrigin(input2) {
|
|
1442
1442
|
if (Array.isArray(input2))
|
|
@@ -5791,8 +5791,8 @@ function az_default() {
|
|
|
5791
5791
|
}
|
|
5792
5792
|
|
|
5793
5793
|
// ../../node_modules/.pnpm/zod@4.6.5/node_modules/zod/v4/locales/be.js
|
|
5794
|
-
function getBelarusianPlural(
|
|
5795
|
-
const absCount = Math.abs(
|
|
5794
|
+
function getBelarusianPlural(count2, one, few, many) {
|
|
5795
|
+
const absCount = Math.abs(count2);
|
|
5796
5796
|
const lastDigit = absCount % 10;
|
|
5797
5797
|
const lastTwoDigits = absCount % 100;
|
|
5798
5798
|
if (lastTwoDigits >= 11 && lastTwoDigits <= 19) {
|
|
@@ -8439,8 +8439,8 @@ function hu_default() {
|
|
|
8439
8439
|
}
|
|
8440
8440
|
|
|
8441
8441
|
// ../../node_modules/.pnpm/zod@4.6.5/node_modules/zod/v4/locales/hy.js
|
|
8442
|
-
function getArmenianPlural(
|
|
8443
|
-
return Math.abs(
|
|
8442
|
+
function getArmenianPlural(count2, one, many) {
|
|
8443
|
+
return Math.abs(count2) === 1 ? one : many;
|
|
8444
8444
|
}
|
|
8445
8445
|
function withDefiniteArticle(word) {
|
|
8446
8446
|
if (!word)
|
|
@@ -9524,8 +9524,8 @@ function ko_default() {
|
|
|
9524
9524
|
}
|
|
9525
9525
|
|
|
9526
9526
|
// ../../node_modules/.pnpm/zod@4.6.5/node_modules/zod/v4/locales/lt.js
|
|
9527
|
-
var capitalizeFirstCharacter = (
|
|
9528
|
-
return
|
|
9527
|
+
var capitalizeFirstCharacter = (text3) => {
|
|
9528
|
+
return text3.charAt(0).toUpperCase() + text3.slice(1);
|
|
9529
9529
|
};
|
|
9530
9530
|
function getUnitTypeFromNumber(number4) {
|
|
9531
9531
|
const abs = Math.abs(number4);
|
|
@@ -11178,8 +11178,8 @@ function ro_default() {
|
|
|
11178
11178
|
}
|
|
11179
11179
|
|
|
11180
11180
|
// ../../node_modules/.pnpm/zod@4.6.5/node_modules/zod/v4/locales/ru.js
|
|
11181
|
-
function getRussianPlural(
|
|
11182
|
-
const absCount = Math.abs(
|
|
11181
|
+
function getRussianPlural(count2, one, few, many) {
|
|
11182
|
+
const absCount = Math.abs(count2);
|
|
11183
11183
|
const lastDigit = absCount % 10;
|
|
11184
11184
|
const lastTwoDigits = absCount % 100;
|
|
11185
11185
|
if (lastTwoDigits >= 11 && lastTwoDigits <= 19) {
|
|
@@ -22120,9 +22120,9 @@ var Connection = class {
|
|
|
22120
22120
|
return;
|
|
22121
22121
|
}
|
|
22122
22122
|
const responseBatch = isResponseBatch(batch);
|
|
22123
|
-
const responseCount = responseBatch ? 0 : batch.reduce((
|
|
22123
|
+
const responseCount = responseBatch ? 0 : batch.reduce((count2, message) => count2 + (isNotificationMessage(message) ? 0 : 1), 0);
|
|
22124
22124
|
let remaining = responseCount;
|
|
22125
|
-
let remainingNotifications = batch.reduce((
|
|
22125
|
+
let remainingNotifications = batch.reduce((count2, message) => count2 + (isNotificationMessage(message) ? 1 : 0), 0);
|
|
22126
22126
|
let responseSent = false;
|
|
22127
22127
|
const responses = [];
|
|
22128
22128
|
const sendResponsesIfReady = async () => {
|
|
@@ -23934,8 +23934,8 @@ function createAcpConnection(options) {
|
|
|
23934
23934
|
}
|
|
23935
23935
|
await dispatchMessage(value);
|
|
23936
23936
|
};
|
|
23937
|
-
const pullEnqueued = async (
|
|
23938
|
-
for (let i = 0; i <
|
|
23937
|
+
const pullEnqueued = async (count2) => {
|
|
23938
|
+
for (let i = 0; i < count2; i += 1) {
|
|
23939
23939
|
const { value, done } = await incoming.read();
|
|
23940
23940
|
if (done || value === void 0) {
|
|
23941
23941
|
return;
|
|
@@ -24937,6 +24937,13 @@ function parseSessionModeState(sessionResponse) {
|
|
|
24937
24937
|
availableModes
|
|
24938
24938
|
};
|
|
24939
24939
|
}
|
|
24940
|
+
function acpCommandsToSlashCommands(commands) {
|
|
24941
|
+
return commands.map((command) => ({
|
|
24942
|
+
name: command.name,
|
|
24943
|
+
...command.description === void 0 ? {} : { description: command.description },
|
|
24944
|
+
...command.inputHint === void 0 ? {} : { input: { hint: command.inputHint } }
|
|
24945
|
+
}));
|
|
24946
|
+
}
|
|
24940
24947
|
function parseAvailableCommandsUpdate(params) {
|
|
24941
24948
|
const update = params.update;
|
|
24942
24949
|
if (update["sessionUpdate"] !== "available_commands_update") {
|
|
@@ -25036,11 +25043,11 @@ function extractToolCallCommand(rawInput, title) {
|
|
|
25036
25043
|
}
|
|
25037
25044
|
var TOOL_CALL_CONTENT_MAX_CHARS = 8e3;
|
|
25038
25045
|
var TOOL_CALL_CONTENT_TRUNCATION_MARKER = "[Earlier output truncated]\n\n";
|
|
25039
|
-
function boundToolCallOutputText(
|
|
25040
|
-
if (
|
|
25041
|
-
return
|
|
25046
|
+
function boundToolCallOutputText(text3) {
|
|
25047
|
+
if (text3.length <= TOOL_CALL_CONTENT_MAX_CHARS) {
|
|
25048
|
+
return text3;
|
|
25042
25049
|
}
|
|
25043
|
-
const tail =
|
|
25050
|
+
const tail = text3.slice(text3.length - TOOL_CALL_CONTENT_MAX_CHARS);
|
|
25044
25051
|
return `${TOOL_CALL_CONTENT_TRUNCATION_MARKER}${tail}`;
|
|
25045
25052
|
}
|
|
25046
25053
|
var RAW_OUTPUT_TEXT_FIELDS = ["content", "stdout", "stderr", "output"];
|
|
@@ -25072,9 +25079,9 @@ function extractTextContentFromToolCallContent(content) {
|
|
|
25072
25079
|
const typed = content;
|
|
25073
25080
|
const chunks = [];
|
|
25074
25081
|
for (const entry of typed) {
|
|
25075
|
-
const
|
|
25076
|
-
if (
|
|
25077
|
-
chunks.push(
|
|
25082
|
+
const text3 = toolCallContentText(entry)?.trim();
|
|
25083
|
+
if (text3) {
|
|
25084
|
+
chunks.push(text3);
|
|
25078
25085
|
}
|
|
25079
25086
|
}
|
|
25080
25087
|
if (chunks.length === 0) {
|
|
@@ -25325,11 +25332,11 @@ function parseSessionUpdateEvent(params) {
|
|
|
25325
25332
|
const contentType = content?.["type"];
|
|
25326
25333
|
const streamKind = kind === "agent_thought_chunk" ? "reasoning_text" : "assistant_text";
|
|
25327
25334
|
if (contentType === "text") {
|
|
25328
|
-
const
|
|
25329
|
-
if (
|
|
25335
|
+
const text3 = typeof content?.["text"] === "string" ? content["text"] : "";
|
|
25336
|
+
if (text3.length > 0) {
|
|
25330
25337
|
events.push({
|
|
25331
25338
|
_tag: "ContentDelta",
|
|
25332
|
-
text:
|
|
25339
|
+
text: text3,
|
|
25333
25340
|
streamKind,
|
|
25334
25341
|
rawPayload: params
|
|
25335
25342
|
});
|
|
@@ -25362,9 +25369,9 @@ function parseSessionUpdateEvent(params) {
|
|
|
25362
25369
|
case "compaction_summary_chunk": {
|
|
25363
25370
|
const compactionId = readAcpText(upd, "compactionId");
|
|
25364
25371
|
const content = isRecord5(upd["content"]) ? upd["content"] : void 0;
|
|
25365
|
-
const
|
|
25366
|
-
if (compactionId === void 0 || typeof
|
|
25367
|
-
events.push({ _tag: "CompactionSummaryChunk", compactionId, text:
|
|
25372
|
+
const text3 = content?.["type"] === "text" ? content["text"] : void 0;
|
|
25373
|
+
if (compactionId === void 0 || typeof text3 !== "string" || text3.length === 0) break;
|
|
25374
|
+
events.push({ _tag: "CompactionSummaryChunk", compactionId, text: text3 });
|
|
25368
25375
|
break;
|
|
25369
25376
|
}
|
|
25370
25377
|
default:
|
|
@@ -25388,24 +25395,7 @@ function filterMcpServersByAgentCapabilities(mcpServers, agentCapabilities) {
|
|
|
25388
25395
|
});
|
|
25389
25396
|
}
|
|
25390
25397
|
|
|
25391
|
-
// ../../packages/ycodium-acp-executor/src/
|
|
25392
|
-
var defaultVendorHooks = {
|
|
25393
|
-
completedStopReason: (response) => response.stopReason
|
|
25394
|
-
};
|
|
25395
|
-
|
|
25396
|
-
// ../../packages/ycodium-acp-executor/src/executor.ts
|
|
25397
|
-
var DEFAULT_CANCEL_GRACE_MS = 5e3;
|
|
25398
|
-
var userInputAnswerOptionId = (question, answers) => {
|
|
25399
|
-
const answer = answers[question.id];
|
|
25400
|
-
const selected = typeof answer === "string" ? answer : Array.isArray(answer) && answer.length === 1 && typeof answer[0] === "string" ? answer[0] : void 0;
|
|
25401
|
-
return selected !== void 0 && question.options.some((option) => option.id === selected) ? selected : void 0;
|
|
25402
|
-
};
|
|
25403
|
-
function defaultNowIso() {
|
|
25404
|
-
return (/* @__PURE__ */ new Date()).toISOString();
|
|
25405
|
-
}
|
|
25406
|
-
function defaultRandomId() {
|
|
25407
|
-
return NodeCrypto.randomUUID();
|
|
25408
|
-
}
|
|
25398
|
+
// ../../packages/ycodium-acp-executor/src/model-selection.ts
|
|
25409
25399
|
function normalizeModelId(value) {
|
|
25410
25400
|
return value?.trim() || void 0;
|
|
25411
25401
|
}
|
|
@@ -25424,6 +25414,25 @@ function modelSelectionStateFromSetup(setup) {
|
|
|
25424
25414
|
advertisedModelValues: strategy === "config-option" ? modelConfigOption === void 0 ? [] : collectSessionConfigOptionValues(modelConfigOption) : collectSessionModelIds(sessionModels)
|
|
25425
25415
|
};
|
|
25426
25416
|
}
|
|
25417
|
+
|
|
25418
|
+
// ../../packages/ycodium-acp-executor/src/vendor-hooks.ts
|
|
25419
|
+
var defaultVendorHooks = {
|
|
25420
|
+
completedStopReason: (response) => response.stopReason
|
|
25421
|
+
};
|
|
25422
|
+
|
|
25423
|
+
// ../../packages/ycodium-acp-executor/src/executor.ts
|
|
25424
|
+
var DEFAULT_CANCEL_GRACE_MS = 5e3;
|
|
25425
|
+
var userInputAnswerOptionId = (question, answers) => {
|
|
25426
|
+
const answer = answers[question.id];
|
|
25427
|
+
const selected = typeof answer === "string" ? answer : Array.isArray(answer) && answer.length === 1 && typeof answer[0] === "string" ? answer[0] : void 0;
|
|
25428
|
+
return selected !== void 0 && question.options.some((option) => option.id === selected) ? selected : void 0;
|
|
25429
|
+
};
|
|
25430
|
+
function defaultNowIso() {
|
|
25431
|
+
return (/* @__PURE__ */ new Date()).toISOString();
|
|
25432
|
+
}
|
|
25433
|
+
function defaultRandomId() {
|
|
25434
|
+
return NodeCrypto.randomUUID();
|
|
25435
|
+
}
|
|
25427
25436
|
function createAcpExecutor(options) {
|
|
25428
25437
|
const hooks = { ...defaultVendorHooks, ...options.hooks };
|
|
25429
25438
|
const cancelGraceMs = options.cancelGraceMs ?? DEFAULT_CANCEL_GRACE_MS;
|
|
@@ -25633,6 +25642,7 @@ function createAcpExecutor(options) {
|
|
|
25633
25642
|
const commands = parseAvailableCommandsUpdate(params);
|
|
25634
25643
|
if (commands !== void 0) {
|
|
25635
25644
|
availableCommands = commands;
|
|
25645
|
+
options.onAvailableCommands?.(commands);
|
|
25636
25646
|
}
|
|
25637
25647
|
if (sessionLoadInFlight) {
|
|
25638
25648
|
droppedReplayUpdates += parsed.events.filter((event) => event._tag !== "ModeChanged").length;
|
|
@@ -26748,13 +26758,13 @@ function parseCliVersion(output2) {
|
|
|
26748
26758
|
}
|
|
26749
26759
|
async function collectCappedText(stream, maxBytes) {
|
|
26750
26760
|
const decoder = new TextDecoder();
|
|
26751
|
-
let
|
|
26761
|
+
let text3 = "";
|
|
26752
26762
|
let total = 0;
|
|
26753
26763
|
for await (const chunk of stream) {
|
|
26754
26764
|
total += chunk.byteLength;
|
|
26755
|
-
if (total <= maxBytes)
|
|
26765
|
+
if (total <= maxBytes) text3 += decoder.decode(chunk, { stream: true });
|
|
26756
26766
|
}
|
|
26757
|
-
return { text:
|
|
26767
|
+
return { text: text3 + decoder.decode(), overflowed: total > maxBytes };
|
|
26758
26768
|
}
|
|
26759
26769
|
async function collectProbeProcess(child, input2) {
|
|
26760
26770
|
try {
|
|
@@ -26975,6 +26985,233 @@ var readGrokAccount = (homePath) => {
|
|
|
26975
26985
|
};
|
|
26976
26986
|
};
|
|
26977
26987
|
|
|
26988
|
+
// src/grokQuota.ts
|
|
26989
|
+
import * as NodeFS2 from "node:fs";
|
|
26990
|
+
import * as NodePath2 from "node:path";
|
|
26991
|
+
import {
|
|
26992
|
+
parseRetryAfterMs
|
|
26993
|
+
} from "@ycodium-ai/plugin-api/usage";
|
|
26994
|
+
var GROK_USAGE_URL = "https://cli-chat-proxy.grok.com/v1/billing?format=credits";
|
|
26995
|
+
var GROK_ISSUER_PREFIX = "https://auth.x.ai::";
|
|
26996
|
+
var AUTH_FILE_NAME2 = "auth.json";
|
|
26997
|
+
var QUOTA_TIMEOUT_MS = 1e4;
|
|
26998
|
+
var asObject = (value) => typeof value === "object" && value !== null && !Array.isArray(value) ? value : null;
|
|
26999
|
+
var asString3 = (value) => typeof value === "string" && value.length > 0 ? value : null;
|
|
27000
|
+
var asNumber = (value) => typeof value === "number" && Number.isFinite(value) ? value : null;
|
|
27001
|
+
var parseJson = (raw) => {
|
|
27002
|
+
try {
|
|
27003
|
+
return JSON.parse(raw);
|
|
27004
|
+
} catch {
|
|
27005
|
+
return null;
|
|
27006
|
+
}
|
|
27007
|
+
};
|
|
27008
|
+
var extractGrokToken = (auth) => {
|
|
27009
|
+
const record3 = asObject(auth);
|
|
27010
|
+
if (record3 === null) return null;
|
|
27011
|
+
for (const [key, value] of Object.entries(record3)) {
|
|
27012
|
+
if (!key.startsWith(GROK_ISSUER_PREFIX)) continue;
|
|
27013
|
+
const nestedKey = asString3(asObject(value)?.["key"]);
|
|
27014
|
+
if (nestedKey !== null) return nestedKey;
|
|
27015
|
+
}
|
|
27016
|
+
return null;
|
|
27017
|
+
};
|
|
27018
|
+
var clampPercent = (value) => Math.min(100, Math.max(0, value));
|
|
27019
|
+
var grokQuotaWindows = (body) => {
|
|
27020
|
+
const config2 = asObject(asObject(body)?.["config"]);
|
|
27021
|
+
const productUsage = config2?.["productUsage"];
|
|
27022
|
+
const fromProduct = Array.isArray(productUsage) ? asNumber(
|
|
27023
|
+
productUsage.map(asObject).find((row) => row !== null && asString3(row["product"]) === "GrokBuild")?.["usagePercent"]
|
|
27024
|
+
) : null;
|
|
27025
|
+
const usedPercent = asNumber(config2?.["creditUsagePercent"]) ?? fromProduct;
|
|
27026
|
+
return usedPercent === null ? [] : [
|
|
27027
|
+
{
|
|
27028
|
+
id: "weekly",
|
|
27029
|
+
label: { key: "usage.window.weekly" },
|
|
27030
|
+
usedPercent: clampPercent(usedPercent),
|
|
27031
|
+
resetsAt: asString3(asObject(config2?.["currentPeriod"])?.["end"]) ?? asString3(config2?.["billingPeriodEnd"])
|
|
27032
|
+
}
|
|
27033
|
+
];
|
|
27034
|
+
};
|
|
27035
|
+
var createGrokUsage = (input2) => {
|
|
27036
|
+
const now = input2.now ?? Date.now;
|
|
27037
|
+
const authPath = NodePath2.join(input2.homePath, AUTH_FILE_NAME2);
|
|
27038
|
+
const readQuota = async (request) => {
|
|
27039
|
+
const baseUrlKey = GROK_CARD.modelConnectivity.baseUrlEnvKey;
|
|
27040
|
+
if (baseUrlKey !== void 0 && (input2.environment[baseUrlKey]?.trim() ?? "") !== "") {
|
|
27041
|
+
return { status: "unavailable", reason: "customEndpoint" };
|
|
27042
|
+
}
|
|
27043
|
+
let token = null;
|
|
27044
|
+
try {
|
|
27045
|
+
token = extractGrokToken(parseJson(NodeFS2.readFileSync(authPath, "utf8")));
|
|
27046
|
+
} catch {
|
|
27047
|
+
token = null;
|
|
27048
|
+
}
|
|
27049
|
+
if (token === null) {
|
|
27050
|
+
const apiKey = input2.environment["XAI_API_KEY"]?.trim() ?? "";
|
|
27051
|
+
return {
|
|
27052
|
+
status: "unavailable",
|
|
27053
|
+
reason: apiKey.length > 0 ? "unsupportedLogin" : "missingCredentials"
|
|
27054
|
+
};
|
|
27055
|
+
}
|
|
27056
|
+
let response;
|
|
27057
|
+
try {
|
|
27058
|
+
response = await input2.fetch(GROK_USAGE_URL, {
|
|
27059
|
+
headers: {
|
|
27060
|
+
Authorization: `Bearer ${token}`,
|
|
27061
|
+
Accept: "application/json",
|
|
27062
|
+
"X-XAI-Token-Auth": "xai-grok-cli"
|
|
27063
|
+
},
|
|
27064
|
+
signal: AbortSignal.any([
|
|
27065
|
+
...request.signal === void 0 ? [] : [request.signal],
|
|
27066
|
+
AbortSignal.timeout(QUOTA_TIMEOUT_MS)
|
|
27067
|
+
])
|
|
27068
|
+
});
|
|
27069
|
+
} catch {
|
|
27070
|
+
return { status: "unavailable", reason: "unreachable" };
|
|
27071
|
+
}
|
|
27072
|
+
if (response.status === 401 || response.status === 403) {
|
|
27073
|
+
return { status: "unavailable", reason: "authRejected" };
|
|
27074
|
+
}
|
|
27075
|
+
if (response.status === 429) {
|
|
27076
|
+
const retryAfterMs = parseRetryAfterMs(response.headers.get("retry-after"), now());
|
|
27077
|
+
return {
|
|
27078
|
+
status: "unavailable",
|
|
27079
|
+
reason: "rateLimited",
|
|
27080
|
+
...retryAfterMs === null ? {} : { retryAfterMs }
|
|
27081
|
+
};
|
|
27082
|
+
}
|
|
27083
|
+
if (!response.ok) return { status: "unavailable", reason: "unreachable" };
|
|
27084
|
+
let body;
|
|
27085
|
+
try {
|
|
27086
|
+
body = parseJson(await response.text());
|
|
27087
|
+
} catch {
|
|
27088
|
+
return { status: "unavailable", reason: "unreachable" };
|
|
27089
|
+
}
|
|
27090
|
+
if (asObject(body) === null) return { status: "unavailable", reason: "unreachable" };
|
|
27091
|
+
return {
|
|
27092
|
+
status: "available",
|
|
27093
|
+
windows: grokQuotaWindows(body),
|
|
27094
|
+
balances: [],
|
|
27095
|
+
accountKey: authPath
|
|
27096
|
+
};
|
|
27097
|
+
};
|
|
27098
|
+
return { readQuota };
|
|
27099
|
+
};
|
|
27100
|
+
|
|
27101
|
+
// src/grokTurnUsage.ts
|
|
27102
|
+
var USAGE_GRACE_MS = 300;
|
|
27103
|
+
var isRecord8 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
27104
|
+
var count = (value) => typeof value === "number" && Number.isFinite(value) && value > 0 ? Math.trunc(value) : 0;
|
|
27105
|
+
var text = (value) => typeof value === "string" && value.trim().length > 0 ? value.trim() : void 0;
|
|
27106
|
+
var readModelTotals = (entry) => {
|
|
27107
|
+
if (!isRecord8(entry)) return void 0;
|
|
27108
|
+
const input2 = count(entry["inputTokens"]);
|
|
27109
|
+
const cachedInputTokens = count(entry["cachedReadTokens"]);
|
|
27110
|
+
const cacheCreationTokens = count(entry["cacheCreationTokens"]);
|
|
27111
|
+
const outputTokens = count(entry["outputTokens"]);
|
|
27112
|
+
return {
|
|
27113
|
+
uncachedInputTokens: Math.max(0, input2 - cachedInputTokens - cacheCreationTokens),
|
|
27114
|
+
cachedInputTokens,
|
|
27115
|
+
cacheCreationTokens,
|
|
27116
|
+
outputTokens,
|
|
27117
|
+
reasoningTokens: Math.min(count(entry["reasoningTokens"]), outputTokens)
|
|
27118
|
+
};
|
|
27119
|
+
};
|
|
27120
|
+
var sumOf = (totals) => totals.uncachedInputTokens + totals.cachedInputTokens + totals.cacheCreationTokens + totals.outputTokens;
|
|
27121
|
+
var grokTurnUsageReport = (promptResponse) => {
|
|
27122
|
+
const meta3 = isRecord8(promptResponse) ? promptResponse["_meta"] : void 0;
|
|
27123
|
+
const usage = isRecord8(meta3) ? meta3["usage"] : void 0;
|
|
27124
|
+
if (!isRecord8(meta3) || !isRecord8(usage)) return void 0;
|
|
27125
|
+
const perModel = /* @__PURE__ */ new Map();
|
|
27126
|
+
const modelUsage = usage["modelUsage"];
|
|
27127
|
+
if (isRecord8(modelUsage)) {
|
|
27128
|
+
for (const [model, entry] of Object.entries(modelUsage)) {
|
|
27129
|
+
const totals = readModelTotals(entry);
|
|
27130
|
+
if (totals !== void 0 && model.trim().length > 0) perModel.set(model.trim(), totals);
|
|
27131
|
+
}
|
|
27132
|
+
}
|
|
27133
|
+
if (perModel.size === 0) {
|
|
27134
|
+
const fallbackModel = text(meta3["modelId"]);
|
|
27135
|
+
const totals = readModelTotals(usage);
|
|
27136
|
+
if (fallbackModel === void 0 || totals === void 0) return void 0;
|
|
27137
|
+
perModel.set(fallbackModel, totals);
|
|
27138
|
+
}
|
|
27139
|
+
let dominant;
|
|
27140
|
+
const sum = {
|
|
27141
|
+
uncachedInputTokens: 0,
|
|
27142
|
+
cachedInputTokens: 0,
|
|
27143
|
+
cacheCreationTokens: 0,
|
|
27144
|
+
outputTokens: 0,
|
|
27145
|
+
reasoningTokens: 0
|
|
27146
|
+
};
|
|
27147
|
+
for (const [model, totals] of perModel) {
|
|
27148
|
+
sum.uncachedInputTokens += totals.uncachedInputTokens;
|
|
27149
|
+
sum.cachedInputTokens += totals.cachedInputTokens;
|
|
27150
|
+
sum.cacheCreationTokens += totals.cacheCreationTokens;
|
|
27151
|
+
sum.outputTokens += totals.outputTokens;
|
|
27152
|
+
sum.reasoningTokens += totals.reasoningTokens;
|
|
27153
|
+
const size = sumOf(totals);
|
|
27154
|
+
if (dominant === void 0 || size > dominant.size) dominant = { model, size };
|
|
27155
|
+
}
|
|
27156
|
+
if (dominant === void 0 || sumOf(sum) === 0) return void 0;
|
|
27157
|
+
const sessionId = text(meta3["sessionId"]);
|
|
27158
|
+
return {
|
|
27159
|
+
provider: "grok",
|
|
27160
|
+
model: dominant.model,
|
|
27161
|
+
totals: sum,
|
|
27162
|
+
...sessionId === void 0 ? {} : { sessionId }
|
|
27163
|
+
};
|
|
27164
|
+
};
|
|
27165
|
+
var createGrokTurnUsageCollector = (base) => {
|
|
27166
|
+
const pastKeys = [];
|
|
27167
|
+
let promptKey;
|
|
27168
|
+
let report;
|
|
27169
|
+
let seen = false;
|
|
27170
|
+
let wake;
|
|
27171
|
+
const mark = () => {
|
|
27172
|
+
seen = true;
|
|
27173
|
+
wake?.();
|
|
27174
|
+
};
|
|
27175
|
+
const observe = (response) => {
|
|
27176
|
+
const key = base.responseKey?.(response);
|
|
27177
|
+
if (key !== void 0 && key !== promptKey && pastKeys.includes(key)) return;
|
|
27178
|
+
report = grokTurnUsageReport(response) ?? report;
|
|
27179
|
+
mark();
|
|
27180
|
+
};
|
|
27181
|
+
const settlement = {
|
|
27182
|
+
...base,
|
|
27183
|
+
requestFields: (key) => {
|
|
27184
|
+
if (promptKey !== void 0) pastKeys.push(promptKey);
|
|
27185
|
+
if (pastKeys.length > 16) pastKeys.shift();
|
|
27186
|
+
promptKey = key;
|
|
27187
|
+
report = void 0;
|
|
27188
|
+
seen = false;
|
|
27189
|
+
return base.requestFields(key);
|
|
27190
|
+
},
|
|
27191
|
+
responseKey: (response) => {
|
|
27192
|
+
observe(response);
|
|
27193
|
+
return base.responseKey?.(response);
|
|
27194
|
+
}
|
|
27195
|
+
};
|
|
27196
|
+
const attach = async (event) => {
|
|
27197
|
+
if (event.type !== "turn.completed" || !isRecord8(event.payload)) return event;
|
|
27198
|
+
if (event.payload["state"] === "completed" && !seen) {
|
|
27199
|
+
await new Promise((resolve2) => {
|
|
27200
|
+
const timer = setTimeout(resolve2, USAGE_GRACE_MS);
|
|
27201
|
+
wake = () => {
|
|
27202
|
+
clearTimeout(timer);
|
|
27203
|
+
resolve2();
|
|
27204
|
+
};
|
|
27205
|
+
});
|
|
27206
|
+
wake = void 0;
|
|
27207
|
+
}
|
|
27208
|
+
const taken = report;
|
|
27209
|
+
report = void 0;
|
|
27210
|
+
return taken === void 0 ? event : { ...event, payload: { ...event.payload, tokenUsage: taken } };
|
|
27211
|
+
};
|
|
27212
|
+
return { settlement, attach };
|
|
27213
|
+
};
|
|
27214
|
+
|
|
26978
27215
|
// src/grokPlanGate.ts
|
|
26979
27216
|
var XAI_EXIT_PLAN_MODE_METHODS = [
|
|
26980
27217
|
"_x.ai/exit_plan_mode",
|
|
@@ -26983,16 +27220,16 @@ var XAI_EXIT_PLAN_MODE_METHODS = [
|
|
|
26983
27220
|
var GROK_PLAN_APPROVE_OPTION_ID = "approved";
|
|
26984
27221
|
var GROK_PLAN_ABANDON_OPTION_ID = "abandoned";
|
|
26985
27222
|
var GROK_EMPTY_PLAN_TEXT = "The agent exited plan mode without writing a plan.";
|
|
26986
|
-
var
|
|
27223
|
+
var isRecord9 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
26987
27224
|
var trimmed = (value) => {
|
|
26988
27225
|
if (typeof value !== "string") return void 0;
|
|
26989
|
-
const
|
|
26990
|
-
return
|
|
27226
|
+
const text3 = value.trim();
|
|
27227
|
+
return text3.length > 0 ? text3 : void 0;
|
|
26991
27228
|
};
|
|
26992
27229
|
function parseXAiExitPlanModeParams(params) {
|
|
26993
|
-
const candidates = [params, ...
|
|
27230
|
+
const candidates = [params, ...isRecord9(params) ? [params["params"]] : []];
|
|
26994
27231
|
for (const candidate of candidates) {
|
|
26995
|
-
if (!
|
|
27232
|
+
if (!isRecord9(candidate)) continue;
|
|
26996
27233
|
const toolCallId = trimmed(candidate["toolCallId"]);
|
|
26997
27234
|
if (toolCallId === void 0) continue;
|
|
26998
27235
|
return { toolCallId, planContent: trimmed(candidate["planContent"]) };
|
|
@@ -27033,18 +27270,18 @@ function makeXAiExitPlanModeResponse(params, resolution) {
|
|
|
27033
27270
|
if (resolution.kind === "cancelled") return abandoned();
|
|
27034
27271
|
const answer = resolution.answers[params.toolCallId];
|
|
27035
27272
|
const selected = typeof answer === "string" ? answer : Array.isArray(answer) && answer.length === 1 && typeof answer[0] === "string" ? answer[0] : void 0;
|
|
27036
|
-
const
|
|
27037
|
-
if (
|
|
27038
|
-
if (
|
|
27039
|
-
if (
|
|
27040
|
-
return { outcome: "request_changes", feedback:
|
|
27273
|
+
const text3 = trimmed(selected);
|
|
27274
|
+
if (text3 === void 0) return abandoned();
|
|
27275
|
+
if (text3 === GROK_PLAN_APPROVE_OPTION_ID) return { outcome: "approved" };
|
|
27276
|
+
if (text3 === GROK_PLAN_ABANDON_OPTION_ID) return abandoned();
|
|
27277
|
+
return { outcome: "request_changes", feedback: text3 };
|
|
27041
27278
|
}
|
|
27042
27279
|
|
|
27043
27280
|
// src/grokBackgroundTasks.ts
|
|
27044
27281
|
var record2 = (value) => typeof value === "object" && value !== null && !Array.isArray(value) ? value : {};
|
|
27045
|
-
var
|
|
27282
|
+
var text2 = (value) => typeof value === "string" ? value.trim() || void 0 : void 0;
|
|
27046
27283
|
var lifecycle = (status, exitCode) => {
|
|
27047
|
-
switch (
|
|
27284
|
+
switch (text2(status)?.toLowerCase()) {
|
|
27048
27285
|
case "pending":
|
|
27049
27286
|
case "running":
|
|
27050
27287
|
return "running";
|
|
@@ -27098,19 +27335,19 @@ function buildGrokBackgroundTaskEvents(input2) {
|
|
|
27098
27335
|
});
|
|
27099
27336
|
};
|
|
27100
27337
|
if (output2["type"] === "Monitor" && toolCallStatus === "completed") {
|
|
27101
|
-
const id =
|
|
27338
|
+
const id = text2(output2["taskId"]);
|
|
27102
27339
|
if (id) {
|
|
27103
|
-
start(id, "monitor",
|
|
27340
|
+
start(id, "monitor", text2(record2(input2.rawInput)["description"]) ?? "Monitor", toolCallId);
|
|
27104
27341
|
}
|
|
27105
27342
|
} else if (output2["type"] === "BackgroundTaskStarted") {
|
|
27106
|
-
const id =
|
|
27107
|
-
const command =
|
|
27343
|
+
const id = text2(output2["task_id"]) ?? text2(output2["taskId"]);
|
|
27344
|
+
const command = text2(output2["command"]);
|
|
27108
27345
|
if (id && command) start(id, "shell", command.split("\n")[0].slice(0, 200), toolCallId);
|
|
27109
27346
|
} else if (output2["type"] === "TaskOutput" || output2["type"] === "KillTask") {
|
|
27110
27347
|
const results = record2(output2["MultiResult"])["results"];
|
|
27111
27348
|
for (const value of Array.isArray(results) ? results : [output2["Result"]]) {
|
|
27112
27349
|
const result = record2(value);
|
|
27113
|
-
const id =
|
|
27350
|
+
const id = text2(result["task_id"]);
|
|
27114
27351
|
if (!id) continue;
|
|
27115
27352
|
if (output2["type"] === "KillTask") {
|
|
27116
27353
|
const task2 = tasks.get(id);
|
|
@@ -27119,11 +27356,11 @@ function buildGrokBackgroundTaskEvents(input2) {
|
|
|
27119
27356
|
}
|
|
27120
27357
|
continue;
|
|
27121
27358
|
}
|
|
27122
|
-
const command =
|
|
27359
|
+
const command = text2(result["command"]);
|
|
27123
27360
|
const status = lifecycle(result["status"], result["exit_code"]);
|
|
27124
27361
|
if (!command || !status || command.startsWith("[subagent:")) continue;
|
|
27125
27362
|
const task = start(id, /^\[monitor[:\]]/.test(command) ? "monitor" : "shell", command);
|
|
27126
|
-
const summary =
|
|
27363
|
+
const summary = text2(result["output"])?.split("\n").find((line) => line.trim())?.trim();
|
|
27127
27364
|
if (status === "running") {
|
|
27128
27365
|
events.push({
|
|
27129
27366
|
type: "task.progress",
|
|
@@ -27140,11 +27377,11 @@ function buildGrokBackgroundTaskEvents(input2) {
|
|
|
27140
27377
|
|
|
27141
27378
|
// src/grokSupport.ts
|
|
27142
27379
|
import { modelSelectionStringOption } from "@ycodium-ai/plugin-api/executor";
|
|
27143
|
-
var
|
|
27380
|
+
var isRecord10 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
27144
27381
|
var trimmed2 = (value) => {
|
|
27145
27382
|
if (typeof value !== "string") return void 0;
|
|
27146
|
-
const
|
|
27147
|
-
return
|
|
27383
|
+
const text3 = value.trim();
|
|
27384
|
+
return text3.length > 0 ? text3 : void 0;
|
|
27148
27385
|
};
|
|
27149
27386
|
function grokReasoningEffortArgs(effort) {
|
|
27150
27387
|
const value = effort?.trim();
|
|
@@ -27255,28 +27492,28 @@ function grokRuntimeModeCaveat(nativeModeId) {
|
|
|
27255
27492
|
}
|
|
27256
27493
|
var GROK_REASONING_OPTION_ID = "reasoningEffort";
|
|
27257
27494
|
function resolveGrokAuthMethodId(initializeResult) {
|
|
27258
|
-
const authMethods =
|
|
27495
|
+
const authMethods = isRecord10(initializeResult) ? initializeResult["authMethods"] : void 0;
|
|
27259
27496
|
if (!Array.isArray(authMethods)) return void 0;
|
|
27260
27497
|
for (const method of authMethods) {
|
|
27261
|
-
if (
|
|
27498
|
+
if (isRecord10(method) && method["id"] === "cached_token") return "cached_token";
|
|
27262
27499
|
}
|
|
27263
27500
|
return void 0;
|
|
27264
27501
|
}
|
|
27265
27502
|
var positive = (value) => typeof value === "number" && Number.isFinite(value) && value > 0 ? Math.trunc(value) : void 0;
|
|
27266
27503
|
function grokPromptUsage(promptResponse) {
|
|
27267
|
-
if (!
|
|
27504
|
+
if (!isRecord10(promptResponse)) return void 0;
|
|
27268
27505
|
const meta3 = promptResponse["_meta"];
|
|
27269
|
-
if (!
|
|
27506
|
+
if (!isRecord10(meta3)) return void 0;
|
|
27270
27507
|
const usedTokens = positive(meta3["totalTokens"]);
|
|
27271
27508
|
if (usedTokens === void 0) return void 0;
|
|
27272
27509
|
return { usedTokens, modelId: trimmed2(meta3["modelId"]) };
|
|
27273
27510
|
}
|
|
27274
27511
|
function grokModelState(initializeResult) {
|
|
27275
|
-
if (!
|
|
27512
|
+
if (!isRecord10(initializeResult)) return void 0;
|
|
27276
27513
|
const meta3 = initializeResult["_meta"];
|
|
27277
|
-
if (!
|
|
27514
|
+
if (!isRecord10(meta3)) return void 0;
|
|
27278
27515
|
const modelState = meta3["modelState"];
|
|
27279
|
-
if (!
|
|
27516
|
+
if (!isRecord10(modelState)) return void 0;
|
|
27280
27517
|
const availableModels = modelState["availableModels"];
|
|
27281
27518
|
if (!Array.isArray(availableModels)) return void 0;
|
|
27282
27519
|
return { currentModelId: trimmed2(modelState["currentModelId"]), availableModels };
|
|
@@ -27286,11 +27523,11 @@ function grokAdvertisedModels(initializeResult) {
|
|
|
27286
27523
|
if (state === void 0) return [];
|
|
27287
27524
|
const models = [];
|
|
27288
27525
|
for (const entry of state.availableModels) {
|
|
27289
|
-
if (!
|
|
27526
|
+
if (!isRecord10(entry)) continue;
|
|
27290
27527
|
const modelId = trimmed2(entry["modelId"]);
|
|
27291
27528
|
if (modelId === void 0) continue;
|
|
27292
27529
|
const modelMeta = entry["_meta"];
|
|
27293
|
-
const contextWindow =
|
|
27530
|
+
const contextWindow = isRecord10(modelMeta) ? positive(modelMeta["totalContextTokens"]) : void 0;
|
|
27294
27531
|
models.push({
|
|
27295
27532
|
modelId,
|
|
27296
27533
|
name: trimmed2(entry["name"]),
|
|
@@ -27305,7 +27542,7 @@ var XAI_ASK_USER_QUESTION_METHODS = [
|
|
|
27305
27542
|
"x.ai/ask_user_question"
|
|
27306
27543
|
];
|
|
27307
27544
|
var readOption = (value) => {
|
|
27308
|
-
if (!
|
|
27545
|
+
if (!isRecord10(value)) return void 0;
|
|
27309
27546
|
const label = typeof value["label"] === "string" ? value["label"] : void 0;
|
|
27310
27547
|
if (label === void 0) return void 0;
|
|
27311
27548
|
return {
|
|
@@ -27316,7 +27553,7 @@ var readOption = (value) => {
|
|
|
27316
27553
|
};
|
|
27317
27554
|
};
|
|
27318
27555
|
var readQuestion = (value) => {
|
|
27319
|
-
if (!
|
|
27556
|
+
if (!isRecord10(value)) return void 0;
|
|
27320
27557
|
const question = typeof value["question"] === "string" ? value["question"] : void 0;
|
|
27321
27558
|
if (question === void 0) return void 0;
|
|
27322
27559
|
const optionsRaw = value["options"];
|
|
@@ -27332,9 +27569,9 @@ var readQuestion = (value) => {
|
|
|
27332
27569
|
};
|
|
27333
27570
|
};
|
|
27334
27571
|
function parseXAiAskUserQuestionParams(params) {
|
|
27335
|
-
const candidates = [params, ...
|
|
27572
|
+
const candidates = [params, ...isRecord10(params) ? [params["params"]] : []];
|
|
27336
27573
|
for (const candidate of candidates) {
|
|
27337
|
-
if (!
|
|
27574
|
+
if (!isRecord10(candidate)) continue;
|
|
27338
27575
|
const questionsRaw = candidate["questions"];
|
|
27339
27576
|
if (!Array.isArray(questionsRaw)) continue;
|
|
27340
27577
|
const questions = questionsRaw.flatMap((entry) => {
|
|
@@ -27360,12 +27597,12 @@ function extractXAiAskUserQuestions(params) {
|
|
|
27360
27597
|
var answerValues = (answer) => {
|
|
27361
27598
|
if (Array.isArray(answer)) {
|
|
27362
27599
|
return answer.flatMap((entry) => {
|
|
27363
|
-
const
|
|
27364
|
-
return
|
|
27600
|
+
const text4 = trimmed2(entry);
|
|
27601
|
+
return text4 === void 0 ? [] : [text4];
|
|
27365
27602
|
});
|
|
27366
27603
|
}
|
|
27367
|
-
const
|
|
27368
|
-
return
|
|
27604
|
+
const text3 = trimmed2(answer);
|
|
27605
|
+
return text3 === void 0 ? [] : [text3];
|
|
27369
27606
|
};
|
|
27370
27607
|
function makeXAiAskUserQuestionResponse(params, answers) {
|
|
27371
27608
|
const normalized = params.questions.flatMap((question) => {
|
|
@@ -27409,21 +27646,21 @@ var XAI_PROMPT_COMPLETE_METHOD = "_x.ai/session/prompt_complete";
|
|
|
27409
27646
|
var GROK_RATE_LIMIT_MESSAGE = "Grok usage limit reached or rate limited. Try again later.";
|
|
27410
27647
|
var grokAgentResultMessage = (value) => {
|
|
27411
27648
|
if (typeof value === "string") return trimmed2(value);
|
|
27412
|
-
return
|
|
27649
|
+
return isRecord10(value) ? trimmed2(value["message"]) : void 0;
|
|
27413
27650
|
};
|
|
27414
27651
|
var grokPromptSettlement = {
|
|
27415
27652
|
// 关联 id 双写 promptId 与 requestId(宿主 XAiAcpExtension 同款):
|
|
27416
27653
|
// agent 认回哪个键是它的事,两个都给才不猜版本。
|
|
27417
27654
|
requestFields: (promptKey) => ({ _meta: { promptId: promptKey, requestId: promptKey } }),
|
|
27418
27655
|
responseKey: (response) => {
|
|
27419
|
-
if (!
|
|
27656
|
+
if (!isRecord10(response)) return void 0;
|
|
27420
27657
|
const meta3 = response["_meta"];
|
|
27421
|
-
if (!
|
|
27658
|
+
if (!isRecord10(meta3)) return void 0;
|
|
27422
27659
|
return trimmed2(meta3["promptId"]) ?? trimmed2(meta3["requestId"]);
|
|
27423
27660
|
},
|
|
27424
27661
|
fromNotification: (method, params) => {
|
|
27425
27662
|
if (method !== XAI_PROMPT_COMPLETE_METHOD) return void 0;
|
|
27426
|
-
if (!
|
|
27663
|
+
if (!isRecord10(params)) return void 0;
|
|
27427
27664
|
const sessionId = params["sessionId"];
|
|
27428
27665
|
if (typeof sessionId !== "string") return void 0;
|
|
27429
27666
|
const stopReason = trimmed2(params["stopReason"]);
|
|
@@ -27441,10 +27678,11 @@ var grokPromptSettlement = {
|
|
|
27441
27678
|
|
|
27442
27679
|
// src/grokSkills.ts
|
|
27443
27680
|
import * as NodeOS from "node:os";
|
|
27681
|
+
import * as NodePath3 from "node:path";
|
|
27444
27682
|
var INSPECT_TIMEOUT_MS = 15e3;
|
|
27445
27683
|
var MAX_INSPECT_OUTPUT_BYTES = 4 * 1024 * 1024;
|
|
27446
27684
|
var GROK_INSPECT_ARGS = ["inspect", "--json"];
|
|
27447
|
-
var
|
|
27685
|
+
var isRecord11 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
27448
27686
|
var trimmedString = (value) => typeof value === "string" ? value.trim() : "";
|
|
27449
27687
|
function parseGrokInspectSkills(stdout) {
|
|
27450
27688
|
let parsed;
|
|
@@ -27453,13 +27691,13 @@ function parseGrokInspectSkills(stdout) {
|
|
|
27453
27691
|
} catch {
|
|
27454
27692
|
return [];
|
|
27455
27693
|
}
|
|
27456
|
-
const entries =
|
|
27694
|
+
const entries = isRecord11(parsed) ? parsed["skills"] : void 0;
|
|
27457
27695
|
if (!Array.isArray(entries)) return [];
|
|
27458
27696
|
const byName = /* @__PURE__ */ new Map();
|
|
27459
27697
|
for (const entry of entries) {
|
|
27460
|
-
if (!
|
|
27698
|
+
if (!isRecord11(entry)) continue;
|
|
27461
27699
|
const name = trimmedString(entry["name"]);
|
|
27462
|
-
const source =
|
|
27700
|
+
const source = isRecord11(entry["source"]) ? entry["source"] : void 0;
|
|
27463
27701
|
const path = trimmedString(source?.["path"]);
|
|
27464
27702
|
if (name.length === 0 || path.length === 0) continue;
|
|
27465
27703
|
const scope = trimmedString(source?.["type"]);
|
|
@@ -27474,27 +27712,51 @@ function parseGrokInspectSkills(stdout) {
|
|
|
27474
27712
|
}
|
|
27475
27713
|
return [...byName.values()].toSorted((left, right) => left.name.localeCompare(right.name));
|
|
27476
27714
|
}
|
|
27715
|
+
var runGrokInspect = async (input2) => {
|
|
27716
|
+
const { recipe, host, env, cwd } = input2;
|
|
27717
|
+
const handle = await host.process.spawn({
|
|
27718
|
+
program: recipe.binaryPath,
|
|
27719
|
+
args: GROK_INSPECT_ARGS,
|
|
27720
|
+
cwd,
|
|
27721
|
+
owner: { bindingId: host.bindingId },
|
|
27722
|
+
...Object.keys(env).length > 0 ? { env } : {}
|
|
27723
|
+
});
|
|
27724
|
+
const run = await collectProbeProcess(handle, {
|
|
27725
|
+
timeoutMs: INSPECT_TIMEOUT_MS,
|
|
27726
|
+
maxOutputBytes: MAX_INSPECT_OUTPUT_BYTES,
|
|
27727
|
+
what: "grok inspect"
|
|
27728
|
+
});
|
|
27729
|
+
if (run.exitCode !== 0 || run.stdout === void 0) {
|
|
27730
|
+
throw new Error(`grok inspect exited with ${String(run.exitCode)}`);
|
|
27731
|
+
}
|
|
27732
|
+
const parsed = JSON.parse(run.stdout);
|
|
27733
|
+
if (!isRecord11(parsed) || !Array.isArray(parsed["skills"])) {
|
|
27734
|
+
throw new Error("grok inspect output has no skills list");
|
|
27735
|
+
}
|
|
27736
|
+
return parseGrokInspectSkills(run.stdout);
|
|
27737
|
+
};
|
|
27477
27738
|
async function probeGrokSkills(input2) {
|
|
27478
|
-
const { recipe, host, env } = input2;
|
|
27479
27739
|
try {
|
|
27480
|
-
|
|
27481
|
-
program: recipe.binaryPath,
|
|
27482
|
-
args: GROK_INSPECT_ARGS,
|
|
27483
|
-
cwd: NodeOS.homedir(),
|
|
27484
|
-
owner: { bindingId: host.bindingId },
|
|
27485
|
-
...Object.keys(env).length > 0 ? { env } : {}
|
|
27486
|
-
});
|
|
27487
|
-
const run = await collectProbeProcess(handle, {
|
|
27488
|
-
timeoutMs: INSPECT_TIMEOUT_MS,
|
|
27489
|
-
maxOutputBytes: MAX_INSPECT_OUTPUT_BYTES,
|
|
27490
|
-
what: "grok inspect"
|
|
27491
|
-
});
|
|
27492
|
-
if (run.exitCode !== 0 || run.stdout === void 0) return [];
|
|
27493
|
-
return parseGrokInspectSkills(run.stdout);
|
|
27740
|
+
return await runGrokInspect({ ...input2, cwd: NodeOS.homedir() });
|
|
27494
27741
|
} catch {
|
|
27495
27742
|
return [];
|
|
27496
27743
|
}
|
|
27497
27744
|
}
|
|
27745
|
+
async function inspectGrokWorkspace(input2) {
|
|
27746
|
+
const skills = await runGrokInspect(input2);
|
|
27747
|
+
const watched = /* @__PURE__ */ new Set([
|
|
27748
|
+
// 项目技能目录的位置没有实测,这两处只是触发重查的提示,不影响答案本身。
|
|
27749
|
+
NodePath3.join(input2.cwd, ".grok", "skills"),
|
|
27750
|
+
NodePath3.join(input2.cwd, ".agents", "skills")
|
|
27751
|
+
]);
|
|
27752
|
+
for (const skill of skills) {
|
|
27753
|
+
watched.add(skill.path);
|
|
27754
|
+
const skillDirectory = NodePath3.dirname(skill.path);
|
|
27755
|
+
watched.add(skillDirectory);
|
|
27756
|
+
watched.add(NodePath3.dirname(skillDirectory));
|
|
27757
|
+
}
|
|
27758
|
+
return { skills, watchPaths: [...watched] };
|
|
27759
|
+
}
|
|
27498
27760
|
|
|
27499
27761
|
// src/probeModels.ts
|
|
27500
27762
|
import {
|
|
@@ -27603,14 +27865,14 @@ var hasDeviceCode = (output2) => deviceCodeUrl(output2) !== void 0 && deviceCode
|
|
|
27603
27865
|
function expandHomePath(value) {
|
|
27604
27866
|
if (value === "~") return NodeOS2.homedir();
|
|
27605
27867
|
if (value.startsWith("~/") || value.startsWith("~\\")) {
|
|
27606
|
-
return
|
|
27868
|
+
return NodePath4.join(NodeOS2.homedir(), value.slice(2));
|
|
27607
27869
|
}
|
|
27608
27870
|
return value;
|
|
27609
27871
|
}
|
|
27610
27872
|
function resolveGrokHomePath(value) {
|
|
27611
27873
|
const trimmed3 = value.trim();
|
|
27612
|
-
if (trimmed3.length === 0) return
|
|
27613
|
-
return
|
|
27874
|
+
if (trimmed3.length === 0) return NodePath4.join(NodeOS2.homedir(), ".grok");
|
|
27875
|
+
return NodePath4.resolve(expandHomePath(trimmed3));
|
|
27614
27876
|
}
|
|
27615
27877
|
function probeGrokAccount(accountPath) {
|
|
27616
27878
|
const resolved = resolveGrokHomePath(accountPath);
|
|
@@ -27629,12 +27891,12 @@ function grokContinuationKey(recipe) {
|
|
|
27629
27891
|
function resolveAccountHomePath(recipe, configuredHome) {
|
|
27630
27892
|
const fromEnvironment = recipe.environment["GROK_HOME"]?.trim();
|
|
27631
27893
|
if (fromEnvironment !== void 0 && fromEnvironment.length > 0) {
|
|
27632
|
-
return
|
|
27894
|
+
return NodePath4.resolve(expandHomePath(fromEnvironment));
|
|
27633
27895
|
}
|
|
27634
27896
|
return resolveGrokHomePath(configuredHome);
|
|
27635
27897
|
}
|
|
27636
27898
|
function absentPath() {
|
|
27637
|
-
return
|
|
27899
|
+
return NodePath4.join(
|
|
27638
27900
|
NodeOS2.tmpdir(),
|
|
27639
27901
|
`ycodium-grok-no-auth-${NodeCrypto2.randomUUID()}`,
|
|
27640
27902
|
"auth.json"
|
|
@@ -27758,6 +28020,23 @@ var createGrokInstance = (config2, host) => {
|
|
|
27758
28020
|
};
|
|
27759
28021
|
const instance = {
|
|
27760
28022
|
probe,
|
|
28023
|
+
// 项目里的技能:探测在 home 下跑 inspect 只看得到整机的;这里在项目目录里再跑一次。
|
|
28024
|
+
workspaceInventory: ({ cwd }) => {
|
|
28025
|
+
if (recipe.binaryPath.length === 0) {
|
|
28026
|
+
return Promise.reject(new Error("Grok program path is not configured"));
|
|
28027
|
+
}
|
|
28028
|
+
const configuredHome = recipe.homePath;
|
|
28029
|
+
return inspectGrokWorkspace({
|
|
28030
|
+
recipe,
|
|
28031
|
+
host,
|
|
28032
|
+
cwd,
|
|
28033
|
+
env: buildSpawnEnv(
|
|
28034
|
+
recipe,
|
|
28035
|
+
resolveGrokHomePath(configuredHome),
|
|
28036
|
+
configuredHome.trim().length > 0
|
|
28037
|
+
)
|
|
28038
|
+
});
|
|
28039
|
+
},
|
|
27761
28040
|
// 有意不处理 input.readOnlyDirectories:grok 的 read_file 在每一档都不弹审批、
|
|
27762
28041
|
// 绝对路径读到哪儿都一样(实测表见 grokSupport.ts),附件目录无需放行。
|
|
27763
28042
|
startSession: async (input2, signal) => {
|
|
@@ -27801,6 +28080,7 @@ var createGrokInstance = (config2, host) => {
|
|
|
27801
28080
|
const requestedModelId = modelIdFromSelection(input2.modelSelection);
|
|
27802
28081
|
let initializeResult;
|
|
27803
28082
|
const backgroundTasks = /* @__PURE__ */ new Map();
|
|
28083
|
+
const turnUsage = createGrokTurnUsageCollector(grokPromptSettlement);
|
|
27804
28084
|
const executor = createAcpExecutor({
|
|
27805
28085
|
readable,
|
|
27806
28086
|
writable,
|
|
@@ -27811,11 +28091,16 @@ var createGrokInstance = (config2, host) => {
|
|
|
27811
28091
|
providerInstanceId: host.instanceId,
|
|
27812
28092
|
clientInfo: GROK_CLIENT_INFO,
|
|
27813
28093
|
log: host.log,
|
|
28094
|
+
// agent 自己宣告的斜杠命令按会话报给宿主,输入区的 / 菜单才有它们。
|
|
28095
|
+
onAvailableCommands: (commands) => host.reportSessionInventory?.({
|
|
28096
|
+
threadId: input2.threadId,
|
|
28097
|
+
slashCommands: acpCommandsToSlashCommands(commands)
|
|
28098
|
+
}),
|
|
27814
28099
|
// 等 `initialize` 回来再挑认证方式:能不能用 `cached_token`,只有 agent
|
|
27815
28100
|
// 播报的 `authMethods` 说了算(见 resolveGrokAuthMethodId)。
|
|
27816
28101
|
authMethodId: resolveGrokAuthMethodId,
|
|
27817
28102
|
hooks: {
|
|
27818
|
-
promptSettlement:
|
|
28103
|
+
promptSettlement: turnUsage.settlement,
|
|
27819
28104
|
onToolCallUpdated: (update) => buildGrokBackgroundTaskEvents({
|
|
27820
28105
|
tasks: backgroundTasks,
|
|
27821
28106
|
toolCallId: update.toolCallId,
|
|
@@ -27867,7 +28152,7 @@ var createGrokInstance = (config2, host) => {
|
|
|
27867
28152
|
});
|
|
27868
28153
|
const forwarding = (async () => {
|
|
27869
28154
|
for await (const event of executor.events) {
|
|
27870
|
-
events.push(event);
|
|
28155
|
+
events.push(await turnUsage.attach(event));
|
|
27871
28156
|
}
|
|
27872
28157
|
})();
|
|
27873
28158
|
try {
|
|
@@ -28014,6 +28299,12 @@ var createGrokInstance = (config2, host) => {
|
|
|
28014
28299
|
return { threadId, turns: booked.turns };
|
|
28015
28300
|
},
|
|
28016
28301
|
events,
|
|
28302
|
+
// 额度读实例自己的账号目录与连接(与它的 CLI 同源);token 走编排账本,见 grokTurnUsage.ts。
|
|
28303
|
+
usage: createGrokUsage({
|
|
28304
|
+
homePath: resolveAccountHomePath(recipe, recipe.homePath),
|
|
28305
|
+
environment: recipe.environment,
|
|
28306
|
+
fetch: host.fetch
|
|
28307
|
+
}),
|
|
28017
28308
|
continuationKey: grokContinuationKey(recipe),
|
|
28018
28309
|
dispose: async () => {
|
|
28019
28310
|
if (disposed) return;
|
|
@@ -28054,9 +28345,9 @@ var createGrokInstance = (config2, host) => {
|
|
|
28054
28345
|
const stdoutText = (async () => {
|
|
28055
28346
|
const decoder = new TextDecoder();
|
|
28056
28347
|
for await (const chunk of handle.stdout) {
|
|
28057
|
-
const
|
|
28058
|
-
collected.push(
|
|
28059
|
-
host.log.info("sign-in output", { text:
|
|
28348
|
+
const text3 = decoder.decode(chunk, { stream: true });
|
|
28349
|
+
collected.push(text3);
|
|
28350
|
+
host.log.info("sign-in output", { text: text3 });
|
|
28060
28351
|
if (onCodeFound !== void 0 && hasDeviceCode(collected.join(""))) {
|
|
28061
28352
|
onCodeFound();
|
|
28062
28353
|
onCodeFound = void 0;
|
package/locales/en.json
CHANGED
|
@@ -10,5 +10,10 @@
|
|
|
10
10
|
"description": "Sessions and the `grok login` credentials live here, so providers sharing this directory can pick up each other's threads and providers with different directories cannot. Leave empty to use the CLI's default (~/.grok).",
|
|
11
11
|
"placeholder": "e.g. ~/.grok-work"
|
|
12
12
|
}
|
|
13
|
+
},
|
|
14
|
+
"usage": {
|
|
15
|
+
"window": {
|
|
16
|
+
"weekly": "Weekly"
|
|
17
|
+
}
|
|
13
18
|
}
|
|
14
19
|
}
|
package/locales/zh-CN.json
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ycodium-ai/agent-grok",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.2694",
|
|
4
4
|
"description": "Grok executor: grok CLI over Agent Client Protocol stdio.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ycodium",
|
|
@@ -21,9 +21,9 @@
|
|
|
21
21
|
"@types/node": "24.12.4",
|
|
22
22
|
"esbuild": "0.28.1",
|
|
23
23
|
"vite-plus": "0.2.2",
|
|
24
|
-
"ycodium-acp-executor": "0.2.
|
|
24
|
+
"ycodium-acp-executor": "0.2.2694",
|
|
25
25
|
"ycodium-executor-testing": "0.0.0",
|
|
26
|
-
"@ycodium-ai/plugin-api": "0.2.
|
|
26
|
+
"@ycodium-ai/plugin-api": "0.2.2694"
|
|
27
27
|
},
|
|
28
28
|
"ycodium": {
|
|
29
29
|
"plugin": "./dist/index.js",
|