Merge remote-tracking branch 'origin/main' into feature/agent-avatar-support
This commit is contained in:
@@ -54,6 +54,7 @@ import { callGatewayTool } from "./tools/gateway.js";
|
||||
import { listNodes, resolveNodeIdFromList } from "./tools/nodes-utils.js";
|
||||
import { getShellConfig, sanitizeBinaryOutput } from "./shell-utils.js";
|
||||
import { buildCursorPositionResponse, stripDsrRequests } from "./pty-dsr.js";
|
||||
import { parseAgentSessionKey, resolveAgentIdFromSessionKey } from "../routing/session-key.js";
|
||||
|
||||
const DEFAULT_MAX_OUTPUT = clampNumber(
|
||||
readEnvInt("PI_BASH_MAX_OUTPUT_CHARS"),
|
||||
@@ -139,7 +140,7 @@ export type { BashSandboxConfig } from "./bash-tools.shared.js";
|
||||
export type ExecElevatedDefaults = {
|
||||
enabled: boolean;
|
||||
allowed: boolean;
|
||||
defaultLevel: "on" | "off";
|
||||
defaultLevel: "on" | "off" | "ask" | "full";
|
||||
};
|
||||
|
||||
const execSchema = Type.Object({
|
||||
@@ -659,6 +660,11 @@ export function createExecTool(
|
||||
const notifyOnExit = defaults?.notifyOnExit !== false;
|
||||
const notifySessionKey = defaults?.sessionKey?.trim() || undefined;
|
||||
const approvalRunningNoticeMs = resolveApprovalRunningNoticeMs(defaults?.approvalRunningNoticeMs);
|
||||
// Derive agentId only when sessionKey is an agent session key.
|
||||
const parsedAgentSession = parseAgentSessionKey(defaults?.sessionKey);
|
||||
const agentId =
|
||||
defaults?.agentId ??
|
||||
(parsedAgentSession ? resolveAgentIdFromSessionKey(defaults?.sessionKey) : undefined);
|
||||
|
||||
return {
|
||||
name: "exec",
|
||||
@@ -700,12 +706,23 @@ export function createExecTool(
|
||||
: clampNumber(params.yieldMs ?? defaultBackgroundMs, defaultBackgroundMs, 10, 120_000)
|
||||
: null;
|
||||
const elevatedDefaults = defaults?.elevated;
|
||||
const elevatedDefaultOn =
|
||||
elevatedDefaults?.defaultLevel === "on" &&
|
||||
elevatedDefaults.enabled &&
|
||||
elevatedDefaults.allowed;
|
||||
const elevatedRequested =
|
||||
typeof params.elevated === "boolean" ? params.elevated : elevatedDefaultOn;
|
||||
const elevatedDefaultMode =
|
||||
elevatedDefaults?.defaultLevel === "full"
|
||||
? "full"
|
||||
: elevatedDefaults?.defaultLevel === "ask"
|
||||
? "ask"
|
||||
: elevatedDefaults?.defaultLevel === "on"
|
||||
? "ask"
|
||||
: "off";
|
||||
const elevatedMode =
|
||||
typeof params.elevated === "boolean"
|
||||
? params.elevated
|
||||
? elevatedDefaultMode === "full"
|
||||
? "full"
|
||||
: "ask"
|
||||
: "off"
|
||||
: elevatedDefaultMode;
|
||||
const elevatedRequested = elevatedMode !== "off";
|
||||
if (elevatedRequested) {
|
||||
if (!elevatedDefaults?.enabled || !elevatedDefaults.allowed) {
|
||||
const runtime = defaults?.sandbox ? "sandboxed" : "direct";
|
||||
@@ -761,6 +778,10 @@ export function createExecTool(
|
||||
const configuredAsk = defaults?.ask ?? "on-miss";
|
||||
const requestedAsk = normalizeExecAsk(params.ask);
|
||||
let ask = maxAsk(configuredAsk, requestedAsk ?? configuredAsk);
|
||||
const bypassApprovals = elevatedRequested && elevatedMode === "full";
|
||||
if (bypassApprovals) {
|
||||
ask = "off";
|
||||
}
|
||||
|
||||
const sandbox = host === "sandbox" ? defaults?.sandbox : undefined;
|
||||
const rawWorkdir = params.workdir?.trim() || defaults?.cwd || process.cwd();
|
||||
@@ -799,7 +820,7 @@ export function createExecTool(
|
||||
|
||||
if (host === "node") {
|
||||
const approvals = resolveExecApprovals(
|
||||
defaults?.agentId,
|
||||
agentId,
|
||||
host === "node" ? { security: "allowlist" } : undefined,
|
||||
);
|
||||
const hostSecurity = minSecurity(security, approvals.agent.security);
|
||||
@@ -865,7 +886,7 @@ export function createExecTool(
|
||||
cwd: workdir,
|
||||
env: nodeEnv,
|
||||
timeoutMs: typeof params.timeout === "number" ? params.timeout * 1000 : undefined,
|
||||
agentId: defaults?.agentId,
|
||||
agentId,
|
||||
sessionKey: defaults?.sessionKey,
|
||||
approved: approvedByAsk,
|
||||
approvalDecision: approvalDecision ?? undefined,
|
||||
@@ -895,9 +916,9 @@ export function createExecTool(
|
||||
host: "node",
|
||||
security: hostSecurity,
|
||||
ask: hostAsk,
|
||||
agentId: defaults?.agentId,
|
||||
resolvedPath: undefined,
|
||||
sessionKey: defaults?.sessionKey,
|
||||
agentId,
|
||||
resolvedPath: null,
|
||||
sessionKey: defaults?.sessionKey ?? null,
|
||||
timeoutMs: DEFAULT_APPROVAL_TIMEOUT_MS,
|
||||
},
|
||||
)) as { decision?: string } | null;
|
||||
@@ -1025,8 +1046,8 @@ export function createExecTool(
|
||||
};
|
||||
}
|
||||
|
||||
if (host === "gateway") {
|
||||
const approvals = resolveExecApprovals(defaults?.agentId, { security: "allowlist" });
|
||||
if (host === "gateway" && !bypassApprovals) {
|
||||
const approvals = resolveExecApprovals(agentId, { security: "allowlist" });
|
||||
const hostSecurity = minSecurity(security, approvals.agent.security);
|
||||
const hostAsk = maxAsk(ask, approvals.agent.ask);
|
||||
const askFallback = approvals.agent.askFallback;
|
||||
@@ -1060,7 +1081,7 @@ export function createExecTool(
|
||||
const approvalSlug = createApprovalSlug(approvalId);
|
||||
const expiresAtMs = Date.now() + DEFAULT_APPROVAL_TIMEOUT_MS;
|
||||
const contextKey = `exec:${approvalId}`;
|
||||
const resolvedPath = analysis.segments[0]?.resolution?.resolvedPath;
|
||||
const resolvedPath = analysis.segments[0]?.resolution?.resolvedPath ?? null;
|
||||
const noticeSeconds = Math.max(1, Math.round(approvalRunningNoticeMs / 1000));
|
||||
const commandText = params.command;
|
||||
const effectiveTimeout =
|
||||
@@ -1080,9 +1101,9 @@ export function createExecTool(
|
||||
host: "gateway",
|
||||
security: hostSecurity,
|
||||
ask: hostAsk,
|
||||
agentId: defaults?.agentId,
|
||||
agentId,
|
||||
resolvedPath,
|
||||
sessionKey: defaults?.sessionKey,
|
||||
sessionKey: defaults?.sessionKey ?? null,
|
||||
timeoutMs: DEFAULT_APPROVAL_TIMEOUT_MS,
|
||||
},
|
||||
)) as { decision?: string } | null;
|
||||
@@ -1123,7 +1144,7 @@ export function createExecTool(
|
||||
for (const segment of analysis.segments) {
|
||||
const pattern = segment.resolution?.resolvedPath ?? "";
|
||||
if (pattern) {
|
||||
addAllowlistEntry(approvals.file, defaults?.agentId, pattern);
|
||||
addAllowlistEntry(approvals.file, agentId, pattern);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1152,7 +1173,7 @@ export function createExecTool(
|
||||
seen.add(match.pattern);
|
||||
recordAllowlistUse(
|
||||
approvals.file,
|
||||
defaults?.agentId,
|
||||
agentId,
|
||||
match,
|
||||
commandText,
|
||||
resolvedPath ?? undefined,
|
||||
@@ -1242,7 +1263,7 @@ export function createExecTool(
|
||||
seen.add(match.pattern);
|
||||
recordAllowlistUse(
|
||||
approvals.file,
|
||||
defaults?.agentId,
|
||||
agentId,
|
||||
match,
|
||||
params.command,
|
||||
analysis.segments[0]?.resolution?.resolvedPath,
|
||||
|
||||
@@ -183,6 +183,8 @@ export function buildSystemPrompt(params: {
|
||||
const { runtimeInfo, userTimezone, userTime, userTimeFormat } = buildSystemPromptParams({
|
||||
config: params.config,
|
||||
agentId: params.agentId,
|
||||
workspaceDir: params.workspaceDir,
|
||||
cwd: process.cwd(),
|
||||
runtime: {
|
||||
host: "clawdbot",
|
||||
os: `${os.type()} ${os.release()}`,
|
||||
|
||||
@@ -68,6 +68,10 @@ function isChatGPTUsageLimitErrorMessage(raw: string): boolean {
|
||||
return msg.includes("hit your chatgpt usage limit") && msg.includes("try again in");
|
||||
}
|
||||
|
||||
function isInstructionsRequiredError(raw: string): boolean {
|
||||
return /instructions are required/i.test(raw);
|
||||
}
|
||||
|
||||
function toInt(value: string | undefined, fallback: number): number {
|
||||
const trimmed = value?.trim();
|
||||
if (!trimmed) return fallback;
|
||||
@@ -443,6 +447,15 @@ describeLive("live models (profile keys)", () => {
|
||||
logProgress(`${progressLabel}: skip (chatgpt usage limit)`);
|
||||
break;
|
||||
}
|
||||
if (
|
||||
allowNotFoundSkip &&
|
||||
model.provider === "openai-codex" &&
|
||||
isInstructionsRequiredError(message)
|
||||
) {
|
||||
skipped.push({ model: id, reason: message });
|
||||
logProgress(`${progressLabel}: skip (instructions required)`);
|
||||
break;
|
||||
}
|
||||
logProgress(`${progressLabel}: failed`);
|
||||
failures.push({ model: id, error: message });
|
||||
break;
|
||||
|
||||
@@ -44,6 +44,8 @@ describe("resolveOpencodeZenModelApi", () => {
|
||||
expect(resolveOpencodeZenModelApi("minimax-m2.1-free")).toBe("anthropic-messages");
|
||||
expect(resolveOpencodeZenModelApi("gemini-3-pro")).toBe("google-generative-ai");
|
||||
expect(resolveOpencodeZenModelApi("gpt-5.2")).toBe("openai-responses");
|
||||
expect(resolveOpencodeZenModelApi("alpha-gd4")).toBe("openai-completions");
|
||||
expect(resolveOpencodeZenModelApi("big-pickle")).toBe("openai-completions");
|
||||
expect(resolveOpencodeZenModelApi("glm-4.7-free")).toBe("openai-completions");
|
||||
expect(resolveOpencodeZenModelApi("some-unknown-model")).toBe("openai-completions");
|
||||
});
|
||||
|
||||
@@ -87,19 +87,19 @@ export function resolveOpencodeZenAlias(modelIdOrAlias: string): string {
|
||||
}
|
||||
|
||||
/**
|
||||
* OpenCode Zen routes models to different APIs based on model family.
|
||||
* OpenCode Zen routes models to specific API shapes by family.
|
||||
*/
|
||||
export function resolveOpencodeZenModelApi(modelId: string): ModelApi {
|
||||
const lower = modelId.toLowerCase();
|
||||
if (lower.startsWith("claude-") || lower.startsWith("minimax") || lower.startsWith("alpha-gd4")) {
|
||||
if (lower.startsWith("gpt-")) {
|
||||
return "openai-responses";
|
||||
}
|
||||
if (lower.startsWith("claude-") || lower.startsWith("minimax-")) {
|
||||
return "anthropic-messages";
|
||||
}
|
||||
if (lower.startsWith("gemini-")) {
|
||||
return "google-generative-ai";
|
||||
}
|
||||
if (lower.startsWith("gpt-")) {
|
||||
return "openai-responses";
|
||||
}
|
||||
return "openai-completions";
|
||||
}
|
||||
|
||||
|
||||
@@ -279,6 +279,8 @@ export async function runEmbeddedAttempt(
|
||||
const { runtimeInfo, userTimezone, userTime, userTimeFormat } = buildSystemPromptParams({
|
||||
config: params.config,
|
||||
agentId: sessionAgentId,
|
||||
workspaceDir: effectiveWorkspace,
|
||||
cwd: process.cwd(),
|
||||
runtime: {
|
||||
host: machineName,
|
||||
os: `${os.type()} ${os.release()}`,
|
||||
|
||||
@@ -76,6 +76,6 @@ export type EmbeddedSandboxInfo = {
|
||||
allowedControlPorts?: number[];
|
||||
elevated?: {
|
||||
allowed: boolean;
|
||||
defaultLevel: "on" | "off";
|
||||
defaultLevel: "on" | "off" | "ask" | "full";
|
||||
};
|
||||
};
|
||||
|
||||
106
src/agents/system-prompt-params.test.ts
Normal file
106
src/agents/system-prompt-params.test.ts
Normal file
@@ -0,0 +1,106 @@
|
||||
import fs from "node:fs/promises";
|
||||
import os from "node:os";
|
||||
import path from "node:path";
|
||||
|
||||
import { describe, expect, it } from "vitest";
|
||||
|
||||
import type { ClawdbotConfig } from "../config/config.js";
|
||||
import { buildSystemPromptParams } from "./system-prompt-params.js";
|
||||
|
||||
async function makeTempDir(label: string): Promise<string> {
|
||||
return fs.mkdtemp(path.join(os.tmpdir(), `clawdbot-${label}-`));
|
||||
}
|
||||
|
||||
async function makeRepoRoot(root: string): Promise<void> {
|
||||
await fs.mkdir(path.join(root, ".git"), { recursive: true });
|
||||
}
|
||||
|
||||
function buildParams(params: { config?: ClawdbotConfig; workspaceDir?: string; cwd?: string }) {
|
||||
return buildSystemPromptParams({
|
||||
config: params.config,
|
||||
workspaceDir: params.workspaceDir,
|
||||
cwd: params.cwd,
|
||||
runtime: {
|
||||
host: "host",
|
||||
os: "os",
|
||||
arch: "arch",
|
||||
node: "node",
|
||||
model: "model",
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
describe("buildSystemPromptParams repo root", () => {
|
||||
it("detects repo root from workspaceDir", async () => {
|
||||
const temp = await makeTempDir("workspace");
|
||||
const repoRoot = path.join(temp, "repo");
|
||||
const workspaceDir = path.join(repoRoot, "nested", "workspace");
|
||||
await fs.mkdir(workspaceDir, { recursive: true });
|
||||
await makeRepoRoot(repoRoot);
|
||||
|
||||
const { runtimeInfo } = buildParams({ workspaceDir });
|
||||
|
||||
expect(runtimeInfo.repoRoot).toBe(repoRoot);
|
||||
});
|
||||
|
||||
it("falls back to cwd when workspaceDir has no repo", async () => {
|
||||
const temp = await makeTempDir("cwd");
|
||||
const repoRoot = path.join(temp, "repo");
|
||||
const workspaceDir = path.join(temp, "workspace");
|
||||
await fs.mkdir(workspaceDir, { recursive: true });
|
||||
await makeRepoRoot(repoRoot);
|
||||
|
||||
const { runtimeInfo } = buildParams({ workspaceDir, cwd: repoRoot });
|
||||
|
||||
expect(runtimeInfo.repoRoot).toBe(repoRoot);
|
||||
});
|
||||
|
||||
it("uses configured repoRoot when valid", async () => {
|
||||
const temp = await makeTempDir("config");
|
||||
const repoRoot = path.join(temp, "config-root");
|
||||
const workspaceDir = path.join(temp, "workspace");
|
||||
await fs.mkdir(repoRoot, { recursive: true });
|
||||
await fs.mkdir(workspaceDir, { recursive: true });
|
||||
await makeRepoRoot(workspaceDir);
|
||||
|
||||
const config: ClawdbotConfig = {
|
||||
agents: {
|
||||
defaults: {
|
||||
repoRoot,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const { runtimeInfo } = buildParams({ config, workspaceDir });
|
||||
|
||||
expect(runtimeInfo.repoRoot).toBe(repoRoot);
|
||||
});
|
||||
|
||||
it("ignores invalid repoRoot config and auto-detects", async () => {
|
||||
const temp = await makeTempDir("invalid");
|
||||
const repoRoot = path.join(temp, "repo");
|
||||
const workspaceDir = path.join(repoRoot, "workspace");
|
||||
await fs.mkdir(workspaceDir, { recursive: true });
|
||||
await makeRepoRoot(repoRoot);
|
||||
|
||||
const config: ClawdbotConfig = {
|
||||
agents: {
|
||||
defaults: {
|
||||
repoRoot: path.join(temp, "missing"),
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const { runtimeInfo } = buildParams({ config, workspaceDir });
|
||||
|
||||
expect(runtimeInfo.repoRoot).toBe(repoRoot);
|
||||
});
|
||||
|
||||
it("returns undefined when no repo is found", async () => {
|
||||
const workspaceDir = await makeTempDir("norepo");
|
||||
|
||||
const { runtimeInfo } = buildParams({ workspaceDir });
|
||||
|
||||
expect(runtimeInfo.repoRoot).toBeUndefined();
|
||||
});
|
||||
});
|
||||
@@ -1,3 +1,6 @@
|
||||
import fs from "node:fs";
|
||||
import path from "node:path";
|
||||
|
||||
import type { ClawdbotConfig } from "../config/config.js";
|
||||
import {
|
||||
formatUserTime,
|
||||
@@ -18,6 +21,7 @@ export type RuntimeInfoInput = {
|
||||
capabilities?: string[];
|
||||
/** Supported message actions for the current channel (e.g., react, edit, unsend) */
|
||||
channelActions?: string[];
|
||||
repoRoot?: string;
|
||||
};
|
||||
|
||||
export type SystemPromptRuntimeParams = {
|
||||
@@ -31,7 +35,14 @@ export function buildSystemPromptParams(params: {
|
||||
config?: ClawdbotConfig;
|
||||
agentId?: string;
|
||||
runtime: Omit<RuntimeInfoInput, "agentId">;
|
||||
workspaceDir?: string;
|
||||
cwd?: string;
|
||||
}): SystemPromptRuntimeParams {
|
||||
const repoRoot = resolveRepoRoot({
|
||||
config: params.config,
|
||||
workspaceDir: params.workspaceDir,
|
||||
cwd: params.cwd,
|
||||
});
|
||||
const userTimezone = resolveUserTimezone(params.config?.agents?.defaults?.userTimezone);
|
||||
const userTimeFormat = resolveUserTimeFormat(params.config?.agents?.defaults?.timeFormat);
|
||||
const userTime = formatUserTime(new Date(), userTimezone, userTimeFormat);
|
||||
@@ -39,9 +50,56 @@ export function buildSystemPromptParams(params: {
|
||||
runtimeInfo: {
|
||||
agentId: params.agentId,
|
||||
...params.runtime,
|
||||
repoRoot,
|
||||
},
|
||||
userTimezone,
|
||||
userTime,
|
||||
userTimeFormat,
|
||||
};
|
||||
}
|
||||
|
||||
function resolveRepoRoot(params: {
|
||||
config?: ClawdbotConfig;
|
||||
workspaceDir?: string;
|
||||
cwd?: string;
|
||||
}): string | undefined {
|
||||
const configured = params.config?.agents?.defaults?.repoRoot?.trim();
|
||||
if (configured) {
|
||||
try {
|
||||
const resolved = path.resolve(configured);
|
||||
const stat = fs.statSync(resolved);
|
||||
if (stat.isDirectory()) return resolved;
|
||||
} catch {
|
||||
// ignore invalid config path
|
||||
}
|
||||
}
|
||||
const candidates = [params.workspaceDir, params.cwd]
|
||||
.map((value) => value?.trim())
|
||||
.filter(Boolean) as string[];
|
||||
const seen = new Set<string>();
|
||||
for (const candidate of candidates) {
|
||||
const resolved = path.resolve(candidate);
|
||||
if (seen.has(resolved)) continue;
|
||||
seen.add(resolved);
|
||||
const root = findGitRoot(resolved);
|
||||
if (root) return root;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function findGitRoot(startDir: string): string | null {
|
||||
let current = path.resolve(startDir);
|
||||
for (let i = 0; i < 12; i += 1) {
|
||||
const gitPath = path.join(current, ".git");
|
||||
try {
|
||||
const stat = fs.statSync(gitPath);
|
||||
if (stat.isDirectory() || stat.isFile()) return current;
|
||||
} catch {
|
||||
// ignore missing .git at this level
|
||||
}
|
||||
const parent = path.dirname(current);
|
||||
if (parent === current) break;
|
||||
current = parent;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -284,6 +284,7 @@ describe("buildAgentSystemPrompt", () => {
|
||||
{
|
||||
agentId: "work",
|
||||
host: "host",
|
||||
repoRoot: "/repo",
|
||||
os: "macOS",
|
||||
arch: "arm64",
|
||||
node: "v20",
|
||||
@@ -297,6 +298,7 @@ describe("buildAgentSystemPrompt", () => {
|
||||
|
||||
expect(line).toContain("agent=work");
|
||||
expect(line).toContain("host=host");
|
||||
expect(line).toContain("repo=/repo");
|
||||
expect(line).toContain("os=macOS (arm64)");
|
||||
expect(line).toContain("node=v20");
|
||||
expect(line).toContain("model=anthropic/claude");
|
||||
@@ -320,7 +322,7 @@ describe("buildAgentSystemPrompt", () => {
|
||||
|
||||
expect(prompt).toContain("You are running in a sandboxed runtime");
|
||||
expect(prompt).toContain("Sub-agents stay sandboxed");
|
||||
expect(prompt).toContain("User can toggle with /elevated on|off.");
|
||||
expect(prompt).toContain("User can toggle with /elevated on|off|ask|full.");
|
||||
expect(prompt).toContain("Current elevated level: on");
|
||||
});
|
||||
|
||||
|
||||
@@ -160,6 +160,7 @@ export function buildAgentSystemPrompt(params: {
|
||||
defaultModel?: string;
|
||||
channel?: string;
|
||||
capabilities?: string[];
|
||||
repoRoot?: string;
|
||||
};
|
||||
messageToolHints?: string[];
|
||||
sandboxInfo?: {
|
||||
@@ -175,7 +176,7 @@ export function buildAgentSystemPrompt(params: {
|
||||
allowedControlPorts?: number[];
|
||||
elevated?: {
|
||||
allowed: boolean;
|
||||
defaultLevel: "on" | "off";
|
||||
defaultLevel: "on" | "off" | "ask" | "full";
|
||||
};
|
||||
};
|
||||
/** Reaction guidance for the agent (for Telegram minimal/extensive modes). */
|
||||
@@ -200,7 +201,7 @@ export function buildAgentSystemPrompt(params: {
|
||||
browser: "Control web browser",
|
||||
canvas: "Present/eval/snapshot the Canvas",
|
||||
nodes: "List/describe/notify/camera/screen on paired nodes",
|
||||
cron: "Manage cron jobs and wake events (use for reminders; include recent context in reminder text if appropriate)",
|
||||
cron: "Manage cron jobs and wake events (use for reminders; when scheduling a reminder, write the systemEvent text as something that will read like a reminder when it fires, and mention that it is a reminder depending on the time gap between setting and firing; include recent context in reminder text if appropriate)",
|
||||
message: "Send messages and channel actions",
|
||||
gateway: "Restart, apply config, or run updates on the running Clawdbot process",
|
||||
agents_list: "List agent ids allowed for sessions_spawn",
|
||||
@@ -351,7 +352,7 @@ export function buildAgentSystemPrompt(params: {
|
||||
"- browser: control clawd's dedicated browser",
|
||||
"- canvas: present/eval/snapshot the Canvas",
|
||||
"- nodes: list/describe/notify/camera/screen on paired nodes",
|
||||
"- cron: manage cron jobs and wake events (use for reminders; include recent context in reminder text if appropriate)",
|
||||
"- cron: manage cron jobs and wake events (use for reminders; when scheduling a reminder, write the systemEvent text as something that will read like a reminder when it fires, and mention that it is a reminder depending on the time gap between setting and firing; include recent context in reminder text if appropriate)",
|
||||
"- sessions_list: list sessions",
|
||||
"- sessions_history: fetch session history",
|
||||
"- sessions_send: send to another session",
|
||||
@@ -443,12 +444,14 @@ export function buildAgentSystemPrompt(params: {
|
||||
params.sandboxInfo.elevated?.allowed
|
||||
? "Elevated exec is available for this session."
|
||||
: "",
|
||||
params.sandboxInfo.elevated?.allowed ? "User can toggle with /elevated on|off." : "",
|
||||
params.sandboxInfo.elevated?.allowed
|
||||
? "You may also send /elevated on|off when needed."
|
||||
? "User can toggle with /elevated on|off|ask|full."
|
||||
: "",
|
||||
params.sandboxInfo.elevated?.allowed
|
||||
? `Current elevated level: ${params.sandboxInfo.elevated.defaultLevel} (on runs exec on host; off runs in sandbox).`
|
||||
? "You may also send /elevated on|off|ask|full when needed."
|
||||
: "",
|
||||
params.sandboxInfo.elevated?.allowed
|
||||
? `Current elevated level: ${params.sandboxInfo.elevated.defaultLevel} (ask runs exec on host with approvals; full auto-approves).`
|
||||
: "",
|
||||
]
|
||||
.filter(Boolean)
|
||||
@@ -570,6 +573,7 @@ export function buildRuntimeLine(
|
||||
node?: string;
|
||||
model?: string;
|
||||
defaultModel?: string;
|
||||
repoRoot?: string;
|
||||
},
|
||||
runtimeChannel?: string,
|
||||
runtimeCapabilities: string[] = [],
|
||||
@@ -578,6 +582,7 @@ export function buildRuntimeLine(
|
||||
return `Runtime: ${[
|
||||
runtimeInfo?.agentId ? `agent=${runtimeInfo.agentId}` : "",
|
||||
runtimeInfo?.host ? `host=${runtimeInfo.host}` : "",
|
||||
runtimeInfo?.repoRoot ? `repo=${runtimeInfo.repoRoot}` : "",
|
||||
runtimeInfo?.os
|
||||
? `os=${runtimeInfo.os}${runtimeInfo?.arch ? ` (${runtimeInfo.arch})` : ""}`
|
||||
: runtimeInfo?.arch
|
||||
|
||||
Reference in New Issue
Block a user