chore: migrate to oxlint and oxfmt

Co-authored-by: Christoph Nakazawa <christoph.pojer@gmail.com>
This commit is contained in:
Peter Steinberger
2026-01-14 14:31:43 +00:00
parent 912ebffc63
commit c379191f80
1480 changed files with 28608 additions and 43547 deletions

View File

@@ -3,8 +3,6 @@ export function isAbortError(err: unknown): boolean {
const name = "name" in err ? String(err.name) : "";
if (name === "AbortError") return true;
const message =
"message" in err && typeof err.message === "string"
? err.message.toLowerCase()
: "";
"message" in err && typeof err.message === "string" ? err.message.toLowerCase() : "";
return message.includes("aborted");
}

View File

@@ -1,21 +1,14 @@
import fs from "node:fs/promises";
import os from "node:os";
import {
createAgentSession,
SessionManager,
SettingsManager,
} from "@mariozechner/pi-coding-agent";
import { createAgentSession, SessionManager, SettingsManager } from "@mariozechner/pi-coding-agent";
import { resolveHeartbeatPrompt } from "../../auto-reply/heartbeat.js";
import type { ReasoningLevel, ThinkLevel } from "../../auto-reply/thinking.js";
import { resolveChannelCapabilities } from "../../config/channel-capabilities.js";
import type { ClawdbotConfig } from "../../config/config.js";
import { getMachineDisplayName } from "../../infra/machine-name.js";
import {
type enqueueCommand,
enqueueCommandInLane,
} from "../../process/command-queue.js";
import { type enqueueCommand, enqueueCommandInLane } from "../../process/command-queue.js";
import { normalizeMessageChannel } from "../../utils/message-channel.js";
import { isReasoningTagProvider } from "../../utils/provider-utils.js";
import { resolveUserPath } from "../../utils.js";
@@ -48,28 +41,16 @@ import {
resolveSkillsPromptForRun,
type SkillSnapshot,
} from "../skills.js";
import {
filterBootstrapFilesForSession,
loadWorkspaceBootstrapFiles,
} from "../workspace.js";
import { filterBootstrapFilesForSession, loadWorkspaceBootstrapFiles } from "../workspace.js";
import { buildEmbeddedExtensionPaths } from "./extensions.js";
import { logToolSchemasForGoogle, sanitizeSessionHistory } from "./google.js";
import {
getDmHistoryLimitFromSessionKey,
limitHistoryTurns,
} from "./history.js";
import { getDmHistoryLimitFromSessionKey, limitHistoryTurns } from "./history.js";
import { resolveGlobalLane, resolveSessionLane } from "./lanes.js";
import { log } from "./logger.js";
import { buildModelAliasLines, resolveModel } from "./model.js";
import { buildEmbeddedSandboxInfo } from "./sandbox-info.js";
import {
prewarmSessionFile,
trackSessionManagerAccess,
} from "./session-manager-cache.js";
import {
buildEmbeddedSystemPrompt,
createSystemPromptOverride,
} from "./system-prompt.js";
import { prewarmSessionFile, trackSessionManagerAccess } from "./session-manager-cache.js";
import { buildEmbeddedSystemPrompt, createSystemPromptOverride } from "./system-prompt.js";
import { splitSdkTools } from "./tool-split.js";
import type { EmbeddedPiCompactResult } from "./types.js";
import {
@@ -102,20 +83,16 @@ export async function compactEmbeddedPiSession(params: {
extraSystemPrompt?: string;
ownerNumbers?: string[];
}): Promise<EmbeddedPiCompactResult> {
const sessionLane = resolveSessionLane(
params.sessionKey?.trim() || params.sessionId,
);
const sessionLane = resolveSessionLane(params.sessionKey?.trim() || params.sessionId);
const globalLane = resolveGlobalLane(params.lane);
const enqueueGlobal =
params.enqueue ??
((task, opts) => enqueueCommandInLane(globalLane, task, opts));
params.enqueue ?? ((task, opts) => enqueueCommandInLane(globalLane, task, opts));
return enqueueCommandInLane(sessionLane, () =>
enqueueGlobal(async () => {
const resolvedWorkspace = resolveUserPath(params.workspaceDir);
const prevCwd = process.cwd();
const provider =
(params.provider ?? DEFAULT_PROVIDER).trim() || DEFAULT_PROVIDER;
const provider = (params.provider ?? DEFAULT_PROVIDER).trim() || DEFAULT_PROVIDER;
const modelId = (params.model ?? DEFAULT_MODEL).trim() || DEFAULT_MODEL;
const agentDir = params.agentDir ?? resolveClawdbotAgentDir();
await ensureClawdbotModelsJson(params.config, agentDir);
@@ -139,9 +116,8 @@ export async function compactEmbeddedPiSession(params: {
});
if (model.provider === "github-copilot") {
const { resolveCopilotApiToken } = await import(
"../../providers/github-copilot-token.js"
);
const { resolveCopilotApiToken } =
await import("../../providers/github-copilot-token.js");
const copilotToken = await resolveCopilotApiToken({
githubToken: apiKeyInfo.apiKey,
});
@@ -205,14 +181,10 @@ export async function compactEmbeddedPiSession(params: {
params.sessionKey ?? params.sessionId,
);
const sessionLabel = params.sessionKey ?? params.sessionId;
const contextFiles: EmbeddedContextFile[] = buildBootstrapContextFiles(
bootstrapFiles,
{
maxChars: resolveBootstrapMaxChars(params.config),
warn: (message) =>
log.warn(`${message} (sessionKey=${sessionLabel})`),
},
);
const contextFiles: EmbeddedContextFile[] = buildBootstrapContextFiles(bootstrapFiles, {
maxChars: resolveBootstrapMaxChars(params.config),
warn: (message) => log.warn(`${message} (sessionKey=${sessionLabel})`),
});
const runAbortController = new AbortController();
const tools = createClawdbotCodingTools({
exec: {
@@ -252,14 +224,9 @@ export async function compactEmbeddedPiSession(params: {
channel: runtimeChannel,
capabilities: runtimeCapabilities,
};
const sandboxInfo = buildEmbeddedSandboxInfo(
sandbox,
params.bashElevated,
);
const sandboxInfo = buildEmbeddedSandboxInfo(sandbox, params.bashElevated);
const reasoningTagHint = isReasoningTagProvider(provider);
const userTimezone = resolveUserTimezone(
params.config?.agents?.defaults?.userTimezone,
);
const userTimezone = resolveUserTimezone(params.config?.agents?.defaults?.userTimezone);
const userTime = formatUserTime(new Date(), userTimezone);
const { defaultAgentId, sessionAgentId } = resolveSessionAgentIds({
sessionKey: params.sessionKey,
@@ -274,9 +241,7 @@ export async function compactEmbeddedPiSession(params: {
ownerNumbers: params.ownerNumbers,
reasoningTagHint,
heartbeatPrompt: isDefaultAgent
? resolveHeartbeatPrompt(
params.config?.agents?.defaults?.heartbeat?.prompt,
)
? resolveHeartbeatPrompt(params.config?.agents?.defaults?.heartbeat?.prompt)
: undefined,
skillsPrompt,
runtimeInfo,
@@ -294,19 +259,12 @@ export async function compactEmbeddedPiSession(params: {
});
try {
await prewarmSessionFile(params.sessionFile);
const sessionManager = guardSessionManager(
SessionManager.open(params.sessionFile),
);
const sessionManager = guardSessionManager(SessionManager.open(params.sessionFile));
trackSessionManagerAccess(params.sessionFile);
const settingsManager = SettingsManager.create(
effectiveWorkspace,
agentDir,
);
const settingsManager = SettingsManager.create(effectiveWorkspace, agentDir);
ensurePiCompactionReserveTokens({
settingsManager,
minReserveTokens: resolveCompactionReserveTokensFloor(
params.config,
),
minReserveTokens: resolveCompactionReserveTokensFloor(params.config),
});
const additionalExtensionPaths = buildEmbeddedExtensionPaths({
cfg: params.config,
@@ -321,9 +279,7 @@ export async function compactEmbeddedPiSession(params: {
sandboxEnabled: !!sandbox?.enabled,
});
let session: Awaited<
ReturnType<typeof createAgentSession>
>["session"];
let session: Awaited<ReturnType<typeof createAgentSession>>["session"];
({ session } = await createAgentSession({
cwd: resolvedWorkspace,
agentDir,

View File

@@ -60,9 +60,7 @@ function buildContextPruningExtension(params: {
}
function resolveCompactionMode(cfg?: ClawdbotConfig): "default" | "safeguard" {
return cfg?.agents?.defaults?.compaction?.mode === "safeguard"
? "safeguard"
: "default";
return cfg?.agents?.defaults?.compaction?.mode === "safeguard" ? "safeguard" : "default";
}
export function buildEmbeddedExtensionPaths(params: {

View File

@@ -84,9 +84,7 @@ function createStreamFnWithExtraParams(
return undefined;
}
log.debug(
`creating streamFn wrapper with params: ${JSON.stringify(streamParams)}`,
);
log.debug(`creating streamFn wrapper with params: ${JSON.stringify(streamParams)}`);
const underlying = baseStreamFn ?? streamSimple;
const wrappedStreamFn: StreamFn = (model, context, options) =>
@@ -116,15 +114,10 @@ export function applyExtraParamsToAgent(
modelId,
thinkLevel,
});
const wrappedStreamFn = createStreamFnWithExtraParams(
agent.streamFn,
extraParams,
);
const wrappedStreamFn = createStreamFnWithExtraParams(agent.streamFn, extraParams);
if (wrappedStreamFn) {
log.debug(
`applying extraParams to agent streamFn for ${provider}/${modelId}`,
);
log.debug(`applying extraParams to agent streamFn for ${provider}/${modelId}`);
agent.streamFn = wrappedStreamFn;
}
}

View File

@@ -37,10 +37,7 @@ const GOOGLE_SCHEMA_UNSUPPORTED_KEYWORDS = new Set([
"maxProperties",
]);
function findUnsupportedSchemaKeywords(
schema: unknown,
path: string,
): string[] {
function findUnsupportedSchemaKeywords(schema: unknown, path: string): string[] {
if (!schema || typeof schema !== "object") return [];
if (Array.isArray(schema)) {
return schema.flatMap((item, index) =>
@@ -54,22 +51,14 @@ function findUnsupportedSchemaKeywords(
violations.push(`${path}.${key}`);
}
if (value && typeof value === "object") {
violations.push(
...findUnsupportedSchemaKeywords(value, `${path}.${key}`),
);
violations.push(...findUnsupportedSchemaKeywords(value, `${path}.${key}`));
}
}
return violations;
}
export function logToolSchemasForGoogle(params: {
tools: AgentTool[];
provider: string;
}) {
if (
params.provider !== "google-antigravity" &&
params.provider !== "google-gemini-cli"
) {
export function logToolSchemasForGoogle(params: { tools: AgentTool[]; provider: string }) {
if (params.provider !== "google-antigravity" && params.provider !== "google-gemini-cli") {
return;
}
const toolNames = params.tools.map((tool, index) => `${index}:${tool.name}`);
@@ -79,10 +68,7 @@ export function logToolSchemasForGoogle(params: {
tools: toolNames,
});
for (const [index, tool] of params.tools.entries()) {
const violations = findUnsupportedSchemaKeywords(
tool.parameters,
`${tool.name}.parameters`,
);
const violations = findUnsupportedSchemaKeywords(tool.parameters, `${tool.name}.parameters`);
if (violations.length > 0) {
log.warn("google tool schema has unsupported keywords", {
index,
@@ -110,8 +96,7 @@ function hasGoogleTurnOrderingMarker(sessionManager: SessionManager): boolean {
.some(
(entry) =>
(entry as CustomEntryLike)?.type === "custom" &&
(entry as CustomEntryLike)?.customType ===
GOOGLE_TURN_ORDERING_CUSTOM_TYPE,
(entry as CustomEntryLike)?.customType === GOOGLE_TURN_ORDERING_CUSTOM_TYPE,
);
} catch {
return false;
@@ -138,9 +123,7 @@ export function applyGoogleTurnOrderingFix(params: {
if (!isGoogleModelApi(params.modelApi)) {
return { messages: params.messages, didPrepend: false };
}
const first = params.messages[0] as
| { role?: unknown; content?: unknown }
| undefined;
const first = params.messages[0] as { role?: unknown; content?: unknown } | undefined;
if (first?.role !== "assistant") {
return { messages: params.messages, didPrepend: false };
}
@@ -148,9 +131,7 @@ export function applyGoogleTurnOrderingFix(params: {
const didPrepend = sanitized !== params.messages;
if (didPrepend && !hasGoogleTurnOrderingMarker(params.sessionManager)) {
const warn = params.warn ?? ((message: string) => log.warn(message));
warn(
`google turn ordering fixup: prepended user bootstrap (sessionId=${params.sessionId})`,
);
warn(`google turn ordering fixup: prepended user bootstrap (sessionId=${params.sessionId})`);
markGoogleTurnOrderingMarker(params.sessionManager);
}
return { messages: sanitized, didPrepend };
@@ -162,14 +143,10 @@ export async function sanitizeSessionHistory(params: {
sessionManager: SessionManager;
sessionId: string;
}): Promise<AgentMessage[]> {
const sanitizedImages = await sanitizeSessionMessagesImages(
params.messages,
"session:history",
{
sanitizeToolCallIds: isGoogleModelApi(params.modelApi),
enforceToolCallLast: params.modelApi === "anthropic-messages",
},
);
const sanitizedImages = await sanitizeSessionMessagesImages(params.messages, "session:history", {
sanitizeToolCallIds: isGoogleModelApi(params.modelApi),
enforceToolCallLast: params.modelApi === "anthropic-messages",
});
const repairedTools = sanitizeToolUseResultPairing(sanitizedImages);
const downgraded = isGoogleModelApi(params.modelApi)

View File

@@ -38,8 +38,7 @@ export function getDmHistoryLimitFromSessionKey(
if (!sessionKey || !config) return undefined;
const parts = sessionKey.split(":").filter(Boolean);
const providerParts =
parts.length >= 3 && parts[0] === "agent" ? parts.slice(2) : parts;
const providerParts = parts.length >= 3 && parts[0] === "agent" ? parts.slice(2) : parts;
const provider = providerParts[0]?.toLowerCase();
if (!provider) return undefined;

View File

@@ -1,8 +1,5 @@
import type { Api, Model } from "@mariozechner/pi-ai";
import {
discoverAuthStorage,
discoverModels,
} from "@mariozechner/pi-coding-agent";
import { discoverAuthStorage, discoverModels } from "@mariozechner/pi-coding-agent";
import type { ClawdbotConfig } from "../../config/config.js";
import { resolveClawdbotAgentDir } from "../agent-paths.js";
@@ -15,9 +12,7 @@ export function buildModelAliasLines(cfg?: ClawdbotConfig) {
for (const [keyRaw, entryRaw] of Object.entries(models)) {
const model = String(keyRaw ?? "").trim();
if (!model) continue;
const alias = String(
(entryRaw as { alias?: string } | undefined)?.alias ?? "",
).trim();
const alias = String((entryRaw as { alias?: string } | undefined)?.alias ?? "").trim();
if (!alias) continue;
entries.push({ alias, model });
}
@@ -67,10 +62,8 @@ export function resolveModel(
reasoning: false,
input: ["text"],
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
contextWindow:
providerCfg?.models?.[0]?.contextWindow ?? DEFAULT_CONTEXT_TOKENS,
maxTokens:
providerCfg?.models?.[0]?.maxTokens ?? DEFAULT_CONTEXT_TOKENS,
contextWindow: providerCfg?.models?.[0]?.contextWindow ?? DEFAULT_CONTEXT_TOKENS,
maxTokens: providerCfg?.models?.[0]?.maxTokens ?? DEFAULT_CONTEXT_TOKENS,
} as Model<Api>);
return { model: fallbackModel, authStorage, modelRegistry };
}

View File

@@ -14,11 +14,7 @@ import {
evaluateContextWindowGuard,
resolveContextWindowInfo,
} from "../context-window-guard.js";
import {
DEFAULT_CONTEXT_TOKENS,
DEFAULT_MODEL,
DEFAULT_PROVIDER,
} from "../defaults.js";
import { DEFAULT_CONTEXT_TOKENS, DEFAULT_MODEL, DEFAULT_PROVIDER } from "../defaults.js";
import { FailoverError, resolveFailoverStatus } from "../failover-error.js";
import {
ensureAuthProfileStore,
@@ -58,13 +54,10 @@ type ApiKeyInfo = {
export async function runEmbeddedPiAgent(
params: RunEmbeddedPiAgentParams,
): Promise<EmbeddedPiRunResult> {
const sessionLane = resolveSessionLane(
params.sessionKey?.trim() || params.sessionId,
);
const sessionLane = resolveSessionLane(params.sessionKey?.trim() || params.sessionId);
const globalLane = resolveGlobalLane(params.lane);
const enqueueGlobal =
params.enqueue ??
((task, opts) => enqueueCommandInLane(globalLane, task, opts));
params.enqueue ?? ((task, opts) => enqueueCommandInLane(globalLane, task, opts));
return enqueueCommandInLane(sessionLane, () =>
enqueueGlobal(async () => {
@@ -72,8 +65,7 @@ export async function runEmbeddedPiAgent(
const resolvedWorkspace = resolveUserPath(params.workspaceDir);
const prevCwd = process.cwd();
const provider =
(params.provider ?? DEFAULT_PROVIDER).trim() || DEFAULT_PROVIDER;
const provider = (params.provider ?? DEFAULT_PROVIDER).trim() || DEFAULT_PROVIDER;
const modelId = (params.model ?? DEFAULT_MODEL).trim() || DEFAULT_MODEL;
const agentDir = params.agentDir ?? resolveClawdbotAgentDir();
await ensureClawdbotModelsJson(params.config, agentDir);
@@ -124,12 +116,9 @@ export async function runEmbeddedPiAgent(
preferredProfile: explicitProfileId,
});
if (explicitProfileId && !profileOrder.includes(explicitProfileId)) {
throw new Error(
`Auth profile "${explicitProfileId}" is not configured for ${provider}.`,
);
throw new Error(`Auth profile "${explicitProfileId}" is not configured for ${provider}.`);
}
const profileCandidates =
profileOrder.length > 0 ? profileOrder : [undefined];
const profileCandidates = profileOrder.length > 0 ? profileOrder : [undefined];
let profileIndex = 0;
const initialThinkLevel = params.thinkLevel ?? "off";
@@ -150,9 +139,8 @@ export async function runEmbeddedPiAgent(
const applyApiKeyInfo = async (candidate?: string): Promise<void> => {
apiKeyInfo = await resolveApiKeyForCandidate(candidate);
if (model.provider === "github-copilot") {
const { resolveCopilotApiToken } = await import(
"../../providers/github-copilot-token.js"
);
const { resolveCopilotApiToken } =
await import("../../providers/github-copilot-token.js");
const copilotToken = await resolveCopilotApiToken({
githubToken: apiKeyInfo.apiKey,
});
@@ -238,13 +226,7 @@ export async function runEmbeddedPiAgent(
enforceFinalTag: params.enforceFinalTag,
});
const {
aborted,
promptError,
timedOut,
sessionIdUsed,
lastAssistant,
} = attempt;
const { aborted, promptError, timedOut, sessionIdUsed, lastAssistant } = attempt;
if (promptError && !aborted) {
const errorText = describeUnknownError(promptError);
@@ -273,11 +255,7 @@ export async function runEmbeddedPiAgent(
};
}
const promptFailoverReason = classifyFailoverReason(errorText);
if (
promptFailoverReason &&
promptFailoverReason !== "timeout" &&
lastProfileId
) {
if (promptFailoverReason && promptFailoverReason !== "timeout" && lastProfileId) {
await markAuthProfileFailure({
store: authStore,
profileId: lastProfileId,
@@ -320,14 +298,11 @@ export async function runEmbeddedPiAgent(
}
const fallbackConfigured =
(params.config?.agents?.defaults?.model?.fallbacks?.length ?? 0) >
0;
(params.config?.agents?.defaults?.model?.fallbacks?.length ?? 0) > 0;
const authFailure = isAuthAssistantError(lastAssistant);
const rateLimitFailure = isRateLimitAssistantError(lastAssistant);
const failoverFailure = isFailoverAssistantError(lastAssistant);
const assistantFailoverReason = classifyFailoverReason(
lastAssistant?.errorMessage ?? "",
);
const assistantFailoverReason = classifyFailoverReason(lastAssistant?.errorMessage ?? "");
const cloudCodeAssistFormatError = attempt.cloudCodeAssistFormatError;
// Treat timeout as potential rate limit (Antigravity hangs on rate limit)
@@ -406,8 +381,7 @@ export async function runEmbeddedPiAgent(
sessionKey: params.sessionKey ?? params.sessionId,
verboseLevel: params.verboseLevel,
reasoningLevel: params.reasoningLevel,
inlineToolResultsAllowed:
!params.onPartialReply && !params.onToolResult,
inlineToolResultsAllowed: !params.onPartialReply && !params.onToolResult,
});
log.debug(

View File

@@ -4,11 +4,7 @@ import os from "node:os";
import type { AgentMessage } from "@mariozechner/pi-agent-core";
import type { AssistantMessage } from "@mariozechner/pi-ai";
import { streamSimple } from "@mariozechner/pi-ai";
import {
createAgentSession,
SessionManager,
SettingsManager,
} from "@mariozechner/pi-coding-agent";
import { createAgentSession, SessionManager, SettingsManager } from "@mariozechner/pi-coding-agent";
import { resolveHeartbeatPrompt } from "../../../auto-reply/heartbeat.js";
import { resolveChannelCapabilities } from "../../../config/channel-capabilities.js";
@@ -41,19 +37,13 @@ import {
loadWorkspaceSkillEntries,
resolveSkillsPromptForRun,
} from "../../skills.js";
import {
filterBootstrapFilesForSession,
loadWorkspaceBootstrapFiles,
} from "../../workspace.js";
import { filterBootstrapFilesForSession, loadWorkspaceBootstrapFiles } from "../../workspace.js";
import { isAbortError } from "../abort.js";
import { buildEmbeddedExtensionPaths } from "../extensions.js";
import { applyExtraParamsToAgent } from "../extra-params.js";
import { logToolSchemasForGoogle, sanitizeSessionHistory } from "../google.js";
import {
getDmHistoryLimitFromSessionKey,
limitHistoryTurns,
} from "../history.js";
import { getDmHistoryLimitFromSessionKey, limitHistoryTurns } from "../history.js";
import { log } from "../logger.js";
import { buildModelAliasLines } from "../model.js";
import {
@@ -62,15 +52,9 @@ import {
setActiveEmbeddedRun,
} from "../runs.js";
import { buildEmbeddedSandboxInfo } from "../sandbox-info.js";
import {
prewarmSessionFile,
trackSessionManagerAccess,
} from "../session-manager-cache.js";
import { prewarmSessionFile, trackSessionManagerAccess } from "../session-manager-cache.js";
import { prepareSessionManagerForRun } from "../session-manager-init.js";
import {
buildEmbeddedSystemPrompt,
createSystemPromptOverride,
} from "../system-prompt.js";
import { buildEmbeddedSystemPrompt, createSystemPromptOverride } from "../system-prompt.js";
import { splitSdkTools } from "../tool-split.js";
import {
formatUserTime,
@@ -79,10 +63,7 @@ import {
resolveUserTimezone,
} from "../utils.js";
import type {
EmbeddedRunAttemptParams,
EmbeddedRunAttemptResult,
} from "./types.js";
import type { EmbeddedRunAttemptParams, EmbeddedRunAttemptResult } from "./types.js";
export async function runEmbeddedAttempt(
params: EmbeddedRunAttemptParams,
@@ -113,8 +94,7 @@ export async function runEmbeddedAttempt(
let restoreSkillEnv: (() => void) | undefined;
process.chdir(effectiveWorkspace);
try {
const shouldLoadSkillEntries =
!params.skillsSnapshot || !params.skillsSnapshot.resolvedSkills;
const shouldLoadSkillEntries = !params.skillsSnapshot || !params.skillsSnapshot.resolvedSkills;
const skillEntries = shouldLoadSkillEntries
? loadWorkspaceSkillEntries(effectiveWorkspace)
: [];
@@ -171,9 +151,7 @@ export async function runEmbeddedAttempt(
logToolSchemasForGoogle({ tools, provider: params.provider });
const machineName = await getMachineDisplayName();
const runtimeChannel = normalizeMessageChannel(
params.messageChannel ?? params.messageProvider,
);
const runtimeChannel = normalizeMessageChannel(params.messageChannel ?? params.messageProvider);
const runtimeCapabilities = runtimeChannel
? (resolveChannelCapabilities({
cfg: params.config,
@@ -193,9 +171,7 @@ export async function runEmbeddedAttempt(
const sandboxInfo = buildEmbeddedSandboxInfo(sandbox, params.bashElevated);
const reasoningTagHint = isReasoningTagProvider(params.provider);
const userTimezone = resolveUserTimezone(
params.config?.agents?.defaults?.userTimezone,
);
const userTimezone = resolveUserTimezone(params.config?.agents?.defaults?.userTimezone);
const userTime = formatUserTime(new Date(), userTimezone);
const { defaultAgentId, sessionAgentId } = resolveSessionAgentIds({
sessionKey: params.sessionKey,
@@ -211,9 +187,7 @@ export async function runEmbeddedAttempt(
ownerNumbers: params.ownerNumbers,
reasoningTagHint,
heartbeatPrompt: isDefaultAgent
? resolveHeartbeatPrompt(
params.config?.agents?.defaults?.heartbeat?.prompt,
)
? resolveHeartbeatPrompt(params.config?.agents?.defaults?.heartbeat?.prompt)
: undefined,
skillsPrompt,
runtimeInfo,
@@ -231,9 +205,7 @@ export async function runEmbeddedAttempt(
});
let sessionManager: ReturnType<typeof guardSessionManager> | undefined;
let session:
| Awaited<ReturnType<typeof createAgentSession>>["session"]
| undefined;
let session: Awaited<ReturnType<typeof createAgentSession>>["session"] | undefined;
try {
const hadSessionFile = await fs
.stat(params.sessionFile)
@@ -241,9 +213,7 @@ export async function runEmbeddedAttempt(
.catch(() => false);
await prewarmSessionFile(params.sessionFile);
sessionManager = guardSessionManager(
SessionManager.open(params.sessionFile),
);
sessionManager = guardSessionManager(SessionManager.open(params.sessionFile));
trackSessionManagerAccess(params.sessionFile);
await prepareSessionManagerForRun({
@@ -254,10 +224,7 @@ export async function runEmbeddedAttempt(
cwd: effectiveWorkspace,
});
const settingsManager = SettingsManager.create(
effectiveWorkspace,
agentDir,
);
const settingsManager = SettingsManager.create(effectiveWorkspace, agentDir);
ensurePiCompactionReserveTokens({
settingsManager,
minReserveTokens: resolveCompactionReserveTokensFloor(params.config),
@@ -412,9 +379,7 @@ export async function runEmbeddedAttempt(
let promptError: unknown = null;
try {
const promptStartedAt = Date.now();
log.debug(
`embedded run prompt start: runId=${params.runId} sessionId=${params.sessionId}`,
);
log.debug(`embedded run prompt start: runId=${params.runId} sessionId=${params.sessionId}`);
try {
await activeSession.prompt(params.prompt, { images: params.images });
} catch (err) {
@@ -448,15 +413,12 @@ export async function runEmbeddedAttempt(
const lastAssistant = messagesSnapshot
.slice()
.reverse()
.find((m) => (m as AgentMessage)?.role === "assistant") as
| AssistantMessage
| undefined;
.find((m) => (m as AgentMessage)?.role === "assistant") as AssistantMessage | undefined;
const toolMetasNormalized = toolMetas
.filter(
(entry): entry is { toolName: string; meta?: string } =>
typeof entry.toolName === "string" &&
entry.toolName.trim().length > 0,
typeof entry.toolName === "string" && entry.toolName.trim().length > 0,
)
.map((entry) => ({ toolName: entry.toolName, meta: entry.meta }));
@@ -473,8 +435,7 @@ export async function runEmbeddedAttempt(
messagingToolSentTexts: getMessagingToolSentTexts(),
messagingToolSentTargets: getMessagingToolSentTargets(),
cloudCodeAssistFormatError: Boolean(
lastAssistant?.errorMessage &&
isCloudCodeAssistFormatError(lastAssistant.errorMessage),
lastAssistant?.errorMessage && isCloudCodeAssistFormatError(lastAssistant.errorMessage),
),
};
} finally {

View File

@@ -1,9 +1,5 @@
import type { ImageContent } from "@mariozechner/pi-ai";
import type {
ReasoningLevel,
ThinkLevel,
VerboseLevel,
} from "../../../auto-reply/thinking.js";
import type { ReasoningLevel, ThinkLevel, VerboseLevel } from "../../../auto-reply/thinking.js";
import type { ClawdbotConfig } from "../../../config/config.js";
import type { enqueueCommand } from "../../../process/command-queue.js";
import type { ExecElevatedDefaults } from "../../bash-tools.js";
@@ -42,10 +38,7 @@ export type RunEmbeddedPiAgentParams = {
runId: string;
abortSignal?: AbortSignal;
shouldEmitToolResult?: () => boolean;
onPartialReply?: (payload: {
text?: string;
mediaUrls?: string[];
}) => void | Promise<void>;
onPartialReply?: (payload: { text?: string; mediaUrls?: string[] }) => void | Promise<void>;
onAssistantMessageStart?: () => void | Promise<void>;
onBlockReply?: (payload: {
text?: string;
@@ -55,18 +48,9 @@ export type RunEmbeddedPiAgentParams = {
onBlockReplyFlush?: () => void | Promise<void>;
blockReplyBreak?: "text_end" | "message_end";
blockReplyChunking?: BlockReplyChunking;
onReasoningStream?: (payload: {
text?: string;
mediaUrls?: string[];
}) => void | Promise<void>;
onToolResult?: (payload: {
text?: string;
mediaUrls?: string[];
}) => void | Promise<void>;
onAgentEvent?: (evt: {
stream: string;
data: Record<string, unknown>;
}) => void;
onReasoningStream?: (payload: { text?: string; mediaUrls?: string[] }) => void | Promise<void>;
onToolResult?: (payload: { text?: string; mediaUrls?: string[] }) => void | Promise<void>;
onAgentEvent?: (evt: { stream: string; data: Record<string, unknown> }) => void;
lane?: string;
enqueue?: typeof enqueueCommand;
extraSystemPrompt?: string;

View File

@@ -1,13 +1,7 @@
import type { AssistantMessage } from "@mariozechner/pi-ai";
import { parseReplyDirectives } from "../../../auto-reply/reply/reply-directives.js";
import type {
ReasoningLevel,
VerboseLevel,
} from "../../../auto-reply/thinking.js";
import {
isSilentReplyText,
SILENT_REPLY_TOKEN,
} from "../../../auto-reply/tokens.js";
import type { ReasoningLevel, VerboseLevel } from "../../../auto-reply/thinking.js";
import { isSilentReplyText, SILENT_REPLY_TOKEN } from "../../../auto-reply/tokens.js";
import { formatToolAggregate } from "../../../auto-reply/tool-meta.js";
import type { ClawdbotConfig } from "../../../config/config.js";
import { formatAssistantErrorText } from "../../pi-embedded-helpers.js";
@@ -57,9 +51,7 @@ export function buildEmbeddedRunPayloads(params: {
if (errorText) replyItems.push({ text: errorText, isError: true });
const inlineToolResults =
params.inlineToolResultsAllowed &&
params.verboseLevel === "on" &&
params.toolMetas.length > 0;
params.inlineToolResultsAllowed && params.verboseLevel === "on" && params.toolMetas.length > 0;
if (inlineToolResults) {
for (const { toolName, meta } of params.toolMetas) {
const agg = formatToolAggregate(toolName, meta ? [meta] : []);
@@ -90,9 +82,7 @@ export function buildEmbeddedRunPayloads(params: {
: "";
if (reasoningText) replyItems.push({ text: reasoningText });
const fallbackAnswerText = params.lastAssistant
? extractAssistantText(params.lastAssistant)
: "";
const fallbackAnswerText = params.lastAssistant ? extractAssistantText(params.lastAssistant) : "";
const answerTexts = params.assistantTexts.length
? params.assistantTexts
: fallbackAnswerText
@@ -108,11 +98,7 @@ export function buildEmbeddedRunPayloads(params: {
replyToTag,
replyToCurrent,
} = parseReplyDirectives(text);
if (
!cleanedText &&
(!mediaUrls || mediaUrls.length === 0) &&
!audioAsVoice
) {
if (!cleanedText && (!mediaUrls || mediaUrls.length === 0) && !audioAsVoice) {
continue;
}
replyItems.push({
@@ -135,12 +121,10 @@ export function buildEmbeddedRunPayloads(params: {
replyToId: item.replyToId,
replyToTag: item.replyToTag,
replyToCurrent: item.replyToCurrent,
audioAsVoice:
item.audioAsVoice || Boolean(hasAudioAsVoiceTag && item.media?.length),
audioAsVoice: item.audioAsVoice || Boolean(hasAudioAsVoiceTag && item.media?.length),
}))
.filter((p) => {
if (!p.text && !p.mediaUrl && (!p.mediaUrls || p.mediaUrls.length === 0))
return false;
if (!p.text && !p.mediaUrl && (!p.mediaUrls || p.mediaUrls.length === 0)) return false;
if (p.text && isSilentReplyText(p.text, SILENT_REPLY_TOKEN)) return false;
return true;
});

View File

@@ -1,20 +1,8 @@
import type { AgentMessage } from "@mariozechner/pi-agent-core";
import type {
Api,
AssistantMessage,
ImageContent,
Model,
} from "@mariozechner/pi-ai";
import type {
discoverAuthStorage,
discoverModels,
} from "@mariozechner/pi-coding-agent";
import type { Api, AssistantMessage, ImageContent, Model } from "@mariozechner/pi-ai";
import type { discoverAuthStorage, discoverModels } from "@mariozechner/pi-coding-agent";
import type {
ReasoningLevel,
ThinkLevel,
VerboseLevel,
} from "../../../auto-reply/thinking.js";
import type { ReasoningLevel, ThinkLevel, VerboseLevel } from "../../../auto-reply/thinking.js";
import type { ClawdbotConfig } from "../../../config/config.js";
import type { ExecElevatedDefaults } from "../../bash-tools.js";
import type { MessagingToolSend } from "../../pi-embedded-messaging.js";
@@ -54,10 +42,7 @@ export type EmbeddedRunAttemptParams = {
runId: string;
abortSignal?: AbortSignal;
shouldEmitToolResult?: () => boolean;
onPartialReply?: (payload: {
text?: string;
mediaUrls?: string[];
}) => void | Promise<void>;
onPartialReply?: (payload: { text?: string; mediaUrls?: string[] }) => void | Promise<void>;
onAssistantMessageStart?: () => void | Promise<void>;
onBlockReply?: (payload: {
text?: string;
@@ -67,18 +52,9 @@ export type EmbeddedRunAttemptParams = {
onBlockReplyFlush?: () => void | Promise<void>;
blockReplyBreak?: "text_end" | "message_end";
blockReplyChunking?: BlockReplyChunking;
onReasoningStream?: (payload: {
text?: string;
mediaUrls?: string[];
}) => void | Promise<void>;
onToolResult?: (payload: {
text?: string;
mediaUrls?: string[];
}) => void | Promise<void>;
onAgentEvent?: (evt: {
stream: string;
data: Record<string, unknown>;
}) => void;
onReasoningStream?: (payload: { text?: string; mediaUrls?: string[] }) => void | Promise<void>;
onToolResult?: (payload: { text?: string; mediaUrls?: string[] }) => void | Promise<void>;
onAgentEvent?: (evt: { stream: string; data: Record<string, unknown> }) => void;
extraSystemPrompt?: string;
ownerNumbers?: string[];
enforceFinalTag?: boolean;

View File

@@ -12,10 +12,7 @@ type EmbeddedRunWaiter = {
};
const EMBEDDED_RUN_WAITERS = new Map<string, Set<EmbeddedRunWaiter>>();
export function queueEmbeddedPiMessage(
sessionId: string,
text: string,
): boolean {
export function queueEmbeddedPiMessage(sessionId: string, text: string): boolean {
const handle = ACTIVE_EMBEDDED_RUNS.get(sessionId);
if (!handle) return false;
if (!handle.isStreaming()) return false;
@@ -41,12 +38,8 @@ export function isEmbeddedPiRunStreaming(sessionId: string): boolean {
return handle.isStreaming();
}
export function waitForEmbeddedPiRunEnd(
sessionId: string,
timeoutMs = 15_000,
): Promise<boolean> {
if (!sessionId || !ACTIVE_EMBEDDED_RUNS.has(sessionId))
return Promise.resolve(true);
export function waitForEmbeddedPiRunEnd(sessionId: string, timeoutMs = 15_000): Promise<boolean> {
if (!sessionId || !ACTIVE_EMBEDDED_RUNS.has(sessionId)) return Promise.resolve(true);
return new Promise((resolve) => {
const waiters = EMBEDDED_RUN_WAITERS.get(sessionId) ?? new Set();
const waiter: EmbeddedRunWaiter = {
@@ -81,17 +74,11 @@ function notifyEmbeddedRunEnded(sessionId: string) {
}
}
export function setActiveEmbeddedRun(
sessionId: string,
handle: EmbeddedPiQueueHandle,
) {
export function setActiveEmbeddedRun(sessionId: string, handle: EmbeddedPiQueueHandle) {
ACTIVE_EMBEDDED_RUNS.set(sessionId, handle);
}
export function clearActiveEmbeddedRun(
sessionId: string,
handle: EmbeddedPiQueueHandle,
) {
export function clearActiveEmbeddedRun(sessionId: string, handle: EmbeddedPiQueueHandle) {
if (ACTIVE_EMBEDDED_RUNS.get(sessionId) === handle) {
ACTIVE_EMBEDDED_RUNS.delete(sessionId);
notifyEmbeddedRunEnded(sessionId);

View File

@@ -7,15 +7,12 @@ export function buildEmbeddedSandboxInfo(
execElevated?: ExecElevatedDefaults,
): EmbeddedSandboxInfo | undefined {
if (!sandbox?.enabled) return undefined;
const elevatedAllowed = Boolean(
execElevated?.enabled && execElevated.allowed,
);
const elevatedAllowed = Boolean(execElevated?.enabled && execElevated.allowed);
return {
enabled: true,
workspaceDir: sandbox.workspaceDir,
workspaceAccess: sandbox.workspaceAccess,
agentWorkspaceMount:
sandbox.workspaceAccess === "ro" ? "/agent" : undefined,
agentWorkspaceMount: sandbox.workspaceAccess === "ro" ? "/agent" : undefined,
browserControlUrl: sandbox.browser?.controlUrl,
browserNoVncUrl: sandbox.browser?.noVncUrl,
hostBrowserAllowed: sandbox.browserAllowHostControl,

View File

@@ -23,21 +23,15 @@ export async function prepareSessionManagerForRun(params: {
const sm = params.sessionManager as {
sessionId: string;
flushed: boolean;
fileEntries: Array<
SessionHeaderEntry | SessionMessageEntry | { type: string }
>;
fileEntries: Array<SessionHeaderEntry | SessionMessageEntry | { type: string }>;
byId?: Map<string, unknown>;
labelsById?: Map<string, unknown>;
leafId?: string | null;
};
const header = sm.fileEntries.find(
(e): e is SessionHeaderEntry => e.type === "session",
);
const header = sm.fileEntries.find((e): e is SessionHeaderEntry => e.type === "session");
const hasAssistant = sm.fileEntries.some(
(e) =>
e.type === "message" &&
(e as SessionMessageEntry).message?.role === "assistant",
(e) => e.type === "message" && (e as SessionMessageEntry).message?.role === "assistant",
);
if (!params.hadSessionFile && header) {

View File

@@ -6,10 +6,7 @@ import { toToolDefinitions } from "../pi-tool-definition-adapter.js";
// and extended toolset remain consistent across providers.
type AnyAgentTool = AgentTool;
export function splitSdkTools(options: {
tools: AnyAgentTool[];
sandboxEnabled: boolean;
}): {
export function splitSdkTools(options: { tools: AnyAgentTool[]; sandboxEnabled: boolean }): {
builtInTools: AnyAgentTool[];
customTools: ReturnType<typeof toToolDefinitions>;
} {

View File

@@ -9,9 +9,7 @@ export function mapThinkingLevel(level?: ThinkLevel): ThinkingLevel {
return level;
}
export function resolveExecToolDefaults(
config?: ClawdbotConfig,
): ExecToolDefaults | undefined {
export function resolveExecToolDefaults(config?: ClawdbotConfig): ExecToolDefaults | undefined {
const tools = config?.tools;
if (!tools) return undefined;
if (!tools.exec) return tools.bash;
@@ -23,9 +21,7 @@ export function resolveUserTimezone(configured?: string): string {
const trimmed = configured?.trim();
if (trimmed) {
try {
new Intl.DateTimeFormat("en-US", { timeZone: trimmed }).format(
new Date(),
);
new Intl.DateTimeFormat("en-US", { timeZone: trimmed }).format(new Date());
return trimmed;
} catch {
// ignore invalid timezone
@@ -35,10 +31,7 @@ export function resolveUserTimezone(configured?: string): string {
return host?.trim() || "UTC";
}
export function formatUserTime(
date: Date,
timeZone: string,
): string | undefined {
export function formatUserTime(date: Date, timeZone: string): string | undefined {
try {
const parts = new Intl.DateTimeFormat("en-CA", {
timeZone,
@@ -54,14 +47,7 @@ export function formatUserTime(
for (const part of parts) {
if (part.type !== "literal") map[part.type] = part.value;
}
if (
!map.weekday ||
!map.year ||
!map.month ||
!map.day ||
!map.hour ||
!map.minute
) {
if (!map.weekday || !map.year || !map.month || !map.day || !map.hour || !map.minute) {
return undefined;
}
return `${map.weekday} ${map.year}-${map.month}-${map.day} ${map.hour}:${map.minute}`;