@epoch-agent/core 2.2.0 → 2.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/index.d.ts +12411 -12373
- package/dist/index.js +301 -152
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { REASONING_EFFORTS, MODEL_ENTRY_PROTOCOLS, PROVIDER_TYPES, isModelEntryId, parseModelRef, OPERATION_TYPES as OPERATION_TYPES$1, COMPLIANCE_CATEGORIES, COMPLIANCE_ACTIONS, SEARCH_PROVIDER_TYPES, CURRENCIES, LANGS, isSettingsPaneId, SETTINGS_PANE_IDS, BRAND_WHEN_SIDEBAR_COLLAPSED, PERMISSION_LEVELS, SHELL_KINDS, cronTimes, SCHEDULE_MAX_TIMES_PER_DAY, SCHEDULE_INTERVAL_MIN_MINUTES, SCHEDULE_INTERVAL_MAX_MINUTES, ToolExposure, MIN_OPTIONS, MAX_OPTIONS, MAX_HEADER_CHARS, MAX_QUESTIONS, isPermissionLevel, SCHEDULE_DRAFT_TOOL, isValidAgentRoleName, DEFAULT_AGENT_ROLE, isValidCommandName, RESERVED_COMMAND_NAMES, isWirePluginArchiveName, systemNote, formatMoney, totalUsageTokens, NOOP_TELEMETRY, METRIC, contentToText, GEN_AI, isPromptOversize, promptTokens, entrySecretName, isEntrySecretName, entryRef, KEY_ACTIONS, tableOf, perAction, isKeyAction, parseSequence, RESERVED_CHORDS, chordId, sequenceId, ACTION_CONTEXTS, SEQUENCE_CONTEXTS, assertNeverPart, normalizeAppearanceTranslucent, MAX_ATTACH_FILES, MAX_ATTACH_TOTAL_BYTES, MAX_SESSION_REFS, utf8ByteLength, truncateToBudget, attachSessionSurface, isContextNearlyFull, isOperationType, normalizeApproval, imagePartOmittedSummary, ENTRY_REF_PREFIX, MAX_ATTACH_BYTES, SIMULTANEOUS_CONTEXTS, SESSION_REFERENCE_ERROR_CODES, filePartSummary, sessionPartSummary } from '@epoch-agent/protocol';
|
|
1
|
+
import { REASONING_EFFORTS, MODEL_ENTRY_PROTOCOLS, PROVIDER_TYPES, isModelEntryId, parseModelRef, OPERATION_TYPES as OPERATION_TYPES$1, COMPLIANCE_CATEGORIES, COMPLIANCE_ACTIONS, SEARCH_PROVIDER_TYPES, CURRENCIES, LANGS, isSettingsPaneId, SETTINGS_PANE_IDS, BRAND_WHEN_SIDEBAR_COLLAPSED, PERMISSION_LEVELS, SHELL_KINDS, cronTimes, SCHEDULE_MAX_TIMES_PER_DAY, SCHEDULE_INTERVAL_MIN_MINUTES, SCHEDULE_INTERVAL_MAX_MINUTES, ToolExposure, MIN_OPTIONS, MAX_OPTIONS, MAX_HEADER_CHARS, MAX_QUESTIONS, isPermissionLevel, SCHEDULE_DRAFT_TOOL, isValidAgentRoleName, DEFAULT_AGENT_ROLE, isValidCommandName, RESERVED_COMMAND_NAMES, isWirePluginArchiveName, systemNote, formatMoney, totalUsageTokens, NOOP_TELEMETRY, METRIC, contentToText, GEN_AI, isPromptOversize, promptTokens, entrySecretName, isEntrySecretName, entryRef, KEY_ACTIONS, tableOf, perAction, isKeyAction, parseSequence, RESERVED_CHORDS, chordId, sequenceId, ACTION_CONTEXTS, SEQUENCE_CONTEXTS, assertNeverPart, normalizeAppearanceTranslucent, MAX_ATTACH_FILES, MAX_ATTACH_TOTAL_BYTES, MAX_SESSION_REFS, utf8ByteLength, truncateToBudget, attachSessionSurface, isContextNearlyFull, isOperationType, normalizeApproval, SCHEDULE_DRAFT_SAVED_MARK, imagePartOmittedSummary, ENTRY_REF_PREFIX, MAX_ATTACH_BYTES, SIMULTANEOUS_CONTEXTS, SESSION_REFERENCE_ERROR_CODES, filePartSummary, sessionPartSummary } from '@epoch-agent/protocol';
|
|
2
2
|
export { API_KEY_ENV_VARS, COMPLIANCE_ACTIONS, COMPLIANCE_CATEGORIES, MAX_ATTACH_BYTES, MAX_ATTACH_FILES, MAX_ATTACH_TOTAL_BYTES, MAX_SESSION_ATTACH_BYTES, MAX_SESSION_REFS, OPERATION_TYPES, PERMISSION_LEVELS, PLAN_OUTCOMES, PROVIDER_INFOS, PROVIDER_TYPES, ToolExposure, apiKeyEnvVar, extractAllMentions, extractMentions, extractSessionMentions, getProviderInfo, isOperationType, isPermissionLevel, isPlanOutcome, isProviderType, normalizeApproval } from '@epoch-agent/protocol';
|
|
3
3
|
import { existsSync, statSync, readdirSync, readFileSync, mkdirSync, writeFileSync, rmSync, renameSync, realpathSync, symlinkSync, cpSync, lstatSync, unlinkSync, rmdirSync, mkdtempSync, copyFileSync, openSync, writeSync, closeSync, readSync } from 'fs';
|
|
4
4
|
import { homedir, platform, tmpdir, hostname } from 'os';
|
|
@@ -2707,13 +2707,48 @@ function createExitTool(deps) {
|
|
|
2707
2707
|
function createPlanModeTools(deps) {
|
|
2708
2708
|
return [createEnterTool(deps), createExitTool(deps)];
|
|
2709
2709
|
}
|
|
2710
|
+
var SCHEDULE_ISSUE_CODES = [
|
|
2711
|
+
"name-empty",
|
|
2712
|
+
"prompt-empty",
|
|
2713
|
+
"permission-unknown",
|
|
2714
|
+
"work-dir-missing",
|
|
2715
|
+
"budget-missing",
|
|
2716
|
+
"max-turns-invalid",
|
|
2717
|
+
"timeout-invalid",
|
|
2718
|
+
"trigger-time-invalid",
|
|
2719
|
+
"trigger-times-too-many",
|
|
2720
|
+
"trigger-weekdays-empty",
|
|
2721
|
+
"trigger-days-invalid",
|
|
2722
|
+
"trigger-interval-invalid",
|
|
2723
|
+
"trigger-once-date-invalid",
|
|
2724
|
+
"trigger-once-past",
|
|
2725
|
+
"date-range-invalid",
|
|
2726
|
+
"date-range-on-once",
|
|
2727
|
+
"rule-invalid",
|
|
2728
|
+
"bypass-needs-workdir",
|
|
2729
|
+
"bypass-workdir-too-broad",
|
|
2730
|
+
"bypass-needs-limits",
|
|
2731
|
+
"bypass-not-confirmed"
|
|
2732
|
+
];
|
|
2733
|
+
var SCHEDULE_DEFAULTS = {
|
|
2734
|
+
maxTurns: DEFAULT_MAX_TURNS,
|
|
2735
|
+
timeoutMs: 60 * 60 * 1e3
|
|
2736
|
+
};
|
|
2737
|
+
var SCHEDULE_FORM_BUDGET_USD = 200;
|
|
2738
|
+
var SCHEDULE_DEFAULT_ALLOWLIST = {
|
|
2739
|
+
allowTools: [],
|
|
2740
|
+
allowOperations: ["file_read"],
|
|
2741
|
+
allowRules: []
|
|
2742
|
+
};
|
|
2743
|
+
// src/schedule/draft.ts
|
|
2710
2744
|
var bad = (message) => ({ ok: false, message });
|
|
2711
2745
|
var good = (value) => ({ ok: true, value });
|
|
2712
2746
|
var PERMISSION_ORDER = [
|
|
2713
2747
|
"plan",
|
|
2714
2748
|
"default",
|
|
2715
2749
|
"acceptEdits",
|
|
2716
|
-
"auto"
|
|
2750
|
+
"auto",
|
|
2751
|
+
"bypass"
|
|
2717
2752
|
];
|
|
2718
2753
|
var OPERATION_TYPES = [
|
|
2719
2754
|
"file_read",
|
|
@@ -2755,16 +2790,18 @@ function operationList(v) {
|
|
|
2755
2790
|
function permission(v) {
|
|
2756
2791
|
const s = str(v);
|
|
2757
2792
|
if (s === void 0) return bad("permission \u662F\u7A7A\u7684");
|
|
2758
|
-
if (s === "bypass") {
|
|
2759
|
-
return bad(
|
|
2760
|
-
"\u8349\u7A3F\u4E0D\u8BB8\u7528 bypass\uFF08\u8DF3\u8FC7\u5168\u90E8\u68C0\u67E5\uFF09\u3002\u65E0\u4EBA\u503C\u5B88\u4E0B\u90A3\u4E00\u6863\u8981\u4EBA\u4EB2\u624B\u52FE\u4E00\u6B21\u786E\u8BA4\uFF0C\u8BA9\u8349\u7A3F\u63D0\u8BAE\u5B83\u7B49\u4E8E\u628A\u90A3\u6B21\u786E\u8BA4\u53D8\u6210\u4F8B\u884C\u624B\u7EED\u3002\u8981\u653E\u5F00\u67D0\u51E0\u4EF6\u4E8B\uFF0C\u7528 permission: default \u52A0\u4E00\u4EFD\u7CBE\u786E\u7684 allowRules"
|
|
2761
|
-
);
|
|
2762
|
-
}
|
|
2763
2793
|
if (!PERMISSION_ORDER.includes(s)) {
|
|
2764
2794
|
return bad(`permission \u53EA\u80FD\u662F ${PERMISSION_ORDER.join(" / ")} \u4E4B\u4E00\uFF0C\u6536\u5230\u7684\u662F ${s}`);
|
|
2765
2795
|
}
|
|
2766
2796
|
return good(s);
|
|
2767
2797
|
}
|
|
2798
|
+
function budget(v) {
|
|
2799
|
+
if (v === void 0) return good(void 0);
|
|
2800
|
+
if (typeof v !== "number" || !Number.isFinite(v) || v <= 0) {
|
|
2801
|
+
return bad("maxBudgetUsd \u8981\u662F\u5927\u4E8E 0 \u7684\u6570\uFF08\u5355\u4F4D\u7F8E\u5143\uFF09\u3002\u4E0D\u7ED9\u5C31\u6309\u65B0\u5EFA\u8868\u5355\u90A3\u4E2A\u7F3A\u7701\uFF08200\uFF09");
|
|
2802
|
+
}
|
|
2803
|
+
return good(v);
|
|
2804
|
+
}
|
|
2768
2805
|
function clock(v) {
|
|
2769
2806
|
const s = str(v);
|
|
2770
2807
|
if (s === void 0 || !/^\d{1,2}:\d{2}$/.test(s))
|
|
@@ -2881,6 +2918,8 @@ function parseCreate(raw, note) {
|
|
|
2881
2918
|
const allow = parseAllowlist(raw);
|
|
2882
2919
|
if (!allow.ok) return allow;
|
|
2883
2920
|
const workDir = str(raw["workDir"]);
|
|
2921
|
+
const usd = budget(raw["maxBudgetUsd"]);
|
|
2922
|
+
if (!usd.ok) return usd;
|
|
2884
2923
|
return good({
|
|
2885
2924
|
action: "create",
|
|
2886
2925
|
name,
|
|
@@ -2889,6 +2928,7 @@ function parseCreate(raw, note) {
|
|
|
2889
2928
|
permission: level.value,
|
|
2890
2929
|
note,
|
|
2891
2930
|
...workDir === void 0 ? {} : { workDir },
|
|
2931
|
+
...usd.value === void 0 ? {} : { maxBudgetUsd: usd.value },
|
|
2892
2932
|
...allow.value
|
|
2893
2933
|
});
|
|
2894
2934
|
}
|
|
@@ -2923,6 +2963,9 @@ function parseUpdate(raw, note) {
|
|
|
2923
2963
|
const timeout = posInt(raw["timeoutMs"], "timeoutMs");
|
|
2924
2964
|
if (!timeout.ok) return timeout;
|
|
2925
2965
|
if (timeout.value !== void 0) patch.timeoutMs = timeout.value;
|
|
2966
|
+
const usd = budget(raw["maxBudgetUsd"]);
|
|
2967
|
+
if (!usd.ok) return usd;
|
|
2968
|
+
if (usd.value !== void 0) patch.maxBudgetUsd = usd.value;
|
|
2926
2969
|
if (Object.keys(patch).length === 0) {
|
|
2927
2970
|
return bad(
|
|
2928
2971
|
"update \u4E00\u683C\u90FD\u6CA1\u6539\u3002\u4E00\u4EFD\u4EC0\u4E48\u90FD\u4E0D\u6539\u7684\u63D0\u6848\u4F1A\u767D\u5360\u7528\u6237\u4E00\u6B21\u70B9\u51FB \u2014\u2014 \u8981\u4E48\u7ED9\u51FA\u5177\u4F53\u6539\u54EA\u51E0\u683C\uFF0C\u8981\u4E48\u522B\u63D0"
|
|
@@ -2948,7 +2991,7 @@ function parseScheduleDraft(raw) {
|
|
|
2948
2991
|
}
|
|
2949
2992
|
function draftWidening(draft, current) {
|
|
2950
2993
|
const out = [];
|
|
2951
|
-
const base2 = draft.action === "update" && current ? current.permission
|
|
2994
|
+
const base2 = draft.action === "update" && current ? current.permission : "default";
|
|
2952
2995
|
const level = draft.permission;
|
|
2953
2996
|
if (level !== void 0 && PERMISSION_ORDER.indexOf(level) > PERMISSION_ORDER.indexOf(base2)) {
|
|
2954
2997
|
out.push("permission");
|
|
@@ -3002,42 +3045,9 @@ function draftCommandLine(draft) {
|
|
|
3002
3045
|
for (const tool of draft.allowTools ?? []) argv.push("--allow-tool", shellArg(tool));
|
|
3003
3046
|
for (const op2 of draft.allowOperations ?? []) argv.push("--allow-operation", op2);
|
|
3004
3047
|
for (const rule of draft.allowRules ?? []) argv.push("--allow-rule", shellArg(rule));
|
|
3005
|
-
argv.push("--budget",
|
|
3048
|
+
argv.push("--budget", String(draft.maxBudgetUsd ?? SCHEDULE_FORM_BUDGET_USD));
|
|
3006
3049
|
return argv.join(" ");
|
|
3007
3050
|
}
|
|
3008
|
-
var SCHEDULE_ISSUE_CODES = [
|
|
3009
|
-
"name-empty",
|
|
3010
|
-
"prompt-empty",
|
|
3011
|
-
"permission-unknown",
|
|
3012
|
-
"work-dir-missing",
|
|
3013
|
-
"budget-missing",
|
|
3014
|
-
"max-turns-invalid",
|
|
3015
|
-
"timeout-invalid",
|
|
3016
|
-
"trigger-time-invalid",
|
|
3017
|
-
"trigger-times-too-many",
|
|
3018
|
-
"trigger-weekdays-empty",
|
|
3019
|
-
"trigger-days-invalid",
|
|
3020
|
-
"trigger-interval-invalid",
|
|
3021
|
-
"trigger-once-date-invalid",
|
|
3022
|
-
"trigger-once-past",
|
|
3023
|
-
"date-range-invalid",
|
|
3024
|
-
"date-range-on-once",
|
|
3025
|
-
"rule-invalid",
|
|
3026
|
-
"bypass-needs-workdir",
|
|
3027
|
-
"bypass-workdir-too-broad",
|
|
3028
|
-
"bypass-needs-limits",
|
|
3029
|
-
"bypass-not-confirmed"
|
|
3030
|
-
];
|
|
3031
|
-
var SCHEDULE_DEFAULTS = {
|
|
3032
|
-
maxTurns: DEFAULT_MAX_TURNS,
|
|
3033
|
-
timeoutMs: 60 * 60 * 1e3
|
|
3034
|
-
};
|
|
3035
|
-
var SCHEDULE_FORM_BUDGET_USD = 200;
|
|
3036
|
-
var SCHEDULE_DEFAULT_ALLOWLIST = {
|
|
3037
|
-
allowTools: [],
|
|
3038
|
-
allowOperations: ["file_read"],
|
|
3039
|
-
allowRules: []
|
|
3040
|
-
};
|
|
3041
3051
|
// src/schedule/unattended-lint.ts
|
|
3042
3052
|
var ANCHORS = [
|
|
3043
3053
|
{ kind: "asks-human", zh: /问(?:一下|下)?我/, en: /\bask\s+(?:me|us)\b/i },
|
|
@@ -3473,7 +3483,7 @@ function validateSchedule(input) {
|
|
|
3473
3483
|
if (input.workDir && !isExistingDir(input.workDir)) {
|
|
3474
3484
|
issues.push({ code: "work-dir-missing", detail: input.workDir });
|
|
3475
3485
|
}
|
|
3476
|
-
if (!
|
|
3486
|
+
if (!Number.isFinite(input.maxBudgetUsd) || input.maxBudgetUsd <= 0) {
|
|
3477
3487
|
issues.push({ code: "budget-missing", detail: String(input.maxBudgetUsd) });
|
|
3478
3488
|
}
|
|
3479
3489
|
if (!Number.isInteger(input.maxTurns) || input.maxTurns < 0) {
|
|
@@ -3535,29 +3545,34 @@ var WIDENING_TEXT = {
|
|
|
3535
3545
|
allowlist: "\u6E05\u5355\u591A\u4E86\u6761\u76EE\uFF08= \u591A\u4E86\u51E0\u4EF6\u4E0D\u7ECF\u786E\u8BA4\u5C31\u4F1A\u505A\u7684\u4E8B\uFF09",
|
|
3536
3546
|
enabled: "\u628A\u4E00\u6761\u505C\u7528\u7684\u4EFB\u52A1\u6539\u6210\u542F\u7528"
|
|
3537
3547
|
};
|
|
3548
|
+
function budgetOf(draft, current) {
|
|
3549
|
+
return draft.maxBudgetUsd ?? current?.maxBudgetUsd ?? SCHEDULE_FORM_BUDGET_USD;
|
|
3550
|
+
}
|
|
3538
3551
|
function validateDraft(draft, homeDir, current) {
|
|
3552
|
+
const permission2 = draft.permission ?? current?.permission ?? "default";
|
|
3539
3553
|
const merged = draft.action === "create" ? {
|
|
3540
3554
|
name: draft.name,
|
|
3541
3555
|
prompt: draft.prompt,
|
|
3542
|
-
permission:
|
|
3556
|
+
permission: permission2,
|
|
3543
3557
|
workDir: draft.workDir ?? "",
|
|
3544
3558
|
maxTurns: SCHEDULE_DEFAULTS.maxTurns,
|
|
3545
|
-
maxBudgetUsd:
|
|
3559
|
+
maxBudgetUsd: budgetOf(draft),
|
|
3546
3560
|
timeoutMs: SCHEDULE_DEFAULTS.timeoutMs,
|
|
3547
3561
|
trigger: draft.trigger,
|
|
3548
3562
|
allowRules: draft.allowRules ?? [],
|
|
3549
|
-
|
|
3563
|
+
bypassAcknowledged: permission2 === "bypass",
|
|
3550
3564
|
homeDir
|
|
3551
3565
|
} : {
|
|
3552
3566
|
name: draft.name ?? current?.name ?? "",
|
|
3553
3567
|
prompt: draft.prompt ?? current?.prompt ?? "",
|
|
3554
|
-
permission:
|
|
3568
|
+
permission: permission2,
|
|
3555
3569
|
workDir: draft.workDir ?? current?.workDir ?? "",
|
|
3556
3570
|
maxTurns: draft.maxTurns ?? current?.maxTurns ?? SCHEDULE_DEFAULTS.maxTurns,
|
|
3557
|
-
maxBudgetUsd: current
|
|
3571
|
+
maxBudgetUsd: budgetOf(draft, current),
|
|
3558
3572
|
timeoutMs: draft.timeoutMs ?? current?.timeoutMs ?? SCHEDULE_DEFAULTS.timeoutMs,
|
|
3559
3573
|
trigger: draft.trigger ?? current?.trigger ?? { kind: "cron", cycle: "daily", at: "09:00" },
|
|
3560
3574
|
allowRules: draft.allowRules ?? current?.allowRules ?? [],
|
|
3575
|
+
bypassAcknowledged: permission2 === "bypass",
|
|
3561
3576
|
homeDir
|
|
3562
3577
|
};
|
|
3563
3578
|
return validateSchedule(merged).issues.map(
|
|
@@ -3590,13 +3605,27 @@ function structuralNotes(draft, current) {
|
|
|
3590
3605
|
}
|
|
3591
3606
|
return out;
|
|
3592
3607
|
}
|
|
3593
|
-
function
|
|
3608
|
+
function registrationLine(outcome) {
|
|
3609
|
+
if (outcome === void 0) return void 0;
|
|
3610
|
+
if (outcome.ok) {
|
|
3611
|
+
return "\u5DF2\u7ECF\u6CE8\u518C\u8FDB\u64CD\u4F5C\u7CFB\u7EDF\uFF0C\u5230\u70B9\u4F1A\u81EA\u5DF1\u8DD1\uFF08\u5173\u6389\u8FD9\u4E2A\u5E94\u7528\u4E5F\u8DD1\uFF09\u3002";
|
|
3612
|
+
}
|
|
3613
|
+
switch (outcome.reason) {
|
|
3614
|
+
case "unsupported-platform":
|
|
3615
|
+
return "\u26A0\uFE0F \u8FD9\u53F0\u673A\u5668\uFF08Linux\uFF09\u6682\u4E0D\u652F\u6301\u81EA\u52A8\u89E6\u53D1 \u2014\u2014 \u4EFB\u52A1\u5B58\u4E0B\u6765\u4E86\uFF0C\u4F46\u5230\u70B9\u4E0D\u4F1A\u81EA\u5DF1\u8DD1\u3002";
|
|
3616
|
+
case "refused":
|
|
3617
|
+
return outcome.refusal === "npx" ? "\u26A0\uFE0F \u6CA1\u6CE8\u518C\u8FDB\u64CD\u4F5C\u7CFB\u7EDF\uFF1A\u8FD9\u4E00\u4EFD\u662F npx \u4E34\u65F6\u8DD1\u8D77\u6765\u7684\uFF0C\u7F13\u5B58\u76EE\u5F55\u4E00\u6E05\u90A3\u6761\u4EFB\u52A1\u5C31\u5E9F\u3002\u88C5\u6210\u5168\u5C40\uFF08`npm i -g`\uFF09\u4E4B\u540E\u91CD\u5EFA\u4E00\u6B21\u624D\u6CE8\u518C\u5F97\u4E0A\u3002\u4EFB\u52A1\u672C\u8EAB\u5B58\u4E0B\u6765\u4E86\u3002" : "\u26A0\uFE0F \u6CA1\u6CE8\u518C\u8FDB\u64CD\u4F5C\u7CFB\u7EDF\uFF1A\u8FD9\u4E2A\u5BBF\u4E3B\u6CA1\u7ED9\u300C\u5230\u70B9\u4E86\u600E\u4E48\u8D77\u4E00\u6B21\u300D\u7684\u5165\u53E3\u3002\u4EFB\u52A1\u5B58\u4E0B\u6765\u4E86\uFF0C\u4F46\u5E94\u7528\u5173\u7740\u7684\u65F6\u5019\u5B83\u4E0D\u4F1A\u8DD1\u3002";
|
|
3618
|
+
case "backend-error":
|
|
3619
|
+
return `\u26A0\uFE0F \u6CE8\u518C\u8FDB\u64CD\u4F5C\u7CFB\u7EDF\u5931\u8D25\u4E86\uFF1A${outcome.detail}\u3002\u4EFB\u52A1\u5B58\u4E0B\u6765\u4E86\uFF0C\u4F46\u5230\u70B9\u4E0D\u4F1A\u81EA\u5DF1\u8DD1\u3002`;
|
|
3620
|
+
}
|
|
3621
|
+
}
|
|
3622
|
+
function summarizeProposal(draft, current, readOnly) {
|
|
3594
3623
|
const lines = [];
|
|
3595
3624
|
lines.push(
|
|
3596
3625
|
draft.action === "create" ? `\u8349\u7A3F\u5DF2\u7ECF\u6446\u5230\u7528\u6237\u773C\u524D\u4E86\uFF08\u4E00\u5F20\u5361\u7247\uFF0C\u6807\u9898\u300C${draft.name}\u300D\uFF09\u3002` : `\u6539\u52A8\u63D0\u6848\u5DF2\u7ECF\u6446\u5230\u7528\u6237\u773C\u524D\u4E86\uFF08\u9488\u5BF9\u300C${current?.name ?? draft.id}\u300D\uFF09\u3002`
|
|
3597
3626
|
);
|
|
3598
3627
|
lines.push(
|
|
3599
|
-
"\u5B83**\u8FD8\u6CA1\u6709\u751F\u6548\uFF0C\u4E5F\u6CA1\u6709\u843D\u5E93** \u2014\u2014 \u8981\u7528\u6237\
|
|
3628
|
+
readOnly ? "\u5B83**\u8FD8\u6CA1\u6709\u751F\u6548\uFF0C\u4E5F\u6CA1\u6709\u843D\u5E93** \u2014\u2014 \u4F60\u5728\u53EA\u8BFB\u8C03\u7814\u6A21\u5F0F\uFF08plan\uFF09\u4E0B\uFF0C\u8FD9\u4E00\u6863\u4E0D\u5199\u76D8\u3002\u8981\u7528\u6237\u81EA\u5DF1\u5BA1\u4E00\u904D\u3001\u70B9\u300C\u5BA1\u9605\u5E76\u4FDD\u5B58\u300D\u624D\u662F\u771F\u7684\u5EFA\u7ACB\u3002" : "\u5B83**\u8FD8\u6CA1\u6709\u843D\u5E93** \u2014\u2014 \u8FD9\u4E2A\u5BBF\u4E3B\u6CA1\u6709\u63A5\u5199\u5165\u8DEF\uFF0C\u8981\u7528\u6237\u81EA\u5DF1\u5BA1\u4E00\u904D\u3001\u70B9\u300C\u5BA1\u9605\u5E76\u4FDD\u5B58\u300D\u624D\u662F\u771F\u7684\u5EFA\u7ACB\u3002"
|
|
3600
3629
|
);
|
|
3601
3630
|
const widening = draftWidening(draft, current);
|
|
3602
3631
|
if (widening.length > 0) {
|
|
@@ -3607,16 +3636,77 @@ function summarize(draft, current) {
|
|
|
3607
3636
|
for (const note of structuralNotes(draft, current)) lines.push(`\u26A0\uFE0F ${note}`);
|
|
3608
3637
|
const cli = draftCommandLine(draft);
|
|
3609
3638
|
lines.push(
|
|
3610
|
-
cli === void 0 ? "\uFF08\u6CA1\u6709\u754C\u9762\u7684\u5BBF\u4E3B\u4E0A\uFF1A\u6539\u4E00\u6761\u5DF2\u6709\u4EFB\u52A1\u4ECA\u5929\u53EA\u6709\u754C\u9762\u90A3\u6761\u8DEF \u2014\u2014 `epoch schedule` \u5E95\u4E0B\u6CA1\u6709\u6539\u5B57\u6BB5\u7684\u5B50\u547D\u4EE4\uFF0C\u53EA\u6709 enable / disable / rm\u3002\u522B\u7F16\u4E00\u6761 update \u51FA\u6765\u3002\uFF09" : `\u6CA1\u6709\u754C\u9762\u7684\u5BBF\u4E3B\u4E0A\uFF0C\u7B49\u4EF7\u7684\u547D\u4EE4\u884C\u662F\
|
|
3639
|
+
cli === void 0 ? "\uFF08\u6CA1\u6709\u754C\u9762\u7684\u5BBF\u4E3B\u4E0A\uFF1A\u6539\u4E00\u6761\u5DF2\u6709\u4EFB\u52A1\u4ECA\u5929\u53EA\u6709\u754C\u9762\u90A3\u6761\u8DEF \u2014\u2014 `epoch schedule` \u5E95\u4E0B\u6CA1\u6709\u6539\u5B57\u6BB5\u7684\u5B50\u547D\u4EE4\uFF0C\u53EA\u6709 enable / disable / rm\u3002\u522B\u7F16\u4E00\u6761 update \u51FA\u6765\u3002\uFF09" : `\u6CA1\u6709\u754C\u9762\u7684\u5BBF\u4E3B\u4E0A\uFF0C\u7B49\u4EF7\u7684\u547D\u4EE4\u884C\u662F\uFF1A
|
|
3611
3640
|
${cli}`
|
|
3612
3641
|
);
|
|
3613
|
-
lines.push("\u522B\u91CD\u590D\u63D0\u4EA4\u540C\u4E00\u4EFD\u8349\u7A3F\u7B49\u5B83\u300C\u751F\u6548\u300D\u2014\u2014 \u7528\u6237\u4EC0\u4E48\u65F6\u5019\u5BA1\u662F\u4ED6\u7684\u4E8B\uFF0C\u4F60\u8FD9\u4E00\u8F6E\u5230\u6B64\u4E3A\u6B62\u3002");
|
|
3614
3642
|
return lines.join("\n");
|
|
3615
3643
|
}
|
|
3644
|
+
function summarizeSaved(draft, def, registration, current) {
|
|
3645
|
+
const lines = [];
|
|
3646
|
+
lines.push(
|
|
3647
|
+
`${SCHEDULE_DRAFT_SAVED_MARK}${def.id}`,
|
|
3648
|
+
draft.action === "create" ? `\u5DF2\u7ECF\u5EFA\u7ACB\u5E76\u751F\u6548\uFF1A\u300C${def.name}\u300D\u3002` : `\u5DF2\u7ECF\u6539\u597D\u4E86\uFF1A\u300C${current?.name ?? def.name}\u300D\u3002`
|
|
3649
|
+
);
|
|
3650
|
+
const when = draft.action === "create" ? draft.trigger : draft.trigger ?? current?.trigger;
|
|
3651
|
+
if (when !== void 0) lines.push(`\u5230\u70B9\uFF1A${JSON.stringify(when)}`);
|
|
3652
|
+
const permission2 = draft.permission ?? current?.permission;
|
|
3653
|
+
if (permission2 !== void 0) lines.push(`\u6743\u9650\u6863\uFF1A${permission2}`);
|
|
3654
|
+
const registered = registrationLine(registration);
|
|
3655
|
+
if (registered !== void 0) lines.push(registered);
|
|
3656
|
+
const widening = draftWidening(draft, current);
|
|
3657
|
+
if (widening.length > 0) {
|
|
3658
|
+
lines.push(
|
|
3659
|
+
`\u26A0\uFE0F \u8FD9\u6B21\u6539\u52A8\u653E\u5BBD\u4E86\u6388\u6743\u9762\uFF1A${widening.map((k) => WIDENING_TEXT[k]).join("\uFF1B")}\u3002\u5728\u4F60\u7684\u56DE\u590D\u91CC**\u4E3B\u52A8**\u628A\u8FD9\u4E00\u70B9\u8BF4\u7ED9\u7528\u6237\u542C \u2014\u2014 \u5B83\u5DF2\u7ECF\u751F\u6548\u4E86\uFF0C\u90A3\u4E2A\u4EBA\u53EA\u6709\u9760\u4F60\u8FD9\u53E5\u8BDD\u624D\u77E5\u9053\u521A\u624D\u591A\u653E\u884C\u4E86\u4EC0\u4E48\u3002`
|
|
3660
|
+
);
|
|
3661
|
+
}
|
|
3662
|
+
for (const note of structuralNotes(draft, current)) lines.push(`\u26A0\uFE0F ${note}`);
|
|
3663
|
+
lines.push(
|
|
3664
|
+
"\u5728\u4F60\u7684\u56DE\u590D\u91CC\u7528\u4E00\u53E5\u8BDD\u4EA4\u4EE3\u300C\u5EFA\u4E86\u4EC0\u4E48\u3001\u4EC0\u4E48\u65F6\u5019\u8DD1\u300D\u5C31\u591F\u4E86\u3002**\u522B\u518D\u8BF4\u300C\u8981\u4E0D\u8981\u6211\u5EFA\u4E00\u6761\u300D** \u2014\u2014 \u5B83\u5DF2\u7ECF\u5728\u4E86\uFF1B\u7528\u6237\u60F3\u64A4\u6389\uFF0C\u5361\u7247\u4E0A\u6709\u64A4\u9500\u952E\uFF0C\u4E5F\u53EF\u4EE5\u53BB\u81EA\u52A8\u5316\u9762\u677F\u5220\u3002"
|
|
3665
|
+
);
|
|
3666
|
+
return lines.join("\n");
|
|
3667
|
+
}
|
|
3668
|
+
async function persist(save, draft, current) {
|
|
3669
|
+
const permission2 = draft.permission ?? current?.permission ?? "default";
|
|
3670
|
+
const acknowledged = { bypassAcknowledged: permission2 === "bypass" };
|
|
3671
|
+
if (draft.action === "create") {
|
|
3672
|
+
return save.create(
|
|
3673
|
+
{
|
|
3674
|
+
name: draft.name,
|
|
3675
|
+
prompt: draft.prompt,
|
|
3676
|
+
permission: draft.permission,
|
|
3677
|
+
maxBudgetUsd: budgetOf(draft),
|
|
3678
|
+
trigger: draft.trigger,
|
|
3679
|
+
...draft.workDir === void 0 ? {} : { workDir: draft.workDir },
|
|
3680
|
+
...draft.allowTools === void 0 ? {} : { allowTools: draft.allowTools },
|
|
3681
|
+
...draft.allowOperations === void 0 ? {} : { allowOperations: draft.allowOperations },
|
|
3682
|
+
...draft.allowRules === void 0 ? {} : { allowRules: draft.allowRules }
|
|
3683
|
+
},
|
|
3684
|
+
acknowledged
|
|
3685
|
+
);
|
|
3686
|
+
}
|
|
3687
|
+
return save.update(
|
|
3688
|
+
draft.id,
|
|
3689
|
+
{
|
|
3690
|
+
...draft.name === void 0 ? {} : { name: draft.name },
|
|
3691
|
+
...draft.prompt === void 0 ? {} : { prompt: draft.prompt },
|
|
3692
|
+
...draft.permission === void 0 ? {} : { permission: draft.permission },
|
|
3693
|
+
...draft.trigger === void 0 ? {} : { trigger: draft.trigger },
|
|
3694
|
+
...draft.workDir === void 0 ? {} : { workDir: draft.workDir },
|
|
3695
|
+
...draft.enabled === void 0 ? {} : { enabled: draft.enabled },
|
|
3696
|
+
...draft.maxTurns === void 0 ? {} : { maxTurns: draft.maxTurns },
|
|
3697
|
+
...draft.timeoutMs === void 0 ? {} : { timeoutMs: draft.timeoutMs },
|
|
3698
|
+
...draft.maxBudgetUsd === void 0 ? {} : { maxBudgetUsd: draft.maxBudgetUsd },
|
|
3699
|
+
...draft.allowTools === void 0 ? {} : { allowTools: draft.allowTools },
|
|
3700
|
+
...draft.allowOperations === void 0 ? {} : { allowOperations: draft.allowOperations },
|
|
3701
|
+
...draft.allowRules === void 0 ? {} : { allowRules: draft.allowRules }
|
|
3702
|
+
},
|
|
3703
|
+
acknowledged
|
|
3704
|
+
);
|
|
3705
|
+
}
|
|
3616
3706
|
function createScheduleDraftTool(deps) {
|
|
3617
3707
|
return {
|
|
3618
3708
|
name: SCHEDULE_DRAFT_TOOL,
|
|
3619
|
-
description: "\
|
|
3709
|
+
description: "\u5EFA\u4E00\u6761\u5B9A\u65F6\u4EFB\u52A1\uFF0C\u6216\u8005\u6539\u4E00\u6761\u5DF2\u6709\u7684\u3002\u5B9A\u65F6\u4EFB\u52A1\u662F\u300C\u5230\u70B9\u4E86\u81EA\u5DF1\u8DD1\u4E00\u6B21\u300D\u2014\u2014\u7528\u6237\u8BF4\u300C\u4EE5\u540E\u6BCF\u5929/\u6BCF\u5468\u5E2E\u6211\u505A\u67D0\u4EF6\u4E8B\u300D\u300C\u5B9A\u671F\u68C0\u67E5\u67D0\u67D0\u300D\uFF0C\u6216\u8005\u4F60\u53D1\u73B0\u67D0\u4EF6\u4E8B\u4ED6\u6BCF\u6B21\u90FD\u8981\u624B\u52A8\u505A\u4E00\u904D\u65F6\uFF0C\u7528\u5B83\u3002action=list \u770B\u73B0\u6709\u4EFB\u52A1\uFF08\u8981\u6539\u67D0\u6761\u5FC5\u987B\u5148 list \u62FF\u5230 id\uFF09\uFF1Baction=create \u76F4\u63A5\u5EFA\u4E00\u6761\uFF1Baction=update \u76F4\u63A5\u6539\u4E00\u6761\u3002\u26A0\uFE0F **\u5B83\u4EA4\u4E0A\u53BB\u5C31\u751F\u6548**\uFF08plan \u53EA\u8BFB\u6863\u4E0B\u9664\u5916\uFF0C\u90A3\u4E00\u6863\u53EA\u4EA4\u63D0\u6848\uFF09\u2014\u2014 \u5EFA\u5B8C\u5728\u4F60\u7684\u56DE\u590D\u91CC\u4EA4\u4EE3\u4E00\u53E5\u5C31\u884C\uFF0C\u522B\u95EE\u300C\u8981\u4E0D\u8981\u6211\u5EFA\u300D\u3002\u9884\u7B97\u4E0D\u7ED9\u5C31\u662F 200 \u7F8E\u5143\uFF1B\u8FD9\u6D3B\u660E\u663E\u66F4\u8F7B\u6216\u66F4\u91CD\u65F6\u81EA\u5DF1\u7ED9 maxBudgetUsd\u3002\u6743\u9650\u6863 plan/default/acceptEdits/auto/bypass \u90FD\u80FD\u63D0 \u2014\u2014 \u4F46**\u9ED8\u8BA4\u7528 plan**\uFF1A\u53EA\u8BFB\u6863\u5929\u7136\u96F6\u6388\u6743\u9762\uFF0C\u9700\u8981\u5199\u4E1C\u897F\u518D\u7528 default \u52A0\u4E00\u4EFD\u7CBE\u786E\u7684 allowRules\uFF08\u6BD4\u5982 terminal(git status)\uFF09\uFF0C\u522B\u4E00\u4E0A\u6765\u5C31 bypass\u3002",
|
|
3620
3710
|
parameters: {
|
|
3621
3711
|
type: "object",
|
|
3622
3712
|
properties: {
|
|
@@ -3627,7 +3717,7 @@ function createScheduleDraftTool(deps) {
|
|
|
3627
3717
|
},
|
|
3628
3718
|
note: {
|
|
3629
3719
|
type: "string",
|
|
3630
|
-
description: "\u4E3A\u4EC0\u4E48\u5EFA\
|
|
3720
|
+
description: "\u4E3A\u4EC0\u4E48\u5EFA\u8FD9\u6761\uFF0C\u4E00\u53E5\u8BDD\u3002create / update \u5FC5\u586B\uFF0C\u4F1A\u5370\u5728\u7528\u6237\u770B\u5230\u7684\u5361\u7247\u4E0A\uFF1B\u8BF4\u4E0D\u51FA\u771F\u5B9E\u7406\u7531\u5C31\u522B\u63D0\u8FD9\u4E2A\u5EFA\u8BAE"
|
|
3631
3721
|
},
|
|
3632
3722
|
id: { type: "string", description: "\u6539\u54EA\u4E00\u6761\u3002update \u5FC5\u586B\uFF0C\u4ECE action=list \u91CC\u62FF" },
|
|
3633
3723
|
name: { type: "string", description: "\u4EFB\u52A1\u540D\uFF0C\u7528\u6237\u5728\u5217\u8868\u91CC\u770B\u5230\u7684\u5C31\u662F\u5B83" },
|
|
@@ -3660,8 +3750,12 @@ function createScheduleDraftTool(deps) {
|
|
|
3660
3750
|
},
|
|
3661
3751
|
permission: {
|
|
3662
3752
|
type: "string",
|
|
3663
|
-
description: "\u6743\u9650\u6863\u3002plan=\u53EA\u8BFB\uFF08\u8BFB\u4E00\u904D\u5199\u4EFD\u62A5\u544A\u7684\u4EFB\u52A1\u5C31\u8BE5\u7528\u5B83\uFF0C\u5929\u7136\u96F6\u6388\u6743\u9762\uFF09\uFF1Bdefault=\u6309\u9700\u786E\u8BA4\uFF1BacceptEdits=\u81EA\u52A8\u63A5\u53D7\u6539\u52A8\uFF1Bauto=\u4E0D\u518D\u786E\u8BA4",
|
|
3664
|
-
enum: ["plan", "default", "acceptEdits", "auto"]
|
|
3753
|
+
description: "\u6743\u9650\u6863\u3002plan=\u53EA\u8BFB\uFF08\u8BFB\u4E00\u904D\u5199\u4EFD\u62A5\u544A\u7684\u4EFB\u52A1\u5C31\u8BE5\u7528\u5B83\uFF0C\u5929\u7136\u96F6\u6388\u6743\u9762\uFF09\uFF1Bdefault=\u6309\u9700\u786E\u8BA4\uFF1BacceptEdits=\u81EA\u52A8\u63A5\u53D7\u6539\u52A8\uFF1Bauto=\u4E0D\u518D\u786E\u8BA4\uFF1Bbypass=\u8DF3\u8FC7\u5168\u90E8\u68C0\u67E5\uFF08**\u6700\u540E\u624B\u6BB5**\uFF1A\u5230\u70B9\u4E86\u5B83\u60F3\u8DD1\u4EC0\u4E48\u5C31\u8DD1\u4EC0\u4E48\uFF09",
|
|
3754
|
+
enum: ["plan", "default", "acceptEdits", "auto", "bypass"]
|
|
3755
|
+
},
|
|
3756
|
+
maxBudgetUsd: {
|
|
3757
|
+
type: "number",
|
|
3758
|
+
description: "\u6BCF\u6B21\u6700\u591A\u82B1\u591A\u5C11\u94B1\uFF08\u7F8E\u5143\uFF0C\u8981\u5927\u4E8E 0\uFF09\u3002\u4E0D\u7ED9\u5C31\u662F 200\u3002\u8FD9\u6D3B\u660E\u663E\u66F4\u8F7B\uFF08\u8BFB\u4E00\u4E2A\u6587\u4EF6\u3001\u53D1\u4E00\u6761\u6D88\u606F\uFF09\u5C31\u7ED9\u5C0F\u4E00\u70B9\uFF0C\u660E\u663E\u66F4\u91CD\uFF08\u626B\u5927\u4ED3\u3001\u591A\u8F6E\u8C03\u7814\uFF09\u5C31\u653E\u5927 \u2014\u2014 \u82B1\u8D85\u4E86\u90A3\u4E00\u8F6E\u4F1A\u505C\u4F4F"
|
|
3665
3759
|
},
|
|
3666
3760
|
allowTools: {
|
|
3667
3761
|
type: "array",
|
|
@@ -3687,58 +3781,71 @@ function createScheduleDraftTool(deps) {
|
|
|
3687
3781
|
exposure: ToolExposure.Direct,
|
|
3688
3782
|
supportsParallel: false,
|
|
3689
3783
|
annotations: {
|
|
3690
|
-
readOnlyHint:
|
|
3691
|
-
destructiveHint:
|
|
3692
|
-
idempotentHint:
|
|
3784
|
+
readOnlyHint: false,
|
|
3785
|
+
destructiveHint: true,
|
|
3786
|
+
idempotentHint: false,
|
|
3693
3787
|
openWorldHint: false
|
|
3694
3788
|
},
|
|
3695
3789
|
operation: "file_read",
|
|
3696
3790
|
describeTarget: (args) => `schedule_draft:${String(args["action"] ?? "list")}`,
|
|
3697
|
-
execute(rawArgs,
|
|
3791
|
+
async execute(rawArgs, ctx) {
|
|
3698
3792
|
const startedAt = Date.now();
|
|
3699
3793
|
const action = rawArgs["action"];
|
|
3700
3794
|
if (action === "list") {
|
|
3701
3795
|
const rows = deps.list();
|
|
3702
|
-
return
|
|
3703
|
-
|
|
3704
|
-
rows.length === 0 ? "\u4E00\u6761\u5B9A\u65F6\u4EFB\u52A1\u90FD\u8FD8\u6CA1\u6709\u3002\u8981\u65B0\u5EFA\u5C31\u7528 action=create\u3002" : `\u73B0\u6709 ${rows.length} \u6761\uFF1A
|
|
3796
|
+
return say4(
|
|
3797
|
+
rows.length === 0 ? "\u4E00\u6761\u5B9A\u65F6\u4EFB\u52A1\u90FD\u8FD8\u6CA1\u6709\u3002\u8981\u65B0\u5EFA\u5C31\u7528 action=create\u3002" : `\u73B0\u6709 ${rows.length} \u6761\uFF1A
|
|
3705
3798
|
${rows.map(describeRow).join("\n")}`,
|
|
3706
|
-
|
|
3707
|
-
|
|
3708
|
-
)
|
|
3799
|
+
true,
|
|
3800
|
+
startedAt
|
|
3709
3801
|
);
|
|
3710
3802
|
}
|
|
3711
3803
|
const parsed = parseScheduleDraft(rawArgs);
|
|
3712
|
-
if (!parsed.ok) return
|
|
3804
|
+
if (!parsed.ok) return say4(parsed.message, false, startedAt);
|
|
3713
3805
|
const draft = parsed.value;
|
|
3714
3806
|
const current = draft.action === "update" ? deps.get(draft.id) : void 0;
|
|
3715
3807
|
if (draft.action === "update" && current === void 0) {
|
|
3716
|
-
return
|
|
3717
|
-
|
|
3808
|
+
return say4(
|
|
3809
|
+
`\u6CA1\u6709 id \u4E3A ${draft.id} \u7684\u4EFB\u52A1\u3002\u5148\u7528 action=list \u770B\u4E00\u773C\u73B0\u6709\u7684\u3002`,
|
|
3810
|
+
false,
|
|
3811
|
+
startedAt
|
|
3718
3812
|
);
|
|
3719
3813
|
}
|
|
3720
3814
|
const issues = validateDraft(draft, deps.homeDir, current);
|
|
3721
3815
|
if (issues.length > 0) {
|
|
3722
|
-
return
|
|
3723
|
-
|
|
3724
|
-
|
|
3725
|
-
|
|
3726
|
-
startedAt
|
|
3727
|
-
)
|
|
3816
|
+
return say4(
|
|
3817
|
+
`\u8FD9\u4EFD\u63D0\u6848\u5B58\u4E0D\u4E0B\u6765\uFF0C\u5148\u6539\u8FD9\u51E0\u5904\u518D\u8BF4\uFF1A${issues.join("\u3001")}\u3002\uFF08\u8FD9\u4E9B\u662F\u6821\u9A8C\u7801\uFF0C\u542B\u4E49\u770B\u5B57\u9762\uFF1Bdetail \u62EC\u5728\u540E\u9762\uFF09`,
|
|
3818
|
+
false,
|
|
3819
|
+
startedAt
|
|
3728
3820
|
);
|
|
3729
3821
|
}
|
|
3730
3822
|
const unattended = unattendedIssues(draft);
|
|
3731
3823
|
if (unattended.length > 0) {
|
|
3732
|
-
return
|
|
3733
|
-
|
|
3734
|
-
`\u8FD9\u4EFD\u8349\u7A3F\u4FDD\u5B58\u5F97\u4E86\uFF0C\u4F46\u5B83\u5230\u70B9\u4E86**\u8DD1\u4E0D\u51FA\u7ED3\u679C** \u2014\u2014 \u5B9A\u65F6\u4EFB\u52A1\u662F\u65E0\u4EBA\u503C\u5B88\u7684\uFF0C\u6CA1\u4EBA\u5728\u65C1\u8FB9\u56DE\u8BDD\u3002\u6539\u5B8C\u518D\u4EA4\uFF1A
|
|
3824
|
+
return say4(
|
|
3825
|
+
`\u8FD9\u4EFD\u63D0\u6848\u5B58\u5F97\u4E0B\u6765\uFF0C\u4F46\u5B83\u5230\u70B9\u4E86**\u8DD1\u4E0D\u51FA\u7ED3\u679C** \u2014\u2014 \u5B9A\u65F6\u4EFB\u52A1\u662F\u65E0\u4EBA\u503C\u5B88\u7684\uFF0C\u6CA1\u4EBA\u5728\u65C1\u8FB9\u56DE\u8BDD\u3002\u6539\u5B8C\u518D\u4EA4\uFF1A
|
|
3735
3826
|
${unattended.map((x) => `\xB7 ${x}`).join("\n")}`,
|
|
3736
|
-
|
|
3737
|
-
|
|
3738
|
-
|
|
3827
|
+
false,
|
|
3828
|
+
startedAt
|
|
3829
|
+
);
|
|
3830
|
+
}
|
|
3831
|
+
const readOnly = ctx.permissionLevel === "plan";
|
|
3832
|
+
if (readOnly || deps.save === void 0) {
|
|
3833
|
+
return say4(summarizeProposal(draft, current, readOnly), true, startedAt);
|
|
3834
|
+
}
|
|
3835
|
+
const saved = await persist(deps.save, draft, current);
|
|
3836
|
+
if (saved.issues.length > 0) {
|
|
3837
|
+
const codes = saved.issues.map((x) => x.detail ? `${x.code}\uFF08${x.detail}\uFF09` : x.code);
|
|
3838
|
+
return say4(`\u5F15\u64CE\u62D2\u7EDD\u4E86\u8FD9\u4EFD\u63D0\u6848\uFF0C\u4E00\u4E2A\u5B57\u90FD\u6CA1\u5199\uFF1A${codes.join("\u3001")}\u3002`, false, startedAt);
|
|
3839
|
+
}
|
|
3840
|
+
const def = saved.schedule;
|
|
3841
|
+
if (def === void 0) {
|
|
3842
|
+
return say4(
|
|
3843
|
+
"\u5F15\u64CE\u8BF4\u5B58\u4E0B\u6765\u4E86\uFF0C\u4F46\u6CA1\u56DE\u90A3\u6761\u4EFB\u52A1 \u2014\u2014 \u53BB\u81EA\u52A8\u5316\u9762\u677F\u770B\u4E00\u773C\u5B83\u5230\u5E95\u5728\u4E0D\u5728\u3002",
|
|
3844
|
+
false,
|
|
3845
|
+
startedAt
|
|
3739
3846
|
);
|
|
3740
3847
|
}
|
|
3741
|
-
return
|
|
3848
|
+
return say4(summarizeSaved(draft, def, saved.registration, current), true, startedAt);
|
|
3742
3849
|
}
|
|
3743
3850
|
};
|
|
3744
3851
|
}
|
|
@@ -4229,41 +4336,41 @@ function clampWindow(raw, fallback2, max) {
|
|
|
4229
4336
|
function stamp2(ms) {
|
|
4230
4337
|
return new Date(ms).toISOString().slice(0, 16).replace("T", " ");
|
|
4231
4338
|
}
|
|
4232
|
-
function
|
|
4339
|
+
function budgetOf2(total) {
|
|
4233
4340
|
const shares = ANCHOR_SHARE + Math.max(0, total - 1);
|
|
4234
4341
|
const unit = Math.max(MIN_BODY, Math.floor(BODY_BUDGET / shares));
|
|
4235
4342
|
return { anchor: unit * ANCHOR_SHARE, other: unit };
|
|
4236
4343
|
}
|
|
4237
|
-
function body(text,
|
|
4344
|
+
function body(text, budget2) {
|
|
4238
4345
|
const flat = text.replace(/\r\n/g, "\n").trimEnd();
|
|
4239
|
-
if (flat.length <=
|
|
4240
|
-
const rest = flat.length -
|
|
4241
|
-
return `${flat.slice(0,
|
|
4346
|
+
if (flat.length <= budget2) return flat;
|
|
4347
|
+
const rest = flat.length - budget2;
|
|
4348
|
+
return `${flat.slice(0, budget2)}
|
|
4242
4349
|
\u2026[cut ${rest} more chars \u2014 lower before/after to spend the budget on fewer messages]`;
|
|
4243
4350
|
}
|
|
4244
4351
|
function surfaceOf(record, isCurrent) {
|
|
4245
4352
|
if (!isCurrent) return record.surface === "active" ? "active there" : "compacted there";
|
|
4246
4353
|
return record.surface === "active" ? "still in your context" : "compacted out of your context";
|
|
4247
4354
|
}
|
|
4248
|
-
function renderRecord(record, mark,
|
|
4355
|
+
function renderRecord(record, mark, budget2, isCurrent) {
|
|
4249
4356
|
const tool = record.toolName ? ` \xB7 ${record.toolName}` : "";
|
|
4250
4357
|
return [
|
|
4251
4358
|
`${mark} #${record.messageId} [${record.role}${tool} \xB7 ${stamp2(record.timestamp)} \xB7 ${surfaceOf(record, isCurrent)}]`,
|
|
4252
|
-
` ${body(record.content,
|
|
4359
|
+
` ${body(record.content, budget2).split("\n").join("\n ")}`
|
|
4253
4360
|
].join("\n");
|
|
4254
4361
|
}
|
|
4255
4362
|
function renderWindow(out, sessionId, isCurrent) {
|
|
4256
4363
|
const anchor = out.anchor;
|
|
4257
4364
|
if (!anchor) return "";
|
|
4258
4365
|
const count = out.before.length + out.after.length + 1;
|
|
4259
|
-
const
|
|
4366
|
+
const budget2 = budgetOf2(count);
|
|
4260
4367
|
return [
|
|
4261
4368
|
`Session ${sessionId}${isCurrent ? " (this session)" : ""} \u2014 ${out.title || "(untitled)"}`,
|
|
4262
4369
|
`${count} of ${out.total} message(s), around #${anchor.messageId}:`,
|
|
4263
4370
|
"",
|
|
4264
|
-
...out.before.map((r) => renderRecord(r, " ",
|
|
4265
|
-
renderRecord(anchor, "\xBB",
|
|
4266
|
-
...out.after.map((r) => renderRecord(r, " ",
|
|
4371
|
+
...out.before.map((r) => renderRecord(r, " ", budget2.other, isCurrent)),
|
|
4372
|
+
renderRecord(anchor, "\xBB", budget2.anchor, isCurrent),
|
|
4373
|
+
...out.after.map((r) => renderRecord(r, " ", budget2.other, isCurrent))
|
|
4267
4374
|
].join("\n");
|
|
4268
4375
|
}
|
|
4269
4376
|
function createSessionMessagesReadTool(deps) {
|
|
@@ -5976,6 +6083,7 @@ var CommandFrontmatterSchema = z.object({
|
|
|
5976
6083
|
});
|
|
5977
6084
|
var FRONTMATTER_KEYS3 = Object.keys(CommandFrontmatterSchema.shape);
|
|
5978
6085
|
var MAX_POSITIONAL = 9;
|
|
6086
|
+
var ARG_PREVIEW_MAX = 120;
|
|
5979
6087
|
var UTILITY_KEYWORD = "utility";
|
|
5980
6088
|
function loadCommands(files, source, prefix) {
|
|
5981
6089
|
const commands = [];
|
|
@@ -6081,6 +6189,14 @@ function expandCommand(def, args, opts = {}) {
|
|
|
6081
6189
|
})
|
|
6082
6190
|
);
|
|
6083
6191
|
}
|
|
6192
|
+
if (trimmed !== "" && used.size === 0 && !def.prompt.includes("$ARGUMENTS")) {
|
|
6193
|
+
warnings.push(
|
|
6194
|
+
t("custom_command.unused_args", {
|
|
6195
|
+
name: def.name,
|
|
6196
|
+
args: trimmed.length > ARG_PREVIEW_MAX ? `${trimmed.slice(0, ARG_PREVIEW_MAX)}\u2026` : trimmed
|
|
6197
|
+
})
|
|
6198
|
+
);
|
|
6199
|
+
}
|
|
6084
6200
|
const model = resolveCommandModel(def, opts, warnings);
|
|
6085
6201
|
return {
|
|
6086
6202
|
prompt: out,
|
|
@@ -6156,7 +6272,7 @@ function loadCommandDefinitions(opts) {
|
|
|
6156
6272
|
}
|
|
6157
6273
|
diags?.ok(
|
|
6158
6274
|
SLASH_COMMANDS_DIAG_MODULE,
|
|
6159
|
-
|
|
6275
|
+
summarize(commands.length, plugin.commands.length, user, project)
|
|
6160
6276
|
);
|
|
6161
6277
|
return {
|
|
6162
6278
|
commands,
|
|
@@ -6167,7 +6283,7 @@ function loadCommandDefinitions(opts) {
|
|
|
6167
6283
|
issues: [...plugin.issues, ...user.issues, ...project.issues]
|
|
6168
6284
|
};
|
|
6169
6285
|
}
|
|
6170
|
-
function
|
|
6286
|
+
function summarize(total, pluginCount, user, project) {
|
|
6171
6287
|
if (total === 0) return t("custom_command.none");
|
|
6172
6288
|
const parts = [
|
|
6173
6289
|
t("custom_command.count_user", { count: user.commands.length }),
|
|
@@ -8924,7 +9040,7 @@ async function snapshotFiles(paths) {
|
|
|
8924
9040
|
}
|
|
8925
9041
|
async function collectDiffs(before, workDir) {
|
|
8926
9042
|
const out = [];
|
|
8927
|
-
let
|
|
9043
|
+
let budget2 = MAX_CALL_BYTES;
|
|
8928
9044
|
for (const [path, old] of before) {
|
|
8929
9045
|
if (old.kind === "opaque") continue;
|
|
8930
9046
|
const now = await readSnapshot(path);
|
|
@@ -8932,8 +9048,8 @@ async function collectDiffs(before, workDir) {
|
|
|
8932
9048
|
if (old.kind === "absent" && now.kind === "absent") continue;
|
|
8933
9049
|
if (old.kind === "text" && now.kind === "text" && old.text === now.text) continue;
|
|
8934
9050
|
const bytes = (old.kind === "text" ? old.bytes : 0) + (now.kind === "text" ? now.bytes : 0);
|
|
8935
|
-
if (bytes >
|
|
8936
|
-
|
|
9051
|
+
if (bytes > budget2) continue;
|
|
9052
|
+
budget2 -= bytes;
|
|
8937
9053
|
out.push({
|
|
8938
9054
|
filePath: workspaceDisplayPath(path, workDir),
|
|
8939
9055
|
...old.kind === "text" ? { oldContent: old.text } : {},
|
|
@@ -9521,10 +9637,10 @@ function renderSettings(s) {
|
|
|
9521
9637
|
bits.push(`\u4E0A\u4E0B\u6587\u7A97\u53E3 ${s.contextLength}`);
|
|
9522
9638
|
bits.push(`\u81EA\u52A8\u538B\u7F29 ${s.compression.enabled ? `\u5F00\uFF08${s.compression.threshold}\uFF09` : "\u5173"}`);
|
|
9523
9639
|
bits.push(`\u7EC8\u7AEF\u6C99\u7BB1 ${s.sandboxTerminal ? "\u5F00" : "\u5173"}`);
|
|
9524
|
-
const
|
|
9525
|
-
if (s.budget?.maxCostUsd !== void 0)
|
|
9526
|
-
if (s.budget?.maxTokens !== void 0)
|
|
9527
|
-
bits.push(`\u9884\u7B97\u4E0A\u9650 ${
|
|
9640
|
+
const budget2 = [];
|
|
9641
|
+
if (s.budget?.maxCostUsd !== void 0) budget2.push(`$${s.budget.maxCostUsd}`);
|
|
9642
|
+
if (s.budget?.maxTokens !== void 0) budget2.push(`${s.budget.maxTokens} tokens`);
|
|
9643
|
+
bits.push(`\u9884\u7B97\u4E0A\u9650 ${budget2.length > 0 ? budget2.join(" / ") : "\u672A\u8BBE"}`);
|
|
9528
9644
|
return [
|
|
9529
9645
|
"<settings>",
|
|
9530
9646
|
bits.join(" \xB7 "),
|
|
@@ -9641,7 +9757,7 @@ function extensionFor(mediaType) {
|
|
|
9641
9757
|
if (sub === "jpeg") return ".jpg";
|
|
9642
9758
|
return /^[a-z0-9]{1,8}$/.test(sub) ? `.${sub}` : ".bin";
|
|
9643
9759
|
}
|
|
9644
|
-
function
|
|
9760
|
+
function persist2(bytes, mediaType, dir, hint) {
|
|
9645
9761
|
const digest2 = createHash("sha256").update(bytes).digest("hex").slice(0, 16);
|
|
9646
9762
|
const safeHint = (hint ?? "").replace(/[^A-Za-z0-9_-]/g, "").slice(0, 40);
|
|
9647
9763
|
const stem = safeHint ? `${safeHint}-${digest2}` : digest2;
|
|
@@ -9682,7 +9798,7 @@ function admitArtifact(raw, policy) {
|
|
|
9682
9798
|
const bytes = Buffer.from(raw.base64, "base64");
|
|
9683
9799
|
const byteLen = bytes.length;
|
|
9684
9800
|
const size = raw.kind === "image" ? readImageSize(bytes) : void 0;
|
|
9685
|
-
const path = policy.artifactsDir ?
|
|
9801
|
+
const path = policy.artifactsDir ? persist2(bytes, raw.mediaType, policy.artifactsDir, raw.filename) : void 0;
|
|
9686
9802
|
const dims = size ? ` ${size.width}\xD7${size.height}` : "";
|
|
9687
9803
|
const head = raw.note ? `${raw.note} ` : "";
|
|
9688
9804
|
const reason9 = rejectionReason(raw, policy, byteLen, size);
|
|
@@ -11768,7 +11884,7 @@ function toAbsolute2(path, workDir) {
|
|
|
11768
11884
|
}
|
|
11769
11885
|
var MAX_TOOL_OUTPUT = 3e4;
|
|
11770
11886
|
var MAX_SUB_CALL_OUTPUT = CODE_MODE_LIMITS.maxValueChars;
|
|
11771
|
-
function
|
|
11887
|
+
function budgetOf3(tool, depth, path = "success") {
|
|
11772
11888
|
if (tool.governsOwnOutput && path === "success") return Number.POSITIVE_INFINITY;
|
|
11773
11889
|
return depth > 0 ? MAX_SUB_CALL_OUTPUT : MAX_TOOL_OUTPUT;
|
|
11774
11890
|
}
|
|
@@ -12019,7 +12135,7 @@ var ToolExecutor = class {
|
|
|
12019
12135
|
permissionLevel: this.deps.permissionManager?.getLevel() || "auto",
|
|
12020
12136
|
...signal ? { signal } : {},
|
|
12021
12137
|
...onOutput ? { onOutput } : {},
|
|
12022
|
-
outputBudget:
|
|
12138
|
+
outputBudget: budgetOf3(et, depth),
|
|
12023
12139
|
...depth < MAX_SUB_CALL_DEPTH ? { callTool: this.subCallChannel(sessionId, signal, span, depth) } : {}
|
|
12024
12140
|
});
|
|
12025
12141
|
if (snapshotted.length > 0) {
|
|
@@ -12051,7 +12167,7 @@ var ToolExecutor = class {
|
|
|
12051
12167
|
success: true,
|
|
12052
12168
|
output: this.renderOutput(
|
|
12053
12169
|
et,
|
|
12054
|
-
appendArtifactSummaries(text, artifacts,
|
|
12170
|
+
appendArtifactSummaries(text, artifacts, budgetOf3(et, depth), shapeOf(r.output))
|
|
12055
12171
|
),
|
|
12056
12172
|
...artifacts.length > 0 ? { artifacts } : {},
|
|
12057
12173
|
...diffs.length > 0 ? { diffs } : {}
|
|
@@ -12062,7 +12178,7 @@ var ToolExecutor = class {
|
|
|
12062
12178
|
success: false,
|
|
12063
12179
|
output: this.renderOutput(
|
|
12064
12180
|
et,
|
|
12065
|
-
truncateForModel(failureText(r),
|
|
12181
|
+
truncateForModel(failureText(r), budgetOf3(et, depth, "failure"), "text")
|
|
12066
12182
|
)
|
|
12067
12183
|
});
|
|
12068
12184
|
} catch (err) {
|
|
@@ -12239,13 +12355,13 @@ function stripHistoryImages(history) {
|
|
|
12239
12355
|
});
|
|
12240
12356
|
return { messages, stripped };
|
|
12241
12357
|
}
|
|
12242
|
-
function budgetStop(
|
|
12243
|
-
const breach =
|
|
12244
|
-
if (breach) return { message:
|
|
12358
|
+
function budgetStop(budget2, messages) {
|
|
12359
|
+
const breach = budget2.breachReason();
|
|
12360
|
+
if (breach) return { message: budget2.describeBreach(breach), breach };
|
|
12245
12361
|
const imageTokens = pendingImageTokens(messages);
|
|
12246
|
-
const projected =
|
|
12362
|
+
const projected = budget2.projectedBreach(imageTokens);
|
|
12247
12363
|
if (!projected) return void 0;
|
|
12248
|
-
return { message:
|
|
12364
|
+
return { message: budget2.describeProjectedBreach(projected, imageTokens), breach: projected };
|
|
12249
12365
|
}
|
|
12250
12366
|
var AgentLoop = class {
|
|
12251
12367
|
config;
|
|
@@ -12481,7 +12597,7 @@ var AgentLoop = class {
|
|
|
12481
12597
|
const addRun = (u) => {
|
|
12482
12598
|
runUsage = runUsage ? addUsage(runUsage, u) : u;
|
|
12483
12599
|
};
|
|
12484
|
-
const
|
|
12600
|
+
const budget2 = new BudgetGuard({
|
|
12485
12601
|
...this.config.budget ? { budget: this.config.budget } : {},
|
|
12486
12602
|
...this.config.modelPricing ? { pricing: this.config.modelPricing } : {},
|
|
12487
12603
|
...input.maxCallCostUsd !== void 0 ? { maxCallCostUsd: input.maxCallCostUsd } : {},
|
|
@@ -12493,7 +12609,7 @@ var AgentLoop = class {
|
|
|
12493
12609
|
const finish = (reason9, breach) => ({
|
|
12494
12610
|
type: "finish",
|
|
12495
12611
|
reason: reason9,
|
|
12496
|
-
usage:
|
|
12612
|
+
usage: budget2.snapshot(),
|
|
12497
12613
|
...runUsage ? { runUsage } : {},
|
|
12498
12614
|
...lastModel ? { model: lastModel } : {},
|
|
12499
12615
|
...lastRequestedModel ? { requestedModel: lastRequestedModel } : {},
|
|
@@ -12545,8 +12661,8 @@ var AgentLoop = class {
|
|
|
12545
12661
|
await this.prompt.syncMemory(userText, lastText);
|
|
12546
12662
|
return;
|
|
12547
12663
|
}
|
|
12548
|
-
|
|
12549
|
-
const stop = budgetStop(
|
|
12664
|
+
budget2.syncFromStore();
|
|
12665
|
+
const stop = budgetStop(budget2, messages);
|
|
12550
12666
|
if (stop) {
|
|
12551
12667
|
yield { type: "text-delta", text: stop.message };
|
|
12552
12668
|
await this.prompt.syncMemory(userText, lastText || stop.message);
|
|
@@ -12598,8 +12714,8 @@ var AgentLoop = class {
|
|
|
12598
12714
|
}
|
|
12599
12715
|
if (rescued.usage) {
|
|
12600
12716
|
addRun(rescued.usage);
|
|
12601
|
-
yield*
|
|
12602
|
-
|
|
12717
|
+
yield* budget2.toEvents(
|
|
12718
|
+
budget2.add(rescued.usage, this.rateOf(rescued.model)),
|
|
12603
12719
|
runUsage
|
|
12604
12720
|
);
|
|
12605
12721
|
}
|
|
@@ -12675,7 +12791,7 @@ var AgentLoop = class {
|
|
|
12675
12791
|
});
|
|
12676
12792
|
if (rescued.usage) {
|
|
12677
12793
|
addRun(rescued.usage);
|
|
12678
|
-
yield*
|
|
12794
|
+
yield* budget2.toEvents(budget2.add(rescued.usage, this.rateOf(rescued.model)), runUsage);
|
|
12679
12795
|
}
|
|
12680
12796
|
if (!shrank(messages, rescued.messages)) throw err;
|
|
12681
12797
|
messages = rescued.messages;
|
|
@@ -12732,14 +12848,14 @@ var AgentLoop = class {
|
|
|
12732
12848
|
"epoch.token_type": "cache_write"
|
|
12733
12849
|
});
|
|
12734
12850
|
}
|
|
12735
|
-
const status =
|
|
12851
|
+
const status = budget2.add(usage, this.rateOf(result.model));
|
|
12736
12852
|
input.onTurnUsage?.(
|
|
12737
12853
|
status.turnCostUsd === void 0 ? usage : { ...usage, costUsd: status.turnCostUsd }
|
|
12738
12854
|
);
|
|
12739
12855
|
addRun(usage);
|
|
12740
12856
|
lastModel = result.model;
|
|
12741
12857
|
lastRequestedModel = result.requestedModel;
|
|
12742
|
-
yield*
|
|
12858
|
+
yield* budget2.toEvents(status, runUsage);
|
|
12743
12859
|
}
|
|
12744
12860
|
const verdict = mergeVerdicts(guard?.verdict(), reasoningGuard?.verdict());
|
|
12745
12861
|
if (verdict) this.reportCompliance(verdict, "output");
|
|
@@ -12976,8 +13092,8 @@ ${finalText}` };
|
|
|
12976
13092
|
messages = compacted.messages;
|
|
12977
13093
|
if (compacted.usage) {
|
|
12978
13094
|
addRun(compacted.usage);
|
|
12979
|
-
yield*
|
|
12980
|
-
|
|
13095
|
+
yield* budget2.toEvents(
|
|
13096
|
+
budget2.add(compacted.usage, this.rateOf(compacted.model)),
|
|
12981
13097
|
runUsage
|
|
12982
13098
|
);
|
|
12983
13099
|
}
|
|
@@ -16916,8 +17032,8 @@ var MemoryManager = class {
|
|
|
16916
17032
|
async add(target, content) {
|
|
16917
17033
|
const label = injectionLabelOf(content);
|
|
16918
17034
|
if (label !== void 0) return this.refuseInjection(label);
|
|
16919
|
-
const
|
|
16920
|
-
if (
|
|
17035
|
+
const budget2 = this.getBudget()[target];
|
|
17036
|
+
if (budget2.current + content.length > budget2.limit) {
|
|
16921
17037
|
this.consolidationFailures++;
|
|
16922
17038
|
if (this.consolidationFailures > MAX_CONSOLIDATION_FAILURES_PER_TURN) {
|
|
16923
17039
|
return {
|
|
@@ -16964,9 +17080,9 @@ var MemoryManager = class {
|
|
|
16964
17080
|
}
|
|
16965
17081
|
const label = injectionLabelOf(content);
|
|
16966
17082
|
if (label !== void 0) return this.refuseInjection(label);
|
|
16967
|
-
const
|
|
17083
|
+
const budget2 = this.getBudget()[target];
|
|
16968
17084
|
const delta = content.length - existing.charLength;
|
|
16969
|
-
if (
|
|
17085
|
+
if (budget2.current + delta > budget2.limit) {
|
|
16970
17086
|
this.consolidationFailures++;
|
|
16971
17087
|
if (this.consolidationFailures > MAX_CONSOLIDATION_FAILURES_PER_TURN) {
|
|
16972
17088
|
return { success: false, done: true, error: "Consolidation limit reached" };
|
|
@@ -17171,11 +17287,11 @@ var MemoryManager = class {
|
|
|
17171
17287
|
for (const target of ["memory", "user"]) {
|
|
17172
17288
|
const rows = kept.filter((e) => e.target === target);
|
|
17173
17289
|
if (rows.length === 0) continue;
|
|
17174
|
-
const
|
|
17290
|
+
const budget2 = this.getBudget()[target];
|
|
17175
17291
|
const label = target === "user" ? "USER PROFILE (who the user is)" : "MEMORY (your personal notes)";
|
|
17176
17292
|
sections.push(
|
|
17177
17293
|
[
|
|
17178
|
-
`${label} [${rows.length} entries \xB7 ${
|
|
17294
|
+
`${label} [${rows.length} entries \xB7 ${budget2.current.toLocaleString()}/${budget2.limit.toLocaleString()} chars]`,
|
|
17179
17295
|
...rows.map((e) => this.indexLine(e))
|
|
17180
17296
|
].join("\n")
|
|
17181
17297
|
);
|
|
@@ -17206,7 +17322,7 @@ var MemoryManager = class {
|
|
|
17206
17322
|
return `${e.id} ${e.summary} (${e.charLength} chars)`;
|
|
17207
17323
|
}
|
|
17208
17324
|
buildConsolidateHint(target) {
|
|
17209
|
-
const
|
|
17325
|
+
const budget2 = this.getBudget()[target];
|
|
17210
17326
|
const heat = /* @__PURE__ */ new Map();
|
|
17211
17327
|
for (const row of this.db.getAll(target)) {
|
|
17212
17328
|
const id = this.idByContent.get(contentKey(row.target, row.content));
|
|
@@ -17214,7 +17330,7 @@ var MemoryManager = class {
|
|
|
17214
17330
|
}
|
|
17215
17331
|
const candidates2 = this.indexEntries(target).sort((a, b) => (heat.get(a.id) ?? 0) - (heat.get(b.id) ?? 0) || b.charLength - a.charLength).slice(0, 5);
|
|
17216
17332
|
return [
|
|
17217
|
-
`Memory at ${
|
|
17333
|
+
`Memory at ${budget2.current.toLocaleString()}/${budget2.limit.toLocaleString()} chars (${budget2.percent}%) for ${target}. Cannot add new entry.`,
|
|
17218
17334
|
"",
|
|
17219
17335
|
"To make room, work by id \u2014 NOT by old_text. The MEMORY INDEX only shows a truncated",
|
|
17220
17336
|
"first line, so text copied from it will never match an entry exactly.",
|
|
@@ -17628,6 +17744,28 @@ function parseTurnFacts(json) {
|
|
|
17628
17744
|
function encodeTurnFacts(facts) {
|
|
17629
17745
|
return facts ? JSON.stringify(facts) : null;
|
|
17630
17746
|
}
|
|
17747
|
+
function parseUserCommand(json) {
|
|
17748
|
+
if (typeof json !== "string" || json.length === 0) return void 0;
|
|
17749
|
+
let raw;
|
|
17750
|
+
try {
|
|
17751
|
+
raw = JSON.parse(json);
|
|
17752
|
+
} catch {
|
|
17753
|
+
return void 0;
|
|
17754
|
+
}
|
|
17755
|
+
if (!isRecord4(raw)) return void 0;
|
|
17756
|
+
const name = str3(raw["name"]);
|
|
17757
|
+
if (!name) return void 0;
|
|
17758
|
+
const displayName = str3(raw["displayName"]);
|
|
17759
|
+
const args = str3(raw["args"]);
|
|
17760
|
+
return {
|
|
17761
|
+
name,
|
|
17762
|
+
...displayName ? { displayName } : {},
|
|
17763
|
+
...args ? { args } : {}
|
|
17764
|
+
};
|
|
17765
|
+
}
|
|
17766
|
+
function encodeUserCommand(command) {
|
|
17767
|
+
return command ? JSON.stringify(command) : null;
|
|
17768
|
+
}
|
|
17631
17769
|
// src/session/db.ts
|
|
17632
17770
|
var NS3 = "session";
|
|
17633
17771
|
var log2 = createLogger("session-db");
|
|
@@ -17923,7 +18061,7 @@ var FTS_EXTERNAL_SCHEMA = `
|
|
|
17923
18061
|
var FTS_EXTERNAL_MIGRATIONS = [
|
|
17924
18062
|
{
|
|
17925
18063
|
id: "fts-external-content",
|
|
17926
|
-
version:
|
|
18064
|
+
version: 16,
|
|
17927
18065
|
description: "\u4E24\u5F20 FTS \u8868\u6539\u6210\u5916\u90E8\u5185\u5BB9\u8868\uFF08\u6B63\u6587\u4E0D\u518D\u5B58\u4E09\u4EFD\uFF0C2026-08-21\uFF09",
|
|
17928
18066
|
up: (db) => {
|
|
17929
18067
|
db.exec(FTS_EXTERNAL_SCHEMA);
|
|
@@ -17935,6 +18073,14 @@ var FTS_EXTERNAL_MIGRATIONS = [
|
|
|
17935
18073
|
db.prepare(`INSERT INTO ${table}(${table}, rank) VALUES('integrity-check', 1)`).run();
|
|
17936
18074
|
}
|
|
17937
18075
|
}
|
|
18076
|
+
},
|
|
18077
|
+
{
|
|
18078
|
+
id: "messages-command",
|
|
18079
|
+
version: 15,
|
|
18080
|
+
description: "\u6D88\u606F\u8868\u52A0 command \u4E00\u5217\uFF08\u8FD9\u6761\u7528\u6237\u6D88\u606F\u662F\u6309\u54EA\u6761\u659C\u6760\u547D\u4EE4\u53D1\u7684\uFF0C2026-10-21\uFF09",
|
|
18081
|
+
up: (db) => {
|
|
18082
|
+
db.exec(`ALTER TABLE messages ADD COLUMN command TEXT`);
|
|
18083
|
+
}
|
|
17938
18084
|
}
|
|
17939
18085
|
];
|
|
17940
18086
|
var SessionDB = class {
|
|
@@ -18128,8 +18274,8 @@ var SessionDB = class {
|
|
|
18128
18274
|
insertMessage(msg) {
|
|
18129
18275
|
const info = this.db.prepare(
|
|
18130
18276
|
`
|
|
18131
|
-
INSERT INTO messages (session_id, role, content, tool_call_id, tool_calls, tool_results, parts, tool_name, timestamp, token_count, finish_reason, reasoning, turn_facts, active, compacted, observed)
|
|
18132
|
-
VALUES (@sessionId, @role, @content, @toolCallId, @toolCalls, @toolResults, @parts, @toolName, @timestamp, @tokenCount, @finishReason, @reasoning, @turnFacts, 1, 0, 0)
|
|
18277
|
+
INSERT INTO messages (session_id, role, content, tool_call_id, tool_calls, tool_results, parts, command, tool_name, timestamp, token_count, finish_reason, reasoning, turn_facts, active, compacted, observed)
|
|
18278
|
+
VALUES (@sessionId, @role, @content, @toolCallId, @toolCalls, @toolResults, @parts, @command, @toolName, @timestamp, @tokenCount, @finishReason, @reasoning, @turnFacts, 1, 0, 0)
|
|
18133
18279
|
`
|
|
18134
18280
|
).run({
|
|
18135
18281
|
...msg,
|
|
@@ -18137,6 +18283,7 @@ var SessionDB = class {
|
|
|
18137
18283
|
toolCalls: encodeColumn(msg.toolCalls),
|
|
18138
18284
|
toolResults: encodeColumn(msg.toolResults),
|
|
18139
18285
|
parts: encodeColumn(msg.parts),
|
|
18286
|
+
command: encodeUserCommand(msg.command),
|
|
18140
18287
|
toolName: msg.toolName ?? null,
|
|
18141
18288
|
tokenCount: msg.tokenCount ?? null,
|
|
18142
18289
|
finishReason: msg.finishReason ?? null,
|
|
@@ -18402,8 +18549,8 @@ var SessionDB = class {
|
|
|
18402
18549
|
forkMessages(fromSessionId, toSessionId, upToIndex) {
|
|
18403
18550
|
const messages = this.db.prepare("SELECT * FROM messages WHERE session_id = ? AND id <= ? ORDER BY timestamp ASC").all(fromSessionId, upToIndex);
|
|
18404
18551
|
const stmt = this.db.prepare(`
|
|
18405
|
-
INSERT INTO messages (session_id, role, content, tool_call_id, tool_calls, tool_results, parts, tool_name, timestamp, token_count, finish_reason, reasoning, turn_facts, active, compacted, observed)
|
|
18406
|
-
VALUES (@sessionId, @role, @content, @toolCallId, @toolCalls, @toolResults, @parts, @toolName, @timestamp, @tokenCount, @finishReason, @reasoning, @turnFacts, @active, @compacted, @observed)
|
|
18552
|
+
INSERT INTO messages (session_id, role, content, tool_call_id, tool_calls, tool_results, parts, command, tool_name, timestamp, token_count, finish_reason, reasoning, turn_facts, active, compacted, observed)
|
|
18553
|
+
VALUES (@sessionId, @role, @content, @toolCallId, @toolCalls, @toolResults, @parts, @command, @toolName, @timestamp, @tokenCount, @finishReason, @reasoning, @turnFacts, @active, @compacted, @observed)
|
|
18407
18554
|
`);
|
|
18408
18555
|
for (const m of messages) {
|
|
18409
18556
|
const { id: _id, ...rest } = m;
|
|
@@ -18415,6 +18562,7 @@ var SessionDB = class {
|
|
|
18415
18562
|
toolCalls: rest["tool_calls"] ?? null,
|
|
18416
18563
|
toolResults: rest["tool_results"] ?? null,
|
|
18417
18564
|
parts: rest["parts"] ?? null,
|
|
18565
|
+
command: rest["command"] ?? null,
|
|
18418
18566
|
toolName: rest["tool_name"] ?? null,
|
|
18419
18567
|
timestamp: rest["timestamp"] ?? Date.now(),
|
|
18420
18568
|
tokenCount: rest["token_count"] ?? null,
|
|
@@ -18496,6 +18644,7 @@ var SessionDB = class {
|
|
|
18496
18644
|
toolCalls: parseToolCalls(row["tool_calls"]),
|
|
18497
18645
|
toolResults: parseToolResults(row["tool_results"]),
|
|
18498
18646
|
parts: parseParts(row["parts"]),
|
|
18647
|
+
command: parseUserCommand(row["command"]),
|
|
18499
18648
|
turnFacts: parseTurnFacts(row["turn_facts"]),
|
|
18500
18649
|
toolName: row["tool_name"],
|
|
18501
18650
|
timestamp: row["timestamp"],
|
|
@@ -19087,7 +19236,7 @@ var SessionManager = class {
|
|
|
19087
19236
|
search(input) {
|
|
19088
19237
|
return this.db.search(input);
|
|
19089
19238
|
}
|
|
19090
|
-
async compact(sessionId,
|
|
19239
|
+
async compact(sessionId, summarize2) {
|
|
19091
19240
|
const messages = this.db.getMessages(sessionId);
|
|
19092
19241
|
const beforeCount = messages.length;
|
|
19093
19242
|
const IMPORTANT_ROUNDS = 5;
|
|
@@ -19098,17 +19247,17 @@ var SessionManager = class {
|
|
|
19098
19247
|
0,
|
|
19099
19248
|
Math.max(0, keyMessages.length - IMPORTANT_ROUNDS * 2)
|
|
19100
19249
|
);
|
|
19101
|
-
const summary = toSummarize.length === 0 ? "" : await this.buildSummary(toSummarize,
|
|
19250
|
+
const summary = toSummarize.length === 0 ? "" : await this.buildSummary(toSummarize, summarize2) ?? outlineOf(toSummarize);
|
|
19102
19251
|
return this.db.compact(sessionId, summary, beforeCount, IMPORTANT_ROUNDS * 2);
|
|
19103
19252
|
}
|
|
19104
19253
|
archiveAndCompact(sessionId, input) {
|
|
19105
19254
|
return this.db.archiveAndCompact(sessionId, input);
|
|
19106
19255
|
}
|
|
19107
|
-
async buildSummary(msgs,
|
|
19108
|
-
if (!
|
|
19256
|
+
async buildSummary(msgs, summarize2) {
|
|
19257
|
+
if (!summarize2) return null;
|
|
19109
19258
|
const transcript = msgs.map((m) => `[${m.role}] ${m.content}`).join("\n\n");
|
|
19110
19259
|
try {
|
|
19111
|
-
const result = await
|
|
19260
|
+
const result = await summarize2(transcript);
|
|
19112
19261
|
return result?.trim() ? result.trim() : null;
|
|
19113
19262
|
} catch {
|
|
19114
19263
|
return null;
|
|
@@ -19296,8 +19445,8 @@ var GoalService = class {
|
|
|
19296
19445
|
const text = objective.trim();
|
|
19297
19446
|
if (!text) return { ok: false, reason: "empty-objective" };
|
|
19298
19447
|
if (text.length > MAX_OBJECTIVE_CHARS) return { ok: false, reason: "objective-too-long" };
|
|
19299
|
-
const
|
|
19300
|
-
if (!Number.isInteger(
|
|
19448
|
+
const budget2 = maxRounds ?? DEFAULT_GOAL_MAX_ROUNDS;
|
|
19449
|
+
if (!Number.isInteger(budget2) || budget2 < 1 || budget2 > MAX_GOAL_MAX_ROUNDS) {
|
|
19301
19450
|
return { ok: false, reason: "bad-budget" };
|
|
19302
19451
|
}
|
|
19303
19452
|
const existing = this.current(sessionId);
|
|
@@ -19309,7 +19458,7 @@ var GoalService = class {
|
|
|
19309
19458
|
objective: text,
|
|
19310
19459
|
phase: "active",
|
|
19311
19460
|
block: void 0,
|
|
19312
|
-
maxRounds:
|
|
19461
|
+
maxRounds: budget2,
|
|
19313
19462
|
roundsUsed: 0,
|
|
19314
19463
|
completeEvidence: void 0,
|
|
19315
19464
|
createdAt: at,
|
|
@@ -23437,7 +23586,7 @@ function stageSkillDir(source, staging, category, name, skills, issues, lang) {
|
|
|
23437
23586
|
const dir = join(staging, category, name);
|
|
23438
23587
|
mkdirSync(dir, { recursive: true });
|
|
23439
23588
|
copyFileSync(join(source, SKILL_FILE), join(dir, SKILL_FILE));
|
|
23440
|
-
let
|
|
23589
|
+
let budget2 = MAX_FILES_PER_SKILL - 1;
|
|
23441
23590
|
for (const entry of readEntries2(source, label, issues, lang)) {
|
|
23442
23591
|
if (entry.name === SKILL_FILE) continue;
|
|
23443
23592
|
if (!entry.isDir || !SKILL_ASSET_DIRS.includes(entry.name)) {
|
|
@@ -23447,7 +23596,7 @@ function stageSkillDir(source, staging, category, name, skills, issues, lang) {
|
|
|
23447
23596
|
});
|
|
23448
23597
|
continue;
|
|
23449
23598
|
}
|
|
23450
|
-
|
|
23599
|
+
budget2 = copyTree(join(source, entry.name), join(dir, entry.name), label, budget2, issues, lang);
|
|
23451
23600
|
}
|
|
23452
23601
|
skills.push({ name, category, dir });
|
|
23453
23602
|
}
|
|
@@ -23506,8 +23655,8 @@ function placeOf(root, parts, lang) {
|
|
|
23506
23655
|
const category = parts.at(-2) ?? "general";
|
|
23507
23656
|
return { name, category: skillSegmentIssue(category, lang) === void 0 ? category : "general" };
|
|
23508
23657
|
}
|
|
23509
|
-
function copyTree(from, to, label,
|
|
23510
|
-
let left =
|
|
23658
|
+
function copyTree(from, to, label, budget2, issues, lang) {
|
|
23659
|
+
let left = budget2;
|
|
23511
23660
|
mkdirSync(to, { recursive: true });
|
|
23512
23661
|
for (const entry of readEntries2(from, label, issues, lang)) {
|
|
23513
23662
|
if (left <= 0) {
|
|
@@ -24571,11 +24720,11 @@ function readOne(path, opts, usedBytes) {
|
|
|
24571
24720
|
}
|
|
24572
24721
|
const remaining = MAX_ATTACH_TOTAL_BYTES - usedBytes;
|
|
24573
24722
|
if (remaining <= 0) return { part: { type: "file", path, omitted: "over-limit", bytes: size } };
|
|
24574
|
-
const
|
|
24575
|
-
if (raw.length <=
|
|
24723
|
+
const budget2 = Math.min(MAX_ATTACH_BYTES, remaining);
|
|
24724
|
+
if (raw.length <= budget2) {
|
|
24576
24725
|
return { part: { type: "file", path, text: raw.toString("utf8"), bytes: size } };
|
|
24577
24726
|
}
|
|
24578
|
-
const { text, truncatedTo } = truncateToBudget(raw,
|
|
24727
|
+
const { text, truncatedTo } = truncateToBudget(raw, budget2);
|
|
24579
24728
|
return {
|
|
24580
24729
|
part: { type: "file", path, text, truncatedTo, bytes: size },
|
|
24581
24730
|
notice: t("mentions.truncated", {
|