Merge 59347115db into 4583f88626
This commit is contained in:
commit
9ddddfc83e
@ -118,6 +118,44 @@ adjust the limit with `agents.defaults.bootstrapMaxChars` (default: 20000).
|
|||||||
`moltbot setup` can recreate missing defaults without overwriting existing
|
`moltbot setup` can recreate missing defaults without overwriting existing
|
||||||
files.
|
files.
|
||||||
|
|
||||||
|
## Extra workspace files
|
||||||
|
|
||||||
|
You can inject additional workspace files into the system prompt alongside the
|
||||||
|
defaults using `extraWorkspaceFiles`:
|
||||||
|
|
||||||
|
```json5
|
||||||
|
{
|
||||||
|
agents: {
|
||||||
|
defaults: {
|
||||||
|
extraWorkspaceFiles: ["PANTHEON.md", "protocols/SHARED.md"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Paths are relative to the workspace directory. Files that do not exist are
|
||||||
|
silently skipped (no "missing file" marker). Duplicates of default files are
|
||||||
|
ignored.
|
||||||
|
|
||||||
|
Per-agent overrides are supported:
|
||||||
|
|
||||||
|
```json5
|
||||||
|
{
|
||||||
|
agents: {
|
||||||
|
defaults: {
|
||||||
|
extraWorkspaceFiles: ["PANTHEON.md"]
|
||||||
|
},
|
||||||
|
list: [
|
||||||
|
{ id: "researcher", extraWorkspaceFiles: ["RESEARCH_PROTOCOL.md"] },
|
||||||
|
{ id: "minimal", extraWorkspaceFiles: [] } // disable extras
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Extra files are included for subagent sessions alongside the default allowlist
|
||||||
|
(AGENTS.md, TOOLS.md).
|
||||||
|
|
||||||
## What is NOT in the workspace
|
## What is NOT in the workspace
|
||||||
|
|
||||||
These live under `~/.clawdbot/` and should NOT be committed to the workspace repo:
|
These live under `~/.clawdbot/` and should NOT be committed to the workspace repo:
|
||||||
|
|||||||
@ -20,6 +20,7 @@ type ResolvedAgentConfig = {
|
|||||||
workspace?: string;
|
workspace?: string;
|
||||||
agentDir?: string;
|
agentDir?: string;
|
||||||
model?: AgentEntry["model"];
|
model?: AgentEntry["model"];
|
||||||
|
extraWorkspaceFiles?: string[];
|
||||||
memorySearch?: AgentEntry["memorySearch"];
|
memorySearch?: AgentEntry["memorySearch"];
|
||||||
humanDelay?: AgentEntry["humanDelay"];
|
humanDelay?: AgentEntry["humanDelay"];
|
||||||
heartbeat?: AgentEntry["heartbeat"];
|
heartbeat?: AgentEntry["heartbeat"];
|
||||||
@ -103,6 +104,9 @@ export function resolveAgentConfig(
|
|||||||
typeof entry.model === "string" || (entry.model && typeof entry.model === "object")
|
typeof entry.model === "string" || (entry.model && typeof entry.model === "object")
|
||||||
? entry.model
|
? entry.model
|
||||||
: undefined,
|
: undefined,
|
||||||
|
extraWorkspaceFiles: Array.isArray(entry.extraWorkspaceFiles)
|
||||||
|
? entry.extraWorkspaceFiles
|
||||||
|
: undefined,
|
||||||
memorySearch: entry.memorySearch,
|
memorySearch: entry.memorySearch,
|
||||||
humanDelay: entry.humanDelay,
|
humanDelay: entry.humanDelay,
|
||||||
heartbeat: entry.heartbeat,
|
heartbeat: entry.heartbeat,
|
||||||
|
|||||||
@ -3,12 +3,13 @@ import path from "node:path";
|
|||||||
import { afterEach, beforeEach, describe, expect, it } from "vitest";
|
import { afterEach, beforeEach, describe, expect, it } from "vitest";
|
||||||
|
|
||||||
import { resolveBootstrapContextForRun, resolveBootstrapFilesForRun } from "./bootstrap-files.js";
|
import { resolveBootstrapContextForRun, resolveBootstrapFilesForRun } from "./bootstrap-files.js";
|
||||||
import { makeTempWorkspace } from "../test-helpers/workspace.js";
|
import { makeTempWorkspace, writeWorkspaceFile } from "../test-helpers/workspace.js";
|
||||||
import {
|
import {
|
||||||
clearInternalHooks,
|
clearInternalHooks,
|
||||||
registerInternalHook,
|
registerInternalHook,
|
||||||
type AgentBootstrapHookContext,
|
type AgentBootstrapHookContext,
|
||||||
} from "../hooks/internal-hooks.js";
|
} from "../hooks/internal-hooks.js";
|
||||||
|
import type { ClawdbotConfig } from "../config/config.js";
|
||||||
|
|
||||||
describe("resolveBootstrapFilesForRun", () => {
|
describe("resolveBootstrapFilesForRun", () => {
|
||||||
beforeEach(() => clearInternalHooks());
|
beforeEach(() => clearInternalHooks());
|
||||||
@ -60,3 +61,72 @@ describe("resolveBootstrapContextForRun", () => {
|
|||||||
expect(extra?.content).toBe("extra");
|
expect(extra?.content).toBe("extra");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("extraWorkspaceFiles per-agent config", () => {
|
||||||
|
beforeEach(() => clearInternalHooks());
|
||||||
|
afterEach(() => clearInternalHooks());
|
||||||
|
|
||||||
|
it("uses per-agent extraWorkspaceFiles over defaults", async () => {
|
||||||
|
const workspaceDir = await makeTempWorkspace("clawdbot-bootstrap-");
|
||||||
|
await writeWorkspaceFile({ dir: workspaceDir, name: "AGENT_SPECIFIC.md", content: "agent" });
|
||||||
|
await writeWorkspaceFile({ dir: workspaceDir, name: "DEFAULT.md", content: "default" });
|
||||||
|
|
||||||
|
const config: ClawdbotConfig = {
|
||||||
|
agents: {
|
||||||
|
defaults: { extraWorkspaceFiles: ["DEFAULT.md"] },
|
||||||
|
list: [{ id: "test-agent", extraWorkspaceFiles: ["AGENT_SPECIFIC.md"] }],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const files = await resolveBootstrapFilesForRun({
|
||||||
|
workspaceDir,
|
||||||
|
config,
|
||||||
|
agentId: "test-agent",
|
||||||
|
});
|
||||||
|
|
||||||
|
// Per-agent config should be used, not defaults
|
||||||
|
expect(files.some((f) => f.name === "AGENT_SPECIFIC.md")).toBe(true);
|
||||||
|
expect(files.some((f) => f.name === "DEFAULT.md")).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("falls back to defaults when agent has no extraWorkspaceFiles", async () => {
|
||||||
|
const workspaceDir = await makeTempWorkspace("clawdbot-bootstrap-");
|
||||||
|
await writeWorkspaceFile({ dir: workspaceDir, name: "DEFAULT.md", content: "default" });
|
||||||
|
|
||||||
|
const config: ClawdbotConfig = {
|
||||||
|
agents: {
|
||||||
|
defaults: { extraWorkspaceFiles: ["DEFAULT.md"] },
|
||||||
|
list: [{ id: "other-agent" }],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const files = await resolveBootstrapFilesForRun({
|
||||||
|
workspaceDir,
|
||||||
|
config,
|
||||||
|
agentId: "other-agent",
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(files.some((f) => f.name === "DEFAULT.md")).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("allows per-agent to disable extras with empty array", async () => {
|
||||||
|
const workspaceDir = await makeTempWorkspace("clawdbot-bootstrap-");
|
||||||
|
await writeWorkspaceFile({ dir: workspaceDir, name: "DEFAULT.md", content: "default" });
|
||||||
|
|
||||||
|
const config: ClawdbotConfig = {
|
||||||
|
agents: {
|
||||||
|
defaults: { extraWorkspaceFiles: ["DEFAULT.md"] },
|
||||||
|
list: [{ id: "no-extras", extraWorkspaceFiles: [] }],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const files = await resolveBootstrapFilesForRun({
|
||||||
|
workspaceDir,
|
||||||
|
config,
|
||||||
|
agentId: "no-extras",
|
||||||
|
});
|
||||||
|
|
||||||
|
// Empty array should override defaults - no extra files
|
||||||
|
expect(files.some((f) => f.name === "DEFAULT.md")).toBe(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
import type { MoltbotConfig } from "../config/config.js";
|
import type { MoltbotConfig } from "../config/config.js";
|
||||||
|
import { resolveAgentConfig } from "./agent-scope.js";
|
||||||
import { applyBootstrapHookOverrides } from "./bootstrap-hooks.js";
|
import { applyBootstrapHookOverrides } from "./bootstrap-hooks.js";
|
||||||
import {
|
import {
|
||||||
filterBootstrapFilesForSession,
|
filterBootstrapFilesForSession,
|
||||||
@ -24,8 +25,13 @@ export async function resolveBootstrapFilesForRun(params: {
|
|||||||
agentId?: string;
|
agentId?: string;
|
||||||
}): Promise<WorkspaceBootstrapFile[]> {
|
}): Promise<WorkspaceBootstrapFile[]> {
|
||||||
const sessionKey = params.sessionKey ?? params.sessionId;
|
const sessionKey = params.sessionKey ?? params.sessionId;
|
||||||
|
// Per-agent extraWorkspaceFiles takes precedence over global defaults
|
||||||
|
const agentConfig =
|
||||||
|
params.agentId && params.config ? resolveAgentConfig(params.config, params.agentId) : undefined;
|
||||||
|
const extraFiles =
|
||||||
|
agentConfig?.extraWorkspaceFiles ?? params.config?.agents?.defaults?.extraWorkspaceFiles;
|
||||||
const bootstrapFiles = filterBootstrapFilesForSession(
|
const bootstrapFiles = filterBootstrapFilesForSession(
|
||||||
await loadWorkspaceBootstrapFiles(params.workspaceDir),
|
await loadWorkspaceBootstrapFiles(params.workspaceDir, { extraFiles }),
|
||||||
sessionKey,
|
sessionKey,
|
||||||
);
|
);
|
||||||
return applyBootstrapHookOverrides({
|
return applyBootstrapHookOverrides({
|
||||||
|
|||||||
@ -1,8 +1,11 @@
|
|||||||
import { describe, expect, it } from "vitest";
|
import { describe, expect, it } from "vitest";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
DEFAULT_AGENTS_FILENAME,
|
||||||
DEFAULT_MEMORY_ALT_FILENAME,
|
DEFAULT_MEMORY_ALT_FILENAME,
|
||||||
DEFAULT_MEMORY_FILENAME,
|
DEFAULT_MEMORY_FILENAME,
|
||||||
|
DEFAULT_TOOLS_FILENAME,
|
||||||
|
filterBootstrapFilesForSession,
|
||||||
loadWorkspaceBootstrapFiles,
|
loadWorkspaceBootstrapFiles,
|
||||||
} from "./workspace.js";
|
} from "./workspace.js";
|
||||||
import { makeTempWorkspace, writeWorkspaceFile } from "../test-helpers/workspace.js";
|
import { makeTempWorkspace, writeWorkspaceFile } from "../test-helpers/workspace.js";
|
||||||
@ -46,4 +49,72 @@ describe("loadWorkspaceBootstrapFiles", () => {
|
|||||||
|
|
||||||
expect(memoryEntries).toHaveLength(0);
|
expect(memoryEntries).toHaveLength(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("includes extraWorkspaceFiles when present", async () => {
|
||||||
|
const tempDir = await makeTempWorkspace("clawdbot-workspace-");
|
||||||
|
await writeWorkspaceFile({ dir: tempDir, name: "PANTHEON.md", content: "shared protocols" });
|
||||||
|
|
||||||
|
const files = await loadWorkspaceBootstrapFiles(tempDir, {
|
||||||
|
extraFiles: ["PANTHEON.md"],
|
||||||
|
});
|
||||||
|
|
||||||
|
const extra = files.find((f) => f.name === "PANTHEON.md");
|
||||||
|
expect(extra).toBeDefined();
|
||||||
|
expect(extra?.missing).toBe(false);
|
||||||
|
expect(extra?.content).toBe("shared protocols");
|
||||||
|
expect(extra?.isExtra).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("skips extraWorkspaceFiles when file does not exist", async () => {
|
||||||
|
const tempDir = await makeTempWorkspace("clawdbot-workspace-");
|
||||||
|
|
||||||
|
const files = await loadWorkspaceBootstrapFiles(tempDir, {
|
||||||
|
extraFiles: ["MISSING.md"],
|
||||||
|
});
|
||||||
|
|
||||||
|
// Extra files that don't exist are silently skipped (not marked missing)
|
||||||
|
const extra = files.find((f) => f.name === "MISSING.md");
|
||||||
|
expect(extra).toBeUndefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("dedupes extraWorkspaceFiles against defaults", async () => {
|
||||||
|
const tempDir = await makeTempWorkspace("clawdbot-workspace-");
|
||||||
|
await writeWorkspaceFile({ dir: tempDir, name: "AGENTS.md", content: "default" });
|
||||||
|
|
||||||
|
const files = await loadWorkspaceBootstrapFiles(tempDir, {
|
||||||
|
extraFiles: ["AGENTS.md"], // duplicate of default
|
||||||
|
});
|
||||||
|
|
||||||
|
// Should only have one AGENTS.md entry (the default)
|
||||||
|
const agentsEntries = files.filter((f) => f.name === DEFAULT_AGENTS_FILENAME);
|
||||||
|
expect(agentsEntries).toHaveLength(1);
|
||||||
|
expect(agentsEntries[0]?.isExtra).toBeUndefined();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("filterBootstrapFilesForSession", () => {
|
||||||
|
it("returns all files for main session", () => {
|
||||||
|
const files = [
|
||||||
|
{ name: DEFAULT_AGENTS_FILENAME, path: "/a/AGENTS.md", missing: false },
|
||||||
|
{ name: DEFAULT_TOOLS_FILENAME, path: "/a/TOOLS.md", missing: false },
|
||||||
|
{ name: "IDENTITY.md", path: "/a/IDENTITY.md", missing: false },
|
||||||
|
{ name: "PANTHEON.md", path: "/a/PANTHEON.md", missing: false, isExtra: true },
|
||||||
|
];
|
||||||
|
|
||||||
|
const filtered = filterBootstrapFilesForSession(files, "agent:main:main");
|
||||||
|
expect(filtered).toHaveLength(4);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("filters to allowlist + extras for subagent session", () => {
|
||||||
|
const files = [
|
||||||
|
{ name: DEFAULT_AGENTS_FILENAME, path: "/a/AGENTS.md", missing: false },
|
||||||
|
{ name: DEFAULT_TOOLS_FILENAME, path: "/a/TOOLS.md", missing: false },
|
||||||
|
{ name: "IDENTITY.md", path: "/a/IDENTITY.md", missing: false },
|
||||||
|
{ name: "PANTHEON.md", path: "/a/PANTHEON.md", missing: false, isExtra: true },
|
||||||
|
];
|
||||||
|
|
||||||
|
const filtered = filterBootstrapFilesForSession(files, "agent:main:subagent:abc123");
|
||||||
|
expect(filtered).toHaveLength(3); // AGENTS.md, TOOLS.md, PANTHEON.md (extra)
|
||||||
|
expect(filtered.map((f) => f.name).sort()).toEqual(["AGENTS.md", "PANTHEON.md", "TOOLS.md"]);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -68,10 +68,13 @@ export type WorkspaceBootstrapFileName =
|
|||||||
| typeof DEFAULT_MEMORY_ALT_FILENAME;
|
| typeof DEFAULT_MEMORY_ALT_FILENAME;
|
||||||
|
|
||||||
export type WorkspaceBootstrapFile = {
|
export type WorkspaceBootstrapFile = {
|
||||||
name: WorkspaceBootstrapFileName;
|
/** Filename (e.g., "AGENTS.md") or custom name for extra files */
|
||||||
|
name: WorkspaceBootstrapFileName | string;
|
||||||
path: string;
|
path: string;
|
||||||
content?: string;
|
content?: string;
|
||||||
missing: boolean;
|
missing: boolean;
|
||||||
|
/** True for user-configured extraWorkspaceFiles */
|
||||||
|
isExtra?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
async function writeFileIfMissing(filePath: string, content: string) {
|
async function writeFileIfMissing(filePath: string, content: string) {
|
||||||
@ -221,12 +224,16 @@ async function resolveMemoryBootstrapEntries(
|
|||||||
return deduped;
|
return deduped;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function loadWorkspaceBootstrapFiles(dir: string): Promise<WorkspaceBootstrapFile[]> {
|
export async function loadWorkspaceBootstrapFiles(
|
||||||
|
dir: string,
|
||||||
|
options?: { extraFiles?: string[] },
|
||||||
|
): Promise<WorkspaceBootstrapFile[]> {
|
||||||
const resolvedDir = resolveUserPath(dir);
|
const resolvedDir = resolveUserPath(dir);
|
||||||
|
|
||||||
const entries: Array<{
|
const entries: Array<{
|
||||||
name: WorkspaceBootstrapFileName;
|
name: WorkspaceBootstrapFileName | string;
|
||||||
filePath: string;
|
filePath: string;
|
||||||
|
isExtra?: boolean;
|
||||||
}> = [
|
}> = [
|
||||||
{
|
{
|
||||||
name: DEFAULT_AGENTS_FILENAME,
|
name: DEFAULT_AGENTS_FILENAME,
|
||||||
@ -260,6 +267,23 @@ export async function loadWorkspaceBootstrapFiles(dir: string): Promise<Workspac
|
|||||||
|
|
||||||
entries.push(...(await resolveMemoryBootstrapEntries(resolvedDir)));
|
entries.push(...(await resolveMemoryBootstrapEntries(resolvedDir)));
|
||||||
|
|
||||||
|
// Add extra workspace files from config
|
||||||
|
if (options?.extraFiles) {
|
||||||
|
const seenPaths = new Set(entries.map((e) => e.filePath.toLowerCase()));
|
||||||
|
for (const extraPath of options.extraFiles) {
|
||||||
|
const trimmed = extraPath.trim();
|
||||||
|
if (!trimmed) continue;
|
||||||
|
// Resolve path relative to workspace dir
|
||||||
|
const filePath = path.isAbsolute(trimmed) ? trimmed : path.join(resolvedDir, trimmed);
|
||||||
|
// Dedupe: skip if already in the default list
|
||||||
|
if (seenPaths.has(filePath.toLowerCase())) continue;
|
||||||
|
seenPaths.add(filePath.toLowerCase());
|
||||||
|
// Use the basename as the display name
|
||||||
|
const name = path.basename(trimmed);
|
||||||
|
entries.push({ name, filePath, isExtra: true });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const result: WorkspaceBootstrapFile[] = [];
|
const result: WorkspaceBootstrapFile[] = [];
|
||||||
for (const entry of entries) {
|
for (const entry of entries) {
|
||||||
try {
|
try {
|
||||||
@ -269,8 +293,11 @@ export async function loadWorkspaceBootstrapFiles(dir: string): Promise<Workspac
|
|||||||
path: entry.filePath,
|
path: entry.filePath,
|
||||||
content,
|
content,
|
||||||
missing: false,
|
missing: false,
|
||||||
|
isExtra: entry.isExtra,
|
||||||
});
|
});
|
||||||
} catch {
|
} catch {
|
||||||
|
// For extra files, only include if they exist (don't mark as missing)
|
||||||
|
if (entry.isExtra) continue;
|
||||||
result.push({ name: entry.name, path: entry.filePath, missing: true });
|
result.push({ name: entry.name, path: entry.filePath, missing: true });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -284,5 +311,8 @@ export function filterBootstrapFilesForSession(
|
|||||||
sessionKey?: string,
|
sessionKey?: string,
|
||||||
): WorkspaceBootstrapFile[] {
|
): WorkspaceBootstrapFile[] {
|
||||||
if (!sessionKey || !isSubagentSessionKey(sessionKey)) return files;
|
if (!sessionKey || !isSubagentSessionKey(sessionKey)) return files;
|
||||||
return files.filter((file) => SUBAGENT_BOOTSTRAP_ALLOWLIST.has(file.name));
|
// For subagents: include allowlisted defaults + all extra workspace files
|
||||||
|
return files.filter(
|
||||||
|
(file) => SUBAGENT_BOOTSTRAP_ALLOWLIST.has(file.name) || file.isExtra === true,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -124,6 +124,7 @@ const FIELD_LABELS: Record<string, string> = {
|
|||||||
"diagnostics.cacheTrace.includePrompt": "Cache Trace Include Prompt",
|
"diagnostics.cacheTrace.includePrompt": "Cache Trace Include Prompt",
|
||||||
"diagnostics.cacheTrace.includeSystem": "Cache Trace Include System",
|
"diagnostics.cacheTrace.includeSystem": "Cache Trace Include System",
|
||||||
"agents.list.*.identity.avatar": "Identity Avatar",
|
"agents.list.*.identity.avatar": "Identity Avatar",
|
||||||
|
"agents.list.*.extraWorkspaceFiles": "Extra Workspace Files",
|
||||||
"gateway.remote.url": "Remote Gateway URL",
|
"gateway.remote.url": "Remote Gateway URL",
|
||||||
"gateway.remote.sshTarget": "Remote Gateway SSH Target",
|
"gateway.remote.sshTarget": "Remote Gateway SSH Target",
|
||||||
"gateway.remote.sshIdentity": "Remote Gateway SSH Identity",
|
"gateway.remote.sshIdentity": "Remote Gateway SSH Identity",
|
||||||
@ -216,6 +217,7 @@ const FIELD_LABELS: Record<string, string> = {
|
|||||||
"agents.defaults.workspace": "Workspace",
|
"agents.defaults.workspace": "Workspace",
|
||||||
"agents.defaults.repoRoot": "Repo Root",
|
"agents.defaults.repoRoot": "Repo Root",
|
||||||
"agents.defaults.bootstrapMaxChars": "Bootstrap Max Chars",
|
"agents.defaults.bootstrapMaxChars": "Bootstrap Max Chars",
|
||||||
|
"agents.defaults.extraWorkspaceFiles": "Extra Workspace Files",
|
||||||
"agents.defaults.envelopeTimezone": "Envelope Timezone",
|
"agents.defaults.envelopeTimezone": "Envelope Timezone",
|
||||||
"agents.defaults.envelopeTimestamp": "Envelope Timestamp",
|
"agents.defaults.envelopeTimestamp": "Envelope Timestamp",
|
||||||
"agents.defaults.envelopeElapsed": "Envelope Elapsed",
|
"agents.defaults.envelopeElapsed": "Envelope Elapsed",
|
||||||
@ -488,6 +490,8 @@ const FIELD_HELP: Record<string, string> = {
|
|||||||
"auth.cooldowns.failureWindowHours": "Failure window (hours) for backoff counters (default: 24).",
|
"auth.cooldowns.failureWindowHours": "Failure window (hours) for backoff counters (default: 24).",
|
||||||
"agents.defaults.bootstrapMaxChars":
|
"agents.defaults.bootstrapMaxChars":
|
||||||
"Max characters of each workspace bootstrap file injected into the system prompt before truncation (default: 20000).",
|
"Max characters of each workspace bootstrap file injected into the system prompt before truncation (default: 20000).",
|
||||||
|
"agents.defaults.extraWorkspaceFiles":
|
||||||
|
"Additional workspace files to auto-inject into the system prompt alongside the defaults (AGENTS.md, SOUL.md, etc.). Paths are relative to the workspace directory (e.g., ['PANTHEON.md', 'protocols/SHARED.md']).",
|
||||||
"agents.defaults.repoRoot":
|
"agents.defaults.repoRoot":
|
||||||
"Optional repository root shown in the system prompt runtime line (overrides auto-detect).",
|
"Optional repository root shown in the system prompt runtime line (overrides auto-detect).",
|
||||||
"agents.defaults.envelopeTimezone":
|
"agents.defaults.envelopeTimezone":
|
||||||
@ -570,6 +574,8 @@ const FIELD_HELP: Record<string, string> = {
|
|||||||
"plugins.installs.*.installedAt": "ISO timestamp of last install/update.",
|
"plugins.installs.*.installedAt": "ISO timestamp of last install/update.",
|
||||||
"agents.list.*.identity.avatar":
|
"agents.list.*.identity.avatar":
|
||||||
"Agent avatar (workspace-relative path, http(s) URL, or data URI).",
|
"Agent avatar (workspace-relative path, http(s) URL, or data URI).",
|
||||||
|
"agents.list.*.extraWorkspaceFiles":
|
||||||
|
"Additional workspace files to auto-inject for this agent (overrides agents.defaults.extraWorkspaceFiles). Paths are relative to the workspace directory.",
|
||||||
"agents.defaults.model.primary": "Primary model (provider/model).",
|
"agents.defaults.model.primary": "Primary model (provider/model).",
|
||||||
"agents.defaults.model.fallbacks":
|
"agents.defaults.model.fallbacks":
|
||||||
"Ordered fallback models (provider/model). Used when the primary model fails.",
|
"Ordered fallback models (provider/model). Used when the primary model fails.",
|
||||||
|
|||||||
@ -106,6 +106,7 @@ export type AgentDefaultsConfig = {
|
|||||||
skipBootstrap?: boolean;
|
skipBootstrap?: boolean;
|
||||||
/** Max chars for injected bootstrap files before truncation (default: 20000). */
|
/** Max chars for injected bootstrap files before truncation (default: 20000). */
|
||||||
bootstrapMaxChars?: number;
|
bootstrapMaxChars?: number;
|
||||||
|
extraWorkspaceFiles?: string[];
|
||||||
/** Optional IANA timezone for the user (used in system prompt; defaults to host timezone). */
|
/** Optional IANA timezone for the user (used in system prompt; defaults to host timezone). */
|
||||||
userTimezone?: string;
|
userTimezone?: string;
|
||||||
/** Time format in system prompt: auto (OS preference), 12-hour, or 24-hour. */
|
/** Time format in system prompt: auto (OS preference), 12-hour, or 24-hour. */
|
||||||
|
|||||||
@ -24,6 +24,7 @@ export type AgentConfig = {
|
|||||||
workspace?: string;
|
workspace?: string;
|
||||||
agentDir?: string;
|
agentDir?: string;
|
||||||
model?: AgentModelConfig;
|
model?: AgentModelConfig;
|
||||||
|
extraWorkspaceFiles?: string[];
|
||||||
memorySearch?: MemorySearchConfig;
|
memorySearch?: MemorySearchConfig;
|
||||||
/** Human-like delay between block replies for this agent. */
|
/** Human-like delay between block replies for this agent. */
|
||||||
humanDelay?: HumanDelayConfig;
|
humanDelay?: HumanDelayConfig;
|
||||||
|
|||||||
@ -45,6 +45,7 @@ export const AgentDefaultsSchema = z
|
|||||||
repoRoot: z.string().optional(),
|
repoRoot: z.string().optional(),
|
||||||
skipBootstrap: z.boolean().optional(),
|
skipBootstrap: z.boolean().optional(),
|
||||||
bootstrapMaxChars: z.number().int().positive().optional(),
|
bootstrapMaxChars: z.number().int().positive().optional(),
|
||||||
|
extraWorkspaceFiles: z.array(z.string()).optional(),
|
||||||
userTimezone: z.string().optional(),
|
userTimezone: z.string().optional(),
|
||||||
timeFormat: z.union([z.literal("auto"), z.literal("12"), z.literal("24")]).optional(),
|
timeFormat: z.union([z.literal("auto"), z.literal("12"), z.literal("24")]).optional(),
|
||||||
envelopeTimezone: z.string().optional(),
|
envelopeTimezone: z.string().optional(),
|
||||||
|
|||||||
@ -422,6 +422,7 @@ export const AgentEntrySchema = z
|
|||||||
workspace: z.string().optional(),
|
workspace: z.string().optional(),
|
||||||
agentDir: z.string().optional(),
|
agentDir: z.string().optional(),
|
||||||
model: AgentModelSchema.optional(),
|
model: AgentModelSchema.optional(),
|
||||||
|
extraWorkspaceFiles: z.array(z.string()).optional(),
|
||||||
memorySearch: MemorySearchSchema,
|
memorySearch: MemorySearchSchema,
|
||||||
humanDelay: HumanDelaySchema.optional(),
|
humanDelay: HumanDelaySchema.optional(),
|
||||||
heartbeat: HeartbeatSchema,
|
heartbeat: HeartbeatSchema,
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user