agent-lyceum 0.7.0 → 0.8.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 +2 -1
- package/README.zh-TW.md +2 -1
- package/dist/adapters/claude.js +5 -0
- package/dist/adapters/codex.js +4 -0
- package/dist/config.d.ts +5 -1
- package/dist/config.js +4 -1
- package/dist/schema.d.ts +18 -0
- package/dist/schema.js +3 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -107,9 +107,10 @@ agents:
|
|
|
107
107
|
lead: { resume: true, can_message: all, can_edit_agent_md: true }
|
|
108
108
|
fe-member: { runtime: codex, can_message: [lead], owns: ["src/web/**"] }
|
|
109
109
|
qa-member: { can_message: [lead], owns: ["tests/**"] }
|
|
110
|
+
pm: { can_message: [lead], allow_web: fetch } # pm may search and read pages; the others have no web tools
|
|
110
111
|
```
|
|
111
112
|
|
|
112
|
-
Agent fields: `runtime` (`claude-code`|`codex`; optional when `model` is recognizable: `opus`/`sonnet`/`haiku`/`claude-*` → Claude Code, `gpt-*`/`o3`/`*codex*` → Codex; precedence: project runtime > project model > global runtime > global model), `model`, `effort` (Claude Code: `low`|`medium`|`high`|`xhigh`|`max` via `--effort`; Codex: `minimal`|`low`|`medium`|`high`|`xhigh` via `model_reasoning_effort`; unset = CLI default), `agent_md`, `memory.global` / `memory.project`, `resume`, `can_message` (`all` or list; default `[lead]`, lead default `all`), `can_edit_agent_md` (default only the lead), `can_ask_user` (may send `type: ask` mail to you and pause the run for an answer; default only the lead), `owns` (repo globs).
|
|
113
|
+
Agent fields: `runtime` (`claude-code`|`codex`; optional when `model` is recognizable: `opus`/`sonnet`/`haiku`/`claude-*` → Claude Code, `gpt-*`/`o3`/`*codex*` → Codex; precedence: project runtime > project model > global runtime > global model), `model`, `effort` (Claude Code: `low`|`medium`|`high`|`xhigh`|`max` via `--effort`; Codex: `minimal`|`low`|`medium`|`high`|`xhigh` via `model_reasoning_effort`; unset = CLI default), `agent_md`, `memory.global` / `memory.project`, `resume`, `can_message` (`all` or list; default `[lead]`, lead default `all`), `can_edit_agent_md` (default only the lead), `can_ask_user` (may send `type: ask` mail to you and pause the run for an answer; default only the lead), `allow_web` (`none`|`search`|`fetch`: what the agent may use of the web; unset means Claude Code gets no web tools and Codex keeps its own default; `search` = `WebSearch` / Codex `web_search="cached"`, `fetch` = `WebSearch` + `WebFetch` / Codex `web_search="live"`, `none` = no web tools / Codex `disabled`; `fetch` pulls whole pages into the agent's context, so give it only to agents that do little editing, such as a requirements or research role), `owns` (repo globs).
|
|
113
114
|
|
|
114
115
|
Rules checked by `validate`: ≥ 2 agents (the lead and one member; the template has three), the lead is a listed agent, every agent has a runtime (explicit or inferred from `model`) and an existing `AGENT.md`, `effort` is valid for the agent's runtime (warning if `runtime` contradicts a recognizable `model`), `can_message` targets exist, memory dirs don't overlap, and with `max_parallel > 1` every non-lead agent needs non-overlapping `owns` and the repo must be a git repository.
|
|
115
116
|
|
package/README.zh-TW.md
CHANGED
|
@@ -108,9 +108,10 @@ agents:
|
|
|
108
108
|
lead: { resume: true, can_message: all, can_edit_agent_md: true }
|
|
109
109
|
fe-member: { runtime: codex, can_message: [lead], owns: ["src/web/**"] }
|
|
110
110
|
qa-member: { can_message: [lead], owns: ["tests/**"] }
|
|
111
|
+
pm: { can_message: [lead], allow_web: fetch } # pm 可以搜尋並讀網頁;其他人沒有網路工具
|
|
111
112
|
```
|
|
112
113
|
|
|
113
|
-
Agent 欄位:`runtime`(`claude-code`|`codex`;若 `model` 可辨識則可省略:`opus`/`sonnet`/`haiku`/`claude-*` → Claude Code,`gpt-*`/`o3`/`*codex*` → Codex;優先順序:專案 runtime > 專案 model > 全域 runtime > 全域 model)、`model`、`effort`(Claude Code:`low`|`medium`|`high`|`xhigh`|`max`,經 `--effort`;Codex:`minimal`|`low`|`medium`|`high`|`xhigh`,經 `model_reasoning_effort`;未設則用 CLI 預設)、`agent_md`、`memory.global` / `memory.project`、`resume`、`can_message`(`all` 或清單;預設 `[lead]`,lead 預設 `all`)、`can_edit_agent_md`(預設只有 lead)、`can_ask_user`(可用 `type: ask` 信件向你提問並暫停 run 等待回答;預設只有 lead)、`owns`(repo glob)。
|
|
114
|
+
Agent 欄位:`runtime`(`claude-code`|`codex`;若 `model` 可辨識則可省略:`opus`/`sonnet`/`haiku`/`claude-*` → Claude Code,`gpt-*`/`o3`/`*codex*` → Codex;優先順序:專案 runtime > 專案 model > 全域 runtime > 全域 model)、`model`、`effort`(Claude Code:`low`|`medium`|`high`|`xhigh`|`max`,經 `--effort`;Codex:`minimal`|`low`|`medium`|`high`|`xhigh`,經 `model_reasoning_effort`;未設則用 CLI 預設)、`agent_md`、`memory.global` / `memory.project`、`resume`、`can_message`(`all` 或清單;預設 `[lead]`,lead 預設 `all`)、`can_edit_agent_md`(預設只有 lead)、`can_ask_user`(可用 `type: ask` 信件向你提問並暫停 run 等待回答;預設只有 lead)、`allow_web`(`none`|`search`|`fetch`:agent 可以使用多少網路;不設時 Claude Code 沒有網路工具、Codex 維持它自己的預設;`search` = `WebSearch`/Codex `web_search="cached"`,`fetch` = `WebSearch` 加 `WebFetch`/Codex `web_search="live"`,`none` = 不給網路工具/Codex `disabled`;`fetch` 會把整個網頁放進 agent 的上下文,只建議給很少改檔的角色,例如需求或研究角色)、`owns`(repo glob)。
|
|
114
115
|
|
|
115
116
|
`validate` 檢查的規則:至少 2 個 agent(lead 加一位成員;範本預設是三位)、lead 在 agent 清單內、每個 agent 都有 runtime(明設或由 `model` 推斷)且 `AGENT.md` 存在、`effort` 對該 runtime 合法(若 `runtime` 與可辨識的 `model` 矛盾則警告)、`can_message` 的目標存在、記憶資料夾互不重疊,且當 `max_parallel > 1` 時,每個非 lead 的 agent 都必須有互不重疊的 `owns`,repo 也必須是 git repository。
|
|
116
117
|
|
package/dist/adapters/claude.js
CHANGED
|
@@ -22,6 +22,11 @@ export function buildClaudeSettings(project, agent) {
|
|
|
22
22
|
const ws = project.workspaces?.[agent.name];
|
|
23
23
|
const repo = repoDirFor(project, agent.name);
|
|
24
24
|
const allow = ["Bash", "Read", "Glob", "Grep"];
|
|
25
|
+
// Web tools are opt-in: `search` is the lighter one (snippets only), `fetch` also pulls whole pages into the agent's context.
|
|
26
|
+
if (agent.allowWeb === "search" || agent.allowWeb === "fetch")
|
|
27
|
+
allow.push("WebSearch");
|
|
28
|
+
if (agent.allowWeb === "fetch")
|
|
29
|
+
allow.push("WebFetch");
|
|
25
30
|
if (pol.restrictRepoToOwns) {
|
|
26
31
|
for (const g of pol.owns)
|
|
27
32
|
allow.push(rule("Edit", path.join(repo, g)));
|
package/dist/adapters/codex.js
CHANGED
|
@@ -48,6 +48,8 @@ export function codexOutputTokens(jsonl) {
|
|
|
48
48
|
}
|
|
49
49
|
return total;
|
|
50
50
|
}
|
|
51
|
+
/** Codex has one `web_search` setting: `cached` answers from an index, `live` browses. */
|
|
52
|
+
const CODEX_WEB_SEARCH = { none: "disabled", search: "cached", fetch: "live" };
|
|
51
53
|
export function buildCodexInvocation(input) {
|
|
52
54
|
const { project, agent, workDir } = input;
|
|
53
55
|
const repo = repoDirFor(project, agent.name);
|
|
@@ -67,6 +69,8 @@ export function buildCodexInvocation(input) {
|
|
|
67
69
|
common.push("-m", agent.model);
|
|
68
70
|
if (agent.effort)
|
|
69
71
|
common.push("-c", `model_reasoning_effort="${agent.effort}"`);
|
|
72
|
+
if (agent.allowWeb)
|
|
73
|
+
common.push("-c", `web_search="${CODEX_WEB_SEARCH[agent.allowWeb]}"`);
|
|
70
74
|
const args = input.sessionId
|
|
71
75
|
? ["exec", "resume", input.sessionId, "-c", 'sandbox_mode="workspace-write"', ...common, "-"]
|
|
72
76
|
: ["exec", "-C", repo, "-s", "workspace-write", "--skip-git-repo-check", ...common, "-"];
|
package/dist/config.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { type ProjectPaths } from "./paths.js";
|
|
2
2
|
import type { AgentWorkspace } from "./worktree.js";
|
|
3
|
-
import { type DispatcherSettings, type Effort, type Runtime } from "./schema.js";
|
|
3
|
+
import { type DispatcherSettings, type Effort, type Runtime, type WebLevel } from "./schema.js";
|
|
4
4
|
export declare class ConfigError extends Error {
|
|
5
5
|
}
|
|
6
6
|
export type Source = "global" | "project" | "default" | "model";
|
|
@@ -20,6 +20,8 @@ export interface ResolvedAgent {
|
|
|
20
20
|
canEditAgentMd: boolean;
|
|
21
21
|
/** May send `type: ask` mail to the user (the run then waits for the answer). */
|
|
22
22
|
canAskUser: boolean;
|
|
23
|
+
/** Web access for this agent; undefined = not configured, so the runtime keeps its own default. */
|
|
24
|
+
allowWeb?: WebLevel;
|
|
23
25
|
owns: string[];
|
|
24
26
|
/** Where each field's value came from (for `validate` output). */
|
|
25
27
|
sources: Record<string, Source>;
|
|
@@ -58,6 +60,7 @@ export declare function loadGlobal(home: string): {
|
|
|
58
60
|
can_message?: "all" | string[] | undefined;
|
|
59
61
|
can_edit_agent_md?: boolean | undefined;
|
|
60
62
|
can_ask_user?: boolean | undefined;
|
|
63
|
+
allow_web?: "fetch" | "none" | "search" | undefined;
|
|
61
64
|
owns?: string[] | undefined;
|
|
62
65
|
}>;
|
|
63
66
|
};
|
|
@@ -88,6 +91,7 @@ export declare function loadProjectRaw(home: string, name: string): {
|
|
|
88
91
|
can_message?: "all" | string[] | undefined;
|
|
89
92
|
can_edit_agent_md?: boolean | undefined;
|
|
90
93
|
can_ask_user?: boolean | undefined;
|
|
94
|
+
allow_web?: "fetch" | "none" | "search" | undefined;
|
|
91
95
|
owns?: string[] | undefined;
|
|
92
96
|
}>;
|
|
93
97
|
};
|
package/dist/config.js
CHANGED
|
@@ -133,6 +133,7 @@ export function resolveProjectFrom(home, name, g, p) {
|
|
|
133
133
|
const canMessage = pick("can_message");
|
|
134
134
|
const canEdit = pick("can_edit_agent_md");
|
|
135
135
|
const canAsk = pick("can_ask_user");
|
|
136
|
+
const allowWeb = pick("allow_web");
|
|
136
137
|
const owns = pick("owns");
|
|
137
138
|
for (const [k, v] of [
|
|
138
139
|
["resume", resume],
|
|
@@ -155,6 +156,7 @@ export function resolveProjectFrom(home, name, g, p) {
|
|
|
155
156
|
canMessage: canMessage ?? (isLead ? "all" : [lead]),
|
|
156
157
|
canEditAgentMd: canEdit ?? isLead,
|
|
157
158
|
canAskUser: canAsk ?? isLead,
|
|
159
|
+
allowWeb,
|
|
158
160
|
owns: owns ?? [],
|
|
159
161
|
sources,
|
|
160
162
|
};
|
|
@@ -203,7 +205,7 @@ export function findProjectForCwd(home, cwd) {
|
|
|
203
205
|
}
|
|
204
206
|
return best?.name;
|
|
205
207
|
}
|
|
206
|
-
const AGENT_FIELDS = ["runtime", "model", "effort", "agent_md", "memory.global", "memory.project", "resume", "can_message", "can_edit_agent_md", "can_ask_user", "owns"];
|
|
208
|
+
const AGENT_FIELDS = ["runtime", "model", "effort", "agent_md", "memory.global", "memory.project", "resume", "can_message", "can_edit_agent_md", "can_ask_user", "allow_web", "owns"];
|
|
207
209
|
/** The resolved project plus, for every setting, the file and key it was taken from (or "default"). */
|
|
208
210
|
export function resolveProjectWithSources(home, name) {
|
|
209
211
|
const project = resolveProject(home, name);
|
|
@@ -261,6 +263,7 @@ export function flattenResolved(project) {
|
|
|
261
263
|
v[`${p}.can_message`] = a.canMessage;
|
|
262
264
|
v[`${p}.can_edit_agent_md`] = a.canEditAgentMd;
|
|
263
265
|
v[`${p}.can_ask_user`] = a.canAskUser;
|
|
266
|
+
v[`${p}.allow_web`] = a.allowWeb;
|
|
264
267
|
v[`${p}.owns`] = a.owns;
|
|
265
268
|
}
|
|
266
269
|
return v;
|
package/dist/schema.d.ts
CHANGED
|
@@ -8,6 +8,9 @@ export type Effort = (typeof EFFORTS)[number];
|
|
|
8
8
|
export declare const RUNTIME_EFFORTS: Record<Runtime, readonly Effort[]>;
|
|
9
9
|
/** Guess the runtime from a model name: Claude aliases/IDs -> claude-code, GPT/o-series/codex names -> codex. */
|
|
10
10
|
export declare function inferRuntime(model: string | undefined): Runtime | undefined;
|
|
11
|
+
/** How much of the web an agent may use: nothing, search only, or search plus fetching pages. Unset leaves each runtime's own default alone. */
|
|
12
|
+
export declare const WEB_LEVELS: readonly ["none", "search", "fetch"];
|
|
13
|
+
export type WebLevel = (typeof WEB_LEVELS)[number];
|
|
11
14
|
export declare const AgentPartial: z.ZodObject<{
|
|
12
15
|
runtime: z.ZodOptional<z.ZodEnum<{
|
|
13
16
|
"claude-code": "claude-code";
|
|
@@ -31,6 +34,11 @@ export declare const AgentPartial: z.ZodObject<{
|
|
|
31
34
|
can_message: z.ZodOptional<z.ZodUnion<readonly [z.ZodLiteral<"all">, z.ZodArray<z.ZodString>]>>;
|
|
32
35
|
can_edit_agent_md: z.ZodOptional<z.ZodBoolean>;
|
|
33
36
|
can_ask_user: z.ZodOptional<z.ZodBoolean>;
|
|
37
|
+
allow_web: z.ZodOptional<z.ZodEnum<{
|
|
38
|
+
fetch: "fetch";
|
|
39
|
+
none: "none";
|
|
40
|
+
search: "search";
|
|
41
|
+
}>>;
|
|
34
42
|
owns: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
35
43
|
}, z.core.$strict>;
|
|
36
44
|
export type AgentPartialT = z.infer<typeof AgentPartial>;
|
|
@@ -71,6 +79,11 @@ export declare const GlobalConfig: z.ZodObject<{
|
|
|
71
79
|
can_message: z.ZodOptional<z.ZodUnion<readonly [z.ZodLiteral<"all">, z.ZodArray<z.ZodString>]>>;
|
|
72
80
|
can_edit_agent_md: z.ZodOptional<z.ZodBoolean>;
|
|
73
81
|
can_ask_user: z.ZodOptional<z.ZodBoolean>;
|
|
82
|
+
allow_web: z.ZodOptional<z.ZodEnum<{
|
|
83
|
+
fetch: "fetch";
|
|
84
|
+
none: "none";
|
|
85
|
+
search: "search";
|
|
86
|
+
}>>;
|
|
74
87
|
owns: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
75
88
|
}, z.core.$strict>>>;
|
|
76
89
|
}, z.core.$strict>;
|
|
@@ -115,6 +128,11 @@ export declare const ProjectConfig: z.ZodObject<{
|
|
|
115
128
|
can_message: z.ZodOptional<z.ZodUnion<readonly [z.ZodLiteral<"all">, z.ZodArray<z.ZodString>]>>;
|
|
116
129
|
can_edit_agent_md: z.ZodOptional<z.ZodBoolean>;
|
|
117
130
|
can_ask_user: z.ZodOptional<z.ZodBoolean>;
|
|
131
|
+
allow_web: z.ZodOptional<z.ZodEnum<{
|
|
132
|
+
fetch: "fetch";
|
|
133
|
+
none: "none";
|
|
134
|
+
search: "search";
|
|
135
|
+
}>>;
|
|
118
136
|
owns: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
119
137
|
}, z.core.$strict>>>;
|
|
120
138
|
}, z.core.$strict>;
|
package/dist/schema.js
CHANGED
|
@@ -18,6 +18,8 @@ export function inferRuntime(model) {
|
|
|
18
18
|
return "codex";
|
|
19
19
|
return undefined;
|
|
20
20
|
}
|
|
21
|
+
/** How much of the web an agent may use: nothing, search only, or search plus fetching pages. Unset leaves each runtime's own default alone. */
|
|
22
|
+
export const WEB_LEVELS = ["none", "search", "fetch"];
|
|
21
23
|
const Memory = z
|
|
22
24
|
.object({
|
|
23
25
|
global: z.string().optional(),
|
|
@@ -35,6 +37,7 @@ export const AgentPartial = z
|
|
|
35
37
|
can_message: z.union([z.literal("all"), z.array(z.string())]).optional(),
|
|
36
38
|
can_edit_agent_md: z.boolean().optional(),
|
|
37
39
|
can_ask_user: z.boolean().optional(),
|
|
40
|
+
allow_web: z.enum(WEB_LEVELS).optional(),
|
|
38
41
|
owns: z.array(z.string()).optional(),
|
|
39
42
|
})
|
|
40
43
|
.strict();
|