Merge 7c5d26aa9c into 09be5d45d5
This commit is contained in:
commit
5dc856bf2a
15
pnpm-lock.yaml
generated
15
pnpm-lock.yaml
generated
@ -172,6 +172,13 @@ importers:
|
|||||||
zod:
|
zod:
|
||||||
specifier: ^4.3.6
|
specifier: ^4.3.6
|
||||||
version: 4.3.6
|
version: 4.3.6
|
||||||
|
optionalDependencies:
|
||||||
|
'@napi-rs/canvas':
|
||||||
|
specifier: ^0.1.88
|
||||||
|
version: 0.1.88
|
||||||
|
node-llama-cpp:
|
||||||
|
specifier: 3.15.0
|
||||||
|
version: 3.15.0(typescript@5.9.3)
|
||||||
devDependencies:
|
devDependencies:
|
||||||
'@grammyjs/types':
|
'@grammyjs/types':
|
||||||
specifier: ^3.23.0
|
specifier: ^3.23.0
|
||||||
@ -254,13 +261,6 @@ importers:
|
|||||||
wireit:
|
wireit:
|
||||||
specifier: ^0.14.12
|
specifier: ^0.14.12
|
||||||
version: 0.14.12
|
version: 0.14.12
|
||||||
optionalDependencies:
|
|
||||||
'@napi-rs/canvas':
|
|
||||||
specifier: ^0.1.88
|
|
||||||
version: 0.1.88
|
|
||||||
node-llama-cpp:
|
|
||||||
specifier: 3.15.0
|
|
||||||
version: 3.15.0(typescript@5.9.3)
|
|
||||||
|
|
||||||
extensions/bluebubbles: {}
|
extensions/bluebubbles: {}
|
||||||
|
|
||||||
@ -1328,7 +1328,6 @@ packages:
|
|||||||
'@lancedb/lancedb@0.23.0':
|
'@lancedb/lancedb@0.23.0':
|
||||||
resolution: {integrity: sha512-aYrIoEG24AC+wILCL57Ius/Y4yU+xFHDPKLvmjzzN4byAjzeIGF0TC86S5RBt4Ji+dxS7yIWV5Q/gE5/fybIFQ==}
|
resolution: {integrity: sha512-aYrIoEG24AC+wILCL57Ius/Y4yU+xFHDPKLvmjzzN4byAjzeIGF0TC86S5RBt4Ji+dxS7yIWV5Q/gE5/fybIFQ==}
|
||||||
engines: {node: '>= 18'}
|
engines: {node: '>= 18'}
|
||||||
cpu: [x64, arm64]
|
|
||||||
os: [darwin, linux, win32]
|
os: [darwin, linux, win32]
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
apache-arrow: '>=15.0.0 <=18.1.0'
|
apache-arrow: '>=15.0.0 <=18.1.0'
|
||||||
|
|||||||
@ -351,6 +351,7 @@ export async function compactEmbeddedPiSessionDirect(
|
|||||||
|
|
||||||
const sessionLock = await acquireSessionWriteLock({
|
const sessionLock = await acquireSessionWriteLock({
|
||||||
sessionFile: params.sessionFile,
|
sessionFile: params.sessionFile,
|
||||||
|
timeoutMs: params.config?.agents?.defaults?.sessionWriteLockTimeoutMs,
|
||||||
});
|
});
|
||||||
try {
|
try {
|
||||||
await prewarmSessionFile(params.sessionFile);
|
await prewarmSessionFile(params.sessionFile);
|
||||||
|
|||||||
@ -386,6 +386,7 @@ export async function runEmbeddedAttempt(
|
|||||||
|
|
||||||
const sessionLock = await acquireSessionWriteLock({
|
const sessionLock = await acquireSessionWriteLock({
|
||||||
sessionFile: params.sessionFile,
|
sessionFile: params.sessionFile,
|
||||||
|
timeoutMs: params.config?.agents?.defaults?.sessionWriteLockTimeoutMs,
|
||||||
});
|
});
|
||||||
|
|
||||||
let sessionManager: ReturnType<typeof guardSessionManager> | undefined;
|
let sessionManager: ReturnType<typeof guardSessionManager> | undefined;
|
||||||
|
|||||||
@ -107,7 +107,9 @@ export async function acquireSessionWriteLock(params: {
|
|||||||
release: () => Promise<void>;
|
release: () => Promise<void>;
|
||||||
}> {
|
}> {
|
||||||
registerCleanupHandlers();
|
registerCleanupHandlers();
|
||||||
const timeoutMs = params.timeoutMs ?? 10_000;
|
// Default timeout increased from 10s to 60s to prevent premature termination
|
||||||
|
// when multiple subagents compete for session file locks (see issue #4355)
|
||||||
|
const timeoutMs = params.timeoutMs ?? 60_000;
|
||||||
const staleMs = params.staleMs ?? 30 * 60 * 1000;
|
const staleMs = params.staleMs ?? 30 * 60 * 1000;
|
||||||
const sessionFile = path.resolve(params.sessionFile);
|
const sessionFile = path.resolve(params.sessionFile);
|
||||||
const sessionDir = path.dirname(sessionFile);
|
const sessionDir = path.dirname(sessionFile);
|
||||||
|
|||||||
87
src/config/config.session-write-lock-timeout.test.ts
Normal file
87
src/config/config.session-write-lock-timeout.test.ts
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
import { describe, expect, it } from "vitest";
|
||||||
|
import type { AgentDefaultsConfig } from "./types.agent-defaults.js";
|
||||||
|
import { AgentDefaultsSchema } from "./zod-schema.agent-defaults.js";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper to resolve session write lock timeout from config.
|
||||||
|
* Matches the pattern in session-write-lock.ts where default is 60_000ms.
|
||||||
|
*/
|
||||||
|
function resolveSessionWriteLockTimeout(config: {
|
||||||
|
agents?: { defaults?: { sessionWriteLockTimeoutMs?: number } };
|
||||||
|
}): number {
|
||||||
|
return config.agents?.defaults?.sessionWriteLockTimeoutMs ?? 60_000;
|
||||||
|
}
|
||||||
|
|
||||||
|
describe("sessionWriteLockTimeoutMs config", () => {
|
||||||
|
it("uses default timeout when unset", () => {
|
||||||
|
const config = {};
|
||||||
|
expect(resolveSessionWriteLockTimeout(config)).toBe(60_000);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("uses default timeout when agents.defaults is empty", () => {
|
||||||
|
const config = { agents: { defaults: {} } };
|
||||||
|
expect(resolveSessionWriteLockTimeout(config)).toBe(60_000);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("uses custom timeout from config", () => {
|
||||||
|
const config = {
|
||||||
|
agents: {
|
||||||
|
defaults: {
|
||||||
|
sessionWriteLockTimeoutMs: 30_000,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
expect(resolveSessionWriteLockTimeout(config)).toBe(30_000);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("accepts large timeout values", () => {
|
||||||
|
const config = {
|
||||||
|
agents: {
|
||||||
|
defaults: {
|
||||||
|
sessionWriteLockTimeoutMs: 120_000,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
expect(resolveSessionWriteLockTimeout(config)).toBe(120_000);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("config type includes sessionWriteLockTimeoutMs field", () => {
|
||||||
|
const config: AgentDefaultsConfig = {
|
||||||
|
sessionWriteLockTimeoutMs: 45_000,
|
||||||
|
};
|
||||||
|
expect(config.sessionWriteLockTimeoutMs).toBe(45_000);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("validates positive integer timeout via zod schema", () => {
|
||||||
|
const validConfig = { sessionWriteLockTimeoutMs: 30_000 };
|
||||||
|
const result = AgentDefaultsSchema.safeParse(validConfig);
|
||||||
|
expect(result.success).toBe(true);
|
||||||
|
if (result.success) {
|
||||||
|
expect(result.data.sessionWriteLockTimeoutMs).toBe(30_000);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it("rejects negative timeout values", () => {
|
||||||
|
const invalidConfig = { sessionWriteLockTimeoutMs: -1000 };
|
||||||
|
const result = AgentDefaultsSchema.safeParse(invalidConfig);
|
||||||
|
expect(result.success).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("rejects zero timeout value", () => {
|
||||||
|
const invalidConfig = { sessionWriteLockTimeoutMs: 0 };
|
||||||
|
const result = AgentDefaultsSchema.safeParse(invalidConfig);
|
||||||
|
expect(result.success).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("rejects non-integer timeout values", () => {
|
||||||
|
const invalidConfig = { sessionWriteLockTimeoutMs: 1000.5 };
|
||||||
|
const result = AgentDefaultsSchema.safeParse(invalidConfig);
|
||||||
|
expect(result.success).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("allows undefined/optional timeout", () => {
|
||||||
|
const config = {};
|
||||||
|
const result = AgentDefaultsSchema.safeParse(config);
|
||||||
|
expect(result.success).toBe(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
@ -196,6 +196,8 @@ export type AgentDefaultsConfig = {
|
|||||||
};
|
};
|
||||||
/** Max concurrent agent runs across all conversations. Default: 1 (sequential). */
|
/** Max concurrent agent runs across all conversations. Default: 1 (sequential). */
|
||||||
maxConcurrent?: number;
|
maxConcurrent?: number;
|
||||||
|
/** Timeout (ms) for acquiring per-session write lock. Default: 10000. */
|
||||||
|
sessionWriteLockTimeoutMs?: number;
|
||||||
/** Sub-agent defaults (spawned via sessions_spawn). */
|
/** Sub-agent defaults (spawned via sessions_spawn). */
|
||||||
subagents?: {
|
subagents?: {
|
||||||
/** Max concurrent sub-agent runs (global lane: "subagent"). Default: 1. */
|
/** Max concurrent sub-agent runs (global lane: "subagent"). Default: 1. */
|
||||||
|
|||||||
@ -123,6 +123,7 @@ export const AgentDefaultsSchema = z
|
|||||||
blockStreamingCoalesce: BlockStreamingCoalesceSchema.optional(),
|
blockStreamingCoalesce: BlockStreamingCoalesceSchema.optional(),
|
||||||
humanDelay: HumanDelaySchema.optional(),
|
humanDelay: HumanDelaySchema.optional(),
|
||||||
timeoutSeconds: z.number().int().positive().optional(),
|
timeoutSeconds: z.number().int().positive().optional(),
|
||||||
|
sessionWriteLockTimeoutMs: z.number().int().positive().optional(),
|
||||||
mediaMaxMb: z.number().positive().optional(),
|
mediaMaxMb: z.number().positive().optional(),
|
||||||
typingIntervalSeconds: z.number().int().positive().optional(),
|
typingIntervalSeconds: z.number().int().positive().optional(),
|
||||||
typingMode: z
|
typingMode: z
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user