@epoch-agent/core 0.4.0 → 0.5.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/dist/index.d.ts +74 -2
- package/dist/index.js +76 -22
- package/package.json +3 -3
package/dist/index.d.ts
CHANGED
|
@@ -7563,6 +7563,13 @@ interface AgentConfig {
|
|
|
7563
7563
|
* 和 `LogFn` 同一条规矩:库不替宿主决定往哪儿发数据,真 SDK 的装配在 runtime。
|
|
7564
7564
|
*/
|
|
7565
7565
|
telemetry?: Telemetry;
|
|
7566
|
+
/**
|
|
7567
|
+
* 一条用户消息底下最多几次模型请求。**`0` = 不设上限**,也是缺省
|
|
7568
|
+
* (判据全文在 infra 的 `DEFAULT_MAX_TURNS` / `UNLIMITED_TURNS` 上)。
|
|
7569
|
+
*
|
|
7570
|
+
* `undefined` 和 `0` 在这一格上**同义**(都落到 `DEFAULT_MAX_TURNS`),
|
|
7571
|
+
* 两者的区别只在 `RunInput.maxTurns` 那一格上才成立 —— 见那儿。
|
|
7572
|
+
*/
|
|
7566
7573
|
maxTurns?: number;
|
|
7567
7574
|
/**
|
|
7568
7575
|
* 工作目录。
|
|
@@ -7909,6 +7916,11 @@ interface RunInput {
|
|
|
7909
7916
|
*
|
|
7910
7917
|
* 是 per-call 而不是改配置:长驻宿主(`--input-format stream-json`)一个进程
|
|
7911
7918
|
* 服务很多次调用,把「这一次最多跑几轮」写进进程级配置就没法逐次收紧了。
|
|
7919
|
+
*
|
|
7920
|
+
* ⚠️ **这一格上 `undefined` 和 `0` 是两个意思**(2026-09-06):`undefined` =
|
|
7921
|
+
* 「这次没给,跟配置走」,`0` = 「这次不限轮次」(`--max-turns 0`,压过一个
|
|
7922
|
+
* 配置里设了上限的会话)。所以消费它的那一行必须是 `??` 而不是 `||` ——
|
|
7923
|
+
* 判据在 `loop.ts` 的 `runTurns()` 上。
|
|
7912
7924
|
*/
|
|
7913
7925
|
maxTurns?: number;
|
|
7914
7926
|
/**
|
|
@@ -9824,6 +9836,21 @@ declare const EpochConfigSchema: z.ZodObject<{
|
|
|
9824
9836
|
prompt: z.ZodString;
|
|
9825
9837
|
icon: z.ZodOptional<z.ZodString>;
|
|
9826
9838
|
}, z.core.$strip>>>;
|
|
9839
|
+
blankGreeting: z.ZodOptional<z.ZodObject<{
|
|
9840
|
+
eyebrow: z.ZodOptional<z.ZodRecord<z.ZodEnum<{
|
|
9841
|
+
zh: "zh";
|
|
9842
|
+
en: "en";
|
|
9843
|
+
}> & z.core.$partial, z.ZodString>>;
|
|
9844
|
+
title: z.ZodOptional<z.ZodRecord<z.ZodEnum<{
|
|
9845
|
+
zh: "zh";
|
|
9846
|
+
en: "en";
|
|
9847
|
+
}> & z.core.$partial, z.ZodString>>;
|
|
9848
|
+
subtitle: z.ZodOptional<z.ZodRecord<z.ZodEnum<{
|
|
9849
|
+
zh: "zh";
|
|
9850
|
+
en: "en";
|
|
9851
|
+
}> & z.core.$partial, z.ZodString>>;
|
|
9852
|
+
hidden: z.ZodOptional<z.ZodBoolean>;
|
|
9853
|
+
}, z.core.$strip>>;
|
|
9827
9854
|
}, z.core.$strip>;
|
|
9828
9855
|
/**
|
|
9829
9856
|
* 全默认配置 —— 从 schema 派生,不是第二份字面量。
|
|
@@ -12968,8 +12995,27 @@ type UpdateScheduleInput = Partial<Omit<CreateScheduleInput, 'maxBudgetUsd'>> &
|
|
|
12968
12995
|
* `maxBudgetUsd` **不在这里**,那是刻意的 —— 它没有缺省值。
|
|
12969
12996
|
*/
|
|
12970
12997
|
declare const SCHEDULE_DEFAULTS: {
|
|
12971
|
-
/**
|
|
12972
|
-
|
|
12998
|
+
/**
|
|
12999
|
+
* 和交互缺省**同一个常量**(2026-09-04,原来这儿是自己的一个 `20`)。
|
|
13000
|
+
*
|
|
13001
|
+
* 那个 20 的理由写的是「无人看着的一轮不该比有人看着的更长」。它不成立了 ——
|
|
13002
|
+
* 它当初拦的是「跑飞了没人按 Esc」,而这一层真正拦住那件事的是 `maxBudgetUsd`:
|
|
13003
|
+
* 它在这套功能里**必填**(所以它不在这份缺省里),而钱是比轮次准的尺子。
|
|
13004
|
+
* 用轮次替它把无人值守的活压到 20,拦掉的绝大多数不是跑飞,是「这个任务本来
|
|
13005
|
+
* 就要 60 轮」—— 而那种失败要等到第二天 9 点才看得见(同下面
|
|
13006
|
+
* `SCHEDULE_DEFAULT_ALLOWLIST` 那节的判据)。
|
|
13007
|
+
*
|
|
13008
|
+
* ⚠️ 这一份是**没有配置在手时的兜底**。真正拿着用户那格 `maxTurns` 的地方是
|
|
13009
|
+
* `server/src/schedule/handlers.ts` 的 `defaultsOf()` —— 表单预填走它,
|
|
13010
|
+
* 所以用户把设置里那个数改成 500,新建任务那一格就预填 500。
|
|
13011
|
+
*
|
|
13012
|
+
* ⚠️ **2026-09-06 起这个缺省是「不设上限」**(`UNLIMITED_TURNS`),因为上面那条
|
|
13013
|
+
* 判据跟着交互缺省一起走到了头:既然轮次拦掉的绝大多数不是跑飞,那把它当无人
|
|
13014
|
+
* 值守的兜底闸门就是**拿错了尺子**。这条路上兜住跑飞的仍然是 `maxBudgetUsd`
|
|
13015
|
+
* (必填,所以它不在这份缺省里)和 `timeoutMs`。要一道轮次闸门的人在新建任务
|
|
13016
|
+
* 那一格自己填一个数。
|
|
13017
|
+
*/
|
|
13018
|
+
readonly maxTurns: 0;
|
|
12973
13019
|
/** 15 分钟。唯一能拦住「一条命令挂住了」的那把尺子 */
|
|
12974
13020
|
readonly timeoutMs: number;
|
|
12975
13021
|
};
|
|
@@ -14374,6 +14420,32 @@ declare class HookManager implements HookManager$1 {
|
|
|
14374
14420
|
} | null>;
|
|
14375
14421
|
trigger(type: HookType, event: HookEvent, ctx: HookContext): Promise<void>;
|
|
14376
14422
|
triggerTransform<T>(type: HookType, event: HookEvent, ctx: HookContext): Promise<T | null>;
|
|
14423
|
+
/**
|
|
14424
|
+
* ## ⚠️ 这个方法**必须**同时读 `commandHooks`(2026-09-04 补的那一半)
|
|
14425
|
+
*
|
|
14426
|
+
* 它原来是三个分发方法里唯一不读配置文件那一半的:
|
|
14427
|
+
*
|
|
14428
|
+
* | 方法 | 读 `this.hooks` | 读 `this.commandHooks` |
|
|
14429
|
+
* | ---- | :--: | :--: |
|
|
14430
|
+
* | {@link trigger} | ✅ | ✅ |
|
|
14431
|
+
* | {@link triggerCommandHooks} | ❌ | ✅ |
|
|
14432
|
+
* | 这一个(改之前) | ✅ | **❌** |
|
|
14433
|
+
*
|
|
14434
|
+
* 而 `verify:stop` **只**走这一条路。两条路当时都是死的:配置文件那一半没人读,
|
|
14435
|
+
* 进程内注册那一半对嵌入宿主也够不着(`BuildRuntimeOptions` 没有 hooks 字段、
|
|
14436
|
+
* `EpochRuntime` 上没有 `hookManager`)。于是「模型说完就停」那唯一一道闸
|
|
14437
|
+
* 对所有人都是关着的,而且**零诊断**:配置合法、`parseHooksConfig` 收下了它、
|
|
14438
|
+
* `issues` 是空的、`commandHooks` map 里真的有它 —— 只是没有任何一处会去读。
|
|
14439
|
+
* 写了它的人拿不到任何反馈,只会以为「配了但模型不听」。
|
|
14440
|
+
*
|
|
14441
|
+
* ## 这里是 `await`,不是 `trigger` 那种 fire-and-forget
|
|
14442
|
+
*
|
|
14443
|
+
* 表决要参与判断(`AgentLoop` 据此决定要不要再跑一轮),所以必须等。
|
|
14444
|
+
* 超时用的是**每条 hook 自己的** `config.timeout`(`runCommandHook` 里缺省
|
|
14445
|
+
* 30 秒),不是上面那个给 JS hook 的 {@link HOOK_TIMEOUT_MS} 5 秒 ——
|
|
14446
|
+
* 那 5 秒对一条要跑测试或跑 lint 的 `verify:stop` 明显偏紧,
|
|
14447
|
+
* 而 `HookEntrySchema` 里本来就有 `timeout` 这一格。
|
|
14448
|
+
*/
|
|
14377
14449
|
triggerVerify(type: HookType, event: HookEvent, ctx: HookContext): Promise<VerifyResult[]>;
|
|
14378
14450
|
private getSorted;
|
|
14379
14451
|
}
|
package/dist/index.js
CHANGED
|
@@ -2,7 +2,7 @@ import { existsSync, readdirSync, readFileSync, mkdirSync, writeFileSync, rmSync
|
|
|
2
2
|
import { homedir, platform, tmpdir, hostname } from 'os';
|
|
3
3
|
import { join, dirname, isAbsolute, resolve, relative, sep, extname, basename } from 'path';
|
|
4
4
|
import { execFile, execSync, execFileSync, spawn } from 'child_process';
|
|
5
|
-
import { createLogger, dbPath, resolveHomeDir, t, unknownKeyIssues, parseLenient, issueDetails, splitWords, checkpointsDir, trustedImportsPath, budgetStatePath, artifactsDir, configPath, managedSettingsPath, projectSettingsPath, projectLocalSettingsPath, getSecretValues, listStoredSecretNames, maskApiKey, setSectionField, isInWorkspace, workspacesPath, openDatabase, migrate, releaseDatabase, automationLogsDir, projectPoliciesDir, projectComplianceDir, projectHooksPath, projectClaudeSettingsPath, projectClaudeLocalSettingsPath, projectSkillsDir, trustPath, detectBackend, EXEC_PATH_AS_NODE_ENV, isolate, createStreamDecoder, writeArtifact, parseShellCommand, envPath, checkDangerousCommand, checkObfuscation, countCodePoints, keepHeadAndTail, normalizeForMatch, isReadOnlyCommand, CODE_EXEC_ROOTS } from '@epoch-agent/infra';
|
|
5
|
+
import { createLogger, dbPath, resolveHomeDir, DEFAULT_MAX_TURNS, t, unknownKeyIssues, parseLenient, issueDetails, splitWords, checkpointsDir, trustedImportsPath, budgetStatePath, artifactsDir, UNLIMITED_TURNS, turnLimitOf, configPath, managedSettingsPath, projectSettingsPath, projectLocalSettingsPath, getSecretValues, listStoredSecretNames, maskApiKey, setSectionField, isInWorkspace, workspacesPath, openDatabase, migrate, releaseDatabase, automationLogsDir, projectPoliciesDir, projectComplianceDir, projectHooksPath, projectClaudeSettingsPath, projectClaudeLocalSettingsPath, projectSkillsDir, trustPath, detectBackend, EXEC_PATH_AS_NODE_ENV, isolate, createStreamDecoder, writeArtifact, parseShellCommand, envPath, checkDangerousCommand, checkObfuscation, countCodePoints, keepHeadAndTail, normalizeForMatch, isReadOnlyCommand, CODE_EXEC_ROOTS } from '@epoch-agent/infra';
|
|
6
6
|
export { IS_WINDOWS, WINDOWS_HIDE_FLAGS, buildBwrapArgs, buildProfile, checkDangerousCommand, checkObfuscation, createLogger, detectBackend, getDefaultShell, getPythonCommand, isInWorkspace, isReadOnlyCommand, isolate, maskApiKey, probeBubblewrap, probeSeatbelt, complianceDir as resolveComplianceDir, policiesDir as resolvePoliciesDir, setLogLevel } from '@epoch-agent/infra';
|
|
7
7
|
import { PROVIDER_TYPES, OPERATION_TYPES, COMPLIANCE_CATEGORIES, COMPLIANCE_ACTIONS, SEARCH_PROVIDER_TYPES, LANGS, PERMISSION_LEVELS, SHELL_KINDS, ToolExposure, MAX_OPTIONS, MIN_OPTIONS, MAX_HEADER_CHARS, MAX_QUESTIONS, isValidAgentRoleName, DEFAULT_AGENT_ROLE, isValidCommandName, RESERVED_COMMAND_NAMES, parseModelRef, systemNote, totalUsageTokens, NOOP_TELEMETRY, METRIC, contentToText, GEN_AI, promptTokens, apiKeyEnvVar, PROVIDER_INFOS, isProviderType, API_KEY_ENV_VARS, isPermissionLevel, KEY_ACTIONS, tableOf, perAction, isKeyAction, parseSequence, RESERVED_CHORDS, chordId, sequenceId, ACTION_CONTEXTS, SEQUENCE_CONTEXTS, assertNeverPart, SCHEDULE_INTERVAL_MINUTES, MAX_ATTACH_FILES, MAX_ATTACH_TOTAL_BYTES, MAX_SESSION_REFS, utf8ByteLength, attachSessionSurface, isContextNearlyFull, isOperationType, normalizeApproval, MAX_ATTACH_BYTES, SIMULTANEOUS_CONTEXTS, SESSION_REFERENCE_ERROR_CODES, filePartSummary, sessionPartSummary } from '@epoch-agent/protocol';
|
|
8
8
|
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';
|
|
@@ -3571,7 +3571,7 @@ var ROLE_FRONTMATTER_SCHEMA = z.object({
|
|
|
3571
3571
|
description: z.string().min(1),
|
|
3572
3572
|
tools: z.array(z.string().min(1)).optional(),
|
|
3573
3573
|
skills: z.array(z.string().min(1)).optional(),
|
|
3574
|
-
maxTurns: z.int().
|
|
3574
|
+
maxTurns: z.int().nonnegative().optional()
|
|
3575
3575
|
});
|
|
3576
3576
|
var FrontmatterSchema = ROLE_FRONTMATTER_SCHEMA;
|
|
3577
3577
|
var FRONTMATTER_KEYS2 = Object.keys(FrontmatterSchema.shape);
|
|
@@ -3646,7 +3646,7 @@ function parseRoleDefinition(raw, file, source) {
|
|
|
3646
3646
|
...prompt ? { prompt } : {},
|
|
3647
3647
|
...fm.tools ? { tools: fm.tools } : {},
|
|
3648
3648
|
...fm.skills ? { skills: fm.skills } : {},
|
|
3649
|
-
...fm.maxTurns ? { maxTurns: fm.maxTurns } : {},
|
|
3649
|
+
...fm.maxTurns !== void 0 ? { maxTurns: fm.maxTurns } : {},
|
|
3650
3650
|
source
|
|
3651
3651
|
},
|
|
3652
3652
|
issues
|
|
@@ -3734,7 +3734,6 @@ var BUILTIN_ROLES = [
|
|
|
3734
3734
|
description: "\u53EA\u8BFB\u68C0\u7D22\u3002\u627E\u6587\u4EF6\u3001\u627E\u7B26\u53F7\u3001\u56DE\u7B54\u300CX \u5728\u54EA\u5B9E\u73B0\u7684\u300D\u3002\u5B83\u6539\u4E0D\u4E86\u4EFB\u4F55\u4E1C\u897F\uFF0C\u56DE\u4F20\u7684\u662F\u6587\u4EF6\u8DEF\u5F84 + \u884C\u53F7\u800C\u4E0D\u662F\u4EE3\u7801\u539F\u6587\uFF0C\u9002\u5408\u9700\u8981\u7FFB\u5F88\u591A\u6587\u4EF6\u4F46\u7ED3\u8BBA\u5F88\u77ED\u7684\u4EFB\u52A1",
|
|
3735
3735
|
prompt: EXPLORE_PROMPT,
|
|
3736
3736
|
tools: [...READ_ONLY_TOOLS],
|
|
3737
|
-
maxTurns: 8,
|
|
3738
3737
|
source: "builtin"
|
|
3739
3738
|
},
|
|
3740
3739
|
{
|
|
@@ -3742,7 +3741,6 @@ var BUILTIN_ROLES = [
|
|
|
3742
3741
|
description: "\u4EE3\u7801\u5BA1\u67E5\u3002\u53EA\u8BFB\uFF0C\u8F93\u51FA\u300C\u6587\u4EF6:\u884C \xB7 \u4E25\u91CD\u5EA6 \xB7 \u4E00\u53E5\u8BDD\u300D\u7684\u95EE\u9898\u6E05\u5355\u3002\u9002\u5408\u6539\u5B8C\u4E00\u6279\u4EE3\u7801\u4E4B\u540E\u627E\u95EE\u9898\uFF0C\u4E0D\u9002\u5408\u8BA9\u5B83\u987A\u624B\u628A\u95EE\u9898\u4FEE\u6389\uFF08\u5B83\u6CA1\u6709\u5199\u5DE5\u5177\uFF09",
|
|
3743
3742
|
prompt: REVIEW_PROMPT,
|
|
3744
3743
|
tools: [...READ_ONLY_TOOLS],
|
|
3745
|
-
maxTurns: 10,
|
|
3746
3744
|
source: "builtin"
|
|
3747
3745
|
}
|
|
3748
3746
|
];
|
|
@@ -3774,7 +3772,7 @@ function mergeRoles(overrides) {
|
|
|
3774
3772
|
...existing,
|
|
3775
3773
|
...incoming.description ? { description: incoming.description } : {},
|
|
3776
3774
|
...incoming.prompt ? { prompt: incoming.prompt } : {},
|
|
3777
|
-
...incoming.maxTurns ? { maxTurns: incoming.maxTurns } : {},
|
|
3775
|
+
...incoming.maxTurns !== void 0 ? { maxTurns: incoming.maxTurns } : {},
|
|
3778
3776
|
...tools ? { tools } : {},
|
|
3779
3777
|
...skills ? { skills } : {},
|
|
3780
3778
|
source: incoming.source
|
|
@@ -8510,6 +8508,15 @@ function wrapUntrusted(source, text) {
|
|
|
8510
8508
|
${escaped}
|
|
8511
8509
|
</${OUTPUT_TAG}>`;
|
|
8512
8510
|
}
|
|
8511
|
+
function outputText(output) {
|
|
8512
|
+
if (output === void 0 || output === null) return "";
|
|
8513
|
+
return typeof output === "string" ? output : JSON.stringify(output) ?? "";
|
|
8514
|
+
}
|
|
8515
|
+
function failureText(r) {
|
|
8516
|
+
const detail = r.error?.message?.trim() || outputText(r.output).trim();
|
|
8517
|
+
if (!detail) return "\u5DE5\u5177\u6267\u884C\u5931\u8D25\uFF08\u5DE5\u5177\u672A\u63D0\u4F9B\u539F\u56E0\uFF09";
|
|
8518
|
+
return r.error?.code === void 0 ? `\u5DE5\u5177\u6267\u884C\u5931\u8D25\uFF1A${detail}` : `\u5DE5\u5177\u6267\u884C\u5931\u8D25 [${r.error.code}]: ${detail}`;
|
|
8519
|
+
}
|
|
8513
8520
|
var ToolExecutor = class {
|
|
8514
8521
|
constructor(deps) {
|
|
8515
8522
|
this.deps = deps;
|
|
@@ -8603,7 +8610,7 @@ var ToolExecutor = class {
|
|
|
8603
8610
|
toolName: et.name,
|
|
8604
8611
|
toolResult: {
|
|
8605
8612
|
success: r.success,
|
|
8606
|
-
output:
|
|
8613
|
+
output: outputText(r.output),
|
|
8607
8614
|
error: r.error
|
|
8608
8615
|
}
|
|
8609
8616
|
},
|
|
@@ -8611,7 +8618,7 @@ var ToolExecutor = class {
|
|
|
8611
8618
|
).catch(() => {
|
|
8612
8619
|
});
|
|
8613
8620
|
if (r.success) {
|
|
8614
|
-
const text =
|
|
8621
|
+
const text = outputText(r.output);
|
|
8615
8622
|
const artifacts = r.artifacts ? admitArtifacts(r.artifacts, this.policy(sessionId)) : [];
|
|
8616
8623
|
const diffs = before ? await collectDiffs(before, this.deps.workDir()) : [];
|
|
8617
8624
|
return finish({
|
|
@@ -8632,7 +8639,10 @@ var ToolExecutor = class {
|
|
|
8632
8639
|
return finish({
|
|
8633
8640
|
...base,
|
|
8634
8641
|
success: false,
|
|
8635
|
-
output:
|
|
8642
|
+
output: this.renderOutput(
|
|
8643
|
+
et,
|
|
8644
|
+
truncate(failureText(r), depth > 0 ? MAX_SUB_CALL_OUTPUT : MAX_TOOL_OUTPUT)
|
|
8645
|
+
)
|
|
8636
8646
|
});
|
|
8637
8647
|
} catch (err) {
|
|
8638
8648
|
span.recordError(err);
|
|
@@ -8900,12 +8910,12 @@ var AgentLoop = class {
|
|
|
8900
8910
|
learnedSkills = [];
|
|
8901
8911
|
constructor(config) {
|
|
8902
8912
|
this.config = {
|
|
8903
|
-
maxTurns:
|
|
8913
|
+
maxTurns: DEFAULT_MAX_TURNS,
|
|
8904
8914
|
workDir: process.cwd(),
|
|
8905
8915
|
contextLength: DEFAULT_CONTEXT_LENGTH,
|
|
8906
8916
|
...config
|
|
8907
8917
|
};
|
|
8908
|
-
if (this.config.maxTurns <
|
|
8918
|
+
if (this.config.maxTurns < 0) this.config.maxTurns = UNLIMITED_TURNS;
|
|
8909
8919
|
if (this.config.site) {
|
|
8910
8920
|
this.site = this.config.site;
|
|
8911
8921
|
} else {
|
|
@@ -9032,7 +9042,7 @@ var AgentLoop = class {
|
|
|
9032
9042
|
yield* this.runTurns(input, turns);
|
|
9033
9043
|
}
|
|
9034
9044
|
async *runTurns(input, turns) {
|
|
9035
|
-
const maxTurns = input.maxTurns ?? this.config.maxTurns;
|
|
9045
|
+
const maxTurns = turnLimitOf(input.maxTurns ?? this.config.maxTurns);
|
|
9036
9046
|
this.stallDetector.resetOnSuccess();
|
|
9037
9047
|
const rawUserText = contentToText(input.userMessage, { imagesCarriedAsParts: true });
|
|
9038
9048
|
const images = imageParts(input.userMessage);
|
|
@@ -9267,6 +9277,10 @@ var AgentLoop = class {
|
|
|
9267
9277
|
return;
|
|
9268
9278
|
}
|
|
9269
9279
|
const toolCalls = result.toolCalls ?? [];
|
|
9280
|
+
const truncated = result.finishReason === "length" && toolCalls.length === 0;
|
|
9281
|
+
if (truncated) {
|
|
9282
|
+
yield { type: "notice", code: "response-truncated", text: t("agent_run.truncated") };
|
|
9283
|
+
}
|
|
9270
9284
|
if (toolCalls.length === 0) {
|
|
9271
9285
|
turns.push({
|
|
9272
9286
|
index: turn,
|
|
@@ -9311,7 +9325,7 @@ ${finalText}` };
|
|
|
9311
9325
|
turns
|
|
9312
9326
|
});
|
|
9313
9327
|
this.maybeLearn(userText, finalText);
|
|
9314
|
-
yield finish("stop");
|
|
9328
|
+
yield finish(truncated ? "length" : "stop");
|
|
9315
9329
|
return;
|
|
9316
9330
|
}
|
|
9317
9331
|
messages.push({
|
|
@@ -9620,6 +9634,17 @@ var BlankCardSchema = z.object({
|
|
|
9620
9634
|
prompt: z.string().min(1),
|
|
9621
9635
|
icon: z.string().min(1).optional()
|
|
9622
9636
|
});
|
|
9637
|
+
var HostTextSchema = z.partialRecord(z.enum(LANGS), z.string().min(1)).refine((text) => Object.values(text).some((value) => value !== void 0), {
|
|
9638
|
+
message: "at least one language must be given"
|
|
9639
|
+
});
|
|
9640
|
+
var BlankGreetingSchema = z.object({
|
|
9641
|
+
eyebrow: HostTextSchema.optional(),
|
|
9642
|
+
title: HostTextSchema.optional(),
|
|
9643
|
+
subtitle: HostTextSchema.optional(),
|
|
9644
|
+
hidden: z.boolean().optional()
|
|
9645
|
+
}).refine((greeting) => Object.values(greeting).some((value) => value !== void 0), {
|
|
9646
|
+
message: "blankGreeting: must set at least one of eyebrow / title / subtitle / hidden"
|
|
9647
|
+
});
|
|
9623
9648
|
var ArtifactsSchema = z.object({
|
|
9624
9649
|
maxAgeDays: z.int().positive().max(3650).default(ARTIFACT_RETENTION_DEFAULTS.maxAgeDays),
|
|
9625
9650
|
maxTotalBytes: z.int().positive().default(ARTIFACT_RETENTION_DEFAULTS.maxTotalBytes)
|
|
@@ -9635,7 +9660,7 @@ var EpochConfigSchema = z.object({
|
|
|
9635
9660
|
model: z.string().min(1).default("gpt-4o-mini"),
|
|
9636
9661
|
models: z.object({ utility: z.string().min(1).optional() }).optional(),
|
|
9637
9662
|
shell: z.enum(SHELL_KINDS).optional(),
|
|
9638
|
-
maxTurns: z.int().
|
|
9663
|
+
maxTurns: z.int().nonnegative().default(DEFAULT_MAX_TURNS),
|
|
9639
9664
|
contextLength: z.int().positive().default(2e5),
|
|
9640
9665
|
homeDir: z.string().min(1).default(() => resolveHomeDir()),
|
|
9641
9666
|
dbPath: z.string().min(1).default(() => dbPath(resolveHomeDir())),
|
|
@@ -9673,7 +9698,8 @@ var EpochConfigSchema = z.object({
|
|
|
9673
9698
|
}).optional(),
|
|
9674
9699
|
blankCards: z.array(BlankCardSchema).min(1).refine((items) => new Set(items.map((item) => item.id)).size === items.length, {
|
|
9675
9700
|
message: "blankCards: id must be unique"
|
|
9676
|
-
}).optional()
|
|
9701
|
+
}).optional(),
|
|
9702
|
+
blankGreeting: BlankGreetingSchema.optional()
|
|
9677
9703
|
});
|
|
9678
9704
|
function defaultConfig() {
|
|
9679
9705
|
return EpochConfigSchema.parse({});
|
|
@@ -10511,7 +10537,7 @@ function applyEnvOverrides(config, issues, track) {
|
|
|
10511
10537
|
}
|
|
10512
10538
|
if (env.EPOCH_MAX_TURNS) {
|
|
10513
10539
|
const turns = Number(env.EPOCH_MAX_TURNS);
|
|
10514
|
-
if (Number.isInteger(turns) && turns
|
|
10540
|
+
if (Number.isInteger(turns) && turns >= 0) {
|
|
10515
10541
|
config.maxTurns = turns;
|
|
10516
10542
|
track.env.add("maxTurns");
|
|
10517
10543
|
} else {
|
|
@@ -12050,7 +12076,7 @@ var DESCRIPTIONS = {
|
|
|
12050
12076
|
"permissions.ask": "\u6BCF\u6B21\u90FD\u95EE\u4E00\u53E5\uFF0C\u5373\u4F7F\u6743\u9650\u7EA7\u522B\u672C\u6765\u4E0D\u95EE\u3002\u5199\u6CD5\u540C allow\u3002",
|
|
12051
12077
|
"permissions.deny": "\u4E00\u5F8B\u62D2\u7EDD\uFF0C\u538B\u8FC7 allow / ask \u548C\u5BA1\u6279\u7F13\u5B58\u3002\u5199\u6CD5\u540C allow\uFF1B\u672A\u4FE1\u4EFB\u7684\u4ED3\u5E93\u91CC\u53EA\u6709\u8FD9\u4E00\u5F20\u5217\u8868\u8FD8\u751F\u6548\u3002",
|
|
12052
12078
|
model: "\u672C\u5C42\u4F7F\u7528\u7684\u6A21\u578B ID\uFF0C\u8986\u76D6\u4F4E\u5C42\u7EA7\u7684\u8BBE\u7F6E\u3002",
|
|
12053
|
-
maxTurns: "\u5355\u6B21\u4F1A\u8BDD\u6700\u591A\u51E0\u8F6E\uFF08\u4E00\u8F6E = \u4E00\u6B21\u6A21\u578B\u8C03\u7528 + \u5B83\u89E6\u53D1\u7684\u5DE5\u5177\u6267\u884C\uFF09\
|
|
12079
|
+
maxTurns: "\u5355\u6B21\u4F1A\u8BDD\u6700\u591A\u51E0\u8F6E\uFF08\u4E00\u8F6E = \u4E00\u6B21\u6A21\u578B\u8C03\u7528 + \u5B83\u89E6\u53D1\u7684\u5DE5\u5177\u6267\u884C\uFF09\u30020 \u6216\u6B63\u6574\u6570\uFF0C**0 = \u4E0D\u8BBE\u4E0A\u9650**\uFF08\u7F3A\u7701\uFF09\u3002",
|
|
12054
12080
|
allowManagedPermissionRulesOnly: "\u6253\u5F00\u540E\uFF0C\u5176\u4F59\u5404\u5C42\uFF08\u7528\u6237\u7EA7 / \u9879\u76EE\u7EA7 / \u9879\u76EE\u672C\u5730 / --settings\uFF09\u7684 allow / ask / deny **\u6574\u4EFD\u5FFD\u7565**\uFF0C\u53EA\u6709\u8FD9\u4EFD\u6258\u7BA1\u6587\u4EF6\u91CC\u7684\u89C4\u5219\u7B97\u6570\u3002\u8FD9\u662F\u5168\u6D41\u7A0B\u552F\u4E00\u4E00\u5904\u66FF\u6362\u8BED\u4E49\uFF0C\u4E0D\u662F\u5E76\u96C6\u3002\u9ED8\u8BA4 false\u3002",
|
|
12055
12081
|
allowManagedHooksOnly: "\u6253\u5F00\u540E\uFF0C\u7528\u6237\u7EA7 hook \u4E00\u6761\u90FD\u4E0D\u52A0\u8F7D\uFF08hook \u80FD spawn \u4EFB\u610F\u5B50\u8FDB\u7A0B\uFF09\u3002\u9ED8\u8BA4 false\u3002",
|
|
12056
12082
|
disableBypassPermissionsMode: "\u6253\u5F00\u540E\uFF0C`permission: bypass` **\u62D2\u7EDD\u542F\u52A8**\uFF08\u9000\u51FA\u7801 4\uFF09\uFF0C\u8FD0\u884C\u671F\u5207\u5230 bypass \u4E5F\u4F1A\u88AB\u6321\u4E0B\u3002\u9ED8\u8BA4 false\u3002"
|
|
@@ -15675,7 +15701,6 @@ function suggestRuleFromApproval(request) {
|
|
|
15675
15701
|
].join("\n")
|
|
15676
15702
|
};
|
|
15677
15703
|
}
|
|
15678
|
-
// src/schedule/types.ts
|
|
15679
15704
|
var SCHEDULE_ISSUE_CODES = [
|
|
15680
15705
|
"name-empty",
|
|
15681
15706
|
"prompt-empty",
|
|
@@ -15699,7 +15724,7 @@ var SCHEDULE_ISSUE_CODES = [
|
|
|
15699
15724
|
"bypass-not-confirmed"
|
|
15700
15725
|
];
|
|
15701
15726
|
var SCHEDULE_DEFAULTS = {
|
|
15702
|
-
maxTurns:
|
|
15727
|
+
maxTurns: DEFAULT_MAX_TURNS,
|
|
15703
15728
|
timeoutMs: 15 * 60 * 1e3
|
|
15704
15729
|
};
|
|
15705
15730
|
var SCHEDULE_DEFAULT_ALLOWLIST = {
|
|
@@ -16287,7 +16312,6 @@ function onceInstant(trigger) {
|
|
|
16287
16312
|
if (!date || !clock) return null;
|
|
16288
16313
|
return new Date(date.year, date.month - 1, date.day, clock.hour, clock.minute, 0, 0).getTime();
|
|
16289
16314
|
}
|
|
16290
|
-
var MAX_TURNS_CEILING = 1e3;
|
|
16291
16315
|
var MAX_TIMEOUT_MS = 24 * 60 * 60 * 1e3;
|
|
16292
16316
|
function validateSchedule(input) {
|
|
16293
16317
|
const issues = [];
|
|
@@ -16303,7 +16327,7 @@ function validateSchedule(input) {
|
|
|
16303
16327
|
if (!Number.isFinite(input.maxBudgetUsd) || input.maxBudgetUsd <= 0) {
|
|
16304
16328
|
issues.push({ code: "budget-missing", detail: String(input.maxBudgetUsd) });
|
|
16305
16329
|
}
|
|
16306
|
-
if (!Number.isInteger(input.maxTurns) || input.maxTurns
|
|
16330
|
+
if (!Number.isInteger(input.maxTurns) || input.maxTurns < 0) {
|
|
16307
16331
|
issues.push({ code: "max-turns-invalid", detail: String(input.maxTurns) });
|
|
16308
16332
|
}
|
|
16309
16333
|
if (!Number.isFinite(input.timeoutMs) || input.timeoutMs <= 0 || input.timeoutMs > MAX_TIMEOUT_MS) {
|
|
@@ -16330,7 +16354,7 @@ function bypassIssues(input) {
|
|
|
16330
16354
|
} else if (isTooBroad(input.workDir, input.homeDir)) {
|
|
16331
16355
|
issues.push({ code: "bypass-workdir-too-broad", detail: input.workDir });
|
|
16332
16356
|
}
|
|
16333
|
-
const missingRuler = !(input.maxBudgetUsd > 0) || !(input.
|
|
16357
|
+
const missingRuler = !(input.maxBudgetUsd > 0) || !(input.timeoutMs > 0);
|
|
16334
16358
|
if (missingRuler) issues.push({ code: "bypass-needs-limits" });
|
|
16335
16359
|
if (input.bypassAcknowledged !== true) issues.push({ code: "bypass-not-confirmed" });
|
|
16336
16360
|
return issues;
|
|
@@ -17903,6 +17927,25 @@ var HookManager = class {
|
|
|
17903
17927
|
});
|
|
17904
17928
|
}
|
|
17905
17929
|
}
|
|
17930
|
+
const cmdEntries = this.commandHooks.get(type);
|
|
17931
|
+
if (cmdEntries) {
|
|
17932
|
+
for (const entry of cmdEntries) {
|
|
17933
|
+
if (!matchesHook(entry.matcher, event)) continue;
|
|
17934
|
+
for (const config of entry.configs) {
|
|
17935
|
+
try {
|
|
17936
|
+
const result = await runCommandHook(config, event, ctx.workDir);
|
|
17937
|
+
reportIfNeverRan(this.log, type, config, result);
|
|
17938
|
+
const verdict = verdictOf2(result);
|
|
17939
|
+
if (verdict) results.push(verdict);
|
|
17940
|
+
} catch (err) {
|
|
17941
|
+
this.log("warn", `[HookManager] ${type} \u7684 command hook \u6267\u884C\u5F02\u5E38: ${describe7(err)}`, {
|
|
17942
|
+
hookType: type,
|
|
17943
|
+
command: config.command
|
|
17944
|
+
});
|
|
17945
|
+
}
|
|
17946
|
+
}
|
|
17947
|
+
}
|
|
17948
|
+
}
|
|
17906
17949
|
return results;
|
|
17907
17950
|
}
|
|
17908
17951
|
getSorted(type) {
|
|
@@ -17914,6 +17957,17 @@ var HookManager = class {
|
|
|
17914
17957
|
function describe7(err) {
|
|
17915
17958
|
return err instanceof Error ? err.message : String(err);
|
|
17916
17959
|
}
|
|
17960
|
+
function verdictOf2(result) {
|
|
17961
|
+
const action = result.output?.["action"];
|
|
17962
|
+
if (action === "continue" || action === "stop") {
|
|
17963
|
+
const message = typeof result.output?.["message"] === "string" ? result.output["message"] : "";
|
|
17964
|
+
return { action, ...message ? { message } : {} };
|
|
17965
|
+
}
|
|
17966
|
+
if (result.blocked) {
|
|
17967
|
+
return { action: "continue", ...result.rejectReason ? { message: result.rejectReason } : {} };
|
|
17968
|
+
}
|
|
17969
|
+
return void 0;
|
|
17970
|
+
}
|
|
17917
17971
|
function reportIfNeverRan(log5, type, config, result) {
|
|
17918
17972
|
if (result.exitCode !== -1) return;
|
|
17919
17973
|
log5(
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@epoch-agent/core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "epoch-agent 核心引擎:ReAct 循环、Provider 路由、工具调度、记忆管理",
|
|
6
6
|
"repository": {
|
|
@@ -27,8 +27,8 @@
|
|
|
27
27
|
"gpt-tokenizer": "^3.4.0",
|
|
28
28
|
"js-yaml": "^5.2.3",
|
|
29
29
|
"zod": "^4.4.3",
|
|
30
|
-
"@epoch-agent/infra": "0.
|
|
31
|
-
"@epoch-agent/protocol": "0.
|
|
30
|
+
"@epoch-agent/infra": "0.5.0",
|
|
31
|
+
"@epoch-agent/protocol": "0.5.0"
|
|
32
32
|
},
|
|
33
33
|
"devDependencies": {
|
|
34
34
|
"@ai-sdk/amazon-bedrock": "^5.0.40",
|