tools and skills, etc in the containers
This commit is contained in:
@@ -3,24 +3,28 @@ import { readdirSync, existsSync, mkdirSync } from "node:fs";
|
||||
import type { Subprocess } from "bun";
|
||||
import type { PiEvent, MessageCost } from "./types";
|
||||
import { readApiKeys } from "../server-settings/pi-mono";
|
||||
import { readSearxngConfig } from "../server-settings/searxng";
|
||||
import { PI_CONFIG_DIR, getGlobalSkillsDir, getUserSkillsDir, getGlobalExtensionsDir, getUserExtensionsDir, getGlobalToolsDir, getUserToolsDir } from "../../data-path";
|
||||
import { ensureDockerContainer } from "../terminal/websocket";
|
||||
import { logger } from "./logger";
|
||||
|
||||
export type PiEventHandler = (event: PiEvent) => void;
|
||||
|
||||
function collectSkillFlags(email: string): string[] {
|
||||
const flags: string[] = [];
|
||||
const dirs = [getGlobalSkillsDir(), getUserSkillsDir(email)];
|
||||
type PathOverrides = { global: string; user: string };
|
||||
|
||||
for (const dir of dirs) {
|
||||
if (!existsSync(dir)) continue;
|
||||
const entries = readdirSync(dir, { withFileTypes: true });
|
||||
for (const entry of entries) {
|
||||
function collectSkillFlags(email: string, containerPaths?: PathOverrides): string[] {
|
||||
const flags: string[] = [];
|
||||
const pairs: Array<[hostDir: string, outputDir: string]> = [
|
||||
[getGlobalSkillsDir(), containerPaths?.global ?? getGlobalSkillsDir()],
|
||||
[getUserSkillsDir(email), containerPaths?.user ?? getUserSkillsDir(email)],
|
||||
];
|
||||
|
||||
for (const [hostDir, outputDir] of pairs) {
|
||||
if (!existsSync(hostDir)) continue;
|
||||
for (const entry of readdirSync(hostDir, { withFileTypes: true })) {
|
||||
if (!entry.isDirectory()) continue;
|
||||
const skillFile = join(dir, entry.name, 'SKILL.md');
|
||||
if (existsSync(skillFile)) {
|
||||
flags.push('--skill', join(dir, entry.name));
|
||||
if (existsSync(join(hostDir, entry.name, 'SKILL.md'))) {
|
||||
flags.push('--skill', `${outputDir}/${entry.name}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -28,18 +32,19 @@ function collectSkillFlags(email: string): string[] {
|
||||
return flags;
|
||||
}
|
||||
|
||||
function collectExtensionFlags(email: string): string[] {
|
||||
function collectExtensionFlags(email: string, containerPaths?: PathOverrides): string[] {
|
||||
const flags: string[] = [];
|
||||
const dirs = [getGlobalExtensionsDir(), getUserExtensionsDir(email)];
|
||||
const pairs: Array<[hostDir: string, outputDir: string]> = [
|
||||
[getGlobalExtensionsDir(), containerPaths?.global ?? getGlobalExtensionsDir()],
|
||||
[getUserExtensionsDir(email), containerPaths?.user ?? getUserExtensionsDir(email)],
|
||||
];
|
||||
|
||||
for (const dir of dirs) {
|
||||
if (!existsSync(dir)) continue;
|
||||
const entries = readdirSync(dir, { withFileTypes: true });
|
||||
for (const entry of entries) {
|
||||
for (const [hostDir, outputDir] of pairs) {
|
||||
if (!existsSync(hostDir)) continue;
|
||||
for (const entry of readdirSync(hostDir, { withFileTypes: true })) {
|
||||
if (!entry.isDirectory()) continue;
|
||||
const entryFile = join(dir, entry.name, 'index.ts');
|
||||
if (existsSync(entryFile)) {
|
||||
flags.push('--extension', entryFile);
|
||||
if (existsSync(join(hostDir, entry.name, 'index.ts'))) {
|
||||
flags.push('--extension', `${outputDir}/${entry.name}/index.ts`);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -66,17 +71,35 @@ export async function spawnPi(
|
||||
if (sandbox) {
|
||||
const container = await ensureDockerContainer(sandbox.email, sandbox.userId, sandbox.homeDir, sandbox.username);
|
||||
const storedKeys = await readApiKeys();
|
||||
const searxng = await readSearxngConfig();
|
||||
const dockerPath = Bun.which('docker') ?? 'docker';
|
||||
const containerId = container.dockerId;
|
||||
const containerHome = `/home/${sandbox.username}`;
|
||||
const containerPiConfig = `${containerHome}/.pi/agent`;
|
||||
const piArgs = ['pi', '--mode', 'rpc', '--no-extensions', '--no-skills', '--no-prompt-templates', '--no-themes'];
|
||||
|
||||
// Collect skill/extension flags using container-side paths
|
||||
const skillFlags = collectSkillFlags(sandbox.email, {
|
||||
global: '/officer/skills',
|
||||
user: '/officer/user/skills',
|
||||
});
|
||||
const extensionFlags = collectExtensionFlags(sandbox.email, {
|
||||
global: '/officer/extensions',
|
||||
user: '/officer/user/extensions',
|
||||
});
|
||||
|
||||
const piArgs = [
|
||||
'pi', '--mode', 'rpc',
|
||||
'--no-skills', '--no-prompt-templates', '--no-themes',
|
||||
...skillFlags,
|
||||
...extensionFlags,
|
||||
];
|
||||
if (model) piArgs.push('--model', model);
|
||||
|
||||
// Build env flags: Pi config dir + all stored API keys
|
||||
const envFlags = [
|
||||
'-e', `PI_CODING_AGENT_DIR=${containerPiConfig}`,
|
||||
'-e', `HOME=${containerHome}`,
|
||||
'-e', `PI_TOOLS_DIRS=/officer/tools:/officer/user/tools`,
|
||||
'-e', `PI_SEARXNG_URL=${searxng.url}`,
|
||||
];
|
||||
for (const [key, value] of Object.entries(storedKeys)) {
|
||||
if (value?.trim()) envFlags.push('-e', `${key}=${value.trim()}`);
|
||||
@@ -96,9 +119,15 @@ export async function spawnPi(
|
||||
stderr: 'pipe',
|
||||
});
|
||||
|
||||
logger.info('Spawned Pi in container', { containerId, model });
|
||||
logger.info('Spawned Pi in container', {
|
||||
containerId,
|
||||
model,
|
||||
skills: skillFlags.filter((f) => f !== '--skill').length,
|
||||
extensions: extensionFlags.filter((f) => f !== '--extension').length,
|
||||
});
|
||||
} else {
|
||||
const storedKeys = await readApiKeys();
|
||||
const searxng = await readSearxngConfig();
|
||||
const skillFlags = collectSkillFlags(email);
|
||||
const extensionFlags = collectExtensionFlags(email);
|
||||
const args = ['pi', '--mode', 'rpc', '--no-skills', '--no-prompt-templates', '--no-themes', ...skillFlags, ...extensionFlags];
|
||||
@@ -115,7 +144,7 @@ export async function spawnPi(
|
||||
stdin: 'pipe',
|
||||
stdout: 'pipe',
|
||||
stderr: 'pipe',
|
||||
env: { ...process.env, ...storedKeys, PI_CODING_AGENT_DIR: PI_CONFIG_DIR, PI_TOOLS_DIRS: toolsDirs },
|
||||
env: { ...process.env, ...storedKeys, PI_CODING_AGENT_DIR: PI_CONFIG_DIR, PI_TOOLS_DIRS: toolsDirs, PI_SEARXNG_URL: searxng.url },
|
||||
});
|
||||
|
||||
logger.info('Spawned Pi locally', {
|
||||
|
||||
Reference in New Issue
Block a user