Merge branch 'main' into fix/media-replies
This commit is contained in:
commit
0e1927875c
@ -8,6 +8,9 @@
|
|||||||
- Logging now rolls daily to `/tmp/warelay/warelay-YYYY-MM-DD.log` (or custom dir) and prunes files older than 24h to reduce data retention.
|
- Logging now rolls daily to `/tmp/warelay/warelay-YYYY-MM-DD.log` (or custom dir) and prunes files older than 24h to reduce data retention.
|
||||||
- Media server now rejects symlinked files and ensures resolved paths stay inside the media directory, closing traversal via symlinks; added regression test. (Thanks @joaohlisboa)
|
- Media server now rejects symlinked files and ensures resolved paths stay inside the media directory, closing traversal via symlinks; added regression test. (Thanks @joaohlisboa)
|
||||||
|
|
||||||
|
### Performance
|
||||||
|
- Web auto-replies using the Pi agent now keep a single long-lived `tau` process in RPC mode instead of spawning per message, eliminating cold-start latency while preserving session/cwd handling.
|
||||||
|
|
||||||
## 1.3.0 — 2025-12-02
|
## 1.3.0 — 2025-12-02
|
||||||
|
|
||||||
### Highlights
|
### Highlights
|
||||||
|
|||||||
@ -47,7 +47,11 @@ function parsePiJson(raw: string): AgentParseResult {
|
|||||||
|
|
||||||
export const piSpec: AgentSpec = {
|
export const piSpec: AgentSpec = {
|
||||||
kind: "pi",
|
kind: "pi",
|
||||||
isInvocation: (argv) => argv.length > 0 && path.basename(argv[0]) === "pi",
|
isInvocation: (argv) => {
|
||||||
|
if (argv.length === 0) return false;
|
||||||
|
const base = path.basename(argv[0]).replace(/\.(m?js)$/i, "");
|
||||||
|
return base === "pi" || base === "tau";
|
||||||
|
},
|
||||||
buildArgs: (ctx) => {
|
buildArgs: (ctx) => {
|
||||||
const argv = [...ctx.argv];
|
const argv = [...ctx.argv];
|
||||||
// Non-interactive print + JSON
|
// Non-interactive print + JSON
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import type { AgentMeta } from "../agents/types.js";
|
|||||||
import type { WarelayConfig } from "../config/config.js";
|
import type { WarelayConfig } from "../config/config.js";
|
||||||
import { isVerbose, logVerbose } from "../globals.js";
|
import { isVerbose, logVerbose } from "../globals.js";
|
||||||
import { logError } from "../logger.js";
|
import { logError } from "../logger.js";
|
||||||
|
import { getChildLogger } from "../logging.js";
|
||||||
import { splitMediaFromOutput } from "../media/parse.js";
|
import { splitMediaFromOutput } from "../media/parse.js";
|
||||||
import { enqueueCommand } from "../process/command-queue.js";
|
import { enqueueCommand } from "../process/command-queue.js";
|
||||||
import type { runCommandWithTimeout } from "../process/exec.js";
|
import type { runCommandWithTimeout } from "../process/exec.js";
|
||||||
@ -100,6 +101,12 @@ export function summarizeClaudeMetadata(payload: unknown): string | undefined {
|
|||||||
export async function runCommandReply(
|
export async function runCommandReply(
|
||||||
params: CommandReplyParams,
|
params: CommandReplyParams,
|
||||||
): Promise<CommandReplyResult> {
|
): Promise<CommandReplyResult> {
|
||||||
|
const logger = getChildLogger({ module: "command-reply" });
|
||||||
|
const verboseLog = (msg: string) => {
|
||||||
|
logger.debug(msg);
|
||||||
|
if (isVerbose()) logVerbose(msg);
|
||||||
|
};
|
||||||
|
|
||||||
const {
|
const {
|
||||||
reply,
|
reply,
|
||||||
templatingCtx,
|
templatingCtx,
|
||||||
@ -182,7 +189,7 @@ export async function runCommandReply(
|
|||||||
systemSent,
|
systemSent,
|
||||||
identityPrefix: agentCfg.identityPrefix,
|
identityPrefix: agentCfg.identityPrefix,
|
||||||
format: agentCfg.format,
|
format: agentCfg.format,
|
||||||
})
|
})
|
||||||
: argv;
|
: argv;
|
||||||
|
|
||||||
logVerbose(
|
logVerbose(
|
||||||
@ -249,17 +256,19 @@ export async function runCommandReply(
|
|||||||
trimmed = cleanedText;
|
trimmed = cleanedText;
|
||||||
if (mediaFound?.length) {
|
if (mediaFound?.length) {
|
||||||
mediaFromCommand = mediaFound;
|
mediaFromCommand = mediaFound;
|
||||||
if (isVerbose()) logVerbose(`MEDIA token extracted: ${mediaFound}`);
|
verboseLog(`MEDIA token extracted: ${mediaFound}`);
|
||||||
} else if (isVerbose()) {
|
} else {
|
||||||
logVerbose("No MEDIA token extracted from final text");
|
verboseLog("No MEDIA token extracted from final text");
|
||||||
}
|
}
|
||||||
if (!trimmed && !mediaFromCommand) {
|
if (!trimmed && !mediaFromCommand) {
|
||||||
const meta = parsed?.meta?.extra?.summary ?? undefined;
|
const meta = parsed?.meta?.extra?.summary ?? undefined;
|
||||||
trimmed = `(command produced no output${meta ? `; ${meta}` : ""})`;
|
trimmed = `(command produced no output${meta ? `; ${meta}` : ""})`;
|
||||||
logVerbose("No text/media produced; injecting fallback notice to user");
|
verboseLog("No text/media produced; injecting fallback notice to user");
|
||||||
}
|
}
|
||||||
logVerbose(`Command auto-reply stdout (trimmed): ${trimmed || "<empty>"}`);
|
verboseLog(`Command auto-reply stdout (trimmed): ${trimmed || "<empty>"}`);
|
||||||
logVerbose(`Command auto-reply finished in ${Date.now() - started}ms`);
|
const elapsed = Date.now() - started;
|
||||||
|
verboseLog(`Command auto-reply finished in ${elapsed}ms`);
|
||||||
|
logger.info({ durationMs: elapsed, agent: agentKind, cwd: reply.cwd }, "command auto-reply finished");
|
||||||
if ((code ?? 0) !== 0) {
|
if ((code ?? 0) !== 0) {
|
||||||
console.error(
|
console.error(
|
||||||
`Command auto-reply exited with code ${code ?? "unknown"} (signal: ${signal ?? "none"})`,
|
`Command auto-reply exited with code ${code ?? "unknown"} (signal: ${signal ?? "none"})`,
|
||||||
@ -346,17 +355,16 @@ export async function runCommandReply(
|
|||||||
killed,
|
killed,
|
||||||
agentMeta: parsed?.meta,
|
agentMeta: parsed?.meta,
|
||||||
};
|
};
|
||||||
if (isVerbose()) {
|
verboseLog(`Command auto-reply meta: ${JSON.stringify(meta)}`);
|
||||||
logVerbose(`Command auto-reply meta: ${JSON.stringify(meta)}`);
|
|
||||||
}
|
|
||||||
return { payload, meta };
|
return { payload, meta };
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
const elapsed = Date.now() - started;
|
const elapsed = Date.now() - started;
|
||||||
|
logger.info({ durationMs: elapsed, agent: agentKind, cwd: reply.cwd }, "command auto-reply failed");
|
||||||
const anyErr = err as { killed?: boolean; signal?: string };
|
const anyErr = err as { killed?: boolean; signal?: string };
|
||||||
const timeoutHit = anyErr.killed === true || anyErr.signal === "SIGKILL";
|
const timeoutHit = anyErr.killed === true || anyErr.signal === "SIGKILL";
|
||||||
const errorObj = err as { stdout?: string; stderr?: string };
|
const errorObj = err as { stdout?: string; stderr?: string };
|
||||||
if (errorObj.stderr?.trim()) {
|
if (errorObj.stderr?.trim()) {
|
||||||
logVerbose(`Command auto-reply stderr: ${errorObj.stderr.trim()}`);
|
verboseLog(`Command auto-reply stderr: ${errorObj.stderr.trim()}`);
|
||||||
}
|
}
|
||||||
if (timeoutHit) {
|
if (timeoutHit) {
|
||||||
console.error(
|
console.error(
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user