wip: uncommitted changes
🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.5
parent
4185db9c75
commit
e8890a2fc1
@@ -89,7 +89,10 @@ class TestAgentSession implements AgentSession {
|
||||
async respondToPermission(): Promise<void> {}
|
||||
|
||||
describePersistence() {
|
||||
return null;
|
||||
return {
|
||||
provider: this.provider,
|
||||
sessionId: this.id,
|
||||
};
|
||||
}
|
||||
|
||||
async interrupt(): Promise<void> {}
|
||||
@@ -165,7 +168,7 @@ describe("AgentManager", () => {
|
||||
|
||||
expect(snapshot.runtimeInfo).toBeDefined();
|
||||
expect(snapshot.runtimeInfo?.model).toBe("gpt-5.2-codex");
|
||||
expect(snapshot.runtimeInfo?.sessionId).toBe(snapshot.sessionId);
|
||||
expect(snapshot.runtimeInfo?.sessionId).toBe(snapshot.persistence?.sessionId);
|
||||
});
|
||||
|
||||
test("runAgent refreshes runtimeInfo after completion", async () => {
|
||||
|
||||
@@ -93,7 +93,6 @@ type ManagedAgentBase = {
|
||||
persistence: AgentPersistenceHandle | null;
|
||||
historyPrimed: boolean;
|
||||
lastUserMessageAt: Date | null;
|
||||
sessionId: string | null;
|
||||
lastUsage?: AgentUsage;
|
||||
lastError?: string;
|
||||
attention: AttentionState;
|
||||
@@ -368,7 +367,6 @@ export class AgentManager {
|
||||
lifecycle: "closed",
|
||||
session: null,
|
||||
pendingRun: null,
|
||||
sessionId: agent.sessionId,
|
||||
};
|
||||
await session.close();
|
||||
this.emitState(closedAgent);
|
||||
@@ -421,8 +419,14 @@ export class AgentManager {
|
||||
}
|
||||
|
||||
const agent = this.requireAgent(agentId);
|
||||
const sessionId = agent.persistence?.sessionId;
|
||||
if (!sessionId) {
|
||||
throw new Error(
|
||||
`Agent ${agentId} has no persistence.sessionId after run completed`
|
||||
);
|
||||
}
|
||||
return {
|
||||
sessionId: agent.sessionId ?? agent.id,
|
||||
sessionId,
|
||||
finalText,
|
||||
usage,
|
||||
timeline,
|
||||
@@ -767,7 +771,6 @@ export class AgentManager {
|
||||
provider: config.provider,
|
||||
cwd: config.cwd,
|
||||
session,
|
||||
sessionId: session.id,
|
||||
capabilities: session.capabilities,
|
||||
config,
|
||||
runtimeInfo: undefined,
|
||||
@@ -878,7 +881,9 @@ export class AgentManager {
|
||||
|
||||
switch (event.type) {
|
||||
case "thread_started":
|
||||
agent.sessionId = event.sessionId;
|
||||
// Update persistence with the new session ID from the provider.
|
||||
// persistence.sessionId is the single source of truth for session identity.
|
||||
agent.persistence = agent.session.describePersistence();
|
||||
break;
|
||||
case "timeline":
|
||||
this.recordTimeline(agent, event.item);
|
||||
|
||||
@@ -407,7 +407,7 @@ describe("agent MCP end-to-end", () => {
|
||||
cwd: agentCwd,
|
||||
title: "MCP interrupt test",
|
||||
agentType: "codex",
|
||||
initialMode: "full-auto",
|
||||
initialMode: "full-access",
|
||||
background: true, // Start in background so create returns immediately
|
||||
},
|
||||
})) as McpToolResult;
|
||||
|
||||
@@ -234,7 +234,6 @@ describe("toAgentPayload", () => {
|
||||
expect(payload.lastUserMessageAt).toBe(agent.lastUserMessageAt?.toISOString());
|
||||
expect(payload.title).toBe("UI Payload");
|
||||
expect(payload.model).toBe(agent.config.model);
|
||||
expect(payload.sessionId).toBe(agent.sessionId);
|
||||
expect(payload.pendingPermissions.map((item) => item.id)).toEqual([
|
||||
"perm-a",
|
||||
"perm-b",
|
||||
|
||||
@@ -77,7 +77,6 @@ export function toAgentPayload(
|
||||
? agent.lastUserMessageAt.toISOString()
|
||||
: null,
|
||||
status: agent.lifecycle,
|
||||
sessionId: agent.sessionId,
|
||||
capabilities: cloneCapabilities(agent.capabilities),
|
||||
currentModeId: agent.currentModeId,
|
||||
availableModes: cloneAvailableModes(agent.availableModes),
|
||||
|
||||
@@ -51,7 +51,6 @@ function createManagedAgent(
|
||||
provider,
|
||||
cwd,
|
||||
session,
|
||||
sessionId: overrides.sessionId ?? "session-123",
|
||||
capabilities:
|
||||
overrides.capabilities ??
|
||||
{
|
||||
|
||||
@@ -66,6 +66,7 @@ export class AgentRegistry {
|
||||
private cache: Map<string, StoredAgentRecord> = new Map();
|
||||
private loaded = false;
|
||||
private filePath: string;
|
||||
private loadPromise: Promise<StoredAgentRecord[]> | null = null;
|
||||
|
||||
constructor(filePath: string) {
|
||||
this.filePath = filePath;
|
||||
@@ -75,6 +76,15 @@ export class AgentRegistry {
|
||||
if (this.loaded) {
|
||||
return Array.from(this.cache.values());
|
||||
}
|
||||
|
||||
if (!this.loadPromise) {
|
||||
this.loadPromise = this.doLoad();
|
||||
}
|
||||
|
||||
return this.loadPromise;
|
||||
}
|
||||
|
||||
private async doLoad(): Promise<StoredAgentRecord[]> {
|
||||
try {
|
||||
const content = await fs.readFile(this.filePath, "utf8");
|
||||
const parsed = await this.parseContent(content);
|
||||
|
||||
@@ -36,6 +36,47 @@ export interface AgentMcpServerOptions {
|
||||
callerAgentId?: string;
|
||||
}
|
||||
|
||||
const CLAUDE_TO_CODEX_MODE: Record<string, string> = {
|
||||
plan: "read-only",
|
||||
default: "auto",
|
||||
acceptEdits: "auto",
|
||||
bypassPermissions: "full-access",
|
||||
};
|
||||
|
||||
const CODEX_TO_CLAUDE_MODE: Record<string, string> = {
|
||||
"read-only": "plan",
|
||||
auto: "default",
|
||||
"full-access": "bypassPermissions",
|
||||
};
|
||||
|
||||
function mapModeAcrossProviders(
|
||||
sourceMode: string,
|
||||
sourceProvider: AgentProvider,
|
||||
targetProvider: AgentProvider
|
||||
): string {
|
||||
if (sourceProvider === targetProvider) {
|
||||
return sourceMode;
|
||||
}
|
||||
|
||||
if (sourceProvider === "claude" && targetProvider === "codex") {
|
||||
const mapped = CLAUDE_TO_CODEX_MODE[sourceMode];
|
||||
if (mapped) {
|
||||
return mapped;
|
||||
}
|
||||
return "auto";
|
||||
}
|
||||
|
||||
if (sourceProvider === "codex" && targetProvider === "claude") {
|
||||
const mapped = CODEX_TO_CLAUDE_MODE[sourceMode];
|
||||
if (mapped) {
|
||||
return mapped;
|
||||
}
|
||||
return "default";
|
||||
}
|
||||
|
||||
return sourceMode;
|
||||
}
|
||||
|
||||
const AgentProviderEnum = z.enum(
|
||||
AGENT_PROVIDER_DEFINITIONS.map((definition) => definition.id) as [
|
||||
AgentProvider,
|
||||
@@ -138,59 +179,91 @@ export async function createAgentMcpServer(
|
||||
version: "2.0.0",
|
||||
});
|
||||
|
||||
const agentToAgentInputSchema = {
|
||||
title: z
|
||||
.string()
|
||||
.trim()
|
||||
.min(1, "Title is required")
|
||||
.max(40, "Title must be 40 characters or fewer")
|
||||
.describe(
|
||||
"Short descriptive title (<= 40 chars) summarizing the agent's focus. Use a single concise sentence that fits on mobile."
|
||||
),
|
||||
agentType: AgentProviderEnum.optional().describe(
|
||||
"Optional agent implementation to spawn. Defaults to 'claude'."
|
||||
),
|
||||
initialPrompt: z
|
||||
.string()
|
||||
.optional()
|
||||
.describe(
|
||||
"Optional task to start immediately after creation (non-blocking)."
|
||||
),
|
||||
background: z
|
||||
.boolean()
|
||||
.optional()
|
||||
.default(false)
|
||||
.describe(
|
||||
"Run agent in background. If false (default), waits for completion or permission request. If true, returns immediately."
|
||||
),
|
||||
};
|
||||
|
||||
const topLevelInputSchema = {
|
||||
cwd: z
|
||||
.string()
|
||||
.describe(
|
||||
"Required working directory for the agent (absolute, relative, or ~)."
|
||||
),
|
||||
title: z
|
||||
.string()
|
||||
.trim()
|
||||
.min(1, "Title is required")
|
||||
.max(40, "Title must be 40 characters or fewer")
|
||||
.describe(
|
||||
"Short descriptive title (<= 40 chars) summarizing the agent's focus. Use a single concise sentence that fits on mobile."
|
||||
),
|
||||
agentType: AgentProviderEnum.optional().describe(
|
||||
"Optional agent implementation to spawn. Defaults to 'claude'."
|
||||
),
|
||||
initialPrompt: z
|
||||
.string()
|
||||
.optional()
|
||||
.describe(
|
||||
"Optional task to start immediately after creation (non-blocking)."
|
||||
),
|
||||
initialMode: z
|
||||
.string()
|
||||
.describe("Required session mode to configure before the first run."),
|
||||
worktreeName: z
|
||||
.string()
|
||||
.optional()
|
||||
.describe(
|
||||
"Optional git worktree branch name (lowercase alphanumerics + hyphen)."
|
||||
),
|
||||
background: z
|
||||
.boolean()
|
||||
.optional()
|
||||
.default(false)
|
||||
.describe(
|
||||
"Run agent in background. If false (default), waits for completion or permission request. If true, returns immediately."
|
||||
),
|
||||
parentAgentId: z
|
||||
.string()
|
||||
.optional()
|
||||
.describe(
|
||||
"Optional parent agent ID. When set, this agent is a child of the specified parent agent."
|
||||
),
|
||||
};
|
||||
|
||||
const createAgentInputSchema = callerAgentId
|
||||
? agentToAgentInputSchema
|
||||
: topLevelInputSchema;
|
||||
|
||||
server.registerTool(
|
||||
"create_agent",
|
||||
{
|
||||
title: "Create Agent",
|
||||
description:
|
||||
"Create a new Claude or Codex agent tied to a working directory. Optionally run an initial prompt immediately or create a git worktree for the agent.",
|
||||
inputSchema: {
|
||||
cwd: z
|
||||
.string()
|
||||
.describe(
|
||||
"Required working directory for the agent (absolute, relative, or ~)."
|
||||
),
|
||||
title: z
|
||||
.string()
|
||||
.trim()
|
||||
.min(1, "Title is required")
|
||||
.max(40, "Title must be 40 characters or fewer")
|
||||
.describe(
|
||||
"Short descriptive title (<= 40 chars) summarizing the agent's focus. Use a single concise sentence that fits on mobile."
|
||||
),
|
||||
agentType: AgentProviderEnum.optional().describe(
|
||||
"Optional agent implementation to spawn. Defaults to 'claude'."
|
||||
),
|
||||
initialPrompt: z
|
||||
.string()
|
||||
.optional()
|
||||
.describe(
|
||||
"Optional task to start immediately after creation (non-blocking)."
|
||||
),
|
||||
initialMode: z
|
||||
.string()
|
||||
.optional()
|
||||
.describe("Optional session mode to configure before the first run."),
|
||||
worktreeName: z
|
||||
.string()
|
||||
.optional()
|
||||
.describe(
|
||||
"Optional git worktree branch name (lowercase alphanumerics + hyphen)."
|
||||
),
|
||||
background: z
|
||||
.boolean()
|
||||
.optional()
|
||||
.default(false)
|
||||
.describe(
|
||||
"Run agent in background. If false (default), waits for completion or permission request. If true, returns immediately."
|
||||
),
|
||||
parentAgentId: z
|
||||
.string()
|
||||
.optional()
|
||||
.describe(
|
||||
"Optional parent agent ID. When set, this agent is a child of the specified parent agent."
|
||||
),
|
||||
},
|
||||
inputSchema: createAgentInputSchema,
|
||||
outputSchema: {
|
||||
agentId: z.string(),
|
||||
type: AgentProviderEnum,
|
||||
@@ -208,35 +281,79 @@ export async function createAgentMcpServer(
|
||||
permission: AgentPermissionRequestPayloadSchema.nullable().optional(),
|
||||
},
|
||||
},
|
||||
async ({
|
||||
cwd,
|
||||
agentType,
|
||||
initialPrompt,
|
||||
initialMode,
|
||||
worktreeName,
|
||||
background = false,
|
||||
title,
|
||||
parentAgentId,
|
||||
}) => {
|
||||
let resolvedCwd = expandPath(cwd);
|
||||
async (args) => {
|
||||
const {
|
||||
agentType,
|
||||
initialPrompt,
|
||||
background = false,
|
||||
title,
|
||||
} = args as {
|
||||
cwd?: string;
|
||||
agentType?: AgentProvider;
|
||||
initialPrompt?: string;
|
||||
initialMode?: string;
|
||||
worktreeName?: string;
|
||||
background?: boolean;
|
||||
title: string;
|
||||
parentAgentId?: string;
|
||||
};
|
||||
|
||||
if (worktreeName) {
|
||||
const worktree = await createWorktree({
|
||||
branchName: worktreeName,
|
||||
cwd: resolvedCwd,
|
||||
worktreeSlug: worktreeName,
|
||||
});
|
||||
resolvedCwd = worktree.worktreePath;
|
||||
let resolvedCwd: string;
|
||||
let resolvedMode: string | undefined;
|
||||
let resolvedParentAgentId: string | undefined;
|
||||
|
||||
if (callerAgentId) {
|
||||
const parentAgent = agentManager.getAgent(callerAgentId);
|
||||
if (!parentAgent) {
|
||||
throw new Error(`Parent agent ${callerAgentId} not found`);
|
||||
}
|
||||
resolvedCwd = parentAgent.cwd;
|
||||
resolvedParentAgentId = callerAgentId;
|
||||
|
||||
const provider: AgentProvider = agentType ?? "claude";
|
||||
const parentMode = parentAgent.currentModeId;
|
||||
if (parentMode) {
|
||||
resolvedMode = mapModeAcrossProviders(
|
||||
parentMode,
|
||||
parentAgent.provider,
|
||||
provider
|
||||
);
|
||||
}
|
||||
} else {
|
||||
const topLevelArgs = args as unknown as {
|
||||
cwd: string;
|
||||
initialMode: string;
|
||||
worktreeName?: string;
|
||||
parentAgentId?: string;
|
||||
};
|
||||
const {
|
||||
cwd,
|
||||
initialMode,
|
||||
worktreeName,
|
||||
parentAgentId,
|
||||
} = topLevelArgs;
|
||||
|
||||
resolvedCwd = expandPath(cwd);
|
||||
|
||||
if (worktreeName) {
|
||||
const worktree = await createWorktree({
|
||||
branchName: worktreeName,
|
||||
cwd: resolvedCwd,
|
||||
worktreeSlug: worktreeName,
|
||||
});
|
||||
resolvedCwd = worktree.worktreePath;
|
||||
}
|
||||
|
||||
resolvedMode = initialMode;
|
||||
resolvedParentAgentId = parentAgentId;
|
||||
}
|
||||
|
||||
const provider: AgentProvider = agentType ?? "claude";
|
||||
const normalizedTitle = title?.trim() ?? null;
|
||||
// Use explicit parentAgentId if provided, otherwise default to caller agent ID
|
||||
const resolvedParentAgentId = parentAgentId ?? callerAgentId;
|
||||
const snapshot = await agentManager.createAgent({
|
||||
provider,
|
||||
cwd: resolvedCwd,
|
||||
modeId: initialMode,
|
||||
modeId: resolvedMode,
|
||||
title: normalizedTitle ?? undefined,
|
||||
parentAgentId: resolvedParentAgentId,
|
||||
});
|
||||
|
||||
@@ -728,6 +728,12 @@ class ClaudeAgentSession implements AgentSession {
|
||||
stderr: (data: string) => {
|
||||
console.error("[ClaudeAgentSDK]", data.trim());
|
||||
},
|
||||
env: {
|
||||
...process.env,
|
||||
// Increase MCP timeouts for long-running tool calls (10 minutes)
|
||||
MCP_TIMEOUT: "600000",
|
||||
MCP_TOOL_TIMEOUT: "600000",
|
||||
},
|
||||
...this.config.extra?.claude,
|
||||
};
|
||||
|
||||
|
||||
@@ -117,6 +117,15 @@ const MODE_PRESETS: Record<
|
||||
},
|
||||
};
|
||||
|
||||
function validateCodexMode(modeId: string): void {
|
||||
if (!(modeId in MODE_PRESETS)) {
|
||||
const validModes = Object.keys(MODE_PRESETS).join(", ");
|
||||
throw new Error(
|
||||
`Invalid Codex mode "${modeId}". Valid modes are: ${validModes}`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function createToolCallTimelineItem(
|
||||
data: Omit<ToolCallTimelineItem, "type">
|
||||
): AgentTimelineItem {
|
||||
@@ -2757,9 +2766,13 @@ class CodexMcpAgentSession implements AgentSession {
|
||||
private pendingResumeFile: string | null = null;
|
||||
|
||||
constructor(config: CodexMcpAgentConfig, resumeHandle?: AgentPersistenceHandle) {
|
||||
if (config.modeId === undefined) {
|
||||
throw new Error("Codex agent requires modeId to be specified");
|
||||
}
|
||||
validateCodexMode(config.modeId);
|
||||
|
||||
this.config = config;
|
||||
this.currentMode =
|
||||
config.modeId !== undefined ? config.modeId : DEFAULT_CODEX_MODE_ID;
|
||||
this.currentMode = config.modeId;
|
||||
this.pendingLocalId = `codex-${randomUUID()}`;
|
||||
|
||||
if (resumeHandle) {
|
||||
@@ -3053,6 +3066,8 @@ class CodexMcpAgentSession implements AgentSession {
|
||||
}
|
||||
|
||||
async setMode(modeId: string): Promise<void> {
|
||||
validateCodexMode(modeId);
|
||||
|
||||
this.currentMode = modeId;
|
||||
this.config.modeId = modeId;
|
||||
|
||||
|
||||
@@ -243,7 +243,6 @@ export const AgentSnapshotPayloadSchema = z.object({
|
||||
updatedAt: z.string(),
|
||||
lastUserMessageAt: z.string().nullable(),
|
||||
status: AgentStatusSchema,
|
||||
sessionId: z.string().nullable(),
|
||||
capabilities: AgentCapabilityFlagsSchema,
|
||||
currentModeId: z.string().nullable(),
|
||||
availableModes: z.array(AgentModeSchema),
|
||||
@@ -340,7 +339,7 @@ export const SendAgentMessageSchema = z.object({
|
||||
|
||||
export const SendAgentAudioSchema = z.object({
|
||||
type: z.literal("send_agent_audio"),
|
||||
agentId: z.string(),
|
||||
agentId: z.string().optional(), // Required for auto_run mode, optional for transcribe_only
|
||||
audio: z.string(), // base64 encoded
|
||||
format: z.string(),
|
||||
isLast: z.boolean(),
|
||||
|
||||
@@ -49,7 +49,6 @@ function createManagedAgent(
|
||||
provider,
|
||||
cwd,
|
||||
session,
|
||||
sessionId: overrides.sessionId ?? "session-123",
|
||||
capabilities:
|
||||
overrides.capabilities ??
|
||||
{
|
||||
|
||||
@@ -609,7 +609,6 @@ export class Session {
|
||||
updatedAt: updatedAt.toISOString(),
|
||||
lastUserMessageAt: lastUserMessageAt ? lastUserMessageAt.toISOString() : null,
|
||||
status: record.lastStatus,
|
||||
sessionId: null,
|
||||
capabilities: defaultCapabilities,
|
||||
currentModeId: record.lastModeId ?? null,
|
||||
availableModes: [],
|
||||
@@ -1107,6 +1106,17 @@ export class Session {
|
||||
const { agentId, audio, format, isLast, requestId, mode } = msg;
|
||||
const shouldAutoRun = mode === "auto_run";
|
||||
|
||||
// agentId is required for auto_run mode
|
||||
if (shouldAutoRun && !agentId) {
|
||||
console.error(
|
||||
`[Session ${this.clientId}] agentId is required for auto_run mode`
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
// Use placeholder for logging when agentId is not provided
|
||||
const logAgentId = agentId ?? "transcription";
|
||||
|
||||
// Decode base64
|
||||
const audioBuffer = Buffer.from(audio, "base64");
|
||||
|
||||
@@ -1114,20 +1124,20 @@ export class Session {
|
||||
// In the future, we might want to buffer chunks similar to realtime audio
|
||||
if (!isLast) {
|
||||
console.log(
|
||||
`[Session ${this.clientId}] Buffering agent audio chunk for agent ${agentId}`
|
||||
`[Session ${this.clientId}] Buffering agent audio chunk for agent ${logAgentId}`
|
||||
);
|
||||
// TODO: Implement buffering if needed
|
||||
return;
|
||||
}
|
||||
|
||||
console.log(
|
||||
`[Session ${this.clientId}] Transcribing audio for agent ${agentId}`
|
||||
`[Session ${this.clientId}] Transcribing audio for agent ${logAgentId}`
|
||||
);
|
||||
|
||||
try {
|
||||
// Transcribe the audio
|
||||
const result = await this.sttManager.transcribe(audioBuffer, format, {
|
||||
agentId,
|
||||
agentId: logAgentId,
|
||||
requestId,
|
||||
label: shouldAutoRun ? "dictation:auto_run" : "dictation",
|
||||
});
|
||||
@@ -1135,13 +1145,13 @@ export class Session {
|
||||
const transcriptText = result.text.trim();
|
||||
if (!transcriptText) {
|
||||
console.log(
|
||||
`[Session ${this.clientId}] Empty transcription for agent ${agentId}, ignoring`
|
||||
`[Session ${this.clientId}] Empty transcription for agent ${logAgentId}, ignoring`
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
console.log(
|
||||
`[Session ${this.clientId}] Transcribed audio for agent ${agentId}: ${transcriptText}`
|
||||
`[Session ${this.clientId}] Transcribed audio for agent ${logAgentId}: ${transcriptText}`
|
||||
);
|
||||
|
||||
// Emit transcription result to client with requestId
|
||||
@@ -1162,16 +1172,19 @@ export class Session {
|
||||
|
||||
if (!shouldAutoRun) {
|
||||
console.log(
|
||||
`[Session ${this.clientId}] Completed transcription for agent ${agentId} (requestId: ${requestId ?? "n/a"})`
|
||||
`[Session ${this.clientId}] Completed transcription for agent ${logAgentId} (requestId: ${requestId ?? "n/a"})`
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
// At this point, agentId is guaranteed to be defined (validated at function start)
|
||||
const validAgentId = agentId!;
|
||||
|
||||
try {
|
||||
await this.ensureAgentLoaded(agentId);
|
||||
await this.ensureAgentLoaded(validAgentId);
|
||||
} catch (error) {
|
||||
this.handleAgentRunError(
|
||||
agentId,
|
||||
validAgentId,
|
||||
error,
|
||||
"Failed to initialize agent before sending audio prompt"
|
||||
);
|
||||
@@ -1179,10 +1192,10 @@ export class Session {
|
||||
}
|
||||
|
||||
try {
|
||||
await this.interruptAgentIfRunning(agentId);
|
||||
await this.interruptAgentIfRunning(validAgentId);
|
||||
} catch (error) {
|
||||
this.handleAgentRunError(
|
||||
agentId,
|
||||
validAgentId,
|
||||
error,
|
||||
"Failed to interrupt running agent before sending audio prompt"
|
||||
);
|
||||
@@ -1190,22 +1203,22 @@ export class Session {
|
||||
}
|
||||
|
||||
try {
|
||||
this.agentManager.recordUserMessage(agentId, transcriptText);
|
||||
this.agentManager.recordUserMessage(validAgentId, transcriptText);
|
||||
} catch (recordError) {
|
||||
console.error(
|
||||
`[Session ${this.clientId}] Failed to record transcribed user message for agent ${agentId}:`,
|
||||
`[Session ${this.clientId}] Failed to record transcribed user message for agent ${validAgentId}:`,
|
||||
recordError
|
||||
);
|
||||
}
|
||||
|
||||
// Send transcribed text to agent
|
||||
this.startAgentStream(agentId, transcriptText);
|
||||
this.startAgentStream(validAgentId, transcriptText);
|
||||
console.log(
|
||||
`[Session ${this.clientId}] Sent transcribed text to agent ${agentId}`
|
||||
`[Session ${this.clientId}] Sent transcribed text to agent ${validAgentId}`
|
||||
);
|
||||
} catch (error: any) {
|
||||
console.error(
|
||||
`[Session ${this.clientId}] Failed to process audio for agent ${agentId}:`,
|
||||
`[Session ${this.clientId}] Failed to process audio for agent ${logAgentId}:`,
|
||||
error
|
||||
);
|
||||
this.emit({
|
||||
|
||||
@@ -14,6 +14,7 @@ import type {
|
||||
AgentPersistenceHandle,
|
||||
AgentProvider,
|
||||
} from "../agent/agent-sdk-types.js";
|
||||
import { getAgentProviderDefinition } from "../agent/provider-manifest.js";
|
||||
|
||||
// ============================================================================
|
||||
// Configuration
|
||||
@@ -147,6 +148,12 @@ export class DaemonClient {
|
||||
// Record the current queue position so we only check NEW messages
|
||||
const startPosition = this.messageQueue.length;
|
||||
|
||||
// Apply default modeId if not provided (mimics frontend behavior)
|
||||
const modeId =
|
||||
options.modeId ??
|
||||
getAgentProviderDefinition(options.provider).defaultModeId ??
|
||||
undefined;
|
||||
|
||||
this.send({
|
||||
type: "create_agent_request",
|
||||
requestId,
|
||||
@@ -155,7 +162,7 @@ export class DaemonClient {
|
||||
cwd: options.cwd,
|
||||
title: options.title,
|
||||
model: options.model,
|
||||
modeId: options.modeId,
|
||||
modeId,
|
||||
mcpServers: options.mcpServers,
|
||||
extra: options.extra,
|
||||
},
|
||||
@@ -209,6 +216,12 @@ export class DaemonClient {
|
||||
// Record the current queue position so we only check NEW messages
|
||||
const startPosition = this.messageQueue.length;
|
||||
|
||||
// Apply default modeId if not provided (mimics frontend behavior)
|
||||
const modeId =
|
||||
options.modeId ??
|
||||
getAgentProviderDefinition(options.provider).defaultModeId ??
|
||||
undefined;
|
||||
|
||||
this.send({
|
||||
type: "create_agent_request",
|
||||
requestId,
|
||||
@@ -217,7 +230,7 @@ export class DaemonClient {
|
||||
cwd: options.cwd,
|
||||
title: options.title,
|
||||
model: options.model,
|
||||
modeId: options.modeId,
|
||||
modeId,
|
||||
mcpServers: options.mcpServers,
|
||||
extra: options.extra,
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user